base64_encode.ls

on base64_encode str
  --  
  -- Base 64 encoding for director strings.
  -- http://www.fourmilab.ch/webtools/base64/rfc1341.html
  --
  -- Cole Tierney -- <colet at putnamhill dot net>
  --
  --
  -- Set up some constants.
  --  
  --  set bit16Mask = integer( 255 + 255 * power(2,8) ) --==  65535
  set bit16Mask = 65535              -- 00000000 00000000 11111111 11111111
  set bit17mask = bit16Mask + 1      -- 00000000 00000001 00000000 00000000
  --  set bit24Mask = integer( 255 + 255* power(2,8) + 255 * power(2,16) ) --== 16777215
  set bit24Mask = 16777215           -- 00000000 11111111 11111111 11111111
  set bit25Mask = bit24mask + 1      -- 00000001 00000000 00000000 00000000
  
  set base64alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  
  set encodedStr = ""
  set bit24grp = ""
  
  
  repeat while length( str ) > 0
    
    set ch = char 1 of str
    delete char 1 of str
    
    if length( bit24grp ) < 3 then -- Add the char to our group.
      put ch after bit24grp
    end if
    
    if length( bit24grp ) = 3 then
      
      -- If here, then we have a complete group of 24 bits (3 chars).
      -- So extract our 4 six bit numbers, and add them to our encoded string.  
      -- First we'll turn it into an integer so we can perform our bitwise operations.
      set c1 = charToNum( char 1 of bit24grp )
      set c2 = charToNum( char 2 of bit24grp )
      set c3 = charToNum( char 3 of bit24grp )
      
      set int24bit = c3 + c2 * 256 + c1 * 65536 -- First byte will be high order.
      
      repeat with i = 1 to 4 -- For each 6bit number (4 of them per group)...    
        set bit6Int = 0  
        
        repeat with j = 1 to 6 -- For each 6 bits...
          set bit6Int = bit6Int * 2 -- First make room for another bit by shifting the 6 bit integer one place to the left.
          set int24bit = int24bit * 2 -- Shift bits one place to the left.
          set bit6Int = bitOr( bit6Int, bitAnd( int24bit, bit25Mask ) > 0 ) -- ...roll this bit into our 6 bit integer.
          set int24bit = bitAnd( int24bit, bit24Mask ) -- Strip anything that landed in the 25th bit slot.
        end repeat
        
        -- Should now have our 6 bit base 64 index, so fetch our new character.
        put char bit6Int + 1 of base64alphabet after encodedStr
        
      end repeat
      
      -- Start another 24 bit string
      set bit24grp = ""
    end if
  end repeat
  
  
  set bit6Int = 0
  
  -- If current length of our 24 bit group string is non-zero then have an incomplete 24 bit group, so deal with it.  
  set bitGroupSize = length( bit24grp )
  case bitGroupSize of
      
    1: -- Have 8 bits left to encode:
      -- Get the first 6 bits by shifting right twice (divide by 4).
      set c1 = charToNum(char 1 of bit24grp)
      set bit6int = c1
      set bit6int = integer( bit6int / 4 )
      put char bit6Int + 1 of base64alphabet after encodedStr
      
      -- Get the last two bits by masking off the first 6 bits.
      set bit6int = charToNum(char 1 of bit24grp)
      set bit6int = bitAnd( c1, 3 )
      
      -- Now shift left 4 times to make it 6 bits wide (double it 4 times).
      set bit6int = bit6int * 16
      put char bit6Int + 1 of base64alphabet after encodedStr
      
      put "==" after encodedStr  -- Finish off the 4 6bit group with the "=" pad char.
      
    2: -- Have 16 bits (2 bytes) left to encode:
      -- Get the first 6 bits by shifting right twice (divide by 4).
      set c1 = charToNum(char 1 of bit24grp)
      set c2 = charToNum(char 2 of bit24grp)
      set bit16int = c2 + c1 * 256 -- First byte is high order.
      
      repeat with i = 1 to 3
        set bit6Int = 0  
        
        repeat with j = 1 to 6 -- For each 6 bits...
          -- First make room for another bit by shifting resulting 6 bit integer one place to the left.
          set bit6Int = bit6Int * 2
          -- Start pealing bits off the left each time we shift left.    
          -- Shift bits one place to the left.
          set bit16int = bit16int * 2
          -- If a bit fell off the left end (bit 17 == 1), then add to our six bit number.
          if bitAnd( bit16int, bit17Mask ) <> 0 then set bit6Int = bit6Int + 1  
          -- Strip anything that landed in the 17th bit slot.
          set bit16int = bitAnd( bit16int, bit16Mask )
        end repeat
        
        -- Should now have our 6 bit base 64 index, so fetch our new character.
        put char bit6Int + 1 of base64alphabet after encodedStr
        
      end repeat
      
      put "=" after encodedStr  -- Finish off the 4 6bit group with the "=" pad char.
      
  end case
  
  
  return encodedStr  
  
end