1 /* 2 * Copyright 1996-2006 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 26 package java.util.zip; 27 28 import java.io.FilterOutputStream; 29 import java.io.OutputStream; 30 import java.io.InputStream; 31 import java.io.IOException; 32 33 /** 34 * This class implements an output stream filter for compressing data in 35 * the "deflate" compression format. It is also used as the basis for other 36 * types of compression filters, such as GZIPOutputStream. 37 * 38 * @see Deflater 39 * @author David Connelly 40 */ 41 public 42 class DeflaterOutputStream extends FilterOutputStream { 43 /** 44 * Compressor for this stream. 45 */ 46 protected Deflater def; 47 48 /** 49 * Output buffer for writing compressed data. 50 */ 51 protected byte[] buf; 52 53 /** 54 * Indicates that the stream has been closed. 55 */ 56 57 private boolean closed = false; 58 59 /** 60 * Creates a new output stream with the specified compressor and 61 * buffer size. 62 * @param out the output stream 63 * @param def the compressor ("deflater") 64 * @param size the output buffer size 65 * @exception IllegalArgumentException if size is <= 0 66 */ 67 public DeflaterOutputStream(OutputStream out, Deflater def, int size) { 68 super(out); 69 if (out == null || def == null) { 70 throw new NullPointerException(); 71 } else if (size <= 0) { 72 throw new IllegalArgumentException("buffer size <= 0"); 73 } 74 this.def = def; 75 buf = new byte[size]; 76 } 77 78 /** 79 * Creates a new output stream with the specified compressor and 80 * a default buffer size. 81 * @param out the output stream 82 * @param def the compressor ("deflater") 83 */ 84 public DeflaterOutputStream(OutputStream out, Deflater def) { 85 this(out, def, 512); 86 } 87 88 boolean usesDefaultDeflater = false; 89 90 /** 91 * Creates a new output stream with a default compressor and buffer size. 92 * @param out the output stream 93 */ 94 public DeflaterOutputStream(OutputStream out) { 95 this(out, new Deflater()); 96 usesDefaultDeflater = true; 97 } 98 99 /** 100 * Writes a byte to the compressed output stream. This method will 101 * block until the byte can be written. 102 * @param b the byte to be written 103 * @exception IOException if an I/O error has occurred 104 */ 105 public void write(int b) throws IOException { 106 byte[] buf = new byte[1]; 107 buf[0] = (byte)(b & 0xff); 108 write(buf, 0, 1); 109 } 110 111 /** 112 * Writes an array of bytes to the compressed output stream. This 113 * method will block until all the bytes are written. 114 * @param b the data to be written 115 * @param off the start offset of the data 116 * @param len the length of the data 117 * @exception IOException if an I/O error has occurred 118 */ 119 public void write(byte[] b, int off, int len) throws IOException { 120 if (def.finished()) { 121 throw new IOException("write beyond end of stream"); 122 } 123 if ((off | len | (off + len) | (b.length - (off + len))) < 0) { 124 throw new IndexOutOfBoundsException(); 125 } else if (len == 0) { 126 return; 127 } 128 if (!def.finished()) { 129 // Deflate no more than stride bytes at a time. This avoids 130 // excess copying in deflateBytes (see Deflater.c) 131 int stride = buf.length; 132 for (int i = 0; i < len; i+= stride) { 133 def.setInput(b, off + i, Math.min(stride, len - i)); 134 while (!def.needsInput()) { 135 deflate(); 136 } 137 } 138 } 139 } 140 141 /** 142 * Finishes writing compressed data to the output stream without closing 143 * the underlying stream. Use this method when applying multiple filters 144 * in succession to the same output stream. 145 * @exception IOException if an I/O error has occurred 146 */ 147 public void finish() throws IOException { 148 if (!def.finished()) { 149 def.finish(); 150 while (!def.finished()) { 151 deflate(); 152 } 153 } 154 } 155 156 /** 157 * Writes remaining compressed data to the output stream and closes the 158 * underlying stream. 159 * @exception IOException if an I/O error has occurred 160 */ 161 public void close() throws IOException { 162 if (!closed) { 163 finish(); 164 if (usesDefaultDeflater) 165 def.end(); 166 out.close(); 167 closed = true; 168 } 169 } 170 171 /** 172 * Writes next block of compressed data to the output stream. 173 * @throws IOException if an I/O error has occurred 174 */ 175 protected void deflate() throws IOException { 176 int len = def.deflate(buf, 0, buf.length); 177 if (len > 0) { 178 out.write(buf, 0, len); 179 } 180 } 181 }