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.*;
028
029/**
030 * This class creates gzip compressors/decompressors. 
031 */
032@InterfaceAudience.Public
033@InterfaceStability.Evolving
034public class GzipCodec extends DefaultCodec {
035  /**
036   * A bridge that wraps around a DeflaterOutputStream to make it 
037   * a CompressionOutputStream.
038   */
039  @InterfaceStability.Evolving
040  protected static class GzipOutputStream extends CompressorStream {
041
042    private static class ResetableGZIPOutputStream extends GZIPOutputStream {
043      
044      public ResetableGZIPOutputStream(OutputStream out) throws IOException {
045        super(out);
046      }
047      
048      public void resetState() throws IOException {
049        def.reset();
050      }
051    }
052
053    public GzipOutputStream(OutputStream out) throws IOException {
054      super(new ResetableGZIPOutputStream(out));
055    }
056    
057    /**
058     * Allow children types to put a different type in here.
059     * @param out the Deflater stream to use
060     */
061    protected GzipOutputStream(CompressorStream out) {
062      super(out);
063    }
064    
065    @Override
066    public void close() throws IOException {
067      out.close();
068    }
069    
070    @Override
071    public void flush() throws IOException {
072      out.flush();
073    }
074    
075    @Override
076    public void write(int b) throws IOException {
077      out.write(b);
078    }
079    
080    @Override
081    public void write(byte[] data, int offset, int length) 
082      throws IOException {
083      out.write(data, offset, length);
084    }
085    
086    @Override
087    public void finish() throws IOException {
088      ((ResetableGZIPOutputStream) out).finish();
089    }
090
091    @Override
092    public void resetState() throws IOException {
093      ((ResetableGZIPOutputStream) out).resetState();
094    }
095  }
096
097  @Override
098  public CompressionOutputStream createOutputStream(OutputStream out) 
099    throws IOException {
100    return (ZlibFactory.isNativeZlibLoaded(conf)) ?
101               new CompressorStream(out, createCompressor(),
102                                    conf.getInt("io.file.buffer.size", 4*1024)) :
103               new GzipOutputStream(out);
104  }
105  
106  @Override
107  public CompressionOutputStream createOutputStream(OutputStream out, 
108                                                    Compressor compressor) 
109  throws IOException {
110    return (compressor != null) ?
111               new CompressorStream(out, compressor,
112                                    conf.getInt("io.file.buffer.size", 
113                                                4*1024)) :
114               createOutputStream(out);
115  }
116
117  @Override
118  public Compressor createCompressor() {
119    return (ZlibFactory.isNativeZlibLoaded(conf))
120      ? new GzipZlibCompressor(conf)
121      : null;
122  }
123
124  @Override
125  public Class<? extends Compressor> getCompressorType() {
126    return ZlibFactory.isNativeZlibLoaded(conf)
127      ? GzipZlibCompressor.class
128      : null;
129  }
130
131  @Override
132  public CompressionInputStream createInputStream(InputStream in)
133  throws IOException {
134    return createInputStream(in, null);
135  }
136
137  @Override
138  public CompressionInputStream createInputStream(InputStream in,
139                                                  Decompressor decompressor)
140  throws IOException {
141    if (decompressor == null) {
142      decompressor = createDecompressor();  // always succeeds (or throws)
143    }
144    return new DecompressorStream(in, decompressor,
145                                  conf.getInt("io.file.buffer.size", 4*1024));
146  }
147
148  @Override
149  public Decompressor createDecompressor() {
150    return (ZlibFactory.isNativeZlibLoaded(conf))
151      ? new GzipZlibDecompressor()
152      : new BuiltInGzipDecompressor();
153  }
154
155  @Override
156  public Class<? extends Decompressor> getDecompressorType() {
157    return ZlibFactory.isNativeZlibLoaded(conf)
158      ? GzipZlibDecompressor.class
159      : BuiltInGzipDecompressor.class;
160  }
161
162  @Override
163  public String getDefaultExtension() {
164    return ".gz";
165  }
166
167  static final class GzipZlibCompressor extends ZlibCompressor {
168    public GzipZlibCompressor() {
169      super(ZlibCompressor.CompressionLevel.DEFAULT_COMPRESSION,
170          ZlibCompressor.CompressionStrategy.DEFAULT_STRATEGY,
171          ZlibCompressor.CompressionHeader.GZIP_FORMAT, 64*1024);
172    }
173    
174    public GzipZlibCompressor(Configuration conf) {
175      super(ZlibFactory.getCompressionLevel(conf),
176           ZlibFactory.getCompressionStrategy(conf),
177           ZlibCompressor.CompressionHeader.GZIP_FORMAT,
178           64 * 1024);
179    }
180  }
181
182  static final class GzipZlibDecompressor extends ZlibDecompressor {
183    public GzipZlibDecompressor() {
184      super(ZlibDecompressor.CompressionHeader.AUTODETECT_GZIP_ZLIB, 64*1024);
185    }
186  }
187
188}