#include "includes.h"
 
/**************************************|****************************************
 "Routine   : PutBit"
                                                          MSB    LSB
                                                    b[1]   | b[0] |
Input  par: int bitn (bit number to be placed ie: 10100101 00110101   )
                                                  ^               ^
                                                bit n           bit 0 

            unsigned char bit    (bit to be placed 0 or 1)
            unsigned char *bytes (byte array to be manipulated)
Output par: unsigned char (manipulated byte extracted from bytes[])
Function  : put a bit in a bytearray at place bitn
***************************************|***************************************/
 
 unsigned char PutBit(int bitn, unsigned char bit, unsigned char *bytes)
  {
   int index  = bitn / 8;
   int b=bitn-index*8;
   unsigned char in,out;
   
   /* if (index >= strlen(bytes) ) 
   ErrorHandler(OUT_OF_RANGE,"PutBit needs larger array to place bitn"); */
   
   in = ~(0x00 | (1 << b)) ; /* setup mask */
   out = bytes[index] & in;  /* reset bitn */
   out = out          | (bit << b); /* set bitn to 0 or 1 */
   
   return out;
  }
 
/**************************************|****************************************
 "Routine   : GetBit"
                                                      MSB    LSB
                                                b[1]   | b[0] |
Input  par: int bitn (bit to be extracted ie: 10100101 00110101
                                              ^               ^
                                            bit n           bit 0
            unsigned char *bytes (byte array to extract from)
Output par: unsigned char (bit extracted)
Function  : extract a specific bit from a bytearray
***************************************|***************************************/
 
 unsigned char GetBit(int bitn, unsigned char *bytes)
  {
   int index  = bitn / 8;
   int b=bitn-index*8;
   /* if (index >= strlen(bytes) ) 
   ErrorHandler(OUT_OF_RANGE,"GetBit needs larger array to extract bitn"); */
   return (unsigned char) ((bytes[index] >> b) & 1);
  }
 
/**************************************|****************************************
 "Routine   : IOBitArray"
Input  par: int mode   (mode for routine i.e. FILE_READ, FILE_WRITE,
                        FILE_APPEND or FILE_CLOSE )
            char *file (sting for filename to be treated)
            unsigned char *bitarray (in or output bitarray -> warning:
                bitarray is altered in readmode as global var)
Output par: int (error)
Function  : General module for reading and writeing a specfic numbers of bits.
            Bits is buffered through a byte - therefore explicit open, read, write,
            append and close actions are needed.

            Works as a finite state maschine being in read, write or append mode:

            FSM:                            FILE_READ
                                           /----<----\
                        FILE_OPENREAD      |         |
            FILE_CLOSED-------->------FILE_OPENREAD--/ 
            | |  | |  ^                       |
            | |  | |  \--------<--------------/
            | |  | |       FILE_CLOSE
            | |  ^ |                        FILE_WRITE
            | |  | |                       /----<----\
            | |  | |    FILE_OPENWRITE     |         |
            | |  | \----------->------FILE_OPENWRITE-/
            ^ |  |                            |
            | |  \-------------<--------------|
            | |            FILE_CLOSE
            | |                             FILE_WRITE
            | |                            /----<----\
            | |        FILE_OPENAPPEND     |         |
            | \---------------->------FILE_OPENAPPEND/
            |                                 |
            \------------------<--------------/
                           FILE_CLOSE

***************************************|***************************************/
 
 int IOBitArray(int mode, char *file,int nbits, unsigned char *bitarray)
  {
   static int internalmode=FILE_CLOSED;
   static FILE *iofile;
   static unsigned char buff=0;
   static int buffn=0;
   
   unsigned char temp;
   int i,j=0,duum; /* j=bit nr in bitarray */
   
   if ((mode==FILE_WRITE) || (mode==FILE_APPEND)) /* write/append bits */
    {
     if ((internalmode==FILE_OPENWRITE) ||  (internalmode==FILE_OPENAPPEND))
      {
       while (j<nbits)
        {
         if (buffn<8)  buff = buff | (GetBit(j++,bitarray) << buffn++);
         /* fill up byte buffer */
         else
          {
           if (0>fprintf(iofile,"%c",buff))
           ErrorHandler(ERROR_WRITING,"IOBitArray could not write bits"); 
           buff=0;  /* reset buffer */
           buffn=0; /* reset buff counter */
          }
        }
       return(NO_ERROR);
      }
     else return(FILEMODE_ERROR);
    }
   
   if (mode==FILE_READ) /* read bits */
    {
     if (internalmode==FILE_OPENREAD)
      {
       i=0;
       
       do bitarray[i]=0;
       while(i++<(nbits/8)+2); /* reset array */
       
       while (j<nbits)
        {
         if (buffn==0)
          {
           duum=fgetc(iofile);
           buff=(unsigned char)duum;
           if (duum==EOF) ErrorHandler(ERROR_READING,"Reached EOF");
           buffn=8; /* 8 bit in buffer now */
          }
         temp = (GetBit(8-buffn--,&buff));
         bitarray[j/8] = PutBit(j,temp,bitarray);
         j++;
        }
       return(NO_ERROR);
      }
     else return(FILEMODE_ERROR);
    }
   
   else if ((mode==FILE_OPENWRITE) || (mode==FILE_OPENAPPEND) || (mode==FILE_OPENREAD) )
   /* should we go to writemode ? */
    {
     if (internalmode==FILE_CLOSED)
      {
       if (mode==FILE_OPENWRITE) 
        {
         if ((iofile=fopen(file,"wb")) == NULL) return(UNABLE_TO_OPEN);
         internalmode=FILE_OPENWRITE; /* really in writemode now */
        }
       else if (mode == FILE_OPENAPPEND)
        {
         if ((iofile=fopen(file,"ab")) == NULL) return(UNABLE_TO_OPEN);
         internalmode=FILE_OPENAPPEND; /* really in appendmode now */
        }
       else
        {
         if ((iofile=fopen(file,"rb")) == NULL) return(UNABLE_TO_OPEN);
         internalmode=FILE_OPENREAD; /* really in readmode now */
        }
       return(NO_ERROR);
      }
     else return(FILEMODE_ERROR);
    }
   
   else if (mode==FILE_CLOSE) /* close file ? */
    {
     if ((internalmode==FILE_OPENWRITE) || (internalmode==FILE_OPENAPPEND))
      {
       if (buffn!=0)
        {
         if (0>fprintf(iofile,"%c",buff)) 
         ErrorHandler(ERROR_WRITING,"IOBitArray could not write bits");
         buff=0;
         buffn=0;
        }
       if (fclose(iofile)) return(UNABLE_TO_CLOSE);
       internalmode=FILE_CLOSED; /* in no mode now */
       return(NO_ERROR);
      }
     else if (internalmode==FILE_READ)
      {
       if (fclose(iofile)) return(UNABLE_TO_CLOSE);
       internalmode=FILE_CLOSED; /* in no mode now */
       buff=0;
       buffn=0;
       return(NO_ERROR);
      }
     else return(FILEMODE_ERROR);
    }
   
   else return(FILEMODE_ERROR);
  }
