(Prev Next) Part of UserLand's MIDAS Website. Wednesday, August 27, 1997.

C source code for Base 64

Here's the C source code for the Base 64 encoder/decoder.

File:base64.c
Created:Saturday, April 5, 1997; 1:30:13 PM
Modified: Tuesday, April 8, 1997; 7:52:28 AM

/*
Dave Winer, dwiner@well.com, UserLand Software, 4/7/97
 
I built this project using Symantec C++ 7.0.4 on a Mac 9500.
 
We needed a handle-based Base 64 encoder/decoder. Looked around the
net, found a bunch of code that couldn't easily be adapted to 
in-memory stuff. Most of them work on files to conserve memory. This
is inelegant in scripting environments such as Frontier.
 
Anyway, so I wrote an encoder/decoder. Docs are being maintained 
on the web, and updates at:
 
http://www.scripting.com/midas/base64/
 
If you port this code to another platform please put the result up
on a website, and send me a pointer. Also send email if you think this
isn't a compatible implementation of Base 64 encoding.
 
BTW, I made it easy to port -- layering out the handle access routines.
Of course there's a small performance penalty for this, and if you don't
like it, change it. Thanks!
*/
 
 
#include <appletdefs.h>
#include <iac.h>
#include "base64.h"
 
 
static char encodingTable [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 long gethandlesize (Handle h) {
 
	return (GetHandleSize (h));
	} /*gethandlesize*/
 
 
static boolean sethandlesize (Handle h, unsigned long newsize) {
 
	SetHandleSize (h, newsize);
 
	return (MemError () == noErr);
	} /*sethandlesize*/
 
 
static unsigned char gethandlechar (Handle h, unsigned long ix) {
 
	return ((*h) [ix]);
	} /*gethandlechar*/
 
 
static void sethandlechar (Handle h, unsigned long ix, unsigned char ch) {
 
	(*h) [ix] = ch;
	} /*sethandlechar*/
 
 
static boolean encodeHandle (Handle htext, Handle h64, short linelength) { 
 
	/*
	encode the handle. some funny stuff about linelength -- it only makes
	sense to make it a multiple of 4. if it's not a multiple of 4, we make it
	so (by only checking it every 4 characters. 
 
	further, if it's 0, we don't add any line breaks at all.
	*/
 
	unsigned long ixtext;
	unsigned long lentext;
	unsigned long origsize;
	long ctremaining;
	unsigned char ch;
	unsigned char inbuf [3], outbuf [4];
	short i;
	short charsonline = 0, ctcopy;
    
	ixtext = 0;
 
	lentext = gethandlesize (htext);
 
	while (true) {
 
		ctremaining = lentext - ixtext;
	
		if (ctremaining <= 0)
			break;
				
		for (i = 0; i < 3; i++) { 
		
			unsigned long ix = ixtext + i;
		
			if (ix < lentext)
				inbuf [i] = gethandlechar (htext, ix);
			else
				inbuf [i] = 0;
			} /*for*/
		
		outbuf [0] = (inbuf [0] & 0xFC) >> 2;
    
		outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4);
    
		outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6);
    	
		outbuf [3] = inbuf [2] & 0x3F;
	
		origsize = gethandlesize (h64);
	
		if (!sethandlesize (h64, origsize + 4))
			return (false);
		
		ctcopy = 4;
	
		switch (ctremaining) {
		
			case 1: 
				ctcopy = 2; 
			
				break;
		
			case 2: 
				ctcopy = 3; 
			
				break;
			} /*switch*/
 
		for (i = 0; i < ctcopy; i++)
			sethandlechar (h64, origsize + i, encodingTable [outbuf [i]]);
		
		for (i = ctcopy; i < 4; i++)
			sethandlechar (h64, origsize + i, '=');
		
		ixtext += 3;
	
		charsonline += 4;
	
		if (linelength > 0) { /*DW 4/8/97 -- 0 means no line breaks*/
	
			if (charsonline >= linelength) {
			
				charsonline = 0;
			
				origsize = gethandlesize (h64);
			
				if (!sethandlesize (h64, origsize + 1))
					return (false);
				
				sethandlechar (h64, origsize, '\n');
				}
			}
		} /*while*/
 
	return (true);
	} /*encodeHandle*/
 
 
