Inflater.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. using System;
  2. using ICSharpCode.SharpZipLib.Checksum;
  3. using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
  4. namespace ICSharpCode.SharpZipLib.Zip.Compression
  5. {
  6. /// <summary>
  7. /// Inflater is used to decompress data that has been compressed according
  8. /// to the "deflate" standard described in rfc1951.
  9. ///
  10. /// By default Zlib (rfc1950) headers and footers are expected in the input.
  11. /// You can use constructor <code> public Inflater(bool noHeader)</code> passing true
  12. /// if there is no Zlib header information
  13. ///
  14. /// The usage is as following. First you have to set some input with
  15. /// <code>SetInput()</code>, then Inflate() it. If inflate doesn't
  16. /// inflate any bytes there may be three reasons:
  17. /// <ul>
  18. /// <li>IsNeedingInput() returns true because the input buffer is empty.
  19. /// You have to provide more input with <code>SetInput()</code>.
  20. /// NOTE: IsNeedingInput() also returns true when, the stream is finished.
  21. /// </li>
  22. /// <li>IsNeedingDictionary() returns true, you have to provide a preset
  23. /// dictionary with <code>SetDictionary()</code>.</li>
  24. /// <li>IsFinished returns true, the inflater has finished.</li>
  25. /// </ul>
  26. /// Once the first output byte is produced, a dictionary will not be
  27. /// needed at a later stage.
  28. ///
  29. /// author of the original java version : John Leuner, Jochen Hoenicke
  30. /// </summary>
  31. public class Inflater
  32. {
  33. #region Constants/Readonly
  34. /// <summary>
  35. /// Copy lengths for literal codes 257..285
  36. /// </summary>
  37. static readonly int[] CPLENS = {
  38. 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  39. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258
  40. };
  41. /// <summary>
  42. /// Extra bits for literal codes 257..285
  43. /// </summary>
  44. static readonly int[] CPLEXT = {
  45. 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
  46. 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0
  47. };
  48. /// <summary>
  49. /// Copy offsets for distance codes 0..29
  50. /// </summary>
  51. static readonly int[] CPDIST = {
  52. 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  53. 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  54. 8193, 12289, 16385, 24577
  55. };
  56. /// <summary>
  57. /// Extra bits for distance codes
  58. /// </summary>
  59. static readonly int[] CPDEXT = {
  60. 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  61. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
  62. 12, 12, 13, 13
  63. };
  64. /// <summary>
  65. /// These are the possible states for an inflater
  66. /// </summary>
  67. const int DECODE_HEADER = 0;
  68. const int DECODE_DICT = 1;
  69. const int DECODE_BLOCKS = 2;
  70. const int DECODE_STORED_LEN1 = 3;
  71. const int DECODE_STORED_LEN2 = 4;
  72. const int DECODE_STORED = 5;
  73. const int DECODE_DYN_HEADER = 6;
  74. const int DECODE_HUFFMAN = 7;
  75. const int DECODE_HUFFMAN_LENBITS = 8;
  76. const int DECODE_HUFFMAN_DIST = 9;
  77. const int DECODE_HUFFMAN_DISTBITS = 10;
  78. const int DECODE_CHKSUM = 11;
  79. const int FINISHED = 12;
  80. #endregion
  81. #region Instance Fields
  82. /// <summary>
  83. /// This variable contains the current state.
  84. /// </summary>
  85. int mode;
  86. /// <summary>
  87. /// The adler checksum of the dictionary or of the decompressed
  88. /// stream, as it is written in the header resp. footer of the
  89. /// compressed stream.
  90. /// Only valid if mode is DECODE_DICT or DECODE_CHKSUM.
  91. /// </summary>
  92. int readAdler;
  93. /// <summary>
  94. /// The number of bits needed to complete the current state. This
  95. /// is valid, if mode is DECODE_DICT, DECODE_CHKSUM,
  96. /// DECODE_HUFFMAN_LENBITS or DECODE_HUFFMAN_DISTBITS.
  97. /// </summary>
  98. int neededBits;
  99. int repLength;
  100. int repDist;
  101. int uncomprLen;
  102. /// <summary>
  103. /// True, if the last block flag was set in the last block of the
  104. /// inflated stream. This means that the stream ends after the
  105. /// current block.
  106. /// </summary>
  107. bool isLastBlock;
  108. /// <summary>
  109. /// The total number of inflated bytes.
  110. /// </summary>
  111. long totalOut;
  112. /// <summary>
  113. /// The total number of bytes set with setInput(). This is not the
  114. /// value returned by the TotalIn property, since this also includes the
  115. /// unprocessed input.
  116. /// </summary>
  117. long totalIn;
  118. /// <summary>
  119. /// This variable stores the noHeader flag that was given to the constructor.
  120. /// True means, that the inflated stream doesn't contain a Zlib header or
  121. /// footer.
  122. /// </summary>
  123. bool noHeader;
  124. readonly StreamManipulator input;
  125. OutputWindow outputWindow;
  126. InflaterDynHeader dynHeader;
  127. InflaterHuffmanTree litlenTree, distTree;
  128. Adler32 adler;
  129. #endregion
  130. #region Constructors
  131. /// <summary>
  132. /// Creates a new inflater or RFC1951 decompressor
  133. /// RFC1950/Zlib headers and footers will be expected in the input data
  134. /// </summary>
  135. public Inflater() : this(false)
  136. {
  137. }
  138. /// <summary>
  139. /// Creates a new inflater.
  140. /// </summary>
  141. /// <param name="noHeader">
  142. /// True if no RFC1950/Zlib header and footer fields are expected in the input data
  143. ///
  144. /// This is used for GZIPed/Zipped input.
  145. ///
  146. /// For compatibility with
  147. /// Sun JDK you should provide one byte of input more than needed in
  148. /// this case.
  149. /// </param>
  150. public Inflater(bool noHeader)
  151. {
  152. this.noHeader = noHeader;
  153. this.adler = new Adler32();
  154. input = new StreamManipulator();
  155. outputWindow = new OutputWindow();
  156. mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
  157. }
  158. #endregion
  159. /// <summary>
  160. /// Resets the inflater so that a new stream can be decompressed. All
  161. /// pending input and output will be discarded.
  162. /// </summary>
  163. public void Reset()
  164. {
  165. mode = noHeader ? DECODE_BLOCKS : DECODE_HEADER;
  166. totalIn = 0;
  167. totalOut = 0;
  168. input.Reset();
  169. outputWindow.Reset();
  170. dynHeader = null;
  171. litlenTree = null;
  172. distTree = null;
  173. isLastBlock = false;
  174. adler.Reset();
  175. }
  176. /// <summary>
  177. /// Decodes a zlib/RFC1950 header.
  178. /// </summary>
  179. /// <returns>
  180. /// False if more input is needed.
  181. /// </returns>
  182. /// <exception cref="SharpZipBaseException">
  183. /// The header is invalid.
  184. /// </exception>
  185. private bool DecodeHeader()
  186. {
  187. int header = input.PeekBits(16);
  188. if (header < 0) {
  189. return false;
  190. }
  191. input.DropBits(16);
  192. // The header is written in "wrong" byte order
  193. header = ((header << 8) | (header >> 8)) & 0xffff;
  194. if (header % 31 != 0) {
  195. throw new SharpZipBaseException("Header checksum illegal");
  196. }
  197. if ((header & 0x0f00) != (Deflater.DEFLATED << 8)) {
  198. throw new SharpZipBaseException("Compression Method unknown");
  199. }
  200. /* Maximum size of the backwards window in bits.
  201. * We currently ignore this, but we could use it to make the
  202. * inflater window more space efficient. On the other hand the
  203. * full window (15 bits) is needed most times, anyway.
  204. int max_wbits = ((header & 0x7000) >> 12) + 8;
  205. */
  206. if ((header & 0x0020) == 0) { // Dictionary flag?
  207. mode = DECODE_BLOCKS;
  208. } else {
  209. mode = DECODE_DICT;
  210. neededBits = 32;
  211. }
  212. return true;
  213. }
  214. /// <summary>
  215. /// Decodes the dictionary checksum after the deflate header.
  216. /// </summary>
  217. /// <returns>
  218. /// False if more input is needed.
  219. /// </returns>
  220. private bool DecodeDict()
  221. {
  222. while (neededBits > 0) {
  223. int dictByte = input.PeekBits(8);
  224. if (dictByte < 0) {
  225. return false;
  226. }
  227. input.DropBits(8);
  228. readAdler = (readAdler << 8) | dictByte;
  229. neededBits -= 8;
  230. }
  231. return false;
  232. }
  233. /// <summary>
  234. /// Decodes the huffman encoded symbols in the input stream.
  235. /// </summary>
  236. /// <returns>
  237. /// false if more input is needed, true if output window is
  238. /// full or the current block ends.
  239. /// </returns>
  240. /// <exception cref="SharpZipBaseException">
  241. /// if deflated stream is invalid.
  242. /// </exception>
  243. private bool DecodeHuffman()
  244. {
  245. int free = outputWindow.GetFreeSpace();
  246. while (free >= 258) {
  247. int symbol;
  248. switch (mode) {
  249. case DECODE_HUFFMAN:
  250. // This is the inner loop so it is optimized a bit
  251. while (((symbol = litlenTree.GetSymbol(input)) & ~0xff) == 0) {
  252. outputWindow.Write(symbol);
  253. if (--free < 258) {
  254. return true;
  255. }
  256. }
  257. if (symbol < 257) {
  258. if (symbol < 0) {
  259. return false;
  260. } else {
  261. // symbol == 256: end of block
  262. distTree = null;
  263. litlenTree = null;
  264. mode = DECODE_BLOCKS;
  265. return true;
  266. }
  267. }
  268. try {
  269. repLength = CPLENS[symbol - 257];
  270. neededBits = CPLEXT[symbol - 257];
  271. } catch (Exception) {
  272. throw new SharpZipBaseException("Illegal rep length code");
  273. }
  274. goto case DECODE_HUFFMAN_LENBITS; // fall through
  275. case DECODE_HUFFMAN_LENBITS:
  276. if (neededBits > 0) {
  277. mode = DECODE_HUFFMAN_LENBITS;
  278. int i = input.PeekBits(neededBits);
  279. if (i < 0) {
  280. return false;
  281. }
  282. input.DropBits(neededBits);
  283. repLength += i;
  284. }
  285. mode = DECODE_HUFFMAN_DIST;
  286. goto case DECODE_HUFFMAN_DIST; // fall through
  287. case DECODE_HUFFMAN_DIST:
  288. symbol = distTree.GetSymbol(input);
  289. if (symbol < 0) {
  290. return false;
  291. }
  292. try {
  293. repDist = CPDIST[symbol];
  294. neededBits = CPDEXT[symbol];
  295. } catch (Exception) {
  296. throw new SharpZipBaseException("Illegal rep dist code");
  297. }
  298. goto case DECODE_HUFFMAN_DISTBITS; // fall through
  299. case DECODE_HUFFMAN_DISTBITS:
  300. if (neededBits > 0) {
  301. mode = DECODE_HUFFMAN_DISTBITS;
  302. int i = input.PeekBits(neededBits);
  303. if (i < 0) {
  304. return false;
  305. }
  306. input.DropBits(neededBits);
  307. repDist += i;
  308. }
  309. outputWindow.Repeat(repLength, repDist);
  310. free -= repLength;
  311. mode = DECODE_HUFFMAN;
  312. break;
  313. default:
  314. throw new SharpZipBaseException("Inflater unknown mode");
  315. }
  316. }
  317. return true;
  318. }
  319. /// <summary>
  320. /// Decodes the adler checksum after the deflate stream.
  321. /// </summary>
  322. /// <returns>
  323. /// false if more input is needed.
  324. /// </returns>
  325. /// <exception cref="SharpZipBaseException">
  326. /// If checksum doesn't match.
  327. /// </exception>
  328. private bool DecodeChksum()
  329. {
  330. while (neededBits > 0) {
  331. int chkByte = input.PeekBits(8);
  332. if (chkByte < 0) {
  333. return false;
  334. }
  335. input.DropBits(8);
  336. readAdler = (readAdler << 8) | chkByte;
  337. neededBits -= 8;
  338. }
  339. if ((int)adler.Value != readAdler) {
  340. throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler);
  341. }
  342. mode = FINISHED;
  343. return false;
  344. }
  345. /// <summary>
  346. /// Decodes the deflated stream.
  347. /// </summary>
  348. /// <returns>
  349. /// false if more input is needed, or if finished.
  350. /// </returns>
  351. /// <exception cref="SharpZipBaseException">
  352. /// if deflated stream is invalid.
  353. /// </exception>
  354. private bool Decode()
  355. {
  356. switch (mode) {
  357. case DECODE_HEADER:
  358. return DecodeHeader();
  359. case DECODE_DICT:
  360. return DecodeDict();
  361. case DECODE_CHKSUM:
  362. return DecodeChksum();
  363. case DECODE_BLOCKS:
  364. if (isLastBlock) {
  365. if (noHeader) {
  366. mode = FINISHED;
  367. return false;
  368. } else {
  369. input.SkipToByteBoundary();
  370. neededBits = 32;
  371. mode = DECODE_CHKSUM;
  372. return true;
  373. }
  374. }
  375. int type = input.PeekBits(3);
  376. if (type < 0) {
  377. return false;
  378. }
  379. input.DropBits(3);
  380. isLastBlock |= (type & 1) != 0;
  381. switch (type >> 1) {
  382. case DeflaterConstants.STORED_BLOCK:
  383. input.SkipToByteBoundary();
  384. mode = DECODE_STORED_LEN1;
  385. break;
  386. case DeflaterConstants.STATIC_TREES:
  387. litlenTree = InflaterHuffmanTree.defLitLenTree;
  388. distTree = InflaterHuffmanTree.defDistTree;
  389. mode = DECODE_HUFFMAN;
  390. break;
  391. case DeflaterConstants.DYN_TREES:
  392. dynHeader = new InflaterDynHeader();
  393. mode = DECODE_DYN_HEADER;
  394. break;
  395. default:
  396. throw new SharpZipBaseException("Unknown block type " + type);
  397. }
  398. return true;
  399. case DECODE_STORED_LEN1: {
  400. if ((uncomprLen = input.PeekBits(16)) < 0) {
  401. return false;
  402. }
  403. input.DropBits(16);
  404. mode = DECODE_STORED_LEN2;
  405. }
  406. goto case DECODE_STORED_LEN2; // fall through
  407. case DECODE_STORED_LEN2: {
  408. int nlen = input.PeekBits(16);
  409. if (nlen < 0) {
  410. return false;
  411. }
  412. input.DropBits(16);
  413. if (nlen != (uncomprLen ^ 0xffff)) {
  414. throw new SharpZipBaseException("broken uncompressed block");
  415. }
  416. mode = DECODE_STORED;
  417. }
  418. goto case DECODE_STORED; // fall through
  419. case DECODE_STORED: {
  420. int more = outputWindow.CopyStored(input, uncomprLen);
  421. uncomprLen -= more;
  422. if (uncomprLen == 0) {
  423. mode = DECODE_BLOCKS;
  424. return true;
  425. }
  426. return !input.IsNeedingInput;
  427. }
  428. case DECODE_DYN_HEADER:
  429. if (!dynHeader.Decode(input)) {
  430. return false;
  431. }
  432. litlenTree = dynHeader.BuildLitLenTree();
  433. distTree = dynHeader.BuildDistTree();
  434. mode = DECODE_HUFFMAN;
  435. goto case DECODE_HUFFMAN; // fall through
  436. case DECODE_HUFFMAN:
  437. case DECODE_HUFFMAN_LENBITS:
  438. case DECODE_HUFFMAN_DIST:
  439. case DECODE_HUFFMAN_DISTBITS:
  440. return DecodeHuffman();
  441. case FINISHED:
  442. return false;
  443. default:
  444. throw new SharpZipBaseException("Inflater.Decode unknown mode");
  445. }
  446. }
  447. /// <summary>
  448. /// Sets the preset dictionary. This should only be called, if
  449. /// needsDictionary() returns true and it should set the same
  450. /// dictionary, that was used for deflating. The getAdler()
  451. /// function returns the checksum of the dictionary needed.
  452. /// </summary>
  453. /// <param name="buffer">
  454. /// The dictionary.
  455. /// </param>
  456. public void SetDictionary(byte[] buffer)
  457. {
  458. SetDictionary(buffer, 0, buffer.Length);
  459. }
  460. /// <summary>
  461. /// Sets the preset dictionary. This should only be called, if
  462. /// needsDictionary() returns true and it should set the same
  463. /// dictionary, that was used for deflating. The getAdler()
  464. /// function returns the checksum of the dictionary needed.
  465. /// </summary>
  466. /// <param name="buffer">
  467. /// The dictionary.
  468. /// </param>
  469. /// <param name="index">
  470. /// The index into buffer where the dictionary starts.
  471. /// </param>
  472. /// <param name="count">
  473. /// The number of bytes in the dictionary.
  474. /// </param>
  475. /// <exception cref="System.InvalidOperationException">
  476. /// No dictionary is needed.
  477. /// </exception>
  478. /// <exception cref="SharpZipBaseException">
  479. /// The adler checksum for the buffer is invalid
  480. /// </exception>
  481. public void SetDictionary(byte[] buffer, int index, int count)
  482. {
  483. if (buffer == null) {
  484. throw new ArgumentNullException("nameof(buffer)");
  485. }
  486. if (index < 0) {
  487. throw new ArgumentOutOfRangeException("nameof(index)");
  488. }
  489. if (count < 0) {
  490. throw new ArgumentOutOfRangeException("nameof(count)");
  491. }
  492. if (!IsNeedingDictionary) {
  493. throw new InvalidOperationException("Dictionary is not needed");
  494. }
  495. adler.Update(buffer, index, count);
  496. if ((int)adler.Value != readAdler) {
  497. throw new SharpZipBaseException("Wrong adler checksum");
  498. }
  499. adler.Reset();
  500. outputWindow.CopyDict(buffer, index, count);
  501. mode = DECODE_BLOCKS;
  502. }
  503. /// <summary>
  504. /// Sets the input. This should only be called, if needsInput()
  505. /// returns true.
  506. /// </summary>
  507. /// <param name="buffer">
  508. /// the input.
  509. /// </param>
  510. public void SetInput(byte[] buffer)
  511. {
  512. SetInput(buffer, 0, buffer.Length);
  513. }
  514. /// <summary>
  515. /// Sets the input. This should only be called, if needsInput()
  516. /// returns true.
  517. /// </summary>
  518. /// <param name="buffer">
  519. /// The source of input data
  520. /// </param>
  521. /// <param name="index">
  522. /// The index into buffer where the input starts.
  523. /// </param>
  524. /// <param name="count">
  525. /// The number of bytes of input to use.
  526. /// </param>
  527. /// <exception cref="System.InvalidOperationException">
  528. /// No input is needed.
  529. /// </exception>
  530. /// <exception cref="System.ArgumentOutOfRangeException">
  531. /// The index and/or count are wrong.
  532. /// </exception>
  533. public void SetInput(byte[] buffer, int index, int count)
  534. {
  535. input.SetInput(buffer, index, count);
  536. totalIn += (long)count;
  537. }
  538. /// <summary>
  539. /// Inflates the compressed stream to the output buffer. If this
  540. /// returns 0, you should check, whether IsNeedingDictionary(),
  541. /// IsNeedingInput() or IsFinished() returns true, to determine why no
  542. /// further output is produced.
  543. /// </summary>
  544. /// <param name="buffer">
  545. /// the output buffer.
  546. /// </param>
  547. /// <returns>
  548. /// The number of bytes written to the buffer, 0 if no further
  549. /// output can be produced.
  550. /// </returns>
  551. /// <exception cref="System.ArgumentOutOfRangeException">
  552. /// if buffer has length 0.
  553. /// </exception>
  554. /// <exception cref="System.FormatException">
  555. /// if deflated stream is invalid.
  556. /// </exception>
  557. public int Inflate(byte[] buffer)
  558. {
  559. if (buffer == null) {
  560. throw new ArgumentNullException("nameof(buffer)");
  561. }
  562. return Inflate(buffer, 0, buffer.Length);
  563. }
  564. /// <summary>
  565. /// Inflates the compressed stream to the output buffer. If this
  566. /// returns 0, you should check, whether needsDictionary(),
  567. /// needsInput() or finished() returns true, to determine why no
  568. /// further output is produced.
  569. /// </summary>
  570. /// <param name="buffer">
  571. /// the output buffer.
  572. /// </param>
  573. /// <param name="offset">
  574. /// the offset in buffer where storing starts.
  575. /// </param>
  576. /// <param name="count">
  577. /// the maximum number of bytes to output.
  578. /// </param>
  579. /// <returns>
  580. /// the number of bytes written to the buffer, 0 if no further output can be produced.
  581. /// </returns>
  582. /// <exception cref="System.ArgumentOutOfRangeException">
  583. /// if count is less than 0.
  584. /// </exception>
  585. /// <exception cref="System.ArgumentOutOfRangeException">
  586. /// if the index and / or count are wrong.
  587. /// </exception>
  588. /// <exception cref="System.FormatException">
  589. /// if deflated stream is invalid.
  590. /// </exception>
  591. public int Inflate(byte[] buffer, int offset, int count)
  592. {
  593. if (buffer == null) {
  594. throw new ArgumentNullException("nameof(buffer)");
  595. }
  596. if (count < 0) {
  597. throw new ArgumentOutOfRangeException("nameof(count)", "count cannot be negative");
  598. }
  599. if (offset < 0) {
  600. throw new ArgumentOutOfRangeException("nameof(offset)", "offset cannot be negative");
  601. }
  602. if (offset + count > buffer.Length) {
  603. throw new ArgumentException("count exceeds buffer bounds");
  604. }
  605. // Special case: count may be zero
  606. if (count == 0) {
  607. if (!IsFinished) { // -jr- 08-Nov-2003 INFLATE_BUG fix..
  608. Decode();
  609. }
  610. return 0;
  611. }
  612. int bytesCopied = 0;
  613. do {
  614. if (mode != DECODE_CHKSUM) {
  615. /* Don't give away any output, if we are waiting for the
  616. * checksum in the input stream.
  617. *
  618. * With this trick we have always:
  619. * IsNeedingInput() and not IsFinished()
  620. * implies more output can be produced.
  621. */
  622. int more = outputWindow.CopyOutput(buffer, offset, count);
  623. if (more > 0) {
  624. adler.Update(buffer, offset, more);
  625. offset += more;
  626. bytesCopied += more;
  627. totalOut += (long)more;
  628. count -= more;
  629. if (count == 0) {
  630. return bytesCopied;
  631. }
  632. }
  633. }
  634. } while (Decode() || ((outputWindow.GetAvailable() > 0) && (mode != DECODE_CHKSUM)));
  635. return bytesCopied;
  636. }
  637. /// <summary>
  638. /// Returns true, if the input buffer is empty.
  639. /// You should then call setInput().
  640. /// NOTE: This method also returns true when the stream is finished.
  641. /// </summary>
  642. public bool IsNeedingInput {
  643. get {
  644. return input.IsNeedingInput;
  645. }
  646. }
  647. /// <summary>
  648. /// Returns true, if a preset dictionary is needed to inflate the input.
  649. /// </summary>
  650. public bool IsNeedingDictionary {
  651. get {
  652. return mode == DECODE_DICT && neededBits == 0;
  653. }
  654. }
  655. /// <summary>
  656. /// Returns true, if the inflater has finished. This means, that no
  657. /// input is needed and no output can be produced.
  658. /// </summary>
  659. public bool IsFinished {
  660. get {
  661. return mode == FINISHED && outputWindow.GetAvailable() == 0;
  662. }
  663. }
  664. /// <summary>
  665. /// Gets the adler checksum. This is either the checksum of all
  666. /// uncompressed bytes returned by inflate(), or if needsDictionary()
  667. /// returns true (and thus no output was yet produced) this is the
  668. /// adler checksum of the expected dictionary.
  669. /// </summary>
  670. /// <returns>
  671. /// the adler checksum.
  672. /// </returns>
  673. public int Adler {
  674. get {
  675. return IsNeedingDictionary ? readAdler : (int)adler.Value;
  676. }
  677. }
  678. /// <summary>
  679. /// Gets the total number of output bytes returned by Inflate().
  680. /// </summary>
  681. /// <returns>
  682. /// the total number of output bytes.
  683. /// </returns>
  684. public long TotalOut {
  685. get {
  686. return totalOut;
  687. }
  688. }
  689. /// <summary>
  690. /// Gets the total number of processed compressed input bytes.
  691. /// </summary>
  692. /// <returns>
  693. /// The total number of bytes of processed input bytes.
  694. /// </returns>
  695. public long TotalIn {
  696. get {
  697. return totalIn - (long)RemainingInput;
  698. }
  699. }
  700. /// <summary>
  701. /// Gets the number of unprocessed input bytes. Useful, if the end of the
  702. /// stream is reached and you want to further process the bytes after
  703. /// the deflate stream.
  704. /// </summary>
  705. /// <returns>
  706. /// The number of bytes of the input which have not been processed.
  707. /// </returns>
  708. public int RemainingInput {
  709. // TODO: This should be a long?
  710. get {
  711. return input.AvailableBytes;
  712. }
  713. }
  714. }
  715. }