diff options
author | bptato <nincsnevem662@gmail.com> | 2023-10-21 23:34:56 +0200 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2023-10-21 23:40:24 +0200 |
commit | 18008acc141a55449b28c1af487a080c4bbcb355 (patch) | |
tree | a81872bfc2e2add0b0c9b6f65f3be15f4d2790c8 /src/js | |
parent | 69870f3b974e65d61b564b396e01d21cc023e6e9 (diff) | |
download | chawan-18008acc141a55449b28c1af487a080c4bbcb355.tar.gz |
base64: reduce pointless re-coding using JSString
We now expose some functions from QuickJS to interact with JavaScript strings without re-encoding them into UTF-8.
Diffstat (limited to 'src/js')
-rw-r--r-- | src/js/base64.nim | 51 | ||||
-rw-r--r-- | src/js/fromjs.nim | 5 | ||||
-rw-r--r-- | src/js/strings.nim | 3 | ||||
-rw-r--r-- | src/js/tojs.nim | 7 |
4 files changed, 31 insertions, 35 deletions
diff --git a/src/js/base64.nim b/src/js/base64.nim index 4b8ae540..912843b4 100644 --- a/src/js/base64.nim +++ b/src/js/base64.nim @@ -1,48 +1,29 @@ import std/base64 +import bindings/quickjs import js/domexception +import js/javascript +import js/strings 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] = +proc atob*(data: string): DOMResult[NarrowString] = 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) + let ds = NarrowString(base64.decode(data)) + return ok(ds) 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)) +proc btoa*(data: JSString): DOMResult[string] = + if JS_IsStringWideChar(data): + return err(newDOMException("Invalid character in string", + "InvalidCharacterError")) + let len = int(JS_GetStringLength(data)) + if len == 0: + return ok("") + let buf = JS_GetNarrowStringBuffer(data) + let res = base64.encode(toOpenArray(buf, 0, len - 1)) + return ok(res) diff --git a/src/js/fromjs.nim b/src/js/fromjs.nim index b2e1cc91..80fdc1cd 100644 --- a/src/js/fromjs.nim +++ b/src/js/fromjs.nim @@ -54,6 +54,9 @@ func fromJSString(ctx: JSContext, val: JSValue): JSResult[string] = JS_FreeCString(ctx, outp) return ok(ret) +func fromJSString2(ctx: JSContext, val: JSValue): JSResult[JSString] = + return ok(JS_VALUE_GET_STRING(val)) + func fromJSInt[T: SomeInteger](ctx: JSContext, val: JSValue): JSResult[T] = if not JS_IsNumber(val): @@ -449,6 +452,8 @@ type FromJSAllowedT = (object and not (Result|Option|Table|JSValue|JSDict)) proc fromJS*[T](ctx: JSContext, val: JSValue): JSResult[T] = when T is string: return fromJSString(ctx, val) + elif T is JSString: + return fromJSString2(ctx, val) elif T is char: return fromJSChar(ctx, val) elif T is Rune: diff --git a/src/js/strings.nim b/src/js/strings.nim new file mode 100644 index 00000000..ab0dd753 --- /dev/null +++ b/src/js/strings.nim @@ -0,0 +1,3 @@ +type + NarrowString* = distinct string + WideString* = distinct seq[uint16] diff --git a/src/js/tojs.nim b/src/js/tojs.nim index e614c451..bf2bfe61 100644 --- a/src/js/tojs.nim +++ b/src/js/tojs.nim @@ -8,6 +8,7 @@ import js/arraybuffer import js/dict import js/error import js/opaque +import js/strings import js/typeptr import types/opt @@ -35,6 +36,9 @@ proc toJS*(ctx: JSContext, promise: EmptyPromise): JSValue proc toJS*(ctx: JSContext, obj: ref object): JSValue proc toJS*(ctx: JSContext, err: JSError): JSValue proc toJS*(ctx: JSContext, f: JSCFunction): JSValue +proc toJS*(ctx: JSContext, abuf: JSArrayBuffer): JSValue +proc toJS*(ctx: JSContext, u8a: JSUint8Array): JSValue +proc toJS*(ctx: JSContext, ns: NarrowString): JSValue # Convert Nim types to the corresponding JavaScript type, with knowledge of # the parent object. @@ -270,6 +274,9 @@ proc toJS*(ctx: JSContext, u8a: JSUint8Array): JSValue = JS_FreeValue(ctx, jsabuf) return ret +proc toJS*(ctx: JSContext, ns: NarrowString): JSValue = + return JS_NewNarrowStringLen(ctx, cstring(ns), csize_t(string(ns).len)) + proc toJSP(ctx: JSContext, parent: ref object, child: var object): JSValue = let p = addr child # Save parent as the original ancestor for this tree. |