base64_decode.ls
on base64_decode encodedStr
--
-- Base 64 encoding for director strings.
-- http://www.fourmilab.ch/webtools/base64/rfc1341.html
--
-- Cole Tierney -- <colet at putnamhill dot net>
--
--
-- First setup some constants to make our life easier.
--
-- set bits12Mask = integer( 255 + 15 * power(2,8) ) --== 4095
set bits12Mask = 4095 -- 00000000 00000000 00001111 11111111
set bit13Mask = bits12Mask + 1 -- 00000000 00000000 00010000 00000000
--
-- set bits18Mask = integer( 255 + 255 * power(2,8) + 3 * power(2,16) ) --== 262143
set bits18Mask = 262143 -- 00000000 00000011 11111111 11111111
set bit19Mask = bits18Mask + 1 -- 00000000 00000100 00000000 00000000
--
-- set bits24Mask = integer( 255 + 255 * power(2,8) + 255 * power(2,16) ) --== 16777215
set bits24Mask = 16777215 -- 00000000 11111111 11111111 11111111
set bit25Mask = bits24Mask + 1 -- 00000001 00000000 00000000 00000000
--
set base64alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
--
-- Since lingo is case insensitive, we'll translate the above into their ascii equivalents.
set base64values = []
set len = length(base64alphabet)
repeat with i = 1 to len
add base64values, chartonum( char i of base64alphabet )
end repeat
--
set base64alphabet = "" -- Don't need this anymore.
--
--
set decodedStr = ""
set bit24grp = ""
repeat while length( encodedStr ) > 0
-- Get next character from the string we passed.
set ch = char 1 of encodedStr
delete char 1 of encodedStr
-- Try to add it to our group of 4 valid base 64 characters.
if length( bit24grp ) < 4 then
set asciiNum = charToNum(ch)
if getPos( base64values, asciiNum ) > 0 or ch = "=" then -- This is a base 64 character, so collect it.
put ch after bit24grp
end if
end if
if length( bit24grp ) = 4 then -- We have a commplete group of 4 base64 characters.
-- If we've got a complete group then decode it...
set padCharOffset = offset( "=", bit24grp )
if padCharOffset = 0 then -- Process a normal unpadded group.
-- we can assume that there are no special processing characters ("=").
-- If here, then we have a complete set of 3 bytes.
set b64int = 0
repeat while length( bit24grp ) > 0
set b64ch = char 1 of bit24grp
delete char 1 of bit24grp
set asciiNum = chartonum( b64ch )
set val = getPos( base64values, asciiNum ) - 1
set b64int = b64int * 64 -- Shift left 6 bits (double it 6 times or multiply by 64).
set b64int = bitOr( b64int, val )
end repeat
-- Ok, now extract the 3 8 bit bytes from our integer (all 24 bits are significant).
repeat with i = 1 to 3
set bit8int = 0
repeat with j = 1 to 8
set bit8int = bit8int * 2 -- Make room for more bits.
set b64int = b64int * 2
set bit8int = bitOr( bit8int, bitAnd( b64int, bit25Mask ) > 0 ) -- ...roll this bit into our 8 bit number.
set b64int = bitAnd( b64int, bits24Mask ) -- Strip the bit from our 24 bit integer and...
end repeat
-- Should have our 8 bit int, so turn it into a char so we can add it to our decoded str.
put numToChar( bit8int ) after decodedStr
end repeat
else
-- Else we must have our last group that happens to be padded with the "=" character.
-- The masks we use will be determined by how many bits we have to processed, so set that first.
if padCharOffset = 3 then -- The offset of the pad character must be either 3 or 4.
maskbits = bits12Mask -- Only two 6bit characters, so use a 12 bit mask.
highBitMask = bit13Mask
else -- must be 18 bits
maskBits = bits18Mask
highBitMask = bit19Mask
end if
set bit24grp = char 1 to padCharOffset - 1 of bit24grp -- First strip off the pad charaters.
set b64int = 0
repeat while length( bit24grp ) > 0
set b64ch = char 1 of bit24grp
delete char 1 of bit24grp
set asciiNum = chartonum( b64ch )
set val = getPos( base64values, asciiNum ) - 1
set b64int = b64int * 64 -- Shift left 6 bits (double it 6 times or multiply by 64).
set b64int = bitOr( b64int, val )
end repeat
-- Ok, now extract the bits from the integer.
repeat while b64int > 0 -- As long there are bits left in our integer, keep rotating out 8 bit charaters.
set bit8int = 0
repeat with j = 1 to 8
set bit8int = bit8int * 2 -- Make room for more bits.
set b64int = b64int * 2 -- Shift bits to left once.
set bit8int = bitOr( bit8int, bitAnd( b64int, highBitMask ) > 0 ) -- ...roll this bit into our 8 bit number.
set b64int = bitAnd( b64int, maskBits ) -- Strip the bit from our 18 bit integer and...
end repeat
-- Should have our 8 bit int, so turn it into a char so we can add it to our decoded str.
put numToChar( bit8int ) after decodedStr
end repeat
end if -- else finished decoding last group containing special processing character ("=").
end if -- Have a base64 group
end repeat -- End of processing base64 characters.
return decodedStr
end