31 #include "v8-profiler.h" 37 #define BUFFER_ID 0xB0E4 39 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 41 #define THROW_AND_RETURN_IF_OOB(r) \ 43 if (!(r)) return env->ThrowRangeError("out of range index"); \ 46 #define SLICE_START_END(start_arg, end_arg, end_max) \ 49 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(start_arg, 0, &start)); \ 50 THROW_AND_RETURN_IF_OOB(ParseArrayIndex(end_arg, end_max, &end)); \ 51 if (end < start) end = start; \ 52 THROW_AND_RETURN_IF_OOB(end <= end_max); \ 53 size_t length = end - start; 62 inline void* BufferMalloc(
size_t length) {
63 return zero_fill_all_buffers ? node::UncheckedCalloc(length) :
64 node::UncheckedMalloc(length);
71 using v8::ArrayBuffer;
72 using v8::ArrayBufferCreationMode;
73 using v8::ArrayBufferView;
75 using v8::EscapableHandleScope;
76 using v8::FunctionCallbackInfo;
85 using v8::Uint32Array;
88 using v8::WeakCallbackInfo;
94 static inline void Free(
char*
data,
void* hint);
95 static inline CallbackInfo*
New(Isolate* isolate,
96 Local<ArrayBuffer>
object,
101 static void WeakCallback(
const WeakCallbackInfo<CallbackInfo>&);
102 inline void WeakCallback(Isolate* isolate);
103 inline CallbackInfo(Isolate* isolate,
104 Local<ArrayBuffer>
object,
109 Persistent<ArrayBuffer> persistent_;
113 DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
117 void CallbackInfo::Free(
char*
data,
void*) {
123 Local<ArrayBuffer>
object,
127 return new CallbackInfo(isolate,
object, callback, data, hint);
131 CallbackInfo::CallbackInfo(Isolate* isolate,
132 Local<ArrayBuffer>
object,
136 : persistent_(isolate,
object),
140 ArrayBuffer::Contents obj_c =
object->GetContents();
141 CHECK_EQ(data_, static_cast<char*>(obj_c.Data()));
142 if (object->ByteLength() != 0)
143 CHECK_NE(data_,
nullptr);
145 persistent_.SetWeak(
this, WeakCallback, v8::WeakCallbackType::kParameter);
146 persistent_.SetWrapperClassId(
BUFFER_ID);
147 persistent_.MarkIndependent();
148 isolate->AdjustAmountOfExternalAllocatedMemory(
sizeof(*
this));
152 CallbackInfo::~CallbackInfo() {
157 void CallbackInfo::WeakCallback(
158 const WeakCallbackInfo<CallbackInfo>& data) {
159 CallbackInfo*
self = data.GetParameter();
160 self->WeakCallback(data.GetIsolate());
165 void CallbackInfo::WeakCallback(Isolate* isolate) {
166 callback_(data_, hint_);
167 int64_t change_in_bytes = -
static_cast<int64_t
>(
sizeof(*this));
168 isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
173 inline MUST_USE_RESULT
bool ParseArrayIndex(Local<Value> arg,
177 if (arg->IsUndefined()) {
182 int64_t tmp_i = arg->IntegerValue();
188 const uint64_t kSizeMax =
static_cast<uint64_t
>(
static_cast<size_t>(-1));
190 if (static_cast<uint64_t>(tmp_i) > kSizeMax - needed)
193 *ret =
static_cast<size_t>(tmp_i);
202 return val->IsArrayBufferView();
207 return obj->IsArrayBufferView();
212 CHECK(val->IsArrayBufferView());
213 Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
214 ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
215 return static_cast<char*
>(ab_c.Data()) + ui->ByteOffset();
219 char*
Data(Local<Object> obj) {
220 CHECK(obj->IsArrayBufferView());
221 Local<ArrayBufferView> ui = obj.As<ArrayBufferView>();
222 ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
223 return static_cast<char*
>(ab_c.Data()) + ui->ByteOffset();
228 CHECK(val->IsArrayBufferView());
229 Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
230 return ui->ByteLength();
235 CHECK(obj->IsArrayBufferView());
236 Local<ArrayBufferView> ui = obj.As<ArrayBufferView>();
237 return ui->ByteLength();
241 MaybeLocal<Object>
New(Isolate* isolate,
242 Local<String>
string,
244 EscapableHandleScope scope(isolate);
246 const size_t length = StringBytes::Size(isolate,
string, enc);
248 char*
data =
nullptr;
251 data =
static_cast<char*
>(BufferMalloc(length));
254 return Local<Object>();
256 actual = StringBytes::Write(isolate, data, length,
string, enc);
257 CHECK(actual <= length);
262 }
else if (actual < length) {
263 data = node::Realloc(data, actual);
268 if (
New(isolate, data, actual).ToLocal(&buf))
269 return scope.Escape(buf);
273 return Local<Object>();
277 MaybeLocal<Object>
New(Isolate* isolate,
size_t length) {
278 EscapableHandleScope handle_scope(isolate);
280 if (
Buffer::New(Environment::GetCurrent(isolate), length).ToLocal(&obj))
281 return handle_scope.Escape(obj);
282 return Local<Object>();
286 MaybeLocal<Object>
New(Environment* env,
size_t length) {
287 EscapableHandleScope scope(env->isolate());
290 if (length > kMaxLength) {
291 return Local<Object>();
296 data = BufferMalloc(length);
298 return Local<Object>();
303 Local<ArrayBuffer> ab =
307 ArrayBufferCreationMode::kInternalized);
310 ui->SetPrototype(env->context(), env->buffer_prototype_object());
311 if (mb.FromMaybe(
false))
312 return scope.Escape(ui);
316 return Local<Object>();
320 MaybeLocal<Object>
Copy(Isolate* isolate,
const char*
data,
size_t length) {
321 EscapableHandleScope handle_scope(isolate);
322 Environment* env = Environment::GetCurrent(isolate);
325 return handle_scope.Escape(obj);
326 return Local<Object>();
330 MaybeLocal<Object>
Copy(Environment* env,
const char*
data,
size_t length) {
331 EscapableHandleScope scope(env->isolate());
334 if (length > kMaxLength) {
335 return Local<Object>();
340 CHECK_NE(data,
nullptr);
341 new_data = node::UncheckedMalloc(length);
342 if (new_data ==
nullptr)
343 return Local<Object>();
344 memcpy(new_data, data, length);
349 Local<ArrayBuffer> ab =
353 ArrayBufferCreationMode::kInternalized);
356 ui->SetPrototype(env->context(), env->buffer_prototype_object());
357 if (mb.FromMaybe(
false))
358 return scope.Escape(ui);
362 return Local<Object>();
366 MaybeLocal<Object>
New(Isolate* isolate,
371 EscapableHandleScope handle_scope(isolate);
372 Environment* env = Environment::GetCurrent(isolate);
374 if (
Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
375 return handle_scope.Escape(obj);
376 return Local<Object>();
380 MaybeLocal<Object>
New(Environment* env,
385 EscapableHandleScope scope(env->isolate());
387 if (length > kMaxLength) {
388 return Local<Object>();
399 ui->SetPrototype(env->context(), env->buffer_prototype_object());
401 if (!mb.FromMaybe(
false))
402 return Local<Object>();
405 return scope.Escape(ui);
409 MaybeLocal<Object>
New(Isolate* isolate,
char*
data,
size_t length) {
410 EscapableHandleScope handle_scope(isolate);
411 Environment* env = Environment::GetCurrent(isolate);
414 return handle_scope.Escape(obj);
415 return Local<Object>();
419 MaybeLocal<Object>
New(Environment* env,
char*
data,
size_t length) {
420 EscapableHandleScope scope(env->isolate());
423 CHECK_NE(data,
nullptr);
424 CHECK(length <= kMaxLength);
427 Local<ArrayBuffer> ab =
431 ArrayBufferCreationMode::kInternalized);
434 ui->SetPrototype(env->context(), env->buffer_prototype_object());
435 if (mb.FromMaybe(
false))
436 return scope.Escape(ui);
437 return Local<Object>();
442 void CreateFromString(
const FunctionCallbackInfo<Value>& args) {
443 CHECK(args[0]->IsString());
444 CHECK(args[1]->IsString());
447 args[1].As<String>(),
450 if (
New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
451 args.GetReturnValue().Set(buf);
455 template <encoding encoding>
456 void StringSlice(
const FunctionCallbackInfo<Value>& args) {
457 Environment* env = Environment::GetCurrent(args);
458 Isolate* isolate = env->isolate();
460 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
461 SPREAD_BUFFER_ARG(args.This(), ts_obj);
463 if (ts_obj_length == 0)
464 return args.GetReturnValue().SetEmptyString();
469 MaybeLocal<Value> ret =
476 CHECK(!error.IsEmpty());
477 isolate->ThrowException(error);
480 args.GetReturnValue().Set(ret.ToLocalChecked());
485 void StringSlice<UCS2>(
const FunctionCallbackInfo<Value>& args) {
486 Isolate* isolate = args.GetIsolate();
487 Environment* env = Environment::GetCurrent(isolate);
489 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
490 SPREAD_BUFFER_ARG(args.This(), ts_obj);
492 if (ts_obj_length == 0)
493 return args.GetReturnValue().SetEmptyString();
498 const char*
data = ts_obj_data + start;
500 bool release =
false;
505 const bool aligned = (
reinterpret_cast<uintptr_t
>(
data) %
sizeof(*buf) == 0);
506 if (IsLittleEndian() && !aligned) {
511 uint16_t* copy =
new uint16_t[length];
512 for (
size_t i = 0, k = 0; i < length; i += 1, k += 2) {
514 const uint8_t lo =
static_cast<uint8_t
>(data[k + 0]);
515 const uint8_t hi =
static_cast<uint8_t
>(data[k + 1]);
516 copy[i] = lo | hi << 8;
521 buf =
reinterpret_cast<const uint16_t*
>(
data);
525 MaybeLocal<Value> ret =
535 CHECK(!error.IsEmpty());
536 isolate->ThrowException(error);
539 args.GetReturnValue().Set(ret.ToLocalChecked());
544 void Copy(
const FunctionCallbackInfo<Value> &args) {
545 Environment* env = Environment::GetCurrent(args);
547 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
548 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
549 Local<Object> buffer_obj = args[0].As<Object>();
550 Local<Object> target_obj = args[1].As<Object>();
551 SPREAD_BUFFER_ARG(buffer_obj, ts_obj);
552 SPREAD_BUFFER_ARG(target_obj, target);
563 if (target_start >= target_length || source_start >= source_end)
564 return args.GetReturnValue().Set(0);
566 if (source_start > ts_obj_length)
567 return env->ThrowRangeError(
"out of range index");
569 if (source_end - source_start > target_length - target_start)
570 source_end = source_start + target_length - target_start;
572 uint32_t to_copy =
MIN(
MIN(source_end - source_start,
573 target_length - target_start),
574 ts_obj_length - source_start);
576 memmove(target_data + target_start, ts_obj_data + source_start, to_copy);
577 args.GetReturnValue().Set(to_copy);
581 void Fill(
const FunctionCallbackInfo<Value>& args) {
582 Environment* env = Environment::GetCurrent(args);
584 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
585 SPREAD_BUFFER_ARG(args[0], ts_obj);
587 size_t start = args[2]->Uint32Value();
588 size_t end = args[3]->Uint32Value();
589 size_t fill_length = end - start;
590 Local<String> str_obj;
598 SPREAD_BUFFER_ARG(args[1], fill_obj);
599 str_length = fill_obj_length;
600 memcpy(ts_obj_data + start, fill_obj_data,
MIN(str_length, fill_length));
605 if (!args[1]->IsString()) {
606 int value = args[1]->Uint32Value() & 255;
607 memset(ts_obj_data + start, value, fill_length);
611 str_obj = args[1]->ToString(env->isolate());
614 enc ==
UTF8 ? str_obj->Utf8Length() :
615 enc ==
UCS2 ? str_obj->Length() *
sizeof(uint16_t) : str_obj->Length();
623 node::Utf8Value str(env->isolate(), args[1]);
624 memcpy(ts_obj_data + start, *str,
MIN(str_length, fill_length));
626 }
else if (enc ==
UCS2) {
627 node::TwoByteValue str(env->isolate(), args[1]);
629 SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);
631 memcpy(ts_obj_data + start, *str,
MIN(str_length, fill_length));
637 str_length = StringBytes::Write(env->isolate(),
653 if (str_length >= fill_length)
657 size_t in_there = str_length;
658 char* ptr = ts_obj_data + start + str_length;
660 while (in_there < fill_length - in_there) {
661 memcpy(ptr, ts_obj_data + start, in_there);
666 if (in_there < fill_length) {
667 memcpy(ptr, ts_obj_data + start, fill_length - in_there);
672 template <encoding encoding>
673 void StringWrite(
const FunctionCallbackInfo<Value>& args) {
674 Environment* env = Environment::GetCurrent(args);
676 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
677 SPREAD_BUFFER_ARG(args.This(), ts_obj);
679 if (!args[0]->IsString())
680 return env->ThrowTypeError(
"Argument must be a string");
682 Local<String> str = args[0]->ToString(env->isolate());
688 if (offset > ts_obj_length)
689 return env->ThrowRangeError(
"Offset is out of bounds");
694 max_length =
MIN(ts_obj_length - offset, max_length);
697 return args.GetReturnValue().Set(0);
699 uint32_t written = StringBytes::Write(env->isolate(),
700 ts_obj_data + offset,
705 args.GetReturnValue().Set(written);
709 static inline void Swizzle(
char* start,
unsigned int len) {
710 char* end = start + len - 1;
711 while (start < end) {
719 template <
typename T, enum Endianness endianness>
720 void ReadFloatGeneric(
const FunctionCallbackInfo<Value>& args) {
721 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
722 SPREAD_BUFFER_ARG(args[0], ts_obj);
724 uint32_t offset = args[1]->Uint32Value();
725 CHECK_LE(offset +
sizeof(T), ts_obj_length);
729 char bytes[
sizeof(T)];
733 const char* ptr =
static_cast<const char*
>(ts_obj_data) + offset;
734 memcpy(na.bytes, ptr,
sizeof(na.bytes));
735 if (endianness != GetEndianness())
736 Swizzle(na.bytes,
sizeof(na.bytes));
738 args.GetReturnValue().Set(na.val);
742 void ReadFloatLE(
const FunctionCallbackInfo<Value>& args) {
743 ReadFloatGeneric<float, kLittleEndian>(args);
747 void ReadFloatBE(
const FunctionCallbackInfo<Value>& args) {
748 ReadFloatGeneric<float, kBigEndian>(args);
752 void ReadDoubleLE(
const FunctionCallbackInfo<Value>& args) {
753 ReadFloatGeneric<double, kLittleEndian>(args);
757 void ReadDoubleBE(
const FunctionCallbackInfo<Value>& args) {
758 ReadFloatGeneric<double, kBigEndian>(args);
762 template <
typename T, enum Endianness endianness>
763 void WriteFloatGeneric(
const FunctionCallbackInfo<Value>& args) {
764 Environment* env = Environment::GetCurrent(args);
766 bool should_assert = args.Length() < 4;
769 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
772 Local<ArrayBufferView> ts_obj = args[0].As<ArrayBufferView>();
773 ArrayBuffer::Contents ts_obj_c = ts_obj->Buffer()->GetContents();
774 const size_t ts_obj_offset = ts_obj->ByteOffset();
775 const size_t ts_obj_length = ts_obj->ByteLength();
776 char*
const ts_obj_data =
777 static_cast<char*
>(ts_obj_c.Data()) + ts_obj_offset;
778 if (ts_obj_length > 0)
779 CHECK_NE(ts_obj_data,
nullptr);
781 T val = args[1]->NumberValue(env->context()).FromMaybe(0);
783 size_t memcpy_num =
sizeof(T);
788 if (!ParseArrayIndex(args[2], 0, &offset, memcpy_num) ||
789 offset >= ts_obj_length) {
798 if (offset + memcpy_num > ts_obj_length) {
802 memcpy_num = ts_obj_length - offset;
807 char bytes[
sizeof(T)];
810 union NoAlias na = { val };
811 char* ptr =
static_cast<char*
>(ts_obj_data) + offset;
812 if (endianness != GetEndianness())
813 Swizzle(na.bytes,
sizeof(na.bytes));
814 memcpy(ptr, na.bytes, memcpy_num);
818 void WriteFloatLE(
const FunctionCallbackInfo<Value>& args) {
819 WriteFloatGeneric<float, kLittleEndian>(args);
823 void WriteFloatBE(
const FunctionCallbackInfo<Value>& args) {
824 WriteFloatGeneric<float, kBigEndian>(args);
828 void WriteDoubleLE(
const FunctionCallbackInfo<Value>& args) {
829 WriteFloatGeneric<double, kLittleEndian>(args);
833 void WriteDoubleBE(
const FunctionCallbackInfo<Value>& args) {
834 WriteFloatGeneric<double, kBigEndian>(args);
838 void ByteLengthUtf8(
const FunctionCallbackInfo<Value> &args) {
839 CHECK(args[0]->IsString());
842 args.GetReturnValue().Set(args[0].As<String>()->Utf8Length());
847 static int normalizeCompareVal(
int val,
size_t a_length,
size_t b_length) {
849 if (a_length > b_length)
851 else if (a_length < b_length)
862 void CompareOffset(
const FunctionCallbackInfo<Value> &args) {
863 Environment* env = Environment::GetCurrent(args);
865 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
866 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
867 SPREAD_BUFFER_ARG(args[0], ts_obj);
868 SPREAD_BUFFER_ARG(args[1], target);
880 if (source_start > ts_obj_length)
881 return env->ThrowRangeError(
"out of range index");
882 if (target_start > target_length)
883 return env->ThrowRangeError(
"out of range index");
885 CHECK_LE(source_start, source_end);
886 CHECK_LE(target_start, target_end);
888 size_t to_cmp =
MIN(
MIN(source_end - source_start,
889 target_end - target_start),
890 ts_obj_length - source_start);
892 int val = normalizeCompareVal(to_cmp > 0 ?
893 memcmp(ts_obj_data + source_start,
894 target_data + target_start,
896 source_end - source_start,
897 target_end - target_start);
899 args.GetReturnValue().Set(val);
902 void Compare(
const FunctionCallbackInfo<Value> &args) {
903 Environment* env = Environment::GetCurrent(args);
905 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
906 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
907 SPREAD_BUFFER_ARG(args[0], obj_a);
908 SPREAD_BUFFER_ARG(args[1], obj_b);
910 size_t cmp_length =
MIN(obj_a_length, obj_b_length);
912 int val = normalizeCompareVal(cmp_length > 0 ?
913 memcmp(obj_a_data, obj_b_data, cmp_length) : 0,
914 obj_a_length, obj_b_length);
915 args.GetReturnValue().Set(val);
922 int64_t IndexOfOffset(
size_t length,
924 int64_t needle_length,
926 int64_t length_i64 =
static_cast<int64_t
>(length);
927 if (offset_i64 < 0) {
928 if (offset_i64 + length_i64 >= 0) {
930 return length_i64 + offset_i64;
931 }
else if (is_forward || needle_length == 0) {
939 if (offset_i64 + needle_length <= length_i64) {
942 }
else if (needle_length == 0) {
945 }
else if (is_forward) {
950 return length_i64 - 1;
955 void IndexOfString(
const FunctionCallbackInfo<Value>& args) {
956 CHECK(args[1]->IsString());
957 CHECK(args[2]->IsNumber());
958 CHECK(args[4]->IsBoolean());
964 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
965 SPREAD_BUFFER_ARG(args[0], ts_obj);
967 Local<String> needle = args[1].As<String>();
968 int64_t offset_i64 = args[2]->IntegerValue();
969 bool is_forward = args[4]->IsTrue();
971 const char* haystack = ts_obj_data;
973 const size_t haystack_length = (enc ==
UCS2) ?
974 ts_obj_length &~ 1 : ts_obj_length;
976 const size_t needle_length =
977 StringBytes::Size(args.GetIsolate(), needle, enc);
979 int64_t opt_offset = IndexOfOffset(haystack_length,
984 if (needle_length == 0) {
986 args.GetReturnValue().Set(static_cast<double>(opt_offset));
990 if (haystack_length == 0) {
991 return args.GetReturnValue().Set(-1);
994 if (opt_offset <= -1) {
995 return args.GetReturnValue().Set(-1);
997 size_t offset =
static_cast<size_t>(opt_offset);
998 CHECK_LT(offset, haystack_length);
999 if ((is_forward && needle_length + offset > haystack_length) ||
1000 needle_length > haystack_length) {
1001 return args.GetReturnValue().Set(-1);
1004 size_t result = haystack_length;
1007 String::Value needle_value(needle);
1008 if (*needle_value ==
nullptr)
1009 return args.GetReturnValue().Set(-1);
1011 if (haystack_length < 2 || needle_value.length() < 1) {
1012 return args.GetReturnValue().Set(-1);
1015 if (IsBigEndian()) {
1016 StringBytes::InlineDecoder decoder;
1017 decoder.Decode(Environment::GetCurrent(args), needle, args[3],
UCS2);
1018 const uint16_t* decoded_string =
1019 reinterpret_cast<const uint16_t*
>(decoder.out());
1021 if (decoded_string ==
nullptr)
1022 return args.GetReturnValue().Set(-1);
1024 result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
1025 haystack_length / 2,
1031 result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
1032 haystack_length / 2,
1033 reinterpret_cast<const uint16_t*>(*needle_value),
1034 needle_value.length(),
1039 }
else if (enc ==
UTF8) {
1040 String::Utf8Value needle_value(needle);
1041 if (*needle_value ==
nullptr)
1042 return args.GetReturnValue().Set(-1);
1044 result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
1046 reinterpret_cast<const uint8_t*>(*needle_value),
1050 }
else if (enc ==
LATIN1) {
1051 uint8_t* needle_data = node::UncheckedMalloc<uint8_t>(needle_length);
1052 if (needle_data ==
nullptr) {
1053 return args.GetReturnValue().Set(-1);
1055 needle->WriteOneByte(
1056 needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
1058 result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
1067 args.GetReturnValue().Set(
1068 result == haystack_length ? -1 : static_cast<int>(result));
1071 void IndexOfBuffer(
const FunctionCallbackInfo<Value>& args) {
1072 CHECK(args[1]->IsObject());
1073 CHECK(args[2]->IsNumber());
1074 CHECK(args[4]->IsBoolean());
1080 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
1081 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[1]);
1082 SPREAD_BUFFER_ARG(args[0], ts_obj);
1083 SPREAD_BUFFER_ARG(args[1],
buf);
1084 int64_t offset_i64 = args[2]->IntegerValue();
1085 bool is_forward = args[4]->IsTrue();
1087 const char* haystack = ts_obj_data;
1088 const size_t haystack_length = ts_obj_length;
1089 const char* needle = buf_data;
1090 const size_t needle_length = buf_length;
1092 int64_t opt_offset = IndexOfOffset(haystack_length,
1097 if (needle_length == 0) {
1099 args.GetReturnValue().Set(static_cast<double>(opt_offset));
1103 if (haystack_length == 0) {
1104 return args.GetReturnValue().Set(-1);
1107 if (opt_offset <= -1) {
1108 return args.GetReturnValue().Set(-1);
1110 size_t offset =
static_cast<size_t>(opt_offset);
1111 CHECK_LT(offset, haystack_length);
1112 if ((is_forward && needle_length + offset > haystack_length) ||
1113 needle_length > haystack_length) {
1114 return args.GetReturnValue().Set(-1);
1117 size_t result = haystack_length;
1120 if (haystack_length < 2 || needle_length < 2) {
1121 return args.GetReturnValue().Set(-1);
1123 result = SearchString(
1124 reinterpret_cast<const uint16_t*>(haystack),
1125 haystack_length / 2,
1126 reinterpret_cast<const uint16_t*>(needle),
1132 result = SearchString(
1133 reinterpret_cast<const uint8_t*>(haystack),
1135 reinterpret_cast<const uint8_t*>(needle),
1141 args.GetReturnValue().Set(
1142 result == haystack_length ? -1 : static_cast<int>(result));
1145 void IndexOfNumber(
const FunctionCallbackInfo<Value>& args) {
1146 CHECK(args[1]->IsNumber());
1147 CHECK(args[2]->IsNumber());
1148 CHECK(args[3]->IsBoolean());
1150 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
1151 SPREAD_BUFFER_ARG(args[0], ts_obj);
1153 uint32_t needle = args[1]->Uint32Value();
1154 int64_t offset_i64 = args[2]->IntegerValue();
1155 bool is_forward = args[3]->IsTrue();
1157 int64_t opt_offset = IndexOfOffset(ts_obj_length, offset_i64, 1, is_forward);
1158 if (opt_offset <= -1 || ts_obj_length == 0) {
1159 return args.GetReturnValue().Set(-1);
1161 size_t offset =
static_cast<size_t>(opt_offset);
1162 CHECK_LT(offset, ts_obj_length);
1166 ptr = memchr(ts_obj_data + offset, needle, ts_obj_length - offset);
1168 ptr = node::stringsearch::MemrchrFill(ts_obj_data, needle, offset + 1);
1170 const char* ptr_char =
static_cast<const char*
>(ptr);
1171 args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - ts_obj_data)
1176 void Swap16(
const FunctionCallbackInfo<Value>& args) {
1177 Environment* env = Environment::GetCurrent(args);
1178 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1179 SPREAD_BUFFER_ARG(args[0], ts_obj);
1180 SwapBytes16(ts_obj_data, ts_obj_length);
1181 args.GetReturnValue().Set(args[0]);
1185 void Swap32(
const FunctionCallbackInfo<Value>& args) {
1186 Environment* env = Environment::GetCurrent(args);
1187 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1188 SPREAD_BUFFER_ARG(args[0], ts_obj);
1189 SwapBytes32(ts_obj_data, ts_obj_length);
1190 args.GetReturnValue().Set(args[0]);
1194 void Swap64(
const FunctionCallbackInfo<Value>& args) {
1195 Environment* env = Environment::GetCurrent(args);
1196 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1197 SPREAD_BUFFER_ARG(args[0], ts_obj);
1198 SwapBytes64(ts_obj_data, ts_obj_length);
1199 args.GetReturnValue().Set(args[0]);
1205 static void EncodeUtf8String(
const FunctionCallbackInfo<Value>& args) {
1206 Environment* env = Environment::GetCurrent(args);
1207 CHECK_GE(args.Length(), 1);
1208 CHECK(args[0]->IsString());
1210 Local<String> str = args[0].As<String>();
1211 size_t length = str->Utf8Length();
1212 char*
data = node::UncheckedMalloc(length);
1213 str->WriteUtf8(data,
1216 String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1218 ArrayBufferCreationMode::kInternalized);
1220 args.GetReturnValue().Set(array);
1225 void SetupBufferJS(
const FunctionCallbackInfo<Value>& args) {
1226 Environment* env = Environment::GetCurrent(args);
1228 CHECK(args[0]->IsObject());
1229 Local<Object> proto = args[0].As<Object>();
1230 env->set_buffer_prototype_object(proto);
1232 env->SetMethod(proto,
"asciiSlice", StringSlice<ASCII>);
1233 env->SetMethod(proto,
"base64Slice", StringSlice<BASE64>);
1234 env->SetMethod(proto,
"latin1Slice", StringSlice<LATIN1>);
1235 env->SetMethod(proto,
"hexSlice", StringSlice<HEX>);
1236 env->SetMethod(proto,
"ucs2Slice", StringSlice<UCS2>);
1237 env->SetMethod(proto,
"utf8Slice", StringSlice<UTF8>);
1239 env->SetMethod(proto,
"asciiWrite", StringWrite<ASCII>);
1240 env->SetMethod(proto,
"base64Write", StringWrite<BASE64>);
1241 env->SetMethod(proto,
"latin1Write", StringWrite<LATIN1>);
1242 env->SetMethod(proto,
"hexWrite", StringWrite<HEX>);
1243 env->SetMethod(proto,
"ucs2Write", StringWrite<UCS2>);
1244 env->SetMethod(proto,
"utf8Write", StringWrite<UTF8>);
1246 if (
auto zero_fill_field = env->isolate_data()->zero_fill_field()) {
1247 CHECK(args[1]->IsObject());
1248 auto binding_object = args[1].As<Object>();
1251 sizeof(*zero_fill_field));
1252 auto name = FIXED_ONE_BYTE_STRING(env->isolate(),
"zeroFill");
1254 CHECK(binding_object->Set(env->context(), name, value).FromJust());
1260 Local<Value> unused,
1261 Local<Context> context) {
1262 Environment* env = Environment::GetCurrent(context);
1264 env->SetMethod(target,
"setupBufferJS", SetupBufferJS);
1265 env->SetMethod(target,
"createFromString", CreateFromString);
1267 env->SetMethod(target,
"byteLengthUtf8", ByteLengthUtf8);
1268 env->SetMethod(target,
"copy",
Copy);
1269 env->SetMethod(target,
"compare", Compare);
1270 env->SetMethod(target,
"compareOffset", CompareOffset);
1271 env->SetMethod(target,
"fill", Fill);
1272 env->SetMethod(target,
"indexOfBuffer", IndexOfBuffer);
1273 env->SetMethod(target,
"indexOfNumber", IndexOfNumber);
1274 env->SetMethod(target,
"indexOfString", IndexOfString);
1276 env->SetMethod(target,
"readDoubleBE", ReadDoubleBE);
1277 env->SetMethod(target,
"readDoubleLE", ReadDoubleLE);
1278 env->SetMethod(target,
"readFloatBE", ReadFloatBE);
1279 env->SetMethod(target,
"readFloatLE", ReadFloatLE);
1281 env->SetMethod(target,
"writeDoubleBE", WriteDoubleBE);
1282 env->SetMethod(target,
"writeDoubleLE", WriteDoubleLE);
1283 env->SetMethod(target,
"writeFloatBE", WriteFloatBE);
1284 env->SetMethod(target,
"writeFloatLE", WriteFloatLE);
1286 env->SetMethod(target,
"swap16", Swap16);
1287 env->SetMethod(target,
"swap32", Swap32);
1288 env->SetMethod(target,
"swap64", Swap64);
1290 env->SetMethod(target,
"encodeUtf8String", EncodeUtf8String);
1292 target->Set(env->context(),
1293 FIXED_ONE_BYTE_STRING(env->isolate(),
"kMaxLength"),
1294 Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
1296 target->Set(env->context(),
1297 FIXED_ONE_BYTE_STRING(env->isolate(),
"kStringMaxLength"),
1298 Integer::New(env->isolate(), String::kMaxLength)).FromJust();
bool HasInstance(Local< Value > val)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
#define THROW_AND_RETURN_IF_OOB(r)
union node::cares_wrap::@8::CaresAsyncData::@0 data
MaybeLocal< Object > New(Environment *env, char *data, size_t length)
size_t Length(Local< Value > val)
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
char * Data(Local< Value > val)
#define SLICE_START_END(start_arg, end_arg, end_max)
enum encoding ParseEncoding(const char *encoding, enum encoding default_encoding)
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
bool zero_fill_all_buffers
void(* FreeCallback)(char *data, void *hint)
NODE_DEPRECATED("Use ParseEncoding(isolate, ...)", inline enum encoding ParseEncoding(v8::Local< v8::Value > encoding_v, enum encoding default_encoding=LATIN1) { return ParseEncoding(v8::Isolate::GetCurrent(), encoding_v, default_encoding);}) NODE_EXTERN void FatalException(v8 NODE_DEPRECATED("Use FatalException(isolate, ...)", inline void FatalException(const v8::TryCatch &try_catch) { return FatalException(v8::Isolate::GetCurrent(), try_catch);}) NODE_EXTERN v8 NODE_EXTERN v8::Local< v8::Value > Encode(v8::Isolate *isolate, const uint16_t *buf, size_t len)
MaybeLocal< Object > Copy(Isolate *isolate, const char *data, size_t length)