/// <summary> /// Reads one <c>ZipEntry</c> from the given stream. If the entry is encrypted, we don't /// decrypt at this point. We also do not decompress. Mostly we read metadata. /// </summary> /// <param name="zc">the ZipContainer this entry belongs to.</param> /// <param name="first">true of this is the first entry being read from the stream.</param> /// <returns>the <c>ZipEntry</c> read from the stream.</returns> internal static ZipEntry ReadEntry(ZipContainer zc, bool first) { ZipFile zf = zc.ZipFile; Stream s = zc.ReadStream; System.Text.Encoding defaultEncoding = zc.ProvisionalAlternateEncoding; ZipEntry entry = new ZipEntry(); entry._Source = ZipEntrySource.ZipFile; entry._container = zc; entry._archiveStream = s; if (zf != null) zf.OnReadEntry(true, null); if (first) HandlePK00Prefix(s); // Read entry header, including any encryption header if (!ReadHeader(entry, defaultEncoding)) return null; // Store the position in the stream for this entry // change for workitem 8098 entry.__FileDataPosition = entry.ArchiveStream.Position; // seek past the data without reading it. We will read on Extract() s.Seek(entry._CompressedFileDataSize + entry._LengthOfTrailer, SeekOrigin.Current); // ReadHeader moves the file pointer to the end of the entry header, // as well as any encryption header. // CompressedFileDataSize includes: // the maybe compressed, maybe encrypted file data // the encryption trailer, if any // the bit 3 descriptor, if any // workitem 5306 // http://www.codeplex.com/DotNetZip/WorkItem/View.aspx?WorkItemId=5306 HandleUnexpectedDataDescriptor(entry); if (zf != null) { zf.OnReadBytes(entry); zf.OnReadEntry(false, entry); } return entry; }
/// <summary> /// Copy metadata that may have been changed by the app. We do this when /// resetting the zipFile instance. If the app calls Save() on a ZipFile, then /// tries to party on that file some more, we may need to Reset() it , which /// means re-reading the entries and then copying the metadata. I think. /// </summary> internal void CopyMetaData(ZipEntry source) { this.__FileDataPosition = source.__FileDataPosition; this.CompressionMethod = source.CompressionMethod; this._CompressionMethod_FromZipFile = source._CompressionMethod_FromZipFile; this._CompressedFileDataSize = source._CompressedFileDataSize; this._UncompressedSize = source._UncompressedSize; this._BitField = source._BitField; this._Source = source._Source; this._LastModified = source._LastModified; this._Mtime = source._Mtime; this._Atime = source._Atime; this._Ctime = source._Ctime; this._ntfsTimesAreSet = source._ntfsTimesAreSet; this._emitUnixTimes = source._emitUnixTimes; this._emitNtfsTimes = source._emitNtfsTimes; }
private static ZipEntry Create(string nameInArchive, ZipEntrySource source, Object arg1, Object arg2) { if (String.IsNullOrEmpty(nameInArchive)) throw new PMDCP.Compression.Zip.ZipException("The entry name must be non-null and non-empty."); ZipEntry entry = new ZipEntry(); // workitem 7071 // workitem 7926 - "version made by" OS should be zero for compat with WinZip entry._VersionMadeBy = (0 << 8) + 45; // indicates the attributes are FAT Attributes, and v4.5 of the spec entry._Source = source; entry._Mtime = entry._Atime = entry._Ctime = DateTime.UtcNow; if (source == ZipEntrySource.Stream) { entry._sourceStream = (arg1 as Stream); // may or may not be null } else if (source == ZipEntrySource.WriteDelegate) { entry._WriteDelegate = (arg1 as WriteDelegate); // may or may not be null } else if (source == ZipEntrySource.JitStream) { entry._OpenDelegate = (arg1 as OpenDelegate); // may or may not be null entry._CloseDelegate = (arg2 as CloseDelegate); // may or may not be null } else if (source == ZipEntrySource.ZipOutputStream) { } // workitem 9073 else if (source == ZipEntrySource.None) { // make this a valid value, for later. entry._Source = ZipEntrySource.FileSystem; } else { String filename = (arg1 as String); // must not be null if (String.IsNullOrEmpty(filename)) throw new PMDCP.Compression.Zip.ZipException("The filename must be non-null and non-empty."); // The named file may or may not exist at this time. For example, when // adding a directory by name. We test existence when necessary: // when saving the ZipFile, or when getting the attributes, and so on. #if NETCF // workitem 6878 // PMDCP.Compression.Zip.SharedUtilities.AdjustTime_Win32ToDotNet entry._Mtime = File.GetLastWriteTime(filename).ToUniversalTime(); entry._Ctime = File.GetCreationTime(filename).ToUniversalTime(); entry._Atime = File.GetLastAccessTime(filename).ToUniversalTime(); // workitem 7071 // can only get attributes of files that exist. if (File.Exists(filename) || Directory.Exists(filename)) entry._ExternalFileAttrs = (int)NetCfFile.GetAttributes(filename); #else // workitem 6878?? // PMDCP.Compression.Zip.SharedUtilities.AdjustTime_Win32ToDotNet entry._Mtime = File.GetLastWriteTimeUtc(filename); entry._Ctime = File.GetCreationTimeUtc(filename); entry._Atime = File.GetLastAccessTimeUtc(filename); // workitem 7071 // can only get attributes on files that exist. if (File.Exists(filename) || Directory.Exists(filename)) entry._ExternalFileAttrs = (int)File.GetAttributes(filename); #endif entry._ntfsTimesAreSet = true; entry._LocalFileName = Path.GetFullPath(filename); // workitem 8813 } entry._LastModified = entry._Mtime; entry._FileNameInArchive = SharedUtilities.NormalizePathForUseInZipFile(nameInArchive); // We don't actually slurp in the file data until the caller invokes Write on this entry. return entry; }
internal static ZipErrorEventArgs Saving(string archiveName, ZipEntry entry, Exception exception) { var x = new ZipErrorEventArgs { EventType = ZipProgressEventType.Error_Saving, ArchiveName = archiveName, CurrentEntry = entry, _exc = exception }; return x; }
/// <summary> /// Constructor for the SaveProgressEventArgs. /// </summary> /// <param name="archiveName">the name of the zip archive.</param> /// <param name="before">whether this is before saving the entry, or after</param> /// <param name="entriesTotal">The total number of entries in the zip archive.</param> /// <param name="entriesSaved">Number of entries that have been saved.</param> /// <param name="entry">The entry involved in the event.</param> internal SaveProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesSaved, ZipEntry entry) : base(archiveName, (before) ? ZipProgressEventType.Saving_BeforeWriteEntry : ZipProgressEventType.Saving_AfterWriteEntry) { this.EntriesTotal = entriesTotal; this.CurrentEntry = entry; this._entriesSaved = entriesSaved; }
internal static ExtractProgressEventArgs ExtractExisting(string archiveName, ZipEntry entry, string extractLocation) { var x = new ExtractProgressEventArgs { ArchiveName = archiveName, EventType = ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite, CurrentEntry = entry, _target = extractLocation, }; return x; }
internal static ExtractProgressEventArgs BeforeExtractEntry(string archiveName, ZipEntry entry, string extractLocation) { var x = new ExtractProgressEventArgs { ArchiveName = archiveName, EventType = ZipProgressEventType.Extracting_BeforeExtractEntry, CurrentEntry = entry, _target = extractLocation, }; return x; }
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. // This was discovered this by analysis of the Crypt.c source file in the InfoZip library // http://www.info-zip.org/pub/infozip/ 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; }
internal void InternalAddEntry(String name, ZipEntry entry) { _entries.Add(name, entry); _zipEntriesAsList = null; _contentsChanged = true; }
// Can be called from within ZipEntry.InternalExtract. internal bool OnSingleEntryExtract(ZipEntry entry, string path, bool before) { if (ExtractProgress != null) { lock (LOCK) { var e = (before) ? ExtractProgressEventArgs.BeforeExtractEntry(ArchiveNameForEvent, entry, path) : ExtractProgressEventArgs.AfterExtractEntry(ArchiveNameForEvent, entry, path); ExtractProgress(this, e); if (e.Cancel) _extractOperationCanceled = true; } } return _extractOperationCanceled; }
internal bool OnSaveBlock(ZipEntry entry, Int64 bytesXferred, Int64 totalBytesToXfer) { if (SaveProgress != null) { lock (LOCK) { var e = SaveProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry, bytesXferred, totalBytesToXfer); SaveProgress(this, e); if (e.Cancel) _saveOperationCanceled = true; } } return _saveOperationCanceled; }
internal void OnReadEntry(bool before, ZipEntry entry) { if (ReadProgress != null) { lock (LOCK) { ReadProgressEventArgs e = (before) ? ReadProgressEventArgs.Before(ArchiveNameForEvent, _entries.Count) : ReadProgressEventArgs.After(ArchiveNameForEvent, entry, _entries.Count); ReadProgress(this, e); } } }
private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding) { int bytesRead = 0; // change for workitem 8098 ze._RelativeOffsetOfLocalHeader = ze.ArchiveStream.Position; int signature = PMDCP.Compression.Zip.SharedUtilities.ReadEntrySignature(ze.ArchiveStream); bytesRead += 4; // Return false if this is not a local file header signature. if (ZipEntry.IsNotValidSig(signature)) { // Getting "not a ZipEntry signature" is not always wrong or an error. // This will happen after the last entry in a zipfile. In that case, we // expect to read : // a ZipDirEntry signature (if a non-empty zip file) or // a ZipConstants.EndOfCentralDirectorySignature. // // Anything else is a surprise. ze.ArchiveStream.Seek(-4, SeekOrigin.Current); // unread the signature if (ZipEntry.IsNotValidZipDirEntrySig(signature) && (signature != ZipConstants.EndOfCentralDirectorySignature)) { throw new BadReadException(String.Format(" ZipEntry::ReadHeader(): Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, ze.ArchiveStream.Position)); } return false; } byte[] block = new byte[26]; int n = ze.ArchiveStream.Read(block, 0, block.Length); if (n != block.Length) return false; bytesRead += n; int i = 0; ze._VersionNeeded = (Int16)(block[i++] + block[i++] * 256); ze._BitField = (Int16)(block[i++] + block[i++] * 256); ze._CompressionMethod_FromZipFile = ze._CompressionMethod = (Int16)(block[i++] + block[i++] * 256); ze._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; // transform the time data into something usable (a DateTime) ze._LastModified = PMDCP.Compression.Zip.SharedUtilities.PackedToDateTime(ze._TimeBlob); ze._timestamp |= ZipEntryTimestamp.DOS; if ((ze._BitField & 0x01) == 0x01) { ze._Encryption_FromZipFile = ze._Encryption = EncryptionAlgorithm.PkzipWeak; // this *may* change after processing the Extra field ze._sourceIsEncrypted = true; } // NB: if ((ze._BitField & 0x0008) != 0x0008), then the Compressed, uncompressed and // CRC values are not true values; the true values will follow the entry data. // But, regardless of the status of bit 3 in the bitfield, the slots for // the three amigos may contain marker values for ZIP64. So we must read them. { ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); if ((uint)ze._CompressedSize == 0xFFFFFFFF || (uint)ze._UncompressedSize == 0xFFFFFFFF) ze._InputUsesZip64 = true; } Int16 filenameLength = (short)(block[i++] + block[i++] * 256); Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256); block = new byte[filenameLength]; n = ze.ArchiveStream.Read(block, 0, block.Length); bytesRead += n; // if the UTF8 bit is set for this entry, override the encoding the application requested. ze._actualEncoding = ((ze._BitField & 0x0800) == 0x0800) ? System.Text.Encoding.UTF8 : defaultEncoding; // need to use this form of GetString() for .NET CF ze._FileNameInArchive = ze._actualEncoding.GetString(block, 0, block.Length); // when creating an entry by reading, the LocalFileName is the same as the FileNameInArchive // No, on second thought, I think it should be empty (null). //ze._LocalFileName = ze._FileNameInArchive; // workitem 6898 if (ze._FileNameInArchive.EndsWith("/")) ze.MarkAsDirectory(); bytesRead += ze.ProcessExtraField(ze.ArchiveStream, extraFieldLength); ze._LengthOfTrailer = 0; // workitem 6607 - don't read for directories // actually get the compressed size and CRC if necessary if (!ze._FileNameInArchive.EndsWith("/") && (ze._BitField & 0x0008) == 0x0008) { // This descriptor exists only if bit 3 of the general // purpose bit flag is set (see below). It is byte aligned // and immediately follows the last byte of compressed data, // as well as any encryption trailer, as with AES. // This descriptor is used only when it was not possible to // seek in the output .ZIP file, e.g., when the output .ZIP file // was standard output or a non-seekable device. For ZIP64(tm) format // archives, the compressed and uncompressed sizes are 8 bytes each. // workitem 8098: ok (restore) long posn = ze.ArchiveStream.Position; // Here, we're going to loop until we find a ZipEntryDataDescriptorSignature and // a consistent data record after that. To be consistent, the data record must // indicate the length of the entry data. bool wantMore = true; long SizeOfDataRead = 0; int tries = 0; while (wantMore) { tries++; // We call the FindSignature shared routine to find the specified signature // in the already-opened zip archive, starting from the current cursor // position in that filestream. If we cannot find the signature, then the // routine returns -1, and the ReadHeader() method returns false, // indicating we cannot read a legal entry header. If we have found it, // then the FindSignature() method returns the number of bytes in the // stream we had to seek forward, to find the sig. We need this to // determine if the zip entry is valid, later. if (ze._container.ZipFile != null) ze._container.ZipFile.OnReadBytes(ze); long d = PMDCP.Compression.Zip.SharedUtilities.FindSignature(ze.ArchiveStream, ZipConstants.ZipEntryDataDescriptorSignature); if (d == -1) return false; // total size of data read (through all loops of this). SizeOfDataRead += d; if (ze._InputUsesZip64) { // read 1x 4-byte (CRC) and 2x 8-bytes (Compressed Size, Uncompressed Size) block = new byte[20]; n = ze.ArchiveStream.Read(block, 0, block.Length); if (n != 20) return false; // do not increment bytesRead - it is for entry header only. // the data we have just read is a footer (falls after the file data) //bytesRead += n; i = 0; ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); ze._CompressedSize = BitConverter.ToInt64(block, i); i += 8; ze._UncompressedSize = BitConverter.ToInt64(block, i); i += 8; ze._LengthOfTrailer += 24; // bytes including sig, CRC, Comp and Uncomp sizes } else { // read 3x 4-byte fields (CRC, Compressed Size, Uncompressed Size) block = new byte[12]; n = ze.ArchiveStream.Read(block, 0, block.Length); if (n != 12) return false; // do not increment bytesRead - it is for entry header only. // the data we have just read is a footer (falls after the file data) //bytesRead += n; i = 0; ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); ze._LengthOfTrailer += 16; // bytes including sig, CRC, Comp and Uncomp sizes } wantMore = (SizeOfDataRead != ze._CompressedSize); if (wantMore) { // Seek back to un-read the last 12 bytes - maybe THEY contain // the ZipEntryDataDescriptorSignature. // (12 bytes for the CRC, Comp and Uncomp size.) ze.ArchiveStream.Seek(-12, SeekOrigin.Current); // Adjust the size to account for the false signature read in // FindSignature(). SizeOfDataRead += 4; } } // seek back to previous position, to prepare to read file data // workitem 8098: ok (restore) ze.ArchiveStream.Seek(posn, SeekOrigin.Begin); } ze._CompressedFileDataSize = ze._CompressedSize; // bit 0 set indicates that some kind of encryption is in use if ((ze._BitField & 0x01) == 0x01) { #if AESCRYPTO if (ze.Encryption == EncryptionAlgorithm.WinZipAes128 || ze.Encryption == EncryptionAlgorithm.WinZipAes256) { int bits = ZipEntry.GetKeyStrengthInBits(ze._Encryption_FromZipFile); // read in the WinZip AES metadata: salt + PV. 18 bytes for AES256. 10 bytes for AES128. ze._aesCrypto_forExtract = WinZipAesCrypto.ReadFromStream(null, bits, ze.ArchiveStream); bytesRead += ze._aesCrypto_forExtract.SizeOfEncryptionMetadata - 10; // MAC (follows crypto bytes) // according to WinZip, the CompressedSize includes the AES Crypto framing data. ze._CompressedFileDataSize -= ze._aesCrypto_forExtract.SizeOfEncryptionMetadata; ze._LengthOfTrailer += 10; // MAC } else #endif { // read in the header data for "weak" encryption ze._WeakEncryptionHeader = new byte[12]; bytesRead += ZipEntry.ReadWeakEncryptionHeader(ze._archiveStream, ze._WeakEncryptionHeader); // decrease the filedata size by 12 bytes ze._CompressedFileDataSize -= 12; } } // Remember the size of the blob for this entry. // We also have the starting position in the stream for this entry. ze._LengthOfHeader = bytesRead; ze._TotalEntrySize = ze._LengthOfHeader + ze._CompressedFileDataSize + ze._LengthOfTrailer; // We've read in the regular entry header, the extra field, and any encryption // header. The pointer in the file is now at the start of the filedata, which is // potentially compressed and encrypted. Just ahead in the file, there are // _CompressedFileDataSize bytes of data, followed by potentially a non-zero length // trailer, consisting of optionally, some encryption stuff (10 byte MAC for AES), // and the bit-3 trailer (16 or 24 bytes). return true; }
private static void HandleUnexpectedDataDescriptor(ZipEntry entry) { Stream s = entry.ArchiveStream; // In some cases, the "data descriptor" is present, without a signature, even when // bit 3 of the BitField is NOT SET. This is the CRC, followed // by the compressed length and the uncompressed length (4 bytes for each // of those three elements). Need to check that here. // uint datum = (uint)PMDCP.Compression.Zip.SharedUtilities.ReadInt(s); if (datum == entry._Crc32) { int sz = PMDCP.Compression.Zip.SharedUtilities.ReadInt(s); if (sz == entry._CompressedSize) { sz = PMDCP.Compression.Zip.SharedUtilities.ReadInt(s); if (sz == entry._UncompressedSize) { // ignore everything and discard it. } else s.Seek(-12, SeekOrigin.Current); // unread the three blocks } else s.Seek(-8, SeekOrigin.Current); // unread the two blocks } else s.Seek(-4, SeekOrigin.Current); // unread the block }
/// <summary> /// Reads one entry from the zip directory structure in the zip file. /// </summary> /// <param name="zf"> /// The zipfile for which a directory entry will be read. From this param, the /// method gets the ReadStream and the expected text encoding /// (ProvisionalAlternateEncoding) which is used if the entry is not marked /// UTF-8. /// </param> /// <returns>the entry read from the archive.</returns> internal static ZipEntry ReadDirEntry(ZipFile zf) { System.IO.Stream s = zf.ReadStream; System.Text.Encoding expectedEncoding = zf.ProvisionalAlternateEncoding; int signature = PMDCP.Compression.Zip.SharedUtilities.ReadSignature(s); // return null if this is not a local file header signature if (IsNotValidZipDirEntrySig(signature)) { s.Seek(-4, System.IO.SeekOrigin.Current); // Getting "not a ZipDirEntry signature" here is not always wrong or an // error. This can happen when walking through a zipfile. After the // last ZipDirEntry, we expect to read an // EndOfCentralDirectorySignature. When we get this is how we know // we've reached the end of the central directory. if (signature != ZipConstants.EndOfCentralDirectorySignature && signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature && signature != ZipConstants.ZipEntrySignature // workitem 8299 ) { throw new BadReadException(String.Format(" ZipEntry::ReadDirEntry(): Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position)); } return null; } int bytesRead = 42 + 4; byte[] block = new byte[42]; int n = s.Read(block, 0, block.Length); if (n != block.Length) return null; int i = 0; ZipEntry zde = new ZipEntry(); zde._Source = ZipEntrySource.ZipFile; zde._container = new ZipContainer(zf); unchecked { zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256); zde._VersionNeeded = (short)(block[i++] + block[i++] * 256); zde._BitField = (short)(block[i++] + block[i++] * 256); zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256); zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._LastModified = PMDCP.Compression.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob); zde._timestamp |= ZipEntryTimestamp.DOS; zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); } // preserve zde._CompressionMethod_FromZipFile = zde._CompressionMethod; zde._filenameLength = (short)(block[i++] + block[i++] * 256); zde._extraFieldLength = (short)(block[i++] + block[i++] * 256); zde._commentLength = (short)(block[i++] + block[i++] * 256); zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256); zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256); zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); // workitem 7801 zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01); block = new byte[zde._filenameLength]; n = s.Read(block, 0, block.Length); bytesRead += n; if ((zde._BitField & 0x0800) == 0x0800) { // UTF-8 is in use zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block); } else { zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding); } // Console.WriteLine("\nEntry : {0}", zde._LocalFileName); // Console.WriteLine(" V Madeby/Needed: 0x{0:X4} / 0x{1:X4}", zde._VersionMadeBy, zde._VersionNeeded); // Console.WriteLine(" BitField/Compression: 0x{0:X4} / 0x{1:X4}", zde._BitField, zde._CompressionMethod); // Console.WriteLine(" Lastmod: {0}", zde._LastModified.ToString("u")); // Console.WriteLine(" CRC: 0x{0:X8}", zde._Crc32); // Console.WriteLine(" Comp / Uncomp: 0x{0:X8} ({0}) 0x{1:X8} ({1})", zde._CompressedSize, zde._UncompressedSize); //zde._FileNameInArchive = zde._LocalFileName; if (zde.AttributesIndicateDirectory) zde.MarkAsDirectory(); // may append a slash to filename if nec. // workitem 6898 else if (zde._FileNameInArchive.EndsWith("/")) zde.MarkAsDirectory(); zde._CompressedFileDataSize = zde._CompressedSize; if ((zde._BitField & 0x01) == 0x01) { zde._Encryption_FromZipFile = zde._Encryption = EncryptionAlgorithm.PkzipWeak; // this may change after processing the Extra field zde._sourceIsEncrypted = true; } if (zde._extraFieldLength > 0) { zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF || zde._UncompressedSize == 0xFFFFFFFF || zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF); // Console.WriteLine(" Input uses Z64?: {0}", zde._InputUsesZip64); bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength); zde._CompressedFileDataSize = zde._CompressedSize; } // we've processed the extra field, so we know the encryption method is set now. if (zde._Encryption == EncryptionAlgorithm.PkzipWeak) { // the "encryption header" of 12 bytes precedes the file data zde._CompressedFileDataSize -= 12; } #if AESCRYPTO else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 || zde.Encryption == EncryptionAlgorithm.WinZipAes256) { zde._CompressedFileDataSize = zde.CompressedSize - (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10); zde._LengthOfTrailer = 10; } #endif // tally the trailing descriptor if ((zde._BitField & 0x0008) == 0x0008) { // sig, CRC, Comp and Uncomp sizes if (zde._InputUsesZip64) zde._LengthOfTrailer += 24; else zde._LengthOfTrailer += 16; } if (zde._commentLength > 0) { block = new byte[zde._commentLength]; n = s.Read(block, 0, block.Length); bytesRead += n; if ((zde._BitField & 0x0800) == 0x0800) { // UTF-8 is in use zde._Comment = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block); } else { zde._Comment = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding); } } //zde._LengthOfDirEntry = bytesRead; return zde; }
/// <summary> /// Reads one entry from the zip directory structure in the zip file. /// </summary> /// <param name="zf"> /// The zipfile for which a directory entry will be read. From this param, the /// method gets the ReadStream and the expected text encoding /// (ProvisionalAlternateEncoding) which is used if the entry is not marked /// UTF-8. /// </param> /// <returns>the entry read from the archive.</returns> internal static ZipEntry ReadDirEntry(ZipFile zf) { System.IO.Stream s = zf.ReadStream; System.Text.Encoding expectedEncoding = zf.ProvisionalAlternateEncoding; int signature = PMDCP.Compression.Zip.SharedUtilities.ReadSignature(s); // return null if this is not a local file header signature if (IsNotValidZipDirEntrySig(signature)) { s.Seek(-4, System.IO.SeekOrigin.Current); // Getting "not a ZipDirEntry signature" here is not always wrong or an // error. This can happen when walking through a zipfile. After the // last ZipDirEntry, we expect to read an // EndOfCentralDirectorySignature. When we get this is how we know // we've reached the end of the central directory. if (signature != ZipConstants.EndOfCentralDirectorySignature && signature != ZipConstants.Zip64EndOfCentralDirectoryRecordSignature && signature != ZipConstants.ZipEntrySignature // workitem 8299 ) { throw new BadReadException(String.Format(" ZipEntry::ReadDirEntry(): Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, s.Position)); } return(null); } int bytesRead = 42 + 4; byte[] block = new byte[42]; int n = s.Read(block, 0, block.Length); if (n != block.Length) { return(null); } int i = 0; ZipEntry zde = new ZipEntry(); zde._Source = ZipEntrySource.ZipFile; zde._container = new ZipContainer(zf); unchecked { zde._VersionMadeBy = (short)(block[i++] + block[i++] * 256); zde._VersionNeeded = (short)(block[i++] + block[i++] * 256); zde._BitField = (short)(block[i++] + block[i++] * 256); zde._CompressionMethod = (Int16)(block[i++] + block[i++] * 256); zde._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._LastModified = PMDCP.Compression.Zip.SharedUtilities.PackedToDateTime(zde._TimeBlob); zde._timestamp |= ZipEntryTimestamp.DOS; zde._Crc32 = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); zde._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); } // preserve zde._CompressionMethod_FromZipFile = zde._CompressionMethod; zde._filenameLength = (short)(block[i++] + block[i++] * 256); zde._extraFieldLength = (short)(block[i++] + block[i++] * 256); zde._commentLength = (short)(block[i++] + block[i++] * 256); zde._diskNumber = (UInt32)(block[i++] + block[i++] * 256); zde._InternalFileAttrs = (short)(block[i++] + block[i++] * 256); zde._ExternalFileAttrs = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256; zde._RelativeOffsetOfLocalHeader = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256); // workitem 7801 zde.IsText = ((zde._InternalFileAttrs & 0x01) == 0x01); block = new byte[zde._filenameLength]; n = s.Read(block, 0, block.Length); bytesRead += n; if ((zde._BitField & 0x0800) == 0x0800) { // UTF-8 is in use zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block); } else { zde._FileNameInArchive = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding); } // Console.WriteLine("\nEntry : {0}", zde._LocalFileName); // Console.WriteLine(" V Madeby/Needed: 0x{0:X4} / 0x{1:X4}", zde._VersionMadeBy, zde._VersionNeeded); // Console.WriteLine(" BitField/Compression: 0x{0:X4} / 0x{1:X4}", zde._BitField, zde._CompressionMethod); // Console.WriteLine(" Lastmod: {0}", zde._LastModified.ToString("u")); // Console.WriteLine(" CRC: 0x{0:X8}", zde._Crc32); // Console.WriteLine(" Comp / Uncomp: 0x{0:X8} ({0}) 0x{1:X8} ({1})", zde._CompressedSize, zde._UncompressedSize); //zde._FileNameInArchive = zde._LocalFileName; if (zde.AttributesIndicateDirectory) { zde.MarkAsDirectory(); // may append a slash to filename if nec. } // workitem 6898 else if (zde._FileNameInArchive.EndsWith("/")) { zde.MarkAsDirectory(); } zde._CompressedFileDataSize = zde._CompressedSize; if ((zde._BitField & 0x01) == 0x01) { zde._Encryption_FromZipFile = zde._Encryption = EncryptionAlgorithm.PkzipWeak; // this may change after processing the Extra field zde._sourceIsEncrypted = true; } if (zde._extraFieldLength > 0) { zde._InputUsesZip64 = (zde._CompressedSize == 0xFFFFFFFF || zde._UncompressedSize == 0xFFFFFFFF || zde._RelativeOffsetOfLocalHeader == 0xFFFFFFFF); // Console.WriteLine(" Input uses Z64?: {0}", zde._InputUsesZip64); bytesRead += zde.ProcessExtraField(s, zde._extraFieldLength); zde._CompressedFileDataSize = zde._CompressedSize; } // we've processed the extra field, so we know the encryption method is set now. if (zde._Encryption == EncryptionAlgorithm.PkzipWeak) { // the "encryption header" of 12 bytes precedes the file data zde._CompressedFileDataSize -= 12; } #if AESCRYPTO else if (zde.Encryption == EncryptionAlgorithm.WinZipAes128 || zde.Encryption == EncryptionAlgorithm.WinZipAes256) { zde._CompressedFileDataSize = zde.CompressedSize - (ZipEntry.GetLengthOfCryptoHeaderBytes(zde.Encryption) + 10); zde._LengthOfTrailer = 10; } #endif // tally the trailing descriptor if ((zde._BitField & 0x0008) == 0x0008) { // sig, CRC, Comp and Uncomp sizes if (zde._InputUsesZip64) { zde._LengthOfTrailer += 24; } else { zde._LengthOfTrailer += 16; } } if (zde._commentLength > 0) { block = new byte[zde._commentLength]; n = s.Read(block, 0, block.Length); bytesRead += n; if ((zde._BitField & 0x0800) == 0x0800) { // UTF-8 is in use zde._Comment = PMDCP.Compression.Zip.SharedUtilities.Utf8StringFromBuffer(block); } else { zde._Comment = PMDCP.Compression.Zip.SharedUtilities.StringFromBuffer(block, expectedEncoding); } } //zde._LengthOfDirEntry = bytesRead; return(zde); }
internal bool OnZipErrorSaving(ZipEntry entry, Exception exc) { if (ZipError != null) { lock (LOCK) { var e = ZipErrorEventArgs.Saving(this.Name, entry, exc); ZipError(this, e); if (e.Cancel) _saveOperationCanceled = true; } } return _saveOperationCanceled; }
private ZipEntry _InternalAddEntry(ZipEntry ze) { // stamp all the props onto the entry ze._container = new ZipContainer(this); ze.CompressionLevel = CompressionLevel; ze.ExtractExistingFile = ExtractExistingFile; ze.ZipErrorAction = this.ZipErrorAction; ze.SetCompression = SetCompression; ze.ProvisionalAlternateEncoding = ProvisionalAlternateEncoding; ze.Password = _Password; ze.Encryption = Encryption; ze.EmitTimesInWindowsFormatWhenSaving = _emitNtfsTimes; ze.EmitTimesInUnixFormatWhenSaving = _emitUnixTimes; //string key = DictionaryKeyForEntry(ze); InternalAddEntry(ze.FileName,ze); AfterAddEntry(ze); return ze; }
private void OnExtractEntry(int current, bool before, ZipEntry currentEntry, string path) { if (ExtractProgress != null) { lock (LOCK) { var e = new ExtractProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, currentEntry, path); ExtractProgress(this, e); if (e.Cancel) _extractOperationCanceled = true; } } }
/// <summary> /// Constructor for the ExtractProgressEventArgs. /// </summary> /// <param name="archiveName">the name of the zip archive.</param> /// <param name="before">whether this is before saving the entry, or after</param> /// <param name="entriesTotal">The total number of entries in the zip archive.</param> /// <param name="entriesExtracted">Number of entries that have been extracted.</param> /// <param name="entry">The entry involved in the event.</param> /// <param name="extractLocation">The location to which entries are extracted.</param> internal ExtractProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesExtracted, ZipEntry entry, string extractLocation) : base(archiveName, (before) ? ZipProgressEventType.Extracting_BeforeExtractEntry : ZipProgressEventType.Extracting_AfterExtractEntry) { this.EntriesTotal = entriesTotal; this.CurrentEntry = entry; this._entriesExtracted = entriesExtracted; this._target = extractLocation; }
private void OnSaveEntry(int current, ZipEntry entry, bool before) { if (SaveProgress != null) { lock (LOCK) { var e = new SaveProgressEventArgs(ArchiveNameForEvent, before, _entries.Count, current, entry); SaveProgress(this, e); if (e.Cancel) _saveOperationCanceled = true; } } }
internal static ExtractProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesWritten, Int64 totalBytes) { var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_EntryBytesWritten); x.ArchiveName = archiveName; x.CurrentEntry = entry; x.BytesTransferred = bytesWritten; x.TotalBytesToTransfer = totalBytes; return x; }
internal void AfterAddEntry(ZipEntry entry) { if (AddProgress != null) { lock (LOCK) { var e = AddProgressEventArgs.AfterEntry(ArchiveNameForEvent, entry, _entries.Count); AddProgress(this, e); } } }
internal static ReadProgressEventArgs After(string archiveName, ZipEntry entry, int entriesTotal) { var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_AfterReadEntry); x.EntriesTotal = entriesTotal; x.CurrentEntry = entry; return x; }
// Can be called from within ZipEntry._ExtractOne. internal bool OnExtractBlock(ZipEntry entry, Int64 bytesWritten, Int64 totalBytesToWrite) { if (ExtractProgress != null) { lock (LOCK) { var e = ExtractProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry, bytesWritten, totalBytesToWrite); ExtractProgress(this, e); if (e.Cancel) _extractOperationCanceled = true; } } return _extractOperationCanceled; }
internal static SaveProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes) { var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_EntryBytesRead); x.ArchiveName = archiveName; x.CurrentEntry = entry; x.BytesTransferred = bytesXferred; x.TotalBytesToTransfer = totalBytes; return x; }
internal bool OnExtractExisting(ZipEntry entry, string path) { if (ExtractProgress != null) { lock (LOCK) { var e = ExtractProgressEventArgs.ExtractExisting(ArchiveNameForEvent, entry, path); ExtractProgress(this, e); if (e.Cancel) _extractOperationCanceled = true; } } return _extractOperationCanceled; }
/// <summary> /// Read the next entry from the zip file. /// </summary> /// /// <remarks> /// <para> /// Call this method just before calling <see cref="Read(byte[], int, int)"/>, /// to position the pointer in the zip file to the next entry that can be /// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the /// data in the zip file, until <c>Read()</c> returns 0. /// </para> /// /// <para> /// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped /// stream is moved to the next entry in the zip file. If you call <see /// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within /// the file, you will need to call <c>GetNextEntry()</c> again, to insure /// that the file pointer is positioned at the beginning of a zip entry. /// </para> /// /// <para> /// This method returns the <c>ZipEntry</c>. Using a stream approach, you will /// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>. /// Alternatively, you can extract an entry into a file, or a stream, by /// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings. /// </para> /// /// </remarks> /// /// <returns> /// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more /// entries in the zip file. /// </returns> /// public ZipEntry GetNextEntry() { if (_findRequired) { // find the next signature long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature); if (d == -1) return null; // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature _inputStream.Seek(-4, SeekOrigin.Current); } _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry); _endOfEntry = _inputStream.Position; _firstEntry = true; _needSetup = true; _findRequired= false; return _currentEntry; }
internal void OnReadBytes(ZipEntry entry) { if (ReadProgress != null) { lock (LOCK) { var e = ReadProgressEventArgs.ByteUpdate(ArchiveNameForEvent, entry, ReadStream.Position, LengthOfReadStream); ReadProgress(this, e); } } }