PageRenderTime 53ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Compression/ZipEntry.cs

#
C# | 984 lines | 568 code | 66 blank | 350 comment | 75 complexity | 1ee0479e05a2d4b1c9554cae8d8731a6 MD5 | raw file
Possible License(s): Apache-2.0
  1. // Based on Mike Krueger's SharpZipLib, Copyright (C) 2001 (GNU license).
  2. // Authors of the original java version: Jochen Hoenicke, John Leuner
  3. // See http://www.ISeeSharpCode.com for more information.
  4. using System;
  5. using System.IO;
  6. using Delta.Utilities.Helpers;
  7. namespace Delta.Utilities.Compression
  8. {
  9. /// <summary>
  10. /// This class represents an entry in a zip archive. This can be a file
  11. /// or a directory ZipFile and ZipInputStream will give you instances of
  12. /// this class as information about the members in an archive.
  13. /// ZipOutputStream uses an instance of this class when creating an entry
  14. /// in a Zip file.
  15. /// <br/>Author of the original java version : Jochen Hoenicke
  16. /// </summary>
  17. public class ZipEntry //: ICloneable
  18. {
  19. #region Constants
  20. private const int KnownSize = 1;
  21. private const int KnownCSize = 2;
  22. private const int KnownCrc = 4;
  23. private const int KnownTime = 8;
  24. private const int KnownExternAttributes = 16;
  25. #endregion
  26. #region CleanName (Static)
  27. /// <summary>
  28. /// Cleans a name making it conform to Zip file conventions.
  29. /// Devices names ('c:\') and UNC share names ('\\server\share') are
  30. /// removed and forward slashes ('\') are converted to back slashes ('/').
  31. /// </summary>
  32. /// <param name="name">Name to clean</param>
  33. /// <param name="relativePath">Make names relative if true or absolute if
  34. /// false</param>
  35. public static string CleanName(string name, bool relativePath)
  36. {
  37. if (name == null)
  38. {
  39. return "";
  40. }
  41. if (Path.IsPathRooted(name))
  42. {
  43. // NOTE:
  44. // for UNC names... \\machine\share\zoom\beet.txt gives \zoom\beet.txt
  45. name = name.Substring(Path.GetPathRoot(name).Length);
  46. }
  47. name = name.Replace(@"\", "/");
  48. if (relativePath)
  49. {
  50. if (name.Length > 0 &&
  51. (name[0] == Path.AltDirectorySeparatorChar ||
  52. name[0] == Path.DirectorySeparatorChar))
  53. {
  54. name = name.Remove(0, 1);
  55. }
  56. }
  57. else
  58. {
  59. if (name.Length > 0 &&
  60. name[0] != Path.AltDirectorySeparatorChar &&
  61. name[0] != Path.DirectorySeparatorChar)
  62. {
  63. name = name.Insert(0, "/");
  64. }
  65. }
  66. return name;
  67. }
  68. /// <summary>
  69. /// Cleans a name making it conform to Zip file conventions.
  70. /// Devices names ('c:\') and UNC share names ('\\server\share') are
  71. /// removed and forward slashes ('\') are converted to back slashes ('/').
  72. /// Names are made relative by trimming leading slashes which is
  73. /// compatible with Windows-XPs built in Zip file handling.
  74. /// </summary>
  75. /// <param name="name">Name to clean</param>
  76. public static string CleanName(string name)
  77. {
  78. return CleanName(name, true);
  79. }
  80. #endregion
  81. #region IsCrypted (Public)
  82. /// <summary>
  83. /// Get/Set flag indicating if entry is encrypted.
  84. /// A simple helper routine to aid interpretation of
  85. /// <see cref="Flags">flags</see>
  86. /// </summary>
  87. public bool IsCrypted
  88. {
  89. get
  90. {
  91. return (flags & 1) != 0;
  92. } // get
  93. set
  94. {
  95. if (value)
  96. {
  97. flags |= 1;
  98. } // if
  99. else
  100. {
  101. flags &= ~1;
  102. } // else
  103. } // set
  104. }
  105. #endregion
  106. #region Flags (Public)
  107. /// <summary>
  108. /// Get/Set general purpose bit flag for entry
  109. /// </summary>
  110. /// <remarks>
  111. /// General purpose bit flag<br/>
  112. /// Bit 0: If set, indicates the file is encrypted<br/>
  113. /// Bit 1-2 Only used for compression type 6 Imploding, and 8, 9
  114. /// deflating<br/>
  115. /// Imploding:<br/>
  116. /// Bit 1 if set indicates an 8K sliding dictionary was used.
  117. /// If clear a 4k dictionary was used<br/>
  118. /// Bit 2 if set indicates 3 Shannon-Fanno trees were used to encode the
  119. /// sliding dictionary, 2 otherwise<br/>
  120. /// <br/>
  121. /// Deflating:<br/>
  122. /// Bit 2 Bit 1<br/>
  123. /// 0 0 Normal compression was used<br/>
  124. /// 0 1 Maximum compression was used<br/>
  125. /// 1 0 Fast compression was used<br/>
  126. /// 1 1 Super fast compression was used<br/>
  127. /// <br/>
  128. /// Bit 3: If set, the fields crc-32, compressed size
  129. /// and uncompressed size are were not able to be written during zip file
  130. /// creation. The correct values are held in a data descriptor immediately
  131. /// following the compressed data. <br/>
  132. /// Bit 4: Reserved for use by PKZIP for enhanced deflating<br/>
  133. /// Bit 5: If set indicates the file contains compressed patch data<br/>
  134. /// Bit 6: If set indicates strong encryption was used.<br/>
  135. /// Bit 7-15: Unused or reserved<br/>
  136. /// </remarks>
  137. public int Flags
  138. {
  139. get
  140. {
  141. return flags;
  142. } // get
  143. set
  144. {
  145. flags = value;
  146. } // set
  147. }
  148. #endregion
  149. #region ZipFileIndex (Public)
  150. /// <summary>
  151. /// Get/Set index of this entry in Zip file
  152. /// </summary>
  153. public int ZipFileIndex
  154. {
  155. get
  156. {
  157. return zipFileIndex;
  158. } // get
  159. set
  160. {
  161. zipFileIndex = value;
  162. } // set
  163. }
  164. #endregion
  165. #region Offset (Public)
  166. /// <summary>
  167. /// Get/set offset for use in central header
  168. /// </summary>
  169. public int Offset
  170. {
  171. get
  172. {
  173. return offset;
  174. }
  175. set
  176. {
  177. if (((ulong)value & 0xFFFFFFFF00000000L) != 0)
  178. {
  179. throw new ArgumentOutOfRangeException("Offset");
  180. } // if
  181. offset = value;
  182. } // set
  183. }
  184. #endregion
  185. #region ExternalFileAttributes (Public)
  186. /// <summary>
  187. /// Get/Set external file attributes as an integer.
  188. /// The values of this are operating system dependant see
  189. /// <see cref="HostSystemId">HostSystem</see> for details
  190. /// </summary>
  191. public int ExternalFileAttributes
  192. {
  193. get
  194. {
  195. if ((known & KnownExternAttributes) == 0)
  196. {
  197. return MathHelper.InvalidIndex;
  198. } // if
  199. else
  200. {
  201. return externalFileAttributes;
  202. } // else
  203. } // get
  204. set
  205. {
  206. externalFileAttributes = value;
  207. known |= KnownExternAttributes;
  208. } // set
  209. }
  210. #endregion
  211. #region VersionMadeBy (Public)
  212. /// <summary>
  213. /// Get the version made by for this entry or zero if unknown.
  214. /// The value / 10 indicates the major version number, and
  215. /// the value mod 10 is the minor version number
  216. /// </summary>
  217. public int VersionMadeBy
  218. {
  219. get
  220. {
  221. return versionMadeBy & 0xff;
  222. } // get
  223. }
  224. #endregion
  225. #region HostSystemId (Public)
  226. /// <summary>
  227. /// Gets the compatability information for the
  228. /// <see cref="ExternalFileAttributes">external file attribute</see>
  229. /// If the external file attributes are compatible with MS-DOS and can be
  230. /// read by PKZIP for DOS version 2.04g then this value will be zero.
  231. /// Otherwise the value will be non-zero and identify the host system on
  232. /// which the attributes are compatible.
  233. /// </summary>
  234. /// <remarks>
  235. /// The values for this as defined in the Zip File format and by others
  236. /// are shown below. The values are somewhat misleading in some cases as
  237. /// they are not all used as shown. You should consult the relevant
  238. /// documentation to obtain up to date and correct information. The
  239. /// modified appnote by the infozip group is particularly helpful as it
  240. /// documents a lot of peculiarities. The document is however a little
  241. /// dated.
  242. /// <list type="table">
  243. /// <item>0 - MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)</item>
  244. /// <item>1 - Amiga</item>
  245. /// <item>2 - OpenVMS</item>
  246. /// <item>3 - Unix</item>
  247. /// <item>4 - VM/CMS</item>
  248. /// <item>5 - Atari ST</item>
  249. /// <item>6 - OS/2 HPFS</item>
  250. /// <item>7 - Macintosh</item>
  251. /// <item>8 - Z-System</item>
  252. /// <item>9 - CP/M</item>
  253. /// <item>10 - Windows NTFS</item>
  254. /// <item>11 - MVS (OS/390 - Z/OS)</item>
  255. /// <item>12 - VSE</item>
  256. /// <item>13 - Acorn Risc</item>
  257. /// <item>14 - VFAT</item>
  258. /// <item>15 - Alternate MVS</item>
  259. /// <item>16 - BeOS</item>
  260. /// <item>17 - Tandem</item>
  261. /// <item>18 - OS/400</item>
  262. /// <item>19 - OS/X (Darwin)</item>
  263. /// <item>99 - WinZip AES</item>
  264. /// <item>remainder - unused</item>
  265. /// </list>
  266. /// </remarks>
  267. public int HostSystemId
  268. {
  269. get
  270. {
  271. return (versionMadeBy >> 8) & 0xff;
  272. } // get
  273. }
  274. #endregion
  275. #region Version (Public)
  276. /// <summary>
  277. /// Get minimum Zip feature version required to extract this
  278. /// entry
  279. /// </summary>
  280. /// <remarks>
  281. /// Minimum features are defined as:<br/>
  282. /// 1.0 - Default value<br/>
  283. /// 1.1 - File is a volume label<br/>
  284. /// 2.0 - File is a folder/directory<br/>
  285. /// 2.0 - File is compressed using Deflate compression<br/>
  286. /// 2.0 - File is encrypted using traditional encryption<br/>
  287. /// 2.1 - File is compressed using Deflate64<br/>
  288. /// 2.5 - File is compressed using PKWARE DCL Implode<br/>
  289. /// 2.7 - File is a patch data set<br/>
  290. /// 4.5 - File uses Zip64 format extensions<br/>
  291. /// 4.6 - File is compressed using BZIP2 compression<br/>
  292. /// 5.0 - File is encrypted using DES<br/>
  293. /// 5.0 - File is encrypted using 3DES<br/>
  294. /// 5.0 - File is encrypted using original RC2 encryption<br/>
  295. /// 5.0 - File is encrypted using RC4 encryption<br/>
  296. /// 5.1 - File is encrypted using AES encryption<br/>
  297. /// 5.1 - File is encrypted using corrected RC2 encryption<br/>
  298. /// 5.1 - File is encrypted using corrected RC2-64 encryption<br/>
  299. /// 6.1 - File is encrypted using non-OAEP key wrapping<br/>
  300. /// 6.2 - Central directory encryption (not confirmed yet)<br/>
  301. /// </remarks>
  302. public int Version
  303. {
  304. get
  305. {
  306. if (versionToExtract != 0)
  307. {
  308. return versionToExtract;
  309. } // if
  310. else
  311. {
  312. int result = 10;
  313. if (CompressionMethod.Deflated == method)
  314. {
  315. result = 20;
  316. } // if
  317. else if (IsDirectory)
  318. {
  319. result = 20;
  320. } // else if
  321. else if (IsCrypted)
  322. {
  323. result = 20;
  324. } // else if
  325. else if ((known & KnownExternAttributes) != 0 &&
  326. (externalFileAttributes & 0x08) != 0)
  327. {
  328. result = 11;
  329. } // else if
  330. return result;
  331. } // else
  332. } // get
  333. }
  334. #endregion
  335. #region RequiresZip64 (Public)
  336. /// <summary>
  337. /// Gets a value indicating if the entry requires Zip64 extensions to be
  338. /// stored.
  339. /// </summary>
  340. public bool RequiresZip64
  341. {
  342. get
  343. {
  344. return (size > uint.MaxValue) ||
  345. (compressedSize > uint.MaxValue);
  346. } // get
  347. }
  348. #endregion
  349. #region DosTime (Public)
  350. /// <summary>
  351. /// Gets/Sets DosTime
  352. /// </summary>
  353. public long DosTime
  354. {
  355. get
  356. {
  357. if ((known & KnownTime) == 0)
  358. {
  359. return 0;
  360. } // if
  361. else
  362. {
  363. return dosTime;
  364. } // else
  365. } // get
  366. set
  367. {
  368. dosTime = (uint)value;
  369. known |= KnownTime;
  370. } // set
  371. }
  372. #endregion
  373. #region DateTime (Public)
  374. /// <summary>
  375. /// Gets/Sets the time of last modification of the entry.
  376. /// </summary>
  377. public DateTime DateTime
  378. {
  379. get
  380. {
  381. // Although technically not valid some archives have dates set to zero.
  382. // This mimics some archivers handling and is a good a cludge as any
  383. // probably.
  384. if (dosTime == 0)
  385. {
  386. return DateTime.Now;
  387. } // if
  388. else
  389. {
  390. uint sec = 2 * (dosTime & 0x1f);
  391. uint min = (dosTime >> 5) & 0x3f;
  392. uint hrs = (dosTime >> 11) & 0x1f;
  393. uint day = (dosTime >> 16) & 0x1f;
  394. uint mon = ((dosTime >> 21) & 0xf);
  395. uint year = ((dosTime >> 25) & 0x7f) + 1980;
  396. return new DateTime((int)year, (int)mon, (int)day,
  397. (int)hrs, (int)min, (int)sec);
  398. } // else
  399. } // get
  400. set
  401. {
  402. DosTime =
  403. ((uint)value.Year - 1980 & 0x7f) << 25 |
  404. ((uint)value.Month) << 21 |
  405. ((uint)value.Day) << 16 |
  406. ((uint)value.Hour) << 11 |
  407. ((uint)value.Minute) << 5 |
  408. ((uint)value.Second) >> 1;
  409. } // set
  410. }
  411. #endregion
  412. #region Name (Public)
  413. /// <summary>
  414. /// Returns the entry name. The path components in the entry should
  415. /// always separated by slashes ('/'). Dos device names like C: should
  416. /// also be removed. See <see cref="CleanName(string)">CleanName</see>.
  417. /// </summary>
  418. public string Name
  419. {
  420. get
  421. {
  422. return name;
  423. } // get
  424. }
  425. #endregion
  426. #region Comment (Public)
  427. /// <summary>
  428. /// Gets/Sets the entry comment.
  429. /// </summary>
  430. /// <exception cref="System.ArgumentOutOfRangeException">
  431. /// If comment is longer than 0xffff.
  432. /// </exception>
  433. /// <returns>
  434. /// The comment or null if not set.
  435. /// </returns>
  436. public string Comment
  437. {
  438. get
  439. {
  440. return comment;
  441. }
  442. set
  443. {
  444. // While the test is correct in that a comment of this length or
  445. // greater is definitely invalid, shorter comments may also have an
  446. // invalid length.
  447. if (value != null &&
  448. value.Length > 0xffff)
  449. {
  450. throw new ArgumentOutOfRangeException();
  451. }
  452. comment = value;
  453. }
  454. }
  455. #endregion
  456. #region IsDirectory (Public)
  457. /// <summary>
  458. /// Gets a value indicating of the if the entry is a directory.
  459. /// A directory is determined by an entry name with a trailing slash '/'.
  460. /// The external file attributes can also mark a file as a directory.
  461. /// The trailing slash convention should always be followed however.
  462. /// </summary>
  463. public bool IsDirectory
  464. {
  465. get
  466. {
  467. int nlen = name.Length;
  468. bool result = nlen > 0 && name[nlen - 1] == '/';
  469. if (result == false &&
  470. (known & KnownExternAttributes) != 0)
  471. {
  472. if (HostSystemId == 0 &&
  473. (ExternalFileAttributes & 16) != 0)
  474. {
  475. result = true;
  476. }
  477. }
  478. return result;
  479. }
  480. }
  481. #endregion
  482. #region IsFile (Public)
  483. /// <summary>
  484. /// Get a value of true if the entry appears to be a file; false otherwise
  485. /// </summary>
  486. /// <remarks>
  487. /// This only takes account Windows attributes. Other operating systems
  488. /// are ignored. For Linux and others the result may be incorrect.
  489. /// </remarks>
  490. public bool IsFile
  491. {
  492. get
  493. {
  494. bool result = !IsDirectory;
  495. // Exclude volume labels
  496. if (result && (known & KnownExternAttributes) != 0)
  497. {
  498. if (HostSystemId == 0 &&
  499. (ExternalFileAttributes & 8) != 0)
  500. {
  501. result = false;
  502. }
  503. }
  504. return result;
  505. }
  506. }
  507. #endregion
  508. #region Size (Public)
  509. /// <summary>
  510. /// Gets/Sets the size of the uncompressed data.
  511. /// </summary>
  512. /// <exception cref="System.ArgumentOutOfRangeException">
  513. /// If the size is not in the range 0..0xffffffffL
  514. /// </exception>
  515. /// <returns>
  516. /// The size or -1 if unknown.
  517. /// </returns>
  518. public long Size
  519. {
  520. get
  521. {
  522. return (known & KnownSize) != 0
  523. ? (long)size
  524. : -1L;
  525. }
  526. set
  527. {
  528. if (((ulong)value & 0xFFFFFFFF00000000L) != 0)
  529. {
  530. throw new ArgumentOutOfRangeException("size");
  531. }
  532. size = (ulong)value;
  533. known |= KnownSize;
  534. }
  535. }
  536. #endregion
  537. #region CompressedSize (Public)
  538. /// <summary>
  539. /// Gets/Sets the size of the compressed data.
  540. /// </summary>
  541. /// <exception cref="System.ArgumentOutOfRangeException">
  542. /// Size is not in the range 0..0xffffffff
  543. /// </exception>
  544. /// <returns>
  545. /// The size or -1 if unknown.
  546. /// </returns>
  547. public long CompressedSize
  548. {
  549. get
  550. {
  551. return (known & KnownCSize) != 0
  552. ? (long)compressedSize
  553. : -1L;
  554. }
  555. set
  556. {
  557. if (((ulong)value & 0xffffffff00000000L) != 0)
  558. {
  559. throw new ArgumentOutOfRangeException();
  560. }
  561. compressedSize = (ulong)value;
  562. known |= KnownCSize;
  563. }
  564. }
  565. #endregion
  566. #region Crc (Public)
  567. /// <summary>
  568. /// Gets/Sets the crc of the uncompressed data.
  569. /// </summary>
  570. /// <exception cref="System.ArgumentOutOfRangeException">
  571. /// Crc is not in the range 0..0xffffffffL
  572. /// </exception>
  573. /// <returns>
  574. /// The crc value or -1 if unknown.
  575. /// </returns>
  576. public long Crc
  577. {
  578. get
  579. {
  580. return (known & KnownCrc) != 0
  581. ? crc & 0xffffffffL
  582. : -1L;
  583. }
  584. set
  585. {
  586. if ((crc & 0xffffffff00000000L) != 0)
  587. {
  588. throw new ArgumentOutOfRangeException();
  589. }
  590. crc = (uint)value;
  591. known |= KnownCrc;
  592. }
  593. }
  594. #endregion
  595. #region CompressionMethod (Public)
  596. /// <summary>
  597. /// Gets/Sets the compression method. Only Deflated and Stored are
  598. /// supported.
  599. /// </summary>
  600. /// <returns>
  601. /// The compression method for this entry
  602. /// </returns>
  603. /// <see cref="Delta.Utilities.Compression.CompressionMethod.Deflated"/>
  604. /// <see cref="Delta.Utilities.Compression.CompressionMethod.Stored"/>
  605. public CompressionMethod CompressionMethod
  606. {
  607. get
  608. {
  609. return method;
  610. }
  611. set
  612. {
  613. method = value;
  614. }
  615. }
  616. #endregion
  617. #region Private
  618. #region known (Private)
  619. /// <summary>
  620. /// Bit flags made up of above bits
  621. /// </summary>
  622. private ushort known;
  623. #endregion
  624. #region externalFileAttributes (Private)
  625. /// <summary>
  626. /// contains external attributes (os dependant)
  627. /// </summary>
  628. private int externalFileAttributes;
  629. #endregion
  630. #region versionMadeBy (Private)
  631. /// <summary>
  632. /// Contains host system and version information
  633. /// only relevant for central header entries
  634. /// </summary>
  635. private ushort versionMadeBy;
  636. #endregion
  637. #region name (Private)
  638. /// <summary>
  639. /// Name
  640. /// </summary>
  641. private string name;
  642. #endregion
  643. #region size (Private)
  644. /// <summary>
  645. /// Size
  646. /// </summary>
  647. private ulong size;
  648. #endregion
  649. #region compressedSize (Private)
  650. /// <summary>
  651. /// Compressed size
  652. /// </summary>
  653. private ulong compressedSize;
  654. #endregion
  655. #region versionToExtract (Private)
  656. /// <summary>
  657. /// Version required to extract (library handles &lt;= 2.0)
  658. /// </summary>
  659. private ushort versionToExtract;
  660. #endregion
  661. #region crc (Private)
  662. /// <summary>
  663. /// Crc
  664. /// </summary>
  665. private uint crc;
  666. #endregion
  667. #region dosTime (Private)
  668. /// <summary>
  669. /// Dos time
  670. /// </summary>
  671. private uint dosTime;
  672. #endregion
  673. #region method (Private)
  674. /// <summary>
  675. /// Method
  676. /// </summary>
  677. private CompressionMethod method;
  678. #endregion
  679. #region extra (Private)
  680. /// <summary>
  681. /// Extra
  682. /// </summary>
  683. private byte[] extra;
  684. #endregion
  685. #region comment (Private)
  686. /// <summary>
  687. /// Comment
  688. /// </summary>
  689. private string comment;
  690. #endregion
  691. #region flags (Private)
  692. /// <summary>
  693. /// general purpose bit flags
  694. /// </summary>
  695. private int flags;
  696. #endregion
  697. #region zipFileIndex (Private)
  698. /// <summary>
  699. /// used by ZipFile
  700. /// </summary>
  701. private int zipFileIndex;
  702. #endregion
  703. #region offset (Private)
  704. /// <summary>
  705. /// used by ZipFile and ZipOutputStream
  706. /// </summary>
  707. private int offset;
  708. #endregion
  709. #endregion
  710. #region Constructors
  711. /// <summary>
  712. /// Creates a zip entry with the given name.
  713. /// </summary>
  714. /// <param name="name">
  715. /// The name for this entry. Can include directory components.
  716. /// The convention for names is 'unix' style paths with no device names
  717. /// and path elements separated by '/' characters. This is not enforced
  718. /// see <see cref="CleanName(string)">CleanName</see> on how to ensure
  719. /// names are valid if this is desired.
  720. /// </param>
  721. /// <exception cref="ArgumentNullException">The name passed is null
  722. /// </exception>
  723. public ZipEntry(string name)
  724. : this(name, 0, ZipConstants.VersionMadeBy)
  725. {
  726. }
  727. /// <summary>
  728. /// Creates a zip entry with the given name and version required to extract
  729. /// </summary>
  730. /// <param name="name">
  731. /// The name for this entry. Can include directory components.
  732. /// The convention for names is 'unix' style paths with no device names
  733. /// and path elements separated by '/' characters. This is not enforced
  734. /// see <see cref="CleanName(string)">CleanName</see> on how to ensure
  735. /// names are valid if this is desired.
  736. /// </param>
  737. /// <param name="versionRequiredToExtract">
  738. /// The minimum 'feature version' required this entry
  739. /// </param>
  740. /// <exception cref="ArgumentNullException">The name passed is null
  741. /// </exception>
  742. internal ZipEntry(string name, int versionRequiredToExtract)
  743. : this(name, versionRequiredToExtract, ZipConstants.VersionMadeBy)
  744. {
  745. }
  746. /// <summary>
  747. /// Initializes an entry with the given name and made by information
  748. /// </summary>
  749. /// <param name="setName">Name for this entry</param>
  750. /// <param name="setMadeByInfo">Version and HostSystem Information</param>
  751. /// <param name="setVersionRequiredToExtract">Minimum required zip feature
  752. /// version required to extract this entry</param>
  753. /// <exception cref="ArgumentNullException">
  754. /// The name passed is null
  755. /// </exception>
  756. /// <exception cref="ArgumentOutOfRangeException">
  757. /// versionRequiredToExtract should be 0 (auto-calculate) or > 10
  758. /// </exception>
  759. /// <remarks>
  760. /// This constructor is used by the ZipFile class when reading from the
  761. /// central header. It is not generally useful, use the constructor
  762. /// specifying the name only.
  763. /// </remarks>
  764. internal ZipEntry(string setName, int setVersionRequiredToExtract,
  765. int setMadeByInfo)
  766. {
  767. if (setName == null)
  768. {
  769. throw new ArgumentNullException("ZipEntry name");
  770. }
  771. if (setName.Length == 0)
  772. {
  773. throw new ArgumentException("ZipEntry name is empty");
  774. }
  775. if (setVersionRequiredToExtract != 0 &&
  776. setVersionRequiredToExtract < 10)
  777. {
  778. throw new ArgumentOutOfRangeException(
  779. "versionRequiredToExtract");
  780. }
  781. DateTime = DateTime.Now;
  782. name = setName;
  783. versionMadeBy = (ushort)setMadeByInfo;
  784. versionToExtract = (ushort)setVersionRequiredToExtract;
  785. method = CompressionMethod.Deflated;
  786. zipFileIndex = MathHelper.InvalidIndex;
  787. externalFileAttributes = MathHelper.InvalidIndex;
  788. }
  789. /// <summary>
  790. /// Can be used for the "Load" method (after saving) or to create a clone.
  791. /// </summary>
  792. private ZipEntry()
  793. {
  794. }
  795. #endregion
  796. #region GetExtraData (Public)
  797. /// <summary>
  798. /// Get extra data
  799. /// </summary>
  800. public byte[] GetExtraData()
  801. {
  802. return extra;
  803. }
  804. #endregion
  805. #region SetExtraData (Public)
  806. /// <summary>
  807. /// Set extra data
  808. /// </summary>
  809. /// <param name="value">Value</param>
  810. public void SetExtraData(byte[] value)
  811. {
  812. if (value == null)
  813. {
  814. extra = null;
  815. return;
  816. }
  817. if (value.Length > 0xffff)
  818. {
  819. throw new ArgumentOutOfRangeException();
  820. }
  821. extra = new byte[value.Length];
  822. Array.Copy(value, 0, extra, 0, value.Length);
  823. try
  824. {
  825. int pos = 0;
  826. while (pos < extra.Length)
  827. {
  828. int sig = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
  829. int len = (extra[pos++] & 0xff) | (extra[pos++] & 0xff) << 8;
  830. if (len < 0 ||
  831. pos + len > extra.Length)
  832. {
  833. // This is still lenient but the extra data is corrupt.
  834. // Note: Drops the extra data. Indicate to user there is a problem.
  835. Log.Warning(
  836. "Dropping extra data in zip entry '" + name + "': " + len);
  837. break;
  838. }
  839. if (sig == 0x5455)
  840. {
  841. // extended time stamp, unix format by Rainer Prem
  842. int extraFlags = extra[pos];
  843. // Can include other times but these are ignored.
  844. // Length of data should actually be 1 + 4 * no of bits in flags.
  845. if ((extraFlags & 1) != 0 &&
  846. len >= 5)
  847. {
  848. int iTime =
  849. ((extra[pos + 1] & 0xff) |
  850. (extra[pos + 2] & 0xff) << 8 |
  851. (extra[pos + 3] & 0xff) << 16 |
  852. (extra[pos + 4] & 0xff) << 24);
  853. DateTime =
  854. (new DateTime(1970, 1, 1, 0, 0, 0) +
  855. new TimeSpan(0, 0, 0, iTime, 0)).ToLocalTime();
  856. known |= KnownTime;
  857. }
  858. }
  859. else if (sig == 0x0001)
  860. {
  861. // ZIP64 extended information extra field
  862. // Of variable size depending on which fields in header are too
  863. // small fields appear here if the corresponding local or central
  864. // directory record field is set to 0xFFFF or 0xFFFFFFFF and the
  865. // entry is in Zip64 format.
  866. //
  867. // Original Size 8 bytes
  868. // Compressed size 8 bytes
  869. // Relative header offset 8 bytes
  870. // Disk start number 4 bytes
  871. }
  872. pos += len;
  873. }
  874. }
  875. catch (Exception)
  876. {
  877. // be lenient
  878. return;
  879. }
  880. }
  881. #endregion
  882. #region Clone (Public)
  883. /// <summary>
  884. /// Creates a copy of this zip entry.
  885. /// </summary>
  886. public ZipEntry Clone()
  887. {
  888. return new ZipEntry
  889. {
  890. known = known,
  891. name = name,
  892. size = size,
  893. compressedSize = compressedSize,
  894. crc = crc,
  895. dosTime = dosTime,
  896. method = method,
  897. extra = extra,
  898. comment = comment,
  899. versionToExtract = versionToExtract,
  900. versionMadeBy = versionMadeBy,
  901. externalFileAttributes = externalFileAttributes,
  902. flags = flags,
  903. zipFileIndex = zipFileIndex,
  904. offset = offset,
  905. };
  906. }
  907. #endregion
  908. #region ToString (Public)
  909. /// <summary>
  910. /// Gets the string representation of this ZipEntry.
  911. /// </summary>
  912. public override string ToString()
  913. {
  914. return name;
  915. }
  916. #endregion
  917. }
  918. }