static boolean decodeHandle (Handle h64, Handle htext) {
 
	unsigned long ixtext;
	unsigned long lentext;
	unsigned long origsize;
	unsigned long ctremaining;
	unsigned char ch;
	unsigned char inbuf [3], outbuf [4];
	short i, ixinbuf;
	boolean flignore;
	boolean flendtext = false;
    
	ixtext = 0;
 
	lentext = gethandlesize (h64);
 
	ixinbuf = 0;
 
	while (true) {
	
		if (ixtext >= lentext)
			break;
		
		ch = gethandlechar (h64, ixtext++);
	
		flignore = false;
	
		if ((ch >= 'A') && (ch <= 'Z'))
			ch = ch - 'A';
	
		else if ((ch >= 'a') && (ch <= 'z'))
			ch = ch - 'a' + 26;
		
		else if ((ch >= '0') && (ch <= '9'))
			ch = ch - '0' + 52;
	
		else if (ch == '+')
			ch = 62;
		
		else if (ch == '=') /*no op -- can't ignore this one*/
			flendtext = true;
		
		else if (ch == '/')
			ch = 63;
	
		else
			flignore = true; 
	
		if (!flignore) {
	
			short ctcharsinbuf = 3;
			boolean flbreak = false;
			 
			if (flendtext) {
			
				if (ixinbuf == 0)
					break;
				
				if ((ixinbuf == 1) || (ixinbuf == 2))
					ctcharsinbuf = 1;
				else
					ctcharsinbuf = 2;
			
				ixinbuf = 3;
			
				flbreak = true;
				}
		
			inbuf [ixinbuf++] = ch;
		
			if (ixinbuf == 4) {
			
				ixinbuf = 0;
			
				outbuf [0] = (inbuf [0] << 2) | ((inbuf [1] & 0x30) >> 4);
			
				outbuf [1] = ((inbuf [1] & 0x0F) << 4) | ((inbuf [2] & 0x3C) >> 2);
			
				outbuf [2] = ((inbuf [2] & 0x03) << 6) | (inbuf [3] & 0x3F);
	
				origsize = gethandlesize (htext);
			
				if (!sethandlesize (htext, origsize + ctcharsinbuf))
					return (false);
	
				for (i = 0; i < ctcharsinbuf; i++) 
					sethandlechar (htext, origsize + i, outbuf [i]);
				}
		
			if (flbreak)
				break;
			}
		} /*while*/
 
	exit:
 
	return (true);
	} /*decodeHandle*/
 
 
void base64encodeVerb (void) {
 
	Handle h64, htext;
	short linelength;
 
	if (!IACgettextparam ((OSType) keyDirectObject, &htext))
		return;
	
	if (!IACgetshortparam ((OSType) 'line', &linelength))
		return;
	
	h64 = NewHandle (0);
	
	if (!encodeHandle (htext, h64, linelength))
		goto error;
	
	DisposHandle (htext);
	
	IACreturntext (h64);
 
	return;
 
	error:
 
	IACreturnerror (1, "\perror encoding the Base 64 text");
	} /*base64encodeVerb*/
 
 
void base64decodeVerb (void) {
 
	Handle h64, htext;
 
	if (!IACgettextparam ((OSType) keyDirectObject, &h64))
		return;
	
	htext = NewHandle (0);
	
	if (!decodeHandle (h64, htext))
		goto error;
	
	DisposHandle (h64);
	
	IACreturntext (htext);
 
	return;
 
	error:
 
	IACreturnerror (1, "\perror decoding the Base 64 text");
	} /*base64decodeVerb*/
 
 
 


This page was last built with Frontier on a Macintosh on Wednesday, August 27, 1997 at 7:34:51 PM. Thanks for checking it out! Dave