Base64 Encoding and Decoding (BASLOAD example)

Post Reply
voidstar
Posts: 494
Joined: Thu Apr 15, 2021 8:05 am

Base64 Encoding and Decoding (BASLOAD example)

Post by voidstar »

Here is an approach for doing "Base64" encoding (as described here). This is different than base-N radix conversion.

To test results with a known reference, see here.

Save this as BASE64ENC.BASL,
then do:
BASLOAD "BASE64ENC.BASL"
RUN

This is using a set of "safe printable characters" in a string to transfer binary data between systems (where normally that binary data might contain non-printable characters that end up interpreted as control codes for the systems involved; so we get around that by converting it to these printable characters, and decoding it back to the original binary after the transfer-- much like how image file attachments work in e-mails).


This version only supports alpha-numeric string input of up to 31 characters. This is not at all an optimized approach, but intended more to show the workflow involved (of breaking the input data into chunks of 6-bits and handling with the ending pad at needed).

Code: Select all

PRINT "ENTER ALPHA-NUMERIC CONTENT TO ENCODE:"
INPUT A$

GOSUB ENCODE64.INIT

REM =============================================
MAIN.LOOP:

  ENCODE.STR$ = A$ : REM MAKE COPY OF INPUT STRING
  GOSUB DO.ENCODE64 : REM RESULT IN ENCODE64.RES$ AND BIN.SEQUENCE$

  PRINT ENCODE64.RES$

  END

  GOTO MAIN.LOOP
REM =============================================

REM EXAMPLE:
REM "THE Q" (AS IN: "THE QUICK BROWN FOX")
REM $54 $48 $45 $20 $51
REM 0101 0100   0100 1000   0100 0101   0010 0000   0101 0001
REM     T           H           E           _           Q
REM 010101 000100 100001 000101 001000 000101 000100 =
REM    V      E      h      F      I      F      E..
REM

REM ====================================================
REM INPUT ENCODE.STR$
DO.ENCODE64:

  BIN.SEQUENCE$=""
  X.LEN = LEN(ENCODE.STR$)
  FOR I = 1 TO X.LEN

    N = ASC( MID$(ENCODE.STR$,I,1) ) : REM CONVERT EACH CHAR OF THE INPUT STRING TO ASCII NUMERIC

    REM CONVERT ASCII NUMERIC TO AN 8-CHAR PADDED BINARY SEQUENCE STRING
    B7$="0":B6$="0":B5$="0":B4$="0":B3$="0":B2$="0":B1$="0":B0$="0"
    IF N AND $80 THEN B7$="1"
    IF N AND $40 THEN B6$="1"
    IF N AND $20 THEN B5$="1"
    IF N AND $10 THEN B4$="1"
    IF N AND $08 THEN B3$="1"
    IF N AND $04 THEN B2$="1"
    IF N AND $02 THEN B1$="1"
    IF N AND $01 THEN B0$="1"

    BIN.SEQUENCE$ = BIN.SEQUENCE$ + B7$ + B6$ + B5$ + B4$ + B3$ + B2$ + B1$ + B0$    
  NEXT I

  X.LEN = LEN(BIN.SEQUENCE$)
  PAD=0
  IDX = X.LEN - INT(X.LEN/6)*6 : REM MODULUS
  IF IDX=4 THEN PAD=1 : BIN.SEQUENCE$ = BIN.SEQUENCE$ + "00" 
  IF IDX=2 THEN PAD=2 : BIN.SEQUENCE$ = BIN.SEQUENCE$ + "0000"

  ENCODE64.RES$ = ""
  I = 1
DO.ENCODE64.NEXTGROUP:    
  TMP$ = MID$(BIN.SEQUENCE$, I, 6)
  PRINT TMP$
  X = 0
  IF MID$(TMP$, 1, 1) = "1" THEN X = X OR 32
  IF MID$(TMP$, 2, 1) = "1" THEN X = X OR 16
  IF MID$(TMP$, 3, 1) = "1" THEN X = X OR 8
  IF MID$(TMP$, 4, 1) = "1" THEN X = X OR 4
  IF MID$(TMP$, 5, 1) = "1" THEN X = X OR 2
  IF MID$(TMP$, 6, 1) = "1" THEN X = X OR 1
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
 
  I = I+6
  IF I >= LEN(BIN.SEQUENCE$) THEN GOTO ENCODE64.DONE
  GOTO DO.ENCODE64.NEXTGROUP

