' Base32 encoding (RFC 4648) with padding — encode binary data to base32 string
#COMPILE EXE
#DIM ALL

FUNCTION PBMAIN() AS LONG
    LOCAL i  AS LONG
    LOCAL j  AS LONG
    LOCAL buffer  AS LONG
    LOCAL bitsRemaining  AS LONG
    LOCAL dataLen  AS LONG
    LOCAL outLen  AS LONG
    LOCAL padLen  AS LONG
    LOCAL b  AS LONG
    LOCAL val  AS LONG
    LOCAL idx  AS LONG
    LOCAL byteVal  AS LONG
    LOCAL src(40) AS LONG
    LOCAL srcLen  AS LONG
    LOCAL outIdx  AS LONG
    LOCAL encoded AS STRING
    LOCAL alphabet AS STRING
    LOCAL testCase AS LONG
    LOCAL pow2(10) AS LONG

    pow2(0) = 1
    pow2(1) = 2
    pow2(2) = 4
    pow2(3) = 8
    pow2(4) = 16
    pow2(5) = 32
    pow2(6) = 64
    pow2(7) = 128
    pow2(8) = 256
    pow2(9) = 512
    pow2(10) = 1024

    alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"

    PRINT "=== Base32 Encoding (RFC 4648) ==="
    PRINT

    srcLen = 5
    src(0) = 102
    src(1) = 111
    src(2) = 111
    src(3) = 98
    src(4) = 97

    PRINT "Test 1: Encoding 'fooba' (5 bytes)"
    PRINT "Input bytes:"
    FOR i = 0 TO srcLen - 1
        PRINT "  " & FORMAT$(src(i))
    NEXT i
    PRINT

    encoded = ""
    i = 0
    WHILE i < srcLen
        buffer = src(i)
        bitsRemaining = 8
        i = i + 1

        WHILE bitsRemaining > 0
            IF bitsRemaining >= 5 THEN
                val = buffer / pow2(bitsRemaining - 5)
                val = val AND 31
                encoded = encoded + MID$(alphabet, val + 1, 1)
                bitsRemaining = bitsRemaining - 5
            ELSE
                val = buffer AND (pow2(bitsRemaining) - 1)
                IF i < srcLen THEN
                    val = val * pow2(5 - bitsRemaining)
                    val = val + (src(i) / pow2(8 - (5 - bitsRemaining)))
                    i = i + 1
                ELSE
                    val = val * pow2(5 - bitsRemaining)
                END IF
                val = val AND 31
                encoded = encoded + MID$(alphabet, val + 1, 1)
                bitsRemaining = 0
            END IF
        WEND
    WEND

    outLen = (srcLen + 4) / 5 * 8
    padLen = outLen - LEN(encoded)
    FOR i = 1 TO padLen
        encoded = encoded + "="
    NEXT i

    PRINT "Base32: " & encoded
    PRINT

    srcLen = 1
    src(0) = 102
    PRINT "Test 2: Single byte 'f'"
    PRINT "Input byte: " & FORMAT$(src(0))

    encoded = ""
    i = 0
    WHILE i < srcLen
        buffer = src(i)
        bitsRemaining = 8
        i = i + 1

        WHILE bitsRemaining > 0
            IF bitsRemaining >= 5 THEN
                val = buffer / pow2(bitsRemaining - 5)
                val = val AND 31
                encoded = encoded + MID$(alphabet, val + 1, 1)
                bitsRemaining = bitsRemaining - 5
            ELSE
                val = buffer AND (pow2(bitsRemaining) - 1)
                IF i < srcLen THEN
                    val = val * pow2(5 - bitsRemaining)
                    val = val + (src(i) / pow2(8 - (5 - bitsRemaining)))
                    i = i + 1
                ELSE
                    val = val * pow2(5 - bitsRemaining)
                END IF
                val = val AND 31
                encoded = encoded + MID$(alphabet, val + 1, 1)
                bitsRemaining = 0
            END IF
        WEND
    WEND

    outLen = (srcLen + 4) / 5 * 8
    padLen = outLen - LEN(encoded)
    FOR i = 1 TO padLen
        encoded = encoded + "="
    NEXT i

    PRINT "Base32: " & encoded
    PRINT

    srcLen = 3
    src(0) = 102
    src(1) = 111
    src(2) = 111
    PRINT "Test 3: Encoding 'foo' (3 bytes)"
    PRINT "Input bytes:"
    FOR i = 0 TO srcLen - 1
        PRINT "  " & FORMAT$(src(i))
    NEXT i
    PRINT

    encoded = ""
    i = 0
    WHILE i < srcLen
        buffer = src(i)
        bitsRemaining = 8
        i = i + 1

        WHILE bitsRemaining > 0
            IF bitsRemaining >= 5 THEN
                val = buffer / pow2(bitsRemaining - 5)
                val = val AND 31
                encoded = encoded + MID$(alphabet, val + 1, 1)
                bitsRemaining = bitsRemaining - 5
            ELSE
                val = buffer AND (pow2(bitsRemaining) - 1)
                IF i < srcLen THEN
                    val = val * pow2(5 - bitsRemaining)
                    val = val + (src(i) / pow2(8 - (5 - bitsRemaining)))
                    i = i + 1
                ELSE
                    val = val * pow2(5 - bitsRemaining)
                END IF
                val = val AND 31
                encoded = encoded + MID$(alphabet, val + 1, 1)
                bitsRemaining = 0
            END IF
        WEND
    WEND

    outLen = (srcLen + 4) / 5 * 8
    padLen = outLen - LEN(encoded)
    FOR i = 1 TO padLen
        encoded = encoded + "="
    NEXT i

    PRINT "Base32: " & encoded
    PRINT

    FOR testCase = 0 TO 4
        FOR i = 0 TO 4
            src(i) = testCase * 51 + i * 17
        NEXT i
        srcLen = 5

        encoded = ""
        i = 0
        WHILE i < srcLen
            buffer = src(i)
            bitsRemaining = 8
            i = i + 1

            WHILE bitsRemaining > 0
                IF bitsRemaining >= 5 THEN
                    val = buffer / pow2(bitsRemaining - 5)
                    val = val AND 31
                    encoded = encoded + MID$(alphabet, val + 1, 1)
                    bitsRemaining = bitsRemaining - 5
                ELSE
                    val = buffer AND (pow2(bitsRemaining) - 1)
                    IF i < srcLen THEN
                        val = val * pow2(5 - bitsRemaining)
                        val = val + (src(i) / pow2(8 - (5 - bitsRemaining)))
                        i = i + 1
                    ELSE
                        val = val * pow2(5 - bitsRemaining)
                    END IF
                    val = val AND 31
                    encoded = encoded + MID$(alphabet, val + 1, 1)
                    bitsRemaining = 0
                END IF
            WEND
        WEND

        outLen = (srcLen + 4) / 5 * 8
        padLen = outLen - LEN(encoded)
        FOR j = 1 TO padLen
            encoded = encoded + "="
        NEXT j

        PRINT "Test " & FORMAT$(testCase) & ": " & encoded
    NEXT testCase

    PRINT
    PRINT "Base32 encoding complete."

    FUNCTION = 0
END FUNCTION
