public override byte[] Extract(VfsEntry entry) { if (!(entry is FPakEntry pakEntry) || entry.Vfs != this) { throw new ArgumentException($"Wrong pak file reader, required {entry.Vfs.Name}, this is {Name}"); } // If this reader is used as a concurrent reader create a clone of the main reader to provide thread safety var reader = IsConcurrent ? (FArchive)Ar.Clone() : Ar; // Pak Entry is written before the file data, // but its the same as the one from the index, just without a name // We don't need to serialize that again so + file.StructSize reader.Position = pakEntry.Offset + pakEntry.StructSize; if (pakEntry.IsCompressed) { #if DEBUG Log.Debug($"{pakEntry.Name} is compressed with {pakEntry.CompressionMethod}"); #endif var data = new MemoryStream((int)pakEntry.UncompressedSize) { Position = 0 }; foreach (var block in pakEntry.CompressionBlocks) { reader.Position = block.CompressedStart; var srcSize = (int)(block.CompressedEnd - block.CompressedStart).Align(pakEntry.IsEncrypted ? Aes.ALIGN : 1); // Read the compressed block byte[] src = ReadAndDecrypt(srcSize, reader, pakEntry.IsEncrypted); // Calculate the uncompressed size, // its either just the compression block size // or if its the last block its the remaining data size var uncompressedSize = (int)Math.Min(pakEntry.CompressionBlockSize, pakEntry.UncompressedSize - data.Length); data.Write(Compression.Compression.Decompress(src, uncompressedSize, pakEntry.CompressionMethod, reader), 0, uncompressedSize); } if (data.Length == pakEntry.UncompressedSize) { return(data.GetBuffer()); } if (data.Length > pakEntry.UncompressedSize) { return(data.GetBuffer().SubByteArray((int)pakEntry.UncompressedSize)); } throw new ParserException(reader, $"Decompression of {pakEntry.Name} failed, {data.Length} < {pakEntry.UncompressedSize}"); } else { // File might be encrypted or just stored normally var size = (int)pakEntry.UncompressedSize.Align(pakEntry.IsEncrypted ? Aes.ALIGN : 1); var data = ReadAndDecrypt(size, reader, pakEntry.IsEncrypted); return(size != pakEntry.UncompressedSize ? data.SubByteArray((int)pakEntry.UncompressedSize) : data); } }
public override byte[] Extract(VfsEntry entry) { if (entry is not FPakEntry pakEntry || entry.Vfs != this) { throw new ArgumentException($"Wrong pak file reader, required {entry.Vfs.Name}, this is {Name}"); } // If this reader is used as a concurrent reader create a clone of the main reader to provide thread safety var reader = IsConcurrent ? (FArchive)Ar.Clone() : Ar; if (pakEntry.IsCompressed) { #if DEBUG Log.Debug($"{pakEntry.Name} is compressed with {pakEntry.CompressionMethod}"); #endif var uncompressed = new byte[(int)pakEntry.UncompressedSize]; var uncompressedOff = 0; foreach (var block in pakEntry.CompressionBlocks) { reader.Position = block.CompressedStart; var blockSize = (int)block.Size; var srcSize = blockSize.Align(pakEntry.IsEncrypted ? Aes.ALIGN : 1); // Read the compressed block byte[] compressed = ReadAndDecrypt(srcSize, reader, pakEntry.IsEncrypted); // Calculate the uncompressed size, // its either just the compression block size // or if its the last block its the remaining data size var uncompressedSize = (int)Math.Min(pakEntry.CompressionBlockSize, pakEntry.UncompressedSize - uncompressedOff); Decompress(compressed, 0, blockSize, uncompressed, uncompressedOff, uncompressedSize, pakEntry.CompressionMethod); uncompressedOff += (int)pakEntry.CompressionBlockSize; } return(uncompressed); } // Pak Entry is written before the file data, // but its the same as the one from the index, just without a name // We don't need to serialize that again so + file.StructSize reader.Position = pakEntry.Offset + pakEntry.StructSize; // Doesn't seem to be the case with older pak versions var size = (int)pakEntry.UncompressedSize.Align(pakEntry.IsEncrypted ? Aes.ALIGN : 1); var data = ReadAndDecrypt(size, reader, pakEntry.IsEncrypted); return(size != pakEntry.UncompressedSize ? data.SubByteArray((int)pakEntry.UncompressedSize) : data); }