/// <summary> /// Instantiates a new instance of <see cref="CpkFileInfo"/>. /// </summary> /// <param name="obfuscated"></param> /// <param name="fileLength"></param> /// <param name="compressedLength"></param> public CpkFileInfo(Stream fileData, CpkRow row, bool obfuscated, long fileLength, long compressedLength) { _fileData = fileData; Row = row; Obfuscated = obfuscated; FileLength = fileLength; CompressedLength = compressedLength; Compressed = FileLength != CompressedLength; }
/// <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); } } }