Summary

Class:ICSharpCode.SharpZipLib.Zip.ZipEntry
Assembly:ICSharpCode.SharpZipLib
File(s):C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipEntry.cs
Covered lines:219
Uncovered lines:69
Coverable lines:288
Total lines:1175
Line coverage:76%
Branch coverage:59.5%

Metrics

MethodCyclomatic ComplexitySequence CoverageBranch Coverage
.ctor(...)1100100
.ctor(...)1100100
.ctor(...)587.577.78
.ctor(...)396.1560
HasDosAttributes(...)4100100
ForceZip64()1100100
IsZip64Forced()1100100
ProcessExtraData(...)1172.2266.67
GetDateTime(...)59033.33
ProcessAESExtraData(...)300
IsCompressionMethodSupported()1100100
Clone()2100100
ToString()100
IsCompressionMethodSupported(...)2100100
CleanName(...)562.555.56

File(s)

C:\Users\Neil\Documents\Visual Studio 2015\Projects\icsharpcode\SZL_master\ICSharpCode.SharpZipLib\Zip\ZipEntry.cs

#LineLine coverage
 1using System;
 2using System.IO;
 3
 4namespace ICSharpCode.SharpZipLib.Zip
 5{
 6  /// <summary>
 7  /// Defines known values for the <see cref="HostSystemID"/> property.
 8  /// </summary>
 9  public enum HostSystemID
 10  {
 11    /// <summary>
 12    /// Host system = MSDOS
 13    /// </summary>
 14    Msdos = 0,
 15    /// <summary>
 16    /// Host system = Amiga
 17    /// </summary>
 18    Amiga = 1,
 19    /// <summary>
 20    /// Host system = Open VMS
 21    /// </summary>
 22    OpenVms = 2,
 23    /// <summary>
 24    /// Host system = Unix
 25    /// </summary>
 26    Unix = 3,
 27    /// <summary>
 28    /// Host system = VMCms
 29    /// </summary>
 30    VMCms = 4,
 31    /// <summary>
 32    /// Host system = Atari ST
 33    /// </summary>
 34    AtariST = 5,
 35    /// <summary>
 36    /// Host system = OS2
 37    /// </summary>
 38    OS2 = 6,
 39    /// <summary>
 40    /// Host system = Macintosh
 41    /// </summary>
 42    Macintosh = 7,
 43    /// <summary>
 44    /// Host system = ZSystem
 45    /// </summary>
 46    ZSystem = 8,
 47    /// <summary>
 48    /// Host system = Cpm
 49    /// </summary>
 50    Cpm = 9,
 51    /// <summary>
 52    /// Host system = Windows NT
 53    /// </summary>
 54    WindowsNT = 10,
 55    /// <summary>
 56    /// Host system = MVS
 57    /// </summary>
 58    MVS = 11,
 59    /// <summary>
 60    /// Host system = VSE
 61    /// </summary>
 62    Vse = 12,
 63    /// <summary>
 64    /// Host system = Acorn RISC
 65    /// </summary>
 66    AcornRisc = 13,
 67    /// <summary>
 68    /// Host system = VFAT
 69    /// </summary>
 70    Vfat = 14,
 71    /// <summary>
 72    /// Host system = Alternate MVS
 73    /// </summary>
 74    AlternateMvs = 15,
 75    /// <summary>
 76    /// Host system = BEOS
 77    /// </summary>
 78    BeOS = 16,
 79    /// <summary>
 80    /// Host system = Tandem
 81    /// </summary>
 82    Tandem = 17,
 83    /// <summary>
 84    /// Host system = OS400
 85    /// </summary>
 86    OS400 = 18,
 87    /// <summary>
 88    /// Host system = OSX
 89    /// </summary>
 90    OSX = 19,
 91    /// <summary>
 92    /// Host system = WinZIP AES
 93    /// </summary>
 94    WinZipAES = 99,
 95  }
 96
 97  /// <summary>
 98  /// This class represents an entry in a zip archive.  This can be a file
 99  /// or a directory
 100  /// ZipFile and ZipInputStream will give you instances of this class as
 101  /// information about the members in an archive.  ZipOutputStream
 102  /// uses an instance of this class when creating an entry in a Zip file.
 103  /// <br/>
 104  /// <br/>Author of the original java version : Jochen Hoenicke
 105  /// </summary>
 106  public class ZipEntry : ICloneable
 107  {
 108    [Flags]
 109    enum Known : byte
 110    {
 111      None = 0,
 112      Size = 0x01,
 113      CompressedSize = 0x02,
 114      Crc = 0x04,
 115      Time = 0x08,
 116      ExternalAttributes = 0x10,
 117    }
 118
 119    #region Constructors
 120    /// <summary>
 121    /// Creates a zip entry with the given name.
 122    /// </summary>
 123    /// <param name="name">
 124    /// The name for this entry. Can include directory components.
 125    /// The convention for names is 'unix' style paths with relative names only.
 126    /// There are with no device names and path elements are separated by '/' characters.
 127    /// </param>
 128    /// <exception cref="ArgumentNullException">
 129    /// The name passed is null
 130    /// </exception>
 131    public ZipEntry(string name)
 65841132      : this(name, 0, ZipConstants.VersionMadeBy, CompressionMethod.Deflated)
 133    {
 65840134    }
 135
 136    /// <summary>
 137    /// Creates a zip entry with the given name and version required to extract
 138    /// </summary>
 139    /// <param name="name">
 140    /// The name for this entry. Can include directory components.
 141    /// The convention for names is 'unix'  style paths with no device names and
 142    /// path elements separated by '/' characters.  This is not enforced see <see cref="CleanName(string)">CleanName</se
 143    /// on how to ensure names are valid if this is desired.
 144    /// </param>
 145    /// <param name="versionRequiredToExtract">
 146    /// The minimum 'feature version' required this entry
 147    /// </param>
 148    /// <exception cref="ArgumentNullException">
 149    /// The name passed is null
 150    /// </exception>
 151    internal ZipEntry(string name, int versionRequiredToExtract)
 81152      : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy,
 81153      CompressionMethod.Deflated)
 154    {
 81155    }
 156
 157    /// <summary>
 158    /// Initializes an entry with the given name and made by information
 159    /// </summary>
 160    /// <param name="name">Name for this entry</param>
 161    /// <param name="madeByInfo">Version and HostSystem Information</param>
 162    /// <param name="versionRequiredToExtract">Minimum required zip feature version required to extract this entry</para
 163    /// <param name="method">Compression method for this entry.</param>
 164    /// <exception cref="ArgumentNullException">
 165    /// The name passed is null
 166    /// </exception>
 167    /// <exception cref="ArgumentOutOfRangeException">
 168    /// versionRequiredToExtract should be 0 (auto-calculate) or > 10
 169    /// </exception>
 170    /// <remarks>
 171    /// This constructor is used by the ZipFile class when reading from the central header
 172    /// It is not generally useful, use the constructor specifying the name only.
 173    /// </remarks>
 131878174    internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo,
 131878175      CompressionMethod method)
 176    {
 131878177       if (name == null) {
 1178        throw new ArgumentNullException(nameof(name));
 179      }
 180
 131877181       if (name.Length > 0xffff) {
 0182        throw new ArgumentException("Name is too long", nameof(name));
 183      }
 184
 131877185       if ((versionRequiredToExtract != 0) && (versionRequiredToExtract < 10)) {
 0186        throw new ArgumentOutOfRangeException(nameof(versionRequiredToExtract));
 187      }
 188
 131877189      this.DateTime = DateTime.Now;
 131877190      this.name = CleanName(name);
 131877191      this.versionMadeBy = (ushort)madeByInfo;
 131877192      this.versionToExtract = (ushort)versionRequiredToExtract;
 131877193      this.method = method;
 131877194    }
 195
 196    /// <summary>
 197    /// Creates a deep copy of the given zip entry.
 198    /// </summary>
 199    /// <param name="entry">
 200    /// The entry to copy.
 201    /// </param>
 202    [Obsolete("Use Clone instead")]
 1203    public ZipEntry(ZipEntry entry)
 204    {
 1205       if (entry == null) {
 0206        throw new ArgumentNullException(nameof(entry));
 207      }
 208
 1209      known = entry.known;
 1210      name = entry.name;
 1211      size = entry.size;
 1212      compressedSize = entry.compressedSize;
 1213      crc = entry.crc;
 1214      dosTime = entry.dosTime;
 1215      dateTime = entry.dateTime;
 1216      method = entry.method;
 1217      comment = entry.comment;
 1218      versionToExtract = entry.versionToExtract;
 1219      versionMadeBy = entry.versionMadeBy;
 1220      externalFileAttributes = entry.externalFileAttributes;
 1221      flags = entry.flags;
 222
 1223      zipFileIndex = entry.zipFileIndex;
 1224      offset = entry.offset;
 225
 1226      forceZip64_ = entry.forceZip64_;
 227
 1228       if (entry.extra != null) {
 1229        extra = new byte[entry.extra.Length];
 1230        Array.Copy(entry.extra, 0, extra, 0, entry.extra.Length);
 231      }
 1232    }
 233
 234    #endregion
 235
 236    /// <summary>
 237    /// Get a value indicating wether the entry has a CRC value available.
 238    /// </summary>
 239    public bool HasCrc {
 240      get {
 65754241        return (known & Known.Crc) != 0;
 242      }
 243    }
 244
 245    /// <summary>
 246    /// Get/Set flag indicating if entry is encrypted.
 247    /// A simple helper routine to aid interpretation of <see cref="Flags">flags</see>
 248    /// </summary>
 249    /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
 250    public bool IsCrypted {
 251      get {
 592001252        return (flags & 1) != 0;
 253      }
 254      set {
 65738255         if (value) {
 38256          flags |= 1;
 38257        } else {
 65700258          flags &= ~1;
 259        }
 65700260      }
 261    }
 262
 263    /// <summary>
 264    /// Get / set a flag indicating wether entry name and comment text are
 265    /// encoded in <a href="http://www.unicode.org">unicode UTF8</a>.
 266    /// </summary>
 267    /// <remarks>This is an assistant that interprets the <see cref="Flags">flags</see> property.</remarks>
 268    public bool IsUnicodeText {
 269      get {
 4270        return (flags & (int)GeneralBitFlags.UnicodeText) != 0;
 271      }
 272      set {
 177273         if (value) {
 8274          flags |= (int)GeneralBitFlags.UnicodeText;
 8275        } else {
 169276          flags &= ~(int)GeneralBitFlags.UnicodeText;
 277        }
 169278      }
 279    }
 280
 281    /// <summary>
 282    /// Value used during password checking for PKZIP 2.0 / 'classic' encryption.
 283    /// </summary>
 284    internal byte CryptoCheckValue {
 285      get {
 34286        return cryptoCheckValue_;
 287      }
 288
 289      set {
 66037290        cryptoCheckValue_ = value;
 66037291      }
 292    }
 293
 294    /// <summary>
 295    /// Get/Set general purpose bit flag for entry
 296    /// </summary>
 297    /// <remarks>
 298    /// General purpose bit flag<br/>
 299    /// <br/>
 300    /// Bit 0: If set, indicates the file is encrypted<br/>
 301    /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9 deflating<br/>
 302    /// Imploding:<br/>
 303    /// Bit 1 if set indicates an 8K sliding dictionary was used.  If clear a 4k dictionary was used<br/>
 304    /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the sliding dictionary, 2 otherwise<br/>
 305    /// <br/>
 306    /// Deflating:<br/>
 307    ///   Bit 2    Bit 1<br/>
 308    ///     0        0       Normal compression was used<br/>
 309    ///     0        1       Maximum compression was used<br/>
 310    ///     1        0       Fast compression was used<br/>
 311    ///     1        1       Super fast compression was used<br/>
 312    /// <br/>
 313    /// Bit 3: If set, the fields crc-32, compressed size
 314    /// and uncompressed size are were not able to be written during zip file creation
 315    /// The correct values are held in a data descriptor immediately following the compressed data. <br/>
 316    /// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>
 317    /// Bit 5: If set indicates the file contains compressed patch data<br/>
 318    /// Bit 6: If set indicates strong encryption was used.<br/>
 319    /// Bit 7-10: Unused or reserved<br/>
 320    /// Bit 11: If set the name and comments for this entry are in <a href="http://www.unicode.org">unicode</a>.<br/>
 321    /// Bit 12-15: Unused or reserved<br/>
 322    /// </remarks>
 323    /// <seealso cref="IsUnicodeText"></seealso>
 324    /// <seealso cref="IsCrypted"></seealso>
 325    public int Flags {
 326      get {
 395994327        return flags;
 328      }
 329      set {
 66249330        flags = value;
 66249331      }
 332    }
 333
 334    /// <summary>
 335    /// Get/Set index of this entry in Zip file
 336    /// </summary>
 337    /// <remarks>This is only valid when the entry is part of a <see cref="ZipFile"></see></remarks>
 338    public long ZipFileIndex {
 339      get {
 65933340        return zipFileIndex;
 341      }
 342      set {
 65956343        zipFileIndex = value;
 65956344      }
 345    }
 346
 347    /// <summary>
 348    /// Get/set offset for use in central header
 349    /// </summary>
 350    public long Offset {
 351      get {
 396693352        return offset;
 353      }
 354      set {
 131833355        offset = value;
 131833356      }
 357    }
 358
 359    /// <summary>
 360    /// Get/Set external file attributes as an integer.
 361    /// The values of this are operating system dependant see
 362    /// <see cref="HostSystem">HostSystem</see> for details
 363    /// </summary>
 364    public int ExternalFileAttributes {
 365      get {
 527438366         if ((known & Known.ExternalAttributes) == 0) {
 65824367          return -1;
 368        } else {
 461614369          return externalFileAttributes;
 370        }
 371      }
 372
 373      set {
 65965374        externalFileAttributes = value;
 65965375        known |= Known.ExternalAttributes;
 65965376      }
 377    }
 378
 379    /// <summary>
 380    /// Get the version made by for this entry or zero if unknown.
 381    /// The value / 10 indicates the major version number, and
 382    /// the value mod 10 is the minor version number
 383    /// </summary>
 384    public int VersionMadeBy {
 385      get {
 0386        return (versionMadeBy & 0xff);
 387      }
 388    }
 389
 390    /// <summary>
 391    /// Get a value indicating this entry is for a DOS/Windows system.
 392    /// </summary>
 393    public bool IsDOSEntry {
 394      get {
 2395        return ((HostSystem == (int)HostSystemID.Msdos) ||
 2396          (HostSystem == (int)HostSystemID.WindowsNT));
 397      }
 398    }
 399
 400    /// <summary>
 401    /// Test the external attributes for this <see cref="ZipEntry"/> to
 402    /// see if the external attributes are Dos based (including WINNT and variants)
 403    /// and match the values
 404    /// </summary>
 405    /// <param name="attributes">The attributes to test.</param>
 406    /// <returns>Returns true if the external attributes are known to be DOS/Windows
 407    /// based and have the same attributes set as the value passed.</returns>
 408    bool HasDosAttributes(int attributes)
 409    {
 920886410      bool result = false;
 920886411       if ((known & Known.ExternalAttributes) != 0) {
 461462412        result |= (((HostSystem == (int)HostSystemID.Msdos) ||
 461462413          (HostSystem == (int)HostSystemID.WindowsNT)) &&
 461462414          (ExternalFileAttributes & attributes) == attributes);
 415      }
 920886416      return result;
 417    }
 418
 419    /// <summary>
 420    /// Gets the compatability information for the <see cref="ExternalFileAttributes">external file attribute</see>
 421    /// If the external file attributes are compatible with MS-DOS and can be read
 422    /// by PKZIP for DOS version 2.04g then this value will be zero.  Otherwise the value
 423    /// will be non-zero and identify the host system on which the attributes are compatible.
 424    /// </summary>
 425    ///
 426    /// <remarks>
 427    /// The values for this as defined in the Zip File format and by others are shown below.  The values are somewhat
 428    /// misleading in some cases as they are not all used as shown.  You should consult the relevant documentation
 429    /// to obtain up to date and correct information.  The modified appnote by the infozip group is
 430    /// particularly helpful as it documents a lot of peculiarities.  The document is however a little dated.
 431    /// <list type="table">
 432    /// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>
 433    /// <item>1 - Amiga</item>
 434    /// <item>2 - OpenVMS</item>
 435    /// <item>3 - Unix</item>
 436    /// <item>4 - VM/CMS</item>
 437    /// <item>5 - Atari ST</item>
 438    /// <item>6 - OS/2 HPFS</item>
 439    /// <item>7 - Macintosh</item>
 440    /// <item>8 - Z-System</item>
 441    /// <item>9 - CP/M</item>
 442    /// <item>10 - Windows NTFS</item>
 443    /// <item>11 - MVS (OS/390 - Z/OS)</item>
 444    /// <item>12 - VSE</item>
 445    /// <item>13 - Acorn Risc</item>
 446    /// <item>14 - VFAT</item>
 447    /// <item>15 - Alternate MVS</item>
 448    /// <item>16 - BeOS</item>
 449    /// <item>17 - Tandem</item>
 450    /// <item>18 - OS/400</item>
 451    /// <item>19 - OS/X (Darwin)</item>
 452    /// <item>99 - WinZip AES</item>
 453    /// <item>remainder - unused</item>
 454    /// </list>
 455    /// </remarks>
 456    public int HostSystem {
 457      get {
 461464458        return (versionMadeBy >> 8) & 0xff;
 459      }
 460
 461      set {
 0462        versionMadeBy &= 0xff;
 0463        versionMadeBy |= (ushort)((value & 0xff) << 8);
 0464      }
 465    }
 466
 467    /// <summary>
 468    /// Get minimum Zip feature version required to extract this entry
 469    /// </summary>
 470    /// <remarks>
 471    /// Minimum features are defined as:<br/>
 472    /// 1.0 - Default value<br/>
 473    /// 1.1 - File is a volume label<br/>
 474    /// 2.0 - File is a folder/directory<br/>
 475    /// 2.0 - File is compressed using Deflate compression<br/>
 476    /// 2.0 - File is encrypted using traditional encryption<br/>
 477    /// 2.1 - File is compressed using Deflate64<br/>
 478    /// 2.5 - File is compressed using PKWARE DCL Implode<br/>
 479    /// 2.7 - File is a patch data set<br/>
 480    /// 4.5 - File uses Zip64 format extensions<br/>
 481    /// 4.6 - File is compressed using BZIP2 compression<br/>
 482    /// 5.0 - File is encrypted using DES<br/>
 483    /// 5.0 - File is encrypted using 3DES<br/>
 484    /// 5.0 - File is encrypted using original RC2 encryption<br/>
 485    /// 5.0 - File is encrypted using RC4 encryption<br/>
 486    /// 5.1 - File is encrypted using AES encryption<br/>
 487    /// 5.1 - File is encrypted using corrected RC2 encryption<br/>
 488    /// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>
 489    /// 6.1 - File is encrypted using non-OAEP key wrapping<br/>
 490    /// 6.2 - Central directory encryption (not confirmed yet)<br/>
 491    /// 6.3 - File is compressed using LZMA<br/>
 492    /// 6.3 - File is compressed using PPMD+<br/>
 493    /// 6.3 - File is encrypted using Blowfish<br/>
 494    /// 6.3 - File is encrypted using Twofish<br/>
 495    /// </remarks>
 496    /// <seealso cref="CanDecompress"></seealso>
 497    public int Version {
 498      get {
 499        // Return recorded version if known.
 198066500         if (versionToExtract != 0) {
 66394501          return versionToExtract & 0x00ff;               // Only lower order byte. High order is O/S file system.
 502        } else {
 131672503          int result = 10;
 131672504           if (AESKeySize > 0) {
 0505            result = ZipConstants.VERSION_AES;          // Ver 5.1 = AES
 131672506           } else if (CentralHeaderRequiresZip64) {
 247507            result = ZipConstants.VersionZip64;
 131672508           } else if (CompressionMethod.Deflated == method) {
 321509            result = 20;
 131425510           } else if (IsDirectory == true) {
 0511            result = 20;
 131104512           } else if (IsCrypted == true) {
 0513            result = 20;
 131104514           } else if (HasDosAttributes(0x08)) {
 0515            result = 11;
 516          }
 131672517          return result;
 518        }
 519      }
 520    }
 521
 522    /// <summary>
 523    /// Get a value indicating whether this entry can be decompressed by the library.
 524    /// </summary>
 525    /// <remarks>This is based on the <see cref="Version"></see> and
 526    /// wether the <see cref="IsCompressionMethodSupported()">compression method</see> is supported.</remarks>
 527    public bool CanDecompress {
 528      get {
 73529         return (Version <= ZipConstants.VersionMadeBy) &&
 73530          ((Version == 10) ||
 73531          (Version == 11) ||
 73532          (Version == 20) ||
 73533          (Version == 45) ||
 73534          (Version == 51)) &&
 73535          IsCompressionMethodSupported();
 536      }
 537    }
 538
 539    /// <summary>
 540    /// Force this entry to be recorded using Zip64 extensions.
 541    /// </summary>
 542    public void ForceZip64()
 543    {
 124544      forceZip64_ = true;
 124545    }
 546
 547    /// <summary>
 548    /// Get a value indicating wether Zip64 extensions were forced.
 549    /// </summary>
 550    /// <returns>A <see cref="bool"/> value of true if Zip64 extensions have been forced on; false if not.</returns>
 551    public bool IsZip64Forced()
 552    {
 132042553      return forceZip64_;
 554    }
 555
 556    /// <summary>
 557    /// Gets a value indicating if the entry requires Zip64 extensions
 558    /// to store the full entry values.
 559    /// </summary>
 560    /// <value>A <see cref="bool"/> value of true if a local header requires Zip64 extensions; false if not.</value>
 561    public bool LocalHeaderRequiresZip64 {
 562      get {
 395536563        bool result = forceZip64_;
 564
 395536565         if (!result) {
 394651566          ulong trueCompressedSize = compressedSize;
 567
 394651568           if ((versionToExtract == 0) && IsCrypted) {
 68569            trueCompressedSize += ZipConstants.CryptoHeaderSize;
 570          }
 571
 572          // TODO: A better estimation of the true limit based on compression overhead should be used
 573          // to determine when an entry should use Zip64.
 394651574          result =
 394651575            ((this.size >= uint.MaxValue) || (trueCompressedSize >= uint.MaxValue)) &&
 394651576            ((versionToExtract == 0) || (versionToExtract >= ZipConstants.VersionZip64));
 577        }
 578
 395536579        return result;
 580      }
 581    }
 582
 583    /// <summary>
 584    /// Get a value indicating wether the central directory entry requires Zip64 extensions to be stored.
 585    /// </summary>
 586    public bool CentralHeaderRequiresZip64 {
 587      get {
 197572588        return LocalHeaderRequiresZip64 || (offset >= uint.MaxValue);
 589      }
 590    }
 591
 592    /// <summary>
 593    /// Get/Set DosTime value.
 594    /// </summary>
 595    /// <remarks>
 596    /// The MS-DOS date format can only represent dates between 1/1/1980 and 12/31/2107.
 597    /// </remarks>
 598    public long DosTime {
 599      get {
 131812600         if ((known & Known.Time) == 0) {
 0601          return 0;
 602        } else {
 131812603          return dosTime;
 604        }
 605      }
 606
 607      set {
 608        unchecked {
 197925609          dosTime = (uint)value;
 610        }
 611
 197925612        known |= Known.Time;
 197925613      }
 614    }
 615
 616    /// <summary>
 617    /// Gets/Sets the time of last modification of the entry.
 618    /// </summary>
 619    /// <remarks>
 620    /// The <see cref="DosTime"></see> property is updated to match this as far as possible.
 621    /// </remarks>
 622    public DateTime DateTime
 623    {
 2624      get { return dateTime; }
 625
 626      set {
 131886627        var year = (uint)value.Year;
 131886628        var month = (uint)value.Month;
 131886629        var day = (uint)value.Day;
 131886630        var hour = (uint)value.Hour;
 131886631        var minute = (uint)value.Minute;
 131886632        var second = (uint)value.Second;
 633
 131886634         if (year < 1980) {
 0635          year = 1980;
 0636          month = 1;
 0637          day = 1;
 0638          hour = 0;
 0639          minute = 0;
 0640          second = 0;
 131886641         } else if (year > 2107) {
 0642          year = 2107;
 0643          month = 12;
 0644          day = 31;
 0645          hour = 23;
 0646          minute = 59;
 0647          second = 59;
 648        }
 649
 131886650        DosTime = ((year - 1980) & 0x7f) << 25 |
 131886651          (month << 21) |
 131886652          (day << 16) |
 131886653          (hour << 11) |
 131886654          (minute << 5) |
 131886655          (second >> 1);
 131886656      }
 657    }
 658
 659    /// <summary>
 660    /// Returns the entry name.
 661    /// </summary>
 662    /// <remarks>
 663    /// The unix naming convention is followed.
 664    /// Path components in the entry should always separated by forward slashes ('/').
 665    /// Dos device names like C: should also be removed.
 666    /// See the <see cref="ZipNameTransform"/> class, or <see cref="CleanName(string)"/>
 667    ///</remarks>
 668    public string Name {
 669      get {
 527086670        return name;
 671      }
 672    }
 673
 674    /// <summary>
 675    /// Gets/Sets the size of the uncompressed data.
 676    /// </summary>
 677    /// <returns>
 678    /// The size or -1 if unknown.
 679    /// </returns>
 680    /// <remarks>Setting the size before adding an entry to an archive can help
 681    /// avoid compatability problems with some archivers which dont understand Zip64 extensions.</remarks>
 682    public long Size {
 683      get {
 593205684         return (known & Known.Size) != 0 ? (long)size : -1L;
 685      }
 686      set {
 131877687        this.size = (ulong)value;
 131877688        this.known |= Known.Size;
 131877689      }
 690    }
 691
 692    /// <summary>
 693    /// Gets/Sets the size of the compressed data.
 694    /// </summary>
 695    /// <returns>
 696    /// The compressed entry size or -1 if unknown.
 697    /// </returns>
 698    public long CompressedSize {
 699      get {
 462089700         return (known & Known.CompressedSize) != 0 ? (long)compressedSize : -1L;
 701      }
 702      set {
 262984703        this.compressedSize = (ulong)value;
 262984704        this.known |= Known.CompressedSize;
 262984705      }
 706    }
 707
 708    /// <summary>
 709    /// Gets/Sets the crc of the uncompressed data.
 710    /// </summary>
 711    /// <exception cref="System.ArgumentOutOfRangeException">
 712    /// Crc is not in the range 0..0xffffffffL
 713    /// </exception>
 714    /// <returns>
 715    /// The crc value or -1 if unknown.
 716    /// </returns>
 717    public long Crc {
 718      get {
 329635719         return (known & Known.Crc) != 0 ? crc & 0xffffffffL : -1L;
 720      }
 721      set {
 131852722         if (((ulong)crc & 0xffffffff00000000L) != 0) {
 0723          throw new ArgumentOutOfRangeException(nameof(value));
 724        }
 131852725        this.crc = (uint)value;
 131852726        this.known |= Known.Crc;
 131852727      }
 728    }
 729
 730    /// <summary>
 731    /// Gets/Sets the compression method. Only Deflated and Stored are supported.
 732    /// </summary>
 733    /// <returns>
 734    /// The compression method for this entry
 735    /// </returns>
 736    /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Deflated"/>
 737    /// <see cref="ICSharpCode.SharpZipLib.Zip.CompressionMethod.Stored"/>
 738    public CompressionMethod CompressionMethod {
 739      get {
 461414740        return method;
 741      }
 742
 743      set {
 65837744         if (!IsCompressionMethodSupported(value)) {
 1745          throw new NotSupportedException("Compression method not supported");
 746        }
 65836747        this.method = value;
 65836748      }
 749    }
 750
 751    /// <summary>
 752    /// Gets the compression method for outputting to the local or central header.
 753    /// Returns same value as CompressionMethod except when AES encrypting, which
 754    /// places 99 in the method and places the real method in the extra data.
 755    /// </summary>
 756    internal CompressionMethod CompressionMethodForHeader {
 757      get {
 257758         return (AESKeySize > 0) ? CompressionMethod.WinZipAES : method;
 759      }
 760    }
 761
 762    /// <summary>
 763    /// Gets/Sets the extra data.
 764    /// </summary>
 765    /// <exception cref="System.ArgumentOutOfRangeException">
 766    /// Extra data is longer than 64KB (0xffff) bytes.
 767    /// </exception>
 768    /// <returns>
 769    /// Extra data or null if not set.
 770    /// </returns>
 771    public byte[] ExtraData {
 772
 773      get {
 774        // TODO: This is slightly safer but less efficient.  Think about wether it should change.
 775        //        return (byte[]) extra.Clone();
 263288776        return extra;
 777      }
 778
 779      set {
 65874780         if (value == null) {
 0781          extra = null;
 0782        } else {
 65874783           if (value.Length > 0xffff) {
 0784            throw new System.ArgumentOutOfRangeException(nameof(value));
 785          }
 786
 65874787          extra = new byte[value.Length];
 65874788          Array.Copy(value, 0, extra, 0, value.Length);
 789        }
 65874790      }
 791    }
 792
 793
 794    /// <summary>
 795    /// For AES encrypted files returns or sets the number of bits of encryption (128, 192 or 256).
 796    /// When setting, only 0 (off), 128 or 256 is supported.
 797    /// </summary>
 798    public int AESKeySize {
 799      get {
 800        // the strength (1 or 3) is in the entry header
 132508801         switch (_aesEncryptionStrength) {
 802          case 0:
 132508803            return 0;   // Not AES
 804          case 1:
 0805            return 128;
 806          case 2:
 0807            return 192; // Not used by WinZip
 808          case 3:
 0809            return 256;
 810          default:
 0811            throw new ZipException("Invalid AESEncryptionStrength " + _aesEncryptionStrength);
 812        }
 813      }
 814      set {
 0815         switch (value) {
 816          case 0:
 0817            _aesEncryptionStrength = 0;
 0818            break;
 819          case 128:
 0820            _aesEncryptionStrength = 1;
 0821            break;
 822          case 256:
 0823            _aesEncryptionStrength = 3;
 0824            break;
 825          default:
 0826            throw new ZipException("AESKeySize must be 0, 128 or 256: " + value);
 827        }
 828      }
 829    }
 830
 831    /// <summary>
 832    /// AES Encryption strength for storage in extra data in entry header.
 833    /// 1 is 128 bit, 2 is 192 bit, 3 is 256 bit.
 834    /// </summary>
 835    internal byte AESEncryptionStrength {
 836      get {
 0837        return (byte)_aesEncryptionStrength;
 838      }
 839    }
 840
 841    /// <summary>
 842    /// Returns the length of the salt, in bytes
 843    /// </summary>
 844    internal int AESSaltLen {
 845      get {
 846        // Key size -> Salt length: 128 bits = 8 bytes, 192 bits = 12 bytes, 256 bits = 16 bytes.
 0847        return AESKeySize / 16;
 848      }
 849    }
 850
 851    /// <summary>
 852    /// Number of extra bytes required to hold the AES Header fields (Salt, Pwd verify, AuthCode)
 853    /// </summary>
 854    internal int AESOverheadSize {
 855      get {
 856        // File format:
 857        //   Bytes    Content
 858        // Variable    Salt value
 859        //     2    Password verification value
 860        // Variable    Encrypted file data
 861        //    10    Authentication code
 0862        return 12 + AESSaltLen;
 863      }
 864    }
 865
 866    /// <summary>
 867    /// Process extra data fields updating the entry based on the contents.
 868    /// </summary>
 869    /// <param name="localHeader">True if the extra data fields should be handled
 870    /// for a local header, rather than for a central header.
 871    /// </param>
 872    internal void ProcessExtraData(bool localHeader)
 873    {
 66037874      var extraData = new ZipExtraData(this.extra);
 875
 66037876       if (extraData.Find(0x0001)) {
 877        // Version required to extract is ignored here as some archivers dont set it correctly
 878        // in theory it should be version 45 or higher
 879
 880        // The recorded size will change but remember that this is zip64.
 123881        forceZip64_ = true;
 882
 123883         if (extraData.ValueLength < 4) {
 0884          throw new ZipException("Extra data extended Zip64 information length is invalid");
 885        }
 886
 887        // (localHeader ||) was deleted, because actually there is no specific difference with reading sizes between loc
 888        // https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT
 889        // ...
 890        // 4.4  Explanation of fields
 891        // ...
 892        //  4.4.8 compressed size: (4 bytes)
 893        //  4.4.9 uncompressed size: (4 bytes)
 894        //
 895        //    The size of the file compressed (4.4.8) and uncompressed,
 896        //    (4.4.9) respectively.  When a decryption header is present it
 897        //    will be placed in front of the file data and the value of the
 898        //    compressed file size will include the bytes of the decryption
 899        //    header.  If bit 3 of the general purpose bit flag is set,
 900        //    these fields are set to zero in the local header and the
 901        //    correct values are put in the data descriptor and
 902        //    in the central directory.  If an archive is in ZIP64 format
 903        //    and the value in this field is 0xFFFFFFFF, the size will be
 904        //    in the corresponding 8 byte ZIP64 extended information
 905        //    extra field.  When encrypting the central directory, if the
 906        //    local header is not in ZIP64 format and general purpose bit
 907        //    flag 13 is set indicating masking, the value stored for the
 908        //    uncompressed size in the Local Header will be zero.
 909        //
 910        // Othewise there is problem with minizip implementation
 123911         if (size == uint.MaxValue) {
 123912          size = (ulong)extraData.ReadLong();
 913        }
 914
 123915         if (compressedSize == uint.MaxValue) {
 123916          compressedSize = (ulong)extraData.ReadLong();
 917        }
 918
 123919         if (!localHeader && (offset == uint.MaxValue)) {
 0920          offset = extraData.ReadLong();
 921        }
 922
 923        // Disk number on which file starts is ignored
 0924      } else {
 65914925         if (
 65914926          ((versionToExtract & 0xff) >= ZipConstants.VersionZip64) &&
 65914927          ((size == uint.MaxValue) || (compressedSize == uint.MaxValue))
 65914928        ) {
 0929          throw new ZipException("Zip64 Extended information required but is missing.");
 930        }
 931      }
 932
 66037933      dateTime = GetDateTime(extraData);
 66037934       if (method == CompressionMethod.WinZipAES) {
 0935        ProcessAESExtraData(extraData);
 936      }
 66037937    }
 938
 939    private DateTime GetDateTime(ZipExtraData extraData) {
 940      // Check for NT timestamp
 941            // NOTE: Disable by default to match behavior of InfoZIP
 942#if RESPECT_NT_TIMESTAMP
 943      NTTaggedData ntData = extraData.GetData<NTTaggedData>();
 944      if (ntData != null)
 945        return ntData.LastModificationTime;
 946#endif
 947
 948      // Check for Unix timestamp
 66037949      ExtendedUnixData unixData = extraData.GetData<ExtendedUnixData>();
 66037950       if (unixData != null &&
 66037951        // Only apply modification time, but require all other values to be present
 66037952        // This is done to match InfoZIP's behaviour
 66037953        ((unixData.Include & ExtendedUnixData.Flags.ModificationTime) != 0) &&
 66037954        ((unixData.Include & ExtendedUnixData.Flags.AccessTime) != 0) &&
 66037955        ((unixData.Include & ExtendedUnixData.Flags.CreateTime) != 0))
 0956        return unixData.ModificationTime;
 957
 958      // Fall back to DOS time
 66037959      uint sec = Math.Min(59, 2 * (dosTime & 0x1f));
 66037960      uint min = Math.Min(59, (dosTime >> 5) & 0x3f);
 66037961      uint hrs = Math.Min(23, (dosTime >> 11) & 0x1f);
 66037962      uint mon = Math.Max(1, Math.Min(12, ((dosTime >> 21) & 0xf)));
 66037963      uint year = ((dosTime >> 25) & 0x7f) + 1980;
 66037964      int day = Math.Max(1, Math.Min(DateTime.DaysInMonth((int)year, (int)mon), (int)((dosTime >> 16) & 0x1f)));
 66037965      return new DateTime((int)year, (int)mon, day, (int)hrs, (int)min, (int)sec, DateTimeKind.Utc);
 966    }
 967
 968    // For AES the method in the entry is 99, and the real compression method is in the extradata
 969    //
 970    private void ProcessAESExtraData(ZipExtraData extraData)
 971    {
 972
 0973       if (extraData.Find(0x9901)) {
 974        // Set version and flag for Zipfile.CreateAndInitDecryptionStream
 0975        versionToExtract = ZipConstants.VERSION_AES;            // Ver 5.1 = AES see "Version" getter
 976                                    // Set StrongEncryption flag for ZipFile.CreateAndInitDecryptionStream
 0977        Flags = Flags | (int)GeneralBitFlags.StrongEncryption;
 978        //
 979        // Unpack AES extra data field see http://www.winzip.com/aes_info.htm
 0980        int length = extraData.ValueLength;         // Data size currently 7
 0981         if (length < 7)
 0982          throw new ZipException("AES Extra Data Length " + length + " invalid.");
 0983        int ver = extraData.ReadShort();            // Version number (1=AE-1 2=AE-2)
 0984        int vendorId = extraData.ReadShort();       // 2-character vendor ID 0x4541 = "AE"
 0985        int encrStrength = extraData.ReadByte();    // encryption strength 1 = 128 2 = 192 3 = 256
 0986        int actualCompress = extraData.ReadShort(); // The actual compression method used to compress the file
 0987        _aesVer = ver;
 0988        _aesEncryptionStrength = encrStrength;
 0989        method = (CompressionMethod)actualCompress;
 0990      } else
 0991        throw new ZipException("AES Extra Data missing");
 992    }
 993
 994    /// <summary>
 995    /// Gets/Sets the entry comment.
 996    /// </summary>
 997    /// <exception cref="System.ArgumentOutOfRangeException">
 998    /// If comment is longer than 0xffff.
 999    /// </exception>
 1000    /// <returns>
 1001    /// The comment or null if not set.
 1002    /// </returns>
 1003    /// <remarks>
 1004    /// A comment is only available for entries when read via the <see cref="ZipFile"/> class.
 1005    /// The <see cref="ZipInputStream"/> class doesnt have the comment data available.
 1006    /// </remarks>
 1007    public string Comment {
 1008      get {
 1316731009        return comment;
 1010      }
 1011      set {
 1012        // This test is strictly incorrect as the length is in characters
 1013        // while the storage limit is in bytes.
 1014        // While the test is partially correct in that a comment of this length or greater
 1015        // is definitely invalid, shorter comments may also have an invalid length
 1016        // where there are multi-byte characters
 1017        // The full test is not possible here however as the code page to apply conversions with
 1018        // isnt available.
 31019         if ((value != null) && (value.Length > 0xffff)) {
 01020          throw new ArgumentOutOfRangeException(nameof(value), "cannot exceed 65535");
 1021        }
 1022
 31023        comment = value;
 31024      }
 1025    }
 1026
 1027    /// <summary>
 1028    /// Gets a value indicating if the entry is a directory.
 1029    /// however.
 1030    /// </summary>
 1031    /// <remarks>
 1032    /// A directory is determined by an entry name with a trailing slash '/'.
 1033    /// The external file attributes can also indicate an entry is for a directory.
 1034    /// Currently only dos/windows attributes are tested in this manner.
 1035    /// The trailing slash convention should always be followed.
 1036    /// </remarks>
 1037    public bool IsDirectory {
 1038      get {
 5263341039        int nameLength = name.Length;
 5263341040        bool result =
 5263341041          ((nameLength > 0) &&
 5263341042          ((name[nameLength - 1] == '/') || (name[nameLength - 1] == '\\'))) ||
 5263341043          HasDosAttributes(16)
 5263341044          ;
 271045        return result;
 1046      }
 1047    }
 1048
 1049    /// <summary>
 1050    /// Get a value of true if the entry appears to be a file; false otherwise
 1051    /// </summary>
 1052    /// <remarks>
 1053    /// This only takes account of DOS/Windows attributes.  Other operating systems are ignored.
 1054    /// For linux and others the result may be incorrect.
 1055    /// </remarks>
 1056    public bool IsFile {
 1057      get {
 2634861058        return !IsDirectory && !HasDosAttributes(8);
 1059      }
 1060    }
 1061
 1062    /// <summary>
 1063    /// Test entry to see if data can be extracted.
 1064    /// </summary>
 1065    /// <returns>Returns true if data can be extracted for this entry; false otherwise.</returns>
 1066    public bool IsCompressionMethodSupported()
 1067    {
 1320121068      return IsCompressionMethodSupported(CompressionMethod);
 1069    }
 1070
 1071    #region ICloneable Members
 1072    /// <summary>
 1073    /// Creates a copy of this zip entry.
 1074    /// </summary>
 1075    /// <returns>An <see cref="Object"/> that is a copy of the current instance.</returns>
 1076    public object Clone()
 1077    {
 4610931078      var result = (ZipEntry)this.MemberwiseClone();
 1079
 1080      // Ensure extra data is unique if it exists.
 4610931081       if (extra != null) {
 721082        result.extra = new byte[extra.Length];
 721083        Array.Copy(extra, 0, result.extra, 0, extra.Length);
 1084      }
 1085
 4610931086      return result;
 1087    }
 1088
 1089    #endregion
 1090
 1091    /// <summary>
 1092    /// Gets a string representation of this ZipEntry.
 1093    /// </summary>
 1094    /// <returns>A readable textual representation of this <see cref="ZipEntry"/></returns>
 1095    public override string ToString()
 1096    {
 01097      return name;
 1098    }
 1099
 1100    /// <summary>
 1101    /// Test a <see cref="CompressionMethod">compression method</see> to see if this library
 1102    /// supports extracting data compressed with that method
 1103    /// </summary>
 1104    /// <param name="method">The compression method to test.</param>
 1105    /// <returns>Returns true if the compression method is supported; false otherwise</returns>
 1106    public static bool IsCompressionMethodSupported(CompressionMethod method)
 1107    {
 1978491108      return
 1978491109        (method == CompressionMethod.Deflated) ||
 1978491110        (method == CompressionMethod.Stored);
 1111    }
 1112
 1113    /// <summary>
 1114    /// Cleans a name making it conform to Zip file conventions.
 1115    /// Devices names ('c:\') and UNC share names ('\\server\share') are removed
 1116    /// and forward slashes ('\') are converted to back slashes ('/').
 1117    /// Names are made relative by trimming leading slashes which is compatible
 1118    /// with the ZIP naming convention.
 1119    /// </summary>
 1120    /// <param name="name">The name to clean</param>
 1121    /// <returns>The 'cleaned' name.</returns>
 1122    /// <remarks>
 1123    /// The <seealso cref="ZipNameTransform">Zip name transform</seealso> class is more flexible.
 1124    /// </remarks>
 1125    public static string CleanName(string name)
 1126    {
 1318771127       if (name == null) {
 01128        return string.Empty;
 1129      }
 1130
 1318771131       if (Path.IsPathRooted(name)) {
 1132        // NOTE:
 1133        // for UNC names...  \\machine\share\zoom\beet.txt gives \zoom\beet.txt
 01134        name = name.Substring(Path.GetPathRoot(name).Length);
 1135      }
 1136
 1318771137      name = name.Replace(@"\", "/");
 1138
 1318771139       while ((name.Length > 0) && (name[0] == '/')) {
 01140        name = name.Remove(0, 1);
 1141      }
 1318771142      return name;
 1143    }
 1144
 1145    #region Instance Fields
 1146    Known known;
 1318791147    int externalFileAttributes = -1;     // contains external attributes (O/S dependant)
 1148
 1149    ushort versionMadeBy;                   // Contains host system and version information
 1150                        // only relevant for central header entries
 1151
 1152    string name;
 1153    ulong size;
 1154    ulong compressedSize;
 1155    ushort versionToExtract;                // Version required to extract (library handles <= 2.0)
 1156    uint crc;
 1157    uint dosTime;
 1158    DateTime dateTime;
 1159
 1318791160    CompressionMethod method = CompressionMethod.Deflated;
 1161    byte[] extra;
 1162    string comment;
 1163
 1164    int flags;                             // general purpose bit flags
 1165
 1318791166    long zipFileIndex = -1;                // used by ZipFile
 1167    long offset;                           // used by ZipFile and ZipOutputStream
 1168
 1169    bool forceZip64_;
 1170    byte cryptoCheckValue_;
 1171    int _aesVer;                            // Version number (2 = AE-2 ?). Assigned but not used.
 1172    int _aesEncryptionStrength;             // Encryption strength 1 = 128 2 = 192 3 = 256
 1173    #endregion
 1174  }
 1175}