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 InputStream 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 = 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    private long processBitsGreater57(final int count) throws IOException {
129        final long bitsOut;
130        int overflowBits = 0;
131        long overflow = 0L;
132
133        // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow
134        int bitsToAddCount = count - bitsCachedSize;
135        overflowBits = Byte.SIZE - bitsToAddCount;
136        final long nextByte = in.read();
137        if (nextByte < 0) {
138            return nextByte;
139        }
140        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
141            long bitsToAdd = nextByte & MASKS[bitsToAddCount];
142            bitsCached |= (bitsToAdd << bitsCachedSize);
143            overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits];
144        } else {
145            bitsCached <<= bitsToAddCount;
146            long bitsToAdd = (nextByte >>> (overflowBits)) & MASKS[bitsToAddCount];
147            bitsCached |= bitsToAdd;
148            overflow = nextByte & MASKS[overflowBits];
149        }
150        bitsOut = bitsCached & MASKS[count];
151        bitsCached = overflow;
152        bitsCachedSize = overflowBits;
153        return bitsOut;
154    }
155
156    private long readCachedBits(int count) {
157        final long bitsOut;
158        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
159            bitsOut = (bitsCached & MASKS[count]);
160            bitsCached >>>= count;
161        } else {
162            bitsOut = (bitsCached >> (bitsCachedSize - count)) & MASKS[count];
163        }
164        bitsCachedSize -= count;
165        return bitsOut;
166    }
167
168    /**
169     * Fills the cache up to 56 bits
170     * @param count
171     * @return return true, when EOF
172     * @throws IOException
173     */
174    private boolean ensureCache(final int count) throws IOException {
175        while (bitsCachedSize < count && bitsCachedSize < 57) {
176            final long nextByte = in.read();
177            if (nextByte < 0) {
178                return true;
179            }
180            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
181                bitsCached |= (nextByte << bitsCachedSize);
182            } else {
183                bitsCached <<= Byte.SIZE;
184                bitsCached |= nextByte;
185            }
186            bitsCachedSize += Byte.SIZE;
187        }
188        return false;
189    }
190}