ENCODE64.DONE:
  IF PAD > 0 THEN ENCODE64.RES$ = ENCODE64.RES$ + "=" : PAD=PAD-1 : GOTO ENCODE64.DONE
  RETURN


ENCODE64.INIT:
DIM E642A$(63) : REM INDEX 0-64  Encode64 to ASCII
E642A$( 0) = "A"
E642A$( 1) = "B"
E642A$( 2) = "C"
E642A$( 3) = "D"
E642A$( 4) = "E"
E642A$( 5) = "F"
E642A$( 6) = "G"
E642A$( 7) = "H"
E642A$( 8) = "I"
E642A$( 9) = "J"
E642A$(10) = "K"
E642A$(11) = "L"
E642A$(12) = "M"
E642A$(13) = "N"
E642A$(14) = "O"
E642A$(15) = "P"
E642A$(16) = "Q"
E642A$(17) = "R"
E642A$(18) = "S"
E642A$(19) = "T"
E642A$(20) = "U"
E642A$(21) = "V"
E642A$(22) = "W"
E642A$(23) = "X"
E642A$(24) = "Y"
E642A$(25) = "Z"
E642A$(26) = "a"
E642A$(27) = "b"
E642A$(28) = "c"
E642A$(29) = "d"
E642A$(30) = "e"
E642A$(31) = "f"
E642A$(32) = "g"
E642A$(33) = "h"
E642A$(34) = "i"
E642A$(35) = "j"
E642A$(36) = "k"
E642A$(37) = "l"
E642A$(38) = "m"
E642A$(39) = "n"
E642A$(40) = "o"
E642A$(41) = "p"
E642A$(42) = "q"
E642A$(43) = "r"
E642A$(44) = "s"
E642A$(45) = "t"
E642A$(46) = "u"
E642A$(47) = "v"
E642A$(48) = "w"
E642A$(49) = "x"
E642A$(50) = "y"
E642A$(51) = "z"
E642A$(52) = "0"
E642A$(53) = "1"
E642A$(54) = "2"
E642A$(55) = "3"
E642A$(56) = "4"
E642A$(57) = "5"
E642A$(58) = "6"
E642A$(59) = "7"
E642A$(60) = "8"
E642A$(61) = "9"
E642A$(62) = "+"
E642A$(63) = "/"
RETURN
Attached is the tokenized BASIC version that you can use LOAD with (instead of BASLOAD).
Attachments
BASE64ENC.PRG
(1.87 KiB) Downloaded 72 times
Last edited by voidstar on Sat Jun 22, 2024 6:36 am, edited 2 times in total.
User avatar
ahenry3068
Posts: 1135
Joined: Tue Apr 04, 2023 9:57 pm

Re: Base64 Encoding (BASLOAD example)

Post by ahenry3068 »

You should expand on this. Make it encode to file and also decode said file (or perhaps a seperate PRG to do the decoding, that would be reasonable. ). If you do this I'll do a port to XC=BASIC as well for a compiled binary.
voidstar
Posts: 494
Joined: Thu Apr 15, 2021 8:05 am

Re: Base64 Encoding (BASLOAD example)

Post by voidstar »

Here is a follow up 2nd version that can work with any length string (since it doesn't store the intermediate binary sequence string).

It "works as it goes" and doesn't use as much memory, so it should be suitable for processing a file input. Can remove the PRINTs, those are just for some debugging to verify the processing. The resulting base64-encoded string gets shown using PETSCI (it's not really intended to be shown, but can use ALT+O ISO mode to see it as "normal ASCII").


I'll add a DECODE64 next.

Code: Select all

REM V* - JUNE 2024 VERSION2

PRINT "ENTER ALPHA-NUMERIC CONTENT TO ENCODE:"
INPUT A$

GOSUB ENCODE64.INIT

REM =============================================
MAIN.LOOP:

  ENCODE.STR$ = A$ : REM MAKE COPY OF INPUT STRING
  GOSUB DO.ENCODE64 : REM RESULT IN ENCODE64.RES$ AND BIN.SEQUENCE$

  PRINT ENCODE64.RES$
  REM GOSUB DO.DECODE64  - TBD

  END

  GOTO MAIN.LOOP
REM =============================================

REM EXAMPLE:
REM "THE Q" (AS IN: "THE QUICK BROWN FOX")
REM $54 $48 $45 $20 $51
REM 0101 0100   0100 1000   0100 0101   0010 0000   0101 0001
REM     T           H           E           _           Q
REM 010101 000100 100001 000101 001000 000101 000100 =
REM    V      E      h      F      I      F      E..
REM

