123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827 |
- // 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;
- 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>
- public 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, _currentEntry.Encryption, _currentEntry._Crc32, _currentEntry.ArchiveStream, _currentEntry.UncompressedSize);
- _inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
- // workitem 10178
- Ionic.Zip.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
- Ionic.Zip.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);
- Ionic.Zip.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
- Ionic.Zip.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 Ionic.Crc.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;
- }
- }
|