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 }