/***************************************************************************
 *                                                                         *
 *   MIMEB64.C                                                             *
 *                                                                         *
 *   Copyright (c) 1995-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   MIME Content-Type field for different file types                      *
 *                                                                         *
 *                               6/1/95 - Bert Love,                       *
 *                                        Scott Brinker,                   *
 *                                        Charles Dunn &                   *
 *                                        Mahesh Neelakanta                *
 *   Moved from SMTPRECV.C      7/16/96 - Bob Stein                        *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "mimeb64.h"

#define FILREV "$Revision: 4 $"

static CHAR const b64tab[256]={
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* 00 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* 10 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* 20 */
     0xFF,0xFF,0xFF,0x3E,0xFF,0xFF,0xFF,0x3F,
     0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,     /* 30 */
     0x3C,0x3D,0xFF,0xFF,0xFF,0xF0,0xFF,0xFF,
     0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,     /* 40 */
     0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
     0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,     /* 50 */
     0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,     /* 60 */
     0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
     0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,     /* 70 */
     0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* 80 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* 90 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* A0 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* B0 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* C0 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* D0 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* E0 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,     /* F0 */
     0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

INT                                /*   returns number of output bytes     */
base64dc(                          /* decode base64 string                 */
CHAR *inp,                   /*   input, encoded string, '\0' term   */
CHAR *outp)                        /*   output, decoded stg, NOT '\0' term */
{                                  /*   (for in-place conversion, outp=inp)*/
     INT len,i,outpsiz,grpos;
     ULONG accum=0;
     CHAR ch;

     depad(inp);
     len=strlen(inp);
     for (i=outpsiz=grpos=0 ; i < len ; i++) {
          if ((ch=b64tab[inp[i]]) == '\xF0') {
               if (grpos == 3) {
                    outp[outpsiz++]=(CHAR)(accum>>10);
                    outp[outpsiz++]=(CHAR)(accum>>2);
               }
               else if (grpos == 2) {
                    outp[outpsiz++]=(CHAR)(accum>>4);
               }
               return(outpsiz);
          }
          else if (ch != '\xFF') {
               accum=(accum<<6)|(ULONG)ch;
               ++grpos;
          }
          if (grpos == 4) {
               outp[outpsiz++]=(CHAR)(accum>>16);
               outp[outpsiz++]=(CHAR)(accum>>8);
               outp[outpsiz++]=(CHAR)(accum);
               accum=0;
               grpos=0;
          }
     }
     return(outpsiz);
}

VOID
base64nc(
const CHAR* inBuffer,
CHAR* outBuffer,
INT outBufferSize)
{
  const CHAR b64nctab[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
                    "0123456789+/";

  INT inLength = strlen(inBuffer);
  INT i0,i1,i2;
  INT i,j;
  memset(outBuffer,0,outBufferSize);
  for ( i=0,j=0 ; i < inLength && j <= outBufferSize-4-1 ; i+=3) {
    switch (inLength-i) {
    case 1:
      i0=inBuffer[i];
      i1=0;
      i2=0;
      break;
    case 2:
      i0=inBuffer[i];
      i1=inBuffer[i+1];
      i2=0;
      break;
    default:
      i0=inBuffer[i];
      i1=inBuffer[i+1];
      i2=inBuffer[i+2];
      break;
    }
     outBuffer[j++]=b64nctab[ (i0&0xFC)>>2 ];
     outBuffer[j++]=b64nctab[ ((i0&0x03)<<4) | (i1>>4) ];
     outBuffer[j++]=b64nctab[ ((i1&0x0F)<<2) | (i2>>6) ];
     outBuffer[j++]=b64nctab[ i2&0x3F ];
  }
  switch (inLength%3) {
  case 1:
       outBuffer[j-2]='=';
  case 2:
       outBuffer[j-1]='=';
       break;
  }
}
