View Javadoc
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  
19  import java.io.Closeable;
20  import java.io.IOException;
21  import java.io.InputStream;
22  
23  import org.apache.commons.compress.compressors.CompressorInputStream;
24  import org.apache.commons.compress.utils.InputStreamStatistics;
25  
26  /**
27   * Deflate64 decompressor.
28   *
29   * @since 1.16
30   * @NotThreadSafe
31   */
32  public class Deflate64CompressorInputStream extends CompressorInputStream implements InputStreamStatistics {
33      private InputStream originalStream;
34      private HuffmanDecoder decoder;
35      private long compressedBytesRead;
36      private final byte[] oneByte = new byte[1];
37  
38      Deflate64CompressorInputStream(final HuffmanDecoder decoder) {
39          this.decoder = decoder;
40      }
41  
42      /**
43       * Constructs a Deflate64CompressorInputStream.
44       *
45       * @param in the stream to read from
46       */
47      public Deflate64CompressorInputStream(final InputStream in) {
48          this(new HuffmanDecoder(in));
49          originalStream = in;
50      }
51  
52      @Override
53      public int available() throws IOException {
54          return decoder != null ? decoder.available() : 0;
55      }
56  
57      @Override
58      public void close() throws IOException {
59          try {
60              closeDecoder();
61          } finally {
62              if (originalStream != null) {
63                  originalStream.close();
64                  originalStream = null;
65              }
66          }
67      }
68  
69      private void closeDecoder() {
70          final Closeable c = decoder;
71          org.apache.commons.io.IOUtils.closeQuietly(c);
72          decoder = null;
73      }
74  
75      /**
76       * @since 1.17
77       */
78      @Override
79      public long getCompressedCount() {
80          return compressedBytesRead;
81      }
82  
83      /**
84       * @throws java.io.EOFException if the underlying stream is exhausted before the end of deflated data was reached.
85       */
86      @Override
87      public int read() throws IOException {
88          while (true) {
89              final int r = read(oneByte);
90              switch (r) {
91              case 1:
92                  return oneByte[0] & 0xFF;
93              case -1:
94                  return -1;
95              case 0:
96                  continue;
97              default:
98                  throw new IllegalStateException("Invalid return value from read: " + r);
99              }
100         }
101     }
102 
103     /**
104      * @throws java.io.EOFException if the underlying stream is exhausted before the end of deflated data was reached.
105      */
106     @Override
107     public int read(final byte[] b, final int off, final int len) throws IOException {
108         if (len == 0) {
109             return 0;
110         }
111         int read = -1;
112         if (decoder != null) {
113             try {
114                 read = decoder.decode(b, off, len);
115             } catch (final RuntimeException ex) {
116                 throw new IOException("Invalid Deflate64 input", ex);
117             }
118             compressedBytesRead = decoder.getBytesRead();
119             count(read);
120             if (read == -1) {
121                 closeDecoder();
122             }
123         }
124         return read;
125     }
126 }