about summary refs log blame commit diff stats
path: root/src/js/base64.nim
blob: 4b8ae540ae9a44c045b6ea0bb2396c456b561bf2 (plain) (tree)
1
2
3
4
5


                      
                
 










                                                                            

                                             








                                              




                                                             















                                                               
import std/base64

import js/domexception
import types/opt

# atob and btoa convert Latin-1 to base64 and vice versa. (And throw on
# anything above latin-1.)
# We could do this quite efficiently if we had an API for the QuickJS string
# internal representation. Unfortunately we do not, so we do the following:
# * atob: decode, convert latin-1 to utf-8, pass to qjs, where it is then
#   converted to latin-1 again.
# * btoa: qjs converts its string (either utf-16 or latin-1) to utf-8,
#   we convert this to latin-1 (or throw), then encode.
# That is two conversions more than needed (i.e. 0) for each step. We should
# really write an API for handling QJS strings sometime...

proc atob*(data: string): DOMResult[string] =
  try:
    let ds = base64.decode(data)
    var s = newStringOfCap(ds.len)
    for c in ds:
      if uint8(c) <= 0x7F:
        s &= c
      else: # latin-1
        s &= char((uint8(c) shr 6) or 0xC0)
        s &= char((uint8(c) and 0x3F) or 0x80)
    return ok(s)
  except ValueError:
    return err(newDOMException("Invalid character in string",
      "InvalidCharacterError"))

proc btoa*(data: string): DOMResult[string] =
  var s = newStringOfCap(data.len)
  var i = 0
  while i < data.len:
    let c = data[i]
    let n = uint8(c)
    if n <= 0x7F: # ascii
      s &= c
      inc i
    elif n <= 0xC3: # latin-1
      inc i
      s &= char((n shl 6) or (uint8(data[i]) and 0x3F))
      inc i
    else:
      return err(newDOMException("Invalid character in string",
        "InvalidCharacterError"))
  return ok(base64.encode(s))