    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,
    013 * software distributed under the License is distributed on an
    014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    015 * KIND, either express or implied.  See the License for the
    016 * specific language governing permissions and limitations
    017 * under the License.
    018 */
    019package org.apache.commons.compress.compressors.deflate;
    020
    021import java.io.IOException;
    022import java.io.InputStream;
    023import java.util.zip.Inflater;
    024import java.util.zip.InflaterInputStream;
    025
    026import org.apache.commons.compress.compressors.CompressorInputStream;
    027
    028/**
    029 * Deflate decompressor.
    030 * @since 1.9
    031 */
    032public class DeflateCompressorInputStream extends CompressorInputStream {
    033    private static final int MAGIC_1 = 0x78;
    034    private static final int MAGIC_2a = 0x01;
    035    private static final int MAGIC_2b = 0x5e;
    036    private static final int MAGIC_2c = 0x9c;
    037    private static final int MAGIC_2d = 0xda;
    038
    039    private final InputStream in;
    040    private final Inflater inflater;
    041
    042    /**
    043     * Creates a new input stream that decompresses Deflate-compressed data
    044     * from the specified input stream.
    045     *
    046     * @param       inputStream where to read the compressed data
    047     *
    048     */
    049    public DeflateCompressorInputStream(final InputStream inputStream) {
    050        this(inputStream, new DeflateParameters());
    051    }
    052
    053    /**
    054     * Creates a new input stream that decompresses Deflate-compressed data
    055     * from the specified input stream.
    056     *
    057     * @param       inputStream where to read the compressed data
    058     * @param       parameters parameters
    059     */
    060    public DeflateCompressorInputStream(final InputStream inputStream,
    061                                        final DeflateParameters parameters) {
    062        inflater = new Inflater(!parameters.withZlibHeader());
    063        in = new InflaterInputStream(inputStream, inflater);
    064    }
    065
    066    /** {@inheritDoc} */
    067    @Override
    068    public int read() throws IOException {
    069        final int ret = in.read();
    070        count(ret == -1 ? 0 : 1);
    071        return ret;
    072    }
    073
    074    /** {@inheritDoc} */
    075    @Override
    076    public int read(final byte[] buf, final int off, final int len) throws IOException {
    077        final int ret = in.read(buf, off, len);
    078        count(ret);
    079        return ret;
    080    }
    081
    082    /** {@inheritDoc} */
    083    @Override
    084    public long skip(final long n) throws IOException {
    085        return in.skip(n);
    086    }
    087
    088    /** {@inheritDoc} */
    089    @Override
    090    public int available() throws IOException {
    091        return in.available();
    092    }
    093
    094    /** {@inheritDoc} */
    095    @Override
    096    public void close() throws IOException {
    097        try {
    098            in.close();
    099        } finally {
    100            inflater.end();
    101        }
    102    }
    103
    104    /**
    105     * Checks if the signature matches what is expected for a zlib / deflated file
    106     *  with the zlib header.
    107     *
    108     * @param signature
    109     *            the bytes to check
    110     * @param length
    111     *            the number of bytes to check
    112     * @return true, if this stream is zlib / deflate compressed with a header
    113     * stream, false otherwise
    114     *
    115     * @since 1.10
    116     */
    117    public static boolean matches(final byte[] signature, final int length) {
    118        return length > 3 && signature[0] == MAGIC_1 && (
    119                signature[1] == (byte) MAGIC_2a ||
    120                signature[1] == (byte) MAGIC_2b ||
    121                signature[1] == (byte) MAGIC_2c ||
    122                signature[1] == (byte) MAGIC_2d);
    123    }
    124}