InputStream utility based on the java.nio package. Reads up to 32 bits at a time from a file, using multiple buffers to quickly process read calls

0

I have an assignment where you should use Huffman coding to compress/un-compress binary files, and the professor sent us this input stream class to help us, I don't understand how it works. so, I was hoping if anyone knows a good website or any sources that can help me understand it? what do we use the bit mask array for and does anyone have a different (and simpler) implementation for a similar class?

/**
 *  InputStream utility based on the java.nio package.  Reads
 *  up to 32 bits at a time from a file, using multiple buffers
 *  to quickly process read calls.  Runtime is approximately
 *  100 times faster than previous iteration built on java.io.
 *
 *  @contributor Owen Astrachan
 *  @author Brian Lavallee
 *  @date 10 April 2016
 */

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

public class BitInputStream extends InputStream {
    
    private static final int BYTE_SIZE = 8;
    private static final int INT_SIZE = 32;
    private static final int BIT_BUFFER_SIZE = 8;
    private static final int BUFFER_SIZE = 8192;
    
    private static final long bitMask[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff, 0x7ff,
            0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff, 0x1ffff, 0x3ffff, 0x7ffff, 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
            0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffffl,
            0x1ffffffffl, 0x3ffffffffl, 0x7ffffffffl, 0xfffffffffl, 0x1fffffffffl, 0x3fffffffffl, 0x7fffffffffl,
            0xffffffffffl, 0x1ffffffffffl, 0x3ffffffffffl, 0x7ffffffffffl, 0xfffffffffffl, 0x1fffffffffffl,
            0x3fffffffffffl, 0x7fffffffffffl, 0xffffffffffffl, 0x1ffffffffffffl, 0x3ffffffffffffl, 0x7ffffffffffffl,
            0xfffffffffffffl, 0x1fffffffffffffl, 0x3fffffffffffffl, 0x7fffffffffffffl, 0xffffffffffffffl,
            0x1ffffffffffffffl, 0x3ffffffffffffffl, 0x7ffffffffffffffl, 0xfffffffffffffffl, 0x1fffffffffffffffl,
            0x3fffffffffffffffl, 0x7fffffffffffffffl, 0xffffffffffffffffl };
    
    private InputStream source;
    private ReadableByteChannel input;
    private ByteBuffer buffer;
    private int bitsRead, available, limit;
    private long bitBuffer;
    
    public BitInputStream(String filePath) {
        this(new File(filePath));
    }
    
    public BitInputStream(File fileSource) {
        try {
            initialize(new FileInputStream(fileSource));
        }
        catch (FileNotFoundException fnf) {
            throw new RuntimeException(fnf);
        }
    }
    
    public BitInputStream(InputStream in) {
        initialize(in);
    }
    
    private void initialize(InputStream in) {
        source = new BufferedInputStream(in);
        source.mark(Integer.MAX_VALUE);
        bitsRead = available = 0;
        bitBuffer = 0;
        limit = BUFFER_SIZE;
        input = Channels.newChannel(source);
        buffer = ByteBuffer.allocate(BUFFER_SIZE);
        buffer.position(BUFFER_SIZE);
    }
    
    public int bitsRead() {
        return bitsRead;
    }
    
    public void reset() {
        try {
            source.reset();
            source.mark(Integer.MAX_VALUE);
            bitsRead = available = 0;
            bitBuffer = 0;
            limit = BUFFER_SIZE;
            input = Channels.newChannel(source);
            buffer = ByteBuffer.allocate(BUFFER_SIZE);
            buffer.position(BUFFER_SIZE);
        }
        catch (IOException io) {
            throw new RuntimeException(io);
        }
    }
    
    public void close() {
        try {
            source.close();
            input.close();
        }
        catch (IOException io) {
            throw new RuntimeException(io);
        }
    }
    
    public int read() {
        return readBits(BYTE_SIZE);
    }
    
    public int readBits(int numBits) {
        if (numBits > INT_SIZE || numBits < 1) {
            throw new RuntimeException("Illegal argument: numBits must be on [1, 32]");
        }
        
        bitsRead += numBits;
        
        int value = 0;
        
        if (numBits > available) {
            value = (int) bitBuffer;
            numBits -= available;
            value <<= numBits;
            if (!fillBitBuffer()) {
                return -1;
            }
        }
        
        if (numBits > available) {
            return -1;
        }
        
        value |= bitBuffer >>> (available - numBits);
        bitBuffer &= bitMask[available - numBits];
        available -= numBits;
        
        return value;
    }
    
    private boolean fillBitBuffer() {
        if (!buffer.hasRemaining()) {
            if (!fillBuffer()) {
                return false;
            }
        }
        
        available = BYTE_SIZE * Math.min(BIT_BUFFER_SIZE, limit - buffer.position());
        bitBuffer = buffer.getLong();
        bitBuffer >>>= (int) Math.pow(2, BIT_BUFFER_SIZE) - available;
        return true;
    }
    
    private boolean fillBuffer() {
        try {
            buffer.clear();
            limit = input.read(buffer);
            buffer.flip();
            if (limit == -1) {
                return false;
            }
            buffer.limit(limit + (BIT_BUFFER_SIZE - limit % BIT_BUFFER_SIZE) % BIT_BUFFER_SIZE);
            return true;
        }
        catch (IOException io) {
            throw new RuntimeException(io);
        }
    }
}
java
compression
bufferedreader
huffman-code
bitstream

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0