示例#1
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);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Instantiates a new <see cref="CPK"/> from an input <see cref="Stream"/>.
        /// </summary>
        /// <param name="input"></param>
        public CPK(Stream input)
        {
            using (var br = new BinaryReaderX(input, true))
            {
                // Read in the CPK table.
                HeaderTable = new CpkTable(br.BaseStream);

                // Check the Magic
                if (HeaderTable.Header.Magic != "CPK ")
                {
                    throw new FormatException("The loaded file is not a CPK archive.");
                }

                Alignment = (short)(ushort)HeaderTable.Rows.First().Values["Align"].Value;

                // Retrieve the offsets for the other tables.
                var tocOffset = (long)(ulong)HeaderTable.Rows.First().Values["TocOffset"].Value;
                var tocSize   = (long)(ulong)HeaderTable.Rows.First().Values["TocSize"].Value;

                var etocOffset = (long)(ulong)HeaderTable.Rows.First().Values["EtocOffset"].Value;
                var etocSize   = (long)(ulong)HeaderTable.Rows.First().Values["EtocSize"].Value;

                var itocOffset = (long)(ulong)HeaderTable.Rows.First().Values["ItocOffset"].Value;
                var itocSize   = (long)(ulong)HeaderTable.Rows.First().Values["ItocSize"].Value;

                // Read in the TOC table.
                if (tocOffset > 0)
                {
                    // Fluff
                    br.BaseStream.Position = HeaderTable.Header.PacketSize + 0x10;
                    _unknownPostHeaderData = HeaderTable.UtfObfuscation ? UtfTools.XorUtf(br.ReadBytes((int)tocOffset - (int)br.BaseStream.Position)) : br.ReadBytes((int)tocOffset - (int)br.BaseStream.Position);

                    // Set the file offset base value
                    FileOffsetBase = tocOffset;

                    br.BaseStream.Position = tocOffset;
                    TocTable = new CpkTable(new SubStream(br.BaseStream, tocOffset, tocSize));

                    // Read in the ETOC table.
                    if (etocOffset > 0)
                    {
                        br.BaseStream.Position = etocOffset;
                        ETocTable = new CpkTable(new SubStream(br.BaseStream, etocOffset, etocSize));
                    }

                    // Populate files
                    foreach (var row in TocTable.Rows)
                    {
                        var dir            = ((string)row["DirName"].Value).Replace("/", "\\");
                        var name           = (string)row["FileName"].Value;
                        var offset         = FileOffsetBase + Convert.ToInt64(row["FileOffset"].Value);
                        var compressedSize = Convert.ToInt32(row["FileSize"].Value);
                        var fileSize       = Convert.ToInt32(row["ExtractSize"].Value);

                        Files.Add(new CpkFileInfo(new SubStream(br.BaseStream, offset, compressedSize), row, TocTable.UtfObfuscation, fileSize, compressedSize)
                        {
                            FileName = Path.Combine(dir, name),
                            State    = ArchiveFileState.Archived
                        });
                    }

                    // Sort files by offset
                    Files.Sort((a, b) => Convert.ToInt32(((CpkFileInfo)a).Row["FileOffset"].Value).CompareTo(Convert.ToInt32(((CpkFileInfo)b).Row["FileOffset"].Value)));
                }
                // Read in the ITOC table.
                else if (itocOffset > 0)
                {
                    // Fluff
                    br.BaseStream.Position = HeaderTable.Header.PacketSize + 0x10;
                    _unknownPostHeaderData = HeaderTable.UtfObfuscation ? UtfTools.XorUtf(br.ReadBytes((int)itocOffset - (int)br.BaseStream.Position)) : br.ReadBytes((int)itocOffset - (int)br.BaseStream.Position);

                    // Set the file offset base value
                    FileOffsetBase = itocOffset;

                    br.BaseStream.Position = itocOffset;
                    ITocTable = new CpkTable(new SubStream(br.BaseStream, itocOffset, itocSize));
                }
            }
        }