/* $Id: encodeB.c,v 1.3 1998/03/21 18:30:27 lindberg Exp $*/
/* $Name: ezmlm-idx-040 $*/

#include "stralloc.h"
#include "uint32.h"
#include "mime.h"
#include "strerr.h"
#include "errtxt.h"

static void die_nomem(fatal)
  char *fatal;
{
  strerr_die2x(111,fatal,ERR_NOMEM);
}

static unsigned char base64char[] =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static unsigned int pos = 0;
static unsigned int i = 0;
static uint32 hold32;
static unsigned char *cpout;

static void addone(ch)
unsigned char ch;
{
 if (!(pos++))
    hold32 = (uint32) ch;
  else
    hold32 = (hold32 << 8) | ch;
  if (pos == 3) {
    *cpout++ = base64char[(hold32 >> 18) & 0x3f];
    *cpout++ = base64char[(hold32 >> 12) & 0x3f];
    *cpout++ = base64char[(hold32 >>  6) & 0x3f];
    *cpout++ = base64char[hold32 & 0x3f];
    if (++i == 18) {
      *cpout++ = '\n';
      i = 0;
    }
    pos = 0;
  }
}

static void dorest()
{
  switch (pos) {
    case 2:
      hold32 = hold32 << 2;
      *cpout++ = base64char[(hold32 >> 12) & 0x3f];
      *cpout++ = base64char[(hold32 >> 06) & 0x3f];
      *cpout++ = base64char[hold32 & 0x3f];
      *cpout++ = '=';
      break;
    case 1:
      hold32 = hold32 << 4;
      *cpout++ = base64char[(hold32 >> 06) & 0x3f];
      *cpout++ = base64char[hold32 & 0x3f];
      *cpout++ = '=';
      *cpout++ = '=';
      break;
    default:
      break;
  }
  *cpout++ = '\n';
}   

void encodeB(indata,n,outdata,control,fatal)
unsigned char *indata;
unsigned int n;
stralloc *outdata;
int control;	/* 1 = init, 2 = flush */
char *fatal;
	/* converts any character with the high order bit set to */
	/* base64. In: n chars of indata, out: stralloc outdata  */
	/* as '=' is not allowed within the block, we cannot flush after */
	/* each line, so we carry over data from call to call. The last  */
	/* call to encodeB should have control = 2 to do the flushing.   */
	/* control = 0 resets, and the routine starts out reset. */
{
  register unsigned char ch;

  if (control == 1) {
    pos = 0;
    i = 0;
  }
  if (!stralloc_copys(outdata,"")) die_nomem(fatal);
  if (!stralloc_ready(outdata,n*8/3 + n/72 + 5)) die_nomem(fatal);
  cpout = (unsigned char *) outdata->s;
  while (n--) {
    ch = *indata++;
    if (ch == '\n')
      addone('\r');
    addone(ch);
  }
  if (control == 2)
    dorest();
  outdata->len = (unsigned int) (cpout - (unsigned char *) outdata->s);
}

