Listing 6 Encode 9 bytes to 11 characters

/* EBAZ.Cz
 * Contributed to Public Domain 9/93
 * by Thad Smith, Boulder Co.
 */
#include <stdlib.h>
#include <string.h>
#include "baz.h"
#include "bazcom.h"
#include "crc16.h"

static unsigned int crc;/* input CRC */
static int width;       /* # output chars/line */
static int col;         /* current column      */
static int ninb;        /* # bytes in inbuf    */
static unsigned char inbuf[BINB_LEN * 2];
static char outbuf[ENCB_LEN * 2];
static int (*outfunc) (const char *out, size_t len);

#define BASESQ (unsigned long)(BASE*BASE)
#define MAKE_PRINT(c) (char)((c)+FIRST_CODE)
#define CV2ASCII(p,v) ((p)[0]=MAKE_PRINT((v)/BASE), \
                   (p)[1]=MAKE_PRINT((v)%BASE))

static int putn (const char *out, int n);

/* Initialize the BAZ911 encoder. */
int ebaz_init (
   int p_width,           /* width of output lines */
   outf_t *p_outfunc
){
   initcrctab ();
   crc = CRC_INIT_VALUE;
   ninb = 0;
   col = 0;
   outfunc = p_outfunc;
   width = p_width;
   return 0;
}

/* Encode the next block of data. */
int ebaz_data (
   const unsigned char *data,
   size_t len           /* length of data or 0=end */
){
   int         s;       /* output return status */

   if (len) {
      unsigned int cl;  /* # bytes needed for block */
      while (len > MAX_ENDBLK_DB - ninb) {
         if (ninb) {
            if (ninb < BINB_LEN) {
               cl = BINB_LEN - ninb;
               memcpy (inbuf + ninb, data, cl);
               len -= cl;
               data += cl;
               ninb = BINB_LEN;
            }
            /* convert block in inbuf */
            crc = updcrc (crc, inbuf, BINB_LEN);
            encode_9_to_11 (outbuf, inbuf);
            if ((s = putn (outbuf, ENCB_LEN)) != 0)
               return s;

            /* Now move remainder in inbuf down */
            memmove (inbuf, inbuf + BINB_LEN, ninb -= BINB_LEN);
          } else {
            /* Encode full blocks from input buffer */
            for (; len > MAX_ENDBLK_DB;
                data += BINB_LEN, len -= BINB_LEN) {

              crc = updcrc (crc, data, BINB_LEN);
              encode_9_to_11 (outbuf, data);
              if ((s = putn (outbuf, ENCB_LEN)) !=0)
                 return s;
            }
         }
      }
      /* Copy remainder of input to working buffer */
      memcpy (inbuf + ninb, data, len);
      ninb += len;
      return 0;

   } else {              /* final block of data */
      /** Write endmarker with final byte count.
       * Insert CRC and fill out blocks with 0xff to
       * prevent change when output is truncated.   */
      char        endmark[2];
      endmark[0] = END_FLAG;
      endmark[1] = MAKE_PRINT(ninb);
      if ((s = putn (endmark, sizeof endmark)) != 0)
         return s;

      crc = updcrc (crc, inbuf, ninb);
      inbuf[ninb++] = (crc >> 8) & 0xff;
      inbuf[ninb++] = crc & 0xff;
      memset (inbuf + ninb, 0xff, BINB_LEN * 2 - ninb);
      encode_9_to_11 (outbuf, inbuf);
      if (ninb > BINB_LEN) {
         ninb += 2;
         encode_9_to_11 (outbuf + ENCB_LEN,
                      inbuf + BINB_LEN);
      } else if (ninb < BINB_LEN-2) ninb = BINB_LEN-2;
      /* Truncate the last block to the number of
       * required characters for the length.        */
      if ((s = putn (outbuf, ninb + 2)) != 0)
         return s;
      return outfunc ("\n", 1);
   }
}

/* Send output to the output function, adding newline
 * character every width encoded characters.        */
static int
putn (const char *out, int n)
{
  int         s;       /* output return status */
  while (width && col + n > width) {
     if (width > col) {
        if ((s = outfunc (out, width - col)) != 0)
           return s;
     }
     if ((s = outfunc ("\n", 1)) != 0)
        return s;
     n    -= (width - col);
     out  += (width - col);
     col   = 0;
   }
   col +=n;
   return outfunc (out, n);
}

/* Encode 9 bytes into 11 printable ASCII chars.  */
void encode_9_to_11 (char out[11],
                  const unsigned char in[9])
{
   unsigned long block; /* conversion area      */
   int  i;              /* input byte index     */
   unsigned int qb = 0; /* prefixes             */
   ldiv_t      ld;      /* quotient, remainder  */

   for (i = 1; i < 9; i += 4) {
     unsigned     q;
     block = ((unsigned long)
            (((unsigned)in[i+0]<<8) | in[i+1])<<16)+
           (((unsigned) in[i+2]<<8) | in[i+3]);

     q = (unsigned) (block >> 16) / PBMULT;
     block = block- ((unsigned long)(q*PBMULT) << 16);
     ld = ldiv ((long) block, (long) BASESQ);
     CV2ASCII(out+i+2, (unsigned) ld.quot);
     CV2ASCII(out+i+4, (unsigned) ld.rem);
     qb = qb * PBASE + q;
   }

   /* Now convert the remaining byte and prefixes
   * from previous block conversions                */
   block = ((unsigned long) qb << 8) |in[0];
   ld =ldiv ((long) block, (long) BASESQ);
   out[0] = MAKE_PRINT((unsigned) ld.quot);
   CV2ASCII(out+1, (unsigned) ld.rem);
}

/* End of file */