@@ -943,9 +943,44 @@ void Compare(const FunctionCallbackInfo<Value> &args) {
943943}
944944
945945
946+ // Computes the offset for starting an indexOf or lastIndexOf search.
947+ // Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
948+ // or -1 to signal that there is no possible match.
949+ int64_t IndexOfOffset (size_t length, int64_t offset_i64, bool is_forward) {
950+ int64_t length_i64 = static_cast <int64_t >(length);
951+ if (length_i64 == 0 ) {
952+ // Empty buffer, no match.
953+ return -1 ;
954+ }
955+ if (offset_i64 < 0 ) {
956+ if (offset_i64 + length_i64 >= 0 ) {
957+ // Negative offsets count backwards from the end of the buffer.
958+ return length_i64 + offset_i64;
959+ } else if (is_forward) {
960+ // indexOf from before the start of the buffer: search the whole buffer.
961+ return 0 ;
962+ } else {
963+ // lastIndexOf from before the start of the buffer: no match.
964+ return -1 ;
965+ }
966+ } else {
967+ if (offset_i64 < length_i64) {
968+ // Valid positive offset.
969+ return offset_i64;
970+ } else if (is_forward) {
971+ // indexOf from past the end of the buffer: no match.
972+ return -1 ;
973+ } else {
974+ // lastIndexOf from past the end of the buffer: search the whole buffer.
975+ return length_i64 - 1 ;
976+ }
977+ }
978+ }
979+
946980void IndexOfString (const FunctionCallbackInfo<Value>& args) {
947981 ASSERT (args[1 ]->IsString ());
948982 ASSERT (args[2 ]->IsNumber ());
983+ ASSERT (args[4 ]->IsBoolean ());
949984
950985 enum encoding enc = ParseEncoding (args.GetIsolate (),
951986 args[3 ],
@@ -955,31 +990,26 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
955990 SPREAD_ARG (args[0 ], ts_obj);
956991
957992 Local<String> needle = args[1 ].As <String>();
993+ int64_t offset_i64 = args[2 ]->IntegerValue ();
994+ bool is_forward = args[4 ]->IsTrue ();
995+
958996 const char * haystack = ts_obj_data;
959997 const size_t haystack_length = ts_obj_length;
960998 // Extended latin-1 characters are 2 bytes in Utf8.
961999 const size_t needle_length =
9621000 enc == BINARY ? needle->Length () : needle->Utf8Length ();
9631001
964-
9651002 if (needle_length == 0 || haystack_length == 0 ) {
9661003 return args.GetReturnValue ().Set (-1 );
9671004 }
9681005
969- int64_t offset_i64 = args[2 ]->IntegerValue ();
970- size_t offset = 0 ;
971-
972- if (offset_i64 < 0 ) {
973- if (offset_i64 + static_cast <int64_t >(haystack_length) < 0 ) {
974- offset = 0 ;
975- } else {
976- offset = static_cast <size_t >(haystack_length + offset_i64);
977- }
978- } else {
979- offset = static_cast <size_t >(offset_i64);
1006+ int64_t opt_offset = IndexOfOffset (haystack_length, offset_i64, is_forward);
1007+ if (opt_offset <= -1 ) {
1008+ return args.GetReturnValue ().Set (-1 );
9801009 }
981-
982- if (haystack_length < offset || needle_length + offset > haystack_length) {
1010+ size_t offset = static_cast <size_t >(opt_offset);
1011+ CHECK_LT (offset, haystack_length);
1012+ if (is_forward && needle_length + offset > haystack_length) {
9831013 return args.GetReturnValue ().Set (-1 );
9841014 }
9851015
@@ -1007,13 +1037,15 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
10071037 haystack_length / 2 ,
10081038 decoded_string,
10091039 decoder.size () / 2 ,
1010- offset / 2 );
1040+ offset / 2 ,
1041+ is_forward);
10111042 } else {
10121043 result = SearchString (reinterpret_cast <const uint16_t *>(haystack),
10131044 haystack_length / 2 ,
10141045 reinterpret_cast <const uint16_t *>(*needle_value),
10151046 needle_value.length (),
1016- offset / 2 );
1047+ offset / 2 ,
1048+ is_forward);
10171049 }
10181050 result *= 2 ;
10191051 } else if (enc == UTF8) {
@@ -1025,7 +1057,8 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
10251057 haystack_length,
10261058 reinterpret_cast <const uint8_t *>(*needle_value),
10271059 needle_length,
1028- offset);
1060+ offset,
1061+ is_forward);
10291062 } else if (enc == BINARY) {
10301063 uint8_t * needle_data = static_cast <uint8_t *>(malloc (needle_length));
10311064 if (needle_data == nullptr ) {
@@ -1038,7 +1071,8 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
10381071 haystack_length,
10391072 needle_data,
10401073 needle_length,
1041- offset);
1074+ offset,
1075+ is_forward);
10421076 free (needle_data);
10431077 }
10441078
@@ -1049,17 +1083,18 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
10491083void IndexOfBuffer (const FunctionCallbackInfo<Value>& args) {
10501084 ASSERT (args[1 ]->IsObject ());
10511085 ASSERT (args[2 ]->IsNumber ());
1086+ ASSERT (args[4 ]->IsBoolean ());
10521087
10531088 enum encoding enc = ParseEncoding (args.GetIsolate (),
10541089 args[3 ],
10551090 UTF8);
10561091
10571092 THROW_AND_RETURN_UNLESS_BUFFER (Environment::GetCurrent (args), args[0 ]);
1093+ THROW_AND_RETURN_UNLESS_BUFFER (Environment::GetCurrent (args), args[1 ]);
10581094 SPREAD_ARG (args[0 ], ts_obj);
10591095 SPREAD_ARG (args[1 ], buf);
1060-
1061- if (buf_length > 0 )
1062- CHECK_NE (buf_data, nullptr );
1096+ int64_t offset_i64 = args[2 ]->IntegerValue ();
1097+ bool is_forward = args[4 ]->IsTrue ();
10631098
10641099 const char * haystack = ts_obj_data;
10651100 const size_t haystack_length = ts_obj_length;
@@ -1070,19 +1105,13 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
10701105 return args.GetReturnValue ().Set (-1 );
10711106 }
10721107
1073- int64_t offset_i64 = args[2 ]->IntegerValue ();
1074- size_t offset = 0 ;
1075-
1076- if (offset_i64 < 0 ) {
1077- if (offset_i64 + static_cast <int64_t >(haystack_length) < 0 )
1078- offset = 0 ;
1079- else
1080- offset = static_cast <size_t >(haystack_length + offset_i64);
1081- } else {
1082- offset = static_cast <size_t >(offset_i64);
1108+ int64_t opt_offset = IndexOfOffset (haystack_length, offset_i64, is_forward);
1109+ if (opt_offset <= -1 ) {
1110+ return args.GetReturnValue ().Set (-1 );
10831111 }
1084-
1085- if (haystack_length < offset || needle_length + offset > haystack_length) {
1112+ size_t offset = static_cast <size_t >(opt_offset);
1113+ CHECK_LT (offset, haystack_length);
1114+ if (is_forward && needle_length + offset > haystack_length) {
10861115 return args.GetReturnValue ().Set (-1 );
10871116 }
10881117
@@ -1097,15 +1126,17 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
10971126 haystack_length / 2 ,
10981127 reinterpret_cast <const uint16_t *>(needle),
10991128 needle_length / 2 ,
1100- offset / 2 );
1129+ offset / 2 ,
1130+ is_forward);
11011131 result *= 2 ;
11021132 } else {
11031133 result = SearchString (
11041134 reinterpret_cast <const uint8_t *>(haystack),
11051135 haystack_length,
11061136 reinterpret_cast <const uint8_t *>(needle),
11071137 needle_length,
1108- offset);
1138+ offset,
1139+ is_forward);
11091140 }
11101141
11111142 args.GetReturnValue ().Set (
@@ -1115,28 +1146,29 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
11151146void IndexOfNumber (const FunctionCallbackInfo<Value>& args) {
11161147 ASSERT (args[1 ]->IsNumber ());
11171148 ASSERT (args[2 ]->IsNumber ());
1149+ ASSERT (args[3 ]->IsBoolean ());
11181150
11191151 THROW_AND_RETURN_UNLESS_BUFFER (Environment::GetCurrent (args), args[0 ]);
11201152 SPREAD_ARG (args[0 ], ts_obj);
11211153
11221154 uint32_t needle = args[1 ]->Uint32Value ();
11231155 int64_t offset_i64 = args[2 ]->IntegerValue ();
1124- size_t offset;
1125-
1126- if (offset_i64 < 0 ) {
1127- if (offset_i64 + static_cast <int64_t >(ts_obj_length) < 0 )
1128- offset = 0 ;
1129- else
1130- offset = static_cast <size_t >(ts_obj_length + offset_i64);
1131- } else {
1132- offset = static_cast <size_t >(offset_i64);
1133- }
1156+ bool is_forward = args[3 ]->IsTrue ();
11341157
1135- if (ts_obj_length == 0 || offset + 1 > ts_obj_length)
1158+ int64_t opt_offset = IndexOfOffset (ts_obj_length, offset_i64, is_forward);
1159+ if (opt_offset <= -1 ) {
11361160 return args.GetReturnValue ().Set (-1 );
1161+ }
1162+ size_t offset = static_cast <size_t >(opt_offset);
1163+ CHECK_LT (offset, ts_obj_length);
11371164
1138- void * ptr = memchr (ts_obj_data + offset, needle, ts_obj_length - offset);
1139- char * ptr_char = static_cast <char *>(ptr);
1165+ const void * ptr;
1166+ if (is_forward) {
1167+ ptr = memchr (ts_obj_data + offset, needle, ts_obj_length - offset);
1168+ } else {
1169+ ptr = node::stringsearch::MemrchrFill (ts_obj_data, needle, offset + 1 );
1170+ }
1171+ const char * ptr_char = static_cast <const char *>(ptr);
11401172 args.GetReturnValue ().Set (ptr ? static_cast <int >(ptr_char - ts_obj_data)
11411173 : -1 );
11421174}
0 commit comments