diff --git a/packages/compiler/src/frontend/lowering/containers/bytes.ts b/packages/compiler/src/frontend/lowering/containers/bytes.ts index 8d1d17821..46ddb1dbb 100644 --- a/packages/compiler/src/frontend/lowering/containers/bytes.ts +++ b/packages/compiler/src/frontend/lowering/containers/bytes.ts @@ -1479,6 +1479,8 @@ function lowerBufferInstanceMethod( if (encName === "utf16le") align = 2; } else if (vT?.kind === "bytes" && vT.elem === "u8") { needle = lowerer.lowerExpr(args[0]!); + // A Buffer needle under utf16le also searches whole 2-byte units. + if (encName === "utf16le") align = 2; } else { lowerer.noLowering( `.${name} of '${lowerer.checker.typeToString(lowerer.typeOf(args[0]!))}' values`, diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index 6262b2530..69e26e5d7 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -1489,8 +1489,10 @@ ScrStr *scr_strdec_end(const ScrStr *enc, double pending) { static void scr_bytes_to_str_bounds(const ScrBytes *b, double start, double end, size_t *s0_out, size_t *e0_out) { size_t len = b->len; - size_t s0 = start <= 0 ? 0 : ((size_t)start > len ? len : (size_t)start); - size_t e0 = end <= 0 ? 0 : ((size_t)end > len ? len : (size_t)end); + /* Clamped before the conversion: NaN and values at or below 0 are 0, + * values at or past the length (Infinity included) are the length. */ + size_t s0 = !(start > 0) ? 0 : start >= (double)len ? len : (size_t)start; + size_t e0 = !(end > 0) ? 0 : end >= (double)len ? len : (size_t)end; if (e0 < s0) e0 = s0; *s0_out = s0; *e0_out = e0; @@ -3204,15 +3206,61 @@ double scr_bytes_compare(const ScrBytes *src, const ScrBytes *target, double nar return sn < tn ? -1 : 1; } +/* node_buffer.cc's IndexOfBuffer/IndexOfString for the UCS2 encoding over + * an encoded needle: buffer.js clamps the byteOffset to the int32 range, + * IndexOfOffset picks the start, the search runs over whole 2-byte units of + * the haystack (an odd trailing byte of either side is ignored), and a match + * is reported at its byte position. */ +static double scr_bytes_index_of_ucs2(const ScrBytes *haystack, const ScrBytes *needle, double at, bool fwd) { + int64_t length = (int64_t)haystack->len, needle_length = (int64_t)needle->len; + /* NaN (an omitted or non-numeric byteOffset) searches everything. */ + if (at > 2147483647.0) at = 2147483647.0; + else if (at < -2147483648.0) at = -2147483648.0; + int64_t offset_i64 = at != at ? (fwd ? 0 : length) : (int64_t)trunc(at); + int64_t opt_offset; + if (offset_i64 < 0) { + if (offset_i64 + length >= 0) opt_offset = length + offset_i64; + else opt_offset = fwd || needle_length == 0 ? 0 : -1; + } else if (offset_i64 + needle_length <= length) { + opt_offset = offset_i64; + } else if (needle_length == 0) { + opt_offset = length; + } else { + opt_offset = fwd ? -1 : length - 1; + } + size_t search_end = haystack->len & ~(size_t)1; + if (needle_length == 0) return (double)(opt_offset < (int64_t)search_end ? opt_offset : (int64_t)search_end); + if (length == 0 || opt_offset <= -1) return -1; + size_t offset = (size_t)opt_offset; + if (offset >= search_end) { + if (fwd || search_end == 0) return -1; + offset = search_end - 1; + } + if ((fwd && needle->len + offset > search_end) || needle->len > search_end) return -1; + if (search_end < 2 || needle->len < 2) return -1; + size_t units = search_end / 2, needle_units = needle->len / 2, start = offset / 2; + if (units < needle_units) return -1; + size_t last = units - needle_units; + if (fwd) { + for (size_t p = start; p <= last; p++) + if (!memcmp(haystack->data + 2 * p, needle->data, 2 * needle_units)) return (double)(2 * p); + return -1; + } + for (size_t p = start < last ? start : last;; p--) { + if (!memcmp(haystack->data + 2 * p, needle->data, 2 * needle_units)) return (double)(2 * p); + if (p == 0) return -1; + } +} + /* The shared search core: needle bytes, a coerced byteOffset (trunc; NaN * means 'search everything' — 0 forward, the end backward; negatives * count from the end, and a still-negative backward search answers -1), - * and the utf16le alignment stride. */ + * and the alignment: 2 searches utf16le units (scr_bytes_index_of_ucs2). */ double scr_bytes_index_of(const ScrBytes *b, const ScrBytes *needle, double off, double align, bool fwd) { SCR_BYTES_SNAPSHOT(b); SCR_BYTES_SNAPSHOT(needle); + if (align == 2) return scr_bytes_index_of_ucs2(b, needle, off, fwd); size_t len = b->len, nlen = needle->len; - size_t step = align == 2 ? 2 : 1; double o = (off != off) ? (fwd ? 0 : (double)len) : trunc(off); if (o < 0) { o += (double)len; @@ -3225,17 +3273,15 @@ double scr_bytes_index_of(const ScrBytes *b, const ScrBytes *needle, double off, if (nlen > len) return -1; if (fwd) { size_t start = o > (double)len ? len : (size_t)o; - if (step == 2) start += start % 2; - for (size_t i = start; i + nlen <= len; i += step) { + for (size_t i = start; i + nlen <= len; i++) { if (memcmp(b->data + i, needle->data, nlen) == 0) return (double)i; } return -1; } size_t start = o > (double)(len - nlen) ? len - nlen : (size_t)o; - if (step == 2) start -= start % 2; - for (size_t i = start;; i -= step) { + for (size_t i = start;; i--) { if (memcmp(b->data + i, needle->data, nlen) == 0) return (double)i; - if (i < step) break; + if (i == 0) break; } return -1; } diff --git a/packages/runtime/src/scr_bytes_dyn.c b/packages/runtime/src/scr_bytes_dyn.c index 58130a072..280aa423c 100644 --- a/packages/runtime/src/scr_bytes_dyn.c +++ b/packages/runtime/src/scr_bytes_dyn.c @@ -187,6 +187,91 @@ static ScrStr *scr_bytes_dyn_quoted(const ScrStr *text) { return scr_jb_finish(&jb); } +/* Appends Node's inspect of an ArrayBuffer at indentation level `indent`: + * the first 100 bytes as hex pairs, on one line when it fits the 80-column + * break length (reduceToSingleString), one entry per line otherwise. */ +static void scr_bytes_dyn_inspect_array_buffer(ScrJsonBuf *jb, const ScrBytes *owner, size_t indent) { + static const char digits[] = "0123456789abcdef"; + size_t len = owner->len * scr_bytes_elem_size(owner->elem); + size_t shown = len < 100 ? len : 100; + ScrJsonBuf contents; + scr_jb_init(&contents); + scr_jb_puts(&contents, "[Uint8Contents]: <"); + for (size_t i = 0; i < shown; i++) { + uint8_t byte; + scr_bytes_read(owner, i, &byte, 1); + if (i) scr_jb_putc(&contents, ' '); + scr_jb_putc(&contents, digits[byte >> 4]); + scr_jb_putc(&contents, digits[byte & 15]); + } + if (len > shown) { + char more[48]; + snprintf(more, sizeof more, " ... %zu more byte%s", len - shown, len - shown > 1 ? "s" : ""); + scr_jb_puts(&contents, more); + } + scr_jb_putc(&contents, '>'); + ScrStr *first = scr_jb_finish(&contents); + char second[40]; + int second_len = snprintf(second, sizeof second, "[byteLength]: %zu", len); + /* isBelowBreakLength with two entries, start = 2 + indentation + "ArrayBuffer {" + 10. */ + size_t total = 2 + (2 + indent + 13 + 10) + first->len + (size_t)second_len; + if (total <= 80) { + scr_jb_puts(jb, "ArrayBuffer { "); + scr_jb_put_str(jb, first); + scr_jb_puts(jb, ", "); + scr_jb_puts(jb, second); + scr_jb_puts(jb, " }"); + } else { + scr_jb_puts(jb, "ArrayBuffer {\n"); + for (size_t i = 0; i < indent + 2; i++) scr_jb_putc(jb, ' '); + scr_jb_put_str(jb, first); + scr_jb_puts(jb, ",\n"); + for (size_t i = 0; i < indent + 2; i++) scr_jb_putc(jb, ' '); + scr_jb_puts(jb, second); + scr_jb_putc(jb, '\n'); + for (size_t i = 0; i < indent; i++) scr_jb_putc(jb, ' '); + scr_jb_putc(jb, '}'); + } + scr_str_release(first); +} + +/* ERR_INVALID_ARG_VALUE for an empty ArrayBufferView fill value: Node's + * inspect of the view (a Buffer, an empty typed array, or a DataView with + * its buffer), cut to 128 characters followed by "...". */ +static ScrStr *scr_bytes_dyn_empty_view_message(const ScrDyn *value) { + const ScrBytes *view = value->v.bytes; + ScrJsonBuf jb; + scr_jb_init(&jb); + if (value->buffer) { + scr_jb_puts(&jb, ""); + } else if (!view->is_data_view) { + scr_jb_puts(&jb, scr_bytes_elem_name(view->elem)); + scr_jb_puts(&jb, "(0) []"); + } else { + const ScrBytes *owner = view->backing ? view->backing : view; + char line[64]; + snprintf(line, sizeof line, "DataView {\n [byteLength]: 0,\n [byteOffset]: %zu,\n [buffer]: ", + (size_t)(view->data - owner->data)); + scr_jb_puts(&jb, line); + scr_bytes_dyn_inspect_array_buffer(&jb, owner, 2); + scr_jb_puts(&jb, "\n}"); + } + ScrStr *inspected = scr_jb_finish(&jb); + ScrJsonBuf out; + scr_jb_init(&out); + scr_jb_puts(&out, "The argument 'value' is invalid. Received "); + if (inspected->len > 128) { + ScrStr *head = scr_str_new(inspected->data, 128); + scr_jb_put_str(&out, head); + scr_str_release(head); + scr_jb_puts(&out, "..."); + } else { + scr_jb_put_str(&out, inspected); + } + scr_str_release(inspected); + return scr_jb_finish(&out); +} + /* buf.fill(value[, offset[, end]][, encoding]): buffer.js's _fill. A string * takes its encoding from the first string among offset and end; numbers and * other non-view values fill with ToUint32(value) & 255. Answers the receiver. */ @@ -244,9 +329,23 @@ static ScrDyn *scr_bytes_dyn_fill(ScrDyn *recv, ScrDyn *const *args, size_t argc /* An empty string fills with zeros. */ out = text->len == 0 ? scr_bytes_fill_num(b, 0, 2, from, to) : scr_bytes_fill(b, pattern, 2, from, to); scr_bytes_release(pattern); - } else if (value->kind == SCR_DYN_BYTES && !value->v.bytes->is_data_view && - value->v.bytes->elem == SCR_BYTES_U8) { - out = scr_bytes_fill(b, value->v.bytes, 2, from, to); + } else if (value->kind == SCR_DYN_BYTES) { + /* Any ArrayBufferView repeats its raw bytes: a byte view over the + * value's storage (a typed array of wider elements, or a DataView). */ + const ScrBytes *view = value->v.bytes; + if (view->len == 0) { + ScrStr *message = scr_bytes_dyn_empty_view_message(value); + scr_throw_error_msg_code(SCR_ERR_TYPE, message->data, message->len, "ERR_INVALID_ARG_VALUE"); + scr_str_release(message); + return NULL; + } + ScrBytes pattern = { .rc = 1, + .len = view->len * scr_bytes_elem_size(view->elem), + .elem = SCR_BYTES_U8, + .data = view->data, + .backing = NULL, + .shared = view->shared }; + out = scr_bytes_fill(b, &pattern, 2, from, to); } else { double n; if (!scr_dyn_number_coerce_js(value, &n)) return NULL; @@ -256,21 +355,27 @@ static ScrDyn *scr_bytes_dyn_fill(ScrDyn *recv, ScrDyn *const *args, size_t argc scr_bytes_release(out); return scr_dyn_retain(recv); } -/* buf.toString(encoding, start, end): the window clamps to - * [0, length] with NaN as 0, an empty window answers "" before the - * encoding resolves, and an undefined encoding is utf8. */ +/* buf.toString(encoding, start, end): the window clamps to [0, length] + * with NaN as 0 (infinite and out-of-range values included), an empty + * window answers "" before the encoding resolves, and an undefined encoding + * is utf8. */ static ScrDyn *scr_bytes_dyn_to_string(ScrBytes *b, ScrDyn *const *args, size_t argc) { const ScrDyn *encoding = scr_bytes_dyn_arg(args, argc, 0); const ScrDyn *start = scr_bytes_dyn_arg(args, argc, 1); const ScrDyn *end = scr_bytes_dyn_arg(args, argc, 2); - double from = 0, to = (double)b->len; + const double len = (double)b->len; + double from = NAN, to = len; if (!scr_bytes_dyn_undef(start) && !scr_dyn_number_coerce_js(start, &from)) return NULL; if (!scr_bytes_dyn_undef(end) && !scr_dyn_number_coerce_js(end, &to)) return NULL; - if (from != from) from = 0; - if (to != to) to = 0; - from = trunc(from); - to = trunc(to); - if (from >= (double)b->len || to <= from || to <= 0) return scr_bytes_dyn_str("", 0); + /* `if (start <= 0) start = 0; else if (start >= len) return ''; else + * start = MathTrunc(start) || 0`, then `end > len` clamps to the length + * and other ends truncate (NaN as 0), so both stay within [0, len]. */ + if (from <= 0) from = 0; + else if (from >= len) return scr_bytes_dyn_str("", 0); + else from = from == from ? trunc(from) : 0; + if (to > len) to = len; + else to = to == to ? trunc(to) : 0; + if (to <= from) return scr_bytes_dyn_str("", 0); ScrStr *enc = scr_bytes_dyn_undef(encoding) ? scr_str_new("utf8", 4) : scr_bytes_dyn_encoding(encoding); if (!enc) return NULL; ScrStr *text = scr_bytes_to_str_range(b, enc, from, to); @@ -313,6 +418,23 @@ static ScrDyn *scr_bytes_dyn_copy(const ScrBytes *b, ScrDyn *const *args, size_t return scr_dyn_new_num(scr_bytes_copy_into(b, target->v.bytes, 3, offsets[0], offsets[1], offsets[2])); } +/* Whether an encoding name is one of the utf16le spellings, in any ASCII case. */ +static bool scr_bytes_dyn_is_ucs2(const ScrStr *raw) { + static const char *const names[] = { "utf16le", "utf-16le", "ucs2", "ucs-2" }; + for (size_t i = 0; i < sizeof names / sizeof names[0]; i++) { + size_t n = strlen(names[i]); + if (raw->len != n) continue; + size_t k = 0; + for (; k < n; k++) { + char c = raw->data[k]; + if (c >= 'A' && c <= 'Z') c = (char)(c + ('a' - 'A')); + if (c != names[i][k]) break; + } + if (k == n) return true; + } + return false; +} + /* buf.indexOf/lastIndexOf/includes(value[, byteOffset][, encoding]): * buffer.js's bidirectionalIndexOf. A string byteOffset is the encoding; * the offset clamps to the int32 range, and NaN searches everything. */ @@ -333,25 +455,30 @@ static ScrDyn *scr_bytes_dyn_index_of(const ScrBytes *b, ScrDyn *const *args, si if (value->kind == SCR_DYN_NUM) { found = scr_bytes_index_of_num(b, value->v.num, at, fwd); } else { - ScrStr *enc = NULL; + ScrStr *raw = NULL; if (!scr_bytes_dyn_undef(encoding)) { - ScrStr *raw = scr_dyn_string_coerce_js(encoding); + raw = scr_dyn_string_coerce_js(encoding); if (!raw) return NULL; - /* An unknown encoding throws for a string needle only. */ - enc = value->kind == SCR_DYN_STR ? scr_bytes_normalize_encoding(raw) : NULL; - scr_str_release(raw); - if (value->kind == SCR_DYN_STR && !enc) return NULL; } if (value->kind == SCR_DYN_STR) { - if (!enc) enc = scr_str_new("utf8", 4); + /* An unknown encoding throws for a string needle. */ + ScrStr *enc = raw ? scr_bytes_normalize_encoding(raw) : scr_str_new("utf8", 4); + if (raw) scr_str_release(raw); + if (!enc) return NULL; + bool ucs2 = enc->len == 7 && !memcmp(enc->data, "utf16le", 7); ScrBytes *needle = scr_bytes_from_str(value->v.str, enc); - found = scr_bytes_index_of(b, needle, at, enc->len == 7 && !memcmp(enc->data, "utf16le", 7) ? 2 : 1, fwd); + found = scr_bytes_index_of(b, needle, at, ucs2 ? 2 : 1, fwd); scr_bytes_release(needle); scr_str_release(enc); } else if (value->kind == SCR_DYN_BYTES && !value->v.bytes->is_data_view && value->v.bytes->elem == SCR_BYTES_U8) { - found = scr_bytes_index_of(b, value->v.bytes, at, 1, fwd); + /* A Buffer needle searches 2-byte units under a utf16le encoding and + * bytes under any other, an unknown name included. */ + bool ucs2 = raw && scr_bytes_dyn_is_ucs2(raw); + if (raw) scr_str_release(raw); + found = scr_bytes_index_of(b, value->v.bytes, at, ucs2 ? 2 : 1, fwd); } else { + if (raw) scr_str_release(raw); scr_dyn_arg_type_fail("value", "one of type number or string or an instance of Buffer or Uint8Array", value); return NULL; } diff --git a/tests/corpus/6930-dyn-buffer-methods.cjs b/tests/corpus/6930-dyn-buffer-methods.cjs index d9870d274..5167a3188 100644 --- a/tests/corpus/6930-dyn-buffer-methods.cjs +++ b/tests/corpus/6930-dyn-buffer-methods.cjs @@ -143,3 +143,125 @@ console.log(box.text.indexOf("an"), box.text.lastIndexOf("an"), box.text.include console.log(box.list.indexOf(2), box.list.includes(4), box.list.fill(0, 1).join(","), box.list.toString()); console.log(Array.from(box.bytes.fill(9, 2)), box.bytes.toString()); console.log(box.sink.write("x"), box.sink.written, box.sink.toString(1, 2)); + +// fill with other ArrayBufferViews repeats their raw bytes; an empty view is +// ERR_INVALID_ARG_VALUE with Node's inspect of the view. +const tm = (name, f) => { + try { + const v = f(); + console.log(name, Buffer.isBuffer(v) ? `<${v.toString("hex")}>` : JSON.stringify(v)); + } catch (e) { + console.log(name, e.name, e.code, JSON.stringify(e.message)); + } +}; +function Held(bytes) { + this.b = bytes; +} +const held = (bytes) => new Held(bytes).b; +const filled = (n) => held(Buffer.alloc(n)); +tm("fill Uint16Array", () => filled(6).fill(new Uint16Array([0x0102]))); +tm("fill DataView", () => filled(6).fill(new DataView(new Uint8Array([7, 8, 9]).buffer))); +tm("fill DataView window", () => filled(6).fill(new DataView(new Uint8Array([1, 2, 3, 4]).buffer, 1, 2))); +tm("fill Float64Array", () => filled(10).fill(new Float64Array([1]))); +tm("fill subarray", () => filled(6).fill(new Uint16Array([1, 2, 3]).subarray(1))); +tm("fill Int8Array range", () => filled(6).fill(new Int8Array([-1, 2]), 1, 4)); +tm("fill empty Uint16Array", () => filled(6).fill(new Uint16Array(0))); +tm("fill empty Uint8Array", () => filled(6).fill(new Uint8Array(0))); +for (const [size, offset] of [[0, 0], [1, 1], [6, 6], [7, 7], [8, 8], [120, 3], [101, 101]]) + tm(`fill empty DataView ${size}/${offset}`, () => filled(6).fill(new DataView(new ArrayBuffer(size), offset, 0))); +tm("fill empty DataView over bytes", () => filled(6).fill(new DataView(new Uint8Array(200).fill(171).buffer, 7, 0))); + +// Buffer needles under utf16le search whole 2-byte units. +const units = held(Buffer.from("abcabc", "utf16le")); +const split = held(Buffer.from([0x61, 0x00, 0x62, 0x00, 0x00, 0x62, 0x00, 0x63])); +const N = (bytes) => Buffer.from(bytes); +tm("indexOf utf16le needle", () => [split.indexOf(N([0x62, 0x00]), 0, "ucs2"), split.indexOf(N([0x62, 0x00]))]); +tm("indexOf utf16le odd position", () => [ + split.indexOf(N([0x00, 0x62]), 0, "ucs2"), + split.indexOf(N([0x00, 0x62]), 0, "UTF-16LE"), + split.indexOf(N([0x00, 0x62])), +]); +tm("lastIndexOf utf16le needle", () => [ + units.lastIndexOf(N([0x62, 0x00]), undefined, "ucs2"), + split.lastIndexOf(N([0x00, 0x62]), undefined, "ucs2"), + ...[5, 3, 2, 1, -100, 100].map((at) => split.lastIndexOf(N([0x62, 0x00]), at, "ucs2")), +]); +tm("indexOf utf16le offsets", () => [1, 2, 3, -5, 7, 2.9].map((at) => split.indexOf(N([0x62, 0x00]), at, "ucs2"))); +tm("indexOf utf16le short needles", () => [ + split.indexOf(N([0x62]), 0, "ucs2"), + held(N([0x62])).indexOf(N([0x62]), 0, "ucs2"), + split.indexOf(Buffer.alloc(0), 3, "ucs2"), + split.indexOf(Buffer.alloc(0), 30, "ucs2"), + split.indexOf(N([0x62, 0, 0]), 0, "ucs2"), +]); +tm("indexOf utf16le odd lengths", () => [ + held(N([1, 0, 2, 0, 3])).indexOf(N([2, 0, 3]), 0, "ucs2"), + held(N([1, 0, 2, 0, 3, 0])).indexOf(N([2, 0, 3]), 0, "ucs2"), + held(N([1, 2, 1, 2, 1, 2])).indexOf(N([2, 1, 2]), 0, "ucs2"), + held(N([1, 0, 2, 0, 3])).lastIndexOf(N([3]), undefined, "ucs2"), + held(N([0, 2, 0, 2, 0])).lastIndexOf(N([2, 0]), undefined, "ucs2"), +]); +tm("indexOf buffer needle other encodings", () => [ + split.indexOf(N([0x62, 0x00]), 0, "nope"), + split.indexOf(N([0x00, 0x62]), 0, "nope"), + split.indexOf(N([0x00, 0x62]), 0, "latin1"), +]); +tm("indexOf utf16le strings", () => [ + split.indexOf("b", 0, "ucs2"), + units.lastIndexOf("b", undefined, "ucs2"), + units.indexOf("b", 3, "ucs2"), + units.lastIndexOf("b", 3, "ucs2"), + units.indexOf("", 3, "ucs2"), + units.indexOf("", 30, "ucs2"), + units.lastIndexOf("", 30, "ucs2"), + split.indexOf("戀", 0, "ucs2"), +]); +tm("includes utf16le needle", () => [split.includes(N([0x00, 0x62]), 0, "ucs2"), split.includes(N([0x62, 0x00]), 3, "ucs2")]); + +// toString windows with infinite and out-of-range bounds. +const word = held(Buffer.from("hello")); +tm("toString infinite bounds", () => [ + word.toString("utf8", 1, Infinity), + word.toString("utf8", -Infinity, 2), + word.toString("utf8", Infinity), + word.toString("utf8", NaN, 3), + word.toString("utf8", 1e300, 2), + word.toString("utf8", 1, 1e300), + word.toString("utf8", -1e300, 1e300), + word.toString("utf8", 0, -Infinity), + word.toString("utf8", 2, NaN), + word.toString("utf8", 0.5, 4.5), + word.toString("hex", -0.5, -0), + word.toString("latin1", 4.9), + word.toString(undefined, undefined, Infinity), +]); + +// The same searches and windows on Buffers the compiler types statically. +const typed = Buffer.from([0x61, 0x00, 0x62, 0x00, 0x00, 0x62, 0x00, 0x63]); +const typedUnits = Buffer.from("abcabc", "utf16le"); +console.log( + "typed utf16le", + typed.indexOf(Buffer.from([0x00, 0x62]), 0, "ucs2"), + Buffer.from([0x62]).indexOf(Buffer.from([0x62]), 0, "ucs2"), + typed.lastIndexOf(Buffer.from([0x62, 0x00]), 5, "ucs2"), + typed.indexOf(Buffer.from([0x62, 0x00]), 3, "ucs2"), + typed.includes(Buffer.from([0x00, 0x62]), 0, "utf16le"), + typed.indexOf("b", 0, "ucs2"), + typedUnits.lastIndexOf("b", 100, "ucs2"), + typedUnits.lastIndexOf("b", 3, "ucs2"), + typedUnits.indexOf("", 30, "ucs2"), + typedUnits.indexOf("b", 1e300, "ucs2"), + typedUnits.indexOf("c", -1e300, "ucs2"), +); +const typedWord = Buffer.from("hello"); +console.log( + "typed windows", + JSON.stringify([ + typedWord.toString("utf8", 1, Infinity), + typedWord.toString("utf8", -Infinity, 2), + typedWord.toString("utf8", Infinity), + typedWord.toString("utf8", NaN, 3), + typedWord.toString("utf8", 1, 1e300), + typedWord.toString("hex", 0, -Infinity), + ]), +); diff --git a/tests/harness/corpus-costs/6930-dyn-buffer-methods.cjs.json b/tests/harness/corpus-costs/6930-dyn-buffer-methods.cjs.json index 83181fc36..bd8f85745 100644 --- a/tests/harness/corpus-costs/6930-dyn-buffer-methods.cjs.json +++ b/tests/harness/corpus-costs/6930-dyn-buffer-methods.cjs.json @@ -1 +1 @@ -{ "plain": 7800, "san": 39000 } +{ "plain": 12000, "san": 39000 }