1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
/* * @(#)DeflaterOutputStream.java 1.36 06/03/13 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util.zip; import java.io.FilterOutputStream; import java.io.OutputStream; import java.io.InputStream; import java.io.IOException; /** * This class implements an output stream filter for compressing data in * the "deflate" compression format. It is also used as the basis for other * types of compression filters, such as GZIPOutputStream. * * @see Deflater * @version 1.36, 03/13/06 * @author David Connelly */ public class DeflaterOutputStream extends FilterOutputStream { /** * Compressor for this stream. */ protected Deflater def; /** * Output buffer for writing compressed data. */ protected byte[] buf; /** * Indicates that the stream has been closed. */ private boolean closed = false; /** * Creates a new output stream with the specified compressor and * buffer size. * @param out the output stream * @param def the compressor ("deflater") * @param size the output buffer size * @exception IllegalArgumentException if size is <= 0 */ public DeflaterOutputStream(OutputStream out, Deflater def, int size) { super(out); if (out == null || def == null) { throw new NullPointerException(); } else if (size <= 0) { throw new IllegalArgumentException("buffer size <= 0"); } this.def = def; buf = new byte[size]; } /** * Creates a new output stream with the specified compressor and * a default buffer size. * @param out the output stream * @param def the compressor ("deflater") */ public DeflaterOutputStream(OutputStream out, Deflater def) { this(out, def, 512); } boolean usesDefaultDeflater = false; /** * Creates a new output stream with a default compressor and buffer size. * @param out the output stream */ public DeflaterOutputStream(OutputStream out) { this(out, new Deflater()); usesDefaultDeflater = true; } /** * Writes a byte to the compressed output stream. This method will * block until the byte can be written. * @param b the byte to be written * @exception IOException if an I/O error has occurred */ public void write(int b) throws IOException { byte[] buf = new byte[1]; buf[0] = (byte)(b & 0xff); write(buf, 0, 1); } /** * Writes an array of bytes to the compressed output stream. This * method will block until all the bytes are written. * @param b 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 void write(byte[] b, int off, int len) throws IOException { if (def.finished()) { throw new IOException("write beyond end of stream"); } if ((off | len | (off + len) | (b.length - (off + len))) < 0) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } if (!def.finished()) { // Deflate no more than stride bytes at a time. This avoids // excess copying in deflateBytes (see Deflater.c) int stride = buf.length; for (int i = 0; i < len; i+= stride) { def.setInput(b, off + i, Math.min(stride, len - i)); while (!def.needsInput()) { deflate(); } } } } /** * 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(); } } } /** * 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 { if (!closed) { finish(); if (usesDefaultDeflater) def.end(); out.close(); closed = true; } } /** * Writes next block of compressed data to the output stream. * @throws IOException if an I/O error has occurred */ protected void deflate() throws IOException { int len = def.deflate(buf, 0, buf.length); if (len > 0) { out.write(buf, 0, len); } } }