details: https://hg.nginx.org/njs/rev/f146b5dc21cc branches: changeset: 2325:f146b5dc21cc user: Dmitry Volyntsev <xei...@nginx.com> date: Wed May 01 17:31:01 2024 -0700 description: QuickJS: added zlib module.
diffstat: auto/init | 1 + auto/make | 42 +- auto/qjs_module | 6 + auto/qjs_modules | 20 + auto/quickjs | 21 + auto/sources | 4 + configure | 3 +- external/njs_shell.c | 15 +- external/qjs_zlib_module.c | 512 +++++++++++++++++++ src/qjs.c | 109 ++++ src/qjs.h | 79 ++ src/qjs_buffer.c | 1174 ++++++++++++++++++++++++++++++++++++++++++++ src/test/njs_unit_test.c | 301 ----------- test/buffer.t.js | 236 ++++++++ test/harness/runTsuite.js | 10 +- test/setup | 2 +- test/zlib.t.mjs | 109 ++++ 17 files changed, 2322 insertions(+), 322 deletions(-) diffs (truncated from 2828 to 1000 lines): diff -r 18fc657411ca -r f146b5dc21cc auto/init --- a/auto/init Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/init Wed May 01 17:31:01 2024 -0700 @@ -16,6 +16,7 @@ NJS_CFLAGS=${NJS_CFLAGS=} NJS_BUILD_DIR=${NJS_BUILD_DIR:-build} NJS_LIB_MODULES= +QJS_LIB_MODULES= NJS_LIBRT= diff -r 18fc657411ca -r f146b5dc21cc auto/make --- a/auto/make Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/make Wed May 01 17:31:01 2024 -0700 @@ -15,11 +15,6 @@ njs_modules_c=$NJS_BUILD_DIR/njs_modules NJS_LIB_SRCS="$NJS_LIB_SRCS $njs_modules_c" -njs_incs=`echo $NJS_LIB_INCS \ - | sed -e "s# *\([^ ]*\)#$njs_regex_cont-I\1#g"` -njs_objs=`echo $NJS_LIB_SRCS \ - | sed -e "s# *\([^ ]*\.\)c#$NJS_BUILD_DIR/\1o$njs_regex_cont#g"` - cat << END > $njs_modules_c #include <njs_main.h> @@ -45,6 +40,43 @@ cat << END END +if [ $NJS_HAVE_QUICKJS = YES ]; then + +qjs_modules_c=$NJS_BUILD_DIR/qjs_modules.c + +NJS_LIB_SRCS="$NJS_LIB_SRCS $qjs_modules_c" + +cat << END > $qjs_modules_c + +#include <qjs.h> + +END + +for mod in $QJS_LIB_MODULES +do + echo "extern qjs_module_t $mod;" >> $qjs_modules_c +done + +echo >> $qjs_modules_c +echo 'qjs_module_t *qjs_modules[] = {' >> $qjs_modules_c + +for mod in $QJS_LIB_MODULES +do + echo " &$mod," >> $qjs_modules_c +done + +cat << END >> $qjs_modules_c + NULL +}; + +END +fi + +njs_incs=`echo $NJS_LIB_INCS \ + | sed -e "s# *\([^ ]*\)#$njs_regex_cont-I\1#g"` +njs_objs=`echo $NJS_LIB_SRCS \ + | sed -e "s# *\([^ ]*\.\)c#$NJS_BUILD_DIR/\1o$njs_regex_cont#g"` + cat << END > $NJS_MAKEFILE # This file is auto-generated by configure diff -r 18fc657411ca -r f146b5dc21cc auto/qjs_module --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/qjs_module Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,6 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) F5, Inc + +QJS_LIB_MODULES="$QJS_LIB_MODULES $njs_module_name" +NJS_LIB_SRCS="$NJS_LIB_SRCS $njs_module_srcs" +NJS_LIB_INCS="$NJS_LIB_INCS $njs_module_incs" diff -r 18fc657411ca -r f146b5dc21cc auto/qjs_modules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/auto/qjs_modules Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,20 @@ +# Copyright (C) Dmitry Volyntsev +# Copyright (C) F5, Inc + +if [ $NJS_HAVE_QUICKJS = YES ]; then + + njs_module_name=qjs_buffer_module + njs_module_incs= + njs_module_srcs=src/qjs_buffer.c + + . auto/qjs_module + + if [ $NJS_ZLIB = YES -a $NJS_HAVE_ZLIB = YES ]; then + njs_module_name=qjs_zlib_module + njs_module_incs= + njs_module_srcs=external/qjs_zlib_module.c + + . auto/qjs_module + fi + +fi diff -r 18fc657411ca -r f146b5dc21cc auto/quickjs --- a/auto/quickjs Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/quickjs Wed May 01 17:31:01 2024 -0700 @@ -25,6 +25,7 @@ if [ $NJS_TRY_QUICKJS = YES ]; then JSRuntime *rt; rt = JS_NewRuntime(); + (void) JS_GetClassID; JS_FreeRuntime(rt); return 0; }" @@ -54,6 +55,26 @@ if [ $NJS_TRY_QUICKJS = YES ]; then fi if [ $njs_found = yes ]; then + + njs_feature="QuickJS JS_NewTypedArray()" + njs_feature_test="#if defined(__GNUC__) && (__GNUC__ >= 8) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored \"-Wcast-function-type\" + #endif + + #include <quickjs.h> + + int main() { + (void) JS_NewTypedArray; + return 0; + }" + + . auto/feature + + if [ $njs_found = yes ]; then + njs_define=NJS_HAVE_QUICKJS_NEW_TYPED_ARRAY . auto/define + fi + NJS_HAVE_QUICKJS=YES NJS_QUICKJS_LIB="$njs_feature_libs" NJS_LIB_INCS="$NJS_LIB_INCS $njs_feature_incs" diff -r 18fc657411ca -r f146b5dc21cc auto/sources --- a/auto/sources Fri Apr 26 16:48:19 2024 -0700 +++ b/auto/sources Wed May 01 17:31:01 2024 -0700 @@ -72,6 +72,10 @@ if [ "$NJS_HAVE_LIBBFD" = "YES" -a "$NJS NJS_LIB_SRCS="$NJS_LIB_SRCS src/njs_addr2line.c" fi +if [ "$NJS_HAVE_QUICKJS" = "YES" ]; then + NJS_LIB_SRCS="$NJS_LIB_SRCS src/qjs.c" +fi + NJS_TS_SRCS=$(find ts/ -name "*.d.ts" -o -name "*.json") NJS_TEST_TS_SRCS=$(find test/ts/ -name "*.ts" -o -name "*.json") diff -r 18fc657411ca -r f146b5dc21cc configure --- a/configure Fri Apr 26 16:48:19 2024 -0700 +++ b/configure Wed May 01 17:31:01 2024 -0700 @@ -21,7 +21,7 @@ NJS_AUTOCONF_ERR=$NJS_BUILD_DIR/autoconf NJS_AUTO_CONFIG_H=$NJS_BUILD_DIR/njs_auto_config.h NJS_MAKEFILE=$NJS_BUILD_DIR/Makefile -NJS_LIB_INCS="src $NJS_BUILD_DIR" +NJS_LIB_INCS="src external $NJS_BUILD_DIR" test -d $NJS_BUILD_DIR || mkdir $NJS_BUILD_DIR @@ -59,6 +59,7 @@ NJS_LIB_AUX_LIBS= . auto/sources . auto/modules +. auto/qjs_modules . auto/make . auto/expect . auto/summary diff -r 18fc657411ca -r f146b5dc21cc external/njs_shell.c --- a/external/njs_shell.c Fri Apr 26 16:48:19 2024 -0700 +++ b/external/njs_shell.c Wed May 01 17:31:01 2024 -0700 @@ -12,18 +12,7 @@ #include <njs_rbtree.h> #if (NJS_HAVE_QUICKJS) -#if defined(__GNUC__) && (__GNUC__ >= 8) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - -#include <quickjs.h> - -#if defined(__GNUC__) && (__GNUC__ >= 8) -#pragma GCC diagnostic pop -#endif -#define NJS_QUICKJS_VERSION "Unknown version" -#include <pthread.h> +#include <qjs.h> #endif #if (!defined NJS_FUZZER_TARGET && defined NJS_HAVE_READLINE) @@ -2822,7 +2811,7 @@ njs_engine_qjs_init(njs_engine_t *engine return NJS_ERROR; } - engine->u.qjs.ctx = JS_NewContext(engine->u.qjs.rt); + engine->u.qjs.ctx = qjs_new_context(engine->u.qjs.rt); if (engine->u.qjs.ctx == NULL) { njs_stderror("JS_NewContext() failed\n"); return NJS_ERROR; diff -r 18fc657411ca -r f146b5dc21cc external/qjs_zlib_module.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/external/qjs_zlib_module.c Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,512 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include <qjs.h> +#include <zlib.h> + +#define NJS_ZLIB_CHUNK_SIZE 1024 + +static JSValue qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int raw); +static JSValue qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv, int raw); + +static JSModuleDef *qjs_zlib_init(JSContext *ctx, const char *name); +static void *qjs_zlib_alloc(void *opaque, u_int items, u_int size); +static void qjs_zlib_free(void *opaque, void *address); + + +static const JSCFunctionListEntry qjs_zlib_constants[] = { + JS_PROP_INT32_DEF("Z_NO_COMPRESSION", + Z_NO_COMPRESSION, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_BEST_SPEED", + Z_BEST_SPEED, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_BEST_COMPRESSION", + Z_BEST_COMPRESSION, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_FILTERED", + Z_FILTERED, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_HUFFMAN_ONLY", + Z_HUFFMAN_ONLY, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_RLE", + Z_RLE, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_FIXED", + Z_FIXED, + JS_PROP_ENUMERABLE), + JS_PROP_INT32_DEF("Z_DEFAULT_STRATEGY", + Z_DEFAULT_STRATEGY, + JS_PROP_ENUMERABLE), +}; + +static const JSCFunctionListEntry qjs_zlib_export[] = { + JS_CFUNC_MAGIC_DEF("deflateRawSync", 2, qjs_zlib_ext_deflate, 1), + JS_CFUNC_MAGIC_DEF("deflateSync", 2, qjs_zlib_ext_deflate, 0), + JS_CFUNC_MAGIC_DEF("inflateRawSync", 2, qjs_zlib_ext_inflate, 1), + JS_CFUNC_MAGIC_DEF("inflateSync", 2, qjs_zlib_ext_inflate, 0), + JS_OBJECT_DEF("constants", + qjs_zlib_constants, + njs_nitems(qjs_zlib_constants), + JS_PROP_CONFIGURABLE), +}; + + +qjs_module_t qjs_zlib_module = { + .name = "zlib", + .init = qjs_zlib_init, +}; + + +static JSValue +qjs_zlib_ext_deflate(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv, int raw) +{ + int rc, chunk_size, level, mem_level, strategy, window_bits; + JSValue ret, options; + z_stream stream; + njs_chb_t chain; + qjs_bytes_t bytes, dictionary; + + chunk_size = NJS_ZLIB_CHUNK_SIZE; + mem_level = 8; + level = Z_DEFAULT_COMPRESSION; + strategy = Z_DEFAULT_STRATEGY; + window_bits = raw ? -MAX_WBITS : MAX_WBITS; + + NJS_CHB_CTX_INIT(&chain, ctx); + dictionary.start = NULL; + dictionary.length = 0; + stream.opaque = NULL; + + options = argv[1]; + + if (JS_IsObject(options)) { + ret = JS_GetPropertyStr(ctx, options, "chunkSize"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &chunk_size, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (chunk_size < 64) { + JS_ThrowRangeError(ctx, "chunkSize must be >= 64"); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "level"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &level, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (level < Z_DEFAULT_COMPRESSION || level > Z_BEST_COMPRESSION) { + JS_ThrowRangeError(ctx, "level must be in the range %d..%d", + Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "windowBits"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &window_bits, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (raw) { + if (window_bits < -15 || window_bits > -9) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "-15..-9"); + return JS_EXCEPTION; + } + + } else { + if (window_bits < 9 || window_bits > 15) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "9..15"); + return JS_EXCEPTION; + } + } + } + + ret = JS_GetPropertyStr(ctx, options, "memLevel"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &mem_level, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (mem_level < 1 || mem_level > 9) { + JS_ThrowRangeError(ctx, "memLevel must be in the range 1..9"); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "strategy"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &strategy, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + switch (strategy) { + case Z_FILTERED: + case Z_HUFFMAN_ONLY: + case Z_RLE: + case Z_FIXED: + case Z_DEFAULT_STRATEGY: + break; + + default: + JS_ThrowRangeError(ctx, "unknown strategy: %d", strategy); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "dictionary"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = qjs_to_bytes(ctx, &dictionary, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + } + } + + rc = qjs_to_bytes(ctx, &bytes, argv[0]); + if (rc != 0) { + return JS_EXCEPTION; + } + + stream.next_in = bytes.start; + stream.avail_in = bytes.length; + + stream.zalloc = qjs_zlib_alloc; + stream.zfree = qjs_zlib_free; + stream.opaque = ctx; + + rc = deflateInit2(&stream, level, Z_DEFLATED, window_bits, mem_level, + strategy); + if (njs_slow_path(rc != Z_OK)) { + JS_ThrowInternalError(ctx, "deflateInit2() failed"); + goto fail; + } + + if (dictionary.start != NULL) { + rc = deflateSetDictionary(&stream, dictionary.start, dictionary.length); + if (rc != Z_OK) { + JS_ThrowInternalError(ctx, "deflateSetDictionary() failed"); + goto fail; + } + } + + do { + stream.next_out = njs_chb_reserve(&chain, chunk_size); + if (njs_slow_path(stream.next_out == NULL)) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + + stream.avail_out = chunk_size; + + rc = deflate(&stream, Z_FINISH); + if (njs_slow_path(rc < 0)) { + JS_ThrowInternalError(ctx, "failed to deflate the data: %s", + stream.msg); + goto fail; + } + + njs_chb_written(&chain, chunk_size - stream.avail_out); + + } while (stream.avail_out == 0); + + deflateEnd(&stream); + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + ret = qjs_buffer_chb_alloc(ctx, &chain); + + njs_chb_destroy(&chain); + + return ret; + +fail: + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + if (stream.opaque != NULL) { + deflateEnd(&stream); + } + + if (chain.pool != NULL) { + njs_chb_destroy(&chain); + } + + return JS_EXCEPTION; +} + + +static JSValue +qjs_zlib_ext_inflate(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv, int raw) +{ + int rc, chunk_size, window_bits; + JSValue ret, options; + z_stream stream; + njs_chb_t chain; + qjs_bytes_t bytes, dictionary; + + chunk_size = NJS_ZLIB_CHUNK_SIZE; + window_bits = raw ? -MAX_WBITS : MAX_WBITS; + + NJS_CHB_CTX_INIT(&chain, ctx); + dictionary.start = NULL; + dictionary.length = 0; + stream.opaque = NULL; + + options = argv[1]; + + if (JS_IsObject(options)) { + ret = JS_GetPropertyStr(ctx, options, "chunkSize"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &chunk_size, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (chunk_size < 64) { + JS_ThrowRangeError(ctx, "chunkSize must be >= 64"); + return JS_EXCEPTION; + } + } + + ret = JS_GetPropertyStr(ctx, options, "windowBits"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = JS_ToInt32(ctx, &window_bits, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + + if (raw) { + if (window_bits < -15 || window_bits > -8) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "-15..-8"); + return JS_EXCEPTION; + } + + } else { + if (window_bits < 8 || window_bits > 15) { + JS_ThrowRangeError(ctx, "windowBits must be in the range " + "8..15"); + return JS_EXCEPTION; + } + } + } + + ret = JS_GetPropertyStr(ctx, options, "dictionary"); + if (JS_IsException(ret)) { + return JS_EXCEPTION; + } + + if (!JS_IsUndefined(ret)) { + rc = qjs_to_bytes(ctx, &dictionary, ret); + JS_FreeValue(ctx, ret); + if (rc != 0) { + return JS_EXCEPTION; + } + } + } + + rc = qjs_to_bytes(ctx, &bytes, argv[0]); + if (rc != 0) { + return JS_EXCEPTION; + } + + stream.next_in = bytes.start; + stream.avail_in = bytes.length; + + stream.zalloc = qjs_zlib_alloc; + stream.zfree = qjs_zlib_free; + stream.opaque = ctx; + + rc = inflateInit2(&stream, window_bits); + if (njs_slow_path(rc != Z_OK)) { + JS_ThrowInternalError(ctx, "inflateInit2() failed"); + goto fail; + } + + if (dictionary.start != NULL) { + rc = inflateSetDictionary(&stream, dictionary.start, dictionary.length); + if (rc != Z_OK) { + JS_ThrowInternalError(ctx, "inflateSetDictionary() failed"); + goto fail; + } + } + + while (rc != Z_STREAM_END) { + stream.next_out = njs_chb_reserve(&chain, chunk_size); + if (njs_slow_path(stream.next_out == NULL)) { + JS_ThrowOutOfMemory(ctx); + goto fail; + } + + stream.avail_out = chunk_size; + + rc = inflate(&stream, Z_NO_FLUSH); + if (njs_slow_path(rc < 0)) { + JS_ThrowInternalError(ctx, "failed to inflate the data: %s", + stream.msg); + goto fail; + } + + njs_chb_written(&chain, chunk_size - stream.avail_out); + } + + rc = inflateEnd(&stream); + if (njs_slow_path(rc != Z_OK)) { + JS_ThrowInternalError(ctx, "inflateEnd() failed"); + goto fail; + } + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + ret = qjs_buffer_chb_alloc(ctx, &chain); + + njs_chb_destroy(&chain); + + return ret; + +fail: + + qjs_bytes_free(ctx, &bytes); + + if (dictionary.start != NULL) { + qjs_bytes_free(ctx, &dictionary); + } + + if (stream.opaque != NULL) { + inflateEnd(&stream); + } + + if (chain.pool != NULL) { + njs_chb_destroy(&chain); + } + + return JS_EXCEPTION; +} + + +static int +qjs_zlib_module_init(JSContext *ctx, JSModuleDef *m) +{ + int rc; + JSValue proto; + + proto = JS_NewObject(ctx); + JS_SetPropertyFunctionList(ctx, proto, qjs_zlib_export, + njs_nitems(qjs_zlib_export)); + + rc = JS_SetModuleExport(ctx, m, "default", proto); + if (rc != 0) { + return -1; + } + + return JS_SetModuleExportList(ctx, m, qjs_zlib_export, + njs_nitems(qjs_zlib_export)); +} + + +static JSModuleDef * +qjs_zlib_init(JSContext *ctx, const char *name) +{ + int rc; + JSModuleDef *m; + + m = JS_NewCModule(ctx, name, qjs_zlib_module_init); + if (m == NULL) { + return NULL; + } + + JS_AddModuleExport(ctx, m, "default"); + rc = JS_AddModuleExportList(ctx, m, qjs_zlib_export, + njs_nitems(qjs_zlib_export)); + if (rc != 0) { + return NULL; + } + + return m; +} + + +static void * +qjs_zlib_alloc(void *opaque, u_int items, u_int size) +{ + return js_malloc(opaque, items * size); +} + + +static void +qjs_zlib_free(void *opaque, void *address) +{ + js_free(opaque, address); +} diff -r 18fc657411ca -r f146b5dc21cc src/qjs.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/qjs.c Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,109 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include <qjs.h> + + +JSContext * +qjs_new_context(JSRuntime *rt) +{ + JSContext *ctx; + qjs_module_t **module; + + ctx = JS_NewContext(rt); + if (ctx == NULL) { + return NULL; + } + + for (module = qjs_modules; *module != NULL; module++) { + if ((*module)->init(ctx, (*module)->name) == NULL) { + return NULL; + } + } + + return ctx; +} + + +int +qjs_to_bytes(JSContext *ctx, qjs_bytes_t *bytes, JSValueConst value) +{ + size_t byte_offset, byte_length; + JSValue val; + + val = JS_GetTypedArrayBuffer(ctx, value, &byte_offset, &byte_length, NULL); + if (!JS_IsException(val)) { + bytes->start = JS_GetArrayBuffer(ctx, &bytes->length, val); + + JS_FreeValue(ctx, val); + + if (bytes->start != NULL) { + bytes->tag = JS_TAG_OBJECT; + bytes->start += byte_offset; + bytes->length = byte_length; + return 0; + } + } + + bytes->start = JS_GetArrayBuffer(ctx, &bytes->length, value); + if (bytes->start != NULL) { + bytes->tag = JS_TAG_OBJECT; + return 0; + } + + bytes->tag = JS_TAG_STRING; + + if (!JS_IsString(value)) { + val = JS_ToString(ctx, value); + + bytes->start = (u_char *) JS_ToCStringLen(ctx, &bytes->length, val); + + JS_FreeValue(ctx, val); + + if (bytes->start == NULL) { + return -1; + } + } + + bytes->start = (u_char *) JS_ToCStringLen(ctx, &bytes->length, value); + + return (bytes->start != NULL) ? 0 : -1; +} + + +void +qjs_bytes_free(JSContext *ctx, qjs_bytes_t *bytes) +{ + if (bytes->tag == JS_TAG_STRING) { + JS_FreeCString(ctx, (char *) bytes->start); + } +} + + +JSValue +qjs_typed_array_data(JSContext *ctx, JSValueConst value, njs_str_t *data) +{ + size_t byte_offset, byte_length; + + value = JS_GetTypedArrayBuffer(ctx, value, &byte_offset, &byte_length, + NULL); + if (JS_IsException(value)) { + return value; + } + + data->start = JS_GetArrayBuffer(ctx, &data->length, value); + + JS_FreeValue(ctx, value); + + if (data->start == NULL) { + return JS_EXCEPTION; + } + + data->start += byte_offset; + data->length = byte_length; + + return JS_UNDEFINED; +} diff -r 18fc657411ca -r f146b5dc21cc src/qjs.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/qjs.h Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,79 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#ifndef _QJS_H_INCLUDED_ +#define _QJS_H_INCLUDED_ + +#include <njs_auto_config.h> + +#include <njs_types.h> +#include <njs_clang.h> +#include <string.h> +#include <njs_str.h> +#include <njs_unicode.h> +#include <njs_utf8.h> +#include <njs_chb.h> + +#if defined(__GNUC__) && (__GNUC__ >= 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + +#include <quickjs.h> + +#if defined(__GNUC__) && (__GNUC__ >= 8) +#pragma GCC diagnostic pop +#endif +#define NJS_QUICKJS_VERSION "Unknown version" +#include <pthread.h> + + +typedef JSModuleDef *(*qjs_addon_init_pt)(JSContext *ctx, const char *name); + +typedef struct { + const char *name; + qjs_addon_init_pt init; +} qjs_module_t; + + +JSContext *qjs_new_context(JSRuntime *rt); + + +JSValue qjs_buffer_alloc(JSContext *ctx, size_t size); +JSValue qjs_buffer_chb_alloc(JSContext *ctx, njs_chb_t *chain); + +typedef int (*qjs_buffer_encode_t)(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +typedef size_t (*qjs_buffer_encode_length_t)(JSContext *ctx, + const njs_str_t *src); + +typedef struct { + njs_str_t name; + qjs_buffer_encode_t encode; + qjs_buffer_encode_length_t encode_length; + qjs_buffer_encode_t decode; + qjs_buffer_encode_length_t decode_length; +} qjs_buffer_encoding_t; + +const qjs_buffer_encoding_t *qjs_buffer_encoding(JSContext *ctx, + JSValueConst value, JS_BOOL thrw); + + +typedef struct { + int tag; + size_t length; + u_char *start; +} qjs_bytes_t; + +int qjs_to_bytes(JSContext *ctx, qjs_bytes_t *data, JSValueConst value); +void qjs_bytes_free(JSContext *ctx, qjs_bytes_t *data); +JSValue qjs_typed_array_data(JSContext *ctx, JSValueConst value, + njs_str_t *data); + + +extern qjs_module_t *qjs_modules[]; + +#endif /* _QJS_H_INCLUDED_ */ diff -r 18fc657411ca -r f146b5dc21cc src/qjs_buffer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/qjs_buffer.c Wed May 01 17:31:01 2024 -0700 @@ -0,0 +1,1174 @@ + +/* + * Copyright (C) Dmitry Volyntsev + * Copyright (C) F5, Inc. + */ + +#include <qjs.h> + +static JSValue qjs_buffer(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv); +static JSValue qjs_buffer_from(JSContext *ctx, JSValueConst this_val, int argc, + JSValueConst *argv); +static JSValue qjs_buffer_is_buffer(JSContext *ctx, JSValueConst this_val, + int argc, JSValueConst *argv); +static JSValue qjs_buffer_prototype_to_json(JSContext *ctx, + JSValueConst this_val, int argc, JSValueConst *argv); +static JSValue qjs_buffer_prototype_to_string(JSContext *ctx, + JSValueConst this_val, int argc, JSValueConst *argv); +static JSValue qjs_buffer_from_string(JSContext *ctx, JSValueConst str, + JSValueConst encoding); +static JSValue qjs_buffer_from_typed_array(JSContext *ctx, JSValueConst obj, + size_t offset, size_t size, size_t bytes, int float32); +static JSValue qjs_buffer_from_array_buffer(JSContext *ctx, u_char *buf, + size_t size, JSValueConst offset, JSValueConst length); +static JSValue qjs_buffer_from_object(JSContext *ctx, JSValueConst obj); +static int qjs_base64_encode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static size_t qjs_base64_encode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_base64_decode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static size_t qjs_base64_decode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_base64url_encode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static int qjs_base64url_decode(JSContext *ctx, const njs_str_t *src, + njs_str_t *dst); +static size_t qjs_base64url_decode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_hex_encode(JSContext *ctx, const njs_str_t *src, njs_str_t *dst); +static size_t qjs_hex_encode_length(JSContext *ctx, const njs_str_t *src); +static int qjs_hex_decode(JSContext *ctx, const njs_str_t *src, njs_str_t *dst); +static size_t qjs_hex_decode_length(JSContext *ctx, const njs_str_t *src); +static JSValue qjs_new_uint8_array(JSContext *ctx, size_t size); +static JSModuleDef *qjs_buffer_init(JSContext *ctx, const char *name); + + +static qjs_buffer_encoding_t qjs_buffer_encodings[] = +{ + { + njs_str("utf-8"), + NULL, + NULL, + NULL, + NULL, + }, + + { + njs_str("utf8"), + NULL, + NULL, + NULL, + NULL, + }, + + { + njs_str("base64"), + qjs_base64_encode, + qjs_base64_encode_length, + qjs_base64_decode, + qjs_base64_decode_length, + }, + + { + njs_str("base64url"), + qjs_base64url_encode, + qjs_base64_encode_length, + qjs_base64url_decode, + qjs_base64url_decode_length, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel