Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_buffer.cc
Go to the documentation of this file.
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #include "node.h"
23 #include "node_buffer.h"
24 
25 #include "env.h"
26 #include "env-inl.h"
27 #include "string_bytes.h"
28 #include "string_search.h"
29 #include "util.h"
30 #include "util-inl.h"
31 #include "v8-profiler.h"
32 #include "v8.h"
33 
34 #include <string.h>
35 #include <limits.h>
36 
37 #define BUFFER_ID 0xB0E4
38 
39 #define MIN(a, b) ((a) < (b) ? (a) : (b))
40 
41 #define THROW_AND_RETURN_IF_OOB(r) \
42  do { \
43  if (!(r)) return env->ThrowRangeError("out of range index"); \
44  } while (0)
45 
46 #define SLICE_START_END(start_arg, end_arg, end_max) \
47  size_t start; \
48  size_t end; \
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;
54 
55 namespace node {
56 
57 // if true, all Buffer and SlowBuffer instances will automatically zero-fill
58 bool zero_fill_all_buffers = false;
59 
60 namespace {
61 
62 inline void* BufferMalloc(size_t length) {
63  return zero_fill_all_buffers ? node::UncheckedCalloc(length) :
64  node::UncheckedMalloc(length);
65 }
66 
67 } // namespace
68 
69 namespace Buffer {
70 
71 using v8::ArrayBuffer;
72 using v8::ArrayBufferCreationMode;
73 using v8::ArrayBufferView;
74 using v8::Context;
75 using v8::EscapableHandleScope;
76 using v8::FunctionCallbackInfo;
77 using v8::Integer;
78 using v8::Isolate;
79 using v8::Local;
80 using v8::Maybe;
81 using v8::MaybeLocal;
82 using v8::Object;
83 using v8::Persistent;
84 using v8::String;
85 using v8::Uint32Array;
86 using v8::Uint8Array;
87 using v8::Value;
88 using v8::WeakCallbackInfo;
89 
90 namespace {
91 
92 class CallbackInfo {
93  public:
94  static inline void Free(char* data, void* hint);
95  static inline CallbackInfo* New(Isolate* isolate,
96  Local<ArrayBuffer> object,
97  FreeCallback callback,
98  char* data,
99  void* hint = 0);
100  private:
101  static void WeakCallback(const WeakCallbackInfo<CallbackInfo>&);
102  inline void WeakCallback(Isolate* isolate);
103  inline CallbackInfo(Isolate* isolate,
104  Local<ArrayBuffer> object,
105  FreeCallback callback,
106  char* data,
107  void* hint);
108  ~CallbackInfo();
109  Persistent<ArrayBuffer> persistent_;
110  FreeCallback const callback_;
111  char* const data_;
112  void* const hint_;
113  DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
114 };
115 
116 
117 void CallbackInfo::Free(char* data, void*) {
118  ::free(data);
119 }
120 
121 
122 CallbackInfo* CallbackInfo::New(Isolate* isolate,
123  Local<ArrayBuffer> object,
124  FreeCallback callback,
125  char* data,
126  void* hint) {
127  return new CallbackInfo(isolate, object, callback, data, hint);
128 }
129 
130 
131 CallbackInfo::CallbackInfo(Isolate* isolate,
132  Local<ArrayBuffer> object,
133  FreeCallback callback,
134  char* data,
135  void* hint)
136  : persistent_(isolate, object),
137  callback_(callback),
138  data_(data),
139  hint_(hint) {
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);
144 
145  persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
146  persistent_.SetWrapperClassId(BUFFER_ID);
147  persistent_.MarkIndependent();
148  isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
149 }
150 
151 
152 CallbackInfo::~CallbackInfo() {
153  persistent_.Reset();
154 }
155 
156 
157 void CallbackInfo::WeakCallback(
158  const WeakCallbackInfo<CallbackInfo>& data) {
159  CallbackInfo* self = data.GetParameter();
160  self->WeakCallback(data.GetIsolate());
161  delete self;
162 }
163 
164 
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);
169 }
170 
171 
172 // Parse index for external array data.
173 inline MUST_USE_RESULT bool ParseArrayIndex(Local<Value> arg,
174  size_t def,
175  size_t* ret,
176  size_t needed = 0) {
177  if (arg->IsUndefined()) {
178  *ret = def;
179  return true;
180  }
181 
182  int64_t tmp_i = arg->IntegerValue();
183 
184  if (tmp_i < 0)
185  return false;
186 
187  // Check that the result fits in a size_t.
188  const uint64_t kSizeMax = static_cast<uint64_t>(static_cast<size_t>(-1));
189  // coverity[pointless_expression]
190  if (static_cast<uint64_t>(tmp_i) > kSizeMax - needed)
191  return false;
192 
193  *ret = static_cast<size_t>(tmp_i);
194  return true;
195 }
196 
197 } // anonymous namespace
198 
199 // Buffer methods
200 
201 bool HasInstance(Local<Value> val) {
202  return val->IsArrayBufferView();
203 }
204 
205 
206 bool HasInstance(Local<Object> obj) {
207  return obj->IsArrayBufferView();
208 }
209 
210 
211 char* Data(Local<Value> val) {
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();
216 }
217 
218 
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();
224 }
225 
226 
227 size_t Length(Local<Value> val) {
228  CHECK(val->IsArrayBufferView());
229  Local<ArrayBufferView> ui = val.As<ArrayBufferView>();
230  return ui->ByteLength();
231 }
232 
233 
234 size_t Length(Local<Object> obj) {
235  CHECK(obj->IsArrayBufferView());
236  Local<ArrayBufferView> ui = obj.As<ArrayBufferView>();
237  return ui->ByteLength();
238 }
239 
240 
241 MaybeLocal<Object> New(Isolate* isolate,
242  Local<String> string,
243  enum encoding enc) {
244  EscapableHandleScope scope(isolate);
245 
246  const size_t length = StringBytes::Size(isolate, string, enc);
247  size_t actual = 0;
248  char* data = nullptr;
249 
250  if (length > 0) {
251  data = static_cast<char*>(BufferMalloc(length));
252 
253  if (data == nullptr)
254  return Local<Object>();
255 
256  actual = StringBytes::Write(isolate, data, length, string, enc);
257  CHECK(actual <= length);
258 
259  if (actual == 0) {
260  free(data);
261  data = nullptr;
262  } else if (actual < length) {
263  data = node::Realloc(data, actual);
264  }
265  }
266 
267  Local<Object> buf;
268  if (New(isolate, data, actual).ToLocal(&buf))
269  return scope.Escape(buf);
270 
271  // Object failed to be created. Clean up resources.
272  free(data);
273  return Local<Object>();
274 }
275 
276 
277 MaybeLocal<Object> New(Isolate* isolate, size_t length) {
278  EscapableHandleScope handle_scope(isolate);
279  Local<Object> obj;
280  if (Buffer::New(Environment::GetCurrent(isolate), length).ToLocal(&obj))
281  return handle_scope.Escape(obj);
282  return Local<Object>();
283 }
284 
285 
286 MaybeLocal<Object> New(Environment* env, size_t length) {
287  EscapableHandleScope scope(env->isolate());
288 
289  // V8 currently only allows a maximum Typed Array index of max Smi.
290  if (length > kMaxLength) {
291  return Local<Object>();
292  }
293 
294  void* data;
295  if (length > 0) {
296  data = BufferMalloc(length);
297  if (data == nullptr)
298  return Local<Object>();
299  } else {
300  data = nullptr;
301  }
302 
303  Local<ArrayBuffer> ab =
304  ArrayBuffer::New(env->isolate(),
305  data,
306  length,
307  ArrayBufferCreationMode::kInternalized);
308  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
309  Maybe<bool> mb =
310  ui->SetPrototype(env->context(), env->buffer_prototype_object());
311  if (mb.FromMaybe(false))
312  return scope.Escape(ui);
313 
314  // Object failed to be created. Clean up resources.
315  free(data);
316  return Local<Object>();
317 }
318 
319 
320 MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
321  EscapableHandleScope handle_scope(isolate);
322  Environment* env = Environment::GetCurrent(isolate);
323  Local<Object> obj;
324  if (Buffer::Copy(env, data, length).ToLocal(&obj))
325  return handle_scope.Escape(obj);
326  return Local<Object>();
327 }
328 
329 
330 MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
331  EscapableHandleScope scope(env->isolate());
332 
333  // V8 currently only allows a maximum Typed Array index of max Smi.
334  if (length > kMaxLength) {
335  return Local<Object>();
336  }
337 
338  void* new_data;
339  if (length > 0) {
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);
345  } else {
346  new_data = nullptr;
347  }
348 
349  Local<ArrayBuffer> ab =
350  ArrayBuffer::New(env->isolate(),
351  new_data,
352  length,
353  ArrayBufferCreationMode::kInternalized);
354  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
355  Maybe<bool> mb =
356  ui->SetPrototype(env->context(), env->buffer_prototype_object());
357  if (mb.FromMaybe(false))
358  return scope.Escape(ui);
359 
360  // Object failed to be created. Clean up resources.
361  free(new_data);
362  return Local<Object>();
363 }
364 
365 
366 MaybeLocal<Object> New(Isolate* isolate,
367  char* data,
368  size_t length,
369  FreeCallback callback,
370  void* hint) {
371  EscapableHandleScope handle_scope(isolate);
372  Environment* env = Environment::GetCurrent(isolate);
373  Local<Object> obj;
374  if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
375  return handle_scope.Escape(obj);
376  return Local<Object>();
377 }
378 
379 
380 MaybeLocal<Object> New(Environment* env,
381  char* data,
382  size_t length,
383  FreeCallback callback,
384  void* hint) {
385  EscapableHandleScope scope(env->isolate());
386 
387  if (length > kMaxLength) {
388  return Local<Object>();
389  }
390 
391  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
392  // `Neuter()`ing is required here to prevent materialization of the backing
393  // store in v8. `nullptr` buffers are not writable, so this is semantically
394  // correct.
395  if (data == nullptr)
396  ab->Neuter();
397  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
398  Maybe<bool> mb =
399  ui->SetPrototype(env->context(), env->buffer_prototype_object());
400 
401  if (!mb.FromMaybe(false))
402  return Local<Object>();
403 
404  CallbackInfo::New(env->isolate(), ab, callback, data, hint);
405  return scope.Escape(ui);
406 }
407 
408 
409 MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
410  EscapableHandleScope handle_scope(isolate);
411  Environment* env = Environment::GetCurrent(isolate);
412  Local<Object> obj;
413  if (Buffer::New(env, data, length).ToLocal(&obj))
414  return handle_scope.Escape(obj);
415  return Local<Object>();
416 }
417 
418 
419 MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
420  EscapableHandleScope scope(env->isolate());
421 
422  if (length > 0) {
423  CHECK_NE(data, nullptr);
424  CHECK(length <= kMaxLength);
425  }
426 
427  Local<ArrayBuffer> ab =
428  ArrayBuffer::New(env->isolate(),
429  data,
430  length,
431  ArrayBufferCreationMode::kInternalized);
432  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
433  Maybe<bool> mb =
434  ui->SetPrototype(env->context(), env->buffer_prototype_object());
435  if (mb.FromMaybe(false))
436  return scope.Escape(ui);
437  return Local<Object>();
438 }
439 
440 namespace {
441 
442 void CreateFromString(const FunctionCallbackInfo<Value>& args) {
443  CHECK(args[0]->IsString());
444  CHECK(args[1]->IsString());
445 
446  enum encoding enc = ParseEncoding(args.GetIsolate(),
447  args[1].As<String>(),
448  UTF8);
449  Local<Object> buf;
450  if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
451  args.GetReturnValue().Set(buf);
452 }
453 
454 
455 template <encoding encoding>
456 void StringSlice(const FunctionCallbackInfo<Value>& args) {
457  Environment* env = Environment::GetCurrent(args);
458  Isolate* isolate = env->isolate();
459 
460  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
461  SPREAD_BUFFER_ARG(args.This(), ts_obj);
462 
463  if (ts_obj_length == 0)
464  return args.GetReturnValue().SetEmptyString();
465 
466  SLICE_START_END(args[0], args[1], ts_obj_length)
467 
468  Local<Value> error;
469  MaybeLocal<Value> ret =
470  StringBytes::Encode(isolate,
471  ts_obj_data + start,
472  length,
473  encoding,
474  &error);
475  if (ret.IsEmpty()) {
476  CHECK(!error.IsEmpty());
477  isolate->ThrowException(error);
478  return;
479  }
480  args.GetReturnValue().Set(ret.ToLocalChecked());
481 }
482 
483 
484 template <>
485 void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
486  Isolate* isolate = args.GetIsolate();
487  Environment* env = Environment::GetCurrent(isolate);
488 
489  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
490  SPREAD_BUFFER_ARG(args.This(), ts_obj);
491 
492  if (ts_obj_length == 0)
493  return args.GetReturnValue().SetEmptyString();
494 
495  SLICE_START_END(args[0], args[1], ts_obj_length)
496  length /= 2;
497 
498  const char* data = ts_obj_data + start;
499  const uint16_t* buf;
500  bool release = false;
501 
502  // Node's "ucs2" encoding expects LE character data inside a Buffer, so we
503  // need to reorder on BE platforms. See http://nodejs.org/api/buffer.html
504  // regarding Node's "ucs2" encoding specification.
505  const bool aligned = (reinterpret_cast<uintptr_t>(data) % sizeof(*buf) == 0);
506  if (IsLittleEndian() && !aligned) {
507  // Make a copy to avoid unaligned accesses in v8::String::NewFromTwoByte().
508  // This applies ONLY to little endian platforms, as misalignment will be
509  // handled by a byte-swapping operation in StringBytes::Encode on
510  // big endian platforms.
511  uint16_t* copy = new uint16_t[length];
512  for (size_t i = 0, k = 0; i < length; i += 1, k += 2) {
513  // Assumes that the input is little endian.
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;
517  }
518  buf = copy;
519  release = true;
520  } else {
521  buf = reinterpret_cast<const uint16_t*>(data);
522  }
523 
524  Local<Value> error;
525  MaybeLocal<Value> ret =
526  StringBytes::Encode(isolate,
527  buf,
528  length,
529  &error);
530 
531  if (release)
532  delete[] buf;
533 
534  if (ret.IsEmpty()) {
535  CHECK(!error.IsEmpty());
536  isolate->ThrowException(error);
537  return;
538  }
539  args.GetReturnValue().Set(ret.ToLocalChecked());
540 }
541 
542 
543 // bytesCopied = copy(buffer, target[, targetStart][, sourceStart][, sourceEnd])
544 void Copy(const FunctionCallbackInfo<Value> &args) {
545  Environment* env = Environment::GetCurrent(args);
546 
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);
553 
554  size_t target_start;
555  size_t source_start;
556  size_t source_end;
557 
558  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[2], 0, &target_start));
559  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[3], 0, &source_start));
560  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[4], ts_obj_length, &source_end));
561 
562  // Copy 0 bytes; we're done
563  if (target_start >= target_length || source_start >= source_end)
564  return args.GetReturnValue().Set(0);
565 
566  if (source_start > ts_obj_length)
567  return env->ThrowRangeError("out of range index");
568 
569  if (source_end - source_start > target_length - target_start)
570  source_end = source_start + target_length - target_start;
571 
572  uint32_t to_copy = MIN(MIN(source_end - source_start,
573  target_length - target_start),
574  ts_obj_length - source_start);
575 
576  memmove(target_data + target_start, ts_obj_data + source_start, to_copy);
577  args.GetReturnValue().Set(to_copy);
578 }
579 
580 
581 void Fill(const FunctionCallbackInfo<Value>& args) {
582  Environment* env = Environment::GetCurrent(args);
583 
584  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
585  SPREAD_BUFFER_ARG(args[0], ts_obj);
586 
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;
591  size_t str_length;
592  enum encoding enc;
593  THROW_AND_RETURN_IF_OOB(start <= end);
594  THROW_AND_RETURN_IF_OOB(fill_length + start <= ts_obj_length);
595 
596  // First check if Buffer has been passed.
597  if (Buffer::HasInstance(args[1])) {
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));
601  goto start_fill;
602  }
603 
604  // Then coerce everything that's not a string.
605  if (!args[1]->IsString()) {
606  int value = args[1]->Uint32Value() & 255;
607  memset(ts_obj_data + start, value, fill_length);
608  return;
609  }
610 
611  str_obj = args[1]->ToString(env->isolate());
612  enc = ParseEncoding(env->isolate(), args[4], UTF8);
613  str_length =
614  enc == UTF8 ? str_obj->Utf8Length() :
615  enc == UCS2 ? str_obj->Length() * sizeof(uint16_t) : str_obj->Length();
616 
617  if (str_length == 0)
618  return;
619 
620  // Can't use StringBytes::Write() in all cases. For example if attempting
621  // to write a two byte character into a one byte Buffer.
622  if (enc == UTF8) {
623  node::Utf8Value str(env->isolate(), args[1]);
624  memcpy(ts_obj_data + start, *str, MIN(str_length, fill_length));
625 
626  } else if (enc == UCS2) {
627  node::TwoByteValue str(env->isolate(), args[1]);
628  if (IsBigEndian())
629  SwapBytes16(reinterpret_cast<char*>(&str[0]), str_length);
630 
631  memcpy(ts_obj_data + start, *str, MIN(str_length, fill_length));
632 
633  } else {
634  // Write initial String to Buffer, then use that memory to copy remainder
635  // of string. Correct the string length for cases like HEX where less than
636  // the total string length is written.
637  str_length = StringBytes::Write(env->isolate(),
638  ts_obj_data + start,
639  fill_length,
640  str_obj,
641  enc,
642  nullptr);
643  // This check is also needed in case Write() returns that no bytes could
644  // be written.
645  // TODO(trevnorris): Should this throw? Because of the string length was
646  // greater than 0 but couldn't be written then the string was invalid.
647  if (str_length == 0)
648  return;
649  }
650 
651  start_fill:
652 
653  if (str_length >= fill_length)
654  return;
655 
656 
657  size_t in_there = str_length;
658  char* ptr = ts_obj_data + start + str_length;
659 
660  while (in_there < fill_length - in_there) {
661  memcpy(ptr, ts_obj_data + start, in_there);
662  ptr += in_there;
663  in_there *= 2;
664  }
665 
666  if (in_there < fill_length) {
667  memcpy(ptr, ts_obj_data + start, fill_length - in_there);
668  }
669 }
670 
671 
672 template <encoding encoding>
673 void StringWrite(const FunctionCallbackInfo<Value>& args) {
674  Environment* env = Environment::GetCurrent(args);
675 
676  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
677  SPREAD_BUFFER_ARG(args.This(), ts_obj);
678 
679  if (!args[0]->IsString())
680  return env->ThrowTypeError("Argument must be a string");
681 
682  Local<String> str = args[0]->ToString(env->isolate());
683 
684  size_t offset;
685  size_t max_length;
686 
687  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[1], 0, &offset));
688  if (offset > ts_obj_length)
689  return env->ThrowRangeError("Offset is out of bounds");
690 
691  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[2], ts_obj_length - offset,
692  &max_length));
693 
694  max_length = MIN(ts_obj_length - offset, max_length);
695 
696  if (max_length == 0)
697  return args.GetReturnValue().Set(0);
698 
699  uint32_t written = StringBytes::Write(env->isolate(),
700  ts_obj_data + offset,
701  max_length,
702  str,
703  encoding,
704  nullptr);
705  args.GetReturnValue().Set(written);
706 }
707 
708 
709 static inline void Swizzle(char* start, unsigned int len) {
710  char* end = start + len - 1;
711  while (start < end) {
712  char tmp = *start;
713  *start++ = *end;
714  *end-- = tmp;
715  }
716 }
717 
718 
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);
723 
724  uint32_t offset = args[1]->Uint32Value();
725  CHECK_LE(offset + sizeof(T), ts_obj_length);
726 
727  union NoAlias {
728  T val;
729  char bytes[sizeof(T)];
730  };
731 
732  union NoAlias na;
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));
737 
738  args.GetReturnValue().Set(na.val);
739 }
740 
741 
742 void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
743  ReadFloatGeneric<float, kLittleEndian>(args);
744 }
745 
746 
747 void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
748  ReadFloatGeneric<float, kBigEndian>(args);
749 }
750 
751 
752 void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
753  ReadFloatGeneric<double, kLittleEndian>(args);
754 }
755 
756 
757 void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
758  ReadFloatGeneric<double, kBigEndian>(args);
759 }
760 
761 
762 template <typename T, enum Endianness endianness>
763 void WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
764  Environment* env = Environment::GetCurrent(args);
765 
766  bool should_assert = args.Length() < 4;
767 
768  if (should_assert) {
769  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
770  }
771 
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);
780 
781  T val = args[1]->NumberValue(env->context()).FromMaybe(0);
782 
783  size_t memcpy_num = sizeof(T);
784  size_t offset;
785 
786  // If the offset is negative or larger than the size of the ArrayBuffer,
787  // throw an error (if needed) and return directly.
788  if (!ParseArrayIndex(args[2], 0, &offset, memcpy_num) ||
789  offset >= ts_obj_length) {
790  if (should_assert)
792  return;
793  }
794 
795  // If the offset is too large for the entire value, but small enough to fit
796  // part of the value, throw an error and return only if should_assert is
797  // true. Otherwise, write the part of the value that fits.
798  if (offset + memcpy_num > ts_obj_length) {
799  if (should_assert)
801  else
802  memcpy_num = ts_obj_length - offset;
803  }
804 
805  union NoAlias {
806  T val;
807  char bytes[sizeof(T)];
808  };
809 
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);
815 }
816 
817 
818 void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
819  WriteFloatGeneric<float, kLittleEndian>(args);
820 }
821 
822 
823 void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
824  WriteFloatGeneric<float, kBigEndian>(args);
825 }
826 
827 
828 void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
829  WriteFloatGeneric<double, kLittleEndian>(args);
830 }
831 
832 
833 void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
834  WriteFloatGeneric<double, kBigEndian>(args);
835 }
836 
837 
838 void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
839  CHECK(args[0]->IsString());
840 
841  // Fast case: avoid StringBytes on UTF8 string. Jump to v8.
842  args.GetReturnValue().Set(args[0].As<String>()->Utf8Length());
843 }
844 
845 // Normalize val to be an integer in the range of [1, -1] since
846 // implementations of memcmp() can vary by platform.
847 static int normalizeCompareVal(int val, size_t a_length, size_t b_length) {
848  if (val == 0) {
849  if (a_length > b_length)
850  return 1;
851  else if (a_length < b_length)
852  return -1;
853  } else {
854  if (val > 0)
855  return 1;
856  else
857  return -1;
858  }
859  return val;
860 }
861 
862 void CompareOffset(const FunctionCallbackInfo<Value> &args) {
863  Environment* env = Environment::GetCurrent(args);
864 
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);
869 
870  size_t target_start;
871  size_t source_start;
872  size_t source_end;
873  size_t target_end;
874 
875  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[2], 0, &target_start));
876  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[3], 0, &source_start));
877  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[4], target_length, &target_end));
878  THROW_AND_RETURN_IF_OOB(ParseArrayIndex(args[5], ts_obj_length, &source_end));
879 
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");
884 
885  CHECK_LE(source_start, source_end);
886  CHECK_LE(target_start, target_end);
887 
888  size_t to_cmp = MIN(MIN(source_end - source_start,
889  target_end - target_start),
890  ts_obj_length - source_start);
891 
892  int val = normalizeCompareVal(to_cmp > 0 ?
893  memcmp(ts_obj_data + source_start,
894  target_data + target_start,
895  to_cmp) : 0,
896  source_end - source_start,
897  target_end - target_start);
898 
899  args.GetReturnValue().Set(val);
900 }
901 
902 void Compare(const FunctionCallbackInfo<Value> &args) {
903  Environment* env = Environment::GetCurrent(args);
904 
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);
909 
910  size_t cmp_length = MIN(obj_a_length, obj_b_length);
911 
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);
916 }
917 
918 
919 // Computes the offset for starting an indexOf or lastIndexOf search.
920 // Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
921 // or -1 to signal that there is no possible match.
922 int64_t IndexOfOffset(size_t length,
923  int64_t offset_i64,
924  int64_t needle_length,
925  bool is_forward) {
926  int64_t length_i64 = static_cast<int64_t>(length);
927  if (offset_i64 < 0) {
928  if (offset_i64 + length_i64 >= 0) {
929  // Negative offsets count backwards from the end of the buffer.
930  return length_i64 + offset_i64;
931  } else if (is_forward || needle_length == 0) {
932  // indexOf from before the start of the buffer: search the whole buffer.
933  return 0;
934  } else {
935  // lastIndexOf from before the start of the buffer: no match.
936  return -1;
937  }
938  } else {
939  if (offset_i64 + needle_length <= length_i64) {
940  // Valid positive offset.
941  return offset_i64;
942  } else if (needle_length == 0) {
943  // Out of buffer bounds, but empty needle: point to end of buffer.
944  return length_i64;
945  } else if (is_forward) {
946  // indexOf from past the end of the buffer: no match.
947  return -1;
948  } else {
949  // lastIndexOf from past the end of the buffer: search the whole buffer.
950  return length_i64 - 1;
951  }
952  }
953 }
954 
955 void IndexOfString(const FunctionCallbackInfo<Value>& args) {
956  CHECK(args[1]->IsString());
957  CHECK(args[2]->IsNumber());
958  CHECK(args[4]->IsBoolean());
959 
960  enum encoding enc = ParseEncoding(args.GetIsolate(),
961  args[3],
962  UTF8);
963 
964  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
965  SPREAD_BUFFER_ARG(args[0], ts_obj);
966 
967  Local<String> needle = args[1].As<String>();
968  int64_t offset_i64 = args[2]->IntegerValue();
969  bool is_forward = args[4]->IsTrue();
970 
971  const char* haystack = ts_obj_data;
972  // Round down to the nearest multiple of 2 in case of UCS2.
973  const size_t haystack_length = (enc == UCS2) ?
974  ts_obj_length &~ 1 : ts_obj_length; // NOLINT(whitespace/operators)
975 
976  const size_t needle_length =
977  StringBytes::Size(args.GetIsolate(), needle, enc);
978 
979  int64_t opt_offset = IndexOfOffset(haystack_length,
980  offset_i64,
981  needle_length,
982  is_forward);
983 
984  if (needle_length == 0) {
985  // Match String#indexOf() and String#lastIndexOf() behaviour.
986  args.GetReturnValue().Set(static_cast<double>(opt_offset));
987  return;
988  }
989 
990  if (haystack_length == 0) {
991  return args.GetReturnValue().Set(-1);
992  }
993 
994  if (opt_offset <= -1) {
995  return args.GetReturnValue().Set(-1);
996  }
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);
1002  }
1003 
1004  size_t result = haystack_length;
1005 
1006  if (enc == UCS2) {
1007  String::Value needle_value(needle);
1008  if (*needle_value == nullptr)
1009  return args.GetReturnValue().Set(-1);
1010 
1011  if (haystack_length < 2 || needle_value.length() < 1) {
1012  return args.GetReturnValue().Set(-1);
1013  }
1014 
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());
1020 
1021  if (decoded_string == nullptr)
1022  return args.GetReturnValue().Set(-1);
1023 
1024  result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
1025  haystack_length / 2,
1026  decoded_string,
1027  decoder.size() / 2,
1028  offset / 2,
1029  is_forward);
1030  } else {
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(),
1035  offset / 2,
1036  is_forward);
1037  }
1038  result *= 2;
1039  } else if (enc == UTF8) {
1040  String::Utf8Value needle_value(needle);
1041  if (*needle_value == nullptr)
1042  return args.GetReturnValue().Set(-1);
1043 
1044  result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
1045  haystack_length,
1046  reinterpret_cast<const uint8_t*>(*needle_value),
1047  needle_length,
1048  offset,
1049  is_forward);
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);
1054  }
1055  needle->WriteOneByte(
1056  needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
1057 
1058  result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
1059  haystack_length,
1060  needle_data,
1061  needle_length,
1062  offset,
1063  is_forward);
1064  free(needle_data);
1065  }
1066 
1067  args.GetReturnValue().Set(
1068  result == haystack_length ? -1 : static_cast<int>(result));
1069 }
1070 
1071 void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
1072  CHECK(args[1]->IsObject());
1073  CHECK(args[2]->IsNumber());
1074  CHECK(args[4]->IsBoolean());
1075 
1076  enum encoding enc = ParseEncoding(args.GetIsolate(),
1077  args[3],
1078  UTF8);
1079 
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();
1086 
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;
1091 
1092  int64_t opt_offset = IndexOfOffset(haystack_length,
1093  offset_i64,
1094  needle_length,
1095  is_forward);
1096 
1097  if (needle_length == 0) {
1098  // Match String#indexOf() and String#lastIndexOf() behaviour.
1099  args.GetReturnValue().Set(static_cast<double>(opt_offset));
1100  return;
1101  }
1102 
1103  if (haystack_length == 0) {
1104  return args.GetReturnValue().Set(-1);
1105  }
1106 
1107  if (opt_offset <= -1) {
1108  return args.GetReturnValue().Set(-1);
1109  }
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);
1115  }
1116 
1117  size_t result = haystack_length;
1118 
1119  if (enc == UCS2) {
1120  if (haystack_length < 2 || needle_length < 2) {
1121  return args.GetReturnValue().Set(-1);
1122  }
1123  result = SearchString(
1124  reinterpret_cast<const uint16_t*>(haystack),
1125  haystack_length / 2,
1126  reinterpret_cast<const uint16_t*>(needle),
1127  needle_length / 2,
1128  offset / 2,
1129  is_forward);
1130  result *= 2;
1131  } else {
1132  result = SearchString(
1133  reinterpret_cast<const uint8_t*>(haystack),
1134  haystack_length,
1135  reinterpret_cast<const uint8_t*>(needle),
1136  needle_length,
1137  offset,
1138  is_forward);
1139  }
1140 
1141  args.GetReturnValue().Set(
1142  result == haystack_length ? -1 : static_cast<int>(result));
1143 }
1144 
1145 void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
1146  CHECK(args[1]->IsNumber());
1147  CHECK(args[2]->IsNumber());
1148  CHECK(args[3]->IsBoolean());
1149 
1150  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
1151  SPREAD_BUFFER_ARG(args[0], ts_obj);
1152 
1153  uint32_t needle = args[1]->Uint32Value();
1154  int64_t offset_i64 = args[2]->IntegerValue();
1155  bool is_forward = args[3]->IsTrue();
1156 
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);
1160  }
1161  size_t offset = static_cast<size_t>(opt_offset);
1162  CHECK_LT(offset, ts_obj_length);
1163 
1164  const void* ptr;
1165  if (is_forward) {
1166  ptr = memchr(ts_obj_data + offset, needle, ts_obj_length - offset);
1167  } else {
1168  ptr = node::stringsearch::MemrchrFill(ts_obj_data, needle, offset + 1);
1169  }
1170  const char* ptr_char = static_cast<const char*>(ptr);
1171  args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - ts_obj_data)
1172  : -1);
1173 }
1174 
1175 
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]);
1182 }
1183 
1184 
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]);
1191 }
1192 
1193 
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]);
1200 }
1201 
1202 
1203 // Encode a single string to a UTF-8 Uint8Array (not Buffer).
1204 // Used in TextEncoder.prototype.encode.
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());
1209 
1210  Local<String> str = args[0].As<String>();
1211  size_t length = str->Utf8Length();
1212  char* data = node::UncheckedMalloc(length);
1213  str->WriteUtf8(data,
1214  -1, // We are certain that `data` is sufficiently large
1215  NULL,
1216  String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1217  auto array_buf = ArrayBuffer::New(env->isolate(), data, length,
1218  ArrayBufferCreationMode::kInternalized);
1219  auto array = Uint8Array::New(array_buf, 0, length);
1220  args.GetReturnValue().Set(array);
1221 }
1222 
1223 
1224 // pass Buffer object to load prototype methods
1225 void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
1226  Environment* env = Environment::GetCurrent(args);
1227 
1228  CHECK(args[0]->IsObject());
1229  Local<Object> proto = args[0].As<Object>();
1230  env->set_buffer_prototype_object(proto);
1231 
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>);
1238 
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>);
1245 
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>();
1249  auto array_buffer = ArrayBuffer::New(env->isolate(),
1250  zero_fill_field,
1251  sizeof(*zero_fill_field));
1252  auto name = FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill");
1253  auto value = Uint32Array::New(array_buffer, 0, 1);
1254  CHECK(binding_object->Set(env->context(), name, value).FromJust());
1255  }
1256 }
1257 
1258 
1259 void Initialize(Local<Object> target,
1260  Local<Value> unused,
1261  Local<Context> context) {
1262  Environment* env = Environment::GetCurrent(context);
1263 
1264  env->SetMethod(target, "setupBufferJS", SetupBufferJS);
1265  env->SetMethod(target, "createFromString", CreateFromString);
1266 
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);
1275 
1276  env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
1277  env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
1278  env->SetMethod(target, "readFloatBE", ReadFloatBE);
1279  env->SetMethod(target, "readFloatLE", ReadFloatLE);
1280 
1281  env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
1282  env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
1283  env->SetMethod(target, "writeFloatBE", WriteFloatBE);
1284  env->SetMethod(target, "writeFloatLE", WriteFloatLE);
1285 
1286  env->SetMethod(target, "swap16", Swap16);
1287  env->SetMethod(target, "swap32", Swap32);
1288  env->SetMethod(target, "swap64", Swap64);
1289 
1290  env->SetMethod(target, "encodeUtf8String", EncodeUtf8String);
1291 
1292  target->Set(env->context(),
1293  FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
1294  Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
1295 
1296  target->Set(env->context(),
1297  FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
1298  Integer::New(env->isolate(), String::kMaxLength)).FromJust();
1299 }
1300 
1301 } // anonymous namespace
1302 } // namespace Buffer
1303 } // namespace node
1304 
bool HasInstance(Local< Value > val)
Definition: node_buffer.cc:201
unsigned char * buf
Definition: cares_wrap.cc:483
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
#define THROW_AND_RETURN_IF_OOB(r)
Definition: node_buffer.cc:41
int len
Definition: cares_wrap.cc:485
union node::cares_wrap::@8::CaresAsyncData::@0 data
MaybeLocal< Object > New(Environment *env, char *data, size_t length)
Definition: node_buffer.cc:419
size_t Length(Local< Value > val)
Definition: node_buffer.cc:227
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
Definition: node_http2.cc:1172
encoding
Definition: node.h:322
char * Data(Local< Value > val)
Definition: node_buffer.cc:211
#define SLICE_START_END(start_arg, end_arg, end_max)
Definition: node_buffer.cc:46
enum encoding ParseEncoding(const char *encoding, enum encoding default_encoding)
Definition: node.cc:1485
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
Definition: node_buffer.cc:241
bool zero_fill_all_buffers
Definition: node_buffer.cc:58
#define MIN(a, b)
Definition: node_buffer.cc:39
#define BUFFER_ID
Definition: node_buffer.cc:37
void(* FreeCallback)(char *data, void *hint)
Definition: node_buffer.h:37
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)
Definition: node.h:350
MaybeLocal< Object > Copy(Isolate *isolate, const char *data, size_t length)
Definition: node_buffer.cc:320