All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.compress.archivers.zip.BitStream Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.apache.commons.compress.archivers.zip;

import java.io.IOException;
import java.io.InputStream;

/**
 * Iterates over the bits of an InputStream. For each byte the bits
 * are read from the right to the left.
 *
 * @since 1.7
 */
class BitStream {

    private final InputStream in;

    /** The bits read from the underlying stream but not consumed by nextBits() */
    private long bitCache;

    /** The number of bits available in the bit cache */
    private int bitCacheSize;

    /** Bit masks for extracting the right most bits from a byte */
    private static final int[] MASKS = new int[]{ 
            0x00, // 00000000
            0x01, // 00000001
            0x03, // 00000011
            0x07, // 00000111
            0x0F, // 00001111
            0x1F, // 00011111
            0x3F, // 00111111
            0x7F, // 01111111
            0xFF  // 11111111
    };

    BitStream(InputStream in) {
        this.in = in;
    }

    private boolean fillCache() throws IOException {
        boolean filled = false;
        
        while (bitCacheSize <= 56) {
            long nextByte = in.read();
            if (nextByte == -1) {
                break;
            }
            
            filled = true;
            bitCache = bitCache | (nextByte << bitCacheSize);
            bitCacheSize += 8;
        }

        return filled;
    }

    /**
     * Returns the next bit.
     * 
     * @return The next bit (0 or 1) or -1 if the end of the stream has been reached
     */
    int nextBit() throws IOException {
        if (bitCacheSize == 0 && !fillCache()) {
            return -1;
        }

        int bit = (int) (bitCache & 1); // extract the right most bit

        bitCache = (bitCache >>> 1); // shift the remaning bits to the right
        bitCacheSize--;

        return bit;
    }

    /**
     * Returns the integer value formed by the n next bits (up to 8 bits).
     *
     * @param n the number of bits read (up to 8)
     * @return The value formed by the n bits, or -1 if the end of the stream has been reached
     */
    int nextBits(final int n) throws IOException {
        if (bitCacheSize < n && !fillCache()) {
            return -1;
        }

        final int bits = (int) (bitCache & MASKS[n]); // extract the right most bits

        bitCache = (bitCache >>> n); // shift the remaning bits to the right
        bitCacheSize = bitCacheSize - n;

        return bits;
    }

    int nextByte() throws IOException {
        return nextBits(8);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy