public void Deserialize(BinaryReader Reader) { Tag = Reader.ReadUInt32(); if (Tag != PACKAGE_FILE_TAG) { throw new Exception("Not a valid Unreal Engine package."); } FileVersion = Reader.ReadUInt16(); LicenseeVersion = Reader.ReadUInt16(); TotalHeaderSize = Reader.ReadInt32(); FolderName.Deserialize(Reader); PackageFlags = Reader.ReadUInt32(); NameCount = Reader.ReadInt32(); NameOffset = Reader.ReadInt32(); ExportCount = Reader.ReadInt32(); ExportOffset = Reader.ReadInt32(); ImportCount = Reader.ReadInt32(); ImportOffset = Reader.ReadInt32(); DependsOffset = Reader.ReadInt32(); Unknown1 = Reader.ReadInt32(); Unknown2 = Reader.ReadInt32(); Unknown3 = Reader.ReadInt32(); Unknown4 = Reader.ReadInt32(); Guid.Deserialize(Reader); Generations.Deserialize(Reader); EngineVersion = Reader.ReadUInt32(); CookerVersion = Reader.ReadUInt32(); CompressionFlags = (ECompressionFlags)(Reader.ReadUInt32()); CompressedChunks = new TArray <FCompressedChunkInfo>(() => new FCompressedChunkInfo(this)); CompressedChunks.Deserialize(Reader); Unknown5 = Reader.ReadInt32(); UnknownStringArray.Deserialize(Reader); UnknownTypeArray.Deserialize(Reader); GarbageSize = Reader.ReadInt32(); CompressedChunkInfoOffset = Reader.ReadInt32(); LastBlockSize = Reader.ReadInt32(); }
private static void ProcessFile(string Path, string OutPath) { using (var Input = File.OpenRead(Path)) { using (var Reader = new BinaryReader(Input)) { var Sum = new FPackageFileSummary(); Sum.Deserialize(Reader); if ((Sum.CompressionFlags & ECompressionFlags.COMPRESS_ZLIB) == 0) { throw new Exception("Unsupported CompressionFlags"); } // Decrypt the rest of the package header var EncryptedSize = Sum.TotalHeaderSize - Sum.GarbageSize - Sum.NameOffset; EncryptedSize = (EncryptedSize + 15) & ~15; // Round up to the next block var EncryptedData = new byte[EncryptedSize]; Input.Seek(Sum.NameOffset, SeekOrigin.Begin); Input.Read(EncryptedData, 0, EncryptedData.Length); var DecryptedData = Decrypt(EncryptedData); var ChunkInfo = new TArray <FCompressedChunkInfo>(() => new FCompressedChunkInfo(Sum)); using (var DecryptedStream = new MemoryStream(DecryptedData)) { using (var DecryptedReader = new BinaryReader(DecryptedStream)) { // Get the compressed chunk info from inside the encrypted data DecryptedStream.Seek(Sum.CompressedChunkInfoOffset, SeekOrigin.Begin); ChunkInfo.Deserialize(DecryptedReader); // Store exports for reserialization DecryptedStream.Seek(Sum.ExportOffset - Sum.NameOffset, SeekOrigin.Begin); } } // Copy the original file data var FileBuf = new byte[Input.Length]; Input.Seek(0, SeekOrigin.Begin); Input.Read(FileBuf, 0, FileBuf.Length); // Save to output file using (var Output = File.Open(OutPath, FileMode.Create)) { Output.Write(FileBuf, 0, FileBuf.Length); // Write decrypted data Output.Seek(Sum.NameOffset, SeekOrigin.Begin); Output.Write(DecryptedData, 0, DecryptedData.Length); // Decompress compressed chunks foreach (var Chunk in ChunkInfo) { Input.Seek(Chunk.CompressedOffset, SeekOrigin.Begin); var Header = new FCompressedChunkHeader(); Header.Deserialize(Reader); var TotalBlockSize = 0; var Blocks = new List <FCompressedChunkBlock>(); while (TotalBlockSize < Header.Sum.UncompressedSize) { var Block = new FCompressedChunkBlock(); Block.Deserialize(Reader); Blocks.Add(Block); TotalBlockSize += Block.UncompressedSize; } Output.Seek(Chunk.UncompressedOffset, SeekOrigin.Begin); foreach (var Block in Blocks) { var CompressedData = new byte[Block.CompressedSize]; Input.Read(CompressedData, 0, CompressedData.Length); // Zlib inflate var ZlibStream = new InflaterInputStream(new MemoryStream(CompressedData)); ZlibStream.CopyTo(Output); } } } } } }