Deflater.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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
  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
  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
  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
  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. level = 6;
  155. } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
  156. throw new ArgumentOutOfRangeException("nameof(level)");
  157. }
  158. pending = new DeflaterPending();
  159. engine = new DeflaterEngine(pending);
  160. this.noZlibHeaderOrFooter = noZlibHeaderOrFooter;
  161. SetStrategy(DeflateStrategy.Default);
  162. SetLevel(level);
  163. Reset();
  164. }
  165. #endregion
  166. /// <summary>
  167. /// Resets the deflater. The deflater acts afterwards as if it was
  168. /// just created with the same compression level and strategy as it
  169. /// had before.
  170. /// </summary>
  171. public void Reset()
  172. {
  173. state = (noZlibHeaderOrFooter ? BUSY_STATE : INIT_STATE);
  174. totalOut = 0;
  175. pending.Reset();
  176. engine.Reset();
  177. }
  178. /// <summary>
  179. /// Gets the current adler checksum of the data that was processed so far.
  180. /// </summary>
  181. public int Adler {
  182. get {
  183. return engine.Adler;
  184. }
  185. }
  186. /// <summary>
  187. /// Gets the number of input bytes processed so far.
  188. /// </summary>
  189. public long TotalIn {
  190. get {
  191. return engine.TotalIn;
  192. }
  193. }
  194. /// <summary>
  195. /// Gets the number of output bytes so far.
  196. /// </summary>
  197. public long TotalOut {
  198. get {
  199. return totalOut;
  200. }
  201. }
  202. /// <summary>
  203. /// Flushes the current input block. Further calls to deflate() will
  204. /// produce enough output to inflate everything in the current input
  205. /// block. This is not part of Sun's JDK so I have made it package
  206. /// private. It is used by DeflaterOutputStream to implement
  207. /// flush().
  208. /// </summary>
  209. public void Flush()
  210. {
  211. state |= IS_FLUSHING;
  212. }
  213. /// <summary>
  214. /// Finishes the deflater with the current input block. It is an error
  215. /// to give more input after this method was called. This method must
  216. /// be called to force all bytes to be flushed.
  217. /// </summary>
  218. public void Finish()
  219. {
  220. state |= (IS_FLUSHING | IS_FINISHING);
  221. }
  222. /// <summary>
  223. /// Returns true if the stream was finished and no more output bytes
  224. /// are available.
  225. /// </summary>
  226. public bool IsFinished {
  227. get {
  228. return (state == FINISHED_STATE) && pending.IsFlushed;
  229. }
  230. }
  231. /// <summary>
  232. /// Returns true, if the input buffer is empty.
  233. /// You should then call setInput().
  234. /// NOTE: This method can also return true when the stream
  235. /// was finished.
  236. /// </summary>
  237. public bool IsNeedingInput {
  238. get {
  239. return engine.NeedsInput();
  240. }
  241. }
  242. /// <summary>
  243. /// Sets the data which should be compressed next. This should be only
  244. /// called when needsInput indicates that more input is needed.
  245. /// If you call setInput when needsInput() returns false, the
  246. /// previous input that is still pending will be thrown away.
  247. /// The given byte array should not be changed, before needsInput() returns
  248. /// true again.
  249. /// This call is equivalent to <code>setInput(input, 0, input.length)</code>.
  250. /// </summary>
  251. /// <param name="input">
  252. /// the buffer containing the input data.
  253. /// </param>
  254. /// <exception cref="System.InvalidOperationException">
  255. /// if the buffer was finished() or ended().
  256. /// </exception>
  257. public void SetInput(byte[] input)
  258. {
  259. SetInput(input, 0, input.Length);
  260. }
  261. /// <summary>
  262. /// Sets the data which should be compressed next. This should be
  263. /// only called when needsInput indicates that more input is needed.
  264. /// The given byte array should not be changed, before needsInput() returns
  265. /// true again.
  266. /// </summary>
  267. /// <param name="input">
  268. /// the buffer containing the input data.
  269. /// </param>
  270. /// <param name="offset">
  271. /// the start of the data.
  272. /// </param>
  273. /// <param name="count">
  274. /// the number of data bytes of input.
  275. /// </param>
  276. /// <exception cref="System.InvalidOperationException">
  277. /// if the buffer was Finish()ed or if previous input is still pending.
  278. /// </exception>
  279. public void SetInput(byte[] input, int offset, int count)
  280. {
  281. if ((state & IS_FINISHING) != 0) {
  282. throw new InvalidOperationException("Finish() already called");
  283. }
  284. engine.SetInput(input, offset, count);
  285. }
  286. /// <summary>
  287. /// Sets the compression level. There is no guarantee of the exact
  288. /// position of the change, but if you call this when needsInput is
  289. /// true the change of compression level will occur somewhere near
  290. /// before the end of the so far given input.
  291. /// </summary>
  292. /// <param name="level">
  293. /// the new compression level.
  294. /// </param>
  295. public void SetLevel(int level)
  296. {
  297. if (level == DEFAULT_COMPRESSION) {
  298. level = 6;
  299. } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) {
  300. throw new ArgumentOutOfRangeException("nameof(level)");
  301. }
  302. if (this.level != level) {
  303. this.level = level;
  304. engine.SetLevel(level);
  305. }
  306. }
  307. /// <summary>
  308. /// Get current compression level
  309. /// </summary>
  310. /// <returns>Returns the current compression level</returns>
  311. public int GetLevel()
  312. {
  313. return level;
  314. }
  315. /// <summary>
  316. /// Sets the compression strategy. Strategy is one of
  317. /// DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact
  318. /// position where the strategy is changed, the same as for
  319. /// SetLevel() applies.
  320. /// </summary>
  321. /// <param name="strategy">
  322. /// The new compression strategy.
  323. /// </param>
  324. public void SetStrategy(DeflateStrategy strategy)
  325. {
  326. engine.Strategy = strategy;
  327. }
  328. /// <summary>
  329. /// Deflates the current input block with to the given array.
  330. /// </summary>
  331. /// <param name="output">
  332. /// The buffer where compressed data is stored
  333. /// </param>
  334. /// <returns>
  335. /// The number of compressed bytes added to the output, or 0 if either
  336. /// IsNeedingInput() or IsFinished returns true or length is zero.
  337. /// </returns>
  338. public int Deflate(byte[] output)
  339. {
  340. return Deflate(output, 0, output.Length);
  341. }
  342. /// <summary>
  343. /// Deflates the current input block to the given array.
  344. /// </summary>
  345. /// <param name="output">
  346. /// Buffer to store the compressed data.
  347. /// </param>
  348. /// <param name="offset">
  349. /// Offset into the output array.
  350. /// </param>
  351. /// <param name="length">
  352. /// The maximum number of bytes that may be stored.
  353. /// </param>
  354. /// <returns>
  355. /// The number of compressed bytes added to the output, or 0 if either
  356. /// needsInput() or finished() returns true or length is zero.
  357. /// </returns>
  358. /// <exception cref="System.InvalidOperationException">
  359. /// If Finish() was previously called.
  360. /// </exception>
  361. /// <exception cref="System.ArgumentOutOfRangeException">
  362. /// If offset or length don't match the array length.
  363. /// </exception>
  364. public int Deflate(byte[] output, int offset, int length)
  365. {
  366. int origLength = length;
  367. if (state == CLOSED_STATE) {
  368. throw new InvalidOperationException("Deflater closed");
  369. }
  370. if (state < BUSY_STATE) {
  371. // output header
  372. int header = (DEFLATED +
  373. ((DeflaterConstants.MAX_WBITS - 8) << 4)) << 8;
  374. int level_flags = (level - 1) >> 1;
  375. if (level_flags < 0 || level_flags > 3) {
  376. level_flags = 3;
  377. }
  378. header |= level_flags << 6;
  379. if ((state & IS_SETDICT) != 0) {
  380. // Dictionary was set
  381. header |= DeflaterConstants.PRESET_DICT;
  382. }
  383. header += 31 - (header % 31);
  384. pending.WriteShortMSB(header);
  385. if ((state & IS_SETDICT) != 0) {
  386. int chksum = engine.Adler;
  387. engine.ResetAdler();
  388. pending.WriteShortMSB(chksum >> 16);
  389. pending.WriteShortMSB(chksum & 0xffff);
  390. }
  391. state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING));
  392. }
  393. for (;;) {
  394. int count = pending.Flush(output, offset, length);
  395. offset += count;
  396. totalOut += count;
  397. length -= count;
  398. if (length == 0 || state == FINISHED_STATE) {
  399. break;
  400. }
  401. if (!engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) {
  402. switch (state) {
  403. case BUSY_STATE:
  404. // We need more input now
  405. return origLength - length;
  406. case FLUSHING_STATE:
  407. if (level != NO_COMPRESSION) {
  408. /* We have to supply some lookahead. 8 bit lookahead
  409. * is needed by the zlib inflater, and we must fill
  410. * the next byte, so that all bits are flushed.
  411. */
  412. int neededbits = 8 + ((-pending.BitCount) & 7);
  413. while (neededbits > 0) {
  414. /* write a static tree block consisting solely of
  415. * an EOF:
  416. */
  417. pending.WriteBits(2, 10);
  418. neededbits -= 10;
  419. }
  420. }
  421. state = BUSY_STATE;
  422. break;
  423. case FINISHING_STATE:
  424. pending.AlignToByte();
  425. // Compressed data is complete. Write footer information if required.
  426. if (!noZlibHeaderOrFooter) {
  427. int adler = engine.Adler;
  428. pending.WriteShortMSB(adler >> 16);
  429. pending.WriteShortMSB(adler & 0xffff);
  430. }
  431. state = FINISHED_STATE;
  432. break;
  433. }
  434. }
  435. }
  436. return origLength - length;
  437. }
  438. /// <summary>
  439. /// Sets the dictionary which should be used in the deflate process.
  440. /// This call is equivalent to <code>setDictionary(dict, 0, dict.Length)</code>.
  441. /// </summary>
  442. /// <param name="dictionary">
  443. /// the dictionary.
  444. /// </param>
  445. /// <exception cref="System.InvalidOperationException">
  446. /// if SetInput () or Deflate () were already called or another dictionary was already set.
  447. /// </exception>
  448. public void SetDictionary(byte[] dictionary)
  449. {
  450. SetDictionary(dictionary, 0, dictionary.Length);
  451. }
  452. /// <summary>
  453. /// Sets the dictionary which should be used in the deflate process.
  454. /// The dictionary is a byte array containing strings that are
  455. /// likely to occur in the data which should be compressed. The
  456. /// dictionary is not stored in the compressed output, only a
  457. /// checksum. To decompress the output you need to supply the same
  458. /// dictionary again.
  459. /// </summary>
  460. /// <param name="dictionary">
  461. /// The dictionary data
  462. /// </param>
  463. /// <param name="index">
  464. /// The index where dictionary information commences.
  465. /// </param>
  466. /// <param name="count">
  467. /// The number of bytes in the dictionary.
  468. /// </param>
  469. /// <exception cref="System.InvalidOperationException">
  470. /// If SetInput () or Deflate() were already called or another dictionary was already set.
  471. /// </exception>
  472. public void SetDictionary(byte[] dictionary, int index, int count)
  473. {
  474. if (state != INIT_STATE) {
  475. throw new InvalidOperationException();
  476. }
  477. state = SETDICT_STATE;
  478. engine.SetDictionary(dictionary, index, count);
  479. }
  480. #region Instance Fields
  481. /// <summary>
  482. /// Compression level.
  483. /// </summary>
  484. int level;
  485. /// <summary>
  486. /// If true no Zlib/RFC1950 headers or footers are generated
  487. /// </summary>
  488. bool noZlibHeaderOrFooter;
  489. /// <summary>
  490. /// The current state.
  491. /// </summary>
  492. int state;
  493. /// <summary>
  494. /// The total bytes of output written.
  495. /// </summary>
  496. long totalOut;
  497. /// <summary>
  498. /// The pending output.
  499. /// </summary>
  500. DeflaterPending pending;
  501. /// <summary>
  502. /// The deflater engine.
  503. /// </summary>
  504. DeflaterEngine engine;
  505. #endregion
  506. }
  507. }