private void ReadFileListV15(BinaryReader reader, Package package) { int numFiles = reader.ReadInt32(); int compressedSize = reader.ReadInt32(); byte[] compressedFileList = reader.ReadBytes(compressedSize); int fileBufferSize = Marshal.SizeOf(typeof(FileEntry15)) * numFiles; var uncompressedList = new byte[fileBufferSize]; int uncompressedSize = LZ4Codec.Decode(compressedFileList, 0, compressedFileList.Length, uncompressedList, 0, fileBufferSize, true); if (uncompressedSize != fileBufferSize) { string msg = $"LZ4 compressor disagrees about the size of file headers; expected {fileBufferSize}, got {uncompressedSize}"; throw new InvalidDataException(msg); } var ms = new MemoryStream(uncompressedList); var msr = new BinaryReader(ms); var entries = new FileEntry15[numFiles]; BinUtils.ReadStructs(msr, entries); foreach (var entry in entries) { package.Files.Add(PackagedFileInfo.CreateFromEntry(entry, _streams[entry.ArchivePart])); } }
private Package ReadPackageV15(FileStream mainStream, BinaryReader reader) { var package = new Package(); var header = BinUtils.ReadStruct <LSPKHeader15>(reader); if (header.Version != (ulong)PackageVersion.V15) { string msg = $"Unsupported package version {header.Version}; this layout is only supported for {PackageVersion.V15}"; throw new InvalidDataException(msg); } package.Metadata.Flags = (PackageFlags)header.Flags; package.Metadata.Priority = header.Priority; package.Version = PackageVersion.V15; if (_metadataOnly) { return(package); } OpenStreams(mainStream, 1); mainStream.Seek((long)header.FileListOffset, SeekOrigin.Begin); int numFiles = reader.ReadInt32(); int compressedSize = reader.ReadInt32(); byte[] compressedFileList = reader.ReadBytes(compressedSize); int fileBufferSize = Marshal.SizeOf(typeof(FileEntry15)) * numFiles; var uncompressedList = new byte[fileBufferSize]; int uncompressedSize = LZ4Codec.Decode(compressedFileList, 0, compressedFileList.Length, uncompressedList, 0, fileBufferSize, true); if (uncompressedSize != fileBufferSize) { string msg = $"LZ4 compressor disagrees about the size of file headers; expected {fileBufferSize}, got {uncompressedSize}"; throw new InvalidDataException(msg); } var ms = new MemoryStream(uncompressedList); var msr = new BinaryReader(ms); var entries = new FileEntry15[numFiles]; BinUtils.ReadStructs(msr, entries); foreach (var entry in entries) { package.Files.Add(PackagedFileInfo.CreateFromEntry(entry, _streams[0])); } return(package); }
private Package ReadPackageV13(FileStream mainStream, BinaryReader reader) { var package = new Package(); var header = BinUtils.ReadStruct <LSPKHeader13>(reader); if (header.Version != (ulong)PackageVersion.V13) { string msg = $"Unsupported package version {header.Version}; this package layout is only supported for {PackageVersion.V13}"; throw new InvalidDataException(msg); } package.Metadata.Flags = (PackageFlags)header.Flags; package.Metadata.Priority = header.Priority; package.Version = PackageVersion.V13; if (_metadataOnly) { return(package); } OpenStreams(mainStream, header.NumParts); mainStream.Seek(header.FileListOffset, SeekOrigin.Begin); int numFiles = reader.ReadInt32(); int fileBufferSize = Marshal.SizeOf(typeof(FileEntry13)) * numFiles; byte[] compressedFileList = reader.ReadBytes((int)header.FileListSize - 4); var uncompressedList = new byte[fileBufferSize]; int uncompressedSize = LZ4Codec.Decode(compressedFileList, 0, compressedFileList.Length, uncompressedList, 0, fileBufferSize, true); if (uncompressedSize != fileBufferSize) { string msg = $"LZ4 compressor disagrees about the size of file headers; expected {fileBufferSize}, got {uncompressedSize}"; throw new InvalidDataException(msg); } var ms = new MemoryStream(uncompressedList); var msr = new BinaryReader(ms); var entries = new FileEntry13[numFiles]; BinUtils.ReadStructs(msr, entries); if ((package.Metadata.Flags & PackageFlags.Solid) == PackageFlags.Solid && numFiles > 0) { // Calculate compressed frame offset and bounds uint totalUncompressedSize = 0; uint totalSizeOnDisk = 0; uint firstOffset = 0xffffffff; uint lastOffset = 0; foreach (var entry in entries) { totalUncompressedSize += entry.UncompressedSize; totalSizeOnDisk += entry.SizeOnDisk; if (entry.OffsetInFile < firstOffset) { firstOffset = entry.OffsetInFile; } if (entry.OffsetInFile + entry.SizeOnDisk > lastOffset) { lastOffset = entry.OffsetInFile + entry.SizeOnDisk; } } if (firstOffset != 7 || lastOffset - firstOffset != totalSizeOnDisk) { string msg = $"Incorrectly compressed solid archive; offsets {firstOffset}/{lastOffset}, bytes {totalSizeOnDisk}"; throw new InvalidDataException(msg); } // Decompress all files as a single frame (solid) byte[] frame = new byte[lastOffset]; mainStream.Seek(0, SeekOrigin.Begin); mainStream.Read(frame, 0, (int)lastOffset); byte[] decompressed = Native.LZ4FrameCompressor.Decompress(frame); var decompressedStream = new MemoryStream(decompressed); // Update offsets to point to the decompressed chunk uint offset = 7; uint compressedOffset = 0; foreach (var entry in entries) { if (entry.OffsetInFile != offset) { throw new InvalidDataException("File list in solid archive not contiguous"); } var file = PackagedFileInfo.CreateSolidFromEntry(entry, _streams[entry.ArchivePart], compressedOffset, decompressedStream); package.Files.Add(file); offset += entry.SizeOnDisk; compressedOffset += entry.UncompressedSize; } } else { foreach (var entry in entries) { package.Files.Add(PackagedFileInfo.CreateFromEntry(entry, _streams[entry.ArchivePart])); } } return(package); }