0N/A/*
2362N/A * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.util.zip;
0N/A
0N/Aimport java.io.FilterOutputStream;
0N/Aimport java.io.IOException;
0N/Aimport java.io.OutputStream;
0N/A
0N/A/**
0N/A * Implements an output stream filter for uncompressing data stored in the
0N/A * "deflate" compression format.
0N/A *
0N/A * @since 1.6
0N/A * @author David R Tribble (david@tribble.com)
0N/A *
0N/A * @see InflaterInputStream
0N/A * @see DeflaterInputStream
0N/A * @see DeflaterOutputStream
0N/A */
0N/A
0N/Apublic class InflaterOutputStream extends FilterOutputStream {
0N/A /** Decompressor for this stream. */
0N/A protected final Inflater inf;
0N/A
0N/A /** Output buffer for writing uncompressed data. */
0N/A protected final byte[] buf;
0N/A
0N/A /** Temporary write buffer. */
0N/A private final byte[] wbuf = new byte[1];
0N/A
0N/A /** Default decompressor is used. */
0N/A private boolean usesDefaultInflater = false;
0N/A
0N/A /** true iff {@link #close()} has been called. */
0N/A private boolean closed = false;
0N/A
0N/A /**
0N/A * Checks to make sure that this stream has not been closed.
0N/A */
0N/A private void ensureOpen() throws IOException {
0N/A if (closed) {
0N/A throw new IOException("Stream closed");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Creates a new output stream with a default decompressor and buffer
0N/A * size.
0N/A *
0N/A * @param out output stream to write the uncompressed data to
0N/A * @throws NullPointerException if {@code out} is null
0N/A */
0N/A public InflaterOutputStream(OutputStream out) {
0N/A this(out, new Inflater());
0N/A usesDefaultInflater = true;
0N/A }
0N/A
0N/A /**
0N/A * Creates a new output stream with the specified decompressor and a
0N/A * default buffer size.
0N/A *
0N/A * @param out output stream to write the uncompressed data to
0N/A * @param infl decompressor ("inflater") for this stream
0N/A * @throws NullPointerException if {@code out} or {@code infl} is null
0N/A */
0N/A public InflaterOutputStream(OutputStream out, Inflater infl) {
0N/A this(out, infl, 512);
0N/A }
0N/A
0N/A /**
0N/A * Creates a new output stream with the specified decompressor and
0N/A * buffer size.
0N/A *
0N/A * @param out output stream to write the uncompressed data to
0N/A * @param infl decompressor ("inflater") for this stream
0N/A * @param bufLen decompression buffer size
0N/A * @throws IllegalArgumentException if {@code bufLen} is <= 0
0N/A * @throws NullPointerException if {@code out} or {@code infl} is null
0N/A */
0N/A public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) {
0N/A super(out);
0N/A
0N/A // Sanity checks
0N/A if (out == null)
0N/A throw new NullPointerException("Null output");
0N/A if (infl == null)
0N/A throw new NullPointerException("Null inflater");
0N/A if (bufLen <= 0)
0N/A throw new IllegalArgumentException("Buffer size < 1");
0N/A
0N/A // Initialize
0N/A inf = infl;
0N/A buf = new byte[bufLen];
0N/A }
0N/A
0N/A /**
0N/A * Writes any remaining uncompressed data to the output stream and closes
0N/A * the underlying output stream.
0N/A *
0N/A * @throws IOException if an I/O error occurs
0N/A */
0N/A public void close() throws IOException {
0N/A if (!closed) {
0N/A // Complete the uncompressed output
0N/A try {
0N/A finish();
0N/A } finally {
0N/A out.close();
0N/A closed = true;
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Flushes this output stream, forcing any pending buffered output bytes to be
0N/A * written.
0N/A *
0N/A * @throws IOException if an I/O error occurs or this stream is already
0N/A * closed
0N/A */
0N/A public void flush() throws IOException {
0N/A ensureOpen();
0N/A
0N/A // Finish decompressing and writing pending output data
0N/A if (!inf.finished()) {
0N/A try {
0N/A while (!inf.finished() && !inf.needsInput()) {
0N/A int n;
0N/A
0N/A // Decompress pending output data
0N/A n = inf.inflate(buf, 0, buf.length);
0N/A if (n < 1) {
0N/A break;
0N/A }
0N/A
0N/A // Write the uncompressed output data block
0N/A out.write(buf, 0, n);
0N/A }
0N/A super.flush();
0N/A } catch (DataFormatException ex) {
0N/A // Improperly formatted compressed (ZIP) data
0N/A String msg = ex.getMessage();
0N/A if (msg == null) {
0N/A msg = "Invalid ZLIB data format";
0N/A }
0N/A throw new ZipException(msg);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Finishes writing uncompressed data to the output stream without closing
0N/A * the underlying stream. Use this method when applying multiple filters in
0N/A * succession to the same output stream.
0N/A *
0N/A * @throws IOException if an I/O error occurs or this stream is already
0N/A * closed
0N/A */
0N/A public void finish() throws IOException {
0N/A ensureOpen();
0N/A
0N/A // Finish decompressing and writing pending output data
0N/A flush();
0N/A if (usesDefaultInflater) {
0N/A inf.end();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Writes a byte to the uncompressed output stream.
0N/A *
0N/A * @param b a single byte of compressed data to decompress and write to
0N/A * the output stream
0N/A * @throws IOException if an I/O error occurs or this stream is already
0N/A * closed
0N/A * @throws ZipException if a compression (ZIP) format error occurs
0N/A */
0N/A public void write(int b) throws IOException {
0N/A // Write a single byte of data
0N/A wbuf[0] = (byte) b;
0N/A write(wbuf, 0, 1);
0N/A }
0N/A
0N/A /**
0N/A * Writes an array of bytes to the uncompressed output stream.
0N/A *
0N/A * @param b buffer containing compressed data to decompress and write to
0N/A * the output stream
0N/A * @param off starting offset of the compressed data within {@code b}
0N/A * @param len number of bytes to decompress from {@code b}
0N/A * @throws IndexOutOfBoundsException if {@code off} < 0, or if
0N/A * {@code len} < 0, or if {@code len} > {@code b.length - off}
0N/A * @throws IOException if an I/O error occurs or this stream is already
0N/A * closed
0N/A * @throws NullPointerException if {@code b} is null
0N/A * @throws ZipException if a compression (ZIP) format error occurs
0N/A */
0N/A public void write(byte[] b, int off, int len) throws IOException {
0N/A // Sanity checks
0N/A ensureOpen();
0N/A if (b == null) {
0N/A throw new NullPointerException("Null buffer for read");
0N/A } else if (off < 0 || len < 0 || len > b.length - off) {
0N/A throw new IndexOutOfBoundsException();
0N/A } else if (len == 0) {
0N/A return;
0N/A }
0N/A
0N/A // Write uncompressed data to the output stream
0N/A try {
0N/A for (;;) {
0N/A int n;
0N/A
0N/A // Fill the decompressor buffer with output data
0N/A if (inf.needsInput()) {
0N/A int part;
0N/A
0N/A if (len < 1) {
0N/A break;
0N/A }
0N/A
0N/A part = (len < 512 ? len : 512);
0N/A inf.setInput(b, off, part);
0N/A off += part;
0N/A len -= part;
0N/A }
0N/A
0N/A // Decompress and write blocks of output data
0N/A do {
0N/A n = inf.inflate(buf, 0, buf.length);
0N/A if (n > 0) {
0N/A out.write(buf, 0, n);
0N/A }
0N/A } while (n > 0);
0N/A
0N/A // Check the decompressor
0N/A if (inf.finished()) {
0N/A break;
0N/A }
0N/A if (inf.needsDictionary()) {
0N/A throw new ZipException("ZLIB dictionary missing");
0N/A }
0N/A }
0N/A } catch (DataFormatException ex) {
0N/A // Improperly formatted compressed (ZIP) data
0N/A String msg = ex.getMessage();
0N/A if (msg == null) {
0N/A msg = "Invalid ZLIB data format";
0N/A }
0N/A throw new ZipException(msg);
0N/A }
0N/A }
0N/A}