    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;
    044    private int bitsCachedSize;
    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 IOException("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        final 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        final int overflowBits;
    143        long overflow = 0L;
    144
    145        // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow
    146        final 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            final long bitsToAdd = nextByte & MASKS[bitsToAddCount];
    154            bitsCached |= (bitsToAdd << bitsCachedSize);
    155            overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits];
    156        } else {
    157            bitsCached <<= bitsToAddCount;
    158            final 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(final 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}