Inflater.cs 23 KB

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