preliminary commit for UTF table writing - DOES NOT WORK - one file writes ok, the other not good at all

This commit is contained in:
Michael Becker 2019-11-17 02:44:30 -05:00
parent b5bc8c0ec1
commit 138c5c03ba
No known key found for this signature in database
GPG Key ID: 389DFF5D73781A12
8 changed files with 676 additions and 291 deletions

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="CRI Middleware UTF database">
<FileNameFilters>
<FileNameFilter>*.utf</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="String">@UTF</MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Database.DatabaseObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.Plugins.CRI.DataFormats.Database.UTF.UTFDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -652,6 +652,7 @@
<Content Include="Extensions\GameDeveloper\Associations\FileSystem\SquareSoftLGP.uexml" />
<Content Include="Extensions\GameDeveloper\Associations\FileSystem\CRI\AFS.uexml" />
<Content Include="Extensions\GameDeveloper\Associations\FileSystem\CRI\CPK.uexml" />
<Content Include="Extensions\GameDeveloper\Associations\Database\CRI\UTF.uexml" />
</ItemGroup>
<ItemGroup>
<Content Include="Configuration\Application.upl" />
@ -675,6 +676,8 @@
<Folder Include="Panels\SolutionExplorer\" />
<Folder Include="Panels\SolutionExplorer\Languages\" />
<Folder Include="Extensions\GameDeveloper\Associations\FileSystem\CRI\" />
<Folder Include="Extensions\GameDeveloper\Associations\Database\" />
<Folder Include="Extensions\GameDeveloper\Associations\Database\CRI\" />
</ItemGroup>
<ItemGroup>
<Content Include="Extensions\SoftwareDeveloper\Templates\Project\Software Development\Arduino\Images\Blink.xcf" />

View File

