001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.compress.utils;
020
021import java.io.Closeable;
022import java.io.IOException;
023import java.io.InputStream;
024import java.nio.ByteOrder;
025
026/**
027 * Reads bits from an InputStream.
028 * @since 1.10
029 * @NotThreadSafe
030 */
031public class BitInputStream implements Closeable {
032    private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit
033    private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1];
034
035    static {
036        for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) {
037            MASKS[i] = (MASKS[i - 1] << 1) + 1;
038        }
039    }
040
041    private final CountingInputStream in;
042    private final ByteOrder byteOrder;
043    private long bitsCached = 0;
044    private int bitsCachedSize = 0;
045
046    /**
047     * Constructor taking an InputStream and its bit arrangement.
048     * @param in the InputStream
049     * @param byteOrder the bit arrangement across byte boundaries,
050     *      either BIG_ENDIAN (aaaaabbb bb000000) or LITTLE_ENDIAN (bbbaaaaa 000000bb)
051     */
052    public BitInputStream(final InputStream in, final ByteOrder byteOrder) {
053        this.in = new CountingInputStream(in);
054        this.byteOrder = byteOrder;
055    }
056
057    @Override
058    public void close() throws IOException {
059        in.close();
060    }
061
062    /**
063     * Clears the cache of bits that have been read from the
064     * underlying stream but not yet provided via {@link #readBits}.
065     */
066    public void clearBitCache() {
067        bitsCached = 0;
068        bitsCachedSize = 0;
069    }
070
071    /**
072     * Returns at most 63 bits read from the underlying stream.
073     *
074     * @param count the number of bits to read, must be a positive
075     * number not bigger than 63.
076     * @return the bits concatenated as a long using the stream's byte order.
077     *         -1 if the end of the underlying stream has been reached before reading
078     *         the requested number of bits
079     * @throws IOException on error
080     */
081    public long readBits(final int count) throws IOException {
082        if (count < 0 || count > MAXIMUM_CACHE_SIZE) {
083            throw new IllegalArgumentException("count must not be negative or greater than " + MAXIMUM_CACHE_SIZE);
084        }
085        if (ensureCache(count)) {
086            return -1;
087        }
088
089        if (bitsCachedSize < count) {
090            return processBitsGreater57(count);
091        }
092        return readCachedBits(count);
093    }
094
095    /**
096     * Returns the number of bits that can be read from this input
097     * stream without reading from the underlying input stream at all.
098     * @return estimate of the number of bits that can be read without reading from the underlying stream
099     * @since 1.16
100     */
101    public int bitsCached() {
102        return bitsCachedSize;
103    }
104
105    /**
106     * Returns an estimate of the number of bits that can be read from
107     * this input stream without blocking by the next invocation of a
108     * method for this input stream.
109     * @throws IOException if the underlying stream throws one when calling available
110     * @return estimate of the number of bits that can be read without blocking
111     * @since 1.16
112     */
113    public long bitsAvailable() throws IOException {
114        return bitsCachedSize + ((long) Byte.SIZE) * in.available();
115    }
116
117    /**
118     * Drops bits until the next bits will be read from a byte boundary.
119     * @since 1.16
120     */
121    public void alignWithByteBoundary() {
122        int toSkip = bitsCachedSize % Byte.SIZE;
123        if (toSkip > 0) {
124            readCachedBits(toSkip);
125        }
126    }
127
128    /**
129     * Returns the number of bytes read from the underlying stream.
130     *
131     * <p>This includes the bytes read to fill the current cache and
132     * not read as bits so far.</p>
133     * @return the number of bytes read from the underlying stream
134     * @since 1.17
135     */
136    public long getBytesRead() {
137        return in.getBytesRead();
138    }
139
140    private long processBitsGreater57(final int count) throws IOException {
141        final long bitsOut;
142        int overflowBits = 0;
143        long overflow = 0L;
144
145        // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow
146        int bitsToAddCount = count - bitsCachedSize;
147        overflowBits = Byte.SIZE - bitsToAddCount;
148        final long nextByte = in.read();
149        if (nextByte < 0) {
150            return nextByte;
151        }
152        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
153            long bitsToAdd = nextByte & MASKS[bitsToAddCount];
154            bitsCached |= (bitsToAdd << bitsCachedSize);
155            overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits];
156        } else {
157            bitsCached <<= bitsToAddCount;
158            long bitsToAdd = (nextByte >>> (overflowBits)) & MASKS[bitsToAddCount];
159            bitsCached |= bitsToAdd;
160            overflow = nextByte & MASKS[overflowBits];
161        }
162        bitsOut = bitsCached & MASKS[count];
163        bitsCached = overflow;
164        bitsCachedSize = overflowBits;
165        return bitsOut;
166    }
167
168    private long readCachedBits(int count) {
169        final long bitsOut;
170        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
171            bitsOut = (bitsCached & MASKS[count]);
172            bitsCached >>>= count;
173        } else {
174            bitsOut = (bitsCached >> (bitsCachedSize - count)) & MASKS[count];
175        }
176        bitsCachedSize -= count;
177        return bitsOut;
178    }
179
180    /**
181     * Fills the cache up to 56 bits
182     * @param count
183     * @return return true, when EOF
184     * @throws IOException
185     */
186    private boolean ensureCache(final int count) throws IOException {
187        while (bitsCachedSize < count && bitsCachedSize < 57) {
188            final long nextByte = in.read();
189            if (nextByte < 0) {
190                return true;
191            }
192            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
193                bitsCached |= (nextByte << bitsCachedSize);
194            } else {
195                bitsCached <<= Byte.SIZE;
196                bitsCached |= nextByte;
197            }
198            bitsCachedSize += Byte.SIZE;
199        }
200        return false;
201    }
202
203}