| // ZipInputStream.cs |
| // |
| // ------------------------------------------------------------------ |
| // |
| // Copyright (c) 2009-2010 Dino Chiesa. |
| // All rights reserved. |
| // |
| // This code module is part of DotNetZip, a zipfile class library. |
| // |
| // ------------------------------------------------------------------ |
| // |
| // This code is licensed under the Microsoft Public License. |
| // See the file License.txt for the license details. |
| // More info on: http://dotnetzip.codeplex.com |
| // |
| // ------------------------------------------------------------------ |
| // |
| // last saved (in emacs): |
| // Time-stamp: <2011-July-31 14:48:30> |
| // |
| // ------------------------------------------------------------------ |
| // |
| // This module defines the ZipInputStream class, which is a stream metaphor for |
| // reading zip files. This class does not depend on Ionic.Zip.ZipFile, but rather |
| // stands alongside it as an alternative "container" for ZipEntry, when reading zips. |
| // |
| // It adds one interesting method to the normal "stream" interface: GetNextEntry. |
| // |
| // ------------------------------------------------------------------ |
| // |
| |
| using System; |
| using System.Threading; |
| using System.Collections.Generic; |
| using System.IO; |
| using Ionic.Zip; |
| using OfficeOpenXml.Packaging.Ionic.Zip; |
| using OfficeOpenXml.Packaging.Ionic.Crc; |
| |
| namespace Ionic.Zip |
| { |
| /// <summary> |
| /// Provides a stream metaphor for reading zip files. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// <para> |
| /// This class provides an alternative programming model for reading zip files to |
| /// the one enabled by the <see cref="ZipFile"/> class. Use this when reading zip |
| /// files, as an alternative to the <see cref="ZipFile"/> class, when you would |
| /// like to use a Stream class to read the file. |
| /// </para> |
| /// |
| /// <para> |
| /// Some application designs require a readable stream for input. This stream can |
| /// be used to read a zip file, and extract entries. |
| /// </para> |
| /// |
| /// <para> |
| /// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used |
| /// to read and extract zip files. Both of them support many of the common zip |
| /// features, including Unicode, different compression levels, and ZIP64. The |
| /// programming models differ. For example, when extracting entries via calls to |
| /// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the |
| /// <c>ZipInputStream</c> class, the caller is responsible for creating the file, |
| /// writing the bytes into the file, setting the attributes on the file, and |
| /// setting the created, last modified, and last accessed timestamps on the |
| /// file. All of these things are done automatically by a call to <see |
| /// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the |
| /// <c>ZipInputStream</c> is generally recommended for when your application wants |
| /// to extract the data, without storing that data into a file. |
| /// </para> |
| /// |
| /// <para> |
| /// Aside from the obvious differences in programming model, there are some |
| /// differences in capability between the <c>ZipFile</c> class and the |
| /// <c>ZipInputStream</c> class. |
| /// </para> |
| /// |
| /// <list type="bullet"> |
| /// <item> |
| /// <c>ZipFile</c> can be used to create or update zip files, or read and |
| /// extract zip files. <c>ZipInputStream</c> can be used only to read and |
| /// extract zip files. If you want to use a stream to create zip files, check |
| /// out the <see cref="ZipOutputStream"/>. |
| /// </item> |
| /// |
| /// <item> |
| /// <c>ZipInputStream</c> cannot read segmented or spanned |
| /// zip files. |
| /// </item> |
| /// |
| /// <item> |
| /// <c>ZipInputStream</c> will not read Zip file comments. |
| /// </item> |
| /// |
| /// <item> |
| /// When reading larger files, <c>ZipInputStream</c> will always underperform |
| /// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the |
| /// zip file, while the <c>ZipFile</c> class reads the central directory of the |
| /// zip file. |
| /// </item> |
| /// |
| /// </list> |
| /// |
| /// </remarks> |
| internal class ZipInputStream : Stream |
| { |
| /// <summary> |
| /// Create a <c>ZipInputStream</c>, wrapping it around an existing stream. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// |
| /// <para> |
| /// While the <see cref="ZipFile"/> class is generally easier |
| /// to use, this class provides an alternative to those |
| /// applications that want to read from a zipfile directly, |
| /// using a <see cref="System.IO.Stream"/>. |
| /// </para> |
| /// |
| /// <para> |
| /// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used |
| /// to read and extract zip files. Both of them support many of the common zip |
| /// features, including Unicode, different compression levels, and ZIP64. The |
| /// programming models differ. For example, when extracting entries via calls to |
| /// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the |
| /// <c>ZipInputStream</c> class, the caller is responsible for creating the file, |
| /// writing the bytes into the file, setting the attributes on the file, and |
| /// setting the created, last modified, and last accessed timestamps on the |
| /// file. All of these things are done automatically by a call to <see |
| /// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the |
| /// <c>ZipInputStream</c> is generally recommended for when your application wants |
| /// to extract the data, without storing that data into a file. |
| /// </para> |
| /// |
| /// <para> |
| /// Aside from the obvious differences in programming model, there are some |
| /// differences in capability between the <c>ZipFile</c> class and the |
| /// <c>ZipInputStream</c> class. |
| /// </para> |
| /// |
| /// <list type="bullet"> |
| /// <item> |
| /// <c>ZipFile</c> can be used to create or update zip files, or read and extract |
| /// zip files. <c>ZipInputStream</c> can be used only to read and extract zip |
| /// files. If you want to use a stream to create zip files, check out the <see |
| /// cref="ZipOutputStream"/>. |
| /// </item> |
| /// |
| /// <item> |
| /// <c>ZipInputStream</c> cannot read segmented or spanned |
| /// zip files. |
| /// </item> |
| /// |
| /// <item> |
| /// <c>ZipInputStream</c> will not read Zip file comments. |
| /// </item> |
| /// |
| /// <item> |
| /// When reading larger files, <c>ZipInputStream</c> will always underperform |
| /// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the |
| /// zip file, while the <c>ZipFile</c> class reads the central directory of the |
| /// zip file. |
| /// </item> |
| /// |
| /// </list> |
| /// |
| /// </remarks> |
| /// |
| /// <param name="stream"> |
| /// The stream to read. It must be readable. This stream will be closed at |
| /// the time the <c>ZipInputStream</c> is closed. |
| /// </param> |
| /// |
| /// <example> |
| /// |
| /// This example shows how to read a zip file, and extract entries, using the |
| /// <c>ZipInputStream</c> class. |
| /// |
| /// <code lang="C#"> |
| /// private void Unzip() |
| /// { |
| /// byte[] buffer= new byte[2048]; |
| /// int n; |
| /// using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read)) |
| /// { |
| /// using (var input= new ZipInputStream(raw)) |
| /// { |
| /// ZipEntry e; |
| /// while (( e = input.GetNextEntry()) != null) |
| /// { |
| /// if (e.IsDirectory) continue; |
| /// string outputPath = Path.Combine(extractDir, e.FileName); |
| /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) |
| /// { |
| /// while ((n= input.Read(buffer, 0, buffer.Length)) > 0) |
| /// { |
| /// output.Write(buffer,0,n); |
| /// } |
| /// } |
| /// } |
| /// } |
| /// } |
| /// } |
| /// </code> |
| /// |
| /// <code lang="VB"> |
| /// Private Sub UnZip() |
| /// Dim inputFileName As String = "MyArchive.zip" |
| /// Dim extractDir As String = "extract" |
| /// Dim buffer As Byte() = New Byte(2048) {} |
| /// Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read) |
| /// Using input As ZipInputStream = New ZipInputStream(raw) |
| /// Dim e As ZipEntry |
| /// Do While (Not e = input.GetNextEntry Is Nothing) |
| /// If Not e.IsDirectory Then |
| /// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ |
| /// FileMode.Create, FileAccess.ReadWrite) |
| /// Dim n As Integer |
| /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0) |
| /// output.Write(buffer, 0, n) |
| /// Loop |
| /// End Using |
| /// End If |
| /// Loop |
| /// End Using |
| /// End Using |
| /// End Sub |
| /// </code> |
| /// </example> |
| public ZipInputStream(Stream stream) : this (stream, false) { } |
| |
| |
| |
| /// <summary> |
| /// Create a <c>ZipInputStream</c>, given the name of an existing zip file. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// |
| /// <para> |
| /// This constructor opens a <c>FileStream</c> for the given zipfile, and |
| /// wraps a <c>ZipInputStream</c> around that. See the documentation for the |
| /// <see cref="ZipInputStream(Stream)"/> constructor for full details. |
| /// </para> |
| /// |
| /// <para> |
| /// While the <see cref="ZipFile"/> class is generally easier |
| /// to use, this class provides an alternative to those |
| /// applications that want to read from a zipfile directly, |
| /// using a <see cref="System.IO.Stream"/>. |
| /// </para> |
| /// |
| /// </remarks> |
| /// |
| /// <param name="fileName"> |
| /// The name of the filesystem file to read. |
| /// </param> |
| /// |
| /// <example> |
| /// |
| /// This example shows how to read a zip file, and extract entries, using the |
| /// <c>ZipInputStream</c> class. |
| /// |
| /// <code lang="C#"> |
| /// private void Unzip() |
| /// { |
| /// byte[] buffer= new byte[2048]; |
| /// int n; |
| /// using (var input= new ZipInputStream(inputFileName)) |
| /// { |
| /// ZipEntry e; |
| /// while (( e = input.GetNextEntry()) != null) |
| /// { |
| /// if (e.IsDirectory) continue; |
| /// string outputPath = Path.Combine(extractDir, e.FileName); |
| /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) |
| /// { |
| /// while ((n= input.Read(buffer, 0, buffer.Length)) > 0) |
| /// { |
| /// output.Write(buffer,0,n); |
| /// } |
| /// } |
| /// } |
| /// } |
| /// } |
| /// </code> |
| /// |
| /// <code lang="VB"> |
| /// Private Sub UnZip() |
| /// Dim inputFileName As String = "MyArchive.zip" |
| /// Dim extractDir As String = "extract" |
| /// Dim buffer As Byte() = New Byte(2048) {} |
| /// Using input As ZipInputStream = New ZipInputStream(inputFileName) |
| /// Dim e As ZipEntry |
| /// Do While (Not e = input.GetNextEntry Is Nothing) |
| /// If Not e.IsDirectory Then |
| /// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _ |
| /// FileMode.Create, FileAccess.ReadWrite) |
| /// Dim n As Integer |
| /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0) |
| /// output.Write(buffer, 0, n) |
| /// Loop |
| /// End Using |
| /// End If |
| /// Loop |
| /// End Using |
| /// End Sub |
| /// </code> |
| /// </example> |
| public ZipInputStream(String fileName) |
| { |
| Stream stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read ); |
| _Init(stream, false, fileName); |
| } |
| |
| |
| /// <summary> |
| /// Create a <c>ZipInputStream</c>, explicitly specifying whether to |
| /// keep the underlying stream open. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// See the documentation for the <see |
| /// cref="ZipInputStream(Stream)">ZipInputStream(Stream)</see> |
| /// constructor for a discussion of the class, and an example of how to use the class. |
| /// </remarks> |
| /// |
| /// <param name="stream"> |
| /// The stream to read from. It must be readable. |
| /// </param> |
| /// |
| /// <param name="leaveOpen"> |
| /// true if the application would like the stream |
| /// to remain open after the <c>ZipInputStream</c> has been closed. |
| /// </param> |
| public ZipInputStream(Stream stream, bool leaveOpen) |
| { |
| _Init(stream, leaveOpen, null); |
| } |
| |
| private void _Init(Stream stream, bool leaveOpen, string name) |
| { |
| _inputStream = stream; |
| if (!_inputStream.CanRead) |
| throw new ZipException("The stream must be readable."); |
| _container= new ZipContainer(this); |
| _provisionalAlternateEncoding = System.Text.Encoding.ASCII; |
| _leaveUnderlyingStreamOpen = leaveOpen; |
| _findRequired= true; |
| _name = name ?? "(stream)"; |
| } |
| |
| |
| /// <summary>Provides a string representation of the instance.</summary> |
| /// <remarks> |
| /// <para> |
| /// This can be useful for debugging purposes. |
| /// </para> |
| /// </remarks> |
| /// <returns>a string representation of the instance.</returns> |
| public override String ToString() |
| { |
| return String.Format ("ZipInputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen); |
| } |
| |
| |
| /// <summary> |
| /// The text encoding to use when reading entries into the zip archive, for |
| /// those entries whose filenames or comments cannot be encoded with the |
| /// default (IBM437) encoding. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// <para> |
| /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its |
| /// zip specification</see>, PKWare describes two options for encoding |
| /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools |
| /// or libraries do not follow the specification, and instead encode |
| /// characters using the system default code page. For example, WinRAR when |
| /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese |
| /// (950) code page. This behavior is contrary to the Zip specification, but |
| /// it occurs anyway. |
| /// </para> |
| /// |
| /// <para> |
| /// When using DotNetZip to read zip archives that use something other than |
| /// UTF-8 or IBM437, set this property to specify the code page to use when |
| /// reading encoded filenames and comments for each <c>ZipEntry</c> in the zip |
| /// file. |
| /// </para> |
| /// |
| /// <para> |
| /// This property is "provisional". When the entry in the zip archive is not |
| /// explicitly marked as using UTF-8, then IBM437 is used to decode filenames |
| /// and comments. If a loss of data would result from using IBM436 - |
| /// specifically when encoding and decoding is not reflexive - the codepage |
| /// specified here is used. It is possible, therefore, to have a given entry |
| /// with a <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with |
| /// the specified "provisional" codepage. |
| /// </para> |
| /// |
| /// <para> |
| /// When a zip file uses an arbitrary, non-UTF8 code page for encoding, there |
| /// is no standard way for the reader application - whether DotNetZip, WinZip, |
| /// WinRar, or something else - to know which codepage has been used for the |
| /// entries. Readers of zip files are not able to inspect the zip file and |
| /// determine the codepage that was used for the entries contained within it. |
| /// It is left to the application or user to determine the necessary codepage |
| /// when reading zip files encoded this way. If you use an incorrect codepage |
| /// when reading a zipfile, you will get entries with filenames that are |
| /// incorrect, and the incorrect filenames may even contain characters that |
| /// are not legal for use within filenames in Windows. Extracting entries with |
| /// illegal characters in the filenames will lead to exceptions. It's too bad, |
| /// but this is just the way things are with code pages in zip files. Caveat |
| /// Emptor. |
| /// </para> |
| /// |
| /// </remarks> |
| public System.Text.Encoding ProvisionalAlternateEncoding |
| { |
| get |
| { |
| return _provisionalAlternateEncoding; |
| } |
| set |
| { |
| _provisionalAlternateEncoding = value; |
| } |
| } |
| |
| |
| /// <summary> |
| /// Size of the work buffer to use for the ZLIB codec during decompression. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// Setting this affects the performance and memory efficiency of compression |
| /// and decompression. For larger files, setting this to a larger size may |
| /// improve performance, but the exact numbers vary depending on available |
| /// memory, and a bunch of other variables. I don't have good firm |
| /// recommendations on how to set it. You'll have to test it yourself. Or |
| /// just leave it alone and accept the default. |
| /// </remarks> |
| public int CodecBufferSize |
| { |
| get; |
| set; |
| } |
| |
| |
| /// <summary> |
| /// Sets the password to be used on the <c>ZipInputStream</c> instance. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// |
| /// <para> |
| /// When reading a zip archive, this password is used to read and decrypt the |
| /// entries that are encrypted within the zip file. When entries within a zip |
| /// file use different passwords, set the appropriate password for the entry |
| /// before the first call to <c>Read()</c> for each entry. |
| /// </para> |
| /// |
| /// <para> |
| /// When reading an entry that is not encrypted, the value of this property is |
| /// ignored. |
| /// </para> |
| /// |
| /// </remarks> |
| /// |
| /// <example> |
| /// |
| /// This example uses the ZipInputStream to read and extract entries from a |
| /// zip file, using a potentially different password for each entry. |
| /// |
| /// <code lang="C#"> |
| /// byte[] buffer= new byte[2048]; |
| /// int n; |
| /// using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read )) |
| /// { |
| /// using (var input= new ZipInputStream(raw)) |
| /// { |
| /// ZipEntry e; |
| /// while (( e = input.GetNextEntry()) != null) |
| /// { |
| /// input.Password = PasswordForEntry(e.FileName); |
| /// if (e.IsDirectory) continue; |
| /// string outputPath = Path.Combine(_extractDir, e.FileName); |
| /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)) |
| /// { |
| /// while ((n= input.Read(buffer,0,buffer.Length)) > 0) |
| /// { |
| /// output.Write(buffer,0,n); |
| /// } |
| /// } |
| /// } |
| /// } |
| /// } |
| /// |
| /// </code> |
| /// </example> |
| public String Password |
| { |
| set |
| { |
| if (_closed) |
| { |
| _exceptionPending = true; |
| throw new System.InvalidOperationException("The stream has been closed."); |
| } |
| _Password = value; |
| } |
| } |
| |
| |
| private void SetupStream() |
| { |
| // Seek to the correct posn in the file, and open a |
| // stream that can be read. |
| _crcStream= _currentEntry.InternalOpenReader(_Password); |
| _LeftToRead = _crcStream.Length; |
| _needSetup = false; |
| } |
| |
| |
| |
| internal Stream ReadStream |
| { |
| get |
| { |
| return _inputStream; |
| } |
| } |
| |
| |
| /// <summary> |
| /// Read the data from the stream into the buffer. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// <para> |
| /// The data for the zipentry will be decrypted and uncompressed, as |
| /// necessary, before being copied into the buffer. |
| /// </para> |
| /// |
| /// <para> |
| /// You must set the <see cref="Password"/> property before calling |
| /// <c>Read()</c> the first time for an encrypted entry. To determine if an |
| /// entry is encrypted and requires a password, check the <see |
| /// cref="ZipEntry.Encryption">ZipEntry.Encryption</see> property. |
| /// </para> |
| /// </remarks> |
| /// |
| /// <param name="buffer">The buffer to hold the data read from the stream.</param> |
| /// <param name="offset">the offset within the buffer to copy the first byte read.</param> |
| /// <param name="count">the number of bytes to read.</param> |
| /// <returns>the number of bytes read, after decryption and decompression.</returns> |
| public override int Read(byte[] buffer, int offset, int count) |
| { |
| if (_closed) |
| { |
| _exceptionPending = true; |
| throw new System.InvalidOperationException("The stream has been closed."); |
| } |
| |
| if (_needSetup) |
| SetupStream(); |
| |
| if (_LeftToRead == 0) return 0; |
| |
| int len = (_LeftToRead > count) ? count : (int)_LeftToRead; |
| int n = _crcStream.Read(buffer, offset, len); |
| |
| _LeftToRead -= n; |
| |
| if (_LeftToRead == 0) |
| { |
| int CrcResult = _crcStream.Crc; |
| _currentEntry.VerifyCrcAfterExtract(CrcResult); |
| _inputStream.Seek(_endOfEntry, SeekOrigin.Begin); |
| // workitem 10178 |
| SharedUtilities.Workaround_Ladybug318918(_inputStream); |
| } |
| |
| return n; |
| } |
| |
| |
| |
| /// <summary> |
| /// Read the next entry from the zip file. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// <para> |
| /// Call this method just before calling <see cref="Read(byte[], int, int)"/>, |
| /// to position the pointer in the zip file to the next entry that can be |
| /// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the |
| /// data in the zip file, until <c>Read()</c> returns 0. |
| /// </para> |
| /// |
| /// <para> |
| /// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped |
| /// stream is moved to the next entry in the zip file. If you call <see |
| /// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within |
| /// the file, you will need to call <c>GetNextEntry()</c> again, to insure |
| /// that the file pointer is positioned at the beginning of a zip entry. |
| /// </para> |
| /// |
| /// <para> |
| /// This method returns the <c>ZipEntry</c>. Using a stream approach, you will |
| /// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>. |
| /// Alternatively, you can extract an entry into a file, or a stream, by |
| /// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings. |
| /// </para> |
| /// |
| /// </remarks> |
| /// |
| /// <returns> |
| /// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more |
| /// entries in the zip file. |
| /// </returns> |
| /// |
| public ZipEntry GetNextEntry() |
| { |
| if (_findRequired) |
| { |
| // find the next signature |
| long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature); |
| if (d == -1) return null; |
| // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature |
| _inputStream.Seek(-4, SeekOrigin.Current); |
| // workitem 10178 |
| SharedUtilities.Workaround_Ladybug318918(_inputStream); |
| } |
| // workitem 10923 |
| else if (_firstEntry) |
| { |
| // we've already read one entry. |
| // Seek to the end of it. |
| _inputStream.Seek(_endOfEntry, SeekOrigin.Begin); |
| SharedUtilities.Workaround_Ladybug318918(_inputStream); |
| } |
| |
| _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry); |
| // ReadEntry leaves the file position after all the entry |
| // data and the optional bit-3 data descriptpr. This is |
| // where the next entry would normally start. |
| _endOfEntry = _inputStream.Position; |
| _firstEntry = true; |
| _needSetup = true; |
| _findRequired= false; |
| return _currentEntry; |
| } |
| |
| |
| /// <summary> |
| /// Dispose the stream. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// <para> |
| /// This method disposes the ZipInputStream. It may also close the |
| /// underlying stream, depending on which constructor was used. |
| /// </para> |
| /// |
| /// <para> |
| /// Typically the application will call <c>Dispose()</c> implicitly, via |
| /// a <c>using</c> statement in C#, or a <c>Using</c> statement in VB. |
| /// </para> |
| /// |
| /// <para> |
| /// Application code won't call this code directly. This method may |
| /// be invoked in two distinct scenarios. If disposing == true, the |
| /// method has been called directly or indirectly by a user's code, |
| /// for example via the public Dispose() method. In this case, both |
| /// managed and unmanaged resources can be referenced and disposed. |
| /// If disposing == false, the method has been called by the runtime |
| /// from inside the object finalizer and this method should not |
| /// reference other objects; in that case only unmanaged resources |
| /// must be referenced or disposed. |
| /// </para> |
| /// </remarks> |
| /// |
| /// <param name="disposing"> |
| /// true if the Dispose method was invoked by user code. |
| /// </param> |
| protected override void Dispose(bool disposing) |
| { |
| if (_closed) return; |
| |
| if (disposing) // not called from finalizer |
| { |
| // When ZipInputStream is used within a using clause, and an |
| // exception is thrown, Close() is invoked. But we don't want to |
| // try to write anything in that case. Eventually the exception |
| // will be propagated to the application. |
| if (_exceptionPending) return; |
| |
| if (!_leaveUnderlyingStreamOpen) |
| { |
| #if NETCF |
| _inputStream.Close(); |
| #else |
| _inputStream.Dispose(); |
| #endif |
| } |
| } |
| _closed= true; |
| } |
| |
| |
| /// <summary> |
| /// Always returns true. |
| /// </summary> |
| public override bool CanRead { get { return true; }} |
| |
| /// <summary> |
| /// Returns the value of <c>CanSeek</c> for the underlying (wrapped) stream. |
| /// </summary> |
| public override bool CanSeek { get { return _inputStream.CanSeek; } } |
| |
| /// <summary> |
| /// Always returns false. |
| /// </summary> |
| public override bool CanWrite { get { return false; } } |
| |
| /// <summary> |
| /// Returns the length of the underlying stream. |
| /// </summary> |
| public override long Length { get { return _inputStream.Length; }} |
| |
| /// <summary> |
| /// Gets or sets the position of the underlying stream. |
| /// </summary> |
| /// <remarks> |
| /// Setting the position is equivalent to calling <c>Seek(value, SeekOrigin.Begin)</c>. |
| /// </remarks> |
| public override long Position |
| { |
| get { return _inputStream.Position;} |
| set { Seek(value, SeekOrigin.Begin); } |
| } |
| |
| /// <summary> |
| /// This is a no-op. |
| /// </summary> |
| public override void Flush() |
| { |
| throw new NotSupportedException("Flush"); |
| } |
| |
| |
| /// <summary> |
| /// This method always throws a NotSupportedException. |
| /// </summary> |
| /// <param name="buffer">ignored</param> |
| /// <param name="offset">ignored</param> |
| /// <param name="count">ignored</param> |
| public override void Write(byte[] buffer, int offset, int count) |
| { |
| throw new NotSupportedException("Write"); |
| } |
| |
| |
| /// <summary> |
| /// This method seeks in the underlying stream. |
| /// </summary> |
| /// |
| /// <remarks> |
| /// <para> |
| /// Call this method if you want to seek around within the zip file for random access. |
| /// </para> |
| /// |
| /// <para> |
| /// Applications can intermix calls to <c>Seek()</c> with calls to <see |
| /// cref="GetNextEntry()"/>. After a call to <c>Seek()</c>, |
| /// <c>GetNextEntry()</c> will get the next <c>ZipEntry</c> that falls after |
| /// the current position in the input stream. You're on your own for finding |
| /// out just where to seek in the stream, to get to the various entries. |
| /// </para> |
| /// |
| /// </remarks> |
| /// |
| /// <param name="offset">the offset point to seek to</param> |
| /// <param name="origin">the reference point from which to seek</param> |
| /// <returns>The new position</returns> |
| public override long Seek(long offset, SeekOrigin origin) |
| { |
| _findRequired= true; |
| var x = _inputStream.Seek(offset, origin); |
| // workitem 10178 |
| SharedUtilities.Workaround_Ladybug318918(_inputStream); |
| return x; |
| } |
| |
| /// <summary> |
| /// This method always throws a NotSupportedException. |
| /// </summary> |
| /// <param name="value">ignored</param> |
| public override void SetLength(long value) |
| { |
| throw new NotSupportedException(); |
| } |
| |
| |
| private Stream _inputStream; |
| private System.Text.Encoding _provisionalAlternateEncoding; |
| private ZipEntry _currentEntry; |
| private bool _firstEntry; |
| private bool _needSetup; |
| private ZipContainer _container; |
| private CrcCalculatorStream _crcStream; |
| private Int64 _LeftToRead; |
| internal String _Password; |
| private Int64 _endOfEntry; |
| private string _name; |
| |
| private bool _leaveUnderlyingStreamOpen; |
| private bool _closed; |
| private bool _findRequired; |
| private bool _exceptionPending; |
| } |
| |
| |
| |
| } |