gunawantw

Encode Decode Base64

Jan 9th, 2021
444
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. 'Base64 1.4:
  2.  
  3. Option Public
  4. Option Explicit
  5.  
  6. %REM
  7. This set of functions will allow you to encode and decode strings and files
  8. in Base64 format. The implementation is all in LotusScript, and requires no
  9. external DLLs or tricks. It was written and tested in R5, but it should be
  10. backwards compatible to at least 4.6
  11.  
  12. This is the 1.4 "release" of the functions, from December 28, 2002.
  13. The code was originally written by Julian Robichaux, and is maintained
  14. by him on the http://www.nsftools.com website.
  15.  
  16. Release History:
  17. 1.4 (Dec 28, 2002)
  18.   --  fixed TrimBytesFromFile function to properly handle writing odd numbers
  19.       of bytes to a new file (thanks to Peter Leugner at www.as-computer.de)
  20.  
  21. 1.3 (Dec 26, 2002)
  22.   --  Modified DecodeFile function to properly handle the line terminators
  23.       that the Print statement adds
  24.   --  Fixed GetFileChunk function to properly read the last byte in a file
  25.  
  26. 1.2 (Dec 17, 2002)
  27.   --  Added functions for encrypting and decrypting entire files
  28.  
  29. 1.1 (Nov 5, 2002)
  30.   --  Fixed typo/error in EncodeBase64 function
  31.  
  32. 1.0 (Nov 1, 2002)
  33.   --  Initial release
  34. %END REM
  35.  
  36.  
  37. '** the characters used to encode in Base64, in order of appearance
  38. Const b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  39.  
  40.  
  41. Sub Initialize
  42.     '** examples of using the Base64 functions in this agent
  43.     Dim eString As String, dString As String
  44.     Dim isOkay As Integer
  45.    
  46.     eString = "QUJDREVGRw=="        '** ABCDEFG
  47.     dString = DecodeBase64(eString)
  48.    
  49.     isOkay = IsBase64(eString)
  50.    
  51.     eString = EncodeBase64("AbCdEfG" & Chr(0) & "123")
  52.     eString = BreakString(eString, 5)
  53.     dString = DecodeBase64(eString)
  54.    
  55.     isOkay = IsBase64(RemoveWhitespace(eString))
  56.     isOkay = IsBase64(dString)
  57.    
  58.     isOkay = EncodeFile("C:\Autoexec.bat", "C:\Autoexec.enc")
  59.     isOkay = DecodeFile("C:\Autoexec.enc", "C:\Autoexec.dec")
  60. End Sub
  61.  
  62. Function DecodeBase64 (Byval encText As String) As String
  63.     '** This function will decode a Base64 string. It's probably a good
  64.     '** idea to check the validity of the string with the IsBase64 function
  65.     '** prior to processing it, to avoid strange errors.
  66.     '** by Julian Robichaux -- http://www.nsftools.com
  67.     On Error Goto endOfFunction
  68.    
  69.     Dim encNum As Long
  70.     Dim decText As String
  71.     Dim i As Integer
  72.    
  73.     '** remove any line termination characters and whitespace first
  74.     encText = RemoveWhitespace(encText)
  75.    
  76.     For i = 1 To Len(encText) Step 4
  77.         '** convert the next 2 of 4 characters to a number we can decode
  78.         encNum = (Instr(b64chars, Mid$(encText, i, 1)) - 1) * (2 ^ 18)
  79.         encNum = encNum Or ((Instr(b64chars, Mid$(encText, i+1, 1)) - 1) * (2 ^ 12))
  80.        
  81.         '** deal with trailing '='
  82.         If (Mid$(encText, i+2, 1) = "=") Then
  83.             decText = decText & Chr(Fix(encNum / (2 ^ 16)) And &HFF)
  84.         Elseif (Mid$(encText, i+3, 1) = "=") Then
  85.             encNum = encNum Or ((Instr(b64chars, Mid$(encText, i+2, 1)) - 1) * (2 ^ 6))
  86.             decText = decText & Chr(Fix(encNum / (2 ^ 16)) And &HFF)
  87.             decText = decText & Chr(Fix(encNum / (2 ^ 8)) And &HFF)
  88.         Else
  89.             encNum = encNum Or ((Instr(b64chars, Mid$(encText, i+2, 1)) - 1) * (2 ^ 6))
  90.             encNum = encNum Or (Instr(b64chars, Mid$(encText, i+3, 1)) - 1)
  91.             decText = decText & Chr(Fix(encNum / (2 ^ 16)) And &HFF)
  92.             decText = decText & Chr(Fix(encNum / (2 ^ 8)) And &HFF)
  93.             decText = decText & Chr(encNum And &HFF)
  94.         End If
  95.        
  96.     Next
  97.    
  98. endOfFunction:
  99.     DecodeBase64 = decText
  100.     Exit Function
  101.    
  102. End Function
  103.  
  104. Function EncodeBase64 (decText As String) As String
  105.     '** This function will Base64 encode a string. The string doesn't have to
  106.     '** be text-only, either. You can also encode strings of non-ASCII data,
  107.     '** like the contents of a binary file. If you're encoding a whole file,
  108.     '** make sure you break the contents into lengths divisible by three, so
  109.     '** you can concatenate them together properly.
  110.     '** by Julian Robichaux -- http://www.nsftools.com
  111.     On Error Goto endOfFunction
  112.    
  113.     Dim decNum As Long
  114.     Dim encText As String
  115.     Dim chunk As String
  116.     Dim i As Integer
  117.    
  118.     For i = 1 To Len(decText) Step 3
  119.         '** pad the 3-character string with Chr(0), if need be
  120.         chunk = Left$(Mid$(decText, i, 3) & Chr(0) & Chr(0), 3)
  121.        
  122.         '** get the number we'll use for encoding
  123.         decNum = Asc(Mid$(chunk, 1, 1)) * (2 ^ 16)
  124.         decNum = decNum Or Asc(Mid$(chunk, 2, 1)) * (2 ^ 8)
  125.         decNum = decNum Or Asc(Mid$(chunk, 3, 1))
  126.        
  127.         '** calculate the first 2 of 4 encoded characters
  128.         encText = encText & Mid$(b64chars, (Fix(decNum / (2 ^ 18)) And &H3F) + 1, 1)
  129.         encText = encText & Mid$(b64chars, (Fix(decNum / (2 ^ 12)) And &H3F) + 1, 1)
  130.        
  131.         '** pad with '=' as necessary when we reach the end of the string
  132.         Select Case ( Len(decText) - i )
  133.         Case 0 :
  134.             encText = encText & "=="
  135.         Case 1 :
  136.             encText = encText & Mid$(b64chars, (Fix(decNum / (2 ^ 6)) And &H3F) + 1, 1)
  137.             encText = encText & "="
  138.         Case Else :
  139.             encText = encText & Mid$(b64chars, (Fix(decNum / (2 ^ 6)) And &H3F) + 1, 1)
  140.             encText = encText & Mid$(b64chars, (decNum And &H3F) + 1, 1)
  141.         End Select
  142.        
  143.     Next
  144.    
  145. endOfFunction: 
  146.     EncodeBase64 = encText
  147.     Exit Function
  148.    
  149. End Function
  150.  
  151. Function IsBase64 (someString As String) As Integer
  152.     '** check to see if the string is a well-formed Base64 string
  153.     Dim legalString As String
  154.     Dim i As Integer
  155.    
  156.     IsBase64 = False
  157.     legalString = b64chars & "="
  158.    
  159.     '** check for bad string length (must be a multiple of 4)
  160.     If (Len(someString) Mod 4 > 0) Then
  161.         Exit Function
  162.     End If
  163.    
  164.     '** check for illegal characters
  165.     For i = 1 To Len(someString)
  166.         If (Instr(legalString, Mid$(someString, i, 1)) = 0) Then
  167.             Exit Function
  168.         End If
  169.     Next
  170.    
  171.     '** make sure any '=' are only at the end
  172.     Select Case (Instr(someString, "="))
  173.     Case 0 :
  174.         '** no equals signs is okay
  175.     Case Is < (Len(someString) - 1) :
  176.         Exit Function
  177.     Case (Len(someString) - 1) :
  178.         If (Right$(someString, 1) <> "=") Then
  179.             Exit Function
  180.         End If
  181.     End Select
  182.    
  183.     '** if we made it through all the conditions, then the string looks good
  184.     IsBase64 = True
  185.    
  186. End Function
  187.  
  188. Function BreakString (text As String, lineLength As Integer) As String
  189.     '** add line terminators to a string at the given interval
  190.     Dim newText As String
  191.     Dim lineTerm As String
  192.     Dim i As Integer
  193.    
  194.     lineTerm = Chr(13) & Chr(10)
  195.    
  196.     For i = 1 To Len(text) Step lineLength
  197.         newText = newText & Mid$(text, i, lineLength) & lineTerm
  198.     Next
  199.    
  200.     newText = Left$(newText, Len(newText) - Len(lineTerm))
  201.     BreakString = newText
  202. End Function
  203.  
  204. Function RemoveWhitespace (Byval text As String) As String
  205.     '** remove line terminators, spaces, and tabs from a string
  206.     Call ReplaceSubstring(text, Chr(13), "")
  207.     Call ReplaceSubstring(text, Chr(10), "")
  208.     Call ReplaceSubstring(text, Chr(9), "")
  209.     Call ReplaceSubstring(text, " ", "")
  210.    
  211.     RemoveWhitespace = text
  212. End Function
  213.  
  214. Function ReplaceSubstring (text As String, find As String, replace As String)
  215.     Dim pos As Integer
  216.     pos = Instr(text, find)
  217.    
  218.     Do While (pos > 0)
  219.         text = Left$(text, pos - 1) & replace & Mid$(text, pos + Len(find))
  220.         pos = Instr(pos + Len(replace), text, find)
  221.     Loop
  222. End Function
  223.  
  224. Function EncodeFile (fileIn As String, fileOut As String) As Integer
  225.     '** Base64 encode an entire file (fileIn) and write the output to
  226.     '** another file (fileOut). We're writing the output to another file
  227.     '** because there's a possibility that the output will be larger than
  228.     '** 32,000 characters, which would overflow an output String.
  229.     On Error Goto processError
  230.    
  231.     Dim fin As Integer, fout As Integer
  232.     Dim finOpen As Integer, foutOpen As Integer
  233.     Dim datain As String, dataout As String
  234.     Dim worktext As String, leftover As String
  235.     Const CHUNKSIZE = 15000
  236.    
  237.     '** open the files for input/output (if there are any errors here,
  238.     '** we'll exit in the processError section at the bottom)
  239.     fin = Freefile()
  240.     Open fileIn For Input As fin
  241.     finOpen = True
  242.     fout = Freefile
  243.     Open fileOut For Output As fout
  244.     foutOpen = True
  245.    
  246.     '** start getting data from the input file, encoding it, and sending it
  247.     '** to the output file
  248.     datain = GetFileChunk(fin, CHUNKSIZE)
  249.     Do While (Len(datain) > 0)
  250.         '** encode in groups of 57 characters, which will give us output
  251.         '** in lines of 76 characters (fairly standard)
  252.         leftover = leftover & datain
  253.         While (Len(leftover) > 57)
  254.             worktext = Left$(leftover, 57)
  255.             leftover = Mid$(leftover, 58)
  256.             dataout = EncodeBase64(worktext)
  257.             Print #fout, dataout
  258.         Wend
  259.         datain = GetFileChunk(fin, CHUNKSIZE)
  260.     Loop
  261.    
  262.     '** encode anything we had left, and close the files
  263.     If (Len(leftover) > 0) Then
  264.         Print #fout, EncodeBase64(leftover)
  265.     End If
  266.    
  267.     Close #fin, #fout
  268.     EncodeFile = True
  269.     Exit Function
  270.    
  271. processError:
  272.     If (finOpen) Then Close #fin
  273.     If (foutOpen) Then Close #fout
  274.     EncodeFile = False
  275.     Exit Function
  276.    
  277. End Function
  278.  
  279. Function DecodeFile (fileIn As String, fileOut As String) As Integer
  280.     '** Base64 decode an entire file (fileIn) and write the output to
  281.     '** another file (fileOut). We're writing the output to another file
  282.     '** because there's a possibility that the output will be larger than
  283.     '** 32,000 characters, which would overflow an output String.
  284.     On Error Goto processError
  285.    
  286.     Dim fin As Integer, fout As Integer
  287.     Dim finOpen As Integer, foutOpen As Integer
  288.     Dim datain As String, dataout As String
  289.     Dim worktext As String, leftover As String
  290.     Const CHUNKSIZE = 16000
  291.    
  292.     '** figure out how long the line terminator character is
  293.     Dim session As New NotesSession
  294.     Dim lineTermLen As Integer
  295.     If (Instr(session.Platform, "Windows") > 0) Then
  296.         lineTermLen = 2
  297.     Else
  298.         lineTermLen = 1
  299.     End If
  300.    
  301.     '** open the files for input/output (if there are any errors here,
  302.     '** we'll exit in the processError section at the bottom)
  303.     fin = Freefile()
  304.     Open fileIn For Input As fin
  305.     finOpen = True
  306.     fout = Freefile
  307.     Open fileOut For Output As fout
  308.     foutOpen = True
  309.    
  310.     '** start getting data from the input file, encoding it, and sending it
  311.     '** to the temporary output file
  312.     datain = GetFileChunk(fin, CHUNKSIZE)
  313.     Do While (Len(datain) > 0)
  314.         datain = RemoveWhitespace(datain)
  315.        
  316.         '** make sure we're decoding in groups of characters
  317.         '** that are multiples of 4
  318.         leftover = leftover & datain
  319.         worktext = Left$(leftover, Len(leftover) - (Len(leftover) Mod 4))
  320.         leftover = Right$(leftover, Len(leftover) Mod 4)
  321.         dataout = DecodeBase64(worktext)
  322.         Print #fout, dataout
  323.         '** adjust the cursor position so we overwrite the line terminator that's
  324.         '** automatically been appended to the end of the line by Print
  325.         Seek #fout, Seek(fout) - lineTermLen
  326.        
  327.         datain = GetFileChunk(fin, CHUNKSIZE)
  328.     Loop
  329.    
  330.     '** decode anything we had left, and close the files
  331.     If (Len(leftover) > 0) Then
  332.         Print #fout, leftover
  333.     End If
  334.    
  335.     Close #fin, #fout
  336.     finOpen = False
  337.     foutOpen = False
  338.    
  339.     '** okay, so here's the problem: the Print statement automatically appends
  340.     '** a line terminator to the end of all the lines it printed. We accounted for
  341.     '** this while we were writing to the output file in the Do While loop, but
  342.     '** there's going to be an extra line terminator at the end of the file that we
  343.     '** couldn't do anything about. So we'll need to copy all but the last one or
  344.     '** two bytes (depending on the length of the line terminator on this platform)
  345.     '** from the temporary output file to the output file that the user wants using
  346.     '** Get and Put commands. We couldn't use Put before because when Put
  347.     '** writes a text string to a file, it always writes the Unicode version of the
  348.     '** string, which isn't what we wanted (try it sometime and see how it looks...)
  349.     '** The TrimBytesFromFile function will take care of the problem.
  350.     Call TrimBytesFromFile(fileOut, lineTermLen)
  351.    
  352.     DecodeFile = True
  353.     Exit Function
  354.    
  355. processError:
  356.     If (finOpen) Then Close #fin
  357.     If (foutOpen) Then Close #fout
  358.     DecodeFile = False
  359.     Exit Function
  360.    
  361. End Function
  362.  
  363. Function GetFileChunk (fileNum As Integer, size As Integer) As String
  364.     '** get the next chunk of text from a Random file, up to a given size
  365.     On Error Goto processError
  366.     Dim dataLength As Long
  367.    
  368.     dataLength = Lof(fileNum) - Seek(fileNum) + 1
  369.     Select Case (dataLength)
  370.     Case Is <= 0
  371.         GetFileChunk = ""
  372.     Case Is > size
  373.         GetFileChunk = Input$(size, fileNum)
  374.     Case Else
  375.         GetFileChunk = Input$(Cint(dataLength), fileNum)
  376.     End Select
  377.    
  378.     Exit Function
  379.    
  380. processError:
  381.     GetFileChunk = ""
  382.     Exit Function
  383.    
  384. End Function
  385.  
  386. Function TrimBytesFromFile (fileName As String, bytesToTrim As Integer)
  387.     '** trim the specified number of bytes from the end of the specified
  388.     '** file by copying the file contents to a temporary file using Get and
  389.     '** Put, and then deleting the specified file and replacing it with
  390.     '** the temporary file
  391.     On Error Goto processError
  392.    
  393.     Dim tempFileName As String
  394.     Dim fin As Integer, fout As Integer
  395.     Dim finOpen As Integer, foutOpen As Integer
  396.     Dim dataLength As Long
  397.     Dim lineLength As Integer
  398.     Dim data As String
  399.     Dim dataInt As Integer
  400.     Const CHUNKSIZE = 15000
  401.    
  402.     tempFileName = fileName & ".tmp"
  403.    
  404.     fin = Freefile()
  405.     Open fileName For Binary As fin
  406.     finOpen = True
  407.     fout = Freefile()
  408.     Open tempFileName For Binary As fout
  409.     foutOpen = True
  410.    
  411.     '** this works almost exactly like the GetFileChunk function, subtracting
  412.     '** bytesToTrim when we reach the last "chunk" of the file
  413.     dataLength = Lof(fin) - Seek(fin) + 1 - bytesToTrim
  414.     Do While (dataLength > 1)
  415.         If (dataLength > CHUNKSIZE) Then
  416.             lineLength = CHUNKSIZE
  417.         Else
  418.             lineLength = Cint(dataLength)
  419.         End If
  420.        
  421.         '** a LotusScript string is actually 2 bytes per character, so we only
  422.         '** want to get a string that's half the length of the number of bytes
  423.         '** that we need
  424.         data = Space$(Fix(lineLength / 2))
  425.         Get #fin, , data
  426.         Put #fout, , data
  427.        
  428.         dataLength = Lof(fin) - Seek(fin) + 1 - bytesToTrim
  429.     Loop
  430.    
  431.     '** if there's only one more byte to read, we need to back up one byte
  432.     '** because there are no one-byte data types in LotusScript prior to R6,
  433.     '** so we're always writing an even number of bytes at a time
  434.     If (dataLength = 1) Then
  435.         Seek #fin, Seek(fin) - 1
  436.         Seek #fout, Seek(fout) - 1
  437.         Get #fin, , dataInt
  438.         Put #fout, , dataInt
  439.     End If
  440.    
  441.     Close #fin, #fout
  442.     finOpen = False
  443.     foutOpen = False
  444.    
  445.     '** once all the files are closed, delete the original file and rename the
  446.     '** temporary file so it becomes the original
  447.     Kill fileName
  448.     Name tempFileName As fileName
  449.     Exit Function
  450.    
  451. processError:
  452.     If (finOpen) Then Close #fin
  453.     If (foutOpen) Then Close #fout
  454.     Exit Function
  455.    
  456. End Function
  457.  
  458.  
Add Comment
Please, Sign In to add comment