diff --git a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs index ee34d575..9b75592e 100644 --- a/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs +++ b/src/SharpCompress/Writers/Zip/ZipCentralDirectoryEntry.cs @@ -73,60 +73,39 @@ namespace SharpCompress.Writers.Zip usedCompression = ZipCompressionMethod.None; } - byte[] intBuf = new byte[] { 80, 75, 1, 2, version, 0, version, 0 }; + byte[] intBuf = { 80, 75, 1, 2, version, 0, version, 0 }; //constant sig, then version made by, then version to extract await outputStream.WriteAsync(intBuf, 0, 8, cancellationToken); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)usedCompression); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); // zipping method - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, ModificationTime.DateTimeToDosTime()); - await outputStream.WriteAsync(intBuf, 0, 4, cancellationToken); + await outputStream.WriteUInt16( (ushort)flags, cancellationToken); + await outputStream.WriteUInt16( (ushort)usedCompression, cancellationToken);// zipping method + await outputStream.WriteUInt32(ModificationTime.DateTimeToDosTime(), cancellationToken); // zipping date and time - // zipping date and time - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, Crc); - await outputStream.WriteAsync(intBuf, 0, 4, cancellationToken); // file CRC - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, compressedvalue); - await outputStream.WriteAsync(intBuf, 0, 4, cancellationToken); // compressed file size - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, decompressedvalue); - await outputStream.WriteAsync(intBuf, 0, 4, cancellationToken); // uncompressed file size - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedFilename.Length); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); // Filename in zip - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)extralength); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); // extra length - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)encodedComment.Length); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); + await outputStream.WriteUInt32(Crc, cancellationToken); // file CRC + await outputStream.WriteUInt32(compressedvalue, cancellationToken); // compressed file size + await outputStream.WriteUInt32(decompressedvalue, cancellationToken); // uncompressed file size + await outputStream.WriteUInt16((ushort)encodedFilename.Length, cancellationToken); // Filename in zip + await outputStream.WriteUInt16( (ushort)extralength, cancellationToken); // extra length + await outputStream.WriteUInt16((ushort)encodedComment.Length, cancellationToken); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); // disk=0 - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); // file type: binary - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)flags); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); // Internal file attributes - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x8100); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); + await outputStream.WriteUInt16(0, cancellationToken); // disk=0 + await outputStream.WriteUInt16( (ushort)flags, cancellationToken); // file type: binary + await outputStream.WriteUInt16( (ushort)flags, cancellationToken); // Internal file attributes + await outputStream.WriteUInt16(0x8100, cancellationToken); // External file attributes (normal/readable) - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, headeroffsetvalue); - await outputStream.WriteAsync(intBuf, 0, 4, cancellationToken); // Offset of header + await outputStream.WriteUInt32(headeroffsetvalue, cancellationToken); // Offset of header await outputStream.WriteAsync(encodedFilename, 0, encodedFilename.Length, cancellationToken); if (zip64) { - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, (ushort)(extralength - 4)); - await outputStream.WriteAsync(intBuf, 0, 2, cancellationToken); + await outputStream.WriteUInt16(0x0001, cancellationToken); + await outputStream.WriteUInt16((ushort)(extralength - 4), cancellationToken); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, Decompressed); - await outputStream.WriteAsync(intBuf, 0, 8, cancellationToken); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, Compressed); - await outputStream.WriteAsync(intBuf, 0, 8, cancellationToken); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, HeaderOffset); - await outputStream.WriteAsync(intBuf, 0, 8, cancellationToken); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf, 0); - await outputStream.WriteAsync(intBuf, 0, 4, cancellationToken); // VolumeNumber = 0 + await outputStream.WriteUInt64(Decompressed, cancellationToken); + await outputStream.WriteUInt64(Compressed, cancellationToken); + await outputStream.WriteUInt64(HeaderOffset, cancellationToken); + await outputStream.WriteUInt32(0, cancellationToken); // VolumeNumber = 0 } await outputStream.WriteAsync(encodedComment, 0, encodedComment.Length, cancellationToken); diff --git a/src/SharpCompress/Writers/Zip/ZipWriter.cs b/src/SharpCompress/Writers/Zip/ZipWriter.cs index ec4cf7b0..2af446af 100644 --- a/src/SharpCompress/Writers/Zip/ZipWriter.cs +++ b/src/SharpCompress/Writers/Zip/ZipWriter.cs @@ -99,8 +99,8 @@ namespace SharpCompress.Writers.Zip public override ValueTask WriteAsync(string filename, Stream source, DateTime? modificationTime, CancellationToken cancellationToken = default) { return WriteAsync(filename, source, new ZipWriterEntryOptions() - { - ModificationDateTime = modificationTime + { + ModificationDateTime = modificationTime }, cancellationToken); } @@ -151,8 +151,8 @@ namespace SharpCompress.Writers.Zip return filename.Trim('/'); } - private async Task WriteHeaderAsync(string filename, ZipWriterEntryOptions zipWriterEntryOptions, ZipCentralDirectoryEntry entry, bool useZip64, - CancellationToken cancellationToken) + private async ValueTask WriteHeaderAsync(string filename, ZipWriterEntryOptions zipWriterEntryOptions, ZipCentralDirectoryEntry entry, bool useZip64, + CancellationToken cancellationToken) { // We err on the side of caution until the zip specification clarifies how to support this if (!OutputStream.CanSeek && useZip64) @@ -163,33 +163,21 @@ namespace SharpCompress.Writers.Zip var explicitZipCompressionInfo = ToZipCompressionMethod(zipWriterEntryOptions.CompressionType ?? compressionType); byte[] encodedFilename = WriterOptions.ArchiveEncoding.Encode(filename); - using var buffer = MemoryPool.Shared.Rent(4); - var intBuf = buffer.Memory.Slice(0, 4); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, ZipHeaderFactory.ENTRY_HEADER_BYTES); - await OutputStream.WriteAsync(intBuf, cancellationToken); + await OutputStream.WriteUInt32(ZipHeaderFactory.ENTRY_HEADER_BYTES, cancellationToken: cancellationToken); if (explicitZipCompressionInfo == ZipCompressionMethod.Deflate) { if (OutputStream.CanSeek && useZip64) { - using var buf1 = MemoryPool.Shared.Rent(2); - buf1.Memory.Span[0] = 45; - buf1.Memory.Span[1] = 0; - await OutputStream.WriteAsync(buf1.Memory.Slice(0, 2), cancellationToken); //smallest allowed version for zip64 + await OutputStream.WriteBytes(45, 0 ); //smallest allowed version for zip64 } else { - using var buf1 = MemoryPool.Shared.Rent(2); - buf1.Memory.Span[0] = 20; - buf1.Memory.Span[1] = 0; - await OutputStream.WriteAsync(buf1.Memory.Slice(0, 2), cancellationToken); //older version which is more compatible + await OutputStream.WriteBytes(20, 0 ); //older version which is more compatible } } else { - using var buf1 = MemoryPool.Shared.Rent(2); - buf1.Memory.Span[0] = 63; - buf1.Memory.Span[1] = 0; - await OutputStream.WriteAsync(buf1.Memory.Slice(0, 2), cancellationToken); //version says we used PPMd or LZMA + await OutputStream.WriteBytes(63, 0); //version says we used PPMd or LZMA } HeaderFlags flags = Equals(WriterOptions.ArchiveEncoding.GetEncoding(), Encoding.UTF8) ? HeaderFlags.Efs : 0; if (!OutputStream.CanSeek) @@ -202,21 +190,13 @@ namespace SharpCompress.Writers.Zip } } - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, (ushort)flags); - await OutputStream.WriteAsync(intBuf.Slice(0,2), cancellationToken); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, (ushort)explicitZipCompressionInfo); - await OutputStream.WriteAsync(intBuf.Slice(0,2), cancellationToken); // zipping method - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime()); - await OutputStream.WriteAsync(intBuf, cancellationToken); - - // zipping date and time - using var buf2 = MemoryPool.Shared.Rent(12); - buf2.Memory.Span.Clear(); - await OutputStream.WriteAsync(buf2.Memory.Slice(0, 12), cancellationToken); - + await OutputStream.WriteUInt16((ushort)flags, cancellationToken: cancellationToken); + await OutputStream.WriteUInt16((ushort)explicitZipCompressionInfo, cancellationToken: cancellationToken); // zipping method + await OutputStream.WriteUInt32(zipWriterEntryOptions.ModificationDateTime.DateTimeToDosTime(), cancellationToken: cancellationToken); // zipping date and time // unused CRC, un/compressed size, updated later - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, (ushort)encodedFilename.Length); - await OutputStream.WriteAsync(intBuf.Slice(0,2), cancellationToken);// filename length + await OutputStream.WriteBytes(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + await OutputStream.WriteUInt16((ushort)encodedFilename.Length, cancellationToken: cancellationToken);// filename length var extralength = 0; if (OutputStream.CanSeek && useZip64) @@ -224,34 +204,26 @@ namespace SharpCompress.Writers.Zip extralength = 2 + 2 + 8 + 8; } - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, (ushort)extralength); - await OutputStream.WriteAsync(intBuf.Slice(0,2), cancellationToken);// extra length - await OutputStream.WriteAsync(encodedFilename.AsMemory(), cancellationToken); + await OutputStream.WriteUInt16( (ushort)extralength, cancellationToken: cancellationToken); // extra length + await OutputStream.WriteAsync(encodedFilename, 0, encodedFilename.Length, cancellationToken); if (extralength != 0) { - using var buf3 = MemoryPool.Shared.Rent(extralength); - buf2.Memory.Span.Clear(); - await OutputStream.WriteAsync(buf3.Memory.Slice(0, extralength), cancellationToken); // reserve space for zip64 data + await OutputStream.WriteAsync(new byte[extralength], 0, extralength, cancellationToken); // reserve space for zip64 data entry.Zip64HeaderOffset = (ushort)(6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length); } return 6 + 2 + 2 + 4 + 12 + 2 + 2 + encodedFilename.Length + extralength; } - private async Task WriteFooterAsync(uint crc, uint compressed, uint uncompressed) + private async ValueTask WriteFooterAsync(uint crc, uint compressed, uint uncompressed) { - using var buffer = MemoryPool.Shared.Rent(4); - var intBuf = buffer.Memory.Slice(0, 4); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, crc); - await OutputStream.WriteAsync(intBuf); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, compressed); - await OutputStream.WriteAsync(intBuf); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, uncompressed); - await OutputStream.WriteAsync(intBuf); + await OutputStream.WriteUInt32(crc); + await OutputStream.WriteUInt32(compressed); + await OutputStream.WriteUInt32(uncompressed); } - private async Task WriteEndRecordAsync(ulong size) + private async ValueTask WriteEndRecordAsync(ulong size) { var zip64 = isZip64 || entries.Count > ushort.MaxValue || streamPosition >= uint.MaxValue || size >= uint.MaxValue; @@ -259,77 +231,46 @@ namespace SharpCompress.Writers.Zip var sizevalue = size >= uint.MaxValue ? uint.MaxValue : (uint)size; var streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streamPosition; - using var buffer = MemoryPool.Shared.Rent(8); - var intBuf = buffer.Memory.Slice(0, 8); if (zip64) { var recordlen = 2 + 2 + 4 + 4 + 8 + 8 + 8 + 8; // Write zip64 end of central directory record - var s = intBuf.Slice(0, 4); - s.Span[0] = 80; - s.Span[1] = 75; - s.Span[2] = 6; - s.Span[3] = 6; - await OutputStream.WriteAsync(s); + await OutputStream.WriteBytes(80, 75, 6, 6); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Span, (ulong)recordlen); - await OutputStream.WriteAsync(intBuf.Slice(0,8));// Size of zip64 end of central directory record - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, 45); - await OutputStream.WriteAsync(intBuf.Slice(0, 2)); // Made by - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, 45); - await OutputStream.WriteAsync(intBuf.Slice(0, 2)); // Version needed + await OutputStream.WriteUInt64((ulong)recordlen); // Size of zip64 end of central directory record + await OutputStream.WriteUInt16(45); // Made by + await OutputStream.WriteUInt16(45); // Version needed - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, 0); - await OutputStream.WriteAsync(intBuf.Slice(0, 4)); // Disk number - await OutputStream.WriteAsync(intBuf.Slice(0, 4)); // Central dir disk + await OutputStream.WriteUInt32(0); // Disk number + await OutputStream.WriteUInt32(0); // Central dir disk // TODO: entries.Count is int, so max 2^31 files - BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Span, (ulong)entries.Count); - await OutputStream.WriteAsync(intBuf); // Entries in this disk - await OutputStream.WriteAsync(intBuf); // Total entries - BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Span, size); - await OutputStream.WriteAsync(intBuf); // Central Directory size - BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Span, (ulong)streamPosition); - await OutputStream.WriteAsync(intBuf); // Disk offset + await OutputStream.WriteUInt64((ulong)entries.Count); // Entries in this disk + await OutputStream.WriteUInt64((ulong)entries.Count); // Total entries + await OutputStream.WriteUInt64(size); // Central Directory size + await OutputStream.WriteUInt64((ulong)streamPosition); // Disk offset // Write zip64 end of central directory locator - s = intBuf.Slice(0, 4); - s.Span[0] = 80; - s.Span[1] = 75; - s.Span[2] = 6; - s.Span[3] = 7; - await OutputStream.WriteAsync(s); + await OutputStream.WriteBytes( 80, 75, 6, 7); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, 0); - await OutputStream.WriteAsync(intBuf.Slice(0, 4)); // Entry disk - BinaryPrimitives.WriteUInt64LittleEndian(intBuf.Span, (ulong)streamPosition + size); - await OutputStream.WriteAsync(intBuf); // Offset to the zip64 central directory - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, 1); - await OutputStream.WriteAsync(intBuf.Slice(0, 4)); // Number of disks + await OutputStream.WriteUInt32(0);// Entry disk + await OutputStream.WriteUInt64((ulong)streamPosition + size); // Offset to the zip64 central directory + await OutputStream.WriteUInt32( 1); // Number of disks streamPosition += recordlen + (4 + 4 + 8 + 4); streampositionvalue = streamPosition >= uint.MaxValue ? uint.MaxValue : (uint)streampositionvalue; } // Write normal end of central directory record - intBuf.Span.Clear(); - intBuf.Span[0] = 80; - intBuf.Span[1] = 75; - intBuf.Span[2] = 5; - intBuf.Span[3] = 6; - await OutputStream.WriteAsync(intBuf); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, (ushort)entries.Count); - await OutputStream.WriteAsync(intBuf.Slice(0, 2)); - await OutputStream.WriteAsync(intBuf.Slice(0, 2));//TODO: this is twice? - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, sizevalue); - await OutputStream.WriteAsync(intBuf.Slice(0, 4)); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, streampositionvalue); - await OutputStream.WriteAsync(intBuf.Slice(0, 4)); + await OutputStream.WriteBytes(80, 75, 5, 6, 0, 0, 0, 0); + await OutputStream.WriteUInt16((ushort)entries.Count); + await OutputStream.WriteUInt16((ushort)entries.Count); + await OutputStream.WriteUInt32(sizevalue); + await OutputStream.WriteUInt32( streampositionvalue); byte[] encodedComment = WriterOptions.ArchiveEncoding.Encode(zipComment); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf.Span, (ushort)encodedComment.Length); - await OutputStream.WriteAsync(intBuf.Slice(0, 2)); - await OutputStream.WriteAsync(encodedComment.AsMemory()); + await OutputStream.WriteUInt16((ushort)encodedComment.Length); + await OutputStream.WriteAsync(encodedComment, 0, encodedComment.Length); } #region Nested type: ZipWritingStream @@ -380,7 +321,6 @@ namespace SharpCompress.Writers.Zip private async ValueTask GetWriteStream(Stream writeStream, CancellationToken cancellationToken) { - await Task.CompletedTask; counting = new CountingWritableSubStream(writeStream); Stream output = counting; switch (zipCompressionMethod) @@ -398,17 +338,8 @@ namespace SharpCompress.Writers.Zip return await BZip2Stream.CreateAsync(counting, CompressionMode.Compress, false, cancellationToken); } */ case ZipCompressionMethod.LZMA: - { - using var byteBuffer = MemoryPool.Shared.Rent(1); - var bite = byteBuffer.Memory.Slice(0, 1); - bite.Span[0] = 9; - await counting.WriteAsync(bite, cancellationToken); - bite.Span[0] = 20; - await counting.WriteAsync(bite, cancellationToken); - bite.Span[0] = 5; - await counting.WriteAsync(bite, cancellationToken); - bite.Span[0] = 0; - await counting.WriteAsync(bite, cancellationToken); + { + await counting.WriteBytes(9, 20, 5, 0); LzmaStream lzmaStream = new LzmaStream(new LzmaEncoderProperties(!originalStream.CanSeek), false, counting); @@ -438,95 +369,84 @@ namespace SharpCompress.Writers.Zip await writeStream.DisposeAsync(); - if (limitsExceeded) - { - // We have written invalid data into the archive, - // so we destroy it now, instead of allowing the user to continue - // with a defunct archive + if (limitsExceeded) + { + // We have written invalid data into the archive, + // so we destroy it now, instead of allowing the user to continue + // with a defunct archive await originalStream.DisposeAsync(); - return; + return; + } + + entry.Crc = (uint)crc.Crc32Result; + entry.Compressed = counting!.Count; + entry.Decompressed = decompressed; + + var zip64 = entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; + var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count; + var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed; + + if (originalStream.CanSeek) + { + originalStream.Position = (long)(entry.HeaderOffset + 6); + await originalStream.WriteByteAsync(0); + + if (counting.Count == 0 && entry.Decompressed == 0) + { + // set compression to STORED for zero byte files (no compression data) + originalStream.Position = (long)(entry.HeaderOffset + 8); + await originalStream.WriteByteAsync(0); + await originalStream.WriteByteAsync(0); + } + + originalStream.Position = (long)(entry.HeaderOffset + 14); + + await writer.WriteFooterAsync(entry.Crc, compressedvalue, decompressedvalue); + + // Ideally, we should not throw from Dispose() + // We should not get here as the Write call checks the limits + if (zip64 && entry.Zip64HeaderOffset == 0) + { + throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); + } + + // If we have pre-allocated space for zip64 data, + // fill it out, even if it is not required + if (entry.Zip64HeaderOffset != 0) + { + originalStream.Position = (long)(entry.HeaderOffset + entry.Zip64HeaderOffset); + await originalStream.WriteUInt16(0x0001); + await originalStream.WriteUInt16(8 + 8); + + await originalStream.WriteUInt64(entry.Decompressed); + await originalStream.WriteUInt64(entry.Compressed); + } + + originalStream.Position = writer.streamPosition + (long)entry.Compressed; + writer.streamPosition += (long)entry.Compressed; + } + else + { + // We have a streaming archive, so we should add a post-data-descriptor, + // but we cannot as it does not hold the zip64 values + // Throwing an exception until the zip specification is clarified + + // Ideally, we should not throw from Dispose() + // We should not get here as the Write call checks the limits + if (zip64) + { + throw new NotSupportedException("Streams larger than 4GiB are not supported for non-seekable streams"); + } + + await originalStream.WriteUInt32(ZipHeaderFactory.POST_DATA_DESCRIPTOR); + await writer.WriteFooterAsync(entry.Crc, + compressedvalue, + decompressedvalue); + writer.streamPosition += (long)entry.Compressed + 16; + } + writer.entries.Add(entry); } - entry.Crc = (uint)crc.Crc32Result; - entry.Compressed = counting!.Count; - entry.Decompressed = decompressed; - - var zip64 = entry.Compressed >= uint.MaxValue || entry.Decompressed >= uint.MaxValue; - var compressedvalue = zip64 ? uint.MaxValue : (uint)counting.Count; - var decompressedvalue = zip64 ? uint.MaxValue : (uint)entry.Decompressed; - - if (originalStream.CanSeek) - { - originalStream.Position = (long)(entry.HeaderOffset + 6); - using var byteBuffer = MemoryPool.Shared.Rent(1); - var bite = byteBuffer.Memory.Slice(0, 1); - bite.Span[0] = 0; - await originalStream.WriteAsync(bite); - - if (counting.Count == 0 && entry.Decompressed == 0) - { - // set compression to STORED for zero byte files (no compression data) - originalStream.Position = (long)(entry.HeaderOffset + 8); - await originalStream.WriteAsync(bite); - await originalStream.WriteAsync(bite); - } - - originalStream.Position = (long)(entry.HeaderOffset + 14); - - await writer.WriteFooterAsync(entry.Crc, compressedvalue, decompressedvalue); - - // Ideally, we should not throw from Dispose() - // We should not get here as the Write call checks the limits - if (zip64 && entry.Zip64HeaderOffset == 0) - { - throw new NotSupportedException("Attempted to write a stream that is larger than 4GiB without setting the zip64 option"); - } - - // If we have pre-allocated space for zip64 data, - // fill it out, even if it is not required - if (entry.Zip64HeaderOffset != 0) - { - originalStream.Position = (long)(entry.HeaderOffset + entry.Zip64HeaderOffset); - byte[] intBuf = new byte[8]; - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 0x0001); - await originalStream.WriteAsync(intBuf, 0, 2); - BinaryPrimitives.WriteUInt16LittleEndian(intBuf, 8 + 8); - await originalStream.WriteAsync(intBuf, 0, 2); - - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Decompressed); - await originalStream.WriteAsync(intBuf, 0, 8); - BinaryPrimitives.WriteUInt64LittleEndian(intBuf, entry.Compressed); - await originalStream.WriteAsync(intBuf, 0, 8); - } - - originalStream.Position = writer.streamPosition + (long)entry.Compressed; - writer.streamPosition += (long)entry.Compressed; - } - else - { - // We have a streaming archive, so we should add a post-data-descriptor, - // but we cannot as it does not hold the zip64 values - // Throwing an exception until the zip specification is clarified - - // Ideally, we should not throw from Dispose() - // We should not get here as the Write call checks the limits - if (zip64) - { - throw new NotSupportedException("Streams larger than 4GiB are not supported for non-seekable streams"); - } - - using var buffer = MemoryPool.Shared.Rent(4); - var intBuf = buffer.Memory.Slice(0, 4); - BinaryPrimitives.WriteUInt32LittleEndian(intBuf.Span, ZipHeaderFactory.POST_DATA_DESCRIPTOR); - await originalStream.WriteAsync(intBuf); - await writer.WriteFooterAsync(entry.Crc, - compressedvalue, - decompressedvalue); - writer.streamPosition += (long)entry.Compressed + 16; - } - writer.entries.Add(entry); - } - public override Task FlushAsync(CancellationToken cancellationToken) { return writeStream.FlushAsync(cancellationToken);