buffer: fix indexOf for empty searches
Make searches for empty subsequences do exactly what `String.prototype.indexOf()` does. Fixes: https://github.com/nodejs/node/issues/13023 PR-URL: https://github.com/nodejs/node/pull/13024 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
This commit is contained in:
parent
5a948f6f64
commit
28ddac2ec2
@ -1340,6 +1340,10 @@ console.log(b.indexOf('b', null));
|
||||
console.log(b.indexOf('b', []));
|
||||
```
|
||||
|
||||
If `value` is an empty string or empty `Buffer` and `byteOffset` is less
|
||||
than `buf.length`, `byteOffset` will be returned. If `value` is empty and
|
||||
`byteOffset` is at least `buf.length`, `buf.length` will be returned.
|
||||
|
||||
### buf.keys()
|
||||
<!-- YAML
|
||||
added: v1.1.0
|
||||
@ -1450,6 +1454,8 @@ console.log(b.lastIndexOf('b', null));
|
||||
console.log(b.lastIndexOf('b', []));
|
||||
```
|
||||
|
||||
If `value` is an empty string or empty `Buffer`, `byteOffset` will be returned.
|
||||
|
||||
### buf.length
|
||||
<!-- YAML
|
||||
added: v0.1.90
|
||||
|
@ -686,7 +686,7 @@ function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {
|
||||
// If the offset is undefined, "foo", {}, coerces to NaN, search whole buffer.
|
||||
// `x !== x`-style conditionals are a faster form of `isNaN(x)`
|
||||
if (byteOffset !== byteOffset) {
|
||||
byteOffset = dir ? 0 : (buffer.length - 1);
|
||||
byteOffset = dir ? 0 : buffer.length;
|
||||
}
|
||||
dir = !!dir; // Cast to bool.
|
||||
|
||||
|
@ -919,17 +919,16 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
|
||||
// Computes the offset for starting an indexOf or lastIndexOf search.
|
||||
// Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
|
||||
// or -1 to signal that there is no possible match.
|
||||
int64_t IndexOfOffset(size_t length, int64_t offset_i64, bool is_forward) {
|
||||
int64_t IndexOfOffset(size_t length,
|
||||
int64_t offset_i64,
|
||||
int64_t needle_length,
|
||||
bool is_forward) {
|
||||
int64_t length_i64 = static_cast<int64_t>(length);
|
||||
if (length_i64 == 0) {
|
||||
// Empty buffer, no match.
|
||||
return -1;
|
||||
}
|
||||
if (offset_i64 < 0) {
|
||||
if (offset_i64 + length_i64 >= 0) {
|
||||
// Negative offsets count backwards from the end of the buffer.
|
||||
return length_i64 + offset_i64;
|
||||
} else if (is_forward) {
|
||||
} else if (is_forward || needle_length == 0) {
|
||||
// indexOf from before the start of the buffer: search the whole buffer.
|
||||
return 0;
|
||||
} else {
|
||||
@ -937,9 +936,12 @@ int64_t IndexOfOffset(size_t length, int64_t offset_i64, bool is_forward) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (offset_i64 < length_i64) {
|
||||
if (offset_i64 + needle_length <= length_i64) {
|
||||
// Valid positive offset.
|
||||
return offset_i64;
|
||||
} else if (needle_length == 0) {
|
||||
// Out of buffer bounds, but empty needle: point to end of buffer.
|
||||
return length_i64;
|
||||
} else if (is_forward) {
|
||||
// indexOf from past the end of the buffer: no match.
|
||||
return -1;
|
||||
@ -974,11 +976,21 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
|
||||
const size_t needle_length =
|
||||
StringBytes::Size(args.GetIsolate(), needle, enc);
|
||||
|
||||
if (needle_length == 0 || haystack_length == 0) {
|
||||
int64_t opt_offset = IndexOfOffset(haystack_length,
|
||||
offset_i64,
|
||||
needle_length,
|
||||
is_forward);
|
||||
|
||||
if (needle_length == 0) {
|
||||
// Match String#indexOf() and String#lastIndexOf() behaviour.
|
||||
args.GetReturnValue().Set(static_cast<double>(opt_offset));
|
||||
return;
|
||||
}
|
||||
|
||||
if (haystack_length == 0) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
|
||||
int64_t opt_offset = IndexOfOffset(haystack_length, offset_i64, is_forward);
|
||||
if (opt_offset <= -1) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
@ -1077,11 +1089,21 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
|
||||
const char* needle = buf_data;
|
||||
const size_t needle_length = buf_length;
|
||||
|
||||
if (needle_length == 0 || haystack_length == 0) {
|
||||
int64_t opt_offset = IndexOfOffset(haystack_length,
|
||||
offset_i64,
|
||||
needle_length,
|
||||
is_forward);
|
||||
|
||||
if (needle_length == 0) {
|
||||
// Match String#indexOf() and String#lastIndexOf() behaviour.
|
||||
args.GetReturnValue().Set(static_cast<double>(opt_offset));
|
||||
return;
|
||||
}
|
||||
|
||||
if (haystack_length == 0) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
|
||||
int64_t opt_offset = IndexOfOffset(haystack_length, offset_i64, is_forward);
|
||||
if (opt_offset <= -1) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
@ -1132,8 +1154,8 @@ void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
|
||||
int64_t offset_i64 = args[2]->IntegerValue();
|
||||
bool is_forward = args[3]->IsTrue();
|
||||
|
||||
int64_t opt_offset = IndexOfOffset(ts_obj_length, offset_i64, is_forward);
|
||||
if (opt_offset <= -1) {
|
||||
int64_t opt_offset = IndexOfOffset(ts_obj_length, offset_i64, 1, is_forward);
|
||||
if (opt_offset <= -1 || ts_obj_length == 0) {
|
||||
return args.GetReturnValue().Set(-1);
|
||||
}
|
||||
size_t offset = static_cast<size_t>(opt_offset);
|
||||
|
@ -29,10 +29,10 @@ assert(b.includes('bc', -Infinity));
|
||||
assert(!b.includes('bc', Infinity));
|
||||
assert(b.includes('f'), b.length - 1);
|
||||
assert(!b.includes('z'));
|
||||
assert(!b.includes(''));
|
||||
assert(!b.includes('', 1));
|
||||
assert(!b.includes('', b.length + 1));
|
||||
assert(!b.includes('', Infinity));
|
||||
assert(b.includes(''));
|
||||
assert(b.includes('', 1));
|
||||
assert(b.includes('', b.length + 1));
|
||||
assert(b.includes('', Infinity));
|
||||
assert(b.includes(buf_a));
|
||||
assert(!b.includes(buf_a, 1));
|
||||
assert(!b.includes(buf_a, -1));
|
||||
@ -51,10 +51,10 @@ assert(b.includes(buf_bc, -Infinity));
|
||||
assert(!b.includes(buf_bc, Infinity));
|
||||
assert(b.includes(buf_f), b.length - 1);
|
||||
assert(!b.includes(buf_z));
|
||||
assert(!b.includes(buf_empty));
|
||||
assert(!b.includes(buf_empty, 1));
|
||||
assert(!b.includes(buf_empty, b.length + 1));
|
||||
assert(!b.includes(buf_empty, Infinity));
|
||||
assert(b.includes(buf_empty));
|
||||
assert(b.includes(buf_empty, 1));
|
||||
assert(b.includes(buf_empty, b.length + 1));
|
||||
assert(b.includes(buf_empty, Infinity));
|
||||
assert(b.includes(0x61));
|
||||
assert(!b.includes(0x61, 1));
|
||||
assert(!b.includes(0x61, -1));
|
||||
|
@ -31,10 +31,10 @@ assert.strictEqual(b.indexOf('bc', -Infinity), 1);
|
||||
assert.strictEqual(b.indexOf('bc', Infinity), -1);
|
||||
assert.strictEqual(b.indexOf('f'), b.length - 1);
|
||||
assert.strictEqual(b.indexOf('z'), -1);
|
||||
assert.strictEqual(b.indexOf(''), -1);
|
||||
assert.strictEqual(b.indexOf('', 1), -1);
|
||||
assert.strictEqual(b.indexOf('', b.length + 1), -1);
|
||||
assert.strictEqual(b.indexOf('', Infinity), -1);
|
||||
assert.strictEqual(b.indexOf(''), 0);
|
||||
assert.strictEqual(b.indexOf('', 1), 1);
|
||||
assert.strictEqual(b.indexOf('', b.length + 1), b.length);
|
||||
assert.strictEqual(b.indexOf('', Infinity), b.length);
|
||||
assert.strictEqual(b.indexOf(buf_a), 0);
|
||||
assert.strictEqual(b.indexOf(buf_a, 1), -1);
|
||||
assert.strictEqual(b.indexOf(buf_a, -1), -1);
|
||||
@ -53,10 +53,10 @@ assert.strictEqual(b.indexOf(buf_bc, -Infinity), 1);
|
||||
assert.strictEqual(b.indexOf(buf_bc, Infinity), -1);
|
||||
assert.strictEqual(b.indexOf(buf_f), b.length - 1);
|
||||
assert.strictEqual(b.indexOf(buf_z), -1);
|
||||
assert.strictEqual(b.indexOf(buf_empty), -1);
|
||||
assert.strictEqual(b.indexOf(buf_empty, 1), -1);
|
||||
assert.strictEqual(b.indexOf(buf_empty, b.length + 1), -1);
|
||||
assert.strictEqual(b.indexOf(buf_empty, Infinity), -1);
|
||||
assert.strictEqual(b.indexOf(buf_empty), 0);
|
||||
assert.strictEqual(b.indexOf(buf_empty, 1), 1);
|
||||
assert.strictEqual(b.indexOf(buf_empty, b.length + 1), b.length);
|
||||
assert.strictEqual(b.indexOf(buf_empty, Infinity), b.length);
|
||||
assert.strictEqual(b.indexOf(0x61), 0);
|
||||
assert.strictEqual(b.indexOf(0x61, 1), -1);
|
||||
assert.strictEqual(b.indexOf(0x61, -1), -1);
|
||||
@ -429,10 +429,10 @@ assert.strictEqual(b.lastIndexOf(buf_bc, -Infinity), -1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_bc, Infinity), 1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_f), b.length - 1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_z), -1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty), -1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty, 1), -1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty, b.length + 1), -1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty, Infinity), -1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty), b.length);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty, 1), 1);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty, b.length + 1), b.length);
|
||||
assert.strictEqual(b.lastIndexOf(buf_empty, Infinity), b.length);
|
||||
// lastIndexOf number:
|
||||
assert.strictEqual(b.lastIndexOf(0x61), 0);
|
||||
assert.strictEqual(b.lastIndexOf(0x61, 1), 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user