

   /*
    * This file contains routines to perform bit-wise reading and
    * writing to a FILE.  It's not a complete set of routines,
    * since it's missing "bread_ones", but it's close.
    *
    *                    Michael Richmond  9/07/1995
    *                    
    */

#include <stdio.h>
#include <malloc.h>
#include "bits.h"


   /*
    * for machines which don't have /usr/include/bstring.h, 
    * we have to declare the "bcopy" and "bzero" functions
    * here.
    */
#ifndef NOBCOPY
#ifdef BSTRINGS
#include <bstring.h>
#else
extern void bcopy(const void *src, void *dst, int length);
extern void bzero(void *b, int length);
#endif /* BSTRINGS */
#endif /* NOBCOPY */

   /*
    * for machines which don't have the "bcopy" and "bzero" 
    * functions (which may be BSD-isms), we have to use our
    * own "private" versions in this file.
    */
#ifdef NOBCOPY
static void bcopy(const void *src, void *dst, int length);
static void bzero(void *ptr, int length);
#endif



#undef DEBUG

#define BUFSIZE    8192        /* number of bytes in buffer */
#define CHUNK      4096        /* write out data in chunks of this size */
                               /*   must be less than BUFSIZE */

static char *buf;
static unsigned int bitp;      /* index of bit into which we'll next write */
static unsigned int boff;      /* offset of current bit from high-order */
                               /*    bit in the current byte */
static char *lastp;            /* ptr to last byte of data read into buffer */
static char *bytep;            /* pointer to byte into which we next write */


   /* 
    * we can use this array to set a bit; if we want to set bit 'N', where
    * 'N' counts downward from high-order bit (this, N=0 means high-order
    * bit, and N=7 means low-order bit), then we can OR with set_bits[N].
    */
static char set_bits[] = {
   0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01
};
   /* 
    * this variable points to the last valid entry in "set_bits"
    */
static char *set_bits_end = set_bits + 7;

   /* 
    * ditto, but we can use this array to set bit N in a 16-bit quantity
    */
static unsigned short int set_big_bits[] = {
   0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
   0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001
};


   /*
    * these arrays will contain the value which should be OR'd with
    * a byte to encode bits properly for some given number, in the
    * following sense:
    *
    *    - first, we assert that the number we are to encode
    *         using these arrays has M <= 8 non-zero bits,
    *         i.e. it can't be more than 255.
    *
    *    - suppose that the current bit pointer is offset H bits
    *         from the high-order end of the current byte.  Note
    *         that H <= 7, since there are only 8 bits in a byte.
    *    - suppose we wish to encode the (unsigned 16-bit) number N, 
    *         which has M bits
    *    - suppose we have 2 ways to encode a number N:
    *         if N <= N(max), we use the lookup tables below to do it.
    *         if N >  N(max), we go bit-by-bit, slowly and painfully.
    *
    *  --> then   nbytes_to_or[H]    holds an integer which tells us how
    *                                   many bytes (including the current
    *                                   byte) are needed to encode those
    *                                   M bits.  It can range from 
    *                                       1  (use current byte only)
    *                                    to
    *                                       2  (use current -- current+1)
    *
    *  --> and    nbytes_to_advance[H]  holds the number of bytes by
    *                                    which we must advance the current
    *                                    byte pointer after we've encoded
    *                                    the M bits.  It can be either
    *                                    0 or 1.
    *
    *  --> also,  bit_array_1[H][N]  contains a byte which should
    *                                   be ORed with the current byte
    *             bit_array_2[H][N]  contains a byte which should be OR'd
    *                                   with the current+1 byte (if necessary)
    *             bit_array_3[H][N]  contains a byte which should be OR'd
    *                                   with the current+2 byte (if necessary)
    *
    * We will set the values of these arrays in the "init_arrays"
    * function.
    */
#define NMAX        255           /* max size of (unsigned) number we encode */
                                  /*    using lookup tables.  Bigger numbers */
                                  /*    will be encoded bit-by-bit "by hand" */