REM ====================================================
REM INPUT ENCODE.STR$
DO.ENCODE64:
  X.LEN = LEN(ENCODE.STR$)
  ENCODE64.STAGE = 0
  FOR I = 1 TO X.LEN

    N = ASC( MID$(ENCODE.STR$,I,1) ) : REM CONVERT EACH CHAR OF THE INPUT STRING TO ASCII NUMERIC
    PRINT HEX$(N);" ";

ENCODE64.STARTOVER:
    X = 0
    IF ENCODE64.STAGE = 0 THEN GOTO ENCODE64.STAGE0
    IF ENCODE64.STAGE = 1 THEN GOTO ENCODE64.STAGE1
    IF ENCODE64.STAGE = 2 THEN GOTO ENCODE64.STAGE2
    IF ENCODE64.STAGE = 3 THEN GOTO ENCODE64.STAGE3

ENCODE64.STAGE0:
    REM STARTING STAGE, CONVERT FIRST 6-BITS OF THE ASCII BYTE    
    IF N AND $80 THEN X = X OR 32
    IF N AND $40 THEN X = X OR 16
    IF N AND $20 THEN X = X OR 8
    IF N AND $10 THEN X = X OR 4
    IF N AND $08 THEN X = X OR 2
    IF N AND $04 THEN X = X OR 1

    PRINT BIN$(N);" ";MID$(BIN$(X),3,6)
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    N.PRIOR = N
    ENCODE64.STAGE = 1
    GOTO ENCODE64.NEXT

ENCODE64.STAGE1:
    REM COMBINE 2-BITS OF PRIOR AND 4-BITS OF CURRENT
    IF N.PRIOR AND $02 THEN X = X OR 32
    IF N.PRIOR AND $01 THEN X = X OR 16
    IF N AND $80 THEN X = X OR 8
    IF N AND $40 THEN X = X OR 4
    IF N AND $20 THEN X = X OR 2
    IF N AND $10 THEN X = X OR 1

    PRINT BIN$(N);" ";MID$(BIN$(X),3,6)
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    N.PRIOR = N
    ENCODE64.STAGE = 2
    GOTO ENCODE64.NEXT

ENCODE64.STAGE2:
    REM COMBINE 4-BITS OF PRIOR AND 2-BITS OF CURRENT
    IF N.PRIOR AND $08 THEN X = X OR 32
    IF N.PRIOR AND $04 THEN X = X OR 16
    IF N.PRIOR AND $02 THEN X = X OR 8
    IF N.PRIOR AND $01 THEN X = X OR 4
    IF N AND $80 THEN X = X OR 2
    IF N AND $40 THEN X = X OR 1

    PRINT BIN$(N);" ";MID$(BIN$(X),3,6)
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    N.PRIOR = N
    ENCODE64.STAGE = 3
    GOTO ENCODE64.NEXT

ENCODE64.STAGE3:
    REM COMBINE ALL 6-BITS OF PRIOR AND THEN START AGAIN AT STAGE0

    PRINT "STAGE3 --> N.PRIOR ";HEX$(N.PRIOR)

    IF N.PRIOR AND $20 THEN X = X OR 32
    IF N.PRIOR AND $10 THEN X = X OR 16
    IF N.PRIOR AND $08 THEN X = X OR 8
    IF N.PRIOR AND $04 THEN X = X OR 4
    IF N.PRIOR AND $02 THEN X = X OR 2
    IF N.PRIOR AND $01 THEN X = X OR 1

    PRINT HEX$(N.PRIOR);" ";BIN$(N.PRIOR);" ";MID$(BIN$(X),3,6)
    PRINT HEX$(N);" ";
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    ENCODE64.STAGE = 0
    GOTO ENCODE64.STARTOVER

ENCODE64.NEXT:
  NEXT I

  REM FINISH WITH FOLLOW UP PROCESSING
  IF ENCODE64.STAGE = 1 THEN GOTO ENCODE64.END1
  IF ENCODE64.STAGE = 2 THEN GOTO ENCODE64.END2
  IF ENCODE64.STAGE = 3 THEN GOTO ENCODE64.END3
  GOTO ENCODE64.END

ENCODE64.END1:
  REM USE 2-BITS OF PRIOR (THEN 2 PADS)
  X = 0
  IF N.PRIOR AND $02 THEN X = X OR 32
  IF N.PRIOR AND $01 THEN X = X OR 16
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
  ENCODE64.RES$ = ENCODE64.RES$ + "=="
  GOTO ENCODE64.END

