SUB CODE64 (InputFile AS STRING, c$())
    IF _FILEEXISTS(InputFile$) THEN
        ff = FREEFILE
        DIM A AS _UNSIGNED _BYTE, B AS _UNSIGNED _BYTE, C AS _UNSIGNED _BYTE, i AS LONG, M AS _MEM
        OPEN InputFile FOR BINARY AS #ff
        size = LOF(ff)
        file$ = SPACE$(size)
        GET ff, , file$
        CLOSE ff
        M = _MEMNEW(size)
        _MEMFILL M, M.OFFSET, size, file$


        ff = 0

        DO UNTIL ff >= M.SIZE
            IF ff < M.SIZE THEN _MEMGET M, M.OFFSET + ff, A
            ff = ff + 1
            IF ff < M.SIZE THEN _MEMGET M, M.OFFSET + ff, B
            ff = ff + 1
            IF ff < M.SIZE THEN _MEMGET M, M.OFFSET + ff, C
            ff = ff + 1
            Binary$ = ""
            BinaryA$ = "000000"
            BinaryB$ = "000000"
            BinaryC$ = "000000"

            BinaryA$ = DECtoBIN$(A)
            BinaryB$ = DECtoBIN$(B)
            BinaryC$ = DECtoBIN$(C)

            Binary$ = BinaryA$ + BinaryB$ + BinaryC$


            FOR Code = 1 TO 24 STEP 6
                C64$ = C64$ + BASE64$(BINtoDEC(MID$(Binary$, Code, 6)))
            NEXT
            IF LEN(C64$) >= 450 THEN
                c$(i) = C64$
                i = i + 1
                C64$ = ""
                REDIM _PRESERVE c(i) AS STRING
            END IF
        LOOP
        IF LEN(C64$) THEN
            c$(i) = C64$
            C64$ = ""
            i = i + 1
            REDIM _PRESERVE c(i) AS STRING
        END IF
    END IF
    _MEMFREE M
END SUB


SUB DECODE64 (c() AS STRING, ToFile$)
    DEFLNG A-Z
    ff = FREEFILE
    IF _FILEEXISTS(ToFile$) THEN KILL ToFile$

    OPEN ToFile$ FOR BINARY AS #ff
    FOR d2 = 0 TO UBOUND(c$) - 1
        FOR d = 1 TO LEN(c$(d2)) STEP 4
            A$ = MID$(c$(d2), d, 1)
            B$ = MID$(c$(d2), d + 1, 1)
            c$ = MID$(c$(d2), d + 2, 1)
            D$ = MID$(c$(d2), d + 3, 1)

            BinaryA$ = DECtoBIN6$(BASE64TODEC(A$))
            BinaryB$ = DECtoBIN6$(BASE64TODEC(B$))
            BinaryC$ = DECtoBIN6$(BASE64TODEC(c$))
            BinaryD$ = DECtoBIN6$(BASE64TODEC(D$))

            Binary$ = BinaryA$ + BinaryB$ + BinaryC$ + BinaryD$

            DIM a AS _UNSIGNED _BYTE
            FOR Code = 1 TO 24 STEP 8
                a = BINtoDEC(MID$(Binary$, Code, 8))
                PUT #ff, , a
            NEXT
            Binary$ = ""
        NEXT d
    NEXT d2
    CLOSE ff
END SUB


FUNCTION BASE64$ (nr AS _UNSIGNED LONG) 'input is number, output is string
    DIM B64(63) AS _UNSIGNED _BYTE, V AS _UNSIGNED LONG
    FOR a = 0 TO 63
        IF a <= 25 THEN B = a + 65
        IF a > 25 THEN B = a + 71
        IF a > 51 THEN B = a - 4
        IF a = 62 THEN B = 43
        IF a = 63 THEN B = 47
        ' https://en.wikipedia.org/wiki/Base64
        B64(a) = B
    NEXT
    REDIM b64out(0) AS _UNSIGNED _BYTE
    IF nr = 0 THEN BASE64$ = CHR$(B64(0))
    DO UNTIL nr = 0
        V = nr MOD 64
        nr = nr \ 64
        b64out(i) = V
        i = i + 1
        REDIM _PRESERVE b64out(i) AS _UNSIGNED _BYTE
    LOOP
    FOR s = i - 1 TO 0 STEP -1
        BASE64$ = BASE64$ + CHR$(B64(b64out(s)))
    NEXT
    ERASE B64
    ERASE b64out
END FUNCTION



FUNCTION BASE64TODEC~& (nr$)
    DIM B64(63) AS _UNSIGNED _BYTE, V AS _UNSIGNED LONG, Si AS LONG
    FOR a = 0 TO 63
        IF a <= 25 THEN B = a + 65
        IF a > 25 THEN B = a + 71
        IF a > 51 THEN B = a - 4
        IF a = 62 THEN B = 43
        IF a = 63 THEN B = 47
        ' https://en.wikipedia.org/wiki/Base64
        B64(a) = B
    NEXT

    FOR Si = 1 TO LEN(nr$)
        V = ASC(nr$, Si)
        FOR search = 0 TO 63
            IF B64(search) = V THEN EXIT FOR
        NEXT
        Sj = LEN(nr$) - Si
        BASE64TODEC~& = BASE64TODEC~& + (search * 64 ^ Sj)
    NEXT
END FUNCTION

FUNCTION DECtoBIN$ (vstup)
    FOR rj = 7 TO 0 STEP -1
        IF vstup AND 2 ^ rj THEN DECtoBIN$ = DECtoBIN$ + "1" ELSE DECtoBIN$ = DECtoBIN$ + "0"
    NEXT rj
END FUNCTION

FUNCTION DECtoBIN6$ (vstup)
    FOR rj = 5 TO 0 STEP -1
        IF vstup AND 2 ^ rj THEN DECtoBIN6$ = DECtoBIN6$ + "1" ELSE DECtoBIN6$ = DECtoBIN6$ + "0"
    NEXT rj
END FUNCTION


FUNCTION BINtoDEC (b AS STRING)
    FOR Si = 1 TO LEN(b)
        e$ = MID$(b$, Si, 1)
        c = VAL(e$) '
        Sj = LEN(b) - Si
        BINtoDEC = BINtoDEC + (c * 2 ^ Sj)
    NEXT Si
END FUNCTION

