mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-05-20 23:17:00 +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)
|
.ReadFullyAsync(props, 0, propsSize, cancellationToken)
|
||||||
.ConfigureAwait(false);
|
.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
|
context = context with
|
||||||
{
|
{
|
||||||
Properties = props,
|
Properties = props,
|
||||||
|
|||||||
@@ -149,6 +149,21 @@ internal abstract partial class ZipFilePart : FilePart
|
|||||||
reader.ReadUInt16(); // LZMA version
|
reader.ReadUInt16(); // LZMA version
|
||||||
var propsLength = reader.ReadUInt16();
|
var propsLength = reader.ReadUInt16();
|
||||||
var props = reader.ReadBytes(propsLength);
|
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
|
context = context with
|
||||||
{
|
{
|
||||||
Properties = props,
|
Properties = props,
|
||||||
|
|||||||
@@ -896,4 +896,18 @@ public class ZipArchiveTests : ArchiveTests
|
|||||||
const int expected = (S_IFREG | 0b110_100_100) << 16; // 0644 mode regular file
|
const int expected = (S_IFREG | 0b110_100_100) << 16; // 0644 mode regular file
|
||||||
Assert.Equal(expected, firstEntry.Attrib);
|
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
|
// Should iterate through all entries, not just the first one
|
||||||
Assert.True(count > 1, $"Expected more than 1 entry, but got {count}");
|
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