[gjs/ewlsh/text-encoding: 1/2] byteArray: Refactor functionality into Encoding
- From: Evan Welsh <ewlsh src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/ewlsh/text-encoding: 1/2] byteArray: Refactor functionality into Encoding
- Date: Mon, 10 May 2021 03:59:03 +0000 (UTC)
commit 69b91ac62d9694e7240e45be53c00e3e2124169e
Author: Evan Welsh <contact evanwelsh com>
Date: Sun Apr 25 13:14:58 2021 -0700
byteArray: Refactor functionality into Encoding
Copies common functionality from byteArray into a Encoding native
module. This refactor is the basis for the WHATWG Encoding work.
gjs/byteArray.cpp | 249 ++---------------------------------------
gjs/context.cpp | 3 +
gjs/text-encoding.cpp | 262 ++++++++++++++++++++++++++++++++++++++++++++
gjs/text-encoding.h | 25 +++++
meson.build | 1 +
modules/script/byteArray.js | 50 ++++++++-
6 files changed, 346 insertions(+), 244 deletions(-)
---
diff --git a/gjs/byteArray.cpp b/gjs/byteArray.cpp
index 4fe361d1..341df69e 100644
--- a/gjs/byteArray.cpp
+++ b/gjs/byteArray.cpp
@@ -5,7 +5,6 @@
#include <config.h>
#include <stdint.h>
-#include <string.h> // for strcmp, memchr, strlen
#include <girepository.h>
#include <glib-object.h>
@@ -13,7 +12,6 @@
#include <js/ArrayBuffer.h>
#include <js/CallArgs.h>
-#include <js/GCAPI.h> // for AutoCheckCannotGC
#include <js/PropertySpec.h>
#include <js/RootingAPI.h>
#include <js/TypeDecls.h>
@@ -28,138 +26,17 @@
#include "gjs/deprecation.h"
#include "gjs/jsapi-util-args.h"
#include "gjs/jsapi-util.h"
+#include "gjs/text-encoding.h"
#include "util/misc.h" // for _gjs_memdup2
/* Callbacks to use with JS::NewExternalArrayBuffer() */
-static void gfree_arraybuffer_contents(void* contents, void*) {
- g_free(contents);
-}
-
static void bytes_unref_arraybuffer(void* contents [[maybe_unused]],
void* user_data) {
auto* gbytes = static_cast<GBytes*>(user_data);
g_bytes_unref(gbytes);
}
-GJS_JSAPI_RETURN_CONVENTION
-bool to_string_impl_slow(JSContext* cx, uint8_t* data, uint32_t len,
- const char* encoding, JS::MutableHandleValue rval) {
- size_t bytes_written;
- GError* error = nullptr;
- GjsAutoChar u16_str = g_convert(reinterpret_cast<char*>(data), len,
- // Make sure the bytes of the UTF-16 string are laid out in memory
- // such that we can simply reinterpret_cast<char16_t> them.
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- "UTF-16LE",
-#else
- "UTF-16BE",
-#endif
- encoding, nullptr, /* bytes read */
- &bytes_written, &error);
- if (!u16_str)
- return gjs_throw_gerror_message(cx, error); // frees GError
-
- // bytes_written should be bytes in a UTF-16 string so should be a multiple
- // of 2
- g_assert((bytes_written % 2) == 0);
-
- // g_convert 0-terminates the string, although the 0 isn't included in
- // bytes_written
- JSString* s =
- JS_NewUCStringCopyZ(cx, reinterpret_cast<char16_t*>(u16_str.get()));
- if (!s)
- return false;
-
- rval.setString(s);
- return true;
-}
-
-/* implement toString() with an optional encoding arg */
-GJS_JSAPI_RETURN_CONVENTION
-static bool to_string_impl(JSContext* context, JS::HandleObject byte_array,
- const char* encoding, JS::MutableHandleValue rval) {
- if (!JS_IsUint8Array(byte_array)) {
- gjs_throw(context,
- "Argument to ByteArray.toString() must be a Uint8Array");
- return false;
- }
-
- bool encoding_is_utf8;
- uint8_t* data;
-
- if (encoding) {
- /* maybe we should be smarter about utf8 synonyms here.
- * doesn't matter much though. encoding_is_utf8 is
- * just an optimization anyway.
- */
- encoding_is_utf8 = (strcmp(encoding, "UTF-8") == 0);
- } else {
- encoding_is_utf8 = true;
- }
-
- uint32_t len;
- bool is_shared_memory;
- js::GetUint8ArrayLengthAndData(byte_array, &len, &is_shared_memory, &data);
-
- if (len == 0) {
- rval.setString(JS_GetEmptyString(context));
- return true;
- }
-
- if (!encoding_is_utf8)
- return to_string_impl_slow(context, data, len, encoding, rval);
-
- // optimization, avoids iconv overhead and runs libmozjs hardwired
- // utf8-to-utf16
-
- // If there are any 0 bytes, including the terminating byte, stop at the
- // first one
- if (data[len - 1] == 0 || memchr(data, 0, len)) {
- if (!gjs_string_from_utf8(context, reinterpret_cast<char*>(data), rval))
- return false;
- } else {
- if (!gjs_string_from_utf8_n(context, reinterpret_cast<char*>(data), len,
- rval))
- return false;
- }
-
- uint8_t* current_data;
- uint32_t current_len;
- bool ignore_val;
-
- // If a garbage collection occurs between when we call
- // js::GetUint8ArrayLengthAndData and return from gjs_string_from_utf8, a
- // use-after-free corruption can occur if the garbage collector shifts the
- // location of the Uint8Array's private data. To mitigate this we call
- // js::GetUint8ArrayLengthAndData again and then compare if the length and
- // pointer are still the same. If the pointers differ, we use the slow path
- // to ensure no data corruption occurred. The shared-ness of an array cannot
- // change between calls, so we ignore it.
- js::GetUint8ArrayLengthAndData(byte_array, ¤t_len, &ignore_val,
- ¤t_data);
-
- // Ensure the private data hasn't changed
- if (current_len == len && current_data == data)
- return true;
-
- // This was the UTF-8 optimized path, so we explicitly pass the encoding
- return to_string_impl_slow(context, current_data, current_len, "UTF-8",
- rval);
-}
-
-GJS_JSAPI_RETURN_CONVENTION
-static bool to_string_func(JSContext* cx, unsigned argc, JS::Value* vp) {
- JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- JS::UniqueChars encoding;
- JS::RootedObject byte_array(cx);
-
- if (!gjs_parse_call_args(cx, "toString", args, "o|s", "byteArray",
- &byte_array, "encoding", &encoding))
- return false;
-
- return to_string_impl(cx, byte_array, encoding.get(), args.rval());
-}
/* Workaround to keep existing code compatible. This function is tacked onto
* any Uint8Array instances created in situations where previously a ByteArray
@@ -180,130 +57,20 @@ static bool instance_to_string_func(JSContext* cx, unsigned argc,
}
GJS_JSAPI_RETURN_CONVENTION
-static bool
-to_gbytes_func(JSContext *context,
- unsigned argc,
- JS::Value *vp)
-{
- JS::CallArgs rec = JS::CallArgsFromVp(argc, vp);
- GIBaseInfo *gbytes_info;
- JS::RootedObject byte_array(context);
-
- if (!gjs_parse_call_args(context, "toGBytes", rec, "o",
- "byteArray", &byte_array))
- return false;
-
- if (!JS_IsUint8Array(byte_array)) {
- gjs_throw(context,
- "Argument to ByteArray.toGBytes() must be a Uint8Array");
- return false;
- }
-
- GBytes* bytes = gjs_byte_array_get_bytes(byte_array);
-
- g_irepository_require(nullptr, "GLib", "2.0", GIRepositoryLoadFlags(0),
- nullptr);
- gbytes_info = g_irepository_find_by_gtype(NULL, G_TYPE_BYTES);
- JSObject* ret_bytes_obj =
- BoxedInstance::new_for_c_struct(context, gbytes_info, bytes);
- g_bytes_unref(bytes);
- if (!ret_bytes_obj)
- return false;
-
- rec.rval().setObject(*ret_bytes_obj);
- return true;
-}
-
-/* fromString() function implementation */
-GJS_JSAPI_RETURN_CONVENTION
-static bool
-from_string_func(JSContext *context,
- unsigned argc,
- JS::Value *vp)
-{
+static bool define_to_string_func(JSContext* context, unsigned argc, JS::Value* vp) {
JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
- JS::UniqueChars encoding;
- JS::UniqueChars utf8;
- bool encoding_is_utf8;
- JS::RootedObject obj(context), array_buffer(context);
- if (!gjs_parse_call_args(context, "fromString", argv, "s|s",
- "string", &utf8,
- "encoding", &encoding))
- return false;
-
- if (argc > 1) {
- /* maybe we should be smarter about utf8 synonyms here.
- * doesn't matter much though. encoding_is_utf8 is
- * just an optimization anyway.
- */
- encoding_is_utf8 = (strcmp(encoding.get(), "UTF-8") == 0);
- } else {
- encoding_is_utf8 = true;
- }
-
- if (encoding_is_utf8) {
- /* optimization? avoids iconv overhead and runs
- * libmozjs hardwired utf16-to-utf8.
- */
- size_t len = strlen(utf8.get());
- array_buffer =
- JS::NewArrayBufferWithContents(context, len, utf8.release());
- } else {
- JSString *str = argv[0].toString(); /* Rooted by argv */
- GError *error = NULL;
- char *encoded = NULL;
- gsize bytes_written;
-
- /* Scope for AutoCheckCannotGC, will crash if a GC is triggered
- * while we are using the string's chars */
- {
- JS::AutoCheckCannotGC nogc;
- size_t len;
-
- if (JS_StringHasLatin1Chars(str)) {
- const JS::Latin1Char *chars =
- JS_GetLatin1StringCharsAndLength(context, nogc, str, &len);
- if (chars == NULL)
- return false;
-
- encoded = g_convert((char *) chars, len,
- encoding.get(), // to_encoding
- "LATIN1", /* from_encoding */
- NULL, /* bytes read */
- &bytes_written, &error);
- } else {
- const char16_t *chars =
- JS_GetTwoByteStringCharsAndLength(context, nogc, str, &len);
- if (chars == NULL)
- return false;
-
- encoded = g_convert((char *) chars, len * 2,
- encoding.get(), // to_encoding
- "UTF-16", /* from_encoding */
- NULL, /* bytes read */
- &bytes_written, &error);
- }
- }
-
- if (!encoded)
- return gjs_throw_gerror_message(context, error); // frees GError
-
- array_buffer =
- JS::NewExternalArrayBuffer(context, bytes_written, encoded,
- gfree_arraybuffer_contents, nullptr);
- }
-
- if (!array_buffer)
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::RootedObject obj(context);
+ if (!gjs_parse_call_args(context, "defineToString", args, "o", "obj", &obj))
return false;
- obj = JS_NewUint8ArrayWithBuffer(context, array_buffer, 0, -1);
const GjsAtoms& atoms = GjsContextPrivate::atoms(context);
if (!JS_DefineFunctionById(context, obj, atoms.to_string(),
instance_to_string_func, 1, 0))
return false;
- argv.rval().setObject(*obj);
+ argv.rval().setUndefined();
return true;
}
@@ -393,10 +160,8 @@ GByteArray* gjs_byte_array_get_byte_array(JSObject* obj) {
}
static JSFunctionSpec gjs_byte_array_module_funcs[] = {
- JS_FN("fromString", from_string_func, 2, 0),
JS_FN("fromGBytes", from_gbytes_func, 1, 0),
- JS_FN("toGBytes", to_gbytes_func, 1, 0),
- JS_FN("toString", to_string_func, 2, 0),
+ JS_FN("defineToString", define_to_string_func, 1, 0),
JS_FS_END};
bool
diff --git a/gjs/context.cpp b/gjs/context.cpp
index ea0be37c..8df40520 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -75,6 +75,7 @@
#include "gjs/objectbox.h"
#include "gjs/profiler-private.h"
#include "gjs/profiler.h"
+#include "gjs/text-encoding.h"
#include "modules/modules.h"
#include "util/log.h"
@@ -313,6 +314,8 @@ gjs_context_class_init(GjsContextClass *klass)
}
gjs_register_native_module("_byteArrayNative", gjs_define_byte_array_stuff);
+ gjs_register_native_module("_encodingNative",
+ gjs_define_text_encoding_stuff);
gjs_register_native_module("_gi", gjs_define_private_gi_stuff);
gjs_register_native_module("gi", gjs_define_repo);
diff --git a/gjs/text-encoding.cpp b/gjs/text-encoding.cpp
new file mode 100644
index 00000000..5e706a83
--- /dev/null
+++ b/gjs/text-encoding.cpp
@@ -0,0 +1,262 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
+// SPDX-FileCopyrightText: 2010 litl, LLC
+// SPDX-FileCopyrightText: 2021 Evan Welsh
+
+#include <config.h>
+
+#include <stdint.h>
+#include <string.h> // for strcmp, memchr, strlen
+
+#include <algorithm>
+#include <vector>
+
+#include <gio/gio.h>
+#include <girepository.h>
+#include <glib-object.h>
+#include <glib.h>
+
+#include <js/ArrayBuffer.h>
+#include <js/CallArgs.h>
+#include <js/CharacterEncoding.h>
+#include <js/GCAPI.h> // for AutoCheckCannotGC
+#include <js/PropertySpec.h>
+#include <js/RootingAPI.h>
+#include <js/TypeDecls.h>
+#include <js/Utility.h> // for UniqueChars
+#include <jsapi.h> // for JS_DefineFunctionById, JS_DefineFun...
+#include <jsfriendapi.h> // for JS_NewUint8ArrayWithBuffer, GetUint...
+
+#include "gi/boxed.h"
+#include "gjs/atoms.h"
+#include "gjs/context-private.h"
+#include "gjs/deprecation.h"
+#include "gjs/jsapi-util-args.h"
+#include "gjs/jsapi-util.h"
+#include "gjs/text-encoding.h"
+
+/* Callbacks to use with JS::NewExternalArrayBuffer() */
+
+static void gfree_arraybuffer_contents(void* contents, void*) {
+ g_free(contents);
+}
+
+GJS_JSAPI_RETURN_CONVENTION
+bool to_string_impl_slow(JSContext* cx, uint8_t* data, uint32_t len,
+ const char* encoding, JS::MutableHandleValue rval) {
+ size_t bytes_written;
+ GError* error = nullptr;
+ GjsAutoChar u16_str = g_convert(reinterpret_cast<char*>(data), len,
+ // Make sure the bytes of the UTF-16 string are laid out in memory
+ // such that we can simply reinterpret_cast<char16_t> them.
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ "UTF-16LE",
+#else
+ "UTF-16BE",
+#endif
+ encoding, nullptr, /* bytes read */
+ &bytes_written, &error);
+ if (!u16_str)
+ return gjs_throw_gerror_message(cx, error); // frees GError
+
+ // bytes_written should be bytes in a UTF-16 string so should be a multiple
+ // of 2
+ g_assert((bytes_written % 2) == 0);
+
+ // g_convert 0-terminates the string, although the 0 isn't included in
+ // bytes_written
+ JSString* s =
+ JS_NewUCStringCopyZ(cx, reinterpret_cast<char16_t*>(u16_str.get()));
+ if (!s)
+ return false;
+
+ rval.setString(s);
+ return true;
+}
+
+/* implement toString() with an optional encoding arg */
+GJS_JSAPI_RETURN_CONVENTION
+bool to_string_impl(JSContext* context, JS::HandleObject byte_array,
+ const char* encoding, JS::MutableHandleValue rval) {
+ if (!JS_IsUint8Array(byte_array)) {
+ gjs_throw(context,
+ "Argument to ByteArray.toString() must be a Uint8Array");
+ return false;
+ }
+
+ bool encoding_is_utf8;
+ uint8_t* data;
+
+ if (encoding) {
+ /* maybe we should be smarter about utf8 synonyms here.
+ * doesn't matter much though. encoding_is_utf8 is
+ * just an optimization anyway.
+ */
+ encoding_is_utf8 = (strcmp(encoding, "UTF-8") == 0);
+ } else {
+ encoding_is_utf8 = true;
+ }
+
+ uint32_t len;
+ bool is_shared_memory;
+ js::GetUint8ArrayLengthAndData(byte_array, &len, &is_shared_memory, &data);
+
+ if (len == 0) {
+ rval.setString(JS_GetEmptyString(context));
+ return true;
+ }
+
+ if (!encoding_is_utf8)
+ return to_string_impl_slow(context, data, len, encoding, rval);
+
+ // optimization, avoids iconv overhead and runs libmozjs hardwired
+ // utf8-to-utf16
+
+ // If there are any 0 bytes, including the terminating byte, stop at the
+ // first one
+ if (data[len - 1] == 0 || memchr(data, 0, len)) {
+ if (!gjs_string_from_utf8(context, reinterpret_cast<char*>(data), rval))
+ return false;
+ } else {
+ if (!gjs_string_from_utf8_n(context, reinterpret_cast<char*>(data), len,
+ rval))
+ return false;
+ }
+
+ uint8_t* current_data;
+ uint32_t current_len;
+ bool ignore_val;
+
+ // If a garbage collection occurs between when we call
+ // js::GetUint8ArrayLengthAndData and return from gjs_string_from_utf8, a
+ // use-after-free corruption can occur if the garbage collector shifts the
+ // location of the Uint8Array's private data. To mitigate this we call
+ // js::GetUint8ArrayLengthAndData again and then compare if the length and
+ // pointer are still the same. If the pointers differ, we use the slow path
+ // to ensure no data corruption occurred. The shared-ness of an array cannot
+ // change between calls, so we ignore it.
+ js::GetUint8ArrayLengthAndData(byte_array, ¤t_len, &ignore_val,
+ ¤t_data);
+
+ // Ensure the private data hasn't changed
+ if (current_len == len && current_data == data)
+ return true;
+
+ // This was the UTF-8 optimized path, so we explicitly pass the encoding
+ return to_string_impl_slow(context, current_data, current_len, "UTF-8",
+ rval);
+}
+
+GJS_JSAPI_RETURN_CONVENTION
+static bool to_string_func(JSContext* cx, unsigned argc, JS::Value* vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ JS::UniqueChars encoding;
+ JS::RootedObject byte_array(cx);
+
+ if (!gjs_parse_call_args(cx, "toString", args, "o|s", "byteArray",
+ &byte_array, "encoding", &encoding))
+ return false;
+
+ return to_string_impl(cx, byte_array, encoding.get(), args.rval());
+}
+
+
+/* fromString() function implementation */
+GJS_JSAPI_RETURN_CONVENTION
+static bool
+from_string_func(JSContext *context,
+ unsigned argc,
+ JS::Value *vp)
+{
+ JS::CallArgs argv = JS::CallArgsFromVp (argc, vp);
+ JS::UniqueChars encoding;
+ JS::UniqueChars utf8;
+ bool encoding_is_utf8;
+ JS::RootedObject obj(context), array_buffer(context);
+
+ if (!gjs_parse_call_args(context, "fromString", argv, "s|s",
+ "string", &utf8,
+ "encoding", &encoding))
+ return false;
+
+ if (argc > 1) {
+ /* maybe we should be smarter about utf8 synonyms here.
+ * doesn't matter much though. encoding_is_utf8 is
+ * just an optimization anyway.
+ */
+ encoding_is_utf8 = (strcmp(encoding.get(), "UTF-8") == 0);
+ } else {
+ encoding_is_utf8 = true;
+ }
+
+ if (encoding_is_utf8) {
+ /* optimization? avoids iconv overhead and runs
+ * libmozjs hardwired utf16-to-utf8.
+ */
+ size_t len = strlen(utf8.get());
+ array_buffer =
+ JS::NewArrayBufferWithContents(context, len, utf8.release());
+ } else {
+ JSString *str = argv[0].toString(); /* Rooted by argv */
+ GError *error = NULL;
+ char *encoded = NULL;
+ gsize bytes_written;
+
+ /* Scope for AutoCheckCannotGC, will crash if a GC is triggered
+ * while we are using the string's chars */
+ {
+ JS::AutoCheckCannotGC nogc;
+ size_t len;
+
+ if (JS_StringHasLatin1Chars(str)) {
+ const JS::Latin1Char *chars =
+ JS_GetLatin1StringCharsAndLength(context, nogc, str, &len);
+ if (chars == NULL)
+ return false;
+
+ encoded = g_convert((char *) chars, len,
+ encoding.get(), // to_encoding
+ "LATIN1", /* from_encoding */
+ NULL, /* bytes read */
+ &bytes_written, &error);
+ } else {
+ const char16_t *chars =
+ JS_GetTwoByteStringCharsAndLength(context, nogc, str, &len);
+ if (chars == NULL)
+ return false;
+
+ encoded = g_convert((char *) chars, len * 2,
+ encoding.get(), // to_encoding
+ "UTF-16", /* from_encoding */
+ NULL, /* bytes read */
+ &bytes_written, &error);
+ }
+ }
+
+ if (!encoded)
+ return gjs_throw_gerror_message(context, error); // frees GError
+
+ array_buffer =
+ JS::NewExternalArrayBuffer(context, bytes_written, encoded,
+ gfree_arraybuffer_contents, nullptr);
+ }
+
+ if (!array_buffer)
+ return false;
+ obj = JS_NewUint8ArrayWithBuffer(context, array_buffer, 0, -1);
+
+ argv.rval().setObject(*obj);
+ return true;
+}
+
+
+static JSFunctionSpec gjs_text_encoding_module_funcs[] = {
+ JS_FN("fromString", from_string_func, 2, 0),
+ JS_FN("toString", to_string_func, 2, 0),
+ JS_FS_END};
+
+bool gjs_define_text_encoding_stuff(JSContext* cx,
+ JS::MutableHandleObject module) {
+ module.set(JS_NewPlainObject(cx));
+ return JS_DefineFunctions(cx, module, gjs_text_encoding_module_funcs);
+}
diff --git a/gjs/text-encoding.h b/gjs/text-encoding.h
new file mode 100644
index 00000000..b389acf2
--- /dev/null
+++ b/gjs/text-encoding.h
@@ -0,0 +1,25 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
+// SPDX-FileCopyrightText: 2021 Evan Welsh
+
+#ifndef GJS_TEXT_ENCODING_H_
+#define GJS_TEXT_ENCODING_H_
+
+#include <config.h>
+
+#include <stddef.h> // for size_t
+
+#include <glib.h>
+
+#include <js/TypeDecls.h>
+
+#include "gjs/macros.h"
+
+[[nodiscard]] bool to_string_impl(JSContext* cx, JS::HandleObject uint8array,
+ const char* encoding,
+ JS::MutableHandleValue rval);
+
+[[nodiscard]] bool gjs_define_text_encoding_stuff(
+ JSContext* cx, JS::MutableHandleObject module);
+
+#endif // GJS_TEXT_ENCODING_H_
diff --git a/meson.build b/meson.build
index 272f2033..14a5152c 100644
--- a/meson.build
+++ b/meson.build
@@ -403,6 +403,7 @@ libgjs_sources = [
'gjs/native.cpp', 'gjs/native.h',
'gjs/objectbox.cpp', 'gjs/objectbox.h',
'gjs/profiler.cpp', 'gjs/profiler-private.h',
+ 'gjs/text-encoding.cpp', 'gjs/text-encoding.h',
'gjs/stack.cpp',
'modules/console.cpp', 'modules/console.h',
'modules/modules.cpp', 'modules/modules.h',
diff --git a/modules/script/byteArray.js b/modules/script/byteArray.js
index fad022d2..e0b650ac 100644
--- a/modules/script/byteArray.js
+++ b/modules/script/byteArray.js
@@ -2,15 +2,61 @@
// SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
// SPDX-FileCopyrightText: 2017 Philip Chimento <philip chimento gmail com>
-/* eslint no-redeclare: ["error", { "builtinGlobals": false }] */ // for toString
-var {fromGBytes, fromString, toGBytes, toString} = imports._byteArrayNative;
+var {fromGBytes, defineToString} = imports._byteArrayNative;
+
+const Encoding = imports._encodingNative;
+const {GLib} = imports.gi;
// For backwards compatibility
+/**
+ * @param {Iterable<number>} a an iterable to convert into a ByteArray wrapper
+ * @returns {ByteArray}
+ */
function fromArray(a) {
return new ByteArray(Uint8Array.from(a));
}
+/**
+ * @param {Uint8Array} array the Uint8Array to convert to GLib.Bytes
+ * @returns {GLib.Bytes}
+ */
+function toGBytes(array) {
+ if (!(array instanceof Uint8Array))
+ throw new Error('Argument to ByteArray.toGBytes() must be a Uint8Array');
+
+ return new GLib.Bytes(array);
+}
+
+// Allow toString to be declared.
+
+/* eslint no-redeclare: ["error", { "builtinGlobals": false }] */
+
+/**
+ * @param {Uint8Array} array the byte array to decode into a string
+ * @param {string} [encoding] a text encoding tag
+ * @returns {string}
+ */
+function toString(array, encoding = 'utf-8') {
+ if (!(array instanceof Uint8Array))
+ throw new Error('Argument to ByteArray.toString() must be a Uint8Array');
+
+ return Encoding.toString(array, encoding);
+}
+
+/**
+ * @param {string} str the string to encode into bytes
+ * @param {string} [encoding] a text encoding tag
+ * @returns {Uint8Array}
+ */
+function fromString(str, encoding = 'utf-8') {
+ const array = Encoding.fromString(str, encoding);
+
+ defineToString(array);
+
+ return array;
+}
+
var ByteArray = class ByteArray {
constructor(arg = 0) {
if (arg instanceof Uint8Array)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]