static int nbytes_to_or[8];
static int nbytes_to_advance[8];
static char bit_array_1[8][NMAX];
static char bit_array_2[8][NMAX];

static int my_noise_bits;         /* number of bits assigned to "noise" */

   /*
    * these two variables are used in "new_bwrite_number" to count
    * the number of times the user call the function with a value 
    *
    *        which _can_ be written in <= noise_bits    num_quick
    *        which _can't_                              num_slow
    */
static long num_quick = 0;
static long num_slow = 0;

   /*
    * static functions in this file 
    */

#ifdef DEBUG
static void
b_print_binary(unsigned short int val);
static void
byte_print_binary(char val);
#endif

static void
check_flush(FILE *fp);

static int
check_read(FILE *fp);

static void 
init_arrays(int noise_bits);



   /*
    * a useful debugging tool
    */


#ifdef DEBUG

static void
b_print_binary
   (
   unsigned short int val              /* quantity to be printed in binary */
   )
{
   int i;

   printf(" val is %6u ", val);
   for (i = 15; i >= 0; i--) {
      if (val & (0x1 << i)) {
         putchar('1');
      }
      else {
         putchar('0');
      }
   }
   putchar('\n');
}


   /*
    * print the given byte value without a newline
    */

static void
byte_print_binary
   (
   char val                  /* quantity to be printed in binary */
   )
{
   int i;

   for (i = 7; i >= 0; i--) {
      if (val & (0x1 << i)) {
         putchar('1');
      }
      else {
         putchar('0');
      }
   }
}

#endif



   /*
    * initialize the buffer, and set all bits to zero.
    */

void
init_buf
   (
   int noise_bits             /* I: number of bits used for "noise" */
   )
{
   if ((buf = (char *)malloc(BUFSIZE)) == NULL) {
      fprintf(stderr, "init_buf: can't malloc for %d bytes", BUFSIZE);
      exit(1);
   }
   bitp = 0;
   bytep = buf;
   lastp = buf + CHUNK - 1;
   bzero(buf, BUFSIZE);

#ifndef SLOW
   init_arrays(noise_bits);
#endif
   my_noise_bits = noise_bits;
}

   /*
    * free the space allocated for the buffer
    */

void
free_buf
   (
   void
   )
{
   free(buf);

#ifdef DEBUG
   printf(" num_quick %ld   num_slow %ld\n", num_quick, num_slow);
#endif
}




   /*
    * flush the buffer into the given FILE (padding with zero bits)
    * and de-allocate memory.
    */

int
finish_buf
   (
   FILE *fp                /* FILE into which to flush the buffer */
   )
{
   int ntowrite, nwritten;

   ntowrite = (bytep - buf) + 1;
   if ((nwritten = fwrite((char *) buf, ntowrite, 1, fp)) != 1) {
      fprintf(stderr, "finish_buf: fwrite returns %d, not %d\n",
    nwritten, 1);
      exit(1);
   }
   free_buf();


   return(0);
}


   /*
    * initialize the arrays that we use to do quick OR'ing of new
    * values into the growing buffer.  
    *
    * Note that we only use these arrays for values <= NMAX. 
    * Larger values will be OR'd 1 bit at a time, "by hand".  That
    * will be slower, but keeps this initialization routine short
    * and fast.
    *
    *
    *  --> then   nbytes_to_or[H]    holds an integer which tells us how
    *                                   many bytes (including the current
    *                                   byte) are needed to encode those
    *                                   M bits.  It can range from 
    *                                       1  (use current byte only)
    *                                    to
    *                                       2  (use current -- current+2)
    * 
    *  --> and    nbytes_to_advance[H]  holds the number of bytes by
    *                                    which we must advance the current
    *                                    byte pointer after we've encoded
    *                                    the M bits.  It can be either
    *                                    0 or 1.
    *
    *  --> also,  bit_array_1[H][N]  contains a byte which should
    *
    *  --> also,  bit_array_1[H][N]  contains a byte which should
    *                                   be ANDed with the current byte
    *             bit_array_2[H][N]  contains a byte which should be OR'd
    *                                   with the current+1 byte (if necessary)
    *             bit_array_3[H][N]  contains a byte which should be OR'd
    *                                   with the current+2 byte (if necessary)
    */

