#include "sbase64.h"

char sbase_six2pr[64] = {
    'A','B','C','D','E','F','G','H','I','J','K','L','M',
    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    'a','b','c','d','e','f','g','h','i','j','k','l','m',
    'n','o','p','q','r','s','t','u','v','w','x','y','z',
    '0','1','2','3','4','5','6','7','8','9','+','/'
};

unsigned char sbase_pr2six[256];

std::string sbase64_encode(const std::string &bufplain, 
                           char ch1, char ch2, char padding)
 {
  std::string bufcoded;

  bufcoded.reserve(bufplain.size()*3);

  /* ENC is the basic 1 character encoding function to make a char printing */
  #define ENC(c) sbase_six2pr[c]

  sbase_six2pr[62]=ch1;
  sbase_six2pr[63]=ch2;

  unsigned int i=bufplain.size();
  const unsigned char *bufin=(const unsigned char *)bufplain.c_str();

  for(; i>=3; i-=3)
   {
    bufcoded+=ENC(bufin[0] >> 2);            /* c1 */
    bufcoded+=ENC(((bufin[0] << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/
    bufcoded+=ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03)); /*c3*/
    bufcoded+=ENC(bufin[2] & 077);           /* c4 */
    bufin+=3;
   }

  if(i==2)
   {
    bufcoded+=ENC(bufin[0] >> 2);            /* c1 */
    bufcoded+=ENC(((bufin[0] << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/
    bufcoded+=ENC((bufin[1] << 2) & 074);    /* c3 */
    if(padding!=0) bufcoded+=padding;        /* c4 */
   }
  else if(i==1)
   {
    bufcoded+=ENC(bufin[0] >> 2);            /* c1 */
    bufcoded+=ENC((bufin[0] << 4) & 060);    /* c2 */
    if(padding!=0)
     {
      bufcoded+=padding;                     /* c3 */
      bufcoded+=padding;                     /* c4 */
     }
   }

  return bufcoded;
 }

std::string sbase64_decode(const std::string &bufcoded,
                           char ch1, char ch2, char padding)
 {
  std::string bufplain;

  bufplain.reserve(bufcoded.size());

  /* single character decode */
  #define DEC(c) sbase_pr2six[(int)c]
  #define MAXVAL 63

  sbase_six2pr[62]=ch1;
  sbase_six2pr[63]=ch2;

  static int first = 1;
  register int nprbytes;
  register const char *bufin=bufcoded.c_str();

  /* If this is the first call, initialize the mapping table.
   * This code should work even on non-ASCII machines.
   */
  if(first)
   {
    unsigned j;

    first = 0;
    for(j=0; j<256; j++) sbase_pr2six[j] = MAXVAL+1;
    for(j=0; j<64; j++) sbase_pr2six[(int)sbase_six2pr[j]] = (unsigned char) j;
   }

  /* Strip leading whitespace. */

  nprbytes=bufcoded.size();

  while(*bufin==' ' || *bufin == '\t' || *bufin=='\r' || *bufin=='\n')
   { bufin++; nprbytes--; }

  for(; nprbytes>0; nprbytes-=4)
   {
    unsigned char c1, c2, c3, c4;
    if(nprbytes>=4) c4=bufin[3]; else c4='=';
    if(nprbytes>=3) c3=bufin[2]; else c3='=';
    if(nprbytes>=2) c2=bufin[1]; else c2='=';
    if(nprbytes>=1) c1=bufin[0]; else c1='=';

    if(c1!='=' && c2!='=' && c1!=padding && c2!=padding)
      bufplain+=(unsigned char) (DEC(c1) << 2 | DEC(c2) >> 4);

    if(c2!='=' && c3!='=' && c2!=padding && c3!=padding)
      bufplain+=(unsigned char) (DEC(c2) << 4 | DEC(c3) >> 2);

    if(c3!='=' && c4!='=' && c3!=padding && c4!=padding)
      bufplain+=(unsigned char) (DEC(c3) << 6 | DEC(c4));

    bufin+=4;
   }

  return bufplain;
 }


syntax highlighted by Code2HTML, v. 0.9.1