@ -19,9 +19,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.Plugins.CRI.DataFormats.FileSystem.CPK
namespace UniversalEditor.Plugins.CRI.DataFormats.Database.UTF
{
enum CPKColumnDataType : byte
public enum UTFColumnDataType : byte
{
Mask = 0x0f,
Data = 0x0b,

View File

@ -19,9 +19,9 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.Plugins.CRI.DataFormats.FileSystem.CPK
namespace UniversalEditor.Plugins.CRI.DataFormats.Database.UTF
{
enum CPKColumnStorageType : byte
public enum UTFColumnStorageType : byte
{
Mask = 0xf0,
PerRow = 0x50,

View File

@ -0,0 +1,553 @@
//
// UTFDataFormat.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Database;
namespace UniversalEditor.Plugins.CRI.DataFormats.Database.UTF
{
public class UTFDataFormat : DataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(DatabaseObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
private struct UTFTABLEINFO
{
public long utfOffset;
public int tableSize;
public int schemaOffset;
public int rowsOffset;
public int stringTableOffset;
public int dataOffset;
public uint tableNameStringOffset;
public short tableColumns;
public short rowWidth;
public int tableRows;
public int stringTableSize;
}
private UTFTABLEINFO ReadUTFTableInfo(IO.Reader br)
{
UTFTABLEINFO info = new UTFTABLEINFO();
info.utfOffset = Accessor.Position;
info.tableSize = br.ReadInt32();
info.schemaOffset = 0x20;
info.rowsOffset = br.ReadInt32();
info.stringTableOffset = br.ReadInt32();
info.dataOffset = br.ReadInt32();
// CPK Header & UTF Header are ignored, so add 8 to each offset
info.tableNameStringOffset = br.ReadUInt32(); // 00000007
info.tableColumns = br.ReadInt16(); // 0023
info.rowWidth = br.ReadInt16(); // 007e
info.tableRows = br.ReadInt32(); // 00000001
info.stringTableSize = info.dataOffset - info.stringTableOffset;
return info;
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
DatabaseObjectModel utf = (objectModel as DatabaseObjectModel);
if (utf == null)
throw new ObjectModelNotSupportedException();
Reader br = base.Accessor.Reader;
string utf_signature = br.ReadFixedLengthString(4);
if (utf_signature != "@UTF")
throw new InvalidDataFormatException(); // we are assuming passed in decrypted UTF from the CPK
DatabaseTable dt = new DatabaseTable();
br.Endianness = IO.Endianness.BigEndian;
UTFTABLEINFO info = ReadUTFTableInfo(br);
int[] columnNameOffsets = new int[info.tableColumns];
long[] constantOffsets = new long[info.tableColumns];
UTFColumnStorageType[] storageTypes = new UTFColumnStorageType[info.tableColumns];
UTFColumnDataType[] dataTypes = new UTFColumnDataType[info.tableColumns];
// Read string table - remember, this is relative to UTF data WITH the "@UTF" signature
br.Accessor.SavePosition();
br.Seek(info.stringTableOffset + 8, IO.SeekOrigin.Begin);
byte[] stringTableData = br.ReadBytes(info.stringTableSize);
MemoryAccessor maStringTable = new MemoryAccessor(stringTableData);
maStringTable.Reader.Seek(info.tableNameStringOffset, IO.SeekOrigin.Begin);
br.Accessor.LoadPosition();
for (int i = 0; i < info.tableColumns; i++)
{
byte schema = br.ReadByte();
/*// wtf is this?
if (schema == 0)
{
br.Accessor.Seek(3, SeekOrigin.Current);
column.flags = br.ReadByte();
}
*/
columnNameOffsets[i] = br.ReadInt32();
storageTypes[i] = (UTFColumnStorageType)(schema & (byte)UTFColumnStorageType.Mask);
dataTypes[i] = (UTFColumnDataType)(schema & (byte)UTFColumnDataType.Mask);
object constantValue = null;
if (storageTypes[i] == UTFColumnStorageType.Constant)
{
constantOffsets[i] = br.Accessor.Position;
switch (dataTypes[i])
{
case UTFColumnDataType.Long:
case UTFColumnDataType.Long2:
case UTFColumnDataType.Data:
{
constantValue = br.ReadInt64();
break;
}
case UTFColumnDataType.Float:
{
constantValue = br.ReadSingle();
break;
}
case UTFColumnDataType.String:
{
int valueOffset = br.ReadInt32();
maStringTable.Reader.Seek(valueOffset, IO.SeekOrigin.Begin);
constantValue = maStringTable.Reader.ReadNullTerminatedString();
break;
}
case UTFColumnDataType.Int:
case UTFColumnDataType.Int2:
{
constantValue = br.ReadInt32();
break;
}
case UTFColumnDataType.Short:
case UTFColumnDataType.Short2:
{
constantValue = br.ReadInt16();
break;
}
case UTFColumnDataType.Byte:
case UTFColumnDataType.Byte2:
{
constantValue = br.ReadByte();
break;
}
default:
{
Console.WriteLine("cpk: ReadUTFTable: unknown data type for column " + i.ToString());
break;
}
}
}
dt.Fields.Add("Field" + i.ToString(), constantValue, DataTypeForDataType(dataTypes[i]));
}
dt.Name = maStringTable.Reader.ReadNullTerminatedString();
for (int i = 0; i < info.tableColumns; i++)
{
maStringTable.Reader.Seek(columnNameOffsets[i], IO.SeekOrigin.Begin);
dt.Fields[i].Name = maStringTable.Reader.ReadNullTerminatedString();
}
for (int i = 0; i < info.tableRows; i++)
{
uint rowOffset = (uint)(info.utfOffset + 4 + info.rowsOffset + (i * info.rowWidth));
uint rowStartOffset = rowOffset;
br.Accessor.Seek(rowOffset, SeekOrigin.Begin);
DatabaseRecord record = new DatabaseRecord();
for (int j = 0; j < info.tableColumns; j++)
{
UTFColumnStorageType storageType = storageTypes[j];
UTFColumnDataType dataType = dataTypes[j];
long constantOffset = constantOffsets[j] - 11;
switch (storageType)
{
case UTFColumnStorageType.PerRow:
{
switch (dataType)
{
case UTFColumnDataType.String:
{
string value = null;
if (storageType == UTFColumnStorageType.Constant)
{
value = (dt.Fields[j].Value as string);
}
else
{
uint stringOffset = br.ReadUInt32();
if (stringOffset < stringTableData.Length)
{
maStringTable.Reader.Seek(stringOffset, IO.SeekOrigin.Begin);
value = maStringTable.Reader.ReadNullTerminatedString();
}
}
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case UTFColumnDataType.Data:
{
uint varDataOffset = br.ReadUInt32();
uint varDataSize = br.ReadUInt32();
byte[] value = new byte[0];
record.Fields.Add(dt.Fields[j].Name, value);
// Is the data in another table??
// ReadUTFTable(br);
break;
}
case UTFColumnDataType.Long:
case UTFColumnDataType.Long2:
{
ulong value = br.ReadUInt64();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case UTFColumnDataType.Int:
case UTFColumnDataType.Int2:
{
uint value = br.ReadUInt32();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case UTFColumnDataType.Short:
case UTFColumnDataType.Short2:
{
ushort value = br.ReadUInt16();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case UTFColumnDataType.Float:
{
float value = br.ReadSingle();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case UTFColumnDataType.Byte:
case UTFColumnDataType.Byte2:
{
byte value = br.ReadByte();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
}
break;
}
case UTFColumnStorageType.Constant:
{
record.Fields.Add(dt.Fields[j].Name, dt.Fields[j].Value);
continue;
}
case UTFColumnStorageType.Zero:
{
record.Fields.Add(dt.Fields[j].Name, null);
continue;
}
}
}
dt.Records.Add(record);
}
utf.Tables.Add(dt);
}
private Type DataTypeForDataType(UTFColumnDataType dataType)
{
switch (dataType)
{
case UTFColumnDataType.Byte:
case UTFColumnDataType.Byte2:
{
return typeof(byte);
}
case UTFColumnDataType.Data:
{
return typeof(byte[]);
}
case UTFColumnDataType.Float:
{
return typeof(float);
}
case UTFColumnDataType.Int:
case UTFColumnDataType.Int2:
{
return typeof(int);
}
case UTFColumnDataType.Long:
case UTFColumnDataType.Long2:
{
return typeof(long);
}
case UTFColumnDataType.Short:
case UTFColumnDataType.Short2:
{
return typeof(short);
}
case UTFColumnDataType.String:
{
return typeof(string);
}
}
return null;
}
protected override void SaveInternal(ObjectModel objectModel)
{
DatabaseObjectModel utf = (objectModel as DatabaseObjectModel);
if (utf == null)
throw new ObjectModelNotSupportedException();
Writer bw = Accessor.Writer;
bw.WriteFixedLengthString("@UTF");
DatabaseTable dt = utf.Tables[0];
bw.Endianness = IO.Endianness.BigEndian;
// do the hard work here to determine if a field should be recorded as zero or not
UTFColumnStorageType[] columnStorageTypes = new UTFColumnStorageType[dt.Fields.Count];
UTFColumnDataType[] columnDataTypes = new UTFColumnDataType[dt.Fields.Count];
for (int i = 0; i < dt.Fields.Count; i++)
{
columnStorageTypes[i] = UTFColumnStorageType.Zero;
if (dt.Fields[i].DataType == typeof(bool))
{
columnDataTypes[i] = UTFColumnDataType.Byte;
}
else if (dt.Fields[i].DataType == typeof(byte[]))
{
columnDataTypes[i] = UTFColumnDataType.Data;
}
else if (dt.Fields[i].DataType == typeof(float))
{
columnDataTypes[i] = UTFColumnDataType.Float;
}
else if (dt.Fields[i].DataType == typeof(int))
{
columnDataTypes[i] = UTFColumnDataType.Int;
}
else if (dt.Fields[i].DataType == typeof(long))
{
columnDataTypes[i] = UTFColumnDataType.Long;
}
else if (dt.Fields[i].DataType == typeof(short))
{
columnDataTypes[i] = UTFColumnDataType.Short;
}
else if (dt.Fields[i].DataType == typeof(string))
{
columnDataTypes[i] = UTFColumnDataType.String;
}
if (dt.Fields[i].Value != null)
{
columnStorageTypes[i] = UTFColumnStorageType.Constant;
continue;
}
for (int j = 0; j < dt.Records.Count; j++)
{
if (dt.Records[j].Fields[i].Value != null)
{
columnStorageTypes[i] = UTFColumnStorageType.PerRow;
break;
}
}
}
int tableSize = 32; // size of entire file
tableSize += (5 * dt.Fields.Count);
short rowWidth = 0x007e;
tableSize += (dt.Name.Length + 1);
tableSize += 7; // "<NULL>\0".Length
for (int i = 0; i < dt.Fields.Count; i++)
{
tableSize += (dt.Fields[i].Name.Length + 1);
}
int rowsOffset = 24 + (5 * dt.Fields.Count);
int stringTableOffset = rowsOffset;
for (int i = 0; i < dt.Records.Count; i++)
{
for (int j = 0; j < dt.Records[i].Fields.Count; j++)
{
if (columnStorageTypes[j] == UTFColumnStorageType.PerRow)
{
switch (columnDataTypes[j])
{
case UTFColumnDataType.String:
{
tableSize += 4;
tableSize += ((string)dt.Records[i].Fields[j].Value).Length + 1;
stringTableOffset += 4;
break;
}
case UTFColumnDataType.Data:
case UTFColumnDataType.Long:
case UTFColumnDataType.Long2:
{
tableSize += 8; // sizeof(long)
stringTableOffset += 8;
break;
}
case UTFColumnDataType.Byte:
case UTFColumnDataType.Byte2:
{
tableSize += 1; // sizeof(byte)
stringTableOffset += 1;
break;
}
case UTFColumnDataType.Float:
case UTFColumnDataType.Int:
case UTFColumnDataType.Int2:
{
tableSize += 4; // sizeof(int)
stringTableOffset += 4;
break;
}
case UTFColumnDataType.Short:
case UTFColumnDataType.Short2:
{
tableSize += 2; // sizeof(short)
stringTableOffset += 2;
break;
}
}
}
}
}
tableSize += ((8 - (tableSize % 8)) % 8);
tableSize -= 8;
bw.WriteInt32(tableSize);
bw.WriteInt32(rowsOffset);
bw.WriteInt32(stringTableOffset);
bw.WriteInt32(tableSize); // data offset - same as table size?
bw.WriteUInt32(7); // "<NULL>\0".Length
bw.WriteInt16((short)dt.Fields.Count); // 0023
bw.WriteInt16(rowWidth); // 007e
bw.WriteInt32(dt.Records.Count); // 00000001
int columnNameOffset = 8 + dt.Name.Length; // add space for "<NULL>\0" string and dt.Name + 1
List<string> stringTable = new List<string>();
stringTable.Add("<NULL>");
stringTable.Add(dt.Name);
for (int i = 0; i < dt.Fields.Count; i++)
{
byte schema = 0;
schema |= (byte)((byte)columnStorageTypes[i] | (byte)columnDataTypes[i]);
bw.WriteByte(schema);
bw.WriteInt32(columnNameOffset);
columnNameOffset += dt.Fields[i].Name.Length + 1;
stringTable.Add(dt.Fields[i].Name);
}
for (int i = 0; i < dt.Records.Count; i++)
{
for (int j = 0; j < dt.Records[i].Fields.Count; j++)
{
if (columnStorageTypes[j] == UTFColumnStorageType.PerRow)
{
switch (columnDataTypes[j])
{
case UTFColumnDataType.String:
{
stringTable.Add((string)dt.Records[i].Fields[j].Value);
bw.WriteUInt32((uint)stringTable.GetItemOffset(stringTable.Count - 1, 1));
break;
}
case UTFColumnDataType.Data:
{
uint varDataOffset = 0;
uint varDataSize = 0;
bw.WriteUInt32(varDataOffset);
bw.WriteUInt32(varDataSize);
break;
}
case UTFColumnDataType.Long:
case UTFColumnDataType.Long2:
{
bw.WriteUInt64((ulong)dt.Records[i].Fields[j].Value);
break;
}
case UTFColumnDataType.Int:
case UTFColumnDataType.Int2:
{
bw.WriteUInt32((uint)dt.Records[i].Fields[j].Value);
break;
}
case UTFColumnDataType.Short:
case UTFColumnDataType.Short2:
{
bw.WriteUInt16((ushort)dt.Records[i].Fields[j].Value);
break;
}
case UTFColumnDataType.Float:
{
bw.WriteSingle((float)dt.Records[i].Fields[j].Value);
break;
}
case UTFColumnDataType.Byte:
case UTFColumnDataType.Byte2:
{
bw.WriteByte((byte)dt.Records[i].Fields[j].Value);
break;
}
}
}
}
}
for (int i = 0; i < stringTable.Count; i++)
{
bw.WriteNullTerminatedString(stringTable[i]);
}
bw.Align(8);
}
}
}

View File

@ -21,6 +21,8 @@ using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Database;
using UniversalEditor.ObjectModels.FileSystem;
using UniversalEditor.Plugins.CRI.DataFormats.Database.UTF;
namespace UniversalEditor.Plugins.CRI.DataFormats.FileSystem.CPK
{
public class CPKDataFormat : DataFormat
@ -65,7 +67,7 @@ namespace UniversalEditor.Plugins.CRI.DataFormats.FileSystem.CPK
ma.Reader.Seek(-4, IO.SeekOrigin.Current);
}
UTF.UTFDataFormat utf_df = new UTF.UTFDataFormat();
UTFDataFormat utf_df = new UTFDataFormat();
DatabaseObjectModel utf_om = new DatabaseObjectModel();
Document.Load(utf_om, utf_df, ma);
@ -154,6 +156,89 @@ namespace UniversalEditor.Plugins.CRI.DataFormats.FileSystem.CPK
e.Data = decompressedData;
}
private DatabaseTable BuildHeaderUTF(FileSystemObjectModel fsom)
{
File[] files = fsom.GetAllFiles();
DatabaseTable dt = new DatabaseTable();
dt.Fields.Add("UpdateDateTime");
dt.Fields.Add("FileSize");
dt.Fields.Add("ContentOffset");
dt.Fields.Add("ContentSize");
dt.Fields.Add("TocOffset");
dt.Fields.Add("TocSize");
dt.Fields.Add("TocCrc");
dt.Fields.Add("EtocOffset");
dt.Fields.Add("EtocSize");
dt.Fields.Add("ItocOffset");
dt.Fields.Add("ItocSize");
dt.Fields.Add("ItocCrc");
dt.Fields.Add("GtocOffset");
dt.Fields.Add("GtocSize");
dt.Fields.Add("GtocCrc");
dt.Fields.Add("EnabledPackedSize");
dt.Fields.Add("EnabledDataSize");
dt.Fields.Add("TotalDataSize");
dt.Fields.Add("Tocs");
dt.Fields.Add("Files");
dt.Fields.Add("Groups");
dt.Fields.Add("Attrs");
dt.Fields.Add("TotalFiles");
dt.Fields.Add("Directories");
dt.Fields.Add("Updates");
dt.Fields.Add("Version");
dt.Fields.Add("Revision");
dt.Fields.Add("Align");
dt.Fields.Add("Sorted");
dt.Fields.Add("EID");
dt.Fields.Add("CpkMode");
dt.Fields.Add("Tvers");
dt.Fields.Add("Comment");
dt.Fields.Add("Codec");
dt.Fields.Add("DpkItoc");
dt.Records.Add(new DatabaseRecord(new DatabaseField[]
{
new DatabaseField("UpdateDateTime", (ulong)1),
new DatabaseField("FileSize", null),
new DatabaseField("ContentOffset", (ulong)153600),
new DatabaseField("ContentSize", (ulong)421693440),
new DatabaseField("TocOffset", (ulong)2048),
new DatabaseField("TocSize", (ulong)117896),
new DatabaseField("TocCrc", null),
new DatabaseField("EtocOffset", (ulong)421847040),
new DatabaseField("EtocSize", (ulong)21768),
new DatabaseField("ItocOffset", (ulong)131072),
new DatabaseField("ItocSize", (ulong)21744),
new DatabaseField("ItocCrc", null),
new DatabaseField("GtocOffset", null),
new DatabaseField("GtocSize", null),
new DatabaseField("GtocCrc", null),
new DatabaseField("EnabledPackedSize", (ulong)837335552),
new DatabaseField("EnabledDataSize", (ulong)837335552),
new DatabaseField("TotalDataSize", null),
new DatabaseField("Tocs", null),
new DatabaseField("Files", (uint)files.Length),
new DatabaseField("Groups", (uint)0),
new DatabaseField("Attrs", (uint)0),
new DatabaseField("TotalFiles", null),
new DatabaseField("Directories", null),
new DatabaseField("Updates", null),
new DatabaseField("Version", (ushort)7),
new DatabaseField("Revision", (ushort)0),
new DatabaseField("Align", (ushort)2048),
new DatabaseField("Sorted", (ushort)1),
new DatabaseField("EID", (ushort)1),
new DatabaseField("CpkMode", (uint)2),
new DatabaseField("Tvers", "CPKMC2.14.00, DLL2.74.00"),
new DatabaseField("Comment", null),
new DatabaseField("Codec", (uint)0),
new DatabaseField("DpkItoc", (uint)0)
}));
return dt;
}
private byte[] DecryptUTF(byte[] input)
{

View File

@ -1,282 +0,0 @@
//
// UTFDataFormat.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.Accessors;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Database;
namespace UniversalEditor.Plugins.CRI.DataFormats.FileSystem.CPK.UTF
{
public class UTFDataFormat : DataFormat
{
private struct UTFTABLEINFO
{
public long utfOffset;
public int tableSize;
public int schemaOffset;
public int rowsOffset;
public int stringTableOffset;
public int dataOffset;
public uint tableNameStringOffset;
public short tableColumns;
public short rowWidth;
public int tableRows;
public int stringTableSize;
}
private UTFTABLEINFO ReadUTFTableInfo(IO.Reader br)
{
UTFTABLEINFO info = new UTFTABLEINFO();
info.utfOffset = Accessor.Position;
info.tableSize = br.ReadInt32();
info.schemaOffset = 0x20;
info.rowsOffset = br.ReadInt32();
info.stringTableOffset = br.ReadInt32();
info.dataOffset = br.ReadInt32();
// CPK Header & UTF Header are ignored, so add 8 to each offset
info.tableNameStringOffset = br.ReadUInt32(); // 00000007
info.tableColumns = br.ReadInt16(); // 0023
info.rowWidth = br.ReadInt16(); // 007e
info.tableRows = br.ReadInt32(); // 00000001
info.stringTableSize = info.dataOffset - info.stringTableOffset;
return info;
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
Reader br = base.Accessor.Reader;
string utf_signature = br.ReadFixedLengthString(4);
if (utf_signature != "@UTF")
throw new InvalidDataFormatException(); // we are assuming passed in decrypted UTF from the CPK
DatabaseObjectModel utf = (objectModel as DatabaseObjectModel);
DatabaseTable dt = new DatabaseTable();
br.Endianness = IO.Endianness.BigEndian;
UTFTABLEINFO info = ReadUTFTableInfo(br);
int[] columnNameOffsets = new int[info.tableColumns];
long[] constantOffsets = new long[info.tableColumns];
CPKColumnStorageType[] storageTypes = new CPKColumnStorageType[info.tableColumns];
CPKColumnDataType[] dataTypes = new CPKColumnDataType[info.tableColumns];
for (int i = 0; i < info.tableColumns; i++)
{
byte schema = br.ReadByte();
/*// wtf is this?
if (schema == 0)
{
br.Accessor.Seek(3, SeekOrigin.Current);
column.flags = br.ReadByte();
}
*/
columnNameOffsets[i] = br.ReadInt32();
storageTypes[i] = (CPKColumnStorageType)(schema & (byte)CPKColumnStorageType.Mask);
dataTypes[i] = (CPKColumnDataType)(schema & (byte)CPKColumnDataType.Mask);
if (storageTypes[i] == CPKColumnStorageType.Constant)
{
constantOffsets[i] = br.Accessor.Position;
switch (dataTypes[i])
{
case CPKColumnDataType.Long:
case CPKColumnDataType.Long2:
case CPKColumnDataType.Data:
{
long dummy = br.ReadInt64();
break;
}
case CPKColumnDataType.Float:
{
float dummy = br.ReadSingle();
break;
}
case CPKColumnDataType.String:
case CPKColumnDataType.Int:
case CPKColumnDataType.Int2:
{
int dummy = br.ReadInt32();
break;
}
case CPKColumnDataType.Short:
case CPKColumnDataType.Short2:
{
short dummy = br.ReadInt16();
break;
}
case CPKColumnDataType.Byte:
case CPKColumnDataType.Byte2:
{
byte dummy = br.ReadByte();
break;
}
default:
{
Console.WriteLine("cpk: ReadUTFTable: unknown data type for column " + i.ToString());
break;
}
}
}
dt.Fields.Add("Field" + i.ToString(), null);
}
// Read string table - remember, this is relative to UTF data WITH the "@UTF" signature
br.Seek(info.stringTableOffset + 8, IO.SeekOrigin.Begin);
byte[] stringTableData = br.ReadBytes(info.stringTableSize);
MemoryAccessor maStringTable = new MemoryAccessor(stringTableData);
maStringTable.Reader.Seek(info.tableNameStringOffset, IO.SeekOrigin.Begin);
dt.Name = maStringTable.Reader.ReadNullTerminatedString();
for (int i = 0; i < info.tableColumns; i++)
{
maStringTable.Reader.Seek(columnNameOffsets[i], IO.SeekOrigin.Begin);
dt.Fields[i].Name = maStringTable.Reader.ReadNullTerminatedString();
}
for (int i = 0; i < info.tableRows; i++)
{
uint rowOffset = (uint)(info.utfOffset + 4 + info.rowsOffset + (i * info.rowWidth));
uint rowStartOffset = rowOffset;
br.Accessor.Seek(rowOffset, SeekOrigin.Begin);
DatabaseRecord record = new DatabaseRecord();
for (int j = 0; j < info.tableColumns; j++)
{
CPKColumnStorageType storageType = storageTypes[j];
CPKColumnDataType dataType = dataTypes[j];
long constantOffset = constantOffsets[j] - 11;
switch (storageType)
{
case CPKColumnStorageType.PerRow:
break;
case CPKColumnStorageType.Constant:
break;
case CPKColumnStorageType.Zero:
record.Fields.Add(dt.Fields[j].Name, null);
continue;
}
long dataOffset1 = 0;
if (storageType == CPKColumnStorageType.Constant)
{
dataOffset1 = constantOffset;
}
else
{
dataOffset1 = rowOffset;
}
// br.Seek(dataOffset1, IO.SeekOrigin.Begin);
switch (dataType)
{
case CPKColumnDataType.String:
{
uint stringOffset = 0;
if (storageType == CPKColumnStorageType.Constant)
{
stringOffset = (uint)constantOffset;
}
else
{
stringOffset = br.ReadUInt32();
}
string value = null;
if (stringOffset < stringTableData.Length)
{
maStringTable.Reader.Seek(stringOffset, IO.SeekOrigin.Begin);
value = maStringTable.Reader.ReadNullTerminatedString();
}
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case CPKColumnDataType.Data:
{
uint varDataOffset = br.ReadUInt32();
uint varDataSize = br.ReadUInt32();
byte[] value = new byte[0];
record.Fields.Add(dt.Fields[j].Name, value);
// Is the data in another table??
// ReadUTFTable(br);
break;
}
case CPKColumnDataType.Long:
case CPKColumnDataType.Long2:
{
ulong value = br.ReadUInt64();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case CPKColumnDataType.Int:
case CPKColumnDataType.Int2:
{
uint value = br.ReadUInt32();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case CPKColumnDataType.Short:
case CPKColumnDataType.Short2:
{
ushort value = br.ReadUInt16();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case CPKColumnDataType.Float:
{
float value = br.ReadSingle();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
case CPKColumnDataType.Byte:
case CPKColumnDataType.Byte2:
{
byte value = br.ReadByte();
record.Fields.Add(dt.Fields[j].Name, value);
break;
}
}
}
dt.Records.Add(record);
}
utf.Tables.Add(dt);
}
protected override void SaveInternal(ObjectModel objectModel)
{
throw new NotImplementedException();
}
}
}

View File

@ -33,20 +33,21 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DataFormats\FileSystem\CPK\CPKColumnDataType.cs" />
<Compile Include="DataFormats\FileSystem\CPK\CPKColumnStorageType.cs" />
<Compile Include="DataFormats\FileSystem\CPK\CPKDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\CPK\UTF\UTFDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\AFS\AFSDataFormat.cs" />
<Compile Include="DataFormats\FileSystem\AFS\AFSFileInfo.cs" />
<Compile Include="DataFormats\FileSystem\AFS\AFSFormatVersion.cs" />
<Compile Include="DataFormats\Database\UTF\UTFDataFormat.cs" />
<Compile Include="DataFormats\Database\UTF\UTFColumnDataType.cs" />
<Compile Include="DataFormats\Database\UTF\UTFColumnStorageType.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="DataFormats\" />
<Folder Include="DataFormats\FileSystem\" />
<Folder Include="DataFormats\FileSystem\CPK\" />
<Folder Include="DataFormats\FileSystem\CPK\UTF\" />
<Folder Include="DataFormats\FileSystem\AFS\" />
<Folder Include="DataFormats\Database\" />
<Folder Include="DataFormats\Database\UTF\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">