static void
init_arrays
   (
   int noise_bits             /* number of noise bits we'll use in encoding */
   )
{
   unsigned char value, val;
   char mask_array[8], mask_array_2[8], mask, mask2;
   int i, ivalue;
   int a, b, c, cur_bitp;
   int max_value;

#ifdef DEBUG
   printf("entering init_arrays\n");
#endif

   if (noise_bits > 8) {
      fprintf(stderr, "init_arrays: too many noise bits!");
      exit(1);
   }

   max_value = (1 << noise_bits) - 1;

   /* 
    * we use this to separate the portions of "value" that we'll 
    * use to set the current byte, and (if necessary) the current+1 byte.
    * 
    * Given some 16-bit value, and that the current bit-pointer is
    * offset 'b' bits from the high-order bit of the current byte,
    *
    *      value & mask_array[b]     will contain the bits we will
    *                                     write into the current output byte
    *                                     (although we may have to shift them
    *                                     in either direction before writing)
    *      value & mask_array_2[b]   will contain the bits we will write
    *                                     into the next output byte
    *                                     (which must always be shifted to
    *                                     start at the most-significant byte)
    */
   mask_array[0] = 0;
   mask_array_2[0] = 0;
   for (i = 0; i < noise_bits; i++) {
      mask_array[0] |= 0x1 << i;
   }
#ifdef DEBUG
      printf(" mask_array[%3d] ", 0);
      byte_print_binary(mask_array[0]);
      printf(" mask_array_2[%3d] ", 0);
      byte_print_binary(mask_array_2[0]);
      printf("\n");
#endif
   for (i = 1; i < 8; i++) {
      mask_array[i] = mask_array[0];
      mask_array_2[i] = mask_array_2[i - 1];
      if (8 - i < noise_bits) {
	 mask_array_2[i] |= (0x1 << (noise_bits - (9 - i)));
	 mask_array[i] = mask_array[i - i] & ~mask_array_2[i];
      }
#ifdef DEBUG
      printf(" mask_array[%3d] ", i);
      byte_print_binary(mask_array[i]);
      printf(" mask_array_2[%3d] ", i);
      byte_print_binary(mask_array_2[i]);
      printf("\n");
#endif
   }

   /*
    * "cur_bitp" will represent the offset of the bit pointer "bitp"
    * inside the current byte.  
    *      cur_bitp  = 0     if bitp points to the highest-order bit
    *      cur_bitp  = 7     if bitp points to the lowest-order bit
    */
   for (cur_bitp = 0; cur_bitp < 8; cur_bitp++) {


      mask  = mask_array[cur_bitp];
      mask2 = mask_array_2[cur_bitp];

      /*
       * we need three quantities to tell us how much to shift the
       * bits into their proper places:
       *    a: pertains to current byte      if > 0, shift bits LEFT
       *                                          by this amount
       *    b: pertains to current byte      if > 0, shift bits RIGHT
       *                                          by this amount
       *    c: pertains to NEXT byte         shift bits LEFT by this amount
       * 
       */
      a = (8 - cur_bitp) - noise_bits;
      b = 0 - a;
      c = (cur_bitp + noise_bits) - 8;

#ifdef DEBUG
      printf(" cur_bitp = %d  mask = ", cur_bitp);
      byte_print_binary(mask);
      printf(" mask2 = ");
      byte_print_binary(mask2);
      printf(" a = %d  b = %d\n", a, b);
#endif

      /* 
       * first, fill the array "nbytes_to_or", which tells us whether we
       * need only to modify the current byte (nbytes_to_or = 1),
       * or whether we'll need to modify the current+1 byte also
       * (in which case we set nbytes_to_or = 2).
       */
      if (cur_bitp + noise_bits <= 8) {
         nbytes_to_or[cur_bitp] = 1;
      }
      else {
         nbytes_to_or[cur_bitp] = 2;
      }
#ifdef DEBUG
      printf("  nbtytes_to_or[%3d] = %d\n", 
	       cur_bitp, nbytes_to_or[cur_bitp]);
#endif

      /*
       * we also want to know if it will be necessary to advance the
       * current byte-pointer after we've encoded this number.
       * The answer is 
       *     Yes [set to 1]      if cur_bitp + noise_bits >= 8
       *     No  [set to 0]                               <  8
       *
       * Note that this is NOT quite the same condition
       * as for "nbytes_to_or", above.
       */
      if (cur_bitp + noise_bits < 8) {
	 nbytes_to_advance[cur_bitp] = 0;
      }
      else {
	 nbytes_to_advance[cur_bitp] = 1;
      }


      /*
       * "value" represents the (unsigned) integer we wish to place into
       * the output bit buffer.  We consider only the lowest-order
       * "noise_bits" bits, left-padding with zero-bits as necessary.
       * Thus, given "noise_bits" = 4 and value = 5, we consider
       * the string of bits '0101'.
       */
      for (ivalue = 0; ivalue <= max_value; ivalue++) {

	 value = ivalue;

#ifdef DEBUG
	 printf("   value = %3u = ", ivalue);
	 byte_print_binary(value);
#endif

         /* 
          * first, we consider the portion of "value" that goes into 
          * the current byte.
          */
         val = value & mask;
         if (a > 0) {
            val <<= a;
#ifdef DEBUG
	    printf(" 1 val=%3d=", (unsigned int) val);
	    byte_print_binary(val);
#endif
         }
         else {
            val >>= b;
#ifdef DEBUG
	    printf(" 2 val=%3u=", (unsigned int) val);
	    byte_print_binary(val);
#endif
         }
         bit_array_1[cur_bitp][ivalue] = val;

         /* 
          * next, we consider the portion of "value" that goes into 
          * the current+1 byte (if any at all does).
          */
         val = value & mask2;
         if (c < 0) {
            /* we don't set any bits in current+1 byte in this case */
            val = 0;
#ifdef DEBUG
	    printf(" 3 val=%3u=", (unsigned int) val);
	    byte_print_binary(val);
#endif
         }
         else {
            val <<= (8 - c);
#ifdef DEBUG
	    printf(" 4 val=%3u=", (unsigned int) val);
	    byte_print_binary(val);
#endif
         }
         bit_array_2[cur_bitp][ivalue] = val;

#ifdef DEBUG
	 printf("\n");
#endif
      }

   }
}



   /*
    * check to see if we need to flush the buffer to the FILE.
    * if so, we
    * 
    *   - write the first CHUNK bytes of buffer to FILE
    *   - set first CHUNK bytes to zeros
    *   - copy all left-over bytes back to the beginning of the buffer
    *   - set all used bytes beyond CHUNK to zero
    *   - reset the pointers
    */

