1. --!parent
  2. --!encoding=utf-8
  3.  
  4. --****************************************************************************
  5. -- @file LSW CORE LIB: BASE64
  6. -- @author Valentin Schmidt
  7. -- @version 0.1
  8. --****************************************************************************
  9.  
  10. property _base64Lookup
  11. property _base64DecodeLookup
  12. property _chunkLen
  13. property _EOL
  14.  
  15. ----------------------------------------
  16. -- @constructor
  17. ----------------------------------------
  18. on new me
  19.     -- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  20.     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]
  21.  
  22.     me._base64DecodeLookup = []
  23.     repeat with k = 1 to 256
  24.         me._base64DecodeLookup[k] = me._base64Lookup.findpos(k)-1
  25.     end repeat
  26.  
  27.     -- defaults
  28.     me._chunkLen = 72
  29.     me._EOL = numtochar(13)&numtochar(10)
  30.  
  31.     return me
  32. end
  33.  
  34. ----------------------------------------
  35. -- Encodes ByteArray as ASCII Base64 string
  36. -- @param {bytearray|string} baData
  37. -- @param {bool} [splitChunks=FALSE]
  38. -- @param {string} [mimeFilename=VOID] - if specified, a MIME header will be prepended
  39. -- @param {string} [mimeType=VOID]
  40. -- @return {string}
  41. ----------------------------------------
  42. on encode (me, baData, splitChunks, mimeFilename, mimeType)
  43.     if stringP(baData) then baData = byteArray(baData)
  44.  
  45.     baOut = byteArray()
  46.  
  47.     if stringP(mimeFilename) then
  48.         mimeHeader = ""
  49.         if stringP(mimeType) then put "Content-Type: "&mimeType&";"&me._EOL after mimeHeader
  50.         put "Content-Transfer-Encoding: base64"&me._EOL after mimeHeader
  51.         put "Content-Disposition: inline; filename="&QUOTE&mimeFilename&QUOTE&me._EOL&me._EOL after mimeHeader
  52.         if not splitChunks then
  53.             baOut.writeRawString(mimeHeader, mimeHeader.length)
  54.         end if
  55.     end if
  56.    
  57.     i=1
  58.     strRemainder = baData.length mod 3
  59.     strLength = baData.length - strRemainder
  60.  
  61.     repeat while i < strLength
  62.         a = baData[i]
  63.         b = baData[i+1]
  64.         c = baData[i+2]
  65.  
  66.         byte1 = me._base64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1]
  67.         byte2 = me._base64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1]
  68.         byte3 = me._base64Lookup[ ( bitAnd( (b*256)+c, 4032 ) / 64 ) + 1]
  69.         byte4 = me._base64Lookup[ ( bitAnd( c, 63 ) ) + 1]
  70.         baOut.writeInt32( byte1 + byte2*256 + byte3*65536 + byte4*16777216)
  71.  
  72.         i = i + 3
  73.     end repeat
  74.  
  75.     if( strRemainder = 1 ) then
  76.         a = baData[i]
  77.         baOut.writeInt8( me._base64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
  78.         baOut.writeInt8( me._base64Lookup[ ( bitAnd( a*256, 1008 ) / 16 ) + 1] )
  79.         baOut.writeRawString( "==", 2)
  80.  
  81.     else if ( strRemainder = 2 ) then
  82.         a = baData[i]
  83.         b = baData[i+1]
  84.         baOut.writeInt8( me._base64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
  85.         baOut.writeInt8( me._base64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1] )
  86.         baOut.writeInt8( me._base64Lookup[ ( bitAnd( b*256, 4032 ) / 64 ) + 1] )
  87.         baOut.writeRawString( "=", 1)
  88.  
  89.     end if
  90.  
  91.     baOut.position = 1
  92.    
  93.     -- break into lines of me._chunkLen chars
  94.     if splitChunks then
  95.  
  96.         baOut2 = byteArray()
  97.         if not voidP(mimeHeader) then baOut2.writeRawString(mimeHeader, mimeHeader.length)
  98.  
  99.         len = baOut.length
  100.         cnt = len/me._chunkLen
  101.         repeat with i = 1 to cnt
  102.             baOut2.writeRawString(baOut.readRawString(me._chunkLen ), me._chunkLen)
  103.             baOut2.writeRawString(me._EOL, me._EOL.length)
  104.         end repeat
  105.  
  106.         if baOut.bytesRemaining>0 then
  107.             str = baOut.readRawString(baOut.bytesRemaining)
  108.             baOut2.writeRawString(str, str.length)
  109.         end if
  110.  
  111.         baOut = baOut2
  112.         baOut.position = 1
  113.     end if
  114.  
  115.     return baOut.readRawString( baOut.length )
  116. end
  117.  
  118. ----------------------------------------
  119. -- Decodes Base64 string or byteArray
  120. -- @param {string|byteArray} baIn
  121. -- @param {bool} [asString=FALSE]
  122. -- @return {byteArray|string}
  123. ----------------------------------------
  124. on decode (me, baIn, asString)
  125.     if stringP(baIn) then baIn = byteArray(baIn)
  126.     baOut = byteArray()
  127.     len = baIn.length
  128.  
  129.     start = 1
  130.    
  131.     -- if there is a mime header, strip it
  132.     if len>8 then
  133.         baIn.position = 1
  134.         if baIn.readRawString(8)="Content-" then
  135.             repeat with i = 9 to len-3
  136.                 if baIn[i]=13 and baIn[i+1]=10 and baIn[i+2]=13 and baIn[i+3]=10 then -- CR LF CR LF
  137.                     start = i+4
  138.                     exit repeat
  139.                 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
  140.                     start = i+2
  141.                     exit repeat
  142.                 end if
  143.             end repeat
  144.         end if
  145.     end if
  146.  
  147.     i = start
  148.     rest = (len-start+1) mod 4
  149.     iEnd = len - rest
  150.  
  151.     repeat while i < iEnd
  152.         a = me._base64DecodeLookup[baIn[i]]
  153.         b = me._base64DecodeLookup[baIn[i+1]]
  154.         c = me._base64DecodeLookup[baIn[i+2]] --a
  155.         d = me._base64DecodeLookup[baIn[i+3]]
  156.  
  157.         byte1 = bitAnd( (a*64)+b, 4080 ) / 16
  158.         byte2 = bitAnd( (b*64)+c, 1020 ) / 4
  159.         baOut.writeInt16( byte1 + byte2*256)
  160.         baOut.writeInt8( bitAnd( (c*64)+d, 255 ) )
  161.  
  162.         i = i + 4
  163.     end repeat
  164.  
  165.     if rest = 3 then
  166.         a = me._base64DecodeLookup[baIn[i]]
  167.         b = me._base64DecodeLookup[baIn[i+1]] --b
  168.         c = me._base64DecodeLookup[baIn[i+2]]
  169.         baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
  170.         baOut.writeInt8( bitAnd( (b*64)+c, 1020 ) / 4   )
  171.  
  172.     else if rest = 2 then
  173.         a = me._base64DecodeLookup[baIn[i]]
  174.         b = me._base64DecodeLookup[baIn[i+1]]--c
  175.         baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
  176.     end if
  177.  
  178.     if asString then
  179.         baOut.position = 1
  180.         return baOut.readRawString(baOut.length)
  181.     else
  182.         return baOut
  183.     end if
  184. end
  185.  
[raw code]