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.imaging.common.itu_t4;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  
22  /**
23   * Input stream that allows reading up to 32 bits
24   * across byte boundaries in most significant
25   * bit first order.
26   */
27  class BitInputStreamFlexible extends InputStream {
28      // TODO should be byte order conscious, ie TIFF for reading
29      // samples size<8 - shuoldn't that effect their order within byte?
30      private final InputStream is;
31      private int cache;
32      private int cacheBitsRemaining;
33      private long bytesRead;
34  
35      public BitInputStreamFlexible(final InputStream is) {
36          this.is = is;
37          // super(is);
38      }
39  
40      @Override
41      public int read() throws IOException {
42          if (cacheBitsRemaining > 0) {
43              throw new IOException("BitInputStream: incomplete bit read");
44          }
45          return is.read();
46      }
47  
48      public final int readBits(int count) throws IOException {
49  
50          if (count <= 32)  {
51              // catch-all
52              int result = 0;
53              // int done = 0;
54  
55              if (cacheBitsRemaining > 0) {
56                  if (count >= cacheBitsRemaining) {
57                      result = ((1 << cacheBitsRemaining) - 1) & cache;
58                      count -= cacheBitsRemaining;
59                      cacheBitsRemaining = 0;
60                  } else {
61                      // cache >>= count;
62                      cacheBitsRemaining -= count;
63                      result = ((1 << count) - 1) & (cache >> cacheBitsRemaining);
64                      count = 0;
65                  }
66              }
67              while (count >= 8) {
68                  cache = is.read();
69                  if (cache < 0) {
70                      throw new IOException("couldn't read bits");
71                  }
72                  // System.out.println("cache 1: " + cache + " ("
73                  // + Integer.toHexString(cache) + ", "
74                  // + Integer.toBinaryString(cache) + ")");
75                  bytesRead++;
76                  result = (result << 8) | (0xff & cache);
77                  count -= 8;
78              }
79              if (count > 0) {
80                  cache = is.read();
81                  if (cache < 0) {
82                      throw new IOException("couldn't read bits");
83                  }
84                  // System.out.println("cache 2: " + cache + " ("
85                  // + Integer.toHexString(cache) + ", "
86                  // + Integer.toBinaryString(cache) + ")");
87                  bytesRead++;
88                  cacheBitsRemaining = 8 - count;
89                  result = (result << count)
90                          | (((1 << count) - 1) & (cache >> cacheBitsRemaining));
91                  count = 0;
92              }
93  
94              return result;
95          }
96  
97          throw new IOException("BitInputStream: unknown error");
98  
99      }
100 
101     public void flushCache() {
102         cacheBitsRemaining = 0;
103     }
104 
105     public long getBytesRead() {
106         return bytesRead;
107     }
108 }