1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.util.zip; 28 29 import java.io.FilterOutputStream; 30 import java.io.OutputStream; 31 import java.io.InputStream; 32 import java.io.IOException; 33 34 /** 35 * This class implements an output stream filter for compressing data in 36 * the "deflate" compression format. It is also used as the basis for other 37 * types of compression filters, such as GZIPOutputStream. 38 * 39 * @see Deflater 40 * @author David Connelly 41 */ 42 public 43 class DeflaterOutputStream extends FilterOutputStream { 44 /** 45 * Compressor for this stream. 46 */ 47 protected Deflater def; 48 49 /** 50 * Output buffer for writing compressed data. 51 */ 52 protected byte[] buf; 53 54 /** 55 * Indicates that the stream has been closed. 56 */ 57 58 private boolean closed = false; 59 60 private final boolean syncFlush; 61 62 /** 63 * Creates a new output stream with the specified compressor, 64 * buffer size and flush mode. 65 66 * @param out the output stream 67 * @param def the compressor ("deflater") 68 * @param size the output buffer size 69 * @param syncFlush 70 * if {@code true} the {@link #flush()} method of this 71 * instance flushes the compressor with flush mode 72 * {@link Deflater#SYNC_FLUSH} before flushing the output 73 * stream, otherwise only flushes the output stream 74 * 75 * @throws IllegalArgumentException if size is <= 0 76 * 77 * @since 1.7 78 */ DeflaterOutputStream(OutputStream out, Deflater def, int size, boolean syncFlush)79 public DeflaterOutputStream(OutputStream out, 80 Deflater def, 81 int size, 82 boolean syncFlush) { 83 super(out); 84 if (out == null || def == null) { 85 throw new NullPointerException(); 86 } else if (size <= 0) { 87 throw new IllegalArgumentException("buffer size <= 0"); 88 } 89 this.def = def; 90 this.buf = new byte[size]; 91 this.syncFlush = syncFlush; 92 } 93 94 95 /** 96 * Creates a new output stream with the specified compressor and 97 * buffer size. 98 * 99 * <p>The new output stream instance is created as if by invoking 100 * the 4-argument constructor DeflaterOutputStream(out, def, size, false). 101 * 102 * @param out the output stream 103 * @param def the compressor ("deflater") 104 * @param size the output buffer size 105 * @exception IllegalArgumentException if size is <= 0 106 */ DeflaterOutputStream(OutputStream out, Deflater def, int size)107 public DeflaterOutputStream(OutputStream out, Deflater def, int size) { 108 this(out, def, size, false); 109 } 110 111 /** 112 * Creates a new output stream with the specified compressor, flush 113 * mode and a default buffer size. 114 * 115 * @param out the output stream 116 * @param def the compressor ("deflater") 117 * @param syncFlush 118 * if {@code true} the {@link #flush()} method of this 119 * instance flushes the compressor with flush mode 120 * {@link Deflater#SYNC_FLUSH} before flushing the output 121 * stream, otherwise only flushes the output stream 122 * 123 * @since 1.7 124 */ DeflaterOutputStream(OutputStream out, Deflater def, boolean syncFlush)125 public DeflaterOutputStream(OutputStream out, 126 Deflater def, 127 boolean syncFlush) { 128 this(out, def, 512, syncFlush); 129 } 130 131 132 /** 133 * Creates a new output stream with the specified compressor and 134 * a default buffer size. 135 * 136 * <p>The new output stream instance is created as if by invoking 137 * the 3-argument constructor DeflaterOutputStream(out, def, false). 138 * 139 * @param out the output stream 140 * @param def the compressor ("deflater") 141 */ DeflaterOutputStream(OutputStream out, Deflater def)142 public DeflaterOutputStream(OutputStream out, Deflater def) { 143 this(out, def, 512, false); 144 } 145 146 boolean usesDefaultDeflater = false; 147 148 149 /** 150 * Creates a new output stream with a default compressor, a default 151 * buffer size and the specified flush mode. 152 * 153 * @param out the output stream 154 * @param syncFlush 155 * if {@code true} the {@link #flush()} method of this 156 * instance flushes the compressor with flush mode 157 * {@link Deflater#SYNC_FLUSH} before flushing the output 158 * stream, otherwise only flushes the output stream 159 * 160 * @since 1.7 161 */ DeflaterOutputStream(OutputStream out, boolean syncFlush)162 public DeflaterOutputStream(OutputStream out, boolean syncFlush) { 163 this(out, new Deflater(), 512, syncFlush); 164 usesDefaultDeflater = true; 165 } 166 167 /** 168 * Creates a new output stream with a default compressor and buffer size. 169 * 170 * <p>The new output stream instance is created as if by invoking 171 * the 2-argument constructor DeflaterOutputStream(out, false). 172 * 173 * @param out the output stream 174 */ DeflaterOutputStream(OutputStream out)175 public DeflaterOutputStream(OutputStream out) { 176 this(out, false); 177 usesDefaultDeflater = true; 178 } 179 180 /** 181 * Writes a byte to the compressed output stream. This method will 182 * block until the byte can be written. 183 * @param b the byte to be written 184 * @exception IOException if an I/O error has occurred 185 */ write(int b)186 public void write(int b) throws IOException { 187 byte[] buf = new byte[1]; 188 buf[0] = (byte)(b & 0xff); 189 write(buf, 0, 1); 190 } 191 192 /** 193 * Writes an array of bytes to the compressed output stream. This 194 * method will block until all the bytes are written. 195 * @param b the data to be written 196 * @param off the start offset of the data 197 * @param len the length of the data 198 * @exception IOException if an I/O error has occurred 199 */ write(byte[] b, int off, int len)200 public void write(byte[] b, int off, int len) throws IOException { 201 if (def.finished()) { 202 throw new IOException("write beyond end of stream"); 203 } 204 if ((off | len | (off + len) | (b.length - (off + len))) < 0) { 205 throw new IndexOutOfBoundsException(); 206 } else if (len == 0) { 207 return; 208 } 209 if (!def.finished()) { 210 def.setInput(b, off, len); 211 while (!def.needsInput()) { 212 deflate(); 213 } 214 } 215 } 216 217 /** 218 * Finishes writing compressed data to the output stream without closing 219 * the underlying stream. Use this method when applying multiple filters 220 * in succession to the same output stream. 221 * @exception IOException if an I/O error has occurred 222 */ finish()223 public void finish() throws IOException { 224 if (!def.finished()) { 225 def.finish(); 226 while (!def.finished()) { 227 deflate(); 228 } 229 } 230 } 231 232 /** 233 * Writes remaining compressed data to the output stream and closes the 234 * underlying stream. 235 * @exception IOException if an I/O error has occurred 236 */ close()237 public void close() throws IOException { 238 if (!closed) { 239 finish(); 240 if (usesDefaultDeflater) 241 def.end(); 242 out.close(); 243 closed = true; 244 } 245 } 246 247 /** 248 * Writes next block of compressed data to the output stream. 249 * @throws IOException if an I/O error has occurred 250 */ deflate()251 protected void deflate() throws IOException { 252 int len = 0; 253 while ((len = def.deflate(buf, 0, buf.length)) > 0) { 254 out.write(buf, 0, len); 255 } 256 } 257 258 /** 259 * Flushes the compressed output stream. 260 * 261 * If {@link #DeflaterOutputStream(OutputStream, Deflater, int, boolean) 262 * syncFlush} is {@code true} when this compressed output stream is 263 * constructed, this method first flushes the underlying {@code compressor} 264 * with the flush mode {@link Deflater#SYNC_FLUSH} to force 265 * all pending data to be flushed out to the output stream and then 266 * flushes the output stream. Otherwise this method only flushes the 267 * output stream without flushing the {@code compressor}. 268 * 269 * @throws IOException if an I/O error has occurred 270 * 271 * @since 1.7 272 */ flush()273 public void flush() throws IOException { 274 if (syncFlush && !def.finished()) { 275 int len = 0; 276 while ((len = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH)) > 0) 277 { 278 out.write(buf, 0, len); 279 if (len < buf.length) 280 break; 281 } 282 } 283 out.flush(); 284 } 285 } 286