Deflater.cs 16 KB

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