//bool _isRoot; protected internal ZipHelperEntry(ZipHelper owner, string path) { _owner = owner; _path = path; if (path == "/" || path == "") { _zipEntry = null; //_isRoot = true; _name = "<root>"; } else { _zipEntry = _owner.GetZipEntry(_path); _name = _owner.ExtractName(_path); } }
/// <summary> /// Checks, if the local header of the entry at index i matches the /// central directory, and returns the offset to the data. /// </summary> /// <returns> /// The start offset of the (compressed) data. /// </returns> /// <exception cref="System.IO.EndOfStreamException"> /// The stream ends prematurely /// </exception> /// <exception cref="Fireball.IO.Compression.Zip.ZipException"> /// The local header signature is invalid, the entry and central header file name lengths are different /// or the local and entry compression methods dont match /// </exception> long CheckLocalHeader(ZipEntry entry) { return TestLocalHeader(entry, false, true); }
/// <summary> /// Test the local header against that provided from the central directory /// </summary> /// <param name="entry"> /// The entry to test against /// </param> /// <param name="fullTest"> /// If true be extremely picky about the testing, otherwise be relaxed /// </param> /// <param name="extractTest"> /// Apply extra testing to see if the entry can be extracted by the library /// </param> /// <returns>The offset of the entries data in the file</returns> long TestLocalHeader(ZipEntry entry, bool fullTest, bool extractTest) { lock(baseStream) { baseStream.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if (ReadLeInt() != ZipConstants.LOCSIG) { throw new ZipException("Wrong local header signature"); } short shortValue = (short)ReadLeShort(); // version required to extract if (extractTest == true && shortValue > ZipConstants.VERSION_MADE_BY) { throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", shortValue)); } short localFlags = (short)ReadLeShort(); // general purpose bit flags. if (extractTest == true) { if ((localFlags & (int)(GeneralBitFlags.Patched | GeneralBitFlags.StrongEncryption | GeneralBitFlags.EnhancedCompress | GeneralBitFlags.HeaderMasked)) != 0) { throw new ZipException("The library doesnt support the zip version required to extract this entry"); } } if (localFlags != entry.Flags) { throw new ZipException("Central header/local header flags mismatch"); } if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) { throw new ZipException("Central header/local header compression method mismatch"); } shortValue = (short)ReadLeShort(); // file time shortValue = (short)ReadLeShort(); // file date int intValue = ReadLeInt(); // Crc if (fullTest) { if ((localFlags & (int)GeneralBitFlags.Descriptor) == 0) { if (intValue != (int)entry.Crc) throw new ZipException("Central header/local header crc mismatch"); } } intValue = ReadLeInt(); // compressed Size intValue = ReadLeInt(); // uncompressed size // TODO: make test more correct... can't compare lengths as was done originally as this can fail for MBCS strings // Assuming a code page at this point is not valid? Best is to store the name length in the ZipEntry probably int storedNameLength = ReadLeShort(); if (entry.Name.Length > storedNameLength) { throw new ZipException("file name length mismatch"); } int extraLen = storedNameLength + ReadLeShort(); return offsetOfFirstEntry + entry.Offset + ZipConstants.LOCHDR + extraLen; } }
/// <summary> /// Search for and read the central directory of a zip file filling the entries /// array. This is called exactly once by the constructors. /// </summary> /// <exception cref="System.IO.IOException"> /// An i/o error occurs. /// </exception> /// <exception cref="Fireball.IO.Compression.Zip.ZipException"> /// The central directory is malformed or cannot be found /// </exception> void ReadEntries() { // Search for the End Of Central Directory. When a zip comment is // present the directory may start earlier. // // TODO: The search is limited to 64K which is the maximum size of a trailing comment field to aid speed. // This should be compatible with both SFX and ZIP files but has only been tested for Zip files // Need to confirm this is valid in all cases. // Could also speed this up by reading memory in larger blocks. if (baseStream.CanSeek == false) { throw new ZipException("ZipFile stream must be seekable"); } long locatedCentralDirOffset = LocateBlockWithSignature(ZipConstants.ENDSIG, baseStream.Length, ZipConstants.ENDHDR, 0xffff); if (locatedCentralDirOffset < 0) { throw new ZipException("Cannot find central directory"); } int thisDiskNumber = ReadLeShort(); int startCentralDirDisk = ReadLeShort(); int entriesForThisDisk = ReadLeShort(); int entriesForWholeCentralDir = ReadLeShort(); int centralDirSize = ReadLeInt(); int offsetOfCentralDir = ReadLeInt(); int commentSize = ReadLeShort(); byte[] zipComment = new byte[commentSize]; baseStream.Read(zipComment, 0, zipComment.Length); comment = ZipConstants.ConvertToString(zipComment); /* Its seems possible that this is too strict, more digging required. if (thisDiskNumber != 0 || startCentralDirDisk != 0 || entriesForThisDisk != entriesForWholeCentralDir) { throw new ZipException("Spanned archives are not currently handled"); } */ entries = new ZipEntry[entriesForWholeCentralDir]; // SFX support, find the offset of the first entry vis the start of the stream // This applies to Zip files that are appended to the end of the SFX stub. // Zip files created by some archivers have the offsets altered to reflect the true offsets // and so dont require any adjustment here... if (offsetOfCentralDir < locatedCentralDirOffset - (4 + centralDirSize)) { offsetOfFirstEntry = locatedCentralDirOffset - (4 + centralDirSize + offsetOfCentralDir); if (offsetOfFirstEntry <= 0) { throw new ZipException("Invalid SFX file"); } } baseStream.Seek(offsetOfFirstEntry + offsetOfCentralDir, SeekOrigin.Begin); for (int i = 0; i < entriesForThisDisk; i++) { if (ReadLeInt() != ZipConstants.CENSIG) { throw new ZipException("Wrong Central Directory signature"); } int versionMadeBy = ReadLeShort(); int versionToExtract = ReadLeShort(); int bitFlags = ReadLeShort(); int method = ReadLeShort(); int dostime = ReadLeInt(); int crc = ReadLeInt(); int csize = ReadLeInt(); int size = ReadLeInt(); int nameLen = ReadLeShort(); int extraLen = ReadLeShort(); int commentLen = ReadLeShort(); int diskStartNo = ReadLeShort(); // Not currently used int internalAttributes = ReadLeShort(); // Not currently used int externalAttributes = ReadLeInt(); int offset = ReadLeInt(); byte[] buffer = new byte[Math.Max(nameLen, commentLen)]; baseStream.Read(buffer, 0, nameLen); string name = ZipConstants.ConvertToString(buffer, nameLen); ZipEntry entry = new ZipEntry(name, versionToExtract, versionMadeBy); entry.CompressionMethod = (CompressionMethod)method; entry.Crc = crc & 0xffffffffL; entry.Size = size & 0xffffffffL; entry.CompressedSize = csize & 0xffffffffL; entry.Flags = bitFlags; entry.DosTime = (uint)dostime; if (extraLen > 0) { byte[] extra = new byte[extraLen]; baseStream.Read(extra, 0, extraLen); entry.ExtraData = extra; } if (commentLen > 0) { baseStream.Read(buffer, 0, commentLen); entry.Comment = ZipConstants.ConvertToString(buffer, commentLen); } entry.ZipFileIndex = i; entry.Offset = offset; entry.ExternalFileAttributes = externalAttributes; entries[i] = entry; } }
/// <summary> /// Closes the zip input stream /// </summary> public override void Close() { base.Close(); crc = null; entry = null; }
void ProcessDirectory(object sender, DirectoryEventArgs e) { if ( !e.HasMatchingFiles && createEmptyDirectories ) { if ( events != null ) { events.OnProcessDirectory(e.Name, e.HasMatchingFiles); } if (e.Name != sourceDirectory) { string cleanedName = nameTransform.TransformDirectory(e.Name); ZipEntry entry = new ZipEntry(cleanedName); outputStream.PutNextEntry(entry); } } }
/// <summary> /// Creates an input stream reading the given zip entry as /// uncompressed data. Normally zip entry should be an entry /// returned by GetEntry(). /// </summary> /// <returns> /// the input stream. /// </returns> /// <exception cref="InvalidOperationException"> /// The ZipFile has already been closed /// </exception> /// <exception cref="Fireball.IO.Compression.Zip.ZipException"> /// The compression method for the entry is unknown /// </exception> /// <exception cref="IndexOutOfRangeException"> /// The entry is not found in the ZipFile /// </exception> public Stream GetInputStream(ZipEntry entry) { if (entries == null) { throw new InvalidOperationException("ZipFile has closed"); } int index = entry.ZipFileIndex; if (index < 0 || index >= entries.Length || entries[index].Name != entry.Name) { index = FindEntry(entry.Name, true); if (index < 0) { throw new IndexOutOfRangeException(); } } return GetInputStream(index); }
Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry) { CryptoStream result = null; if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) { PkzipClassicManaged classicManaged = new PkzipClassicManaged(); OnKeysRequired(entry.Name); if (HaveKeys == false) { throw new ZipException("No password available for encrypted stream"); } result = new CryptoStream(baseStream, classicManaged.CreateEncryptor(key, iv), CryptoStreamMode.Write); if (entry.Crc < 0 || (entry.Flags & 8) != 0) { WriteEncryptionHeader(result, entry.DosTime << 16); } else { WriteEncryptionHeader(result, entry.Crc); } } return result; }
/// <summary> /// Closes the current entry, updating header and footer information as required /// </summary> /// <exception cref="System.IO.IOException"> /// An I/O error occurs. /// </exception> /// <exception cref="System.InvalidOperationException"> /// No entry is active. /// </exception> public void CloseEntry() { if (curEntry == null) { throw new InvalidOperationException("No open entry"); } // First finish the deflater, if appropriate if (curMethod == CompressionMethod.Deflated) { base.Finish(); } long csize = curMethod == CompressionMethod.Deflated ? def.TotalOut : size; if (curEntry.Size < 0) { curEntry.Size = size; } else if (curEntry.Size != size) { throw new ZipException("size was " + size + ", but I expected " + curEntry.Size); } if (curEntry.CompressedSize < 0) { curEntry.CompressedSize = csize; } else if (curEntry.CompressedSize != csize) { throw new ZipException("compressed size was " + csize + ", but I expected " + curEntry.CompressedSize); } if (curEntry.Crc < 0) { curEntry.Crc = crc.Value; } else if (curEntry.Crc != crc.Value) { throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc); } offset += csize; if (offset > 0xffffffff) { throw new ZipException("Maximum Zip file size exceeded"); } if (curEntry.IsCrypted == true) { curEntry.CompressedSize += ZipConstants.CRYPTO_HEADER_SIZE; } // Patch the header if possible if (patchEntryHeader == true) { long curPos = baseOutputStream.Position; baseOutputStream.Seek(headerPatchPos, SeekOrigin.Begin); WriteLeInt((int)curEntry.Crc); WriteLeInt((int)curEntry.CompressedSize); WriteLeInt((int)curEntry.Size); baseOutputStream.Seek(curPos, SeekOrigin.Begin); patchEntryHeader = false; } // Add data descriptor if flagged as required if ((curEntry.Flags & 8) != 0) { WriteLeInt(ZipConstants.EXTSIG); WriteLeInt((int)curEntry.Crc); WriteLeInt((int)curEntry.CompressedSize); WriteLeInt((int)curEntry.Size); offset += ZipConstants.EXTHDR; } entries.Add(curEntry); curEntry = null; }
/// <summary> /// Starts a new Zip entry. It automatically closes the previous /// entry if present. /// All entry elements bar name are optional, but must be correct if present. /// If the compression method is stored and the output is not patchable /// the compression for that entry is automatically changed to deflate level 0 /// </summary> /// <param name="entry"> /// the entry. /// </param> /// <exception cref="System.IO.IOException"> /// if an I/O error occured. /// </exception> /// <exception cref="System.InvalidOperationException"> /// if stream was finished /// </exception> /// <exception cref="ZipException"> /// Too many entries in the Zip file<br/> /// Entry name is too long<br/> /// Finish has already been called<br/> /// </exception> public void PutNextEntry(ZipEntry entry) { if (entries == null) { throw new InvalidOperationException("ZipOutputStream was finished"); } if (curEntry != null) { CloseEntry(); } if (entries.Count >= 0xffff) { throw new ZipException("Too many entries for Zip file"); } CompressionMethod method = entry.CompressionMethod; int compressionLevel = defaultCompressionLevel; entry.Flags = 0; patchEntryHeader = false; bool headerInfoAvailable = true; if (method == CompressionMethod.Stored) { if (entry.CompressedSize >= 0) { if (entry.Size < 0) { entry.Size = entry.CompressedSize; } else if (entry.Size != entry.CompressedSize) { throw new ZipException("Method STORED, but compressed size != size"); } } else { if (entry.Size >= 0) { entry.CompressedSize = entry.Size; } } if (entry.Size < 0 || entry.Crc < 0) { if (CanPatchEntries == true) { headerInfoAvailable = false; } else { // Cant patch entries so storing is not possible. method = CompressionMethod.Deflated; compressionLevel = 0; } } } if (method == CompressionMethod.Deflated) { if (entry.Size == 0) { // No need to compress - no data. entry.CompressedSize = entry.Size; entry.Crc = 0; method = CompressionMethod.Stored; } else if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) { headerInfoAvailable = false; } } if (headerInfoAvailable == false) { if (CanPatchEntries == false) { entry.Flags |= 8; } else { patchEntryHeader = true; } } if (Password != null) { entry.IsCrypted = true; if (entry.Crc < 0) { // Need to append data descriptor as crc is used for encryption and its not known. entry.Flags |= 8; } } entry.Offset = (int)offset; entry.CompressionMethod = (CompressionMethod)method; curMethod = method; // Write the local file header WriteLeInt(ZipConstants.LOCSIG); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((byte)method); WriteLeInt((int)entry.DosTime); if (headerInfoAvailable == true) { WriteLeInt((int)entry.Crc); WriteLeInt(entry.IsCrypted ? (int)entry.CompressedSize + ZipConstants.CRYPTO_HEADER_SIZE : (int)entry.CompressedSize); WriteLeInt((int)entry.Size); } else { if (patchEntryHeader == true) { headerPatchPos = baseOutputStream.Position; } WriteLeInt(0); // Crc WriteLeInt(0); // Compressed size WriteLeInt(0); // Uncompressed size } byte[] name = ZipConstants.ConvertToArray(entry.Name); if (name.Length > 0xFFFF) { throw new ZipException("Entry name too long."); } byte[] extra = entry.ExtraData; if (extra == null) { extra = new byte[0]; } if (extra.Length > 0xFFFF) { throw new ZipException("Extra data too long."); } WriteLeShort(name.Length); WriteLeShort(extra.Length); baseOutputStream.Write(name, 0, name.Length); baseOutputStream.Write(extra, 0, extra.Length); offset += ZipConstants.LOCHDR + name.Length + extra.Length; // Activate the entry. curEntry = entry; crc.Reset(); if (method == CompressionMethod.Deflated) { def.Reset(); def.SetLevel(compressionLevel); } size = 0; if (entry.IsCrypted == true) { if (entry.Crc < 0) { // so testing Zip will says its ok WriteEncryptionHeader(entry.DosTime << 16); } else { WriteEncryptionHeader(entry.Crc); } } }
/// <summary> /// Creates a copy of the given zip entry. /// </summary> /// <param name="e"> /// The entry to copy. /// </param> public ZipEntry(ZipEntry e) { known = e.known; name = e.name; size = e.size; compressedSize = e.compressedSize; crc = e.crc; dosTime = e.dosTime; method = e.method; ExtraData = e.ExtraData; // Note use of property ensuring data is unique comment = e.comment; versionToExtract = e.versionToExtract; versionMadeBy = e.versionMadeBy; externalFileAttributes = e.externalFileAttributes; flags = e.flags; zipFileIndex = -1; offset = 0; }
void ExtractEntry(ZipEntry entry) { bool doExtraction = NameIsValid(entry.Name); string dirName = null; string targetName = null; if ( doExtraction ) { string entryFileName; if (Path.IsPathRooted(entry.Name)) { string workName = Path.GetPathRoot(entry.Name); workName = entry.Name.Substring(workName.Length); entryFileName = Path.Combine(Path.GetDirectoryName(workName), Path.GetFileName(entry.Name)); } else { entryFileName = entry.Name; } targetName = Path.Combine(targetDirectory, entryFileName); dirName = Path.GetDirectoryName(Path.GetFullPath(targetName)); doExtraction = doExtraction && (entryFileName.Length > 0); } if ( doExtraction && !Directory.Exists(dirName) ) { if ( !entry.IsDirectory || this.CreateEmptyDirectories ) { try { Directory.CreateDirectory(dirName); } catch { doExtraction = false; } } } if ( doExtraction && entry.IsFile ) { ExtractFileEntry(entry, targetName); } }
void ExtractFileEntry(ZipEntry entry, string targetName) { bool proceed = true; if ((overwrite == Overwrite.Prompt) && (confirmDelegate != null)) { if (File.Exists(targetName) == true) { proceed = confirmDelegate(targetName); } } if ( proceed ) { if ( events != null ) { events.OnProcessFile(entry.Name); } FileStream streamWriter = File.Create(targetName); try { if ( buffer == null ) { buffer = new byte[4096]; } int size; do { size = inputStream.Read(buffer, 0, buffer.Length); streamWriter.Write(buffer, 0, size); } while (size > 0); } finally { streamWriter.Close(); } if (restoreDateTime) { File.SetLastWriteTime(targetName, entry.DateTime); } } }
void ProcessFile(object sender, ScanEventArgs e) { if ( events != null ) { events.OnProcessFile(e.Name); } string cleanedName = nameTransform.TransformFile(e.Name); ZipEntry entry = new ZipEntry(cleanedName); outputStream.PutNextEntry(entry); AddFileContents(e.Name); }
void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry) { byte[] cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE]; ReadFully(classicCryptoStream, cryptbuffer); if ((entry.Flags & (int)GeneralBitFlags.Descriptor) == 0) { if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(entry.Crc >> 24)) { throw new ZipException("Invalid password"); } } else { if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((entry.DosTime >> 8) & 0xff)) { throw new ZipException("Invalid password"); } } }
Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry) { CryptoStream result = null; if (entry.Version < ZipConstants.VERSION_STRONG_ENCRYPTION || (entry.Flags & (int)GeneralBitFlags.StrongEncryption) == 0) { PkzipClassicManaged classicManaged = new PkzipClassicManaged(); OnKeysRequired(entry.Name); if (HaveKeys == false) { throw new ZipException("No password available for encrypted stream"); } result = new CryptoStream(baseStream, classicManaged.CreateDecryptor(key, iv), CryptoStreamMode.Read); CheckClassicPassword(result, entry); } else { throw new ZipException("Decryption method not supported"); } return result; }
/// <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.CENSIG || header == ZipConstants.ENDSIG || header == ZipConstants.CENDIGITALSIG || header == ZipConstants.CENSIG64) { // No more individual entries exist Close(); return null; } // -jr- 07-Dec-2003 Ignore spanning temporary signatures if found // SPANNINGSIG is same as descriptor signature and is untested as yet. if (header == ZipConstants.SPANTEMPSIG || header == ZipConstants.SPANNINGSIG) { header = inputBuffer.ReadLeInt(); } if (header != ZipConstants.LOCSIG) { 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.ConvertToString(buffer); entry = new ZipEntry(name, versionRequiredToExtract); entry.Flags = flags; if (method == (int)CompressionMethod.Stored && (!isCrypted && csize != size || (isCrypted && csize - ZipConstants.CRYPTO_HEADER_SIZE != size))) { throw new ZipException("Stored, but compressed != uncompressed"); } if (method != (int)CompressionMethod.Stored && method != (int)CompressionMethod.Deflated) { throw new ZipException("Unknown compression method " + method); } entry.CompressionMethod = (CompressionMethod)method; if ((flags & 8) == 0) { entry.Crc = crc2 & 0xFFFFFFFFL; entry.Size = size & 0xFFFFFFFFL; entry.CompressedSize = csize & 0xFFFFFFFFL; } else { // This allows for GNU, WinZip and possibly other archives, the PKZIP spec says these 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.DosTime = dostime; if (extraLen > 0) { byte[] extra = new byte[extraLen]; inputBuffer.ReadRawBuffer(extra); entry.ExtraData = extra; } internalReader = new ReaderDelegate(InitialRead); return entry; }
/// <summary> /// Gets an output stream for the specified <see cref="ZipEntry"/> /// </summary> /// <param name="entry">The entry to get an outputstream for.</param> /// <param name="fileName"></param> /// <returns>The output stream obtained for the entry.</returns> Stream GetOutputStream(ZipEntry entry, string fileName) { baseStream.Seek(0, SeekOrigin.End); Stream result = File.OpenWrite(fileName); if (entry.IsCrypted == true) { result = CreateAndInitEncryptionStream(result, entry); } switch (entry.CompressionMethod) { case CompressionMethod.Stored: break; case CompressionMethod.Deflated: result = new DeflaterOutputStream(result); break; default: throw new ZipException("Unknown compression method " + entry.CompressionMethod); } return result; }
/// <summary> /// Closes the current zip entry and moves to the next one. /// </summary> /// <exception cref="InvalidOperationException"> /// The stream is closed /// </exception> /// <exception cref="ZipException"> /// The Zip stream ends early /// </exception> public void CloseEntry() { if (crc == null) { throw new InvalidOperationException("Closed."); } if (entry == null) { return; } if (method == (int)CompressionMethod.Deflated) { if ((flags & 8) != 0) { // We don't know how much we must skip, read until end. byte[] tmp = new byte[2048]; while (Read(tmp, 0, tmp.Length) > 0) ; // read will close this entry return; } csize -= inf.TotalIn; inputBuffer.Available -= inf.RemainingInput; } if (inputBuffer.Available > csize && csize >= 0) { inputBuffer.Available = (int)((long)inputBuffer.Available - csize); } else { csize -= inputBuffer.Available; inputBuffer.Available = 0; while (csize != 0) { int skipped = (int)base.Skip(csize & 0xFFFFFFFFL); if (skipped <= 0) { throw new ZipException("Zip archive ends early."); } csize -= skipped; } } size = 0; crc.Reset(); if (method == (int)CompressionMethod.Deflated) { inf.Reset(); } entry = null; }
public ZipEntryEnumeration(ZipEntry[] arr) { array = arr; }
/// <summary> /// Reads a block of bytes from the current zip entry. /// </summary> /// <returns> /// The number of bytes read (this may be less than the length requested, even before the end of stream), or 0 on end of stream. /// </returns> /// <exception name="IOException"> /// An i/o error occured. /// </exception> /// <exception cref="ZipException"> /// The deflated stream is corrupted. /// </exception> /// <exception cref="InvalidOperationException"> /// The stream is not open. /// </exception> public int BodyRead(byte[] b, int off, int len) { if (crc == null) { throw new InvalidOperationException("Closed."); } if (entry == null || len <= 0 ) { return 0; } bool finished = false; switch (method) { case (int)CompressionMethod.Deflated: len = base.Read(b, off, len); if (len <= 0) { if (!inf.IsFinished) { throw new ZipException("Inflater not finished!?"); } inputBuffer.Available = inf.RemainingInput; if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) { throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut); } inf.Reset(); finished = true; } break; case (int)CompressionMethod.Stored: if (len > csize && csize >= 0) { len = (int)csize; } len = inputBuffer.ReadClearTextBuffer(b, off, len); if (len > 0) { csize -= len; size -= len; } if (csize == 0) { finished = true; } else { if (len < 0) { throw new ZipException("EOF in stored block"); } } break; } if (len > 0) { crc.Update(b, off, len); } if (finished) { StopDecrypting(); if ((flags & 8) != 0) { ReadDataDescriptor(); } if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) { throw new ZipException("CRC mismatch"); } crc.Reset(); entry = null; } return len; }