PageRenderTime 56ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/Languages/IronPython/IronPython.Modules/zlib/zlib.net/Inflate.cs

http://github.com/IronLanguages/main
C# | 675 lines | 401 code | 102 blank | 172 comment | 137 complexity | 2bfbd98d8d1447bc1615c582dca74592 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception
  1. // Copyright (c) 2006, ComponentAce
  2. // http://www.componentace.com
  3. // All rights reserved.
  4. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
  5. // Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  6. // Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  7. // Neither the name of ComponentAce nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
  8. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  9. /*
  10. Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved.
  11. Redistribution and use in source and binary forms, with or without
  12. modification, are permitted provided that the following conditions are met:
  13. 1. Redistributions of source code must retain the above copyright notice,
  14. this list of conditions and the following disclaimer.
  15. 2. Redistributions in binary form must reproduce the above copyright
  16. notice, this list of conditions and the following disclaimer in
  17. the documentation and/or other materials provided with the distribution.
  18. 3. The names of the authors may not be used to endorse or promote products
  19. derived from this software without specific prior written permission.
  20. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
  21. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  22. FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JCRAFT,
  23. INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  26. OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27. LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  29. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /*
  32. * This program is based on zlib-1.1.3, so all credit should go authors
  33. * Jean-loup Gailly(jloup@gzip.org) and Mark Adler(madler@alumni.caltech.edu)
  34. * and contributors of zlib.
  35. */
  36. using System;
  37. using System.Collections.Generic;
  38. namespace ComponentAce.Compression.Libs.ZLib
  39. {
  40. /// <summary>
  41. /// This enumeration contains modes of inflate processing
  42. /// </summary>
  43. internal enum InflateMode
  44. {
  45. /// <summary>
  46. /// waiting for method byte
  47. /// </summary>
  48. METHOD = 0,
  49. /// <summary>
  50. /// waiting for flag byte
  51. /// </summary>
  52. FLAG = 1,
  53. /// <summary>
  54. /// four dictionary check bytes to go
  55. /// </summary>
  56. DICT4 = 2,
  57. /// <summary>
  58. /// three dictionary check bytes to go
  59. /// </summary>
  60. DICT3 = 3,
  61. /// <summary>
  62. /// two dictionary check bytes to go
  63. /// </summary>
  64. DICT2 = 4,
  65. /// <summary>
  66. /// one dictionary check byte to go
  67. /// </summary>
  68. DICT1 = 5,
  69. /// <summary>
  70. /// waiting for inflateSetDictionary
  71. /// </summary>
  72. DICT0 = 6,
  73. /// <summary>
  74. /// decompressing blocks
  75. /// </summary>
  76. BLOCKS = 7,
  77. /// <summary>
  78. /// four check bytes to go
  79. /// </summary>
  80. CHECK4 = 8,
  81. /// <summary>
  82. /// three check bytes to go
  83. /// </summary>
  84. CHECK3 = 9,
  85. /// <summary>
  86. /// two check bytes to go
  87. /// </summary>
  88. CHECK2 = 10,
  89. /// <summary>
  90. /// one check byte to go
  91. /// </summary>
  92. CHECK1 = 11,
  93. /// <summary>
  94. /// finished check, done
  95. /// </summary>
  96. DONE = 12,
  97. /// <summary>
  98. /// got an error--stay here
  99. /// </summary>
  100. BAD = 13
  101. }
  102. internal sealed class Inflate
  103. {
  104. #region Fields
  105. /// <summary>
  106. /// current inflate mode
  107. /// </summary>
  108. public InflateMode mode;
  109. #region mode dependent information
  110. /// <summary>
  111. /// if FLAGS, method byte
  112. /// </summary>
  113. private int method;
  114. // if CHECK, check values to compare
  115. /// <summary>
  116. /// computed check value
  117. /// </summary>
  118. private long[] was = new long[1];
  119. /// <summary>
  120. /// stream check value
  121. /// </summary>
  122. private long need;
  123. /// <summary>
  124. /// if BAD, inflateSync's marker bytes count
  125. /// </summary>
  126. private int marker;
  127. #endregion
  128. #region mode independent information
  129. /// <summary>
  130. /// flag for no wrapper
  131. /// </summary>
  132. private int nowrap;
  133. /// <summary>
  134. /// log2(Window size) (8..15, defaults to 15)
  135. /// </summary>
  136. private int wbits;
  137. private IEnumerator<object> gzipHeaderRemover;
  138. private bool detectHeader;
  139. #endregion
  140. /// <summary>
  141. /// current inflate_blocks state
  142. /// </summary>
  143. private InfBlocks blocks;
  144. #endregion
  145. #region Methods
  146. /// <summary>
  147. /// Resets the Inflate algorithm
  148. /// </summary>
  149. /// <param name="z">A ZStream object</param>
  150. /// <returns>A result code</returns>
  151. internal int inflateReset(ZStream z)
  152. {
  153. if (z == null || z.istate == null)
  154. return (int)ZLibResultCode.Z_STREAM_ERROR;
  155. z.total_in = z.total_out = 0;
  156. z.msg = null;
  157. z.istate.mode = z.istate.nowrap != 0? InflateMode.BLOCKS: InflateMode.METHOD;
  158. z.istate.blocks.reset(z, null);
  159. return (int)ZLibResultCode.Z_OK;
  160. }
  161. /// <summary>
  162. /// Finishes the inflate algorithm processing
  163. /// </summary>
  164. /// <param name="z">A ZStream object</param>
  165. /// <returns>Operation result code</returns>
  166. internal int inflateEnd(ZStream z)
  167. {
  168. if (blocks != null)
  169. blocks.free(z);
  170. blocks = null;
  171. // ZFREE(z, z->state);
  172. return (int)ZLibResultCode.Z_OK;
  173. }
  174. /// <summary>
  175. /// Initializes the inflate algorithm
  176. /// </summary>
  177. /// <param name="z">A ZStream object</param>
  178. /// <param name="windowBits">Window size</param>
  179. /// <returns>Operation result code</returns>
  180. internal int inflateInit(ZStream z, int windowBits)
  181. {
  182. z.msg = null;
  183. blocks = null;
  184. // handle undocumented nowrap option (no zlib header or check)
  185. nowrap = 0;
  186. detectHeader = false;
  187. if (windowBits < 0)
  188. {
  189. // deflate, no header
  190. windowBits = - windowBits;
  191. nowrap = 1;
  192. }
  193. else if ((windowBits & 16) != 0)
  194. {
  195. gzipHeaderRemover = GzipHeader.CreateRemover(z);
  196. windowBits &= ~16;
  197. }
  198. else if ((windowBits & 32) != 0)
  199. {
  200. detectHeader = true;
  201. windowBits &= ~32;
  202. }
  203. // set Window size
  204. if (windowBits < 8 || windowBits > 15)
  205. {
  206. inflateEnd(z);
  207. return (int)ZLibResultCode.Z_STREAM_ERROR;
  208. }
  209. wbits = windowBits;
  210. z.istate.blocks = new InfBlocks(z, z.istate.nowrap == 0, 1 << windowBits);
  211. // reset state
  212. inflateReset(z);
  213. return (int)ZLibResultCode.Z_OK;
  214. }
  215. /// <summary>
  216. /// Runs inflate algorithm
  217. /// </summary>
  218. /// <param name="z">A ZStream object</param>
  219. /// <param name="flush">Flush strategy</param>
  220. /// <returns>Operation result code</returns>
  221. internal int inflate(ZStream z, FlushStrategy flush)
  222. {
  223. int r;
  224. int b;
  225. int internalFlush = (int)flush;
  226. int res_temp;
  227. if (z == null || z.istate == null || z.next_in == null)
  228. return (int)ZLibResultCode.Z_STREAM_ERROR;
  229. res_temp = internalFlush == (int)FlushStrategy.Z_FINISH ? (int)ZLibResultCode.Z_BUF_ERROR : (int)ZLibResultCode.Z_OK;
  230. r = (int)ZLibResultCode.Z_BUF_ERROR;
  231. if (detectHeader)
  232. {
  233. if (z.avail_in == 0)
  234. return r;
  235. if (z.next_in[z.next_in_index] == 0x1F)
  236. gzipHeaderRemover = GzipHeader.CreateRemover(z);
  237. detectHeader = false;
  238. }
  239. if (gzipHeaderRemover != null)
  240. {
  241. if (z.avail_in == 0)
  242. return r;
  243. if (gzipHeaderRemover.MoveNext())
  244. return r;
  245. gzipHeaderRemover = null;
  246. z.istate.mode = InflateMode.BLOCKS;
  247. z.istate.blocks.needCheck = false;
  248. nowrap = 1;
  249. }
  250. while (true)
  251. {
  252. switch (z.istate.mode)
  253. {
  254. case InflateMode.METHOD:
  255. if (z.avail_in == 0)
  256. return r; r = res_temp;
  257. z.avail_in--; z.total_in++;
  258. if (((z.istate.method = z.next_in[z.next_in_index++]) & 0xf) != ZLibUtil.Z_DEFLATED)
  259. {
  260. z.istate.mode = InflateMode.BAD;
  261. z.msg = "unknown compression method";
  262. z.istate.marker = 5; // can't try inflateSync
  263. break;
  264. }
  265. if ((z.istate.method >> 4) + 8 > z.istate.wbits)
  266. {
  267. z.istate.mode = InflateMode.BAD;
  268. z.msg = "invalid Window size";
  269. z.istate.marker = 5; // can't try inflateSync
  270. break;
  271. }
  272. z.istate.mode = InflateMode.FLAG;
  273. goto case InflateMode.FLAG;
  274. case InflateMode.FLAG:
  275. if (z.avail_in == 0)
  276. return r; r = res_temp;
  277. z.avail_in--; z.total_in++;
  278. b = (z.next_in[z.next_in_index++]) & 0xff;
  279. if ((((z.istate.method << 8) + b) % 31) != 0)
  280. {
  281. z.istate.mode = InflateMode.BAD;
  282. z.msg = "incorrect header check";
  283. z.istate.marker = 5; // can't try inflateSync
  284. break;
  285. }
  286. if ((b & ZLibUtil.PRESET_DICT) == 0)
  287. {
  288. z.istate.mode = InflateMode.BLOCKS;
  289. break;
  290. }
  291. z.istate.mode = InflateMode.DICT4;
  292. goto case InflateMode.DICT4;
  293. case InflateMode.DICT4:
  294. if (z.avail_in == 0)
  295. return r; r = res_temp;
  296. z.avail_in--; z.total_in++;
  297. z.istate.need = ((long)(z.next_in[z.next_in_index++] & 0xff) << 24) & unchecked((int) 0xff000000L);
  298. z.istate.mode = InflateMode.DICT3;
  299. goto case InflateMode.DICT3;
  300. case InflateMode.DICT3:
  301. if (z.avail_in == 0)
  302. return r; r = res_temp;
  303. z.avail_in--; z.total_in++;
  304. z.istate.need += (((long)(z.next_in[z.next_in_index++] & 0xff) << 16) & 0xff0000L);
  305. z.istate.mode = InflateMode.DICT2;
  306. goto case InflateMode.DICT2;
  307. case InflateMode.DICT2:
  308. if (z.avail_in == 0)
  309. return r; r = res_temp;
  310. z.avail_in--; z.total_in++;
  311. z.istate.need += (((long)(z.next_in[z.next_in_index++] & 0xff) << 8) & 0xff00L);
  312. z.istate.mode = InflateMode.DICT1;
  313. goto case InflateMode.DICT1;
  314. case InflateMode.DICT1:
  315. if (z.avail_in == 0)
  316. return r; r = res_temp;
  317. z.avail_in--; z.total_in++;
  318. z.istate.need += (z.next_in[z.next_in_index++] & 0xffL);
  319. z.adler = z.istate.need;
  320. z.istate.mode = InflateMode.DICT0;
  321. return (int)ZLibResultCode.Z_NEED_DICT;
  322. case InflateMode.DICT0:
  323. z.istate.mode = InflateMode.BAD;
  324. z.msg = "need dictionary";
  325. z.istate.marker = 0; // can try inflateSync
  326. return (int)ZLibResultCode.Z_STREAM_ERROR;
  327. case InflateMode.BLOCKS:
  328. r = z.istate.blocks.proc(z, r);
  329. if (r == (int)ZLibResultCode.Z_DATA_ERROR)
  330. {
  331. z.istate.mode = InflateMode.BAD;
  332. z.istate.marker = 0; // can try inflateSync
  333. break;
  334. }
  335. if (r == (int)ZLibResultCode.Z_OK)
  336. {
  337. r = res_temp;
  338. }
  339. if (r != (int)ZLibResultCode.Z_STREAM_END)
  340. {
  341. return r;
  342. }
  343. r = res_temp;
  344. z.istate.blocks.reset(z, z.istate.was);
  345. if (z.istate.nowrap != 0)
  346. {
  347. z.istate.mode = InflateMode.DONE;
  348. break;
  349. }
  350. z.istate.mode = InflateMode.CHECK4;
  351. goto case InflateMode.CHECK4;
  352. case InflateMode.CHECK4:
  353. if (z.avail_in == 0)
  354. return r; r = res_temp;
  355. z.avail_in--; z.total_in++;
  356. z.istate.need = ((z.next_in[z.next_in_index++] & 0xff) << 24) & unchecked((int) 0xff000000L);
  357. z.istate.mode = InflateMode.CHECK3;
  358. goto case InflateMode.CHECK3;
  359. case InflateMode.CHECK3:
  360. if (z.avail_in == 0)
  361. return r; r = res_temp;
  362. z.avail_in--; z.total_in++;
  363. z.istate.need += (((z.next_in[z.next_in_index++] & 0xff) << 16) & 0xff0000L);
  364. z.istate.mode = InflateMode.CHECK2;
  365. goto case InflateMode.CHECK2;
  366. case InflateMode.CHECK2:
  367. if (z.avail_in == 0)
  368. return r; r = res_temp;
  369. z.avail_in--; z.total_in++;
  370. z.istate.need += (((z.next_in[z.next_in_index++] & 0xff) << 8) & 0xff00L);
  371. z.istate.mode = InflateMode.CHECK1;
  372. goto case InflateMode.CHECK1;
  373. case InflateMode.CHECK1:
  374. if (z.avail_in == 0)
  375. return r; r = res_temp;
  376. z.avail_in--; z.total_in++;
  377. z.istate.need += (z.next_in[z.next_in_index++] & 0xffL);
  378. if (unchecked(((int) (z.istate.was[0])) != ((int) (z.istate.need))))
  379. {
  380. z.istate.mode = InflateMode.BAD;
  381. z.msg = "incorrect data check";
  382. z.istate.marker = 5; // can't try inflateSync
  383. break;
  384. }
  385. z.istate.mode = InflateMode.DONE;
  386. goto case InflateMode.DONE;
  387. case InflateMode.DONE:
  388. return (int)ZLibResultCode.Z_STREAM_END;
  389. case InflateMode.BAD:
  390. return (int)ZLibResultCode.Z_DATA_ERROR;
  391. default:
  392. return (int)ZLibResultCode.Z_STREAM_ERROR;
  393. }
  394. }
  395. }
  396. /// <summary>
  397. /// Sets dictionary for the inflate operation
  398. /// </summary>
  399. /// <param name="z">A ZStream object</param>
  400. /// <param name="dictionary">An array of byte - dictionary</param>
  401. /// <param name="dictLength">Dictionary length</param>
  402. /// <returns>Operation result code</returns>
  403. internal int inflateSetDictionary(ZStream z, byte[] dictionary, int dictLength)
  404. {
  405. int index = 0;
  406. int length = dictLength;
  407. if (z == null || z.istate == null || z.istate.mode != InflateMode.DICT0)
  408. return (int)ZLibResultCode.Z_STREAM_ERROR;
  409. if (Adler32.GetAdler32Checksum(1L, dictionary, 0, dictLength) != z.adler)
  410. {
  411. return (int)ZLibResultCode.Z_DATA_ERROR;
  412. }
  413. z.adler = Adler32.GetAdler32Checksum(0, null, 0, 0);
  414. if (length >= (1 << z.istate.wbits))
  415. {
  416. length = (1 << z.istate.wbits) - 1;
  417. index = dictLength - length;
  418. }
  419. z.istate.blocks.set_dictionary(dictionary, index, length);
  420. z.istate.mode = InflateMode.BLOCKS;
  421. return (int)ZLibResultCode.Z_OK;
  422. }
  423. /// <summary>
  424. /// Inflate synchronization
  425. /// </summary>
  426. /// <param name="z">A ZStream object</param>
  427. /// <returns>Operation result code</returns>
  428. internal int inflateSync(ZStream z)
  429. {
  430. int n; // number of bytes to look at
  431. int p; // pointer to bytes
  432. int m; // number of marker bytes found in a row
  433. long r, w; // temporaries to save _total_in and _total_out
  434. // set up
  435. if (z == null || z.istate == null)
  436. return (int)ZLibResultCode.Z_STREAM_ERROR;
  437. if (z.istate.mode != InflateMode.BAD)
  438. {
  439. z.istate.mode = InflateMode.BAD;
  440. z.istate.marker = 0;
  441. }
  442. if ((n = z.avail_in) == 0)
  443. return (int)ZLibResultCode.Z_BUF_ERROR;
  444. p = z.next_in_index;
  445. m = z.istate.marker;
  446. // search
  447. while (n != 0 && m < 4)
  448. {
  449. if (z.next_in[p] == ZLibUtil.mark[m])
  450. {
  451. m++;
  452. }
  453. else if (z.next_in[p] != 0)
  454. {
  455. m = 0;
  456. }
  457. else
  458. {
  459. m = 4 - m;
  460. }
  461. p++; n--;
  462. }
  463. // restore
  464. z.total_in += p - z.next_in_index;
  465. z.next_in_index = p;
  466. z.avail_in = n;
  467. z.istate.marker = m;
  468. // return no joy or set up to restart on a new block
  469. if (m != 4)
  470. {
  471. return (int)ZLibResultCode.Z_DATA_ERROR;
  472. }
  473. r = z.total_in; w = z.total_out;
  474. inflateReset(z);
  475. z.total_in = r; z.total_out = w;
  476. z.istate.mode = InflateMode.BLOCKS;
  477. return (int)ZLibResultCode.Z_OK;
  478. }
  479. ///<summary>
  480. /// Returns true if inflate is currently at the End of a block generated
  481. /// by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
  482. /// implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH
  483. /// but removes the length bytes of the resulting empty stored block. When
  484. /// decompressing, PPP checks that at the End of input packet, inflate is
  485. /// waiting for these length bytes.
  486. /// </summary>
  487. internal int inflateSyncPoint(ZStream z)
  488. {
  489. if (z == null || z.istate == null || z.istate.blocks == null)
  490. return (int)ZLibResultCode.Z_STREAM_ERROR;
  491. return z.istate.blocks.sync_point();
  492. }
  493. #endregion
  494. }
  495. internal class GzipHeader {
  496. /// <summary>
  497. /// Creates header remover.
  498. /// As long as header is not completed, call to Remover.MoveNext() returns true and
  499. /// adjust state of z.
  500. /// </summary>
  501. /// <param name="z">Stream where gzip header will appear.</param>
  502. /// <returns></returns>
  503. public static IEnumerator<object> CreateRemover(ZStream z) {
  504. return new GzipHeader().StartHeaderSkipping(z).GetEnumerator();
  505. }
  506. [Flags]
  507. private enum HEADER_FLAG {
  508. // FTEXT = 1,
  509. FHCRC = 2,
  510. FEXTRA = 4,
  511. FNAME = 8,
  512. FCOMMENT = 16
  513. }
  514. private const int FIXED_HEADER_SIZE = 10;
  515. private byte GetNext(ZStream z) {
  516. z.avail_in--;
  517. z.total_in++;
  518. return z.next_in[z.next_in_index++];
  519. }
  520. private IEnumerable<object> StartHeaderSkipping(ZStream z) {
  521. var headerCollector = new List<byte>(FIXED_HEADER_SIZE);
  522. do {
  523. if (z.avail_in == 0)
  524. yield return false;
  525. headerCollector.Add(GetNext(z));
  526. } while (headerCollector.Count < FIXED_HEADER_SIZE);
  527. var flag = headerCollector[3];
  528. if (0 != (flag & (byte)HEADER_FLAG.FEXTRA)) {
  529. if (z.avail_in == 0)
  530. yield return null;
  531. var outstandingSize = (int)GetNext(z);
  532. if (z.avail_in == 0)
  533. yield return null;
  534. outstandingSize += 256 * GetNext(z);
  535. do {
  536. if (z.avail_in == 0)
  537. yield return null;
  538. GetNext(z);
  539. } while (--outstandingSize != 0);
  540. }
  541. // STATE_NAME
  542. if (0 != (flag & (byte)HEADER_FLAG.FNAME)) {
  543. do {
  544. if (z.avail_in == 0) {
  545. yield return null;
  546. }
  547. } while (GetNext(z) != 0);
  548. }
  549. // STATE_COMMENT:
  550. if (0 != (flag & (byte)HEADER_FLAG.FCOMMENT)) {
  551. do {
  552. if (z.avail_in == 0)
  553. yield return null;
  554. } while (GetNext(z) != 0);
  555. }
  556. // STATE_CRC:
  557. if (0 != (flag & (byte)HEADER_FLAG.FHCRC)) {
  558. var outstandingSize = 4;
  559. do {
  560. if (z.avail_in == 0) {
  561. yield return null;
  562. }
  563. GetNext(z);
  564. } while (--outstandingSize != 0);
  565. }
  566. }
  567. }
  568. }