--****************************************************************************
-- Script: BASE64 CLASS
-- Version: 0.5
-- Date: 2011-10-25
-- Author: Valentin Schmidt
-- Contact: fluxus@freenet.de
--
-- Requirements/Dependencies:
-- o parent script "ProgressDialog" (optional)
--
--****************************************************************************
property pBase64Lookup
property pBase64DecodeLookup
property pReturn
property pMimeHeader
property pChunkLen
----------------------------------------
--
----------------------------------------
on new me
-- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
pBase64Lookup = [65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,54,55,56,57,43,47]
-- Noisecrime Optimisation: Build also lookup of decode byte to table position
pBase64DecodeLookup = []
repeat with k = 1 to 256
pBase64DecodeLookup[k] = pBase64Lookup.findpos(k)-1
end repeat
-- defaults
pReturn = numtochar(13)&numtochar(10)
pMimeHeader = ""
pChunkLen = 72
return me
end
----------------------------------------
-- HOOK FOR PROGRESS BAR (overwrite, either directly or in child script!)
----------------------------------------
on showProgress (me, prog)
-- put prog*100 && "%"
end
----------------------------------------
--
----------------------------------------
on setMimeHeader me, tFilename, tMimeType
pMimeHeader = ""
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
----------------------------------------
-- ByteArray/String -> ASCII String
----------------------------------------
on encode (me, baData, splitChunks)
if ilk(baData)=#string then
str = baData
baData = bytearray()
baData.writeRawString(str, str.length)
end if
baOut = ByteArray()
if not splitChunks then
baOut.writeRawString(pMimeHeader, pMimeHeader.length)
end if
i=1
strRemainder = baData.length mod 3
strLength = baData.length - strRemainder
repeat while i < strLength
if i mod 100 = 0 then me.showProgress(float(i)/strLength)
a = baData[i]
b = baData[i+1]
c = baData[i+2]
-- Noisecrime Optimisation
-- Replaced per byte writing with a single 32bit write
-- Potential performance gain of 20% over orignal code
byte1 = pBase64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1]
byte2 = pBase64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1]
byte3 = pBase64Lookup[ ( bitAnd( (b*256)+c, 4032 ) / 64 ) + 1]
byte4 = pBase64Lookup[ ( bitAnd( c, 63 ) ) + 1]
baOut.writeInt32( byte1 + byte2*256 + byte3*65536 + byte4*16777216)
i = i + 3
end repeat
if( strRemainder = 1 ) then
a = baData[i]
baOut.writeInt8( pBase64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
baOut.writeInt8( pBase64Lookup[ ( bitAnd( a*256, 1008 ) / 16 ) + 1] )
baOut.writeRawString( "==", 2)
else if ( strRemainder = 2 ) then
a = baData[i]
b = baData[i+1]
baOut.writeInt8( pBase64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
baOut.writeInt8( pBase64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1] )
baOut.writeInt8( pBase64Lookup[ ( bitAnd( b*256, 4032 ) / 64 ) + 1] )
baOut.writeRawString( "=", 1)
end if
baOut.position = 1
-- break into lines of pChunkLen chars
if splitChunks then
baOut2 = ByteArray()
baOut2.writeRawString(pMimeHeader, pMimeHeader.length)
len = baOut.length
cnt = len/pChunkLen
repeat with i = 1 to cnt
baOut2.writeRawString( baOut.readRawString( pChunkLen ), pChunkLen)
baOut2.writeRawString( pReturn, pReturn.length )
end repeat
if baOut.bytesRemaining>0 then
str = baOut.readRawString( baOut.bytesRemaining )
baOut2.writeRawString(str, str.length)
end if
baOut = baOut2
baOut.position = 1
end if
me.showProgress(1)
return baOut.readRawString( baOut.length )
end
----------------------------------------
-- ASCII String -> ByteArray
-- TO DO: handle code split in lines (LF, CR, CR LF)!!!
----------------------------------------
on decode (me, str)
baIn = ByteArray(str)
baOut = ByteArray()
--quanta = []
len = baIn.length
if baIn[len]=61 then len=len-1 -- strip "="
if baIn[len]=61 then len=len-1 -- strip "="
-- strip mime header
start = 1
if baIn[8]=45 then
repeat with i = 9 to len-3
if baIn[i]=13 AND baIn[i+1]=10 AND baIn[i+2]=13 AND baIn[i+3]=10 then -- 0D 0A 0D 0A
start = i+4
exit repeat
end if
end repeat
end if
i = start
iEnd = integer(((len)/4.0)-0.5)*4
repeat while i < iEnd
a = pBase64DecodeLookup[baIn[i]]
b = pBase64DecodeLookup[baIn[i+1]]
c = pBase64DecodeLookup[baIn[i+2]]
d = pBase64DecodeLookup[baIn[i+3]]
byte1 = bitAnd( (a*64)+b, 4080 ) / 16
byte2 = bitAnd( (b*64)+c, 1020 ) / 4
baOut.writeInt16( byte1 + byte2*256)
baOut.writeInt8( bitAnd( (c*64)+d, 255 ) )
i = i + 4
end repeat
if( len-iEnd = 3 ) then
a = pBase64DecodeLookup[baIn[i]]
b = pBase64DecodeLookup[baIn[i+1]]
c = pBase64DecodeLookup[baIn[i+2]]
baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
baOut.writeInt8( bitAnd( (b*64)+c, 1020 ) / 4 )
else if( len-iEnd = 2 ) then
a = pBase64DecodeLookup[baIn[i]]
b = pBase64DecodeLookup[baIn[i+1]]
baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
end if
return baOut
end