context: // ZipInputStream.cs
  //
  // Copyright (C) 2001 Mike Krueger
  // Copyright (C) 2004 John Reilly
  //
  // This file was translated from java, it was part of the GNU Classpath
  // Copyright (C) 2001 Free Software Foundation, Inc.
  //
  // This program is free software; you can redistribute it and/or
  // modify it under the terms of the GNU General Public License
  // as published by the Free Software Foundation; either version 2
  // of the License, or (at your option) any later version.
  //
  // This program is distributed in the hope that it will be useful,
  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  // GNU General Public License for more details.
  //
  // You should have received a copy of the GNU General Public License
  // along with this program; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  //
  // Linking this library statically or dynamically with other modules is
  // making a combined work based on this library.  Thus, the terms and
  // conditions of the GNU General Public License cover the whole
  // combination.
  // 
  // As a special exception, the copyright holders of this library give you
  // permission to link this library with independent modules to produce an
  // executable, regardless of the license terms of these independent
  // modules, and to copy and distribute the resulting executable under
  // terms of your choice, provided that you also meet, for each linked
  // independent module, the terms and conditions of the license of that
  // module.  An independent module is a module which is not derived from
  // or based on this library.  If you modify this library, you may extend
  // this exception to your version of the library, but you are not
  // obligated to do so.  If you do not wish to do so, delete this
  // exception statement from your version.
  
  // HISTORY
  //	2010-05-25	Z-1663	Fixed exception when testing local header compressed size of -1
  
  using System;
  using System.IO;
  
  using ICSharpCode.SharpZipLib.Checksums;
  using ICSharpCode.SharpZipLib.Zip.Compression;
  using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
  
  #if !NETCF_1_0
  using ICSharpCode.SharpZipLib.Encryption;
  #endif
  
  namespace ICSharpCode.SharpZipLib.Zip
  {
  	/// <summary>
  	/// This is an InflaterInputStream that reads the files baseInputStream an zip archive
  	/// one after another.  It has a special method to get the zip entry of
  	/// the next file.  The zip entry contains information about the file name
  	/// size, compressed size, Crc, etc.
  	/// It includes support for Stored and Deflated entries.
  	/// <br/>
  	/// <br/>Author of the original java version : Jochen Hoenicke
  	/// </summary>
  	/// 
  	/// <example> This sample shows how to read a zip file
  	/// <code lang="C#">
  	/// using System;
  	/// using System.Text;
  	/// using System.IO;
  	/// 
  	/// using ICSharpCode.SharpZipLib.Zip;
  	/// 
  	/// class MainClass
  	/// {
  	/// 	public static void Main(string[] args)
  	/// 	{
  	/// 		using ( ZipInputStream s = new ZipInputStream(File.OpenRead(args[0]))) {
  	///
  	/// 			ZipEntry theEntry;
      /// 			const int size = 2048;
      /// 			byte[] data = new byte[2048];
      /// 			
      /// 			while ((theEntry = s.GetNextEntry()) != null) {
  	///                 if ( entry.IsFile ) {
  	/// 				    Console.Write("Show contents (y/n) ?");
  	/// 				    if (Console.ReadLine() == "y") {
  	/// 				    	while (true) {
  	/// 				    		size = s.Read(data, 0, data.Length);
  	/// 				    		if (size > 0) {
  	/// 				    			Console.Write(new ASCIIEncoding().GetString(data, 0, size));
  	/// 				    		} else {
  	/// 				    			break;
  	/// 				    		}
  	/// 				    	}
  	/// 				    }
      /// 				}
  	/// 			}
  	/// 		}
  	/// 	}
  	/// }
  	/// </code>
  	/// </example>
  	public class ZipInputStream : InflaterInputStream
  	{
  		#region Instance Fields
  
  		/// <summary>
  		/// Delegate for reading bytes from a stream. 
  		/// </summary>
  		delegate int ReadDataHandler(byte[] b, int offset, int length);
  		
  		/// <summary>
  		/// The current reader this instance.
  		/// </summary>
  		ReadDataHandler internalReader;
  		
  		Crc32 crc = new Crc32();
  		ZipEntry entry;
  		
  		long size;
  		int method;
  		int flags;
  		string password;
  		#endregion
  
  		#region Constructors
  		/// <summary>
  		/// Creates a new Zip input stream, for reading a zip archive.
  		/// </summary>
  		/// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
  		public ZipInputStream(Stream baseInputStream)
  			: base(baseInputStream, new Inflater(true))
  		{
  			internalReader = new ReadDataHandler(ReadingNotAvailable);
  		}
  
          /// <summary>
          /// Creates a new Zip input stream, for reading a zip archive.
          /// </summary>
          /// <param name="baseInputStream">The underlying <see cref="Stream"/> providing data.</param>
          /// <param name="bufferSize">Size of the buffer.</param>
          public ZipInputStream( Stream baseInputStream, int bufferSize )
              : base(baseInputStream, new Inflater(true), bufferSize)
          {
              internalReader = new ReadDataHandler(ReadingNotAvailable);
          }
          #endregion
  		
  		/// <summary>
  		/// Optional password used for encryption when non-null
  		/// </summary>
  		/// <value>A password for all encrypted <see cref="ZipEntry">entries </see> in this <see cref="ZipInputStream"/></value>
  		public string Password
  		{
  			get {
  				return password;
  			}
  			set {
  				password = value;
  			}
  		}
  		
  		
  		/// <summary>
  		/// Gets a value indicating if there is a current entry and it can be decompressed
  		/// </summary>
  		/// <remarks>
  		/// The entry can only be decompressed if the library supports the zip features required to extract it.
  		/// See the <see cref="ZipEntry.Version">ZipEntry Version</see> property for more details.
  		/// </remarks>
  		public bool CanDecompressEntry {
  			get {
  				return (entry != null) && entry.CanDecompress;
  			}
  		}
  		
  		/// <summary>
  		/// Advances to the next entry in the archive
  		/// </summary>
  		/// <returns>
  		/// The next <see cref="ZipEntry">entry</see> in the archive or null if there are no more entries.
  		/// </returns>
  		/// <remarks>
  		/// If the previous entry is still open <see cref="CloseEntry">CloseEntry</see> is called.
  		/// </remarks>
  		/// <exception cref="InvalidOperationException">
  		/// Input stream is closed
  		/// </exception>
  		/// <exception cref="ZipException">
  		/// Password is not set, password is invalid, compression method is invalid,
  		/// version required to extract is not supported
  		/// </exception>
  		public ZipEntry GetNextEntry()
  		{
  			if (crc == null) {
  				throw new InvalidOperationException("Closed.");
  			}
  			
  			if (entry != null) {
  				CloseEntry();
  			}
  			
  			int header = inputBuffer.ReadLeInt();
  			
  			if (header == ZipConstants.CentralHeaderSignature ||
  				header == ZipConstants.EndOfCentralDirectorySignature ||
  				header == ZipConstants.CentralHeaderDigitalSignature ||
  				header == ZipConstants.ArchiveExtraDataSignature ||
  				header == ZipConstants.Zip64CentralFileHeaderSignature) {
  				// No more individual entries exist
  				Close();
  				return null;
  			}
  			
  			// -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
  			// Spanning signature is same as descriptor signature and is untested as yet.
  			if ( (header == ZipConstants.SpanningTempSignature) || (header == ZipConstants.SpanningSignature) ) {
  				header = inputBuffer.ReadLeInt();
  			}
  			
  			if (header != ZipConstants.LocalHeaderSignature) {
  				throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
  			}
  			
  			short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();
  			
  			flags          = inputBuffer.ReadLeShort();
  			method         = inputBuffer.ReadLeShort();
  			uint dostime   = (uint)inputBuffer.ReadLeInt();
  			int crc2       = inputBuffer.ReadLeInt();
  			csize          = inputBuffer.ReadLeInt();
  			size           = inputBuffer.ReadLeInt();
  			int nameLen    = inputBuffer.ReadLeShort();
  			int extraLen   = inputBuffer.ReadLeShort();
  			
  			bool isCrypted = (flags & 1) == 1;
  			
  			byte[] buffer = new byte[nameLen];
  			inputBuffer.ReadRawBuffer(buffer);
  			
  			string name = ZipConstants.ConvertToStringExt(flags, buffer);
  			
  			entry = new ZipEntry(name, versionRequiredToExtract);
  			entry.Flags = flags;
  			
  			entry.CompressionMethod = (CompressionMethod)method;
  			
  			if ((flags & 8) == 0) {
  				entry.Crc  = crc2 & 0xFFFFFFFFL;
  				entry.Size = size & 0xFFFFFFFFL;
  				entry.CompressedSize = csize & 0xFFFFFFFFL;
  
  				entry.CryptoCheckValue = (byte)((crc2 >> 24) & 0xff);
  
  			} else {
  				
  				// This allows for GNU, WinZip and possibly other archives, the PKZIP spec
  				// says these values are zero under these circumstances.
  				if (crc2 != 0) {
  					entry.Crc = crc2 & 0xFFFFFFFFL;
  				}
  				
  				if (size != 0) {
  					entry.Size = size & 0xFFFFFFFFL;
  				}
  
  				if (csize != 0) {
  					entry.CompressedSize = csize & 0xFFFFFFFFL;
  				}
  
  				entry.CryptoCheckValue = (byte)((dostime >> 8) & 0xff);
  			}
  			
  			entry.DosTime = dostime;
  
  			// If local header requires Zip64 is true then the extended header should contain
  			// both values.
  
  			// Handle extra data if present.  This can set/alter some fields of the entry.
  			if (extraLen > 0) {
  				byte[] extra = new byte[extraLen];
  				inputBuffer.ReadRawBuffer(extra);
  				entry.ExtraData = extra;
  			}
  
  			entry.ProcessExtraData(true);
  			if ( entry.CompressedSize >= 0 ) {
  				csize = entry.CompressedSize;
  			}
  
  			if ( entry.Size >= 0 ) {
  				size = entry.Size;
  			}
  			
  			if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CryptoHeaderSize != size))) {
  				throw new ZipException("Stored, but compressed != uncompressed");
  			}
  
  			// Determine how to handle reading of data if this is attempted.
  			if (entry.IsCompressionMethodSupported()) {
  				internalReader = new ReadDataHandler(InitialRead);
  			} else {
  
gt: 				internalReader = new ReadDataHandler(ReadingNotSupported);