public BlockEntry FromData(Span <byte> xorData, PackfileHeader header)
            {
                if (header.IsEncrypted)
                {
                    XorKey1 = Bits.ToUInt32(xorData.Slice(12));         // 0xC
                    XorKey2 = Bits.ToUInt32(xorData.Slice(28));         // 0x1C

                    var key1 = header.BuildXorKey(Bits.GetBytes(XorKey1));
                    var key2 = header.BuildXorKey(Bits.GetBytes(XorKey2));

                    for (int i = 0; i < 16; i++)
                    {
                        xorData[i + 0] ^= key1[i];// XOR bytes 0 to 16
                    }
                    for (int i = 0; i < 16; i++)
                    {
                        xorData[i + 16] ^= key2[i];// XOR bytes 16 to 32
                    }
                    // The XOR keys at offset 0xC and 0x1C in xorData are trashed now. They are manually restored in game code.
                }

                DecompressedOffset = Bits.ToUInt64(xorData.Slice(0));   // 0x0
                DecompressedSize   = Bits.ToUInt32(xorData.Slice(8));   // 0x8
                Offset             = Bits.ToUInt64(xorData.Slice(16));  // 0x10
                Size = Bits.ToUInt32(xorData.Slice(24));                // 0x18

                return(this);
            }
            public FileEntry FromData(Span <byte> xorData, PackfileHeader header)
            {
                if (header.IsEncrypted)
                {
                    XorKey1 = Bits.ToUInt32(xorData.Slice(4));          // 0x4
                    XorKey2 = Bits.ToUInt32(xorData.Slice(28));         // 0x1C

                    var key1 = header.BuildXorKey(Bits.GetBytes(XorKey1));
                    var key2 = header.BuildXorKey(Bits.GetBytes(XorKey2));

                    for (int i = 0; i < 16; i++)
                    {
                        xorData[i + 0] ^= key1[i];// XOR bytes 0 to 16
                    }
                    for (int i = 0; i < 16; i++)
                    {
                        xorData[i + 16] ^= key2[i];// XOR bytes 16 to 32
                    }
                    // The XOR keys at offset 0x4 and 0x1C in xorData are trashed now. They seem to ignore it.
                }

                //_ = Bits.ToUInt32(xorData.Slice(0));                  // 0x0 Not used?
                PathHash           = Bits.ToUInt64(xorData.Slice(8));   // 0x8
                DecompressedOffset = Bits.ToUInt64(xorData.Slice(16));  // 0x10
                DecompressedSize   = Bits.ToUInt32(xorData.Slice(24));  // 0x18

                return(this);
            }
            public void ToData(BinaryWriter writer, PackfileHeader header)
            {
                Span <byte> data = stackalloc byte[DataHeaderSize];

                Bits.TryWriteBytes(data.Slice(0), DecompressedOffset);  // 0x0
                Bits.TryWriteBytes(data.Slice(8), DecompressedSize);    // 0x8
                Bits.TryWriteBytes(data.Slice(16), Offset);             // 0x10
                Bits.TryWriteBytes(data.Slice(24), Size);               // 0x18

                if (header.IsEncrypted)
                {
                    var key1 = header.BuildXorKey(Bits.GetBytes(XorKey1));
                    var key2 = header.BuildXorKey(Bits.GetBytes(XorKey2));

                    for (int i = 0; i < 16; i++)
                    {
                        data[i + 0] ^= key1[i];// XOR bytes 0 to 16
                    }
                    for (int i = 0; i < 16; i++)
                    {
                        data[i + 16] ^= key2[i];// XOR bytes 16 to 32
                    }
                }

                Bits.TryWriteBytes(data.Slice(12), XorKey1);            // 0xC
                Bits.TryWriteBytes(data.Slice(28), XorKey2);            // 0x1C

                writer.Write(data.ToArray());
            }
Beispiel #4
0
        public PackfileReader(string archivePath)
        {
            _archivePath     = archivePath;
            using var handle = File.OpenRead(_archivePath);

            using var reader = new BinaryReader(handle, Encoding.UTF8, true);

            Header       = new PackfileHeader().FromData(reader);
            FileEntries  = new List <FileEntry>((int)Header.FileEntryCount);
            BlockEntries = new List <BlockEntry>((int)Header.BlockEntryCount);

            Span <byte> fileData = reader.ReadBytes(Header.FileEntryCount * FileEntry.DataHeaderSize);

            for (int i = 0; i < Header.FileEntryCount; i++)
            {
                var data = fileData.Slice(i * FileEntry.DataHeaderSize, FileEntry.DataHeaderSize);
                FileEntries.Add(new FileEntry().FromData(data, Header));
            }

            Span <byte> blockData = reader.ReadBytes(Header.BlockEntryCount * BlockEntry.DataHeaderSize);

            for (int i = 0; i < Header.BlockEntryCount; i++)
            {
                var data = blockData.Slice(i * BlockEntry.DataHeaderSize, BlockEntry.DataHeaderSize);
                BlockEntries.Add(new BlockEntry().FromData(data, Header));
            }
        }
