[njs] Added support for typed-arrays in String.bytesFrom().
Dmitry Volyntsev
xeioex at nginx.com
Thu Jan 16 12:15:42 UTC 2020
details: https://hg.nginx.org/njs/rev/cb4f1052954f
branches:
changeset: 1300:cb4f1052954f
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Thu Jan 16 15:14:38 2020 +0300
description:
Added support for typed-arrays in String.bytesFrom().
diffstat:
src/njs_string.c | 146 +++++++++++++++++++++++++++++++---------------
src/test/njs_unit_test.c | 20 +++++-
2 files changed, 117 insertions(+), 49 deletions(-)
diffs (239 lines):
diff -r b840b7af946e -r cb4f1052954f src/njs_string.c
--- a/src/njs_string.c Tue Jan 14 16:52:42 2020 +0300
+++ b/src/njs_string.c Thu Jan 16 15:14:38 2020 +0300
@@ -64,10 +64,10 @@ static njs_int_t njs_string_from_code_po
njs_uint_t nargs, njs_index_t unused);
static njs_int_t njs_string_bytes_from(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_index_t unused);
-static njs_int_t njs_string_bytes_from_array(njs_vm_t *vm,
- const njs_value_t *value);
+static njs_int_t njs_string_bytes_from_array_like(njs_vm_t *vm,
+ njs_value_t *value);
static njs_int_t njs_string_bytes_from_string(njs_vm_t *vm,
- const njs_value_t *args, njs_uint_t nargs);
+ const njs_value_t *string, const njs_value_t *encoding);
static njs_int_t njs_string_starts_or_ends_with(njs_vm_t *vm, njs_value_t *args,
njs_uint_t nargs, njs_bool_t starts);
static njs_int_t njs_string_trim(njs_vm_t *vm, njs_value_t *value,
@@ -1603,8 +1603,8 @@ done:
/*
- * String.bytesFrom(array).
- * Converts an array containing octets into a byte string.
+ * String.bytesFrom(array-like).
+ * Converts an array-like object containing octets into a byte string.
*
* String.bytesFrom(string[, encoding]).
* Converts a string using provided encoding: hex, base64, base64url to
@@ -1619,38 +1619,63 @@ njs_string_bytes_from(njs_vm_t *vm, njs_
value = njs_arg(args, nargs, 1);
- if (njs_is_string(value)) {
- return njs_string_bytes_from_string(vm, args, nargs);
- }
-
- if (njs_is_array(value)) {
- return njs_string_bytes_from_array(vm, njs_arg(args, nargs, 1));
- }
-
- njs_type_error(vm, "value must be a string or array");
+ switch (value->type) {
+ case NJS_OBJECT_STRING:
+ value = njs_object_value(value);
+
+ /* Fall through. */
+
+ case NJS_STRING:
+ return njs_string_bytes_from_string(vm, value, njs_arg(args, nargs, 2));
+
+ default:
+ if (njs_is_object(value)) {
+ return njs_string_bytes_from_array_like(vm, value);
+ }
+ }
+
+ njs_type_error(vm, "value must be a string or array-like object");
return NJS_ERROR;
}
static njs_int_t
-njs_string_bytes_from_array(njs_vm_t *vm, const njs_value_t *value)
+njs_string_bytes_from_array_like(njs_vm_t *vm, njs_value_t *value)
{
- u_char *p;
- uint32_t i, length;
- njs_int_t ret;
- njs_array_t *array;
- njs_value_t *octet;
-
- array = njs_array(value);
- length = array->length;
-
- for (i = 0; i < length; i++) {
- if (!njs_is_numeric(&array->start[i])) {
- ret = njs_value_to_numeric(vm, &array->start[i], &array->start[i]);
- if (ret != NJS_OK) {
- return ret;
- }
+ u_char *p;
+ uint32_t u32, length;
+ njs_int_t ret;
+ njs_array_t *array;
+ njs_value_t *octet, index, prop;
+ njs_array_buffer_t *buffer;
+
+ array = NULL;
+ buffer = NULL;
+
+ switch (value->type) {
+ case NJS_ARRAY:
+ array = njs_array(value);
+ length = array->length;
+ break;
+
+ case NJS_ARRAY_BUFFER:
+ case NJS_TYPED_ARRAY:
+
+ if (njs_is_typed_array(value)) {
+ buffer = njs_typed_array(value)->buffer;
+
+ } else {
+ buffer = njs_array_buffer(value);
+ }
+
+ length = buffer->size;
+ break;
+
+ default:
+ ret = njs_object_length(vm, value, &length);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
}
}
@@ -1659,12 +1684,42 @@ njs_string_bytes_from_array(njs_vm_t *vm
return NJS_ERROR;
}
- octet = array->start;
-
- while (length != 0) {
- *p++ = (u_char) njs_number_to_uint32(njs_number(octet));
- octet++;
- length--;
+ if (array != NULL) {
+ octet = array->start;
+
+ while (length != 0) {
+ ret = njs_value_to_uint32(vm, octet, &u32);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *p++ = (u_char) u32;
+ octet++;
+ length--;
+ }
+
+ } else if (buffer != NULL) {
+ memcpy(p, buffer->u.u8, length);
+
+ } else {
+ p += length - 1;
+
+ while (length != 0) {
+ njs_uint32_to_string(&index, length - 1);
+
+ ret = njs_value_property(vm, value, &index, &prop);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ ret = njs_value_to_uint32(vm, &prop, &u32);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *p-- = (u_char) u32;
+ length--;
+ }
}
return NJS_OK;
@@ -1672,21 +1727,18 @@ njs_string_bytes_from_array(njs_vm_t *vm
static njs_int_t
-njs_string_bytes_from_string(njs_vm_t *vm, const njs_value_t *args,
- njs_uint_t nargs)
+njs_string_bytes_from_string(njs_vm_t *vm, const njs_value_t *string,
+ const njs_value_t *encoding)
{
- njs_str_t enc, str;
- njs_value_t *enc_val;
-
- enc_val = njs_arg(args, nargs, 2);
-
- if (njs_slow_path(nargs > 1 && !njs_is_string(enc_val))) {
- njs_type_error(vm, "encoding must be a string");
+ njs_str_t enc, str;
+
+ if (!njs_is_string(encoding)) {
+ njs_type_error(vm, "\"encoding\" must be a string");
return NJS_ERROR;
}
- njs_string_get(enc_val, &enc);
- njs_string_get(&args[1], &str);
+ njs_string_get(encoding, &enc);
+ njs_string_get(string, &str);
if (enc.length == 3 && memcmp(enc.start, "hex", 3) == 0) {
return njs_string_decode_hex(vm, &vm->retval, &str);
diff -r b840b7af946e -r cb4f1052954f src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Tue Jan 14 16:52:42 2020 +0300
+++ b/src/test/njs_unit_test.c Thu Jan 16 15:14:38 2020 +0300
@@ -7635,8 +7635,15 @@ static njs_unit_test_t njs_test[] =
{ njs_str("'abc'.padEnd(10, Symbol())"),
njs_str("TypeError: Cannot convert a Symbol value to a string") },
- { njs_str("String.bytesFrom({})"),
- njs_str("TypeError: value must be a string or array") },
+ { njs_str("[undefined, null, Symbol()]"
+ ".every(v=> { try {String.bytesFrom(v);} catch(e) {return e.name == 'TypeError'} })"),
+ njs_str("true") },
+
+ { njs_str("String.bytesFrom({}).length"),
+ njs_str("0") },
+
+ { njs_str("String.bytesFrom({length:5, 0:'A'.charCodeAt(0), 2:'X', 3:NaN,4:0xfd}).toString('hex')"),
+ njs_str("41000000fd") },
{ njs_str("String.bytesFrom([1, 2, 0.23, '5', 'A']).toString('hex')"),
njs_str("0102000500") },
@@ -7644,12 +7651,21 @@ static njs_unit_test_t njs_test[] =
{ njs_str("String.bytesFrom([NaN, Infinity]).toString('hex')"),
njs_str("0000") },
+ { njs_str("String.bytesFrom(new Uint8Array([0xff,0xde,0xba])).toString('hex')"),
+ njs_str("ffdeba") },
+
+ { njs_str("String.bytesFrom((new Uint8Array([0xff,0xde,0xba])).buffer).toString('hex')"),
+ njs_str("ffdeba") },
+
{ njs_str("String.bytesFrom('', 'hex')"),
njs_str("") },
{ njs_str("String.bytesFrom('00aabbcc', 'hex').toString('hex')"),
njs_str("00aabbcc") },
+ { njs_str("String.bytesFrom(new String('00aabbcc'), 'hex').toString('hex')"),
+ njs_str("00aabbcc") },
+
{ njs_str("String.bytesFrom('deadBEEF##', 'hex').toString('hex')"),
njs_str("deadbeef") },
More information about the nginx-devel
mailing list