BASE91 - Fast Base-91 Encoder/Decoder Functions - Dav - 12-29-2025
BASE91.BAS contains fast Base-91 Encoding/Decoding functions you can use to convert binary files to text. This updated version is greatly improved over the previous one I shared at the forum a while back, the speed increase being really huge, now encodes over 43,800 percent faster. A 1MB file takes only .2 seconds to encode now (not 96 seconds as before). Description and more info are in the code comments for you to read more about what this does.
NOTE: This does not produce standard Base-91 encoded text as it uses an custom 91-Character set - one that outputs text that should be OK to put in code here at the forum (I replaced the @ symbol and a couple others that may be a problem with forum posts).
- Dav
Code: (Select All)
'==========
'BASE91.BAS v1.1
'==========
'Base-91 Encoder/Decoder Functions.
'Coded by Dav for QB64-PE, DEC/2025
'New for v1.1 - HUGE increase in encoding/decoding speed!
' Previous version took 96.8 secs to encode 1MB,
' This one takes only .2 sec - a 43,800% increase.
'Like Base-64/Base-85 encoding, Base-91 is a way of encoding binary
'data to viewable text so it can be included in messages or code.
'It can later be decoded back into the original binary data safely.
'Base-91 encoding is more efficient than Base-64, producing smaller
'encoded output as the demo program here will show.
'First part of demo: compare Base-64 & Base-91 output size.
'We will encode/decode in both Base-64 and base-91 to compare them.
'The Base-64 results in about a 33% size increase, Base-91 is only
'14% increase. The downside to using these Base-91 functions over
'QB64-PE's built in_Base64Encode/Decode functions are in the speed.
'Base-91 is a little slower, but not that much - a 1MB file can be
'encoded/decoded in .2 sec on my T470s Thinkpad - almost instantly.
'The Base-64 functions in QB64-PE do work instantly (0 seconds).
'Second part of demo: Ensure Base-91 encode/decode safely.
'We will enter a loop of testing encode/decoding random data to
'ensure Base-91 functions are encode/decoding data safely. Press
'the ESC key to stop the loop of data testing. If data errors are
'found, the loop will stop automatically.
'NOTE: This is using a modified Base-91 character set so the output
'won't include symbols that may conflict with QB64-PE forum posting.
'==================================================================
Screen 12: _FullScreen
_ControlChr Off
Color 15, 1
Print "Making 1MB test data to use."
a$ = String$(1000000, 0)
Print "Original byte size ="; Len(a$)
Color 7, 0
Print
t1 = Timer
e$ = _Base64Encode$(a$)
Print "Base-64 Encoded in"; Timer - t1; "secs, bytes ="; Len(e$)
t1 = Timer
d$ = _Base64Decode$(e$)
Print "Base-64 Decoded in"; Timer - t1; "secs, bytes ="; Len(d$)
If Len(a$) = Len(d$) Then
Print "Original and Base-64 decoded sizes match!"
Else
Print "Original and Base-64 decoded sizes DO NOT match."
End If
If a$ = d$ Then
Print "Original and Base-64 decoded data match!"
Else
Print "Original and Base-64 decoded data DO NOT match."
End If
Print "Size increase:"; Int((Len(e$) - Len(a$)) / Len(a$) * 100); "%"
Print
t1 = Timer
e$ = Base91Encode$(a$)
Print "Base-91 Encoded in"; Timer - t1; "secs, bytes ="; Len(e$)
t1 = Timer
d$ = Base91Decode$(e$)
Print "Base-91 Decoded in"; Timer - t1; "secs, bytes ="; Len(d$)
If Len(a$) = Len(d$) Then
Print "Original and Base-91 decoded sizes match!"
Else
Print "Original and Base-91 decoded sizes DO NOT match."
End If
If a$ = d$ Then
Print "Original and Base-91 decoded data match!"
Else
Print "Original and Base-91 decoded data DO NOT match."
End If
Print "Size increase:"; Int((Len(e$) - Len(a$)) / Len(a$) * 100); "%"
Print
Print "PRESS ANY KEY TO GO TO NEXT TEST..."
Sleep
Do
Cls
Color 15, 1: Print "Checking bytes loop -- Hit ESC key to stop checking ..."
a$ = ""
Print
Color 7, 0: Print "Original:"
bytes = 200 + Int(Rnd * 55)
For i = 0 To bytes
a$ = a$ + Chr$(Int(Rnd * 255))
Next
Print a$
Print Len(a$); "bytes"
Print
Print "Encoded:"
a2$ = Base91Encode$(a$): Print a2$
Print Len(a2$); "bytes"
Print
Print "Decoded:"
a3$ = Base91Decode$(a2$): Print a3$
Print Len(a3$); "bytes"
Print
If Len(a$) <> Len(a3$) Then Color 12, 0: Print "Size don't match!"; t: End
If a$ <> a3$ Then Color 12, 0: Print "Bytes don't match!"; t: End
_Display
_Limit 10
If _KeyHit = 27 Then Exit Do
loopcount = loopcount + 1
bytecount = bytecount + bytes
Loop
Print
Print "No data encoding/decoding errors detected!"
Function Base91Encode$ (in$)
'Build 91 characters to use
For i = 33 To 126
If i <> 34 And i <> 64 And i <> 96 Then Chars$ = Chars$ + Chr$(i)
Next
out$ = Space$(Int(Len(in$) * 1.3)): opos = 0
nbits = 0
For i& = 1 To Len(in$)
bits = bits Or (_ShL(Asc(Mid$(in$, i&, 1)), nbits))
nbits = nbits + 8
If nbits > 13 Then
value = bits Mod 8192
If value > 88 Then
bits = (bits \ 8192)
nbits = nbits - 13
Else
value = bits Mod 16384
bits = (bits \ 16384)
nbits = nbits - 14
End If
Mid$(out$, opos + 1, 2) = Mid$(Chars$, (value Mod 91) + 1, 1) + Mid$(Chars$, (value \ 91) + 1, 1)
opos = opos + 2
End If
Next
If nbits > 0 Then
Mid$(out$, opos + 1, 1) = Mid$(Chars$, (bits Mod 91) + 1, 1)
opos = opos + 1
If nbits > 7 Or bits > 90 Then
Mid$(out$, opos + 1, 1) = Mid$(Chars$, (bits \ 91) + 1, 1)
opos = opos + 1
End If
End If
Base91Encode$ = Mid$(out$, 1, opos)
End Function
Function Base91Decode$ (in$)
'Build 91 characters to use
For i = 33 To 126
If i <> 34 And i <> 64 And i <> 96 Then Chars$ = Chars$ + Chr$(i)
Next
out$ = Space$(Len(in$)): opos = 0
value = -1: nbits = 0
For i& = 1 To Len(in$)
ascii = InStr(Chars$, Mid$(in$, i&, 1)) - 1
If value < 0 Then
value = ascii
Else
value = value + (ascii * 91)
bits = bits Or _ShL(value, nbits)
nbits = nbits + 13 + (((value And 8191) <= 88) * -1)
Do Until (nbits > 7) = 0
Mid$(out$, opos + 1, 1) = Chr$(bits And 255)
opos = opos + 1
bits = _ShR(bits, 8)
nbits = nbits - 8
Loop
value = -1
End If
Next
If (value + 1) Then
Mid$(out$, opos + 1, 1) = Chr$((bits Or _ShL(value, nbits)) And 255)
opos = opos + 1
End If
Base91Decode$ = Mid$(out$, 1, opos)
End Function
RE: BASE91 - Fast Base-91 Encoder/Decoder Functions - Jack - 12-30-2025
hello Dav 
in Function Base91Encode you use nbits before it's assigned any value
same thing in Function Base91Decode
Code: (Select All)
For i& = 1 To Len(in$)
bits = bits Or (_ShL(Asc(Mid$(in$, i&, 1)), nbits))
RE: BASE91 - Fast Base-91 Encoder/Decoder Functions - Dav - 12-30-2025
(12-30-2025, 04:33 AM)Jack Wrote: hello Dav 
in Function Base91Encode you use nbits before it's assigned any value
same thing in Function Base91Decode
Code: (Select All)
For i& = 1 To Len(in$)
bits = bits Or (_ShL(Asc(Mid$(in$, i&, 1)), nbits))
I sure did. Thanks for catching that, i will take a closer look - i maybe have copied and pasted something wrong before posting this, iwas messing with several versions of the program before posting it. I will have to check this code in the morning, off my pc for the night (wife/warden clamped down on my programming time for the evening). Thanks, Jack!
- Dav
RE: BASE91 - Fast Base-91 Encoder/Decoder Functions - Dav - 12-30-2025
I checked it out, Jack. On my other versions I had nbits = 0 defined, but removed it when tidying up the code I guess. Good news is it didn't matter because nbits is worth zero when first being used, so the functions work. I will fix the code to assign nbits though, because it is proper coding.
Using OPTION _EXPLICIT would help my coding a lot I think, maybe a good New Years resolution for me is to start using it, would prevent a lot of mistakes I often make.
- Dav
|