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