/// <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 { method = CompressionMethod.Deflated; compressionLevel = 0; } } } if (method == CompressionMethod.Deflated) { if (entry.Size == 0) { 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) { 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; }
/// <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> /// 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(); } if (this.cryptbuffer != null) { if (avail == 0 && inf.RemainingInput != 0) { avail = inf.RemainingInput - 16; inf.Reset(); } baseInputStream.Position -= this.len; baseInputStream.Read(this.buf, 0, this.len); } if (avail <= 0) { FillBuf(ZipConstants.LOCHDR); } int header = 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 = ReadLeInt(); } if (header != ZipConstants.LOCSIG) { throw new ZipException("Wrong Local header signature: 0x" + String.Format("{0:X}", header)); } short versionRequiredToExtract = (short)ReadLeShort(); flags = ReadLeShort(); method = ReadLeShort(); uint dostime = (uint)ReadLeInt(); int crc2 = ReadLeInt(); csize = ReadLeInt(); size = ReadLeInt(); int nameLen = ReadLeShort(); int extraLen = ReadLeShort(); bool isCrypted = (flags & 1) == 1; byte[] buffer = new byte[nameLen]; ReadFully(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; BufferReadSize = 0; } else { if (isCrypted) { BufferReadSize = 1; } else { BufferReadSize = 0; } // 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]; ReadFully(extra); entry.ExtraData = extra; } // TODO How to handle this? // This library cannot handle versions greater than 20 // Throwing an exception precludes getting at later possibly useable entries. // Could also skip this entry entirely // Letting it slip past here isnt so great as it wont work if (versionRequiredToExtract > 20) { throw new ZipException("Libray cannot extract this entry version required (" + versionRequiredToExtract.ToString() + ")"); } // test for encryption if (isCrypted) { if (password == null) { throw new ZipException("No password set."); } InitializePassword(password); cryptbuffer = new byte[ZipConstants.CRYPTO_HEADER_SIZE]; ReadFully(cryptbuffer); DecryptBlock(cryptbuffer, 0, cryptbuffer.Length); if ((flags & 8) == 0) { if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)(crc2 >> 24)) { throw new ZipException("Invalid password"); } } else { if (cryptbuffer[ZipConstants.CRYPTO_HEADER_SIZE - 1] != (byte)((dostime >> 8) & 0xff)) { throw new ZipException("Invalid password"); } } if (csize >= ZipConstants.CRYPTO_HEADER_SIZE) { csize -= ZipConstants.CRYPTO_HEADER_SIZE; } } else { cryptbuffer = null; } if (method == (int)CompressionMethod.Deflated && avail > 0) { System.Array.Copy(buf, len - (int)avail, buf, 0, (int)avail); len = (int)avail; avail = 0; if (isCrypted) { DecryptBlock(buf, 0, Math.Min((int)csize, len)); } inf.SetInput(buf, 0, len); } return entry; }
/// <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 override int Read(byte[] b, int off, int len) { if (crc == null) { throw new InvalidOperationException("Closed."); } if (entry == null) { 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!?"); } avail = 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 = ReadBuf(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"); } } // cipher text needs decrypting if (cryptbuffer != null) { DecryptBlock(b, off, len); } 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; }
/// <summary> /// Closes the zip input stream /// </summary> public override void Close() { base.Close(); crc = null; entry = null; }
/// <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; avail = inf.RemainingInput; } if (avail > csize && csize >= 0) { avail -= csize; } else { csize -= avail; avail = 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> /// Zips and compresses files. /// You should give the full path for the zipFileName. /// You should give the full path for the rootDirectoryName. /// You should give relative path for the names of the files to zip. Relative to the root /// Example: ZipCompressUtility.TryZipAndCompressFiles( "C:\Aucent\Folio1.zip", /// "C:\DirectoryWithHtmlFiles\Folio1", /// new string[]{"index.html", "DependentHoppers\hopper.html"} ); /// </summary> /// <param name="zipFileName">Set to the name that you want the zip file to be. (e.g. C:\Aucent\SalesFolio.zip)</param> /// <param name="rootDirectoryName">The root directory to start looking for files and directories in.</param> /// <param name="filesToZip">List of all the files you want to zip.</param> /// <returns></returns> public static bool TryZipAndCompressFiles(string zipFileName, string rootDirectoryName, string[] filesToZip) { bool ok = false; using (ZipOutputStream s = new ZipOutputStream(File.Create(zipFileName))) { try { if (rootDirectoryName[rootDirectoryName.Length - 1] != Path.DirectorySeparatorChar) { // append directory separator char rootDirectoryName += Path.DirectorySeparatorChar; } s.SetLevel(9); // 0 - store only to 9 - means best compression if (filesToZip != null) { foreach (string file in filesToZip) { byte[] buffer = FileUtilities.ReadFileToByteArray(rootDirectoryName + file); if (buffer != null) { ZipEntry entry = new ZipEntry(file); s.PutNextEntry(entry); s.Write(buffer, 0, buffer.Length); } } } ok = true; } catch { ok = false; } } return ok; }
/// <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="Aucent.MAX.AXE.Common.ZipCompressDecompress.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 pos = baseStream.Length - ZipConstants.ENDHDR; if (pos <= 0) { throw new ZipException("File is too small to be a Zip file"); } long giveUpMarker = Math.Max(pos - 0x10000, 0); do { if (pos < giveUpMarker) { throw new ZipException("central directory not found, probably not a zip file"); } baseStream.Seek(pos--, SeekOrigin.Begin); } while (ReadLeInt() != ZipConstants.ENDSIG); 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]; baseStream.Seek(offsetOfCentralDir, SeekOrigin.Begin); for (int i = 0; i < entriesForWholeCentralDir; 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> /// 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="Aucent.MAX.AXE.Common.ZipCompressDecompress.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) { lock(baseStream) { baseStream.Seek(entry.Offset, SeekOrigin.Begin); if (ReadLeInt() != ZipConstants.LOCSIG) { throw new ZipException("Wrong Local header signature"); } short shortValue = (short)ReadLeShort(); // version required to extract if (shortValue > ZipConstants.VERSION_MADE_BY) { throw new ZipException(string.Format("Version required to extract this entry not supported ({0})", shortValue)); } shortValue = (short)ReadLeShort(); // general purpose bit flags. if ((shortValue & 0x30) != 0) { throw new ZipException("The library doesnt support the zip version required to extract this entry"); } if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) { throw new ZipException("Compression method mismatch"); } // Skip time, crc, size and csize long oldPos = baseStream.Position; baseStream.Position += ZipConstants.LOCNAM - ZipConstants.LOCTIM; if (baseStream.Position - oldPos != ZipConstants.LOCNAM - ZipConstants.LOCTIM) { throw new ZipException("End of stream"); } // TODO make test more correct... cant compare lengths as was done originally as this can fail for MBCS strings int storedNameLength = ReadLeShort(); if (entry.Name.Length > storedNameLength) { throw new ZipException("file name length mismatch"); } int extraLen = storedNameLength + ReadLeShort(); return entry.Offset + ZipConstants.LOCHDR + extraLen; } }
/// <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="Aucent.MAX.AXE.Common.ZipCompressDecompress.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); }
/// <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="Aucent.MAX.AXE.Common.ZipCompressDecompress.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 pos = baseStream.Length - ZipConstants.ENDHDR; if (pos <= 0) { throw new ZipException("File is too small to be a Zip file"); } long giveUpMarker = Math.Max(pos - 0x10000, 0); do { if (pos < giveUpMarker) { throw new ZipException("central directory not found, probably not a zip file"); } baseStream.Seek(pos--, SeekOrigin.Begin); } while (ReadLeInt() != ZipConstants.ENDSIG); 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]; baseStream.Seek(offsetOfCentralDir, SeekOrigin.Begin); for (int i = 0; i < entriesForWholeCentralDir; 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> /// Creates a new <see cref="ZipFileInfo"/> instance with the given zip /// entry as the base. /// </summary> /// <param name="zip">The base <see cref="ZipEntry"/> upon which to /// create an instance.</param> public ZipFileInfo( ZipEntry zip ) { this._length = zip.Size; this.Name = zip.Name; }