1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package java.util.zip; 19 20 import dalvik.system.CloseGuard; 21 import java.util.Arrays; 22 import libcore.util.EmptyArray; 23 24 /** 25 * This class compresses data using the <i>DEFLATE</i> algorithm (see <a 26 * href="http://www.gzip.org/algorithm.txt">specification</a>). 27 * 28 * <p>It is usually more convenient to use {@link DeflaterOutputStream}. 29 * 30 * <p>To compress an in-memory {@code byte[]} to another in-memory {@code byte[]} manually: 31 * <pre> 32 * byte[] originalBytes = ... 33 * 34 * Deflater deflater = new Deflater(); 35 * deflater.setInput(originalBytes); 36 * deflater.finish(); 37 * 38 * ByteArrayOutputStream baos = new ByteArrayOutputStream(); 39 * byte[] buf = new byte[8192]; 40 * while (!deflater.finished()) { 41 * int byteCount = deflater.deflate(buf); 42 * baos.write(buf, 0, byteCount); 43 * } 44 * deflater.end(); 45 * 46 * byte[] compressedBytes = baos.toByteArray(); 47 * </pre> 48 * <p>In situations where you don't have all the input in one array (or have so much 49 * input that you want to feed it to the deflater in chunks), it's possible to call 50 * {@link #setInput setInput} repeatedly, but you're much better off using 51 * {@link DeflaterOutputStream} to handle all this for you. {@link DeflaterOutputStream} also helps 52 * minimize memory requirements — the sample code above is very expensive. 53 */ 54 public class Deflater { 55 56 /** 57 * Upper bound for the compression level range. 58 */ 59 public static final int BEST_COMPRESSION = 9; 60 61 /** 62 * Lower bound for compression level range. 63 */ 64 public static final int BEST_SPEED = 1; 65 66 /** 67 * The default compression level. 68 */ 69 public static final int DEFAULT_COMPRESSION = -1; 70 71 /** 72 * The default compression strategy. 73 */ 74 public static final int DEFAULT_STRATEGY = 0; 75 76 /** 77 * The default compression method. 78 */ 79 public static final int DEFLATED = 8; 80 81 /** 82 * A compression strategy. 83 */ 84 public static final int FILTERED = 1; 85 86 /** 87 * A compression strategy. 88 */ 89 public static final int HUFFMAN_ONLY = 2; 90 91 /** 92 * A compression level. 93 */ 94 public static final int NO_COMPRESSION = 0; 95 96 /** 97 * Use buffering for best compression. 98 * 99 * @hide 100 * @since 1.7 101 */ 102 public static final int NO_FLUSH = 0; 103 104 /** 105 * Flush buffers so recipients can immediately decode the data sent thus 106 * far. This mode may degrade compression. 107 * 108 * @hide 109 * @since 1.7 110 */ 111 public static final int SYNC_FLUSH = 2; 112 113 /** 114 * Flush buffers so recipients can immediately decode the data sent thus 115 * far. The compression state is also reset to permit random access and 116 * recovery for clients who have discarded or damaged their own copy. This 117 * mode may degrade compression. 118 * 119 * @hide 120 * @since 1.7 121 */ 122 public static final int FULL_FLUSH = 3; 123 124 /** 125 * Flush buffers and mark the end of the data stream. 126 */ 127 private static final int FINISH = 4; 128 129 /** 130 * The ugly name flushParm is for RI compatibility, should code need to access this 131 * field via reflection if it's not able to use public API to choose what 132 * kind of flushing it gets. 133 */ 134 private int flushParm = NO_FLUSH; 135 136 private boolean finished; 137 138 private int compressLevel = DEFAULT_COMPRESSION; 139 140 private int strategy = DEFAULT_STRATEGY; 141 142 private long streamHandle = -1; 143 144 private byte[] inputBuffer; 145 146 private int inRead; 147 148 private int inLength; 149 150 private final CloseGuard guard = CloseGuard.get(); 151 152 /** 153 * Constructs a new {@code Deflater} instance using the default compression 154 * level. The strategy can be specified with {@link #setStrategy}. A 155 * header is added to the output by default; use {@link 156 * #Deflater(int, boolean)} if you need to omit the header. 157 */ Deflater()158 public Deflater() { 159 this(DEFAULT_COMPRESSION, false); 160 } 161 162 /** 163 * Constructs a new {@code Deflater} instance using compression 164 * level {@code level}. The strategy can be specified with {@link #setStrategy}. 165 * A header is added to the output by default; use 166 * {@link #Deflater(int, boolean)} if you need to omit the header. 167 * 168 * @param level 169 * the compression level in the range between 0 and 9. 170 */ Deflater(int level)171 public Deflater(int level) { 172 this(level, false); 173 } 174 175 /** 176 * Constructs a new {@code Deflater} instance with a specific compression 177 * level. If {@code noHeader} is true, no ZLIB header is added to the 178 * output. In a ZIP archive every entry (compressed file) comes with such a 179 * header. The strategy can be specified using {@link #setStrategy}. 180 * 181 * @param level 182 * the compression level in the range between 0 and 9. 183 * @param noHeader 184 * {@code true} indicates that no ZLIB header should be written. 185 */ Deflater(int level, boolean noHeader)186 public Deflater(int level, boolean noHeader) { 187 if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) { 188 throw new IllegalArgumentException(); 189 } 190 compressLevel = level; 191 streamHandle = createStream(compressLevel, strategy, noHeader); 192 guard.open("end"); 193 } 194 195 /** 196 * Deflates the data (previously passed to {@link #setInput setInput}) into the 197 * supplied buffer. 198 * 199 * @return number of bytes of compressed data written to {@code buf}. 200 */ deflate(byte[] buf)201 public int deflate(byte[] buf) { 202 return deflate(buf, 0, buf.length); 203 } 204 205 /** 206 * Deflates data (previously passed to {@link #setInput setInput}) into a specific 207 * region within the supplied buffer. 208 * 209 * @return the number of bytes of compressed data written to {@code buf}. 210 */ deflate(byte[] buf, int offset, int byteCount)211 public synchronized int deflate(byte[] buf, int offset, int byteCount) { 212 return deflateImpl(buf, offset, byteCount, flushParm); 213 } 214 215 /** 216 * Deflates data (previously passed to {@link #setInput setInput}) into a specific 217 * region within the supplied buffer, optionally flushing the input buffer. 218 * 219 * @param flush one of {@link #NO_FLUSH}, {@link #SYNC_FLUSH} or {@link #FULL_FLUSH}. 220 * @return the number of compressed bytes written to {@code buf}. If this 221 * equals {@code byteCount}, the number of bytes of input to be flushed 222 * may have exceeded the output buffer's capacity. In this case, 223 * finishing a flush will require the output buffer to be drained 224 * and additional calls to {@link #deflate} to be made. 225 * @hide 226 * @since 1.7 227 */ deflate(byte[] buf, int offset, int byteCount, int flush)228 public synchronized int deflate(byte[] buf, int offset, int byteCount, int flush) { 229 if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) { 230 throw new IllegalArgumentException("Bad flush value: " + flush); 231 } 232 return deflateImpl(buf, offset, byteCount, flush); 233 } 234 deflateImpl(byte[] buf, int offset, int byteCount, int flush)235 private synchronized int deflateImpl(byte[] buf, int offset, int byteCount, int flush) { 236 checkOpen(); 237 Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 238 if (inputBuffer == null) { 239 setInput(EmptyArray.BYTE); 240 } 241 return deflateImpl(buf, offset, byteCount, streamHandle, flush); 242 } 243 deflateImpl(byte[] buf, int offset, int byteCount, long handle, int flushParm)244 private native int deflateImpl(byte[] buf, int offset, int byteCount, long handle, int flushParm); 245 246 /** 247 * Frees all resources held onto by this deflating algorithm. Any unused 248 * input or output is discarded. This method should be called explicitly in 249 * order to free native resources as soon as possible. After {@code end()} is 250 * called, other methods will typically throw {@code IllegalStateException}. 251 */ end()252 public synchronized void end() { 253 guard.close(); 254 endImpl(); 255 } 256 endImpl()257 private void endImpl() { 258 if (streamHandle != -1) { 259 endImpl(streamHandle); 260 inputBuffer = null; 261 streamHandle = -1; 262 } 263 } 264 endImpl(long handle)265 private native void endImpl(long handle); 266 finalize()267 @Override protected void finalize() { 268 try { 269 if (guard != null) { 270 guard.warnIfOpen(); 271 } 272 synchronized (this) { 273 end(); // to allow overriding classes to clean up 274 endImpl(); // in case those classes don't call super.end() 275 } 276 } finally { 277 try { 278 super.finalize(); 279 } catch (Throwable t) { 280 throw new AssertionError(t); 281 } 282 } 283 } 284 285 /** 286 * Indicates to the {@code Deflater} that all uncompressed input has been provided 287 * to it. 288 * 289 * @see #finished 290 */ finish()291 public synchronized void finish() { 292 flushParm = FINISH; 293 } 294 295 /** 296 * Returns true if {@link #finish finish} has been called and all 297 * data provided by {@link #setInput setInput} has been 298 * successfully compressed and consumed by {@link #deflate deflate}. 299 */ finished()300 public synchronized boolean finished() { 301 return finished; 302 } 303 304 /** 305 * Returns the {@link Adler32} checksum of the uncompressed data read so far. 306 */ getAdler()307 public synchronized int getAdler() { 308 checkOpen(); 309 return getAdlerImpl(streamHandle); 310 } 311 getAdlerImpl(long handle)312 private native int getAdlerImpl(long handle); 313 314 /** 315 * Returns the total number of bytes of input read by this {@code Deflater}. This 316 * method is limited to 32 bits; use {@link #getBytesRead} instead. 317 */ getTotalIn()318 public synchronized int getTotalIn() { 319 checkOpen(); 320 return (int) getTotalInImpl(streamHandle); 321 } 322 getTotalInImpl(long handle)323 private native long getTotalInImpl(long handle); 324 325 /** 326 * Returns the total number of bytes written to the output buffer by this {@code 327 * Deflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead. 328 */ getTotalOut()329 public synchronized int getTotalOut() { 330 checkOpen(); 331 return (int) getTotalOutImpl(streamHandle); 332 } 333 getTotalOutImpl(long handle)334 private native long getTotalOutImpl(long handle); 335 336 /** 337 * Returns true if {@link #setInput setInput} must be called before deflation can continue. 338 * If all uncompressed data has been provided to the {@code Deflater}, 339 * {@link #finish} must be called to ensure the compressed data is output. 340 */ needsInput()341 public synchronized boolean needsInput() { 342 if (inputBuffer == null) { 343 return true; 344 } 345 return inRead == inLength; 346 } 347 348 /** 349 * Resets the {@code Deflater} to accept new input without affecting any 350 * previously made settings for the compression strategy or level. This 351 * operation <i>must</i> be called after {@link #finished} returns 352 * true if the {@code Deflater} is to be reused. 353 */ reset()354 public synchronized void reset() { 355 checkOpen(); 356 flushParm = NO_FLUSH; 357 finished = false; 358 resetImpl(streamHandle); 359 inputBuffer = null; 360 } 361 resetImpl(long handle)362 private native void resetImpl(long handle); 363 364 /** 365 * Sets the dictionary to be used for compression by this {@code Deflater}. 366 * This method can only be called if this {@code Deflater} supports the writing 367 * of ZLIB headers. This is the default, but can be overridden 368 * using {@link #Deflater(int, boolean)}. 369 */ setDictionary(byte[] dictionary)370 public void setDictionary(byte[] dictionary) { 371 setDictionary(dictionary, 0, dictionary.length); 372 } 373 374 /** 375 * Sets the dictionary to be used for compression by this {@code Deflater}. 376 * This method can only be called if this {@code Deflater} supports the writing 377 * of ZLIB headers. This is the default, but can be overridden 378 * using {@link #Deflater(int, boolean)}. 379 */ setDictionary(byte[] buf, int offset, int byteCount)380 public synchronized void setDictionary(byte[] buf, int offset, int byteCount) { 381 checkOpen(); 382 Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 383 setDictionaryImpl(buf, offset, byteCount, streamHandle); 384 } 385 setDictionaryImpl(byte[] buf, int offset, int byteCount, long handle)386 private native void setDictionaryImpl(byte[] buf, int offset, int byteCount, long handle); 387 388 /** 389 * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes 390 * for later compression. 391 */ setInput(byte[] buf)392 public void setInput(byte[] buf) { 393 setInput(buf, 0, buf.length); 394 } 395 396 /** 397 * Sets the input buffer the {@code Deflater} will use to extract uncompressed bytes 398 * for later compression. 399 */ setInput(byte[] buf, int offset, int byteCount)400 public synchronized void setInput(byte[] buf, int offset, int byteCount) { 401 checkOpen(); 402 Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 403 inLength = byteCount; 404 inRead = 0; 405 if (inputBuffer == null) { 406 setLevelsImpl(compressLevel, strategy, streamHandle); 407 } 408 inputBuffer = buf; 409 setInputImpl(buf, offset, byteCount, streamHandle); 410 } 411 setLevelsImpl(int level, int strategy, long handle)412 private native void setLevelsImpl(int level, int strategy, long handle); 413 setInputImpl(byte[] buf, int offset, int byteCount, long handle)414 private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle); 415 416 /** 417 * Sets the compression level to be used when compressing data. The 418 * compression level must be a value between 0 and 9. This value must be set 419 * prior to calling {@link #setInput setInput}. 420 * @exception IllegalArgumentException 421 * If the compression level is invalid. 422 */ setLevel(int level)423 public synchronized void setLevel(int level) { 424 if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) { 425 throw new IllegalArgumentException("Bad level: " + level); 426 } 427 if (inputBuffer != null) { 428 throw new IllegalStateException("setLevel cannot be called after setInput"); 429 } 430 compressLevel = level; 431 } 432 433 /** 434 * Sets the compression strategy to be used. The strategy must be one of 435 * FILTERED, HUFFMAN_ONLY or DEFAULT_STRATEGY. This value must be set prior 436 * to calling {@link #setInput setInput}. 437 * 438 * @exception IllegalArgumentException 439 * If the strategy specified is not one of FILTERED, 440 * HUFFMAN_ONLY or DEFAULT_STRATEGY. 441 */ setStrategy(int strategy)442 public synchronized void setStrategy(int strategy) { 443 if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) { 444 throw new IllegalArgumentException("Bad strategy: " + strategy); 445 } 446 if (inputBuffer != null) { 447 throw new IllegalStateException("setStrategy cannot be called after setInput"); 448 } 449 this.strategy = strategy; 450 } 451 452 /** 453 * Returns the total number of bytes read by the {@code Deflater}. This 454 * method is the same as {@link #getTotalIn} except that it returns a 455 * {@code long} value instead of an integer. 456 */ getBytesRead()457 public synchronized long getBytesRead() { 458 checkOpen(); 459 return getTotalInImpl(streamHandle); 460 } 461 462 /** 463 * Returns a the total number of bytes written by this {@code Deflater}. This 464 * method is the same as {@code getTotalOut} except it returns a 465 * {@code long} value instead of an integer. 466 */ getBytesWritten()467 public synchronized long getBytesWritten() { 468 checkOpen(); 469 return getTotalOutImpl(streamHandle); 470 } 471 createStream(int level, int strategy1, boolean noHeader1)472 private native long createStream(int level, int strategy1, boolean noHeader1); 473 checkOpen()474 private void checkOpen() { 475 if (streamHandle == -1) { 476 throw new IllegalStateException("attempt to use Deflater after calling end"); 477 } 478 } 479 } 480