Skip to content

Commit 1fddd10

Browse files
authored
Merge pull request #1219 from adamhathcock/copilot/fix-nullreferenceexception-7z-extraction
2 parents c81e78b + 13fdb4d commit 1fddd10

File tree

5 files changed

+78
-8
lines changed

5 files changed

+78
-8
lines changed

src/SharpCompress/Archives/SevenZip/SevenZipArchive.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ protected override EntryStream GetEntryStream()
164164

165165
var folder = entry.FilePart.Folder;
166166

167+
// If folder is null (empty stream entry), return empty stream
168+
if (folder is null)
169+
{
170+
return CreateEntryStream(Stream.Null);
171+
}
172+
167173
// Check if we're starting a new folder - dispose old folder stream if needed
168174
if (folder != _currentFolder)
169175
{

src/SharpCompress/IO/SharpCompressStream.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,22 @@ public override void Flush()
206206
throw new NotSupportedException();
207207
}
208208

209-
public override long Length =>
210-
_isPassthrough ? stream.Length : throw new NotSupportedException();
209+
public override long Length
210+
{
211+
get
212+
{
213+
if (_isPassthrough)
214+
{
215+
return stream.Length;
216+
}
217+
218+
if (_ringBuffer is not null)
219+
{
220+
return _ringBuffer.Length;
221+
}
222+
throw new NotSupportedException();
223+
}
224+
}
211225

212226
public override long Position
213227
{

src/SharpCompress/packages.lock.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,9 @@
216216
"net10.0": {
217217
"Microsoft.NET.ILLink.Tasks": {
218218
"type": "Direct",
219-
"requested": "[10.0.0, )",
220-
"resolved": "10.0.0",
221-
"contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA=="
219+
"requested": "[10.0.2, )",
220+
"resolved": "10.0.2",
221+
"contentHash": "sXdDtMf2qcnbygw9OdE535c2lxSxrZP8gO4UhDJ0xiJbl1wIqXS1OTcTDFTIJPOFd6Mhcm8gPEthqWGUxBsTqw=="
222222
},
223223
"Microsoft.NETFramework.ReferenceAssemblies": {
224224
"type": "Direct",
@@ -264,9 +264,9 @@
264264
"net8.0": {
265265
"Microsoft.NET.ILLink.Tasks": {
266266
"type": "Direct",
267-
"requested": "[8.0.22, )",
268-
"resolved": "8.0.22",
269-
"contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ=="
267+
"requested": "[8.0.23, )",
268+
"resolved": "8.0.23",
269+
"contentHash": "GqHiB1HbbODWPbY/lc5xLQH8siEEhNA0ptpJCC6X6adtAYNEzu5ZlqV3YHA3Gh7fuEwgA8XqVwMtH2KNtuQM1Q=="
270270
},
271271
"Microsoft.NETFramework.ReferenceAssemblies": {
272272
"type": "Direct",

tests/SharpCompress.Test/SevenZip/SevenZipArchiveTests.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using SharpCompress.Archives;
55
using SharpCompress.Archives.SevenZip;
66
using SharpCompress.Common;
7+
using SharpCompress.Common.SevenZip;
78
using SharpCompress.Factories;
89
using SharpCompress.Readers;
910
using Xunit;
@@ -344,4 +345,53 @@ public void SevenZipArchive_Solid_VerifyStreamReuse()
344345
// The critical check: within a single folder, the stream should NEVER be recreated
345346
Assert.Equal(0, streamRecreationsWithinFolder); // Folder stream should remain the same for all entries in the same folder
346347
}
348+
349+
[Fact]
350+
public void SevenZipArchive_EmptyStream_WriteToDirectory()
351+
{
352+
// This test specifically verifies that archives with empty-stream entries
353+
// (files with size 0 and no compressed data) can be extracted without throwing
354+
// NullReferenceException. This was previously failing because the folder was null
355+
// for empty-stream entries.
356+
var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "7Zip.EmptyStream.7z");
357+
using var archive = SevenZipArchive.OpenArchive(testArchive);
358+
359+
var emptyStreamFileCount = 0;
360+
foreach (var entry in archive.Entries)
361+
{
362+
if (!entry.IsDirectory)
363+
{
364+
// Verify this is actually an empty-stream entry (HasStream == false)
365+
var sevenZipEntry = entry as SevenZipEntry;
366+
if (sevenZipEntry?.FilePart.Header.HasStream == false)
367+
{
368+
emptyStreamFileCount++;
369+
}
370+
371+
// This should not throw NullReferenceException
372+
entry.WriteToDirectory(SCRATCH_FILES_PATH);
373+
}
374+
}
375+
376+
// Ensure we actually tested empty-stream entries
377+
Assert.True(
378+
emptyStreamFileCount > 0,
379+
"Test archive should contain at least one empty-stream entry"
380+
);
381+
382+
// Verify that empty files were created
383+
var extractedFiles = Directory.GetFiles(
384+
SCRATCH_FILES_PATH,
385+
"*",
386+
SearchOption.AllDirectories
387+
);
388+
Assert.NotEmpty(extractedFiles);
389+
390+
// All extracted files should be empty (0 bytes)
391+
foreach (var file in extractedFiles)
392+
{
393+
var fileInfo = new FileInfo(file);
394+
Assert.Equal(0, fileInfo.Length);
395+
}
396+
}
347397
}
182 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)