Add UTF-8 support for UTF tables

This commit is contained in:
Skyth 2017-01-30 13:47:50 +03:00
parent b4598ad8f6
commit 8b2333eecf
10 changed files with 99 additions and 33 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -75,18 +75,21 @@ namespace CsbEditor
{ {
CriCpkEntry cpkEntry = cpkArchive.GetByPath(sdlName); CriCpkEntry cpkEntry = cpkArchive.GetByPath(sdlName);
using (Stream cpkSource = File.OpenRead(cpkPath)) if (cpkEntry != null)
using (Stream aaxSource = cpkEntry.Open(cpkSource))
{ {
aaxArchive.Read(aaxSource); using (Stream cpkSource = File.OpenRead(cpkPath))
using (Stream aaxSource = cpkEntry.Open(cpkSource))
foreach (CriAaxEntry entry in aaxArchive)
{ {
using (Stream destination = File.Create(Path.Combine(destinationPath.FullName, aaxArchive.Read(aaxSource);
entry.Flag == CriAaxEntryFlag.Intro ? "Intro.adx" : "Loop.adx")))
using (Stream entrySource = entry.Open(aaxSource)) foreach (CriAaxEntry entry in aaxArchive)
{ {
entrySource.CopyTo(destination); using (Stream destination = File.Create(Path.Combine(destinationPath.FullName,
entry.Flag == CriAaxEntryFlag.Intro ? "Intro.adx" : "Loop.adx")))
using (Stream entrySource = entry.Open(aaxSource))
{
entrySource.CopyTo(destination);
}
} }
} }
} }

View File

@ -564,7 +564,20 @@ namespace SonicAudioLib.Archive
public CriCpkEntry GetByPath(string path) public CriCpkEntry GetByPath(string path)
{ {
return entries.FirstOrDefault(entry => ((entry.DirectoryName + "/" + entry.Name) == path)); string correctedPath = path.Replace('\\', '/');
return entries.FirstOrDefault(entry =>
{
string search = string.Empty;
if (!string.IsNullOrEmpty(entry.DirectoryName))
{
search += $"{entry.DirectoryName.Replace('\\', '/')}/";
}
search += entry.Name;
return search == correctedPath;
});
} }
private DateTime DateTimeFromCpkDateTime(ulong dateTime) private DateTime DateTimeFromCpkDateTime(ulong dateTime)

View File

@ -4,10 +4,13 @@ namespace SonicAudioLib.CriMw
{ {
struct CriTableHeader struct CriTableHeader
{ {
public static readonly string Signature = "@UTF"; public const string Signature = "@UTF";
public const byte EncodingTypeShiftJis = 0;
public const byte EncodingTypeUtf8 = 1;
public uint Length { get; set; } public uint Length { get; set; }
public bool FirstBoolean { get; set; } public byte UnknownByte { get; set; }
public bool SecondBoolean { get; set; } public byte EncodingType { get; set; }
public ushort RowsPosition { get; set; } public ushort RowsPosition { get; set; }
public uint StringPoolPosition { get; set; } public uint StringPoolPosition { get; set; }
public uint DataPoolPosition { get; set; } public uint DataPoolPosition { get; set; }
@ -18,7 +21,7 @@ namespace SonicAudioLib.CriMw
} }
[Flags] [Flags]
enum CriFieldFlag enum CriFieldFlag : byte
{ {
Name = 16, Name = 16,
DefaultValue = 32, DefaultValue = 32,

View File

@ -12,7 +12,8 @@ namespace SonicAudioLib.CriMw
private List<CriTableField> fields; private List<CriTableField> fields;
private Stream source; private Stream source;
private CriTableHeader header; private CriTableHeader header;
private int rowIndex = -1; private Encoding encoding;
private long rowIndex = -1;
private uint headerPosition; private uint headerPosition;
private bool leaveOpen; private bool leaveOpen;
@ -56,7 +57,7 @@ namespace SonicAudioLib.CriMw
} }
} }
public int CurrentRow public long CurrentRow
{ {
get get
{ {
@ -72,6 +73,14 @@ namespace SonicAudioLib.CriMw
} }
} }
public Encoding EncodingType
{
get
{
return encoding;
}
}
private void ReadTable() private void ReadTable()
{ {
headerPosition = (uint)source.Position; headerPosition = (uint)source.Position;
@ -102,8 +111,29 @@ namespace SonicAudioLib.CriMw
} }
header.Length = ReadUInt32() + 0x8; header.Length = ReadUInt32() + 0x8;
header.FirstBoolean = ReadBoolean(); header.UnknownByte = ReadByte();
header.SecondBoolean = ReadBoolean(); header.EncodingType = ReadByte();
if (header.UnknownByte != 0)
{
throw new Exception($"Invalid byte ({header.UnknownByte}. Please report the error with the file.");
}
// This actually might be a boolean telling the reader that it's using UTF-8 encoding, but idk
switch (header.EncodingType)
{
case CriTableHeader.EncodingTypeShiftJis:
encoding = Encoding.GetEncoding("shift-jis");
break;
case CriTableHeader.EncodingTypeUtf8:
encoding = Encoding.UTF8;
break;
default:
throw new Exception($"Unknown encoding type ({header.EncodingType}). Please report the error with the file.");
}
header.RowsPosition = (ushort)(ReadUInt16() + 0x8); header.RowsPosition = (ushort)(ReadUInt16() + 0x8);
header.StringPoolPosition = ReadUInt32() + 0x8; header.StringPoolPosition = ReadUInt32() + 0x8;
header.DataPoolPosition = ReadUInt32() + 0x8; header.DataPoolPosition = ReadUInt32() + 0x8;
@ -112,11 +142,6 @@ namespace SonicAudioLib.CriMw
header.RowLength = ReadUInt16(); header.RowLength = ReadUInt16();
header.NumberOfRows = ReadUInt32(); header.NumberOfRows = ReadUInt32();
if (header.FirstBoolean)
{
throw new Exception($"Invalid boolean ({header.FirstBoolean}. Please report the error with the file.");
}
for (ushort i = 0; i < header.NumberOfFields; i++) for (ushort i = 0; i < header.NumberOfFields; i++)
{ {
CriTableField field = new CriTableField(); CriTableField field = new CriTableField();
@ -271,7 +296,7 @@ namespace SonicAudioLib.CriMw
return true; return true;
} }
public bool MoveToRow(int rowIndex) public bool MoveToRow(long rowIndex)
{ {
if (rowIndex >= header.NumberOfRows) if (rowIndex >= header.NumberOfRows)
{ {
@ -617,7 +642,7 @@ namespace SonicAudioLib.CriMw
long previousPosition = source.Position; long previousPosition = source.Position;
source.Position = headerPosition + header.StringPoolPosition + stringPosition; source.Position = headerPosition + header.StringPoolPosition + stringPosition;
string strResult = EndianStream.ReadCString(source, Encoding.GetEncoding("shift-jis")); string strResult = EndianStream.ReadCString(source, encoding);
source.Position = previousPosition; source.Position = previousPosition;
if (strResult == "<NULL>" || if (strResult == "<NULL>" ||
@ -675,12 +700,12 @@ namespace SonicAudioLib.CriMw
ReadData(out vldPosition, out vldLength); ReadData(out vldPosition, out vldLength);
// SecondBoolean being true, check if utf table // Some ACB files have the length info set to zero for UTF table fields, so find the correct length
if (vldPosition > 0 && vldLength == 0) if (vldPosition > 0 && vldLength == 0)
{ {
source.Position = headerPosition + header.DataPoolPosition + vldPosition; source.Position = headerPosition + header.DataPoolPosition + vldPosition;
if (Encoding.ASCII.GetString(ReadBytes(4)) == "@UTF") if (EndianStream.ReadCString(source, 4) == "@UTF")
{ {
vldLength = ReadUInt32() + 8; vldLength = ReadUInt32() + 8;
} }

View File

@ -71,8 +71,8 @@ namespace SonicAudioLib.CriMw
EndianStream.WriteCString(destination, CriTableHeader.Signature, 4); EndianStream.WriteCString(destination, CriTableHeader.Signature, 4);
WriteUInt32(uint.MinValue); WriteUInt32(uint.MinValue);
WriteBoolean(false); WriteByte(byte.MinValue);
WriteBoolean(false); WriteByte(byte.MinValue);
WriteUInt16(ushort.MinValue); WriteUInt16(ushort.MinValue);
WriteUInt32(uint.MinValue); WriteUInt32(uint.MinValue);
WriteUInt32(uint.MinValue); WriteUInt32(uint.MinValue);
@ -112,13 +112,20 @@ namespace SonicAudioLib.CriMw
header.Length = (uint)destination.Position - headerPosition; header.Length = (uint)destination.Position - headerPosition;
header.FirstBoolean = false; if (settings.EncodingType == Encoding.GetEncoding("shift-jis"))
header.SecondBoolean = false; {
header.EncodingType = CriTableHeader.EncodingTypeShiftJis;
}
else if (settings.EncodingType == Encoding.UTF8)
{
header.EncodingType = CriTableHeader.EncodingTypeUtf8;
}
destination.Position = headerPosition + 4; destination.Position = headerPosition + 4;
WriteUInt32(header.Length - 8); WriteUInt32(header.Length - 8);
WriteBoolean(header.FirstBoolean); WriteByte(header.UnknownByte);
WriteBoolean(header.SecondBoolean); WriteByte(header.EncodingType);
WriteUInt16((ushort)(header.RowsPosition - 8)); WriteUInt16((ushort)(header.RowsPosition - 8));
WriteUInt32(header.StringPoolPosition - 8); WriteUInt32(header.StringPoolPosition - 8);
WriteUInt32(header.DataPoolPosition - 8); WriteUInt32(header.DataPoolPosition - 8);
@ -670,6 +677,11 @@ namespace SonicAudioLib.CriMw
set set
{ {
if (value != Encoding.UTF8 || value != Encoding.GetEncoding("shift-jis"))
{
return;
}
encodingType = value; encodingType = value;
} }
} }

View File

@ -43,6 +43,16 @@ namespace SonicAudioLib.IO
return buffer; return buffer;
} }
public static byte[] ReadBytesAt(Stream source, int length, long position)
{
long oldPosition = source.Position;
source.Position = position;
FillBuffer(source, length);
source.Position = oldPosition;
return buffer;
}
public static void WriteBytes(Stream destination, byte[] value) public static void WriteBytes(Stream destination, byte[] value)
{ {
destination.Write(value, 0, value.Length); destination.Write(value, 0, value.Length);