Beispiel #5
0
        /// <summary>
        /// Open an archive (.bin) file and prepare for writing.
        /// </summary>
        /// <param name="archivePath">Disk path</param>
        /// <param name="encrypted">Encrypt file data</param>
        /// <param name="mode">File creation mode</param>
        public PackfileWriter(string archivePath, bool encrypted = false, FileMode mode = FileMode.CreateNew)
        {
            _fileHandle = new FileStream(archivePath, mode, FileAccess.ReadWrite, FileShare.Read);

            Header        = new PackfileHeader();
            _fileEntries  = new List <FileEntry>();
            _blockEntries = new List <BlockEntry>();

            Header.IsEncrypted = encrypted;
        }
        public PackfileWriter(string archivePath, bool encrypted = false, bool allowOverwrite = false)
        {
            _archivePath    = archivePath;
            _allowOverwrite = allowOverwrite;

            Header       = new PackfileHeader();
            FileEntries  = new List <FileEntry>();
            BlockEntries = new List <BlockEntry>();

            Header.IsEncrypted = encrypted;
        }
        /// <summary>
        /// Open an archive (.bin) file and prepare for writing.
        /// </summary>
        /// <param name="archivePath">Disk path</param>
        /// <param name="encrypted">Encrypt file data</param>
        /// <param name="mode">File creation mode</param>
        public PackfileWriterFast(string archivePath, bool encrypted = false, FileMode mode = FileMode.CreateNew)
        {
            _archivePath = archivePath;
            _fileMode    = mode;

            Header        = new PackfileHeader();
            _fileEntries  = new List <FileEntry>();
            _blockEntries = new List <BlockEntry>();

            Header.IsEncrypted = encrypted;
        }
Beispiel #8
0
            public static PackfileHeader FromData(BinaryReader reader)
            {
                var x = new PackfileHeader();

                x.Magic           = reader.ReadUInt32();        // 0
                _                 = reader.ReadBytesStrict(20); // 4
                x.FileEntryCount  = reader.ReadUInt32();        // 24
                _                 = reader.ReadUInt32();        // 28
                x.BlockEntryCount = reader.ReadUInt32();        // 32
                _                 = reader.ReadUInt32();        // 36

                return(x);
            }
Beispiel #9
0
        public Packfile(string archivePath, FileMode mode = FileMode.Open)
        {
            if (mode == FileMode.Open)
            {
                ArchiveFileHandle = File.Open(archivePath, mode, FileAccess.Read, FileShare.Read);

                using (var reader = new BinaryReader(ArchiveFileHandle, Encoding.UTF8, true))
                {
                    Header = PackfileHeader.FromData(reader);

                    if (Header.Magic != PackfileHeader.HardcodedMagic)
                    {
                        throw new InvalidDataException("Unknown header magic");
                    }

                    FileEntries  = new FileEntry[Header.FileEntryCount];
                    BlockEntries = new BlockEntry[Header.BlockEntryCount];

                    for (uint i = 0; i < FileEntries.Length; i++)
                    {
                        FileEntries[i] = FileEntry.FromData(reader);
                    }

                    for (uint i = 0; i < BlockEntries.Length; i++)
                    {
                        BlockEntries[i] = BlockEntry.FromData(reader);
                    }
                }
            }
            else if (mode == FileMode.Create || mode == FileMode.CreateNew)
            {
                throw new NotImplementedException("Writing archives is not supported at the moment");
            }
            else
            {
                throw new NotImplementedException("Archive file mode must be Open, Create, or CreateNew");
            }
        }
Beispiel #10
0
        /// <summary>
        /// Open an archive (.bin) file and prepare for reading
        /// </summary>
        /// <param name="archivePath">Disk path</param>
        public PackfileReader(string archivePath)
        {
            _fileHandle      = CreateReadStream(archivePath);
            using var reader = new BinaryReader(_fileHandle, Encoding.UTF8, true);

            Header        = PackfileHeader.FromData(reader);
            _fileEntries  = new List <FileEntry>((int)Header.FileEntryCount);
            _blockEntries = new List <BlockEntry>(Header.BlockEntryCount);

            Span <byte> fileData  = reader.ReadBytesStrict((int)Header.FileEntryCount * FileEntry.DataHeaderSize);
            Span <byte> blockData = reader.ReadBytesStrict(Header.BlockEntryCount * BlockEntry.DataHeaderSize);

            for (int i = 0; i < (int)Header.FileEntryCount; i++)
            {
                var data = fileData.Slice(i * FileEntry.DataHeaderSize);
                _fileEntries.Add(FileEntry.FromData(data, Header));
            }

            for (int i = 0; i < Header.BlockEntryCount; i++)
            {
                var data = blockData.Slice(i * BlockEntry.DataHeaderSize);
                _blockEntries.Add(BlockEntry.FromData(data, Header));
            }
        }