mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-26 00:42:13 +00:00
`ReaderFactory.Open()` calls `ZipArchive.IsZipFile()` to determine if the `Stream` is a zip archive, which calls into `ZipHeaderFactory.ReadHeader()`, which throws a `NotSupportedException` when the `Stream` is not a zip archive. To be clear, this exception is caught and `IsZipFile()` returns `false`, but when called in a hot-path, these exceptions can become expensive. To address this issue, `ReadHeader` now returns `null` in the default cause instead of throwing. All callsites were already checking for and handling `null`, so no behavior changes.
70 lines
2.8 KiB
C#
70 lines
2.8 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using SharpCompress.Common.Zip.Headers;
|
|
using SharpCompress.IO;
|
|
using System.Text;
|
|
|
|
namespace SharpCompress.Common.Zip
|
|
{
|
|
internal class StreamingZipHeaderFactory : ZipHeaderFactory
|
|
{
|
|
internal StreamingZipHeaderFactory(string password, ArchiveEncoding archiveEncoding)
|
|
: base(StreamingMode.Streaming, password, archiveEncoding)
|
|
{
|
|
}
|
|
|
|
internal IEnumerable<ZipHeader> ReadStreamHeader(Stream stream)
|
|
{
|
|
RewindableStream rewindableStream;
|
|
if (stream is RewindableStream)
|
|
{
|
|
rewindableStream = stream as RewindableStream;
|
|
}
|
|
else
|
|
{
|
|
rewindableStream = new RewindableStream(stream);
|
|
}
|
|
while (true)
|
|
{
|
|
ZipHeader header = null;
|
|
BinaryReader reader = new BinaryReader(rewindableStream);
|
|
if (_lastEntryHeader != null &&
|
|
(FlagUtility.HasFlag(_lastEntryHeader.Flags, HeaderFlags.UsePostDataDescriptor) || _lastEntryHeader.IsZip64))
|
|
{
|
|
reader = (_lastEntryHeader.Part as StreamingZipFilePart).FixStreamedFileLocation(ref rewindableStream);
|
|
long? pos = rewindableStream.CanSeek ? (long?)rewindableStream.Position : null;
|
|
uint crc = reader.ReadUInt32();
|
|
if (crc == POST_DATA_DESCRIPTOR)
|
|
{
|
|
crc = reader.ReadUInt32();
|
|
}
|
|
_lastEntryHeader.Crc = crc;
|
|
_lastEntryHeader.CompressedSize = reader.ReadUInt32();
|
|
_lastEntryHeader.UncompressedSize = reader.ReadUInt32();
|
|
if (pos.HasValue)
|
|
{
|
|
_lastEntryHeader.DataStartPosition = pos - _lastEntryHeader.CompressedSize;
|
|
}
|
|
}
|
|
_lastEntryHeader = null;
|
|
uint headerBytes = reader.ReadUInt32();
|
|
header = ReadHeader(headerBytes, reader);
|
|
if (header == null) { yield break; }
|
|
|
|
//entry could be zero bytes so we need to know that.
|
|
if (header.ZipHeaderType == ZipHeaderType.LocalEntry)
|
|
{
|
|
bool isRecording = rewindableStream.IsRecording;
|
|
if (!isRecording)
|
|
{
|
|
rewindableStream.StartRecording();
|
|
}
|
|
uint nextHeaderBytes = reader.ReadUInt32();
|
|
header.HasData = !IsHeader(nextHeaderBytes);
|
|
rewindableStream.Rewind(!isRecording);
|
|
}
|
|
yield return header;
|
|
}
|
|
}
|
|
}
|
|
} |