--!parent
--!encoding=utf-8
--****************************************************************************
-- @file LSW CORE LIB: BASE64
-- @author Valentin Schmidt
-- @version 0.1
--****************************************************************************
property _base64Lookup
property _base64DecodeLookup
property _chunkLen
property _EOL
----------------------------------------
-- @constructor
----------------------------------------
on new me
-- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
me._base64Lookup = [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]
me._base64DecodeLookup = []
repeat with k = 1 to 256
me._base64DecodeLookup[k] = me._base64Lookup.findpos(k)-1
end repeat
-- defaults
me._chunkLen = 72
me._EOL = numtochar(13)&numtochar(10)
return me
end
----------------------------------------
-- Encodes ByteArray as ASCII Base64 string
-- @param {bytearray|string} baData
-- @param {bool} [splitChunks=FALSE]
-- @param {string} [mimeFilename=VOID] - if specified, a MIME header will be prepended
-- @param {string} [mimeType=VOID]
-- @return {string}
----------------------------------------
on encode (me, baData, splitChunks, mimeFilename, mimeType)
if stringP(baData) then baData = byteArray(baData)
baOut = byteArray()
if stringP(mimeFilename) then
mimeHeader = ""
if stringP(mimeType) then put "Content-Type: "&mimeType&";"&me._EOL after mimeHeader
put "Content-Transfer-Encoding: base64"&me._EOL after mimeHeader
put "Content-Disposition: inline; filename=""E&mimeFilename"E&me._EOL&me._EOL after mimeHeader
if not splitChunks then
baOut.writeRawString(mimeHeader, mimeHeader.length)
end if
end if
i=1
strRemainder = baData.length mod 3
strLength = baData.length - strRemainder
repeat while i < strLength
a = baData[i]
b = baData[i+1]
c = baData[i+2]
byte1 = me._base64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1]
byte2 = me._base64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1]
byte3 = me._base64Lookup[ ( bitAnd( (b*256)+c, 4032 ) / 64 ) + 1]
byte4 = me._base64Lookup[ ( 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( me._base64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
baOut.writeInt8( me._base64Lookup[ ( bitAnd( a*256, 1008 ) / 16 ) + 1] )
baOut.writeRawString( "==", 2)
else if ( strRemainder = 2 ) then
a = baData[i]
b = baData[i+1]
baOut.writeInt8( me._base64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
baOut.writeInt8( me._base64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1] )
baOut.writeInt8( me._base64Lookup[ ( bitAnd( b*256, 4032 ) / 64 ) + 1] )
baOut.writeRawString( "=", 1)
end if
baOut.position = 1
-- break into lines of me._chunkLen chars
if splitChunks then
baOut2 = byteArray()
if not voidP(mimeHeader) then baOut2.writeRawString(mimeHeader, mimeHeader.length)
len = baOut.length
cnt = len/me._chunkLen
repeat with i = 1 to cnt
baOut2.writeRawString(baOut.readRawString(me._chunkLen ), me._chunkLen)
baOut2.writeRawString(me._EOL, me._EOL.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
return baOut.readRawString( baOut.length )
end
----------------------------------------
-- Decodes Base64 string or byteArray
-- @param {string|byteArray} baIn
-- @param {bool} [asString=FALSE]
-- @return {byteArray|string}
----------------------------------------
on decode (me, baIn, asString)
if stringP(baIn) then baIn = byteArray(baIn)
baOut = byteArray()
len = baIn.length
start = 1
-- if there is a mime header, strip it
if len>8 then
baIn.position = 1
if baIn.readRawString(8)="Content-" 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 -- CR LF CR LF
start = i+4
exit repeat
else if (baIn[i]=13 and baIn[i+1]=13) or (baIn[i]=10 and baIn[i+1]=10) then -- CR CR or LF LF
start = i+2
exit repeat
end if
end repeat
end if
end if
i = start
rest = (len-start+1) mod 4
iEnd = len - rest
repeat while i < iEnd
a = me._base64DecodeLookup[baIn[i]]
b = me._base64DecodeLookup[baIn[i+1]]
c = me._base64DecodeLookup[baIn[i+2]] --a
d = me._base64DecodeLookup[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 rest = 3 then
a = me._base64DecodeLookup[baIn[i]]
b = me._base64DecodeLookup[baIn[i+1]] --b
c = me._base64DecodeLookup[baIn[i+2]]
baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
baOut.writeInt8( bitAnd( (b*64)+c, 1020 ) / 4 )
else if rest = 2 then
a = me._base64DecodeLookup[baIn[i]]
b = me._base64DecodeLookup[baIn[i+1]]--c
baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
end if
if asString then
baOut.position = 1
return baOut.readRawString(baOut.length)
else
return baOut
end if
end