BitStreamInputStream.java
contents ::
  App.java
  BitStreamInputStream.java
  BitStreamOutputStream.java
  lzwScript
  input

//---------------------------
// Class BitStreamInputStream
// --------------------------
// Implements an enhanced InputStream which allows you to read a
// stream of bit fields ranging in size from 1 bit (a true bit
// stream) to 32 bits (a stream of integers). The size of the current
// bitfield can be changed at any point while reading the stream.
// (c) Laurence Vanhelsuwe 1996. E-Mail: LVA@telework.demon.co.uk
//------------------------------------------------------------------

package jlittle_ex9;

import java.io.*;

public class BitStreamInputStream extends FilterInputStream {
    final static int EIGHT = 8; // 8 bits per byte
    protected short buffer; // our BYTE bitstream read-ahead
    // buffer declared as short to cope with EOF
    protected int bitsInCache;  // how many unread bits left in our byte
    protected int fieldSize;    // current size of bitstream read fields

    //------------------------------------------------------------------
    public BitStreamInputStream(InputStream in) {

         this(in, EIGHT);       // default to a normal byte stream
    }
    //------------------------------------------------------------------
    public BitStreamInputStream(InputStream in, int bitFieldSize) {
         super(in);
         setBitFieldSize(bitFieldSize);
         bitsInCache = 0;        // we haven't got any cached bits
    }
    //------------------------------------------------------------------
    // Set the current bitfield size.
    //------------------------------------------------------------------
    public void setBitFieldSize(int bits) throws IllegalArgumentException {
         if (bits>32 || bits<1) throw new IllegalArgumentException
             (
              "BitField size ("+ bits + ") no good. Has to be between 1 and 32."
              );
         this.fieldSize = bits;
    }
    //------------------------------------------------------------------
    public int getBitFieldSize() {
         return this.fieldSize;
    }
    //------------------------------------------------------------------
    // Read a bitfield from the input stream. The number of bits read is
    // the current bitfield length. Bitfield can be on arbitrary bit boundaries.
    //------------------------------------------------------------------
    public long readBitField() throws IOException {

         int bitField;               // what we're going to return to caller
         int bitsToRead;             // remaining bits to assemble into BF
         int availableNumberOfBits;
         int OR_position;
         int rightAlignedBFPartial;
         bitField    = 0;        // start with empty jigsaw
         bitsToRead  = fieldSize;
         OR_position = fieldSize;

         while (bitsToRead > 0) {
             if (bitsInCache == 0) {
                  if ( (buffer = (short) in.read()) == -1) {
                      return -1;          // reached EOF
                  }
                  bitsInCache = EIGHT;    // we've got a full byte again
             }
             availableNumberOfBits = Math.min( bitsToRead, bitsInCache );
             rightAlignedBFPartial = buffer >> (EIGHT - availableNumberOfBits);
             // always keep next partial left aligned and clean
             buffer <<= availableNumberOfBits;
             buffer &= 255;
             OR_position -= availableNumberOfBits;
             // add bitfield subfield
             bitField |= rightAlignedBFPartial << OR_position;
             // track # of cached bits
             // track how much left to do

             bitsInCache -= availableNumberOfBits;
             bitsToRead  -= availableNumberOfBits;
         }
         return bitField;
    }
    //---------------------------------------------
    // The remaining methods are methods we override
    // from our parent class: FilterInputStream
    //---------------------------------------------
    //------------------------------------------------------------------
    // Overridden read() still reads a byte, but on any bit boundary.
    //------------------------------------------------------------------
    public int read() throws IOException {
         int previousBFSize;
         int theByte;
         previousBFSize = getBitFieldSize();
         setBitFieldSize( EIGHT );
         try {
             theByte = (int) readBitField();
         }
         finally {
             setBitFieldSize( previousBFSize );
         }
         return theByte;
    }
    //------------------------------------------------------------------
    // Override block read() methods to use basic read() as building block.
    // The implementation we want for this read() is the same as that
    // for class InputStream.
    // According to the Java language spec, two elegant (and short
    // solution should work:
    //   ((InputStream) this).read(..)      // i.e. a cast
    //   InputStream.read(..)               // i.e. fully specifiying
    // Unfortunately neither work, so I am forced to paste in the
    // original code for InputStream.read(byte b[], int off, int len).
    //------------------------------------------------------------------

    public int read(byte b[], int off, int len) throws IOException {

         if (len <= 0) {
             return 0;
         }
         int c = read();
         if (c == -1) {
             return -1;
         }
         b[off] = (byte)c;
                 
         int i = 1;
         try {
             for (; i < len ; i++) {
                  c = read();
                  if (c == -1) {
                      break;
                  }
                  if (b != null) {
                      b[off + i] = (byte)c;
                  }
             }
         } catch (IOException ee) {}
         return i;
    }
    //------------------------------------------------------------------
    // Overridden FilterInputStream.read(byte b[])
    //------------------------------------------------------------------
    public int read(byte b[]) throws IOException {
         return read(b, 0, b.length);
    }
    //------------------------------------------------------------------
    // Overridden FilterInputStream.skip(long n)
    // If any client relies heavily on skipping multi-byte strings in
    // the bitstream, then this method has to be re-implemented to be more
    // efficient. Current implementation is functional but highly inefficient.
    //------------------------------------------------------------------
    public long skip(long n) throws IOException {
         long i;

         for(i=0; i < n; i++) {
             if (read() == -1) break;
         }
         return i;
    }
} // End of Class BitStreamInputStream

James Little