/// Bug 4679743: Additional Compressed Streams Requested /// This file is also available at: /// http://david.tribble.com/src/jdk/InflaterOutputStream.java ///--- CUT HERE ---------------------------------------------------------------- /* * @(#)InflaterOutputStream.java 1.2 2005-08-09 * * Copyright ©2005 Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A. * All rights reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. */ package java.util.zip; // System imports import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.IllegalArgumentException; import java.lang.NullPointerException; import java.lang.String; import java.lang.Throwable; // Local imports import java.util.zip.DataFormatException; import java.util.zip.Inflater; import java.util.zip.ZipException; /******************************************************************************* * Implements an output stream filter for uncompressing data stored in the * "deflate" compression format. * * @version 1.2 2005-08-09 * @since JDK 1.6 * @author David R Tribble (david@tribble.com) * * @see InflaterInputStream * @see DeflaterInputStream * @see DeflaterOutputStream */ public class InflaterOutputStream extends java.io.FilterOutputStream { /** Default buffer size (512 bytes). */ private static final int DFL_BUFLEN = 512; /** Partial write block size. */ private static final int PART_LEN = 512; /** Decompressor for this stream. */ protected Inflater inf; /** Output buffer for writing compressed data. */ protected byte[] buf; /** Temporary write buffer. */ private byte[] wbuf = new byte[1]; /** Default decompressor is used. */ private boolean isDefault; /*************************************************************************** * Construct a new output stream with a default decompressor and buffer * size. * * @param out * Output stream to write the uncompressed data to. */ public InflaterOutputStream(OutputStream out) { this(out, new Inflater(), DFL_BUFLEN); isDefault = true; } /*************************************************************************** * Construct a new output stream with the specified decompressor and a * default buffer size. * * @param out * Output stream to write the uncompressed data to. * * @param infl * Decompressor ("inflater") for this stream. */ public InflaterOutputStream(OutputStream out, Inflater infl) { this(out, infl, DFL_BUFLEN); } /*************************************************************************** * Construct a new output stream with the specified decompressor and buffer * size. * * @param out * Output stream to write the uncompressed data to. * * @param infl * Decompressor ("inflater") for this stream. * * @param bufLen * Decompression buffer size. * * @throws NullPointerException (unchecked) * Thrown if out or infl is null. * * @throws IllegalArgumentException (unchecked) * Thrown if bufLen is less than 1. */ public InflaterOutputStream(OutputStream out, Inflater infl, int bufLen) { super(out); // Sanity checks if (out == null) throw new NullPointerException("Null output"); if (infl == null) throw new NullPointerException("Null inflater"); if (bufLen < 1) throw new IllegalArgumentException("Buffer size < 1"); // Initialize inf = infl; buf = new byte[bufLen]; } /*************************************************************************** * Write any remaining uncompressed data to the output stream and close the * underlying output stream. * * @throws IOException * Thrown if an I/O error occurs. */ public void close() throws IOException { if (out == null) return; // Complete the uncompressed output flush(); // Clean up if (isDefault) inf.end(); inf = null; buf = null; out.close(); out = null; } /*************************************************************************** * Flush this output stream and force any buffered output bytes to be * written out to the stream. * * @throws IOException * Thrown if an I/O error occurs. * * @throws NullPointerException (unchecked) * Thrown if the output stream is closed. */ public void flush() throws IOException { if (out == null) throw new NullPointerException(); // Finish decompressing and writing pending output data if (!inf.finished()) { try { while (!inf.finished() && !inf.needsInput()) { int n; // Decompress pending output data n = inf.inflate(this.buf, 0, this.buf.length); if (n < 1) break; // Write the decompressed output data block out.write(this.buf, 0, n); } } catch (DataFormatException ex) { String msg; // Improperly formatted compressed (ZIP) data msg = ex.getMessage(); if (msg == null) msg = "Invalid ZLIB data format"; throw new ZipException(msg); } } } /*************************************************************************** * Finishes writing uncompressed data to the output stream without closing * the underlying stream. * Use this method when applying multiple filters in succession to the same * output stream. * * @throws IOException * Thrown if an I/O error occurs. * * @throws NullPointerException (unchecked) * Thrown if the output stream is closed. */ public void finish() throws IOException { if (out == null) throw new NullPointerException(); // Finish decompressing and writing pending output data inf.end(); flush(); } /*************************************************************************** * Write data to this uncompressed output stream. * * @param b * A single byte of compresses data to decompress and write to the output * stream. * * @throws ZipException * Thrown if a compression (ZIP) format error occurs. * * @throws IOException * Thrown if an I/O error occurs. * * @throws NullPointerException (unchecked) * Thrown if the output stream is closed. */ public void write(int b) throws IOException { // Write a single byte of data wbuf[0] = (byte) b; write(wbuf, 0, 1); } /*************************************************************************** * Write data to this uncompressed output stream. * * @param buf * Buffer containing compressed data to decompress and write to the output * stream. * * @throws ZipException * Thrown if a compression (ZIP) format error occurs. * * @throws IOException * Thrown if an I/O error occurs. * * @throws NullPointerException (unchecked) * Thrown if the output stream is closed. */ public void write(/*const*/ byte[] buf) throws IOException { // Write a block of uncompressed data write(buf, 0, buf.length); } /*************************************************************************** * Write data to this uncompressed output stream. * * @param buf * Buffer containing compressed data to decompress and write to the output * stream. * * @param off * Starting offset of the compressed data within buf. * * @param len * Number of bytes to decompress from buf. * * @throws ZipException * Thrown if a compression (ZIP) format error occurs. * * @throws IOException * Thrown if an I/O error occurs. * * @throws NullPointerException (unchecked) * Thrown if the output stream is closed. */ public void write(/*const*/ byte[] buf, int off, int len) throws IOException { // Sanity checks if (out == null) throw new NullPointerException(); if ((off | len | (off + len)) < 0) throw new IndexOutOfBoundsException(); if ((buf.length - (off + len)) < 0) throw new IndexOutOfBoundsException(); // Write decompressed data to the output stream try { for (;;) { int n; // Fill the decompressor buffer with output data if (inf.needsInput()) { int part; if (len < 1) break; part = (len < PART_LEN ? len : PART_LEN); inf.setInput(buf, off, part); off += part; len -= part; } // Decompress and write blocks of output data do { n = inf.inflate(this.buf, 0, this.buf.length); if (n > 0) { out.write(this.buf, 0, n); } } while (n > 0); // Check the decompressor if (inf.finished()) break; if (inf.needsDictionary()) throw new ZipException("ZLIB dictionary missing"); } } catch (DataFormatException ex) { String msg; // Improperly formatted compressed (ZIP) data msg = ex.getMessage(); if (msg == null) msg = "Invalid ZLIB data format"; throw new ZipException(msg); } } } // End InflaterOutputStream.java