static void
check_flush
   (
   FILE *fp                  /* FILE into which we write data */
   )
{
   int nwritten;

   if ((bytep - buf) >= CHUNK) {
      if ((nwritten = fwrite((char *) buf, CHUNK, 1, fp)) != 1) {
         fprintf(stderr, "check_flush: fwrite returns %d, not %d\n",
                    nwritten, 1);
         exit(1);
      }
      bzero(buf, CHUNK);
      bcopy(buf + CHUNK, buf, ((bytep - buf) - CHUNK) + 1);
      bzero(buf + CHUNK, ((bytep - buf) - CHUNK) + 1);
      bytep -= CHUNK;
      bitp -= (CHUNK << 3);

#ifdef DEBUG
      {
      long pos;

      pos = ftell(fp);
      printf("pos is %ld, bitp is now %d\n", pos, bitp);
      }
#endif

   }


}
          

   /*
    * write n 0-bits to the given FILE.
    * 
    * return 0 if all is well, 1 if there is a problem.
    */

int
bwrite_zeroes
   (
   FILE *fp,                 /* write into this file */
   int n                     /* write this many zero bits */
   )
{

   /* all we have to do is advance the bit pointer by 'n' */
   bitp += n;

   /* and adjust the byte pointer */
   bytep = buf + (bitp >> 3);

   /* and check to see if we need to flush the buffer */
   check_flush(fp);

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bwrite_zeroes: write %d, bitp = %u, pos = %ld\n", n, bitp, pos);
   }
