/*
** Translation Table as described in RFC1113
*/
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";



char bc64(char sym)
{
   if ((sym >= 'A')&&(sym <= 'Z'))
      return sym - 'A';
   if ((sym >= 'a')&&(sym <= 'z'))
      return (sym - 'a') + 26;
   if ((sym >= '0')&&(sym <= '9'))
      return sym-'0'+52;
   if (sym=='+')
      return 62;
   if (sym=='/')
      return 63;
   return 0;
}


/*
 * encodeblock
 *
 * encode 3 8-bit binary bytes as 4 '6-bit' characters
 */
void encodeblock( const unsigned char in[3], char out[4], int len )
{
    unsigned char in0 = in[0];
    unsigned char in1 = (len > 1) ? in[1] : 0;
    unsigned char in2 = (len > 2) ? in[2] : 0;


    out[0] = cb64[ in0 >> 2 ];
    out[1] = cb64[ ((in0 & 0x03) << 4) | ((in1 & 0xf0) >> 4) ];
    out[2] = (unsigned char) (len > 1 ? cb64[ ((in1 & 0x0f) << 2) | ((in2 & 0xc0) >> 6) ] : '=');
    out[3] = (unsigned char) (len > 2 ? cb64[ in2 & 0x3f ] : '=');
}

/*
** decodeblock
**
** decode 4 '6-bit' characters into 3 8-bit binary bytes
*/
int decodeblock( const char in[4], unsigned char out[3] )
{   
   //unsigned char in_dec[4];
    int out_size = 1;

    out[ 0 ] = (unsigned char ) (bc64(in[0]) << 2 | bc64(in[1]) >> 4);
    if (in[2] != '=')
    {
        out[ 1 ] = (unsigned char ) (bc64(in[1]) << 4 | bc64(in[2]) >> 2);
        out_size++;
    }
    if (in[3]!='=')
    {
        out[ 2 ] = (unsigned char ) (((bc64(in[2]) << 6) & 0xc0) | bc64(in[3]));
        out_size++;
    }
    return out_size;
}


int Radix64_Encode(const unsigned char* data, int size, char* msg)
{
   int i,k;
   for (i=0,k=0; i < size; i+=3,k+=4)
      encodeblock(&data[i], &msg[k], size-i);
   return k;
}

int Radix64_Decode(const char* msg, int size, unsigned char* data)
{
   int i,k, out_size=0;
   for (i=0,k=0; i < size; i+=4,k+=3)
   {
      out_size+=decodeblock(&msg[i], &data[k]);
   }
   return out_size;
}
