1d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// Copyright 2015 Google Inc. All rights reserved.
2d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden//
3d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// Licensed under the Apache License, Version 2.0 (the "License");
4d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// you may not use this file except in compliance with the License.
5d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// You may obtain a copy of the License at
6d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden//
7d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden//     http://www.apache.org/licenses/LICENSE-2.0
8d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden//
9d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// Unless required by applicable law or agreed to in writing, software
10d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// distributed under the License is distributed on an "AS IS" BASIS,
11d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// See the License for the specific language governing permissions and
13d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden// limitations under the License.
14d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
15d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenpackage com.google.archivepatcher.shared;
16d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
17d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenimport java.io.IOException;
18d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenimport java.io.InputStream;
19d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenimport java.io.OutputStream;
20d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenimport java.util.zip.Deflater;
21d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenimport java.util.zip.DeflaterOutputStream;
22d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
23d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden/**
24d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden * Implementation of {@link Compressor} based on Java's built-in {@link Deflater}. Uses default
25d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden * compression, the default strategy, and no-wrap by default along with a 32k read buffer and a 32k
26d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden * write buffer. Buffers are allocated on-demand and discarded after use.
27d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden */
28d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Haydenpublic class DeflateCompressor implements Compressor {
29d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
30d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
31d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * The compression level to use. Defaults to {@link Deflater#DEFAULT_COMPRESSION}.
32d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
33d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private int compressionLevel = Deflater.DEFAULT_COMPRESSION;
34d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
35d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
36d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * The compression strategy to use. Defaults to {@link Deflater#DEFAULT_STRATEGY}.
37d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
38d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private int strategy = Deflater.DEFAULT_STRATEGY;
39d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
40d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
41d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Whether or not to suppress wrapping the deflate output with the
42d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * standard zlib header and checksum fields. Defaults to true.
43d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
44d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private boolean nowrap = true;
45d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
46d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
47d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * The size of the buffer used for reading data in during
48d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link #compress(InputStream, OutputStream)}.
49d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
50d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private int inputBufferSize = 32768;
51d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
52d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
53d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * The size of the buffer used for writing data out during
54d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link #compress(InputStream, OutputStream)}.
55d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
56d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private int outputBufferSize = 32768;
57d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
58d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
59d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Cached {@link Deflater} to be used.
60d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
61d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private Deflater deflater = null;
62d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
63d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
64d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Whether or not to cache {@link Deflater} instances, which is a major performance tradeoff.
65d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
66d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  private boolean caching = false;
67d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
68d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
69d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns whether or not to suppress wrapping the deflate output with the standard zlib header
70d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * and checksum fields.
71d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return the value
72d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @see Deflater#Deflater(int, boolean)
73d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
74d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public boolean isNowrap() {
75d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return nowrap;
76d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
77d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
78d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
79d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Sets whether or not to suppress wrapping the deflate output with the standard zlib header and
80d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * checksum fields. Defaults to false.
81d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @param nowrap see {@link Deflater#Deflater(int, boolean)}
82d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
83d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void setNowrap(boolean nowrap) {
84d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    if (nowrap != this.nowrap) {
85d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      release(); // Cannot re-use the deflater any more.
86d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      this.nowrap = nowrap;
87d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
88d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
89d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
90d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
91d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns the compression level that will be used, in the range 0-9.
92d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return the level
93d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
94d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public int getCompressionLevel() {
95d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return compressionLevel;
96d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
97d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
98d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
99d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Sets the compression level to be used. Defaults to {@link Deflater#BEST_COMPRESSION}.
100d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @param compressionLevel the level, in the range 0-9
101d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
102d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void setCompressionLevel(int compressionLevel) {
103d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    if (compressionLevel < 0 || compressionLevel > 9) {
104d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      throw new IllegalArgumentException(
105d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden          "compressionLevel must be in the range [0,9]: " + compressionLevel);
106d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
107d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    if (deflater != null && compressionLevel != this.compressionLevel) {
108d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      deflater.reset();
109ec0fc6394e5abd1dbd47fe58d2988b997bac60dcAndrew Hayden      deflater.setLevel(compressionLevel);
110d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
111d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    this.compressionLevel = compressionLevel;
112d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
113d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
114d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
115d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns the strategy that will be used, from {@link Deflater}.
116d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return the strategy
117d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
118d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public int getStrategy() {
119d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return strategy;
120d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
121d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
122d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
123d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Sets the strategy that will be used. Valid values can be found in {@link Deflater}. Defaults to
124d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link Deflater#DEFAULT_STRATEGY}
125d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @param strategy the strategy to be used
126d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
127d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void setStrategy(int strategy) {
128d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    if (deflater != null && strategy != this.strategy) {
129d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      deflater.reset();
130ec0fc6394e5abd1dbd47fe58d2988b997bac60dcAndrew Hayden      deflater.setStrategy(strategy);
131d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
132d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    this.strategy = strategy;
133d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
134d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
135d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
136d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns the size of the buffer used for reading from the input stream in
137d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link #compress(InputStream, OutputStream)}.
138d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return the size (default is 32768)
139d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
140d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public int getInputBufferSize() {
141d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return inputBufferSize;
142d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
143d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
144d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
145d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Sets the size of the buffer used for reading from the input stream in
146d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link #compress(InputStream, OutputStream)}.
147d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @param inputBufferSize the size to set (default is 32768)
148d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
149d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void setInputBufferSize(int inputBufferSize) {
150d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    this.inputBufferSize = inputBufferSize;
151d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
152d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
153d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
154d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns the size of the buffer used for writing to the output stream in
155d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link #compress(InputStream, OutputStream)}.
156d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return the size (default is 32768)
157d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
158d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public int getOutputBufferSize() {
159d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return outputBufferSize;
160d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
161d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
162d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
163d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Sets the size of the buffer used for writing to the output stream in
164d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * {@link #compress(InputStream, OutputStream)}.
165d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * NB: {@link Deflater} uses an <em>internal</em> buffer and this method adjusts the size of that
166d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * buffer. This buffer is important for performance, <em>even if the {@link OutputStream} is
167d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * is already buffered</em>.
168d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @param outputBufferSize the size to set (default is 32768)
169d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
170d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void setOutputBufferSize(int outputBufferSize) {
171d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    this.outputBufferSize = outputBufferSize;
172d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
173d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
174d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
175d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns if caching is enabled.
176d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return true if enabled, otherwise false
177d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @see #setCaching(boolean)
178d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
179d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public boolean isCaching() {
180d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return caching;
181d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
182d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
183d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
184d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Sets whether or not to cache the {@link Deflater} instance. Defaults to false. If set to true,
185d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * the {@link Deflater} is kept until this object is finalized or until {@link #release()} is
186d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * called. Instances of {@link Deflater} can be surprisingly expensive, so caching is advised in
187d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * situations where many resources need to be deflated.
188d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @param caching whether to enable caching
189d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
190d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void setCaching(boolean caching) {
191d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    this.caching = caching;
192d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
193d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
194d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
195d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Returns the {@link Deflater} to be used, creating a new one if necessary and caching it for
196d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * future use.
197d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * @return the deflater
198d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
199d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  protected Deflater createOrResetDeflater() {
200d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    Deflater result = deflater;
201d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    if (result == null) {
202d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      result = new Deflater(compressionLevel, nowrap);
203d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      result.setStrategy(strategy);
204d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      if (caching) {
205d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden        deflater = result;
206d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      }
207d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    } else {
208d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      result.reset();
209d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
210d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    return result;
211d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
212d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
213d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  /**
214d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   * Immediately releases any cached {@link Deflater} instance.
215d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden   */
216d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void release() {
217d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    if (deflater != null) {
218d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      deflater.end();
219d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      deflater = null;
220d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
221d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
222d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden
223d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  @Override
224d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  public void compress(InputStream uncompressedIn, OutputStream compressedOut) throws IOException {
225d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    byte[] buffer = new byte[inputBufferSize];
226d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    DeflaterOutputStream deflaterOut =
227d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden        new DeflaterOutputStream(compressedOut, createOrResetDeflater(), outputBufferSize);
228d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    int numRead = 0;
229d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    while ((numRead = uncompressedIn.read(buffer)) >= 0) {
230d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden      deflaterOut.write(buffer, 0, numRead);
231d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    }
232d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    deflaterOut.finish();
233d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden    deflaterOut.flush();
234d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden  }
235d84e46c30d0ea027d047ee4c75c040a173ec9ffcAndrew Hayden}
236