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