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        while (bitsCachedSize < count && bitsCachedSize < 57) {
086            final long nextByte = in.read();
087            if (nextByte < 0) {
088                return nextByte;
089            }
090            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
091                bitsCached |= (nextByte << bitsCachedSize);
092            } else {
093                bitsCached <<= 8;
094                bitsCached |= nextByte;
095            }
096            bitsCachedSize += 8;
097        }
098        int overflowBits = 0;
099        long overflow = 0l;
100        if (bitsCachedSize < count) {
101            // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow
102            int bitsToAddCount = count - bitsCachedSize;
103            overflowBits = 8 - bitsToAddCount;
104            final long nextByte = in.read();
105            if (nextByte < 0) {
106                return nextByte;
107            }
108            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
109                long bitsToAdd = nextByte & MASKS[bitsToAddCount];
110                bitsCached |= (bitsToAdd << bitsCachedSize);
111                overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits];
112            } else {
113                bitsCached <<= bitsToAddCount;
114                long bitsToAdd = (nextByte >>> (overflowBits)) & MASKS[bitsToAddCount];
115                bitsCached |= bitsToAdd;
116                overflow = nextByte & MASKS[overflowBits];
117            }
118            bitsCachedSize = count;
119        }
120        
121        final long bitsOut;
122        if (overflowBits == 0) {
123            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
124                bitsOut = (bitsCached & MASKS[count]);
125                bitsCached >>>= count;
126            } else {
127                bitsOut = (bitsCached >> (bitsCachedSize - count)) & MASKS[count];
128            }
129            bitsCachedSize -= count;
130        } else {
131            bitsOut = bitsCached & MASKS[count];
132            bitsCached = overflow;
133            bitsCachedSize = overflowBits;
134        }
135        return bitsOut;
136    }
137}