Home | History | Annotate | Download | only in zip
      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 java.io.FilterOutputStream;
     21 import java.io.IOException;
     22 import java.io.OutputStream;
     23 import java.util.Arrays;
     24 
     25 /**
     26  * An {@code OutputStream} filter to decompress data. Callers write
     27  * compressed data in the "deflate" format, and uncompressed data is
     28  * written to the underlying stream.
     29  * @since 1.6
     30  */
     31 public class InflaterOutputStream extends FilterOutputStream {
     32     private static final int DEFAULT_BUFFER_SIZE = 1024;
     33 
     34     protected final Inflater inf;
     35     protected final byte[] buf;
     36 
     37     private boolean closed = false;
     38 
     39     /**
     40      * Constructs an {@code InflaterOutputStream} with a new {@code Inflater} and an
     41      * implementation-defined default internal buffer size. {@code out} is a destination
     42      * for uncompressed data, and compressed data will be written to this stream.
     43      *
     44      * @param out the destination {@code OutputStream}
     45      */
     46     public InflaterOutputStream(OutputStream out) {
     47         this(out, new Inflater());
     48     }
     49 
     50     /**
     51      * Constructs an {@code InflaterOutputStream} with the given {@code Inflater} and an
     52      * implementation-defined default internal buffer size. {@code out} is a destination
     53      * for uncompressed data, and compressed data will be written to this stream.
     54      *
     55      * @param out the destination {@code OutputStream}
     56      * @param inf the {@code Inflater} to be used for decompression
     57      */
     58     public InflaterOutputStream(OutputStream out, Inflater inf) {
     59         this(out, inf, DEFAULT_BUFFER_SIZE);
     60     }
     61 
     62     /**
     63      * Constructs an {@code InflaterOutputStream} with the given {@code Inflater} and
     64      * given internal buffer size. {@code out} is a destination
     65      * for uncompressed data, and compressed data will be written to this stream.
     66      *
     67      * @param out the destination {@code OutputStream}
     68      * @param inf the {@code Inflater} to be used for decompression
     69      * @param bufferSize the length in bytes of the internal buffer
     70      */
     71     public InflaterOutputStream(OutputStream out, Inflater inf, int bufferSize) {
     72         super(out);
     73         if (out == null) {
     74             throw new NullPointerException("out == null");
     75         } else if (inf == null) {
     76             throw new NullPointerException("inf == null");
     77         }
     78         if (bufferSize <= 0) {
     79             throw new IllegalArgumentException("bufferSize <= 0: " + bufferSize);
     80         }
     81         this.inf = inf;
     82         this.buf = new byte[bufferSize];
     83     }
     84 
     85     /**
     86      * Writes remaining data into the output stream and closes the underlying
     87      * output stream.
     88      */
     89     @Override
     90     public void close() throws IOException {
     91         if (!closed) {
     92             finish();
     93             inf.end();
     94             out.close();
     95             closed = true;
     96         }
     97     }
     98 
     99     @Override
    100     public void flush() throws IOException {
    101         finish();
    102         out.flush();
    103     }
    104 
    105     /**
    106      * Finishes writing current uncompressed data into the InflaterOutputStream
    107      * without closing it.
    108      *
    109      * @throws IOException if an I/O error occurs, or the stream has been closed
    110      */
    111     public void finish() throws IOException {
    112         checkClosed();
    113         write();
    114     }
    115 
    116     /**
    117      * Writes a byte to the decompressing output stream. {@code b} should be a byte of
    118      * compressed input. The corresponding uncompressed data will be written to the underlying
    119      * stream.
    120      *
    121      * @param b the byte
    122      * @throws IOException if an I/O error occurs, or the stream has been closed
    123      * @throws ZipException if a zip exception occurs.
    124      */
    125     @Override
    126     public void write(int b) throws IOException, ZipException {
    127         write(new byte[] { (byte) b }, 0, 1);
    128     }
    129 
    130     /**
    131      * Writes to the decompressing output stream. The {@code bytes} array should contain
    132      * compressed input. The corresponding uncompressed data will be written to the underlying
    133      * stream.
    134      *
    135      * @throws IOException if an I/O error occurs, or the stream has been closed
    136      * @throws ZipException if a zip exception occurs.
    137      * @throws NullPointerException if {@code b == null}.
    138      * @throws IndexOutOfBoundsException if {@code off < 0 || len < 0 || off + len > b.length}
    139      */
    140     @Override
    141     public void write(byte[] bytes, int offset, int byteCount) throws IOException, ZipException {
    142         checkClosed();
    143         Arrays.checkOffsetAndCount(bytes.length, offset, byteCount);
    144         inf.setInput(bytes, offset, byteCount);
    145         write();
    146     }
    147 
    148     private void write() throws IOException, ZipException {
    149         try {
    150             int inflated;
    151             while ((inflated = inf.inflate(buf)) > 0) {
    152                 out.write(buf, 0, inflated);
    153             }
    154         } catch (DataFormatException e) {
    155             throw new ZipException();
    156         }
    157     }
    158 
    159     private void checkClosed() throws IOException {
    160         if (closed) {
    161             throw new IOException();
    162         }
    163     }
    164 }
    165