QB64.org Forum

Active Forums => Programs => Topic started by: NOVARSEG on December 17, 2020, 01:58:14 am

Title: Base 64 encoder / decoder
Post by: NOVARSEG on December 17, 2020, 01:58:14 am
Encodes  base 256  to base 64
Decodes base 64 to base 256

The code is more of an example of the math behind base to base conversions.

The earlier version had a bug  - now corrected.

Code: QB64: [Select]
  1. 'BASE 64 encoder / decoder
  2.  
  3. 'prints the string to be encoded
  4. 'prints the encoded base 64 string
  5. 'prints the decoded base 64 string
  6.  
  7. DIM string1 AS STRING
  8. DIM string2 AS STRING
  9.  
  10. string1 = "ASCII stands for American Standard Code for Information Interchange.."
  11.  
  12. PRINT "STRING1 "; string1
  13. FOR x% = 1 TO LEN(string1) STEP 3
  14.     a = ASC(MID$(string1, x%, 1))
  15.     b = ASC(MID$(string1, x% + 1, 1))
  16.     c = ASC(MID$(string1, x% + 2, 1))
  17.  
  18.  
  19.     s = a * 256 ^ 2 + b * 256 + c
  20.  
  21.  
  22.     IF s >= 64 ^ 3 THEN
  23.         i = INT(s / 64 ^ 3)
  24.         s = s - i * 64 ^ 3
  25.         e = CHR$(i + 48)
  26.     END IF
  27.  
  28.     IF s >= 64 ^ 2 THEN
  29.         i = INT(s / 64 ^ 2)
  30.         s = s - i * 64 ^ 2
  31.         f = CHR$(i + 48)
  32.     END IF
  33.  
  34.     IF s >= 64 ^ 1 THEN
  35.         i = INT(s / 64 ^ 1)
  36.         s = s - i * 64 ^ 1
  37.         g = CHR$(i + 48)
  38.     END IF
  39.  
  40.     IF s >= 64 ^ 0 THEN
  41.         i = INT(s / 64 ^ 0)
  42.         s = s - i * 64 ^ 0
  43.         h = CHR$(i + 48)
  44.     END IF
  45.  
  46.  
  47.     string2 = string2 + (e + f + g + h)
  48. NEXT x%
  49. PRINT "STRING2 "; string2
  50. string1 = ""
  51. '********************
  52. FOR x% = 1 TO LEN(string2) STEP 4
  53.     a = ASC(MID$(string2, x%, 1)) - 48
  54.     b = ASC(MID$(string2, x% + 1, 1)) - 48
  55.     c = ASC(MID$(string2, x% + 2, 1)) - 48
  56.     d = ASC(MID$(string2, x% + 3, 1)) - 48
  57.  
  58.  
  59.     s = a * 64 ^ 3 + b * 64 ^ 2 + c * 64 + d
  60.  
  61.     IF s >= 256 ^ 2 THEN
  62.         i = INT(s / 256 ^ 2)
  63.         s = s - i * 256 ^ 2
  64.         e = CHR$(i)
  65.     END IF
  66.  
  67.     IF s >= 256 ^ 1 THEN
  68.         i = INT(s / 256 ^ 1)
  69.         s = s - i * 256 ^ 1
  70.         f = CHR$(i)
  71.     END IF
  72.  
  73.     IF s >= 256 ^ 0 THEN
  74.         i = INT(s / 256 ^ 0)
  75.         s = s - i * 256 ^ 0
  76.         g = CHR$(i)
  77.     END IF
  78.  
  79.     string1 = string1 + (e + f + g)
  80.  
  81. NEXT x%
  82.  
  83. PRINT "STRING1 "; string1
  84.  
  85.  
  86.  








Title: Re: Base 64 encoder
Post by: bplus on December 17, 2020, 01:06:06 pm
What's the POINT?

Wouldn't numbers be more handy for processing?

ColorNumber~& = _RGB32(red, green, blue, alpha)

And the reverse, simple handy SUB for analyzing a color:
Code: QB64: [Select]
  1. SUB cAnalysis (c AS _UNSIGNED LONG, outRed, outGrn, outBlu, outAlp)
  2.     outRed = _RED32(c): outGrn = _GREEN32(c): outBlu = _BLUE32(c): outAlp = _ALPHA32(c)
  3.  

Demo test:
Code: QB64: [Select]
  1. red = 50: green = 100: blue = 200: alpha = 100
  2. ColorNumber~& = _RGBA32(red, green, blue, alpha)
  3. PRINT red, green, blue, alpha, ColorNumber~&
  4. cAnalysis ColorNumber~&, outR, outG, outB, outA
  5. PRINT outR, outG, outB, outA
  6.  
  7.  
  8. 'And the reverse, simple handy SUB for analyzing a color:
  9.  
  10. SUB cAnalysis (c AS _UNSIGNED LONG, outRed, outGrn, outBlu, outAlp)
  11.     outRed = _RED32(c): outGrn = _GREEN32(c): outBlu = _BLUE32(c): outAlp = _ALPHA32(c)
  12.  

Convert red, green, blue, alpha to Binary, Hex, Oct....

Title: Re: Base 64 encoder
Post by: SMcNeill on December 17, 2020, 04:26:13 pm
Here's my Base-128 converter:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(640, 480, 32)
  2.  
  3. a$ = "  The Old Woman and the Wine-Jar" + CHR$(10)
  4. a$ = a$ + "AN OLD WOMAN found an empty jar which had lately been full of prime old wine and which still retained the fragrant smell of its former contents.  She greedily placed it several times to her nose, and drawing it backwards and forwards said, 'O most delicious! How nice must the Wine itself have been, when it leaves behind in the very vessel which contained it so sweet a perfume!'" + CHR$(10)
  5. a$ = a$ + "The memory of a good deed lives.     "
  6.  
  7. d$ = B256to128$(a$)
  8. i$ = B128to256$(d$)
  9. PRINT "-----------------"
  10. PRINT "-----------------"
  11. PRINT "-----------------"
  12. PRINT "Length of original:"; LEN(a$)
  13. PRINT "Length of 128-bit DATA ready conversion:"; LEN(d$)
  14. PRINT "Length of restored:"; LEN(i$)
  15.  
  16.  
  17.  
  18.  
  19.  
  20. FUNCTION B256to128$ (temp$)
  21.     text$ = _DEFLATE$(temp$)
  22.     l = 8 * LEN(text$)
  23.     'convert the text to the 8 bit array
  24.     FOR i = 1 TO LEN(text$)
  25.         b = ASC(text$, i)
  26.         p = (i - 1) * 8 + 1
  27.         FOR j = 0 TO 7
  28.             IF b AND (2 ^ j) THEN A(p + j) = 1 'ELSE A(p + j) = 0
  29.         NEXT
  30.     NEXT
  31.     'convert the array to 7bit strings
  32.     FOR i = 1 TO l STEP 7
  33.         b = 0
  34.         FOR j = 6 TO 0 STEP -1
  35.             IF i + j < l THEN
  36.                 IF A(i + j) THEN b = b + (2 ^ j)
  37.             END IF
  38.         NEXT
  39.         b = b + 59
  40.         t$ = t$ + CHR$(b)
  41.  
  42.     NEXT
  43.     B256to128 = t$
  44.  
  45. FUNCTION B128to256$ (text$)
  46.     l = 7 * LEN(text$)
  47.     'convert the text to the 8 bit array
  48.     FOR i = 1 TO LEN(text$)
  49.         b = ASC(text$, i) - 59
  50.         FOR j = 0 TO 6
  51.             p = p + 1: IF p > l THEN EXIT FOR
  52.             IF b AND (2 ^ j) THEN A(p) = 1 ELSE A(p) = 0
  53.         NEXT
  54.     NEXT
  55.     'convert the array to 8bit strings
  56.     p = 0
  57.     FOR i = 1 TO l STEP 8
  58.         b = 0
  59.         FOR j = 0 TO 7
  60.             p = p + 1
  61.             IF p > l THEN EXIT FOR
  62.             IF A(p) THEN b = b + (2 ^ j)
  63.         NEXT
  64.         t$ = t$ + CHR$(b)
  65.     NEXT
  66.     B128to256 = _INFLATE$(t$)

