Source for java.util.zip.Deflater

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