/*
 * Output a base64 string.
 *
 * Options include:
 * - Character 62 and 63;
 * - To pad or not to pad.
 */

#include <inttypes.h>
#include <base64.h>

size_t genbase64(char *output, const void *input, size_t size, int flags)
{
  static char charz[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_";
  uint8_t buf[3];
  int j;
  const uint8_t *p;
  char *q;
  uint32_t bv;
  int left = size;

  charz[62] = (char)flags;
  charz[63] = (char)(flags >> 8);

  p = input;  q = output;

  while (left > 0) {
    if (left < 3) {
      buf[0] = p[0];
      buf[1] = (left > 1) ? p[1] : 0;
      buf[2] = 0;
      p = buf;
    }

    bv = (p[0] << 16) | (p[1] << 8) | p[2];
    p += 3;
    left -= 3;

    for ( j = 0 ; j < 4 ; j++ ) {
      *q++ = charz[(bv >> 18) & 0x3f];
      bv <<= 6;
    }
  }

  switch (left) {
  case -1:
    if (flags & BASE64_PAD)
      q[-1] = '=';
    else
      q--;
    break;

  case -2:
    if (flags & BASE64_PAD)
      q[-2] = q[-1] = '=';
    else
      q -= 2;
    break;

  default:
    break;
  }

  *q = '\0';

  return q-output;
}

#ifdef TEST

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  int i;
  char buf[4096];
  int len, bytes;

  for (i = 1; i < argc; i++) {
    printf("Original: \"%s\"\n", argv[i]);

    len = strlen(argv[i]);
    bytes = genbase64(buf, argv[i], len, BASE64_MIME|BASE64_PAD);
    printf("    MIME: \"%s\" (%d)\n", buf, bytes);
    bytes = genbase64(buf, argv[i], len, BASE64_SAFE);
    printf("    Safe: \"%s\" (%d)\n", buf, bytes);
  }

  return 0;
}

#endif

