|  | // 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; | 
|  | } | 
|  |  | 
|  |  | 
|  |  | 
|  | } |