Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
BASE91 - Fast Base-91 Encoder/Decoder Functions
#1
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

Find my programs here in Dav's QB64 Corner
Reply
#2
hello Dav  Smile
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))
Reply
#3
(12-30-2025, 04:33 AM)Jack Wrote: hello Dav  Smile
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

Find my programs here in Dav's QB64 Corner
Reply
#4
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

Find my programs here in Dav's QB64 Corner
Reply


Forum Jump:


Users browsing this thread: