HomeForumSourceResearchGuide
Sign in to contribute to source. how it works
Component encoding.Encoder:base64 by barry
expand copy to clipboardexpand
// https://en.wikipedia.org/wiki/Base64

component provides Encoder:base64 {
	
	static char indexTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
	
	char[] Encoder:encode(char x[])
		{
		//detect how many padding bytes we need in the result (0 or 4)
		int paddn = ((x.arrayLength % 3) != 0) * 4
		
		char result[] = new char[((x.arrayLength / 3)*4)+paddn]
		int ri = 0
		int i
		
		for (i = 0; i+2 < x.arrayLength; i += 3)
			{
			//take each 6-bit sequence and encode into a character
			result[ri] = indexTable[x[i] >> 2]
			ri ++
			
			result[ri] = indexTable[(x[i] << 4) | (x[i+1] >> 4)]
			ri ++
			
			result[ri] = indexTable[(x[i+1] << 2) | (x[i+2] >> 6)]
			ri ++
			
			result[ri] = indexTable[x[i+2]]
			ri ++
			}
		
		//pad result out, if needed
		if (x.arrayLength % 3 == 2)
			{
			result[ri] = indexTable[x[i] >> 2]
			ri ++
			
			result[ri] = indexTable[(x[i] << 4) | (x[i+1] >> 4)]
			ri ++
			
			result[ri] = indexTable[x[i+1] << 2]
			ri ++
			
			result[ri] = "="
			}
			else if (x.arrayLength % 3 == 1)
			{
			result[ri] = indexTable[x[i] >> 2]
			ri ++
			
			result[ri] = indexTable[(x[i] << 4)]
			ri ++
			
			result[ri] = "="
			result[ri+1] = "="
			}
		
		return result
		}
	
	byte indexOf(byte b)
		{
		if (b >= 65 && b <= 90)
			return b - 65
			else if (b >= 97 && b <= 122)
			return b - 71
			else if (b >= 48 && b <= 57)
			return b + 4
			else if (b == "+")
			return 62
			else if (b == "/")
			return 63
			else
			throw new Exception("Malformed base64 content")
		}
	
	bool validEncoding(char x[])
		{
		if (x == null || x.arrayLength == 0)
			return true
		
		if (x[x.arrayLength-1] == "=" && (x.arrayLength % 4) != 0)
			return false
		
		for (int i = 0; i < x.arrayLength; i ++)
			{
			if (x[i] < 48 || (x[i] > 57 && x[i] < 65) || (x[i] > 90 && x[i] < 97) || (x[i] > 122))
				{
				if (x[i] == "=" && i < i == x.arrayLength-2)
					return false
				}
			}
		
		if (x.arrayLength >= 2 && (x[x.arrayLength-2] == "=" && x[x.arrayLength-1] != "="))
			return false
		
		return true
		}
	
	//here we support decoding of both padded and unpadded data
	char[] Encoder:decode(char x[])
		{
		if (!validEncoding(x))
			throw new Exception("Malformed base64 content")
		
		int paddm = (x[x.arrayLength-1] == "=") + (x[x.arrayLength-2] == "=")
		
		char result[] = new char[((x.arrayLength / 4)*3) - paddm]
		int ri = 0
		int i
		
		for (i = 0; i + 3 < x.arrayLength; i += 4)
			{
			if (x[i+2] == "=")
				{
				result[ri] = (indexOf(x[i]) << 2) | (indexOf(x[i+1]) >> 4)
				}
				else if (x[i+3] == "=")
				{
				result[ri] = (indexOf(x[i]) << 2) | (indexOf(x[i+1]) >> 4)
				result[ri+1] = (indexOf(x[i+1]) << 4) | (indexOf(x[i+2]) >> 2)
				}
				else
				{
				result[ri] = (indexOf(x[i]) << 2) | (indexOf(x[i+1]) >> 4)
				result[ri+1] = (indexOf(x[i+1]) << 4) | (indexOf(x[i+2]) >> 2)
				result[ri+2] = (indexOf(x[i+2]) << 6) | (indexOf(x[i+3]))
				}
			
			ri += 3
			}
		
		//finally, deal with unpadded overflow
		if (i + 2 < x.arrayLength)
			{
			char add[] = new char[2]
			add[0] = (indexOf(x[i]) << 2) | (indexOf(x[i+1]) >> 4)
			add[1] = (indexOf(x[i+1]) << 4) | (indexOf(x[i+2]) >> 2)
			result = new char[](result, add)
			}
			else if (i + 1 < x.arrayLength)
			{
			char add[] = new char[1]
			add[0] = (indexOf(x[i]) << 2) | (indexOf(x[i+1]) >> 4)
			result = new char[](result, add)
			}
		
		return result
		}
	
	}
Revision history
To propose a new revision to this entity, use dana source put -uc your/new/version.dn -n encoding.Encoder:base64 -m "reason for update" -u yourUsername
Version 1 (this version) by barry
Notes for this version: Standard Library Initialisation