#endif


   return(0);
}


   /*
    * write n 1-bits to the given FILE.
    * 
    * return 0 if all is well, 1 if there is a problem.
    */

int
bwrite_ones
   (
   FILE *fp,                 /* write into this file */
   int n                     /* write this many zero bits */
   )
{
   int i, j, k, offset, eight_m_offset;
   int nbytes;

   /* 
    * figure out the offset of the current bit inside the current byte,
    * where 
    *    the offset = 0 at highest-order bit, 
    *    the offset = 7 at lowest-order  bit
    */
   offset = bitp % 8;
   eight_m_offset = 8 - offset;

   /*
    * write up to (8 - offset) bits into the current byte 
    */
   for (i = 0; (i < n) && (i < eight_m_offset); i++) {
      *bytep |= (0x80 >> offset++);
   }
   bitp += i;

   /* we might be done.  If so, update pointers and return. */
   if (i == n) {
      bytep = buf + (bitp >> 3);
      check_flush(fp);
#ifdef DEBUG
      {
      long pos;
      pos = ftell(fp);
      printf("  bwrite_ones  : write %d, bitp = %u, pos = %ld\n", n, bitp, pos);
      }
#endif

      return(0);
   }

   /* 
    * if we got this far, we need to write into the next byte, and maybe
    * more.  First, calculate how many more bytes we need to touch.
    */
   nbytes = 1 + ((n - i) >> 8);

   /*
    * and move the byte pointer to the next byte, since we just
    * filled the last one.
    */
   bytep++;

   /* 
    * first, let's take care of the (nbytes - 1) bytes that we'll fill
    * completely, and leave the last byte that might not be completely
    * filled for a bit later.
    */
   for (j = 0; j < nbytes - 1; j++) {
      /* fill current byte with ones */
      *bytep = 0xFF;
      /* move to the next byte */
      bytep++;
      /* increase the bit pointer accordingly */
      bitp += 8;
   }
   
   /*
    * okay, now we have to deal with the (n-i % 8) left-over 1-bits that might
    * not fill a byte completely.
    */
   k = (n - i) % 8;
   for (j = 0; j < k; j++) {
      bitp++;
      *bytep |= (0x80 >> j);
   }

   /* check to see if we need to flush the buffer */
   check_flush(fp);

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bwrite_ones  : write %d, bitp = %u, pos = %ld\n", n, bitp, pos);
   }
#endif


   return(0);
}



   /*
    * write n 0-bits to the given FILE, followed by a single 1-bit.
    * This is equivalent to a call to "bwrite_zeroes", followed
    * by a call to "bwrite_ones", but quicker.
    * 
    * return 0 if all is well, 1 if there is a problem.
    */

int
bwrite_zeroes_and_a_one
   (
   FILE *fp,                 /* write into this file */
   int n                     /* write this many zero bits */
   )
{
   int offset;

   /* First, take care of the zeroes. */

   /* we advance the bit pointer by 'n' */
   bitp += n;
   /* and adjust the byte pointer */
   bytep = buf + (bitp >> 3);


   /* Next, we have to write a single 1-bit. */

   /* 
    * figure out the offset of the current bit inside the current byte,
    * where 
    *    the offset = 0 at highest-order bit, 
    *    the offset = 7 at lowest-order  bit
    */
   offset = bitp % 8;

   /*
    * write the single bit into the current byte 
    */
   *bytep |= (0x80 >> offset);

   /* update the bit pointer */
   bitp++;

   /* 
    * check to see if we've finished the current byte.  If so, we make
    * further checks to see if we need to flush the buffer.
    */
   if (offset == 7) {
      bytep++;
      check_flush(fp);
   }

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bwrite_zeroes_and_a_one: write %d, bitp = %u, pos = %ld\n", 
	    n, bitp, pos);
   }
