1. --****************************************************************************
  2. -- Script:   BASE64 CLASS
  3. -- Version:  0.5
  4. -- Date:     2011-10-25
  5. -- Author:   Valentin Schmidt
  6. -- Contact:  fluxus@freenet.de
  7. --
  8. -- Requirements/Dependencies:
  9. -- o parent script "ProgressDialog" (optional)
  10. --
  11. --****************************************************************************
  12.  
  13. property pBase64Lookup
  14. property pBase64DecodeLookup
  15.  
  16. property pReturn
  17. property pMimeHeader
  18. property pChunkLen
  19.  
  20. ----------------------------------------
  21. --
  22. ----------------------------------------
  23. on new me
  24.   -- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"  
  25.   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]
  26.  
  27.   -- Noisecrime Optimisation: Build also lookup of decode byte to table position
  28.   pBase64DecodeLookup = []
  29.   repeat with k = 1 to 256
  30.     pBase64DecodeLookup[k] =  pBase64Lookup.findpos(k)-1
  31.   end repeat
  32.  
  33.   -- defaults
  34.   pReturn = numtochar(13)&numtochar(10)
  35.   pMimeHeader = ""
  36.   pChunkLen = 72
  37.  
  38.   return me
  39. end
  40.  
  41. ----------------------------------------
  42. -- HOOK FOR PROGRESS BAR (overwrite, either directly or in child script!)
  43. ----------------------------------------
  44. on showProgress (me, prog)
  45.   -- put prog*100 && "%"
  46. end
  47.  
  48. ----------------------------------------
  49. --
  50. ----------------------------------------
  51. on setMimeHeader me, tFilename, tMimeType
  52.   pMimeHeader = ""
  53.   if stringP(tMimeType) then put "Content-Type: "&tMimeType&";"&pReturn after pMimeHeader
  54.   put "Content-Transfer-Encoding: base64"&pReturn after pMimeHeader
  55.   put "Content-Disposition: inline; filename="&QUOTE&tFilename&QUOTE&pReturn&pReturn after pMimeHeader
  56. end
  57.  
  58. ----------------------------------------
  59. -- ByteArray/String -> ASCII String
  60. ----------------------------------------
  61. on encode (me, baData, splitChunks)
  62.  
  63.   if ilk(baData)=#string then
  64.     str = baData
  65.     baData = bytearray()
  66.     baData.writeRawString(str, str.length)
  67.   end if
  68.  
  69.   baOut = ByteArray()
  70.   if not splitChunks then
  71.     baOut.writeRawString(pMimeHeader, pMimeHeader.length)
  72.   end if
  73.  
  74.   i=1
  75.   strRemainder = baData.length mod 3
  76.   strLength    = baData.length - strRemainder
  77.  
  78.   repeat while i < strLength
  79.    
  80.     if i mod 100 = 0 then me.showProgress(float(i)/strLength)
  81.    
  82.     a = baData[i]
  83.     b = baData[i+1]
  84.     c = baData[i+2]
  85.    
  86.     -- Noisecrime Optimisation
  87.     -- Replaced per byte writing with a single 32bit write
  88.     -- Potential performance gain of 20% over orignal code
  89.     byte1 = pBase64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1]
  90.     byte2 = pBase64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1]
  91.     byte3 = pBase64Lookup[ ( bitAnd( (b*256)+c, 4032 ) / 64 ) + 1]
  92.     byte4 = pBase64Lookup[ ( bitAnd( c, 63 ) ) + 1]
  93.     baOut.writeInt32( byte1 + byte2*256 + byte3*65536 + byte4*16777216)
  94.    
  95.     i = i + 3    
  96.   end repeat
  97.  
  98.   if( strRemainder = 1 ) then
  99.     a = baData[i]
  100.     baOut.writeInt8( pBase64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
  101.     baOut.writeInt8( pBase64Lookup[ ( bitAnd( a*256, 1008 ) / 16 ) + 1] )
  102.     baOut.writeRawString( "==", 2)
  103.    
  104.   else if ( strRemainder = 2 ) then
  105.     a = baData[i]
  106.     b = baData[i+1]
  107.     baOut.writeInt8( pBase64Lookup[ ( bitAnd( a, 252 ) / 4 ) + 1] )
  108.     baOut.writeInt8( pBase64Lookup[ ( bitAnd( (a*256)+b, 1008 ) / 16 ) + 1] )
  109.     baOut.writeInt8( pBase64Lookup[ ( bitAnd( b*256, 4032 ) / 64 ) + 1] )
  110.     baOut.writeRawString( "=", 1)
  111.    
  112.   end if
  113.  
  114.   baOut.position = 1
  115.  
  116.   -- break into lines of pChunkLen chars
  117.   if splitChunks then
  118.    
  119.     baOut2 = ByteArray()
  120.     baOut2.writeRawString(pMimeHeader, pMimeHeader.length)
  121.    
  122.     len = baOut.length
  123.     cnt = len/pChunkLen
  124.        
  125.     repeat with i = 1 to cnt
  126.       baOut2.writeRawString( baOut.readRawString( pChunkLen ), pChunkLen)
  127.       baOut2.writeRawString( pReturn, pReturn.length )
  128.     end repeat
  129.    
  130.     if baOut.bytesRemaining>0 then
  131.       str = baOut.readRawString( baOut.bytesRemaining )
  132.       baOut2.writeRawString(str, str.length)
  133.     end if
  134.    
  135.     baOut = baOut2
  136.     baOut.position = 1
  137.   end if
  138.  
  139.   me.showProgress(1)
  140.  
  141.   return baOut.readRawString( baOut.length )
  142. end
  143.  
  144. ----------------------------------------
  145. -- ASCII String -> ByteArray
  146. -- TO DO: handle code split in lines (LF, CR, CR LF)!!!
  147. ----------------------------------------
  148. on decode (me, str)
  149.  
  150.   baIn = ByteArray(str)  
  151.   baOut = ByteArray()
  152.   --quanta = []
  153.   len = baIn.length
  154.   if baIn[len]=61 then len=len-1 -- strip "="
  155.   if baIn[len]=61 then len=len-1 -- strip "="
  156.  
  157.   -- strip mime header
  158.   start = 1
  159.   if baIn[8]=45 then
  160.     repeat with i = 9 to len-3
  161.       if baIn[i]=13 AND baIn[i+1]=10 AND baIn[i+2]=13 AND baIn[i+3]=10 then -- 0D 0A 0D 0A
  162.         start = i+4
  163.         exit repeat
  164.       end if
  165.     end repeat
  166.   end if
  167.    
  168.   i    = start
  169.   iEnd = integer(((len)/4.0)-0.5)*4
  170.  
  171.   repeat while i < iEnd
  172.     a = pBase64DecodeLookup[baIn[i]]
  173.     b = pBase64DecodeLookup[baIn[i+1]]
  174.     c = pBase64DecodeLookup[baIn[i+2]]
  175.     d = pBase64DecodeLookup[baIn[i+3]]
  176.    
  177.     byte1 = bitAnd( (a*64)+b, 4080 ) / 16
  178.     byte2 = bitAnd( (b*64)+c, 1020 ) / 4      
  179.     baOut.writeInt16( byte1 + byte2*256)
  180.     baOut.writeInt8( bitAnd( (c*64)+d, 255 ) )
  181.    
  182.     i = i + 4
  183.   end repeat
  184.  
  185.   if( len-iEnd = 3 ) then
  186.     a = pBase64DecodeLookup[baIn[i]]
  187.     b = pBase64DecodeLookup[baIn[i+1]]
  188.     c = pBase64DecodeLookup[baIn[i+2]]
  189.     baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
  190.     baOut.writeInt8( bitAnd( (b*64)+c, 1020 ) / 4  )
  191.   else if( len-iEnd = 2 ) then
  192.     a = pBase64DecodeLookup[baIn[i]]
  193.     b = pBase64DecodeLookup[baIn[i+1]]
  194.     baOut.writeInt8( bitAnd( (a*64)+b, 4080 ) / 16 )
  195.   end if  
  196.  
  197.   return baOut
  198. end
  199.  
[raw code]