Listing 7 Decode 9 bytes from 11 characters

/* DBAZ.C
 * 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"

#define LAST_CODE    (FIRST_CODE + BASE -1)
#defin e BASESQ      (unsigned long)(BASE*BASE)
#define BASEVAL(c)   (unsigned)((c)-FIRST_CODE)
#define ISENCODE(c)  ((c) >= FIRST_CODE && \
                  (c) <= LAST_CODE)

static unsigned int crc;/* input file CRC */
static size_t n_unused; /* # unused input bytes */
static int ninb;        /* # bytes in inbuf     */
static int done;        /* set if finished      */
static char inbuf[ENCB_LEN * 2 + 2];
static unsigned char outbuf[BINB_LEN * 2];
static int (*outfunc) (const char *out, size_t len);

static decode_stat
decode_endmark(const char *data, size_t len);
/* Initialize the BAZ911 decoder. */
int dbaz_init (outf_t *p_outfunc) {
   initcrctab ();
   crc = CRC_INIT_VALUE;
   done = 0;
   ninb = 0;
   n_unused = 0;
   outfunc = p_outfunc;
   return 0;
}

/* Decode block of data. */
decode_stat
dbaz_data (const unsigned char *data, size_t len) {
   int        s;        /* output return status */

   if (done) {
     n_unused +=len;
     return DECR_END;
   } else if (len == 0)
     return DECR_NO_ENDMARK;

   for (;;) {
     /* fill block input buffer */
     while (ninb < ENCB_LEN) {
        if (ISENCODE(*data))
           inbuf[ninb++]= (char) *data;
        data++;
        if (--len == 0)
           return DEC_OK;
     }
     if (*inbuf == END_FLAG) {
        return decode_endmark ((const char *) data,
                                       len);

     }
     if (decode_11_to_9 (outbuf, inbuf))
        return DECR_INVALID_DATA;
     ninb = 0;
     crc = updcrc (crc, outbuf, BINB_LEN);
     if ((s= outfunc ((char *)outbuf,BINB_LEN)) != 0)
        return (decode_stat) s;
   }
}

/* Return number of characters in internal buffer.
 * This can be used after DECR_END status is returned
 * to determine the number of unused characters given
 * to the decoder.                                  */
size_t dbaz_excess_chars (void) {
   return n_unused;
}

decode_stat decode_endmark (
   const char *data,   /* data following inbuf     */
   size_t len          /* length of data           */
)
{
   int         s;      /* output return status     */
   int         nreq;   /* # input bytes required for
                    * end ensemble              */
   unsigned int rc;    /* # remaining data bytes   */

   if ((rc = BASEVAL(inbuf[1])) > MAX_ENDBLK_DB)
      return DECR_INVALID_DATA;

   memset (inbuf+ninb, FIRST_CODE, 2*ENCB_LEN+2-ninb);
   nreq = rc +4 +CRCLBY;
   if (nreq < ENCB_LEN)
      nreq = ENCB_LEN;     /* min size is 1 block */
   if (rc > BINB_LEN - CRCLBY)
      nreq += 2;           /* use part of 2nd blk */
   /* get remaining characters */
   while (ninb < nreq) {
      if (len == 0)
         return DECR_OK;   /* need more input chars */
      if (ISENCODE(*data))
         inbuf[ninb++] = *data;
      data++;
      len--;
   }
   done = 1;
   if (decode_11_to_9 (outbuf, inbuf+2))
      return DECR_INVALID_DATA;
   if (rc > BINB_LEN - CRCLBY) {
      if (decode_11_to_9 (outbuf+BINB_LEN,
                       inbuf+2+ENCB_LEN))
         return DECR_INVALID_DATA;
   }
   crc = updcrc (crc, outbuf, rc);
   if ((s = outfunc ((char *) outbuf, rc)) != 0)
      return (decode_stat) s;
   if (((crc >> 8) & 0xff) != outbuf[rc] ||
       ( crc      & 0xff) != outbuf[rc+1] )
      return DECR_CRC_ERR;
   n_unused = len;
   return DECR_END;
}

/* Decode 11 printable ASCII characters into 9 bytes */
int             /* return: 0=OK, 1= invalid input */
decode_11_to_9 (unsigned char out[], const char in[]) {
   unsigned long block;
   unsigned    b2, q1, q2, i;

   block = BASEVAL(in[0]) * BASESQ +
      (BASEVAL(in[1]) * BASE + BASEVAL(in[2]));
   out[0] = (unsigned) block & 0xff;
   b2 = (unsigned) (block >> 8);
   q1 = b2 / PBASE;
   q2 = b2 - q1 * PBASE;
   if (q1 >= PBASE) return 1;

   for (i = 1; i < 9; i += 4) {
      block = (BASEVAL(in[i+2]) * BASE +
              BASEVAL(in[i+3])) * BASESQ +
         (BASEVAL(in[i+4]) * BASE + BASEVAL(in[i+5]));

      if (((unsigned)(block >> 16) >= PBMULT) ||
         q1 == PBASE-1 && block >
         (0xffffffffUL -(PBMULT*(PBASE-1UL) << 16))) {
        return 1;
      }

      block += (unsigned long) (q1 * PBMULT) << 16;
      out[i+0] = (unsigned char) (block >> 24);
      out[i+1] = (unsigned char) (block >> 16);
      out[i+2] = (unsigned char) (block >> 8);
      out[i+3] = (unsigned char) block;
      q1 = q2;
   }
   return 0;
}

/* End of File */