#endif

   return(0);
}


   /*
    * write the low-order n bits of the given unsigned 16-bit integer to 
    * the FILE.
    * 
    * return 0 if all is well, 1 if there is a problem.
    */



int
bwrite_number
   (
   FILE *fp,                 /* write into this file */
   int n,                    /* write this many of the lowest-order bits */
   unsigned short int uval   /*   of this unsigned 16-bit integer */
   )
{
   int i;
   int offset, val_offset, bitval;
   register char *output_bitp;
   register unsigned short int *input_bitp;

   /* 
    * first, set "offset" to the bit inside the current byte which we'll
    * set next.  We count from the highest-order bit, so 
    * 
    *     offset=0 means we're about to set the highest-order bit 
    *     offset=7 means we're about to set the lowest-order bit
    */
   offset = bitp % 8;
   output_bitp = set_bits + offset;
   

   /*
    * next, set "val_offset" to the bit inside "uval" that we'll access
    * first.  If "n=2", then we want to use the 2 lowest-order bytes ...
    * which means that the first bit we'll use is the 6'th, counting
    * from the highest-order bit.
    */
   val_offset = 16 - n;
   input_bitp = set_big_bits + val_offset;

   for (i = 0; i < n; i++) {

#ifdef DEBUG
      printf(" loop i = %d, val_offset = %d, offset = %d\n", 
       i, val_offset, offset);
#endif

      /* "bitval" is the value of the current bit in "uval" */
      bitval = uval & *input_bitp++;

      /* and we set the next bit in the buffer to that value */
      if (bitval != 0) {
         *bytep |= *output_bitp;
      }


#ifdef DEBUG
      b_print_binary((unsigned short int) *bytep);
#endif

      /* 
       * now we check to see if we need to advance "bytep" -- and
       * and if so, we also have to re-set "offset" to 0.
       */
      bitp++;
      if (++output_bitp > set_bits_end) {
	 output_bitp = set_bits;
	 bytep++;
      }
   }

   if (bytep >= lastp) {
      check_flush(fp);
   }

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bwrite_number: write %u (%d bits), bitp = %u, pos = %ld\n", 
      uval, n, bitp, pos);
   }
#endif


   return(0);
}

   /*
    * This is a faster (I hope) method of writing a 16-bit unsigned
    * integer to the given the FILE.
    *
    *    if n <= noise_bits, we use a quick table-lookup method
    *                   and just one or two logical ORs
    *    if n >  noise_bits, we have to use a slower method
    *                   of setting bits one by one.
    * 
    * return 0 if all is well, 1 if there is a problem.
    */



