diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bindings/quickjs.nim | 11 | ||||
-rw-r--r-- | src/html/env.nim | 6 | ||||
-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 | ||||
-rw-r--r-- | src/local/client.nim | 5 |
7 files changed, 49 insertions, 39 deletions
diff --git a/src/bindings/quickjs.nim b/src/bindings/quickjs.nim index a401bf1b..f6719e3d 100644 --- a/src/bindings/quickjs.nim +++ b/src/bindings/quickjs.nim @@ -90,6 +90,8 @@ type JSFreeArrayBufferDataFunc* = proc (rt: JSRuntime, opaque, p: pointer) {.cdecl.} + JSString* {.importc: "JSString*", header: qjsheader.} = distinct pointer + JSPropertyDescriptor* {.importc, header: qjsheader.} = object flags*: cint value*: JSValue @@ -264,6 +266,9 @@ const const JS_PARSE_JSON_EXT* = (1 shl 0) +template JS_VALUE_GET_STRING*(v: untyped): JSString = + JSString(JS_VALUE_GET_PTR(v)) + template JS_CFUNC_DEF*(n: string, len: uint8, func1: JSCFunction): JSCFunctionListEntry = JSCFunctionListEntry(name: cstring(n), @@ -432,6 +437,12 @@ proc JS_ToCStringLen*(ctx: JSContext, plen: ptr csize_t, val1: JSValue): cstring proc JS_ToCString*(ctx: JSContext, val1: JSValue): cstring proc JS_FreeCString*(ctx: JSContext, `ptr`: cstring) +proc JS_NewNarrowStringLen*(ctx: JSContext, s: cstring, len: csize_t): JSValue +proc JS_IsStringWideChar*(str: JSString): JS_BOOL +proc JS_GetNarrowStringBuffer*(str: JSString): ptr UncheckedArray[uint8] +proc JS_GetWideStringBuffer*(str: JSString): ptr UncheckedArray[uint16] +proc JS_GetStringLength*(str: JSString): uint32 + proc JS_Eval*(ctx: JSContext, input: cstring, input_len: cint, filename: cstring, eval_flags: cint): JSValue proc JS_SetInterruptHandler*(rt: JSRuntime, cb: JSInterruptHandler, opaque: pointer) proc JS_SetCanBlock*(rt: JSRuntime, can_block: JS_BOOL) diff --git a/src/html/env.nim b/src/html/env.nim index d300400b..0543a60c 100644 --- a/src/html/env.nim +++ b/src/html/env.nim @@ -1,6 +1,7 @@ import selectors import streams +import bindings/quickjs import display/winattrs import html/chadombuilder import html/dom @@ -13,6 +14,7 @@ import js/encoding import js/error import js/intl import js/javascript +import js/strings import js/timeout import loader/headers import loader/loader @@ -102,10 +104,10 @@ proc setLocation(window: Window, s: string): Err[JSError] proc getWindow(window: Window): Window {.jsuffget: "window".} = return window -proc atob(window: Window, data: string): DOMResult[string] {.jsfunc.} = +proc atob(window: Window, data: string): DOMResult[NarrowString] {.jsfunc.} = return atob(data) -proc btoa(window: Window, data: string): DOMResult[string] {.jsfunc.} = +proc btoa(window: Window, data: JSString): DOMResult[string] {.jsfunc.} = return btoa(data) proc addScripting*(window: Window, selector: Selector[int]) = 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. diff --git a/src/local/client.nim b/src/local/client.nim index 9cff0f2f..906c5bee 100644 --- a/src/local/client.nim +++ b/src/local/client.nim @@ -34,6 +34,7 @@ import js/fromjs import js/intl import js/javascript import js/module +import js/strings import js/timeout import js/tojs import loader/headers @@ -613,10 +614,10 @@ proc jsCollect(client: Client) {.jsfunc.} = proc sleep(client: Client, millis: int) {.jsfunc.} = sleep millis -proc atob(client: Client, data: string): DOMResult[string] {.jsfunc.} = +proc atob(client: Client, data: string): DOMResult[NarrowString] {.jsfunc.} = return atob(data) -proc btoa(client: Client, data: string): DOMResult[string] {.jsfunc.} = +proc btoa(client: Client, data: JSString): DOMResult[string] {.jsfunc.} = return btoa(data) func line(client: Client): LineEdit {.jsfget.} = |