BitInputStream.java

  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.  * http://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. import java.io.Closeable;
  21. import java.io.IOException;
  22. import java.io.InputStream;
  23. import java.nio.ByteOrder;

  24. /**
  25.  * Reads bits from an InputStream.
  26.  *
  27.  * @since 1.10
  28.  * @NotThreadSafe
  29.  */
  30. public class BitInputStream implements Closeable {
  31.     private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit
  32.     private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1];

  33.     static {
  34.         for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) {
  35.             MASKS[i] = (MASKS[i - 1] << 1) + 1;
  36.         }
  37.     }

  38.     private final org.apache.commons.io.input.BoundedInputStream in;
  39.     private final ByteOrder byteOrder;
  40.     private long bitsCached;
  41.     private int bitsCachedSize;

  42.     /**
  43.      * Constructor taking an InputStream and its bit arrangement.
  44.      *
  45.      * @param in        the InputStream
  46.      * @param byteOrder the bit arrangement across byte boundaries, either BIG_ENDIAN (aaaaabbb bb000000) or LITTLE_ENDIAN (bbbaaaaa 000000bb)
  47.      */
  48.     public BitInputStream(final InputStream in, final ByteOrder byteOrder) {
  49.         this.in = org.apache.commons.io.input.BoundedInputStream.builder().setInputStream(in).asSupplier().get();
  50.         this.byteOrder = byteOrder;
  51.     }

  52.     /**
  53.      * Drops bits until the next bits will be read from a byte boundary.
  54.      *
  55.      * @since 1.16
  56.      */
  57.     public void alignWithByteBoundary() {
  58.         final int toSkip = bitsCachedSize % Byte.SIZE;
  59.         if (toSkip > 0) {
  60.             readCachedBits(toSkip);
  61.         }
  62.     }

  63.     /**
  64.      * 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
  65.      * stream.
  66.      *
  67.      * @throws IOException if the underlying stream throws one when calling available
  68.      * @return estimate of the number of bits that can be read without blocking
  69.      * @since 1.16
  70.      */
  71.     public long bitsAvailable() throws IOException {
  72.         return bitsCachedSize + (long) Byte.SIZE * in.available();
  73.     }

  74.     /**
  75.      * Returns the number of bits that can be read from this input stream without reading from the underlying input stream at all.
  76.      *
  77.      * @return estimate of the number of bits that can be read without reading from the underlying stream
  78.      * @since 1.16
  79.      */
  80.     public int bitsCached() {
  81.         return bitsCachedSize;
  82.     }

  83.     /**
  84.      * Clears the cache of bits that have been read from the underlying stream but not yet provided via {@link #readBits}.
  85.      */
  86.     public void clearBitCache() {
  87.         bitsCached = 0;
  88.         bitsCachedSize = 0;
  89.     }

  90.     @Override
  91.     public void close() throws IOException {
  92.         in.close();
  93.     }

  94.     /**
  95.      * Fills the cache up to 56 bits
  96.      *
  97.      * @param count
  98.      * @return return true, when EOF
  99.      * @throws IOException
  100.      */
  101.     private boolean ensureCache(final int count) throws IOException {
  102.         while (bitsCachedSize < count && bitsCachedSize < 57) {
  103.             final long nextByte = in.read();
  104.             if (nextByte < 0) {
  105.                 return true;
  106.             }
  107.             if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
  108.                 bitsCached |= nextByte << bitsCachedSize;
  109.             } else {
  110.                 bitsCached <<= Byte.SIZE;
  111.                 bitsCached |= nextByte;
  112.             }
  113.             bitsCachedSize += Byte.SIZE;
  114.         }
  115.         return false;
  116.     }

  117.     /**
  118.      * Returns the number of bytes read from the underlying stream.
  119.      * <p>
  120.      * This includes the bytes read to fill the current cache and not read as bits so far.
  121.      * </p>
  122.      *
  123.      * @return the number of bytes read from the underlying stream
  124.      * @since 1.17
  125.      */
  126.     public long getBytesRead() {
  127.         return in.getCount();
  128.     }

  129.     private long processBitsGreater57(final int count) throws IOException {
  130.         final long bitsOut;
  131.         final int overflowBits;
  132.         long overflow = 0L;

  133.         // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow
  134.         final 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.             final long bitsToAdd = nextByte & MASKS[bitsToAddCount];
  142.             bitsCached |= bitsToAdd << bitsCachedSize;
  143.             overflow = nextByte >>> bitsToAddCount & MASKS[overflowBits];
  144.         } else {
  145.             bitsCached <<= bitsToAddCount;
  146.             final 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.      * Returns at most 63 bits read from the underlying stream.
  157.      *
  158.      * @param count the number of bits to read, must be a positive number not bigger than 63.
  159.      * @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
  160.      *         requested number of bits
  161.      * @throws IOException on error
  162.      */
  163.     public long readBits(final int count) throws IOException {
  164.         if (count < 0 || count > MAXIMUM_CACHE_SIZE) {
  165.             throw new IOException("count must not be negative or greater than " + MAXIMUM_CACHE_SIZE);
  166.         }
  167.         if (ensureCache(count)) {
  168.             return -1;
  169.         }

  170.         if (bitsCachedSize < count) {
  171.             return processBitsGreater57(count);
  172.         }
  173.         return readCachedBits(count);
  174.     }

  175.     private long readCachedBits(final int count) {
  176.         final long bitsOut;
  177.         if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
  178.             bitsOut = bitsCached & MASKS[count];
  179.             bitsCached >>>= count;
  180.         } else {
  181.             bitsOut = bitsCached >> bitsCachedSize - count & MASKS[count];
  182.         }
  183.         bitsCachedSize -= count;
  184.         return bitsOut;
  185.     }

  186. }