diff options
author | bptato <nincsnevem662@gmail.com> | 2024-04-25 20:31:46 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2024-04-25 20:39:01 +0200 |
commit | a42f96ee6287c714ce90206009f20494995940db (patch) | |
tree | a7d76007e2360c84c0b309d8aa934c186851dbe6 /src/utils/twtstr.nim | |
parent | 91707a9b2ee3ceee6bdd13f5262dcc1dd675fbc7 (diff) | |
download | chawan-a42f96ee6287c714ce90206009f20494995940db.tar.gz |
data: replace std/base64 with atob
std's version is known to be broken on versions we still support, and it makes no sense to use different decoders anyway. (This does introduce a bit of a dependency hell, because js/base64 depends on js/javascript which tries to bring in the entire QuickJS runtime. So we move that out into twtstr, and manually convert a Result[string, string] to DOMException in js/base64.)
Diffstat (limited to 'src/utils/twtstr.nim')
-rw-r--r-- | src/utils/twtstr.nim | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/utils/twtstr.nim b/src/utils/twtstr.nim index 66a211b9..6cab9ac7 100644 --- a/src/utils/twtstr.nim +++ b/src/utils/twtstr.nim @@ -711,3 +711,66 @@ proc getContentTypeAttr*(contentType, attrname: string): string = else: s &= c return s + +func atob(c: char): uint8 {.inline.} = + # see RFC 4648 table + if c in AsciiUpperAlpha: + return uint8(c) - uint8('A') + if c in AsciiLowerAlpha: + return uint8(c) - uint8('a') + 26 + if c in AsciiDigit: + return uint8(c) - uint8('0') + 52 + if c == '+': + return 62 + if c == '/': + return 63 + return uint8.high + +func atob0*(data: string): Result[string, string] = + var outs = newStringOfCap(data.len div 4 * 3) + var buf: array[4, uint8] + var i = 0 + var j = 0 + var pad = 0 + while true: + i = data.skipBlanks(i) + if i >= data.len: + break + if data[i] == '=': + i = data.skipBlanks(i + 1) + inc pad + break + buf[j] = atob(data[i]) + if buf[j] == uint8.high: + return err("Invalid character in encoded string") + if j == 3: + let ob1 = (buf[0] shl 2) or (buf[1] shr 4) # 6 bits of b0 | 2 bits of b1 + let ob2 = (buf[1] shl 4) or (buf[2] shr 2) # 4 bits of b1 | 4 bits of b2 + let ob3 = (buf[2] shl 6) or buf[3] # 2 bits of b2 | 6 bits of b3 + outs &= char(ob1) + outs &= char(ob2) + outs &= char(ob3) + j = 0 + else: + inc j + inc i + if i < data.len: + if i < data.len and data[i] == '=': + inc pad + inc i + i = data.skipBlanks(i) + if pad > 0 and j + pad != 4: + return err("Too much padding") + if i < data.len: + return err("Invalid character after encoded string") + if j == 3: + let ob1 = (buf[0] shl 2) or (buf[1] shr 4) # 6 bits of b0 | 2 bits of b1 + let ob2 = (buf[1] shl 4) or (buf[2] shr 2) # 4 bits of b1 | 4 bits of b2 + outs &= char(ob1) + outs &= char(ob2) + elif j == 2: + let ob1 = (buf[0] shl 2) or (buf[1] shr 4) # 6 bits of b0 | 2 bits of b1 + outs &= char(ob1) + elif j != 0: + return err("Incorrect number of characters in encoded string") + return ok(outs) |