PageRenderTime 61ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/dotnet/common-windsor-net/windsor-commons-compression/DotNetZip/Library/ZipEntry.cs

http://opennode2.googlecode.com/
C# | 3960 lines | 2441 code | 327 blank | 1192 comment | 246 complexity | 0490151077d9c42f7c2318602c17223c MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-3.0, Apache-2.0, LGPL-2.1, CC-BY-SA-3.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. #region License
  2. /*
  3. Copyright (c) 2009, The Environmental Council of the States (ECOS)
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions
  7. are met:
  8. * Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in the
  12. documentation and/or other materials provided with the distribution.
  13. * Neither the name of the ECOS nor the names of its contributors may
  14. be used to endorse or promote products derived from this software
  15. without specific prior written permission.
  16. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  17. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  18. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  19. FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  20. COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  21. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  22. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  24. CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  26. ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #endregion
  30. #define OPTIMIZE_WI6612
  31. // ZipEntry.cs
  32. //
  33. // Copyright (c) 2006, 2007, 2008, 2009 Microsoft Corporation. All rights reserved.
  34. //
  35. // Part of an implementation of a zipfile class library.
  36. // See the file ZipFile.cs for the license and for further information.
  37. //
  38. // Created: Tue, 27 Mar 2007 15:30
  39. //
  40. using System;
  41. using System.IO;
  42. using RE = System.Text.RegularExpressions;
  43. namespace Ionic.Zip
  44. {
  45. /// <summary>
  46. /// An enum that provides the various encryption algorithms supported by this library.
  47. /// </summary>
  48. /// <remarks>
  49. /// <para>
  50. /// PkzipWeak implies the use of Zip 2.0 encryption, which is known to be weak and subvertible.
  51. /// </para>
  52. /// <para>
  53. /// A note on interoperability: Values of PkzipWeak and None are specified in the PKWare AppNote.txt document, are
  54. /// considered to be "standard". Zip archives produced using these options will be interoperable with many other
  55. /// zip tools and libraries, including Windows Explorer.
  56. /// </para>
  57. /// <para>
  58. /// Values of WinZipAes128 and WinZipAes256 are not part of the Zip specification, but rather imply the use of a
  59. /// vendor-specific extension from WinZip. If you want to produce interoperable Zip archives, do not use these values.
  60. /// For example, if you
  61. /// produce a zip archive using WinZipAes256, you will be able to open it in Windows Explorer on Windows XP and Vista,
  62. /// but you will not be able to extract entries; trying this will lead to an "unspecified error". For this reason,
  63. /// some people have said that a zip archive that uses WinZip's AES encryption is not actually a zip archive at all.
  64. /// A zip archive produced this way will be readable with the WinZip tool
  65. /// (Version 11 and beyond).
  66. /// </para>
  67. /// <para>
  68. /// There are other third-party tools and libraries, both commercial and otherwise, that support WinZip's
  69. /// AES encryption. These will be able to read AES-encrypted zip archives produced by DotNetZip, and conversely applications
  70. /// that use DotNetZip to read zip archives will be able to read AES-encrypted archives produced by those tools
  71. /// or libraries. Consult the documentation for those other tools and libraries to find out if WinZip's AES
  72. /// encryption is supported.
  73. /// </para>
  74. /// <para>
  75. /// In case you care: According to the WinZip specification, the actual key used is derived from the
  76. /// <see cref="ZipEntry.Password"/> via an algorithm that complies with RFC 2898, using an iteration count of 1000.
  77. /// I am no security expert, but I think you should use a long-ish password if you employ 256-bit AES
  78. /// encryption. Make it 16 characters or more.
  79. /// </para>
  80. /// <para>
  81. /// The WinZip AES algorithms are not supported with the version of DotNetZip that runs on the .NET Compact Framework.
  82. /// This is because .NET CF lacks the HMACSHA1 class that is required for producing the archive.
  83. /// </para>
  84. /// </remarks>
  85. public enum EncryptionAlgorithm
  86. {
  87. /// <summary>
  88. /// No encryption at all.
  89. /// </summary>
  90. None = 0,
  91. /// <summary>
  92. /// Traditional or Classic pkzip encryption.
  93. /// </summary>
  94. PkzipWeak,
  95. #if AESCRYPTO
  96. /// <summary>
  97. /// WinZip AES encryption (128 key bits).
  98. /// </summary>
  99. WinZipAes128,
  100. /// <summary>
  101. /// WinZip AES encryption (256 key bits).
  102. /// </summary>
  103. WinZipAes256,
  104. #endif
  105. // others... not implemented (yet?)
  106. }
  107. /// <summary>
  108. /// An enum that specifies the source of the ZipEntry.
  109. /// </summary>
  110. internal enum EntrySource
  111. {
  112. /// <summary>
  113. /// Default value. Invalid on a bonafide ZipEntry.
  114. /// </summary>
  115. None = 0,
  116. /// <summary>
  117. /// Entry was instantiated by Adding an entry from the filesystem.
  118. /// </summary>
  119. Filesystem,
  120. /// <summary>
  121. /// Entry was instantiated by reading a zipfile.
  122. /// </summary>
  123. Zipfile,
  124. /// <summary>
  125. /// Entry was instantiated via a stream or string.
  126. /// </summary>
  127. Stream,
  128. }
  129. /// <summary>
  130. /// Represents a single entry in a ZipFile. Typically, applications
  131. /// get a ZipEntry by enumerating the entries within a ZipFile,
  132. /// or by adding an entry to a ZipFile.
  133. /// </summary>
  134. public partial class ZipEntry
  135. {
  136. internal ZipEntry() { }
  137. /// <summary>
  138. /// The time and date at which the file indicated by the ZipEntry was last modified.
  139. /// </summary>
  140. ///
  141. /// <remarks>
  142. /// <para>
  143. /// The DotNetZip library sets the LastModified value for an entry, equal to the
  144. /// Last Modified time of the file in the filesystem. If an entry is added from a stream,
  145. /// in which case no Last Modified attribute is available, the library uses
  146. /// <c>System.DateTime.Now</c> for this value, for the given entry.
  147. /// </para>
  148. ///
  149. /// <para>
  150. /// It is also possible to set the LastModified value on an entry, to an arbitrary
  151. /// value. Be aware that because of the way the PKZip specification describes how
  152. /// times are stored in the zip file, the full precision of the
  153. /// <c>System.DateTime</c> datatype is not stored in LastModified when saving zip
  154. /// files. For more information on how times are formatted, see the PKZip
  155. /// specification.
  156. /// </para>
  157. ///
  158. /// <para>
  159. /// The last modified time of the file created upon a call to <c>ZipEntry.Extract()</c>
  160. /// may be adjusted during extraction to compensate
  161. /// for differences in how the .NET Base Class Library deals
  162. /// with daylight saving time (DST) versus how the Windows
  163. /// filesystem deals with daylight saving time.
  164. /// See http://blogs.msdn.com/oldnewthing/archive/2003/10/24/55413.aspx for more context.
  165. /// </para>
  166. /// <para>
  167. /// In a nutshell: Daylight savings time rules change regularly. In
  168. /// 2007, for example, the inception week of DST changed. In 1977,
  169. /// DST was in place all year round. In 1945, likewise. And so on.
  170. /// Win32 does not attempt to guess which time zone rules were in
  171. /// effect at the time in question. It will render a time as
  172. /// "standard time" and allow the app to change to DST as necessary.
  173. /// .NET makes a different choice.
  174. /// </para>
  175. /// <para>
  176. /// Compare the output of FileInfo.LastWriteTime.ToString("f") with
  177. /// what you see in the Windows Explorer property sheet for a file that was last
  178. /// written to on the other side of the DST transition. For example,
  179. /// suppose the file was last modified on October 17, 2003, during DST but
  180. /// DST is not currently in effect. Explorer's file properties
  181. /// reports Thursday, October 17, 2003, 8:45:38 AM, but .NETs
  182. /// FileInfo reports Thursday, October 17, 2003, 9:45 AM.
  183. /// </para>
  184. /// <para>
  185. /// Win32 says, "Thursday, October 17, 2002 8:45:38 AM PST". Note:
  186. /// Pacific STANDARD Time. Even though October 17 of that year
  187. /// occurred during Pacific Daylight Time, Win32 displays the time as
  188. /// standard time because that's what time it is NOW.
  189. /// </para>
  190. /// <para>
  191. /// .NET BCL assumes that the current DST rules were in place at the
  192. /// time in question. So, .NET says, "Well, if the rules in effect
  193. /// now were also in effect on October 17, 2003, then that would be
  194. /// daylight time" so it displays "Thursday, October 17, 2003, 9:45
  195. /// AM PDT" - daylight time.
  196. /// </para>
  197. /// <para>
  198. /// So .NET gives a value which is more intuitively correct, but is
  199. /// also potentially incorrect, and which is not invertible. Win32
  200. /// gives a value which is intuitively incorrect, but is strictly
  201. /// correct.
  202. /// </para>
  203. /// <para>
  204. /// Because of this funkiness, this library adds one hour to the LastModified time
  205. /// on the extracted file, if necessary. That is to say, if the time in question
  206. /// had occurred in what the .NET Base Class Library assumed to be DST (an
  207. /// assumption that may be wrong given the constantly changing DST rules).
  208. /// </para>
  209. /// </remarks>
  210. ///
  211. public DateTime LastModified
  212. {
  213. get { return _LastModified; }
  214. set
  215. {
  216. _LastModified = value;
  217. //SetLastModDateTimeWithAdjustment(this);
  218. _metadataChanged = true;
  219. }
  220. }
  221. #if LEGACY
  222. /// <summary>
  223. /// When this is set, this class trims the volume (eg C:\) from any
  224. /// fully-qualified pathname on the ZipEntry, before writing the ZipEntry into
  225. /// the ZipFile. This flag affects only zip creation. By default, this flag is TRUE,
  226. /// which means volume names will not be included in the filenames on entries in
  227. /// the archive. Your best bet is to just leave this alone.
  228. /// </summary>
  229. internal bool TrimVolumeFromFullyQualifiedPaths
  230. {
  231. get { return _TrimVolumeFromFullyQualifiedPaths; }
  232. set { _TrimVolumeFromFullyQualifiedPaths = value; }
  233. }
  234. #endif
  235. /// <summary>
  236. /// When this is set, the entry is not compressed when written to
  237. /// the archive. For example, the application might want to set flag to <c>true</c>
  238. /// this when zipping up JPG or MP3 files, which are already compressed.
  239. /// </summary>
  240. /// <seealso cref="Ionic.Zip.ZipFile.ForceNoCompression"/>
  241. ///
  242. public bool ForceNoCompression
  243. {
  244. get { return _ForceNoCompression; }
  245. set
  246. {
  247. if (value == _ForceNoCompression) return; // nothing to do.
  248. // If the source is a zip archive and there was encryption on the
  249. // entry, changing the compression method is not supported.
  250. if (this._Source == EntrySource.Zipfile && _sourceIsEncrypted)
  251. throw new InvalidOperationException("Cannot change compression method on encrypted entries read from archives.");
  252. _ForceNoCompression = value;
  253. }
  254. }
  255. /// <summary>
  256. /// The name of the filesystem file, referred to by the ZipEntry.
  257. /// </summary>
  258. ///
  259. /// <remarks>
  260. /// <para>
  261. /// This may be different than the path used in the archive itself. What I mean is,
  262. /// if you call <c>Zip.AddFile("fooo.txt", AlternativeDirectory)</c>, then the
  263. /// path used for the ZipEntry within the zip archive will be different than this path.
  264. /// This path is used to locate the thing-to-be-zipped on disk.
  265. /// </para>
  266. /// <para>
  267. /// If the entry is being added from a stream, then this is null (Nothing in VB).
  268. /// </para>
  269. ///
  270. /// </remarks>
  271. /// <seealso cref="FileName"/>
  272. public string LocalFileName
  273. {
  274. get { return _LocalFileName; }
  275. }
  276. /// <summary>
  277. /// The name of the file contained in the ZipEntry.
  278. /// </summary>
  279. ///
  280. /// <remarks>
  281. /// <para>
  282. /// When writing a zip, this path has backslashes replaced with
  283. /// forward slashes, according to the zip spec, for compatibility
  284. /// with Unix(tm) and ... get this.... Amiga!
  285. /// </para>
  286. ///
  287. /// <para>
  288. /// This is the name of the entry in the ZipFile itself. This name may be different
  289. /// than the name of the filesystem file used to create the entry (LocalFileName). In fact, there
  290. /// may be no filesystem file at all, if the entry is created from a stream or a string.
  291. /// </para>
  292. ///
  293. /// <para>
  294. /// When setting this property, the value is made permanent only after a call to one of the ZipFile.Save() methods
  295. /// on the ZipFile that contains the ZipEntry. By reading in a ZipFile, then explicitly setting the FileName on an
  296. /// entry contained within the ZipFile, and then calling Save(), you will effectively rename the entry within
  297. /// the zip archive.
  298. /// </para>
  299. /// </remarks>
  300. /// <seealso cref="LocalFileName"/>
  301. public string FileName
  302. {
  303. get { return _FileNameInArchive; }
  304. set
  305. {
  306. // rename the entry!
  307. if (value == null || value == "") throw new ZipException("The FileName must be non empty and non-null.");
  308. var filename = ZipEntry.NameInArchive(value, null);
  309. _FileNameInArchive = value;
  310. if (this._zipfile != null) this._zipfile.NotifyEntryChanged();
  311. _metadataChanged = true;
  312. }
  313. }
  314. /// <summary>
  315. /// The version of the zip engine needed to read the ZipEntry.
  316. /// </summary>
  317. /// <remarks>
  318. /// This is usually 0x14.
  319. /// (Decimal 20). If ZIP64 is in use, the version will be decimal 45.
  320. /// </remarks>
  321. public Int16 VersionNeeded
  322. {
  323. get { return _VersionNeeded; }
  324. }
  325. /// <summary>
  326. /// The comment attached to the ZipEntry.
  327. /// </summary>
  328. ///
  329. /// <remarks>
  330. /// By default, the Comment is encoded in IBM437 code page. You can specify
  331. /// an alternative with <see cref="ProvisionalAlternateEncoding"/>
  332. /// </remarks>
  333. /// <seealso cref="ProvisionalAlternateEncoding">ProvisionalAlternateEncoding</seealso>
  334. public string Comment
  335. {
  336. get { return _Comment; }
  337. set
  338. {
  339. _Comment = value;
  340. _metadataChanged = true;
  341. }
  342. }
  343. /// <summary>
  344. /// Indicates whether the entry requires ZIP64 extensions.
  345. /// </summary>
  346. /// <remarks>
  347. /// <para>
  348. /// This property is null (Nothing in VB) until a Save() method on the containing
  349. /// <see cref="ZipFile"/> instance has been called. The property is non-null (HasValue is true)
  350. /// only after a Save() method has been called.
  351. /// </para>
  352. /// <para>
  353. /// After the containing ZipFile has been saved. the Value of this property is true if any of the following
  354. /// three conditions holds: the uncompressed size of the entry is larger than 0xFFFFFFFF;
  355. /// the compressed size of the entry is larger than 0xFFFFFFFF; the relative offset of the entry within the
  356. /// zip archive is larger than 0xFFFFFFFF. These quantities are not known until a Save() is attempted on the
  357. /// zip archive and the compression is applied.
  358. /// </para>
  359. /// <para>If none of the three conditions holds, then the Value is false.</para>
  360. /// <para>
  361. /// A value of false does not indicate that the entry, as saved in the zip archive, does not use
  362. /// ZIP64. It merely indicates that ZIP64 is not required. An entry may use ZIP64 even when not
  363. /// required if the <see cref="ZipFile.UseZip64WhenSaving"/> property on the containing ZipFile
  364. /// instance is set to <see cref="Zip64Option.Always"/>, or if
  365. /// the <see cref="ZipFile.UseZip64WhenSaving"/> property on the containing ZipFile
  366. /// instance is set to <see cref="Zip64Option.AsNecessary"/> and the output stream was not seekable.
  367. /// </para>
  368. /// </remarks>
  369. /// <seealso cref="OutputUsedZip64"/>
  370. public Nullable<bool> RequiresZip64
  371. {
  372. get
  373. {
  374. return _entryRequiresZip64;
  375. }
  376. }
  377. /// <summary>
  378. /// Indicates whether the entry actually used ZIP64 extensions, as it was most recently written
  379. /// to the output file or stream.
  380. /// </summary>
  381. /// <remarks>
  382. /// <para>
  383. /// This Nullable property is null (Nothing in VB) until a Save() method on the containing
  384. /// <see cref="ZipFile"/> instance has been called. HasValue is true only after a Save() method
  385. /// has been called.
  386. /// </para>
  387. /// <para>
  388. /// The value of this property for a particular ZipEntry may change over successive calls to
  389. /// Save() methods on the containing ZipFile, even if the file that corresponds to the ZipEntry does
  390. /// not. This may happen if other entries contained in the ZipFile expand, causing the offset
  391. /// for this particular entry to exceed 0xFFFFFFFF.
  392. /// </para>
  393. /// </remarks>
  394. /// <seealso cref="RequiresZip64"/>
  395. public Nullable<bool> OutputUsedZip64
  396. {
  397. get { return _OutputUsesZip64; }
  398. }
  399. /// <summary>
  400. /// The bitfield as defined in the zip spec. You probably never need to look at this.
  401. /// </summary>
  402. ///
  403. /// <remarks>
  404. /// <code>
  405. /// bit 0 - set if encryption is used.
  406. /// b. 1-2 - set to determine whether normal, max, fast deflation.
  407. /// This library always leaves these bits unset when writing (indicating
  408. /// "normal" deflation").
  409. ///
  410. /// bit 3 - indicates crc32, compressed and uncompressed sizes are zero in
  411. /// local header. We always leave this as zero on writing, but can read
  412. /// a zip with it nonzero.
  413. ///
  414. /// bit 4 - reserved for "enhanced deflating". This library doesn't do enhanced deflating.
  415. /// bit 5 - set to indicate the zip is compressed patched data. This library doesn't do that.
  416. /// bit 6 - set if strong encryption is used (must also set bit 1 if bit 6 is set)
  417. /// bit 7 - unused
  418. /// bit 8 - unused
  419. /// bit 9 - unused
  420. /// bit 10 - unused
  421. /// Bit 11 - Language encoding flag (EFS). If this bit is set,
  422. /// the filename and comment fields for this file
  423. /// must be encoded using UTF-8. This library currently does not support UTF-8.
  424. /// Bit 12 - Reserved by PKWARE for enhanced compression.
  425. /// Bit 13 - Used when encrypting the Central Directory to indicate
  426. /// selected data values in the Local Header are masked to
  427. /// hide their actual values. See the section describing
  428. /// the Strong Encryption Specification for details.
  429. /// Bit 14 - Reserved by PKWARE.
  430. /// Bit 15 - Reserved by PKWARE.
  431. /// </code>
  432. /// </remarks>
  433. public Int16 BitField
  434. {
  435. get { return _BitField; }
  436. }
  437. /// <summary>
  438. /// The compression method employed for this ZipEntry.
  439. /// </summary>
  440. ///
  441. /// <remarks>
  442. /// <para>
  443. /// The ZIP specification allows a variety of compression methods. This library
  444. /// supports just two: 0x08 = Deflate. 0x00 = Store (no compression).
  445. /// </para>
  446. ///
  447. /// <para>
  448. /// When reading an entry from an existing zipfile, the value you retrieve here
  449. /// indicates the compression method used on the entry by the original creator of the zip.
  450. /// When writing a zipfile, you can specify either 0x08 (Deflate) or 0x00 (None). If you
  451. /// try setting something else, you will get an exception.
  452. /// </para>
  453. ///
  454. /// <para>
  455. /// You may wish to set CompressionMethod to 0 (None) when zipping previously compressed
  456. /// data like a jpg, png, or mp3 file. This can save time and cpu cycles.
  457. /// Setting CompressionMethod to 0 is equivalent to setting ForceNoCompression to true.
  458. /// </para>
  459. ///
  460. /// <para>
  461. /// When updating a ZipFile, you may not modify the CompressionMethod on an entry that has been encrypted.
  462. /// In other words, if you read an existing ZipFile with one of the ZipFile.Read() methods, and then
  463. /// change the CompressionMethod on an entry that has Encryption not equal to None, you will receive an exception.
  464. /// There is no way to modify the compression on an encrypted entry, without extracting it and re-adding it
  465. /// into the ZipFile.
  466. /// </para>
  467. /// </remarks>
  468. ///
  469. /// <example>
  470. /// In this example, the first entry added to the zip archive uses
  471. /// the default behavior - compression is used where it makes sense.
  472. /// The second entry, the MP3 file, is added to the archive without being compressed.
  473. /// <code>
  474. /// using (ZipFile zip = new ZipFile(ZipFileToCreate))
  475. /// {
  476. /// ZipEntry e1= zip.AddFile(@"c:\temp\Readme.txt");
  477. /// ZipEntry e2= zip.AddFile(@"c:\temp\StopThisTrain.mp3");
  478. /// e2.CompressionMethod = 0;
  479. /// zip.Save();
  480. /// }
  481. /// </code>
  482. ///
  483. /// <code lang="VB">
  484. /// Using zip as new ZipFile(ZipFileToCreate)
  485. /// zip.AddFile("c:\temp\Readme.txt")
  486. /// Dim e2 as ZipEntry = zip.AddFile("c:\temp\StopThisTrain.mp3")
  487. /// e2.CompressionMethod = 0
  488. /// zip.Save
  489. /// End Using
  490. /// </code>
  491. /// </example>
  492. public Int16 CompressionMethod
  493. {
  494. get { return _CompressionMethod; }
  495. set
  496. {
  497. if (value == _CompressionMethod) return; // nothing to do.
  498. if (value != 0x00 && value != 0x08)
  499. throw new InvalidOperationException("Unsupported compression method. Specify 8 or 0.");
  500. // If the source is a zip archive and there was encryption on the
  501. // entry, changing the compression method is not supported.
  502. if (this._Source == EntrySource.Zipfile && _sourceIsEncrypted)
  503. throw new InvalidOperationException("Cannot change compression method on encrypted entries read from archives.");
  504. _CompressionMethod = value;
  505. _ForceNoCompression = (_CompressionMethod == 0x0);
  506. _restreamRequiredOnSave = true;
  507. }
  508. }
  509. /// <summary>
  510. /// The compressed size of the file, in bytes, within the zip archive.
  511. /// </summary>
  512. /// <remarks>
  513. /// The compressed size is computed during compression. This means that it is only
  514. /// valid to read this AFTER reading in an existing zip file, or AFTER saving a
  515. /// zipfile you are creating.
  516. /// </remarks>
  517. public Int64 CompressedSize
  518. {
  519. get { return _CompressedSize; }
  520. }
  521. /// <summary>
  522. /// The size of the file, in bytes, before compression, or after extraction.
  523. /// </summary>
  524. /// <remarks>
  525. /// This property is valid AFTER reading in an existing zip file, or AFTER saving the
  526. /// ZipFile that contains the ZipEntry.
  527. /// </remarks>
  528. public Int64 UncompressedSize
  529. {
  530. get { return _UncompressedSize; }
  531. }
  532. /// <summary>
  533. /// The ratio of compressed size to uncompressed size of the ZipEntry.
  534. /// </summary>
  535. ///
  536. /// <remarks>
  537. /// <para>
  538. /// This is a ratio of the compressed size to the uncompressed size of the entry,
  539. /// expressed as a double in the range of 0 to 100+. A value of 100 indicates no
  540. /// compression at all. It could be higher than 100 when the compression algorithm
  541. /// actually inflates the data.
  542. /// </para>
  543. ///
  544. /// <para>
  545. /// You could format it for presentation to a user via a format string of "{3,5:F0}%"
  546. /// to see it as a percentage.
  547. /// </para>
  548. ///
  549. /// <para>
  550. /// If the size of the original uncompressed file is 0, (indicating a denominator of 0)
  551. /// the return value will be zero.
  552. /// </para>
  553. ///
  554. /// <para>
  555. /// This property is valid AFTER reading in an existing zip file, or AFTER saving the
  556. /// ZipFile that contains the ZipEntry.
  557. /// </para>
  558. ///
  559. /// </remarks>
  560. public Double CompressionRatio
  561. {
  562. get
  563. {
  564. if (UncompressedSize == 0) return 0;
  565. return 100 * (1.0 - (1.0 * CompressedSize) / (1.0 * UncompressedSize));
  566. }
  567. }
  568. /// <summary>
  569. /// The CRC (Cyclic Redundancy Check) on the contents of the ZipEntry.
  570. /// </summary>
  571. ///
  572. /// <remarks>
  573. /// You probably don't need to concern yourself with this. The CRC is generated according
  574. /// to the algorithm described in the Pkzip specification. It is a read-only property;
  575. /// when creating a Zip archive, the CRC for each entry is set only after a call to
  576. /// Save() on the containing ZipFile.
  577. /// </remarks>
  578. public Int32 Crc32
  579. {
  580. get { return _Crc32; }
  581. }
  582. /// <summary>
  583. /// True if the entry is a directory (not a file).
  584. /// This is a readonly property on the entry.
  585. /// </summary>
  586. public bool IsDirectory
  587. {
  588. get { return _IsDirectory; }
  589. }
  590. /// <summary>
  591. /// A derived property that is <c>true</c> if the entry uses encryption.
  592. /// </summary>
  593. /// <remarks>
  594. /// This is a readonly property on the entry.
  595. /// Upon reading an entry, this bool is determined by
  596. /// the data read. When writing an entry, this bool is
  597. /// determined by whether the Encryption property is set to something other than
  598. /// EncryptionAlgorithm.None.
  599. /// </remarks>
  600. public bool UsesEncryption
  601. {
  602. get { return (Encryption != EncryptionAlgorithm.None); }
  603. }
  604. /// <summary>
  605. /// Set this to specify which encryption algorithm to use for the entry.
  606. /// </summary>
  607. ///
  608. /// <remarks>
  609. /// <para>
  610. /// When setting this property, you must also set a Password on the entry. The set of
  611. /// algorithms supported is determined by the authors of this library. The PKZIP
  612. /// specification from PKWare defines a set of encryption algorithms, and the data formats
  613. /// for the zip archive that support them. Other vendors of tools and libraries, such as
  614. /// WinZip or Xceed, also specify and support different encryption algorithms and data
  615. /// formats.
  616. /// </para>
  617. ///
  618. /// <para>
  619. /// There is no common, ubiquitous multi-vendor standard for strong encryption. There is
  620. /// broad support for "traditional" Zip encryption, sometimes called Zip 2.0 encryption,
  621. /// as specified by PKWare, but this encryption is considered weak. This library currently
  622. /// supports AES 128 and 256 in addition to the Zip 2.0 "weak" encryption.
  623. /// </para>
  624. ///
  625. /// <para>
  626. /// The WinZip AES encryption algorithms are not supported on the .NET Compact Framework.
  627. /// </para>
  628. /// </remarks>
  629. public EncryptionAlgorithm Encryption
  630. {
  631. get
  632. {
  633. return _Encryption;
  634. }
  635. set
  636. {
  637. if (value == _Encryption) return;
  638. _Encryption = value;
  639. // If the source is a zip archive and there was encryption
  640. // on the entry, this will not work.
  641. if (this._Source == EntrySource.Zipfile && _sourceIsEncrypted)
  642. throw new InvalidOperationException("You cannot change the encryption method on encrypted entries read from archives.");
  643. _restreamRequiredOnSave = true;
  644. #if AESCRYPTO
  645. if (value == EncryptionAlgorithm.WinZipAes256) this._KeyStrengthInBits = 256;
  646. else if (value == EncryptionAlgorithm.WinZipAes128) this._KeyStrengthInBits = 128;
  647. #endif
  648. }
  649. }
  650. /// <summary>
  651. /// The Password to be used when encrypting a ZipEntry upon ZipFile.Save(), or
  652. /// when decrypting an entry upon Extract().
  653. /// </summary>
  654. ///
  655. /// <remarks>
  656. /// <para>
  657. /// This is a write-only property on the entry.
  658. /// Set this to request that the entry be encrypted when writing the zip
  659. /// archive, or set it to specify the password to be used when extracting an
  660. /// existing entry that is encrypted.
  661. /// </para>
  662. ///
  663. /// <para>
  664. /// The password set here is implicitly
  665. /// used to encrypt the entry during the Save() operation, or to decrypt during
  666. /// the <see cref="Extract()"/> or <see cref="OpenReader()"/> operation.
  667. /// </para>
  668. ///
  669. /// <para>
  670. /// Some comments on Updating archives: Suppose you read a zipfile, and there is an
  671. /// encrypted entry. Setting the password on that entry and then saving the zipfile
  672. /// does not update the password on that entry in the archive. Instead, what happens
  673. /// is the existing entry is copied through to the new zip archive, in its original
  674. /// encrypted form. Upon re-reading that archive, the entry can be decrypted with its
  675. /// original password.
  676. /// </para>
  677. ///
  678. /// <para>
  679. /// If you read a zipfile, you cannot modify the password on any encrypted entry,
  680. /// except by extracting the entry with the first password (if any), removing the original
  681. /// entry via <see cref="ZipFile.RemoveEntry(ZipEntry)"/>, and then adding
  682. /// a new entry with a new password.
  683. /// </para>
  684. ///
  685. /// <para>
  686. /// If you read a zipfile, and there is an un-encrypted entry, you can set the password
  687. /// on the entry and then call Save() on the ZipFile, and get encryption on that entry.
  688. /// </para>
  689. ///
  690. /// </remarks>
  691. public string Password
  692. {
  693. set
  694. {
  695. _Password = value;
  696. if (_Password == null)
  697. {
  698. _Encryption = EncryptionAlgorithm.None;
  699. }
  700. else
  701. {
  702. // We're setting a non-null password.
  703. // For entries obtained from a zip file that are encrypted, we cannot
  704. // simply restream (recompress, re-encrypt) the file data, because we
  705. // need the old password in order to decrypt the data, and then we
  706. // need the new password to encrypt. So, setting the password is
  707. // never going to work on an entry that is stored encrypted in a zipfile.
  708. // But it is not en error to set the password, obviously: callers will
  709. // set the password in order to Extract encrypted archives.
  710. // If the source is a zip archive and there was previously no encryption
  711. // on the entry, then we must re-stream the entry in order to encrypt it.
  712. if (this._Source == EntrySource.Zipfile && !_sourceIsEncrypted)
  713. _restreamRequiredOnSave = true;
  714. if (Encryption == EncryptionAlgorithm.None)
  715. {
  716. _Encryption = EncryptionAlgorithm.PkzipWeak;
  717. }
  718. }
  719. }
  720. }
  721. /// <summary>
  722. /// Specifies that the extraction should overwrite any existing files.
  723. /// </summary>
  724. /// <remarks>
  725. /// This applies only when calling an Extract method. By default this
  726. /// property is false. Generally you will get overwrite behavior by calling
  727. /// one of the overloads of the Extract() method that accepts a boolean flag
  728. /// to indicate explicitly whether you want overwrite.
  729. /// </remarks>
  730. /// <seealso cref="Ionic.Zip.ZipEntry.Extract(bool)"/>
  731. public bool OverwriteOnExtract
  732. {
  733. get { return _OverwriteOnExtract; }
  734. set { _OverwriteOnExtract = value; }
  735. }
  736. /// <summary>
  737. /// A callback that allows the application to specify whether multiple reads of the
  738. /// stream should be performed, in the case that a compression operation actually
  739. /// inflates the size of the file data.
  740. /// </summary>
  741. ///
  742. /// <remarks>
  743. /// <para>
  744. /// In some cases, applying the Deflate compression algorithm in DeflateStream can
  745. /// result an increase in the size of the data. This "inflation" can happen with
  746. /// previously compressed files, such as a zip, jpg, png, mp3, and so on. In a few
  747. /// tests, inflation on zip files can be as large as 60%! Inflation can also happen
  748. /// with very small files. In these cases, by default, the DotNetZip library
  749. /// discards the compressed bytes, and stores the uncompressed file data into the
  750. /// zip archive. This is an optimization where smaller size is preferred over
  751. /// longer run times.
  752. /// </para>
  753. ///
  754. /// <para>
  755. /// The application can specify that compression is not even tried, by setting the
  756. /// ForceNoCompression flag. In this case, the compress-and-check-sizes process as
  757. /// decribed above, is not done.
  758. /// </para>
  759. ///
  760. /// <para>
  761. /// In some cases, neither choice is optimal. The application wants compression,
  762. /// but in some cases also wants to avoid reading the stream more than once. This
  763. /// may happen when the stream is very large, or when the read is very expensive, or
  764. /// when the difference between the compressed and uncompressed sizes is not
  765. /// significant.
  766. /// </para>
  767. ///
  768. /// <para>
  769. /// To satisfy these applications, this delegate allows the DotNetZip library to ask
  770. /// the application to for approval for re-reading the stream. As with other
  771. /// properties (like Password and ForceNoCompression), setting the corresponding
  772. /// delegate on the ZipFile class itself will set it on all ZipEntry items that are
  773. /// subsequently added to the ZipFile instance.
  774. /// </para>
  775. ///
  776. /// </remarks>
  777. /// <seealso cref="Ionic.Zip.ZipFile.WillReadTwiceOnInflation"/>
  778. /// <seealso cref="Ionic.Zip.ReReadApprovalCallback"/>
  779. public ReReadApprovalCallback WillReadTwiceOnInflation
  780. {
  781. get;
  782. set;
  783. }
  784. /// <summary>
  785. /// A callback that allows the application to specify whether compression should
  786. /// be used for a given entry that is about to be added to the zip archive.
  787. /// </summary>
  788. ///
  789. /// <remarks>
  790. /// See <see cref="ZipFile.WantCompression" />
  791. /// </remarks>
  792. public WantCompressionCallback WantCompression
  793. {
  794. get;
  795. set;
  796. }
  797. /// <summary>
  798. /// Set to indicate whether to use UTF-8 encoding on filenames and
  799. /// comments, according to the PKWare specification.
  800. /// </summary>
  801. /// <remarks>
  802. /// If this flag is set, the entry will be marked as encoded with UTF-8,
  803. /// according to the PWare spec, if necessary. Necessary means, if the filename or
  804. /// entry comment (if any) cannot be reflexively encoded with the default (IBM437) code page.
  805. /// </remarks>
  806. /// <remarks>
  807. /// Setting this flag to true is equivalent to setting <see cref="ProvisionalAlternateEncoding"/> to <c>System.Text.Encoding.UTF8</c>
  808. /// </remarks>
  809. public bool UseUnicodeAsNecessary
  810. {
  811. get
  812. {
  813. return _provisionalAlternateEncoding == System.Text.Encoding.GetEncoding("UTF-8");
  814. }
  815. set
  816. {
  817. _provisionalAlternateEncoding = (value) ? System.Text.Encoding.GetEncoding("UTF-8") : Ionic.Zip.ZipFile.DefaultEncoding;
  818. }
  819. }
  820. /// <summary>
  821. /// The text encoding to use for this ZipEntry, when the default
  822. /// encoding is insufficient.
  823. /// </summary>
  824. ///
  825. /// <remarks>
  826. /// <para>
  827. /// According to the zip specification from PKWare, filenames and comments for a
  828. /// ZipEntry are encoded either with IBM437 or with UTF8. But, some archivers do not
  829. /// follow the specification, and instead encode characters using the system default
  830. /// code page, or an arbitrary code page. For example, WinRAR when run on a machine in
  831. /// Shanghai may encode filenames with the Chinese (Big-5) code page. This behavior is
  832. /// contrary to the Zip specification, but it occurs anyway. This property exists to
  833. /// support that non-compliant behavior when reading or writing zip files.
  834. /// </para>
  835. /// <para>
  836. /// When writing zip archives that will be read by one of these other archivers, use this property to
  837. /// specify the code page to use when encoding filenames and comments into the zip
  838. /// file, when the IBM437 code page will not suffice.
  839. /// </para>
  840. /// <para>
  841. /// Be aware that a zip file created after you've explicitly specified the code page will not
  842. /// be compliant to the PKWare specification, and may not be readable by compliant archivers.
  843. /// On the other hand, many archivers are non-compliant and can read zip files created in
  844. /// arbitrary code pages.
  845. /// </para>
  846. /// <para>
  847. /// When using an arbitrary, non-UTF8 code page for encoding, there is no standard way for the
  848. /// creator (DotNetZip) to specify in the zip file which code page has been used. DotNetZip is not
  849. /// able to inspect the zip file and determine the codepage used for the entries within it. Therefore,
  850. /// you, the application author, must determine that. If you use a codepage which results in filenames
  851. /// that are not legal in Windows, you will get exceptions upon extract. Caveat Emptor.
  852. /// </para>
  853. /// </remarks>
  854. public System.Text.Encoding ProvisionalAlternateEncoding
  855. {
  856. get
  857. {
  858. return _provisionalAlternateEncoding;
  859. }
  860. set
  861. {
  862. _provisionalAlternateEncoding = value;
  863. }
  864. }
  865. /// <summary>
  866. /// The text encoding actually used for this ZipEntry.
  867. /// </summary>
  868. public System.Text.Encoding ActualEncoding
  869. {
  870. get
  871. {
  872. return _actualEncoding;
  873. }
  874. }
  875. private static bool ReadHeader(ZipEntry ze, System.Text.Encoding defaultEncoding)
  876. {
  877. int bytesRead = 0;
  878. ze._RelativeOffsetOfLocalHeader = (int)ze.ArchiveStream.Position;
  879. int signature = Ionic.Zip.SharedUtilities.ReadSignature(ze.ArchiveStream);
  880. bytesRead += 4;
  881. // Return false if this is not a local file header signature.
  882. if (ZipEntry.IsNotValidSig(signature))
  883. {
  884. // Getting "not a ZipEntry signature" is not always wrong or an error.
  885. // This will happen after the last entry in a zipfile. In that case, we
  886. // expect to read :
  887. // a ZipDirEntry signature (if a non-empty zip file) or
  888. // a ZipConstants.EndOfCentralDirectorySignature.
  889. //
  890. // Anything else is a surprise.
  891. ze.ArchiveStream.Seek(-4, System.IO.SeekOrigin.Current); // unread the signature
  892. if (ZipEntry.IsNotValidZipDirEntrySig(signature) && (signature != ZipConstants.EndOfCentralDirectorySignature))
  893. {
  894. throw new BadReadException(String.Format(" ZipEntry::ReadHeader(): Bad signature (0x{0:X8}) at position 0x{1:X8}", signature, ze.ArchiveStream.Position));
  895. }
  896. return false;
  897. }
  898. byte[] block = new byte[26];
  899. int n = ze.ArchiveStream.Read(block, 0, block.Length);
  900. if (n != block.Length) return false;
  901. bytesRead += n;
  902. int i = 0;
  903. ze._VersionNeeded = (short)(block[i++] + block[i++] * 256);
  904. ze._BitField = (short)(block[i++] + block[i++] * 256);
  905. ze._CompressionMethod = (short)(block[i++] + block[i++] * 256);
  906. ze._TimeBlob = block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256;
  907. // transform the time data into something usable (a DateTime)
  908. ze._LastModified = Ionic.Zip.SharedUtilities.PackedToDateTime(ze._TimeBlob);
  909. // NB: if ((ze._BitField & 0x0008) != 0x0008), then the Compressed, uncompressed and
  910. // CRC values are not true values; the true values will follow the entry data.
  911. // Nevertheless, regardless of the statis of bit 3 in the bitfield, the slots for
  912. // the three amigos may contain marker values for ZIP64. So we must read them.
  913. {
  914. ze._Crc32 = (Int32)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
  915. ze._CompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
  916. ze._UncompressedSize = (uint)(block[i++] + block[i++] * 256 + block[i++] * 256 * 256 + block[i++] * 256 * 256 * 256);
  917. // validate ZIP64? No. We don't need to be pedantic about it.
  918. //if (((uint)ze._CompressedSize == 0xFFFFFFFF &&
  919. // (uint)ze._UncompressedSize != 0xFFFFFFFF) ||
  920. // ((uint)ze._CompressedSize != 0xFFFFFFFF &&
  921. // (uint)ze._UncompressedSize == 0xFFFFFFFF))
  922. // throw new BadReadException(String.Format(" ZipEntry::Read(): Inconsistent uncompressed size (0x{0:X8}) for zip64, at position 0x{1:X16}", ze._UncompressedSize, ze.ArchiveStream.Position));
  923. if ((uint)ze._CompressedSize == 0xFFFFFFFF ||
  924. (uint)ze._UncompressedSize == 0xFFFFFFFF)
  925. ze._InputUsesZip64 = true;
  926. //throw new BadReadException(" DotNetZip does not currently support reading the ZIP64 format.");
  927. }
  928. // else
  929. // {
  930. // // The CRC, compressed size, and uncompressed size stored here are not valid.
  931. // // The actual values are stored later in the stream.
  932. // // Here, we advance the pointer to skip the dummy data.
  933. // i += 12;
  934. // }
  935. Int16 filenameLength = (short)(block[i++] + block[i++] * 256);
  936. Int16 extraFieldLength = (short)(block[i++] + block[i++] * 256);
  937. block = new byte[filenameLength];
  938. n = ze.ArchiveStream.Read(block, 0, block.Length);
  939. bytesRead += n;
  940. // if the UTF8 bit is set for this entry, we override the encoding the application requested.
  941. ze._actualEncoding = ((ze._BitField & 0x0800) == 0x0800)
  942. ? System.Text.Encoding.UTF8
  943. : defaultEncoding;
  944. // need to use this form of GetString() for .NET CF
  945. ze._FileNameInArchive = ze._actualEncoding.GetString(block, 0, block.Length);
  946. // when creating an entry by reading, the LocalFileName is the same as the FileNameInArchive
  947. ze._LocalFileName = ze._FileNameInArchive;
  948. // workitem 6898
  949. if (ze._LocalFileName.EndsWith("/")) ze.MarkAsDirectory();
  950. bytesRead += ze.ProcessExtraField(extraFieldLength);
  951. ze._LengthOfTrailer = 0;
  952. // workitem 6607 - don't read for directories
  953. // actually get the compressed size and CRC if necessary
  954. if (!ze._LocalFileName.EndsWith("/") && (ze._BitField & 0x0008) == 0x0008)
  955. {
  956. // This descriptor exists only if bit 3 of the general
  957. // purpose bit flag is set (see below). It is byte aligned
  958. // and immediately follows the last byte of compressed data.
  959. // This descriptor is used only when it was not possible to
  960. // seek in the output .ZIP file, e.g., when the output .ZIP file
  961. // was standard output or a non-seekable device. For ZIP64(tm) format
  962. // archives, the compressed and uncompressed sizes are 8 bytes each.
  963. long posn = ze.ArchiveStream.Position;
  964. // Here, we're going to loop until we find a ZipEntryDataDescriptorSignature and
  965. // a consistent data record after that. To be consistent, the data record must
  966. // indicate the length of the entry data.
  967. bool wantMore = true;
  968. long SizeOfDataRead = 0;
  969. int tries = 0;
  970. while (wantMore)
  971. {
  972. tries++;
  973. // We call the FindSignature shared routine to find the specified signature
  974. // in the already-opened zip archive, starting from the current cursor
  975. // position in that filestream. There are two possibilities: either we
  976. // find the signature or we don't. If we cannot find it, then the routine
  977. // returns -1, and the ReadHeader() method returns false, indicating we
  978. // cannot read a legal entry header. If we have found it, then the
  979. // FindSignature() method returns the number of bytes in the stream we had
  980. // to seek forward, to find the sig. We need this to determine if the zip
  981. // entry is valid, later.
  982. ze._zipfile.OnReadBytes(ze);
  983. long d = Ionic.Zip.SharedUtilities.FindSignature(ze.ArchiveStream, ZipConstants.ZipEntryDataDescriptorSignature);
  984. if (d == -1) return false;
  985. // total size of data read (through all loops of this).
  986. SizeOfDataRead += d;
  987. if (ze._InputUsesZip64 == true)
  988. {
  989. // read 1x 4-byte (CRC) and 2x 8-bytes (Compressed Size, Uncompressed Size)
  990. block = new byte[20];
  991. n = ze.ArchiveStream.Read(

Large files files are truncated, but you can click here to view the full file