--- /dev/null
+
+/*
+ * Copyright (C) Alexander Borisov
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#include <njs_main.h>
+
+
+#define INT24_MAX 0x7FFFFF
+#define INT40_MAX 0x7FFFFFFFFFULL
+#define INT48_MAX 0x7FFFFFFFFFFFULL
+
+#define njs_buffer_magic(size, sign, little) \
+ ((size << 2) | (sign << 1) | little)
+
+
+typedef njs_int_t (*njs_buffer_encode)(njs_vm_t *vm, njs_value_t *value,
+ const njs_str_t *src);
+typedef size_t (*njs_buffer_encode_length)(const njs_str_t *src,
+ size_t *out_size);
+
+typedef struct {
+ njs_str_t name;
+ njs_buffer_encode encode;
+ njs_buffer_encode decode;
+ njs_buffer_encode_length decode_length;
+} njs_buffer_encoding_t;
+
+
+static njs_buffer_encoding_t njs_buffer_encodings[] =
+{
+ {
+ njs_str("utf-8"),
+ njs_string_decode_utf8,
+ njs_string_decode_utf8,
+ njs_decode_utf8_length
+ },
+
+ {
+ njs_str("utf8"),
+ njs_string_decode_utf8,
+ njs_string_decode_utf8,
+ njs_decode_utf8_length
+ },
+
+ {
+ njs_str("hex"),
+ njs_string_hex,
+ njs_string_decode_hex,
+ njs_decode_hex_length
+ },
+
+ {
+ njs_str("base64"),
+ njs_string_base64,
+ njs_string_decode_base64,
+ njs_decode_base64_length
+ },
+
+ {
+ njs_str("base64url"),
+ njs_string_base64url,
+ njs_string_decode_base64url,
+ njs_decode_base64url_length
+ },
+
+ { njs_null_str, 0, 0, 0 }
+
+#define njs_buffer_utf8_encoding() &njs_buffer_encodings[0]
+};
+
+
+static njs_int_t njs_buffer_from_object(njs_vm_t *vm, njs_value_t *value);
+static njs_int_t njs_buffer_from_array_buffer(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *length, njs_value_t *offset);
+static njs_int_t njs_buffer_from_typed_array(njs_vm_t *vm, njs_value_t *value);
+static njs_int_t njs_buffer_from_string(njs_vm_t *vm, njs_value_t *value,
+ const njs_buffer_encoding_t *encoding);
+static njs_int_t njs_buffer_write_string(njs_vm_t *vm, njs_value_t *value,
+ njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
+ uint64_t offset, uint64_t length);
+static njs_int_t njs_buffer_fill(njs_vm_t *vm, njs_typed_array_t *array,
+ njs_value_t *value, const njs_buffer_encoding_t *encoding, uint64_t offset,
+ uint64_t end);
+static njs_int_t njs_buffer_fill_string(njs_vm_t *vm, njs_value_t *value,
+ njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
+ uint8_t *start, uint8_t *end);
+static njs_int_t njs_buffer_fill_typed_array(njs_vm_t *vm, njs_value_t *value,
+ njs_typed_array_t *array, uint8_t *start, uint8_t *end);
+static const njs_buffer_encoding_t *njs_buffer_encoding(njs_vm_t *vm,
+ njs_value_t *value);
+static njs_int_t njs_buffer_decode_string(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *dst, const njs_buffer_encoding_t *encoding);
+static void njs_buffer_decode_destroy(njs_vm_t *vm, njs_value_t *source,
+ njs_value_t *target);
+
+
+njs_int_t
+njs_buffer_set(njs_vm_t *vm, njs_value_t *value, const u_char *start,
+ uint32_t size)
+{
+ njs_object_t *proto;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ array = njs_mp_alloc(vm->mem_pool, sizeof(njs_typed_array_t)
+ + sizeof(njs_array_buffer_t));
+ if (njs_slow_path(array == NULL)) {
+ njs_memory_error(vm);
+ return NJS_ERROR;
+ }
+
+ buffer = (njs_array_buffer_t *) &array[1];
+
+ proto = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+
+ njs_lvlhsh_init(&buffer->object.hash);
+ njs_lvlhsh_init(&buffer->object.shared_hash);
+ buffer->object.__proto__ = proto;
+ buffer->object.slots = NULL;
+ buffer->object.type = NJS_ARRAY_BUFFER;
+ buffer->object.shared = 1;
+ buffer->object.extensible = 1;
+ buffer->object.error_data = 0;
+ buffer->object.fast_array = 0;
+ buffer->u.data = (void *) start;
+ buffer->size = size;
+
+ array->type = NJS_OBJ_TYPE_UINT8_ARRAY;
+ njs_lvlhsh_init(&array->object.hash);
+ njs_lvlhsh_init(&array->object.shared_hash);
+ array->object.__proto__ = &vm->prototypes[array->type].object;
+ array->object.slots = NULL;
+ array->object.type = NJS_TYPED_ARRAY;
+ array->object.shared = 0;
+ array->object.extensible = 1;
+ array->object.error_data = 0;
+ array->object.fast_array = 1;
+ array->buffer = buffer;
+ array->offset = 0;
+ array->byte_length = size;
+
+ njs_set_typed_array(value, array);
+
+ return NJS_OK;
+}
+
+
+static njs_typed_array_t *
+njs_buffer_alloc_array(njs_vm_t *vm, size_t size, njs_bool_t zeroing)
+{
+ njs_value_t value;
+ njs_typed_array_t *array;
+
+ njs_set_number(&value, size);
+
+ array = njs_typed_array_alloc(vm, &value, 1, zeroing,
+ NJS_OBJ_TYPE_UINT8_ARRAY);
+ if (njs_slow_path(array == NULL)) {
+ return NULL;
+ }
+
+ array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+
+ return array;
+}
+
+
+static njs_int_t
+njs_buffer_constructor(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_type_error(vm, "Buffer is not a constructor");
+
+ return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_buffer_alloc(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t safe)
+{
+ double size;
+ njs_int_t ret;
+ njs_typed_array_t *array;
+ const njs_buffer_encoding_t *encoding;
+
+ if (njs_slow_path(!njs_is_number(njs_arg(args, nargs, 1)))) {
+ njs_type_error(vm, "\"size\" argument must be of type number");
+ return NJS_ERROR;
+ }
+
+ size = njs_number(njs_argument(args, 1));
+ if (njs_slow_path(size < 0 || size > INT32_MAX)) {
+ njs_range_error(vm, "invalid size");
+ return NJS_ERROR;
+ }
+
+ array = njs_buffer_alloc_array(vm, size, safe || nargs <= 2);
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (safe && nargs > 2) {
+ encoding = njs_buffer_utf8_encoding();
+
+ if (nargs > 3 && njs_is_string(njs_argument(args, 2))) {
+ encoding = njs_buffer_encoding(vm, njs_argument(args, 3));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ ret = njs_buffer_fill(vm, array, njs_argument(args, 2), encoding, 0,
+ array->byte_length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
+
+ njs_set_typed_array(&vm->retval, array);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_from(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_int_t ret;
+ njs_value_t *value;
+ const njs_buffer_encoding_t *encoding;
+
+ value = njs_arg(args, nargs, 1);
+
+ switch (value->type) {
+ case NJS_TYPED_ARRAY:
+ return njs_buffer_from_typed_array(vm, value);
+
+ case NJS_ARRAY_BUFFER:
+ return njs_buffer_from_array_buffer(vm, value, njs_arg(args, nargs, 2),
+ njs_arg(args, nargs, 3));
+
+ case NJS_STRING:
+ encoding = njs_buffer_utf8_encoding();
+
+ if (nargs > 2) {
+ encoding = njs_buffer_encoding(vm, njs_argument(args, 2));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ return njs_buffer_from_string(vm, value, encoding);
+
+ default:
+ if (njs_is_object(value)) {
+ ret = njs_buffer_from_object(vm, value);
+ if (njs_slow_path(ret != NJS_DECLINED)) {
+ return ret;
+ }
+ }
+
+ njs_type_error(vm, "first argument %s is not a string "
+ "or Buffer-like object", njs_type_string(value->type));
+ }
+
+ return NJS_ERROR;
+}
+
+
+static njs_int_t
+njs_buffer_from_object(njs_vm_t *vm, njs_value_t *value)
+{
+ double num;
+ int64_t len;
+ uint8_t *p;
+ uint32_t i;
+ njs_str_t str;
+ njs_int_t ret;
+ njs_array_t *array;
+ njs_value_t retval, length;
+ njs_typed_array_t *buffer;
+
+ static const njs_value_t string_length = njs_string("length");
+ static const njs_str_t str_buffer = njs_str("Buffer");
+
+next:
+
+ ret = njs_value_property(vm, value, njs_value_arg(&string_length),
+ &length);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (ret == NJS_DECLINED) {
+ ret = njs_value_property(vm, value, njs_value_arg(&njs_string_type),
+ &retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_DECLINED;
+ }
+
+ ret = njs_value_to_string(vm, &retval, &retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_DECLINED;
+ }
+
+ njs_string_get(&retval, &str);
+
+ if (!njs_strstr_eq(&str, &str_buffer)) {
+ return NJS_DECLINED;
+ }
+
+ ret = njs_value_property(vm, value, njs_value_arg(&njs_string_data),
+ &retval);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_DECLINED;
+ }
+
+ if (njs_is_object(&retval)) {
+ value = &retval;
+ goto next;
+ }
+
+ return NJS_DECLINED;
+ }
+
+ ret = njs_value_to_length(vm, &length, &len);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ buffer = njs_buffer_alloc_array(vm, len, 0);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ p = njs_typed_array_buffer(buffer)->u.u8;
+
+ if (njs_is_fast_array(value)) {
+ array = njs_array(value);
+
+ for (i = 0; i < array->length; i++) {
+ ret = njs_value_to_number(vm, &array->start[i], &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *p++ = njs_number_to_int32(num);
+ }
+
+ njs_set_typed_array(&vm->retval, buffer);
+
+ return NJS_OK;
+ }
+
+ for (i = 0; i < len; i++) {
+ ret = njs_value_property_i64(vm, value, i, &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ ret = njs_value_to_number(vm, &retval, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ *p++ = njs_number_to_int32(num);
+ }
+
+ njs_set_typed_array(&vm->retval, buffer);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_from_array_buffer(njs_vm_t *vm, njs_value_t *value,
+ njs_value_t *offset, njs_value_t *length)
+{
+ int64_t off, len;
+ njs_int_t ret;
+ njs_value_t arg;
+ njs_typed_array_t *buffer;
+ njs_array_buffer_t *array;
+
+ array = njs_array_buffer(value);
+
+ ret = njs_value_to_index(vm, offset, (uint64_t *) &off);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if ((size_t) off > array->size) {
+ njs_range_error(vm, "\"offset\" is outside of buffer bounds");
+ return NJS_ERROR;
+ }
+
+ if (njs_is_defined(length)) {
+ ret = njs_value_to_length(vm, length, &len);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ } else {
+ len = array->size - off;
+ }
+
+ if ((size_t) (off + len) > array->size) {
+ njs_range_error(vm, "\"length\" is outside of buffer bounds");
+ return NJS_ERROR;
+ }
+
+ njs_set_array_buffer(&arg, array);
+
+ buffer = njs_typed_array_alloc(vm, &arg, 1, 0, NJS_OBJ_TYPE_UINT8_ARRAY);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ buffer->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+
+ buffer->offset = off;
+ buffer->byte_length = len;
+
+ njs_set_typed_array(&vm->retval, buffer);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_from_typed_array(njs_vm_t *vm, njs_value_t *value)
+{
+ uint8_t *p;
+ uint32_t i, length;
+ njs_typed_array_t *buffer, *array;
+
+ array = njs_typed_array(value);
+ length = njs_typed_array_length(array);
+
+ buffer = njs_buffer_alloc_array(vm, length, 0);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ p = njs_typed_array_buffer(buffer)->u.u8;
+
+ for (i = 0; i < length; i++) {
+ *p++ = njs_number_to_int32(njs_typed_array_prop(array, i));
+ }
+
+ njs_set_typed_array(&vm->retval, buffer);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_from_string(njs_vm_t *vm, njs_value_t *value,
+ const njs_buffer_encoding_t *encoding)
+{
+ njs_int_t ret;
+ njs_str_t str;
+ njs_value_t dst;
+ njs_typed_array_t *buffer;
+
+ ret = njs_buffer_decode_string(vm, value, &dst, encoding);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&dst, &str);
+
+ buffer = njs_buffer_alloc_array(vm, str.length, 0);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ memcpy(njs_typed_array_buffer(buffer)->u.u8, str.start, str.length);
+
+ njs_buffer_decode_destroy(vm, value, &dst);
+
+ njs_set_typed_array(&vm->retval, buffer);
+
+ return NJS_OK;
+}
+
+
+static size_t
+njs_buffer_decode_string_length(njs_value_t *value,
+ const njs_buffer_encoding_t *encoding)
+{
+ size_t size;
+ njs_str_t str;
+ njs_string_prop_t string;
+
+ (void) njs_string_prop(&string, value);
+
+ str.start = string.start;
+ str.length = string.size;
+ size = string.size;
+
+ if (encoding->decode == njs_string_decode_utf8 && string.length != 0) {
+ return size;
+ }
+
+ encoding->decode_length(&str, &size);
+
+ return size;
+}
+
+
+static njs_int_t
+njs_buffer_byte_length(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ size_t size;
+ njs_value_t *value, *enc;
+ const njs_buffer_encoding_t *encoding;
+
+ value = njs_arg(args, nargs, 1);
+
+ switch (value->type) {
+ case NJS_TYPED_ARRAY:
+ njs_set_number(&vm->retval, njs_typed_array(value)->byte_length);
+ return NJS_OK;
+
+ case NJS_ARRAY_BUFFER:
+ njs_set_number(&vm->retval, njs_array_buffer(value)->size);
+ return NJS_OK;
+
+ case NJS_DATA_VIEW:
+ njs_set_number(&vm->retval, njs_data_view(value)->byte_length);
+ return NJS_OK;
+
+ case NJS_STRING:
+ enc = njs_arg(args, nargs, 2);
+ encoding = njs_buffer_utf8_encoding();
+
+ if (njs_is_defined(enc)) {
+ encoding = njs_buffer_encoding(vm, enc);
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ size = njs_buffer_decode_string_length(value, encoding);
+
+ njs_set_number(&vm->retval, size);
+
+ return NJS_OK;
+
+ default:
+ njs_type_error(vm, "first argument %s is not a string "
+ "or Buffer-like object", njs_type_string(value->type));
+ }
+
+ return NJS_ERROR;
+}
+
+
+static njs_typed_array_t *
+njs_buffer_slot(njs_vm_t *vm, njs_value_t *value, const char *name)
+{
+ njs_typed_array_t *array;
+
+ if (njs_slow_path(!njs_is_object(value))) {
+ goto failed;
+ }
+
+ array = njs_object_proto_lookup(njs_object(value), NJS_TYPED_ARRAY,
+ njs_typed_array_t);
+
+ if (njs_slow_path(array != NULL
+ && array->type != NJS_OBJ_TYPE_UINT8_ARRAY))
+ {
+ goto failed;
+ }
+
+ return array;
+
+failed:
+
+ njs_type_error(vm, "\"%s\" argument must be an instance "
+ "of Buffer or Uint8Array", name);
+ return NULL;
+}
+
+
+static njs_int_t
+njs_buffer_array_range(njs_vm_t *vm, njs_typed_array_t *array,
+ const njs_value_t *start, const njs_value_t *end, const char *name,
+ uint8_t **out_start, uint8_t **out_end)
+{
+ uint8_t *u8;
+ uint64_t num_start, num_end;
+ njs_int_t ret;
+
+ num_start = 0;
+
+ if (njs_is_defined(start)) {
+ ret = njs_value_to_index(vm, njs_value_arg(start), &num_start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ if (num_start > array->byte_length) {
+ njs_range_error(vm, "\"%sStart\" is out of range: %L", name, num_start);
+ return NJS_ERROR;
+ }
+
+ num_end = array->byte_length;
+
+ if (njs_is_defined(end)) {
+ ret = njs_value_to_index(vm, njs_value_arg(end), &num_end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ if (num_end > array->byte_length) {
+ njs_range_error(vm, "\"%sEnd\" is out of range: %L", name, num_end);
+ return NJS_ERROR;
+ }
+
+ if (num_start > num_end) {
+ num_end = num_start;
+ }
+
+ u8 = njs_typed_array_buffer(array)->u.u8;
+ *out_start = &u8[array->offset + num_start];
+ *out_end = &u8[array->offset + num_end];
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_compare_array(njs_vm_t *vm, njs_value_t *val1, njs_value_t *val2,
+ const njs_value_t *target_start, const njs_value_t *target_end,
+ const njs_value_t *source_start, const njs_value_t *source_end)
+{
+ size_t size, src_size, trg_size;
+ uint8_t *src, *src_end, *trg, *trg_end;
+ njs_int_t ret;
+ njs_typed_array_t *source, *target;
+
+ source = njs_buffer_slot(vm , val1, "source");
+ if (njs_slow_path(source == NULL)) {
+ return NJS_ERROR;
+ }
+
+ target = njs_buffer_slot(vm , val2, "target");
+ if (njs_slow_path(target == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_buffer_array_range(vm, target, target_start, target_end, "target",
+ &trg, &trg_end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_buffer_array_range(vm, source, source_start, source_end, "source",
+ &src, &src_end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ trg_size = trg_end - trg;
+ src_size = src_end - src;
+
+ size = njs_min(trg_size, src_size);
+
+ ret = memcmp(trg, src, size);
+
+ if (ret != 0) {
+ njs_set_number(&vm->retval, (ret < 0) ? 1 : -1);
+ return NJS_OK;
+ }
+
+ if (trg_size > src_size) {
+ ret = -1;
+
+ } else if (trg_size < src_size) {
+ ret = 1;
+ }
+
+ njs_set_number(&vm->retval, ret);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_compare(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ return njs_buffer_compare_array(vm, njs_arg(args, nargs, 1),
+ njs_arg(args, nargs, 2),
+ &njs_value_undefined, &njs_value_undefined,
+ &njs_value_undefined, &njs_value_undefined);
+}
+
+
+static njs_int_t
+njs_buffer_concat(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ u_char *p;
+ size_t n;
+ int64_t i, len, list_len;
+ njs_int_t ret;
+ njs_value_t *list, *value, *length, retval;
+ njs_array_t *array;
+ njs_typed_array_t *buffer, *arr;
+
+ list = njs_arg(args, nargs, 1);
+
+ if (njs_slow_path(!njs_is_array(list))) {
+ njs_type_error(vm, "\"list\" argument must be an instance of Array");
+ return NJS_ERROR;
+ }
+
+ len = 0;
+ ret = njs_object_length(vm, list, &list_len);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (njs_is_fast_array(list)) {
+ array = njs_array(list);
+ for (i = 0; i < list_len; i++) {
+ value = &array->start[i];
+
+ if (njs_slow_path(!njs_is_typed_array_uint8(value))) {
+ njs_type_error(vm, "\"list[%L]\" argument must be an "
+ "instance of Buffer or Uint8Array", i);
+ return NJS_ERROR;
+ }
+
+ arr = njs_typed_array(value);
+
+ if (njs_slow_path((SIZE_MAX - len) < arr->byte_length)) {
+ njs_type_error(vm, "Invalid length");
+ return NJS_ERROR;
+ }
+
+ len += arr->byte_length;
+ }
+
+ } else {
+
+ for (i = 0; i < list_len; i++) {
+ ret = njs_value_property_i64(vm, list, i, &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ if (njs_slow_path(!njs_is_typed_array(&retval))) {
+ njs_type_error(vm, "\"list[%L]\" argument must be an "
+ "instance of Buffer or Uint8Array", i);
+ return NJS_ERROR;
+ }
+
+ arr = njs_typed_array(&retval);
+
+ if (njs_slow_path((SIZE_MAX - len) < arr->byte_length)) {
+ njs_type_error(vm, "Invalid length");
+ return NJS_ERROR;
+ }
+
+ len += arr->byte_length;
+ }
+ }
+
+ length = njs_arg(args, nargs, 2);
+ if (njs_is_defined(length)) {
+ if (njs_slow_path(!njs_is_number(length))) {
+ njs_type_error(vm, "\"length\" argument must be of type number");
+ return NJS_ERROR;
+ }
+
+ len = njs_number(length);
+ if (njs_slow_path(len < 0)) {
+ njs_range_error(vm, "\"length\" is out of range");
+ return NJS_ERROR;
+ }
+ }
+
+ buffer = njs_buffer_alloc_array(vm, len, 0);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ p = njs_typed_array_buffer(buffer)->u.u8;
+
+ if (njs_is_fast_array(list)) {
+ array = njs_array(list);
+
+ for (i = 0; len != 0 && i < list_len; i++) {
+ arr = njs_typed_array(&array->start[i]);
+ n = njs_min((size_t) len, arr->byte_length);
+
+ p = njs_cpymem(p, njs_typed_array_buffer(arr)->u.u8, n);
+
+ len -= n;
+ }
+
+ } else {
+ for (i = 0; len != 0 && i < list_len; i++) {
+ ret = njs_value_property_i64(vm, list, i, &retval);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ arr = njs_typed_array(&retval);
+ n = njs_min((size_t) len, arr->byte_length);
+
+ p = njs_cpymem(p, njs_typed_array_buffer(arr)->u.u8, n);
+
+ len -= n;
+ }
+ }
+
+ if (len != 0) {
+ njs_memzero(p, len);
+ }
+
+ njs_set_typed_array(&vm->retval, buffer);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_is_buffer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_bool_t is;
+ njs_typed_array_t *array;
+
+ is = 0;
+
+ array = njs_buffer_slot(vm , njs_arg(args, nargs, 1), "source");
+
+ if (njs_fast_path(array != NULL && array->object.__proto__
+ == &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object))
+ {
+ is = 1;
+ }
+
+ njs_set_boolean(&vm->retval, is);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_is_encoding(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_set_boolean(&vm->retval,
+ njs_buffer_encoding(vm, njs_arg(args, nargs, 1)) != NULL);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_length(njs_vm_t *vm, njs_object_prop_t *prop,
+ njs_value_t *value, njs_value_t *setval, njs_value_t *retval)
+{
+ njs_typed_array_t *array;
+
+ array = njs_buffer_slot(vm, value, "this");
+ if (njs_slow_path(array == NULL)) {
+ njs_set_undefined(retval);
+ return NJS_DECLINED;
+ }
+
+ njs_set_number(retval, array->byte_length);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_read_int(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t magic)
+{
+ double v;
+ uint32_t u32;
+ uint64_t u64, index, size;
+ njs_int_t ret;
+ njs_bool_t little, swap, sign;
+ njs_value_t *this, *value;
+ const uint8_t *u8;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ this = njs_argument(args, 0);
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_index(vm, njs_arg(args, nargs, 1), &index);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ size = magic >> 2;
+
+ if (!size) {
+ value = njs_arg(args, nargs, 2);
+ if (njs_slow_path(!njs_is_number(value))) {
+ njs_type_error(vm, "\"byteLength\" is not a number");
+ return NJS_ERROR;
+ }
+
+ size = (size_t) njs_number(value);
+ if (njs_slow_path(size > 6)) {
+ njs_type_error(vm, "\"byteLength\" must be <= 6");
+ return NJS_ERROR;
+ }
+ }
+
+ if (njs_slow_path(size + index > array->byte_length)) {
+ njs_range_error(vm, "index %uL is outside the bound of the buffer",
+ index);
+ return NJS_ERROR;
+ }
+
+ sign = (magic >> 1) & 1;
+ little = magic & 1;
+ swap = little;
+
+#if NJS_HAVE_LITTLE_ENDIAN
+ swap = !swap;
+#endif
+
+ buffer = array->buffer;
+ u8 = &buffer->u.u8[index + array->offset];
+
+ switch (size) {
+ case 1:
+ if (sign) {
+ v = (int8_t) *u8;
+
+ } else {
+ v = *u8;
+ }
+
+ break;
+
+ case 2:
+ u32 = *((uint16_t *) u8);
+
+ if (swap) {
+ u32 = njs_bswap_u16(u32);
+ }
+
+ if (sign) {
+ /* Sign extension. */
+
+ u32 |= (u32 & (INT16_MAX + 1ULL)) * UINT32_MAX;
+ v = (int16_t) u32;
+
+ } else {
+ v = u32;
+ }
+
+ break;
+
+ case 3:
+ if (little) {
+ u32 = (u8[2] << 16) | (u8[1] << 8) | u8[0];
+
+ } else {
+ u32 = (u8[0] << 16) | (u8[1] << 8) | u8[2];
+ }
+
+ if (sign) {
+ /* Sign extension. */
+
+ u32 |= (u32 & (INT24_MAX + 1ULL)) * UINT32_MAX;
+ v = (int32_t) u32;
+
+ } else {
+ v = u32;
+ }
+
+ break;
+
+ case 4:
+ u32 = *((uint32_t *) u8);
+
+ if (swap) {
+ u32 = njs_bswap_u32(u32);
+ }
+
+ if (sign) {
+ /* Sign extension. */
+
+ u32 |= (u32 & (INT32_MAX + 1ULL)) * UINT32_MAX;
+ v = (int32_t) u32;
+
+ } else {
+ v = u32;
+ }
+
+ break;
+
+ case 5:
+ if (little) {
+ u64 = ((uint64_t) u8[4] << 32)
+ | ((uint64_t) u8[3] << 24)
+ | (u8[2] << 16)
+ | (u8[1] << 8)
+ | u8[0];
+
+ } else {
+ u64 = ((uint64_t) u8[0] << 32)
+ | ((uint64_t) u8[1] << 24)
+ | (u8[2] << 16)
+ | (u8[3] << 8)
+ | u8[4];
+ }
+
+ if (sign) {
+ /* Sign extension. */
+
+ u64 |= (u64 & (INT40_MAX + 1ULL)) * UINT64_MAX;
+ v = (int64_t) u64;
+
+ } else {
+ v = u64;
+ }
+
+ break;
+
+ case 6:
+ default:
+ if (little) {
+ u64 = ((uint64_t) u8[5] << 40)
+ | ((uint64_t) u8[4] << 32)
+ |((uint64_t) u8[3] << 24)
+ | (u8[2] << 16)
+ | (u8[1] << 8)
+ | u8[0];
+
+ } else {
+ u64 = ((uint64_t) u8[0] << 40)
+ | ((uint64_t) u8[1] << 32)
+ | ((uint64_t) u8[2] << 24)
+ | (u8[3] << 16)
+ | (u8[4] << 8)
+ | u8[5];
+ }
+
+ if (sign) {
+ /* Sign extension. */
+
+ u64 |= (u64 & (INT48_MAX + 1ULL)) * UINT64_MAX;
+ v = (int64_t) u64;
+
+ } else {
+ v = u64;
+ }
+
+ break;
+ }
+
+ njs_set_number(&vm->retval, v);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_read_float(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t magic)
+{
+ double v;
+ uint32_t u32;
+ uint64_t index, size;
+ njs_int_t ret;
+ njs_bool_t little, swap;
+ njs_value_t *this;
+ const uint8_t *u8;
+ njs_conv_f32_t conv_f32;
+ njs_conv_f64_t conv_f64;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ this = njs_argument(args, 0);
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_index(vm, njs_arg(args, nargs, 1), &index);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ size = magic >> 2;
+
+ if (njs_slow_path(size + index > array->byte_length)) {
+ njs_range_error(vm, "index %uL is outside the bound of the buffer",
+ index);
+ return NJS_ERROR;
+ }
+
+ little = magic & 1;
+ swap = little;
+
+#if NJS_HAVE_LITTLE_ENDIAN
+ swap = !swap;
+#endif
+
+ buffer = array->buffer;
+ u8 = &buffer->u.u8[index + array->offset];
+
+ switch (size) {
+ case 4:
+ u32 = *((uint32_t *) u8);
+
+ if (swap) {
+ u32 = njs_bswap_u32(u32);
+ }
+
+ conv_f32.u = u32;
+ v = conv_f32.f;
+ break;
+
+ case 8:
+ default:
+ conv_f64.u = *((uint64_t *) u8);
+
+ if (swap) {
+ conv_f64.u = njs_bswap_u64(conv_f64.u);
+ }
+
+ v = conv_f64.f;
+ }
+
+ njs_set_number(&vm->retval, v);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_write_int(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t magic)
+{
+ uint8_t *u8;
+ int64_t i64;
+ uint32_t u32;
+ uint64_t index, size;
+ njs_int_t ret;
+ njs_bool_t little, swap;
+ njs_value_t *this, *value;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ this = njs_argument(args, 0);
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_integer(vm, njs_arg(args, nargs, 1), &i64);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ index = 0;
+
+ if (nargs > 2) {
+ ret = njs_value_to_index(vm, njs_argument(args, 2), &index);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
+
+ size = magic >> 2;
+
+ if (!size) {
+ value = njs_arg(args, nargs, 3);
+ if (njs_slow_path(!njs_is_number(value))) {
+ njs_type_error(vm, "\"byteLength\" is not a number");
+ return NJS_ERROR;
+ }
+
+ size = (size_t) njs_number(value);
+ if (njs_slow_path(size > 6)) {
+ njs_type_error(vm, "\"byteLength\" must be <= 6");
+ return NJS_ERROR;
+ }
+ }
+
+ if (njs_slow_path(size + index > array->byte_length)) {
+ njs_range_error(vm, "index %uL is outside the bound of the buffer",
+ index);
+ return NJS_ERROR;
+ }
+
+ little = magic & 1;
+ swap = little;
+
+#if NJS_HAVE_LITTLE_ENDIAN
+ swap = !swap;
+#endif
+
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ u8 = &buffer->u.u8[index + array->offset];
+
+ switch (size) {
+ case 1:
+ *u8 = i64;
+ break;
+
+ case 2:
+ u32 = (uint16_t) i64;
+
+ if (swap) {
+ u32 = njs_bswap_u16(u32);
+ }
+
+ *((uint16_t *) u8) = u32;
+ break;
+
+ case 3:
+ if (little) {
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64;
+
+ } else {
+ u8 += 2;
+
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8 = i64;
+ }
+
+ break;
+
+ case 4:
+ u32 = i64;
+
+ if (swap) {
+ u32 = njs_bswap_u32(u32);
+ }
+
+ *((uint32_t *) u8) = u32;
+ break;
+
+ case 5:
+ if (little) {
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64;
+
+ } else {
+ u8 += 4;
+
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8 = i64;
+ }
+
+ break;
+
+ case 6:
+ default:
+ if (little) {
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64; i64 >>= 8;
+ *u8++ = i64;
+
+ } else {
+ u8 += 5;
+
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8-- = i64; i64 >>= 8;
+ *u8 = i64;
+ }
+
+ break;
+ }
+
+ njs_set_undefined(&vm->retval);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_write_float(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t magic)
+{
+ double v;
+ uint8_t *u8;
+ uint64_t index, size;
+ njs_int_t ret;
+ njs_bool_t little, swap;
+ njs_value_t *this;
+ njs_conv_f32_t conv_f32;
+ njs_conv_f64_t conv_f64;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ this = njs_argument(args, 0);
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_value_to_number(vm, njs_arg(args, nargs, 1), &v);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ index = 0;
+
+ if (nargs > 2) {
+ ret = njs_value_to_index(vm, njs_argument(args, 2), &index);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
+
+ size = magic >> 2;
+
+ if (njs_slow_path(size + index > array->byte_length)) {
+ njs_range_error(vm, "index %uL is outside the bound of the buffer",
+ index);
+ return NJS_ERROR;
+ }
+
+ little = magic & 1;
+ swap = little;
+
+#if NJS_HAVE_LITTLE_ENDIAN
+ swap = !swap;
+#endif
+
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ u8 = &buffer->u.u8[index + array->offset];
+
+ switch (size) {
+ case 4:
+ conv_f32.f = (float) v;
+
+ if (swap) {
+ conv_f32.u = njs_bswap_u32(conv_f32.u);
+ }
+
+ *((uint32_t *) u8) = conv_f32.u;
+ break;
+
+ case 8:
+ default:
+ conv_f64.f = v;
+
+ if (swap) {
+ conv_f64.u = njs_bswap_u64(conv_f64.u);
+ }
+
+ *((uint64_t *) u8) = conv_f64.u;
+ }
+
+ njs_set_undefined(&vm->retval);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_write(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ uint64_t offset, length;
+ njs_int_t ret;
+ njs_value_t *this, *value, *value_offset, *value_length,
+ *enc;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+ const njs_buffer_encoding_t *encoding;
+
+ this = njs_argument(args, 0);
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ value = njs_arg(args, nargs, 1);
+ value_offset = njs_arg(args, nargs, 2);
+ value_length = njs_arg(args, nargs, 3);
+ enc = njs_arg(args, nargs, 4);
+
+ offset = 0;
+ length = array->byte_length;
+ encoding = njs_buffer_utf8_encoding();
+
+ if (njs_slow_path(!njs_is_string(value))) {
+ njs_type_error(vm, "first argument must be a string");
+ return NJS_ERROR;
+ }
+
+ if (njs_is_defined(value_offset)) {
+ if (njs_is_string(value_offset)) {
+ enc = value_offset;
+ goto encoding;
+ }
+
+ ret = njs_value_to_index(vm, value_offset, &offset);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ if (njs_is_defined(value_length)) {
+ if (njs_is_string(value_length)) {
+ enc = value_length;
+ goto encoding;
+ }
+
+ ret = njs_value_to_index(vm, value_length, &length);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ if (njs_is_defined(enc)) {
+ if (njs_slow_path(!njs_is_string(enc))) {
+ njs_type_error(vm, "\"encoding\" argument must be of type string");
+ return NJS_ERROR;
+ }
+
+ encoding:
+
+ encoding = njs_buffer_encoding(vm, enc);
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (offset >= array->byte_length) {
+ njs_range_error(vm, "\"offset\" is out of range");
+ return NJS_ERROR;
+ }
+
+ return njs_buffer_write_string(vm, value, array, encoding, offset, length);
+}
+
+
+static njs_int_t
+njs_buffer_write_string(njs_vm_t *vm, njs_value_t *value,
+ njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
+ uint64_t offset, uint64_t length)
+{
+ uint8_t *start;
+ njs_int_t ret;
+ njs_str_t str;
+ njs_value_t dst;
+ njs_array_buffer_t *buffer;
+
+ buffer = njs_typed_array_buffer(array);
+
+ ret = njs_buffer_decode_string(vm, value, &dst, encoding);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&dst, &str);
+
+ start = &buffer->u.u8[array->offset + offset];
+
+ if (length > array->byte_length - offset) {
+ length = array->byte_length - offset;
+ }
+
+ if (str.length == 0) {
+ length = 0;
+ goto done;
+ }
+
+ memcpy(start, str.start, length);
+
+done:
+
+ njs_buffer_decode_destroy(vm, value, &dst);
+
+ njs_set_number(&vm->retval, length);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_fill(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ uint64_t offset, end;
+ njs_int_t ret;
+ njs_value_t *this, *value, *value_offset, *value_end,
+ *encode;
+ njs_typed_array_t *array;
+ const njs_buffer_encoding_t *encoding;
+
+ this = njs_argument(args, 0);
+ if (njs_slow_path(nargs < 2)) {
+ goto done;
+ }
+
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ value = njs_arg(args, nargs, 1);
+ value_offset = njs_arg(args, nargs, 2);
+ value_end = njs_arg(args, nargs, 3);
+ encode = njs_arg(args, nargs, 4);
+ encoding = njs_buffer_utf8_encoding();
+
+
+ offset = 0;
+ end = array->byte_length;
+
+ if (njs_is_defined(value_offset)) {
+ if (njs_is_string(value) && njs_is_string(value_offset)) {
+ encode = value_offset;
+ goto encoding;
+ }
+
+ ret = njs_value_to_index(vm, value_offset, &offset);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
+
+ if (njs_is_defined(value_end)) {
+ if (njs_is_string(value) && njs_is_string(value_end)) {
+ encode = value_end;
+ goto encoding;
+ }
+
+ ret = njs_value_to_index(vm, value_end, &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+ }
+
+ if (njs_is_defined(encode)) {
+ if (njs_slow_path(!njs_is_string(encode))) {
+ njs_type_error(vm, "\"encoding\" argument must be of type string");
+ return NJS_ERROR;
+ }
+
+ encoding:
+
+ encoding = njs_buffer_encoding(vm, encode);
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ ret = njs_buffer_fill(vm, array, value, encoding, offset, end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+done:
+
+ njs_vm_retval_set(vm, this);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_fill(njs_vm_t *vm, njs_typed_array_t *array, njs_value_t *value,
+ const njs_buffer_encoding_t *encoding, uint64_t offset, uint64_t end)
+{
+ double num;
+ uint8_t *start, *stop;
+ njs_int_t ret;
+ njs_array_buffer_t *buffer;
+
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if (njs_slow_path(offset > array->byte_length)) {
+ njs_range_error(vm, "\"offset\" is out of range");
+ return NJS_ERROR;
+ }
+
+ if (njs_slow_path(end > array->byte_length)) {
+ njs_range_error(vm, "\"end\" is out of range");
+ return NJS_ERROR;
+ }
+
+ if (njs_slow_path(offset >= end)) {
+ return NJS_OK;
+ }
+
+ start = &buffer->u.u8[array->offset + offset];
+ stop = &buffer->u.u8[array->offset + end];
+
+ switch (value->type) {
+ case NJS_STRING:
+ return njs_buffer_fill_string(vm, value, array, encoding, start, stop);
+
+ case NJS_TYPED_ARRAY:
+ return njs_buffer_fill_typed_array(vm, value, array, start, stop);
+
+ default:
+ ret = njs_value_to_number(vm, value, &num);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ memset(start, njs_number_to_uint32(num) & 0xff, end - offset);
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_fill_string(njs_vm_t *vm, njs_value_t *value,
+ njs_typed_array_t *array, const njs_buffer_encoding_t *encoding,
+ uint8_t *start, uint8_t *end)
+{
+ uint64_t n;
+ njs_int_t ret;
+ njs_str_t str;
+ njs_value_t dst;
+
+ ret = njs_buffer_decode_string(vm, value, &dst, encoding);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ njs_string_get(&dst, &str);
+
+ if (str.length == 0) {
+ memset(start, 0, end - start);
+ goto done;
+ }
+
+ while (start < end) {
+ n = njs_min(str.length, (size_t) (end - start));
+ start = njs_cpymem(start, str.start, n);
+ }
+
+done:
+
+ njs_buffer_decode_destroy(vm, value, &dst);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_fill_typed_array(njs_vm_t *vm, njs_value_t *value,
+ njs_typed_array_t *array, uint8_t *to, uint8_t *end)
+{
+ size_t byte_length;
+ uint8_t *from;
+ uint64_t n;
+ njs_typed_array_t *arr_from;
+ njs_array_buffer_t *buffer;
+
+ buffer = njs_typed_array_buffer(array);
+
+ arr_from = njs_typed_array(value);
+ byte_length = arr_from->byte_length;
+ from = &njs_typed_array_buffer(arr_from)->u.u8[arr_from->offset];
+
+ if (njs_typed_array_buffer(arr_from)->u.u8 == buffer->u.u8) {
+ while (to < end) {
+ n = njs_min(byte_length, (size_t) (end - to));
+ memmove(to, from, n);
+ to += n;
+ }
+
+ } else {
+ while (to < end) {
+ n = njs_min(byte_length, (size_t) (end - to));
+ to = njs_cpymem(to, from, n);
+ }
+ }
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_to_string(njs_vm_t *vm, njs_value_t *args,
+ njs_uint_t nargs, njs_index_t unused)
+{
+ uint64_t start, end;
+ njs_int_t ret;
+ njs_str_t str;
+ njs_value_t *this, *enc, *value_start, *value_end;
+ njs_typed_array_t *array;
+ const njs_buffer_encoding_t *encoding;
+
+ this = njs_argument(args, 0);
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ enc = njs_arg(args, nargs, 1);
+ value_start = njs_arg(args, nargs, 2);
+ value_end = njs_arg(args, nargs, 3);
+
+ start = 0;
+ end = array->byte_length;
+ encoding = njs_buffer_utf8_encoding();
+
+ if (njs_is_defined(enc)) {
+ encoding = njs_buffer_encoding(vm, njs_argument(args, 1));
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ if (njs_is_defined(value_start)) {
+ ret = njs_value_to_index(vm, value_start, &start);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ start = njs_min(start, array->byte_length);
+ }
+
+ if (njs_is_defined(value_end)) {
+ ret = njs_value_to_index(vm, value_end, &end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ end = njs_min(end, array->byte_length);
+ }
+
+ str.start = &njs_typed_array_buffer(array)->u.u8[array->offset + start];
+ str.length = end - start;
+
+ if (njs_slow_path(str.length == 0)) {
+ njs_vm_retval_set(vm, &njs_string_empty);
+ return NJS_OK;
+ }
+
+ return encoding->encode(vm, &vm->retval, &str);
+}
+
+
+static njs_int_t
+njs_buffer_prototype_compare(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ return njs_buffer_compare_array(vm, njs_argument(args, 0),
+ njs_arg(args, nargs, 1), njs_arg(args, nargs, 2),
+ njs_arg(args, nargs, 3), njs_arg(args, nargs, 4),
+ njs_arg(args, nargs, 5));
+}
+
+
+static njs_int_t
+njs_buffer_prototype_copy(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ size_t size;
+ uint8_t *src, *src_end, *trg, *trg_end;
+ njs_int_t ret;
+ njs_value_t *val1, *val2;
+ njs_typed_array_t *source, *target;
+ njs_array_buffer_t *buffer, *array;
+
+ val1 = njs_argument(args, 0);
+ val2 = njs_arg(args, nargs, 1);
+
+ source = njs_buffer_slot(vm, val1, "source");
+ if (njs_slow_path(source == NULL)) {
+ return NJS_ERROR;
+ }
+
+ target = njs_buffer_slot(vm, val2, "target");
+ if (njs_slow_path(target == NULL)) {
+ return NJS_ERROR;
+ }
+
+ ret = njs_buffer_array_range(vm, target, njs_arg(args, nargs, 2),
+ &njs_value_undefined, "target", &trg,
+ &trg_end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ ret = njs_buffer_array_range(vm, source, njs_arg(args, nargs, 3),
+ njs_arg(args, nargs, 4), "source", &src,
+ &src_end);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ buffer = njs_typed_array_writable(vm, target);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ array = njs_typed_array_buffer(source);
+
+ size = njs_min(trg_end - trg, src_end - src);
+
+ if (buffer->u.data != array->u.data) {
+ memcpy(trg, src, size);
+
+ } else {
+ memmove(trg, src, size);
+ }
+
+ njs_set_number(&vm->retval, size);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_equals(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_int_t ret;
+
+ ret = njs_buffer_compare_array(vm, njs_argument(args, 0),
+ njs_arg(args, nargs, 1), &njs_value_undefined,
+ &njs_value_undefined, &njs_value_undefined,
+ &njs_value_undefined);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_set_boolean(&vm->retval, njs_number(&vm->retval) == 0);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_index_of(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t last)
+{
+ uint8_t *u8, byte;
+ int64_t from, to, increment, length, offset, index, i;
+ njs_int_t ret;
+ njs_str_t str;
+ njs_value_t *this, *value, *value_from, *enc, dst;
+ njs_typed_array_t *array, *src;
+ const njs_buffer_encoding_t *encoding;
+
+ encoding = njs_buffer_utf8_encoding();
+
+ this = njs_argument(args, 0);
+ value = njs_arg(args, nargs, 1);
+ value_from = njs_arg(args, nargs, 2);
+ enc = njs_arg(args, nargs, 3);
+
+ array = njs_buffer_slot(vm, this, "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ index = -1;
+
+ if (njs_slow_path(array->byte_length == 0)) {
+ goto done;
+ }
+
+ length = array->byte_length;
+
+ if (last) {
+ from = length - 1;
+ to = -1;
+ increment = -1;
+
+ } else {
+ from = 0;
+ to = length;
+ increment = 1;
+ }
+
+ if (njs_is_defined(value_from)) {
+ if (njs_is_string(value) && njs_is_string(value_from)) {
+ enc = value_from;
+ goto encoding;
+ }
+
+ ret = njs_value_to_integer(vm, value_from, &from);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ if (last) {
+ if (from >= 0) {
+ from = njs_min(from, length - 1);
+
+ } else if (from < 0) {
+ from += length;
+ }
+
+ if (from <= to) {
+ goto done;
+ }
+
+ } else {
+ if (from < 0) {
+ from += length;
+
+ if (from < 0) {
+ from = 0;
+ }
+ }
+
+ if (from >= to) {
+ goto done;
+ }
+ }
+ }
+
+ if (njs_is_defined(enc)) {
+
+ encoding:
+
+ encoding = njs_buffer_encoding(vm, enc);
+ if (njs_slow_path(encoding == NULL)) {
+ return NJS_ERROR;
+ }
+ }
+
+ u8 = &njs_typed_array_buffer(array)->u.u8[0];
+ offset = array->offset;
+
+ switch (value->type) {
+ case NJS_STRING:
+ case NJS_TYPED_ARRAY:
+ if (njs_is_string(value)) {
+ ret = njs_buffer_decode_string(vm, value, &dst, encoding);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_string_get(&dst, &str);
+
+ } else {
+ src = njs_typed_array(value);
+ if (njs_slow_path(src->type != NJS_OBJ_TYPE_UINT8_ARRAY)) {
+ goto fail;
+ }
+
+ str.start = &src->buffer->u.u8[src->offset];
+ str.length = src->byte_length;
+ }
+
+ if (njs_slow_path(str.length == 0)) {
+ index = (last) ? length : 0;
+ goto done;
+ }
+
+ if (last) {
+ if (from - to < (int64_t) str.length) {
+ goto done;
+ }
+
+ from -= str.length - 1;
+
+ } else {
+ if (to - from < (int64_t) str.length) {
+ goto done;
+ }
+
+ to -= str.length - 1;
+ }
+
+ for (i = from; i != to; i += increment) {
+ if (memcmp(&u8[offset + i], str.start, str.length) == 0) {
+ index = i;
+ goto done;
+ }
+ }
+
+ break;
+
+ case NJS_NUMBER:
+ byte = njs_number_to_uint32(njs_number(value));
+
+ for (i = from; i != to; i += increment) {
+ if (u8[offset + i] == byte) {
+ index = i;
+ goto done;
+ }
+ }
+
+ break;
+
+ default:
+fail:
+ njs_type_error(vm, "\"value\" argument %s is not a string "
+ "or Buffer-like object", njs_type_string(value->type));
+ return NJS_ERROR;
+ }
+
+done:
+
+ njs_set_number(&vm->retval, index);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_includes(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_int_t ret;
+
+ ret = njs_buffer_prototype_index_of(vm, args, nargs, unused);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ njs_set_boolean(&vm->retval, (njs_number(&vm->retval) != -1));
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_slice(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ njs_int_t ret;
+ njs_typed_array_t *array;
+
+ ret = njs_typed_array_prototype_slice(vm, args, nargs, unused);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ array = njs_typed_array(&vm->retval);
+ array->object.__proto__ = &vm->prototypes[NJS_OBJ_TYPE_BUFFER].object;
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_swap(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t size)
+{
+ uint8_t *p, *end;
+ njs_typed_array_t *array;
+ njs_array_buffer_t *buffer;
+
+ array = njs_buffer_slot(vm, njs_argument(args, 0), "this");
+ if (njs_slow_path(array == NULL)) {
+ return NJS_ERROR;
+ }
+
+ if ((array->byte_length % size) != 0) {
+ njs_range_error(vm, "Buffer size must be a multiple of %d-bits",
+ (int) (size << 3));
+ return NJS_ERROR;
+ }
+
+ buffer = njs_typed_array_writable(vm, array);
+ if (njs_slow_path(buffer == NULL)) {
+ return NJS_ERROR;
+ }
+
+ p = &buffer->u.u8[array->offset];
+ end = p + array->byte_length;
+
+ switch (size) {
+ case 2:
+ for (; p < end; p += 2) {
+ *((uint16_t *) p) = njs_bswap_u16(*((uint16_t *) p));
+ }
+
+ break;
+
+ case 4:
+ for (; p < end; p += 4) {
+ *((uint32_t *) p) = njs_bswap_u32(*((uint32_t *) p));
+ }
+
+ case 8:
+ default:
+ for (; p < end; p += 8) {
+ *((uint64_t *) p) = njs_bswap_u64(*((uint64_t *) p));
+ }
+ }
+
+ njs_set_typed_array(&vm->retval, array);
+
+ return NJS_OK;
+}
+
+
+static njs_int_t
+njs_buffer_prototype_to_json(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
+ njs_index_t unused)
+{
+ u_char *p, *end;
+ njs_int_t ret;
+ njs_value_t *value;
+ njs_value_t object, array;
+ njs_array_t *arr;
+ njs_object_t *obj;
+ njs_typed_array_t *ta;
+
+ static const njs_value_t string_buffer = njs_string("Buffer");
+
+ ta = njs_buffer_slot(vm, njs_argument(args, 0), "this");
+ if (njs_slow_path(ta == NULL)) {
+ return NJS_ERROR;
+ }
+
+ obj = njs_object_alloc(vm);
+ if (njs_slow_path(obj == NULL)) {
+ return NJS_ERROR;
+ }
+
+ njs_set_object(&object, obj);
+
+ ret = njs_value_property_set(vm, &object, njs_value_arg(&njs_string_type),
+ njs_value_arg(&string_buffer));
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ arr = njs_array_alloc(vm, 1, ta->byte_length, 0);
+ if (njs_slow_path(arr == NULL)) {
+ return NJS_ERROR;
+ }
+
+ p = &njs_typed_array_buffer(ta)->u.u8[ta->offset];
+ end = p + ta->byte_length;
+ value = arr->start;
+
+ while (p < end) {
+ njs_set_number(value++, *p++);
+ }
+
+ njs_set_array(&array, arr);
+
+ ret = njs_value_property_set(vm, &object, njs_value_arg(&njs_string_data),
+ &array);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
+ }
+
+ njs_set_object(&vm->retval, obj);
+
+ return NJS_OK;
+}
+
+
+static const njs_buffer_encoding_t *
+njs_buffer_encoding(njs_vm_t *vm, njs_value_t *value)
+{
+ njs_str_t str;
+ njs_int_t ret;
+ njs_buffer_encoding_t *encoding;
+
+ if (njs_slow_path(!njs_is_string(value))) {
+ ret = njs_value_to_string(vm, value, value);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NULL;
+ }
+ }
+
+ njs_string_get(value, &str);
+
+ for (encoding = &njs_buffer_encodings[0];
+ encoding->name.length != 0;
+ encoding++)
+ {
+ if (njs_strstr_eq(&str, &encoding->name)) {
+ return encoding;
+ }
+ }
+
+ njs_type_error(vm, "\"%V\" encoding is not supported", &str);
+
+ return NULL;
+}
+
+
+static njs_int_t
+njs_buffer_decode_string(njs_vm_t *vm, njs_value_t *value, njs_value_t *dst,
+ const njs_buffer_encoding_t *encoding)
+{
+ njs_int_t ret;
+ njs_str_t str;
+ njs_string_prop_t string;
+
+ (void) njs_string_prop(&string, value);
+
+ str.start = string.start;
+ str.length = string.size;
+
+ *dst = *value;
+
+ if (encoding->decode == njs_string_decode_utf8 && string.length != 0) {
+ return NJS_OK;
+ }
+
+ ret = encoding->decode(vm, dst, &str);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ return NJS_OK;
+}
+
+
+static void
+njs_buffer_decode_destroy(njs_vm_t *vm, njs_value_t *source,
+ njs_value_t *target)
+{
+ njs_str_t src, trg;
+
+ njs_string_get(source, &src);
+ njs_string_get(target, &trg);
+
+ if (src.start != trg.start) {
+ njs_mp_free(vm->mem_pool, trg.start);
+ }
+}
+
+
+static const njs_object_prop_t njs_buffer_prototype_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_wellknown_symbol(NJS_SYMBOL_TO_STRING_TAG),
+ .value = njs_string("Buffer"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("constructor"),
+ .value = njs_prop_handler(njs_object_prototype_create_constructor),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("length"),
+ .value = njs_prop_handler(njs_buffer_prototype_length),
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readInt8"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(1, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUInt8"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(1, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readInt16LE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(2, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUInt16LE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(2, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readInt16BE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(2, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUInt16BE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(2, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readInt32LE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(4, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUInt32LE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(4, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readInt32BE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(4, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUInt32BE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 1,
+ njs_buffer_magic(4, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readIntLE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 2,
+ njs_buffer_magic(0, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUIntLE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 2,
+ njs_buffer_magic(0, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readIntBE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 2,
+ njs_buffer_magic(0, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readUIntBE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_int, 2,
+ njs_buffer_magic(0, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readFloatLE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_float, 1,
+ njs_buffer_magic(4, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readFloatBE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_float, 1,
+ njs_buffer_magic(4, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readDoubleLE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_float, 1,
+ njs_buffer_magic(8, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("readDoubleBE"),
+ .value = njs_native_function2(njs_buffer_prototype_read_float, 1,
+ njs_buffer_magic(8, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeInt8"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(1, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUInt8"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(1, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeInt16LE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(2, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUInt16LE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(2, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeInt16BE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(2, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUInt16BE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(2, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeInt32LE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(4, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUInt32LE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(4, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeInt32BE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(4, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUInt32BE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 1,
+ njs_buffer_magic(4, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeIntLE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 3,
+ njs_buffer_magic(0, 1, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUIntLE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 3,
+ njs_buffer_magic(0, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeIntBE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 3,
+ njs_buffer_magic(0, 1, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeUIntBE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_int, 3,
+ njs_buffer_magic(0, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeFloatLE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_float, 1,
+ njs_buffer_magic(4, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeFloatBE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_float, 1,
+ njs_buffer_magic(4, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeDoubleLE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_float, 1,
+ njs_buffer_magic(8, 0, 1)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("writeDoubleBE"),
+ .value = njs_native_function2(njs_buffer_prototype_write_float, 1,
+ njs_buffer_magic(8, 0, 0)),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("write"),
+ .value = njs_native_function(njs_buffer_prototype_write, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("fill"),
+ .value = njs_native_function(njs_buffer_prototype_fill, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("toString"),
+ .value = njs_native_function(njs_buffer_prototype_to_string, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("compare"),
+ .value = njs_native_function(njs_buffer_prototype_compare, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("copy"),
+ .value = njs_native_function(njs_buffer_prototype_copy, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("equals"),
+ .value = njs_native_function(njs_buffer_prototype_equals, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("indexOf"),
+ .value = njs_native_function2(njs_buffer_prototype_index_of, 1, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("lastIndexOf"),
+ .value = njs_native_function2(njs_buffer_prototype_index_of, 1, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("includes"),
+ .value = njs_native_function(njs_buffer_prototype_includes, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("subarray"),
+ .value = njs_native_function2(njs_buffer_prototype_slice, 2, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("slice"),
+ .value = njs_native_function2(njs_buffer_prototype_slice, 2, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("swap16"),
+ .value = njs_native_function2(njs_buffer_prototype_swap, 0, 2),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("swap32"),
+ .value = njs_native_function2(njs_buffer_prototype_swap, 0, 4),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("swap64"),
+ .value = njs_native_function2(njs_buffer_prototype_swap, 0, 8),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("toJSON"),
+ .value = njs_native_function(njs_buffer_prototype_to_json, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+};
+
+
+const njs_object_init_t njs_buffer_prototype_init = {
+ njs_buffer_prototype_properties,
+ njs_nitems(njs_buffer_prototype_properties),
+};
+
+
+static const njs_object_prop_t njs_buffer_constructor_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("Buffer"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("length"),
+ .value = njs_value(NJS_NUMBER, 0, 0.0),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("alloc"),
+ .value = njs_native_function2(njs_buffer_alloc, 0, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("allocUnsafe"),
+ .value = njs_native_function2(njs_buffer_alloc, 1, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("allocUnsafeSlow"),
+ .value = njs_native_function2(njs_buffer_alloc, 1, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("byteLength"),
+ .value = njs_native_function(njs_buffer_byte_length, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("compare"),
+ .value = njs_native_function(njs_buffer_compare, 2),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("concat"),
+ .value = njs_native_function(njs_buffer_concat, 1),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("from"),
+ .value = njs_native_function(njs_buffer_from, 3),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("isBuffer"),
+ .value = njs_native_function(njs_buffer_is_buffer, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("isEncoding"),
+ .value = njs_native_function(njs_buffer_is_encoding, 0),
+ .writable = 1,
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("prototype"),
+ .value = njs_prop_handler(njs_object_prototype_create),
+ },
+};
+
+
+const njs_object_init_t njs_buffer_constructor_init = {
+ njs_buffer_constructor_properties,
+ njs_nitems(njs_buffer_constructor_properties),
+};
+
+
+const njs_object_type_init_t njs_buffer_type_init = {
+ .constructor = njs_native_ctor(njs_buffer_constructor, 0, 0),
+ .prototype_props = &njs_buffer_prototype_init,
+ .constructor_props = &njs_buffer_constructor_init,
+ .prototype_value = { .object = { .type = NJS_OBJECT } },
+};
+
+
+static const njs_object_prop_t njs_buffer_constants_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("MAX_LENGTH"),
+ .value = njs_value(NJS_NUMBER, 1, INT32_MAX),
+ .enumerable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_long_string("MAX_STRING_LENGTH"),
+ .value = njs_value(NJS_NUMBER, 1, NJS_STRING_MAX_LENGTH),
+ .enumerable = 1,
+ },
+};
+
+
+static const njs_object_init_t njs_buffer_constants_init = {
+ njs_buffer_constants_properties,
+ njs_nitems(njs_buffer_constants_properties),
+};
+
+
+static njs_int_t
+njs_buffer_constants(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value,
+ njs_value_t *unused, njs_value_t *retval)
+{
+ return njs_object_prop_init(vm, &njs_buffer_constants_init, prop, value,
+ retval);
+}
+
+
+static njs_int_t
+njs_buffer(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *value,
+ njs_value_t *unused, njs_value_t *retval)
+{
+ return njs_object_prop_init(vm, &njs_buffer_constructor_init, prop, value,
+ retval);
+}
+
+
+static const njs_object_prop_t njs_buffer_object_properties[] =
+{
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("name"),
+ .value = njs_string("buffer"),
+ .configurable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("constants"),
+ .value = njs_prop_handler(njs_buffer_constants),
+ .enumerable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY_HANDLER,
+ .name = njs_string("Buffer"),
+ .value = njs_prop_handler(njs_buffer),
+ .enumerable = 1,
+ },
+
+ {
+ .type = NJS_PROPERTY,
+ .name = njs_string("kMaxLength"),
+ .value = njs_value(NJS_NUMBER, 1, INT32_MAX),
+ .enumerable = 1,
+ },
+};
+
+
+const njs_object_init_t njs_buffer_object_init = {
+ njs_buffer_object_properties,
+ njs_nitems(njs_buffer_object_properties),
+};
"delete " nm "[0];"
+#define njs_buffer_byte_map(func, sign, divisor) \
+ "var buf = Buffer.alloc(6);" \
+ "[1,2,3,4,5,6].map(byte => {" \
+ " buf." func "(" sign "(2 ** (byte * 7)) / " \
+ njs_stringify(divisor) ", 0, byte);" \
+ " return njs.dump(buf);" \
+ "})"
+
+
typedef struct {
njs_str_t script;
njs_str_t ret;
"var en = new TextEncoder();"
"njs.dump(en.encode(de.decode(buf)))"),
njs_str("Uint8Array [2,0,0,0]") },
+
+ /* Buffer */
+
+ { njs_str("new Buffer();"),
+ njs_str("TypeError: Buffer is not a constructor") },
+
+ { njs_str("var buf = Buffer.alloc();"),
+ njs_str("TypeError: \"size\" argument must be of type number") },
+
+ { njs_str("var buf = Buffer.alloc('best buffer');"),
+ njs_str("TypeError: \"size\" argument must be of type number") },
+
+ { njs_str("var buf = Buffer.alloc(-1);"),
+ njs_str("RangeError: invalid size") },
+
+ { njs_str("var buf = Buffer.alloc(4); njs.dump(buf)"),
+ njs_str("Buffer [0,0,0,0]") },
+
+ { njs_str("var buf = Buffer.alloc(4, 88); buf"),
+ njs_str("XXXX") },
+
+ { njs_str("var buf = Buffer.alloc(4, 945); njs.dump(buf)"),
+ njs_str("Buffer [177,177,177,177]") },
+
+ { njs_str("var buf = Buffer.alloc(4, -1); njs.dump(buf)"),
+ njs_str("Buffer [255,255,255,255]") },
+
+ { njs_str("var buf = Buffer.alloc(4, -1, 'utf-128'); njs.dump(buf)"),
+ njs_str("Buffer [255,255,255,255]") },
+
+ { njs_str("var buf = Buffer.alloc(10, 'α'); buf"),
+ njs_str("ααααα") },
+
+ { njs_str("var buf = Buffer.alloc(4, 'α'); njs.dump(buf)"),
+ njs_str("Buffer [206,177,206,177]") },
+
+ { njs_str("var buf = Buffer.alloc(2, 'ααααα'); njs.dump(buf)"),
+ njs_str("Buffer [206,177]") },
+
+ { njs_str("var buf = Buffer.alloc(1, 'α'); njs.dump(buf)"),
+ njs_str("Buffer [206]") },
+
+ { njs_str("var buf = Buffer.alloc(4, 'ZXZpbA==', 'base64'); buf"),
+ njs_str("evil") },
+
+ { njs_str("var buf = Buffer.alloc(8, 'ZXZpbA==', 'base64'); buf"),
+ njs_str("evilevil") },
+
+ { njs_str("var buf = Buffer.alloc(8, 'evil', 'utf-128'); buf"),
+ njs_str("TypeError: \"utf-128\" encoding is not supported") },
+
+ { njs_str("var foo = new Uint8Array(10).fill(88);"
+ "var buf = Buffer.alloc(8, foo); buf"),
+ njs_str("XXXXXXXX") },
+
+ { njs_str("var foo = new Uint16Array(10).fill(0xB1CE);"
+ "var buf = Buffer.alloc(10, foo); buf"),
+ njs_str("ααααα") },
+
+ { njs_str("var foo = new Uint16Array(20).fill(0xB1CE);"
+ "var buf = Buffer.alloc(10, foo); buf"),
+ njs_str("ααααα") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(0xB1CE);"
+ "var buf = Buffer.alloc(10, foo); buf"),
+ njs_str("ααααα") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(0xB1CE);"
+ "var buf = Buffer.alloc(10, foo); buf"),
+ njs_str("ααααα") },
+
+ { njs_str("var foo = Buffer.alloc(10, 'α');"
+ "var buf = Buffer.alloc(4, foo); buf"),
+ njs_str("αα") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(10).fill('α'); buf"),
+ njs_str("ααααα") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(-1)"),
+ njs_str("RangeError: invalid size") },
+
+ { njs_str("["
+ " ['6576696c', 'hex', 4],"
+ " ['6576696', 'hex', 3],"
+ " ['', 'hex', 0],"
+ " ['', 'base64', 0],"
+ " ['ZXZpbA==', 'base64', 4],"
+ " ['ZXZpbA', 'base64url', 4],"
+ " ['ααααα', undefined, 10],"
+ "].every(args => Buffer.byteLength(args[0], args[1]) == args[2])"),
+ njs_str("true") },
+
+ { njs_str("Buffer.from([])"),
+ njs_str("") },
+
+ { njs_str("Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72])"),
+ njs_str("buffer") },
+
+ { njs_str(njs_declare_sparse_array("arr", 6)
+ "[0x62, 0x75, 0x66, 0x66, 0x65, 0x72].map((v, i) => {arr[i] = v;});"
+ "Buffer.from(arr)"),
+ njs_str("buffer") },
+
+ { njs_str("Buffer.from({length:3, 0:0x62, 1:0x75, 2:0x66})"),
+ njs_str("buf") },
+
+ { njs_str("njs.dump(Buffer.from([-1,1,255,22323,-Infinity,Infinity,NaN]))"),
+ njs_str("Buffer [255,1,255,51,0,0,0]") },
+
+ { njs_str("var buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); njs.dump(buf)"),
+ njs_str("Buffer [98,117,102,102,101,114]") },
+
+ { njs_str("var buf = Buffer.from([1,2,3]); njs.dump(Buffer.from(buf.toJSON()))"),
+ njs_str("Buffer [1,2,3]") },
+
+ { njs_str("["
+ " {type: 'B'},"
+ " {type: undefined},"
+ " {type:'Buffer'},"
+ " {type:'Buffer', data:null},"
+ " {type:'Buffer', data:{}},"
+ "].every(v=>{ try { Buffer.from(v)} catch(e) {return e.name == 'TypeError'}})"),
+ njs_str("true") },
+
+ { njs_str("var foo = new Uint16Array(2);"
+ "foo[0] = 5000; foo[1] = 4000;"
+ "var buf = Buffer.from(foo.buffer);"
+ "foo[1] = 6000;"
+ "njs.dump(buf)"),
+ njs_str("Buffer [136,19,112,23]") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 1); njs.dump(buf)"),
+ njs_str("Buffer [3,182,3]") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, -1); njs.dump(buf)"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 5); njs.dump(buf)"),
+ njs_str("RangeError: \"offset\" is outside of buffer bounds") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 2, 1); njs.dump(buf)"),
+ njs_str("Buffer [182]") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 2, -1); njs.dump(buf)"),
+ njs_str("Buffer []") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 2, 3); njs.dump(buf)"),
+ njs_str("RangeError: \"length\" is outside of buffer bounds") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 2, 0); njs.dump(buf)"),
+ njs_str("Buffer []") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, 2, 2); njs.dump(buf)"),
+ njs_str("Buffer [182,3]") },
+
+ { njs_str("var foo = new Uint16Array(2).fill(950);"
+ "var buf = Buffer.from(foo.buffer, '2', '2'); njs.dump(buf)"),
+ njs_str("Buffer [182,3]") },
+
+ { njs_str("var foo = new Uint32Array(1).fill(0xF1F2F3F4);"
+ "var buf = Buffer.from(foo); njs.dump(buf)"),
+ njs_str("Buffer [244]") },
+
+ { njs_str("var foo = new Uint32Array(2).fill(0xF1F2F3F4);"
+ "var buf = Buffer.from(foo); njs.dump(buf)"),
+ njs_str("Buffer [244,244]") },
+
+ { njs_str("var foo = new Uint8Array(5);"
+ "foo[0] = 1; foo[1] = 2; foo[2] = 3; foo[3] = 4; foo[4] = 5;"
+ "foo = foo.subarray(1, 3);"
+ "var buf = Buffer.from(foo); njs.dump(buf)"),
+ njs_str("Buffer [2,3]") },
+
+ { njs_str("var buf = Buffer.from(''); njs.dump(buf)"),
+ njs_str("Buffer []") },
+
+ { njs_str("var buf = Buffer.from('α'); njs.dump(buf)"),
+ njs_str("Buffer [206,177]") },
+
+ { njs_str("["
+ " ['6576696c', 'hex'],"
+ " ['ZXZpbA==', 'base64'],"
+ " ['ZXZpbA==#', 'base64'],"
+ " ['ZXZpbA', 'base64url'],"
+ " ['ZXZpbA##', 'base64url'],"
+ "].every(args => Buffer.from(args[0], args[1]) == 'evil')"),
+ njs_str("true") },
+
+ { njs_str("var buf = Buffer.from(String.bytesFrom([0xF3])); buf"),
+ njs_str("�") },
+
+ { njs_str("Buffer.from('', 'utf-128')"),
+ njs_str("TypeError: \"utf-128\" encoding is not supported") },
+
+ { njs_str("[Buffer.from('α'), new Uint8Array(10), {}, 1]"
+ ".map(v=>Buffer.isBuffer(v))"),
+ njs_str("true,false,false,false") },
+
+ { njs_str("['utf8', 'utf-8', 'hex', 'base64', 'base64url', 'utf-88', '1hex']"
+ ".map(v=>Buffer.isEncoding(v))"),
+ njs_str("true,true,true,true,true,false,false") },
+
+ { njs_str("["
+ " ['ABC', 'ABCD', -1],"
+ " ['ABCD', 'ABC', 1],"
+ " ['ABC', 'ACB', -1],"
+ " ['ACB', 'ABC', 1],"
+ " ['ABC', 'ABC', 0],"
+ " ['', 'ABC', -1],"
+ " ['', '', 0],"
+ "].every(args => {"
+ " if (Buffer.compare(Buffer.from(args[0]), Buffer.from(args[1])) != args[2]) {"
+ " throw new TypeError("
+ " `Buffer.compare(Buffer.from(${args[0]}), Buffer.from(${args[1]})) != ${args[2]}`);"
+ " }"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("["
+ " ['ABC', 'ABCD', -1],"
+ " ['ABCD', 'ABC', 1],"
+ " ['ABC', 'ACB', -1],"
+ " ['ACB', 'ABC', 1],"
+ " ['ABC', 'ABC', 0],"
+ " ['', 'ABC', -1],"
+ " ['', '', 0],"
+ "].every(args => {"
+ " if (Buffer.from(args[0]).compare(Buffer.from(args[1])) != args[2]) {"
+ " throw new TypeError("
+ " `Buffer.from(${args[0]}).compare(Buffer.from(${args[1]})) != ${args[2]}`);"
+ " }"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "["
+ " [0,3,0,2, -1],"
+ " [0,2,0,3, 1],"
+ " [3,4,3,4, 0],"
+ " [undefined, undefined, undefined, undefined, 0],"
+ " [-1, undefined, undefined, undefined, 'invalid index'],"
+ " [0, -1, undefined, undefined, 'invalid index'],"
+ " [0, 0, -1, undefined, 'invalid index'],"
+ " [0, 0, 0, -1, 'invalid index'],"
+ "]"
+ ".every(as => {"
+ " try {"
+ " if (buf.compare(buf, as[0], as[1], as[2], as[3]) != as[4]) {"
+ " throw new TypeError("
+ " `buf.compare(${as[0]}, ${as[1]}, ${as[2]}, ${as[3]}) != ${as[4]}`);"
+ " }"
+ " } catch (e) { return e.message == as[4]}"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD');"
+ "var buf2 = Buffer.from('ABCD');"
+ "buf1.compare(buf2, 5)"),
+ njs_str("RangeError: \"targetStart\" is out of range: 5") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD');"
+ "var buf2 = Buffer.from('ABCD');"
+ "buf1.compare(buf2, 0, 3, 5)"),
+ njs_str("RangeError: \"sourceStart\" is out of range: 5") },
+
+ { njs_str("var arr = new Uint8Array(4);"
+ "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+ "arr = arr.subarray(1, 4);"
+ "var buf = Buffer.from('ABCD');"
+ "buf.compare(arr, 0, 3, 1, 4)"),
+ njs_str("0") },
+
+ { njs_str("['123', 'abc', '124', '', 'AB', 'ABCD']"
+ ".map(v=>Buffer.from(v)).sort(Buffer.compare).map(v=>v.toString())"),
+ njs_str(",123,124,AB,ABCD,abc") },
+
+ { njs_str("Buffer.compare(Buffer.alloc(1), 'text')"),
+ njs_str("TypeError: \"target\" argument must be an instance of Buffer or Uint8Array") },
+
+ { njs_str("Buffer.compare('text', Buffer.from('ACB'))"),
+ njs_str("TypeError: \"source\" argument must be an instance of Buffer or Uint8Array") },
+
+ { njs_str("Buffer.concat()"),
+ njs_str("TypeError: \"list\" argument must be an instance of Array") },
+
+ { njs_str("Buffer.concat([])"),
+ njs_str("") },
+
+ { njs_str("Buffer.concat([new Uint16Array(10)])"),
+ njs_str("TypeError: \"list[0]\" argument must be an instance of Buffer or Uint8Array") },
+
+ { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)]).fill('abc')"),
+ njs_str("abc") },
+
+ { njs_str("Buffer.concat([Buffer.from('AB'), Buffer.from('CD')])"),
+ njs_str("ABCD") },
+
+ { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)], 2).fill('abc')"),
+ njs_str("ab") },
+
+ { njs_str("Buffer.concat([new Uint8Array(2), new Uint8Array(1)], 6).fill('abc')"),
+ njs_str("abcabc") },
+
+ { njs_str(njs_declare_sparse_array("list", 2)
+ "list[0] = new Uint8Array(2); list[1] = new Uint8Array(3);"
+ "Buffer.concat(list).fill('ab');"),
+ njs_str("ababa") },
+
+ { njs_str("Buffer.concat([], '123')"),
+ njs_str("TypeError: \"length\" argument must be of type number") },
+
+ { njs_str("Buffer.concat([], -1)"),
+ njs_str("RangeError: \"length\" is out of range") },
+
+ { njs_str("var buf = Buffer.from('α'); buf[1]"),
+ njs_str("177") },
+
+ { njs_str("var buf = Buffer.from('α'); buf[1] = 1; njs.dump(buf)"),
+ njs_str("Buffer [206,1]") },
+
+ { njs_str("var arrBuf = new ArrayBuffer(16);"
+ "var buf = Buffer.from(arrBuf); buf.buffer === arrBuf"),
+ njs_str("true") },
+
+ { njs_str("["
+ " [[0], 4, '65,66,67,68,0,0,0,0,0,0'],"
+ " [[5], 4, '0,0,0,0,0,65,66,67,68,0'],"
+ " [[8], 2, '0,0,0,0,0,0,0,0,65,66'],"
+ " [[8,2,4], 2, '0,0,0,0,0,0,0,0,67,68'],"
+ " [[10], 0, '0,0,0,0,0,0,0,0,0,0'],"
+ "]"
+ ".every(args => {"
+ " var buf1 = Buffer.from('ABCD');"
+ " var buf2 = Buffer.alloc(10, 0);"
+ " var as = args[0];"
+ " var length = buf1.copy(buf2, as[0], as[1], as[2]);"
+ ""
+ " if (length != args[1]) {"
+ " throw new TypeError(`buf1.copy(buf2, ${as[0]}, ${as[1]}, ${as[2]}): ${length} != ${args[1]}`)"
+ " }"
+ ""
+ " if (njs.dump(buf2) != `Buffer [${args[2]}]`) {"
+ " throw new TypeError("
+ " `buf1.copy(buf2, ${as[0]}, ${as[1]}, ${as[2]}): ${njs.dump(buf2)} != Buffer [${args[2]}]`);"
+ " }"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("["
+ " [[0], 'ABCDEF'],"
+ " [[0,2], 'CDEFEF'],"
+ " [[0,2,6], 'CDEFEF'],"
+ " [[1,2,4], 'ACDDEF'],"
+ " [[1,2,3], 'ACCDEF']"
+ "]"
+ ".every(args => {"
+ " var buf = Buffer.from('ABCDEF');"
+ " var as = args[0];"
+ " buf.copy(buf, as[0], as[1], as[2]);"
+ ""
+ " if (buf.toString() != args[1]) {"
+ " throw new TypeError("
+ " `buf.copy(buf, ${as[0]}, ${as[1]}, ${as[2]}): buf.toString() != ${args[1]}`);"
+ " }"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD');"
+ "var buf2 = Buffer.alloc(10, 0);"
+ "buf1.copy(buf2, -1)"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD');"
+ "var buf2 = Buffer.alloc(10, 0);"
+ "buf1.copy(buf2, 0, -1)"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD');"
+ "var buf2 = Buffer.alloc(10, 0);"
+ "buf1.copy(buf2, 0, 5)"),
+ njs_str("RangeError: \"sourceStart\" is out of range: 5") },
+
+ { njs_str("var arr = new Uint8Array(4);"
+ "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+ "arr = arr.subarray(1, 4);"
+ "var buf1 = Buffer.from(arr);"
+ "var buf2 = Buffer.alloc(10, 0);"
+ "var length = buf1.copy(buf2, 1, 1, 2); [length, njs.dump(buf2)]"),
+ njs_str("1,Buffer [0,67,0,0,0,0,0,0,0,0]") },
+
+ { njs_str("var arr = new Uint8Array(4);"
+ "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+ "arr = arr.subarray(1, 4);"
+ "var buf1 = Buffer.from(arr);"
+ "var buf2 = Buffer.alloc(10, 0);"
+ "var length = buf1.copy(buf2, 1, 1, 2); [length, njs.dump(buf2)]"),
+ njs_str("1,Buffer [0,67,0,0,0,0,0,0,0,0]") },
+
+ { njs_str("["
+ " ['ABC', 'ABCD', false],"
+ " ['ABCD', 'ABC', false],"
+ " ['ABC', 'ACB', false],"
+ " ['ACB', 'ABC', false],"
+ " ['ABC', 'ABC', true],"
+ " ['', 'ABC', false],"
+ " ['', '', true],"
+ "].every(args => {"
+ " if (Buffer.from(args[0]).equals(Buffer.from(args[1])) != args[2]) {"
+ " throw new TypeError("
+ " `Buffer.from(${args[0]}).compare(Buffer.from(${args[1]})) != ${args[2]}`);"
+ " }"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("var buf = Buffer.alloc(4);"
+ "buf.fill('ZXZpbA==', 'base64')"),
+ njs_str("evil") },
+
+ { njs_str("var buf = Buffer.alloc(4);"
+ "buf.fill('6576696c', 'hex')"),
+ njs_str("evil") },
+
+ { njs_str("var buf = Buffer.alloc(4);"
+ "buf.fill('ZXZpbA==', '')"),
+ njs_str("TypeError: \"\" encoding is not supported") },
+
+ { njs_str("var buf = Buffer.alloc(8);"
+ "buf.fill('6576696c', 'hex')"),
+ njs_str("evilevil") },
+
+ { njs_str("var buf = Buffer.alloc(10);"
+ "buf.fill('evil')"),
+ njs_str("evilevilev") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(5);"
+ "buf[3] = 1;"
+ "buf.fill(''); njs.dump(buf)"),
+ njs_str("Buffer [0,0,0,0,0]") },
+
+ { njs_str("var arr = new Uint8Array(4);"
+ "arr[0] = 0x41; arr[1] = 0x42; arr[2] = 0x43; arr[3] = 0x44;"
+ "arr = arr.subarray(1, 4);"
+ "var buf = Buffer.allocUnsafe(6);"
+ "buf.fill(arr); njs.dump(buf)"),
+ njs_str("Buffer [66,67,68,66,67,68]") },
+
+ { njs_str("var buf = Buffer.alloc(6, 'ABCDEF');"
+ "buf.fill(buf, 2, 6)"),
+ njs_str("ABABCD") },
+
+ { njs_str("Buffer.alloc(6).fill(0x41)"),
+ njs_str("AAAAAA") },
+
+ { njs_str("Buffer.alloc(6).fill({valueOf(){return 0x42}})"),
+ njs_str("BBBBBB") },
+
+ { njs_str("njs.dump(Buffer.alloc(3).fill(-1))"),
+ njs_str("Buffer [255,255,255]") },
+
+ { njs_str("[NaN, Infinity, -Infinity, undefined, null, {}]"
+ ".every(v => njs.dump(Buffer.alloc(3).fill(v)) == 'Buffer [0,0,0]')"),
+ njs_str("true") },
+
+ { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 4,3))"),
+ njs_str("Buffer [0,0,0,0,0,0]") },
+
+ { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 3,3))"),
+ njs_str("Buffer [0,0,0,0,0,0]") },
+
+ { njs_str("njs.dump(Buffer.alloc(6).fill({valueOf(){throw 'Oops'}}, 2,3))"),
+ njs_str("Oops") },
+
+ { njs_str("njs.dump(Buffer.alloc(5).fill('α'))"),
+ njs_str("Buffer [206,177,206,177,206]") },
+
+ { njs_str("Buffer.alloc(4).fill('ABCD', -1)"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("Buffer.alloc(4).fill('ABCD', 5)"),
+ njs_str("RangeError: \"offset\" is out of range") },
+
+ { njs_str("Buffer.alloc(4).fill('ABCD', 0, -1)"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("Buffer.alloc(4).fill('ABCD', 0, 5)"),
+ njs_str("RangeError: \"end\" is out of range") },
+
+ { njs_str("Buffer.alloc(513).fill('A'.repeat(512)).length"),
+ njs_str("513") },
+
+ { njs_str("njs.dump(Buffer.alloc(4).fill((new Uint8Array(5)).fill(1)))"),
+ njs_str("Buffer [1,1,1,1]") },
+
+ { njs_str("var src = new Uint8Array(10).fill(255);"
+ "var u8 = new Uint8Array(src.buffer, 1, 8);"
+ "u8.set([1,2,3,4,5,6,7,8]);"
+ "njs.dump(Buffer.alloc(9).fill(u8))"),
+ njs_str("Buffer [1,2,3,4,5,6,7,8,1]") },
+
+ { njs_str("Buffer.alloc(513).fill((new Uint8Array(512)).fill(1)).length"),
+ njs_str("513") },
+
+ { njs_str("Buffer.alloc(4).fill('ABCD', undefined, undefined, 'utf-128')"),
+ njs_str("TypeError: \"utf-128\" encoding is not supported") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 3);"
+ "buf1.fill('B', 1, 2); njs.dump(buf1)"),
+ njs_str("Buffer [66,66]") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 3);"
+ "buf1.fill(0x42, 1, 2); njs.dump(buf1)"),
+ njs_str("Buffer [66,66]") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 2);"
+ "var buf2 = Buffer.from('ABCD').subarray(1, 3);"
+ "buf2.fill(buf1, 1, 2); njs.dump(buf2)"),
+ njs_str("Buffer [66,66]") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "['BC', 'CB', 'ABCD', 'ABCDE', ''].map(v=>buf.indexOf(v))"),
+ njs_str("1,-1,0,-1,0") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "[0,5,-2,-1].map(v=>buf.indexOf('C', v))"),
+ njs_str("2,-1,2,-1") },
+
+ { njs_str("var buf = Buffer.from('evil');"
+ "buf.indexOf('ZXZpbA==', undefined, 'base64')"),
+ njs_str("0") },
+
+ { njs_str("var buf = Buffer.from('evil');"
+ "buf.indexOf('6576696c', undefined, 'hex')"),
+ njs_str("0") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "buf.indexOf('C', undefined, 'utf-128')"),
+ njs_str("TypeError: \"utf-128\" encoding is not supported") },
+
+ { njs_str("var buf = Buffer.from('ABCDABC');"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.indexOf(Buffer.from(v)))"),
+ njs_str("1,-1,0,-1,0,2,-1") },
+
+ { njs_str("var buf = Buffer.from('ABCDABC');"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.includes(Buffer.from(v)))"),
+ njs_str("true,false,true,false,true,true,false") },
+
+ { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.indexOf(Buffer.from(v)))"),
+ njs_str("1,-1,0,-1,0,2,-1") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "buf.indexOf(0x43)"),
+ njs_str("2") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "buf.indexOf(0x43, -2)"),
+ njs_str("2") },
+
+ { njs_str("var buf = Buffer.from('ABCD');"
+ "buf.indexOf(0x43, -1)"),
+ njs_str("-1") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD');"
+ "var buf2 = Buffer.from('XXCX').subarray(2, 3);"
+ "buf1.indexOf(buf2)"),
+ njs_str("2") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 4);"
+ "buf1.indexOf(0x43)"),
+ njs_str("1") },
+
+ { njs_str("var buf1 = Buffer.from('ABCD').subarray(1, 4);"
+ "buf1.indexOf('C')"),
+ njs_str("1") },
+
+ { njs_str("var buf = Buffer.from('ABCDABC');"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(v))"),
+ njs_str("5,-1,0,-1,7,6,-1") },
+
+ { njs_str("var buf = Buffer.from('ABCDABC');"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(Buffer.from(v)))"),
+ njs_str("5,-1,0,-1,7,6,-1") },
+
+ { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(v))"),
+ njs_str("5,-1,0,-1,7,6,-1") },
+
+ { njs_str("var buf = Buffer.from('ZABCDABC').subarray(1);"
+ "['BC', 'CB', 'ABCD', 'ABCDE', '', 'C', 'ABCDABCD'].map(v=>buf.lastIndexOf(Buffer.from(v)))"),
+ njs_str("5,-1,0,-1,7,6,-1") },
+
+ { njs_str("var buf = Buffer.from('CABCD');"
+ "[2,-2,1,-10,10,-5,-4,0].map(v=>buf.lastIndexOf('C', v))"),
+ njs_str("0,3,0,-1,3,0,0,0") },
+
+ { njs_str("var buf = Buffer.from('CABCD');"
+ "[2,-2,1,-10,10,-5,-4,0].map(v=>buf.lastIndexOf(Buffer.from('CZ').subarray(0,1), v))"),
+ njs_str("0,3,0,-1,3,0,0,0") },
+
+ { njs_str("var buf = Buffer.from('CABCD');"
+ "buf.lastIndexOf(0x43)"),
+ njs_str("3") },
+
+ { njs_str("var buf = Buffer.from('CABCD');"
+ "[2,1,0,4,5,-1,-5].map(v=>buf.lastIndexOf(0x43, v))"),
+ njs_str("0,0,0,3,3,3,0") },
+
+ { njs_str("var buf1 = Buffer.from('ACBCD').subarray(1, 4);"
+ "var buf2 = Buffer.from('C');"
+ "buf1.lastIndexOf(buf2)"),
+ njs_str("2") },
+
+ { njs_str("var buf1 = Buffer.from('XXCXX').subarray(2,3);"
+ "buf1.lastIndexOf(Buffer.from('X'))"),
+ njs_str("-1") },
+
+ { njs_str("var buf = Buffer.from('ACBCD').subarray(1, 4);"
+ "buf.lastIndexOf(0x43)"),
+ njs_str("2") },
+
+ { njs_str("var buf = Buffer.from('ACBCD').subarray(1, 4);"
+ "buf.lastIndexOf('C')"),
+ njs_str("2") },
+
+ { njs_str("['swap16', 'swap32', 'swap64'].every(method => {"
+ " var buf = Buffer.from([]);"
+ " buf[method]();"
+ " return njs.dump(buf) === 'Buffer []';"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("['swap16', 'swap32', 'swap64'].every(method => {"
+ " var buf = Buffer.from([1,2,3]);"
+ " try { buf[method]() } "
+ " catch(e) {return e.message === `Buffer size must be a multiple of ${method.substr(4)}-bits`};"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("['swap16', 'swap32', 'swap64'].map(method => {"
+ " var buf = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]);"
+ " buf[method]();"
+ " return njs.dump(buf);"
+ "})"),
+ njs_str("Buffer [2,1,4,3,6,5,8,7],"
+ "Buffer [4,3,2,1,8,7,6,5],"
+ "Buffer [8,7,6,5,4,3,2,1]") },
+
+ { njs_str("['swap16', 'swap32', 'swap64'].map(method => {"
+ " var u8 = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8]);"
+ " var buf = Buffer.from(u8.buffer, 1);"
+ " buf[method]();"
+ " return njs.dump(buf);"
+ "})"),
+ njs_str("Buffer [2,1,4,3,6,5,8,7],"
+ "Buffer [4,3,2,1,8,7,6,5],"
+ "Buffer [8,7,6,5,4,3,2,1]") },
+
+ { njs_str("njs.dump(Buffer.from('αααα').toJSON())"),
+ njs_str("{type:'Buffer',data:[206,177,206,177,206,177,206,177]}") },
+
+ { njs_str("njs.dump(Buffer.from('').toJSON())"),
+ njs_str("{type:'Buffer',data:[]}") },
+
+ { njs_str("["
+ " [['base64'], 'ZXZpbA=='],"
+ " [['base64url'], 'ZXZpbA'],"
+ " [['hex'], '6576696c'],"
+ " [[undefined,1,3], 'vi'],"
+ " [[undefined,5], ''],"
+ " [[undefined,undefined,5], 'evil'],"
+ " [[undefined,undefined,undefined], 'evil'],"
+ "].every(args => {"
+ " var buf = Buffer.from('evil');"
+ " var as = args[0];"
+ " if (buf.toString(as[0], as[1], as[2]) != args[1]) {"
+ " throw new TypeError("
+ " `buf.toString(${as[0]}, ${as[1]}, ${as[2]}) != ${args[1]}`);"
+ " }"
+ " return true;"
+ "})"),
+ njs_str("true") },
+
+ { njs_str("Buffer.from('evil').toString('utf-128')"),
+ njs_str("TypeError: \"utf-128\" encoding is not supported") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4);"
+ "var len = buf.write('ZXZpbA==', 'base64'); [len, buf]"),
+ njs_str("4,evil") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4);"
+ "var len = buf.write('ZXZpbA==', undefined, 'base64'); [len, buf]"),
+ njs_str("4,evil") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4);"
+ "var len = buf.write('ZXZpbA==', undefined, undefined, 'base64'); [len, buf]"),
+ njs_str("4,evil") },
+
+ { njs_str("Buffer.allocUnsafe(4).write()"),
+ njs_str("TypeError: first argument must be a string") },
+
+ { njs_str("Buffer.allocUnsafe(4).write({a: 1})"),
+ njs_str("TypeError: first argument must be a string") },
+
+ { njs_str("Buffer.alloc(4).write('evil', 4, 1);"),
+ njs_str("RangeError: \"offset\" is out of range") },
+
+ { njs_str("Buffer.alloc(4).write('evil', -1);"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("var buf = Buffer.alloc(4);"
+ "var len = buf.write('evil', 3, 1); [len, njs.dump(buf)]"),
+ njs_str("1,Buffer [0,0,0,101]") },
+
+ { njs_str("var buf = Buffer.alloc(4);"
+ "var len = buf.write('evil', 0, 5); [len, buf]"),
+ njs_str("4,evil") },
+
+ { njs_str("Buffer.alloc(4).write('evil', undefined, -1);"),
+ njs_str("RangeError: invalid index") },
+
+ { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+ "[1,2,3,4,5,6].map(byte => [buf.readUIntLE(0, byte), buf.readUIntLE(1, byte)])"),
+ njs_str("250,251,"
+ "64506,64763,"
+ "16579578,16645371,"
+ "4261215226,4278058235,"
+ "1095182908410,1099494718715,"
+ "281470647991290,274877890034939") },
+
+ { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+ "[1,2,3,4,5,6].map(byte => [buf.readIntLE(0, byte), buf.readIntLE(1, byte)])"),
+ njs_str("-6,-5,"
+ "-1030,-773,"
+ "-197638,-131845,"
+ "-33752070,-16909061,"
+ "-4328719366,-16909061,"
+ "-4328719366,-6597086675717") },
+
+ { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+ "[1,2,3,4,5,6].map(byte => [buf.readUIntBE(0, byte), buf.readUIntBE(1, byte)])"),
+ njs_str("250,251,"
+ "64251,64508,"
+ "16448508,16514301,"
+ "4210818301,4227661310,"
+ "1077969485310,1082281295615,"
+ "275960188239615,277064011677689") },
+
+ { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+ "[1,2,3,4,5,6].map(byte => [buf.readIntBE(0, byte), buf.readIntBE(1, byte)])"),
+ njs_str("-6,-5,"
+ "-1285,-1028,"
+ "-328708,-262915,"
+ "-84148995,-67305986,"
+ "-21542142466,-17230332161,"
+ "-5514788471041,-4410965032967") },
+
+ { njs_str("var buf = Buffer.from([0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xF9, 0xf8]);"
+ "function t(sign, endianness, offset) { "
+ " return [1,2,4].every(size => {"
+ " var method = `read${sign}Int${size * 8}`;"
+ " if (size > 1) { method += endianness};"
+ " var gmethod = `read${sign}Int${endianness}`;"
+ " var gv = buf[gmethod](offset, size);"
+ " var sv = buf[method](offset);"
+ " if (gv != sv) {throw Error(`${gmethod}(${offset},${size}):${gv} != ${method}(${offset}):${sv}`)}"
+ " return true;"
+ " });"
+ "}; "
+ "t('U', 'LE', 0) && t('U', 'LE', 1)"
+ "&& t('', 'LE', 0) && t('', 'LE', 1)"
+ "&& t('U', 'BE', 0) && t('U', 'BE', 1)"
+ "&& t('', 'BE', 0) && t('', 'BE', 1)"),
+ njs_str("true") },
+
+ { njs_str("var buf = Buffer.alloc(9);"
+ "function t(sign, endianness, offset) { "
+ " return [1,2,4].every(size => {"
+ " var rgmethod = `read${sign}Int${endianness}`;"
+ " var wgmethod = `write${sign}Int${endianness}`;"
+ " var rmethod = `read${sign}Int${size * 8}`;"
+ " var wmethod = `write${sign}Int${size * 8}`;"
+ " if (size > 1) { rmethod += endianness; wmethod += endianness; };"
+ " var v = 0x7abbccddeeff & (size * 8 - 1);"
+ ""
+ " buf[wgmethod](v, offset, size);"
+ " var gv = buf[rgmethod](offset, size);"
+ ""
+ " buf.fill(0);"
+ " buf[wmethod](v, offset);"
+ " var sv = buf[rmethod](offset);"
+ " if (gv != sv) {throw Error(`${wmethod}(${v}, ${offset}):${sv} != ${wgmethod}(${v},${offset}):${gv}`)}"
+ " return true;"
+ " });"
+ "}; "
+ "t('U', 'LE', 0) && t('U', 'LE', 1)"
+ "&& t('', 'LE', 0) && t('', 'LE', 1)"
+ "&& t('U', 'BE', 0) && t('U', 'BE', 1)"
+ "&& t('', 'BE', 0) && t('', 'BE', 1)"),
+ njs_str("true") },
+
+ { njs_str(njs_buffer_byte_map("writeUIntLE", "+", 1)),
+ njs_str("Buffer [128,0,0,0,0,0],"
+ "Buffer [0,64,0,0,0,0],"
+ "Buffer [0,0,32,0,0,0],"
+ "Buffer [0,0,0,16,0,0],"
+ "Buffer [0,0,0,0,8,0],"
+ "Buffer [0,0,0,0,0,4]") },
+
+ { njs_str(njs_buffer_byte_map("writeUIntBE", "+", 1)),
+ njs_str("Buffer [128,0,0,0,0,0],"
+ "Buffer [64,0,0,0,0,0],"
+ "Buffer [32,0,0,0,0,0],"
+ "Buffer [16,0,0,0,0,0],"
+ "Buffer [8,0,0,0,0,0],"
+ "Buffer [4,0,0,0,0,0]") },
+
+ { njs_str(njs_buffer_byte_map("writeIntLE", "-", 2)),
+ njs_str("Buffer [192,0,0,0,0,0],"
+ "Buffer [0,224,0,0,0,0],"
+ "Buffer [0,0,240,0,0,0],"
+ "Buffer [0,0,0,248,0,0],"
+ "Buffer [0,0,0,0,252,0],"
+ "Buffer [0,0,0,0,0,254]") },
+
+ { njs_str(njs_buffer_byte_map("writeIntBE", "-", 2)),
+ njs_str("Buffer [192,0,0,0,0,0],"
+ "Buffer [224,0,0,0,0,0],"
+ "Buffer [240,0,0,0,0,0],"
+ "Buffer [248,0,0,0,0,0],"
+ "Buffer [252,0,0,0,0,0],"
+ "Buffer [254,0,0,0,0,0]") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleBE()"),
+ njs_str("8.20788039913184e-304") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleLE()"),
+ njs_str("5.447603722011605e-270") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4]).readFloatBE()"),
+ njs_str("2.387939260590663e-38") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4]).readFloatLE()"),
+ njs_str("1.539989614439558e-36") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleBE(1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4, 5, 6, 7, 8]).readDoubleLE(1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4]).readFloatBE(1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("Buffer.from([1, 2, 3, 4]).readFloatLE(1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(8);"
+ "buf.writeDoubleBE(123.456); njs.dump(buf)"),
+ njs_str("Buffer [64,94,221,47,26,159,190,119]") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(8);"
+ "buf.writeDoubleLE(123.456); njs.dump(buf)"),
+ njs_str("Buffer [119,190,159,26,47,221,94,64]") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4);"
+ "buf.writeFloatBE(123.456); njs.dump(buf)"),
+ njs_str("Buffer [66,246,233,121]") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4);"
+ "buf.writeFloatLE(123.456); njs.dump(buf)"),
+ njs_str("Buffer [121,233,246,66]") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(8).writeDoubleBE(123.456, 1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(8).writeDoubleLE(123.456, 1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4).writeFloatBE(123.456, 1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("var buf = Buffer.allocUnsafe(4).writeFloatLE(123.456, 1)"),
+ njs_str("RangeError: index 1 is outside the bound of the buffer") },
+
+ { njs_str("var buffer = require('buffer');"
+ "buffer.Buffer.alloc(5).fill('ABC')"),
+ njs_str("ABCAB") },
+
+ { njs_str("var buffer = require('buffer');"
+ "typeof buffer.kMaxLength === 'number' "),
+ njs_str("true") },
+
+ { njs_str("var buffer = require('buffer');"
+ "typeof buffer.constants.MAX_LENGTH === 'number' "),
+ njs_str("true") },
+
+ { njs_str("var buffer = require('buffer');"
+ "typeof buffer.constants.MAX_STRING_LENGTH === 'number' "),
+ njs_str("true") },
};
"[r.uri, r.host, r.props.a, njs.dump(r.vars), njs.dump(r.consts), r.header['02']]"),
njs_str("АБВ,АБВГДЕЁЖЗИЙ,1,{},{},02|АБВ") },
- { njs_str("var s = (new TextDecoder()).decode($r.u8buffer); [s, s.length]"),
+ { njs_str("var s = (new TextDecoder()).decode($r.buffer); [s, s.length]"),
njs_str("АБВГДЕЁЖЗИЙ,11") },
- { njs_str("var b = $r.u8buffer; "
+ { njs_str("var b = $r.buffer; "
"b[4] = '@'.codePointAt(0); b[5] = '#'.codePointAt(0);"
"var s = (new TextDecoder()).decode(b); [s, s.length]"),
njs_str("АБ@#ГДЕЁЖЗИЙ,12") },
- { njs_str("var b = $r.u8buffer; "
+ { njs_str("var b = $r.buffer; "
"b.copyWithin(16,0,6);"
"var s = (new TextDecoder()).decode(b); [s, s.length]"),
njs_str("АБВГДЕЁЖАБВ,11") },
- { njs_str("var b = $r.u8buffer; "
+ { njs_str("var b = $r.buffer; "
"b.fill('#'.codePointAt(0));"
"var s = (new TextDecoder()).decode(b); [s, s.length]"),
njs_str("######################,22") },
- { njs_str("var b = $r.u8buffer; "
+ { njs_str("var b = $r.buffer; "
"b.set(['@'.codePointAt(0), '#'.codePointAt(0)], 4);"
"var s = (new TextDecoder()).decode(b); [s, s.length]"),
njs_str("АБ@#ГДЕЁЖЗИЙ,12") },
- { njs_str("var b = $r.u8buffer; "
+ { njs_str("var b = $r.buffer; "
"var u16 = new Uint16Array(b.buffer); u16.reverse();"
"var s = (new TextDecoder()).decode(u16); [s, s.length]"),
njs_str("ЙИЗЖЁЕДГВБА,11") },
- { njs_str("$r.u8buffer.sort().slice(0,3)"),
+ { njs_str("$r.buffer.sort().slice(0,3)"),
njs_str("129,144,145") },
};