ENCODE64.END2:
  REM USE 4-BITS OF PRIOR (THEN 1 PAD)
  X = 0
  IF N.PRIOR AND $08 THEN X = X OR 32
  IF N.PRIOR AND $04 THEN X = X OR 16
  IF N.PRIOR AND $02 THEN X = X OR 8
  IF N.PRIOR AND $01 THEN X = X OR 4
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
  ENCODE64.RES$ = ENCODE64.RES$ + "="
  GOTO ENCODE64.END

ENCODE64.END3:
  REM USE 6-BITS OF PRIOR (NO PAD)
  X = 0
  IF N.PRIOR AND $20 THEN X = X OR 32
  IF N.PRIOR AND $10 THEN X = X OR 16
  IF N.PRIOR AND $08 THEN X = X OR 8
  IF N.PRIOR AND $04 THEN X = X OR 4
  IF N.PRIOR AND $02 THEN X = X OR 2
  IF N.PRIOR AND $01 THEN X = X OR 1
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
  GOTO ENCODE64.END
 
ENCODE64.END:
  RETURN


ENCODE64.INIT:
DIM E642A$(63) : REM INDEX 0-64  Encode64 to ASCII
E642A$( 0) = "A"
E642A$( 1) = "B"
E642A$( 2) = "C"
E642A$( 3) = "D"
E642A$( 4) = "E"
E642A$( 5) = "F"
E642A$( 6) = "G"
E642A$( 7) = "H"
E642A$( 8) = "I"
E642A$( 9) = "J"
E642A$(10) = "K"
E642A$(11) = "L"
E642A$(12) = "M"
E642A$(13) = "N"
E642A$(14) = "O"
E642A$(15) = "P"
E642A$(16) = "Q"
E642A$(17) = "R"
E642A$(18) = "S"
E642A$(19) = "T"
E642A$(20) = "U"
E642A$(21) = "V"
E642A$(22) = "W"
E642A$(23) = "X"
E642A$(24) = "Y"
E642A$(25) = "Z"
E642A$(26) = "a"
E642A$(27) = "b"
E642A$(28) = "c"
E642A$(29) = "d"
E642A$(30) = "e"
E642A$(31) = "f"
E642A$(32) = "g"
E642A$(33) = "h"
E642A$(34) = "i"
E642A$(35) = "j"
E642A$(36) = "k"
E642A$(37) = "l"
E642A$(38) = "m"
E642A$(39) = "n"
E642A$(40) = "o"
E642A$(41) = "p"
E642A$(42) = "q"
E642A$(43) = "r"
E642A$(44) = "s"
E642A$(45) = "t"
E642A$(46) = "u"
E642A$(47) = "v"
E642A$(48) = "w"
E642A$(49) = "x"
E642A$(50) = "y"
E642A$(51) = "z"
E642A$(52) = "0"
E642A$(53) = "1"
E642A$(54) = "2"
E642A$(55) = "3"
E642A$(56) = "4"
E642A$(57) = "5"
E642A$(58) = "6"
E642A$(59) = "7"
E642A$(60) = "8"
E642A$(61) = "9"
E642A$(62) = "+"
E642A$(63) = "/"
RETURN
Attachments
encode64.jpg
encode64.jpg (291.43 KiB) Viewed 1050 times
BASE64ENCV2.PRG
(2.52 KiB) Downloaded 67 times
voidstar
Posts: 494
Joined: Thu Apr 15, 2021 8:05 am

Re: Base64 Encoding (BASLOAD example)

Post by voidstar »

Ok, now have the DECODE of this also done in BASLOAD.

Now to just decide how to handle input and output.

For input, replace the INPUT keyword with something from a file. And same for output, replace the PRINT's in the DECODE64 "sub-routine" with where you want to stream the results back out to.

Code: Select all

REM V* - JUNE 2024 VERSION3 ENCODE & DECODE

PRINT "ENTER ALPHA-NUMERIC CONTENT TO ENCODE:"
INPUT A$

GOSUB ENCODE64.INIT
GOSUB DECODE64.INIT

REM =============================================
MAIN.LOOP:

  ENCODE.STR$ = A$ : REM MAKE COPY OF INPUT STRING
  GOSUB DO.ENCODE64 : REM RESULT IN ENCODE64.RES$ AND BIN.SEQUENCE$

  PRINT ENCODE64.RES$
  GOSUB DO.DECODE64 : REM USES ENCODE64.RES$ AS INPUT

  END

  GOTO MAIN.LOOP
