#include "stralloc.h"
#include "uint32.h"
#include "mime.h"
#include "strerr.h"
#include "messages.h"
#include "die.h"
#include "idx.h"

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

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

static void addone(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(void)
{
  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(const char *indata,unsigned int n,stralloc *outdata,
	     int control)	/* 1 = init, 2 = flush */
	/* 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. */
{
  unsigned char ch;

  if (control == 1) {
    pos = 0;
    i = 0;
  }
  if (!stralloc_copys(outdata,"")) die_nomem();
  if (!stralloc_ready(outdata,n*8/3 + n/72 + 5)) die_nomem();
  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);
}