int
new_bwrite_number
   (
   FILE *fp,                 /* write into this file */
   int n,                    /* write this many of the lowest-order bits */
   unsigned short int uval   /*   of this unsigned 16-bit integer */
   )
{
   int i;
   int offset, val_offset, bitval;
   register char *output_bitp;
   register unsigned short int *input_bitp;

   /* 
    * first, set "offset" to the bit inside the current byte which we'll
    * set next.  We count from the highest-order bit, so 
    * 
    *     offset=0 means we're about to set the highest-order bit 
    *     offset=7 means we're about to set the lowest-order bit
    */
   offset = bitp % 8;
   

   /*
    * check to see if we can use the quick table-lookup method.
    */
   if (n <= my_noise_bits) {

      /* count the number of times we entered here ... */
      num_quick++;

      *bytep |= bit_array_1[offset][uval];
      if (nbytes_to_or[offset] == 2) {
	 *(bytep + 1) |= bit_array_2[offset][uval];
      }

      /* 
       * now advance the bit pointer, and the byte pointer,
       * if necessary.
       */
      bitp += n;
      bytep += nbytes_to_advance[offset];

   }
   else {
      /* 
       * nope, we have to use the slower, bit-by-bit method
       */

      /* count the number of times we entered here ... */
      num_slow++;

      /*
       * next, set "val_offset" to the bit inside "uval" that we'll access
       * first.  If "n=2", then we want to use the 2 lowest-order bytes ...
       * which means that the first bit we'll use is the 6'th, counting
       * from the highest-order bit.
       */
      val_offset = 16 - n;
      input_bitp = set_big_bits + val_offset;
      output_bitp = set_bits + offset;

      for (i = 0; i < n; i++) {

#ifdef DEBUG
	 printf(" loop i = %d, val_offset = %d, offset = %d\n", 
                i, val_offset, offset);
#endif

	 /* "bitval" is the value of the current bit in "uval" */
	 bitval = uval & *input_bitp++;

	 /* and we set the next bit in the buffer to that value */
	 if (bitval != 0) {
	    *bytep |= *output_bitp;
	 }


#ifdef DEBUG
	 b_print_binary((unsigned short int) *bytep);
#endif

	 /* 
	  * now we check to see if we need to advance "bytep" -- and
	  * and if so, we also have to re-set "offset" to 0.
	  */
	 bitp++;
	 if (++output_bitp > set_bits_end) {
	    output_bitp = set_bits;
	    bytep++;
	 }
      }
   }

   if (bytep >= lastp) {
      check_flush(fp);
   }

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bwrite_number: write %u (%d bits), bitp = %u, pos = %ld\n", 
      uval, n, bitp, pos);
   }
#endif


   return(0);
}


/******************* routines for reading data from a file ****************/


   /*
    * read data from the given file into the buffer.  If we reach the 
    * end of file, then set the "lastbit" variable to the index
    * of the last bit in the current buffer. 
    */

int
fill_buf
   (
   FILE *fp                /* FILE from which we read into buffer */
   )
{
   int nread;

   if ((nread = fread((char *) buf, 1, CHUNK, fp)) != CHUNK) {
      lastp = buf + nread - 1;
   }
   else {
      lastp = buf + CHUNK - 1;
   }

   return(0);
}

   /*
    * we have come to the end of the current set of data in the buffer.
    * Check to see if we need to read more data from the given FILE.
    * 
    *   - if lastp % CHUNK == 0, then, yes, we do need to read more
    *        so read another CHUNK, overwriting the current contents.
    *        return 0
    *       
    *   - if not, no, we don't need to read more -- we're done.
    *        return 1
    * 
    */

static int
check_read
   (
   FILE *fp                /* FILE from which we read into buffer */
   )
{
   int nread;

   if ((bytep >= lastp) && (boff > 7)) {
      nread = fread((char *) buf, 1, CHUNK, fp);

      /* check to see if the file ends here.  If so, return 1 */
      if (nread == 0) {
         return(1);
      }

      /* reset the pointers */
      lastp = buf + nread - 1;
      bytep = buf;
      bitp = 0;
      boff = 0;
      return(0);
   }

   /* if we get here, the file must already be finished.  return 1. */
   return(1);
}


   /*
    * read a string of consecutive 0-bits from given FILE.
    * return the number of 0-bits read, or -1 if the file
    * terminated (prematurely).
    * 
    */

int
bread_zeroes
   (
   FILE *fp                  /* read from this file */
   )
{
   int n;

   n = 0;
   while (!(*bytep & (0x80 >> boff))) {
      n++;
      bitp++;
      if (++boff > 7) {
         if (++bytep > lastp) {
            if (check_read(fp) != 0) {
               return(-1);
            }
         }
         boff = 0;
      }
   }


#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bread_zeroes: read %d, bitp = %u, pos = %ld\n", n, bitp, pos);
   }
#endif

   return(n);
}


   /*
    * read a single 1-bit from the given FILE.
    * 
    * return 0 if the bit is, indeed, a 1.
    * return 1 if the bit is NOT a 1.
    * return -1 if the file ends prematurely after this bit.
    * 
    */

