--****************************************************************************
-- Script: BASE64 CLASS
-- Version: 1.3
-- Date: 2015-02-03
-- Author: Valentin Schmidt
--
-- Requirements/Dependencies:
-- o parent script "ProgressDialog" (optional)
--
--****************************************************************************
property pBase64Lookup
property pSubLengthLim
property pReturn
property pMimeHeader
property pIsMac
----------------------------------------
-- @constructor
----------------------------------------
on new me
pBase64Lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
pIsMac = the platform contains "mac"
-- defaults
pSubLengthLim = 6000 -- tune for optimization, win: 1000 ? mac: 6000 ?
pReturn = numtochar(13)&numtochar(10)
pMimeHeader = ""
return me
end
----------------------------------------
-- HOOK FOR PROGRESS BAR (overwrite, either directly or in child script!)
-- @param {float} prog
----------------------------------------
on showProgress (me, prog)
-- put prog*100 && "%"
end
----------------------------------------
-- Sets mime header
-- If called without arguments, header is reset to empty (=no header)
-- @param {string} tFilename - optional
-- @param {string} tMimeType - optional
----------------------------------------
on setMimeHeader (me, tFilename, tMimeType)
pMimeHeader = ""
if stringP(tFilename) then
if stringP(tMimeType) then put "Content-Type: "&tMimeType&";"&pReturn after pMimeHeader
put "Content-Transfer-Encoding: base64"&pReturn after pMimeHeader
put "Content-Disposition: inline; filename=""E&tFilename"E&pReturn&pReturn after pMimeHeader
end if
end
----------------------------------------
-- Encodes binary string
-- @param {string} str
-- @param {bool} splitChunks - optional
-- @return {string}
----------------------------------------
on base64Encode (me, str, splitChunks)
if pIsMac then
return me.base64EncodeMAC (str, splitChunks)
else
return me.base64EncodePC (str, splitChunks)
end if
end
----------------------------------------
-- Encodes binary string (PC version)
-- Optimized for PC by LingoGuy@sbcglobal.net 3/29/04
-- @param {string} str
-- @param {bool} splitChunks - optional
-- @return {string}
----------------------------------------
on base64EncodePC (me, str, splitChunks)
subStrings = []
out = ""
i=1
strRemainder = str.length mod 3
strLength = str.length - strRemainder
repeat while i < strLength
if i mod 100 = 0 then me.showProgress(float(i)/strLength)
a = charToNum( str.char[ i ] )
b = charToNum( str.char[ i+1 ] )
c = charToNum( str.char[ i+2 ] )
put pBase64Lookup.char[ ( bitAnd( a, 252 ) / 4 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( (b*256)+c, 4032 ) / 64 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( c, 63 ) ) + 1] after out
i = i + 3
if splitChunks AND i mod 54=1 then put pReturn after out
if length(out) > pSubLengthLim then --- cach segment in array, start new out string
subStrings.append(out)
out = empty
end if
end repeat
if (strRemainder = 1) then
a = charToNum( str.char[ i ] )
put pBase64Lookup.char[ ( bitAnd( a, 252 ) / 4 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( a*256, 1008 ) / 16 ) + 1 ] after out
put "=" after out
put "=" after out
else if (strRemainder = 2) then
a = charToNum( str.char[ i ] )
b = charToNum( str.char[ i+1 ] )
put pBase64Lookup.char[ ( bitAnd( a, 252 ) / 4 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( b*256, 4032 ) / 64 ) + 1 ] after out
put "=" after out
end if
b64Str = ""
repeat with s in subStrings
put s after b64Str
end repeat
put out after b64Str -- last uncached bit
if splitChunks then
if b64Str.char[b64Str.length-pReturn.length+1..b64Str.length]=pReturn then
delete char (b64Str.length-pReturn.length+1) to b64Str.length of b64Str
end if
end if
put pMimeHeader before b64Str
me.showProgress(1)
return b64Str
end
----------------------------------------
-- Encodes binary string (Mac version)
-- Optimized for mac by Alex da Franca
-- @param {string} str
-- @param {bool} splitChunks - optional
-- @return {string}
----------------------------------------
on base64EncodeMAC (me, str, splitChunks)
out = ""
i=1
strLength = str.length
strRemainder = strLength mod 3
strLength = strLength - strRemainder
chunk = char 1 to pSubLengthLim of str
delete char 1 to pSubLengthLim of str
b64Str = ""
repeat while i < strLength
if i mod 100 = 0 then me.showProgress(float(i)/strLength)
a = charToNum( chunk.char[ 1 ] )
b = charToNum( chunk.char[ 2 ] )
c = charToNum( chunk.char[ 3 ] )
put pBase64Lookup.char[ ( bitAnd( a, 252 ) / 4 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( (b*256)+c, 4032 ) / 64 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( c, 63 ) ) + 1] after out
i = i + 3
if splitChunks AND i mod 54=1 then put pReturn after out
delete char 1 to 3 of chunk
if (i - 1) mod pSubLengthLim = 0 then
chunk = char 1 to pSubLengthLim of str
delete char 1 to pSubLengthLim of str
put out after b64Str
out = ""
end if
end repeat
if( strRemainder = 1 ) then
a = charToNum( chunk.char[ 1 ] )
put pBase64Lookup.char[ ( bitAnd( a, 252 ) / 4 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( a*256, 1008 ) / 16 ) + 1 ] after out
put "==" after out
else if ( strRemainder = 2 ) then
a = charToNum( chunk.char[ 1 ] )
b = charToNum( chunk.char[ 2 ] )
put pBase64Lookup.char[ ( bitAnd( a, 252 ) / 4 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1 ] after out
put pBase64Lookup.char[ ( bitAnd( b*256, 4032 ) / 64 ) + 1 ] after out
put "=" after out
end if
put out after b64Str -- last uncached bit
if splitChunks then
if b64Str.char[b64Str.length-pReturn.length+1..b64Str.length]=pReturn then
delete char (b64Str.length-pReturn.length+1) to b64Str.length of b64Str
end if
end if
put pMimeHeader before b64Str
me.showProgress(1)
return b64Str
end
----------------------------------------
-- Decodes Base64 encoded string, returns (binary) string or false
-- @param {string} str
-- @return {string|false}
----------------------------------------
on base64Decode (me, str)
Base64Lookup = [ "A":0, "B":1, "C":2, "D":3, "E":4, "F":5, "G":6, "H":7, "I":8, \
"J":9, "K":10, "L":11, "M":12, "N":13, "O":14, "P":15, "Q":16, "R":17, "S":18, \
"T":19, "U":20, "V":21, "W":22, "X":23, "Y":24, "Z":25, "a":26, "b":27, "c":28, \
"d":29, "e":30, "f":31, "g":32, "h":33, "i":34, "j":35, "k":36, "l":37, "m":38, \
"n":39, "o":40, "p":41, "q":42, "r":43, "s":44, "t":45, "u":46, "v":47, "w":48, \
"x":49, "y":50, "z":51, "0":52, "1":53, "2":54, "3":55, "4":56, "5":57, "6":58, \
"7":59, "8":60, "9":61, "+":62, "/":63 ]
n = 1
-- mime header detection:
if str.line[1] contains ":" then
check = [numtochar(13)&numtochar(10)&numtochar(13)&numtochar(10), numtochar(13)&numtochar(13), numtochar(10)&numtochar(10)]
repeat with c in check
n = offset(c, str)
if n > 0 then
n = n+c.length
exit repeat
end if
end repeat
if n=0 then
put "error parsing mime header!"
return false
end if
end if
subStrings = []
out = ""
quanta = []
repeat with i = n to str.length
c = Base64Lookup.getaProp( str.char[i] )
if not voidP(c) then quanta.add(c)
if( quanta.count = 4 ) then
put numToChar( bitAnd( (quanta[1]*64)+quanta[2], 4080 ) / 16 ) after out
put numToChar( bitAnd( (quanta[2]*64)+quanta[3], 1020 ) / 4 ) after out
put numToChar( bitAnd( (quanta[3]*64)+quanta[4], 255 ) ) after out
quanta = []
if length(out) > pSubLengthLim then --- cache segment in list, start new out string
subStrings.append(out)
out = empty
end if
end if
end repeat
if( quanta.count = 3 ) then
put numToChar( bitAnd( (quanta[1]*64)+quanta[2], 4080 ) / 16 ) after out
put numToChar( bitAnd( (quanta[2]*64)+quanta[3], 1020 ) / 4 ) after out
else if( quanta.count = 2 ) then
put numToChar( bitAnd( (quanta[1]*64)+quanta[2], 4080 ) / 16 ) after out
end if
str = ""
repeat with s in subStrings
put s after str
end repeat
put out after str -- last uncached bit
return str
end