diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.Async.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.Async.cs index bdaf8817..dded9a20 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.Async.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.Async.cs @@ -236,8 +236,13 @@ internal sealed partial class StreamingZipHeaderFactory { lastEntryHeader.DataStartPosition = pos - lastEntryHeader.CompressedSize; + // For SeekableRewindableStream, seek back to just after the local header signature. + // Plain RewindableStream cannot seek to arbitrary positions, so we skip this. // 4 = First 4 bytes of the entry header (i.e. 50 4B 03 04) - _rewindableStream.Position = pos.Value + 4; + if (_rewindableStream is SeekableRewindableStream) + { + _rewindableStream.Position = pos.Value + 4; + } } } else @@ -299,12 +304,27 @@ internal sealed partial class StreamingZipHeaderFactory } else { - _rewindableStream.StartRecording(); - var nextHeaderBytes = await _reader - .ReadUInt32Async(_cancellationToken) - .ConfigureAwait(false); - _rewindableStream.Rewind(true); - header.HasData = !IsHeader(nextHeaderBytes); + // Only start recording if not already recording. + // The stream may already be recording if it was created by ReaderFactory. + if (!_rewindableStream.IsRecording) + { + _rewindableStream.StartRecording(); + var nextHeaderBytes = await _reader + .ReadUInt32Async(_cancellationToken) + .ConfigureAwait(false); + _rewindableStream.Rewind(true); + header.HasData = !IsHeader(nextHeaderBytes); + } + else + { + // If already recording, save position and restore after peek + var savedPosition = _rewindableStream.Position; + var nextHeaderBytes = await _reader + .ReadUInt32Async(_cancellationToken) + .ConfigureAwait(false); + _rewindableStream.Position = savedPosition; + header.HasData = !IsHeader(nextHeaderBytes); + } } } else // We are not streaming and compressed size is 0, we have no data diff --git a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs index 3498e481..24d7c0ff 100644 --- a/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs +++ b/src/SharpCompress/Common/Zip/StreamingZipHeaderFactory.cs @@ -134,8 +134,13 @@ internal sealed partial class StreamingZipHeaderFactory : ZipHeaderFactory { _lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize; + // For SeekableRewindableStream, seek back to just after the local header signature. + // Plain RewindableStream cannot seek to arbitrary positions, so we skip this. // 4 = First 4 bytes of the entry header (i.e. 50 4B 03 04) - rewindableStream.Position = pos.Value + 4; + if (rewindableStream is SeekableRewindableStream) + { + rewindableStream.Position = pos.Value + 4; + } } } else @@ -190,10 +195,23 @@ internal sealed partial class StreamingZipHeaderFactory : ZipHeaderFactory } else { - rewindableStream.StartRecording(); - var nextHeaderBytes = reader.ReadUInt32(); - rewindableStream.Rewind(true); - header.HasData = !IsHeader(nextHeaderBytes); + // Only start recording if not already recording. + // The stream may already be recording if it was created by ReaderFactory. + if (!rewindableStream.IsRecording) + { + rewindableStream.StartRecording(); + var nextHeaderBytes = reader.ReadUInt32(); + rewindableStream.Rewind(true); + header.HasData = !IsHeader(nextHeaderBytes); + } + else + { + // If already recording, save position and restore after peek + var savedPosition = rewindableStream.Position; + var nextHeaderBytes = reader.ReadUInt32(); + rewindableStream.Position = savedPosition; + header.HasData = !IsHeader(nextHeaderBytes); + } } } else // We are not streaming and compressed size is 0, we have no data