REM =============================================

REM EXAMPLE:
REM "THE Q" (AS IN: "THE QUICK BROWN FOX")
REM $54 $48 $45 $20 $51
REM 0101 0100   0100 1000   0100 0101   0010 0000   0101 0001
REM     T           H           E           _           Q
REM 010101 000100 100001 000101 001000 000101 000100 =
REM    V      E      h      F      I      F      E..
REM

REM ====================================================
REM INPUT ENCODE.STR$
DO.ENCODE64:
  X.LEN = LEN(ENCODE.STR$)
  ENCODE64.STAGE = 0
  FOR I = 1 TO X.LEN

    N = ASC( MID$(ENCODE.STR$,I,1) ) : REM CONVERT EACH CHAR OF THE INPUT STRING TO ASCII NUMERIC
    PRINT HEX$(N);" ";

ENCODE64.STARTOVER:
    X = 0
    IF ENCODE64.STAGE = 0 THEN GOTO ENCODE64.STAGE0
    IF ENCODE64.STAGE = 1 THEN GOTO ENCODE64.STAGE1
    IF ENCODE64.STAGE = 2 THEN GOTO ENCODE64.STAGE2
    IF ENCODE64.STAGE = 3 THEN GOTO ENCODE64.STAGE3
    STOP : REM SHOULD NOT REACH THIS POINT

ENCODE64.STAGE0:
    REM STARTING STAGE, CONVERT FIRST 6-BITS OF THE ASCII BYTE    
    IF N AND $80 THEN X = X OR 32
    IF N AND $40 THEN X = X OR 16
    IF N AND $20 THEN X = X OR 8
    IF N AND $10 THEN X = X OR 4
    IF N AND $08 THEN X = X OR 2
    IF N AND $04 THEN X = X OR 1

    PRINT BIN$(N);" ";MID$(BIN$(X),3,6)
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    N.PRIOR = N
    ENCODE64.STAGE = 1
    GOTO ENCODE64.NEXT

ENCODE64.STAGE1:
    REM COMBINE 2-BITS OF PRIOR AND 4-BITS OF CURRENT
    IF N.PRIOR AND $02 THEN X = X OR 32
    IF N.PRIOR AND $01 THEN X = X OR 16
    IF N AND $80 THEN X = X OR 8
    IF N AND $40 THEN X = X OR 4
    IF N AND $20 THEN X = X OR 2
    IF N AND $10 THEN X = X OR 1

    PRINT BIN$(N);" ";MID$(BIN$(X),3,6)
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    N.PRIOR = N
    ENCODE64.STAGE = 2
    GOTO ENCODE64.NEXT

ENCODE64.STAGE2:
    REM COMBINE 4-BITS OF PRIOR AND 2-BITS OF CURRENT
    IF N.PRIOR AND $08 THEN X = X OR 32
    IF N.PRIOR AND $04 THEN X = X OR 16
    IF N.PRIOR AND $02 THEN X = X OR 8
    IF N.PRIOR AND $01 THEN X = X OR 4
    IF N AND $80 THEN X = X OR 2
    IF N AND $40 THEN X = X OR 1

    PRINT BIN$(N);" ";MID$(BIN$(X),3,6)
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    N.PRIOR = N
    ENCODE64.STAGE = 3
    GOTO ENCODE64.NEXT

ENCODE64.STAGE3:
    REM COMBINE ALL 6-BITS OF PRIOR AND THEN START AGAIN AT STAGE0

    PRINT "STAGE3 --> N.PRIOR ";HEX$(N.PRIOR)

    IF N.PRIOR AND $20 THEN X = X OR 32
    IF N.PRIOR AND $10 THEN X = X OR 16
    IF N.PRIOR AND $08 THEN X = X OR 8
    IF N.PRIOR AND $04 THEN X = X OR 4
    IF N.PRIOR AND $02 THEN X = X OR 2
    IF N.PRIOR AND $01 THEN X = X OR 1

    PRINT HEX$(N.PRIOR);" ";BIN$(N.PRIOR);" ";MID$(BIN$(X),3,6)
    PRINT HEX$(N);" ";
    ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
    ENCODE64.STAGE = 0
    GOTO ENCODE64.STARTOVER

ENCODE64.NEXT:
  NEXT I

  REM FINISH WITH FOLLOW UP PROCESSING
  IF ENCODE64.STAGE = 1 THEN GOTO ENCODE64.END1
  IF ENCODE64.STAGE = 2 THEN GOTO ENCODE64.END2
  IF ENCODE64.STAGE = 3 THEN GOTO ENCODE64.END3
  GOTO ENCODE64.END

