/*
 * BitIO.java
 * Provides classes to read and write to a file on a bit-basis:
 *   BitInputStream class
 *   BitOutputStream class 
*/
import java.io.*;
//import java.util.BitSet;
   
class BitInputStream
{
  private InputStream ins;
  private int value;
  private int bitPos = 8;
  private final int max_bits = 30;
  
  public BitInputStream( InputStream in ) 
  {
       ins = in;
  }
  
  //read one bit
  synchronized public int readBit() throws IOException 
  {
     if (ins == null)
       throw new IOException( "Stream closed" );
   
     if ( bitPos == 8 ) {
         value = ins.read();
   
         if (value==-1)
           return -1;      //out of data
         
          bitPos = 0;
     }
  
     //LSB first 
     int bit = value & (1<<bitPos);
     bitPos++;
   
     return ( bit == 0 ? 0 : 1 );
   
   }
   
  //read n bits 
  synchronized public int readBits( int n ) throws IOException 
  {
    if ( n > max_bits - 1 ) {
      System.out.println("Cannot handle " + n  + " bits at one time.");
      return -2;
    }
   
    int bit; 
    int num = 0;
    int mask = 1;	//LSB first
    for ( int i = 0; i < n; ++i ){
      if ( ( bit = readBit() ) == -1 )
        return -1;
      if ( bit == 1 )
        num |=  mask;
      mask <<= 1;
    }

    return num;
  }

   public void close() throws IOException {
     ins.close();
     ins = null;
   }
}  //class BitInputStream

class BitOutputStream
{
  private OutputStream outs;
  private int value;
  private int bitCount;
   
  public BitOutputStream( OutputStream out ) 
  {
    outs = out;
  }
   
  synchronized public void writeBit( int bit ) throws IOException 
  {
    if (outs==null)
      throw new IOException( "File closed" );
   
    if (bit != 0 && bit != 1) 
       throw new IOException( bit+" is not a bit" );
   
    value |= bit << bitCount;
    bitCount++;
   
    if ( bitCount == 8 ) {
         flush();
    }
  }
   
  synchronized public void writeBits( int data, int n ) throws IOException 
  {
    int bit;
    for ( int i = 0; i < n; i++ ) {
       bit = data & 0x00000001;		//LSB first
       writeBit ( bit );
       data >>= 1;
    }
  }

  private void flush() throws IOException 
  {
    if (bitCount>0) {
         outs.write( value );
         bitCount=0;
         value=0;
    }
  }
   
  public void close() throws IOException {
     flush();
     outs.close();
     outs = null;
  }
} //BitOutputStream
