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