001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.io.compress;
020
021import java.io.*;
022import java.util.zip.GZIPOutputStream;
023import org.apache.hadoop.classification.InterfaceAudience;
024import org.apache.hadoop.classification.InterfaceStability;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.io.compress.DefaultCodec;
027import org.apache.hadoop.io.compress.zlib.*;
028import org.apache.hadoop.io.compress.zlib.ZlibDecompressor.ZlibDirectDecompressor;
029
030import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
031
032/**
033 * This class creates gzip compressors/decompressors. 
034 */
035@InterfaceAudience.Public
036@InterfaceStability.Evolving
037public class GzipCodec extends DefaultCodec {
038  /**
039   * A bridge that wraps around a DeflaterOutputStream to make it 
040   * a CompressionOutputStream.
041   */
042  @InterfaceStability.Evolving
043  protected static class GzipOutputStream extends CompressorStream {
044
045    private static class ResetableGZIPOutputStream extends GZIPOutputStream {
046      private static final int TRAILER_SIZE = 8;
047      public static final String JVMVersion= System.getProperty("java.version");
048      private static final boolean HAS_BROKEN_FINISH =
049          (IBM_JAVA && JVMVersion.contains("1.6.0"));
050
051      public ResetableGZIPOutputStream(OutputStream out) throws IOException {
052        super(out);
053      }
054      
055      public void resetState() throws IOException {
056        def.reset();
057      }
058    }
059
060    public GzipOutputStream(OutputStream out) throws IOException {
061      super(new ResetableGZIPOutputStream(out));
062    }
063    
064    /**
065     * Allow children types to put a different type in here.
066     * @param out the Deflater stream to use
067     */
068    protected GzipOutputStream(CompressorStream out) {
069      super(out);
070    }
071    
072    @Override
073    public void close() throws IOException {
074      out.close();
075    }
076    
077    @Override
078    public void flush() throws IOException {
079      out.flush();
080    }
081    
082    @Override
083    public void write(int b) throws IOException {
084      out.write(b);
085    }
086    
087    @Override
088    public void write(byte[] data, int offset, int length) 
089      throws IOException {
090      out.write(data, offset, length);
091    }
092    
093    @Override
094    public void finish() throws IOException {
095      ((ResetableGZIPOutputStream) out).finish();
096    }
097
098    @Override
099    public void resetState() throws IOException {
100      ((ResetableGZIPOutputStream) out).resetState();
101    }
102  }
103
104  @Override
105  public CompressionOutputStream createOutputStream(OutputStream out) 
106    throws IOException {
107    if (!ZlibFactory.isNativeZlibLoaded(conf)) {
108      return new GzipOutputStream(out);
109    }
110    return CompressionCodec.Util.
111        createOutputStreamWithCodecPool(this, conf, out);
112  }
113  
114  @Override
115  public CompressionOutputStream createOutputStream(OutputStream out, 
116                                                    Compressor compressor) 
117  throws IOException {
118    return (compressor != null) ?
119               new CompressorStream(out, compressor,
120                                    conf.getInt("io.file.buffer.size", 
121                                                4*1024)) :
122               createOutputStream(out);
123  }
124
125  @Override
126  public Compressor createCompressor() {
127    return (ZlibFactory.isNativeZlibLoaded(conf))
128      ? new GzipZlibCompressor(conf)
129      : null;
130  }
131
132  @Override
133  public Class<? extends Compressor> getCompressorType() {
134    return ZlibFactory.isNativeZlibLoaded(conf)
135      ? GzipZlibCompressor.class
136      : null;
137  }
138
139  @Override
140  public CompressionInputStream createInputStream(InputStream in)
141      throws IOException {
142    return CompressionCodec.Util.
143        createInputStreamWithCodecPool(this, conf, in);
144  }
145
146  @Override
147  public CompressionInputStream createInputStream(InputStream in,
148                                                  Decompressor decompressor)
149  throws IOException {
150    if (decompressor == null) {
151      decompressor = createDecompressor();  // always succeeds (or throws)
152    }
153    return new DecompressorStream(in, decompressor,
154                                  conf.getInt("io.file.buffer.size", 4*1024));
155  }
156
157  @Override
158  public Decompressor createDecompressor() {
159    return (ZlibFactory.isNativeZlibLoaded(conf))
160      ? new GzipZlibDecompressor()
161      : new BuiltInGzipDecompressor();
162  }
163
164  @Override
165  public Class<? extends Decompressor> getDecompressorType() {
166    return ZlibFactory.isNativeZlibLoaded(conf)
167      ? GzipZlibDecompressor.class
168      : BuiltInGzipDecompressor.class;
169  }
170    
171  @Override
172  public DirectDecompressor createDirectDecompressor() {
173    return ZlibFactory.isNativeZlibLoaded(conf) 
174        ? new ZlibDecompressor.ZlibDirectDecompressor(
175          ZlibDecompressor.CompressionHeader.AUTODETECT_GZIP_ZLIB, 0) : null;
176  }
177
178  @Override
179  public String getDefaultExtension() {
180    return ".gz";
181  }
182
183  static final class GzipZlibCompressor extends ZlibCompressor {
184    public GzipZlibCompressor() {
185      super(ZlibCompressor.CompressionLevel.DEFAULT_COMPRESSION,
186          ZlibCompressor.CompressionStrategy.DEFAULT_STRATEGY,
187          ZlibCompressor.CompressionHeader.GZIP_FORMAT, 64*1024);
188    }
189    
190    public GzipZlibCompressor(Configuration conf) {
191      super(ZlibFactory.getCompressionLevel(conf),
192           ZlibFactory.getCompressionStrategy(conf),
193           ZlibCompressor.CompressionHeader.GZIP_FORMAT,
194           64 * 1024);
195    }
196  }
197
198  static final class GzipZlibDecompressor extends ZlibDecompressor {
199    public GzipZlibDecompressor() {
200      super(ZlibDecompressor.CompressionHeader.AUTODETECT_GZIP_ZLIB, 64*1024);
201    }
202  }
203
204}