001    /* DeflaterOutputStream.java - Output filter for compressing.
002       Copyright (C) 1999, 2000, 2001, 2004, 2005 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package java.util.zip;
040    
041    import java.io.FilterOutputStream;
042    import java.io.IOException;
043    import java.io.OutputStream;
044    
045    /* Written using on-line Java Platform 1.2 API Specification
046     * and JCL book.
047     * Believed complete and correct.
048     */
049    
050    /**
051     * This is a special FilterOutputStream deflating the bytes that are
052     * written through it.  It uses the Deflater for deflating.
053     *
054     * A special thing to be noted is that flush() doesn't flush
055     * everything in Sun's JDK, but it does so in jazzlib. This is because
056     * Sun's Deflater doesn't have a way to flush() everything, without
057     * finishing the stream.
058     *
059     * @author Tom Tromey, Jochen Hoenicke
060     * @date Jan 11, 2001 
061     */
062    public class DeflaterOutputStream extends FilterOutputStream
063    {
064      /** 
065       * This buffer is used temporarily to retrieve the bytes from the
066       * deflater and write them to the underlying output stream.  
067       */
068      protected byte[] buf;
069    
070      /** 
071       * The deflater which is used to deflate the stream.
072       */
073      protected Deflater def;
074      
075      /**
076       * Deflates everything in the def's input buffers.  This will call
077       * <code>def.deflate()</code> until all bytes from the input buffers
078       * are processed.
079       */
080      protected void deflate() throws IOException
081      {
082        while (! def.needsInput())
083          {
084            int len = def.deflate(buf, 0, buf.length);
085    
086            //      System.err.println("DOS deflated " + len + " out of " + buf.length);
087            if (len <= 0)
088              break;
089            out.write(buf, 0, len);
090          }
091    
092        if (! def.needsInput())
093          throw new InternalError("Can't deflate all input?");
094      }
095    
096      /** 
097       * Creates a new DeflaterOutputStream with a default Deflater and
098       * default buffer size.
099       * @param out the output stream where deflated output should be written.
100       */
101      public DeflaterOutputStream(OutputStream out)
102      {
103        this(out, new Deflater(), 4096);
104      }
105    
106      /** 
107       * Creates a new DeflaterOutputStream with the given Deflater and
108       * default buffer size.
109       * @param out the output stream where deflated output should be written.
110       * @param defl the underlying deflater.
111       */
112      public DeflaterOutputStream(OutputStream out, Deflater defl)
113      {
114        this(out, defl, 4096);
115      }
116    
117      /** 
118       * Creates a new DeflaterOutputStream with the given Deflater and
119       * buffer size.
120       * @param out the output stream where deflated output should be written.
121       * @param defl the underlying deflater.
122       * @param bufsize the buffer size.
123       * @exception IllegalArgumentException if bufsize isn't positive.
124       */
125      public DeflaterOutputStream(OutputStream out, Deflater defl, int bufsize)
126      {
127        super(out);
128        if (bufsize <= 0)
129          throw new IllegalArgumentException("bufsize <= 0");
130        buf = new byte[bufsize];
131        def = defl;
132      }
133    
134      /**  
135       * Flushes the stream by calling flush() on the deflater and then
136       * on the underlying stream.  This ensures that all bytes are
137       * flushed.  This function doesn't work in Sun's JDK, but only in
138       * jazzlib.
139       */
140      public void flush() throws IOException
141      {
142        def.flush();
143        deflate();
144        out.flush();
145      }
146    
147      /**
148       * Finishes the stream by calling finish() on the deflater.  This
149       * was the only way to ensure that all bytes are flushed in Sun's
150       * JDK.  
151       */
152      public void finish() throws IOException
153      {
154        def.finish();
155        while (! def.finished())
156          {
157            int len = def.deflate(buf, 0, buf.length);
158            if (len <= 0)
159              break;
160            out.write(buf, 0, len);
161          }
162        if (! def.finished())
163          throw new InternalError("Can't deflate all input?");
164        out.flush();
165      }
166    
167      /**
168       * Calls finish() and closes the stream. 
169       */
170      public void close() throws IOException
171      {
172        finish();
173        out.close();
174      }
175    
176      /**
177       * Writes a single byte to the compressed output stream.
178       * @param bval the byte value.
179       */
180      public void write(int bval) throws IOException
181      {
182        byte[] b = new byte[1];
183        b[0] = (byte) bval;
184        write(b, 0, 1);
185      }
186    
187      /**
188       * Writes a len bytes from an array to the compressed stream.
189       * @param buf the byte array.
190       * @param off the offset into the byte array where to start.
191       * @param len the number of bytes to write.
192       */
193      public void write(byte[] buf, int off, int len) throws IOException
194      {
195        def.setInput(buf, off, len);
196        deflate();
197      }
198    }