| // 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.GetEncoding("IBM437"); | |
| _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; | |
| } | |
| } |