diff --git a/api-test.c b/api-test.c index d0d69c22a..4e5da750d 100644 --- a/api-test.c +++ b/api-test.c @@ -233,6 +233,42 @@ static void module_serde(void) JS_FreeRuntime(rt); } +static void two_byte_string(void) +{ + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + { + JSValue v = JS_NewTwoByteString(ctx, NULL, 0); + assert(!JS_IsException(v)); + const char *s = JS_ToCString(ctx, v); + assert(s); + assert(!strcmp(s, "")); + JS_FreeCString(ctx, s); + JS_FreeValue(ctx, v); + } + { + JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){'o','k'}, 2); + assert(!JS_IsException(v)); + const char *s = JS_ToCString(ctx, v); + assert(s); + assert(!strcmp(s, "ok")); + JS_FreeCString(ctx, s); + JS_FreeValue(ctx, v); + } + { + JSValue v = JS_NewTwoByteString(ctx, (uint16_t[]){0xD800}, 1); + assert(!JS_IsException(v)); + const char *s = JS_ToCString(ctx, v); + assert(s); + // questionable but surrogates don't map to UTF-8 without WTF-8 + assert(!strcmp(s, "\xED\xA0\x80")); + JS_FreeCString(ctx, s); + JS_FreeValue(ctx, v); + } + JS_FreeContext(ctx); + JS_FreeRuntime(rt); +} + int main(void) { sync_call(); @@ -241,5 +277,6 @@ int main(void) raw_context_global_var(); is_array(); module_serde(); + two_byte_string(); return 0; } diff --git a/quickjs.c b/quickjs.c index 97654bc7e..09986c2fc 100644 --- a/quickjs.c +++ b/quickjs.c @@ -4030,6 +4030,19 @@ JSValue JS_NewStringLen(JSContext *ctx, const char *buf, size_t buf_len) return JS_MKPTR(JS_TAG_STRING, str); } +JSValue JS_NewTwoByteString(JSContext *ctx, const uint16_t *buf, size_t len) +{ + JSString *str; + + if (!len) + return JS_AtomToString(ctx, JS_ATOM_empty_string); + str = js_alloc_string(ctx, len, 1); + if (!str) + return JS_EXCEPTION; + memcpy(str16(str), buf, len * sizeof(*buf)); + return JS_MKPTR(JS_TAG_STRING, str); +} + static JSValue JS_ConcatString3(JSContext *ctx, const char *str1, JSValue str2, const char *str3) { diff --git a/quickjs.h b/quickjs.h index cd529274c..77f72a2f8 100644 --- a/quickjs.h +++ b/quickjs.h @@ -761,6 +761,10 @@ JS_EXTERN JSValue JS_NewStringLen(JSContext *ctx, const char *str1, size_t len1) static inline JSValue JS_NewString(JSContext *ctx, const char *str) { return JS_NewStringLen(ctx, str, strlen(str)); } +// makes a copy of the input; does not check if the input is valid UTF-16, +// that is the responsibility of the caller +JS_EXTERN JSValue JS_NewTwoByteString(JSContext *ctx, const uint16_t *buf, + size_t len); JS_EXTERN JSValue JS_NewAtomString(JSContext *ctx, const char *str); JS_EXTERN JSValue JS_ToString(JSContext *ctx, JSValueConst val); JS_EXTERN JSValue JS_ToPropertyKey(JSContext *ctx, JSValueConst val);