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 18package java.util.zip; 19 20import dalvik.system.CloseGuard; 21import java.io.FileDescriptor; 22import java.util.Arrays; 23 24/** 25 * This class decompresses data that was compressed using the <i>DEFLATE</i> 26 * algorithm (see <a href="http://www.gzip.org/algorithm.txt">specification</a>). 27 * 28 * <p>It is usually more convenient to use {@link InflaterInputStream}. 29 * 30 * <p>To decompress an in-memory {@code byte[]} to another in-memory {@code byte[]} manually: 31 * <pre> 32 * byte[] compressedBytes = ... 33 * int decompressedByteCount = ... // From your format's metadata. 34 * Inflater inflater = new Inflater(); 35 * inflater.setInput(compressedBytes, 0, compressedBytes.length); 36 * byte[] decompressedBytes = new byte[decompressedByteCount]; 37 * if (inflater.inflate(decompressedBytes) != decompressedByteCount) { 38 * throw new AssertionError(); 39 * } 40 * inflater.end(); 41 * </pre> 42 * <p>In situations where you don't have all the input in one array (or have so much 43 * input that you want to feed it to the inflater in chunks), it's possible to call 44 * {@link #setInput} repeatedly, but you're much better off using {@link InflaterInputStream} 45 * to handle all this for you. 46 * 47 * <p>If you don't know how big the decompressed data will be, you can call {@link #inflate} 48 * repeatedly on a temporary buffer, copying the bytes to a {@link java.io.ByteArrayOutputStream}, 49 * but this is probably another sign you'd be better off using {@link InflaterInputStream}. 50 */ 51public class Inflater { 52 53 private int inLength; 54 55 private int inRead; // Set by inflateImpl. 56 private boolean finished; // Set by inflateImpl. 57 private boolean needsDictionary; // Set by inflateImpl. 58 59 private long streamHandle = -1; 60 61 private final CloseGuard guard = CloseGuard.get(); 62 63 /** 64 * This constructor creates an inflater that expects a header from the input 65 * stream. Use {@link #Inflater(boolean)} if the input comes without a ZLIB 66 * header. 67 */ 68 public Inflater() { 69 this(false); 70 } 71 72 /** 73 * This constructor allows to create an inflater that expects no header from 74 * the input stream. 75 * 76 * @param noHeader 77 * {@code true} indicates that no ZLIB header comes with the 78 * input. 79 */ 80 public Inflater(boolean noHeader) { 81 streamHandle = createStream(noHeader); 82 guard.open("end"); 83 } 84 85 private native long createStream(boolean noHeader1); 86 87 /** 88 * Releases resources associated with this {@code Inflater}. Any unused 89 * input or output is discarded. This method should be called explicitly in 90 * order to free native resources as soon as possible. After {@code end()} is 91 * called, other methods will typically throw {@code IllegalStateException}. 92 */ 93 public synchronized void end() { 94 guard.close(); 95 if (streamHandle != -1) { 96 endImpl(streamHandle); 97 inRead = 0; 98 inLength = 0; 99 streamHandle = -1; 100 } 101 } 102 103 private native void endImpl(long handle); 104 105 @Override protected void finalize() { 106 try { 107 if (guard != null) { 108 guard.warnIfOpen(); 109 } 110 end(); 111 } finally { 112 try { 113 super.finalize(); 114 } catch (Throwable t) { 115 throw new AssertionError(t); 116 } 117 } 118 } 119 120 /** 121 * Indicates if the {@code Inflater} has inflated the entire deflated 122 * stream. If deflated bytes remain and {@link #needsInput} returns {@code 123 * true} this method will return {@code false}. This method should be 124 * called after all deflated input is supplied to the {@code Inflater}. 125 * 126 * @return {@code true} if all input has been inflated, {@code false} 127 * otherwise. 128 */ 129 public synchronized boolean finished() { 130 return finished; 131 } 132 133 /** 134 * Returns the {@link Adler32} checksum of the bytes inflated so far, or the 135 * checksum of the preset dictionary if {@link #needsDictionary} returns true. 136 */ 137 public synchronized int getAdler() { 138 checkOpen(); 139 return getAdlerImpl(streamHandle); 140 } 141 142 private native int getAdlerImpl(long handle); 143 144 /** 145 * Returns the total number of bytes read by the {@code Inflater}. This 146 * method is the same as {@link #getTotalIn} except that it returns a 147 * {@code long} value instead of an integer. 148 */ 149 public synchronized long getBytesRead() { 150 checkOpen(); 151 return getTotalInImpl(streamHandle); 152 } 153 154 /** 155 * Returns a the total number of bytes written by this {@code Inflater}. This 156 * method is the same as {@code getTotalOut} except it returns a 157 * {@code long} value instead of an integer. 158 */ 159 public synchronized long getBytesWritten() { 160 checkOpen(); 161 return getTotalOutImpl(streamHandle); 162 } 163 164 /** 165 * Returns the number of bytes of current input remaining to be read by this 166 * inflater. 167 */ 168 public synchronized int getRemaining() { 169 return inLength - inRead; 170 } 171 172 /** 173 * Returns the offset of the next byte to read in the underlying buffer. 174 * 175 * For internal use only. 176 */ 177 synchronized int getCurrentOffset() { 178 return inRead; 179 } 180 181 /** 182 * Returns the total number of bytes of input read by this {@code Inflater}. This 183 * method is limited to 32 bits; use {@link #getBytesRead} instead. 184 */ 185 public synchronized int getTotalIn() { 186 checkOpen(); 187 return (int) Math.min(getTotalInImpl(streamHandle), (long) Integer.MAX_VALUE); 188 } 189 190 private native long getTotalInImpl(long handle); 191 192 /** 193 * Returns the total number of bytes written to the output buffer by this {@code 194 * Inflater}. The method is limited to 32 bits; use {@link #getBytesWritten} instead. 195 */ 196 public synchronized int getTotalOut() { 197 checkOpen(); 198 return (int) Math.min(getTotalOutImpl(streamHandle), (long) Integer.MAX_VALUE); 199 } 200 201 private native long getTotalOutImpl(long handle); 202 203 /** 204 * Inflates bytes from the current input and stores them in {@code buf}. 205 * 206 * @param buf 207 * the buffer where decompressed data bytes are written. 208 * @return the number of bytes inflated. 209 * @throws DataFormatException 210 * if the underlying stream is corrupted or was not compressed 211 * using a {@code Deflater}. 212 */ 213 public int inflate(byte[] buf) throws DataFormatException { 214 return inflate(buf, 0, buf.length); 215 } 216 217 /** 218 * Inflates up to {@code byteCount} bytes from the current input and stores them in 219 * {@code buf} starting at {@code offset}. 220 * 221 * @throws DataFormatException 222 * if the underlying stream is corrupted or was not compressed 223 * using a {@code Deflater}. 224 * @return the number of bytes inflated. 225 */ 226 public synchronized int inflate(byte[] buf, int offset, int byteCount) throws DataFormatException { 227 Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 228 229 checkOpen(); 230 231 if (needsInput()) { 232 return 0; 233 } 234 235 boolean neededDict = needsDictionary; 236 needsDictionary = false; 237 int result = inflateImpl(buf, offset, byteCount, streamHandle); 238 if (needsDictionary && neededDict) { 239 throw new DataFormatException("Needs dictionary"); 240 } 241 return result; 242 } 243 244 private native int inflateImpl(byte[] buf, int offset, int byteCount, long handle); 245 246 /** 247 * Returns true if the input bytes were compressed with a preset 248 * dictionary. This method should be called if the first call to {@link #inflate} returns 0, 249 * to determine whether a dictionary is required. If so, {@link #setDictionary} 250 * should be called with the appropriate dictionary before calling {@code 251 * inflate} again. Use {@link #getAdler} to determine which dictionary is required. 252 */ 253 public synchronized boolean needsDictionary() { 254 return needsDictionary; 255 } 256 257 /** 258 * Returns true if {@link #setInput} must be called before inflation can continue. 259 */ 260 public synchronized boolean needsInput() { 261 return inRead == inLength; 262 } 263 264 /** 265 * Resets this {@code Inflater}. Should be called prior to inflating a new 266 * set of data. 267 */ 268 public synchronized void reset() { 269 checkOpen(); 270 finished = false; 271 needsDictionary = false; 272 inLength = inRead = 0; 273 resetImpl(streamHandle); 274 } 275 276 private native void resetImpl(long handle); 277 278 /** 279 * Sets the preset dictionary to be used for inflation to {@code dictionary}. 280 * See {@link #needsDictionary} for details. 281 */ 282 public synchronized void setDictionary(byte[] dictionary) { 283 setDictionary(dictionary, 0, dictionary.length); 284 } 285 286 /** 287 * Sets the preset dictionary to be used for inflation to a subsequence of {@code dictionary} 288 * starting at {@code offset} and continuing for {@code byteCount} bytes. See {@link 289 * #needsDictionary} for details. 290 */ 291 public synchronized void setDictionary(byte[] dictionary, int offset, int byteCount) { 292 checkOpen(); 293 Arrays.checkOffsetAndCount(dictionary.length, offset, byteCount); 294 setDictionaryImpl(dictionary, offset, byteCount, streamHandle); 295 } 296 297 private native void setDictionaryImpl(byte[] dictionary, int offset, int byteCount, long handle); 298 299 /** 300 * Sets the current input to to be decompressed. This method should only be 301 * called if {@link #needsInput} returns {@code true}. 302 */ 303 public synchronized void setInput(byte[] buf) { 304 setInput(buf, 0, buf.length); 305 } 306 307 /** 308 * Sets the current input to to be decompressed. This method should only be 309 * called if {@link #needsInput} returns {@code true}. 310 */ 311 public synchronized void setInput(byte[] buf, int offset, int byteCount) { 312 checkOpen(); 313 Arrays.checkOffsetAndCount(buf.length, offset, byteCount); 314 inRead = 0; 315 inLength = byteCount; 316 setInputImpl(buf, offset, byteCount, streamHandle); 317 } 318 319 private native void setInputImpl(byte[] buf, int offset, int byteCount, long handle); 320 321 synchronized int setFileInput(FileDescriptor fd, long offset, int byteCount) { 322 checkOpen(); 323 inRead = 0; 324 inLength = setFileInputImpl(fd, offset, byteCount, streamHandle); 325 return inLength; 326 } 327 328 private native int setFileInputImpl(FileDescriptor fd, long offset, int byteCount, long handle); 329 330 private void checkOpen() { 331 if (streamHandle == -1) { 332 throw new IllegalStateException("attempt to use Inflater after calling end"); 333 } 334 } 335} 336