With this, I can take file assets such as images, sounds, or memblocks, and I can convert them down from BASE-256 characters to compressed BASE-128 characters, so that they'll paste into a DATA statement without any invalid characters causing problems.

For example, we can't have this in QB64:

DATA He said, "Foobar on your toolbar."

Those quotes and commas are problematic, as would a CHR$(0) or ":" be.  Not all 256 characters play nice with DATA statements, so I convert my data down to 128-bytes and place them into a program instead. 

Note: Routines above haven't been optimized for speed, so they may take a few seconds to convert and restore your data, in the case of large image or sound files.  I should honestly fix that sometime soon, but since I usually only use these routines for small assets (such as storing internal data for such things such as character information), it's never been too much of an issue for me.  Just be aware:  Large files can take a while to process with this method -- especially on an older, slower machine.
Title: Re: Base 64 encoder
Post by: NOVARSEG on December 17, 2020, 06:50:44 pm
with base 256 to base 64 conversion, it will  require 4 base 64 characters to encode 3 bytes.

with base 256 to base 128 conversion, it will require 4 base 128 characters to encode 3 bytes.

4 characters are required for both methods

base 256 to base 64 conversion is exactly efficient because 256^3 = 64^4

Any encoded characters like "," or quotes, can be mapped to other characters which is much easier since there are only 64 characters in the encoding set.
Title: Re: Base 64 encoder
Post by: SMcNeill on December 17, 2020, 07:48:21 pm
with base 256 to base 64 conversion, it will  require 4 base 64 characters to encode 3 bytes.

with base 256 to base 128 conversion, it will require 4 base 128 characters to encode 3 bytes.

4 characters are required for both methods

base 256 to base 64 conversion is exactly efficient because 256^3 = 64^4

Any encoded characters like "," or quotes, can be mapped to other characters which is much easier since there are only 64 characters in the encoding set.

Base 64 lets you pack 6 bits of data per character.
Base 128 lets you pack 7 bits of data per character.

So 7 bytes of ASCII data is 56-BITS.

In base-64, you'll need 56/6 = 10 characters to hold your data.  (Round up, as you don't have fractional characters.)

In base-128, you'll need 56/7 = 8 characters to hold your data. 

It's simple to see how base-128 packs more data into 7-bits than base-64 can pack into 6-bits.

How often are you converting ONLY 3 bytes?  Why not convert a whole row of pixels at once?  Or the whole screen?  No need to do pixel by pixel, when you can do image by image.
Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 17, 2020, 10:00:41 pm
SMcNeill

Hi
In the previous example I'm processing 3 bytes at a time.

For longer strings say 21 bytes * 8 = 168 bits

base 64 encoding would require 28 characters

Putting the 21 bytes into 7 bit bytes would require  only 24 characters

So that is 14.2% smaller encoding for the 7 bit method.

***************
In a convertor that Dav posted the encoded data looks to be base 64. Here is a bit of code from his convertor.

   
Quote
A$ = A$ + "8d;ai7=B`OhkhbAWZm^?Fbe6f0W?h7feD]G466?ShkeZZW3K;QCaWihI9W;b"
    A$ = A$ + "m7>F^WijPf?n<[cniJbW=]JNo=`efa5IkHO:\:hK`cP[1WSWQlL;oH2edC1C"
    A$ = A$ + "RWe`X`^Ah<df0J?9fHHG>Uf:aCK9X=SfEH9oghnoIT6[dl==i<0]513JdFZF"
    A$ = A$ + "J[dL\g7hoVf;;GYSbeoo[Y#?aO#e;iaGn9YJgl`V>EKUKf^17RH4R69RI0a3"
    A$ = A$ + "H\V;AOG;C;FShWNlA?7?O^oJcanNNR=IRbe6ZEii?g0BFQ6TLg9jEnYO__Ul"
    A$ = A$ + "gn7mk:O_?ok;OQGlnb[Om;:_be?_l_jCoZbgi;nITk<aPfkdn?oI9;MJ?SaW"
    A$ = A$ + "Xo1n;K6coLUIm\CAVcDWZ\\i?OIQcIfR?;HnbbFlRlDlI9b9>jQTSOT38[Ni"
    A$ = A$ + ";FFa2V[\YE^2eN[E9Kc_EJfd6PZKJk:_Jo[OEbagF0VV2G<c;#]W>g4>Q5cK"
    A$ = A$ + "\IRo3Q]0Wa]=n<[CaC<g?VIK5U2lVS`XYiYm14eGQUh\KS2eOMjUH9n?1MGH"
    A$ = A$ + "38<#HB=DXfnH9I;iYJb8_3Yn1e=XnbPeGaTnN9Ge>WJb#]W9g<dg=EKLR?:k"
    A$ = A$ + "H;8fCJea:9aH\SSmAMdRC8JS=DJBaJJJZ;kd\j`lIHMiYf7Q=<dFNmh_jdRc"
    A$ = A$ + "N_7MED7ZV<CdhB`Thc`ZQiRo\QMbkEh?9>g3DGijcg`<o9ae0^XSS`faGC\M"

The encoded bytes range from ASC 48  "0"  to ASC 111 "o".  111 - 48  = 63 (64 characters). In that range, the comma and quotes are avoided.

However, the base 128 encoding packs in more data.

Title: Re: Base 64 encoder / decoder
Post by: SMcNeill on December 17, 2020, 10:13:41 pm
If you're curious, here's where Petr and I had a nice discussion over Base64 encoding/decoding: https://www.qb64.org/forum/index.php?topic=2017.msg112422#msg112422
Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 17, 2020, 11:06:14 pm
I just fixed major bugs in my code up top.  It works now.

I read the link you posted. 

 7 bytes = 8  (7 bit) bytes Ok I will try that.



Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 18, 2020, 01:01:25 am
Here is a  base 256 to base 128 encoder.
Does not decode yet.   Encodes 7 bytes at a time.

Code: QB64: [Select]
  1.  'BASE 128 encoder
  2.  
  3. DIM b8, b7, b6, b5, b4, b3, b2, b1 AS INTEGER
  4.  
  5.  
  6. DIM string1 AS STRING 'input string
  7. DIM string2 AS STRING 'output string
  8. '
  9. string1 = "ASCII stands for American Standard Code for Information Interchange..."
  10. PRINT LEN(string1) 'must be a multiple of 7
  11.  
  12. PRINT "STRING1 "; string1
  13.  
  14. n = 45 'offset into ASCII table
  15.  
  16.  
  17. FOR x% = 1 TO LEN(string1) STEP 7
  18.     b7 = ASC(MID$(string1, x%, 1))
  19.     b6 = ASC(MID$(string1, x% + 1, 1))
  20.     b5 = ASC(MID$(string1, x% + 2, 1))
  21.     b4 = ASC(MID$(string1, x% + 3, 1))
  22.     b3 = ASC(MID$(string1, x% + 4, 1))
  23.     b2 = ASC(MID$(string1, x% + 5, 1))
  24.     b1 = ASC(MID$(string1, x% + 6, 1))
  25.  
  26.  
  27.     IF b7 >= 128 THEN
  28.         b8 = 64
  29.         b7 = b7 - 128
  30.     END IF
  31.     s7 = CHR$(b7 + n)
  32.  
  33.     IF b6 >= 128 THEN
  34.         b8 = b8 + 32
  35.         b6 = b6 - 128
  36.     END IF
  37.     s6 = CHR$(b6 + n)
  38.  
  39.     IF b5 >= 128 THEN
  40.         b8 = b8 + 16
  41.         b5 = b5 - 128
  42.     END IF
  43.     s5 = CHR$(b5 + n)
  44.  
  45.     IF b4 >= 128 THEN
  46.         b8 = b8 + 8
  47.         b4 = b4 - 128
  48.     END IF
  49.     s4 = CHR$(b4 + n)
  50.  
  51.     IF b3 >= 128 THEN
  52.         b8 = b8 + 4
  53.         b3 = b3 - 128
  54.     END IF
  55.     s3 = CHR$(b3 + n)
  56.  
  57.     IF b2 >= 128 THEN
  58.         b8 = b8 + 2
  59.         b2 = b2 - 128
  60.     END IF
  61.     s2 = CHR$(b2 + n)
  62.  
  63.     IF b1 >= 128 THEN
  64.         b8 = b8 + 1
  65.         b1 = b1 - 128
  66.     END IF
  67.     s1 = CHR$(b1 + n)
  68.  
  69.     s8 = CHR$(b8+n)
  70.    
  71.     string2 = string2 + (s8 + s7 + s6 + s5 + s4 + s3 + s2 + s1)
  72. NEXT x%
  73.  
  74.  
  75. PRINT string2
  76.  
  77.  

Title: Re: Base 64 encoder / decoder
Post by: SpriggsySpriggs on December 18, 2020, 08:28:02 am
@NOVARSEG

My API collection has WinAPI code for encoding and decoding in Base 64. Feel free to check it out.
Title: Re: Base 64 encoder / decoder
Post by: SMcNeill on December 18, 2020, 09:53:50 am
@NOVARSEG

My API collection has WinAPI code for encoding and decoding in Base 64. Feel free to check it out.

@SpriggsySpriggs -- I was looking at your encoder/decoder...  Are you certain you need to add a CHR$(0) to the code?

        encode = encode + CHR$(0)

This isn't a null-terminated C-function; you have to specify the length of the string for it to work properly.  As it is, you're adding characters to your conversion routines, as below:

Code: QB64: [Select]
  1.  
  2. DIM encode AS STRING
  3. PRINT "My name is Inigo Montoya", LEN("My name is Inigo Montoya")
  4. encode = encodeBase64("My name is Inigo Montoya")
  5.  
  6. PRINT encode, LEN(encode)
  7.  
  8. DIM decode AS STRING
  9. decode = decodeBase64(encode)
  10.  
  11. PRINT decode, LEN(decode)
  12.  
  13.  
  14. $IF WIN THEN
  15.     'DECLARE LIBRARY ".\pipecom"
  16.     '    FUNCTION pipecom$ (cmd AS STRING)
  17.     'END DECLARE
  18.     'FUNCTION encodeBase64$ (encode AS STRING)
  19.     '    DIM encoded AS STRING
  20.     '    DIM encodefile AS INTEGER
  21.     '    encodefile = FREEFILE
  22.     '    OPEN "3nc0deb64" FOR OUTPUT AS #encodefile
  23.     '    PRINT #encodefile, encode
  24.     '    CLOSE #encodefile
  25.     '    encoded = pipecom("certutil -encode 3nc0deb64 3nc0dedb64 && type 3nc0dedb64 && del 3nc0dedb64 && del 3nc0deb64")
  26.     '    encoded = MID$(encoded, INSTR(encoded, "-----BEGIN CERTIFICATE-----") + LEN("-----BEGIN CERTIFICATE-----") + 1)
  27.     '    encoded = MID$(encoded, 1, INSTR(encoded, "-----END CERTIFICATE-----") - 2)
  28.     '    encodeBase64 = encoded
  29.     'END FUNCTION
  30.  
  31.     'FUNCTION decodeBase64$ (decode AS STRING)
  32.     '    DIM decoded AS STRING
  33.     '    DIM decodefile AS INTEGER
  34.     '    decodefile = FREEFILE
  35.     '    OPEN "d3c0deb64" FOR OUTPUT AS #decodefile
  36.     '    PRINT #decodefile, decode
  37.     '    CLOSE #decodefile
  38.     '    decoded = pipecom("certutil -decode d3c0deb64 d3c0dedb64 && type d3c0dedb64 && del d3c0deb64 && del d3c0dedb64")
  39.     '    decoded = MID$(decoded, _INSTRREV(decoded, "successfully.") + 1 + LEN("successfully."))
  40.     '    decoded = MID$(decoded, 1, LEN(decoded) - 1)
  41.     '    decodeBase64 = decoded
  42.     'END FUNCTION
  43.  
  44.     DECLARE DYNAMIC LIBRARY "Crypt32"
  45.         FUNCTION CryptBinaryToString%% ALIAS CryptBinaryToStringA (BYVAL pbBinary AS _OFFSET, BYVAL cbBinary AS LONG, BYVAL dwFlags AS LONG, BYVAL pszString AS _OFFSET, BYVAL pcchString AS _OFFSET)
  46.         FUNCTION CryptStringToBinary%% ALIAS CryptStringToBinaryA (BYVAL pszString AS _OFFSET, BYVAL cchString AS LONG, BYVAL dwFlags AS LONG, BYVAL pbBinary AS _OFFSET, BYVAL pcbBinary AS _OFFSET, BYVAL pdwSkip AS _OFFSET, BYVAL pdwFlags AS _OFFSET)
  47.     END DECLARE
  48.  
  49.     FUNCTION encodeBase64$ (encode AS STRING)
  50.         CONST CRYPT_STRING_NOCRLF = &H40000000
  51.         CONST CRYPT_STRING_BASE64 = &H00000001
  52.  
  53.         DIM a AS _BYTE
  54.         DIM lengthencode AS LONG
  55.         DIM encoded AS STRING
  56.         DIM lengthencoded AS LONG
  57.  
  58.         encode = encode + CHR$(0)
  59.         lengthencode = LEN(encode)
  60.  
  61.         a = CryptBinaryToString(_OFFSET(encode), lengthencode, CRYPT_STRING_BASE64 OR CRYPT_STRING_NOCRLF, 0, _OFFSET(lengthencoded))
  62.         'Calculate buffer length
  63.         IF a <> 0 THEN
  64.             encoded = SPACE$(lengthencoded)
  65.         ELSE
  66.             encodeBase64 = ""
  67.             EXIT FUNCTION
  68.         END IF
  69.         a = CryptBinaryToString(_OFFSET(encode), lengthencode, CRYPT_STRING_BASE64 OR CRYPT_STRING_NOCRLF, _OFFSET(encoded), _OFFSET(lengthencoded))
  70.         'Acual conversion
  71.         IF a <> 0 THEN
  72.             encodeBase64 = encoded
  73.         ELSE
  74.             encodeBase64 = ""
  75.         END IF
  76.  
  77.     FUNCTION decodeBase64$ (decode AS STRING)
  78.         CONST CRYPT_STRING_BASE64_ANY = &H00000006
  79.  
  80.         DIM a AS _BYTE
  81.         DIM lengthdecode AS LONG
  82.         DIM decoded AS STRING
  83.         DIM lengthdecoded AS LONG
  84.  
  85.         decode = decode + CHR$(0)
  86.         lengthdecode = LEN(decode) - 1
  87.         a = CryptStringToBinary(_OFFSET(decode), lengthdecode, CRYPT_STRING_BASE64_ANY, 0, _OFFSET(lengthdecoded), 0, 0)
  88.         'Calculate buffer length
  89.         IF a <> 0 THEN
  90.             decoded = SPACE$(lengthdecoded)
  91.         ELSE
  92.             decodeBase64 = ""
  93.             EXIT FUNCTION
  94.         END IF
  95.         a = CryptStringToBinary(_OFFSET(decode), lengthdecode, CRYPT_STRING_BASE64_ANY, _OFFSET(decoded), _OFFSET(lengthdecoded), 0, 0)
  96.         'Actual conversion
  97.         IF a <> 0 THEN
  98.             decodeBase64 = decoded
  99.         ELSE
  100.             decodeBase64 = ""
  101.         END IF
  102.     DECLARE LIBRARY "./pipecom"
  103.     FUNCTION pipecom$ (cmd AS STRING)
  104.     END DECLARE
  105.  
  106.     FUNCTION encodeBase64$ (encode AS STRING)
  107.     DIM encoded AS STRING
  108.     DIM encodefile AS INTEGER
  109.     encodefile = FREEFILE
  110.     OPEN "3nc0deb64" FOR OUTPUT AS #encodefile
  111.     PRINT #encodefile, encode
  112.     CLOSE #encodefile
  113.     encoded = pipecom("base64 3nc0deb64")
  114.     KILL "3nc0deb64"
  115.     encodeBase64 = MID$(encoded, 1, LEN(encoded) - 1)
  116.  
  117.     FUNCTION decodeBase64$ (decode AS STRING)
  118.     DIM decoded AS STRING
  119.     DIM decodefile AS INTEGER
  120.     decodefile = FREEFILE
  121.     OPEN "d3c0deb64" FOR OUTPUT AS #decodefile
  122.     PRINT #decodefile, decode
  123.     CLOSE #decodefile
  124.     decoded = pipecom("base64 -d d3c0deb64")
  125.     KILL "d3c0deb64"
  126.     decodeBase64 = decoded

