/// 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