// build the TOC by reading each entry in the file. private static void ReadIntoInstance_Orig(ZipFile zf) { zf.OnReadStarted(); //zf._entries = new System.Collections.Generic.List<ZipEntry>(); zf._entries = new System.Collections.Generic.Dictionary <String, ZipEntry>(); ZipEntry e; if (zf.Verbose) { if (zf.Name == null) { zf.StatusMessageTextWriter.WriteLine("Reading zip from stream..."); } else { zf.StatusMessageTextWriter.WriteLine("Reading zip {0}...", zf.Name); } } // work item 6647: PK00 (packed to removable disk) bool firstEntry = true; ZipContainer zc = new ZipContainer(zf); while ((e = ZipEntry.ReadEntry(zc, firstEntry)) != null) { if (zf.Verbose) { zf.StatusMessageTextWriter.WriteLine(" {0}", e.FileName); } zf._entries.Add(e.FileName, e); firstEntry = false; } // read the zipfile's central directory structure here. // workitem 9912 // But, because it may be corrupted, ignore errors. try { ZipEntry de; // in lieu of hashset, use a dictionary var previouslySeen = new Dictionary <String, Object>(); while ((de = ZipEntry.ReadDirEntry(zf, previouslySeen)) != null) { // Housekeeping: Since ZipFile exposes ZipEntry elements in the enumerator, // we need to copy the comment that we grab from the ZipDirEntry // into the ZipEntry, so the application can access the comment. // Also since ZipEntry is used to Write zip files, we need to copy the // file attributes to the ZipEntry as appropriate. ZipEntry e1 = zf._entries[de.FileName]; if (e1 != null) { e1._Comment = de.Comment; if (de.IsDirectory) { e1.MarkAsDirectory(); } } previouslySeen.Add(de.FileName, null); // to prevent dupes } // workitem 8299 if (zf._locEndOfCDS > 0) { zf.ReadStream.Seek(zf._locEndOfCDS, SeekOrigin.Begin); } ReadCentralDirectoryFooter(zf); if (zf.Verbose && !String.IsNullOrEmpty(zf.Comment)) { zf.StatusMessageTextWriter.WriteLine("Zip file Comment: {0}", zf.Comment); } } catch (ZipException) { } catch (IOException) { } zf.OnReadCompleted(); }
public static ZipCrypto ForRead(string password, ZipEntry e) { System.IO.Stream s = e._archiveStream; e._WeakEncryptionHeader = new byte[12]; byte[] eh = e._WeakEncryptionHeader; ZipCrypto z = new ZipCrypto(); if (password == null) { throw new BadPasswordException("This entry requires a password."); } z.InitCipher(password); ZipEntry.ReadWeakEncryptionHeader(s, eh); // Decrypt the header. This has a side effect of "further initializing the // encryption keys" in the traditional zip encryption. byte[] DecryptedHeader = z.DecryptMessage(eh, eh.Length); // CRC check // According to the pkzip spec, the final byte in the decrypted header // is the highest-order byte in the CRC. We check it here. if (DecryptedHeader[11] != (byte)((e._Crc32 >> 24) & 0xff)) { // In the case that bit 3 of the general purpose bit flag is set to // indicate the presence of an 'Extended File Header' or a 'data // descriptor' (signature 0x08074b50), the last byte of the decrypted // header is sometimes compared with the high-order byte of the // lastmodified time, rather than the high-order byte of the CRC, to // verify the password. // // This is not documented in the PKWare Appnote.txt. It was // discovered this by analysis of the Crypt.c source file in the // InfoZip library http://www.info-zip.org/pub/infozip/ // // The reason for this is that the CRC for a file cannot be known // until the entire contents of the file have been streamed. This // means a tool would have to read the file content TWICE in its // entirety in order to perform PKZIP encryption - once to compute // the CRC, and again to actually encrypt. // // This is so important for performance that using the timeblob as // the verification should be the standard practice for DotNetZip // when using PKZIP encryption. This implies that bit 3 must be // set. The downside is that some tools still cannot cope with ZIP // files that use bit 3. Therefore, DotNetZip DOES NOT force bit 3 // when PKZIP encryption is in use, and instead, reads the stream // twice. // if ((e._BitField & 0x0008) != 0x0008) { throw new BadPasswordException("The password did not match."); } else if (DecryptedHeader[11] != (byte)((e._TimeBlob >> 8) & 0xff)) { throw new BadPasswordException("The password did not match."); } // We have a good password. } else { // A-OK } return(z); }
private static void ReadCentralDirectory(ZipFile zf) { // We must have the central directory footer record, in order to properly // read zip dir entries from the central directory. This because the logic // knows when to open a spanned file when the volume number for the central // directory differs from the volume number for the zip entry. The // _diskNumberWithCd was set when originally finding the offset for the // start of the Central Directory. // workitem 9214 bool inputUsesZip64 = false; ZipEntry de; // in lieu of hashset, use a dictionary var previouslySeen = new Dictionary <String, object>(); while ((de = ZipEntry.ReadDirEntry(zf, previouslySeen)) != null) { de.ResetDirEntry(); zf.OnReadEntry(true, null); if (zf.Verbose) { zf.StatusMessageTextWriter.WriteLine("entry {0}", de.FileName); } zf._entries.Add(de.FileName, de); // workitem 9214 if (de._InputUsesZip64) { inputUsesZip64 = true; } previouslySeen.Add(de.FileName, null); // to prevent dupes } // workitem 9214; auto-set the zip64 flag if (inputUsesZip64) { zf.UseZip64WhenSaving = Zip64Option.Always; } // workitem 8299 if (zf._locEndOfCDS > 0) { zf.ReadStream.Seek(zf._locEndOfCDS, SeekOrigin.Begin); } ReadCentralDirectoryFooter(zf); if (zf.Verbose && !String.IsNullOrEmpty(zf.Comment)) { zf.StatusMessageTextWriter.WriteLine("Zip file Comment: {0}", zf.Comment); } // We keep the read stream open after reading. if (zf.Verbose) { zf.StatusMessageTextWriter.WriteLine("read in {0} entries.", zf._entries.Count); } zf.OnReadCompleted(); }