Results 1 to 34 of 34

Thread: Mime (Base64) Speed Challenge

  1. #1

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131

    Mime (Base64) Speed Challenge

    Ok... I'm back with another speed challenge. This time, it's converting strings and files to/from base64.

    A friend and I have developed code that is lightning fast and I’m wondering if ANYONE here can beat our times. (It WONT be easy!!)

    Simple code for conversion to (and from) Base64 can be found here:

    http://www.vbsquare.com/internet/sen...dmail.bas.html

    Our times follow, good luck beating them!! If you do, I’d love to see your code, if you can’t, I’ll show you ours. (Times were generated on: AMD T-Bird 750Mhz, 256MB PC133)

    Code:
    String, 1000000 bytes
    Total Successes : 10
    Total Failures : 0
    Average Line Count : 1000000
    Average Encode Time : 0.3703 sec
    Average Decode Time : 0.975 sec
    Average Total Time : 1.3453 sec
    
    File VMM32.VXD, 1,032,956 bytes
    Total Successes : 10
    Total Failures : 0
    Average Line Count : 0
    Average Encode Time : 0.2703 sec
    Average Decode Time : 1.0742 sec
    Average Total Time : 1.3445 sec
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  2. #2

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    well?
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  3. #3

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    bump
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  4. #4
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    When you say converting it to base 64, what kind of system are you talking about? 4 characters for each one, or crunching more than that into each character?
    Alphanos

  5. #5
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    BTW, would you consider testing my encryption program on that file you tested your blowfish code on and see if mine is slower or not? That'll tell me if there's more optimization to be done, because theoretically it should run faster than blowfish.

    Thanks in advance if you do.
    Alphanos

  6. #6
    So Unbanned DiGiTaIErRoR's Avatar
    Join Date
    Apr 1999
    Location
    /dev/null
    Posts
    4,111
    I'm guessing base64 would work like hex?

    A-Z ....a-z .....0-9 ....+ ..\
    0-25 26-51 52 - 61 62 63

    ?

    then in two character units like hex also?

    XY where x * 64 + y?

  7. #7
    Frenzied Member nishantp's Avatar
    Join Date
    Jan 2001
    Location
    Where you least expect me to be
    Posts
    1,375
    And may i ask what purpose base-64 would have over decimal or hex?
    You just proved that sig advertisements work.

  8. #8
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    The reason that I'm asking is that strings are in essence base 256 numbers. One character is one digit of base 256 (0-255*256^0). So does he mean to separate it into four ascii codes, where the last 2 bits are unused? Or to use 6 bits of one character for the first 64^0, and another 2 of the next character for 64^1(since you'd only ever need 64*3 with ascii codes)? Or to pack 2 characters into two characters using a different method so that its in base 64? I'm sorry if I'm being stupid, but what Rikk's saying seems unclear.
    Alphanos

  9. #9
    So Unbanned DiGiTaIErRoR's Avatar
    Join Date
    Apr 1999
    Location
    /dev/null
    Posts
    4,111
    Yeah.. if you where gonna do a large base why not do base 256 and use the ASCii char set?

    That would seem easier.

    XY x * 256 + y

    so at max for two characters you could yeild 65535

    cuz hex works like XYZ where x*256+y*16+z*1

    so base 256 with XYZ would be:
    x*65536+y*256+z*1

    so at max for 3 char would be 16777215
    4:4,294,967,040
    5:1,099,511,562,240
    6:281,474,959,933,440
    ...
    16:340,282,346,638,528,859,811,704,183,484,516,925,440

    wow...

    but really bases are based on the Nth place to the power of the base.

    so base64 would be
    64^3*q+64^2*x+64^1*y+64^0*z

    but still why!

  10. #10
    So Unbanned DiGiTaIErRoR's Avatar
    Join Date
    Apr 1999
    Location
    /dev/null
    Posts
    4,111
    I remember back in the day when all we had was base2!!!

    You lucky youngin's!

  11. #11
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    When you get right down to it, one digit of base 256 is 8 bits, so you actually are working in binary. Just in a simpler form; 4 characters instead of 32 bits. A hexit represents 4 bits, an octet 3, but a digit of base 256 represents 8 bits.

    I've thought about this for a while now, and a 4-character string is a good way to represent a long value, because they're the same amount of data. So in an OOP project I'm working on I'm having classes generate and read their records based on dynamic field lengths based on fixed-length index numbers. There's always a 4-character long value, followed by that many characters for the field, followed by another 4-character long value, etc. In that form, the idea is expanded to write the class records in a text database system using binary-access files.
    Alphanos

  12. #12
    Tygur
    Guest

    Re: Mime (Base64) Speed Challenge

    Originally posted by Rikk
    Ok... I'm back with another speed challenge. This time, it's converting strings and files to/from base64.
    If you're still offering that challenge, I'd like to take it up. I just need to know exactly what this code is supposed to do. I'm guessing it's supposed to be an encode and decode function that takes and returns strings. Exactly what is a Base64 decoder doing?

    By the way, I unserstand the purpose. The puropse is so that files with funky characters can be sent in email without problems. The characters would be encoded.

  13. #13

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131

    Re: Re: Mime (Base64) Speed Challenge

    Originally posted by Tygur

    If you're still offering that challenge, I'd like to take it up. I just need to know exactly what this code is supposed to do. I'm guessing it's supposed to be an encode and decode function that takes and returns strings. Exactly what is a Base64 decoder doing?

    By the way, I unserstand the purpose. The puropse is so that files with funky characters can be sent in email without problems. The characters would be encoded.
    Here is a web site about Base64 (MIME)
    Link to RFC: 1341 (MIME -- Multipurpose Internet Mail Extensions)

    Below is sample code for encoding and decoding to/from Base64. The code is NOT fast but does work.

    Code:
    Function Base64Encode(inData)
      'rfc1521
      '2001 Antonin Foller, PSTRUH Software, http://pstruh.cz
      Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
      Dim cOut, sOut, I
      
      'For each group of 3 bytes
      For I = 1 To Len(inData) Step 3
        Dim nGroup, pOut, sGroup
        
        'Create one long from this 3 bytes.
        nGroup = &H10000 * Asc(Mid(inData, I, 1)) + _
          &H100 * MyASC(Mid(inData, I + 1, 1)) + MyASC(Mid(inData, I + 2, 1))
        
        'Oct splits the long to 8 groups with 3 bits
        nGroup = Oct(nGroup)
        
        'Add leading zeros
        nGroup = String(8 - Len(nGroup), "0") & nGroup
        
        'Convert to base64
        pOut = Mid(Base64, CLng("&o" & Mid(nGroup, 1, 2)) + 1, 1) + _
          Mid(Base64, CLng("&o" & Mid(nGroup, 3, 2)) + 1, 1) + _
          Mid(Base64, CLng("&o" & Mid(nGroup, 5, 2)) + 1, 1) + _
          Mid(Base64, CLng("&o" & Mid(nGroup, 7, 2)) + 1, 1)
        
        'Add the part to output string
        sOut = sOut + pOut
        
        'Add a new line for each 76 chars in dest (76*3/4 = 57)
        If (I + 2) Mod 57 = 0 Then sOut = sOut + vbCrLf
      Next
      Select Case Len(inData) Mod 3
        Case 1: '8 bit final
          sOut = Left(sOut, Len(sOut) - 2) + "=="
        Case 2: '16 bit final
          sOut = Left(sOut, Len(sOut) - 1) + "="
      End Select
      Base64Encode = sOut
    End Function
    
    Function MyASC(OneChar)
      If OneChar = "" Then MyASC = 0 Else MyASC = Asc(OneChar)
    End Function
    
    Function Base64Decode(ByVal base64String)
      'rfc1521
      '1999 Antonin Foller, PSTRUH Software, http://pstruh.cz
      Const Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
      Dim dataLength, sOut, groupBegin
      
      'remove white spaces, if any
      base64String = Replace(base64String, vbCrLf, "")
      base64String = Replace(base64String, vbTab, "")
      base64String = Replace(base64String, " ", "")
      
      'The source must consists from groups with len of 4 chars
      dataLength = Len(base64String)
      If dataLength Mod 4 <> 0 Then
        Err.Raise 1, "Base64Decode", "Bad Base64 string."
        Exit Function
      End If
    
      
      ' Now decode each group:
      For groupBegin = 1 To dataLength Step 4
        Dim numDataBytes, CharCounter, thisChar, thisData, nGroup, pOut
        ' Each data group encodes up To 3 actual bytes.
        numDataBytes = 3
        nGroup = 0
    
        For CharCounter = 0 To 3
          ' Convert each character into 6 bits of data, And add it To
          ' an integer For temporary storage.  If a character is a '=', there
          ' is one fewer data byte.  (There can only be a maximum of 2 '=' In
          ' the whole string.)
    
          thisChar = Mid(base64String, groupBegin + CharCounter, 1)
    
          If thisChar = "=" Then
            numDataBytes = numDataBytes - 1
            thisData = 0
          Else
            thisData = InStr(Base64, thisChar) - 1
          End If
          If thisData = -1 Then
            Err.Raise 2, "Base64Decode", "Bad character In Base64 string."
            Exit Function
          End If
    
          nGroup = 64 * nGroup + thisData
        Next
        
        'Hex splits the long to 6 groups with 4 bits
        nGroup = Hex(nGroup)
        
        'Add leading zeros
        nGroup = String(6 - Len(nGroup), "0") & nGroup
        
        'Convert the 3 byte hex integer (6 chars) to 3 characters
        pOut = Chr(CByte("&H" & Mid(nGroup, 1, 2))) + _
          Chr(CByte("&H" & Mid(nGroup, 3, 2))) + _
          Chr(CByte("&H" & Mid(nGroup, 5, 2)))
        
        'add numDataBytes characters to out string
        sOut = sOut & Left(pOut, numDataBytes)
      Next
    
      Base64Decode = sOut
    End Function
    Now see the time it took to encode and decode 100000 bytes. (NOTE: this is a string 10 times smaller than the one in the original post)

    Code:
    String, 100000 bytes
    Total Successes : 10
    Total Failures : 0
    Average Line Count : 100000
    Average Encode Time : 28.28906 sec
    Average Decode Time : 14.39063 sec
    Average Total Time : 42.67969 sec
    I got the code from here:


    http://www.pstruh.cz/tips/detpg_Base64.htm

    Good luck!!!
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  14. #14
    Frenzied Member
    Join Date
    Mar 2001
    Location
    You are HERE •™
    Posts
    1,300
    Here try this one out. I just whipped it up....
    j/k...actually I got it from here: http://www.vbip.com/winsock/winsock_http_04_01.asp
    VB Code:
    1. Private Function Base64_Encode(strSource) As String
    2.  
    3.     Const BASE64_TABLE As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    4.    
    5.     Dim strTempLine As String
    6.     Dim j As Integer
    7.    
    8.     For j = 1 To (Len(strSource) - Len(strSource) Mod 3) Step 3
    9.    
    10.        strTempLine = strTempLine + Mid(BASE64_TABLE, _
    11.                      (Asc(Mid(strSource, j, 1)) \ 4) + 1, 1)
    12.    
    13.        strTempLine = strTempLine + Mid(BASE64_TABLE, _
    14.                      ((Asc(Mid(strSource, j, 1)) Mod 4) * 16 _
    15.                      + Asc(Mid(strSource, j + 1, 1)) \ 16) + 1, 1)
    16.    
    17.        strTempLine = strTempLine + Mid(BASE64_TABLE, _
    18.                      ((Asc(Mid(strSource, j + 1, 1)) Mod 16) * 4 _
    19.                      + Asc(Mid(strSource, j + 2, 1)) \ 64) + 1, 1)
    20.    
    21.        strTempLine = strTempLine + Mid(BASE64_TABLE, _
    22.                      (Asc(Mid(strSource, j + 2, 1)) Mod 64) + 1, 1)
    23.    
    24.     Next j
    25.    
    26.     If Not (Len(strSource) Mod 3) = 0 Then
    27.    
    28.           If (Len(strSource) Mod 3) = 2 Then
    29.    
    30.              strTempLine = strTempLine + Mid(BASE64_TABLE, _
    31.                            (Asc(Mid(strSource, j, 1)) \ 4) + 1, 1)
    32.    
    33.              strTempLine = strTempLine + Mid(BASE64_TABLE, _
    34.                            (Asc(Mid(strSource, j, 1)) Mod 4) * 16 _
    35.                             + Asc(Mid(strSource, j + 1, 1)) \ 16 + 1, 1)
    36.    
    37.              strTempLine = strTempLine + Mid(BASE64_TABLE, _
    38.                            (Asc(Mid(strSource, j + 1, 1)) Mod 16) * 4 + 1, 1)
    39.    
    40.              strTempLine = strTempLine & "="
    41.    
    42.           ElseIf (Len(strSource) Mod 3) = 1 Then
    43.    
    44.              strTempLine = strTempLine + Mid(BASE64_TABLE, _
    45.                            Asc(Mid(strSource, j, 1)) \ 4 + 1, 1)
    46.    
    47.              strTempLine = strTempLine + Mid(BASE64_TABLE, _
    48.                            (Asc(Mid(strSource, j, 1)) Mod 4) * 16 + 1, 1)
    49.    
    50.              strTempLine = strTempLine & "=="
    51.    
    52.           End If
    53.    
    54.        End If
    55.    
    56.     Base64_Encode = strTempLine
    57.  
    58. End Function

  15. #15

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    Bloodeye,

    Your Encode function gave the following times. (Since you didn't provide a decode, I used another one.) BTW, this was compiled.

    Code:
    String, 100000 bytes
    Total Successes : 10
    Total Failures : 0
    Average Line Count : 100000
    Average Encode Time : 91.23828 sec
    Average Decode Time : 14.39063 sec
    Average Total Time : 105.62891 sec
    Thanks! Bloodeye, try again? Anyone else want to try?
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  16. #16

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    bump
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  17. #17
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    I wrote one up, and its decent, but it doesn't even come close to the kind of times you're getting. I'm interested in how you're doing it, because on mine the decode is a LOT faster than the encode.
    Alphanos

  18. #18
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    Here's the code I used if you're interested. Don't even bother testing the speed though, its a lot slower than yours.

    Init has to be called before you can run either of the two main subs.
    VB Code:
    1. Option Explicit
    2.     Private Encode1(0 To 63) As Byte
    3.     Private Encode2(0 To 192) As Byte
    4.     Private Decode1(48 To 51) As Byte
    5.     Private Decode2(48 To 122) As Byte
    6. Public Sub ShutDown()
    7.     Erase Encode1
    8.     Erase Encode2
    9.     Erase Decode1
    10.     Erase Decode2
    11.    
    12.     Dim TempForm As Form
    13.     For Each TempForm In Forms
    14.         Unload TempForm
    15.         Set TempForm = Nothing
    16.     Next TempForm
    17.    
    18.     End
    19. End Sub
    20. Public Sub EncodeTo64(ByRef TextString As String)
    21.     Dim i As Long
    22.     Dim i2 As Long
    23.     Dim TextLen As Long
    24.     Dim ByteArray() As Byte
    25.     Dim TextBytes() As Byte
    26.    
    27.     TextLen = Len(TextString)
    28.    
    29.     ReDim ByteArray(TextLen * 2) As Byte
    30.     TextLen = TextLen - 1
    31.     TextBytes() = StrConv(TextString, vbFromUnicode)
    32.     i = -1
    33.     Do
    34.         i = i + 1
    35.         ByteArray(i2) = Encode2(TextBytes(i) And 192)
    36.         i2 = i2 + 1
    37.         ByteArray(i2) = Encode1(TextBytes(i) And 63)
    38.         i2 = i2 + 1
    39.     Loop Until i = TextLen
    40.    
    41.     TextString = StrConv(ByteArray(), vbUnicode)
    42.     Erase ByteArray
    43.     Erase TextBytes
    44. End Sub
    45. Public Sub DecodeFrom64(ByRef TextString As String)
    46.     Dim i As Long
    47.     Dim i2 As Long
    48.     Dim TextLen As Long
    49.     Dim ByteArray() As Byte
    50.     Dim TextBytes() As Byte
    51.    
    52.     TextLen = Len(TextString)
    53.    
    54.     ReDim ByteArray(TextLen * 0.5) As Byte
    55.    
    56.     TextBytes() = StrConv(TextString, vbFromUnicode)
    57.    
    58.     Do
    59.         ByteArray(i2) = Decode1(TextBytes(i)) Or (Decode2(TextBytes(i + 1)))
    60.         i = i + 2
    61.         i2 = i2 + 1
    62.     Loop Until i = TextLen
    63.    
    64.     TextString = StrConv(ByteArray(), vbUnicode)
    65.     Erase ByteArray
    66.     Erase TextBytes
    67.  
    68. End Sub
    69. Public Sub Init()
    70.     Encode2(0) = 48
    71.     Encode2(64) = 49
    72.     Encode2(128) = 50
    73.     Encode2(192) = 51
    74.     Decode1(48) = 0
    75.     Decode1(49) = 64
    76.     Decode1(50) = 128
    77.     Decode1(51) = 192
    78.    
    79.     Dim i As Long
    80.     Dim i2 As Long
    81.    
    82.     i = 0
    83.     i2 = 48
    84.     Do
    85.         Encode1(i) = i2
    86.         Decode2(i2) = i
    87.         i = i + 1
    88.         i2 = i2 + 1
    89.     Loop Until i2 = 58
    90.    
    91.     i2 = 65
    92.     Do
    93.         Encode1(i) = i2
    94.         Decode2(i2) = i
    95.         i = i + 1
    96.         i2 = i2 + 1
    97.     Loop Until i2 = 93
    98.    
    99.     i2 = 97
    100.     Do
    101.         Encode1(i) = i2
    102.         Decode2(i2) = i
    103.         i = i + 1
    104.         i2 = i2 + 1
    105.     Loop Until i2 = 123
    106. End Sub
    Alphanos

  19. #19

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    Originally posted by Alphanos
    I wrote one up, and its decent, but it doesn't even come close to the kind of times you're getting. I'm interested in how you're doing it, because on mine the decode is a LOT faster than the encode.
    In ours (I say that because myself and a friend worked on this for two weeks) we use what I call direct Base64/Base265 conversion for a big-time speed increase. It took an hour at the white-board to figure this method out. See code below...

    ENCODE

    VB Code:
    1. Public Function Encode(strToEncode As String, Optional srcIsFile As Boolean, Optional writeFile As Boolean, Optional outFileName) As String
    2. Dim a As Long, b As Integer, c As Byte, d As Byte, decVal As Byte, z As Long, y As Long 'counters
    3. Dim fso, ff As Integer, newFileName As String 'file vars
    4. Dim padCount As Byte 'determines count of equal signs at the end of file
    5. Dim charInput() As Byte 'holds input data
    6. Dim mimeArray(111111) As Byte 'holds the mime equiv from index(binary) to value(ascii)
    7. Dim addArray(11) As Long 'holds values from 100000 - 1 in binary
    8. Dim dblConvArray(255, 2, 3) As Double 'holds every character and the possible positions 1,2,3
    9. Dim charOutput() As Byte 'final output
    10. 'We have to make sure people use common sense!
    11.     If Not Len(strToEncode) > 0 Then Exit Function
    12.     If srcIsFile = False And writeFile And IsMissing(outFileName) Then
    13.         Err.Raise 10001, "Encoder DLL - Encode", "You must include the output file name when the source is not a file!"
    14.         Exit Function
    15.     End If
    16.     If srcIsFile Then
    17.         Set fso = CreateObject("Scripting.FileSystemObject")
    18.         If Not fso.FileExists(strToEncode) Then
    19.             Err.Raise 10002, "Encoder.DLL - Encode", "The path specified is invalid!"
    20.             Exit Function
    21.         End If
    22.     End If
    23. 'Make the mime array
    24.     mimeArray(0) = 65: mimeArray(1) = 66: mimeArray(10) = 67:
    25.     mimeArray(11) = 68: mimeArray(100) = 69: mimeArray(101) = 70:
    26.     mimeArray(110) = 71: mimeArray(111) = 72: mimeArray(1000) = 73:
    27.     mimeArray(1001) = 74: mimeArray(1010) = 75: mimeArray(1011) = 76:
    28.     mimeArray(1100) = 77: mimeArray(1101) = 78: mimeArray(1110) = 79:
    29.     mimeArray(1111) = 80: mimeArray(10000) = 81: mimeArray(10001) = 82:
    30.     mimeArray(10010) = 83: mimeArray(10011) = 84: mimeArray(10100) = 85:
    31.     mimeArray(10101) = 86: mimeArray(10110) = 87: mimeArray(10111) = 88:
    32.     mimeArray(11000) = 89: mimeArray(11001) = 90: mimeArray(11010) = 97:
    33.     mimeArray(11011) = 98: mimeArray(11100) = 99: mimeArray(11101) = 100:
    34.     mimeArray(11110) = 101: mimeArray(11111) = 102: mimeArray(100000) = 103:
    35.     mimeArray(100001) = 104: mimeArray(100010) = 105: mimeArray(100011) = 106:
    36.     mimeArray(100100) = 107: mimeArray(100101) = 108: mimeArray(100110) = 109:
    37.     mimeArray(100111) = 110: mimeArray(101000) = 111: mimeArray(101001) = 112:
    38.     mimeArray(101010) = 113: mimeArray(101011) = 114: mimeArray(101100) = 115:
    39.     mimeArray(101101) = 116: mimeArray(101110) = 117: mimeArray(101111) = 118:
    40.     mimeArray(110000) = 119: mimeArray(110001) = 120: mimeArray(110010) = 121:
    41.     mimeArray(110011) = 122: mimeArray(110100) = 48: mimeArray(110101) = 49:
    42.     mimeArray(110110) = 50: mimeArray(110111) = 51: mimeArray(111000) = 52:
    43.     mimeArray(111001) = 53: mimeArray(111010) = 54: mimeArray(111011) = 55:
    44.     mimeArray(111100) = 56: mimeArray(111101) = 57: mimeArray(111110) = 43:
    45.     mimeArray(111111) = 47:
    46. 'determine input type
    47.     If srcIsFile Then
    48. 'File Manipulation
    49.         ff = FreeFile
    50.         Open strToEncode For Binary As #ff
    51.         ReDim charInput(FileLen(strToEncode) - 1)
    52.         Get #ff, , charInput
    53.         Close #ff
    54.     Else
    55. 'Store the string into ascii/byte array
    56.         charInput = StrConv(strToEncode, vbFromUnicode)
    57.     End If
    58. 'build array to help build main array
    59.     addArray(0) = 100000: addArray(1) = 10000: addArray(2) = 1000: addArray(3) = 100: addArray(4) = 10: addArray(5) = 1
    60.     addArray(6) = 100000: addArray(7) = 10000: addArray(8) = 1000: addArray(9) = 100: addArray(10) = 10: addArray(11) = 1
    61. 'build array to to hold the possibilities of each character
    62.     For b = 0 To 255
    63.         decVal = b
    64.         For c = 0 To 2
    65.             For d = 0 To 7
    66.                 If (2 ^ (7 - d)) <= decVal Then
    67.                     If c = 0 And d < 6 Then dblConvArray(b, 0, 0) = dblConvArray(b, 0, 0) + addArray(d)
    68.                     If c = 0 And d > 5 Then dblConvArray(b, 0, 1) = dblConvArray(b, 0, 1) + addArray(d)
    69.                     If c = 1 And d < 4 Then dblConvArray(b, 1, 1) = dblConvArray(b, 1, 1) + addArray(d + 2)
    70.                     If c = 1 And d > 3 Then dblConvArray(b, 1, 2) = dblConvArray(b, 1, 2) + addArray(d + 2)
    71.                     If c = 2 And d < 2 Then dblConvArray(b, 2, 2) = dblConvArray(b, 2, 2) + addArray(d + 4)
    72.                     If c = 2 And d > 1 Then dblConvArray(b, 2, 3) = dblConvArray(b, 2, 3) + addArray(d + 4)
    73.                     decVal = decVal - (2 ^ (7 - d))
    74.                 End If
    75.             Next d
    76.             decVal = b
    77.         Next c
    78.     Next b
    79. 'destroy array
    80.     Erase addArray
    81. 'redim the output array to the calculated size
    82.     ReDim charOutput(((Int(UBound(charInput) / 3) * 4) + (UBound(charInput) Mod 3) + 1))
    83. 'now run a loop to check for line breaks and padding
    84.     If UBound(charOutput) + 1 > 72 Then
    85. 'resize the array to hold the total number of cr's and lf's
    86.         If ((UBound(charOutput) + 1) / 72) <> Int((UBound(charOutput) + 1) / 72) Then
    87.             ReDim Preserve charOutput((Int((UBound(charOutput) + 1) / 72) * 2) + UBound(charOutput))
    88.         Else
    89.             ReDim Preserve charOutput(((Int((UBound(charOutput) + 1) / 72) * 2) + UBound(charOutput)) - 2)
    90.         End If
    91. 're-pad the array
    92.         For z = 0 To padCount - 1
    93.             charOutput(UBound(charOutput) - z) = 61
    94.         Next z
    95.     Else
    96. 'the array isn't big enough to cr so just take care of padding
    97.         While (UBound(charOutput) + 1) / 4 <> Int((UBound(charOutput) + 1) / 4)
    98.             padCount = padCount + 1
    99.             ReDim Preserve charOutput(UBound(charOutput) + 1)
    100.             charOutput(UBound(charOutput)) = 61
    101.         Wend
    102.     End If
    103. 'clear y
    104.     y = 0
    105. 'start the main loop
    106.     For z = 0 To UBound(charInput) Step 3
    107. 'here we are actually inserting the cr and lf. We just accounted for them before. Padding was taken care of though
    108.         If z / 54 = Fix(z / 54) And z <> 0 Then
    109.             charOutput(y) = 13
    110.             charOutput(y + 1) = 10
    111.             y = y + 2
    112.         End If
    113. 'from here down...its greek...but basically we are adding the bits to get the 4 (6bit) chars from 3 (8bit) chars
    114.         charOutput(y) = mimeArray(dblConvArray(charInput(z), 0, 0))
    115.         If z + 1 > UBound(charInput) Then
    116.             charOutput(y + 1) = mimeArray(dblConvArray(charInput(z), 0, 1))
    117.             Exit For
    118.         End If
    119.         charOutput(y + 1) = mimeArray(dblConvArray(charInput(z), 0, 1) + dblConvArray(charInput(z + 1), 1, 1))
    120.         If z + 2 > UBound(charInput) Then
    121.             charOutput(y + 2) = mimeArray(dblConvArray(charInput(z + 1), 1, 2))
    122.             Exit For
    123.         End If
    124.         charOutput(y + 2) = mimeArray(dblConvArray(charInput(z + 1), 1, 2) + dblConvArray(charInput(z + 2), 2, 2))
    125.         charOutput(y + 3) = mimeArray(dblConvArray(charInput(z + 2), 2, 3))
    126.         y = y + 4
    127.     Next z
    128. 'destroy all arrays
    129.     Erase mimeArray
    130.     Erase dblConvArray
    131.     Erase charInput
    132. 'convert the byte array to string and return it
    133.     If writeFile Then
    134.         ff = FreeFile
    135.         If IsMissing(outFileName) Then
    136.             newFileName = strToEncode & ".encode"
    137.         Else
    138.             newFileName = outFileName
    139.         End If
    140.         Open newFileName For Output As #ff
    141.         Print #ff, "s"
    142.         Close #ff
    143.         Open newFileName For Binary As #ff
    144.         Put #ff, , charOutput
    145.         Close #ff
    146.     Else
    147. 'create a string for output
    148.         Encode = Left$(StrConv(charOutput, vbUnicode), UBound(charOutput) + 1)
    149.     End If
    150. 'destroy final array
    151.     Erase charOutput
    152. End Function
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  20. #20

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    DECODE

    VB Code:
    1. Public Function Decode(strToDecode As String, Optional srcIsFile As Boolean, Optional writeFile As Boolean, Optional outFileName) As String
    2. Dim a As Long, b As Long, z As Integer 'counter vars
    3. Dim fso, ff As Integer, newFileName As String, strClean As String 'file vars
    4. Dim charInput() As Byte 'holds input data as bytes
    5. Dim lngMimeArray(255) As Long 'holds the long equiv to mime chars
    6. Dim bConvArray(255, 3, 2) As Byte 'Array for conversion from 6bit binary to 8bit binary
    7. Dim charOutput() As Byte 'holds output characters after conversion
    8. 'We have to make sure people use common sense!
    9.     If srcIsFile = False And writeFile And IsMissing(outFileName) Then
    10.         Err.Raise 10001, "Encoder DLL - Decode", "You must include the output file name when the source is not a file!"
    11.         Exit Function
    12.     End If
    13.     If srcIsFile Then
    14.         Set fso = CreateObject("Scripting.FileSystemObject")
    15.         If Not fso.FileExists(strToDecode) Then
    16.             Err.Raise 10002, "Encoder.DLL - Decode", "The path specified is invalid!"
    17.             Exit Function
    18.         End If
    19.     End If
    20. 'determine input type
    21.     If srcIsFile Then
    22.         ff = FreeFile
    23.         Open strToDecode For Binary As #ff
    24.         ReDim Preserve charInput(FileLen(strToDecode) - 1)
    25.         Get #ff, , charInput
    26.         Close #ff
    27. 'revert this to a string for cleaning
    28.         strClean = Left$(StrConv(charInput, vbUnicode), UBound(charInput) + 1)
    29. 'destroy the array
    30.         Erase charInput
    31. 'clean the special chars
    32.         strClean = Replace(strClean, Chr(13), "")
    33.         strClean = Replace(strClean, Chr(10), "")
    34.         strClean = Replace(strClean, Chr(61), "")
    35. 'revert back to an array
    36.         charInput = StrConv(strClean, vbFromUnicode)
    37.     Else
    38.         strToDecode = Replace(strToDecode, Chr(13), "")
    39.         strToDecode = Replace(strToDecode, Chr(10), "")
    40.         strToDecode = Replace(strToDecode, Chr(61), "")
    41.         charInput = StrConv(strToDecode, vbFromUnicode)
    42.     End If
    43. 'build the mime array, byte to long conversion
    44.     lngMimeArray(65) = 0: lngMimeArray(66) = 1: lngMimeArray(67) = 10: lngMimeArray(68) = 11
    45.     lngMimeArray(69) = 100: lngMimeArray(70) = 101: lngMimeArray(71) = 110: lngMimeArray(72) = 111
    46.     lngMimeArray(73) = 1000: lngMimeArray(74) = 1001: lngMimeArray(75) = 1010: lngMimeArray(76) = 1011
    47.     lngMimeArray(77) = 1100: lngMimeArray(78) = 1101: lngMimeArray(80) = 1111: lngMimeArray(81) = 10000
    48.     lngMimeArray(82) = 10001: lngMimeArray(83) = 10010: lngMimeArray(84) = 10011: lngMimeArray(85) = 10100
    49.     lngMimeArray(86) = 10101: lngMimeArray(87) = 10110: lngMimeArray(88) = 10111: lngMimeArray(89) = 11000
    50.     lngMimeArray(90) = 11001: lngMimeArray(97) = 11010: lngMimeArray(98) = 11011: lngMimeArray(99) = 11100
    51.     lngMimeArray(100) = 11101: lngMimeArray(101) = 11110: lngMimeArray(102) = 11111: lngMimeArray(103) = 100000
    52.     lngMimeArray(104) = 100001: lngMimeArray(105) = 100010: lngMimeArray(106) = 100011: lngMimeArray(107) = 100100
    53.     lngMimeArray(108) = 100101: lngMimeArray(109) = 100110: lngMimeArray(110) = 100111: lngMimeArray(111) = 101000
    54.     lngMimeArray(112) = 101001: lngMimeArray(113) = 101010: lngMimeArray(114) = 101011: lngMimeArray(115) = 101100
    55.     lngMimeArray(116) = 101101: lngMimeArray(117) = 101110: lngMimeArray(118) = 101111: lngMimeArray(119) = 110000
    56.     lngMimeArray(120) = 110001: lngMimeArray(121) = 110010: lngMimeArray(122) = 110011: lngMimeArray(48) = 110100
    57.     lngMimeArray(49) = 110101: lngMimeArray(50) = 110110: lngMimeArray(51) = 110111: lngMimeArray(52) = 111000
    58.     lngMimeArray(53) = 111001: lngMimeArray(54) = 111010: lngMimeArray(55) = 111011: lngMimeArray(56) = 111100
    59.     lngMimeArray(57) = 111101: lngMimeArray(43) = 111110: lngMimeArray(47) = 111111: lngMimeArray(79) = 1110
    60. 'build the byte conversion array
    61.     For z = 0 To 255
    62.         bConvArray(z, 0, 0) = getcharVal(lngMimeArray(z) * 100)
    63.         bConvArray(z, 1, 0) = getcharVal(Int(lngMimeArray(z) / 10000))
    64.         bConvArray(z, 1, 1) = getcharVal((lngMimeArray(z) Mod 10000) * 10000)
    65.         bConvArray(z, 2, 1) = getcharVal(Int(lngMimeArray(z) / 100))
    66.         bConvArray(z, 2, 2) = getcharVal((lngMimeArray(z) Mod 100) * 1000000)
    67.         bConvArray(z, 3, 2) = getcharVal(lngMimeArray(z))
    68.     Next z
    69. 'Destroy the mime array
    70.     Erase lngMimeArray
    71. 'redim the output array to the calculated size
    72.     ReDim charOutput(Int(UBound(charInput) / 4) * 3)
    73. 'add space for padding
    74.     If Int(((UBound(charInput) / 4) - Int(UBound(charInput) / 4)) * 10) = 5 Then ReDim charOutput(UBound(charOutput) + 1)
    75.     If Int(((UBound(charInput) / 4) - Int(UBound(charInput) / 4)) * 10) = 7 Then ReDim charOutput(UBound(charOutput) + 2)
    76. 'Start the main loop of conversion
    77.     For a = 0 To UBound(charInput) Step 4
    78.         b = (a / 4) * 3
    79.         If a = UBound(charInput) Then
    80. 'last character
    81.             charOutput(b) = bConvArray(charInput(a), 0, 0)
    82.             Exit For
    83.         End If
    84. 'first in series of 3
    85.         charOutput(b) = bConvArray(charInput(a), 0, 0) + bConvArray(charInput(a + 1), 1, 0)
    86.         If a + 2 > UBound(charInput) Then
    87.             If Not b + 1 > UBound(charOutput) Then
    88. 'if there is no third one write the second
    89.                 charOutput(b + 1) = bConvArray(charInput(a + 1), 1, 1)
    90.             End If
    91.         Else
    92. 'otherwise use the second and third to make the second
    93.             charOutput(b + 1) = bConvArray(charInput(a + 1), 1, 1) + bConvArray(charInput(a + 2), 2, 1)
    94.         End If
    95.         If a + 3 > UBound(charInput) Then
    96.             If Not b + 2 > UBound(charOutput) Then
    97.                 charOutput(b + 2) = bConvArray(charInput(a + 2), 2, 2)
    98.             End If
    99.         Else
    100.             charOutput(b + 2) = bConvArray(charInput(a + 2), 2, 2) + bConvArray(charInput(a + 3), 3, 2)
    101.         End If
    102.     Next a
    103. 'destroy input array
    104.     Erase charInput
    105.     Erase bConvArray
    106. 'determine output type
    107.     If writeFile Then
    108.         ff = FreeFile
    109.         If IsMissing(outFileName) Then
    110.             newFileName = strToDecode & ".decode"
    111.         Else
    112.             newFileName = outFileName
    113.         End If
    114.         Open newFileName For Output As #ff
    115.         Print #ff, "s"
    116.         Close #ff
    117.         Open newFileName For Binary As #ff
    118.         Put #ff, , charOutput
    119.         Close #ff
    120.     Else
    121.         Decode = Left$(StrConv(charOutput, vbUnicode), UBound(charOutput) + 1)
    122.     End If
    123.     Erase charOutput
    124. End Function
    125. Private Function getcharVal(ByVal tmpLng As Long) As Byte
    126. Dim char As Byte
    127. 'this returns the ascii value from binary
    128.     If tmpLng > 9999999 Then tmpLng = tmpLng - 10000000: char = 128
    129.     If tmpLng > 999999 Then tmpLng = tmpLng - 1000000: char = char + 64
    130.     If tmpLng > 99999 Then tmpLng = tmpLng - 100000: char = char + 32
    131.     If tmpLng > 9999 Then tmpLng = tmpLng - 10000: char = char + 16
    132.     If tmpLng > 999 Then tmpLng = tmpLng - 1000: char = char + 8
    133.     If tmpLng > 99 Then tmpLng = tmpLng - 100: char = char + 4
    134.     If tmpLng > 9 Then tmpLng = tmpLng - 10: char = char + 2
    135.     If tmpLng > 0 Then char = char + 1
    136. 'return the value
    137.     getcharVal = char
    138. End Function

    If you see ways to make this faster, please let me know...
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  21. #21

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    bump
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  22. #22
    Hyperactive Member
    Join Date
    Dec 2001
    Location
    I'm in front of the computer.
    Posts
    270
    I tried reading it, but I need to read it again some other time when my brain is working better.
    Alphanos

  23. #23

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    thanks
    Last edited by Rikk; Dec 16th, 2001 at 01:01 PM.
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  24. #24

    Thread Starter
    Addicted Member Rikk's Avatar
    Join Date
    Nov 2001
    Location
    Atlanta
    Posts
    131
    bump
    Rikk =\=
    Starcraft, Protoss Scout Driver!

  25. #25
    Frenzied Member David.Poundall's Avatar
    Join Date
    Sep 2002
    Location
    Robin Hood Land
    Posts
    1,457

    Re: Mime (Base64) Speed Challenge

    This code needs to go in the codebank somewhere. It is blindingly fast and you need something like this for encoding and decoding E-mail attachments.
    David

    Learn the Rules so that you know how to break them properly.

    Printing dll dBTools MZTools Winsock API WinsockVB More Winsock SGrid2 MSChart Mail2Web

    If you have found this thread useful then read this

  26. #26
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Mime (Base64) Speed Challenge

    Too bad they never actually released the code; just saying your code is fast and showing some results doesn't tell a whole lot. Atleast I didn't see the code being submitted anywhere.

    Anyways, I might be able to do a late challenge, just not sure if I bother. Are there more than one person here who needs a fast Base64?

  27. #27
    Frenzied Member David.Poundall's Avatar
    Join Date
    Sep 2002
    Location
    Robin Hood Land
    Posts
    1,457

    Re: Mime (Base64) Speed Challenge

    Yes they did - threads 19 and 20.
    David

    Learn the Rules so that you know how to break them properly.

    Printing dll dBTools MZTools Winsock API WinsockVB More Winsock SGrid2 MSChart Mail2Web

    If you have found this thread useful then read this

  28. #28
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Mime (Base64) Speed Challenge

    Ah, missread the nick there. Humm... it does look like it could be beaten.

  29. #29
    Addicted Member
    Join Date
    Mar 2005
    Posts
    158

    Re: Mime (Base64) Speed Challenge

    this is a nice tutorial about base64 conversion
    http://www.cpp-home.com/tutorial.php?102_1
    if u felt my post make u happy ,
    then u could make me happy too by rating my post

  30. #30
    Member
    Join Date
    Oct 2005
    Posts
    48

    Re: Mime (Base64) Speed Challenge

    a question ,i write a code program to encrypt/decrypt ,i want to save files in Base64(more small size) ,but the Rikk code is for strings. How i have to modify to also send bytes??

    dim buffer() as byte ,FileO as integer,key as string
    FileO = FreeFile
    Buffer() = EncryptArray(Which, Buffer(), Key)
    Open OutFile For Binary As #FileO
    Put #FileO, , Encode(Buffer) ????????
    End If
    Close #FileO

    And what to decode???

    Thanks for your help

  31. #31
    Fanatic Member Comintern's Avatar
    Join Date
    Nov 2004
    Location
    Lincoln, NE
    Posts
    826

    Re: Mime (Base64) Speed Challenge

    Hey, thanks for resurrecting this thread! I decided to see if I could do better than Rikk's code expecting to come close, but I ended up smoking it . I used a simple bit-masking and bit-shifting to calculate individual characters in both the encode and decode functions, with a couple of lookup tables (mainly for avoiding repeated multiplications). At first, I tried manipulating the strings with the CopyMemory API, but it turned out that indexing into a byte array was a lot faster so I ended up going with that. My functions only take strings as inputs, so in the interest of fairness I commented out all of Rikk's code that dealt with the file functions (saves a couple of If tests). For testing, I used an input of a 1,000,000 character randomly generated string. This is the test code:
    VB Code:
    1. Private Sub SpeedCompare()
    2.  
    3.     Dim lStart As Long, lEnd As Long, lTotal As Long, sTemp As String, sDoc As String, iCount As Integer
    4.  
    5.     sDoc = TestString(1000000)  'Generate a random 1000000 char string.
    6.    
    7.     For iCount = 1 To 10
    8.         lStart = GetTickCount
    9.         sTemp = MyEncode(sDoc)
    10.         lEnd = GetTickCount
    11.         lTotal = lTotal + (lEnd - lStart)
    12.     Next iCount
    13.     Debug.Print ("My Average Encode: " & lTotal / 10000 & " seconds.")
    14.    
    15.     For iCount = 1 To 10
    16.         lStart = GetTickCount
    17.         sDoc = MyDecode(sTemp)
    18.         lEnd = GetTickCount
    19.         lTotal = lTotal + (lEnd - lStart)
    20.     Next iCount
    21.     Debug.Print ("My Average Decode: " & lTotal / 10000 & " seconds.")
    22.    
    23.     For iCount = 1 To 10
    24.         lStart = GetTickCount
    25.         sTemp = Encode(sDoc)
    26.         lEnd = GetTickCount
    27.         lTotal = lTotal + (lEnd - lStart)
    28.     Next iCount
    29.     Debug.Print ("His Average Encode: " & lTotal / 10000 & " seconds.")
    30.    
    31.     For iCount = 1 To 10
    32.         lStart = GetTickCount
    33.         sDoc = Decode(sTemp)
    34.         lEnd = GetTickCount
    35.         lTotal = lTotal + (lEnd - lStart)
    36.     Next iCount
    37.     Debug.Print ("His Average Decode: " & lTotal / 10000 & " seconds.")
    38.    
    39. End Sub
    40.  
    41. Private Function TestString(lLen As Long) As String
    42.  
    43.     Dim lCount As Long, bOut() As Byte
    44.    
    45.     Randomize
    46.     ReDim bOut(lLen - 1)
    47.     For lCount = 0 To UBound(bOut)
    48.         bOut(lCount) = Int(Rnd * 255)
    49.     Next lCount
    50.    
    51.     TestString = StrConv(bOut, vbUnicode)
    52.  
    53. End Function
    And here are my encode and decode functions (a little easier to read I might add):
    VB Code:
    1. Option Explicit
    2.  
    3. Private Const clOneMask = 16515072          '000000 111111 111111 111111
    4. Private Const clTwoMask = 258048            '111111 000000 111111 111111
    5. Private Const clThreeMask = 4032            '111111 111111 000000 111111
    6. Private Const clFourMask = 63               '111111 111111 111111 000000
    7.  
    8. Private Const clHighMask = 16711680         '11111111 00000000 00000000
    9. Private Const clMidMask = 65280             '00000000 11111111 00000000
    10. Private Const clLowMask = 255               '00000000 00000000 11111111
    11.  
    12. Private Const cl2Exp18 = 262144             '2 to the 18th power
    13. Private Const cl2Exp12 = 4096               '2 to the 12th
    14. Private Const cl2Exp6 = 64                  '2 to the 6th
    15. Private Const cl2Exp8 = 256                 '2 to the 8th
    16. Private Const cl2Exp16 = 65536              '2 to the 16th
    17.  
    18. Public Function MyEncode(sString As String) As String
    19.  
    20.     Dim bTrans(63) As Byte, lPowers8(255) As Long, lPowers16(255) As Long, bOut() As Byte, bIn() As Byte
    21.     Dim lChar As Long, lTrip As Long, iPad As Integer, lLen As Long, lTemp As Long, lPos As Long
    22.    
    23.     For lTemp = 0 To 63                     'Fill the translation table.
    24.         Select Case lTemp
    25.             Case 0 To 25
    26.                 bTrans(lTemp) = 65 + lTemp  'A - Z
    27.             Case 26 To 51
    28.                 bTrans(lTemp) = 71 + lTemp  'a - z
    29.             Case 52 To 61
    30.                 bTrans(lTemp) = lTemp - 4   '1 - 0
    31.             Case 62
    32.                 bTrans(lTemp) = 43          'Chr(43) = "+"
    33.             Case 63
    34.                 bTrans(lTemp) = 47          'Chr(47) = "/"
    35.         End Select
    36.     Next lTemp
    37.  
    38.     For lTemp = 0 To 255                    'Fill the 2^8 and 2^16 lookup tables.
    39.         lPowers8(lTemp) = lTemp * cl2Exp8
    40.         lPowers16(lTemp) = lTemp * cl2Exp16
    41.     Next lTemp
    42.  
    43.     iPad = Len(sString) Mod 3               'See if the length is divisible by 3
    44.     If iPad Then                            'If not, figure out the end pad and resize the input.
    45.         iPad = 3 - iPad
    46.         sString = sString & String(iPad, Chr(0))
    47.     End If
    48.    
    49.     bIn = StrConv(sString, vbFromUnicode)   'Load the input string.
    50.     lLen = ((UBound(bIn) + 1) / 3) * 4      'Length of resulting string.
    51.     lTemp = lLen \ 72                       'Added space for vbCrLfs.
    52.     ReDim bOut(((lTemp * 2) + lLen) - 1)    'Make the output buffer.
    53.    
    54.     lLen = 0                                'Reusing this one, so reset it.
    55.    
    56.     For lChar = LBound(bIn) To UBound(bIn) Step 3
    57.         lTrip = lPowers16(bIn(lChar)) + lPowers8(bIn(lChar + 1)) + bIn(lChar + 2)    'Combine the 3 bytes
    58.         lTemp = lTrip And clOneMask                 'Mask for the first 6 bits
    59.         bOut(lPos) = bTrans(lTemp \ cl2Exp18)       'Shift it down to the low 6 bits and get the value
    60.         lTemp = lTrip And clTwoMask                 'Mask for the second set.
    61.         bOut(lPos + 1) = bTrans(lTemp \ cl2Exp12)   'Shift it down and translate.
    62.         lTemp = lTrip And clThreeMask               'Mask for the third set.
    63.         bOut(lPos + 2) = bTrans(lTemp \ cl2Exp6)    'Shift it down and translate.
    64.         bOut(lPos + 3) = bTrans(lTrip And clFourMask) 'Mask for the low set.
    65.         If lLen = 68 Then                           'Ready for a newline
    66.             bOut(lPos + 4) = 13                     'Chr(13) = vbCr
    67.             bOut(lPos + 5) = 10                     'Chr(10) = vbLf
    68.             lLen = 0                                'Reset the counter
    69.             lPos = lPos + 6
    70.         Else
    71.             lLen = lLen + 4
    72.             lPos = lPos + 4
    73.         End If
    74.     Next lChar
    75.    
    76.     If iPad = 1 Then                                'Add the padding chars if any.
    77.         bOut(UBound(bOut)) = 61                     'Chr(61) = "="
    78.     ElseIf iPad = 2 Then
    79.         bOut(UBound(bOut)) = 61
    80.         bOut(UBound(bOut) - 1) = 61
    81.     End If
    82.    
    83.     MyEncode = StrConv(bOut, vbUnicode)             'Convert back to a string and return it.
    84.    
    85. End Function
    86.  
    87. Public Function MyDecode(sString As String) As String
    88.  
    89.     Dim bOut() As Byte, bIn() As Byte, bTrans(255) As Byte, lPowers6(63) As Long, lPowers12(63) As Long
    90.     Dim lPowers18(63) As Long, lQuad As Long, iPad As Integer, lChar As Long, lPos As Long, sOut As String
    91.     Dim lTemp As Long
    92.  
    93.     sString = Replace(sString, vbCr, vbNullString)      'Get rid of the vbCrLfs.  These could be in...
    94.     sString = Replace(sString, vbLf, vbNullString)      'either order.
    95.  
    96.     lTemp = Len(sString) Mod 4              'Test for valid input.
    97.     If lTemp Then
    98.         Call Err.Raise(vbObjectError, "MyDecode", "Input string is not valid Base64.")
    99.     End If
    100.    
    101.     If InStrRev(sString, "==") Then         'InStrRev is faster when you know its at the end.
    102.         iPad = 2                            'Note:  These translate to 0, so you can leave them...
    103.     ElseIf InStrRev(sString, "=") Then      'in the string and just resize the output.
    104.         iPad = 1
    105.     End If
    106.      
    107.     For lTemp = 0 To 255                    'Fill the translation table.
    108.         Select Case lTemp
    109.             Case 65 To 90
    110.                 bTrans(lTemp) = lTemp - 65  'A - Z
    111.             Case 97 To 122
    112.                 bTrans(lTemp) = lTemp - 71  'a - z
    113.             Case 48 To 57
    114.                 bTrans(lTemp) = lTemp + 4   '1 - 0
    115.             Case 43
    116.                 bTrans(lTemp) = 62          'Chr(43) = "+"
    117.             Case 47
    118.                 bTrans(lTemp) = 63          'Chr(47) = "/"
    119.         End Select
    120.     Next lTemp
    121.  
    122.     For lTemp = 0 To 63                     'Fill the 2^6, 2^12, and 2^18 lookup tables.
    123.         lPowers6(lTemp) = lTemp * cl2Exp6
    124.         lPowers12(lTemp) = lTemp * cl2Exp12
    125.         lPowers18(lTemp) = lTemp * cl2Exp18
    126.     Next lTemp
    127.  
    128.     bIn = StrConv(sString, vbFromUnicode)           'Load the input byte array.
    129.     ReDim bOut((((UBound(bIn) + 1) \ 4) * 3) - 1)   'Prepare the output buffer.
    130.    
    131.     For lChar = 0 To UBound(bIn) Step 4
    132.         lQuad = lPowers18(bTrans(bIn(lChar))) + lPowers12(bTrans(bIn(lChar + 1))) + _
    133.                 lPowers6(bTrans(bIn(lChar + 2))) + bTrans(bIn(lChar + 3))           'Rebuild the bits.
    134.         lTemp = lQuad And clHighMask                'Mask for the first byte
    135.         bOut(lPos) = lTemp \ cl2Exp16               'Shift it down
    136.         lTemp = lQuad And clMidMask                 'Mask for the second byte
    137.         bOut(lPos + 1) = lTemp \ cl2Exp8            'Shift it down
    138.         bOut(lPos + 2) = lQuad And clLowMask        'Mask for the third byte
    139.         lPos = lPos + 3
    140.     Next lChar
    141.  
    142.     sOut = StrConv(bOut, vbUnicode)                     'Convert back to a string.
    143.     If iPad Then sOut = Left$(sOut, Len(sOut) - iPad)   'Chop off any extra bytes.
    144.     MyDecode = sOut
    145.  
    146. End Function
    Finally, the results on my machine. Sometimes the simpler solutions are better.
    Code:
    My Average Encode: 0.4422 seconds.
    My Average Decode: 0.9156 seconds.
    His Average Encode: 1.6359 seconds.
    His Average Decode: 2.3 seconds.
    Anyone else want to take a stab?

  32. #32
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Mime (Base64) Speed Challenge

    See this thread for a tip on how to avoid using StrConv and see how to use a Integer array instead (which is faster to access and you don't need StrConv at all). Though you'd still have to figure out how to reserve space quickly for the output string, but that's why there are VBspeed solutions for that.

    I don't have the time to do a faster code myself. Mathwise I don't see many problems in your code, though I'd replace this:

    VB Code:
    1. lLen = ((UBound(bIn) + 1) / 3) * 4
    with this:
    VB Code:
    1. lLen = ((UBound(bIn) + 1) * 4) \ 3

  33. #33
    Fanatic Member Comintern's Avatar
    Join Date
    Nov 2004
    Location
    Lincoln, NE
    Posts
    826

    Re: Mime (Base64) Speed Challenge

    Quote Originally Posted by Merri
    See this thread for a tip on how to avoid using StrConv and see how to use a Integer array instead (which is faster to access and you don't need StrConv at all). Though you'd still have to figure out how to reserve space quickly for the output string, but that's why there are VBspeed solutions for that.
    Very interesting thread. It never really occured to me to use an integer instead of a byte to represent Unicode, even though it seems so obvious now that you mention it .

    Quote Originally Posted by Merri
    I don't have the time to do a faster code myself. Mathwise I don't see many problems in your code, though I'd replace this:

    VB Code:
    1. lLen = ((UBound(bIn) + 1) / 3) * 4
    with this:
    VB Code:
    1. lLen = ((UBound(bIn) + 1) * 4) \ 3
    Nice catch. I'll chalk this one up to a typo on my part -- I thought I'd used all intdivides. One thing that surprised me was how fast the intdivides by powers of 2 process. I'd be curious to find out how those instructions get compiled, because I'd always assumed that any divide instruction was expensive, float or not. I know that bit shifts are blindingly fast by comparison. Might have to compile it and look at the resulting assembly. BTW, I did the divide before the multiply to minimize the chance of overflowing the long. Is there a performance issue in the order of the multiply and divide operations?

    One other area that I see room for improvement in is the 2 Replace() calls at the start of the decode function, but I have no clue how to get around that. As far as a performance breakdown in comparision to Rikk's code, I think the main things I cut out were the conditional tests and repeated calls to UBound inside the en/decoding loops. I'm not sure if the size of the lookup arrays are relevent, but I always tend to think that the more compact the table the better.

  34. #34
    VB6, XHTML & CSS hobbyist Merri's Avatar
    Join Date
    Oct 2002
    Location
    Finland
    Posts
    6,654

    Re: Mime (Base64) Speed Challenge

    Humm... I didn't take a careful look. I'd remove InStrRev (it is awfully slow) and Replace completely. Just skip the line changes. It might be wise to check if there are any line changes (using InStr) so the code could determine a mode to work in.

    The current maximum file size that it can handle is 512 MB thanks to the * 4 \ 3 line, so it should be enough for about any use. I'm pretty sure nobody does a Base64 encoding/decoding for a file bigger than that.

    Afaik \ is not a real divider, but I've already forgotten how it was supposed to work. Anyways, the main advantage with \ is that it doesn't require a coercion in memory: if you do a floating point division (and floating point is much slower than integer), you also make a behind-the-scenes datatype coercion (as this is VB we're talking about).

    The tables could be an array defined outside the function and it could be made only once; then just store a static boolean value to know if it has been filled or not.

    As for encoding, I'd swap If lLen = 68 Then to If lLen <> 68 Then because the first If occurs first and doing Else is slower. At the moment the Else gets called far more often. Humm, there is also String used to add empty stuff at the end. A big no-no, I'm sure it could be done using another faster method. All string based handling is slow, so we really want to get rid of all string handling besides the quick and efficient string allocation (for which one can find code at VBspeed I linked). InStr might be the only "worthwhile to use" string function thanks to its good speed with one and two character keywords.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width