mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-02-04 05:25:00 +00:00
Fix GZip extraction for non-seekable streams
- Modified GZipFilePart to only access stream.Position when stream.CanSeek is true - Modified GZipArchiveEntry.OpenEntryStream to check CanSeek before accessing Position - Added test case GZip_Archive_NonSeekableStream to verify non-seekable stream support - All existing tests pass Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com>
This commit is contained in:
@@ -15,9 +15,10 @@ public class GZipArchiveEntry : GZipEntry, IArchiveEntry
|
||||
{
|
||||
//this is to reset the stream to be read multiple times
|
||||
var part = (GZipFilePart)Parts.Single();
|
||||
if (part.GetRawStream().Position != part.EntryStartPosition)
|
||||
var rawStream = part.GetRawStream();
|
||||
if (rawStream.CanSeek && rawStream.Position != part.EntryStartPosition)
|
||||
{
|
||||
part.GetRawStream().Position = part.EntryStartPosition;
|
||||
rawStream.Position = part.EntryStartPosition;
|
||||
}
|
||||
return Parts.Single().GetCompressedStream().NotNull();
|
||||
}
|
||||
|
||||
@@ -24,8 +24,12 @@ internal sealed class GZipFilePart : FilePart
|
||||
stream.Position = stream.Length - 8;
|
||||
ReadTrailer();
|
||||
stream.Position = position;
|
||||
EntryStartPosition = position;
|
||||
}
|
||||
else
|
||||
{
|
||||
EntryStartPosition = 0;
|
||||
}
|
||||
EntryStartPosition = stream.Position;
|
||||
}
|
||||
|
||||
internal long EntryStartPosition { get; }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using SharpCompress.Archives;
|
||||
@@ -124,4 +125,60 @@ public class GZipArchiveTests : ArchiveTests
|
||||
using var archive = GZipArchive.Open(stream);
|
||||
Assert.Equal(archive.Type, ArchiveType.GZip);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GZip_Archive_NonSeekableStream()
|
||||
{
|
||||
// Test that GZip extraction works with non-seekable streams (like HttpBaseStream)
|
||||
using var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
|
||||
var buffer = new MemoryStream();
|
||||
fileStream.CopyTo(buffer);
|
||||
buffer.Position = 0;
|
||||
|
||||
// Create a non-seekable wrapper around the MemoryStream
|
||||
using var nonSeekableStream = new NonSeekableStream(buffer);
|
||||
using var reader = SharpCompress.Readers.GZip.GZipReader.Open(nonSeekableStream);
|
||||
|
||||
// Verify we can move to the first entry and read it without exceptions
|
||||
Assert.True(reader.MoveToNextEntry());
|
||||
Assert.NotNull(reader.Entry);
|
||||
|
||||
// Extract and verify the entry can be read
|
||||
using var outputStream = new MemoryStream();
|
||||
reader.WriteEntryTo(outputStream);
|
||||
|
||||
Assert.True(outputStream.Length > 0);
|
||||
}
|
||||
|
||||
// Helper class to simulate a non-seekable stream like HttpBaseStream
|
||||
private class NonSeekableStream : Stream
|
||||
{
|
||||
private readonly Stream _baseStream;
|
||||
|
||||
public NonSeekableStream(Stream baseStream) => _baseStream = baseStream;
|
||||
|
||||
public override bool CanRead => _baseStream.CanRead;
|
||||
public override bool CanSeek => false; // Simulate non-seekable stream
|
||||
public override bool CanWrite => false;
|
||||
public override long Length => throw new NotSupportedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotSupportedException();
|
||||
set => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void Flush() => _baseStream.Flush();
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count) =>
|
||||
_baseStream.Read(buffer, offset, count);
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin) =>
|
||||
throw new NotSupportedException();
|
||||
|
||||
public override void SetLength(long value) => throw new NotSupportedException();
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count) =>
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user