1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.commons.compress.utils;
20
21 import java.io.Closeable;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.nio.ByteOrder;
25
26 /**
27 * Reads bits from an InputStream.
28 *
29 * @since 1.10
30 * @NotThreadSafe
31 */
32 public class BitInputStream implements Closeable {
33 private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit
34 private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1];
35
36 static {
37 for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) {
38 MASKS[i] = (MASKS[i - 1] << 1) + 1;
39 }
40 }
41
42 private final org.apache.commons.io.input.BoundedInputStream in;
43 private final ByteOrder byteOrder;
44 private long bitsCached;
45 private int bitsCachedSize;
46
47 /**
48 * Constructor taking an InputStream and its bit arrangement.
49 *
50 * @param in the InputStream
51 * @param byteOrder the bit arrangement across byte boundaries, either BIG_ENDIAN (aaaaabbb bb000000) or LITTLE_ENDIAN (bbbaaaaa 000000bb)
52 */
53 public BitInputStream(final InputStream in, final ByteOrder byteOrder) {
54 this.in = org.apache.commons.io.input.BoundedInputStream.builder().setInputStream(in).asSupplier().get();
55 this.byteOrder = byteOrder;
56 }
57
58 /**
59 * Drops bits until the next bits will be read from a byte boundary.
60 *
61 * @since 1.16
62 */
63 public void alignWithByteBoundary() {
64 final int toSkip = bitsCachedSize % Byte.SIZE;
65 if (toSkip > 0) {
66 readCachedBits(toSkip);
67 }
68 }
69
70 /**
71 * Returns an estimate of the number of bits that can be read from this input stream without blocking by the next invocation of a method for this input
72 * stream.
73 *
74 * @throws IOException if the underlying stream throws one when calling available
75 * @return estimate of the number of bits that can be read without blocking
76 * @since 1.16
77 */
78 public long bitsAvailable() throws IOException {
79 return bitsCachedSize + (long) Byte.SIZE * in.available();
80 }
81
82 /**
83 * Returns the number of bits that can be read from this input stream without reading from the underlying input stream at all.
84 *
85 * @return estimate of the number of bits that can be read without reading from the underlying stream
86 * @since 1.16
87 */
88 public int bitsCached() {
89 return bitsCachedSize;
90 }
91
92 /**
93 * Clears the cache of bits that have been read from the underlying stream but not yet provided via {@link #readBits}.
94 */
95 public void clearBitCache() {
96 bitsCached = 0;
97 bitsCachedSize = 0;
98 }
99
100 @Override
101 public void close() throws IOException {
102 in.close();
103 }
104
105 /**
106 * Fills the cache up to 56 bits
107 *
108 * @param count
109 * @return return true, when EOF
110 * @throws IOException if an I/O error occurs.
111 */
112 private boolean ensureCache(final int count) throws IOException {
113 while (bitsCachedSize < count && bitsCachedSize < 57) {
114 final long nextByte = in.read();
115 if (nextByte < 0) {
116 return true;
117 }
118 if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
119 bitsCached |= nextByte << bitsCachedSize;
120 } else {
121 bitsCached <<= Byte.SIZE;
122 bitsCached |= nextByte;
123 }
124 bitsCachedSize += Byte.SIZE;
125 }
126 return false;
127 }
128
129 /**
130 * Gets the number of bytes read from the underlying stream.
131 * <p>
132 * This includes the bytes read to fill the current cache and not read as bits so far.
133 * </p>
134 *
135 * @return the number of bytes read from the underlying stream
136 * @since 1.17
137 */
138 public long getBytesRead() {
139 return in.getCount();
140 }
141
142 private long processBitsGreater57(final int count) throws IOException {
143 final long bitsOut;
144 final int overflowBits;
145 long overflow = 0L;
146
147 // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow
148 final int bitsToAddCount = count - bitsCachedSize;
149 overflowBits = Byte.SIZE - bitsToAddCount;
150 final long nextByte = in.read();
151 if (nextByte < 0) {
152 return nextByte;
153 }
154 if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
155 final long bitsToAdd = nextByte & MASKS[bitsToAddCount];
156 bitsCached |= bitsToAdd << bitsCachedSize;
157 overflow = nextByte >>> bitsToAddCount & MASKS[overflowBits];
158 } else {
159 bitsCached <<= bitsToAddCount;
160 final long bitsToAdd = nextByte >>> overflowBits & MASKS[bitsToAddCount];
161 bitsCached |= bitsToAdd;
162 overflow = nextByte & MASKS[overflowBits];
163 }
164 bitsOut = bitsCached & MASKS[count];
165 bitsCached = overflow;
166 bitsCachedSize = overflowBits;
167 return bitsOut;
168 }
169
170 /**
171 * Reads and returns the next bit read from the underlying stream.
172 *
173 * @return the next bit (0 or 1) or -1 if the end of the stream has been reached
174 * @throws IOException if an I/O error occurs.
175 * @since 1.28
176 */
177 public int readBit() throws IOException {
178 return (int) readBits(1);
179 }
180
181 /**
182 * Reads and returns at most 63 bits read from the underlying stream.
183 *
184 * @param count the number of bits to read, must be a positive number not bigger than 63.
185 * @return the bits concatenated as a long using the stream's byte order. -1 if the end of the underlying stream has been reached before reading the
186 * requested number of bits
187 * @throws IOException if an I/O error occurs.
188 */
189 public long readBits(final int count) throws IOException {
190 if (count < 0 || count > MAXIMUM_CACHE_SIZE) {
191 throw new IOException("count must not be negative or greater than " + MAXIMUM_CACHE_SIZE);
192 }
193 if (ensureCache(count)) {
194 return -1;
195 }
196
197 if (bitsCachedSize < count) {
198 return processBitsGreater57(count);
199 }
200 return readCachedBits(count);
201 }
202
203 private long readCachedBits(final int count) {
204 final long bitsOut;
205 if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
206 bitsOut = bitsCached & MASKS[count];
207 bitsCached >>>= count;
208 } else {
209 bitsOut = bitsCached >> bitsCachedSize - count & MASKS[count];
210 }
211 bitsCachedSize -= count;
212 return bitsOut;
213 }
214
215 }