ENCODE64.END1:
  REM USE 2-BITS OF PRIOR (THEN 2 PADS)
  X = 0
  IF N.PRIOR AND $02 THEN X = X OR 32
  IF N.PRIOR AND $01 THEN X = X OR 16
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
  ENCODE64.RES$ = ENCODE64.RES$ + "=="
  GOTO ENCODE64.END

ENCODE64.END2:
  REM USE 4-BITS OF PRIOR (THEN 1 PAD)
  X = 0
  IF N.PRIOR AND $08 THEN X = X OR 32
  IF N.PRIOR AND $04 THEN X = X OR 16
  IF N.PRIOR AND $02 THEN X = X OR 8
  IF N.PRIOR AND $01 THEN X = X OR 4
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
  ENCODE64.RES$ = ENCODE64.RES$ + "="
  GOTO ENCODE64.END

ENCODE64.END3:
  REM USE 6-BITS OF PRIOR (NO PAD)
  X = 0
  IF N.PRIOR AND $20 THEN X = X OR 32
  IF N.PRIOR AND $10 THEN X = X OR 16
  IF N.PRIOR AND $08 THEN X = X OR 8
  IF N.PRIOR AND $04 THEN X = X OR 4
  IF N.PRIOR AND $02 THEN X = X OR 2
  IF N.PRIOR AND $01 THEN X = X OR 1
  ENCODE64.RES$ = ENCODE64.RES$ + E642A$(X)
  GOTO ENCODE64.END
 
ENCODE64.END:
  RETURN


DO.DECODE64:
  DEC.LEN = LEN(ENCODE64.RES$)
  DECODE64.STAGE = 0
  FOR I = 1 TO DEC.LEN
    N = ASC( MID$(ENCODE64.RES$,I,1) ) - $2B : REM CONVERT EACH CHAR OF THE DECODE STRING TO ASCII NUMERIC
    REM $2B IS USED TO RE-ALIGN THE GIVEN ASCII SYMBOL TO THE D642V ARRAY INDEX
    V = D642V(N)

    IF DECODE64.STAGE = 0 THEN GOTO DECODE64.BORROW2
    IF DECODE64.STAGE = 1 THEN GOTO DECODE64.BORROW4
    IF DECODE64.STAGE = 2 THEN GOTO DECODE64.BORROW6
    STOP : REM SHOULD NOT REACH THIS POINT

DECODE64.BORROW2:
    REM 2-BITS BORROWED FROM NEXT ENCODED SYMBOL
    PRINT "STAGE 1: ";
    N.NEXT = ASC( MID$(ENCODE64.RES$,I+1,1) ) - $2B    
    IF N.NEXT = 18 THEN GOTO DECODE64.DONE : REM HANDLE PAD
    V.NEXT = D642V(N.NEXT)
    X = (V AND %00111111) * 4 : REM *4 MEANS SHIFT LEFT 2 BITS
    X.TMP = (V.NEXT AND %00110000) / 16 : REM /16 MEANS SHIFT RIGHT 4 BITS
    RES = X OR X.TMP
    PRINT HEX$(RES);" ";CHR$(RES)
    DECODE64.STAGE = 1
    GOTO DECODE64.NEXT

DECODE64.BORROW4:
    REM 4-BITS BORROWED FROM NEXT ENCODED SYMBOL
    PRINT "STAGE 2: ";
    N.NEXT = ASC( MID$(ENCODE64.RES$,I+1,1) ) - $2B    
    IF N.NEXT = 18 THEN GOTO DECODE64.DONE : REM HANDLE PAD
    V.NEXT = D642V(N.NEXT)
    X = (V AND %00001111) * 16 : REM *16 MEANS SHIFT LEFT 4 BITS
    X.TMP = (V.NEXT AND %00111100) / 4 : REM /4 MEANS SHIFT RIGHT 2 BITS
    RES = X OR X.TMP
    PRINT HEX$(RES);" ";CHR$(RES)
    DECODE64.STAGE = 2
    GOTO DECODE64.NEXT   

DECODE64.BORROW6:
    REM 6-BITS BORROWED FROM NEXT ENCODED SYMBOL (I.E. THE ENTIRE SYMBOL)
    PRINT "STAGE 3: ";
    N.NEXT = ASC( MID$(ENCODE64.RES$,I+1,1) ) - $2B
    IF N.NEXT = 18 THEN GOTO DECODE64.DONE : REM HANDLE PAD
    V.NEXT = D642V(N.NEXT)
    X = (V AND %00000011) * 64 : REM *64 MEANS SHIFT LEFT 6 BITS
    X.TMP = (V.NEXT AND %00111111)
    RES = X OR X.TMP
    PRINT HEX$(RES);" ";CHR$(RES)
    REM SINCE WE BORROW THE ENTIRE SYMBOL, WE CAN SKIP IT IN THIS LOOP
    I = I+1
    DECODE64.STAGE = 0 : REM START PROCESS OVER AGAIN
    GOTO DECODE64.NEXT    

DECODE64.NEXT:
  NEXT I

DECODE64.DONE:
  
  RETURN


ENCODE64.INIT:
DIM E642A$(63) : REM INDEX 0-64  ENCODE64 TO ASCII
E642A$( 0) = "A"
E642A$( 1) = "B"
E642A$( 2) = "C"
E642A$( 3) = "D"
E642A$( 4) = "E"
E642A$( 5) = "F"
E642A$( 6) = "G"
E642A$( 7) = "H"
E642A$( 8) = "I"
E642A$( 9) = "J"
E642A$(10) = "K"
E642A$(11) = "L"
E642A$(12) = "M"
E642A$(13) = "N"
E642A$(14) = "O"
E642A$(15) = "P"
E642A$(16) = "Q"
E642A$(17) = "R"
E642A$(18) = "S"
E642A$(19) = "T"
E642A$(20) = "U"
E642A$(21) = "V"
E642A$(22) = "W"
E642A$(23) = "X"
E642A$(24) = "Y"
E642A$(25) = "Z"
E642A$(26) = "a"
E642A$(27) = "b"
E642A$(28) = "c"
E642A$(29) = "d"
E642A$(30) = "e"
E642A$(31) = "f"
E642A$(32) = "g"
E642A$(33) = "h"
E642A$(34) = "i"
E642A$(35) = "j"
E642A$(36) = "k"
E642A$(37) = "l"
E642A$(38) = "m"
E642A$(39) = "n"
E642A$(40) = "o"
E642A$(41) = "p"
E642A$(42) = "q"
E642A$(43) = "r"
E642A$(44) = "s"
E642A$(45) = "t"
E642A$(46) = "u"
E642A$(47) = "v"
E642A$(48) = "w"
E642A$(49) = "x"
E642A$(50) = "y"
E642A$(51) = "z"
E642A$(52) = "0"
E642A$(53) = "1"
E642A$(54) = "2"
E642A$(55) = "3"
E642A$(56) = "4"
E642A$(57) = "5"
E642A$(58) = "6"
E642A$(59) = "7"
E642A$(60) = "8"
E642A$(61) = "9"
E642A$(62) = "+"
E642A$(63) = "/"
RETURN

