예제 #1
0
        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);
            }
        }
예제 #2
0
        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);
        }