Information wants to be free...

Base64 Decoder and Encoder

I looked through my old code collection and found the source code for these two small tools that will encode and decode Base64 files, in the MIME compatible format.

Here is the decoder code:

#include <stdio.h>

enum
{
  MIME_62 = '+',
  MIME_63 = '/',
  MIME_PADDING = '=',
  MIME_ERROR_NUMBER = 64, /* Not valid base64 number. */
};

/* mime_to_base64: Convert MIME compatible ASCII character to number. */
int mime_to_base64(int n)
{
  if (n >= 0x60) /* Lowercase letters */
    return n - 0x47;
  else if (n >= 0x40) /* Uppercase letters */
    return n - 0x41;
  else if (n >= 0x30) /* Numbers */
    return n + 0x4;
  else if (n == MIME_62)
    return 62;
  else if (n == MIME_63)
    return 63;
  else
    return MIME_ERROR_NUMBER; /* Unkown (Skip) */
}

/* main: Input and output filter. */
int main(void)
{
  int c, n, i;
  unsigned char ascii[3];  /* 24-bit buffer */
  unsigned char base64[4]; /* 4 characters */

  n = 0;
  while ((c = fgetc(stdin)) != EOF) {
    if ((base64[n] = mime_to_base64(c)) == MIME_ERROR_NUMBER)
      continue; /* Unkown character (e.g. newline), skip it. */
    if (c == MIME_PADDING) /* No need to get more data. */
      break;
    if (n == 3) { /* Buffer full, time to output. */
      ascii[0] = base64[0] << 2;
      ascii[0] += (base64[1] & 0x30) >> 4;   /* 110000 */
      ascii[1] = (base64[1] & 0xf) << 4;     /* 001111 */
      ascii[1] += ((base64[2] & 0x3c) >> 2); /* 111100 */
      ascii[2] = ((base64[2] & 0x3) << 6);   /* 000011 */
      ascii[2] += base64[3]; 

      for (i = 0; i < 3; i++) {
        fputc(ascii[i], stdout);
      }
      n = 0;
    } else
      n++;
  }

  /* Check for remaining data in buffer. */
  if (n == 2) { /* Two paddings, one character missing. */
    ascii[0] = base64[0] << 2;
    ascii[0] += (base64[1] & 0x30) >> 4;
    fputc(ascii[0], stdout);
  } else if (n == 3) { /* One padding, two characters missing. */
    ascii[0] = base64[0] << 2;
    ascii[0] += (base64[1] & 0x30) >> 4;
    ascii[1] = (base64[1] & 0xf) << 4;
    ascii[1] += ((base64[2] & 0x3c) >> 2);
    fputc(ascii[0], stdout);
    fputc(ascii[1], stdout);
  }
  
  return 0;
}
          


And here is the encoder code:

#include <stdio.h>

enum
{
  MIME_62 = '+',
  MIME_63 = '/',
  MIME_PADDING = '=',
};

/* base64_to_mime: Convert number to MIME compatible ASCII character. */
int base64_to_mime(int n)
{
  if (n == 63)
    return MIME_63;
  else if (n == 62)
    return MIME_62;
  else if (n > 51) /* Numbers */
    return n - 0x4;
  else if (n > 25) /* Lowercase letters */
    return n + 0x47;
  else /* Uppercase letters */
    return n + 0x41;
}

/* main: Input and output filter. */
int main(void)
{
  int c, n, i;
  unsigned char ascii[3];  /* 24-bit buffer */
  unsigned char base64[4]; /* 4 characters */

  n = 0;
  while ((c = fgetc(stdin)) != EOF) {
    ascii[n] = c;
    if (n == 2) { /* Buffer full, time to output. */
      base64[0] = ascii[0] >> 2;
      base64[1] = (ascii[1] >> 4) & 0xf;     /* 00001111 */
      base64[1] += ((ascii[0] & 0x3) << 4);  /* 00000011 */
      base64[2] = (ascii[1] << 2) & 0x3c;    /* 00111100 */
      base64[2] += ((ascii[2] & 0xc0) >> 6); /* 11000000 */
      base64[3] = ascii[2] & 0x3f;           /* 00111111 */

      for (i = 0; i < 4; i++) {
        fputc(base64_to_mime(base64[i]), stdout);
      }
      n = 0;
    } else
      n++;
  }

  /* Check for remaining data in buffer. */
  if (n == 1) {
      base64[0] = ascii[0] >> 2;
      base64[1] = (ascii[0] & 0x3) << 4;
      fputc(base64_to_mime(base64[0]), stdout);
      fputc(base64_to_mime(base64[1]), stdout);
      fputc(MIME_PADDING, stdout);
      fputc(MIME_PADDING, stdout);
  } else if (n == 2) {
      base64[0] = ascii[0] >> 2;
      base64[1] = (ascii[1] >> 4) & 0xf;
      base64[1] += ((ascii[0] & 0x3) << 4);
      base64[2] = (ascii[1] << 2) & 0x3c;
      fputc(base64_to_mime(base64[0]), stdout);
      fputc(base64_to_mime(base64[1]), stdout);
      fputc(base64_to_mime(base64[2]), stdout);
      fputc(MIME_PADDING, stdout);
  }
  
  return 0;
}
          


Topic: Scripts and Code, by Kjetil @ 14/05-2010, Article Link