REM "BASE64" ENCODING SYMBOLS:
REM ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
DECODE64.INIT: REM DECODE64 TO VALUE
DIM D642V(79)
REM                                             HEX     DEC     IDX             SYMBOL
D642V(	0	)=%	00111110	:REM	2B	43	43		+	
D642V(	1	)=%	00000000	:REM			44		not_used	
D642V(	2	)=%	00000000	:REM			45		not_used	
D642V(	3	)=%	00000000	:REM			46		not_used	
D642V(	4	)=%	00111111	:REM	2F	47	47		/	
D642V(	5	)=%	00110100	:REM	30	48	48		0	
D642V(	6	)=%	00110101	:REM	31	49	49		1	
D642V(	7	)=%	00110110	:REM	32	50	50		2	
D642V(	8	)=%	00110111	:REM	33	51	51		3	
D642V(	9	)=%	00111000	:REM	34	52	52		4	
D642V(	10	)=%	00111001	:REM	35	53	53		5	
D642V(	11	)=%	00111010	:REM	36	54	54		6	
D642V(	12	)=%	00111011	:REM	37	55	55		7	
D642V(	13	)=%	00111100	:REM	38	56	56		8	
D642V(	14	)=%	00111101	:REM	39	57	57		9	
D642V(	15	)=%	00000000	:REM			58		not_used	
D642V(	16	)=%	00000000	:REM			59		not_used	
D642V(	17	)=%	00000000	:REM			60		not_used	
D642V(	18	)=%	00000000	:REM 	(PAD)		61		(pad symbol =)
D642V(	19	)=%	00000000	:REM			62		not_used	
D642V(	20	)=%	00000000	:REM			63		not_used	
D642V(	21	)=%	00000000	:REM			64		not_used	
D642V(	22	)=%	00000000	:REM	41	65	65		A	
D642V(	23	)=%	00000001	:REM	42	66	66		B	
D642V(	24	)=%	00000010	:REM	43	67	67		C	
D642V(	25	)=%	00000011	:REM	44	68	68		D	
D642V(	26	)=%	00000100	:REM	45	69	69		E	
D642V(	27	)=%	00000101	:REM	46	70	70		F	
D642V(	28	)=%	00000110	:REM	47	71	71		G	
D642V(	29	)=%	00000111	:REM	48	72	72		H	
D642V(	30	)=%	00001000	:REM	49	73	73		I	
D642V(	31	)=%	00001001	:REM	4A	74	74		J	
D642V(	32	)=%	00001010	:REM	4B	75	75		K	
D642V(	33	)=%	00001011	:REM	4C	76	76		L	
D642V(	34	)=%	00001100	:REM	4D	77	77		M	
D642V(	35	)=%	00001101	:REM	4E	78	78		N	
D642V(	36	)=%	00001110	:REM	4F	79	79		O	
D642V(	37	)=%	00001111	:REM	50	80	80		P	
D642V(	38	)=%	00010000	:REM	51	81	81		Q	
D642V(	39	)=%	00010001	:REM	52	82	82		R	
D642V(	40	)=%	00010010	:REM	53	83	83		S	
D642V(	41	)=%	00010011	:REM	54	84	84		T	
D642V(	42	)=%	00010100	:REM	55	85	85		U	
D642V(	43	)=%	00010101	:REM	56	86	86		V	
D642V(	44	)=%	00010110	:REM	57	87	87		W	
D642V(	45	)=%	00010111	:REM	58	88	88		X	
D642V(	46	)=%	00011000	:REM	59	89	89		Y	
D642V(	47	)=%	00011001	:REM	5A	90	90		Z	
D642V(	48	)=%	00000000	:REM			91		not_used	
D642V(	49	)=%	00000000	:REM			92		not_used	
D642V(	50	)=%	00000000	:REM			93		not_used	
D642V(	51	)=%	00000000	:REM			94		not_used	
D642V(	52	)=%	00000000	:REM			95		not_used	
D642V(	53	)=%	00000000	:REM			96		not_used	
D642V(	54	)=%	00011010	:REM	61	97	97		a	
D642V(	55	)=%	00011011	:REM	62	98	98		b	
D642V(	56	)=%	00011100	:REM	63	99	99		c	
D642V(	57	)=%	00011101	:REM	64	100	100		d	
D642V(	58	)=%	00011110	:REM	65	101	101		e	
D642V(	59	)=%	00011111	:REM	66	102	102		f	
D642V(	60	)=%	00100000	:REM	67	103	103		g	
D642V(	61	)=%	00100001	:REM	68	104	104		h	
D642V(	62	)=%	00100010	:REM	69	105	105		i	
D642V(	63	)=%	00100011	:REM	6A	106	106		j	
D642V(	64	)=%	00100100	:REM	6B	107	107		k	
D642V(	65	)=%	00100101	:REM	6C	108	108		l	
D642V(	66	)=%	00100110	:REM	6D	109	109		m	
D642V(	67	)=%	00100111	:REM	6E	110	110		n	
D642V(	68	)=%	00101000	:REM	6F	111	111		o	
D642V(	69	)=%	00101001	:REM	70	112	112		p	
D642V(	70	)=%	00101010	:REM	71	113	113		q	
D642V(	71	)=%	00101011	:REM	72	114	114		r	
D642V(	72	)=%	00101100	:REM	73	115	115		s	
D642V(	73	)=%	00101101	:REM	74	116	116		t	
D642V(	74	)=%	00101110	:REM	75	117	117		u	
D642V(	75	)=%	00101111	:REM	76	118	118		v	
D642V(	76	)=%	00110000	:REM	77	119	119		w	
D642V(	77	)=%	00110001	:REM	78	120	120		x	
D642V(	78	)=%	00110010	:REM	79	121	121		y	
D642V(	79	)=%	00110011	:REM	7A	122	122		z	
RETURN
Attachments
BASE64ENCV3.PRG
(4.86 KiB) Downloaded 68 times
encodedecode64.jpg
encodedecode64.jpg (180.89 KiB) Viewed 1033 times
Post Reply