mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-04-05 21:51:09 +00:00
Merge pull request #1237 from adamhathcock/copilot/fix-zip-extraction-error
Fix DataErrorException when extracting LZMA-compressed zero-byte ZIP entries
This commit is contained in:
@@ -158,6 +158,20 @@ internal abstract partial class ZipFilePart
|
||||
.ReadFullyAsync(props, 0, propsSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
// When the uncompressed size is known to be zero, skip remaining compressed
|
||||
// bytes (required for streaming reads) and return an empty stream.
|
||||
// Bit1 (EOS marker flag) means the output size is not stored in the header
|
||||
// (the LZMA stream itself contains an end-of-stream marker instead), so we
|
||||
// only short-circuit when the size is explicitly known to be zero.
|
||||
if (
|
||||
!FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
&& Header.UncompressedSize == 0
|
||||
)
|
||||
{
|
||||
await stream.SkipAsync(cancellationToken).ConfigureAwait(false);
|
||||
return Stream.Null;
|
||||
}
|
||||
|
||||
context = context with
|
||||
{
|
||||
Properties = props,
|
||||
|
||||
@@ -149,6 +149,21 @@ internal abstract partial class ZipFilePart : FilePart
|
||||
reader.ReadUInt16(); // LZMA version
|
||||
var propsLength = reader.ReadUInt16();
|
||||
var props = reader.ReadBytes(propsLength);
|
||||
|
||||
// When the uncompressed size is known to be zero, skip remaining compressed
|
||||
// bytes (required for streaming reads) and return an empty stream.
|
||||
// Bit1 (EOS marker flag) means the output size is not stored in the header
|
||||
// (the LZMA stream itself contains an end-of-stream marker instead), so we
|
||||
// only short-circuit when the size is explicitly known to be zero.
|
||||
if (
|
||||
!FlagUtility.HasFlag(Header.Flags, HeaderFlags.Bit1)
|
||||
&& Header.UncompressedSize == 0
|
||||
)
|
||||
{
|
||||
stream.Skip();
|
||||
return Stream.Null;
|
||||
}
|
||||
|
||||
context = context with
|
||||
{
|
||||
Properties = props,
|
||||
|
||||
@@ -896,4 +896,18 @@ public class ZipArchiveTests : ArchiveTests
|
||||
const int expected = (S_IFREG | 0b110_100_100) << 16; // 0644 mode regular file
|
||||
Assert.Equal(expected, firstEntry.Attrib);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_LZMA_ZeroSizeEntry_CanExtract()
|
||||
{
|
||||
using var archive = ArchiveFactory.OpenArchive(
|
||||
Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.empty.zip")
|
||||
);
|
||||
var entries = archive.Entries.Where(x => !x.IsDirectory).ToList();
|
||||
Assert.Single(entries);
|
||||
Assert.Equal(0, entries[0].Size);
|
||||
var outStream = new MemoryStream();
|
||||
entries[0].WriteTo(outStream);
|
||||
Assert.Equal(0, outStream.Length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,4 +543,27 @@ public class ZipReaderTests : ReaderTests
|
||||
// Should iterate through all entries, not just the first one
|
||||
Assert.True(count > 1, $"Expected more than 1 entry, but got {count}");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Zip_LZMA_ZeroSizeEntry_CanExtract_Streaming()
|
||||
{
|
||||
var path = Path.Combine(TEST_ARCHIVES_PATH, "Zip.lzma.empty.zip");
|
||||
using var fileStream = File.OpenRead(path);
|
||||
using Stream stream = new ForwardOnlyStream(fileStream);
|
||||
using var reader = ReaderFactory.OpenReader(stream);
|
||||
|
||||
var count = 0;
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
count++;
|
||||
Assert.Equal(0, reader.Entry.Size);
|
||||
var outStream = new MemoryStream();
|
||||
reader.WriteEntryTo(outStream);
|
||||
Assert.Equal(0, outStream.Length);
|
||||
}
|
||||
}
|
||||
Assert.Equal(1, count);
|
||||
}
|
||||
}
|
||||
|
||||
BIN
tests/TestArchives/Archives/Zip.lzma.empty.zip
Normal file
BIN
tests/TestArchives/Archives/Zip.lzma.empty.zip
Normal file
Binary file not shown.
Reference in New Issue
Block a user