// ZipEntry.cs // ------------------------------------------------------------------ // // Copyright (c) 2006-2010 Dino Chiesa. // All rights reserved. // // This code module is part of DotNetZip, a zipfile class library. // // ------------------------------------------------------------------ // // This code is licensed under the Microsoft Public License. // See the file License.txt for the license details. // More info on: http://dotnetzip.codeplex.com // // ------------------------------------------------------------------ // // last saved (in emacs): // Time-stamp: <2011-August-06 17:25:53> // // ------------------------------------------------------------------ // // This module defines the ZipEntry class, which models the entries within a zip file. // // Created: Tue, 27 Mar 2007 15:30 // // ------------------------------------------------------------------ using System; using System.IO; using Interop = System.Runtime.InteropServices; namespace OfficeOpenXml.Packaging.Ionic.Zip { /// /// Represents a single entry in a ZipFile. Typically, applications get a ZipEntry /// by enumerating the entries within a ZipFile, or by adding an entry to a ZipFile. /// [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00004")] [Interop.ComVisible(true)] #if !NETCF [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)] // AutoDual #endif internal partial class ZipEntry { /// /// Default constructor. /// /// /// Applications should never need to call this directly. It is exposed to /// support COM Automation environments. /// public ZipEntry() { _CompressionMethod = (Int16)CompressionMethod.Deflate; _CompressionLevel = Ionic.Zlib.CompressionLevel.Default; _Encryption = EncryptionAlgorithm.None; _Source = ZipEntrySource.None; AlternateEncoding = System.Text.Encoding.GetEncoding("IBM437"); AlternateEncodingUsage = ZipOption.Never; } /// /// The time and date at which the file indicated by the ZipEntry was /// last modified. /// /// /// /// /// The DotNetZip library sets the LastModified value for an entry, equal to /// the Last Modified time of the file in the filesystem. If an entry is /// added from a stream, the library uses System.DateTime.Now for this /// value, for the given entry. /// /// /// /// This property allows the application to retrieve and possibly set the /// LastModified value on an entry, to an arbitrary value. values with a /// setting of DateTimeKind.Unspecified are taken to be expressed as /// DateTimeKind.Local. /// /// /// /// Be aware that because of the way PKWare's /// Zip specification describes how times are stored in the zip file, /// the full precision of the System.DateTime datatype is not stored /// for the last modified time when saving zip files. For more information on /// how times are formatted, see the PKZip specification. /// /// /// /// The actual last modified time of a file can be stored in multiple ways in /// the zip file, and they are not mutually exclusive: /// /// /// /// /// In the so-called "DOS" format, which has a 2-second precision. Values /// are rounded to the nearest even second. For example, if the time on the /// file is 12:34:43, then it will be stored as 12:34:44. This first value /// is accessible via the LastModified property. This value is always /// present in the metadata for each zip entry. In some cases the value is /// invalid, or zero. /// /// /// /// In the so-called "Windows" or "NTFS" format, as an 8-byte integer /// quantity expressed as the number of 1/10 milliseconds (in other words /// the number of 100 nanosecond units) since January 1, 1601 (UTC). This /// format is how Windows represents file times. This time is accessible /// via the ModifiedTime property. /// /// /// /// In the "Unix" format, a 4-byte quantity specifying the number of seconds since /// January 1, 1970 UTC. /// /// /// /// In an older format, now deprecated but still used by some current /// tools. This format is also a 4-byte quantity specifying the number of /// seconds since January 1, 1970 UTC. /// /// /// /// /// /// Zip tools and libraries will always at least handle (read or write) the /// DOS time, and may also handle the other time formats. Keep in mind that /// while the names refer to particular operating systems, there is nothing in /// the time formats themselves that prevents their use on other operating /// systems. /// /// /// /// When reading ZIP files, the DotNetZip library reads the Windows-formatted /// time, if it is stored in the entry, and sets both LastModified and /// ModifiedTime to that value. When writing ZIP files, the DotNetZip /// library by default will write both time quantities. It can also emit the /// Unix-formatted time if desired (See .) /// /// /// /// The last modified time of the file created upon a call to /// ZipEntry.Extract() may be adjusted during extraction to compensate /// for differences in how the .NET Base Class Library deals with daylight /// saving time (DST) versus how the Windows filesystem deals with daylight /// saving time. Raymond Chen provides /// some good context. /// /// /// /// In a nutshell: Daylight savings time rules change regularly. In 2007, for /// example, the inception week of DST changed. In 1977, DST was in place all /// year round. In 1945, likewise. And so on. Win32 does not attempt to /// guess which time zone rules were in effect at the time in question. It /// will render a time as "standard time" and allow the app to change to DST /// as necessary. .NET makes a different choice. /// /// /// /// Compare the output of FileInfo.LastWriteTime.ToString("f") with what you /// see in the Windows Explorer property sheet for a file that was last /// written to on the other side of the DST transition. For example, suppose /// the file was last modified on October 17, 2003, during DST but DST is not /// currently in effect. Explorer's file properties reports Thursday, October /// 17, 2003, 8:45:38 AM, but .NETs FileInfo reports Thursday, October 17, /// 2003, 9:45 AM. /// /// /// /// Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note: Pacific /// STANDARD Time. Even though October 17 of that year occurred during Pacific /// Daylight Time, Win32 displays the time as standard time because that's /// what time it is NOW. /// /// /// /// .NET BCL assumes that the current DST rules were in place at the time in /// question. So, .NET says, "Well, if the rules in effect now were also in /// effect on October 17, 2003, then that would be daylight time" so it /// displays "Thursday, October 17, 2003, 9:45 AM PDT" - daylight time. /// /// /// /// So .NET gives a value which is more intuitively correct, but is also /// potentially incorrect, and which is not invertible. Win32 gives a value /// which is intuitively incorrect, but is strictly correct. /// /// /// /// Because of this funkiness, this library adds one hour to the LastModified /// time on the extracted file, if necessary. That is to say, if the time in /// question had occurred in what the .NET Base Class Library assumed to be /// DST. This assumption may be wrong given the constantly changing DST rules, /// but it is the best we can do. /// /// /// /// public DateTime LastModified { get { return _LastModified.ToLocalTime(); } set { _LastModified = (value.Kind == DateTimeKind.Unspecified) ? DateTime.SpecifyKind(value, DateTimeKind.Local) : value.ToLocalTime(); _Mtime = Ionic.Zip.SharedUtilities.AdjustTime_Reverse(_LastModified).ToUniversalTime(); _metadataChanged = true; } } private int BufferSize { get { return this._container.BufferSize; } } /// /// Last Modified time for the file represented by the entry. /// /// /// /// /// /// This value corresponds to the "last modified" time in the NTFS file times /// as described in the Zip /// specification. When getting this property, the value may be /// different from . When setting the property, /// the property also gets set, but with a lower /// precision. /// /// /// /// Let me explain. It's going to take a while, so get /// comfortable. Originally, waaaaay back in 1989 when the ZIP specification /// was originally described by the esteemed Mr. Phil Katz, the dominant /// operating system of the time was MS-DOS. MSDOS stored file times with a /// 2-second precision, because, c'mon, who is ever going to need better /// resolution than THAT? And so ZIP files, regardless of the platform on /// which the zip file was created, store file times in exactly the same format that DOS used /// in 1989. /// /// /// /// Since then, the ZIP spec has evolved, but the internal format for file /// timestamps remains the same. Despite the fact that the way times are /// stored in a zip file is rooted in DOS heritage, any program on any /// operating system can format a time in this way, and most zip tools and /// libraries DO - they round file times to the nearest even second and store /// it just like DOS did 25+ years ago. /// /// /// /// PKWare extended the ZIP specification to allow a zip file to store what /// are called "NTFS Times" and "Unix(tm) times" for a file. These are the /// last write, last access, and file creation /// times of a particular file. These metadata are not actually specific /// to NTFS or Unix. They are tracked for each file by NTFS and by various /// Unix filesystems, but they are also tracked by other filesystems, too. /// The key point is that the times are formatted in the zip file /// in the same way that NTFS formats the time (ticks since win32 epoch), /// or in the same way that Unix formats the time (seconds since Unix /// epoch). As with the DOS time, any tool or library running on any /// operating system is capable of formatting a time in one of these ways /// and embedding it into the zip file. /// /// /// /// These extended times are higher precision quantities than the DOS time. /// As described above, the (DOS) LastModified has a precision of 2 seconds. /// The Unix time is stored with a precision of 1 second. The NTFS time is /// stored with a precision of 0.0000001 seconds. The quantities are easily /// convertible, except for the loss of precision you may incur. /// /// /// /// A zip archive can store the {C,A,M} times in NTFS format, in Unix format, /// or not at all. Often a tool running on Unix or Mac will embed the times /// in Unix format (1 second precision), while WinZip running on Windows might /// embed the times in NTFS format (precision of of 0.0000001 seconds). When /// reading a zip file with these "extended" times, in either format, /// DotNetZip represents the values with the /// ModifiedTime, AccessedTime and CreationTime /// properties on the ZipEntry. /// /// /// /// While any zip application or library, regardless of the platform it /// runs on, could use any of the time formats allowed by the ZIP /// specification, not all zip tools or libraries do support all these /// formats. Storing the higher-precision times for each entry is /// optional for zip files, and many tools and libraries don't use the /// higher precision quantities at all. The old DOS time, represented by /// , is guaranteed to be present, though it /// sometimes unset. /// /// /// /// Ok, getting back to the question about how the LastModified /// property relates to this ModifiedTime /// property... LastModified is always set, while /// ModifiedTime is not. (The other times stored in the NTFS /// times extension, CreationTime and AccessedTime also /// may not be set on an entry that is read from an existing zip file.) /// When reading a zip file, then LastModified takes the DOS time /// that is stored with the file. If the DOS time has been stored as zero /// in the zipfile, then this library will use DateTime.Now for the /// LastModified value. If the ZIP file was created by an evolved /// tool, then there will also be higher precision NTFS or Unix times in /// the zip file. In that case, this library will read those times, and /// set LastModified and ModifiedTime to the same value, the /// one corresponding to the last write time of the file. If there are no /// higher precision times stored for the entry, then ModifiedTime /// remains unset (likewise AccessedTime and CreationTime), /// and LastModified keeps its DOS time. /// /// /// /// When creating zip files with this library, by default the extended time /// properties (ModifiedTime, AccessedTime, and /// CreationTime) are set on the ZipEntry instance, and these data are /// stored in the zip archive for each entry, in NTFS format. If you add an /// entry from an actual filesystem file, then the entry gets the actual file /// times for that file, to NTFS-level precision. If you add an entry from a /// stream, or a string, then the times get the value DateTime.Now. In /// this case LastModified and ModifiedTime will be identical, /// to 2 seconds of precision. You can explicitly set the /// CreationTime, AccessedTime, and ModifiedTime of an /// entry using the property setters. If you want to set all of those /// quantities, it's more efficient to use the method. Those /// changes are not made permanent in the zip file until you call or one of its cousins. /// /// /// /// When creating a zip file, you can override the default behavior of /// this library for formatting times in the zip file, disabling the /// embedding of file times in NTFS format or enabling the storage of file /// times in Unix format, or both. You may want to do this, for example, /// when creating a zip file on Windows, that will be consumed on a Mac, /// by an application that is not hip to the "NTFS times" format. To do /// this, use the and /// properties. A valid zip /// file may store the file times in both formats. But, there are no /// guarantees that a program running on Mac or Linux will gracefully /// handle the NTFS-formatted times when Unix times are present, or that a /// non-DotNetZip-powered application running on Windows will be able to /// handle file times in Unix format. DotNetZip will always do something /// reasonable; other libraries or tools may not. When in doubt, test. /// /// /// /// I'll bet you didn't think one person could type so much about time, eh? /// And reading it was so enjoyable, too! Well, in appreciation, maybe you /// should donate? /// /// /// /// /// /// /// public DateTime ModifiedTime { get { return _Mtime; } set { SetEntryTimes(_Ctime, _Atime, value); } } /// /// Last Access time for the file represented by the entry. /// /// /// This value may or may not be meaningful. If the ZipEntry was read from an existing /// Zip archive, this information may not be available. For an explanation of why, see /// . /// /// /// /// public DateTime AccessedTime { get { return _Atime; } set { SetEntryTimes(_Ctime, value, _Mtime); } } /// /// The file creation time for the file represented by the entry. /// /// /// /// This value may or may not be meaningful. If the ZipEntry was read /// from an existing zip archive, and the creation time was not set on the entry /// when the zip file was created, then this property may be meaningless. For an /// explanation of why, see . /// /// /// /// public DateTime CreationTime { get { return _Ctime; } set { SetEntryTimes(value, _Atime, _Mtime); } } /// /// Sets the NTFS Creation, Access, and Modified times for the given entry. /// /// /// /// /// When adding an entry from a file or directory, the Creation, Access, and /// Modified times for the given entry are automatically set from the /// filesystem values. When adding an entry from a stream or string, the /// values are implicitly set to DateTime.Now. The application may wish to /// set these values to some arbitrary value, before saving the archive, and /// can do so using the various setters. If you want to set all of the times, /// this method is more efficient. /// /// /// /// The values you set here will be retrievable with the , and properties. /// /// /// /// When this method is called, if both and are false, then the /// EmitTimesInWindowsFormatWhenSaving flag is automatically set. /// /// /// /// DateTime values provided here without a DateTimeKind are assumed to be Local Time. /// /// /// /// the creation time of the entry. /// the last access time of the entry. /// the last modified time of the entry. /// /// /// /// /// /// public void SetEntryTimes(DateTime created, DateTime accessed, DateTime modified) { _ntfsTimesAreSet = true; if (created == _zeroHour && created.Kind == _zeroHour.Kind) created = _win32Epoch; if (accessed == _zeroHour && accessed.Kind == _zeroHour.Kind) accessed = _win32Epoch; if (modified == _zeroHour && modified.Kind == _zeroHour.Kind) modified = _win32Epoch; _Ctime = created.ToUniversalTime(); _Atime = accessed.ToUniversalTime(); _Mtime = modified.ToUniversalTime(); _LastModified = _Mtime; if (!_emitUnixTimes && !_emitNtfsTimes) _emitNtfsTimes = true; _metadataChanged = true; } /// /// Specifies whether the Creation, Access, and Modified times for the given /// entry will be emitted in "Windows format" when the zip archive is saved. /// /// /// /// /// An application creating a zip archive can use this flag to explicitly /// specify that the file times for the entry should or should not be stored /// in the zip archive in the format used by Windows. The default value of /// this property is true. /// /// /// /// When adding an entry from a file or directory, the Creation (), Access (), and Modified /// () times for the given entry are automatically /// set from the filesystem values. When adding an entry from a stream or /// string, all three values are implicitly set to DateTime.Now. Applications /// can also explicitly set those times by calling . /// /// /// /// PKWARE's /// zip specification describes multiple ways to format these times in a /// zip file. One is the format Windows applications normally use: 100ns ticks /// since Jan 1, 1601 UTC. The other is a format Unix applications typically /// use: seconds since January 1, 1970 UTC. Each format can be stored in an /// "extra field" in the zip entry when saving the zip archive. The former /// uses an extra field with a Header Id of 0x000A, while the latter uses a /// header ID of 0x5455. /// /// /// /// Not all zip tools and libraries can interpret these fields. Windows /// compressed folders is one that can read the Windows Format timestamps, /// while I believe the Infozip /// tools can read the Unix format timestamps. Although the time values are /// easily convertible, subject to a loss of precision, some tools and /// libraries may be able to read only one or the other. DotNetZip can read or /// write times in either or both formats. /// /// /// /// The times stored are taken from , , and . /// /// /// /// This property is not mutually exclusive from the property. It is /// possible that a zip entry can embed the timestamps in both forms, one /// form, or neither. But, there are no guarantees that a program running on /// Mac or Linux will gracefully handle NTFS Formatted times, or that a /// non-DotNetZip-powered application running on Windows will be able to /// handle file times in Unix format. When in doubt, test. /// /// /// /// Normally you will use the ZipFile.EmitTimesInWindowsFormatWhenSaving /// property, to specify the behavior for all entries in a zip, rather than /// the property on each individual entry. /// /// /// /// /// /// /// /// /// public bool EmitTimesInWindowsFormatWhenSaving { get { return _emitNtfsTimes; } set { _emitNtfsTimes = value; _metadataChanged = true; } } /// /// Specifies whether the Creation, Access, and Modified times for the given /// entry will be emitted in "Unix(tm) format" when the zip archive is saved. /// /// /// /// /// An application creating a zip archive can use this flag to explicitly /// specify that the file times for the entry should or should not be stored /// in the zip archive in the format used by Unix. By default this flag is /// false, meaning the Unix-format times are not stored in the zip /// archive. /// /// /// /// When adding an entry from a file or directory, the Creation (), Access (), and Modified /// () times for the given entry are automatically /// set from the filesystem values. When adding an entry from a stream or /// string, all three values are implicitly set to DateTime.Now. Applications /// can also explicitly set those times by calling . /// /// /// /// PKWARE's /// zip specification describes multiple ways to format these times in a /// zip file. One is the format Windows applications normally use: 100ns ticks /// since Jan 1, 1601 UTC. The other is a format Unix applications typically /// use: seconds since Jan 1, 1970 UTC. Each format can be stored in an /// "extra field" in the zip entry when saving the zip archive. The former /// uses an extra field with a Header Id of 0x000A, while the latter uses a /// header ID of 0x5455. /// /// /// /// Not all tools and libraries can interpret these fields. Windows /// compressed folders is one that can read the Windows Format timestamps, /// while I believe the Infozip /// tools can read the Unix format timestamps. Although the time values are /// easily convertible, subject to a loss of precision, some tools and /// libraries may be able to read only one or the other. DotNetZip can read or /// write times in either or both formats. /// /// /// /// The times stored are taken from , , and . /// /// /// /// This property is not mutually exclusive from the property. It is /// possible that a zip entry can embed the timestamps in both forms, one /// form, or neither. But, there are no guarantees that a program running on /// Mac or Linux will gracefully handle NTFS Formatted times, or that a /// non-DotNetZip-powered application running on Windows will be able to /// handle file times in Unix format. When in doubt, test. /// /// /// /// Normally you will use the ZipFile.EmitTimesInUnixFormatWhenSaving /// property, to specify the behavior for all entries, rather than the /// property on each individual entry. /// /// /// /// /// /// /// /// /// public bool EmitTimesInUnixFormatWhenSaving { get { return _emitUnixTimes; } set { _emitUnixTimes = value; _metadataChanged = true; } } /// /// The type of timestamp attached to the ZipEntry. /// /// /// /// This property is valid only for a ZipEntry that was read from a zip archive. /// It indicates the type of timestamp attached to the entry. /// /// /// /// internal ZipEntryTimestamp Timestamp { get { return _timestamp; } } /// /// The file attributes for the entry. /// /// /// /// /// /// The attributes in NTFS include /// ReadOnly, Archive, Hidden, System, and Indexed. When adding a /// ZipEntry to a ZipFile, these attributes are set implicitly when /// adding an entry from the filesystem. When adding an entry from a stream /// or string, the Attributes are not set implicitly. Regardless of the way /// an entry was added to a ZipFile, you can set the attributes /// explicitly if you like. /// /// /// /// When reading a ZipEntry from a ZipFile, the attributes are /// set according to the data stored in the ZipFile. If you extract the /// entry from the archive to a filesystem file, DotNetZip will set the /// attributes on the resulting file accordingly. /// /// /// /// The attributes can be set explicitly by the application. For example the /// application may wish to set the FileAttributes.ReadOnly bit for all /// entries added to an archive, so that on unpack, this attribute will be set /// on the extracted file. Any changes you make to this property are made /// permanent only when you call a Save() method on the ZipFile /// instance that contains the ZipEntry. /// /// /// /// For example, an application may wish to zip up a directory and set the /// ReadOnly bit on every file in the archive, so that upon later extraction, /// the resulting files will be marked as ReadOnly. Not every extraction tool /// respects these attributes, but if you unpack with DotNetZip, as for /// example in a self-extracting archive, then the attributes will be set as /// they are stored in the ZipFile. /// /// /// /// These attributes may not be interesting or useful if the resulting archive /// is extracted on a non-Windows platform. How these attributes get used /// upon extraction depends on the platform and tool used. /// /// /// /// This property is only partially supported in the Silverlight version /// of the library: applications can read attributes on entries within /// ZipFiles. But extracting entries within Silverlight will not set the /// attributes on the extracted files. /// /// /// public System.IO.FileAttributes Attributes { // workitem 7071 get { return (System.IO.FileAttributes)_ExternalFileAttrs; } set { _ExternalFileAttrs = (int)value; // Since the application is explicitly setting the attributes, overwriting // whatever was there, we will explicitly set the Version made by field. // workitem 7926 - "version made by" OS should be zero for compat with WinZip _VersionMadeBy = (0 << 8) + 45; // v4.5 of the spec _metadataChanged = true; } } /// /// The name of the filesystem file, referred to by the ZipEntry. /// /// /// /// /// This property specifies the thing-to-be-zipped on disk, and is set only /// when the ZipEntry is being created from a filesystem file. If the /// ZipFile is instantiated by reading an existing .zip archive, then /// the LocalFileName will be null (Nothing in VB). /// /// /// /// When it is set, the value of this property may be different than , which is the path used in the archive itself. If you /// call Zip.AddFile("foop.txt", AlternativeDirectory), then the path /// used for the ZipEntry within the zip archive will be different /// than this path. /// /// /// /// If the entry is being added from a stream, then this is null (Nothing in VB). /// /// /// /// internal string LocalFileName { get { return _LocalFileName; } } /// /// The name of the file contained in the ZipEntry. /// /// /// /// /// /// This is the name of the entry in the ZipFile itself. When creating /// a zip archive, if the ZipEntry has been created from a filesystem /// file, via a call to or , or a related overload, the value /// of this property is derived from the name of that file. The /// FileName property does not include drive letters, and may include a /// different directory path, depending on the value of the /// directoryPathInArchive parameter used when adding the entry into /// the ZipFile. /// /// /// /// In some cases there is no related filesystem file - for example when a /// ZipEntry is created using or one of the similar overloads. In this case, the value of /// this property is derived from the fileName and the directory path passed /// to that method. /// /// /// /// When reading a zip file, this property takes the value of the entry name /// as stored in the zip file. If you extract such an entry, the extracted /// file will take the name given by this property. /// /// /// /// Applications can set this property when creating new zip archives or when /// reading existing archives. When setting this property, the actual value /// that is set will replace backslashes with forward slashes, in accordance /// with the Zip /// specification, for compatibility with Unix(tm) and ... get /// this.... Amiga! /// /// /// /// If an application reads a ZipFile via or a related overload, and then explicitly /// sets the FileName on an entry contained within the ZipFile, and /// then calls , the application will effectively /// rename the entry within the zip archive. /// /// /// /// If an application sets the value of FileName, then calls /// Extract() on the entry, the entry is extracted to a file using the /// newly set value as the filename. The FileName value is made /// permanent in the zip archive only after a call to one of the /// ZipFile.Save() methods on the ZipFile that contains the /// ZipEntry. /// /// /// /// If an application attempts to set the FileName to a value that /// would result in a duplicate entry in the ZipFile, an exception is /// thrown. /// /// /// /// When a ZipEntry is contained within a ZipFile, applications /// cannot rename the entry within the context of a foreach (For /// Each in VB) loop, because of the way the ZipFile stores /// entries. If you need to enumerate through all the entries and rename one /// or more of them, use ZipFile.EntriesSorted as the /// collection. See also, ZipFile.GetEnumerator(). /// /// /// public string FileName { get { return _FileNameInArchive; } set { if (_container.ZipFile == null) throw new ZipException("Cannot rename; this is not supported in ZipOutputStream/ZipInputStream."); // rename the entry! if (String.IsNullOrEmpty(value)) throw new ZipException("The FileName must be non empty and non-null."); var filename = ZipEntry.NameInArchive(value, null); // workitem 8180 if (_FileNameInArchive == filename) return; // nothing to do // workitem 8047 - when renaming, must remove old and then add a new entry this._container.ZipFile.RemoveEntry(this); this._container.ZipFile.InternalAddEntry(filename, this); _FileNameInArchive = filename; _container.ZipFile.NotifyEntryChanged(); _metadataChanged = true; } } /// /// The stream that provides content for the ZipEntry. /// /// /// /// /// /// The application can use this property to set the input stream for an /// entry on a just-in-time basis. Imagine a scenario where the application /// creates a ZipFile comprised of content obtained from hundreds of /// files, via calls to AddFile(). The DotNetZip library opens streams /// on these files on a just-in-time basis, only when writing the entry out to /// an external store within the scope of a ZipFile.Save() call. Only /// one input stream is opened at a time, as each entry is being written out. /// /// /// /// Now imagine a different application that creates a ZipFile /// with content obtained from hundreds of streams, added through . Normally the /// application would supply an open stream to that call. But when large /// numbers of streams are being added, this can mean many open streams at one /// time, unnecessarily. /// /// /// /// To avoid this, call and specify delegates that open and close the stream at /// the time of Save. /// /// /// /// /// Setting the value of this property when the entry was not added from a /// stream (for example, when the ZipEntry was added with or , or when the entry was added by /// reading an existing zip archive) will throw an exception. /// /// /// /// public Stream InputStream { get { return _sourceStream; } set { if (this._Source != ZipEntrySource.Stream) throw new ZipException("You must not set the input stream for this entry."); _sourceWasJitProvided = true; _sourceStream = value; } } /// /// A flag indicating whether the InputStream was provided Just-in-time. /// /// /// /// /// /// When creating a zip archive, an application can obtain content for one or /// more of the ZipEntry instances from streams, using the method. At the time /// of calling that method, the application can supply null as the value of /// the stream parameter. By doing so, the application indicates to the /// library that it will provide a stream for the entry on a just-in-time /// basis, at the time one of the ZipFile.Save() methods is called and /// the data for the various entries are being compressed and written out. /// /// /// /// In this case, the application can set the /// property, typically within the SaveProgress event (event type: ) for that entry. /// /// /// /// The application will later want to call Close() and Dispose() on that /// stream. In the SaveProgress event, when the event type is , the application can /// do so. This flag indicates that the stream has been provided by the /// application on a just-in-time basis and that it is the application's /// responsibility to call Close/Dispose on that stream. /// /// /// /// public bool InputStreamWasJitProvided { get { return _sourceWasJitProvided; } } /// /// An enum indicating the source of the ZipEntry. /// internal ZipEntrySource Source { get { return _Source; } } /// /// The version of the zip engine needed to read the ZipEntry. /// /// /// /// /// This is a readonly property, indicating the version of the Zip /// specification that the extracting tool or library must support to /// extract the given entry. Generally higher versions indicate newer /// features. Older zip engines obviously won't know about new features, and /// won't be able to extract entries that depend on those newer features. /// /// /// /// /// value /// Features /// /// /// /// 20 /// a basic Zip Entry, potentially using PKZIP encryption. /// /// /// /// /// 45 /// The ZIP64 extension is used on the entry. /// /// /// /// /// 46 /// File is compressed using BZIP2 compression* /// /// /// /// 50 /// File is encrypted using PkWare's DES, 3DES, (broken) RC2 or RC4 /// /// /// /// 51 /// File is encrypted using PKWare's AES encryption or corrected RC2 encryption. /// /// /// /// 52 /// File is encrypted using corrected RC2-64 encryption** /// /// /// /// 61 /// File is encrypted using non-OAEP key wrapping*** /// /// /// /// 63 /// File is compressed using LZMA, PPMd+, Blowfish, or Twofish /// /// /// /// /// /// There are other values possible, not listed here. DotNetZip supports /// regular PKZip encryption, and ZIP64 extensions. DotNetZip cannot extract /// entries that require a zip engine higher than 45. /// /// /// /// This value is set upon reading an existing zip file, or after saving a zip /// archive. /// /// public Int16 VersionNeeded { get { return _VersionNeeded; } } /// /// The comment attached to the ZipEntry. /// /// /// /// /// Each entry in a zip file can optionally have a comment associated to /// it. The comment might be displayed by a zip tool during extraction, for /// example. /// /// /// /// By default, the Comment is encoded in IBM437 code page. You can /// specify an alternative with and /// . /// /// /// /// public string Comment { get { return _Comment; } set { _Comment = value; _metadataChanged = true; } } /// /// Indicates whether the entry requires ZIP64 extensions. /// /// /// /// /// /// This property is null (Nothing in VB) until a Save() method on the /// containing instance has been called. The property is /// non-null (HasValue is true) only after a Save() method has /// been called. /// /// /// /// After the containing ZipFile has been saved, the Value of this /// property is true if any of the following three conditions holds: the /// uncompressed size of the entry is larger than 0xFFFFFFFF; the compressed /// size of the entry is larger than 0xFFFFFFFF; the relative offset of the /// entry within the zip archive is larger than 0xFFFFFFFF. These quantities /// are not known until a Save() is attempted on the zip archive and /// the compression is applied. /// /// /// /// If none of the three conditions holds, then the Value is false. /// /// /// /// A Value of false does not indicate that the entry, as saved in the /// zip archive, does not use ZIP64. It merely indicates that ZIP64 is /// not required. An entry may use ZIP64 even when not required if /// the property on the containing /// ZipFile instance is set to , or if /// the property on the containing /// ZipFile instance is set to /// and the output stream was not seekable. /// /// /// /// public Nullable RequiresZip64 { get { return _entryRequiresZip64; } } /// /// Indicates whether the entry actually used ZIP64 extensions, as it was most /// recently written to the output file or stream. /// /// /// /// /// /// This Nullable property is null (Nothing in VB) until a Save() /// method on the containing instance has been /// called. HasValue is true only after a Save() method has been /// called. /// /// /// /// The value of this property for a particular ZipEntry may change /// over successive calls to Save() methods on the containing ZipFile, /// even if the file that corresponds to the ZipEntry does not. This /// may happen if other entries contained in the ZipFile expand, /// causing the offset for this particular entry to exceed 0xFFFFFFFF. /// /// /// public Nullable OutputUsedZip64 { get { return _OutputUsesZip64; } } /// /// The bitfield for the entry as defined in the zip spec. You probably /// never need to look at this. /// /// /// /// /// You probably do not need to concern yourself with the contents of this /// property, but in case you do: /// /// /// /// /// bit /// meaning /// /// /// /// 0 /// set if encryption is used. /// /// /// /// 1-2 /// /// set to determine whether normal, max, fast deflation. DotNetZip library /// always leaves these bits unset when writing (indicating "normal" /// deflation"), but can read an entry with any value here. /// /// /// /// /// 3 /// /// Indicates that the Crc32, Compressed and Uncompressed sizes are zero in the /// local header. This bit gets set on an entry during writing a zip file, when /// it is saved to a non-seekable output stream. /// /// /// /// /// /// 4 /// reserved for "enhanced deflating". This library doesn't do enhanced deflating. /// /// /// /// 5 /// set to indicate the zip is compressed patched data. This library doesn't do that. /// /// /// /// 6 /// /// set if PKWare's strong encryption is used (must also set bit 1 if bit 6 is /// set). This bit is not set if WinZip's AES encryption is set. /// /// /// /// 7 /// not used /// /// /// /// 8 /// not used /// /// /// /// 9 /// not used /// /// /// /// 10 /// not used /// /// /// /// 11 /// /// Language encoding flag (EFS). If this bit is set, the filename and comment /// fields for this file must be encoded using UTF-8. This library currently /// does not support UTF-8. /// /// /// /// /// 12 /// Reserved by PKWARE for enhanced compression. /// /// /// /// 13 /// /// Used when encrypting the Central Directory to indicate selected data /// values in the Local Header are masked to hide their actual values. See /// the section in the Zip /// specification describing the Strong Encryption Specification for /// details. /// /// /// /// /// 14 /// Reserved by PKWARE. /// /// /// /// 15 /// Reserved by PKWARE. /// /// /// /// /// public Int16 BitField { get { return _BitField; } } /// /// The compression method employed for this ZipEntry. /// /// /// /// /// /// The /// Zip specification allows a variety of compression methods. This /// library supports just two: 0x08 = Deflate. 0x00 = Store (no compression), /// for reading or writing. /// /// /// /// When reading an entry from an existing zipfile, the value you retrieve /// here indicates the compression method used on the entry by the original /// creator of the zip. When writing a zipfile, you can specify either 0x08 /// (Deflate) or 0x00 (None). If you try setting something else, you will get /// an exception. /// /// /// /// You may wish to set CompressionMethod to CompressionMethod.None (0) /// when zipping already-compressed data like a jpg, png, or mp3 file. /// This can save time and cpu cycles. /// /// /// /// When setting this property on a ZipEntry that is read from an /// existing zip file, calling ZipFile.Save() will cause the new /// CompressionMethod to be used on the entry in the newly saved zip file. /// /// /// /// Setting this property may have the side effect of modifying the /// CompressionLevel property. If you set the CompressionMethod to a /// value other than None, and CompressionLevel is previously /// set to None, then CompressionLevel will be set to /// Default. /// /// /// /// /// /// /// In this example, the first entry added to the zip archive uses the default /// behavior - compression is used where it makes sense. The second entry, /// the MP3 file, is added to the archive without being compressed. /// /// using (ZipFile zip = new ZipFile(ZipFileToCreate)) /// { /// ZipEntry e1= zip.AddFile(@"notes\Readme.txt"); /// ZipEntry e2= zip.AddFile(@"music\StopThisTrain.mp3"); /// e2.CompressionMethod = CompressionMethod.None; /// zip.Save(); /// } /// /// /// /// Using zip As New ZipFile(ZipFileToCreate) /// zip.AddFile("notes\Readme.txt") /// Dim e2 as ZipEntry = zip.AddFile("music\StopThisTrain.mp3") /// e2.CompressionMethod = CompressionMethod.None /// zip.Save /// End Using /// /// internal CompressionMethod CompressionMethod { get { return (CompressionMethod)_CompressionMethod; } set { if (value == (CompressionMethod)_CompressionMethod) return; // nothing to do. if (value != CompressionMethod.None && value != CompressionMethod.Deflate #if BZIP && value != CompressionMethod.BZip2 #endif ) throw new InvalidOperationException("Unsupported compression method."); // If the source is a zip archive and there was encryption on the // entry, changing the compression method is not supported. // if (this._Source == ZipEntrySource.ZipFile && _sourceIsEncrypted) // throw new InvalidOperationException("Cannot change compression method on encrypted entries read from archives."); _CompressionMethod = (Int16)value; if (_CompressionMethod == (Int16)Ionic.Zip.CompressionMethod.None) _CompressionLevel = Ionic.Zlib.CompressionLevel.None; else if (CompressionLevel == Ionic.Zlib.CompressionLevel.None) _CompressionLevel = Ionic.Zlib.CompressionLevel.Default; if (_container.ZipFile != null) _container.ZipFile.NotifyEntryChanged(); _restreamRequiredOnSave = true; } } /// /// Sets the compression level to be used for the entry when saving the zip /// archive. This applies only for CompressionMethod = DEFLATE. /// /// /// /// /// When using the DEFLATE compression method, Varying the compression /// level used on entries can affect the size-vs-speed tradeoff when /// compression and decompressing data streams or files. /// /// /// /// If you do not set this property, the default compression level is used, /// which normally gives a good balance of compression efficiency and /// compression speed. In some tests, using BestCompression can /// double the time it takes to compress, while delivering just a small /// increase in compression efficiency. This behavior will vary with the /// type of data you compress. If you are in doubt, just leave this setting /// alone, and accept the default. /// /// /// /// When setting this property on a ZipEntry that is read from an /// existing zip file, calling ZipFile.Save() will cause the new /// CompressionLevel to be used on the entry in the newly saved zip file. /// /// /// /// Setting this property may have the side effect of modifying the /// CompressionMethod property. If you set the CompressionLevel /// to a value other than None, CompressionMethod will be set /// to Deflate, if it was previously None. /// /// /// /// Setting this property has no effect if the CompressionMethod is something /// other than Deflate or None. /// /// /// /// public OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel CompressionLevel { get { return _CompressionLevel; } set { if (_CompressionMethod != (short)CompressionMethod.Deflate && _CompressionMethod != (short)CompressionMethod.None) return ; // no effect if (value == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.Default && _CompressionMethod == (short)CompressionMethod.Deflate) return; // nothing to do _CompressionLevel = value; if (value == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.None && _CompressionMethod == (short)CompressionMethod.None) return; // nothing more to do if (_CompressionLevel == OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel.None) _CompressionMethod = (short)OfficeOpenXml.Packaging.Ionic.Zip.CompressionMethod.None; else _CompressionMethod = (short)OfficeOpenXml.Packaging.Ionic.Zip.CompressionMethod.Deflate; if (_container.ZipFile != null) _container.ZipFile.NotifyEntryChanged(); _restreamRequiredOnSave = true; } } /// /// The compressed size of the file, in bytes, within the zip archive. /// /// /// /// When reading a ZipFile, this value is read in from the existing /// zip file. When creating or updating a ZipFile, the compressed /// size is computed during compression. Therefore the value on a /// ZipEntry is valid after a call to Save() (or one of its /// overloads) in that case. /// /// /// public Int64 CompressedSize { get { return _CompressedSize; } } /// /// The size of the file, in bytes, before compression, or after extraction. /// /// /// /// When reading a ZipFile, this value is read in from the existing /// zip file. When creating or updating a ZipFile, the uncompressed /// size is computed during compression. Therefore the value on a /// ZipEntry is valid after a call to Save() (or one of its /// overloads) in that case. /// /// /// public Int64 UncompressedSize { get { return _UncompressedSize; } } /// /// The ratio of compressed size to uncompressed size of the ZipEntry. /// /// /// /// /// This is a ratio of the compressed size to the uncompressed size of the /// entry, expressed as a double in the range of 0 to 100+. A value of 100 /// indicates no compression at all. It could be higher than 100 when the /// compression algorithm actually inflates the data, as may occur for small /// files, or uncompressible data that is encrypted. /// /// /// /// You could format it for presentation to a user via a format string of /// "{3,5:F0}%" to see it as a percentage. /// /// /// /// If the size of the original uncompressed file is 0, implying a /// denominator of 0, the return value will be zero. /// /// /// /// This property is valid after reading in an existing zip file, or after /// saving the ZipFile that contains the ZipEntry. You cannot know the /// effect of a compression transform until you try it. /// /// /// public Double CompressionRatio { get { if (UncompressedSize == 0) return 0; return 100 * (1.0 - (1.0 * CompressedSize) / (1.0 * UncompressedSize)); } } /// /// The 32-bit CRC (Cyclic Redundancy Check) on the contents of the ZipEntry. /// /// /// /// /// You probably don't need to concern yourself with this. It is used /// internally by DotNetZip to verify files or streams upon extraction. /// /// The value is a 32-bit /// CRC using 0xEDB88320 for the polynomial. This is the same CRC-32 used in /// PNG, MPEG-2, and other protocols and formats. It is a read-only property; when /// creating a Zip archive, the CRC for each entry is set only after a call to /// Save() on the containing ZipFile. When reading an existing zip file, the value /// of this property reflects the stored CRC for the entry. /// /// public Int32 Crc { get { return _Crc32; } } /// /// True if the entry is a directory (not a file). /// This is a readonly property on the entry. /// public bool IsDirectory { get { return _IsDirectory; } } /// /// A derived property that is true if the entry uses encryption. /// /// /// /// /// This is a readonly property on the entry. When reading a zip file, /// the value for the ZipEntry is determined by the data read /// from the zip file. After saving a ZipFile, the value of this /// property for each ZipEntry indicates whether encryption was /// actually used (which will have been true if the was set and the property /// was something other than . /// /// public bool UsesEncryption { get { return (_Encryption_FromZipFile != EncryptionAlgorithm.None); } } /// /// Set this to specify which encryption algorithm to use for the entry when /// saving it to a zip archive. /// /// /// /// /// /// Set this property in order to encrypt the entry when the ZipFile is /// saved. When setting this property, you must also set a on the entry. If you set a value other than on this property and do not set a /// Password then the entry will not be encrypted. The ZipEntry /// data is encrypted as the ZipFile is saved, when you call or one of its cousins on the containing /// ZipFile instance. You do not need to specify the Encryption /// when extracting entries from an archive. /// /// /// /// The Zip specification from PKWare defines a set of encryption algorithms, /// and the data formats for the zip archive that support them, and PKWare /// supports those algorithms in the tools it produces. Other vendors of tools /// and libraries, such as WinZip or Xceed, typically support a /// subset of the algorithms specified by PKWare. These tools can /// sometimes support additional different encryption algorithms and data /// formats, not specified by PKWare. The AES Encryption specified and /// supported by WinZip is the most popular example. This library supports a /// subset of the complete set of algorithms specified by PKWare and other /// vendors. /// /// /// /// There is no common, ubiquitous multi-vendor standard for strong encryption /// within zip files. There is broad support for so-called "traditional" Zip /// encryption, sometimes called Zip 2.0 encryption, as specified /// by PKWare, but this encryption is considered weak and /// breakable. This library currently supports the Zip 2.0 "weak" encryption, /// and also a stronger WinZip-compatible AES encryption, using either 128-bit /// or 256-bit key strength. If you want DotNetZip to support an algorithm /// that is not currently supported, call the author of this library and maybe /// we can talk business. /// /// /// /// The class also has a property. In most cases you will use /// that property when setting encryption. This property takes /// precedence over any Encryption set on the ZipFile itself. /// Typically, you would use the per-entry Encryption when most entries in the /// zip archive use one encryption algorithm, and a few entries use a /// different one. If all entries in the zip file use the same Encryption, /// then it is simpler to just set this property on the ZipFile itself, when /// creating a zip archive. /// /// /// /// Some comments on updating archives: If you read a ZipFile, you can /// modify the Encryption on an encrypted entry: you can remove encryption /// from an entry that was encrypted; you can encrypt an entry that was not /// encrypted previously; or, you can change the encryption algorithm. The /// changes in encryption are not made permanent until you call Save() on the /// ZipFile. To effect changes in encryption, the entry content is /// streamed through several transformations, depending on the modification /// the application has requested. For example if the entry is not encrypted /// and the application sets Encryption to PkzipWeak, then at /// the time of Save(), the original entry is read and decompressed, /// then re-compressed and encrypted. Conversely, if the original entry is /// encrypted with PkzipWeak encryption, and the application sets the /// Encryption property to WinZipAes128, then at the time of /// Save(), the original entry is decrypted via PKZIP encryption and /// decompressed, then re-compressed and re-encrypted with AES. This all /// happens automatically within the library, but it can be time-consuming for /// large entries. /// /// /// /// Additionally, when updating archives, it is not possible to change the /// password when changing the encryption algorithm. To change both the /// algorithm and the password, you need to Save() the zipfile twice. First /// set the Encryption to None, then call Save(). Then set the /// Encryption to the new value (not "None"), then call Save() /// once again. /// /// /// /// The WinZip AES encryption algorithms are not supported on the .NET Compact /// Framework. /// /// /// /// /// /// This example creates a zip archive that uses encryption, and then extracts /// entries from the archive. When creating the zip archive, the ReadMe.txt /// file is zipped without using a password or encryption. The other file /// uses encryption. /// /// /// // Create a zip archive with AES Encryption. /// using (ZipFile zip = new ZipFile()) /// { /// zip.AddFile("ReadMe.txt") /// ZipEntry e1= zip.AddFile("2008-Regional-Sales-Report.pdf"); /// e1.Encryption= EncryptionAlgorithm.WinZipAes256; /// e1.Password= "Top.Secret.No.Peeking!"; /// zip.Save("EncryptedArchive.zip"); /// } /// /// // Extract a zip archive that uses AES Encryption. /// // You do not need to specify the algorithm during extraction. /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) /// { /// // Specify the password that is used during extraction, for /// // all entries that require a password: /// zip.Password= "Top.Secret.No.Peeking!"; /// zip.ExtractAll("extractDirectory"); /// } /// /// /// /// ' Create a zip that uses Encryption. /// Using zip As New ZipFile() /// zip.AddFile("ReadMe.txt") /// Dim e1 as ZipEntry /// e1= zip.AddFile("2008-Regional-Sales-Report.pdf") /// e1.Encryption= EncryptionAlgorithm.WinZipAes256 /// e1.Password= "Top.Secret.No.Peeking!" /// zip.Save("EncryptedArchive.zip") /// End Using /// /// ' Extract a zip archive that uses AES Encryption. /// ' You do not need to specify the algorithm during extraction. /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) /// ' Specify the password that is used during extraction, for /// ' all entries that require a password: /// zip.Password= "Top.Secret.No.Peeking!" /// zip.ExtractAll("extractDirectory") /// End Using /// /// /// /// /// /// Thrown in the setter if EncryptionAlgorithm.Unsupported is specified. /// /// /// ZipEntry.Password /// ZipFile.Encryption internal EncryptionAlgorithm Encryption { get { return _Encryption; } set { if (value == _Encryption) return; // no change if (value == EncryptionAlgorithm.Unsupported) throw new InvalidOperationException("You may not set Encryption to that value."); // If the source is a zip archive and there was encryption // on the entry, this will not work. //if (this._Source == ZipEntrySource.ZipFile && _sourceIsEncrypted) // throw new InvalidOperationException("You cannot change the encryption method on encrypted entries read from archives."); _Encryption = value; _restreamRequiredOnSave = true; if (_container.ZipFile!=null) _container.ZipFile.NotifyEntryChanged(); } } /// /// The Password to be used when encrypting a ZipEntry upon /// ZipFile.Save(), or when decrypting an entry upon Extract(). /// /// /// /// /// This is a write-only property on the entry. Set this to request that the /// entry be encrypted when writing the zip archive, or set it to specify the /// password to be used when extracting an existing entry that is encrypted. /// /// /// /// The password set here is implicitly used to encrypt the entry during the /// operation, or to decrypt during the or operation. If you set /// the Password on a ZipEntry after calling Save(), there is no /// effect. /// /// /// /// Consider setting the property when using a /// password. Answering concerns that the standard password protection /// supported by all zip tools is weak, WinZip has extended the ZIP /// specification with a way to use AES Encryption to protect entries in the /// Zip file. Unlike the "PKZIP 2.0" encryption specified in the PKZIP /// specification, AES /// Encryption uses a standard, strong, tested, encryption /// algorithm. DotNetZip can create zip archives that use WinZip-compatible /// AES encryption, if you set the property. But, /// archives created that use AES encryption may not be readable by all other /// tools and libraries. For example, Windows Explorer cannot read a /// "compressed folder" (a zip file) that uses AES encryption, though it can /// read a zip file that uses "PKZIP encryption." /// /// /// /// The class also has a /// property. This property takes precedence over any password set on the /// ZipFile itself. Typically, you would use the per-entry Password when most /// entries in the zip archive use one password, and a few entries use a /// different password. If all entries in the zip file use the same password, /// then it is simpler to just set this property on the ZipFile itself, /// whether creating a zip archive or extracting a zip archive. /// /// /// /// Some comments on updating archives: If you read a ZipFile, you /// cannot modify the password on any encrypted entry, except by extracting /// the entry with the original password (if any), removing the original entry /// via , and then adding a new /// entry with a new Password. /// /// /// /// For example, suppose you read a ZipFile, and there is an encrypted /// entry. Setting the Password property on that ZipEntry and then /// calling Save() on the ZipFile does not update the password /// on that entry in the archive. Neither is an exception thrown. Instead, /// what happens during the Save() is the existing entry is copied /// through to the new zip archive, in its original encrypted form. Upon /// re-reading that archive, the entry can be decrypted with its original /// password. /// /// /// /// If you read a ZipFile, and there is an un-encrypted entry, you can set the /// Password on the entry and then call Save() on the ZipFile, and get /// encryption on that entry. /// /// /// /// /// /// /// This example creates a zip file with two entries, and then extracts the /// entries from the zip file. When creating the zip file, the two files are /// added to the zip file using password protection. Each entry uses a /// different password. During extraction, each file is extracted with the /// appropriate password. /// /// /// // create a file with encryption /// using (ZipFile zip = new ZipFile()) /// { /// ZipEntry entry; /// entry= zip.AddFile("Declaration.txt"); /// entry.Password= "123456!"; /// entry = zip.AddFile("Report.xls"); /// entry.Password= "1Secret!"; /// zip.Save("EncryptedArchive.zip"); /// } /// /// // extract entries that use encryption /// using (ZipFile zip = ZipFile.Read("EncryptedArchive.zip")) /// { /// ZipEntry entry; /// entry = zip["Declaration.txt"]; /// entry.Password = "123456!"; /// entry.Extract("extractDir"); /// entry = zip["Report.xls"]; /// entry.Password = "1Secret!"; /// entry.Extract("extractDir"); /// } /// /// /// /// /// Using zip As New ZipFile /// Dim entry as ZipEntry /// entry= zip.AddFile("Declaration.txt") /// entry.Password= "123456!" /// entry = zip.AddFile("Report.xls") /// entry.Password= "1Secret!" /// zip.Save("EncryptedArchive.zip") /// End Using /// /// /// ' extract entries that use encryption /// Using (zip as ZipFile = ZipFile.Read("EncryptedArchive.zip")) /// Dim entry as ZipEntry /// entry = zip("Declaration.txt") /// entry.Password = "123456!" /// entry.Extract("extractDir") /// entry = zip("Report.xls") /// entry.Password = "1Secret!" /// entry.Extract("extractDir") /// End Using /// /// /// /// /// /// /// ZipFile.Password public string Password { set { _Password = value; if (_Password == null) { _Encryption = EncryptionAlgorithm.None; } else { // We're setting a non-null password. // For entries obtained from a zip file that are encrypted, we cannot // simply restream (recompress, re-encrypt) the file data, because we // need the old password in order to decrypt the data, and then we // need the new password to encrypt. So, setting the password is // never going to work on an entry that is stored encrypted in a zipfile. // But it is not en error to set the password, obviously: callers will // set the password in order to Extract encrypted archives. // If the source is a zip archive and there was previously no encryption // on the entry, then we must re-stream the entry in order to encrypt it. if (this._Source == ZipEntrySource.ZipFile && !_sourceIsEncrypted) _restreamRequiredOnSave = true; if (Encryption == EncryptionAlgorithm.None) { _Encryption = EncryptionAlgorithm.PkzipWeak; } } } private get { return _Password; } } internal bool IsChanged { get { return _restreamRequiredOnSave | _metadataChanged; } } /// /// The action the library should take when extracting a file that already exists. /// /// /// /// /// This property affects the behavior of the Extract methods (one of the /// Extract() or ExtractWithPassword() overloads), when /// extraction would would overwrite an existing filesystem file. If you do /// not set this property, the library throws an exception when extracting /// an entry would overwrite an existing file. /// /// /// /// This property has no effect when extracting to a stream, or when the file to be /// extracted does not already exist. /// /// /// /// /// /// /// This example shows how to set the ExtractExistingFile property in /// an ExtractProgress event, in response to user input. The /// ExtractProgress event is invoked if and only if the /// ExtractExistingFile property was previously set to /// ExtractExistingFileAction.InvokeExtractProgressEvent. /// /// public static void ExtractProgress(object sender, ExtractProgressEventArgs e) /// { /// if (e.EventType == ZipProgressEventType.Extracting_BeforeExtractEntry) /// Console.WriteLine("extract {0} ", e.CurrentEntry.FileName); /// /// else if (e.EventType == ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite) /// { /// ZipEntry entry = e.CurrentEntry; /// string response = null; /// // Ask the user if he wants overwrite the file /// do /// { /// Console.Write("Overwrite {0} in {1} ? (y/n/C) ", entry.FileName, e.ExtractLocation); /// response = Console.ReadLine(); /// Console.WriteLine(); /// /// } while (response != null && response[0]!='Y' && /// response[0]!='N' && response[0]!='C'); /// /// if (response[0]=='C') /// e.Cancel = true; /// else if (response[0]=='Y') /// entry.ExtractExistingFile = ExtractExistingFileAction.OverwriteSilently; /// else /// entry.ExtractExistingFile= ExtractExistingFileAction.DoNotOverwrite; /// } /// } /// /// internal ExtractExistingFileAction ExtractExistingFile { get; set; } /// /// The action to take when an error is encountered while /// opening or reading files as they are saved into a zip archive. /// /// /// /// /// Errors can occur within a call to ZipFile.Save, as the various files contained /// in a ZipFile are being saved into the zip archive. During the /// Save, DotNetZip will perform a File.Open on the file /// associated to the ZipEntry, and then will read the entire contents of /// the file as it is zipped. Either the open or the Read may fail, because /// of lock conflicts or other reasons. Using this property, you can /// specify the action to take when such errors occur. /// /// /// /// Typically you will NOT set this property on individual ZipEntry /// instances. Instead, you will set the ZipFile.ZipErrorAction property on /// the ZipFile instance, before adding any entries to the /// ZipFile. If you do this, errors encountered on behalf of any of /// the entries in the ZipFile will be handled the same way. /// /// /// /// But, if you use a handler, you will want /// to set this property on the ZipEntry within the handler, to /// communicate back to DotNetZip what you would like to do with the /// particular error. /// /// /// /// /// internal ZipErrorAction ZipErrorAction { get; set; } /// /// Indicates whether the entry was included in the most recent save. /// /// /// An entry can be excluded or skipped from a save if there is an error /// opening or reading the entry. /// /// internal bool IncludedInMostRecentSave { get { return !_skippedDuringSave; } } /// /// A callback that allows the application to specify the compression to use /// for a given entry that is about to be added to the zip archive. /// /// /// /// /// See /// /// public SetCompressionCallback SetCompression { get; set; } /// /// Set to indicate whether to use UTF-8 encoding for filenames and comments. /// /// /// /// /// /// If this flag is set, the comment and filename for the entry will be /// encoded with UTF-8, as described in the Zip /// specification, if necessary. "Necessary" means, the filename or /// entry comment (if any) cannot be reflexively encoded and decoded using the /// default code page, IBM437. /// /// /// /// Setting this flag to true is equivalent to setting to System.Text.Encoding.UTF8. /// /// /// /// This flag has no effect or relation to the text encoding used within the /// file itself. /// /// /// [Obsolete("Beginning with v1.9.1.6 of DotNetZip, this property is obsolete. It will be removed in a future version of the library. Your applications should use AlternateEncoding and AlternateEncodingUsage instead.")] public bool UseUnicodeAsNecessary { get { return (AlternateEncoding == System.Text.Encoding.GetEncoding("UTF-8")) && (AlternateEncodingUsage == ZipOption.AsNecessary); } set { if (value) { AlternateEncoding = System.Text.Encoding.GetEncoding("UTF-8"); AlternateEncodingUsage = ZipOption.AsNecessary; } else { AlternateEncoding = Ionic.Zip.ZipFile.DefaultEncoding; AlternateEncodingUsage = ZipOption.Never; } } } /// /// The text encoding to use for the FileName and Comment on this ZipEntry, /// when the default encoding is insufficient. /// /// /// /// /// /// Don't use this property. See . /// /// /// [Obsolete("This property is obsolete since v1.9.1.6. Use AlternateEncoding and AlternateEncodingUsage instead.", true)] public System.Text.Encoding ProvisionalAlternateEncoding { get; set; } /// /// Specifies the alternate text encoding used by this ZipEntry /// /// /// /// The default text encoding used in Zip files for encoding filenames and /// comments is IBM437, which is something like a superset of ASCII. In /// cases where this is insufficient, applications can specify an /// alternate encoding. /// /// /// When creating a zip file, the usage of the alternate encoding is /// governed by the property. /// Typically you would set both properties to tell DotNetZip to employ an /// encoding that is not IBM437 in the zipfile you are creating. /// /// /// Keep in mind that because the ZIP specification states that the only /// valid encodings to use are IBM437 and UTF-8, if you use something /// other than that, then zip tools and libraries may not be able to /// successfully read the zip archive you generate. /// /// /// The zip specification states that applications should presume that /// IBM437 is in use, except when a special bit is set, which indicates /// UTF-8. There is no way to specify an arbitrary code page, within the /// zip file itself. When you create a zip file encoded with gb2312 or /// ibm861 or anything other than IBM437 or UTF-8, then the application /// that reads the zip file needs to "know" which code page to use. In /// some cases, the code page used when reading is chosen implicitly. For /// example, WinRar uses the ambient code page for the host desktop /// operating system. The pitfall here is that if you create a zip in /// Copenhagen and send it to Tokyo, the reader of the zipfile may not be /// able to decode successfully. /// /// /// /// This example shows how to create a zipfile encoded with a /// language-specific encoding: /// /// using (var zip = new ZipFile()) /// { /// zip.AlternateEnoding = System.Text.Encoding.GetEncoding("ibm861"); /// zip.AlternateEnodingUsage = ZipOption.Always; /// zip.AddFileS(arrayOfFiles); /// zip.Save("Myarchive-Encoded-in-IBM861.zip"); /// } /// /// /// public System.Text.Encoding AlternateEncoding { get; set; } /// /// Describes if and when this instance should apply /// AlternateEncoding to encode the FileName and Comment, when /// saving. /// /// internal ZipOption AlternateEncodingUsage { get; set; } // /// // /// The text encoding actually used for this ZipEntry. // /// // /// // /// // /// // /// // /// This read-only property describes the encoding used by the // /// ZipEntry. If the entry has been read in from an existing ZipFile, // /// then it may take the value UTF-8, if the entry is coded to specify UTF-8. // /// If the entry does not specify UTF-8, the typical case, then the encoding // /// used is whatever the application specified in the call to // /// ZipFile.Read(). If the application has used one of the overloads of // /// ZipFile.Read() that does not accept an encoding parameter, then the // /// encoding used is IBM437, which is the default encoding described in the // /// ZIP specification. // /// // /// // /// If the entry is being created, then the value of ActualEncoding is taken // /// according to the logic described in the documentation for . // /// // /// // /// An application might be interested in retrieving this property to see if // /// an entry read in from a file has used Unicode (UTF-8). // /// // /// // /// // /// // public System.Text.Encoding ActualEncoding // { // get // { // return _actualEncoding; // } // } internal static string NameInArchive(String filename, string directoryPathInArchive) { string result = null; if (directoryPathInArchive == null) result = filename; else { if (String.IsNullOrEmpty(directoryPathInArchive)) { result = Path.GetFileName(filename); } else { // explicitly specify a pathname for this file result = Path.Combine(directoryPathInArchive, Path.GetFileName(filename)); } } //result = Path.GetFullPath(result); result = SharedUtilities.NormalizePathForUseInZipFile(result); return result; } // workitem 9073 internal static ZipEntry CreateFromNothing(String nameInArchive) { return Create(nameInArchive, ZipEntrySource.None, null, null); } internal static ZipEntry CreateFromFile(String filename, string nameInArchive) { return Create(nameInArchive, ZipEntrySource.FileSystem, filename, null); } internal static ZipEntry CreateForStream(String entryName, Stream s) { return Create(entryName, ZipEntrySource.Stream, s, null); } internal static ZipEntry CreateForWriter(String entryName, WriteDelegate d) { return Create(entryName, ZipEntrySource.WriteDelegate, d, null); } internal static ZipEntry CreateForJitStreamProvider(string nameInArchive, OpenDelegate opener, CloseDelegate closer) { return Create(nameInArchive, ZipEntrySource.JitStream, opener, closer); } internal static ZipEntry CreateForZipOutputStream(string nameInArchive) { return Create(nameInArchive, ZipEntrySource.ZipOutputStream, null, null); } private static ZipEntry Create(string nameInArchive, ZipEntrySource source, Object arg1, Object arg2) { if (String.IsNullOrEmpty(nameInArchive)) throw new Ionic.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 Ionic.Zip.ZipException("The filename must be non-null and non-empty."); try { // 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 // Ionic.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); #elif SILVERLIGHT entry._Mtime = entry._Ctime = entry._Atime = System.DateTime.UtcNow; entry._ExternalFileAttrs = (int)0; #else // workitem 6878?? entry._Mtime = File.GetLastWriteTime(filename).ToUniversalTime(); entry._Ctime = File.GetCreationTime(filename).ToUniversalTime(); entry._Atime = File.GetLastAccessTime(filename).ToUniversalTime(); // 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 } catch (System.IO.PathTooLongException ptle) { // workitem 14035 var msg = String.Format("The path is too long, filename={0}", filename); throw new ZipException(msg, ptle); } } 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 void MarkAsDirectory() { _IsDirectory = true; // workitem 6279 if (!_FileNameInArchive.EndsWith("/")) _FileNameInArchive += "/"; } /// /// Indicates whether an entry is marked as a text file. Be careful when /// using on this property. Unless you have a good reason, you should /// probably ignore this property. /// /// /// /// /// The ZIP format includes a provision for specifying whether an entry in /// the zip archive is a text or binary file. This property exposes that /// metadata item. Be careful when using this property: It's not clear /// that this property as a firm meaning, across tools and libraries. /// /// /// /// To be clear, when reading a zip file, the property value may or may /// not be set, and its value may or may not be valid. Not all entries /// that you may think of as "text" entries will be so marked, and entries /// marked as "text" are not guaranteed in any way to be text entries. /// Whether the value is set and set correctly depends entirely on the /// application that produced the zip file. /// /// /// /// There are many zip tools available, and when creating zip files, some /// of them "respect" the IsText metadata field, and some of them do not. /// Unfortunately, even when an application tries to do "the right thing", /// it's not always clear what "the right thing" is. /// /// /// /// There's no firm definition of just what it means to be "a text file", /// and the zip specification does not help in this regard. Twenty years /// ago, text was ASCII, each byte was less than 127. IsText meant, all /// bytes in the file were less than 127. These days, it is not the case /// that all text files have all bytes less than 127. Any unicode file /// may have bytes that are above 0x7f. The zip specification has nothing /// to say on this topic. Therefore, it's not clear what IsText really /// means. /// /// /// /// This property merely tells a reading application what is stored in the /// metadata for an entry, without guaranteeing its validity or its /// meaning. /// /// /// /// When DotNetZip is used to create a zipfile, it attempts to set this /// field "correctly." For example, if a file ends in ".txt", this field /// will be set. Your application may override that default setting. When /// writing a zip file, you must set the property before calling /// Save() on the ZipFile. /// /// /// /// When reading a zip file, a more general way to decide just what kind /// of file is contained in a particular entry is to use the file type /// database stored in the operating system. The operating system stores /// a table that says, a file with .jpg extension is a JPG image file, a /// file with a .xml extension is an XML document, a file with a .txt is a /// pure ASCII text document, and so on. To get this information on /// Windows, you /// need to read and parse the registry. /// /// /// /// /// using (var zip = new ZipFile()) /// { /// var e = zip.UpdateFile("Descriptions.mme", ""); /// e.IsText = true; /// zip.Save(zipPath); /// } /// /// /// /// Using zip As New ZipFile /// Dim e2 as ZipEntry = zip.AddFile("Descriptions.mme", "") /// e.IsText= True /// zip.Save(zipPath) /// End Using /// /// public bool IsText { // workitem 7801 get { return _IsText; } set { _IsText = value; } } /// Provides a string representation of the instance. /// a string representation of the instance. public override String ToString() { return String.Format("ZipEntry::{0}", FileName); } internal Stream ArchiveStream { get { if (_archiveStream == null) { if (_container.ZipFile != null) { var zf = _container.ZipFile; zf.Reset(false); _archiveStream = zf.StreamForDiskNumber(_diskNumber); } else { _archiveStream = _container.ZipOutputStream.OutputStream; } } return _archiveStream; } } private void SetFdpLoh() { // The value for FileDataPosition has not yet been set. // Therefore, seek to the local header, and figure the start of file data. // workitem 8098: ok (restore) long origPosition = this.ArchiveStream.Position; try { this.ArchiveStream.Seek(this._RelativeOffsetOfLocalHeader, SeekOrigin.Begin); // workitem 10178 Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream); } catch (System.IO.IOException exc1) { string description = String.Format("Exception seeking entry({0}) offset(0x{1:X8}) len(0x{2:X8})", this.FileName, this._RelativeOffsetOfLocalHeader, this.ArchiveStream.Length); throw new BadStateException(description, exc1); } byte[] block = new byte[30]; this.ArchiveStream.Read(block, 0, block.Length); // At this point we could verify the contents read from the local header // with the contents read from the central header. We could, but don't need to. // So we won't. Int16 filenameLength = (short)(block[26] + block[27] * 256); Int16 extraFieldLength = (short)(block[28] + block[29] * 256); // Console.WriteLine(" pos 0x{0:X8} ({0})", this.ArchiveStream.Position); // Console.WriteLine(" seek 0x{0:X8} ({0})", filenameLength + extraFieldLength); this.ArchiveStream.Seek(filenameLength + extraFieldLength, SeekOrigin.Current); // workitem 10178 Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream); this._LengthOfHeader = 30 + extraFieldLength + filenameLength + GetLengthOfCryptoHeaderBytes(_Encryption_FromZipFile); // Console.WriteLine(" ROLH 0x{0:X8} ({0})", _RelativeOffsetOfLocalHeader); // Console.WriteLine(" LOH 0x{0:X8} ({0})", _LengthOfHeader); // workitem 8098: ok (arithmetic) this.__FileDataPosition = _RelativeOffsetOfLocalHeader + _LengthOfHeader; // Console.WriteLine(" FDP 0x{0:X8} ({0})", __FileDataPosition); // restore file position: // workitem 8098: ok (restore) this.ArchiveStream.Seek(origPosition, SeekOrigin.Begin); // workitem 10178 Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(this.ArchiveStream); } #if AESCRYPTO private static int GetKeyStrengthInBits(EncryptionAlgorithm a) { if (a == EncryptionAlgorithm.WinZipAes256) return 256; else if (a == EncryptionAlgorithm.WinZipAes128) return 128; return -1; } #endif internal static int GetLengthOfCryptoHeaderBytes(EncryptionAlgorithm a) { //if ((_BitField & 0x01) != 0x01) return 0; if (a == EncryptionAlgorithm.None) return 0; #if AESCRYPTO if (a == EncryptionAlgorithm.WinZipAes128 || a == EncryptionAlgorithm.WinZipAes256) { int KeyStrengthInBits = GetKeyStrengthInBits(a); int sizeOfSaltAndPv = ((KeyStrengthInBits / 8 / 2) + 2); return sizeOfSaltAndPv; } #endif if (a == EncryptionAlgorithm.PkzipWeak) return 12; throw new ZipException("internal error"); } internal long FileDataPosition { get { if (__FileDataPosition == -1) SetFdpLoh(); return __FileDataPosition; } } private int LengthOfHeader { get { if (_LengthOfHeader == 0) SetFdpLoh(); return _LengthOfHeader; } } private ZipCrypto _zipCrypto_forExtract; private ZipCrypto _zipCrypto_forWrite; #if AESCRYPTO private WinZipAesCrypto _aesCrypto_forExtract; private WinZipAesCrypto _aesCrypto_forWrite; private Int16 _WinZipAesMethod; #endif internal DateTime _LastModified; private DateTime _Mtime, _Atime, _Ctime; // workitem 6878: NTFS quantities private bool _ntfsTimesAreSet; private bool _emitNtfsTimes = true; private bool _emitUnixTimes; // by default, false private bool _TrimVolumeFromFullyQualifiedPaths = true; // by default, trim them. internal string _LocalFileName; private string _FileNameInArchive; internal Int16 _VersionNeeded; internal Int16 _BitField; internal Int16 _CompressionMethod; private Int16 _CompressionMethod_FromZipFile; private Ionic.Zlib.CompressionLevel _CompressionLevel; internal string _Comment; private bool _IsDirectory; private byte[] _CommentBytes; internal Int64 _CompressedSize; internal Int64 _CompressedFileDataSize; // CompressedSize less 12 bytes for the encryption header, if any internal Int64 _UncompressedSize; internal Int32 _TimeBlob; private bool _crcCalculated; internal Int32 _Crc32; internal byte[] _Extra; private bool _metadataChanged; private bool _restreamRequiredOnSave; private bool _sourceIsEncrypted; private bool _skippedDuringSave; private UInt32 _diskNumber; private static System.Text.Encoding ibm437 = System.Text.Encoding.GetEncoding("IBM437"); //private System.Text.Encoding _provisionalAlternateEncoding = System.Text.Encoding.GetEncoding("IBM437"); private System.Text.Encoding _actualEncoding; internal ZipContainer _container; private long __FileDataPosition = -1; private byte[] _EntryHeader; internal Int64 _RelativeOffsetOfLocalHeader; private Int64 _future_ROLH; private Int64 _TotalEntrySize; private int _LengthOfHeader; private int _LengthOfTrailer; internal bool _InputUsesZip64; private UInt32 _UnsupportedAlgorithmId; internal string _Password; internal ZipEntrySource _Source; internal EncryptionAlgorithm _Encryption; internal EncryptionAlgorithm _Encryption_FromZipFile; internal byte[] _WeakEncryptionHeader; internal Stream _archiveStream; private Stream _sourceStream; private Nullable _sourceStreamOriginalPosition; private bool _sourceWasJitProvided; private bool _ioOperationCanceled; private bool _presumeZip64; private Nullable _entryRequiresZip64; private Nullable _OutputUsesZip64; private bool _IsText; // workitem 7801 private ZipEntryTimestamp _timestamp; private static System.DateTime _unixEpoch = new System.DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); private static System.DateTime _win32Epoch = System.DateTime.FromFileTimeUtc(0L); private static System.DateTime _zeroHour = new System.DateTime(1, 1, 1, 0, 0, 0, DateTimeKind.Utc); private WriteDelegate _WriteDelegate; private OpenDelegate _OpenDelegate; private CloseDelegate _CloseDelegate; // summary // The default size of the IO buffer for ZipEntry instances. Currently it is 8192 bytes. // summary //public const int IO_BUFFER_SIZE_DEFAULT = 8192; // 0x8000; // 0x4400 } /// /// An enum that specifies the type of timestamp available on the ZipEntry. /// /// /// /// /// /// The last modified time of a file can be stored in multiple ways in /// a zip file, and they are not mutually exclusive: /// /// /// /// /// In the so-called "DOS" format, which has a 2-second precision. Values /// are rounded to the nearest even second. For example, if the time on the /// file is 12:34:43, then it will be stored as 12:34:44. This first value /// is accessible via the LastModified property. This value is always /// present in the metadata for each zip entry. In some cases the value is /// invalid, or zero. /// /// /// /// In the so-called "Windows" or "NTFS" format, as an 8-byte integer /// quantity expressed as the number of 1/10 milliseconds (in other words /// the number of 100 nanosecond units) since January 1, 1601 (UTC). This /// format is how Windows represents file times. This time is accessible /// via the ModifiedTime property. /// /// /// /// In the "Unix" format, a 4-byte quantity specifying the number of seconds since /// January 1, 1970 UTC. /// /// /// /// In an older format, now deprecated but still used by some current /// tools. This format is also a 4-byte quantity specifying the number of /// seconds since January 1, 1970 UTC. /// /// /// /// /// /// This bit field describes which of the formats were found in a ZipEntry that was read. /// /// /// [Flags] internal enum ZipEntryTimestamp { /// /// Default value. /// None = 0, /// /// A DOS timestamp with 2-second precision. /// DOS = 1, /// /// A Windows timestamp with 100-ns precision. /// Windows = 2, /// /// A Unix timestamp with 1-second precision. /// Unix = 4, /// /// A Unix timestamp with 1-second precision, stored in InfoZip v1 format. This /// format is outdated and is supported for reading archives only. /// InfoZip1 = 8, } /// /// The method of compression to use for a particular ZipEntry. /// /// /// /// PKWare's /// ZIP Specification describes a number of distinct /// cmopression methods that can be used within a zip /// file. DotNetZip supports a subset of them. /// internal enum CompressionMethod { /// /// No compression at all. For COM environments, the value is 0 (zero). /// None = 0, /// /// DEFLATE compression, as described in IETF RFC /// 1951. This is the "normal" compression used in zip /// files. For COM environments, the value is 8. /// Deflate = 8, #if BZIP /// /// BZip2 compression, a compression algorithm developed by Julian Seward. /// For COM environments, the value is 12. /// BZip2 = 12, #endif } #if NETCF internal class NetCfFile { public static int SetTimes(string filename, DateTime ctime, DateTime atime, DateTime mtime) { IntPtr hFile = (IntPtr) CreateFileCE(filename, (uint)0x40000000L, // (uint)FileAccess.Write, (uint)0x00000002L, // (uint)FileShare.Write, 0, (uint) 3, // == open existing (uint)0, // flagsAndAttributes 0); if((int)hFile == -1) { // workitem 7944: don't throw on failure to set file times // throw new ZipException("CreateFileCE Failed"); return Interop.Marshal.GetLastWin32Error(); } SetFileTime(hFile, BitConverter.GetBytes(ctime.ToFileTime()), BitConverter.GetBytes(atime.ToFileTime()), BitConverter.GetBytes(mtime.ToFileTime())); CloseHandle(hFile); return 0; } public static int SetLastWriteTime(string filename, DateTime mtime) { IntPtr hFile = (IntPtr) CreateFileCE(filename, (uint)0x40000000L, // (uint)FileAccess.Write, (uint)0x00000002L, // (uint)FileShare.Write, 0, (uint) 3, // == open existing (uint)0, // flagsAndAttributes 0); if((int)hFile == -1) { // workitem 7944: don't throw on failure to set file time // throw new ZipException(String.Format("CreateFileCE Failed ({0})", // Interop.Marshal.GetLastWin32Error())); return Interop.Marshal.GetLastWin32Error(); } SetFileTime(hFile, null, null, BitConverter.GetBytes(mtime.ToFileTime())); CloseHandle(hFile); return 0; } [Interop.DllImport("coredll.dll", EntryPoint="CreateFile", SetLastError=true)] internal static extern int CreateFileCE(string lpFileName, uint dwDesiredAccess, uint dwShareMode, int lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, int hTemplateFile); [Interop.DllImport("coredll", EntryPoint="GetFileAttributes", SetLastError=true)] internal static extern uint GetAttributes(string lpFileName); [Interop.DllImport("coredll", EntryPoint="SetFileAttributes", SetLastError=true)] internal static extern bool SetAttributes(string lpFileName, uint dwFileAttributes); [Interop.DllImport("coredll", EntryPoint="SetFileTime", SetLastError=true)] internal static extern bool SetFileTime(IntPtr hFile, byte[] lpCreationTime, byte[] lpLastAccessTime, byte[] lpLastWriteTime); [Interop.DllImport("coredll.dll", SetLastError=true)] internal static extern bool CloseHandle(IntPtr hObject); } #endif }