From ab9155dfc550d5a17a93b093730389ee754ba47f Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Sun, 28 Apr 2013 11:07:13 +0100 Subject: [PATCH] zip/gzip skipping now doesn't involve decompression https://github.com/simmotech/sharpcompress --- .gitignore | 1 + .../Archive/GZip/GZipArchiveEntry.cs | 2 +- .../Archive/Rar/FileInfoRarFilePart.cs | 2 +- .../Archive/Rar/SeekableStreamFilePart.cs | 2 +- .../Archive/SevenZip/SevenZipArchiveEntry.cs | 2 +- SharpCompress/Archive/Tar/TarArchiveEntry.cs | 2 +- SharpCompress/Archive/Zip/ZipArchiveEntry.cs | 2 +- SharpCompress/Common/Entry.cs | 2 ++ SharpCompress/Common/FilePart.cs | 3 +- SharpCompress/Common/GZip/GZipFilePart.cs | 31 +++++++++++-------- SharpCompress/Common/Rar/RarFilePart.cs | 8 ++++- .../Common/SevenZip/SevenZipFilePart.cs | 7 ++++- SharpCompress/Common/Tar/TarFilePart.cs | 7 ++++- .../Common/Zip/SeekableZipFilePart.cs | 4 +-- .../Common/Zip/StreamingZipFilePart.cs | 4 +-- SharpCompress/Common/Zip/ZipFilePart.cs | 11 ++++++- .../Rar/MultiVolumeReadOnlyStream.cs | 2 +- SharpCompress/Reader/AbstractReader.cs | 26 +++++++++++++--- .../Reader/Rar/NonSeekableStreamFilePart.cs | 2 +- SharpCompress/Reader/Rar/RarReaderEntry.cs | 2 -- 20 files changed, 85 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index 71f2a07a..2d1bf74c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ _ReSharper.SharpCompress/ bin/ *.suo TestArchives/Scratch/ +TestArchives/Scratch2/ diff --git a/SharpCompress/Archive/GZip/GZipArchiveEntry.cs b/SharpCompress/Archive/GZip/GZipArchiveEntry.cs index 6f1aa028..f6a7ce22 100644 --- a/SharpCompress/Archive/GZip/GZipArchiveEntry.cs +++ b/SharpCompress/Archive/GZip/GZipArchiveEntry.cs @@ -17,7 +17,7 @@ namespace SharpCompress.Archive.GZip public virtual Stream OpenEntryStream() { - return Parts.Single().GetStream(); + return Parts.Single().GetCompressedStream(); } #region IArchiveEntry Members diff --git a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs b/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs index 5c58d686..22d75a9b 100644 --- a/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs +++ b/SharpCompress/Archive/Rar/FileInfoRarFilePart.cs @@ -21,7 +21,7 @@ namespace SharpCompress.Archive.Rar private set; } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { var stream = volume.Stream; stream.Position = FileHeader.DataStartPosition; diff --git a/SharpCompress/Archive/Rar/SeekableStreamFilePart.cs b/SharpCompress/Archive/Rar/SeekableStreamFilePart.cs index 02e8f030..eaff37c2 100644 --- a/SharpCompress/Archive/Rar/SeekableStreamFilePart.cs +++ b/SharpCompress/Archive/Rar/SeekableStreamFilePart.cs @@ -18,7 +18,7 @@ namespace SharpCompress.Archive.Rar private set; } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { Stream.Position = FileHeader.DataStartPosition; return Stream; diff --git a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs b/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs index 1177e112..fff4644b 100644 --- a/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs +++ b/SharpCompress/Archive/SevenZip/SevenZipArchiveEntry.cs @@ -17,7 +17,7 @@ namespace SharpCompress.Archive.SevenZip public Stream OpenEntryStream() { - return Parts.Single().GetStream(); + return Parts.Single().GetCompressedStream(); } public void WriteTo(Stream stream) diff --git a/SharpCompress/Archive/Tar/TarArchiveEntry.cs b/SharpCompress/Archive/Tar/TarArchiveEntry.cs index f462e41e..d3f0ac72 100644 --- a/SharpCompress/Archive/Tar/TarArchiveEntry.cs +++ b/SharpCompress/Archive/Tar/TarArchiveEntry.cs @@ -16,7 +16,7 @@ namespace SharpCompress.Archive.Tar public virtual Stream OpenEntryStream() { - return Parts.Single().GetStream(); + return Parts.Single().GetCompressedStream(); } #region IArchiveEntry Members diff --git a/SharpCompress/Archive/Zip/ZipArchiveEntry.cs b/SharpCompress/Archive/Zip/ZipArchiveEntry.cs index ea52408c..1acd6a1a 100644 --- a/SharpCompress/Archive/Zip/ZipArchiveEntry.cs +++ b/SharpCompress/Archive/Zip/ZipArchiveEntry.cs @@ -16,7 +16,7 @@ namespace SharpCompress.Archive.Zip public virtual Stream OpenEntryStream() { - return Parts.Single().GetStream(); + return Parts.Single().GetCompressedStream(); } #region IArchiveEntry Members diff --git a/SharpCompress/Common/Entry.cs b/SharpCompress/Common/Entry.cs index c60ecdb9..7637a36a 100644 --- a/SharpCompress/Common/Entry.cs +++ b/SharpCompress/Common/Entry.cs @@ -5,6 +5,8 @@ namespace SharpCompress.Common { public abstract class Entry : SharpCompress.Common.IEntry { + internal bool IsSolid { get; set; } + /// /// The File's 32 bit CRC Hash /// diff --git a/SharpCompress/Common/FilePart.cs b/SharpCompress/Common/FilePart.cs index 6adc6db3..29d7b9fe 100644 --- a/SharpCompress/Common/FilePart.cs +++ b/SharpCompress/Common/FilePart.cs @@ -9,6 +9,7 @@ namespace SharpCompress.Common get; } - internal abstract Stream GetStream(); + internal abstract Stream GetCompressedStream(); + internal abstract Stream GetRawStream(); } } diff --git a/SharpCompress/Common/GZip/GZipFilePart.cs b/SharpCompress/Common/GZip/GZipFilePart.cs index db79efa0..b1025c0a 100644 --- a/SharpCompress/Common/GZip/GZipFilePart.cs +++ b/SharpCompress/Common/GZip/GZipFilePart.cs @@ -9,12 +9,12 @@ namespace SharpCompress.Common.GZip internal class GZipFilePart : FilePart { private string name; - private Stream stream; + private readonly Stream stream; internal GZipFilePart(Stream stream) { ReadAndValidateGzipHeader(stream); - this.stream = new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false); + this.stream = stream; } internal DateTime? DateModified { get; private set; } @@ -24,15 +24,18 @@ namespace SharpCompress.Common.GZip get { return name; } } - internal override Stream GetStream() + internal override Stream GetCompressedStream() + { + return new DeflateStream(stream, CompressionMode.Decompress, CompressionLevel.Default, false); + } + + internal override Stream GetRawStream() { return stream; } - private void ReadAndValidateGzipHeader(Stream stream) { - int totalBytesRead = 0; // read the header on the first read byte[] header = new byte[10]; int n = stream.Read(header, 0, header.Length); @@ -49,19 +52,18 @@ namespace SharpCompress.Common.GZip Int32 timet = BitConverter.ToInt32(header, 4); DateModified = TarHeader.Epoch.AddSeconds(timet); - totalBytesRead += n; if ((header[3] & 0x04) == 0x04) { // read and discard extra field n = stream.Read(header, 0, 2); // 2-byte length field - totalBytesRead += n; Int16 extraLength = (Int16)(header[0] + header[1] * 256); byte[] extra = new byte[extraLength]; n = stream.Read(extra, 0, extra.Length); if (n != extraLength) + { throw new ZlibException("Unexpected end-of-file reading GZIP header."); - totalBytesRead += n; + } } if ((header[3] & 0x08) == 0x08) name = ReadZeroTerminatedString(stream); @@ -72,7 +74,7 @@ namespace SharpCompress.Common.GZip } - private string ReadZeroTerminatedString(Stream stream) + private static string ReadZeroTerminatedString(Stream stream) { byte[] buf1 = new byte[1]; var list = new System.Collections.Generic.List(); @@ -82,13 +84,16 @@ namespace SharpCompress.Common.GZip // workitem 7740 int n = stream.Read(buf1, 0, 1); if (n != 1) + { throw new ZlibException("Unexpected EOF reading GZIP header."); + } + if (buf1[0] == 0) + { + done = true; + } else { - if (buf1[0] == 0) - done = true; - else - list.Add(buf1[0]); + list.Add(buf1[0]); } } while (!done); byte[] a = list.ToArray(); diff --git a/SharpCompress/Common/Rar/RarFilePart.cs b/SharpCompress/Common/Rar/RarFilePart.cs index 4d62042f..2b7aa27d 100644 --- a/SharpCompress/Common/Rar/RarFilePart.cs +++ b/SharpCompress/Common/Rar/RarFilePart.cs @@ -1,4 +1,5 @@ -using SharpCompress.Common.Rar.Headers; +using System.IO; +using SharpCompress.Common.Rar.Headers; namespace SharpCompress.Common.Rar { @@ -24,5 +25,10 @@ namespace SharpCompress.Common.Rar get; private set; } + + internal override Stream GetRawStream() + { + return null; + } } } diff --git a/SharpCompress/Common/SevenZip/SevenZipFilePart.cs b/SharpCompress/Common/SevenZip/SevenZipFilePart.cs index 5a881106..5cd02bc1 100644 --- a/SharpCompress/Common/SevenZip/SevenZipFilePart.cs +++ b/SharpCompress/Common/SevenZip/SevenZipFilePart.cs @@ -22,7 +22,7 @@ namespace SharpCompress.Common.SevenZip get { return Header.Name; } } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { if (!Header.HasStream) { @@ -36,6 +36,11 @@ namespace SharpCompress.Common.SevenZip return new ReadOnlySubStream(stream, (long)Header.Size); } + internal override Stream GetRawStream() + { + return null; + } + public CompressionType CompressionType { get diff --git a/SharpCompress/Common/Tar/TarFilePart.cs b/SharpCompress/Common/Tar/TarFilePart.cs index 51ddce26..7fd69c3c 100644 --- a/SharpCompress/Common/Tar/TarFilePart.cs +++ b/SharpCompress/Common/Tar/TarFilePart.cs @@ -20,7 +20,7 @@ namespace SharpCompress.Common.Tar get { return Header.Name; } } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { if (seekableStream != null) { @@ -29,5 +29,10 @@ namespace SharpCompress.Common.Tar } return Header.PackedStream; } + + internal override Stream GetRawStream() + { + return null; + } } } diff --git a/SharpCompress/Common/Zip/SeekableZipFilePart.cs b/SharpCompress/Common/Zip/SeekableZipFilePart.cs index e40e600f..72035742 100644 --- a/SharpCompress/Common/Zip/SeekableZipFilePart.cs +++ b/SharpCompress/Common/Zip/SeekableZipFilePart.cs @@ -14,14 +14,14 @@ namespace SharpCompress.Common.Zip this.headerFactory = headerFactory; } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { if (!isLocalHeaderLoaded) { LoadLocalHeader(); isLocalHeaderLoaded = true; } - return base.GetStream(); + return base.GetCompressedStream(); } internal string Comment diff --git a/SharpCompress/Common/Zip/StreamingZipFilePart.cs b/SharpCompress/Common/Zip/StreamingZipFilePart.cs index 849998e2..26ae58f4 100644 --- a/SharpCompress/Common/Zip/StreamingZipFilePart.cs +++ b/SharpCompress/Common/Zip/StreamingZipFilePart.cs @@ -19,7 +19,7 @@ namespace SharpCompress.Common.Zip return Header.PackedStream; } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { if (!Header.HasData) { @@ -43,7 +43,7 @@ namespace SharpCompress.Common.Zip { if (decompressionStream == null) { - decompressionStream = GetStream(); + decompressionStream = GetCompressedStream(); } decompressionStream.SkipAll(); diff --git a/SharpCompress/Common/Zip/ZipFilePart.cs b/SharpCompress/Common/Zip/ZipFilePart.cs index f69a190d..99057598 100644 --- a/SharpCompress/Common/Zip/ZipFilePart.cs +++ b/SharpCompress/Common/Zip/ZipFilePart.cs @@ -29,7 +29,7 @@ namespace SharpCompress.Common.Zip get { return Header.Name; } } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { if (!Header.HasData) { @@ -43,6 +43,15 @@ namespace SharpCompress.Common.Zip return decompressionStream; } + internal override Stream GetRawStream() + { + if (!Header.HasData) + { + return Stream.Null; + } + return CreateBaseStream(); + } + protected abstract Stream CreateBaseStream(); protected bool LeaveStreamOpen diff --git a/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs b/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs index 0b51e0de..28c0425e 100644 --- a/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs +++ b/SharpCompress/Compressor/Rar/MultiVolumeReadOnlyStream.cs @@ -55,7 +55,7 @@ namespace SharpCompress.Compressor.Rar { currentStream.Dispose(); } - currentStream = filePartEnumerator.Current.GetStream(); + currentStream = filePartEnumerator.Current.GetCompressedStream(); currentPartTotalReadBytes = 0; diff --git a/SharpCompress/Reader/AbstractReader.cs b/SharpCompress/Reader/AbstractReader.cs index a19255be..62880144 100644 --- a/SharpCompress/Reader/AbstractReader.cs +++ b/SharpCompress/Reader/AbstractReader.cs @@ -136,12 +136,28 @@ namespace SharpCompress.Reader } } - internal void Skip() + readonly byte[] skipBuffer = new byte[4096]; + + private void Skip() { - var buffer = new byte[4096]; - using (Stream s = OpenEntryStream()) + if (!Entry.IsSolid) { - while (s.Read(buffer, 0, buffer.Length) > 0) + var rawStream = Entry.Parts.First().GetRawStream(); + + if (rawStream != null) + { + var bytesToAdvance = Entry.CompressedSize; + for (var i = 0; i < bytesToAdvance / skipBuffer.Length; i++) + { + rawStream.Read(skipBuffer, 0, skipBuffer.Length); + } + rawStream.Read(skipBuffer, 0, (int)(bytesToAdvance % skipBuffer.Length)); + return; + } + } + using (var s = OpenEntryStream()) + { + while (s.Read(skipBuffer, 0, skipBuffer.Length) > 0) { } } @@ -183,7 +199,7 @@ namespace SharpCompress.Reader protected virtual EntryStream GetEntryStream() { - return new EntryStream(Entry.Parts.First().GetStream()); + return new EntryStream(Entry.Parts.First().GetCompressedStream()); } #endregion diff --git a/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs b/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs index c40edf39..c2c43977 100644 --- a/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs +++ b/SharpCompress/Reader/Rar/NonSeekableStreamFilePart.cs @@ -11,7 +11,7 @@ namespace SharpCompress.Reader.Rar { } - internal override Stream GetStream() + internal override Stream GetCompressedStream() { return FileHeader.PackedStream; } diff --git a/SharpCompress/Reader/Rar/RarReaderEntry.cs b/SharpCompress/Reader/Rar/RarReaderEntry.cs index 53e392a3..810a1c6f 100644 --- a/SharpCompress/Reader/Rar/RarReaderEntry.cs +++ b/SharpCompress/Reader/Rar/RarReaderEntry.cs @@ -13,8 +13,6 @@ namespace SharpCompress.Reader.Rar IsSolid = solid; } - internal bool IsSolid { get; private set; } - internal RarFilePart Part { get; private set; } internal override IEnumerable Parts