If you notice, you've tacked a stray CHR$(0) onto the end of the decoded results. 
Title: Re: Base 64 encoder / decoder
Post by: SpriggsySpriggs on December 18, 2020, 09:58:07 am
@SMcNeill

https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptstringtobinarya (https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptstringtobinarya)

What I should have done instead is make the length argument be zero or just not do a CHR$(0). I think there might have been issues and that's why I did that but feel free to comment that one line out.
Title: Re: Base 64 encoder / decoder
Post by: SpriggsySpriggs on December 18, 2020, 10:04:36 am
@SMcNeill

Yeah, I just got used to having to do null-terminated strings. I'll fix the code in the zip folder momentarily.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Code: QB64: [Select]
  1. 'DIM encode AS STRING
  2. 'encode = encodeBase64("My name is Inigo Montoya")
  3. DIM encoded AS STRING
  4. 'PRINT encode
  5.     LINE INPUT "Input Base64 String: ", encoded
  6. LOOP UNTIL encoded <> ""
  7. DIM decode AS STRING
  8. decode = decodeBase64(encoded)
  9.  
  10. PRINT decode
  11.  
  12. $IF WIN THEN
  13.     'DECLARE LIBRARY ".\pipecom"
  14.     '    FUNCTION pipecom$ (cmd AS STRING)
  15.     'END DECLARE
  16.     'FUNCTION encodeBase64$ (encode AS STRING)
  17.     '    DIM encoded AS STRING
  18.     '    DIM encodefile AS INTEGER
  19.     '    encodefile = FREEFILE
  20.     '    OPEN "3nc0deb64" FOR OUTPUT AS #encodefile
  21.     '    PRINT #encodefile, encode
  22.     '    CLOSE #encodefile
  23.     '    encoded = pipecom("certutil -encode 3nc0deb64 3nc0dedb64 && type 3nc0dedb64 && del 3nc0dedb64 && del 3nc0deb64")
  24.     '    encoded = MID$(encoded, INSTR(encoded, "-----BEGIN CERTIFICATE-----") + LEN("-----BEGIN CERTIFICATE-----") + 1)
  25.     '    encoded = MID$(encoded, 1, INSTR(encoded, "-----END CERTIFICATE-----") - 2)
  26.     '    encodeBase64 = encoded
  27.     'END FUNCTION
  28.  
  29.     'FUNCTION decodeBase64$ (decode AS STRING)
  30.     '    DIM decoded AS STRING
  31.     '    DIM decodefile AS INTEGER
  32.     '    decodefile = FREEFILE
  33.     '    OPEN "d3c0deb64" FOR OUTPUT AS #decodefile
  34.     '    PRINT #decodefile, decode
  35.     '    CLOSE #decodefile
  36.     '    decoded = pipecom("certutil -decode d3c0deb64 d3c0dedb64 && type d3c0dedb64 && del d3c0deb64 && del d3c0dedb64")
  37.     '    decoded = MID$(decoded, _INSTRREV(decoded, "successfully.") + 1 + LEN("successfully."))
  38.     '    decoded = MID$(decoded, 1, LEN(decoded) - 1)
  39.     '    decodeBase64 = decoded
  40.     'END FUNCTION
  41.  
  42.     DECLARE DYNAMIC LIBRARY "Crypt32"
  43.         FUNCTION CryptBinaryToString%% ALIAS CryptBinaryToStringA (BYVAL pbBinary AS _OFFSET, BYVAL cbBinary AS LONG, BYVAL dwFlags AS LONG, BYVAL pszString AS _OFFSET, BYVAL pcchString AS _OFFSET)
  44.         FUNCTION CryptStringToBinary%% ALIAS CryptStringToBinaryA (BYVAL pszString AS _OFFSET, BYVAL cchString AS LONG, BYVAL dwFlags AS LONG, BYVAL pbBinary AS _OFFSET, BYVAL pcbBinary AS _OFFSET, BYVAL pdwSkip AS _OFFSET, BYVAL pdwFlags AS _OFFSET)
  45.     END DECLARE
  46.  
  47.     FUNCTION encodeBase64$ (encode AS STRING)
  48.         CONST CRYPT_STRING_NOCRLF = &H40000000
  49.         CONST CRYPT_STRING_BASE64 = &H00000001
  50.  
  51.         DIM a AS _BYTE
  52.         DIM lengthencode AS LONG
  53.         DIM encoded AS STRING
  54.         DIM lengthencoded AS LONG
  55.  
  56.         lengthencode = LEN(encode)
  57.  
  58.         a = CryptBinaryToString(_OFFSET(encode), lengthencode, CRYPT_STRING_BASE64 OR CRYPT_STRING_NOCRLF, 0, _OFFSET(lengthencoded))
  59.         'Calculate buffer length
  60.         IF a <> 0 THEN
  61.             encoded = SPACE$(lengthencoded)
  62.         ELSE
  63.             encodeBase64 = ""
  64.             EXIT FUNCTION
  65.         END IF
  66.         a = CryptBinaryToString(_OFFSET(encode), lengthencode, CRYPT_STRING_BASE64 OR CRYPT_STRING_NOCRLF, _OFFSET(encoded), _OFFSET(lengthencoded))
  67.         'Acual conversion
  68.         IF a <> 0 THEN
  69.             encodeBase64 = encoded
  70.         ELSE
  71.             encodeBase64 = ""
  72.         END IF
  73.  
  74.     FUNCTION decodeBase64$ (decode AS STRING)
  75.         CONST CRYPT_STRING_BASE64_ANY = &H00000006
  76.  
  77.         DIM a AS _BYTE
  78.         DIM lengthdecode AS LONG
  79.         DIM decoded AS STRING
  80.         DIM lengthdecoded AS LONG
  81.  
  82.         lengthdecode = LEN(decode)
  83.         a = CryptStringToBinary(_OFFSET(decode), lengthdecode, CRYPT_STRING_BASE64_ANY, 0, _OFFSET(lengthdecoded), 0, 0)
  84.         'Calculate buffer length
  85.         IF a <> 0 THEN
  86.             decoded = SPACE$(lengthdecoded)
  87.         ELSE
  88.             decodeBase64 = ""
  89.             EXIT FUNCTION
  90.         END IF
  91.         a = CryptStringToBinary(_OFFSET(decode), lengthdecode, CRYPT_STRING_BASE64_ANY, _OFFSET(decoded), _OFFSET(lengthdecoded), 0, 0)
  92.         'Actual conversion
  93.         IF a <> 0 THEN
  94.             decodeBase64 = decoded
  95.         ELSE
  96.             decodeBase64 = ""
  97.         END IF
  98.     DECLARE LIBRARY "./pipecom"
  99.     FUNCTION pipecom$ (cmd AS STRING)
  100.     END DECLARE
  101.  
  102.     FUNCTION encodeBase64$ (encode AS STRING)
  103.     DIM encoded AS STRING
  104.     DIM encodefile AS INTEGER
  105.     encodefile = FREEFILE
  106.     OPEN "3nc0deb64" FOR OUTPUT AS #encodefile
  107.     PRINT #encodefile, encode
  108.     CLOSE #encodefile
  109.     encoded = pipecom("base64 3nc0deb64")
  110.     KILL "3nc0deb64"
  111.     encodeBase64 = MID$(encoded, 1, LEN(encoded) - 1)
  112.  
  113.     FUNCTION decodeBase64$ (decode AS STRING)
  114.     DIM decoded AS STRING
  115.     DIM decodefile AS INTEGER
  116.     decodefile = FREEFILE
  117.     OPEN "d3c0deb64" FOR OUTPUT AS #decodefile
  118.     PRINT #decodefile, decode
  119.     CLOSE #decodefile
  120.     decoded = pipecom("base64 -d d3c0deb64")
  121.     KILL "d3c0deb64"
  122.     decodeBase64 = decoded
