001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.util.zip;
019:
020: import org.apache.harmony.luni.platform.OSResourcesMonitor;
021:
022: /**
023: * The Deflater class is used to compress bytes using the DEFLATE compression
024: * algorithm. Deflation is performed by the ZLIB compression library.
025: *
026: * @see DeflaterOutputStream
027: * @see Inflater
028: */
029: public class Deflater {
030:
031: /** Constant value representing the best available compression level. */
032: public static final int BEST_COMPRESSION = 9;
033:
034: /** Constant value representing the fastest available compression level. */
035: public static final int BEST_SPEED = 1;
036:
037: /** Constant value representing the default compression level. */
038: public static final int DEFAULT_COMPRESSION = -1;
039:
040: /** Constant value representing the default compression strategy. */
041: public static final int DEFAULT_STRATEGY = 0;
042:
043: /** Constant value representing the deflate compression strategy. */
044: public static final int DEFLATED = 8;
045:
046: /** Constant value representing the filtered compression strategy. */
047: public static final int FILTERED = 1;
048:
049: /** Constant value representing the Huffman compression strategy. */
050: public static final int HUFFMAN_ONLY = 2;
051:
052: /** Constant value representing the no compression strategy. */
053: public static final int NO_COMPRESSION = 0;
054:
055: private static final int Z_NO_FLUSH = 0;
056:
057: private static final int Z_FINISH = 4;
058:
059: // Fill in the JNI id caches
060: private static native void oneTimeInitialization();
061:
062: // A stub buffer used when deflate() called while inputBuffer has not been
063: // set.
064: private static final byte[] STUB_INPUT_BUFFER = new byte[0];
065:
066: static {
067: oneTimeInitialization();
068: }
069:
070: private int flushParm = Z_NO_FLUSH;
071:
072: private boolean finished;
073:
074: private int compressLevel = DEFAULT_COMPRESSION;
075:
076: private int strategy = DEFAULT_STRATEGY;
077:
078: private long streamHandle = -1;
079:
080: private byte[] inputBuffer;
081:
082: private int inRead;
083:
084: private int inLength;
085:
086: /**
087: * Constructs a new Deflater instance with default compression level and
088: * strategy.
089: */
090: public Deflater() {
091: this (DEFAULT_COMPRESSION, false);
092: }
093:
094: /**
095: * Constructs a new Deflater instance with compression level level and
096: * default compression strategy. THe compression level provided must be
097: * between 0 and 9.
098: *
099: * @param level
100: * the compression level to use
101: */
102: public Deflater(int level) {
103: this (level, false);
104: }
105:
106: /**
107: * Constructs a new Deflater instance with compression level level and
108: * default compression strategy. If the noHeader parameter is specified then
109: * no ZLIB header will be written as part of the compressed output. The
110: * compression level specified must be between 0 and 9.
111: *
112: * @param level
113: * the compression level to use
114: * @param noHeader
115: * if true do not write the ZLIB header
116: */
117: public Deflater(int level, boolean noHeader) {
118: super ();
119: if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
120: throw new IllegalArgumentException();
121: }
122: compressLevel = level;
123: streamHandle = createStreamWithMemoryEnsurance(compressLevel,
124: strategy, noHeader);
125: }
126:
127: /**
128: * Deflates data into the supplied buffer
129: *
130: * @param buf
131: * buffer to store compressed data
132: *
133: * @return number of bytes of compressed data stored
134: *
135: */
136: public int deflate(byte[] buf) {
137: return deflate(buf, 0, buf.length);
138: }
139:
140: /**
141: * Deflates data into the supplied buffer using the region from off to
142: * nbytes - 1.
143: *
144: * @param buf
145: * buffer to store compressed data
146: * @param off
147: * offset inf buf to start storing data
148: * @param nbytes
149: * number of bytes of compressed data to store in buf
150: *
151: * @return number of bytes of compressed data stored
152: *
153: */
154: public synchronized int deflate(byte[] buf, int off, int nbytes) {
155: if (streamHandle == -1) {
156: throw new IllegalStateException();
157: }
158: // avoid int overflow, check null buf
159: if (off <= buf.length && nbytes >= 0 && off >= 0
160: && buf.length - off >= nbytes) {
161: // put a stub buffer, no effect.
162: if (null == inputBuffer) {
163: setInput(STUB_INPUT_BUFFER);
164: }
165: return deflateImpl(buf, off, nbytes, streamHandle,
166: flushParm);
167: }
168: throw new ArrayIndexOutOfBoundsException();
169: }
170:
171: private synchronized native int deflateImpl(byte[] buf, int off,
172: int nbytes, long handle, int flushParm1);
173:
174: private synchronized native void endImpl(long handle);
175:
176: /**
177: * Frees all resources held onto by this Deflater. Any unused input or
178: * output is discarded. This is also called from the finalize method.
179: *
180: * @see #finalize
181: */
182: public synchronized void end() {
183: if (streamHandle != -1) {
184: endImpl(streamHandle);
185: inputBuffer = null;
186: streamHandle = -1;
187: }
188: }
189:
190: @Override
191: protected void finalize() {
192: end();
193: }
194:
195: /**
196: * Indicates to the Deflater that all uncompressed input has been provided
197: * to it.
198: *
199: * @see #finished()
200: */
201: public synchronized void finish() {
202: flushParm = Z_FINISH;
203: }
204:
205: /**
206: * Returns whether or not all provided data has been successfully
207: * compressed.
208: *
209: * @return true if all data has been compressed, false otherwise
210: */
211: public synchronized boolean finished() {
212: return finished;
213: }
214:
215: /**
216: * Returns the Adler32 checksum of uncompressed data currently read. If a
217: * preset dictionary is used getAdler() will return the Adler32 checksum of
218: * the dictionary used.
219: *
220: * @return The Adler32 checksum of uncompressed data or preset dictionary if
221: * used
222: *
223: * @see #setDictionary(byte[])
224: * @see #setDictionary(byte[], int, int)
225: */
226: public synchronized int getAdler() {
227: if (streamHandle == -1) {
228: throw new IllegalStateException();
229: }
230:
231: return getAdlerImpl(streamHandle);
232: }
233:
234: private synchronized native int getAdlerImpl(long handle);
235:
236: /**
237: * Returns the total number of bytes of input consumed by the deflater.
238: *
239: * @return number of bytes of input read.
240: */
241: public synchronized int getTotalIn() {
242: if (streamHandle == -1) {
243: throw new IllegalStateException();
244: }
245:
246: return (int) getTotalInImpl(streamHandle);
247: }
248:
249: private synchronized native long getTotalInImpl(long handle);
250:
251: /**
252: * Returns the total number of compressed bytes output by this Deflater.
253: *
254: * @return number of compressed bytes output.
255: */
256: public synchronized int getTotalOut() {
257: if (streamHandle == -1) {
258: throw new IllegalStateException();
259: }
260:
261: return (int) getTotalOutImpl(streamHandle);
262: }
263:
264: private synchronized native long getTotalOutImpl(long handle);
265:
266: /**
267: * Indicates whether or not all bytes of uncompressed input have been
268: * consumed by the Deflater. If needsInput() answers true setInput() must be
269: * called before deflation can continue. If all bytes of uncompressed data
270: * have been provided to the Deflater finish() must be called to ensure the
271: * compressed data is output.
272: *
273: * @return True if input is required for deflation to continue, false
274: * otherwise
275: * @see #finished()
276: * @see #setInput(byte[])
277: * @see #setInput(byte[], int, int)
278: */
279: public synchronized boolean needsInput() {
280: if (inputBuffer == null) {
281: return true;
282: }
283: return inRead == inLength;
284: }
285:
286: /**
287: * Resets the <code>Deflater</code> to accept new input without affecting
288: * any previously made settings for the compression strategy or level. This
289: * operation <i>must</i> be called after <code>finished()</code> returns
290: * <code>true</code> if the <code>Deflater</code> is to be reused.
291: *
292: * @see #finished()
293: */
294: public synchronized void reset() {
295: if (streamHandle == -1) {
296: throw new NullPointerException();
297: }
298:
299: flushParm = Z_NO_FLUSH;
300: finished = false;
301: resetImpl(streamHandle);
302: inputBuffer = null;
303: }
304:
305: private synchronized native void resetImpl(long handle);
306:
307: /**
308: * Defines a dictionary to be used for compression by the receiver.
309: *
310: * @param buf
311: * the entire set of bytes comprising the dictionary
312: * @see #setDictionary(byte[], int, int)
313: */
314: public void setDictionary(byte[] buf) {
315: setDictionary(buf, 0, buf.length);
316: }
317:
318: /**
319: * Sets the dictionary to be used for compression by this Deflater.
320: *
321: * <code>setDictionary()</code> can only be called if this Deflater
322: * supports the writing of ZLIB headers. This is the default behaviour but
323: * can be overridden using <code>Deflater(int, boolean)</code>.
324: *
325: * @param buf
326: * the byte array containing the dictionary
327: * @param off
328: * offset into the byte array
329: * @param nbytes
330: * number of bytes comprising the dictionary
331: *
332: * @see Deflater#Deflater(int, boolean)
333: */
334: public synchronized void setDictionary(byte[] buf, int off,
335: int nbytes) {
336: if (streamHandle == -1) {
337: throw new IllegalStateException();
338: }
339: // avoid int overflow, check null buf
340: if (off <= buf.length && nbytes >= 0 && off >= 0
341: && buf.length - off >= nbytes) {
342: setDictionaryImpl(buf, off, nbytes, streamHandle);
343: } else {
344: throw new ArrayIndexOutOfBoundsException();
345: }
346: }
347:
348: private synchronized native void setDictionaryImpl(byte[] buf,
349: int off, int nbytes, long handle);
350:
351: /**
352: * Sets the input buffer the Deflater will use to extract uncompressed bytes
353: * for later compression.
354: *
355: * @param buf
356: * the input buffer
357: */
358: public void setInput(byte[] buf) {
359: setInput(buf, 0, buf.length);
360: }
361:
362: /**
363: * Sets the input buffer the Deflater will use to extract uncompressed bytes
364: * for later compression. Input will be taken from the buffer region
365: * starting at off and ending at nbytes - 1.
366: *
367: * @param buf
368: * the input data byte array
369: * @param off
370: * offset into the input bytes
371: * @param nbytes
372: * number of valid bytes in the input array
373: */
374: public synchronized void setInput(byte[] buf, int off, int nbytes) {
375: if (streamHandle == -1) {
376: throw new IllegalStateException();
377: }
378: // avoid int overflow, check null buf
379: if (off <= buf.length && nbytes >= 0 && off >= 0
380: && buf.length - off >= nbytes) {
381: inLength = nbytes;
382: inRead = 0;
383: if (inputBuffer == null) {
384: setLevelsImpl(compressLevel, strategy, streamHandle);
385: }
386: inputBuffer = buf;
387: setInputImpl(buf, off, nbytes, streamHandle);
388: } else {
389: throw new ArrayIndexOutOfBoundsException();
390: }
391: }
392:
393: private synchronized native void setLevelsImpl(int level,
394: int strategy, long handle);
395:
396: private synchronized native void setInputImpl(byte[] buf, int off,
397: int nbytes, long handle);
398:
399: /**
400: * Sets the compression level to be used when compressing data. The
401: * compression level must be a value between 0 and 9. This value must be set
402: * prior to calling setInput().
403: *
404: * @param level
405: * compression level to use
406: * @exception IllegalArgumentException
407: * If the compression level is invalid.
408: */
409: public synchronized void setLevel(int level) {
410: if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
411: throw new IllegalArgumentException();
412: }
413: if (inputBuffer != null) {
414: throw new IllegalStateException();
415: }
416: compressLevel = level;
417: }
418:
419: /**
420: * Sets the compression strategy to be used. The strategy must be one of
421: * FILTERED, HUFFMAN_ONLY or DEFAULT_STRATEGY.This value must be set prior
422: * to calling setInput().
423: *
424: * @param strategy
425: * compression strategy to use
426: * @exception IllegalArgumentException
427: * If the strategy specified is not one of FILTERED,
428: * HUFFMAN_ONLY or DEFAULT_STRATEGY.
429: */
430: public synchronized void setStrategy(int strategy) {
431: if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) {
432: throw new IllegalArgumentException();
433: }
434: if (inputBuffer != null) {
435: throw new IllegalStateException();
436: }
437: this .strategy = strategy;
438: }
439:
440: /**
441: * Returns a long int of total number of bytes read by the Deflater. This
442: * method performs the same as getTotalIn except it returns a long value
443: * instead of an integer
444: *
445: * @see #getTotalIn()
446: * @return bytes exactly read by deflater
447: */
448: public synchronized long getBytesRead() {
449: // Throw NPE here
450: if (streamHandle == -1) {
451: throw new NullPointerException();
452: }
453: return getTotalInImpl(streamHandle);
454: }
455:
456: /**
457: * Returns a long int of total number of bytes of read by the Deflater. This
458: * method performs the same as getTotalOut except it returns a long value
459: * instead of an integer
460: *
461: * @see #getTotalOut()
462: * @return bytes exactly write by deflater
463: */
464: public synchronized long getBytesWritten() {
465: // Throw NPE here
466: if (streamHandle == -1) {
467: throw new NullPointerException();
468: }
469: return getTotalOutImpl(streamHandle);
470: }
471:
472: private long createStreamWithMemoryEnsurance(int level,
473: int strategy1, boolean noHeader1) {
474: OSResourcesMonitor.ensurePhysicalMemoryCapacity();
475: return createStream(level, strategy1, noHeader1);
476: }
477:
478: private native long createStream(int level, int strategy1,
479: boolean noHeader1);
480: }
|