int
bread_single_one
   (
   FILE *fp                  /* read from this file */
   )
{

   if (!(*bytep & (0x80 >> boff))) {
      return(1);
   }

   /* if we got here, the current bit is a 1-bit */
   bitp++;
   if (++boff > 7) {
      if (++bytep > lastp) {
         if (check_read(fp) != 0) {
            return(-1);
         }
      }
      boff = 0;
   }


#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bread_single_one: read 1, bitp = %u, pos = %ld\n", bitp, pos);
   }
#endif

   return(0);
}

   /*
    * read a string of consecutive 0-bits from given FILE, 
    * _and_, in addition, a single 1-bit.
    * 
    * return the number of 0-bits read, or -1 if the file
    * terminated (prematurely).  
    * 
    */

int
bread_zeroes_and_a_one
   (
   FILE *fp                  /* read from this file */
   )
{
   int n;
   register char *boffp;

   n = 0;
   boffp = set_bits + boff;
#if 0
   while (!(*bytep & (0x80 >> boff))) {
#else
   while (!(*bytep & (*boffp++))) {
#endif
      n++;
      bitp++;
      if (++boff > 7) {
         if (++bytep > lastp) {
            if (check_read(fp) != 0) {
               return(-1);
            }
         }
         boff = 0;
	 boffp = set_bits;
      }
   }

   /* now advance past the 1-bit */
   bitp++;
   if (++boff > 7) {
      if (++bytep > lastp) {
	 if (check_read(fp) != 0) {
	    return(-1);
	 }
      }
      boff = 0;
   }
      

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bread_zeroes: read %d, bitp = %u, pos = %ld\n", n, bitp, pos);
   }
#endif

   return(n);
}


   /*
    * read N bits from the given FILE, creating an unsigned 16-bit 
    * integer by placing the bits into the lowest N bits of a
    * word.  Place the N'th bit read from the buffer into the
    * lowest-order bit, the N-1'th into the second-lowest, etc.
    * 
    * Place the 16-bit unsigned value into the argument 'uval'.
    *
    * return 0 if all goes well.
    * return 1 if the file ends (prematurely).
    * 
    */

int
bread_number
   (
   FILE *fp,                 /* read from this file */
   int nbits,                /* read this many bits from file */
   unsigned short int *uval  /* place result into this argument */
   )
{
   int i, val_offset;
   int bitval;

   *uval = 0;
   val_offset = 16 - nbits;

   for (i = 0; i < nbits; i++) {
#ifdef DEBUG
      printf(" loop i = %d, val_offset = %d, boff = %d\n", i, val_offset, boff);
#endif
      if ((bitval = *bytep & (0x80 >> boff)) != 0) {
         *uval |= 0x8000 >> val_offset;
      }
#ifdef DEBUG
      b_print_binary(*uval);
#endif
      val_offset++;
      bitp++;
      if (++boff > 7) {
         if (++bytep > lastp) {
            if (check_read(fp) != 0) {
               return(1);
            }
         }
         boff = 0;
      }
   }

#ifdef DEBUG
   {
   long pos;
   pos = ftell(fp);
   printf("  bread_number: read %d bits = %u, bitp = %u, pos = %ld\n", 
      nbits, *uval, bitp, pos);
   }
#endif

   return(0);
}



#ifdef NOBCOPY

   /*
    * this function copies "length" bytes from the location "src"
    * to the location "dst".  It does not check for overwriting
    * memory, since we don't mis-use it.
    */

static void
bcopy
   (
   const void *src,          /* copy from this location */
   void *dst,                /* copy into this location */
   int length                /* copy this many bytes */
   )
{
   register char *fromp, *last, *top;

   fromp = (char *) src;
   last = fromp + length;
   top = (char *) dst;
   while (fromp < last) {
      *top++ = *fromp++;
   }
}


   /*
    * this function sets "length" bytes to zero, starting at the
    * position "b".
    */

static void
bzero
   (
   void *ptr,                /* start setting to zero here */
   int length                /* set this many bytes to zero */
   )
{
   register char *p, *last;

   p = (char *) ptr;
   last = p + length;
   while (p < last) {
      *p++ = 0;
   }
}

#endif /* NOBCOPY */