Title: Re: Base 64 encoder / decoder
Post by: SMcNeill on December 18, 2020, 10:13:36 am
One more pointer, which might be of interest to you:  When passing pointers, you can just declare it without BYVAL.

Instead of:
  FUNCTION CryptBinaryToString%% ALIAS CryptBinaryToStringA (BYVAL pbBinary AS _OFFSET....

You can go with:
  FUNCTION CryptBinaryToString%% ALIAS CryptBinaryToStringA (pbBinary AS STRING....

Then when you call the function, instead of this:
a = CryptBinaryToString(_OFFSET(encode)....

It'd be:
a = CryptBinaryToString(encode....




It might be a trick to help simplify your libraries a bit, and cut down on some typing for you.  (Not just on strings, but all cases where pointers to something is required, rather than the actual data value itself.)

Not that what you're doing is wrong; I just thought you might not realize WHY that BYVAL is there, and what we do when it's not.  ;)

With BYVAL, we pass the value.
Without it, we pass the offset to whatever.
Title: Re: Base 64 encoder / decoder
Post by: SpriggsySpriggs on December 18, 2020, 10:21:31 am
@SMcNeill

Yeah, I know I can. I typically pass _OFFSETs unless it is more convenient for myself to just pass it as text rather than a variable (usually it isn't, due to the number of arguments, so I just write a wrapper that does all that B.S.). So instead of foo(_OFFSET(stringvalue$)) I would just do foo("this is my string"). I try to stay consistent with my code. Since I've done almost all of my code using _OFFSET rather than passing the string itself I just go ahead and keep using _OFFSETs unless absolutely necessary. I don't mind the extra typing. I passed this variable as a string for this particular function (different topic) because it didn't require a null character at the end and would be too much work for a 3 character string.

Code: QB64: [Select]
  1. GetDiskFreeSpace("L:\", 0, 0, _OFFSET(totalFreeBytesOnDisk))

But yeah, I typically don't pass a string to a function without _OFFSET unless I pass it as plain text.
Title: Re: Base 64 encoder / decoder
Post by: Dav on December 18, 2020, 10:25:35 am
This thread has re-sparked my interest in binary to text encoders.  Always looking for something better than base64 to output code safe to post on forums.  Has anyone tried to implement base91 before? 

Edit: Nevermind-- looks like base91 is patented (https://patents.google.com/patent/US20030152220A1/en).

- Dav
Title: Re: Base 64 encoder / decoder
Post by: SMcNeill on December 18, 2020, 10:33:45 am
@Dav

You posted an encoding routine which you use, a while back, which:

Quote
The encoded bytes range from ASC 48  "0"  to ASC 111 "o".  111 - 48  = 63 (64 characters). In that range, the comma and quotes are avoided.

I had a similar method going for my stuff, but then I ran into an issue, which might affect your encoder as well:

58 is ":", which in QB64 is a command separator.

My solution was simply to change my code so that it started at 59 instead, and thus that problem is forever avoided and I don't have to enclose the output in quotes if I want to use it for something like DATA statements.  ;)
Title: Re: Base 64 encoder / decoder
Post by: Dav on December 18, 2020, 10:40:04 am
Thanks for the tip, @SMcNeill.  Yes, I would need to change that if my output wasn't in quotes.  One problem I did have to fix in my last few encoders here was using the @ symbol.  That was interfering with posted code because of the forums way of using @ to note members, so I had to swap it out with an unused character.

Edit: Thread about the @ problem here (https://www.qb64.org/forum/index.php?topic=2589.0).

- Dav
Title: Re: Base 64 encoder / decoder
Post by: SpriggsySpriggs on December 18, 2020, 11:54:06 am
One problem I did have to fix in my last few encoders here was using the @ symbol.  That was interfering with posted code because of the forums way of using @ to note members, so I had to swap it out with an unused character.

@Dav

I remember that! It feels like such a long time ago. Your code revolutionized includes for me.

By the way, how did you hide the URL and show just "here"? I haven't figured out how to do that. Never mind. Figured out how to do that (https://wiki.simplemachines.org/smf/Url)
Title: Re: Base 64 encoder / decoder
Post by: bplus on December 18, 2020, 12:31:33 pm
I found we were on this very same subject last year! Petr and AndyA were doing things.

I am wondering if all this data packing slows program loads?
Title: Re: Base 64 encoder / decoder
Post by: Petr on December 18, 2020, 01:05:07 pm
Quote
I am wondering if all this data packing slows program loads?

My version slows down, AndyA's version practically not at all. This is the difference between using the logical AND operator (AndyA version) and / or strings (my version).
Title: Re: Base 64 encoder / decoder
Post by: Dav on December 18, 2020, 01:19:13 pm
I haven't tested mine for speed, but I imagine it's slow as molasses. Not familiar with AndyA's version (I didn't hang around here too much last year) but I'll search for it.   Maybe these encoding schemes would make a good test in a benchmark program!

- Dav
Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 18, 2020, 04:43:02 pm
Here is base 256 to base 128 encoder / decoder


detected bug . . . .fixed

Code: QB64: [Select]
  1. 'BASE 128 encoder  / decoder
  2. 'input string is encoded then decoded
  3.  
  4. DIM b8, b7, b6, b5, b4, b3, b2, b1 AS INTEGER
  5. DIM string1 AS STRING 'input string
  6. DIM string2 AS STRING 'output string
  7. string1 = "ASCII stands for American Standard Code for Information Interchange..." + CHR$(166) + CHR$(167) + CHR$(168) + CHR$(169) + CHR$(170) + CHR$(171) + CHR$(172)
  8. 'string1 = "ASCII stands for American Standard Code for Information Interchange..."
  9.  
  10. 'string1 must be a multiple of 7 bytes
  11.  
  12. PRINT "string1"
  13. PRINT string1
  14. n = 45 'offset into ASCII table
  15.  
  16. 'Encode
  17. FOR x% = 1 TO LEN(string1) STEP 7
  18.     b7 = ASC(MID$(string1, x%, 1))
  19.     b6 = ASC(MID$(string1, x% + 1, 1))
  20.     b5 = ASC(MID$(string1, x% + 2, 1))
  21.     b4 = ASC(MID$(string1, x% + 3, 1))
  22.     b3 = ASC(MID$(string1, x% + 4, 1))
  23.     b2 = ASC(MID$(string1, x% + 5, 1))
  24.     b1 = ASC(MID$(string1, x% + 6, 1))
  25.  
  26.     IF b7 >= 128 THEN
  27.         b7 = b7 - 128
  28.         b8 = 64
  29.     END IF
  30.     s7 = CHR$(b7 + n)
  31.  
  32.     IF b6 >= 128 THEN
  33.         b6 = b6 - 128
  34.         b8 = b8 + 32
  35.     END IF
  36.     s6 = CHR$(b6 + n)
  37.  
  38.     IF b5 >= 128 THEN
  39.         b5 = b5 - 128
  40.         b8 = b8 + 16
  41.     END IF
  42.     s5 = CHR$(b5 + n)
  43.  
  44.     IF b4 >= 128 THEN
  45.         b4 = b4 - 128
  46.         b8 = b8 + 8
  47.     END IF
  48.     s4 = CHR$(b4 + n)
  49.  
  50.     IF b3 >= 128 THEN
  51.         b3 = b3 - 128
  52.         b8 = b8 + 4
  53.     END IF
  54.     s3 = CHR$(b3 + n)
  55.  
  56.     IF b2 >= 128 THEN
  57.         b2 = b2 - 128
  58.         b8 = b8 + 2
  59.     END IF
  60.     s2 = CHR$(b2 + n)
  61.  
  62.     IF b1 >= 128 THEN
  63.         b1 = b1 - 128
  64.         b8 = b8 + 1
  65.     END IF
  66.     s1 = CHR$(b1 + n)
  67.  
  68.     s8 = CHR$(b8 + n)
  69.  
  70.     string2 = string2 + (s8 + s7 + s6 + s5 + s4 + s3 + s2 + s1)
  71.  
  72. NEXT x%
  73.  
  74. string1 = ""
  75.  
  76. PRINT "string1 encoded"
  77. PRINT string2
  78.  
  79.  
  80. 'Decode
  81. FOR x% = 1 TO LEN(string2) STEP 8
  82.  
  83.     b8 = ASC(MID$(string2, x%, 1)) - n
  84.     b7 = ASC(MID$(string2, x% + 1, 1)) - n
  85.     b6 = ASC(MID$(string2, x% + 2, 1)) - n
  86.     b5 = ASC(MID$(string2, x% + 3, 1)) - n
  87.     b4 = ASC(MID$(string2, x% + 4, 1)) - n
  88.     b3 = ASC(MID$(string2, x% + 5, 1)) - n
  89.     b2 = ASC(MID$(string2, x% + 6, 1)) - n
  90.     b1 = ASC(MID$(string2, x% + 7, 1)) - n
  91.  
  92.     IF b8 >= 64 THEN
  93.         b8 = b8 - 64
  94.         b7 = b7 + 128
  95.     END IF
  96.     s7 = CHR$(b7)
  97.  
  98.     IF b8 >= 32 THEN
  99.         b8 = b8 - 32
  100.         b6 = b6 + 128
  101.     END IF
  102.     s6 = CHR$(b6)
  103.  
  104.     IF b8 >= 16 THEN
  105.         b8 = b8 - 16
  106.         b5 = b5 + 128
  107.     END IF
  108.     s5 = CHR$(b5)
  109.  
  110.     IF b8 >= 8 THEN
  111.         b8 = b8 - 8
  112.         b4 = b4 + 128
  113.     END IF
  114.     s4 = CHR$(b4)
  115.  
  116.     IF b8 >= 4 THEN
  117.         b8 = b8 - 4
  118.         b3 = b3 + 128
  119.     END IF
  120.     s3 = CHR$(b3)
  121.  
  122.     IF b8 >= 2 THEN
  123.         b8 = b8 - 2
  124.         b2 = b2 + 128
  125.     END IF
  126.     s2 = CHR$(b2)
  127.  
  128.     IF b8 >= 1 THEN
  129.         b8 = b8 - 1
  130.         b1 = b1 + 128
  131.     END IF
  132.     s1 = CHR$(b1)
  133.  
  134.     string1 = string1 + (s7 + s6 + s5 + s4 + s3 + s2 + s1)
  135.  
  136.  
  137. NEXT x%
  138.  
  139. PRINT "decoded"
  140. "
  141. PRINT string1
  142. PRINT
  143. PRINT
  144.  
  145. END
  146.  
Title: Re: Base 64 encoder / decoder
Post by: bplus on December 18, 2020, 06:47:51 pm
Quote
FOR x% = 1 TO LEN(string1) STEP 7
    b7 = ASC(MID$(string1, x%, 1))
    b6 = ASC(MID$(string1, x% + 1, 1))
    b5 = ASC(MID$(string1, x% + 2, 1))
    b4 = ASC(MID$(string1, x% + 3, 1))
    b3 = ASC(MID$(string1, x% + 4, 1))
    b2 = ASC(MID$(string1, x% + 5, 1))
    b1 = ASC(MID$(string1, x% + 6, 1))
Oh I think I see the error...

Anyway here is a tip:
Code: QB64: [Select]
  1. s$ = "string"
  2. FOR i = 1 TO LEN(s$)
  3.     PRINT ASC(s$, i); "  =  "; ASC(MID$(s$, i, 1)) '   <<<<<<<<<<<<< tip
Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 18, 2020, 07:35:59 pm
Thanks bplus

code updated

Code: QB64: [Select]
  1. 'BASE 128 encoder  / decoder
  2. 'input string is encoded then decoded
  3.  
  4. DIM b8, b7, b6, b5, b4, b3, b2, b1 AS INTEGER
  5. DIM string1 AS STRING 'input string
  6. DIM string2 AS STRING 'output string
  7. string1 = "ASCII stands for American Standard Code for Information Interchange..." + CHR$(166) + CHR$(167) + CHR$(168) + CHR$(169) + CHR$(170) + CHR$(171) + CHR$(172)
  8. 'string1 = "ASCII stands for American Standard Code for Information Interchange..."
  9.  
  10. 'string1 must be a multiple of 7 bytes
  11.  
  12. PRINT "string1"
  13. PRINT string1
  14. n = 45 'offset into ASCII table
  15.  
  16. 'Encode
  17. FOR x% = 1 TO LEN(string1) STEP 7
  18.  
  19.     b7 = ASC(string1, x%)
  20.     b6 = ASC(string1, x% + 1)
  21.     b5 = ASC(string1, x% + 2)
  22.     b4 = ASC(string1, x% + 3)
  23.     b3 = ASC(string1, x% + 4)
  24.     b2 = ASC(string1, x% + 5)
  25.     b1 = ASC(string1, x% + 6)
  26.  
  27.     IF b7 >= 128 THEN
  28.         b7 = b7 - 128
  29.         b8 = 64
  30.     END IF
  31.     s7 = CHR$(b7 + n)
  32.  
  33.     IF b6 >= 128 THEN
  34.         b6 = b6 - 128
  35.         b8 = b8 + 32
  36.     END IF
  37.     s6 = CHR$(b6 + n)
  38.  
  39.     IF b5 >= 128 THEN
  40.         b5 = b5 - 128
  41.         b8 = b8 + 16
  42.     END IF
  43.     s5 = CHR$(b5 + n)
  44.  
  45.     IF b4 >= 128 THEN
  46.         b4 = b4 - 128
  47.         b8 = b8 + 8
  48.     END IF
  49.     s4 = CHR$(b4 + n)
  50.  
  51.     IF b3 >= 128 THEN
  52.         b3 = b3 - 128
  53.         b8 = b8 + 4
  54.     END IF
  55.     s3 = CHR$(b3 + n)
  56.  
  57.     IF b2 >= 128 THEN
  58.         b2 = b2 - 128
  59.         b8 = b8 + 2
  60.     END IF
  61.     s2 = CHR$(b2 + n)
  62.  
  63.     IF b1 >= 128 THEN
  64.         b1 = b1 - 128
  65.         b8 = b8 + 1
  66.     END IF
  67.     s1 = CHR$(b1 + n)
  68.  
  69.     s8 = CHR$(b8 + n)
  70.  
  71.     string2 = string2 + (s8 + s7 + s6 + s5 + s4 + s3 + s2 + s1)
  72.  
  73. NEXT x%
  74.  
  75. string1 = ""
  76.  
  77. PRINT "string1 encoded"
  78. PRINT string2
  79.  
  80.  
  81. 'Decode
  82. FOR x% = 1 TO LEN(string2) STEP 8
  83.  
  84.     b8 = ASC(string2, x%) - n
  85.     b7 = ASC(string2, x% + 1) - n
  86.     b6 = ASC(string2, x% + 2) - n
  87.     b5 = ASC(string2, x% + 3) - n
  88.     b4 = ASC(string2, x% + 4) - n
  89.     b3 = ASC(string2, x% + 5) - n
  90.     b2 = ASC(string2, x% + 6) - n
  91.     b1 = ASC(string2, x% + 7) - n
  92.  
  93.     IF b8 >= 64 THEN
  94.         b8 = b8 - 64
  95.         b7 = b7 + 128
  96.     END IF
  97.     s7 = CHR$(b7)
  98.  
  99.     IF b8 >= 32 THEN
  100.         b8 = b8 - 32
  101.         b6 = b6 + 128
  102.     END IF
  103.     s6 = CHR$(b6)
  104.  
  105.     IF b8 >= 16 THEN
  106.         b8 = b8 - 16
  107.         b5 = b5 + 128
  108.     END IF
  109.     s5 = CHR$(b5)
  110.  
  111.     IF b8 >= 8 THEN
  112.         b8 = b8 - 8
  113.         b4 = b4 + 128
  114.     END IF
  115.     s4 = CHR$(b4)
  116.  
  117.     IF b8 >= 4 THEN
  118.         b8 = b8 - 4
  119.         b3 = b3 + 128
  120.     END IF
  121.     s3 = CHR$(b3)
  122.  
  123.     IF b8 >= 2 THEN
  124.         b8 = b8 - 2
  125.         b2 = b2 + 128
  126.     END IF
  127.     s2 = CHR$(b2)
  128.  
  129.     IF b8 >= 1 THEN
  130.         b8 = b8 - 1
  131.         b1 = b1 + 128
  132.     END IF
  133.     s1 = CHR$(b1)
  134.  
  135.     string1 = string1 + (s7 + s6 + s5 + s4 + s3 + s2 + s1)
  136.  
  137.  
  138. NEXT x%
  139.  
  140. PRINT "decoded"
  141. PRINT string1
  142.  
  143.  
Title: Re: Base 64 encoder / decoder
Post by: SMcNeill on December 18, 2020, 08:13:31 pm
One note:

DIM b8, b7, b6, b5, b4, b3, b2, b1 AS INTEGER

You do realize only b1 is an INTEGER?  The other b's are SINGLE.
Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 18, 2020, 09:57:47 pm
Thanks SMcNeill
It's amazing it still worked!

Updated

Code: QB64: [Select]
  1. 'BASE 128 encoder  / decoder
  2. 'input string is encoded then decoded
  3.  
  4.  
  5. DIM string1 AS STRING 'input string
  6. DIM string2 AS STRING 'output string
  7. string1 = "ASCII stands for American Standard Code for Information Interchange..." + CHR$(166) + CHR$(1) + CHR$(168) + CHR$(169) + CHR$(170) + CHR$(171) + CHR$(172)
  8. 'string1 = "ASCII stands for American Standard Code for Information Interchange..."
  9.  
  10. 'string1 must be a multiple of 7 bytes
  11.  
  12. PRINT "string1"
  13. PRINT string1
  14. n = 65 'offset into ASCII table  starts at asc 65 "A"  to  asc 192
  15. 'no quotes, comma, :, @
  16.  
  17. 'Encode
  18. FOR x% = 1 TO LEN(string1) STEP 7
  19.  
  20.     b7 = ASC(string1, x%)
  21.     b6 = ASC(string1, x% + 1)
  22.     b5 = ASC(string1, x% + 2)
  23.     b4 = ASC(string1, x% + 3)
  24.     b3 = ASC(string1, x% + 4)
  25.     b2 = ASC(string1, x% + 5)
  26.     b1 = ASC(string1, x% + 6)
  27.  
  28.     IF b7 >= 128 THEN
  29.         b7 = b7 - 128
  30.         b8 = 64
  31.     END IF
  32.     s7 = CHR$(b7 + n)
  33.  
  34.     IF b6 >= 128 THEN
  35.         b6 = b6 - 128
  36.         b8 = b8 + 32
  37.     END IF
  38.     s6 = CHR$(b6 + n)
  39.  
  40.     IF b5 >= 128 THEN
  41.         b5 = b5 - 128
  42.         b8 = b8 + 16
  43.     END IF
  44.     s5 = CHR$(b5 + n)
  45.  
  46.     IF b4 >= 128 THEN
  47.         b4 = b4 - 128
  48.         b8 = b8 + 8
  49.     END IF
  50.     s4 = CHR$(b4 + n)
  51.  
  52.     IF b3 >= 128 THEN
  53.         b3 = b3 - 128
  54.         b8 = b8 + 4
  55.     END IF
  56.     s3 = CHR$(b3 + n)
  57.  
  58.     IF b2 >= 128 THEN
  59.         b2 = b2 - 128
  60.         b8 = b8 + 2
  61.     END IF
  62.     s2 = CHR$(b2 + n)
  63.  
  64.     IF b1 >= 128 THEN
  65.         b1 = b1 - 128
  66.         b8 = b8 + 1
  67.     END IF
  68.     s1 = CHR$(b1 + n)
  69.  
  70.     s8 = CHR$(b8 + n)
  71.  
  72.     string2 = string2 + (s8 + s7 + s6 + s5 + s4 + s3 + s2 + s1)
  73.  
  74. NEXT x%
  75.  
  76. string1 = ""
  77.  
  78. PRINT "string1 encoded"
  79. PRINT string2
  80.  
  81.  
  82. 'Decode
  83. FOR x% = 1 TO LEN(string2) STEP 8
  84.  
  85.     b8 = ASC(string2, x%) - n
  86.     b7 = ASC(string2, x% + 1) - n
  87.     b6 = ASC(string2, x% + 2) - n
  88.     b5 = ASC(string2, x% + 3) - n
  89.     b4 = ASC(string2, x% + 4) - n
  90.     b3 = ASC(string2, x% + 5) - n
  91.     b2 = ASC(string2, x% + 6) - n
  92.     b1 = ASC(string2, x% + 7) - n
  93.  
  94.     IF b8 >= 64 THEN
  95.         b8 = b8 - 64
  96.         b7 = b7 + 128
  97.     END IF
  98.     s7 = CHR$(b7)
  99.  
  100.     IF b8 >= 32 THEN
  101.         b8 = b8 - 32
  102.         b6 = b6 + 128
  103.     END IF
  104.     s6 = CHR$(b6)
  105.  
  106.     IF b8 >= 16 THEN
  107.         b8 = b8 - 16
  108.         b5 = b5 + 128
  109.     END IF
  110.     s5 = CHR$(b5)
  111.  
  112.     IF b8 >= 8 THEN
  113.         b8 = b8 - 8
  114.         b4 = b4 + 128
  115.     END IF
  116.     s4 = CHR$(b4)
  117.  
  118.     IF b8 >= 4 THEN
  119.         b8 = b8 - 4
  120.         b3 = b3 + 128
  121.     END IF
  122.     s3 = CHR$(b3)
  123.  
  124.     IF b8 >= 2 THEN
  125.         b8 = b8 - 2
  126.         b2 = b2 + 128
  127.     END IF
  128.     s2 = CHR$(b2)
  129.  
  130.     IF b8 >= 1 THEN
  131.         b8 = b8 - 1
  132.         b1 = b1 + 128
  133.     END IF
  134.     s1 = CHR$(b1)
  135.  
  136.     string1 = string1 + (s7 + s6 + s5 + s4 + s3 + s2 + s1)
  137.  
  138.  
  139. NEXT x%
  140.  
  141. PRINT "decoded"
  142. PRINT string1
  143.  
  144.  
Title: Re: Base 64 encoder / decoder
Post by: Petr on December 19, 2020, 03:12:49 am
@Dav: Here is it: https://www.qb64.org/forum/index.php?topic=2041.0
Title: Re: Base 64 encoder / decoder
Post by: Dav on December 19, 2020, 07:45:39 am
@Dav: Here is it: https://www.qb64.org/forum/index.php?topic=2041.0

Thank you @Petr!

- Dav
Title: Re: Base 64 encoder / decoder
Post by: NOVARSEG on December 19, 2020, 10:11:41 pm
Base 256 to base 128 decoder using _SHR , _SHL,  AND

There are no conditional statements or loops other than one FOR NEXT which is need to process either 7 or 8 bytes at a time

How it works.  7 bytes are encoded at a time.  The MSB of the 7 input bytes form an 8th byte.

Decoding left shifts the 8th byte to obtain the MSB which is  added to the original byte.
Code should run pretty fast.

Code: QB64: [Select]
  1. 'BASE 128 encoder  / decoder   using _SHR , _SHL,  AND
  2. 'input string is encoded then decoded
  3.  
  4.  
  5. DIM string1 AS STRING
  6. DIM string2 AS STRING
  7.  
  8. string1 = "ASCII stands for American Standard Code for Information Interchange..." + CHR$(127) + CHR$(128) + CHR$(129) + CHR$(130) + CHR$(1) + CHR$(2) + CHR$(1)
  9.  
  10.  
  11. 'string1 must be a multiple of 7 bytes
  12.  
  13. PRINT "string1"
  14. PRINT string1
  15.  
  16. n = 65 'offset into ASCII table  starts at asc 65 "A"  to  asc 192
  17. 'no quotes, comma, :, @
  18.  
  19. 'Encode
  20. FOR x% = 1 TO LEN(string1) STEP 7
  21.  
  22.     b7 = ASC(string1, x%)
  23.     b6 = ASC(string1, x% + 1)
  24.     b5 = ASC(string1, x% + 2)
  25.     b4 = ASC(string1, x% + 3)
  26.     b3 = ASC(string1, x% + 4)
  27.     b2 = ASC(string1, x% + 5)
  28.     b1 = ASC(string1, x% + 6)
  29.  
  30.  
  31.     b8 = (128 AND b7) + b8
  32.     b8 = _SHR(b8, 1)
  33.     b7 = (b7 AND 127) + n
  34.  
  35.     b8 = (128 AND b6) + b8
  36.     b8 = _SHR(b8, 1)
  37.     b6 = (b6 AND 127) + n
  38.  
  39.     b8 = (128 AND b5) + b8
  40.     b8 = _SHR(b8, 1)
  41.     b5 = (b5 AND 127) + n
  42.  
  43.     b8 = (128 AND b4) + b8
  44.     b8 = _SHR(b8, 1)
  45.     b4 = (b4 AND 127) + n
  46.  
  47.     b8 = (128 AND b3) + b8
  48.     b8 = _SHR(b8, 1)
  49.     b3 = (b3 AND 127) + n
  50.  
  51.     b8 = (128 AND b2) + b8
  52.     b8 = _SHR(b8, 1)
  53.     b2 = (b2 AND 127) + n
  54.  
  55.     b8 = (128 AND b1) + b8
  56.     b8 = _SHR(b8, 1)
  57.     b1 = (b1 AND 127) + n
  58.  
  59.     b8 = b8 + n
  60.  
  61.  
  62.     string2 = string2 + (CHR$(b8) + CHR$(b7) + CHR$(b6) + CHR$(b5) + CHR$(b4) + CHR$(b3) + CHR$(b2) + CHR$(b1))
  63.  
  64.  
  65. NEXT x%
  66.  
  67. string1 = ""
  68.  
  69. PRINT "string1 encoded"
  70. PRINT string2
  71.  
  72.  
  73. 'Decode
  74. FOR x% = 1 TO LEN(string2) STEP 8
  75.  
  76.     b8 = ASC(string2, x%) - n
  77.     b7 = ASC(string2, x% + 1) - n
  78.     b6 = ASC(string2, x% + 2) - n
  79.     b5 = ASC(string2, x% + 3) - n
  80.     b4 = ASC(string2, x% + 4) - n
  81.     b3 = ASC(string2, x% + 5) - n
  82.     b2 = ASC(string2, x% + 6) - n
  83.     b1 = ASC(string2, x% + 7) - n
  84.  
  85.  
  86.     b8 = _SHL(b8, 1)
  87.     b1 = (128 AND b8) + b1
  88.  
  89.     b8 = _SHL(b8, 1)
  90.     b2 = (128 AND b8) + b2
  91.  
  92.     b8 = _SHL(b8, 1)
  93.     b3 = (128 AND b8) + b3
  94.  
  95.     b8 = _SHL(b8, 1)
  96.     b4 = (128 AND b8) + b4
  97.  
  98.     b8 = _SHL(b8, 1)
  99.     b5 = (128 AND b8) + b5
  100.  
  101.     b8 = _SHL(b8, 1)
  102.     b6 = (128 AND b8) + b6
  103.  
  104.     b8 = _SHL(b8, 1)
  105.     b7 = (128 AND b8) + b7
  106.  
  107.  
  108.     string1 = string1 + (CHR$(b7) + CHR$(b6) + CHR$(b5) + CHR$(b4) + CHR$(b3) + CHR$(b2) + CHR$(b1))
  109.  
  110. NEXT x%
  111.  
  112. PRINT "decoded"
  113. PRINT string1
  114.  
  115.