CRC32.cs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. // CRC32.cs
  2. // ------------------------------------------------------------------
  3. //
  4. // Copyright (c) 2011 Dino Chiesa.
  5. // All rights reserved.
  6. //
  7. // This code module is part of DotNetZip, a zipfile class library.
  8. //
  9. // ------------------------------------------------------------------
  10. //
  11. // This code is licensed under the Microsoft Public License.
  12. // See the file License.txt for the license details.
  13. // More info on: http://dotnetzip.codeplex.com
  14. //
  15. // ------------------------------------------------------------------
  16. //
  17. // Last Saved: <2011-August-02 18:25:54>
  18. //
  19. // ------------------------------------------------------------------
  20. //
  21. // This module defines the CRC32 class, which can do the CRC32 algorithm, using
  22. // arbitrary starting polynomials, and bit reversal. The bit reversal is what
  23. // distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP
  24. // files, or GZIP files. This class does both.
  25. //
  26. // ------------------------------------------------------------------
  27. using System;
  28. using Interop = System.Runtime.InteropServices;
  29. namespace Ionic.Crc
  30. {
  31. /// <summary>
  32. /// Computes a CRC-32. The CRC-32 algorithm is parameterized - you
  33. /// can set the polynomial and enable or disable bit
  34. /// reversal. This can be used for GZIP, BZip2, or ZIP.
  35. /// </summary>
  36. /// <remarks>
  37. /// This type is used internally by DotNetZip; it is generally not used
  38. /// directly by applications wishing to create, read, or manipulate zip
  39. /// archive files.
  40. /// </remarks>
  41. #if !PCL
  42. [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")]
  43. [Interop.ComVisible(true)]
  44. #if !NETCF
  45. [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
  46. #endif
  47. #endif
  48. public class CRC32
  49. {
  50. /// <summary>
  51. /// Indicates the total number of bytes applied to the CRC.
  52. /// </summary>
  53. public Int64 TotalBytesRead
  54. {
  55. get
  56. {
  57. return _TotalBytesRead;
  58. }
  59. }
  60. /// <summary>
  61. /// Indicates the current CRC for all blocks slurped in.
  62. /// </summary>
  63. public Int32 Crc32Result
  64. {
  65. get
  66. {
  67. return unchecked((Int32)(~_register));
  68. }
  69. }
  70. /// <summary>
  71. /// Returns the CRC32 for the specified stream.
  72. /// </summary>
  73. /// <param name="input">The stream over which to calculate the CRC32</param>
  74. /// <returns>the CRC32 calculation</returns>
  75. public Int32 GetCrc32(System.IO.Stream input)
  76. {
  77. return GetCrc32AndCopy(input, null);
  78. }
  79. /// <summary>
  80. /// Returns the CRC32 for the specified stream, and writes the input into the
  81. /// output stream.
  82. /// </summary>
  83. /// <param name="input">The stream over which to calculate the CRC32</param>
  84. /// <param name="output">The stream into which to deflate the input</param>
  85. /// <returns>the CRC32 calculation</returns>
  86. public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
  87. {
  88. if (input == null)
  89. throw new Exception("The input stream must not be null.");
  90. unchecked
  91. {
  92. byte[] buffer = new byte[BUFFER_SIZE];
  93. int readSize = BUFFER_SIZE;
  94. _TotalBytesRead = 0;
  95. int count = input.Read(buffer, 0, readSize);
  96. if (output != null) output.Write(buffer, 0, count);
  97. _TotalBytesRead += count;
  98. while (count > 0)
  99. {
  100. SlurpBlock(buffer, 0, count);
  101. count = input.Read(buffer, 0, readSize);
  102. if (output != null) output.Write(buffer, 0, count);
  103. _TotalBytesRead += count;
  104. }
  105. return (Int32)(~_register);
  106. }
  107. }
  108. /// <summary>
  109. /// Get the CRC32 for the given (word,byte) combo. This is a
  110. /// computation defined by PKzip for PKZIP 2.0 (weak) encryption.
  111. /// </summary>
  112. /// <param name="W">The word to start with.</param>
  113. /// <param name="B">The byte to combine it with.</param>
  114. /// <returns>The CRC-ized result.</returns>
  115. public Int32 ComputeCrc32(Int32 W, byte B)
  116. {
  117. return _InternalComputeCrc32((UInt32)W, B);
  118. }
  119. internal Int32 _InternalComputeCrc32(UInt32 W, byte B)
  120. {
  121. return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8));
  122. }
  123. /// <summary>
  124. /// Update the value for the running CRC32 using the given block of bytes.
  125. /// This is useful when using the CRC32() class in a Stream.
  126. /// </summary>
  127. /// <param name="block">block of bytes to slurp</param>
  128. /// <param name="offset">starting point in the block</param>
  129. /// <param name="count">how many bytes within the block to slurp</param>
  130. public void SlurpBlock(byte[] block, int offset, int count)
  131. {
  132. if (block == null)
  133. throw new Exception("The data buffer must not be null.");
  134. // bzip algorithm
  135. for (int i = 0; i < count; i++)
  136. {
  137. int x = offset + i;
  138. byte b = block[x];
  139. if (this.reverseBits)
  140. {
  141. UInt32 temp = (_register >> 24) ^ b;
  142. _register = (_register << 8) ^ crc32Table[temp];
  143. }
  144. else
  145. {
  146. UInt32 temp = (_register & 0x000000FF) ^ b;
  147. _register = (_register >> 8) ^ crc32Table[temp];
  148. }
  149. }
  150. _TotalBytesRead += count;
  151. }
  152. /// <summary>
  153. /// Process one byte in the CRC.
  154. /// </summary>
  155. /// <param name = "b">the byte to include into the CRC . </param>
  156. public void UpdateCRC(byte b)
  157. {
  158. if (this.reverseBits)
  159. {
  160. UInt32 temp = (_register >> 24) ^ b;
  161. _register = (_register << 8) ^ crc32Table[temp];
  162. }
  163. else
  164. {
  165. UInt32 temp = (_register & 0x000000FF) ^ b;
  166. _register = (_register >> 8) ^ crc32Table[temp];
  167. }
  168. }
  169. /// <summary>
  170. /// Process a run of N identical bytes into the CRC.
  171. /// </summary>
  172. /// <remarks>
  173. /// <para>
  174. /// This method serves as an optimization for updating the CRC when a
  175. /// run of identical bytes is found. Rather than passing in a buffer of
  176. /// length n, containing all identical bytes b, this method accepts the
  177. /// byte value and the length of the (virtual) buffer - the length of
  178. /// the run.
  179. /// </para>
  180. /// </remarks>
  181. /// <param name = "b">the byte to include into the CRC. </param>
  182. /// <param name = "n">the number of times that byte should be repeated. </param>
  183. public void UpdateCRC(byte b, int n)
  184. {
  185. while (n-- > 0)
  186. {
  187. if (this.reverseBits)
  188. {
  189. uint temp = (_register >> 24) ^ b;
  190. _register = (_register << 8) ^ crc32Table[(temp >= 0)
  191. ? temp
  192. : (temp + 256)];
  193. }
  194. else
  195. {
  196. UInt32 temp = (_register & 0x000000FF) ^ b;
  197. _register = (_register >> 8) ^ crc32Table[(temp >= 0)
  198. ? temp
  199. : (temp + 256)];
  200. }
  201. }
  202. }
  203. private static uint ReverseBits(uint data)
  204. {
  205. unchecked
  206. {
  207. uint ret = data;
  208. ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555;
  209. ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333;
  210. ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F;
  211. ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24);
  212. return ret;
  213. }
  214. }
  215. private static byte ReverseBits(byte data)
  216. {
  217. unchecked
  218. {
  219. uint u = (uint)data * 0x00020202;
  220. uint m = 0x01044010;
  221. uint s = u & m;
  222. uint t = (u << 2) & (m << 1);
  223. return (byte)((0x01001001 * (s + t)) >> 24);
  224. }
  225. }
  226. private void GenerateLookupTable()
  227. {
  228. crc32Table = new UInt32[256];
  229. unchecked
  230. {
  231. UInt32 dwCrc;
  232. byte i = 0;
  233. do
  234. {
  235. dwCrc = i;
  236. for (byte j = 8; j > 0; j--)
  237. {
  238. if ((dwCrc & 1) == 1)
  239. {
  240. dwCrc = (dwCrc >> 1) ^ dwPolynomial;
  241. }
  242. else
  243. {
  244. dwCrc >>= 1;
  245. }
  246. }
  247. if (reverseBits)
  248. {
  249. crc32Table[ReverseBits(i)] = ReverseBits(dwCrc);
  250. }
  251. else
  252. {
  253. crc32Table[i] = dwCrc;
  254. }
  255. i++;
  256. } while (i!=0);
  257. }
  258. #if VERBOSE
  259. Console.WriteLine();
  260. Console.WriteLine("private static readonly UInt32[] crc32Table = {");
  261. for (int i = 0; i < crc32Table.Length; i+=4)
  262. {
  263. Console.Write(" ");
  264. for (int j=0; j < 4; j++)
  265. {
  266. Console.Write(" 0x{0:X8}U,", crc32Table[i+j]);
  267. }
  268. Console.WriteLine();
  269. }
  270. Console.WriteLine("};");
  271. Console.WriteLine();
  272. #endif
  273. }
  274. private uint gf2_matrix_times(uint[] matrix, uint vec)
  275. {
  276. uint sum = 0;
  277. int i=0;
  278. while (vec != 0)
  279. {
  280. if ((vec & 0x01)== 0x01)
  281. sum ^= matrix[i];
  282. vec >>= 1;
  283. i++;
  284. }
  285. return sum;
  286. }
  287. private void gf2_matrix_square(uint[] square, uint[] mat)
  288. {
  289. for (int i = 0; i < 32; i++)
  290. square[i] = gf2_matrix_times(mat, mat[i]);
  291. }
  292. /// <summary>
  293. /// Combines the given CRC32 value with the current running total.
  294. /// </summary>
  295. /// <remarks>
  296. /// This is useful when using a divide-and-conquer approach to
  297. /// calculating a CRC. Multiple threads can each calculate a
  298. /// CRC32 on a segment of the data, and then combine the
  299. /// individual CRC32 values at the end.
  300. /// </remarks>
  301. /// <param name="crc">the crc value to be combined with this one</param>
  302. /// <param name="length">the length of data the CRC value was calculated on</param>
  303. public void Combine(int crc, int length)
  304. {
  305. uint[] even = new uint[32]; // even-power-of-two zeros operator
  306. uint[] odd = new uint[32]; // odd-power-of-two zeros operator
  307. if (length == 0)
  308. return;
  309. uint crc1= ~_register;
  310. uint crc2= (uint) crc;
  311. // put operator for one zero bit in odd
  312. odd[0] = this.dwPolynomial; // the CRC-32 polynomial
  313. uint row = 1;
  314. for (int i = 1; i < 32; i++)
  315. {
  316. odd[i] = row;
  317. row <<= 1;
  318. }
  319. // put operator for two zero bits in even
  320. gf2_matrix_square(even, odd);
  321. // put operator for four zero bits in odd
  322. gf2_matrix_square(odd, even);
  323. uint len2 = (uint) length;
  324. // apply len2 zeros to crc1 (first square will put the operator for one
  325. // zero byte, eight zero bits, in even)
  326. do {
  327. // apply zeros operator for this bit of len2
  328. gf2_matrix_square(even, odd);
  329. if ((len2 & 1)== 1)
  330. crc1 = gf2_matrix_times(even, crc1);
  331. len2 >>= 1;
  332. if (len2 == 0)
  333. break;
  334. // another iteration of the loop with odd and even swapped
  335. gf2_matrix_square(odd, even);
  336. if ((len2 & 1)==1)
  337. crc1 = gf2_matrix_times(odd, crc1);
  338. len2 >>= 1;
  339. } while (len2 != 0);
  340. crc1 ^= crc2;
  341. _register= ~crc1;
  342. //return (int) crc1;
  343. return;
  344. }
  345. /// <summary>
  346. /// Create an instance of the CRC32 class using the default settings: no
  347. /// bit reversal, and a polynomial of 0xEDB88320.
  348. /// </summary>
  349. public CRC32() : this(false)
  350. {
  351. }
  352. /// <summary>
  353. /// Create an instance of the CRC32 class, specifying whether to reverse
  354. /// data bits or not.
  355. /// </summary>
  356. /// <param name='reverseBits'>
  357. /// specify true if the instance should reverse data bits.
  358. /// </param>
  359. /// <remarks>
  360. /// <para>
  361. /// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
  362. /// want a CRC32 with compatibility with BZip2, you should pass true
  363. /// here. In the CRC-32 used by GZIP and PKZIP, the bits are not
  364. /// reversed; Therefore if you want a CRC32 with compatibility with
  365. /// those, you should pass false.
  366. /// </para>
  367. /// </remarks>
  368. public CRC32(bool reverseBits) :
  369. this( unchecked((int)0xEDB88320), reverseBits)
  370. {
  371. }
  372. /// <summary>
  373. /// Create an instance of the CRC32 class, specifying the polynomial and
  374. /// whether to reverse data bits or not.
  375. /// </summary>
  376. /// <param name='polynomial'>
  377. /// The polynomial to use for the CRC, expressed in the reversed (LSB)
  378. /// format: the highest ordered bit in the polynomial value is the
  379. /// coefficient of the 0th power; the second-highest order bit is the
  380. /// coefficient of the 1 power, and so on. Expressed this way, the
  381. /// polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320.
  382. /// </param>
  383. /// <param name='reverseBits'>
  384. /// specify true if the instance should reverse data bits.
  385. /// </param>
  386. ///
  387. /// <remarks>
  388. /// <para>
  389. /// In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
  390. /// want a CRC32 with compatibility with BZip2, you should pass true
  391. /// here for the <c>reverseBits</c> parameter. In the CRC-32 used by
  392. /// GZIP and PKZIP, the bits are not reversed; Therefore if you want a
  393. /// CRC32 with compatibility with those, you should pass false for the
  394. /// <c>reverseBits</c> parameter.
  395. /// </para>
  396. /// </remarks>
  397. public CRC32(int polynomial, bool reverseBits)
  398. {
  399. this.reverseBits = reverseBits;
  400. this.dwPolynomial = (uint) polynomial;
  401. this.GenerateLookupTable();
  402. }
  403. /// <summary>
  404. /// Reset the CRC-32 class - clear the CRC "remainder register."
  405. /// </summary>
  406. /// <remarks>
  407. /// <para>
  408. /// Use this when employing a single instance of this class to compute
  409. /// multiple, distinct CRCs on multiple, distinct data blocks.
  410. /// </para>
  411. /// </remarks>
  412. public void Reset()
  413. {
  414. _register = 0xFFFFFFFFU;
  415. }
  416. // private member vars
  417. private UInt32 dwPolynomial;
  418. private Int64 _TotalBytesRead;
  419. private bool reverseBits;
  420. private UInt32[] crc32Table;
  421. private const int BUFFER_SIZE = 8192;
  422. private UInt32 _register = 0xFFFFFFFFU;
  423. }
  424. /// <summary>
  425. /// A Stream that calculates a CRC32 (a checksum) on all bytes read,
  426. /// or on all bytes written.
  427. /// </summary>
  428. ///
  429. /// <remarks>
  430. /// <para>
  431. /// This class can be used to verify the CRC of a ZipEntry when
  432. /// reading from a stream, or to calculate a CRC when writing to a
  433. /// stream. The stream should be used to either read, or write, but
  434. /// not both. If you intermix reads and writes, the results are not
  435. /// defined.
  436. /// </para>
  437. ///
  438. /// <para>
  439. /// This class is intended primarily for use internally by the
  440. /// DotNetZip library.
  441. /// </para>
  442. /// </remarks>
  443. public class CrcCalculatorStream : System.IO.Stream, IDisposable
  444. {
  445. static readonly Int64 UnsetLengthLimit = -99;
  446. readonly System.IO.Stream _innerStream;
  447. readonly CRC32 _crc32;
  448. readonly Int64 _lengthLimit = -99;
  449. bool _leaveOpen;
  450. /// <summary>
  451. /// The default constructor.
  452. /// </summary>
  453. /// <remarks>
  454. /// <para>
  455. /// Instances returned from this constructor will leave the underlying
  456. /// stream open upon Close(). The stream uses the default CRC32
  457. /// algorithm, which implies a polynomial of 0xEDB88320.
  458. /// </para>
  459. /// </remarks>
  460. /// <param name="stream">The underlying stream</param>
  461. public CrcCalculatorStream(System.IO.Stream stream)
  462. : this(true, UnsetLengthLimit, stream, null)
  463. {
  464. }
  465. /// <summary>
  466. /// The constructor allows the caller to specify how to handle the
  467. /// underlying stream at close.
  468. /// </summary>
  469. /// <remarks>
  470. /// <para>
  471. /// The stream uses the default CRC32 algorithm, which implies a
  472. /// polynomial of 0xEDB88320.
  473. /// </para>
  474. /// </remarks>
  475. /// <param name="stream">The underlying stream</param>
  476. /// <param name="leaveOpen">true to leave the underlying stream
  477. /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
  478. public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
  479. : this(leaveOpen, UnsetLengthLimit, stream, null)
  480. {
  481. }
  482. /// <summary>
  483. /// A constructor allowing the specification of the length of the stream
  484. /// to read.
  485. /// </summary>
  486. /// <remarks>
  487. /// <para>
  488. /// The stream uses the default CRC32 algorithm, which implies a
  489. /// polynomial of 0xEDB88320.
  490. /// </para>
  491. /// <para>
  492. /// Instances returned from this constructor will leave the underlying
  493. /// stream open upon Close().
  494. /// </para>
  495. /// </remarks>
  496. /// <param name="stream">The underlying stream</param>
  497. /// <param name="length">The length of the stream to slurp</param>
  498. public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
  499. : this(true, length, stream, null)
  500. {
  501. if (length < 0)
  502. throw new ArgumentException("length");
  503. }
  504. /// <summary>
  505. /// A constructor allowing the specification of the length of the stream
  506. /// to read, as well as whether to keep the underlying stream open upon
  507. /// Close().
  508. /// </summary>
  509. /// <remarks>
  510. /// <para>
  511. /// The stream uses the default CRC32 algorithm, which implies a
  512. /// polynomial of 0xEDB88320.
  513. /// </para>
  514. /// </remarks>
  515. /// <param name="stream">The underlying stream</param>
  516. /// <param name="length">The length of the stream to slurp</param>
  517. /// <param name="leaveOpen">true to leave the underlying stream
  518. /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
  519. public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
  520. : this(leaveOpen, length, stream, null)
  521. {
  522. if (length < 0)
  523. throw new ArgumentException("length");
  524. }
  525. /// <summary>
  526. /// A constructor allowing the specification of the length of the stream
  527. /// to read, as well as whether to keep the underlying stream open upon
  528. /// Close(), and the CRC32 instance to use.
  529. /// </summary>
  530. /// <remarks>
  531. /// <para>
  532. /// The stream uses the specified CRC32 instance, which allows the
  533. /// application to specify how the CRC gets calculated.
  534. /// </para>
  535. /// </remarks>
  536. /// <param name="stream">The underlying stream</param>
  537. /// <param name="length">The length of the stream to slurp</param>
  538. /// <param name="leaveOpen">true to leave the underlying stream
  539. /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
  540. /// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
  541. public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
  542. CRC32 crc32)
  543. : this(leaveOpen, length, stream, crc32)
  544. {
  545. if (length < 0)
  546. throw new ArgumentException("length");
  547. }
  548. // This ctor is private - no validation except null is done here.
  549. // This is to allow the use
  550. // of a (specific) negative value for the _lengthLimit, to indicate that there
  551. // is no length set. So we validate the length limit in those ctors that use an
  552. // explicit param, otherwise we don't validate, because it could be our special
  553. // value.
  554. CrcCalculatorStream(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
  555. {
  556. if (stream == null) throw new ArgumentNullException("stream");
  557. _innerStream = stream;
  558. _crc32 = crc32 ?? new CRC32();
  559. _lengthLimit = length;
  560. _leaveOpen = leaveOpen;
  561. }
  562. /// <summary>
  563. /// Gets the total number of bytes run through the CRC32 calculator.
  564. /// </summary>
  565. ///
  566. /// <remarks>
  567. /// This is either the total number of bytes read, or the total number of
  568. /// bytes written, depending on the direction of this stream.
  569. /// </remarks>
  570. public Int64 TotalBytesSlurped
  571. {
  572. get { return _crc32.TotalBytesRead; }
  573. }
  574. /// <summary>
  575. /// Provides the current CRC for all blocks slurped in.
  576. /// </summary>
  577. /// <remarks>
  578. /// <para>
  579. /// The running total of the CRC is kept as data is written or read
  580. /// through the stream. read this property after all reads or writes to
  581. /// get an accurate CRC for the entire stream.
  582. /// </para>
  583. /// </remarks>
  584. public Int32 Crc
  585. {
  586. get { return _crc32.Crc32Result; }
  587. }
  588. /// <summary>
  589. /// Indicates whether the underlying stream will be left open when the
  590. /// <c>CrcCalculatorStream</c> is Closed.
  591. /// </summary>
  592. /// <remarks>
  593. /// <para>
  594. /// Set this at any point before calling <see cref="Close()"/>.
  595. /// </para>
  596. /// </remarks>
  597. public bool LeaveOpen
  598. {
  599. get { return _leaveOpen; }
  600. set { _leaveOpen = value; }
  601. }
  602. /// <summary>
  603. /// Read from the stream
  604. /// </summary>
  605. /// <param name="buffer">the buffer to read</param>
  606. /// <param name="offset">the offset at which to start</param>
  607. /// <param name="count">the number of bytes to read</param>
  608. /// <returns>the number of bytes actually read</returns>
  609. public override int Read(byte[] buffer, int offset, int count)
  610. {
  611. int bytesToRead = count;
  612. // Need to limit the # of bytes returned, if the stream is intended to have
  613. // a definite length. This is especially useful when returning a stream for
  614. // the uncompressed data directly to the application. The app won't
  615. // necessarily read only the UncompressedSize number of bytes. For example
  616. // wrapping the stream returned from OpenReader() into a StreadReader() and
  617. // calling ReadToEnd() on it, We can "over-read" the zip data and get a
  618. // corrupt string. The length limits that, prevents that problem.
  619. if (_lengthLimit != CrcCalculatorStream.UnsetLengthLimit)
  620. {
  621. if (_crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
  622. Int64 bytesRemaining = _lengthLimit - _crc32.TotalBytesRead;
  623. if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
  624. }
  625. int n = _innerStream.Read(buffer, offset, bytesToRead);
  626. if (n > 0) _crc32.SlurpBlock(buffer, offset, n);
  627. return n;
  628. }
  629. /// <summary>
  630. /// Write to the stream.
  631. /// </summary>
  632. /// <param name="buffer">the buffer from which to write</param>
  633. /// <param name="offset">the offset at which to start writing</param>
  634. /// <param name="count">the number of bytes to write</param>
  635. public override void Write(byte[] buffer, int offset, int count)
  636. {
  637. if (count > 0) _crc32.SlurpBlock(buffer, offset, count);
  638. _innerStream.Write(buffer, offset, count);
  639. }
  640. /// <summary>
  641. /// Indicates whether the stream supports reading.
  642. /// </summary>
  643. public override bool CanRead
  644. {
  645. get { return _innerStream.CanRead; }
  646. }
  647. /// <summary>
  648. /// Indicates whether the stream supports seeking.
  649. /// </summary>
  650. /// <remarks>
  651. /// <para>
  652. /// Always returns false.
  653. /// </para>
  654. /// </remarks>
  655. public override bool CanSeek
  656. {
  657. get { return false; }
  658. }
  659. /// <summary>
  660. /// Indicates whether the stream supports writing.
  661. /// </summary>
  662. public override bool CanWrite
  663. {
  664. get { return _innerStream.CanWrite; }
  665. }
  666. /// <summary>
  667. /// Flush the stream.
  668. /// </summary>
  669. public override void Flush()
  670. {
  671. _innerStream.Flush();
  672. }
  673. /// <summary>
  674. /// Returns the length of the underlying stream.
  675. /// </summary>
  676. public override long Length
  677. {
  678. get
  679. {
  680. if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
  681. return _innerStream.Length;
  682. else return _lengthLimit;
  683. }
  684. }
  685. /// <summary>
  686. /// The getter for this property returns the total bytes read.
  687. /// If you use the setter, it will throw
  688. /// <see cref="NotSupportedException"/>.
  689. /// </summary>
  690. public override long Position
  691. {
  692. get { return _crc32.TotalBytesRead; }
  693. set { throw new NotSupportedException(); }
  694. }
  695. /// <summary>
  696. /// Seeking is not supported on this stream. This method always throws
  697. /// <see cref="NotSupportedException"/>
  698. /// </summary>
  699. /// <param name="offset">N/A</param>
  700. /// <param name="origin">N/A</param>
  701. /// <returns>N/A</returns>
  702. public override long Seek(long offset, System.IO.SeekOrigin origin)
  703. {
  704. throw new NotSupportedException();
  705. }
  706. /// <summary>
  707. /// This method always throws
  708. /// <see cref="NotSupportedException"/>
  709. /// </summary>
  710. /// <param name="value">N/A</param>
  711. public override void SetLength(long value)
  712. {
  713. throw new NotSupportedException();
  714. }
  715. void IDisposable.Dispose()
  716. {
  717. InnerClose();
  718. }
  719. private void InnerClose()
  720. {
  721. if (!_leaveOpen)
  722. {
  723. #if !PCL
  724. _innerStream.Close();
  725. #else
  726. _innerStream.Dispose();
  727. #endif
  728. }
  729. }
  730. /// <summary>
  731. /// Closes the stream.
  732. /// </summary>
  733. #if !PCL
  734. public override void Close()
  735. {
  736. base.Close();
  737. InnerClose();
  738. }
  739. #endif
  740. }
  741. }