//============================================================================== // DeflaterInputStream.java //============================================================================== package tribble.io; // System imports import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.IllegalArgumentException; import java.lang.NullPointerException; import java.lang.String; import java.lang.System; import java.lang.Throwable; import java.util.zip.Deflater; import java.util.zip.DeflaterOutputStream; // Local imports // (None) /******************************************************************************* * Implements an input stream filter for compressing data in the "deflate" * compression format. * *
* This class serves as a complement to the standard * java.util.zip.InflaterInputStream and * java.util.zip.DeflaterOutputStream classes. * It compresses ("deflates") data like the latter class, but reads the * compressed data from an input stream like the former class. * * * @version $Revision: 1.6 $ $Date: 2006/02/13 23:58:17 $ * @since 2005-05-29 * @author David R. Tribble * (david@tribble.com). * *
* Copyright ©2005 by David R. Tribble, all rights reserved.
*
* Permission is granted to freely use and distribute this source
* code provided that the original copyright and authorship notices
* remain intact.
*
* @see InflaterOutputStream
* @see java.util.zip.DeflaterOutputStream
* @see java.util.zip.InflaterInputStream
* @see java.util.zip.DeflaterInputStream
*/
public class DeflaterInputStream
extends java.io.FilterInputStream
{
// Identification
/** Revision information. */
static final String REV =
"@(#)tribble/io/DeflaterInputStream.java $Revision: 1.6 $ $Date: 2006/02/13 23:58:17 $\n";
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Constants
/** Default buffer size (512 bytes). */
private static final int DFL_BUFLEN = 512;
/** I/O buffer size (in bytes) (see {@link #main main()}). */
private static final int IO_BUFLEN = 4*1024;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Static methods
/***************************************************************************
* Uncompress a file containing data stored in the "deflate" compression
* format.
*
*
* The file to be uncompressed should contain compressed data stored in the * "deflate" compression format, such as the output from the * {@link InflaterOutputStream} class. * * *
* Usage *
* * java tribble.io.DeflaterInputStream [-option...] file * * *
* Options *
*
* Note that this method can be called multiple times with no ill effects. * * @throws IOException * Thrown if an I/O error occurs. * * @since 1.1, 2005-06-29 */ public void close() throws IOException //overrides java.io.FilterInputStream { InputStream inp; Deflater defl; // Sanity check if (super.in == null) return; // Clean up inp = super.in; super.in = null; defl = m_defl; m_defl = null; m_buf = null; if (m_isDefault) defl.end(); inp.close(); } /*************************************************************************** * Read compressed data from the input stream. * This will block until some input can be read and compressed. * * @return * A single byte of compressed data (in the range * [0x00,0xFF]), or -1 if the end of the uncompressed input * stream is reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. * * @since 1.1, 2005-06-29 */ public int read() throws IOException //overrides java.io.FilterInputStream { int len; // Read a single byte of compressed data len = read(m_rbuf, 0, 1); if (len <= 0) return (-1); return (m_rbuf[0] & 0xFF); } /*************************************************************************** * Read compressed data from the input stream. * This will block until some input can be read and compressed. * * @param buf * Buffer into which the data is read. * An attempt is made to fill the entire array. * * @return * The actual number of bytes read, or -1 if the end of the uncompressed * input stream is reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. * * @since 1.1, 2005-06-29 */ public int read(byte[] buf) throws IOException //overrides java.io.FilterInputStream { // Read a block of compressed data return (read(buf, 0, buf.length)); } /*************************************************************************** * Read compressed data from the input stream. * This will block until some input can be read and compressed. * * @param buf * Buffer into which the data is read. * * @param off * Starting offset of the data within buf. * * @param len * Maximum number of compressed bytes to read into buf. * * @return * The actual number of bytes read, or -1 if the end of the uncompressed * input stream is reached. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. * * @since 1.1, 2005-06-29 */ public int read(byte[] buf, int off, int len) throws IOException //overrides java.io.FilterInputStream { int cnt; // Sanity checks if (super.in == null) throw new NullPointerException(); if ((off | len | (off + len)) < 0) throw new IndexOutOfBoundsException(); if ((buf.length - (off + len)) < 0) throw new IndexOutOfBoundsException(); // Read and compress (deflate) input data bytes cnt = 0; while (len > 0 && !m_defl.finished()) { int n; // Read data from the input stream if (m_defl.needsInput() && !m_eof) { n = super.in.read(m_buf, 0, m_buf.length); if (n < 0) { // End of the input stream reached m_defl.finish(); m_eof = true; } else if (n > 0) { m_inBytes += n; m_defl.setInput(m_buf, 0, n); } } // Compress the input data, filling the read buffer n = m_defl.deflate(buf, off, len); cnt += n; off += n; len -= n; m_outBytes += n; } // Done if (cnt == 0 && m_eof) return (-1); return (cnt); } /*************************************************************************** * Skip over and discard data from the input stream. * This method may block until the specified number of bytes are read and * skipped. * * @param n * Number of bytes to be skipped. * * @return * The actual number of bytes skipped. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @throws NullPointerException (unchecked) * Thrown if the underlying input stream is closed. * * @since 1.1, 2005-06-29 */ public long skip(long n) throws IOException //overrides java.io.FilterInputStream { long cnt; // Sanity checks if (super.in == null) throw new NullPointerException(); // Set up if (m_rbuf.length < 128) m_rbuf = new byte[128]; // Skip bytes by repeatedly decompressing small blocks cnt = 0; while (n > 0) { int len; // Read a small block of uncompressed bytes len = m_rbuf.length; len = read(m_rbuf, 0, (n <= len ? (int) n : len)); // Check for end of input reached if (len < 0) break; // Update counters cnt += len; n -= len; } return (cnt); } /*************************************************************************** * Determine the number of bytes that can be read from this input stream * without blocking. * *
* Programs should not count on this method to return the actual number * of bytes that could be read without blocking. * * @return * Zero after the end of the underlying input stream has been reached, * otherwise always returns 1. * * @throws IOException * Thrown if an I/O (read) error occurs. * * @since 1.1, 2005-06-29 */ public int available() throws IOException //overrides java.io.FilterInputStream { if (m_eof || super.in == null) return (0); return (1); } /*************************************************************************** * Test if this input stream supports the {@link #mark mark()} and * {@link #reset reset()} methods. * These operations are not supported. * * @return * False, always. * * @since 1.1, 2005-06-29 */ public boolean markSupported() //overrides java.io.FilterInputStream { // Operation not supported return (false); } /*************************************************************************** * This operation is not supported. * * @param limit * Maximum bytes that can be read before invalidating the position marker. * * @since 1.1, 2005-06-29 */ public void mark(int limit) //overrides java.io.FilterInputStream { // Operation not supported } /*************************************************************************** * This operation is not supported. * * @throws IOException * Always thrown. * * @since 1.1, 2005-06-29 */ public void reset() throws IOException //overrides java.io.FilterInputStream { // Operation not supported throw new IOException("Mark/reset operation not supported"); } /*************************************************************************** * Determine the total number of bytes read from the underlying input stream. * * @return * The actual number of bytes read from the underlying input stream prior to * being compressed. * * @since 1.2, 2005-06-30 */ public long getTotalIn() { return (m_inBytes); } /*************************************************************************** * Determine the total number of bytes read from this compressed input * stream. * * @return * The number of bytes read from this input stream after being compressed. * * @since 1.2, 2005-06-30 */ public long getTotalOut() { return (m_outBytes); } /*************************************************************************** * Finalization. * * @since 1.6, 2006-02-13 */ protected synchronized void finalize() throws Throwable //overrides java.io.FilterInputStream { Deflater defl; // Shut down the compressor m_buf = null; defl = m_defl; m_defl = null; if (defl != null && m_isDefault) defl.end(); // Cascade super.finalize(); super.in = null; } } // End DeflaterInputStream.java