Mes documents/Visual Studio 2005/Projects/TES4ModTranslator/TES4ModTranslator/Zip/ZipInputStream.cs

Go to the documentation of this file.
00001 // ZipInputStream.cs
00002 //
00003 // Copyright (C) 2001 Mike Krueger
00004 // Copyright (C) 2004 John Reilly
00005 //
00006 // This file was translated from java, it was part of the GNU Classpath
00007 // Copyright (C) 2001 Free Software Foundation, Inc.
00008 //
00009 // This program is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU General Public License
00011 // as published by the Free Software Foundation; either version 2
00012 // of the License, or (at your option) any later version.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 //
00023 // Linking this library statically or dynamically with other modules is
00024 // making a combined work based on this library.  Thus, the terms and
00025 // conditions of the GNU General Public License cover the whole
00026 // combination.
00027 // 
00028 // As a special exception, the copyright holders of this library give you
00029 // permission to link this library with independent modules to produce an
00030 // executable, regardless of the license terms of these independent
00031 // modules, and to copy and distribute the resulting executable under
00032 // terms of your choice, provided that you also meet, for each linked
00033 // independent module, the terms and conditions of the license of that
00034 // module.  An independent module is a module which is not derived from
00035 // or based on this library.  If you modify this library, you may extend
00036 // this exception to your version of the library, but you are not
00037 // obligated to do so.  If you do not wish to do so, delete this
00038 // exception statement from your version.
00039 
00040 using System;
00041 using System.Text;
00042 using System.IO;
00043 
00044 using ICSharpCode.SharpZipLib.Checksums;
00045 using ICSharpCode.SharpZipLib.Zip.Compression;
00046 using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
00047 using ICSharpCode.SharpZipLib.Encryption;
00048 
00049 namespace ICSharpCode.SharpZipLib.Zip 
00050 {
00097         public class ZipInputStream : InflaterInputStream
00098         {
00099                 // Delegate for reading bytes from a stream.
00100                 delegate int ReaderDelegate(byte[] b, int offset, int length);
00101 
00105                 ReaderDelegate internalReader;
00106 
00107                 Crc32 crc = new Crc32();
00108                 ZipEntry entry = null;
00109                 
00110                 long size;
00111                 int method;
00112                 int flags;
00113                 string password = null;
00114 
00118                 public ZipInputStream(Stream baseInputStream) : base(baseInputStream, new Inflater(true))
00119                 {
00120                         internalReader = new ReaderDelegate(InitialRead);
00121                 }
00122 
00123                 
00127                 public string Password 
00128                 {
00129                         get {
00130                                 return password;
00131                         }
00132                         set {
00133                                 password = value;
00134                         }
00135                 }
00136                 
00137 
00145                 public bool CanDecompressEntry {
00146                         get {
00147                                 return entry != null && entry.Version <= ZipConstants.VERSION_MADE_BY;
00148                         }
00149                 }
00150                 
00167                 public ZipEntry GetNextEntry()
00168                 {
00169                         if (crc == null) {
00170                                 throw new InvalidOperationException("Closed.");
00171                         }
00172                         
00173                         if (entry != null) {
00174                                 CloseEntry();
00175                         }
00176 
00177                         int header = inputBuffer.ReadLeInt();
00178 
00179                         if (header == ZipConstants.CENSIG || 
00180                             header == ZipConstants.ENDSIG || 
00181                             header == ZipConstants.CENDIGITALSIG || 
00182                             header == ZipConstants.CENSIG64) {
00183                             // No more individual entries exist
00184                                 Close();
00185                                 return null;
00186                         }
00187 
00188                         // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found
00189                         // SPANNINGSIG is same as descriptor signature and is untested as yet.
00190                         if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG) {
00191                                 header = inputBuffer.ReadLeInt();
00192                         }
00193                         
00194                         if (header != ZipConstants.LOCSIG) {
00195                                 throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header));
00196                         }
00197                         
00198                         short versionRequiredToExtract = (short)inputBuffer.ReadLeShort();
00199                         
00200                         flags          = inputBuffer.ReadLeShort();
00201                         method         = inputBuffer.ReadLeShort();
00202                         uint dostime   = (uint)inputBuffer.ReadLeInt();
00203                         int crc2       = inputBuffer.ReadLeInt();
00204                         csize          = inputBuffer.ReadLeInt();
00205                         size           = inputBuffer.ReadLeInt();
00206                         int nameLen    = inputBuffer.ReadLeShort();
00207                         int extraLen   = inputBuffer.ReadLeShort();
00208                         
00209                         bool isCrypted = (flags & 1) == 1;
00210                         
00211                         byte[] buffer = new byte[nameLen];
00212                         inputBuffer.ReadRawBuffer(buffer);
00213                         
00214                         string name = ZipConstants.ConvertToString(buffer);
00215                         
00216                         entry = new ZipEntry(name, versionRequiredToExtract);
00217                         entry.Flags = flags;
00218                         
00219                         if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CRYPTO_HEADER_SIZE != size))) {
00220                                 throw new ZipException("Stored, but compressed != uncompressed");
00221                         }
00222                         
00223                         if (method != (int)CompressionMethod.Stored && method != (int)CompressionMethod.Deflated) {
00224                                 throw new ZipException("Unknown compression method " + method);
00225                         }
00226                         
00227                         entry.CompressionMethod = (CompressionMethod)method;
00228                         
00229                         if ((flags & 8) == 0) {
00230                                 entry.Crc  = crc2 & 0xFFFFFFFFL;
00231                                 entry.Size = size & 0xFFFFFFFFL;
00232                                 entry.CompressedSize = csize & 0xFFFFFFFFL;
00233                         } else {
00234                                 
00235                                 // This allows for GNU, WinZip and possibly other archives, the PKZIP spec says these are zero
00236                                 // under these circumstances.
00237                                 if (crc2 != 0) {
00238                                         entry.Crc = crc2 & 0xFFFFFFFFL;
00239                                 }
00240                                 
00241                                 if (size != 0) {
00242                                         entry.Size = size & 0xFFFFFFFFL;
00243                                 }
00244                                 if (csize != 0) {
00245                                         entry.CompressedSize = csize & 0xFFFFFFFFL;
00246                                 }
00247                         }
00248                         
00249                         entry.DosTime = dostime;
00250                         
00251                         if (extraLen > 0) {
00252                                 byte[] extra = new byte[extraLen];
00253                                 inputBuffer.ReadRawBuffer(extra);
00254                                 entry.ExtraData = extra;
00255                         }
00256 
00257                         internalReader = new ReaderDelegate(InitialRead);
00258                         return entry;
00259                 }
00260                 
00261                 // Read data descriptor at the end of compressed data.
00262                 void ReadDataDescriptor()
00263                 {
00264                         if (inputBuffer.ReadLeInt() != ZipConstants.EXTSIG) {
00265                                 throw new ZipException("Data descriptor signature not found");
00266                         }
00267                         
00268                         entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL;
00269                         csize = inputBuffer.ReadLeInt();
00270                         size = inputBuffer.ReadLeInt();
00271                         
00272                         entry.Size = size & 0xFFFFFFFFL;
00273                         entry.CompressedSize = csize & 0xFFFFFFFFL;
00274                 }
00275                 
00285                 public void CloseEntry()
00286                 {
00287                         if (crc == null) {
00288                                 throw new InvalidOperationException("Closed.");
00289                         }
00290                         
00291                         if (entry == null) {
00292                                 return;
00293                         }
00294                         
00295                         if (method == (int)CompressionMethod.Deflated) {
00296                                 if ((flags & 8) != 0) {
00297                                         // We don't know how much we must skip, read until end.
00298                                         byte[] tmp = new byte[2048];
00299                                         while (Read(tmp, 0, tmp.Length) > 0)
00300                                                 ;
00301                                         // read will close this entry
00302                                         return;
00303                                 }
00304                                 csize -= inf.TotalIn;
00305                                 inputBuffer.Available -= inf.RemainingInput;    
00306                         }
00307 
00308                         if (inputBuffer.Available > csize && csize >= 0) {
00309                                 inputBuffer.Available = (int)((long)inputBuffer.Available - csize);
00310                         } else {
00311                                 csize -= inputBuffer.Available;
00312                                 inputBuffer.Available = 0;
00313                                 while (csize != 0) {
00314                                         int skipped = (int)base.Skip(csize & 0xFFFFFFFFL);
00315                                         
00316                                         if (skipped <= 0) {
00317                                                 throw new ZipException("Zip archive ends early.");
00318                                         }
00319                                         
00320                                         csize -= skipped;
00321                                 }
00322                         }
00323                         
00324                         size = 0;
00325                         crc.Reset();
00326                         if (method == (int)CompressionMethod.Deflated) {
00327                                 inf.Reset();
00328                         }
00329                         entry = null;
00330                 }
00331                 
00336                 public override int Available {
00337                         get {
00338                                 return entry != null ? 1 : 0;
00339                         }
00340                 }
00341                 
00354                 public override int ReadByte()
00355                 {
00356                         byte[] b = new byte[1];
00357                         if (Read(b, 0, 1) <= 0) {
00358                                 return -1;
00359                         }
00360                         return b[0] & 0xff;
00361                 }
00362 
00363                 // Perform the initial read on an entry which may include 
00364                 // reading encryption headers and setting up inflation.
00365                 int InitialRead(byte[] destination, int offset, int count)
00366                 {
00367                         if (entry.Version > ZipConstants.VERSION_MADE_BY) {
00368                                 throw new ZipException("Libray cannot extract this entry version required (" + entry.Version.ToString() + ")");
00369                         }
00370                         
00371                         // test for encryption
00372                         if (entry.IsCrypted) {
00373                 
00374                                 if (password == null) {
00375                                         throw new ZipException("No password set.");
00376                                 }
00377                         
00378                                 // Generate and set crypto transform...
00379                                 PkzipClassicManaged managed = new PkzipClassicManaged();
00380                                 byte[] key = PkzipClassic.GenerateKeys(Encoding.ASCII.GetBytes(password));
00381                                         
00382                                 inputBuffer.CryptoTransform = managed.CreateDecryptor(key, null);
00383                         
00384                                 byte[] cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
00385                                 inputBuffer.ReadClearTextBuffer(cryptbuffer, 0, ZipConstants.CRYPTO_HEADER_SIZE);
00386                                         
00387                                 if ((flags & 8) == 0) {
00388                                         if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(entry.Crc >> 24)) {
00389                                                 throw new ZipException("Invalid password");
00390                                         }
00391                                 }
00392                                 else {
00393                                         if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((entry.DosTime >> 8) & 0xff)) {
00394                                                 throw new ZipException("Invalid password");
00395                                         }
00396                                 }
00397                                         
00398                                 if (csize >= ZipConstants.CRYPTO_HEADER_SIZE) {
00399                                         csize -= ZipConstants.CRYPTO_HEADER_SIZE;
00400                                 }
00401                         } 
00402                         else {
00403                                 inputBuffer.CryptoTransform = null;
00404                         }
00405                         
00406                         if (method == (int)CompressionMethod.Deflated && inputBuffer.Available > 0) {
00407                                 inputBuffer.SetInflaterInput(inf);
00408                         }
00409                         
00410                         internalReader = new ReaderDelegate(BodyRead);
00411                         return BodyRead(destination, offset, count);
00412                 }
00413                 
00414 
00423                 public override int Read(byte[] destination, int index, int count)
00424                 {
00425                         return internalReader(destination, index, count);
00426                 }
00427 
00443                 public int BodyRead(byte[] b, int off, int len)
00444                 {
00445                         if (crc == null) {
00446                                 throw new InvalidOperationException("Closed.");
00447                         }
00448                         
00449                         if (entry == null || len <= 0 ) {
00450                                 return 0;
00451                         }
00452                         
00453                         bool finished = false;
00454                         
00455                         switch (method) {
00456                                 case (int)CompressionMethod.Deflated:
00457                                         len = base.Read(b, off, len);
00458                                         if (len <= 0) {
00459                                                 if (!inf.IsFinished) {
00460                                                         throw new ZipException("Inflater not finished!?");
00461                                                 }
00462                                                 inputBuffer.Available = inf.RemainingInput;
00463                                                 
00464                                                 if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) {
00465                                                         throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut);
00466                                                 }
00467                                                 inf.Reset();
00468                                                 finished = true;
00469                                         }
00470                                         break;
00471                                 
00472                                 case (int)CompressionMethod.Stored:
00473                                         if (len > csize && csize >= 0) {
00474                                                 len = (int)csize;
00475                                         }
00476                                         len = inputBuffer.ReadClearTextBuffer(b, off, len);
00477                                         if (len > 0) {
00478                                                 csize -= len;
00479                                                 size -= len;
00480                                         }
00481                                         
00482                                         if (csize == 0) {
00483                                                 finished = true;
00484                                         } else {
00485                                                 if (len < 0) {
00486                                                         throw new ZipException("EOF in stored block");
00487                                                 }
00488                                         }
00489                                         break;
00490                         }
00491                                 
00492                         if (len > 0) {
00493                                 crc.Update(b, off, len);
00494                         }
00495                         
00496                         if (finished) {
00497                                 StopDecrypting();
00498                                 
00499                                 if ((flags & 8) != 0) {
00500                                         ReadDataDescriptor();
00501                                 }
00502                                 
00503                                 if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) {
00504                                         throw new ZipException("CRC mismatch");
00505                                 }
00506                                 crc.Reset();
00507                                 entry = null;
00508                         }
00509                         return len;
00510                 }
00511 
00515                 public override void Close()
00516                 {
00517                         base.Close();
00518                         crc = null;
00519                         entry = null;
00520                 }
00521         }
00522 }

Generated on Fri Jun 23 21:50:05 2006 for OblivionModTranslator by  doxygen 1.4.6-NO