Listing 6

#include <stdio.h> 
 
#define MAXVAL	255 
 
static char 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','+','/' 
}; 
 
static unsigned char pr2six[256]; 
 
static int encode ( 
	unsigned char	*bufin, 
	unsigned int	nbytes, 
	char 		*bufcoded) 
{ 
#define ENC(c) six2pr[c] 
 
   register char *outptr = bufcoded; 
   unsigned int i; 
 
   for (i=0; i<nbytes; i += 3) { 
      *(outptr++) = ENC(*bufin >> 2);            /* c1 */ 
      *(outptr++) = ENC(((*bufin << 4) & 060) | ((bufin[1] >> 4) & 017)); /*c2*/ 
      *(outptr++) = ENC(((bufin[1] << 2) & 074) | ((bufin[2] >> 6) & 03));/*c3*/ 
      *(outptr++) = ENC(bufin[2] & 077);         /* c4 */ 
 
      bufin += 3; 
   } 
 
   /* If nbytes was not a multiple of 3, then we have encoded too 
    * many characters.  Adjust appropriately. 
    */ 
   if(i == nbytes+1) { 
      /* There were only 2 bytes in that last group */ 
      outptr[-1] = '='; 
   } else if(i == nbytes+2) { 
      /* There was only 1 byte in that last group */ 
      outptr[-1] = '='; 
      outptr[-2] = '='; 
   } 
   *outptr = '\0'; 
   return(outptr - bufcoded); 
#undef ENC 
} 
 
static int decode ( 
	char 		*bufcoded, 
	unsigned char 	*bufplain, 
	int		outbufsize) 
{ 
/* single character decode */ 
#define DEC(c) pr2six[(int)c] 
#define MAXVAL 63 
 
   static int first = 1; 
 
   int nbytesdecoded, j; 
   register char *bufin = bufcoded; 
   register unsigned char *bufout = bufplain; 
   register int nprbytes; 
 
   /* If this is the first call, initialize the mapping table. 
    * This code should work even on non-ASCII machines. 
    */ 
   if(first) { 
      first = 0; 
      for(j=0; j<256; j++) pr2six[j] = MAXVAL+1; 
 
      for(j=0; j<64; j++) pr2six[(int)six2pr[j]] = (unsigned char) j; 
   } 
 
   /* Strip leading whitespace. */ 
 
   while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++; 
 
   /* Figure out how many characters are in the input buffer. 
    * If this would decode into more bytes than would fit into 
    * the output buffer, adjust the number of input bytes downwards. 
    */ 
   bufin = bufcoded; 
   while(pr2six[(int)*(bufin++)] <= MAXVAL); 
   nprbytes = bufin - bufcoded - 1; 
   nbytesdecoded = ((nprbytes+3)/4) * 3; 
   if(nbytesdecoded > outbufsize) { 
      nprbytes = (outbufsize*4)/3; 
   } 
 
   bufin = bufcoded; 
    
   while (nprbytes > 0) { 
      *(bufout++) = (unsigned char) (DEC(*bufin) << 2 | DEC(bufin[1]) >> 4); 
      *(bufout++) = (unsigned char) (DEC(bufin[1]) << 4 | DEC(bufin[2]) >> 2); 
      *(bufout++) = (unsigned char) (DEC(bufin[2]) << 6 | DEC(bufin[3])); 
      bufin += 4; 
      nprbytes -= 4; 
   } 
    
   if(nprbytes & 03) { 
      if(pr2six[(int)bufin[-2]] > MAXVAL) { 
         nbytesdecoded -= 2; 
      } else { 
         nbytesdecoded -= 1; 
      } 
   } 
 
   return(nbytesdecoded); 
#undef DEC 
#undef MAXVAL 
} 
 
main( int argc, char **argv ) 
{ 
	char	bufin[256], bufout[256]; 
	int	cnt; 
 
	if( argc <= 1 ) { 
	    exit( 1 ); 
	} 
 
	if( strcmp( *argv, "decode" ) == 0 ) { 
	    while( --argc ) { 
	        argv++; 
	        cnt = decode( *argv, bufout, sizeof(bufout) ); 
	        bufout[cnt] = '\0'; 
	        printf( "%s\n", bufout ); 
	    } 
	} 
	else { 
	    if( strcmp( *argv, "encode" ) == 0 ) { 
	        while( --argc ) { 
	            argv++; 
	            cnt = decode( *argv, bufout, sizeof(bufout) ); 
	            bufout[cnt] = '\0'; 
	            printf( "%s\n", bufout ); 
	        } 
	    } 
	} 
}
