2 #include "node_buffer.h"
6 #include "string_bytes.h"
7 #include "string_search.h"
10 #include "v8-profiler.h"
16 #define BUFFER_ID 0xB0E4
18 #define MIN(a, b) ((a) < (b) ? (a) : (b))
20 #define CHECK_NOT_OOB(r) \
22 if (!(r)) return env->ThrowRangeError("out of range index"); \
25 #define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \
27 if (!HasInstance(obj)) \
28 return env->ThrowTypeError("argument should be a Buffer"); \
31 #define SPREAD_ARG(val, name) \
32 CHECK((val)->IsUint8Array()); \
33 Local<Uint8Array> name = (val).As<Uint8Array>(); \
34 ArrayBuffer::Contents name##_c = name->Buffer()->GetContents(); \
35 const size_t name##_offset = name->ByteOffset(); \
36 const size_t name##_length = name->ByteLength(); \
37 char* const name##_data = \
38 static_cast<char*>(name##_c.Data()) + name##_offset; \
39 if (name##_length > 0) \
40 CHECK_NE(name##_data, nullptr);
42 #define SLICE_START_END(start_arg, end_arg, end_max) \
45 CHECK_NOT_OOB(ParseArrayIndex(start_arg, 0, &start)); \
46 CHECK_NOT_OOB(ParseArrayIndex(end_arg, end_max, &end)); \
47 if (end < start) end = start; \
48 CHECK_NOT_OOB(end <= end_max); \
49 size_t length = end - start;
54 using v8::ArrayBuffer;
55 using v8::ArrayBufferCreationMode;
57 using v8::EscapableHandleScope;
59 using v8::FunctionCallbackInfo;
60 using v8::FunctionTemplate;
61 using v8::HandleScope;
72 using v8::Uint32Array;
75 using v8::WeakCallbackData;
80 static inline void Free(char* data, void* hint);
81 static inline CallbackInfo* New(Isolate* isolate,
83 FreeCallback callback,
85 inline void Dispose(Isolate* isolate);
86 inline Persistent<Object>* persistent();
88 static void WeakCallback(const WeakCallbackData<Object, CallbackInfo>&);
89 inline void WeakCallback(Isolate* isolate, Local<Object> object);
90 inline CallbackInfo(Isolate* isolate,
92 FreeCallback callback,
95 Persistent<Object> persistent_;
96 FreeCallback const callback_;
98 DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
102 void CallbackInfo::Free(char* data, void*) {
107 CallbackInfo* CallbackInfo::New(Isolate* isolate,
108 Local<Object> object,
109 FreeCallback callback,
111 return new CallbackInfo(isolate, object, callback, hint);
115 void CallbackInfo::Dispose(Isolate* isolate) {
116 WeakCallback(isolate, PersistentToLocal(isolate, persistent_));
120 Persistent<Object>* CallbackInfo::persistent() {
125 CallbackInfo::CallbackInfo(Isolate* isolate,
126 Local<Object> object,
127 FreeCallback callback,
129 : persistent_(isolate, object),
132 persistent_.SetWeak(this, WeakCallback);
133 persistent_.SetWrapperClassId(BUFFER_ID);
134 persistent_.MarkIndependent();
135 isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
139 CallbackInfo::~CallbackInfo() {
144 void CallbackInfo::WeakCallback(
145 const WeakCallbackData<Object, CallbackInfo>& data) {
146 data.GetParameter()->WeakCallback(data.GetIsolate(), data.GetValue());
150 void CallbackInfo::WeakCallback(Isolate* isolate, Local<Object> object) {
151 SPREAD_ARG(object, obj);
152 CHECK_EQ(obj_offset, 0);
153 CHECK_EQ(obj_c.ByteLength(), obj_length);
155 obj->Buffer()->Neuter();
156 callback_(obj_data, hint_);
157 int64_t change_in_bytes = -static_cast<int64_t>(sizeof(*this));
158 isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
166 bool HasInstance(Local<Value> val) {
167 return val->IsUint8Array();
171 bool HasInstance(Local<Object> obj) {
172 return obj->IsUint8Array();
176 char* Data(Local<Value> val) {
177 CHECK(val->IsUint8Array());
178 Local<Uint8Array> ui = val.As<Uint8Array>();
179 ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
180 return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
184 char* Data(Local<Object> obj) {
185 CHECK(obj->IsUint8Array());
186 Local<Uint8Array> ui = obj.As<Uint8Array>();
187 ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
188 return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
192 size_t Length(Local<Value> val) {
193 CHECK(val->IsUint8Array());
194 Local<Uint8Array> ui = val.As<Uint8Array>();
195 return ui->ByteLength();
199 size_t Length(Local<Object> obj) {
200 CHECK(obj->IsUint8Array());
201 Local<Uint8Array> ui = obj.As<Uint8Array>();
202 return ui->ByteLength();
206 MaybeLocal<Object> New(Isolate* isolate,
207 Local<String> string,
209 EscapableHandleScope scope(isolate);
211 size_t length = StringBytes::Size(isolate, string, enc);
212 char* data = static_cast<char*>(malloc(length));
215 return Local<Object>();
217 size_t actual = StringBytes::Write(isolate, data, length, string, enc);
218 CHECK(actual <= length);
220 if (actual < length) {
221 data = static_cast<char*>(realloc(data, actual));
222 CHECK_NE(data, nullptr);
226 if (New(isolate, data, actual).ToLocal(&buf))
227 return scope.Escape(buf);
229 // Object failed to be created. Clean up resources.
231 return Local<Object>();
235 MaybeLocal<Object> New(Isolate* isolate, size_t length) {
236 EscapableHandleScope handle_scope(isolate);
238 if (Buffer::New(Environment::GetCurrent(isolate), length).ToLocal(&obj))
239 return handle_scope.Escape(obj);
240 return Local<Object>();
244 MaybeLocal<Object> New(Environment* env, size_t length) {
245 EscapableHandleScope scope(env->isolate());
247 // V8 currently only allows a maximum Typed Array index of max Smi.
248 if (length > kMaxLength) {
249 return Local<Object>();
254 data = malloc(length);
256 return Local<Object>();
261 Local<ArrayBuffer> ab =
262 ArrayBuffer::New(env->isolate(),
265 ArrayBufferCreationMode::kInternalized);
266 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
268 ui->SetPrototype(env->context(), env->buffer_prototype_object());
269 if (mb.FromMaybe(false))
270 return scope.Escape(ui);
272 // Object failed to be created. Clean up resources.
274 return Local<Object>();
278 MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
279 Environment* env = Environment::GetCurrent(isolate);
280 EscapableHandleScope handle_scope(env->isolate());
282 if (Buffer::Copy(env, data, length).ToLocal(&obj))
283 return handle_scope.Escape(obj);
284 return Local<Object>();
288 MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
289 EscapableHandleScope scope(env->isolate());
291 // V8 currently only allows a maximum Typed Array index of max Smi.
292 if (length > kMaxLength) {
293 return Local<Object>();
298 CHECK_NE(data, nullptr);
299 new_data = malloc(length);
300 if (new_data == nullptr)
301 return Local<Object>();
302 memcpy(new_data, data, length);
307 Local<ArrayBuffer> ab =
308 ArrayBuffer::New(env->isolate(),
311 ArrayBufferCreationMode::kInternalized);
312 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
314 ui->SetPrototype(env->context(), env->buffer_prototype_object());
315 if (mb.FromMaybe(false))
316 return scope.Escape(ui);
318 // Object failed to be created. Clean up resources.
320 return Local<Object>();
324 MaybeLocal<Object> New(Isolate* isolate,
327 FreeCallback callback,
329 Environment* env = Environment::GetCurrent(isolate);
330 EscapableHandleScope handle_scope(env->isolate());
332 if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
333 return handle_scope.Escape(obj);
334 return Local<Object>();
338 MaybeLocal<Object> New(Environment* env,
341 FreeCallback callback,
343 EscapableHandleScope scope(env->isolate());
345 if (length > kMaxLength) {
346 return Local<Object>();
349 Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
350 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
352 ui->SetPrototype(env->context(), env->buffer_prototype_object());
354 if (!mb.FromMaybe(false))
355 return Local<Object>();
357 CallbackInfo::New(env->isolate(), ab, callback, hint);
358 return scope.Escape(ui);
362 MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
363 Environment* env = Environment::GetCurrent(isolate);
364 EscapableHandleScope handle_scope(env->isolate());
366 if (Buffer::New(env, data, length).ToLocal(&obj))
367 return handle_scope.Escape(obj);
368 return Local<Object>();
372 MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
373 EscapableHandleScope scope(env->isolate());
376 CHECK_NE(data, nullptr);
377 CHECK(length <= kMaxLength);
380 Local<ArrayBuffer> ab =
381 ArrayBuffer::New(env->isolate(),
384 ArrayBufferCreationMode::kInternalized);
385 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
387 ui->SetPrototype(env->context(), env->buffer_prototype_object());
388 if (mb.FromMaybe(false))
389 return scope.Escape(ui);
390 return Local<Object>();
394 void CreateFromString(const FunctionCallbackInfo<Value>& args) {
395 CHECK(args[0]->IsString());
396 CHECK(args[1]->IsString());
398 enum encoding enc = ParseEncoding(args.GetIsolate(),
399 args[1].As<String>(),
402 if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
403 args.GetReturnValue().Set(buf);
407 void CreateFromArrayBuffer(const FunctionCallbackInfo<Value>& args) {
408 Environment* env = Environment::GetCurrent(args);
409 if (!args[0]->IsArrayBuffer())
410 return env->ThrowTypeError("argument is not an ArrayBuffer");
411 Local<ArrayBuffer> ab = args[0].As<ArrayBuffer>();
412 Local<Uint8Array> ui = Uint8Array::New(ab, 0, ab->ByteLength());
414 ui->SetPrototype(env->context(), env->buffer_prototype_object());
415 if (!mb.FromMaybe(false))
416 return env->ThrowError("Unable to set Object prototype");
417 args.GetReturnValue().Set(ui);
421 template <encoding encoding>
422 void StringSlice(const FunctionCallbackInfo<Value>& args) {
423 Environment* env = Environment::GetCurrent(args);
424 Isolate* isolate = env->isolate();
426 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
427 SPREAD_ARG(args.This(), ts_obj);
429 if (ts_obj_length == 0)
430 return args.GetReturnValue().SetEmptyString();
432 SLICE_START_END(args[0], args[1], ts_obj_length)
434 args.GetReturnValue().Set(
435 StringBytes::Encode(isolate, ts_obj_data + start, length, encoding));
440 void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
441 Environment* env = Environment::GetCurrent(args);
443 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
444 SPREAD_ARG(args.This(), ts_obj);
446 if (ts_obj_length == 0)
447 return args.GetReturnValue().SetEmptyString();
449 SLICE_START_END(args[0], args[1], ts_obj_length)
452 const char* data = ts_obj_data + start;
454 bool release = false;
456 // Node's "ucs2" encoding expects LE character data inside a Buffer, so we
457 // need to reorder on BE platforms. See http://nodejs.org/api/buffer.html
458 // regarding Node's "ucs2" encoding specification.
459 const bool aligned = (reinterpret_cast<uintptr_t>(data) % sizeof(*buf) == 0);
460 if (IsLittleEndian() && aligned) {
461 buf = reinterpret_cast<const uint16_t*>(data);
463 // Make a copy to avoid unaligned accesses in v8::String::NewFromTwoByte().
464 uint16_t* copy = new uint16_t[length];
465 for (size_t i = 0, k = 0; i < length; i += 1, k += 2) {
466 // Assumes that the input is little endian.
467 const uint8_t lo = static_cast<uint8_t>(data[k + 0]);
468 const uint8_t hi = static_cast<uint8_t>(data[k + 1]);
469 copy[i] = lo | hi << 8;
475 args.GetReturnValue().Set(StringBytes::Encode(env->isolate(), buf, length));
482 void BinarySlice(const FunctionCallbackInfo<Value>& args) {
483 StringSlice<BINARY>(args);
487 void AsciiSlice(const FunctionCallbackInfo<Value>& args) {
488 StringSlice<ASCII>(args);
492 void Utf8Slice(const FunctionCallbackInfo<Value>& args) {
493 StringSlice<UTF8>(args);
497 void Ucs2Slice(const FunctionCallbackInfo<Value>& args) {
498 StringSlice<UCS2>(args);
502 void HexSlice(const FunctionCallbackInfo<Value>& args) {
503 StringSlice<HEX>(args);
507 void Base64Slice(const FunctionCallbackInfo<Value>& args) {
508 StringSlice<BASE64>(args);
512 // bytesCopied = buffer.copy(target[, targetStart][, sourceStart][, sourceEnd]);
513 void Copy(const FunctionCallbackInfo<Value> &args) {
514 Environment* env = Environment::GetCurrent(args);
516 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
517 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
518 Local<Object> target_obj = args[0].As<Object>();
519 SPREAD_ARG(args.This(), ts_obj);
520 SPREAD_ARG(target_obj, target);
526 CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &target_start));
527 CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &source_start));
528 CHECK_NOT_OOB(ParseArrayIndex(args[3], ts_obj_length, &source_end));
530 // Copy 0 bytes; we're done
531 if (target_start >= target_length || source_start >= source_end)
532 return args.GetReturnValue().Set(0);
534 if (source_start > ts_obj_length)
535 return env->ThrowRangeError("out of range index");
537 if (source_end - source_start > target_length - target_start)
538 source_end = source_start + target_length - target_start;
540 uint32_t to_copy = MIN(MIN(source_end - source_start,
541 target_length - target_start),
542 ts_obj_length - source_start);
544 memmove(target_data + target_start, ts_obj_data + source_start, to_copy);
545 args.GetReturnValue().Set(to_copy);
549 void Fill(const FunctionCallbackInfo<Value>& args) {
550 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
551 SPREAD_ARG(args[0], ts_obj);
553 size_t start = args[2]->Uint32Value();
554 size_t end = args[3]->Uint32Value();
555 size_t length = end - start;
556 CHECK(length + start <= ts_obj_length);
558 if (args[1]->IsNumber()) {
559 int value = args[1]->Uint32Value() & 255;
560 memset(ts_obj_data + start, value, length);
564 node::Utf8Value str(args.GetIsolate(), args[1]);
565 size_t str_length = str.length();
566 size_t in_there = str_length;
567 char* ptr = ts_obj_data + start + str_length;
572 memcpy(ts_obj_data + start, *str, MIN(str_length, length));
574 if (str_length >= length)
577 while (in_there < length - in_there) {
578 memcpy(ptr, ts_obj_data + start, in_there);
583 if (in_there < length) {
584 memcpy(ptr, ts_obj_data + start, length - in_there);
590 template <encoding encoding>
591 void StringWrite(const FunctionCallbackInfo<Value>& args) {
592 Environment* env = Environment::GetCurrent(args);
594 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
595 SPREAD_ARG(args.This(), ts_obj);
597 if (!args[0]->IsString())
598 return env->ThrowTypeError("Argument must be a string");
600 Local<String> str = args[0]->ToString(env->isolate());
602 if (encoding == HEX && str->Length() % 2 != 0)
603 return env->ThrowTypeError("Invalid hex string");
608 CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &offset));
609 CHECK_NOT_OOB(ParseArrayIndex(args[2], ts_obj_length - offset, &max_length));
611 max_length = MIN(ts_obj_length - offset, max_length);
614 return args.GetReturnValue().Set(0);
616 if (offset >= ts_obj_length)
617 return env->ThrowRangeError("Offset is out of bounds");
619 uint32_t written = StringBytes::Write(env->isolate(),
620 ts_obj_data + offset,
625 args.GetReturnValue().Set(written);
629 void Base64Write(const FunctionCallbackInfo<Value>& args) {
630 StringWrite<BASE64>(args);
634 void BinaryWrite(const FunctionCallbackInfo<Value>& args) {
635 StringWrite<BINARY>(args);
639 void Utf8Write(const FunctionCallbackInfo<Value>& args) {
640 StringWrite<UTF8>(args);
644 void Ucs2Write(const FunctionCallbackInfo<Value>& args) {
645 StringWrite<UCS2>(args);
649 void HexWrite(const FunctionCallbackInfo<Value>& args) {
650 StringWrite<HEX>(args);
654 void AsciiWrite(const FunctionCallbackInfo<Value>& args) {
655 StringWrite<ASCII>(args);
659 static inline void Swizzle(char* start, unsigned int len) {
660 char* end = start + len - 1;
661 while (start < end) {
669 template <typename T, enum Endianness endianness>
670 void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
671 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
672 SPREAD_ARG(args[0], ts_obj);
674 uint32_t offset = args[1]->Uint32Value();
675 CHECK_LE(offset + sizeof(T), ts_obj_length);
679 char bytes[sizeof(T)];
683 const char* ptr = static_cast<const char*>(ts_obj_data) + offset;
684 memcpy(na.bytes, ptr, sizeof(na.bytes));
685 if (endianness != GetEndianness())
686 Swizzle(na.bytes, sizeof(na.bytes));
688 args.GetReturnValue().Set(na.val);
692 void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
693 ReadFloatGeneric<float, kLittleEndian>(args);
697 void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
698 ReadFloatGeneric<float, kBigEndian>(args);
702 void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
703 ReadFloatGeneric<double, kLittleEndian>(args);
707 void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
708 ReadFloatGeneric<double, kBigEndian>(args);
712 template <typename T, enum Endianness endianness>
713 uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
714 SPREAD_ARG(args[0], ts_obj);
716 T val = args[1]->NumberValue();
717 uint32_t offset = args[2]->Uint32Value();
718 CHECK_LE(offset + sizeof(T), ts_obj_length);
722 char bytes[sizeof(T)];
725 union NoAlias na = { val };
726 char* ptr = static_cast<char*>(ts_obj_data) + offset;
727 if (endianness != GetEndianness())
728 Swizzle(na.bytes, sizeof(na.bytes));
729 memcpy(ptr, na.bytes, sizeof(na.bytes));
730 return offset + sizeof(na.bytes);
734 void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
735 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
736 args.GetReturnValue().Set(WriteFloatGeneric<float, kLittleEndian>(args));
740 void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
741 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
742 args.GetReturnValue().Set(WriteFloatGeneric<float, kBigEndian>(args));
746 void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
747 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
748 args.GetReturnValue().Set(WriteFloatGeneric<double, kLittleEndian>(args));
752 void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
753 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
754 args.GetReturnValue().Set(WriteFloatGeneric<double, kBigEndian>(args));
758 void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
759 CHECK(args[0]->IsString());
761 // Fast case: avoid StringBytes on UTF8 string. Jump to v8.
762 args.GetReturnValue().Set(args[0].As<String>()->Utf8Length());
766 void Compare(const FunctionCallbackInfo<Value> &args) {
767 Environment* env = Environment::GetCurrent(args);
769 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
770 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
771 SPREAD_ARG(args[0], obj_a);
772 SPREAD_ARG(args[1], obj_b);
774 size_t cmp_length = MIN(obj_a_length, obj_b_length);
776 int val = cmp_length > 0 ? memcmp(obj_a_data, obj_b_data, cmp_length) : 0;
778 // Normalize val to be an integer in the range of [1, -1] since
779 // implementations of memcmp() can vary by platform.
781 if (obj_a_length > obj_b_length)
783 else if (obj_a_length < obj_b_length)
792 args.GetReturnValue().Set(val);
796 void IndexOfString(const FunctionCallbackInfo<Value>& args) {
797 ASSERT(args[1]->IsString());
798 ASSERT(args[2]->IsNumber());
800 enum encoding enc = ParseEncoding(args.GetIsolate(),
804 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
805 SPREAD_ARG(args[0], ts_obj);
807 Local<String> needle = args[1].As<String>();
808 const char* haystack = ts_obj_data;
809 const size_t haystack_length = ts_obj_length;
810 const size_t needle_length = needle->Utf8Length();
813 if (needle_length == 0 || haystack_length == 0) {
814 return args.GetReturnValue().Set(-1);
817 int64_t offset_i64 = args[2]->IntegerValue();
820 if (offset_i64 < 0) {
821 if (offset_i64 + static_cast<int64_t>(haystack_length) < 0) {
824 offset = static_cast<size_t>(haystack_length + offset_i64);
827 offset = static_cast<size_t>(offset_i64);
830 if (haystack_length < offset || needle_length + offset > haystack_length) {
831 return args.GetReturnValue().Set(-1);
834 size_t result = haystack_length;
837 String::Value needle_value(needle);
838 if (*needle_value == nullptr)
839 return args.GetReturnValue().Set(-1);
841 if (haystack_length < 2 || needle_value.length() < 1) {
842 return args.GetReturnValue().Set(-1);
845 result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
847 reinterpret_cast<const uint16_t*>(*needle_value),
848 needle_value.length(),
851 } else if (enc == UTF8) {
852 String::Utf8Value needle_value(needle);
853 if (*needle_value == nullptr)
854 return args.GetReturnValue().Set(-1);
856 result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
858 reinterpret_cast<const uint8_t*>(*needle_value),
861 } else if (enc == BINARY) {
862 uint8_t* needle_data = static_cast<uint8_t*>(malloc(needle_length));
863 if (needle_data == nullptr) {
864 return args.GetReturnValue().Set(-1);
866 needle->WriteOneByte(
867 needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
869 result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
877 args.GetReturnValue().Set(
878 result == haystack_length ? -1 : static_cast<int>(result));
881 void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
882 ASSERT(args[1]->IsObject());
883 ASSERT(args[2]->IsNumber());
885 enum encoding enc = ParseEncoding(args.GetIsolate(),
889 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
890 SPREAD_ARG(args[0], ts_obj);
891 SPREAD_ARG(args[1], buf);
894 CHECK_NE(buf_data, nullptr);
896 const char* haystack = ts_obj_data;
897 const size_t haystack_length = ts_obj_length;
898 const char* needle = buf_data;
899 const size_t needle_length = buf_length;
901 if (needle_length == 0 || haystack_length == 0) {
902 return args.GetReturnValue().Set(-1);
905 int64_t offset_i64 = args[2]->IntegerValue();
908 if (offset_i64 < 0) {
909 if (offset_i64 + static_cast<int64_t>(haystack_length) < 0)
912 offset = static_cast<size_t>(haystack_length + offset_i64);
914 offset = static_cast<size_t>(offset_i64);
917 if (haystack_length < offset || needle_length + offset > haystack_length) {
918 return args.GetReturnValue().Set(-1);
921 size_t result = haystack_length;
924 if (haystack_length < 2 || needle_length < 2) {
925 return args.GetReturnValue().Set(-1);
927 result = SearchString(
928 reinterpret_cast<const uint16_t*>(haystack),
930 reinterpret_cast<const uint16_t*>(needle),
935 result = SearchString(
936 reinterpret_cast<const uint8_t*>(haystack),
938 reinterpret_cast<const uint8_t*>(needle),
943 args.GetReturnValue().Set(
944 result == haystack_length ? -1 : static_cast<int>(result));
947 void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
948 ASSERT(args[1]->IsNumber());
949 ASSERT(args[2]->IsNumber());
951 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
952 SPREAD_ARG(args[0], ts_obj);
954 uint32_t needle = args[1]->Uint32Value();
955 int64_t offset_i64 = args[2]->IntegerValue();
958 if (offset_i64 < 0) {
959 if (offset_i64 + static_cast<int64_t>(ts_obj_length) < 0)
962 offset = static_cast<size_t>(ts_obj_length + offset_i64);
964 offset = static_cast<size_t>(offset_i64);
967 if (ts_obj_length == 0 || offset + 1 > ts_obj_length)
968 return args.GetReturnValue().Set(-1);
970 void* ptr = memchr(ts_obj_data + offset, needle, ts_obj_length - offset);
971 char* ptr_char = static_cast<char*>(ptr);
972 args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - ts_obj_data)
977 // pass Buffer object to load prototype methods
978 void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
979 Environment* env = Environment::GetCurrent(args);
981 CHECK(args[0]->IsObject());
982 Local<Object> proto = args[0].As<Object>();
983 env->set_buffer_prototype_object(proto);
985 env->SetMethod(proto, "asciiSlice", AsciiSlice);
986 env->SetMethod(proto, "base64Slice", Base64Slice);
987 env->SetMethod(proto, "binarySlice", BinarySlice);
988 env->SetMethod(proto, "hexSlice", HexSlice);
989 env->SetMethod(proto, "ucs2Slice", Ucs2Slice);
990 env->SetMethod(proto, "utf8Slice", Utf8Slice);
992 env->SetMethod(proto, "asciiWrite", AsciiWrite);
993 env->SetMethod(proto, "base64Write", Base64Write);
994 env->SetMethod(proto, "binaryWrite", BinaryWrite);
995 env->SetMethod(proto, "hexWrite", HexWrite);
996 env->SetMethod(proto, "ucs2Write", Ucs2Write);
997 env->SetMethod(proto, "utf8Write", Utf8Write);
999 env->SetMethod(proto, "copy", Copy);
1001 CHECK(args[1]->IsObject());
1002 Local<Object> bObj = args[1].As<Object>();
1004 uint32_t* const fields = env->array_buffer_allocator_info()->fields();
1005 uint32_t const fields_count =
1006 env->array_buffer_allocator_info()->fields_count();
1008 Local<ArrayBuffer> array_buffer =
1009 ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count);
1011 bObj->Set(String::NewFromUtf8(env->isolate(), "flags"),
1012 Uint32Array::New(array_buffer, 0, fields_count));
1016 void Initialize(Local<Object> target,
1017 Local<Value> unused,
1018 Local<Context> context) {
1019 Environment* env = Environment::GetCurrent(context);
1021 env->SetMethod(target, "setupBufferJS", SetupBufferJS);
1022 env->SetMethod(target, "createFromString", CreateFromString);
1023 env->SetMethod(target, "createFromArrayBuffer", CreateFromArrayBuffer);
1025 env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8);
1026 env->SetMethod(target, "compare", Compare);
1027 env->SetMethod(target, "fill", Fill);
1028 env->SetMethod(target, "indexOfBuffer", IndexOfBuffer);
1029 env->SetMethod(target, "indexOfNumber", IndexOfNumber);
1030 env->SetMethod(target, "indexOfString", IndexOfString);
1032 env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
1033 env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
1034 env->SetMethod(target, "readFloatBE", ReadFloatBE);
1035 env->SetMethod(target, "readFloatLE", ReadFloatLE);
1037 env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
1038 env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
1039 env->SetMethod(target, "writeFloatBE", WriteFloatBE);
1040 env->SetMethod(target, "writeFloatLE", WriteFloatLE);
1042 target->Set(env->context(),
1043 FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
1044 Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
1046 target->Set(env->context(),
1047 FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
1048 Integer::New(env->isolate(), String::kMaxLength)).FromJust();
1052 } // namespace Buffer
1055 NODE_MODULE_CONTEXT_AWARE_BUILTIN(buffer, node::Buffer::Initialize)