001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.util.zip;
019:
020: import java.io.FilterOutputStream;
021: import java.io.IOException;
022: import java.io.OutputStream;
023:
024: import org.apache.harmony.archive.internal.nls.Messages;
025:
026: /**
027: * The DeflaterOutputStream class implements a stream filter for the writing of
028: * compressed data to a stream. Compression is performed by an instance of
029: * Deflater.
030: */
031: public class DeflaterOutputStream extends FilterOutputStream {
032: static final int BUF_SIZE = 512;
033:
034: protected byte[] buf;
035:
036: protected Deflater def;
037:
038: boolean done = false;
039:
040: /**
041: * Constructs a new DeflaterOutputStream instance using os as the underlying
042: * stream. The provided Deflater instance will be used to compress data.
043: *
044: * @param os
045: * OutputStream to receive compressed data
046: * @param def
047: * Deflater to perform compression
048: */
049: public DeflaterOutputStream(OutputStream os, Deflater def) {
050: this (os, def, BUF_SIZE);
051: }
052:
053: /**
054: * Constructs a new DeflaterOutputStream instance using os as the underlying
055: * stream.
056: *
057: * @param os
058: * OutputStream to receive compressed data
059: */
060: public DeflaterOutputStream(OutputStream os) {
061: this (os, new Deflater());
062: }
063:
064: /**
065: * Constructs a new DeflaterOutputStream instance using os as the underlying
066: * stream. The provided Deflater instance will be used to compress data. The
067: * internal buffer for storing compressed data will be of size bsize.
068: *
069: * @param os
070: * OutputStream to receive compressed data
071: * @param def
072: * Deflater to perform compression
073: * @param bsize
074: * size of internal compression buffer
075: */
076: public DeflaterOutputStream(OutputStream os, Deflater def, int bsize) {
077: super (os);
078: if (os == null || def == null) {
079: throw new NullPointerException();
080: }
081: if (bsize <= 0) {
082: throw new IllegalArgumentException();
083: }
084: this .def = def;
085: buf = new byte[bsize];
086: }
087:
088: /**
089: * Compress the data in the input buffer and write it to the underlying
090: * stream.
091: *
092: * @exception java.io.IOException
093: * If an error occurs during deflation.
094: */
095: protected void deflate() throws IOException {
096: int x = 0;
097: do {
098: x = def.deflate(buf);
099: out.write(buf, 0, x);
100: } while (!def.needsInput());
101: }
102:
103: /**
104: * Writes any unwritten compressed data to the underlying stream, the closes
105: * all underlying streams. This stream can no longer be used after close()
106: * has been called.
107: *
108: * @exception java.io.IOException
109: * If an error occurs during close.
110: */
111: @Override
112: public void close() throws IOException {
113: if (!def.finished()) {
114: finish();
115: }
116: def.end();
117: out.close();
118: }
119:
120: /**
121: * Write any unwritten data to the underlying stream. Do not close the
122: * stream. This allows subsequent Deflater's to write to the same stream.
123: * This Deflater cannot be used again.
124: *
125: * @exception java.io.IOException
126: * If an error occurs.
127: */
128: public void finish() throws IOException {
129: if (done) {
130: return;
131: }
132: def.finish();
133: int x = 0;
134: while (!def.finished()) {
135: if (def.needsInput()) {
136: def.setInput(buf, 0, 0);
137: }
138: x = def.deflate(buf);
139: out.write(buf, 0, x);
140: }
141: done = true;
142: }
143:
144: @Override
145: public void write(int i) throws IOException {
146: byte[] b = new byte[1];
147: b[0] = (byte) i;
148: write(b, 0, 1);
149: }
150:
151: /**
152: * Compress data from a buffer and write it to the underlying stream.
153: *
154: * @param buffer
155: * Buffer of data to compress
156: * @param off
157: * offset in buffer to extract data from
158: * @param nbytes
159: * Number of bytes of data to compress and write
160: *
161: * @exception IOException
162: * If an error occurs during writing.
163: */
164: @Override
165: public void write(byte[] buffer, int off, int nbytes)
166: throws IOException {
167: if (done) {
168: throw new IOException(Messages.getString("archive.26")); //$NON-NLS-1$
169: }
170: // avoid int overflow, check null buf
171: if (off <= buffer.length && nbytes >= 0 && off >= 0
172: && buffer.length - off >= nbytes) {
173: if (!def.needsInput()) {
174: throw new IOException();
175: }
176: def.setInput(buffer, off, nbytes);
177: deflate();
178: } else {
179: throw new ArrayIndexOutOfBoundsException();
180: }
181: }
182: }
|