OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / util / zip / DeflaterOutputStream.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package java.util.zip;
19
20 import java.io.FilterOutputStream;
21 import java.io.IOException;
22 import java.io.OutputStream;
23
24 /**
25  * This class provides an implementation of {@code FilterOutputStream} that
26  * compresses data using the <i>DEFLATE</i> algorithm. Basically it wraps the
27  * {@code Deflater} class and takes care of the buffering.
28  *
29  * @see Deflater
30  */
31 public class DeflaterOutputStream extends FilterOutputStream {
32     static final int BUF_SIZE = 512;
33
34     /**
35      * The buffer for the data to be written to.
36      */
37     protected byte[] buf;
38
39     /**
40      * The deflater used.
41      */
42     protected Deflater def;
43
44     boolean done = false;
45
46     private final boolean syncFlush;
47
48     /**
49      * This constructor lets you pass the {@code Deflater} specifying the
50      * compression algorithm.
51      *
52      * @param os
53      *            is the {@code OutputStream} where to write the compressed data
54      *            to.
55      * @param def
56      *            is the specific {@code Deflater} that is used to compress
57      *            data.
58      */
59     public DeflaterOutputStream(OutputStream os, Deflater def) {
60         this(os, def, BUF_SIZE, false);
61     }
62
63     /**
64      * This is the most basic constructor. You only need to pass the {@code
65      * OutputStream} to which the compressed data shall be written to. The
66      * default settings for the {@code Deflater} and internal buffer are used.
67      * In particular the {@code Deflater} produces a ZLIB header in the output
68      * stream.
69      *
70      * @param os
71      *            is the OutputStream where to write the compressed data to.
72      */
73     public DeflaterOutputStream(OutputStream os) {
74         this(os, new Deflater(), BUF_SIZE, false);
75     }
76
77     /**
78      * This constructor lets you specify both the compression algorithm as well
79      * as the internal buffer size to be used.
80      *
81      * @param os
82      *            is the {@code OutputStream} where to write the compressed data
83      *            to.
84      * @param def
85      *            is the specific {@code Deflater} that will be used to compress
86      *            data.
87      * @param bsize
88      *            is the size to be used for the internal buffer.
89      */
90     public DeflaterOutputStream(OutputStream os, Deflater def, int bsize) {
91         this(os, def, bsize, false);
92     }
93
94     /**
95      * @hide
96      * @since 1.7
97      */
98     public DeflaterOutputStream(OutputStream os, boolean syncFlush) {
99         this(os, new Deflater(), BUF_SIZE, syncFlush);
100     }
101
102     /**
103      * @hide
104      * @since 1.7
105      */
106     public DeflaterOutputStream(OutputStream os, Deflater def, boolean syncFlush) {
107         this(os, def, BUF_SIZE, syncFlush);
108     }
109
110     /**
111      * @hide
112      * @since 1.7
113      */
114     public DeflaterOutputStream(OutputStream os, Deflater def, int bsize, boolean syncFlush) {
115         super(os);
116         if (os == null || def == null) {
117             throw new NullPointerException();
118         }
119         if (bsize <= 0) {
120             throw new IllegalArgumentException();
121         }
122         this.def = def;
123         this.syncFlush = syncFlush;
124         buf = new byte[bsize];
125     }
126
127     /**
128      * Compress the data in the input buffer and write it to the underlying
129      * stream.
130      *
131      * @throws IOException
132      *             If an error occurs during deflation.
133      */
134     protected void deflate() throws IOException {
135         int x = 0;
136         do {
137             x = def.deflate(buf);
138             out.write(buf, 0, x);
139         } while (!def.needsInput());
140     }
141
142     /**
143      * Writes any unwritten compressed data to the underlying stream, the closes
144      * all underlying streams. This stream can no longer be used after close()
145      * has been called.
146      *
147      * @throws IOException
148      *             If an error occurs while closing the data compression
149      *             process.
150      */
151     @Override
152     public void close() throws IOException {
153         if (!def.finished()) {
154             finish();
155         }
156         def.end();
157         out.close();
158     }
159
160     /**
161      * Writes any unwritten data to the underlying stream. Does not close the
162      * stream.
163      *
164      * @throws IOException
165      *             If an error occurs.
166      */
167     public void finish() throws IOException {
168         if (done) {
169             return;
170         }
171         def.finish();
172         int x = 0;
173         while (!def.finished()) {
174             if (def.needsInput()) {
175                 def.setInput(buf, 0, 0);
176             }
177             x = def.deflate(buf);
178             out.write(buf, 0, x);
179         }
180         done = true;
181     }
182
183     @Override
184     public void write(int i) throws IOException {
185         byte[] b = new byte[1];
186         b[0] = (byte) i;
187         write(b, 0, 1);
188     }
189
190     /**
191      * Compresses {@code nbytes} of data from {@code buf} starting at
192      * {@code off} and writes it to the underlying stream.
193      *
194      * @param buffer
195      *            the buffer of data to compress.
196      * @param off
197      *            offset in buffer to extract data from.
198      * @param nbytes
199      *            the number of bytes of data to read from the buffer.
200      * @throws IOException
201      *             If an error occurs during writing.
202      */
203     @Override
204     public void write(byte[] buffer, int off, int nbytes) throws IOException {
205         if (done) {
206             throw new IOException("attempt to write after finish");
207         }
208         // avoid int overflow, check null buf
209         if (off <= buffer.length && nbytes >= 0 && off >= 0
210                 && buffer.length - off >= nbytes) {
211             if (!def.needsInput()) {
212                 throw new IOException();
213             }
214             def.setInput(buffer, off, nbytes);
215             deflate();
216         } else {
217             throw new ArrayIndexOutOfBoundsException();
218         }
219     }
220
221     /**
222      * Flushes the underlying stream. This flushes only the bytes that can be
223      * compressed at the highest level.
224      *
225      * <p>For deflater output streams constructed with Java 7's
226      * {@code syncFlush} parameter set to true (not yet available on Android),
227      * this first flushes all outstanding data so that it may be immediately
228      * read by its recipient. Doing so may degrade compression.
229      */
230     @Override public void flush() throws IOException {
231         if (syncFlush) {
232             int count = def.deflate(buf, 0, buf.length, Deflater.SYNC_FLUSH);
233             out.write(buf, 0, count);
234         }
235         out.flush();
236     }
237 }