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.archive.internal.nls.Messages;
021:
022: /**
023: * The Inflater class is used to decompress bytes using the DEFLATE compression
024: * algorithm. Inflation is performed by the ZLIB compression library.
025: *
026: * @see DeflaterOutputStream
027: * @see Inflater
028: */
029: public class Inflater {
030:
031: private static final byte MAGIC_NUMBER = 120;
032:
033: static {
034: oneTimeInitialization();
035: }
036:
037: // Fill in the JNI id caches
038: private static native void oneTimeInitialization();
039:
040: private boolean finished; // Set by the inflateImpl native
041:
042: private boolean gotFirstByte = false;
043:
044: int inLength;
045:
046: int inRead;
047:
048: private boolean needsDictionary; // Set by the inflateImpl native
049:
050: private boolean pass_magic_number_check = true;
051:
052: private long streamHandle = -1;
053:
054: /**
055: * Constructs a new Inflater instance.
056: */
057: public Inflater() {
058: this (false);
059: }
060:
061: /**
062: * Constructs a new Inflater instance. If noHeader is true the Inflater will
063: * not attempt to read a ZLIB header.
064: *
065: * @param noHeader
066: * If true, read a ZLIB header from input.
067: */
068: public Inflater(boolean noHeader) {
069: streamHandle = createStream(noHeader);
070: }
071:
072: private native long createStream(boolean noHeader1);
073:
074: /**
075: * Release any resources associated with this Inflater. Any unused
076: * input/output is discarded. This is also called by the finalize method.
077: */
078: public synchronized void end() {
079: if (streamHandle != -1) {
080: endImpl(streamHandle);
081: inRead = 0;
082: inLength = 0;
083: streamHandle = -1;
084: }
085: }
086:
087: private native synchronized void endImpl(long handle);
088:
089: @Override
090: protected void finalize() {
091: end();
092: }
093:
094: /**
095: * Indicates if the Inflater has inflated the entire deflated stream. If
096: * deflated bytes remain and needsInput returns true this method will return
097: * false. This method should be called after all deflated input is supplied
098: * to the Inflater.
099: *
100: * @return True if all input has been inflated, false otherwise
101: */
102: public synchronized boolean finished() {
103: return finished;
104: }
105:
106: /**
107: * Returns the Adler32 checksum of either all bytes inflated, or the
108: * checksum of the preset dictionary if one has been supplied.
109: *
110: * @return The Adler32 checksum associated with this Inflater.
111: */
112: public synchronized int getAdler() {
113: if (streamHandle == -1) {
114: throw new IllegalStateException();
115: }
116: return getAdlerImpl(streamHandle);
117: }
118:
119: private native synchronized int getAdlerImpl(long handle);
120:
121: /**
122: * Returns a long int of total number of bytes of input read by the
123: * Inflater. This method performs the same as getTotalIn except it returns a
124: * long value instead of an integer
125: *
126: * @see #getTotalIn()
127: * @return Total bytes read
128: */
129: public synchronized long getBytesRead() {
130: // Throw NPE here
131: if (streamHandle == -1) {
132: throw new NullPointerException();
133: }
134: return getTotalInImpl(streamHandle);
135: }
136:
137: /**
138: * Returns a long int of total number of bytes of input output by the
139: * Inflater. This method performs the same as getTotalOut except it returns
140: * a long value instead of an integer
141: *
142: * @see #getTotalOut()
143: * @return Total bytes output
144: */
145: public synchronized long getBytesWritten() {
146: // Throw NPE here
147: if (streamHandle == -1) {
148: throw new NullPointerException();
149: }
150: return getTotalOutImpl(streamHandle);
151: }
152:
153: /**
154: * Returns the number of bytes of current input remaining to be read by the
155: * inflater
156: *
157: * @return Number of bytes of unread input.
158: */
159: public synchronized int getRemaining() {
160: return inLength - inRead;
161: }
162:
163: /**
164: * Returns total number of bytes of input read by the Inflater.
165: *
166: * @return Total bytes read
167: */
168: public synchronized int getTotalIn() {
169: if (streamHandle == -1) {
170: throw new IllegalStateException();
171: }
172: long totalIn = getTotalInImpl(streamHandle);
173: return (totalIn <= Integer.MAX_VALUE ? (int) totalIn
174: : Integer.MAX_VALUE);
175: }
176:
177: private synchronized native long getTotalInImpl(long handle);
178:
179: /**
180: * Returns total number of bytes of input output by the Inflater.
181: *
182: * @return Total bytes output
183: */
184: public synchronized int getTotalOut() {
185: if (streamHandle == -1) {
186: throw new IllegalStateException();
187: }
188: long totalOut = getTotalOutImpl(streamHandle);
189: return (totalOut <= Integer.MAX_VALUE ? (int) totalOut
190: : Integer.MAX_VALUE);
191: }
192:
193: private native synchronized long getTotalOutImpl(long handle);
194:
195: /**
196: * Inflates bytes from current input and stores them in buf.
197: *
198: * @param buf
199: * Buffer to output inflated bytes
200: * @return Number of bytes inflated
201: * @exception DataFormatException
202: * If the underlying stream is corrupted or was not DEFLATED
203: *
204: */
205: public int inflate(byte[] buf) throws DataFormatException {
206: return inflate(buf, 0, buf.length);
207: }
208:
209: /**
210: * Inflates up to nbytes bytes from current input and stores them in buf
211: * starting at off.
212: *
213: * @param buf
214: * Buffer to output inflated bytes
215: * @param off
216: * Offset in buffer into which to store inflated bytes
217: * @param nbytes
218: * Number of inflated bytes to store
219: * @exception DataFormatException
220: * If the underlying stream is corrupted or was not DEFLATED
221: * @return Number of bytes inflated
222: */
223: public synchronized int inflate(byte[] buf, int off, int nbytes)
224: throws DataFormatException {
225: // avoid int overflow, check null buf
226: if (off <= buf.length && nbytes >= 0 && off >= 0
227: && buf.length - off >= nbytes) {
228: if (nbytes == 0)
229: return 0;
230:
231: if (streamHandle == -1) {
232: throw new IllegalStateException();
233: }
234:
235: if (!pass_magic_number_check) {
236: throw new DataFormatException();
237: }
238:
239: if (needsInput()) {
240: return 0;
241: }
242:
243: boolean neededDict = needsDictionary;
244: needsDictionary = false;
245: int result = inflateImpl(buf, off, nbytes, streamHandle);
246: if (needsDictionary && neededDict) {
247: throw new DataFormatException(Messages
248: .getString("archive.27")); //$NON-NLS-1$
249: }
250: return result;
251: }
252: throw new ArrayIndexOutOfBoundsException();
253: }
254:
255: private native synchronized int inflateImpl(byte[] buf, int off,
256: int nbytes, long handle);
257:
258: /**
259: * Indicates whether the input bytes were compressed with a preset
260: * dictionary. This method should be called prior to inflate() to determine
261: * if a dictionary is required. If so setDictionary() should be called with
262: * the appropriate dictionary prior to calling inflate().
263: *
264: * @return true if a preset dictionary is required for inflation.
265: * @see #setDictionary(byte[])
266: * @see #setDictionary(byte[], int, int)
267: */
268: public synchronized boolean needsDictionary() {
269: return needsDictionary;
270: }
271:
272: /**
273: * Answers whether more data is required in the input buffer.
274: *
275: * @return true if the input buffer is empty, and false otherwise.
276: * @see #setInput(byte[])
277: */
278: public synchronized boolean needsInput() {
279: return inRead == inLength;
280: }
281:
282: /**
283: * Resets the Inflater.
284: */
285: public synchronized void reset() {
286: if (streamHandle == -1) {
287: throw new NullPointerException();
288: }
289: finished = false;
290: needsDictionary = false;
291: inLength = inRead = 0;
292: resetImpl(streamHandle);
293: }
294:
295: private native synchronized void resetImpl(long handle);
296:
297: /**
298: * Sets the preset dictionary to be used for inflation.
299: *
300: * <code>needsDictionary()</code> can be called to determine whether the
301: * current input was deflated using a preset dictionary.
302: *
303: * @param buf
304: * The buffer containing the dictionary bytes
305: * @see #needsDictionary()
306: */
307: public synchronized void setDictionary(byte[] buf) {
308: setDictionary(buf, 0, buf.length);
309: }
310:
311: /**
312: * Sets the dictionary used to inflate the given data.
313: *
314: * The dictionary should be set if the {@link #inflate(byte[])} returned
315: * zero bytes inflated and {@link #needsDictionary()} returns
316: * <code>true</code>.
317: *
318: * @param buf
319: * the bytes containing the dictionary
320: * @param off
321: * offset into the buffer to the start of the dictionary
322: * @param nbytes
323: * length of the dictionary, in bytes
324: */
325: public synchronized void setDictionary(byte[] buf, int off,
326: int nbytes) {
327: if (streamHandle == -1) {
328: throw new IllegalStateException();
329: }
330: // avoid int overflow, check null buf
331: if (off <= buf.length && nbytes >= 0 && off >= 0
332: && buf.length - off >= nbytes) {
333: setDictionaryImpl(buf, off, nbytes, streamHandle);
334: } else {
335: throw new ArrayIndexOutOfBoundsException();
336: }
337: }
338:
339: private native synchronized void setDictionaryImpl(byte[] buf,
340: int off, int nbytes, long handle);
341:
342: /**
343: * Sets the current input to buf. This method should only be called if
344: * needsInput() returns true.
345: *
346: * @param buf
347: * input buffer
348: * @see #needsInput
349: */
350: public synchronized void setInput(byte[] buf) {
351: setInput(buf, 0, buf.length);
352: }
353:
354: /**
355: * Sets the current input to the region of buf starting at off and ending at
356: * nbytes - 1. This method should only be called if needsInput() returns
357: * true.
358: *
359: * @param buf
360: * input buffer
361: * @param off
362: * offset to read from in buffer
363: * @param nbytes
364: * number of bytes to read
365: * @see #needsInput
366: */
367: public synchronized void setInput(byte[] buf, int off, int nbytes) {
368: if (streamHandle == -1) {
369: throw new IllegalStateException();
370: }
371: // avoid int overflow, check null buf
372: if (off <= buf.length && nbytes >= 0 && off >= 0
373: && buf.length - off >= nbytes) {
374: inRead = 0;
375: inLength = nbytes;
376: setInputImpl(buf, off, nbytes, streamHandle);
377: } else {
378: throw new ArrayIndexOutOfBoundsException();
379: }
380:
381: if (!gotFirstByte && nbytes > 0) {
382: pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
383: gotFirstByte = true;
384: }
385: }
386:
387: private native synchronized void setInputImpl(byte[] buf, int off,
388: int nbytes, long handle);
389: }
|