//// Writing - TODO: This needs a rewrite since the "Data" type isn't properly supported. /// <summary> /// Writes a value based on the given <see cref="CpkValue"/> and <see cref="CpkColumnInfo"/>. /// </summary> /// <param name="bw"></param> /// <param name="val"></param> /// <param name="col"></param> /// <param name="strings"></param> /// <param name="data"></param> private void WriteValue(BinaryWriterX bw, CpkValue val, CpkColumnInfo col, Dictionary <string, int> strings = null, Dictionary <int, int> data = null) { switch (val.Type) { case CpkDataType.UInt8: bw.Write((byte)val.Value); break; case CpkDataType.SInt8: bw.Write((sbyte)val.Value); break; case CpkDataType.UInt16: bw.Write((ushort)val.Value); break; case CpkDataType.SInt16: bw.Write((short)val.Value); break; case CpkDataType.UInt32: bw.Write((uint)val.Value); break; case CpkDataType.SInt32: bw.Write((int)val.Value); break; case CpkDataType.UInt64: bw.Write((ulong)val.Value); break; case CpkDataType.SInt64: bw.Write((long)val.Value); break; case CpkDataType.Float: bw.Write((float)val.Value); break; case CpkDataType.String: bw.Write(strings[(string)val.Value]); break; case CpkDataType.Data: bw.Write((int)val.Value); bw.Write(data[(int)val.Value]); break; } }
/// <summary> /// Instantiates a new <see cref="CpkTable"/> from an input <see cref="Stream"/>. /// </summary> /// <param name="input"></param> public CpkTable(Stream input) { using (var br = new BinaryReaderX(input, true)) { // Read in the table header. Header = br.ReadType <CpkTableHeader>(); br.ByteOrder = ByteOrder.BigEndian; // Handle obfuscated UTF table if (br.PeekString() != "@UTF") { UtfObfuscation = true; // Decrypt the UTF table _tableStream = new BinaryReaderX(new MemoryStream(UtfTools.XorUtf(br.ReadBytes(Header.PacketSize))), true, ByteOrder.BigEndian); // Read the table info. TableInfo = _tableStream.ReadType <CpkTableInfo>(); // Replace the stream with a new SubStream into the decrypted data. _tableStream = new BinaryReaderX(new SubStream(_tableStream.BaseStream, 0x8, TableInfo.TableSize), true, ByteOrder.BigEndian); } else { // Read the table info. TableInfo = br.ReadType <CpkTableInfo>(); // Create a sub stream of the entire table. _tableStream = new BinaryReaderX(new SubStream(br.BaseStream, 0x18, TableInfo.TableSize), true, ByteOrder.BigEndian); } // Move forward to right after TableInfo _tableStream.BaseStream.Position += 0x18; // Make sure the data isn't bogus. if (Header.PacketSize - 0x8 != TableInfo.TableSize) { throw new FormatException("The packet size doesn't match the table size. The file might be corrupt, encrypted or it is not a CPK."); } if (Header.PacketSize > 100 * 1024 * 1024) { throw new FormatException("The packet size is too big. The file might be corrupt, encrypted or it is not a CPK."); } // Create sub streams for the string data and binary data. _stringStream = new BinaryReaderX(new SubStream(_tableStream.BaseStream, TableInfo.StringsOffset, TableInfo.TableSize - TableInfo.StringsOffset), true, ByteOrder.BigEndian); _binaryStream = new BinaryReaderX(new SubStream(_tableStream.BaseStream, TableInfo.BinaryOffset, TableInfo.TableSize - TableInfo.BinaryOffset), true, ByteOrder.BigEndian); // Read in the table name. Name = ReadString(TableInfo.NameOffset); // Read in the columns. var columns = new List <CpkColumnInfo>(); for (var i = 0; i < TableInfo.ColumnCount; i++) { var flags = _tableStream.ReadByte(); var column = new CpkColumnInfo { Name = ReadString(_tableStream.ReadInt32()), Storage = (CpkColumnStorage)(flags & 0xF0), Type = (CpkDataType)(flags & 0x0F) }; columns.Add(column); if (column.Storage == CpkColumnStorage.Const) { column.Value = ReadValue(column.Type); } if (column.Storage == CpkColumnStorage.Zero) { column.Value = ZeroValue(column.Type); } } Columns = columns; // Read in the values. _tableStream.BaseStream.Position = TableInfo.ValuesOffset; Rows = new List <CpkRow>(); for (var i = 0; i < TableInfo.RowCount; i++) { var row = new CpkRow(Columns); foreach (var column in Columns) { if (column.Storage == CpkColumnStorage.Const || column.Storage == CpkColumnStorage.Zero) { row[column.Name].Value = column.Value.Value; } else if (column.Storage == CpkColumnStorage.Row) { row[column.Name].Value = ReadValue(column.Type).Value; } } Rows.Add(row); } } }