} qjs_bytes_t;
+njs_inline int
+qjs_to_length(JSContext *ctx, JSValueConst value, uint64_t *length)
+{
+ double number;
+
+ if (JS_ToFloat64(ctx, &number, value)) {
+ return -1;
+ }
+
+ if (number != number || number <= 0) {
+ *length = 0;
+
+ } else if (number > 0x1fffffffffffffLL) {
+ *length = 0x1fffffffffffffLL;
+
+ } else {
+ *length = number;
+ }
+
+ return 0;
+}
+
+
njs_inline int
qjs_is_typed_array(JSContext *cx, JSValue val)
{
{
int v;
u_char *p;
- int64_t i, len;
+ uint64_t i, len;
JSValue buffer, ret;
njs_str_t dst;
const char *str;
return JS_EXCEPTION;
}
- len = JS_VALUE_GET_INT(ret);
+ if (qjs_to_length(ctx, ret, &len)) {
+ JS_FreeValue(ctx, ret);
+ return JS_EXCEPTION;
+ }
+
+ JS_FreeValue(ctx, ret);
buffer = qjs_buffer_alloc(ctx, len);
if (JS_IsException(buffer)) {
/*---
-includes: [compatBuffer.js, runTsuite.js, compareArray.js]
+includes: [compatBuffer.js, compatNjs.js, runTsuite.js, compareArray.js]
flags: [async]
---*/
};
+let fromObject_tsuite = {
+ name: "Buffer.from() array-like length tests",
+ skip: () => (!has_buffer()),
+ T: async (params) => {
+ let buffer = Buffer.from(params.value);
+
+ if (buffer.toString() !== params.expected) {
+ throw Error(`unexpected output "${buffer.toString()}"`);
+ }
+
+ return 'SUCCESS';
+ },
+
+ tests: [
+ { value: { length: 1.5, 0: 0x41 }, expected: 'A' },
+ { value: { length: -1, 0: 0x41 }, expected: '' },
+ { value: { length: NaN, 0: 0x41 }, expected: '' },
+ ],
+};
+
+
+let fromObjectLarge_tsuite = {
+ name: "Buffer.from() oversized array-like length tests",
+ skip: () => (!has_buffer() || !has_njs()),
+ T: async () => {
+ assert.throws(RangeError, () => Buffer.from({
+ length: 0x100000010,
+ get 0() { throw Error('unexpected index access'); },
+ }));
+
+ return 'SUCCESS';
+ },
+ tests: [{}],
+};
+
+
let byteLength_tsuite = {
name: "Buffer.byteLength() tests",
skip: () => (!has_buffer()),
run([
alloc_tsuite,
+ fromObject_tsuite,
+ fromObjectLarge_tsuite,
byteLength_tsuite,
concat_tsuite,
concatRevalidate_tsuite,