Very happy to announce an updated version to my base64 decoder. Before, operations were all string based and thus became very slow with very large strings. After utilizing memblocks and changing a few other things, I've managed to boost the speed. A lot. By over 1000x actually. My map data for zelda which once took 76,000 ms to just decode now takes about 60 ms or less! The code below contains 5 paragraphs of lorem ipsum, decoded in only 2ms.
Btw, this version only works in AppGameKit 2 because of setMemblockString()
Function list:
string = b64_encodeString(string)
string = b64_decodeString(string)
memblock _id = b64_decodeStringToMemblock(string)
bool = b64_isBase64(string)
March 8, 2017
- Added the rest of the functions and renamed the commands.
- Redesigned the data string so as to not break the code display in the forum
REM *************************************************
REM * Original Author: Randy Charles Morin
REM * Author's Website: http://www.kbcafe.com (2006)
REM *
REM * Ported from C++ to AGK by: Phaelax
REM * Website: http://zimnox.com
REM *
REM * Edited: Mar 08, 2017
REM * - Renamed functions
REM * - Added encoding functions
REM *
REM * Edited: Mar 03, 2017
REM * - Revised the functions to only work with bytes
REM * instead of string characters
REM * - decode64ToByteArray() now returns a memblock ID
REM *
REM * Edited: Feb 26, 2014
REM * - Added command decode64ToByteArray() to write
REM * decoded bytes to an array called B64[].
REM * Returns array size
REM *************************************************
REM *
REM * Functions
REM * --------------
REM * string = b64_encodeString(string)
REM * string = b64_decodeString(string)
REM * memblock _id = b64_decodeStringToMemblock(string)
REM * bool = b64_isBase64(string)
REM *
REM *************************************************
data$ = "TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gVmVzdGlidWx1b"
data$ = data$ + "SBxdWlzIHRlbXB1cyBvcmNpLg0KVmVzdGlidWx1bSBlc3QganVzdG8sIGZpbmlidXMgc2l0IGFtZXQgcG"
data$ = data$ + "9ydGEgcXVpcywgbWF4aW11cyBhIG1hZ25hLiBEdWlzIHVsbGFtY29ycGVyIGZlbGlzIGEgDQpkdWkgYWx"
data$ = data$ + "pcXVldCwgaW4gbGFjaW5pYSBuaXNsIHZlbmVuYXRpcy4gSW50ZWdlciB2ZWwgY29uZGltZW50dW0gcmlz"
data$ = data$ + "dXMuIEZ1c2NlIG1hbGVzdWFkYSBsb3JlbSBldQ0Kc2NlbGVyaXNxdWUgZmV1Z2lhdC4gTWF1cmlzIGFjI"
data$ = data$ + "GZlbGlzIG5vbiBkb2xvciB1bHRyaWNpZXMgdWx0cmljaWVzLiBQaGFzZWxsdXMgY29uc2VjdGV0dXIgaG"
data$ = data$ + "VuZHJlcml0DQpuaWJoIHZlbCB0aW5jaWR1bnQuIFV0IHZlbmVuYXRpcyBsaWJlcm8gYXJjdSwgc2VkIHR"
data$ = data$ + "yaXN0aXF1ZSBuaWJoIGZldWdpYXQgdmVsLiBWZXN0aWJ1bHVtIGF0DQptYXhpbXVzIHRvcnRvci4gU2Vk"
data$ = data$ + "IGFjY3Vtc2FuIGVzdCBzZWQgbGFjaW5pYSBmYWNpbGlzaXMuIFByb2luIGludGVyZHVtLCBtYXNzYSBwd"
data$ = data$ + "Wx2aW5hciBjdXJzdXMNCnBsYWNlcmF0LCBxdWFtIGVzdCBwbGFjZXJhdCBsaWd1bGEsIGZlcm1lbnR1bS"
data$ = data$ + "BsYW9yZWV0IHRvcnRvciBhcmN1IGVnZXQgZWxpdC4gRXRpYW0gaW4gdGVsbHVzIGlwc3VtLiANCnVpcyB"
data$ = data$ + "uaXNsIGxpZ3VsYSwgbWF4aW11cyBldCBuaWJoIG5vbiwgY29udmFsbGlzIHRpbmNpZHVudCBhcmN1Lg0K"
data$ = data$ + "DQpBbGlxdWFtIGVnZXQgc2FwaWVuIGNvbnNlcXVhdCwgcHVsdmluYXIgZG9sb3Igc2VkLCBsdWN0dXMgb"
data$ = data$ + "GVvLiBDcmFzIHZlbCBsb3JlbSB1cm5hLiBOdW5jDQpwaGFyZXRyYSBvcm5hcmUgbWF1cmlzIG1vbGVzdG"
data$ = data$ + "llIHBsYWNlcmF0LiBWZXN0aWJ1bHVtIHRpbmNpZHVudCBydXRydW0gYXVndWUgdXQgbGFjaW5pYS4gRnV"
data$ = data$ + "zY2UNCnZlbCBsYWNpbmlhIG5pc2ksIGluIG1hdHRpcyBtYXVyaXMuIFV0IHBoYXJldHJhIGxhY3VzIHF1"
data$ = data$ + "aXMgYXJjdSBjb25ndWUsIGFjIHB1bHZpbmFyIG51bmMgaW50ZXJkdW0uDQpOdWxsYW0gbW9sZXN0aWUgZ"
data$ = data$ + "XN0IGF0IGlwc3VtIHZlbmVuYXRpcywgbm9uIGF1Y3RvciByaXN1cyBhbGlxdWFtLiBNYXVyaXMgbm9uIG"
data$ = data$ + "ludGVyZHVtIHNhcGllbi4NCg0KUXVpc3F1ZSBibGFuZGl0IG5pc2kgdmVsIGVsaXQgdGluY2lkdW50IGV"
data$ = data$ + "mZmljaXR1ci4gQWxpcXVhbSBzaXQgYW1ldCBvcmNpIHF1aXMgYXJjdSB1bGxhbWNvcnBlcg0KZGlnbmlz"
data$ = data$ + "c2ltIGV0IG5vbiBsYWN1cy4gTWF1cmlzIHRpbmNpZHVudCBlc3QgZXUgbGlndWxhIHNvbGxpY2l0dWRpb"
data$ = data$ + "iBlZ2VzdGFzLiBJbnRlZ2VyIGRvbG9yIHVybmEsDQpzY2VsZXJpc3F1ZSBhdCBwb3N1ZXJlIGVnZXQsIG"
data$ = data$ + "NvbW1vZG8gYSBxdWFtLiBDdXJhYml0dXIgZGljdHVtIGNvbmRpbWVudHVtIHBvcnRhLiBNYXVyaXMNCmV"
data$ = data$ + "nZXN0YXMgcmlzdXMgYWMgdGVsbHVzIGVnZXN0YXMsIGVnZXQgbW9sZXN0aWUgZW5pbSB1bGxhbWNvcnBl"
data$ = data$ + "ci4gTWFlY2VuYXMgcG9ydGEgaW1wZXJkaWV0IGR1aQ0KZXQgY29uZGltZW50dW0uIEluIGV0IG5pc2wgZ"
data$ = data$ + "WxlaWZlbmQsIGN1cnN1cyBkdWkgZWdldCwgYWxpcXVldCBtZXR1cy4NCg0KTW9yYmkgYXVjdG9yIHBsYW"
data$ = data$ + "NlcmF0IG9kaW8sIHNvZGFsZXMgbWF4aW11cyBuaWJoIGVsZW1lbnR1bSBxdWlzLiBFdGlhbSB0aW5jaWR"
data$ = data$ + "1bnQgbW9sZXN0aWUNCm1hdXJpcywgZXQgdWx0cmljZXMgc2FwaWVuIGludGVyZHVtIGV1LiBOYW0gZ3Jh"
data$ = data$ + "dmlkYSBwaGFyZXRyYSBzb2xsaWNpdHVkaW4uIEN1cmFiaXR1ciBmZXJtZW50dW0NCmV4IGF0IGFudGUgZ"
data$ = data$ + "mVybWVudHVtIHBvcnR0aXRvciBhYyBkaWN0dW0gcmlzdXMuIE51bGxhbSB2YXJpdXMgb2RpbyBjb25ndW"
data$ = data$ + "UgZG9sb3IgY29tbW9kbyANCmNlbGVyaXNxdWUgc2VkIHV0IGV4LiBBbGlxdWFtIGVnZXQgcHVsdmluYXI"
data$ = data$ + "gbmliaCwgZXUgZnJpbmdpbGxhIGxhY3VzLiBJbiBxdWFtIG1pLCBjdXJzdXMgdml0YWUNCnR1cnBpcyBx"
data$ = data$ + "dWlzLCB2dWxwdXRhdGUgdml2ZXJyYSBtYWduYS4gUHJvaW4gcHJldGl1bSBmcmluZ2lsbGEgdWx0cmlja"
data$ = data$ + "WVzLiBQaGFzZWxsdXMgdWxsYW1jb3JwZXINCnByZXRpdW0gcHVydXMsIHZlbCBkaWN0dW0gbGVvIHVsdH"
data$ = data$ + "JpY2llcyBhYy4gUGhhc2VsbHVzIHZvbHV0cGF0IGRpYW0gdHVycGlzLCBzaXQgYW1ldCBvcm5hcmUgaXB"
data$ = data$ + "zdW0NCnBlbGxlbnRlc3F1ZSBub24uDQoNCkZ1c2NlIGVsZWlmZW5kIGZpbmlidXMgZW5pbSwgc2l0IGFt"
data$ = data$ + "ZXQgdmVoaWN1bGEgc2FwaWVuIGZyaW5naWxsYSB1dC4gSW4gaGFjIGhhYml0YXNzZSBwbGF0ZWENCmRpY"
data$ = data$ + "3R1bXN0LiBRdWlzcXVlIHNvbGxpY2l0dWRpbiBuZXF1ZSB0ZWxsdXMsIHNpdCBhbWV0IHRpbmNpZHVudC"
data$ = data$ + "BkdWkgY29uZGltZW50dW0gaWQuIEludGVnZXIgc2VkIA0KZW8gbm9uIHNlbSBmZXVnaWF0IHZ1bHB1dGF"
data$ = data$ + "0ZS4gTG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4g"
data$ = data$ + "SW4gaWQNCnRlbXBvciBkdWksIGluIHZlc3RpYnVsdW0gbnVsbGEuIFN1c3BlbmRpc3NlIHNjZWxlcmlzc"
data$ = data$ + "XVlIHJpc3VzIHZpdGFlIGxhY3VzIHNvbGxpY2l0dWRpbiB2dWxwdXRhdGUuDQpQZWxsZW50ZXNxdWUgdm"
data$ = data$ + "l0YWUgbWFnbmEgY29uc2VxdWF0LCB1bHRyaWNlcyB1cm5hIGdyYXZpZGEsIGlhY3VsaXMgZXguIE1vcmJ"
data$ = data$ + "pIGFjIGRpY3R1bSBxdWFtLCBpbg0KbWF0dGlzIGp1c3RvLiBJbiBoYWMgaGFiaXRhc3NlIHBsYXRlYSBk"
data$ = data$ + "aWN0dW1zdC4gRXRpYW0gbnVuYyByaXN1cywgYXVjdG9yIHF1aXMgZWdlc3RhcyB1dCwNCmZhY2lsaXNpc"
data$ = data$ + "yBub24gbGVjdHVzLiBTZWQgcnV0cnVtIGxhY2luaWEgZXJvcywgcXVpcyBwbGFjZXJhdCBuaXNpIHRpbm"
data$ = data$ + "NpZHVudCBlZ2V0LiBBZW5lYW4gZXQgZGlhbQ0KcXVpcyByaXN1cyBjb25zZXF1YXQgY29uc2VjdGV0dXI"
data$ = data$ + "uIE1hZWNlbmFzIG1heGltdXMgZG9sb3Igc2FnaXR0aXMgbmlzaSBlbGVpZmVuZCwgbmVjIHBvc3VlcmUN"
data$ = data$ + "CmxvcmVtIGNvbnZhbGxpcy4gVmVzdGlidWx1bSBxdWlzIHRpbmNpZHVudCBmZWxpcy4"
start = GetMilliseconds()
mem = b64_decodeStringToMemblock(data$)
finish = GetMilliseconds()
t$ = getMemblockString(mem, 0, getMemblockSize(mem))
do
print(t$)
print(finish-start)
sync()
loop
function b64_encodeString(encode as string)
pos = 0
L = len(encode)
// Convert string to be encoded into bytes (for faster calculations)
m = createMemblock(L+1)
setMemblockString(m, 0, encode)
// Determine size of encoded string
n = ceil(4*(L/3.0))
n = n + 4 - mod(n, 4)
// Where to store the encoded string
e = createMemblock(n)
for i = 0 to L-1 step 3
b1 = getMemblockByte(m, i)
b2 = 0
b3 = 0
if (i+1 <= L) then b2 = getMemblockByte(m, i+1)
if (i+2 <= L) then b3 = getMemblockByte(m, i+2)
b4 = b1 >> 2
b5 = ((b1&&0x3)<<4) || (b2>>4)
b6 = ((b2&&0xf)<<2) || (b3>>6)
b7 = b3 && 0x3f
setMemblockByte(e, pos, b64_encodeByte(b4)) : inc pos
setMemblockByte(e, pos, b64_encodeByte(b5)) : inc pos
if i+1 < L
setMemblockByte(e, pos, b64_encodeByte(b6)) : inc pos
else
setMemblockByte(e, pos, 61) : inc pos
endif
if i+2 < L
setMemblockByte(e, pos, b64_encodeByte(b7)) : inc pos
else
setMemblockByte(e, pos, 61) : inc pos
endif
next i
// free memory and get newly encoded string
deleteMemblock(m)
s$ = getMemblockString(e, 0, n)
deleteMemblock(e)
endfunction s$
function b64_encodeByte(byte)
if byte < 26 then exitfunction 65+byte
if byte < 52 then exitfunction 97+(byte-26)
if byte < 62 then exitfunction 48+(byte-52)
if byte = 62 then exitfunction 43
endfunction 47
function b64_decodeString(decode as string)
m = b64_decodeStringToMemblock(decode)
s$ = getMemblockString(m, 0, getMemblockSize(m))
deleteMemblock(m)
endfunction s$
function b64_decodeStringToMemblock(decode as string)
// Convert string into memblock
// Strings are written with a null terminator
// byte at the end, hence the +1
L = len(decode)
m = createMemblock(L+1)
setMemblockString(m, 0, decode)
// Determine size of decoded bytes
e = 0
for i = L to L-3 step -1
if getMemblockByte(m, i) = 65 then inc e else exit
next i
size = (L/4)*3 - e
// decoded bytes are stored in a memblock
B64 = createMemblock(size)
length = len(decode)
index = 0
for i = 0 to length-1 step 4
c1 = getMemblockByte(m, i)
c2 = 65
c3 = 65
c4 = 65
if i+1 <= length then c2 = getMemblockByte(m, i+1)
if i+2 <= length then c3 = getMemblockByte(m, i+2)
if i+3 <= length then c4 = getMemblockByte(m, i+3)
b1 = b64_decodeChar(c1)
b2 = b64_decodeChar(c2)
b3 = b64_decodeChar(c3)
b4 = b64_decodeChar(c4)
b = b1<<2 || b2>>4
setMemblockByte(B64, index, b)
if c3 <> 61
inc index
b = ((b2&&0xf)<<4) || (b3>>2)
setMemblockByte(B64, index, b)
endif
if c4 <> 61
inc index
b = ((b3&&0x3)<<6) || b4
setMemblockByte(B64, index, b)
endif
inc index
next i
deleteMemblock(m)
endfunction B64
function b64_isBase64(check as string)
L = len(check)
m = createMemblock(L+1)
setMemblockString(m, 0, check)
for i = 0 to L-1
thing = 0
c = GetMemblockByte(m, i)
if c >=65 and c <= 90 : thing = 1
elseif c >= 97 and c <= 122 : thing = 1
elseif c >= 48 and c <= 57 : thing = 1
elseif c = 43 : thing = 1
elseif c = 47 : thing = 1
elseif c = 61 : thing = 1
endif
if thing = 0 then exitfunction 0
next i
endfunction 1
function b64_decodeChar(c as integer)
if c >= 65 and c <= 90
v = c-65
exitfunction v
endif
if c >= 97 and c <= 122
v = c-97+26
exitfunction v
endif
if c >= 48 and c <= 57
v = c-48+52
exitfunction v
endif
if c = 43 then exitfunction 62
endfunction 63
"I like offending people, because I think people who get offended should be offended." - Linus Torvalds