DeflateCompressorInputStream.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  * http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */
  19. package org.apache.commons.compress.compressors.deflate;

  20. import java.io.IOException;
  21. import java.io.InputStream;
  22. import java.util.zip.Inflater;
  23. import java.util.zip.InflaterInputStream;

  24. import org.apache.commons.compress.compressors.CompressorInputStream;
  25. import org.apache.commons.compress.utils.InputStreamStatistics;
  26. import org.apache.commons.io.input.BoundedInputStream;

  27. /**
  28.  * Deflate decompressor.
  29.  *
  30.  * @since 1.9
  31.  */
  32. public class DeflateCompressorInputStream extends CompressorInputStream implements InputStreamStatistics {

  33.     private static final int MAGIC_1 = 0x78;
  34.     private static final int MAGIC_2a = 0x01;
  35.     private static final int MAGIC_2b = 0x5e;
  36.     private static final int MAGIC_2c = 0x9c;
  37.     private static final int MAGIC_2d = 0xda;

  38.     /**
  39.      * Checks if the signature matches what is expected for a zlib / deflated file with the zlib header.
  40.      *
  41.      * @param signature the bytes to check
  42.      * @param length    the number of bytes to check
  43.      * @return true, if this stream is zlib / deflate compressed with a header stream, false otherwise
  44.      *
  45.      * @since 1.10
  46.      */
  47.     public static boolean matches(final byte[] signature, final int length) {
  48.         return length > 3 && signature[0] == MAGIC_1
  49.                 && (signature[1] == (byte) MAGIC_2a || signature[1] == (byte) MAGIC_2b || signature[1] == (byte) MAGIC_2c || signature[1] == (byte) MAGIC_2d);
  50.     }

  51.     private final BoundedInputStream countingStream;
  52.     private final InputStream in;

  53.     private final Inflater inflater;

  54.     /**
  55.      * Creates a new input stream that decompresses Deflate-compressed data from the specified input stream.
  56.      *
  57.      * @param inputStream where to read the compressed data
  58.      */
  59.     public DeflateCompressorInputStream(final InputStream inputStream) {
  60.         this(inputStream, new DeflateParameters());
  61.     }

  62.     /**
  63.      * Creates a new input stream that decompresses Deflate-compressed data from the specified input stream.
  64.      *
  65.      * @param inputStream where to read the compressed data
  66.      * @param parameters  parameters
  67.      */
  68.     public DeflateCompressorInputStream(final InputStream inputStream, final DeflateParameters parameters) {
  69.         inflater = new Inflater(!parameters.withZlibHeader());
  70.         in = new InflaterInputStream(countingStream = BoundedInputStream.builder().setInputStream(inputStream).asSupplier().get(), inflater);
  71.     }

  72.     /** {@inheritDoc} */
  73.     @Override
  74.     public int available() throws IOException {
  75.         return in.available();
  76.     }

  77.     /** {@inheritDoc} */
  78.     @Override
  79.     public void close() throws IOException {
  80.         try {
  81.             in.close();
  82.         } finally {
  83.             inflater.end();
  84.         }
  85.     }

  86.     /**
  87.      * @since 1.17
  88.      */
  89.     @Override
  90.     public long getCompressedCount() {
  91.         return countingStream.getCount();
  92.     }

  93.     /** {@inheritDoc} */
  94.     @Override
  95.     public int read() throws IOException {
  96.         final int ret = in.read();
  97.         count(ret == -1 ? 0 : 1);
  98.         return ret;
  99.     }

  100.     /** {@inheritDoc} */
  101.     @Override
  102.     public int read(final byte[] buf, final int off, final int len) throws IOException {
  103.         if (len == 0) {
  104.             return 0;
  105.         }
  106.         final int ret = in.read(buf, off, len);
  107.         count(ret);
  108.         return ret;
  109.     }

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     public long skip(final long n) throws IOException {
  113.         return org.apache.commons.io.IOUtils.skip(in, n);
  114.     }
  115. }