Deflater.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. using System;
  2. namespace System.Net.ApiService.Compression.Zip.Compression {
  3. /// <summary>
  4. /// This is the Deflater class. The deflater class compresses input
  5. /// with the deflate algorithm described in RFC 1951. It has several
  6. /// compression levels and three different strategies described below.
  7. ///
  8. /// This class is <i>not</i> thread safe. This is inherent in the API, due
  9. /// to the split of deflate and setInput.
  10. ///
  11. /// author of the original java version : Jochen Hoenicke
  12. /// </summary>
  13. public class Deflater
  14. {
  15. #region Deflater Documentation
  16. /*
  17. * The Deflater can do the following state transitions:
  18. *
  19. * (1) -> INIT_STATE ----> INIT_FINISHING_STATE ---.
  20. * / | (2) (5) |
  21. * / v (5) |
  22. * (3)| SETDICT_STATE ---> SETDICT_FINISHING_STATE |(3)
  23. * \ | (3) | ,--------'
  24. * | | | (3) /
  25. * v v (5) v v
  26. * (1) -> BUSY_STATE ----> FINISHING_STATE
  27. * | (6)
  28. * v
  29. * FINISHED_STATE
  30. * \_____________________________________/
  31. * | (7)
  32. * v
  33. * CLOSED_STATE
  34. *
  35. * (1) If we should produce a header we start in INIT_STATE, otherwise
  36. * we start in BUSY_STATE.
  37. * (2) A dictionary may be set only when we are in INIT_STATE, then
  38. * we change the state as indicated.
  39. * (3) Whether a dictionary is set or not, on the first call of deflate
  40. * we change to BUSY_STATE.
  41. * (4) -- intentionally left blank -- :)
  42. * (5) FINISHING_STATE is entered, when flush() is called to indicate that
  43. * there is no more INPUT. There are also states indicating, that
  44. * the header wasn't written yet.
  45. * (6) FINISHED_STATE is entered, when everything has been flushed to the
  46. * internal pending output buffer.
  47. * (7) At any time (7)
  48. *
  49. */
  50. #endregion Deflater Documentation
  51. #region Public Constants
  52. /// <summary>
  53. /// The best and slowest compression level. This tries to find very
  54. /// long and distant string repetitions.
  55. /// </summary>
  56. public const int BEST_COMPRESSION = 9;
  57. /// <summary>
  58. /// The worst but fastest compression level.
  59. /// </summary>
  60. public const int BEST_SPEED = 1;
  61. /// <summary>
  62. /// The default compression level.
  63. /// </summary>
  64. public const int DEFAULT_COMPRESSION = -1;
  65. /// <summary>
  66. /// This level won't compress at all but output uncompressed blocks.
  67. /// </summary>
  68. public const int NO_COMPRESSION = 0;
  69. /// <summary>
  70. /// The compression method. This is the only method supported so far.
  71. /// There is no need to use this constant at all.
  72. /// </summary>
  73. public const int DEFLATED = 8;
  74. #endregion Public Constants
  75. #region Public Enum
  76. /// <summary>
  77. /// Compression Level as an enum for safer use
  78. /// </summary>
  79. public enum CompressionLevel
  80. {
  81. /// <summary>
  82. /// The best and slowest compression level. This tries to find very
  83. /// long and distant string repetitions.
  84. /// </summary>
  85. BEST_COMPRESSION = Deflater.BEST_COMPRESSION,
  86. /// <summary>
  87. /// The worst but fastest compression level.
  88. /// </summary>
  89. BEST_SPEED = Deflater.BEST_SPEED,
  90. /// <summary>
  91. /// The default compression level.
  92. /// </summary>
  93. DEFAULT_COMPRESSION = Deflater.DEFAULT_COMPRESSION,
  94. /// <summary>
  95. /// This level won't compress at all but output uncompressed blocks.
  96. /// </summary>
  97. NO_COMPRESSION = Deflater.NO_COMPRESSION,
  98. /// <summary>
  99. /// The compression method. This is the only method supported so far.
  100. /// There is no need to use this constant at all.
  101. /// </summary>
  102. DEFLATED = Deflater.DEFLATED
  103. }
  104. #endregion Public Enum
  105. #region Local Constants
  106. private const int IS_SETDICT = 0x01;
  107. private const int IS_FLUSHING = 0x04;
  108. private const int IS_FINISHING = 0x08;
  109. private const int INIT_STATE = 0x00;
  110. private const int SETDICT_STATE = 0x01;
  111. // private static int INIT_FINISHING_STATE = 0x08;
  112. // private static int SETDICT_FINISHING_STATE = 0x09;
  113. private const int BUSY_STATE = 0x10;
  114. private const int FLUSHING_STATE = 0x14;
  115. private const int FINISHING_STATE = 0x1c;
  116. private const int FINISHED_STATE = 0x1e;
  117. private const int CLOSED_STATE = 0x7f;
  118. #endregion Local Constants
  119. #region Constructors
  120. /// <summary>
  121. /// Creates a new deflater with default compression level.
  122. /// </summary>
  123. public Deflater() : this(DEFAULT_COMPRESSION, false)
  124. {
  125. }
  126. /// <summary>
  127. /// Creates a new deflater with given compression level.
  128. /// </summary>
  129. /// <param name="level">
  130. /// the compression level, a value between NO_COMPRESSION
  131. /// and BEST_COMPRESSION, or DEFAULT_COMPRESSION.
  132. /// </param>
  133. /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
  134. public Deflater(int level) : this(level, false)
  135. {
  136. }
  137. /// <summary>
  138. /// Creates a new deflater with given compression level.
  139. /// </summary>
  140. /// <param name="level">
  141. /// the compression level, a value between NO_COMPRESSION
  142. /// and BEST_COMPRESSION.
  143. /// </param>
  144. /// <param name="noZlibHeaderOrFooter">
  145. /// true, if we should suppress the Zlib/RFC1950 header at the
  146. /// beginning and the adler checksum at the end of the output. This is
  147. /// useful for the GZIP/PKZIP formats.
  148. /// </param>
  149. /// <exception cref="System.ArgumentOutOfRangeException">if lvl is out of range.</exception>
  150. public Deflater(int level, bool noZlibHeaderOrFooter)
  151. {
  152. if (level == DEFAULT_COMPRESSION)
  153. {
  154. level = 6;
  155. }
  156. else if (level < NO_COMPRESSION || level > BEST_COMPRESSION)
  157. {
  158. throw new ArgumentOutOfRangeException(nameof(level));
  159. }
  160. pending = new DeflaterPending();
  161. engine = new DeflaterEngine(pending, noZlibHeaderOrFooter);
  162. this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
  163. SetStrategy(DeflateStrategy.Default);
  164. SetLevel(level);
  165. Reset();
  166. }
  167. #endregion Constructors
  168. /// <summary>
  169. /// Resets the deflater. The deflater acts afterwards as if it was
  170. /// just created with the same compression level and strategy as it
  171. /// had before.
  172. /// </summary>
  173. public void Reset()
  174. {
  175. state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE);
  176. totalOut = 0;
  177. pending.Reset();
  178. engine.Reset();
  179. }
  180. /// <summary>
  181. /// Gets the current adler checksum of the data that was processed so far.
  182. /// </summary>
  183. public int Adler
  184. {
  185. get
  186. {
  187. return engine.Adler;
  188. }
  189. }
  190. /// <summary>
  191. /// Gets the number of input bytes processed so far.
  192. /// </summary>
  193. public long TotalIn
  194. {
  195. get
  196. {
  197. return engine.TotalIn;
  198. }
  199. }
  200. /// <summary>
  201. /// Gets the number of output bytes so far.
  202. /// </summary>
  203. public long TotalOut
  204. {
  205. get
  206. {
  207. return totalOut;
  208. }
  209. }
  210. /// <summary>
  211. /// Flushes the current input block. Further calls to deflate() will
  212. /// produce enough output to inflate everything in the current input
  213. /// block. This is not part of Sun's JDK so I have made it package
  214. /// private. It is used by DeflaterOutputStream to implement
  215. /// flush().
  216. /// </summary>
  217. public void Flush()
  218. {
  219. state |= IS_FLUSHING;
  220. }
  221. /// <summary>
  222. /// Finishes the deflater with the current input block. It is an error
  223. /// to give more input after this method was called. This method must
  224. /// be called to force all bytes to be flushed.
  225. /// </summary>
  226. public void Finish()
  227. {
  228. state |= (IS_FLUSHING | IS_FINISHING);
  229. }
  230. /// <summary>
  231. /// Returns true if the stream was finished and no more output bytes
  232. /// are available.
  233. /// </summary>
  234. public bool IsFinished
  235. {
  236. get
  237. {
  238. return (state == FINISHED_STATE) && pending.IsFlushed;
  239. }
  240. }
  241. /// <summary>
  242. /// Returns true, if the input buffer is empty.
  243. /// You should then call setInput().
  244. /// NOTE: This method can also return true when the stream
  245. /// was finished.
  246. /// </summary>
  247. public bool IsNeedingInput
  248. {
  249. get
  250. {
  251. return engine.NeedsInput();
  252. }
  253. }
  254. /// <summary>
  255. /// Sets the data which should be compressed next. This should be only
  256. /// called when needsInput indicates that more input is needed.
  257. /// If you call setInput when needsInput() returns false, the
  258. /// previous input that is still pending will be thrown away.
  259. /// The given byte array should not be changed, before needsInput() returns
  260. /// true again.
  261. /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
  262. /// </summary>
  263. /// <param name="input">
  264. /// the buffer containing the input data.
  265. /// </param>
  266. /// <exception cref="System.InvalidOperationException">
  267. /// if the buffer was finished() or ended().
  268. /// </exception>
  269. public void SetInput(byte[] input)
  270. {
  271. SetInput(input, 0, input.Length);
  272. }
  273. /// <summary>
  274. /// Sets the data which should be compressed next. This should be
  275. /// only called when needsInput indicates that more input is needed.
  276. /// The given byte array should not be changed, before needsInput() returns
  277. /// true again.
  278. /// </summary>
  279. /// <param name="input">
  280. /// the buffer containing the input data.
  281. /// </param>
  282. /// <param name="offset">
  283. /// the start of the data.
  284. /// </param>
  285. /// <param name="count">
  286. /// the number of data bytes of input.
  287. /// </param>
  288. /// <exception cref="System.InvalidOperationException">
  289. /// if the buffer was Finish()ed or if previous input is still pending.
  290. /// </exception>
  291. public void SetInput(byte[] input, int offset, int count)
  292. {
  293. if ((state & IS_FINISHING) != 0)
  294. {
  295. throw new InvalidOperationException("Finish() already called");
  296. }
  297. engine.SetInput(input, offset, count);
  298. }
  299. /// <summary>
  300. /// Sets the compression level. There is no guarantee of the exact
  301. /// position of the change, but if you call this when needsInput is
  302. /// true the change of compression level will occur somewhere near
  303. /// before the end of the so far given input.
  304. /// </summary>
  305. /// <param name="level">
  306. /// the new compression level.
  307. /// </param>
  308. public void SetLevel(int level)
  309. {
  310. if (level == DEFAULT_COMPRESSION)
  311. {
  312. level = 6;
  313. }
  314. else if (level < NO_COMPRESSION || level > BEST_COMPRESSION)
  315. {
  316. throw new ArgumentOutOfRangeException(nameof(level));
  317. }
  318. if (this.level != level)
  319. {
  320. this.level = level;
  321. engine.SetLevel(level);
  322. }
  323. }
  324. /// <summary>
  325. /// Get current compression level
  326. /// </summary>
  327. /// <returns>Returns the current compression level</returns>
  328. public int GetLevel()
  329. {
  330. return level;
  331. }
  332. /// <summary>
  333. /// Sets the compression strategy. Strategy is one of
  334. /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
  335. /// position where the strategy is changed, the same as for
  336. /// SetLevel() applies.
  337. /// </summary>
  338. /// <param name="strategy">
  339. /// The new compression strategy.
  340. /// </param>
  341. public void SetStrategy(DeflateStrategy strategy)
  342. {
  343. engine.Strategy = strategy;
  344. }
  345. /// <summary>
  346. /// Deflates the current input block with to the given array.
  347. /// </summary>
  348. /// <param name="output">
  349. /// The buffer where compressed data is stored
  350. /// </param>
  351. /// <returns>
  352. /// The number of compressed bytes added to the output, or 0 if either
  353. /// IsNeedingInput() or IsFinished returns true or length is zero.
  354. /// </returns>
  355. public int Deflate(byte[] output)
  356. {
  357. return Deflate(output, 0, output.Length);
  358. }
  359. /// <summary>
  360. /// Deflates the current input block to the given array.
  361. /// </summary>
  362. /// <param name="output">
  363. /// Buffer to store the compressed data.
  364. /// </param>
  365. /// <param name="offset">
  366. /// Offset into the output array.
  367. /// </param>
  368. /// <param name="length">
  369. /// The maximum number of bytes that may be stored.
  370. /// </param>
  371. /// <returns>
  372. /// The number of compressed bytes added to the output, or 0 if either
  373. /// needsInput() or finished() returns true or length is zero.
  374. /// </returns>
  375. /// <exception cref="System.InvalidOperationException">
  376. /// If Finish() was previously called.
  377. /// </exception>
  378. /// <exception cref="System.ArgumentOutOfRangeException">
  379. /// If offset or length don't match the array length.
  380. /// </exception>
  381. public int Deflate(byte[] output, int offset, int length)
  382. {
  383. int origLength = length;
  384. if (state == CLOSED_STATE)
  385. {
  386. throw new InvalidOperationException("Deflater closed");
  387. }
  388. if (state < BUSY_STATE)
  389. {
  390. // output header
  391. int header = (DEFLATED +
  392. ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
  393. int level_flags = (level - 1) >> 1;
  394. if (level_flags < 0 || level_flags > 3)
  395. {
  396. level_flags = 3;
  397. }
  398. header |= level_flags << 6;
  399. if ((state & IS_SETDICT) != 0)
  400. {
  401. // Dictionary was set
  402. header |= DeflaterConstants.PRESET_DICT;
  403. }
  404. header += 31 - (header % 31);
  405. pending.WriteShortMSB(header);
  406. if ((state & IS_SETDICT) != 0)
  407. {
  408. int chksum = engine.Adler;
  409. engine.ResetAdler();
  410. pending.WriteShortMSB(chksum >> 16);
  411. pending.WriteShortMSB(chksum & 0xffff);
  412. }
  413. state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
  414. }
  415. for (; ; )
  416. {
  417. int count = pending.Flush(output, offset, length);
  418. offset += count;
  419. totalOut += count;
  420. length -= count;
  421. if (length == 0 || state == FINISHED_STATE)
  422. {
  423. break;
  424. }
  425. if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0))
  426. {
  427. switch (state)
  428. {
  429. case BUSY_STATE:
  430. // We need more input now
  431. return origLength - length;
  432. case FLUSHING_STATE:
  433. if (level != NO_COMPRESSION)
  434. {
  435. /* We have to supply some lookahead. 8 bit lookahead
  436. * is needed by the zlib inflater, and we must fill
  437. * the next byte, so that all bits are flushed.
  438. */
  439. int neededbits = 8 + ((-pending.BitCount) & 7);
  440. while (neededbits > 0)
  441. {
  442. /* write a static tree block consisting solely of
  443. * an EOF:
  444. */
  445. pending.WriteBits(2, 10);
  446. neededbits -= 10;
  447. }
  448. }
  449. state = BUSY_STATE;
  450. break;
  451. case FINISHING_STATE:
  452. pending.AlignToByte();
  453. // Compressed data is complete. Write footer information if required.
  454. if (!noZlibHeaderOrFooter)
  455. {
  456. int adler = engine.Adler;
  457. pending.WriteShortMSB(adler >> 16);
  458. pending.WriteShortMSB(adler & 0xffff);
  459. }
  460. state = FINISHED_STATE;
  461. break;
  462. }
  463. }
  464. }
  465. return origLength - length;
  466. }
  467. /// <summary>
  468. /// Sets the dictionary which should be used in the deflate process.
  469. /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
  470. /// </summary>
  471. /// <param name="dictionary">
  472. /// the dictionary.
  473. /// </param>
  474. /// <exception cref="System.InvalidOperationException">
  475. /// if SetInput () or Deflate () were already called or another dictionary was already set.
  476. /// </exception>
  477. public void SetDictionary(byte[] dictionary)
  478. {
  479. SetDictionary(dictionary, 0, dictionary.Length);
  480. }
  481. /// <summary>
  482. /// Sets the dictionary which should be used in the deflate process.
  483. /// The dictionary is a byte array containing strings that are
  484. /// likely to occur in the data which should be compressed. The
  485. /// dictionary is not stored in the compressed output, only a
  486. /// checksum. To decompress the output you need to supply the same
  487. /// dictionary again.
  488. /// </summary>
  489. /// <param name="dictionary">
  490. /// The dictionary data
  491. /// </param>
  492. /// <param name="index">
  493. /// The index where dictionary information commences.
  494. /// </param>
  495. /// <param name="count">
  496. /// The number of bytes in the dictionary.
  497. /// </param>
  498. /// <exception cref="System.InvalidOperationException">
  499. /// If SetInput () or Deflate() were already called or another dictionary was already set.
  500. /// </exception>
  501. public void SetDictionary(byte[] dictionary, int index, int count)
  502. {
  503. if (state != INIT_STATE)
  504. {
  505. throw new InvalidOperationException();
  506. }
  507. state = SETDICT_STATE;
  508. engine.SetDictionary(dictionary, index, count);
  509. }
  510. #region Instance Fields
  511. /// <summary>
  512. /// Compression level.
  513. /// </summary>
  514. private int level;
  515. /// <summary>
  516. /// If true no Zlib/RFC1950 headers or footers are generated
  517. /// </summary>
  518. private bool noZlibHeaderOrFooter;
  519. /// <summary>
  520. /// The current state.
  521. /// </summary>
  522. private int state;
  523. /// <summary>
  524. /// The total bytes of output written.
  525. /// </summary>
  526. private long totalOut;
  527. /// <summary>
  528. /// The pending output.
  529. /// </summary>
  530. private DeflaterPending pending;
  531. /// <summary>
  532. /// The deflater engine.
  533. /// </summary>
  534. private DeflaterEngine engine;
  535. #endregion Instance Fields
  536. }
  537. }