about summary refs log tree commit diff stats
path: root/src/html/jsencoding.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-11-15 17:06:53 +0100
committerbptato <nincsnevem662@gmail.com>2024-11-15 17:06:53 +0100
commitdef4ceccfb77afd74b1dd1273b66d036b766fd5f (patch)
tree8fb976f0ebe632029afe2ee9542d31b88e4f23d1 /src/html/jsencoding.nim
parentfd10019d8b8a1b5dcb0026521fa8f5f072c3a10a (diff)
downloadchawan-def4ceccfb77afd74b1dd1273b66d036b766fd5f.tar.gz
js: reorganize modules, update docs
most of it has already been moved to monoucha, and the rest fits better
in other directories.

also, move urimethodmap to config
Diffstat (limited to 'src/html/jsencoding.nim')
-rw-r--r--src/html/jsencoding.nim100
1 files changed, 100 insertions, 0 deletions
diff --git a/src/html/jsencoding.nim b/src/html/jsencoding.nim
new file mode 100644
index 00000000..7aae5eb2
--- /dev/null
+++ b/src/html/jsencoding.nim
@@ -0,0 +1,100 @@
+import chagashi/charset
+import chagashi/decoder
+import monoucha/javascript
+import monoucha/jserror
+import monoucha/jstypes
+import monoucha/quickjs
+import types/opt
+
+type
+  JSTextEncoder = ref object
+
+  JSTextDecoder = ref object
+    encoding: Charset
+    ignoreBOM {.jsget.}: bool
+    errorMode: DecoderErrorMode
+    stream: bool
+    bomSeen: bool
+    tdctx: TextDecoderContext
+
+jsDestructor(JSTextDecoder)
+jsDestructor(JSTextEncoder)
+
+type TextDecoderOptions = object of JSDict
+  fatal {.jsdefault.}: bool
+  ignoreBOM {.jsdefault.}: bool
+
+func newJSTextDecoder(label = "utf-8"; options = TextDecoderOptions()):
+    JSResult[JSTextDecoder] {.jsctor.} =
+  let encoding = getCharset(label)
+  if encoding in {CHARSET_UNKNOWN, CHARSET_REPLACEMENT}:
+    return errRangeError("Invalid encoding label")
+  let errorMode = if options.fatal: demFatal else: demReplacement
+  return ok(JSTextDecoder(
+    ignoreBOM: options.ignoreBOM,
+    errorMode: errorMode,
+    tdctx: initTextDecoderContext(encoding, errorMode),
+    encoding: encoding
+  ))
+
+func fatal(this: JSTextDecoder): bool {.jsfget.} =
+  return this.errorMode == demFatal
+
+type TextDecodeOptions = object of JSDict
+  stream {.jsdefault.}: bool
+
+#TODO AllowSharedBufferSource
+proc decode(ctx: JSContext; this: JSTextDecoder;
+    input = none(JSArrayBufferView); options = TextDecodeOptions()): JSValue
+    {.jsfunc.} =
+  if not this.stream:
+    this.tdctx = initTextDecoderContext(this.encoding, this.errorMode)
+    this.bomSeen = false
+  this.stream = options.stream
+  if input.isSome:
+    let input = input.get
+    let H = int(input.abuf.len) - 1
+    var oq = ""
+    let stream = this.stream
+    for chunk in this.tdctx.decode(input.abuf.p.toOpenArray(0, H), not stream):
+      oq &= chunk
+    if this.tdctx.failed:
+      this.tdctx.failed = false
+      return JS_ThrowTypeError(ctx, "failed to decode string")
+    return JS_NewStringLen(ctx, cstring(oq), csize_t(oq.len))
+  return JS_NewString(ctx, "")
+
+func jencoding(this: JSTextDecoder): string {.jsfget: "encoding".} =
+  return $this.encoding
+
+func newTextEncoder(): JSTextEncoder {.jsctor.} =
+  return JSTextEncoder()
+
+func jencoding(this: JSTextEncoder): string {.jsfget: "encoding".} =
+  return "utf-8"
+
+proc dealloc_wrap(rt: JSRuntime; opaque, p: pointer) {.cdecl.} =
+  dealloc(p)
+
+proc encode(this: JSTextEncoder; input = ""): JSUint8Array {.jsfunc.} =
+  # we have to validate input first :/
+  #TODO it is possible to do less copies here...
+  var input = input.toValidUTF8()
+  let buf = cast[ptr UncheckedArray[uint8]](alloc(input.len))
+  copyMem(buf, addr input[0], input.len)
+  let abuf = JSArrayBuffer(
+    p: buf,
+    len: csize_t(input.len),
+    dealloc: dealloc_wrap
+  )
+  return JSUint8Array(
+    abuf: abuf,
+    offset: 0,
+    nmemb: csize_t(input.len)
+  )
+
+#TODO encodeInto
+
+proc addEncodingModule*(ctx: JSContext) =
+  ctx.registerType(JSTextDecoder, name = "TextDecoder")
+  ctx.registerType(JSTextEncoder, name = "TextEncoder")