Inflater.cs 23 KB

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