import java.util.zip.*; import java.io.OutputStream; import java.io.IOException; /** * This class essentially copies sources of original GZIPOutputStream, * just adds ability to pass in desired compression level into constructor */ public class GZIPOutputStreamEx extends DeflaterOutputStream { /** * CRC-32 of uncompressed data. */ protected CRC32 crc = new CRC32(); /* * GZIP header magic number. */ private final static int GZIP_MAGIC = 0x8b1f; /** * Creates a new output stream with the specified buffer size. * @param out the output stream * @param size the output buffer size * @exception IOException If an I/O error has occurred. * @exception IllegalArgumentException if size is <= 0 */ public GZIPOutputStreamEx(OutputStream out, int size, int compression) throws IOException { super(out, new Deflater(compression, true), size); writeHeader(); crc.reset(); } /** * Creates a new output stream with a default buffer size. * @param out the output stream * @exception IOException If an I/O error has occurred. */ public GZIPOutputStreamEx(OutputStream out, int compression) throws IOException { this(out, 512, compression); } /** * Writes array of bytes to the compressed output stream. This method * will block until all the bytes are written. * @param buf the data to be written * @param off the start offset of the data * @param len the length of the data * @exception IOException If an I/O error has occurred. */ public synchronized void write(byte[] buf, int off, int len) throws IOException { super.write(buf, off, len); crc.update(buf, off, len); } /** * Finishes writing compressed data to the output stream without closing * the underlying stream. Use this method when applying multiple filters * in succession to the same output stream. * @exception IOException if an I/O error has occurred */ public void finish() throws IOException { if (!def.finished()) { def.finish(); while (!def.finished()) { deflate(); } writeTrailer(); } } /** * Writes remaining compressed data to the output stream and closes the * underlying stream. * @exception IOException if an I/O error has occurred */ public void close() throws IOException { finish(); out.close(); } /* * Writes GZIP member header. */ private void writeHeader() throws IOException { writeShort(GZIP_MAGIC); // Magic number out.write(def.DEFLATED); // Compression method (CM) out.write(0); // Flags (FLG) writeInt(0); // Modification time (MTIME) out.write(0); // Extra flags (XFL) out.write(0); // Operating system (OS) } /* * Writes GZIP member trailer. */ private void writeTrailer() throws IOException { writeInt((int)crc.getValue()); // CRC-32 of uncompressed data writeInt(def.getTotalIn()); // Number of uncompressed bytes } /* * Writes integer in Intel byte order. */ private void writeInt(int i) throws IOException { writeShort(i & 0xffff); writeShort((i >> 16) & 0xffff); } /* * Writes short integer in Intel byte order. */ private void writeShort(int s) throws IOException { out.write(s & 0xff); out.write((s >> 8) & 0xff); } }