1. /*
  2. * @(#)Deflater.java 1.38 03/02/07
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.zip;
  8. /**
  9. * This class provides support for general purpose compression using the
  10. * popular ZLIB compression library. The ZLIB compression library was
  11. * initially developed as part of the PNG graphics standard and is not
  12. * protected by patents. It is fully described in the specifications at
  13. * the <a href="package-summary.html#package_description">java.util.zip
  14. * package description</a>.
  15. *
  16. * <p>The following code fragment demonstrates a trivial compression
  17. * and decompression of a string using <tt>Deflater</tt> and
  18. * <tt>Inflater</tt>.
  19. *
  20. * <blockquote><pre>
  21. * // Encode a String into bytes
  22. * String inputString = "blahblahblah\u20AC\u20AC";
  23. * byte[] input = inputString.getBytes("UTF-8");
  24. *
  25. * // Compress the bytes
  26. * byte[] output = new byte[100];
  27. * Deflater compresser = new Deflater();
  28. * compresser.setInput(input);
  29. * compresser.finish();
  30. * int compressedDataLength = compresser.deflate(output);
  31. *
  32. * // Decompress the bytes
  33. * Inflater decompresser = new Inflater();
  34. * decompresser.setInput(output, 0, compressedDataLength);
  35. * byte[] result = new byte[100];
  36. * int resultLength = decompresser.inflate(result);
  37. * decompresser.end();
  38. *
  39. * // Decode the bytes into a String
  40. * String outputString = new String(result, 0, resultLength, "UTF-8");
  41. * </pre></blockquote>
  42. *
  43. * @see Inflater
  44. * @version 1.38, 02/07/03
  45. * @author David Connelly
  46. */
  47. public
  48. class Deflater {
  49. private long strm;
  50. private byte[] buf = new byte[0];
  51. private int off, len;
  52. private int level, strategy;
  53. private boolean setParams;
  54. private boolean finish, finished;
  55. /**
  56. * Compression method for the deflate algorithm (the only one currently
  57. * supported).
  58. */
  59. public static final int DEFLATED = 8;
  60. /**
  61. * Compression level for no compression.
  62. */
  63. public static final int NO_COMPRESSION = 0;
  64. /**
  65. * Compression level for fastest compression.
  66. */
  67. public static final int BEST_SPEED = 1;
  68. /**
  69. * Compression level for best compression.
  70. */
  71. public static final int BEST_COMPRESSION = 9;
  72. /**
  73. * Default compression level.
  74. */
  75. public static final int DEFAULT_COMPRESSION = -1;
  76. /**
  77. * Compression strategy best used for data consisting mostly of small
  78. * values with a somewhat random distribution. Forces more Huffman coding
  79. * and less string matching.
  80. */
  81. public static final int FILTERED = 1;
  82. /**
  83. * Compression strategy for Huffman coding only.
  84. */
  85. public static final int HUFFMAN_ONLY = 2;
  86. /**
  87. * Default compression strategy.
  88. */
  89. public static final int DEFAULT_STRATEGY = 0;
  90. /*
  91. * Loads the ZLIB library.
  92. */
  93. static {
  94. java.security.AccessController.doPrivileged(
  95. new sun.security.action.LoadLibraryAction("zip"));
  96. initIDs();
  97. }
  98. /**
  99. * Creates a new compressor using the specified compression level.
  100. * If 'nowrap' is true then the ZLIB header and checksum fields will
  101. * not be used in order to support the compression format used in
  102. * both GZIP and PKZIP.
  103. * @param level the compression level (0-9)
  104. * @param nowrap if true then use GZIP compatible compression
  105. */
  106. public Deflater(int level, boolean nowrap) {
  107. this.level = level;
  108. this.strategy = DEFAULT_STRATEGY;
  109. strm = init(level, DEFAULT_STRATEGY, nowrap);
  110. }
  111. /**
  112. * Creates a new compressor using the specified compression level.
  113. * Compressed data will be generated in ZLIB format.
  114. * @param level the compression level (0-9)
  115. */
  116. public Deflater(int level) {
  117. this(level, false);
  118. }
  119. /**
  120. * Creates a new compressor with the default compression level.
  121. * Compressed data will be generated in ZLIB format.
  122. */
  123. public Deflater() {
  124. this(DEFAULT_COMPRESSION, false);
  125. }
  126. /**
  127. * Sets input data for compression. This should be called whenever
  128. * needsInput() returns true indicating that more input data is required.
  129. * @param b the input data bytes
  130. * @param off the start offset of the data
  131. * @param len the length of the data
  132. * @see Deflater#needsInput
  133. */
  134. public synchronized void setInput(byte[] b, int off, int len) {
  135. if (b== null) {
  136. throw new NullPointerException();
  137. }
  138. if (off < 0 || len < 0 || off > b.length - len) {
  139. throw new ArrayIndexOutOfBoundsException();
  140. }
  141. this.buf = b;
  142. this.off = off;
  143. this.len = len;
  144. }
  145. /**
  146. * Sets input data for compression. This should be called whenever
  147. * needsInput() returns true indicating that more input data is required.
  148. * @param b the input data bytes
  149. * @see Deflater#needsInput
  150. */
  151. public void setInput(byte[] b) {
  152. setInput(b, 0, b.length);
  153. }
  154. /**
  155. * Sets preset dictionary for compression. A preset dictionary is used
  156. * when the history buffer can be predetermined. When the data is later
  157. * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
  158. * in order to get the Adler-32 value of the dictionary required for
  159. * decompression.
  160. * @param b the dictionary data bytes
  161. * @param off the start offset of the data
  162. * @param len the length of the data
  163. * @see Inflater#inflate
  164. * @see Inflater#getAdler
  165. */
  166. public synchronized void setDictionary(byte[] b, int off, int len) {
  167. if (strm == 0 || b == null) {
  168. throw new NullPointerException();
  169. }
  170. if (off < 0 || len < 0 || off > b.length - len) {
  171. throw new ArrayIndexOutOfBoundsException();
  172. }
  173. setDictionary(strm, b, off, len);
  174. }
  175. /**
  176. * Sets preset dictionary for compression. A preset dictionary is used
  177. * when the history buffer can be predetermined. When the data is later
  178. * uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
  179. * in order to get the Adler-32 value of the dictionary required for
  180. * decompression.
  181. * @param b the dictionary data bytes
  182. * @see Inflater#inflate
  183. * @see Inflater#getAdler
  184. */
  185. public void setDictionary(byte[] b) {
  186. setDictionary(b, 0, b.length);
  187. }
  188. /**
  189. * Sets the compression strategy to the specified value.
  190. * @param strategy the new compression strategy
  191. * @exception IllegalArgumentException if the compression strategy is
  192. * invalid
  193. */
  194. public synchronized void setStrategy(int strategy) {
  195. switch (strategy) {
  196. case DEFAULT_STRATEGY:
  197. case FILTERED:
  198. case HUFFMAN_ONLY:
  199. break;
  200. default:
  201. throw new IllegalArgumentException();
  202. }
  203. if (this.strategy != strategy) {
  204. this.strategy = strategy;
  205. setParams = true;
  206. }
  207. }
  208. /**
  209. * Sets the current compression level to the specified value.
  210. * @param level the new compression level (0-9)
  211. * @exception IllegalArgumentException if the compression level is invalid
  212. */
  213. public synchronized void setLevel(int level) {
  214. if ((level < 0 || level > 9) && level != DEFAULT_COMPRESSION) {
  215. throw new IllegalArgumentException("invalid compression level");
  216. }
  217. if (this.level != level) {
  218. this.level = level;
  219. setParams = true;
  220. }
  221. }
  222. /**
  223. * Returns true if the input data buffer is empty and setInput()
  224. * should be called in order to provide more input.
  225. * @return true if the input data buffer is empty and setInput()
  226. * should be called in order to provide more input
  227. */
  228. public boolean needsInput() {
  229. return len <= 0;
  230. }
  231. /**
  232. * When called, indicates that compression should end with the current
  233. * contents of the input buffer.
  234. */
  235. public synchronized void finish() {
  236. finish = true;
  237. }
  238. /**
  239. * Returns true if the end of the compressed data output stream has
  240. * been reached.
  241. * @return true if the end of the compressed data output stream has
  242. * been reached
  243. */
  244. public synchronized boolean finished() {
  245. return finished;
  246. }
  247. /**
  248. * Fills specified buffer with compressed data. Returns actual number
  249. * of bytes of compressed data. A return value of 0 indicates that
  250. * needsInput() should be called in order to determine if more input
  251. * data is required.
  252. * @param b the buffer for the compressed data
  253. * @param off the start offset of the data
  254. * @param len the maximum number of bytes of compressed data
  255. * @return the actual number of bytes of compressed data
  256. */
  257. public synchronized int deflate(byte[] b, int off, int len) {
  258. if (b == null) {
  259. throw new NullPointerException();
  260. }
  261. if (off < 0 || len < 0 || off > b.length - len) {
  262. throw new ArrayIndexOutOfBoundsException();
  263. }
  264. return deflateBytes(b, off, len);
  265. }
  266. /**
  267. * Fills specified buffer with compressed data. Returns actual number
  268. * of bytes of compressed data. A return value of 0 indicates that
  269. * needsInput() should be called in order to determine if more input
  270. * data is required.
  271. * @param b the buffer for the compressed data
  272. * @return the actual number of bytes of compressed data
  273. */
  274. public int deflate(byte[] b) {
  275. return deflate(b, 0, b.length);
  276. }
  277. /**
  278. * Returns the ADLER-32 value of the uncompressed data.
  279. * @return the ADLER-32 value of the uncompressed data
  280. */
  281. public synchronized int getAdler() {
  282. if (strm == 0) {
  283. throw new NullPointerException();
  284. }
  285. return getAdler(strm);
  286. }
  287. /**
  288. * Returns the total number of bytes input so far.
  289. * @return the total number of bytes input so far
  290. */
  291. public synchronized int getTotalIn() {
  292. if (strm == 0) {
  293. throw new NullPointerException();
  294. }
  295. return getTotalIn(strm);
  296. }
  297. /**
  298. * Returns the total number of bytes output so far.
  299. * @return the total number of bytes output so far
  300. */
  301. public synchronized int getTotalOut() {
  302. if (strm == 0) {
  303. throw new NullPointerException();
  304. }
  305. return getTotalOut(strm);
  306. }
  307. /**
  308. * Resets deflater so that a new set of input data can be processed.
  309. * Keeps current compression level and strategy settings.
  310. */
  311. public synchronized void reset() {
  312. if (strm == 0) {
  313. throw new NullPointerException();
  314. }
  315. reset(strm);
  316. finish = false;
  317. finished = false;
  318. off = len = 0;
  319. }
  320. /**
  321. * Closes the compressor and discards any unprocessed input.
  322. * This method should be called when the compressor is no longer
  323. * being used, but will also be called automatically by the
  324. * finalize() method. Once this method is called, the behavior
  325. * of the Deflater object is undefined.
  326. */
  327. public synchronized void end() {
  328. if (strm != 0) {
  329. end(strm);
  330. strm = 0;
  331. }
  332. }
  333. /**
  334. * Closes the compressor when garbage is collected.
  335. */
  336. protected void finalize() {
  337. end();
  338. }
  339. private static native void initIDs();
  340. private native static long init(int level, int strategy, boolean nowrap);
  341. private native static void setDictionary(long strm, byte[] b, int off,
  342. int len);
  343. private native int deflateBytes(byte[] b, int off, int len);
  344. private native static int getAdler(long strm);
  345. private native static int getTotalIn(long strm);
  346. private native static int getTotalOut(long strm);
  347. private native static void reset(long strm);
  348. private native static void end(long strm);
  349. }