Example #1
0
        //// 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;
            }
        }
Example #2
0
        /// <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);
                }
            }
        }