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

Go to the documentation of this file.
00001 // ZipFile.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.Security.Cryptography;
00042 using System.Collections;
00043 using System.IO;
00044 using System.Text;
00045 
00046 using ICSharpCode.SharpZipLib.Checksums;
00047 using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
00048 using ICSharpCode.SharpZipLib.Zip.Compression;
00049 using ICSharpCode.SharpZipLib.Encryption;
00050 
00051 namespace ICSharpCode.SharpZipLib.Zip 
00052 {
00053 
00057         public class KeysRequiredEventArgs : EventArgs
00058         {
00059                 string fileName;
00060         
00064                 public string FileName
00065                 {
00066                         get { return fileName; }
00067                 }
00068         
00069                 byte[] key;
00070                 
00074                 public byte[] Key
00075                 {
00076                         get { return key; }
00077                         set { key = value; }
00078                 }
00079         
00084                 public KeysRequiredEventArgs(string name)
00085                 {
00086                         fileName = name;
00087                 }
00088         
00094                 public KeysRequiredEventArgs(string name, byte[] keyValue)
00095                 {
00096                         fileName = name;
00097                         key = keyValue;
00098                 }
00099         }
00100         
00139         public class ZipFile : IEnumerable
00140         {
00141                 string     name;
00142                 string     comment;
00143                 Stream     baseStream;
00144                 bool       isStreamOwner = true;
00145                 long       offsetOfFirstEntry = 0;
00146                 ZipEntry[] entries;
00147                 
00148                 #region KeyHandling
00149                 
00153                 public delegate void KeysRequiredEventHandler(
00154                         object sender,
00155                         KeysRequiredEventArgs e
00156                 );
00157 
00161                 public KeysRequiredEventHandler KeysRequired;
00162 
00167                 void OnKeysRequired(string fileName)
00168                 {
00169                         if (KeysRequired != null) {
00170                                 KeysRequiredEventArgs krea = new KeysRequiredEventArgs(fileName, key);
00171                                 KeysRequired(this, krea);
00172                                 key = krea.Key;
00173                         }
00174                 }
00175                 
00176                 byte[] key = null;
00177                 
00181                 byte[] Key
00182                 {
00183                         get { return key; }
00184                         set { key = value; }
00185                 }
00186                 
00191                 public string Password
00192                 {
00193                         set 
00194                         {
00195                                 if ( (value == null) || (value.Length == 0) ) {
00196                                         key = null;
00197                                 }
00198                                 else {
00199                                         key = PkzipClassic.GenerateKeys(Encoding.ASCII.GetBytes(value));
00200                                 }
00201                         }
00202                 }
00203                 
00204                 byte[] iv = null;
00205                 
00206                 bool HaveKeys
00207                 {
00208                  get { return key != null; }
00209                 }
00210                 #endregion
00211         
00221                 public ZipFile(string name)
00222                 {
00223                         this.name = name;
00224                         this.baseStream = File.OpenRead(name);
00225                         try {
00226                                 ReadEntries();
00227                         }
00228                         catch {
00229                                 Close();
00230                                 throw;
00231                         }
00232                 }
00233                 
00243                 public ZipFile(FileStream file)
00244                 {
00245                         this.baseStream  = file;
00246                         this.name = file.Name;
00247                         try {
00248                                 ReadEntries();
00249                         }
00250                         catch {
00251                                 Close();
00252                                 throw;
00253                         }
00254                 }
00255                 
00266                 public ZipFile(Stream baseStream)
00267                 {
00268                         this.baseStream  = baseStream;
00269                         this.name = null;
00270                         try {
00271                                 ReadEntries();
00272                         }
00273                         catch {
00274                                 Close();
00275                                 throw;
00276                         }
00277                 }
00278                 
00279                 
00287                 bool IsStreamOwner
00288                 {
00289                         get { return isStreamOwner; }
00290                         set { isStreamOwner = value; }
00291                 }
00292                 
00303                 int ReadLeShort()
00304                 {
00305                         return baseStream.ReadByte() | baseStream.ReadByte() << 8;
00306                 }
00307                 
00318                 int ReadLeInt()
00319                 {
00320                         return ReadLeShort() | ReadLeShort() << 16;
00321                 }
00322                 
00323                 // NOTE this returns the offset of the first byte after the signature.
00324                 long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData)
00325                 {
00326                         long pos = endLocation - minimumBlockSize;
00327                         if (pos < 0) {
00328                                 return -1;
00329                         }
00330                 
00331                         long giveUpMarker = Math.Max(pos - maximumVariableData, 0);
00332                 
00333                         // TODO: this loop could be optimised for speed.
00334                         do 
00335                         {
00336                                 if (pos < giveUpMarker) {
00337                                         return -1;
00338                                 }
00339                                 baseStream.Seek(pos--, SeekOrigin.Begin);
00340                         } while (ReadLeInt() != signature);
00341         
00342                         return baseStream.Position;
00343                 }
00344                 
00355                 void ReadEntries()
00356                 {
00357                         // Search for the End Of Central Directory.  When a zip comment is
00358                         // present the directory may start earlier.
00359                         // 
00360                         // TODO: The search is limited to 64K which is the maximum size of a trailing comment field to aid speed.
00361                         // This should be compatible with both SFX and ZIP files but has only been tested for Zip files
00362                         // Need to confirm this is valid in all cases.
00363                         // Could also speed this up by reading memory in larger blocks.                 
00364 
00365                         if (baseStream.CanSeek == false) {
00366                                 throw new ZipException("ZipFile stream must be seekable");
00367                         }
00368                         
00369                         long locatedCentralDirOffset = LocateBlockWithSignature(ZipConstants.ENDSIG, baseStream.Length, ZipConstants.ENDHDR, 0xffff);
00370                         if (locatedCentralDirOffset < 0) {
00371                                 throw new ZipException("Cannot find central directory");
00372                         }
00373 
00374                         int thisDiskNumber            = ReadLeShort();
00375                         int startCentralDirDisk       = ReadLeShort();
00376                         int entriesForThisDisk        = ReadLeShort();
00377                         int entriesForWholeCentralDir = ReadLeShort();
00378                         int centralDirSize            = ReadLeInt();
00379                         int offsetOfCentralDir        = ReadLeInt();
00380                         int commentSize               = ReadLeShort();
00381                         
00382                         byte[] zipComment = new byte[commentSize]; 
00383                         baseStream.Read(zipComment, 0, zipComment.Length); 
00384                         comment = ZipConstants.ConvertToString(zipComment); 
00385                         
00386 /* Its seems possible that this is too strict, more digging required.
00387                         if (thisDiskNumber != 0 || startCentralDirDisk != 0 || entriesForThisDisk != entriesForWholeCentralDir) {
00388                                 throw new ZipException("Spanned archives are not currently handled");
00389                         }
00390 */
00391 
00392                         entries = new ZipEntry[entriesForWholeCentralDir];
00393                         
00394                         // SFX support, find the offset of the first entry vis the start of the stream
00395                         // This applies to Zip files that are appended to the end of the SFX stub.
00396                         // Zip files created by some archivers have the offsets altered to reflect the true offsets
00397                         // and so dont require any adjustment here...
00398                         if (offsetOfCentralDir < locatedCentralDirOffset - (4 + centralDirSize)) {
00399                                 offsetOfFirstEntry = locatedCentralDirOffset - (4 + centralDirSize + offsetOfCentralDir);
00400                                 if (offsetOfFirstEntry <= 0) {
00401                                         throw new ZipException("Invalid SFX file");
00402                                 }
00403                         }
00404 
00405                         baseStream.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin);
00406                         
00407                         for (int i = 0; i < entriesForThisDisk; i++) {
00408                                 if (ReadLeInt() != ZipConstants.CENSIG) {
00409                                         throw new ZipException("Wrong Central Directory signature");
00410                                 }
00411                                 
00412                                 int versionMadeBy      = ReadLeShort();
00413                                 int versionToExtract   = ReadLeShort();
00414                                 int bitFlags           = ReadLeShort();
00415                                 int method             = ReadLeShort();
00416                                 int dostime            = ReadLeInt();
00417                                 int crc                = ReadLeInt();
00418                                 int csize              = ReadLeInt();
00419                                 int size               = ReadLeInt();
00420                                 int nameLen            = ReadLeShort();
00421                                 int extraLen           = ReadLeShort();
00422                                 int commentLen         = ReadLeShort();
00423                                 
00424                                 int diskStartNo        = ReadLeShort();  // Not currently used
00425                                 int internalAttributes = ReadLeShort();  // Not currently used
00426 
00427                                 int externalAttributes = ReadLeInt();
00428                                 int offset             = ReadLeInt();
00429                                 
00430                                 byte[] buffer = new byte[Math.Max(nameLen, commentLen)];
00431                                 
00432                                 baseStream.Read(buffer, 0, nameLen);
00433                                 string name = ZipConstants.ConvertToString(buffer, nameLen);
00434                                 
00435                                 ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy);
00436                                 entry.CompressionMethod = (CompressionMethod)method;
00437                                 entry.Crc = crc & 0xffffffffL;
00438                                 entry.Size = size & 0xffffffffL;
00439                                 entry.CompressedSize = csize & 0xffffffffL;
00440                                 entry.Flags = bitFlags;
00441                                 entry.DosTime = (uint)dostime;
00442                                 
00443                                 if (extraLen > 0) {
00444                                         byte[] extra = new byte[extraLen];
00445                                         baseStream.Read(extra, 0, extraLen);
00446                                         entry.ExtraData = extra;
00447                                 }
00448                                 
00449                                 if (commentLen > 0) {
00450                                         baseStream.Read(buffer, 0, commentLen);
00451                                         entry.Comment = ZipConstants.ConvertToString(buffer, commentLen);
00452                                 }
00453                                 
00454                                 entry.ZipFileIndex           = i;
00455                                 entry.Offset                 = offset;
00456                                 entry.ExternalFileAttributes = externalAttributes;
00457                                 
00458                                 entries[i] = entry;
00459                         }
00460                 }
00461                 
00469                 public void Close()
00470                 {
00471                         entries = null;
00472                         if ( isStreamOwner ) {
00473                                 lock(baseStream) {
00474                                         baseStream.Close();
00475                                 }
00476                         }
00477                 }
00478                 
00485                 public IEnumerator GetEnumerator()
00486                 {
00487                         if (entries == null) {
00488                                 throw new InvalidOperationException("ZipFile has closed");
00489                         }
00490                         
00491                         return new ZipEntryEnumeration(entries);
00492                 }
00493                 
00503                 public int FindEntry(string name, bool ignoreCase)
00504                 {
00505                         if (entries == null) {
00506                                 throw new InvalidOperationException("ZipFile has been closed");
00507                         }
00508                         
00509                         for (int i = 0; i < entries.Length; i++) {
00510                                 if (string.Compare(name, entries[i].Name, ignoreCase) == 0) {
00511                                         return i;
00512                                 }
00513                         }
00514                         return -1;
00515                 }
00516                 
00520                 [System.Runtime.CompilerServices.IndexerNameAttribute("EntryByIndex")]
00521                 public ZipEntry this[int index] {
00522                         get {
00523                                 return (ZipEntry) entries[index].Clone();       
00524                         }
00525                 }
00526                 
00540                 public ZipEntry GetEntry(string name)
00541                 {
00542                         if (entries == null) {
00543                                 throw new InvalidOperationException("ZipFile has been closed");
00544                         }
00545                         
00546                         int index = FindEntry(name, true);
00547                         return index >= 0 ? (ZipEntry) entries[index].Clone() : null;
00548                 }
00554                 public bool TestArchive(bool testData)
00555                 {
00556                         bool result = true;
00557                         try {
00558                                 for (int i = 0; i < Size; ++i) {
00559                                         long offset = TestLocalHeader(this[i], true, true);
00560                                         if (testData) {
00561                                                 Stream entryStream = this.GetInputStream(this[i]);
00562                                                 // TODO: events for updating info, recording errors etc
00563                                                 Crc32 crc = new Crc32();
00564                                                 byte[] buffer = new byte[4096];
00565                                                 int bytesRead;
00566                                                 while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0) {
00567                                                         crc.Update(buffer, 0, bytesRead);
00568                                                 }
00569         
00570                                                 if (this[i].Crc != crc.Value) {
00571                                                         result = false;
00572                                                         // TODO: Event here....
00573                                                         break; // Do all entries giving more info at some point?
00574                                                 }
00575                                         }
00576                                 }
00577                         }
00578                         catch {
00579                                 result = false;
00580                         }
00581                         return result;
00582                 }
00583         
00597                 long TestLocalHeader(ZipEntry entry, bool fullTest, bool extractTest)
00598                 {
00599                         lock(baseStream) 
00600                         {
00601                                 baseStream.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin);
00602                                 if (ReadLeInt() != ZipConstants.LOCSIG) {
00603                                         throw new ZipException("Wrong local header signature");
00604                                 }
00605                                 
00606                                 short shortValue = (short)ReadLeShort();         // version required to extract
00607                                 if (extractTest == true && shortValue > ZipConstants.VERSION_MADE_BY) {
00608                                         throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", shortValue));
00609                                 }
00610 
00611                                 short localFlags = (short)ReadLeShort();                                  // general purpose bit flags.
00612                                 if (extractTest == true) {
00613                                         if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0) {
00614                                                 throw new ZipException("The library doesnt support the zip version required to extract this entry");
00615                                         }
00616                                 }
00617                                         
00618                                 if (localFlags != entry.Flags) {
00619                                    throw new ZipException("Central header/local header flags mismatch");
00620                                 }
00621 
00622                                 if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) {
00623                                    throw new ZipException("Central header/local header compression method mismatch");
00624                                 }
00625         
00626                                 shortValue = (short)ReadLeShort();  // file time
00627                                 shortValue = (short)ReadLeShort();  // file date
00628         
00629                                 int intValue = ReadLeInt();         // Crc
00630         
00631                                 if (fullTest) {
00632                                         if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) {
00633                                                 if (intValue != (int)entry.Crc) 
00634                                                         throw new ZipException("Central header/local header crc mismatch");
00635                                         }
00636                                 }
00637         
00638                                 intValue = ReadLeInt();    // compressed Size
00639                                 intValue = ReadLeInt();    // uncompressed size
00640         
00641                                 // TODO: make test more correct...  can't compare lengths as was done originally as this can fail for MBCS strings
00642                                 // Assuming a code page at this point is not valid?  Best is to store the name length in the ZipEntry probably
00643                                 int storedNameLength = ReadLeShort();
00644                                 if (entry.Name.Length > storedNameLength) {
00645                                         throw new ZipException("file name length mismatch");
00646                                 }
00647                                         
00648                                 int extraLen = storedNameLength + ReadLeShort();
00649                                 return offsetOfFirstEntry + entry.Offset + ZipConstants.LOCHDR + extraLen;
00650                         }
00651                 }
00652                 
00667                 long CheckLocalHeader(ZipEntry entry)
00668                 {
00669                         return TestLocalHeader(entry, false, true);
00670                 }
00671                 
00672                 // Refactor this, its done elsewhere as well
00673                 void ReadFully(Stream s, byte[] outBuf)
00674                 {
00675                         int off = 0;
00676                         int len = outBuf.Length;
00677                         while (len > 0) {
00678                                 int count = s.Read(outBuf, off, len);
00679                                 if (count <= 0) {
00680                                         throw new ZipException("Unexpected EOF"); 
00681                                 }
00682                                 off += count;
00683                                 len -= count;
00684                         }
00685                 }
00686 
00687                 void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry)
00688                 {
00689                         byte[] cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
00690                         ReadFully(classicCryptoStream, cryptbuffer);
00691 
00692                         if ((entry.Flags & (int)GeneralBitFlags.Descriptor) == 0) {
00693                                 if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(entry.Crc >> 24)) {
00694                                         throw new ZipException("Invalid password");
00695                                 }
00696                         }
00697                         else {
00698                                 if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((entry.DosTime >> 8) & 0xff)) {
00699                                         throw new ZipException("Invalid password");
00700                                 }
00701                         }
00702                 }
00703 
00704                 Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry)
00705                 {
00706                         CryptoStream result = null;
00707 
00708                         if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION 
00709                                 || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
00710                                 PkzipClassicManaged classicManaged = new PkzipClassicManaged();
00711 
00712                                 OnKeysRequired(entry.Name);
00713                                 if (HaveKeys == false) {
00714                                         throw new ZipException("No password available for encrypted stream");
00715                                 }
00716 
00717                                 result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, iv), CryptoStreamMode.Read);
00718                                 CheckClassicPassword(result, entry);
00719                         }
00720                         else {
00721                                 throw new ZipException("Decryption method not supported");
00722                         }
00723 
00724                         return result;
00725                 }
00726 
00727                 void WriteEncryptionHeader(Stream stream, long crcValue)
00728                 {
00729                         byte[] cryptBuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE];
00730                         Random rnd = new Random();
00731                         rnd.NextBytes(cryptBuffer);
00732                         cryptBuffer[11] = (byte)(crcValue >> 24);
00733                         stream.Write(cryptBuffer, 0, cryptBuffer.Length);
00734                 }
00735 
00736                 Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry)
00737                 {
00738                         CryptoStream result = null;
00739                         if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION 
00740                             || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) {
00741                                 PkzipClassicManaged classicManaged = new PkzipClassicManaged();
00742 
00743                                 OnKeysRequired(entry.Name);
00744                                 if (HaveKeys == false) {
00745                                         throw new ZipException("No password available for encrypted stream");
00746                                 }
00747 
00748                                 result = new CryptoStream(baseStream, classicManaged.CreateEncryptor(key, iv), CryptoStreamMode.Write);
00749                                 if (entry.Crc < 0 || (entry.Flags & 8) != 0) {
00750                                         WriteEncryptionHeader(result, entry.DosTime << 16);
00751                                 }
00752                                 else {
00753                                         WriteEncryptionHeader(result, entry.Crc);
00754                                 }
00755                         }
00756                         return result;
00757                 }
00758 
00765                 Stream GetOutputStream(ZipEntry entry, string fileName)
00766                 {
00767                         baseStream.Seek(0, SeekOrigin.End);
00768                         Stream result = File.OpenWrite(fileName);
00769                 
00770                         if (entry.IsCrypted == true)
00771                         {
00772                                 result = CreateAndInitEncryptionStream(result, entry);
00773                         }
00774                 
00775                         switch (entry.CompressionMethod) 
00776                         {
00777                                 case CompressionMethod.Stored:
00778                                         break;
00779                 
00780                                 case CompressionMethod.Deflated:
00781                                         result = new DeflaterOutputStream(result);
00782                                         break;
00783                                         
00784                                 default:
00785                                         throw new ZipException("Unknown compression method " + entry.CompressionMethod);
00786                         }
00787                         return result;
00788                 }
00789 
00807                 public Stream GetInputStream(ZipEntry entry)
00808                 {
00809                         if (entries == null) {
00810                                 throw new InvalidOperationException("ZipFile has closed");
00811                         }
00812                         
00813                         int index = entry.ZipFileIndex;
00814                         if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) {
00815                                 index = FindEntry(entry.Name, true);
00816                                 if (index < 0) {
00817                                         throw new IndexOutOfRangeException();
00818                                 }
00819                         }
00820                         return GetInputStream(index);                   
00821                 }
00822                 
00839                 public Stream GetInputStream(int entryIndex)
00840                 {
00841                         if (entries == null) {
00842                                 throw new InvalidOperationException("ZipFile has closed");
00843                         }
00844                         
00845                         long start = CheckLocalHeader(entries[entryIndex]);
00846                         CompressionMethod method = entries[entryIndex].CompressionMethod;
00847                         Stream istr = new PartialInputStream(baseStream, start, entries[entryIndex].CompressedSize);
00848 
00849                         if (entries[entryIndex].IsCrypted == true) {
00850                                 istr = CreateAndInitDecryptionStream(istr, entries[entryIndex]);
00851                                 if (istr == null) {
00852                                         throw new ZipException("Unable to decrypt this entry");
00853                                 }
00854                         }
00855 
00856                         switch (method) {
00857                                 case CompressionMethod.Stored:
00858                                         return istr;
00859                                 case CompressionMethod.Deflated:
00860                                         return new InflaterInputStream(istr, new Inflater(true));
00861                                 default:
00862                                         throw new ZipException("Unsupported compression method " + method);
00863                         }
00864                 }
00865 
00866                 
00870                 public string ZipFileComment {
00871                         get {
00872                                 return comment;
00873                         }
00874                 }
00875                 
00879                 public string Name {
00880                         get {
00881                                 return name;
00882                         }
00883                 }
00884                 
00891                 public int Size {
00892                         get {
00893                                 if (entries != null) {
00894                                         return entries.Length;
00895                                 } else {
00896                                         throw new InvalidOperationException("ZipFile is closed");
00897                                 }
00898                         }
00899                 }
00900                 
00901                 class ZipEntryEnumeration : IEnumerator
00902                 {
00903                         ZipEntry[] array;
00904                         int ptr = -1;
00905                         
00906                         public ZipEntryEnumeration(ZipEntry[] arr)
00907                         {
00908                                 array = arr;
00909                         }
00910                         
00911                         public object Current {
00912                                 get {
00913                                         return array[ptr];
00914                                 }
00915                         }
00916                         
00917                         public void Reset()
00918                         {
00919                                 ptr = -1;
00920                         }
00921                         
00922                         public bool MoveNext() 
00923                         {
00924                                 return (++ptr < array.Length);
00925                         }
00926                 }
00927                 
00928                 class PartialInputStream : InflaterInputStream
00929                 {
00930                         Stream baseStream;
00931                         long filepos, end;
00932                         
00933                         public PartialInputStream(Stream baseStream, long start, long len) : base(baseStream)
00934                         {
00935                                 this.baseStream = baseStream;
00936                                 filepos = start;
00937                                 end = start + len;
00938                         }
00939                         
00940                         public override int Available 
00941                         {
00942                                 get {
00943                                         long amount = end - filepos;
00944                                         if (amount > Int32.MaxValue) {
00945                                                 return Int32.MaxValue;
00946                                         }
00947                                         
00948                                         return (int) amount;
00949                                 }
00950                         }
00951 
00956                         public override int ReadByte()
00957                         {
00958                                 if (filepos == end) {
00959                                         return -1; //ok
00960                                 }
00961                                 
00962                                 lock(baseStream) {
00963                                         baseStream.Seek(filepos++, SeekOrigin.Begin);
00964                                         return baseStream.ReadByte();
00965                                 }
00966                         }
00967                         
00968 
00975                         public override void Close()
00976                         {
00977                                 // Do nothing at all!
00978                         }
00979                         
00980                         public override int Read(byte[] b, int off, int len)
00981                         {
00982                                 if (len > end - filepos) {
00983                                         len = (int) (end - filepos);
00984                                         if (len == 0) {
00985                                                 return 0;
00986                                         }
00987                                 }
00988                                 
00989                                 lock(baseStream) {
00990                                         baseStream.Seek(filepos, SeekOrigin.Begin);
00991                                         int count = baseStream.Read(b, off, len);
00992                                         if (count > 0) {
00993                                                 filepos += len;
00994                                         }
00995                                         return count;
00996                                 }
00997                         }
00998                         
00999                         public long SkipBytes(long amount)
01000                         {
01001                                 if (amount < 0) {
01002                                         throw new ArgumentOutOfRangeException();
01003                                 }
01004                                 if (amount > end - filepos) {
01005                                         amount = end - filepos;
01006                                 }
01007                                 filepos += amount;
01008                                 return amount;
01009                         }
01010                 }
01011         }
01012 }

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