// ZipEntry.cs // // Copyright (C) 2001 Mike Krueger // Copyright (C) 2004 John Reilly // // This file was translated from java, it was part of the GNU Classpath // Copyright (C) 2001 Free Software Foundation, Inc. // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // Linking this library statically or dynamically with other modules is // making a combined work based on this library. Thus, the terms and // conditions of the GNU General Public License cover the whole // combination. // // As a special exception, the copyright holders of this library give you // permission to link this library with independent modules to produce an // executable, regardless of the license terms of these independent // modules, and to copy and distribute the resulting executable under // terms of your choice, provided that you also meet, for each linked // independent module, the terms and conditions of the license of that // module. An independent module is a module which is not derived from // or based on this library. If you modify this library, you may extend // this exception to your version of the library, but you are not // obligated to do so. If you do not wish to do so, delete this // exception statement from your version. // HISTORY // 22-12-2009 DavidPierson Added AES support // 02-02-2010 DavidPierson Changed NTFS Extra Data min length to 4 using ICSharpCode.SharpZipLib.Zip; using System; using System.IO; namespace ICSharpCode.SharpZipLib.Zip1 { /// /// Defines known values for the property. /// public enum HostSystemID { /// /// Host system = MSDOS /// Msdos = 0, /// /// Host system = Amiga /// Amiga = 1, /// /// Host system = Open VMS /// OpenVms = 2, /// /// Host system = Unix /// Unix = 3, /// /// Host system = VMCms /// VMCms = 4, /// /// Host system = Atari ST /// AtariST = 5, /// /// Host system = OS2 /// OS2 = 6, /// /// Host system = Macintosh /// Macintosh = 7, /// /// Host system = ZSystem /// ZSystem = 8, /// /// Host system = Cpm /// Cpm = 9, /// /// Host system = Windows NT /// WindowsNT = 10, /// /// Host system = MVS /// MVS = 11, /// /// Host system = VSE /// Vse = 12, /// /// Host system = Acorn RISC /// AcornRisc = 13, /// /// Host system = VFAT /// Vfat = 14, /// /// Host system = Alternate MVS /// AlternateMvs = 15, /// /// Host system = BEOS /// BeOS = 16, /// /// Host system = Tandem /// Tandem = 17, /// /// Host system = OS400 /// OS400 = 18, /// /// Host system = OSX /// OSX = 19, /// /// Host system = WinZIP AES /// WinZipAES = 99, } /// /// This class represents an entry in a zip archive. This can be a file /// or a directory /// ZipFile and ZipInputStream will give you instances of this class as /// information about the members in an archive. ZipOutputStream /// uses an instance of this class when creating an entry in a Zip file. ///
///
Author of the original java version : Jochen Hoenicke ///
public class ZipEntry : ICloneable { [Flags] enum Known : byte { None = 0, Size = 0x01, CompressedSize = 0x02, Crc = 0x04, Time = 0x08, ExternalAttributes = 0x10, } #region Constructors /// /// Creates a zip entry with the given name. /// /// /// The name for this entry. Can include directory components. /// The convention for names is 'unix' style paths with relative names only. /// There are with no device names and path elements are separated by '/' characters. /// /// /// The name passed is null /// public ZipEntry(string name) : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated) { } /// /// Creates a zip entry with the given name and version required to extract /// /// /// The name for this entry. Can include directory components. /// The convention for names is 'unix' style paths with no device names and /// path elements separated by '/' characters. This is not enforced see CleanName /// on how to ensure names are valid if this is desired. /// /// /// The minimum 'feature version' required this entry /// /// /// The name passed is null /// internal ZipEntry(string name, int versionRequiredToExtract) : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy, CompressionMethod.Deflated) { } /// /// Initializes an entry with the given name and made by information /// /// Name for this entry /// Version and HostSystem Information /// Minimum required zip feature version required to extract this entry /// Compression method for this entry. /// /// The name passed is null /// /// /// versionRequiredToExtract should be 0 (auto-calculate) or > 10 /// /// /// This constructor is used by the ZipFile class when reading from the central header /// It is not generally useful, use the constructor specifying the name only. /// internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo, CompressionMethod method) { if (name == null) { throw new System.ArgumentNullException("name"); } if ( name.Length > 0xffff ) { throw new ArgumentException("Name is too long", "name"); } if ( (versionRequiredToExtract != 0) && (versionRequiredToExtract < 10) ) { throw new ArgumentOutOfRangeException("versionRequiredToExtract"); } this.DateTime = System.DateTime.Now; this.name = name; this.versionMadeBy = (ushort)madeByInfo; this.versionToExtract = (ushort)versionRequiredToExtract; this.method = method; } /// /// Creates a deep copy of the given zip entry. /// /// /// The entry to copy. /// [Obsolete("Use Clone instead")] public ZipEntry(ZipEntry entry) { if ( entry == null ) { throw new ArgumentNullException("entry"); } known = entry.known; name = entry.name; size = entry.size; compressedSize = entry.compressedSize; crc = entry.crc; dosTime = entry.dosTime; method = entry.method; comment = entry.comment; versionToExtract = entry.versionToExtract; versionMadeBy = entry.versionMadeBy; externalFileAttributes = entry.externalFileAttributes; flags = entry.flags; zipFileIndex = entry.zipFileIndex; offset = entry.offset; forceZip64_ = entry.forceZip64_; if ( entry.extra != null ) { extra = new byte[entry.extra.Length]; Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length); } } #endregion /// /// Get a value indicating wether the entry has a CRC value available. /// public bool HasCrc { get { return (known & Known.Crc) != 0; } } /// /// Get/Set flag indicating if entry is encrypted. /// A simple helper routine to aid interpretation of flags /// /// This is an assistant that interprets the flags property. public bool IsCrypted { get { return (flags & 1) != 0; } set { if (value) { flags |= 1; } else { flags &= ~1; } } } /// /// Get / set a flag indicating wether entry name and comment text are /// encoded in unicode UTF8. /// /// This is an assistant that interprets the flags property. public bool IsUnicodeText { get { return ( flags & (int)GeneralBitFlags.UnicodeText ) != 0; } set { if ( value ) { flags |= (int)GeneralBitFlags.UnicodeText; } else { flags &= ~(int)GeneralBitFlags.UnicodeText; } } } /// /// Value used during password checking for PKZIP 2.0 / 'classic' encryption. /// internal byte CryptoCheckValue { get { return cryptoCheckValue_; } set { cryptoCheckValue_ = value; } } /// /// Get/Set general purpose bit flag for entry /// /// /// General purpose bit flag
///
/// Bit 0: If set, indicates the file is encrypted
/// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating
/// Imploding:
/// Bit 1 if set indicates an 8K sliding dictionary was used. If clear a 4k dictionary was used
/// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise
///
/// Deflating:
/// Bit 2 Bit 1
/// 0 0 Normal compression was used
/// 0 1 Maximum compression was used
/// 1 0 Fast compression was used
/// 1 1 Super fast compression was used
///
/// Bit 3: If set, the fields crc-32, compressed size /// and uncompressed size are were not able to be written during zip file creation /// The correct values are held in a data descriptor immediately following the compressed data.
/// Bit 4: Reserved for use by PKZIP for enhanced deflating
/// Bit 5: If set indicates the file contains compressed patch data
/// Bit 6: If set indicates strong encryption was used.
/// Bit 7-10: Unused or reserved
/// Bit 11: If set the name and comments for this entry are in unicode.
/// Bit 12-15: Unused or reserved
///
/// /// public int Flags { get { return flags; } set { flags = value; } } /// /// Get/Set index of this entry in Zip file /// /// This is only valid when the entry is part of a public long ZipFileIndex { get { return zipFileIndex; } set { zipFileIndex = value; } } /// /// Get/set offset for use in central header /// public long Offset { get { return offset; } set { offset = value; } } /// /// Get/Set external file attributes as an integer. /// The values of this are operating system dependant see /// HostSystem for details /// public int ExternalFileAttributes { get { if ((known & Known.ExternalAttributes) == 0) { return -1; } else { return externalFileAttributes; } } set { externalFileAttributes = value; known |= Known.ExternalAttributes; } } /// /// Get the version made by for this entry or zero if unknown. /// The value / 10 indicates the major version number, and /// the value mod 10 is the minor version number /// public int VersionMadeBy { get { return (versionMadeBy & 0xff); } } /// /// Get a value indicating this entry is for a DOS/Windows system. /// public bool IsDOSEntry { get { return ((HostSystem == ( int )HostSystemID.Msdos) || (HostSystem == ( int )HostSystemID.WindowsNT)); } } /// /// Test the external attributes for this to /// see if the external attributes are Dos based (including WINNT and variants) /// and match the values /// /// The attributes to test. /// Returns true if the external attributes are known to be DOS/Windows /// based and have the same attributes set as the value passed. bool HasDosAttributes(int attributes) { bool result = false; if ( (known & Known.ExternalAttributes) != 0 ) { if ( ((HostSystem == (int)HostSystemID.Msdos) || (HostSystem == (int)HostSystemID.WindowsNT)) && (ExternalFileAttributes & attributes) == attributes) { result = true; } } return result; } /// /// Gets the compatability information for the external file attribute /// If the external file attributes are compatible with MS-DOS and can be read /// by PKZIP for DOS version 2.04g then this value will be zero. Otherwise the value /// will be non-zero and identify the host system on which the attributes are compatible. /// /// /// /// The values for this as defined in the Zip File format and by others are shown below. The values are somewhat /// misleading in some cases as they are not all used as shown. You should consult the relevant documentation /// to obtain up to date and correct information. The modified appnote by the infozip group is /// particularly helpful as it documents a lot of peculiarities. The document is however a little dated. /// /// 0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems) /// 1 - Amiga /// 2 - OpenVMS /// 3 - Unix /// 4 - VM/CMS /// 5 - Atari ST /// 6 - OS/2 HPFS /// 7 - Macintosh /// 8 - Z-System /// 9 - CP/M /// 10 - Windows NTFS /// 11 - MVS (OS/390 - Z/OS) /// 12 - VSE /// 13 - Acorn Risc /// 14 - VFAT /// 15 - Alternate MVS /// 16 - BeOS /// 17 - Tandem /// 18 - OS/400 /// 19 - OS/X (Darwin) /// 99 - WinZip AES /// remainder - unused /// /// public int HostSystem { get { return (versionMadeBy >> 8) & 0xff; } set { versionMadeBy &= 0xff; versionMadeBy |= (ushort)((value & 0xff) << 8); } } /// /// Get minimum Zip feature version required to extract this entry /// /// /// Minimum features are defined as:
/// 1.0 - Default value
/// 1.1 - File is a volume label
/// 2.0 - File is a folder/directory
/// 2.0 - File is compressed using Deflate compression
/// 2.0 - File is encrypted using traditional encryption
/// 2.1 - File is compressed using Deflate64
/// 2.5 - File is compressed using PKWARE DCL Implode
/// 2.7 - File is a patch data set
/// 4.5 - File uses Zip64 format extensions
/// 4.6 - File is compressed using BZIP2 compression
/// 5.0 - File is encrypted using DES
/// 5.0 - File is encrypted using 3DES
/// 5.0 - File is encrypted using original RC2 encryption
/// 5.0 - File is encrypted using RC4 encryption
/// 5.1 - File is encrypted using AES encryption
/// 5.1 - File is encrypted using corrected RC2 encryption
/// 5.1 - File is encrypted using corrected RC2-64 encryption
/// 6.1 - File is encrypted using non-OAEP key wrapping
/// 6.2 - Central directory encryption (not confirmed yet)
/// 6.3 - File is compressed using LZMA
/// 6.3 - File is compressed using PPMD+
/// 6.3 - File is encrypted using Blowfish
/// 6.3 - File is encrypted using Twofish
///
/// public int Version { get { // Return recorded version if known. if (versionToExtract != 0) { return versionToExtract; } else { int result = 10; if (AESKeySize > 0) { result = ZipConstants.VERSION_AES; // Ver 5.1 = AES } else if (CentralHeaderRequiresZip64) { result = ZipConstants.VersionZip64; } else if (CompressionMethod.Deflated == method) { result = 20; } else if (IsDirectory == true) { result = 20; } else if (IsCrypted == true) { result = 20; } else if (HasDosAttributes(0x08) ) { result = 11; } return result; } } } /// /// Get a value indicating whether this entry can be decompressed by the library. /// /// This is based on the and /// wether the compression method is supported. public bool CanDecompress { get { return (Version <= ZipConstants.VersionMadeBy) && ((Version == 10) || (Version == 11) || (Version == 20) || (Version == 45) || (Version == 51)) && IsCompressionMethodSupported(); } } /// /// Force this entry to be recorded using Zip64 extensions. /// public void ForceZip64() { forceZip64_ = true; } /// /// Get a value indicating wether Zip64 extensions were forced. /// /// A value of true if Zip64 extensions have been forced on; false if not. public bool IsZip64Forced() { return forceZip64_; } /// /// Gets a value indicating if the entry requires Zip64 extensions /// to store the full entry values. /// /// A value of true if a local header requires Zip64 extensions; false if not. public bool LocalHeaderRequiresZip64 { get { bool result = forceZip64_; if ( !result ) { ulong trueCompressedSize = compressedSize; if ( (versionToExtract == 0) && IsCrypted ) { trueCompressedSize += ZipConstants.CryptoHeaderSize; } // TODO: A better estimation of the true limit based on compression overhead should be used // to determine when an entry should use Zip64. result = ((this.size >= uint.MaxValue) || (trueCompressedSize >= uint.MaxValue)) && ((versionToExtract == 0) || (versionToExtract >= ZipConstants.VersionZip64)); } return result; } } /// /// Get a value indicating wether the central directory entry requires Zip64 extensions to be stored. /// public bool CentralHeaderRequiresZip64 { get { return LocalHeaderRequiresZip64 || (offset >= uint.MaxValue); } } /// /// Get/Set DosTime value. /// /// /// The MS-DOS date format can only represent dates between 1/1/1980 and 12/31/2107. /// public long DosTime { get { if ((known & Known.Time) == 0) { return 0; } else { return dosTime; } } set { unchecked { dosTime = (uint)value; } known |= Known.Time; } } /// /// Gets/Sets the time of last modification of the entry. /// /// /// The property is updated to match this as far as possible. /// public DateTime DateTime { get { uint sec = Math.Min(59, 2 * (dosTime & 0x1f)); uint min = Math.Min(59, (dosTime >> 5) & 0x3f); uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f); uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf))); uint year = ((dosTime >> 25) & 0x7f) + 1980; int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f))); return new System.DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec); } set { uint year = (uint) value.Year; uint month = (uint) value.Month; uint day = (uint) value.Day; uint hour = (uint) value.Hour; uint minute = (uint) value.Minute; uint second = (uint) value.Second; if ( year < 1980 ) { year = 1980; month = 1; day = 1; hour = 0; minute = 0; second = 0; } else if ( year > 2107 ) { year = 2107; month = 12; day = 31; hour = 23; minute = 59; second = 59; } DosTime = ((year - 1980) & 0x7f) << 25 | (month << 21) | (day << 16) | (hour << 11) | (minute << 5) | (second >> 1); } } /// /// Returns the entry name. /// /// /// The unix naming convention is followed. /// Path components in the entry should always separated by forward slashes ('/'). /// Dos device names like C: should also be removed. /// See the class, or /// public string Name { get { return name; } } /// /// Gets/Sets the size of the uncompressed data. /// /// /// The size or -1 if unknown. /// /// Setting the size before adding an entry to an archive can help /// avoid compatability problems with some archivers which dont understand Zip64 extensions. public long Size { get { return (known & Known.Size) != 0 ? (long)size : -1L; } set { this.size = (ulong)value; this.known |= Known.Size; } } /// /// Gets/Sets the size of the compressed data. /// /// /// The compressed entry size or -1 if unknown. /// public long CompressedSize { get { return (known & Known.CompressedSize) != 0 ? (long)compressedSize : -1L; } set { this.compressedSize = (ulong)value; this.known |= Known.CompressedSize; } } /// /// Gets/Sets the crc of the uncompressed data. /// /// /// Crc is not in the range 0..0xffffffffL /// /// /// The crc value or -1 if unknown. /// public long Crc { get { return (known & Known.Crc) != 0 ? crc & 0xffffffffL : -1L; } set { if (((ulong)crc & 0xffffffff00000000L) != 0) { throw new ArgumentOutOfRangeException("value"); } this.crc = (uint)value; this.known |= Known.Crc; } } /// /// Gets/Sets the compression method. Only Deflated and Stored are supported. /// /// /// The compression method for this entry /// /// /// public CompressionMethod CompressionMethod { get { return method; } set { if ( !IsCompressionMethodSupported(value) ) { throw new NotSupportedException("Compression method not supported"); } this.method = value; } } /// /// Gets the compression method for outputting to the local or central header. /// Returns same value as CompressionMethod except when AES encrypting, which /// places 99 in the method and places the real method in the extra data. /// internal CompressionMethod CompressionMethodForHeader { get { return (AESKeySize > 0) ? CompressionMethod.WinZipAES : method; } } /// /// Gets/Sets the extra data. /// /// /// Extra data is longer than 64KB (0xffff) bytes. /// /// /// Extra data or null if not set. /// public byte[] ExtraData { get { // TODO: This is slightly safer but less efficient. Think about wether it should change. // return (byte[]) extra.Clone(); return extra; } set { if (value == null) { extra = null; } else { if (value.Length > 0xffff) { throw new System.ArgumentOutOfRangeException("value"); } extra = new byte[value.Length]; Array.Copy(value, 0, extra, 0, value.Length); } } } #if !NET_1_1 && !NETCF_2_0 /// /// For AES encrypted files returns or sets the number of bits of encryption (128, 192 or 256). /// When setting, only 0 (off), 128 or 256 is supported. /// public int AESKeySize { get { // the strength (1 or 3) is in the entry header switch (_aesEncryptionStrength) { case 0: return 0; // Not AES case 1: return 128; case 2: return 192; // Not used by WinZip case 3: return 256; default: throw new ZipException("Invalid AESEncryptionStrength " + _aesEncryptionStrength); } } set { switch (value) { case 0: _aesEncryptionStrength = 0; break; case 128: _aesEncryptionStrength = 1; break; case 256: _aesEncryptionStrength = 3; break; default: throw new ZipException("AESKeySize must be 0, 128 or 256: " + value); } } } /// /// AES Encryption strength for storage in extra data in entry header. /// 1 is 128 bit, 2 is 192 bit, 3 is 256 bit. /// internal byte AESEncryptionStrength { get { return (byte)_aesEncryptionStrength; } } #else /// /// AES unsupported prior to .NET 2.0 /// internal int AESKeySize; #endif /// /// Returns the length of the salt, in bytes /// internal int AESSaltLen { get { // Key size -> Salt length: 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes. return AESKeySize / 16; } } /// /// Number of extra bytes required to hold the AES Header fields (Salt, Pwd verify, AuthCode) /// internal int AESOverheadSize { get { // File format: // Bytes Content // Variable Salt value // 2 Password verification value // Variable Encrypted file data // 10 Authentication code return 12 + AESSaltLen; } } /// /// Process extra data fields updating the entry based on the contents. /// /// True if the extra data fields should be handled /// for a local header, rather than for a central header. /// internal void ProcessExtraData(bool localHeader) { ZipExtraData extraData = new ZipExtraData(this.extra); if ( extraData.Find(0x0001) ) { // Version required to extract is ignored here as some archivers dont set it correctly // in theory it should be version 45 or higher // The recorded size will change but remember that this is zip64. forceZip64_ = true; if ( extraData.ValueLength < 4 ) { throw new ZipException("Extra data extended Zip64 information length is invalid"); } if ( localHeader || (size == uint.MaxValue) ) { size = (ulong)extraData.ReadLong(); } if ( localHeader || (compressedSize == uint.MaxValue) ) { compressedSize = (ulong)extraData.ReadLong(); } if ( !localHeader && (offset == uint.MaxValue) ) { offset = extraData.ReadLong(); } // Disk number on which file starts is ignored } else { if ( ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) && ((size == uint.MaxValue) || (compressedSize == uint.MaxValue)) ) { throw new ZipException("Zip64 Extended information required but is missing."); } } if ( extraData.Find(10) ) { // No room for any tags. if ( extraData.ValueLength < 4 ) { throw new ZipException("NTFS Extra data invalid"); } extraData.ReadInt(); // Reserved while ( extraData.UnreadCount >= 4 ) { int ntfsTag = extraData.ReadShort(); int ntfsLength = extraData.ReadShort(); if ( ntfsTag == 1 ) { if ( ntfsLength >= 24 ) { long lastModification = extraData.ReadLong(); long lastAccess = extraData.ReadLong(); long createTime = extraData.ReadLong(); DateTime = System.DateTime.FromFileTime(lastModification); } break; } else { // An unknown NTFS tag so simply skip it. extraData.Skip(ntfsLength); } } } else if ( extraData.Find(0x5455) ) { int length = extraData.ValueLength; int flags = extraData.ReadByte(); // Can include other times but these are ignored. Length of data should // actually be 1 + 4 * no of bits in flags. if ( ((flags & 1) != 0) && (length >= 5) ) { int iTime = extraData.ReadInt(); DateTime = (new System.DateTime ( 1970, 1, 1, 0, 0, 0 ).ToUniversalTime() + new TimeSpan ( 0, 0, 0, iTime, 0 )).ToLocalTime(); } } if (method == CompressionMethod.WinZipAES) { ProcessAESExtraData(extraData); } } // For AES the method in the entry is 99, and the real compression method is in the extradata // private void ProcessAESExtraData(ZipExtraData extraData) { #if !NET_1_1 && !NETCF_2_0 if (extraData.Find(0x9901)) { // Set version and flag for Zipfile.CreateAndInitDecryptionStream versionToExtract = ZipConstants.VERSION_AES; // Ver 5.1 = AES see "Version" getter // Set StrongEncryption flag for ZipFile.CreateAndInitDecryptionStream Flags = Flags | (int)GeneralBitFlags.StrongEncryption; // // Unpack AES extra data field see http://www.winzip.com/aes_info.htm int length = extraData.ValueLength; // Data size currently 7 if (length < 7) throw new ZipException("AES Extra Data Length " + length + " invalid."); int ver = extraData.ReadShort(); // Version number (1=AE-1 2=AE-2) int vendorId = extraData.ReadShort(); // 2-character vendor ID 0x4541 = "AE" int encrStrength = extraData.ReadByte(); // encryption strength 1 = 128 2 = 192 3 = 256 int actualCompress = extraData.ReadShort(); // The actual compression method used to compress the file _aesVer = ver; _aesEncryptionStrength = encrStrength; method = (CompressionMethod)actualCompress; } else throw new ZipException("AES Extra Data missing"); #else throw new ZipException("AES unsupported"); #endif } /// /// Gets/Sets the entry comment. /// /// /// If comment is longer than 0xffff. /// /// /// The comment or null if not set. /// /// /// A comment is only available for entries when read via the class. /// The class doesnt have the comment data available. /// public string Comment { get { return comment; } set { // This test is strictly incorrect as the length is in characters // while the storage limit is in bytes. // While the test is partially correct in that a comment of this length or greater // is definitely invalid, shorter comments may also have an invalid length // where there are multi-byte characters // The full test is not possible here however as the code page to apply conversions with // isnt available. if ( (value != null) && (value.Length > 0xffff) ) { #if NETCF_1_0 throw new ArgumentOutOfRangeException("value"); #else throw new ArgumentOutOfRangeException("value", "cannot exceed 65535"); #endif } comment = value; } } /// /// Gets a value indicating if the entry is a directory. /// however. /// /// /// A directory is determined by an entry name with a trailing slash '/'. /// The external file attributes can also indicate an entry is for a directory. /// Currently only dos/windows attributes are tested in this manner. /// The trailing slash convention should always be followed. /// public bool IsDirectory { get { int nameLength = name.Length; bool result = ((nameLength > 0) && ((name[nameLength - 1] == '/') || (name[nameLength - 1] == '\\'))) || HasDosAttributes(16) ; return result; } } /// /// Get a value of true if the entry appears to be a file; false otherwise /// /// /// This only takes account of DOS/Windows attributes. Other operating systems are ignored. /// For linux and others the result may be incorrect. /// public bool IsFile { get { return !IsDirectory && !HasDosAttributes(8); } } /// /// Test entry to see if data can be extracted. /// /// Returns true if data can be extracted for this entry; false otherwise. public bool IsCompressionMethodSupported() { return IsCompressionMethodSupported(CompressionMethod); } #region ICloneable Members /// /// Creates a copy of this zip entry. /// /// An that is a copy of the current instance. public object Clone() { ZipEntry result = (ZipEntry)this.MemberwiseClone(); // Ensure extra data is unique if it exists. if ( extra != null ) { result.extra = new byte[extra.Length]; Array.Copy(extra, 0, result.extra, 0, extra.Length); } return result; } #endregion /// /// Gets a string representation of this ZipEntry. /// /// A readable textual representation of this public override string ToString() { return name; } /// /// Test a compression method to see if this library /// supports extracting data compressed with that method /// /// The compression method to test. /// Returns true if the compression method is supported; false otherwise public static bool IsCompressionMethodSupported(CompressionMethod method) { return ( method == CompressionMethod.Deflated ) || ( method == CompressionMethod.Stored ); } /// /// Cleans a name making it conform to Zip file conventions. /// Devices names ('c:\') and UNC share names ('\\server\share') are removed /// and forward slashes ('\') are converted to back slashes ('/'). /// Names are made relative by trimming leading slashes which is compatible /// with the ZIP naming convention. /// /// The name to clean /// The 'cleaned' name. /// /// The Zip name transform class is more flexible. /// public static string CleanName(string name) { if (name == null) { return string.Empty; } if (Path.IsPathRooted(name) == true) { // NOTE: // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt name = name.Substring(Path.GetPathRoot(name).Length); } name = name.Replace(@"\", "/"); while ( (name.Length > 0) && (name[0] == '/')) { name = name.Remove(0, 1); } return name; } #region Instance Fields Known known; int externalFileAttributes = -1; // contains external attributes (O/S dependant) ushort versionMadeBy; // Contains host system and version information // only relevant for central header entries string name; ulong size; ulong compressedSize; ushort versionToExtract; // Version required to extract (library handles <= 2.0) uint crc; uint dosTime; CompressionMethod method = CompressionMethod.Deflated; byte[] extra; string comment; int flags; // general purpose bit flags long zipFileIndex = -1; // used by ZipFile long offset; // used by ZipFile and ZipOutputStream bool forceZip64_; byte cryptoCheckValue_; #if !NET_1_1 && !NETCF_2_0 int _aesVer; // Version number (2 = AE-2 ?). Assigned but not used. int _aesEncryptionStrength; // Encryption strength 1 = 128 2 = 192 3 = 256 #endif #endregion } }