Deflate64CompressorInputStream.java

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

  18. import java.io.Closeable;
  19. import java.io.IOException;
  20. import java.io.InputStream;

  21. import org.apache.commons.compress.compressors.CompressorInputStream;
  22. import org.apache.commons.compress.utils.InputStreamStatistics;

  23. /**
  24.  * Deflate64 decompressor.
  25.  *
  26.  * @since 1.16
  27.  * @NotThreadSafe
  28.  */
  29. public class Deflate64CompressorInputStream extends CompressorInputStream implements InputStreamStatistics {
  30.     private InputStream originalStream;
  31.     private HuffmanDecoder decoder;
  32.     private long compressedBytesRead;
  33.     private final byte[] oneByte = new byte[1];

  34.     Deflate64CompressorInputStream(final HuffmanDecoder decoder) {
  35.         this.decoder = decoder;
  36.     }

  37.     /**
  38.      * Constructs a Deflate64CompressorInputStream.
  39.      *
  40.      * @param in the stream to read from
  41.      */
  42.     public Deflate64CompressorInputStream(final InputStream in) {
  43.         this(new HuffmanDecoder(in));
  44.         originalStream = in;
  45.     }

  46.     @Override
  47.     public int available() throws IOException {
  48.         return decoder != null ? decoder.available() : 0;
  49.     }

  50.     @Override
  51.     public void close() throws IOException {
  52.         try {
  53.             closeDecoder();
  54.         } finally {
  55.             if (originalStream != null) {
  56.                 originalStream.close();
  57.                 originalStream = null;
  58.             }
  59.         }
  60.     }

  61.     private void closeDecoder() {
  62.         final Closeable c = decoder;
  63.         org.apache.commons.io.IOUtils.closeQuietly(c);
  64.         decoder = null;
  65.     }

  66.     /**
  67.      * @since 1.17
  68.      */
  69.     @Override
  70.     public long getCompressedCount() {
  71.         return compressedBytesRead;
  72.     }

  73.     /**
  74.      * @throws java.io.EOFException if the underlying stream is exhausted before the end of deflated data was reached.
  75.      */
  76.     @Override
  77.     public int read() throws IOException {
  78.         while (true) {
  79.             final int r = read(oneByte);
  80.             switch (r) {
  81.             case 1:
  82.                 return oneByte[0] & 0xFF;
  83.             case -1:
  84.                 return -1;
  85.             case 0:
  86.                 continue;
  87.             default:
  88.                 throw new IllegalStateException("Invalid return value from read: " + r);
  89.             }
  90.         }
  91.     }

  92.     /**
  93.      * @throws java.io.EOFException if the underlying stream is exhausted before the end of deflated data was reached.
  94.      */
  95.     @Override
  96.     public int read(final byte[] b, final int off, final int len) throws IOException {
  97.         if (len == 0) {
  98.             return 0;
  99.         }
  100.         int read = -1;
  101.         if (decoder != null) {
  102.             try {
  103.                 read = decoder.decode(b, off, len);
  104.             } catch (final RuntimeException ex) {
  105.                 throw new IOException("Invalid Deflate64 input", ex);
  106.             }
  107.             compressedBytesRead = decoder.getBytesRead();
  108.             count(read);
  109.             if (read == -1) {
  110.                 closeDecoder();
  111.             }
  112.         }
  113.         return read;
  114.     }
  115. }