2 #include "node_buffer.h"
6 #include "string_bytes.h"
9 #include "v8-profiler.h"
15 #define BUFFER_ID 0xB0E4
17 #define MIN(a, b) ((a) < (b) ? (a) : (b))
19 #define CHECK_NOT_OOB(r) \
21 if (!(r)) return env->ThrowRangeError("out of range index"); \
24 #define THROW_AND_RETURN_UNLESS_BUFFER(env, obj) \
26 if (!HasInstance(obj)) \
27 return env->ThrowTypeError("argument should be a Buffer"); \
30 #define SPREAD_ARG(val, name) \
31 CHECK((val)->IsUint8Array()); \
32 Local<Uint8Array> name = (val).As<Uint8Array>(); \
33 ArrayBuffer::Contents name##_c = name->Buffer()->GetContents(); \
34 const size_t name##_offset = name->ByteOffset(); \
35 const size_t name##_length = name->ByteLength(); \
36 char* const name##_data = \
37 static_cast<char*>(name##_c.Data()) + name##_offset; \
38 if (name##_length > 0) \
39 CHECK_NE(name##_data, nullptr);
41 #define SLICE_START_END(start_arg, end_arg, end_max) \
44 CHECK_NOT_OOB(ParseArrayIndex(start_arg, 0, &start)); \
45 CHECK_NOT_OOB(ParseArrayIndex(end_arg, end_max, &end)); \
46 if (end < start) end = start; \
47 CHECK_NOT_OOB(end <= end_max); \
48 size_t length = end - start;
53 using v8::ArrayBuffer;
54 using v8::ArrayBufferCreationMode;
56 using v8::EscapableHandleScope;
58 using v8::FunctionCallbackInfo;
59 using v8::FunctionTemplate;
60 using v8::HandleScope;
71 using v8::Uint32Array;
74 using v8::WeakCallbackData;
79 static inline void Free(char* data, void* hint);
80 static inline CallbackInfo* New(Isolate* isolate,
82 FreeCallback callback,
84 inline void Dispose(Isolate* isolate);
85 inline Persistent<Object>* persistent();
87 static void WeakCallback(const WeakCallbackData<Object, CallbackInfo>&);
88 inline void WeakCallback(Isolate* isolate, Local<Object> object);
89 inline CallbackInfo(Isolate* isolate,
91 FreeCallback callback,
94 Persistent<Object> persistent_;
95 FreeCallback const callback_;
97 DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
101 void CallbackInfo::Free(char* data, void*) {
106 CallbackInfo* CallbackInfo::New(Isolate* isolate,
107 Local<Object> object,
108 FreeCallback callback,
110 return new CallbackInfo(isolate, object, callback, hint);
114 void CallbackInfo::Dispose(Isolate* isolate) {
115 WeakCallback(isolate, PersistentToLocal(isolate, persistent_));
119 Persistent<Object>* CallbackInfo::persistent() {
124 CallbackInfo::CallbackInfo(Isolate* isolate,
125 Local<Object> object,
126 FreeCallback callback,
128 : persistent_(isolate, object),
131 persistent_.SetWeak(this, WeakCallback);
132 persistent_.SetWrapperClassId(BUFFER_ID);
133 persistent_.MarkIndependent();
134 isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
138 CallbackInfo::~CallbackInfo() {
143 void CallbackInfo::WeakCallback(
144 const WeakCallbackData<Object, CallbackInfo>& data) {
145 data.GetParameter()->WeakCallback(data.GetIsolate(), data.GetValue());
149 void CallbackInfo::WeakCallback(Isolate* isolate, Local<Object> object) {
150 SPREAD_ARG(object, obj);
151 CHECK_EQ(obj_offset, 0);
152 CHECK_EQ(obj_c.ByteLength(), obj_length);
154 obj->Buffer()->Neuter();
155 callback_(obj_data, hint_);
156 int64_t change_in_bytes = -static_cast<int64_t>(sizeof(*this));
157 isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
165 bool HasInstance(Local<Value> val) {
166 return val->IsUint8Array();
170 bool HasInstance(Local<Object> obj) {
171 return obj->IsUint8Array();
175 char* Data(Local<Value> val) {
176 CHECK(val->IsUint8Array());
177 Local<Uint8Array> ui = val.As<Uint8Array>();
178 ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
179 return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
183 char* Data(Local<Object> obj) {
184 CHECK(obj->IsUint8Array());
185 Local<Uint8Array> ui = obj.As<Uint8Array>();
186 ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
187 return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
191 size_t Length(Local<Value> val) {
192 CHECK(val->IsUint8Array());
193 Local<Uint8Array> ui = val.As<Uint8Array>();
194 return ui->ByteLength();
198 size_t Length(Local<Object> obj) {
199 CHECK(obj->IsUint8Array());
200 Local<Uint8Array> ui = obj.As<Uint8Array>();
201 return ui->ByteLength();
205 MaybeLocal<Object> New(Isolate* isolate,
206 Local<String> string,
208 EscapableHandleScope scope(isolate);
210 size_t length = StringBytes::Size(isolate, string, enc);
211 char* data = static_cast<char*>(malloc(length));
214 return Local<Object>();
216 size_t actual = StringBytes::Write(isolate, data, length, string, enc);
217 CHECK(actual <= length);
219 if (actual < length) {
220 data = static_cast<char*>(realloc(data, actual));
221 CHECK_NE(data, nullptr);
225 if (New(isolate, data, actual).ToLocal(&buf))
226 return scope.Escape(buf);
228 // Object failed to be created. Clean up resources.
230 return Local<Object>();
234 MaybeLocal<Object> New(Isolate* isolate, size_t length) {
235 EscapableHandleScope handle_scope(isolate);
237 if (Buffer::New(Environment::GetCurrent(isolate), length).ToLocal(&obj))
238 return handle_scope.Escape(obj);
239 return Local<Object>();
243 MaybeLocal<Object> New(Environment* env, size_t length) {
244 EscapableHandleScope scope(env->isolate());
246 // V8 currently only allows a maximum Typed Array index of max Smi.
247 if (length > kMaxLength) {
248 return Local<Object>();
253 data = malloc(length);
255 return Local<Object>();
260 Local<ArrayBuffer> ab =
261 ArrayBuffer::New(env->isolate(),
264 ArrayBufferCreationMode::kInternalized);
265 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
267 ui->SetPrototype(env->context(), env->buffer_prototype_object());
268 if (mb.FromMaybe(false))
269 return scope.Escape(ui);
271 // Object failed to be created. Clean up resources.
273 return Local<Object>();
277 MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
278 Environment* env = Environment::GetCurrent(isolate);
279 EscapableHandleScope handle_scope(env->isolate());
281 if (Buffer::Copy(env, data, length).ToLocal(&obj))
282 return handle_scope.Escape(obj);
283 return Local<Object>();
287 MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
288 EscapableHandleScope scope(env->isolate());
290 // V8 currently only allows a maximum Typed Array index of max Smi.
291 if (length > kMaxLength) {
292 return Local<Object>();
297 CHECK_NE(data, nullptr);
298 new_data = malloc(length);
299 if (new_data == nullptr)
300 return Local<Object>();
301 memcpy(new_data, data, length);
306 Local<ArrayBuffer> ab =
307 ArrayBuffer::New(env->isolate(),
310 ArrayBufferCreationMode::kInternalized);
311 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
313 ui->SetPrototype(env->context(), env->buffer_prototype_object());
314 if (mb.FromMaybe(false))
315 return scope.Escape(ui);
317 // Object failed to be created. Clean up resources.
319 return Local<Object>();
323 MaybeLocal<Object> New(Isolate* isolate,
326 FreeCallback callback,
328 Environment* env = Environment::GetCurrent(isolate);
329 EscapableHandleScope handle_scope(env->isolate());
331 if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
332 return handle_scope.Escape(obj);
333 return Local<Object>();
337 MaybeLocal<Object> New(Environment* env,
340 FreeCallback callback,
342 EscapableHandleScope scope(env->isolate());
344 if (length > kMaxLength) {
345 return Local<Object>();
348 Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
349 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
351 ui->SetPrototype(env->context(), env->buffer_prototype_object());
353 if (!mb.FromMaybe(false))
354 return Local<Object>();
356 CallbackInfo::New(env->isolate(), ab, callback, hint);
357 return scope.Escape(ui);
361 MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
362 Environment* env = Environment::GetCurrent(isolate);
363 EscapableHandleScope handle_scope(env->isolate());
365 if (Buffer::New(env, data, length).ToLocal(&obj))
366 return handle_scope.Escape(obj);
367 return Local<Object>();
371 MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
372 EscapableHandleScope scope(env->isolate());
375 CHECK_NE(data, nullptr);
376 CHECK(length <= kMaxLength);
379 Local<ArrayBuffer> ab =
380 ArrayBuffer::New(env->isolate(),
383 ArrayBufferCreationMode::kInternalized);
384 Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
386 ui->SetPrototype(env->context(), env->buffer_prototype_object());
387 if (mb.FromMaybe(false))
388 return scope.Escape(ui);
389 return Local<Object>();
393 void CreateFromString(const FunctionCallbackInfo<Value>& args) {
394 CHECK(args[0]->IsString());
395 CHECK(args[1]->IsString());
397 enum encoding enc = ParseEncoding(args.GetIsolate(),
398 args[1].As<String>(),
401 if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
402 args.GetReturnValue().Set(buf);
406 void CreateFromArrayBuffer(const FunctionCallbackInfo<Value>& args) {
407 Environment* env = Environment::GetCurrent(args);
408 if (!args[0]->IsArrayBuffer())
409 return env->ThrowTypeError("argument is not an ArrayBuffer");
410 Local<ArrayBuffer> ab = args[0].As<ArrayBuffer>();
411 Local<Uint8Array> ui = Uint8Array::New(ab, 0, ab->ByteLength());
413 ui->SetPrototype(env->context(), env->buffer_prototype_object());
414 if (!mb.FromMaybe(false))
415 return env->ThrowError("Unable to set Object prototype");
416 args.GetReturnValue().Set(ui);
420 template <encoding encoding>
421 void StringSlice(const FunctionCallbackInfo<Value>& args) {
422 Environment* env = Environment::GetCurrent(args);
423 Isolate* isolate = env->isolate();
425 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
426 SPREAD_ARG(args.This(), ts_obj);
428 if (ts_obj_length == 0)
429 return args.GetReturnValue().SetEmptyString();
431 SLICE_START_END(args[0], args[1], ts_obj_length)
433 args.GetReturnValue().Set(
434 StringBytes::Encode(isolate, ts_obj_data + start, length, encoding));
439 void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
440 Environment* env = Environment::GetCurrent(args);
442 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
443 SPREAD_ARG(args.This(), ts_obj);
445 if (ts_obj_length == 0)
446 return args.GetReturnValue().SetEmptyString();
448 SLICE_START_END(args[0], args[1], ts_obj_length)
451 const char* data = ts_obj_data + start;
453 bool release = false;
455 // Node's "ucs2" encoding expects LE character data inside a Buffer, so we
456 // need to reorder on BE platforms. See http://nodejs.org/api/buffer.html
457 // regarding Node's "ucs2" encoding specification.
458 const bool aligned = (reinterpret_cast<uintptr_t>(data) % sizeof(*buf) == 0);
459 if (IsLittleEndian() && aligned) {
460 buf = reinterpret_cast<const uint16_t*>(data);
462 // Make a copy to avoid unaligned accesses in v8::String::NewFromTwoByte().
463 uint16_t* copy = new uint16_t[length];
464 for (size_t i = 0, k = 0; i < length; i += 1, k += 2) {
465 // Assumes that the input is little endian.
466 const uint8_t lo = static_cast<uint8_t>(data[k + 0]);
467 const uint8_t hi = static_cast<uint8_t>(data[k + 1]);
468 copy[i] = lo | hi << 8;
474 args.GetReturnValue().Set(StringBytes::Encode(env->isolate(), buf, length));
481 void BinarySlice(const FunctionCallbackInfo<Value>& args) {
482 StringSlice<BINARY>(args);
486 void AsciiSlice(const FunctionCallbackInfo<Value>& args) {
487 StringSlice<ASCII>(args);
491 void Utf8Slice(const FunctionCallbackInfo<Value>& args) {
492 StringSlice<UTF8>(args);
496 void Ucs2Slice(const FunctionCallbackInfo<Value>& args) {
497 StringSlice<UCS2>(args);
501 void HexSlice(const FunctionCallbackInfo<Value>& args) {
502 StringSlice<HEX>(args);
506 void Base64Slice(const FunctionCallbackInfo<Value>& args) {
507 StringSlice<BASE64>(args);
511 // bytesCopied = buffer.copy(target[, targetStart][, sourceStart][, sourceEnd]);
512 void Copy(const FunctionCallbackInfo<Value> &args) {
513 Environment* env = Environment::GetCurrent(args);
515 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
516 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
517 Local<Object> target_obj = args[0].As<Object>();
518 SPREAD_ARG(args.This(), ts_obj);
519 SPREAD_ARG(target_obj, target);
525 CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &target_start));
526 CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &source_start));
527 CHECK_NOT_OOB(ParseArrayIndex(args[3], ts_obj_length, &source_end));
529 // Copy 0 bytes; we're done
530 if (target_start >= target_length || source_start >= source_end)
531 return args.GetReturnValue().Set(0);
533 if (source_start > ts_obj_length)
534 return env->ThrowRangeError("out of range index");
536 if (source_end - source_start > target_length - target_start)
537 source_end = source_start + target_length - target_start;
539 uint32_t to_copy = MIN(MIN(source_end - source_start,
540 target_length - target_start),
541 ts_obj_length - source_start);
543 memmove(target_data + target_start, ts_obj_data + source_start, to_copy);
544 args.GetReturnValue().Set(to_copy);
548 void Fill(const FunctionCallbackInfo<Value>& args) {
549 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
550 SPREAD_ARG(args[0], ts_obj);
552 size_t start = args[2]->Uint32Value();
553 size_t end = args[3]->Uint32Value();
554 size_t length = end - start;
555 CHECK(length + start <= ts_obj_length);
557 if (args[1]->IsNumber()) {
558 int value = args[1]->Uint32Value() & 255;
559 memset(ts_obj_data + start, value, length);
563 node::Utf8Value str(args.GetIsolate(), args[1]);
564 size_t str_length = str.length();
565 size_t in_there = str_length;
566 char* ptr = ts_obj_data + start + str_length;
571 memcpy(ts_obj_data + start, *str, MIN(str_length, length));
573 if (str_length >= length)
576 while (in_there < length - in_there) {
577 memcpy(ptr, ts_obj_data + start, in_there);
582 if (in_there < length) {
583 memcpy(ptr, ts_obj_data + start, length - in_there);
589 template <encoding encoding>
590 void StringWrite(const FunctionCallbackInfo<Value>& args) {
591 Environment* env = Environment::GetCurrent(args);
593 THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
594 SPREAD_ARG(args.This(), ts_obj);
596 if (!args[0]->IsString())
597 return env->ThrowTypeError("Argument must be a string");
599 Local<String> str = args[0]->ToString(env->isolate());
601 if (encoding == HEX && str->Length() % 2 != 0)
602 return env->ThrowTypeError("Invalid hex string");
607 CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &offset));
608 CHECK_NOT_OOB(ParseArrayIndex(args[2], ts_obj_length - offset, &max_length));
610 max_length = MIN(ts_obj_length - offset, max_length);
613 return args.GetReturnValue().Set(0);
615 if (offset >= ts_obj_length)
616 return env->ThrowRangeError("Offset is out of bounds");
618 uint32_t written = StringBytes::Write(env->isolate(),
619 ts_obj_data + offset,
624 args.GetReturnValue().Set(written);
628 void Base64Write(const FunctionCallbackInfo<Value>& args) {
629 StringWrite<BASE64>(args);
633 void BinaryWrite(const FunctionCallbackInfo<Value>& args) {
634 StringWrite<BINARY>(args);
638 void Utf8Write(const FunctionCallbackInfo<Value>& args) {
639 StringWrite<UTF8>(args);
643 void Ucs2Write(const FunctionCallbackInfo<Value>& args) {
644 StringWrite<UCS2>(args);
648 void HexWrite(const FunctionCallbackInfo<Value>& args) {
649 StringWrite<HEX>(args);
653 void AsciiWrite(const FunctionCallbackInfo<Value>& args) {
654 StringWrite<ASCII>(args);
658 static inline void Swizzle(char* start, unsigned int len) {
659 char* end = start + len - 1;
660 while (start < end) {
668 template <typename T, enum Endianness endianness>
669 void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
670 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
671 SPREAD_ARG(args[0], ts_obj);
673 uint32_t offset = args[1]->Uint32Value();
674 CHECK_LE(offset + sizeof(T), ts_obj_length);
678 char bytes[sizeof(T)];
682 const char* ptr = static_cast<const char*>(ts_obj_data) + offset;
683 memcpy(na.bytes, ptr, sizeof(na.bytes));
684 if (endianness != GetEndianness())
685 Swizzle(na.bytes, sizeof(na.bytes));
687 args.GetReturnValue().Set(na.val);
691 void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
692 ReadFloatGeneric<float, kLittleEndian>(args);
696 void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
697 ReadFloatGeneric<float, kBigEndian>(args);
701 void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
702 ReadFloatGeneric<double, kLittleEndian>(args);
706 void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
707 ReadFloatGeneric<double, kBigEndian>(args);
711 template <typename T, enum Endianness endianness>
712 uint32_t WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
713 SPREAD_ARG(args[0], ts_obj);
715 T val = args[1]->NumberValue();
716 uint32_t offset = args[2]->Uint32Value();
717 CHECK_LE(offset + sizeof(T), ts_obj_length);
721 char bytes[sizeof(T)];
724 union NoAlias na = { val };
725 char* ptr = static_cast<char*>(ts_obj_data) + offset;
726 if (endianness != GetEndianness())
727 Swizzle(na.bytes, sizeof(na.bytes));
728 memcpy(ptr, na.bytes, sizeof(na.bytes));
729 return offset + sizeof(na.bytes);
733 void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
734 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
735 args.GetReturnValue().Set(WriteFloatGeneric<float, kLittleEndian>(args));
739 void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
740 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
741 args.GetReturnValue().Set(WriteFloatGeneric<float, kBigEndian>(args));
745 void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
746 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
747 args.GetReturnValue().Set(WriteFloatGeneric<double, kLittleEndian>(args));
751 void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
752 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
753 args.GetReturnValue().Set(WriteFloatGeneric<double, kBigEndian>(args));
757 void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
758 CHECK(args[0]->IsString());
760 // Fast case: avoid StringBytes on UTF8 string. Jump to v8.
761 args.GetReturnValue().Set(args[0].As<String>()->Utf8Length());
765 void Compare(const FunctionCallbackInfo<Value> &args) {
766 Environment* env = Environment::GetCurrent(args);
768 THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
769 THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
770 SPREAD_ARG(args[0], obj_a);
771 SPREAD_ARG(args[1], obj_b);
773 size_t cmp_length = MIN(obj_a_length, obj_b_length);
775 int val = cmp_length > 0 ? memcmp(obj_a_data, obj_b_data, cmp_length) : 0;
777 // Normalize val to be an integer in the range of [1, -1] since
778 // implementations of memcmp() can vary by platform.
780 if (obj_a_length > obj_b_length)
782 else if (obj_a_length < obj_b_length)
791 args.GetReturnValue().Set(val);
795 int32_t IndexOf(const char* haystack,
799 CHECK_GE(h_length, n_length);
800 // TODO(trevnorris): Implement Boyer-Moore string search algorithm.
801 for (size_t i = 0; i < h_length - n_length + 1; i++) {
802 if (haystack[i] == needle[0]) {
803 if (memcmp(haystack + i, needle, n_length) == 0)
811 void IndexOfString(const FunctionCallbackInfo<Value>& args) {
812 ASSERT(args[1]->IsString());
813 ASSERT(args[2]->IsNumber());
815 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
816 SPREAD_ARG(args[0], ts_obj);
818 node::Utf8Value str(args.GetIsolate(), args[1]);
819 int32_t offset_i32 = args[2]->Int32Value();
822 if (offset_i32 < 0) {
823 if (offset_i32 + static_cast<int32_t>(ts_obj_length) < 0)
826 offset = static_cast<uint32_t>(ts_obj_length + offset_i32);
828 offset = static_cast<uint32_t>(offset_i32);
831 if (str.length() == 0 ||
832 ts_obj_length == 0 ||
833 (offset != 0 && str.length() + offset <= str.length()) ||
834 str.length() + offset > ts_obj_length)
835 return args.GetReturnValue().Set(-1);
838 IndexOf(ts_obj_data + offset, ts_obj_length - offset, *str, str.length());
839 args.GetReturnValue().Set(r == -1 ? -1 : static_cast<int32_t>(r + offset));
843 void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
844 ASSERT(args[1]->IsObject());
845 ASSERT(args[2]->IsNumber());
847 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
848 SPREAD_ARG(args[0], ts_obj);
849 SPREAD_ARG(args[1], buf);
850 const int32_t offset_i32 = args[2]->Int32Value();
854 CHECK_NE(buf_data, nullptr);
856 if (offset_i32 < 0) {
857 if (offset_i32 + static_cast<int32_t>(ts_obj_length) < 0)
860 offset = static_cast<uint32_t>(ts_obj_length + offset_i32);
862 offset = static_cast<uint32_t>(offset_i32);
865 if (buf_length == 0 ||
866 ts_obj_length == 0 ||
867 (offset != 0 && buf_length + offset <= buf_length) ||
868 buf_length + offset > ts_obj_length)
869 return args.GetReturnValue().Set(-1);
872 IndexOf(ts_obj_data + offset, ts_obj_length - offset, buf_data, buf_length);
873 args.GetReturnValue().Set(r == -1 ? -1 : static_cast<int32_t>(r + offset));
877 void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
878 ASSERT(args[1]->IsNumber());
879 ASSERT(args[2]->IsNumber());
881 THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
882 SPREAD_ARG(args[0], ts_obj);
884 uint32_t needle = args[1]->Uint32Value();
885 int32_t offset_i32 = args[2]->Int32Value();
888 if (offset_i32 < 0) {
889 if (offset_i32 + static_cast<int32_t>(ts_obj_length) < 0)
892 offset = static_cast<uint32_t>(ts_obj_length + offset_i32);
894 offset = static_cast<uint32_t>(offset_i32);
897 if (ts_obj_length == 0 || offset + 1 > ts_obj_length)
898 return args.GetReturnValue().Set(-1);
900 void* ptr = memchr(ts_obj_data + offset, needle, ts_obj_length - offset);
901 char* ptr_char = static_cast<char*>(ptr);
902 args.GetReturnValue().Set(
903 ptr ? static_cast<int32_t>(ptr_char - ts_obj_data) : -1);
907 // pass Buffer object to load prototype methods
908 void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
909 Environment* env = Environment::GetCurrent(args);
911 CHECK(args[0]->IsObject());
912 Local<Object> proto = args[0].As<Object>();
913 env->set_buffer_prototype_object(proto);
915 env->SetMethod(proto, "asciiSlice", AsciiSlice);
916 env->SetMethod(proto, "base64Slice", Base64Slice);
917 env->SetMethod(proto, "binarySlice", BinarySlice);
918 env->SetMethod(proto, "hexSlice", HexSlice);
919 env->SetMethod(proto, "ucs2Slice", Ucs2Slice);
920 env->SetMethod(proto, "utf8Slice", Utf8Slice);
922 env->SetMethod(proto, "asciiWrite", AsciiWrite);
923 env->SetMethod(proto, "base64Write", Base64Write);
924 env->SetMethod(proto, "binaryWrite", BinaryWrite);
925 env->SetMethod(proto, "hexWrite", HexWrite);
926 env->SetMethod(proto, "ucs2Write", Ucs2Write);
927 env->SetMethod(proto, "utf8Write", Utf8Write);
929 env->SetMethod(proto, "copy", Copy);
931 CHECK(args[1]->IsObject());
932 Local<Object> bObj = args[1].As<Object>();
934 uint32_t* const fields = env->array_buffer_allocator_info()->fields();
935 uint32_t const fields_count =
936 env->array_buffer_allocator_info()->fields_count();
938 Local<ArrayBuffer> array_buffer =
939 ArrayBuffer::New(env->isolate(), fields, sizeof(*fields) * fields_count);
941 bObj->Set(String::NewFromUtf8(env->isolate(), "flags"),
942 Uint32Array::New(array_buffer, 0, fields_count));
946 void Initialize(Local<Object> target,
948 Local<Context> context) {
949 Environment* env = Environment::GetCurrent(context);
951 env->SetMethod(target, "setupBufferJS", SetupBufferJS);
952 env->SetMethod(target, "createFromString", CreateFromString);
953 env->SetMethod(target, "createFromArrayBuffer", CreateFromArrayBuffer);
955 env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8);
956 env->SetMethod(target, "compare", Compare);
957 env->SetMethod(target, "fill", Fill);
958 env->SetMethod(target, "indexOfBuffer", IndexOfBuffer);
959 env->SetMethod(target, "indexOfNumber", IndexOfNumber);
960 env->SetMethod(target, "indexOfString", IndexOfString);
962 env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
963 env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
964 env->SetMethod(target, "readFloatBE", ReadFloatBE);
965 env->SetMethod(target, "readFloatLE", ReadFloatLE);
967 env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
968 env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
969 env->SetMethod(target, "writeFloatBE", WriteFloatBE);
970 env->SetMethod(target, "writeFloatLE", WriteFloatLE);
972 target->Set(env->context(),
973 FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
974 Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
976 target->Set(env->context(),
977 FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
978 Integer::New(env->isolate(), String::kMaxLength)).FromJust();
982 } // namespace Buffer
985 NODE_MODULE_CONTEXT_AWARE_BUILTIN(buffer, node::Buffer::Initialize)