ZipInputStream.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. // ZipInputStream.cs
  2. //
  3. // ------------------------------------------------------------------
  4. //
  5. // Copyright (c) 2009-2010 Dino Chiesa.
  6. // All rights reserved.
  7. //
  8. // This code module is part of DotNetZip, a zipfile class library.
  9. //
  10. // ------------------------------------------------------------------
  11. //
  12. // This code is licensed under the Microsoft Public License.
  13. // See the file License.txt for the license details.
  14. // More info on: http://dotnetzip.codeplex.com
  15. //
  16. // ------------------------------------------------------------------
  17. //
  18. // last saved (in emacs):
  19. // Time-stamp: <2011-July-31 14:48:30>
  20. //
  21. // ------------------------------------------------------------------
  22. //
  23. // This module defines the ZipInputStream class, which is a stream metaphor for
  24. // reading zip files. This class does not depend on Ionic.Zip.ZipFile, but rather
  25. // stands alongside it as an alternative "container" for ZipEntry, when reading zips.
  26. //
  27. // It adds one interesting method to the normal "stream" interface: GetNextEntry.
  28. //
  29. // ------------------------------------------------------------------
  30. //
  31. using System;
  32. using System.Threading;
  33. using System.Collections.Generic;
  34. using System.IO;
  35. using Ionic.Zip;
  36. namespace Ionic.Zip
  37. {
  38. /// <summary>
  39. /// Provides a stream metaphor for reading zip files.
  40. /// </summary>
  41. ///
  42. /// <remarks>
  43. /// <para>
  44. /// This class provides an alternative programming model for reading zip files to
  45. /// the one enabled by the <see cref="ZipFile"/> class. Use this when reading zip
  46. /// files, as an alternative to the <see cref="ZipFile"/> class, when you would
  47. /// like to use a Stream class to read the file.
  48. /// </para>
  49. ///
  50. /// <para>
  51. /// Some application designs require a readable stream for input. This stream can
  52. /// be used to read a zip file, and extract entries.
  53. /// </para>
  54. ///
  55. /// <para>
  56. /// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used
  57. /// to read and extract zip files. Both of them support many of the common zip
  58. /// features, including Unicode, different compression levels, and ZIP64. The
  59. /// programming models differ. For example, when extracting entries via calls to
  60. /// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the
  61. /// <c>ZipInputStream</c> class, the caller is responsible for creating the file,
  62. /// writing the bytes into the file, setting the attributes on the file, and
  63. /// setting the created, last modified, and last accessed timestamps on the
  64. /// file. All of these things are done automatically by a call to <see
  65. /// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the
  66. /// <c>ZipInputStream</c> is generally recommended for when your application wants
  67. /// to extract the data, without storing that data into a file.
  68. /// </para>
  69. ///
  70. /// <para>
  71. /// Aside from the obvious differences in programming model, there are some
  72. /// differences in capability between the <c>ZipFile</c> class and the
  73. /// <c>ZipInputStream</c> class.
  74. /// </para>
  75. ///
  76. /// <list type="bullet">
  77. /// <item>
  78. /// <c>ZipFile</c> can be used to create or update zip files, or read and
  79. /// extract zip files. <c>ZipInputStream</c> can be used only to read and
  80. /// extract zip files. If you want to use a stream to create zip files, check
  81. /// out the <see cref="ZipOutputStream"/>.
  82. /// </item>
  83. ///
  84. /// <item>
  85. /// <c>ZipInputStream</c> cannot read segmented or spanned
  86. /// zip files.
  87. /// </item>
  88. ///
  89. /// <item>
  90. /// <c>ZipInputStream</c> will not read Zip file comments.
  91. /// </item>
  92. ///
  93. /// <item>
  94. /// When reading larger files, <c>ZipInputStream</c> will always underperform
  95. /// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the
  96. /// zip file, while the <c>ZipFile</c> class reads the central directory of the
  97. /// zip file.
  98. /// </item>
  99. ///
  100. /// </list>
  101. ///
  102. /// </remarks>
  103. public class ZipInputStream : Stream
  104. {
  105. /// <summary>
  106. /// Create a <c>ZipInputStream</c>, wrapping it around an existing stream.
  107. /// </summary>
  108. ///
  109. /// <remarks>
  110. ///
  111. /// <para>
  112. /// While the <see cref="ZipFile"/> class is generally easier
  113. /// to use, this class provides an alternative to those
  114. /// applications that want to read from a zipfile directly,
  115. /// using a <see cref="System.IO.Stream"/>.
  116. /// </para>
  117. ///
  118. /// <para>
  119. /// Both the <c>ZipInputStream</c> class and the <c>ZipFile</c> class can be used
  120. /// to read and extract zip files. Both of them support many of the common zip
  121. /// features, including Unicode, different compression levels, and ZIP64. The
  122. /// programming models differ. For example, when extracting entries via calls to
  123. /// the <c>GetNextEntry()</c> and <c>Read()</c> methods on the
  124. /// <c>ZipInputStream</c> class, the caller is responsible for creating the file,
  125. /// writing the bytes into the file, setting the attributes on the file, and
  126. /// setting the created, last modified, and last accessed timestamps on the
  127. /// file. All of these things are done automatically by a call to <see
  128. /// cref="ZipEntry.Extract()">ZipEntry.Extract()</see>. For this reason, the
  129. /// <c>ZipInputStream</c> is generally recommended for when your application wants
  130. /// to extract the data, without storing that data into a file.
  131. /// </para>
  132. ///
  133. /// <para>
  134. /// Aside from the obvious differences in programming model, there are some
  135. /// differences in capability between the <c>ZipFile</c> class and the
  136. /// <c>ZipInputStream</c> class.
  137. /// </para>
  138. ///
  139. /// <list type="bullet">
  140. /// <item>
  141. /// <c>ZipFile</c> can be used to create or update zip files, or read and extract
  142. /// zip files. <c>ZipInputStream</c> can be used only to read and extract zip
  143. /// files. If you want to use a stream to create zip files, check out the <see
  144. /// cref="ZipOutputStream"/>.
  145. /// </item>
  146. ///
  147. /// <item>
  148. /// <c>ZipInputStream</c> cannot read segmented or spanned
  149. /// zip files.
  150. /// </item>
  151. ///
  152. /// <item>
  153. /// <c>ZipInputStream</c> will not read Zip file comments.
  154. /// </item>
  155. ///
  156. /// <item>
  157. /// When reading larger files, <c>ZipInputStream</c> will always underperform
  158. /// <c>ZipFile</c>. This is because the <c>ZipInputStream</c> does a full scan on the
  159. /// zip file, while the <c>ZipFile</c> class reads the central directory of the
  160. /// zip file.
  161. /// </item>
  162. ///
  163. /// </list>
  164. ///
  165. /// </remarks>
  166. ///
  167. /// <param name="stream">
  168. /// The stream to read. It must be readable. This stream will be closed at
  169. /// the time the <c>ZipInputStream</c> is closed.
  170. /// </param>
  171. ///
  172. /// <example>
  173. ///
  174. /// This example shows how to read a zip file, and extract entries, using the
  175. /// <c>ZipInputStream</c> class.
  176. ///
  177. /// <code lang="C#">
  178. /// private void Unzip()
  179. /// {
  180. /// byte[] buffer= new byte[2048];
  181. /// int n;
  182. /// using (var raw = File.Open(inputFileName, FileMode.Open, FileAccess.Read))
  183. /// {
  184. /// using (var input= new ZipInputStream(raw))
  185. /// {
  186. /// ZipEntry e;
  187. /// while (( e = input.GetNextEntry()) != null)
  188. /// {
  189. /// if (e.IsDirectory) continue;
  190. /// string outputPath = Path.Combine(extractDir, e.FileName);
  191. /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
  192. /// {
  193. /// while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
  194. /// {
  195. /// output.Write(buffer,0,n);
  196. /// }
  197. /// }
  198. /// }
  199. /// }
  200. /// }
  201. /// }
  202. /// </code>
  203. ///
  204. /// <code lang="VB">
  205. /// Private Sub UnZip()
  206. /// Dim inputFileName As String = "MyArchive.zip"
  207. /// Dim extractDir As String = "extract"
  208. /// Dim buffer As Byte() = New Byte(2048) {}
  209. /// Using raw As FileStream = File.Open(inputFileName, FileMode.Open, FileAccess.Read)
  210. /// Using input As ZipInputStream = New ZipInputStream(raw)
  211. /// Dim e As ZipEntry
  212. /// Do While (Not e = input.GetNextEntry Is Nothing)
  213. /// If Not e.IsDirectory Then
  214. /// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
  215. /// FileMode.Create, FileAccess.ReadWrite)
  216. /// Dim n As Integer
  217. /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
  218. /// output.Write(buffer, 0, n)
  219. /// Loop
  220. /// End Using
  221. /// End If
  222. /// Loop
  223. /// End Using
  224. /// End Using
  225. /// End Sub
  226. /// </code>
  227. /// </example>
  228. public ZipInputStream(Stream stream) : this (stream, false) { }
  229. /// <summary>
  230. /// Create a <c>ZipInputStream</c>, given the name of an existing zip file.
  231. /// </summary>
  232. ///
  233. /// <remarks>
  234. ///
  235. /// <para>
  236. /// This constructor opens a <c>FileStream</c> for the given zipfile, and
  237. /// wraps a <c>ZipInputStream</c> around that. See the documentation for the
  238. /// <see cref="ZipInputStream(Stream)"/> constructor for full details.
  239. /// </para>
  240. ///
  241. /// <para>
  242. /// While the <see cref="ZipFile"/> class is generally easier
  243. /// to use, this class provides an alternative to those
  244. /// applications that want to read from a zipfile directly,
  245. /// using a <see cref="System.IO.Stream"/>.
  246. /// </para>
  247. ///
  248. /// </remarks>
  249. ///
  250. /// <param name="fileName">
  251. /// The name of the filesystem file to read.
  252. /// </param>
  253. ///
  254. /// <example>
  255. ///
  256. /// This example shows how to read a zip file, and extract entries, using the
  257. /// <c>ZipInputStream</c> class.
  258. ///
  259. /// <code lang="C#">
  260. /// private void Unzip()
  261. /// {
  262. /// byte[] buffer= new byte[2048];
  263. /// int n;
  264. /// using (var input= new ZipInputStream(inputFileName))
  265. /// {
  266. /// ZipEntry e;
  267. /// while (( e = input.GetNextEntry()) != null)
  268. /// {
  269. /// if (e.IsDirectory) continue;
  270. /// string outputPath = Path.Combine(extractDir, e.FileName);
  271. /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
  272. /// {
  273. /// while ((n= input.Read(buffer, 0, buffer.Length)) > 0)
  274. /// {
  275. /// output.Write(buffer,0,n);
  276. /// }
  277. /// }
  278. /// }
  279. /// }
  280. /// }
  281. /// </code>
  282. ///
  283. /// <code lang="VB">
  284. /// Private Sub UnZip()
  285. /// Dim inputFileName As String = "MyArchive.zip"
  286. /// Dim extractDir As String = "extract"
  287. /// Dim buffer As Byte() = New Byte(2048) {}
  288. /// Using input As ZipInputStream = New ZipInputStream(inputFileName)
  289. /// Dim e As ZipEntry
  290. /// Do While (Not e = input.GetNextEntry Is Nothing)
  291. /// If Not e.IsDirectory Then
  292. /// Using output As FileStream = File.Open(Path.Combine(extractDir, e.FileName), _
  293. /// FileMode.Create, FileAccess.ReadWrite)
  294. /// Dim n As Integer
  295. /// Do While (n = input.Read(buffer, 0, buffer.Length) > 0)
  296. /// output.Write(buffer, 0, n)
  297. /// Loop
  298. /// End Using
  299. /// End If
  300. /// Loop
  301. /// End Using
  302. /// End Sub
  303. /// </code>
  304. /// </example>
  305. public ZipInputStream(String fileName)
  306. {
  307. Stream stream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read );
  308. _Init(stream, false, fileName);
  309. }
  310. /// <summary>
  311. /// Create a <c>ZipInputStream</c>, explicitly specifying whether to
  312. /// keep the underlying stream open.
  313. /// </summary>
  314. ///
  315. /// <remarks>
  316. /// See the documentation for the <see
  317. /// cref="ZipInputStream(Stream)">ZipInputStream(Stream)</see>
  318. /// constructor for a discussion of the class, and an example of how to use the class.
  319. /// </remarks>
  320. ///
  321. /// <param name="stream">
  322. /// The stream to read from. It must be readable.
  323. /// </param>
  324. ///
  325. /// <param name="leaveOpen">
  326. /// true if the application would like the stream
  327. /// to remain open after the <c>ZipInputStream</c> has been closed.
  328. /// </param>
  329. public ZipInputStream(Stream stream, bool leaveOpen)
  330. {
  331. _Init(stream, leaveOpen, null);
  332. }
  333. private void _Init(Stream stream, bool leaveOpen, string name)
  334. {
  335. _inputStream = stream;
  336. if (!_inputStream.CanRead)
  337. throw new ZipException("The stream must be readable.");
  338. _container= new ZipContainer(this);
  339. _provisionalAlternateEncoding = System.Text.Encoding.GetEncoding("IBM437");
  340. _leaveUnderlyingStreamOpen = leaveOpen;
  341. _findRequired= true;
  342. _name = name ?? "(stream)";
  343. }
  344. /// <summary>Provides a string representation of the instance.</summary>
  345. /// <remarks>
  346. /// <para>
  347. /// This can be useful for debugging purposes.
  348. /// </para>
  349. /// </remarks>
  350. /// <returns>a string representation of the instance.</returns>
  351. public override String ToString()
  352. {
  353. return String.Format ("ZipInputStream::{0}(leaveOpen({1})))", _name, _leaveUnderlyingStreamOpen);
  354. }
  355. /// <summary>
  356. /// The text encoding to use when reading entries into the zip archive, for
  357. /// those entries whose filenames or comments cannot be encoded with the
  358. /// default (IBM437) encoding.
  359. /// </summary>
  360. ///
  361. /// <remarks>
  362. /// <para>
  363. /// In <see href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">its
  364. /// zip specification</see>, PKWare describes two options for encoding
  365. /// filenames and comments: using IBM437 or UTF-8. But, some archiving tools
  366. /// or libraries do not follow the specification, and instead encode
  367. /// characters using the system default code page. For example, WinRAR when
  368. /// run on a machine in Shanghai may encode filenames with the Big-5 Chinese
  369. /// (950) code page. This behavior is contrary to the Zip specification, but
  370. /// it occurs anyway.
  371. /// </para>
  372. ///
  373. /// <para>
  374. /// When using DotNetZip to read zip archives that use something other than
  375. /// UTF-8 or IBM437, set this property to specify the code page to use when
  376. /// reading encoded filenames and comments for each <c>ZipEntry</c> in the zip
  377. /// file.
  378. /// </para>
  379. ///
  380. /// <para>
  381. /// This property is "provisional". When the entry in the zip archive is not
  382. /// explicitly marked as using UTF-8, then IBM437 is used to decode filenames
  383. /// and comments. If a loss of data would result from using IBM436 -
  384. /// specifically when encoding and decoding is not reflexive - the codepage
  385. /// specified here is used. It is possible, therefore, to have a given entry
  386. /// with a <c>Comment</c> encoded in IBM437 and a <c>FileName</c> encoded with
  387. /// the specified "provisional" codepage.
  388. /// </para>
  389. ///
  390. /// <para>
  391. /// When a zip file uses an arbitrary, non-UTF8 code page for encoding, there
  392. /// is no standard way for the reader application - whether DotNetZip, WinZip,
  393. /// WinRar, or something else - to know which codepage has been used for the
  394. /// entries. Readers of zip files are not able to inspect the zip file and
  395. /// determine the codepage that was used for the entries contained within it.
  396. /// It is left to the application or user to determine the necessary codepage
  397. /// when reading zip files encoded this way. If you use an incorrect codepage
  398. /// when reading a zipfile, you will get entries with filenames that are
  399. /// incorrect, and the incorrect filenames may even contain characters that
  400. /// are not legal for use within filenames in Windows. Extracting entries with
  401. /// illegal characters in the filenames will lead to exceptions. It's too bad,
  402. /// but this is just the way things are with code pages in zip files. Caveat
  403. /// Emptor.
  404. /// </para>
  405. ///
  406. /// </remarks>
  407. public System.Text.Encoding ProvisionalAlternateEncoding
  408. {
  409. get
  410. {
  411. return _provisionalAlternateEncoding;
  412. }
  413. set
  414. {
  415. _provisionalAlternateEncoding = value;
  416. }
  417. }
  418. /// <summary>
  419. /// Size of the work buffer to use for the ZLIB codec during decompression.
  420. /// </summary>
  421. ///
  422. /// <remarks>
  423. /// Setting this affects the performance and memory efficiency of compression
  424. /// and decompression. For larger files, setting this to a larger size may
  425. /// improve performance, but the exact numbers vary depending on available
  426. /// memory, and a bunch of other variables. I don't have good firm
  427. /// recommendations on how to set it. You'll have to test it yourself. Or
  428. /// just leave it alone and accept the default.
  429. /// </remarks>
  430. public int CodecBufferSize
  431. {
  432. get;
  433. set;
  434. }
  435. /// <summary>
  436. /// Sets the password to be used on the <c>ZipInputStream</c> instance.
  437. /// </summary>
  438. ///
  439. /// <remarks>
  440. ///
  441. /// <para>
  442. /// When reading a zip archive, this password is used to read and decrypt the
  443. /// entries that are encrypted within the zip file. When entries within a zip
  444. /// file use different passwords, set the appropriate password for the entry
  445. /// before the first call to <c>Read()</c> for each entry.
  446. /// </para>
  447. ///
  448. /// <para>
  449. /// When reading an entry that is not encrypted, the value of this property is
  450. /// ignored.
  451. /// </para>
  452. ///
  453. /// </remarks>
  454. ///
  455. /// <example>
  456. ///
  457. /// This example uses the ZipInputStream to read and extract entries from a
  458. /// zip file, using a potentially different password for each entry.
  459. ///
  460. /// <code lang="C#">
  461. /// byte[] buffer= new byte[2048];
  462. /// int n;
  463. /// using (var raw = File.Open(_inputFileName, FileMode.Open, FileAccess.Read ))
  464. /// {
  465. /// using (var input= new ZipInputStream(raw))
  466. /// {
  467. /// ZipEntry e;
  468. /// while (( e = input.GetNextEntry()) != null)
  469. /// {
  470. /// input.Password = PasswordForEntry(e.FileName);
  471. /// if (e.IsDirectory) continue;
  472. /// string outputPath = Path.Combine(_extractDir, e.FileName);
  473. /// using (var output = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite))
  474. /// {
  475. /// while ((n= input.Read(buffer,0,buffer.Length)) > 0)
  476. /// {
  477. /// output.Write(buffer,0,n);
  478. /// }
  479. /// }
  480. /// }
  481. /// }
  482. /// }
  483. ///
  484. /// </code>
  485. /// </example>
  486. public String Password
  487. {
  488. set
  489. {
  490. if (_closed)
  491. {
  492. _exceptionPending = true;
  493. throw new System.InvalidOperationException("The stream has been closed.");
  494. }
  495. _Password = value;
  496. }
  497. }
  498. private void SetupStream()
  499. {
  500. // Seek to the correct posn in the file, and open a
  501. // stream that can be read.
  502. _crcStream= _currentEntry.InternalOpenReader(_Password);
  503. _LeftToRead = _crcStream.Length;
  504. _needSetup = false;
  505. }
  506. internal Stream ReadStream
  507. {
  508. get
  509. {
  510. return _inputStream;
  511. }
  512. }
  513. /// <summary>
  514. /// Read the data from the stream into the buffer.
  515. /// </summary>
  516. ///
  517. /// <remarks>
  518. /// <para>
  519. /// The data for the zipentry will be decrypted and uncompressed, as
  520. /// necessary, before being copied into the buffer.
  521. /// </para>
  522. ///
  523. /// <para>
  524. /// You must set the <see cref="Password"/> property before calling
  525. /// <c>Read()</c> the first time for an encrypted entry. To determine if an
  526. /// entry is encrypted and requires a password, check the <see
  527. /// cref="ZipEntry.Encryption">ZipEntry.Encryption</see> property.
  528. /// </para>
  529. /// </remarks>
  530. ///
  531. /// <param name="buffer">The buffer to hold the data read from the stream.</param>
  532. /// <param name="offset">the offset within the buffer to copy the first byte read.</param>
  533. /// <param name="count">the number of bytes to read.</param>
  534. /// <returns>the number of bytes read, after decryption and decompression.</returns>
  535. public override int Read(byte[] buffer, int offset, int count)
  536. {
  537. if (_closed)
  538. {
  539. _exceptionPending = true;
  540. throw new System.InvalidOperationException("The stream has been closed.");
  541. }
  542. if (_needSetup)
  543. SetupStream();
  544. if (_LeftToRead == 0) return 0;
  545. int len = (_LeftToRead > count) ? count : (int)_LeftToRead;
  546. int n = _crcStream.Read(buffer, offset, len);
  547. _LeftToRead -= n;
  548. if (_LeftToRead == 0)
  549. {
  550. int CrcResult = _crcStream.Crc;
  551. _currentEntry.VerifyCrcAfterExtract(CrcResult, _currentEntry.Encryption, _currentEntry._Crc32, _currentEntry.ArchiveStream, _currentEntry.UncompressedSize);
  552. _inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
  553. // workitem 10178
  554. Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
  555. }
  556. return n;
  557. }
  558. /// <summary>
  559. /// Read the next entry from the zip file.
  560. /// </summary>
  561. ///
  562. /// <remarks>
  563. /// <para>
  564. /// Call this method just before calling <see cref="Read(byte[], int, int)"/>,
  565. /// to position the pointer in the zip file to the next entry that can be
  566. /// read. Subsequent calls to <c>Read()</c>, will decrypt and decompress the
  567. /// data in the zip file, until <c>Read()</c> returns 0.
  568. /// </para>
  569. ///
  570. /// <para>
  571. /// Each time you call <c>GetNextEntry()</c>, the pointer in the wrapped
  572. /// stream is moved to the next entry in the zip file. If you call <see
  573. /// cref="Seek(long, SeekOrigin)"/>, and thus re-position the pointer within
  574. /// the file, you will need to call <c>GetNextEntry()</c> again, to insure
  575. /// that the file pointer is positioned at the beginning of a zip entry.
  576. /// </para>
  577. ///
  578. /// <para>
  579. /// This method returns the <c>ZipEntry</c>. Using a stream approach, you will
  580. /// read the raw bytes for an entry in a zip file via calls to <c>Read()</c>.
  581. /// Alternatively, you can extract an entry into a file, or a stream, by
  582. /// calling <see cref="ZipEntry.Extract()"/>, or one of its siblings.
  583. /// </para>
  584. ///
  585. /// </remarks>
  586. ///
  587. /// <returns>
  588. /// The <c>ZipEntry</c> read. Returns null (or Nothing in VB) if there are no more
  589. /// entries in the zip file.
  590. /// </returns>
  591. ///
  592. public ZipEntry GetNextEntry()
  593. {
  594. if (_findRequired)
  595. {
  596. // find the next signature
  597. long d = SharedUtilities.FindSignature(_inputStream, ZipConstants.ZipEntrySignature);
  598. if (d == -1) return null;
  599. // back up 4 bytes: ReadEntry assumes the file pointer is positioned before the entry signature
  600. _inputStream.Seek(-4, SeekOrigin.Current);
  601. // workitem 10178
  602. Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
  603. }
  604. // workitem 10923
  605. else if (_firstEntry)
  606. {
  607. // we've already read one entry.
  608. // Seek to the end of it.
  609. _inputStream.Seek(_endOfEntry, SeekOrigin.Begin);
  610. Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
  611. }
  612. _currentEntry = ZipEntry.ReadEntry(_container, !_firstEntry);
  613. // ReadEntry leaves the file position after all the entry
  614. // data and the optional bit-3 data descriptpr. This is
  615. // where the next entry would normally start.
  616. _endOfEntry = _inputStream.Position;
  617. _firstEntry = true;
  618. _needSetup = true;
  619. _findRequired= false;
  620. return _currentEntry;
  621. }
  622. /// <summary>
  623. /// Dispose the stream.
  624. /// </summary>
  625. ///
  626. /// <remarks>
  627. /// <para>
  628. /// This method disposes the ZipInputStream. It may also close the
  629. /// underlying stream, depending on which constructor was used.
  630. /// </para>
  631. ///
  632. /// <para>
  633. /// Typically the application will call <c>Dispose()</c> implicitly, via
  634. /// a <c>using</c> statement in C#, or a <c>Using</c> statement in VB.
  635. /// </para>
  636. ///
  637. /// <para>
  638. /// Application code won't call this code directly. This method may
  639. /// be invoked in two distinct scenarios. If disposing == true, the
  640. /// method has been called directly or indirectly by a user's code,
  641. /// for example via the public Dispose() method. In this case, both
  642. /// managed and unmanaged resources can be referenced and disposed.
  643. /// If disposing == false, the method has been called by the runtime
  644. /// from inside the object finalizer and this method should not
  645. /// reference other objects; in that case only unmanaged resources
  646. /// must be referenced or disposed.
  647. /// </para>
  648. /// </remarks>
  649. ///
  650. /// <param name="disposing">
  651. /// true if the Dispose method was invoked by user code.
  652. /// </param>
  653. protected override void Dispose(bool disposing)
  654. {
  655. if (_closed) return;
  656. if (disposing) // not called from finalizer
  657. {
  658. // When ZipInputStream is used within a using clause, and an
  659. // exception is thrown, Close() is invoked. But we don't want to
  660. // try to write anything in that case. Eventually the exception
  661. // will be propagated to the application.
  662. if (_exceptionPending) return;
  663. if (!_leaveUnderlyingStreamOpen)
  664. {
  665. #if NETCF
  666. _inputStream.Close();
  667. #else
  668. _inputStream.Dispose();
  669. #endif
  670. }
  671. }
  672. _closed= true;
  673. }
  674. /// <summary>
  675. /// Always returns true.
  676. /// </summary>
  677. public override bool CanRead { get { return true; }}
  678. /// <summary>
  679. /// Returns the value of <c>CanSeek</c> for the underlying (wrapped) stream.
  680. /// </summary>
  681. public override bool CanSeek { get { return _inputStream.CanSeek; } }
  682. /// <summary>
  683. /// Always returns false.
  684. /// </summary>
  685. public override bool CanWrite { get { return false; } }
  686. /// <summary>
  687. /// Returns the length of the underlying stream.
  688. /// </summary>
  689. public override long Length { get { return _inputStream.Length; }}
  690. /// <summary>
  691. /// Gets or sets the position of the underlying stream.
  692. /// </summary>
  693. /// <remarks>
  694. /// Setting the position is equivalent to calling <c>Seek(value, SeekOrigin.Begin)</c>.
  695. /// </remarks>
  696. public override long Position
  697. {
  698. get { return _inputStream.Position;}
  699. set { Seek(value, SeekOrigin.Begin); }
  700. }
  701. /// <summary>
  702. /// This is a no-op.
  703. /// </summary>
  704. public override void Flush()
  705. {
  706. throw new NotSupportedException("Flush");
  707. }
  708. /// <summary>
  709. /// This method always throws a NotSupportedException.
  710. /// </summary>
  711. /// <param name="buffer">ignored</param>
  712. /// <param name="offset">ignored</param>
  713. /// <param name="count">ignored</param>
  714. public override void Write(byte[] buffer, int offset, int count)
  715. {
  716. throw new NotSupportedException("Write");
  717. }
  718. /// <summary>
  719. /// This method seeks in the underlying stream.
  720. /// </summary>
  721. ///
  722. /// <remarks>
  723. /// <para>
  724. /// Call this method if you want to seek around within the zip file for random access.
  725. /// </para>
  726. ///
  727. /// <para>
  728. /// Applications can intermix calls to <c>Seek()</c> with calls to <see
  729. /// cref="GetNextEntry()"/>. After a call to <c>Seek()</c>,
  730. /// <c>GetNextEntry()</c> will get the next <c>ZipEntry</c> that falls after
  731. /// the current position in the input stream. You're on your own for finding
  732. /// out just where to seek in the stream, to get to the various entries.
  733. /// </para>
  734. ///
  735. /// </remarks>
  736. ///
  737. /// <param name="offset">the offset point to seek to</param>
  738. /// <param name="origin">the reference point from which to seek</param>
  739. /// <returns>The new position</returns>
  740. public override long Seek(long offset, SeekOrigin origin)
  741. {
  742. _findRequired= true;
  743. var x = _inputStream.Seek(offset, origin);
  744. // workitem 10178
  745. Ionic.Zip.SharedUtilities.Workaround_Ladybug318918(_inputStream);
  746. return x;
  747. }
  748. /// <summary>
  749. /// This method always throws a NotSupportedException.
  750. /// </summary>
  751. /// <param name="value">ignored</param>
  752. public override void SetLength(long value)
  753. {
  754. throw new NotSupportedException();
  755. }
  756. private Stream _inputStream;
  757. private System.Text.Encoding _provisionalAlternateEncoding;
  758. private ZipEntry _currentEntry;
  759. private bool _firstEntry;
  760. private bool _needSetup;
  761. private ZipContainer _container;
  762. private Ionic.Crc.CrcCalculatorStream _crcStream;
  763. private Int64 _LeftToRead;
  764. internal String _Password;
  765. private Int64 _endOfEntry;
  766. private string _name;
  767. private bool _leaveUnderlyingStreamOpen;
  768. private bool _closed;
  769. private bool _findRequired;
  770. private bool _exceptionPending;
  771. }
  772. }