GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/node_buffer.cc Lines: 587 633 92.7 %
Date: 2016-07-26 Branches: 510 820 62.2 %

Line Exec Source
1
#include "node.h"
2
#include "node_buffer.h"
3
4
#include "env.h"
5
#include "env-inl.h"
6
#include "string_bytes.h"
7
#include "string_search.h"
8
#include "util.h"
9
#include "util-inl.h"
10
#include "v8-profiler.h"
11
#include "v8.h"
12
13
#include <string.h>
14
#include <limits.h>
15
#include <utility>
16
17
#define BUFFER_ID 0xB0E4
18
19
#define MIN(a, b) ((a) < (b) ? (a) : (b))
20
21
#define CHECK_NOT_OOB(r)                                                    \
22
  do {                                                                      \
23
    if (!(r)) return env->ThrowRangeError("out of range index");            \
24
  } while (0)
25
26
#define THROW_AND_RETURN_UNLESS_BUFFER(env, obj)                            \
27
  do {                                                                      \
28
    if (!HasInstance(obj))                                                  \
29
      return env->ThrowTypeError("argument should be a Buffer");            \
30
  } while (0)
31
32
#define SPREAD_ARG(val, name)                                                 \
33
  CHECK((val)->IsUint8Array());                                               \
34
  Local<Uint8Array> name = (val).As<Uint8Array>();                            \
35
  ArrayBuffer::Contents name##_c = name->Buffer()->GetContents();             \
36
  const size_t name##_offset = name->ByteOffset();                            \
37
  const size_t name##_length = name->ByteLength();                            \
38
  char* const name##_data =                                                   \
39
      static_cast<char*>(name##_c.Data()) + name##_offset;                    \
40
  if (name##_length > 0)                                                      \
41
    CHECK_NE(name##_data, nullptr);
42
43
#define SLICE_START_END(start_arg, end_arg, end_max)                        \
44
  size_t start;                                                             \
45
  size_t end;                                                               \
46
  CHECK_NOT_OOB(ParseArrayIndex(start_arg, 0, &start));                     \
47
  CHECK_NOT_OOB(ParseArrayIndex(end_arg, end_max, &end));                   \
48
  if (end < start) end = start;                                             \
49
  CHECK_NOT_OOB(end <= end_max);                                            \
50
  size_t length = end - start;
51
52
#define BUFFER_MALLOC(length)                                               \
53
  zero_fill_all_buffers ? calloc(length, 1) : malloc(length)
54
55
#if defined(__GNUC__) || defined(__clang__)
56
#define BSWAP_INTRINSIC_2(x) __builtin_bswap16(x)
57
#define BSWAP_INTRINSIC_4(x) __builtin_bswap32(x)
58
#define BSWAP_INTRINSIC_8(x) __builtin_bswap64(x)
59
#elif defined(__linux__)
60
#include <byteswap.h>
61
#define BSWAP_INTRINSIC_2(x) bswap_16(x)
62
#define BSWAP_INTRINSIC_4(x) bswap_32(x)
63
#define BSWAP_INTRINSIC_8(x) bswap_64(x)
64
#elif defined(_MSC_VER)
65
#include <intrin.h>
66
#define BSWAP_INTRINSIC_2(x) _byteswap_ushort(x);
67
#define BSWAP_INTRINSIC_4(x) _byteswap_ulong(x);
68
#define BSWAP_INTRINSIC_8(x) _byteswap_uint64(x);
69
#else
70
#define BSWAP_INTRINSIC_2(x) ((x) << 8) | ((x) >> 8)
71
#define BSWAP_INTRINSIC_4(x)                                                  \
72
  (((x) & 0xFF) << 24) |                                                      \
73
  (((x) & 0xFF00) << 8) |                                                     \
74
  (((x) >> 8) & 0xFF00) |                                                     \
75
  (((x) >> 24) & 0xFF)
76
#define BSWAP_INTRINSIC_8(x)                                                  \
77
  (((x) & 0xFF00000000000000ull) >> 56) |                                     \
78
  (((x) & 0x00FF000000000000ull) >> 40) |                                     \
79
  (((x) & 0x0000FF0000000000ull) >> 24) |                                     \
80
  (((x) & 0x000000FF00000000ull) >> 8) |                                      \
81
  (((x) & 0x00000000FF000000ull) << 8) |                                      \
82
  (((x) & 0x0000000000FF0000ull) << 24) |                                     \
83
  (((x) & 0x000000000000FF00ull) << 40) |                                     \
84
  (((x) & 0x00000000000000FFull) << 56)
85
#endif
86
87
namespace node {
88
89
// if true, all Buffer and SlowBuffer instances will automatically zero-fill
90
bool zero_fill_all_buffers = false;
91
92
namespace Buffer {
93
94
using v8::ArrayBuffer;
95
using v8::ArrayBufferCreationMode;
96
using v8::Context;
97
using v8::EscapableHandleScope;
98
using v8::Function;
99
using v8::FunctionCallbackInfo;
100
using v8::HandleScope;
101
using v8::Integer;
102
using v8::Isolate;
103
using v8::Local;
104
using v8::Maybe;
105
using v8::MaybeLocal;
106
using v8::Number;
107
using v8::Object;
108
using v8::Persistent;
109
using v8::String;
110
using v8::Uint32;
111
using v8::Uint32Array;
112
using v8::Uint8Array;
113
using v8::Value;
114
using v8::WeakCallbackInfo;
115
116
class CallbackInfo {
117
 public:
118
  static inline void Free(char* data, void* hint);
119
  static inline CallbackInfo* New(Isolate* isolate,
120
                                  Local<ArrayBuffer> object,
121
                                  FreeCallback callback,
122
                                  char* data,
123
                                  void* hint = 0);
124
 private:
125
  static void WeakCallback(const WeakCallbackInfo<CallbackInfo>&);
126
  inline void WeakCallback(Isolate* isolate);
127
  inline CallbackInfo(Isolate* isolate,
128
                      Local<ArrayBuffer> object,
129
                      FreeCallback callback,
130
                      char* data,
131
                      void* hint);
132
  ~CallbackInfo();
133
  Persistent<ArrayBuffer> persistent_;
134
  FreeCallback const callback_;
135
  char* const data_;
136
  void* const hint_;
137
  DISALLOW_COPY_AND_ASSIGN(CallbackInfo);
138
};
139
140
141
void CallbackInfo::Free(char* data, void*) {
142
  ::free(data);
143
}
144
145
146
12
CallbackInfo* CallbackInfo::New(Isolate* isolate,
147
                                Local<ArrayBuffer> object,
148
                                FreeCallback callback,
149
                                char* data,
150
                                void* hint) {
151
12
  return new CallbackInfo(isolate, object, callback, data, hint);
152
}
153
154
155
12
CallbackInfo::CallbackInfo(Isolate* isolate,
156
                           Local<ArrayBuffer> object,
157
                           FreeCallback callback,
158
                           char* data,
159
                           void* hint)
160
    : persistent_(isolate, object),
161
      callback_(callback),
162
      data_(data),
163
24
      hint_(hint) {
164
12
  ArrayBuffer::Contents obj_c = object->GetContents();
165
12
  CHECK_EQ(data_, static_cast<char*>(obj_c.Data()));
166
12
  if (object->ByteLength() != 0)
167
10
    CHECK_NE(data_, nullptr);
168
169
24
  persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
170
24
  persistent_.SetWrapperClassId(BUFFER_ID);
171
24
  persistent_.MarkIndependent();
172
24
  isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
173
12
}
174
175
176
24
CallbackInfo::~CallbackInfo() {
177
24
  persistent_.Reset();
178
}
179
180
181
12
void CallbackInfo::WeakCallback(
182
    const WeakCallbackInfo<CallbackInfo>& data) {
183
12
  CallbackInfo* self = data.GetParameter();
184
24
  self->WeakCallback(data.GetIsolate());
185
24
  delete self;
186
12
}
187
188
189
void CallbackInfo::WeakCallback(Isolate* isolate) {
190
12
  callback_(data_, hint_);
191
12
  int64_t change_in_bytes = -static_cast<int64_t>(sizeof(*this));
192
12
  isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes);
193
}
194
195
196
// Parse index for external array data.
197
909419
inline MUST_USE_RESULT bool ParseArrayIndex(Local<Value> arg,
198
                                            size_t def,
199
                                            size_t* ret) {
200
1818838
  if (arg->IsUndefined()) {
201
529302
    *ret = def;
202
529302
    return true;
203
  }
204
205
380117
  int64_t tmp_i = arg->IntegerValue();
206
207
380117
  if (tmp_i < 0)
208
    return false;
209
210
  // Check that the result fits in a size_t.
211
380113
  const uint64_t kSizeMax = static_cast<uint64_t>(static_cast<size_t>(-1));
212
  // coverity[pointless_expression]
213
  if (static_cast<uint64_t>(tmp_i) > kSizeMax)
214
    return false;
215
216
380113
  *ret = static_cast<size_t>(tmp_i);
217
380113
  return true;
218
}
219
220
221
// Buffer methods
222
223
486237
bool HasInstance(Local<Value> val) {
224
758490
  return val->IsUint8Array();
225
}
226
227
228
1
bool HasInstance(Local<Object> obj) {
229
320511
  return obj->IsUint8Array();
230
}
231
232
233
24510
char* Data(Local<Value> val) {
234
24510
  CHECK(val->IsUint8Array());
235
24510
  Local<Uint8Array> ui = val.As<Uint8Array>();
236
49020
  ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
237
24510
  return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
238
}
239
240
241
34738
char* Data(Local<Object> obj) {
242
34738
  CHECK(obj->IsUint8Array());
243
34738
  Local<Uint8Array> ui = obj.As<Uint8Array>();
244
69476
  ArrayBuffer::Contents ab_c = ui->Buffer()->GetContents();
245
34738
  return static_cast<char*>(ab_c.Data()) + ui->ByteOffset();
246
}
247
248
249
24507
size_t Length(Local<Value> val) {
250
24507
  CHECK(val->IsUint8Array());
251
24507
  Local<Uint8Array> ui = val.As<Uint8Array>();
252
24507
  return ui->ByteLength();
253
}
254
255
256
34435
size_t Length(Local<Object> obj) {
257
34435
  CHECK(obj->IsUint8Array());
258
34435
  Local<Uint8Array> ui = obj.As<Uint8Array>();
259
34435
  return ui->ByteLength();
260
}
261
262
263
1644
MaybeLocal<Object> New(Isolate* isolate,
264
                       Local<String> string,
265
                       enum encoding enc) {
266
3288
  EscapableHandleScope scope(isolate);
267
268
1644
  const size_t length = StringBytes::Size(isolate, string, enc);
269
1644
  size_t actual = 0;
270
1644
  char* data = nullptr;
271
272
  // malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
273
  // that the standard allows them to either return a unique pointer or a
274
  // nullptr for zero-sized allocation requests.  Normalize by always using
275
  // a nullptr.
276
1644
  if (length > 0) {
277
1644
    data = static_cast<char*>(BUFFER_MALLOC(length));
278
279
1644
    if (data == nullptr)
280
      return Local<Object>();
281
282
1644
    actual = StringBytes::Write(isolate, data, length, string, enc);
283
1644
    CHECK(actual <= length);
284
285
1644
    if (actual == 0) {
286
2
      free(data);
287
2
      data = nullptr;
288
1642
    } else if (actual < length) {
289
5
      data = static_cast<char*>(realloc(data, actual));
290
5
      CHECK_NE(data, nullptr);
291
    }
292
  }
293
294
1644
  Local<Object> buf;
295
3288
  if (New(isolate, data, actual).ToLocal(&buf))
296
3288
    return scope.Escape(buf);
297
298
  // Object failed to be created. Clean up resources.
299
  free(data);
300
  return Local<Object>();
301
}
302
303
304
MaybeLocal<Object> New(Isolate* isolate, size_t length) {
305
  EscapableHandleScope handle_scope(isolate);
306
  Local<Object> obj;
307
  if (Buffer::New(Environment::GetCurrent(isolate), length).ToLocal(&obj))
308
    return handle_scope.Escape(obj);
309
  return Local<Object>();
310
}
311
312
313
309
MaybeLocal<Object> New(Environment* env, size_t length) {
314
618
  EscapableHandleScope scope(env->isolate());
315
316
  // V8 currently only allows a maximum Typed Array index of max Smi.
317
309
  if (length > kMaxLength) {
318
    return Local<Object>();
319
  }
320
321
  void* data;
322
309
  if (length > 0) {
323
174
    data = BUFFER_MALLOC(length);
324
174
    if (data == nullptr)
325
      return Local<Object>();
326
  } else {
327
    data = nullptr;
328
  }
329
330
  Local<ArrayBuffer> ab =
331
    ArrayBuffer::New(env->isolate(),
332
        data,
333
        length,
334
309
        ArrayBufferCreationMode::kInternalized);
335
309
  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
336
  Maybe<bool> mb =
337
1236
      ui->SetPrototype(env->context(), env->buffer_prototype_object());
338
618
  if (mb.FromMaybe(false))
339
618
    return scope.Escape(ui);
340
341
  // Object failed to be created. Clean up resources.
342
  free(data);
343
  return Local<Object>();
344
}
345
346
347
834
MaybeLocal<Object> Copy(Isolate* isolate, const char* data, size_t length) {
348
1668
  EscapableHandleScope handle_scope(isolate);
349
834
  Environment* env = Environment::GetCurrent(isolate);
350
834
  Local<Object> obj;
351
1668
  if (Buffer::Copy(env, data, length).ToLocal(&obj))
352
1668
    return handle_scope.Escape(obj);
353
  return Local<Object>();
354
}
355
356
357
1070
MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
358
2140
  EscapableHandleScope scope(env->isolate());
359
360
  // V8 currently only allows a maximum Typed Array index of max Smi.
361
1070
  if (length > kMaxLength) {
362
    return Local<Object>();
363
  }
364
365
  void* new_data;
366
1070
  if (length > 0) {
367
1033
    CHECK_NE(data, nullptr);
368
1033
    new_data = malloc(length);
369
1033
    if (new_data == nullptr)
370
      return Local<Object>();
371
    memcpy(new_data, data, length);
372
  } else {
373
    new_data = nullptr;
374
  }
375
376
  Local<ArrayBuffer> ab =
377
    ArrayBuffer::New(env->isolate(),
378
        new_data,
379
        length,
380
1070
        ArrayBufferCreationMode::kInternalized);
381
1070
  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
382
  Maybe<bool> mb =
383
4280
      ui->SetPrototype(env->context(), env->buffer_prototype_object());
384
2140
  if (mb.FromMaybe(false))
385
2140
    return scope.Escape(ui);
386
387
  // Object failed to be created. Clean up resources.
388
  free(new_data);
389
  return Local<Object>();
390
}
391
392
393
12
MaybeLocal<Object> New(Isolate* isolate,
394
                       char* data,
395
                       size_t length,
396
                       FreeCallback callback,
397
                       void* hint) {
398
24
  EscapableHandleScope handle_scope(isolate);
399
12
  Environment* env = Environment::GetCurrent(isolate);
400
12
  Local<Object> obj;
401
24
  if (Buffer::New(env, data, length, callback, hint).ToLocal(&obj))
402
24
    return handle_scope.Escape(obj);
403
  return Local<Object>();
404
}
405
406
407
12
MaybeLocal<Object> New(Environment* env,
408
                       char* data,
409
                       size_t length,
410
                       FreeCallback callback,
411
                       void* hint) {
412
24
  EscapableHandleScope scope(env->isolate());
413
414
12
  if (length > kMaxLength) {
415
    return Local<Object>();
416
  }
417
418
12
  Local<ArrayBuffer> ab = ArrayBuffer::New(env->isolate(), data, length);
419
  // `Neuter()`ing is required here to prevent materialization of the backing
420
  // store in v8. `nullptr` buffers are not writable, so this is semantically
421
  // correct.
422
12
  if (data == nullptr)
423
1
    ab->Neuter();
424
12
  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
425
  Maybe<bool> mb =
426
48
      ui->SetPrototype(env->context(), env->buffer_prototype_object());
427
428
24
  if (!mb.FromMaybe(false))
429
    return Local<Object>();
430
431
12
  CallbackInfo::New(env->isolate(), ab, callback, data, hint);
432
24
  return scope.Escape(ui);
433
}
434
435
436
1644
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
437
3288
  EscapableHandleScope handle_scope(isolate);
438
1644
  Environment* env = Environment::GetCurrent(isolate);
439
1644
  Local<Object> obj;
440
3288
  if (Buffer::New(env, data, length).ToLocal(&obj))
441
3288
    return handle_scope.Escape(obj);
442
  return Local<Object>();
443
}
444
445
446
17044
MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
447
34088
  EscapableHandleScope scope(env->isolate());
448
449
17044
  if (length > 0) {
450
17026
    CHECK_NE(data, nullptr);
451
17026
    CHECK(length <= kMaxLength);
452
  }
453
454
  Local<ArrayBuffer> ab =
455
      ArrayBuffer::New(env->isolate(),
456
                       data,
457
                       length,
458
17044
                       ArrayBufferCreationMode::kInternalized);
459
17044
  Local<Uint8Array> ui = Uint8Array::New(ab, 0, length);
460
  Maybe<bool> mb =
461
68176
      ui->SetPrototype(env->context(), env->buffer_prototype_object());
462
34088
  if (mb.FromMaybe(false))
463
34088
    return scope.Escape(ui);
464
  return Local<Object>();
465
}
466
467
468
1644
void CreateFromString(const FunctionCallbackInfo<Value>& args) {
469
3288
  CHECK(args[0]->IsString());
470
3288
  CHECK(args[1]->IsString());
471
472
8220
  enum encoding enc = ParseEncoding(args.GetIsolate(),
473
                                    args[1].As<String>(),
474
1644
                                    UTF8);
475
1644
  Local<Object> buf;
476
6576
  if (New(args.GetIsolate(), args[0].As<String>(), enc).ToLocal(&buf))
477
1644
    args.GetReturnValue().Set(buf);
478
1644
}
479
480
481
template <encoding encoding>
482
22545
void StringSlice(const FunctionCallbackInfo<Value>& args) {
483
22545
  Environment* env = Environment::GetCurrent(args);
484
22545
  Isolate* isolate = env->isolate();
485
486
45146
  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
487
90180
  SPREAD_ARG(args.This(), ts_obj);
488
489
22545
  if (ts_obj_length == 0)
490
112
    return args.GetReturnValue().SetEmptyString();
491
492
89956
  SLICE_START_END(args[0], args[1], ts_obj_length)
493
494
67467
  args.GetReturnValue().Set(
495
      StringBytes::Encode(isolate, ts_obj_data + start, length, encoding));
496
}
497
498
499
template <>
500
2673
void StringSlice<UCS2>(const FunctionCallbackInfo<Value>& args) {
501
2673
  Environment* env = Environment::GetCurrent(args);
502
503
5346
  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
504
10692
  SPREAD_ARG(args.This(), ts_obj);
505
506
2673
  if (ts_obj_length == 0)
507
    return args.GetReturnValue().SetEmptyString();
508
509
10692
  SLICE_START_END(args[0], args[1], ts_obj_length)
510
2673
  length /= 2;
511
512
2673
  const char* data = ts_obj_data + start;
513
  const uint16_t* buf;
514
2673
  bool release = false;
515
516
  // Node's "ucs2" encoding expects LE character data inside a Buffer, so we
517
  // need to reorder on BE platforms.  See http://nodejs.org/api/buffer.html
518
  // regarding Node's "ucs2" encoding specification.
519
2673
  const bool aligned = (reinterpret_cast<uintptr_t>(data) % sizeof(*buf) == 0);
520
2673
  if (IsLittleEndian() && !aligned) {
521
    // Make a copy to avoid unaligned accesses in v8::String::NewFromTwoByte().
522
    // This applies ONLY to little endian platforms, as misalignment will be
523
    // handled by a byte-swapping operation in StringBytes::Encode on
524
    // big endian platforms.
525
    uint16_t* copy = new uint16_t[length];
526
    for (size_t i = 0, k = 0; i < length; i += 1, k += 2) {
527
      // Assumes that the input is little endian.
528
      const uint8_t lo = static_cast<uint8_t>(data[k + 0]);
529
      const uint8_t hi = static_cast<uint8_t>(data[k + 1]);
530
      copy[i] = lo | hi << 8;
531
    }
532
    buf = copy;
533
    release = true;
534
  } else {
535
    buf = reinterpret_cast<const uint16_t*>(data);
536
  }
537
538
8019
  args.GetReturnValue().Set(StringBytes::Encode(env->isolate(), buf, length));
539
540
2673
  if (release)
541
    delete[] buf;
542
}
543
544
545
83
void Latin1Slice(const FunctionCallbackInfo<Value>& args) {
546
83
  StringSlice<LATIN1>(args);
547
83
}
548
549
550
4337
void AsciiSlice(const FunctionCallbackInfo<Value>& args) {
551
4337
  StringSlice<ASCII>(args);
552
4337
}
553
554
555
17413
void Utf8Slice(const FunctionCallbackInfo<Value>& args) {
556
17413
  StringSlice<UTF8>(args);
557
17413
}
558
559
560
2673
void Ucs2Slice(const FunctionCallbackInfo<Value>& args) {
561
2673
  StringSlice<UCS2>(args);
562
2673
}
563
564
565
536
void HexSlice(const FunctionCallbackInfo<Value>& args) {
566
536
  StringSlice<HEX>(args);
567
536
}
568
569
570
176
void Base64Slice(const FunctionCallbackInfo<Value>& args) {
571
176
  StringSlice<BASE64>(args);
572
176
}
573
574
575
// bytesCopied = buffer.copy(target[, targetStart][, sourceStart][, sourceEnd]);
576
268439
void Copy(const FunctionCallbackInfo<Value> &args) {
577
268439
  Environment* env = Environment::GetCurrent(args);
578
579
536900
  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
580
536878
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
581
536874
  Local<Object> target_obj = args[0].As<Object>();
582
1073748
  SPREAD_ARG(args.This(), ts_obj);
583
805311
  SPREAD_ARG(target_obj, target);
584
585
  size_t target_start;
586
  size_t source_start;
587
  size_t source_end;
588
589
268437
  CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &target_start));
590
268437
  CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &source_start));
591
268435
  CHECK_NOT_OOB(ParseArrayIndex(args[3], ts_obj_length, &source_end));
592
593
  // Copy 0 bytes; we're done
594
268433
  if (target_start >= target_length || source_start >= source_end)
595
30
    return args.GetReturnValue().Set(0);
596
597
268418
  if (source_start > ts_obj_length)
598
    return env->ThrowRangeError("out of range index");
599
600
268417
  if (source_end - source_start > target_length - target_start)
601
6
    source_end = source_start + target_length - target_start;
602
603
268417
  uint32_t to_copy = MIN(MIN(source_end - source_start,
604
                             target_length - target_start),
605
                             ts_obj_length - source_start);
606
607
536834
  memmove(target_data + target_start, ts_obj_data + source_start, to_copy);
608
536834
  args.GetReturnValue().Set(to_copy);
609
}
610
611
612
869
void Fill(const FunctionCallbackInfo<Value>& args) {
613
869
  Environment* env = Environment::GetCurrent(args);
614
615
2479
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
616
3476
  SPREAD_ARG(args[0], ts_obj);
617
618
869
  size_t start = args[2]->Uint32Value();
619
869
  size_t end = args[3]->Uint32Value();
620
869
  size_t fill_length = end - start;
621
869
  Local<String> str_obj;
622
  size_t str_length;
623
  enum encoding enc;
624
869
  CHECK(fill_length + start <= ts_obj_length);
625
626
  // First check if Buffer has been passed.
627
1738
  if (Buffer::HasInstance(args[1])) {
628
24
    SPREAD_ARG(args[1], fill_obj);
629
6
    str_length = fill_obj_length;
630
12
    memcpy(ts_obj_data + start, fill_obj_data, MIN(str_length, fill_length));
631
    goto start_fill;
632
  }
633
634
  // Then coerce everything that's not a string.
635
1726
  if (!args[1]->IsString()) {
636
713
    int value = args[1]->Uint32Value() & 255;
637
713
    memset(ts_obj_data + start, value, fill_length);
638
    return;
639
  }
640
641
300
  str_obj = args[1]->ToString(env->isolate());
642
150
  enc = ParseEncoding(env->isolate(), args[4], UTF8);
643
  str_length =
644
60
      enc == UTF8 ? str_obj->Utf8Length() :
645
210
      enc == UCS2 ? str_obj->Length() * sizeof(uint16_t) : str_obj->Length();
646
647
150
  if (enc == HEX && str_length  % 2 != 0)
648
    return env->ThrowTypeError("Invalid hex string");
649
650
149
  if (str_length == 0)
651
    return;
652
653
  // Can't use StringBytes::Write() in all cases. For example if attempting
654
  // to write a two byte character into a one byte Buffer.
655
149
  if (enc == UTF8) {
656
120
    node::Utf8Value str(env->isolate(), args[1]);
657
120
    memcpy(ts_obj_data + start, *str, MIN(str_length, fill_length));
658
659
89
  } else if (enc == UCS2) {
660
66
    node::TwoByteValue str(env->isolate(), args[1]);
661
66
    memcpy(ts_obj_data + start, *str, MIN(str_length, fill_length));
662
663
  } else {
664
    // Write initial String to Buffer, then use that memory to copy remainder
665
    // of string. Correct the string length for cases like HEX where less than
666
    // the total string length is written.
667
112
    str_length = StringBytes::Write(env->isolate(),
668
                                    ts_obj_data + start,
669
                                    fill_length,
670
                                    str_obj,
671
                                    enc,
672
56
                                    nullptr);
673
    // This check is also needed in case Write() returns that no bytes could
674
    // be written.
675
    // TODO(trevnorris): Should this throw? Because of the string length was
676
    // greater than 0 but couldn't be written then the string was invalid.
677
56
    if (str_length == 0)
678
      return;
679
  }
680
681
 start_fill:
682
683
154
  if (str_length >= fill_length)
684
    return;
685
686
687
128
  size_t in_there = str_length;
688
128
  char* ptr = ts_obj_data + start + str_length;
689
690
546
  while (in_there < fill_length - in_there) {
691
418
    memcpy(ptr, ts_obj_data + start, in_there);
692
209
    ptr += in_there;
693
209
    in_there *= 2;
694
  }
695
696
128
  if (in_there < fill_length) {
697
128
    memcpy(ptr, ts_obj_data + start, fill_length - in_there);
698
  }
699
}
700
701
702
template <encoding encoding>
703
26853
void StringWrite(const FunctionCallbackInfo<Value>& args) {
704
26853
  Environment* env = Environment::GetCurrent(args);
705
706
53709
  THROW_AND_RETURN_UNLESS_BUFFER(env, args.This());
707
107412
  SPREAD_ARG(args.This(), ts_obj);
708
709
53706
  if (!args[0]->IsString())
710
    return env->ThrowTypeError("Argument must be a string");
711
712
53706
  Local<String> str = args[0]->ToString(env->isolate());
713
714
384
  if (encoding == HEX && str->Length() % 2 != 0)
715
    return env->ThrowTypeError("Invalid hex string");
716
717
  size_t offset;
718
  size_t max_length;
719
720
26852
  CHECK_NOT_OOB(ParseArrayIndex(args[1], 0, &offset));
721
26852
  if (offset >= ts_obj_length)
722
    return env->ThrowRangeError("Offset is out of bounds");
723
724
53700
  CHECK_NOT_OOB(ParseArrayIndex(args[2], ts_obj_length - offset, &max_length));
725
726
26850
  max_length = MIN(ts_obj_length - offset, max_length);
727
728
26850
  if (max_length == 0)
729
    return args.GetReturnValue().Set(0);
730
731
53700
  uint32_t written = StringBytes::Write(env->isolate(),
732
                                        ts_obj_data + offset,
733
                                        max_length,
734
                                        str,
735
                                        encoding,
736
26850
                                        nullptr);
737
53700
  args.GetReturnValue().Set(written);
738
}
739
740
741
145
void Base64Write(const FunctionCallbackInfo<Value>& args) {
742
145
  StringWrite<BASE64>(args);
743
145
}
744
745
746
191
void Latin1Write(const FunctionCallbackInfo<Value>& args) {
747
191
  StringWrite<LATIN1>(args);
748
191
}
749
750
751
25948
void Utf8Write(const FunctionCallbackInfo<Value>& args) {
752
25948
  StringWrite<UTF8>(args);
753
25948
}
754
755
756
148
void Ucs2Write(const FunctionCallbackInfo<Value>& args) {
757
148
  StringWrite<UCS2>(args);
758
148
}
759
760
761
384
void HexWrite(const FunctionCallbackInfo<Value>& args) {
762
384
  StringWrite<HEX>(args);
763
384
}
764
765
766
37
void AsciiWrite(const FunctionCallbackInfo<Value>& args) {
767
37
  StringWrite<ASCII>(args);
768
37
}
769
770
771
static inline void Swizzle(char* start, unsigned int len) {
772
  char* end = start + len - 1;
773
190
  while (start < end) {
774
144
    char tmp = *start;
775
144
    *start++ = *end;
776
144
    *end-- = tmp;
777
  }
778
}
779
780
781
template <typename T, enum Endianness endianness>
782
60
void ReadFloatGeneric(const FunctionCallbackInfo<Value>& args) {
783
120
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
784
240
  SPREAD_ARG(args[0], ts_obj);
785
786
60
  uint32_t offset = args[1]->Uint32Value();
787
60
  CHECK_LE(offset + sizeof(T), ts_obj_length);
788
789
  union NoAlias {
790
    T val;
791
    char bytes[sizeof(T)];
792
  };
793
794
  union NoAlias na;
795
60
  const char* ptr = static_cast<const char*>(ts_obj_data) + offset;
796
60
  memcpy(na.bytes, ptr, sizeof(na.bytes));
797
60
  if (endianness != GetEndianness())
798
    Swizzle(na.bytes, sizeof(na.bytes));
799
800
180
  args.GetReturnValue().Set(na.val);
801
}
802
803
804
13
void ReadFloatLE(const FunctionCallbackInfo<Value>& args) {
805
13
  ReadFloatGeneric<float, kLittleEndian>(args);
806
13
}
807
808
809
11
void ReadFloatBE(const FunctionCallbackInfo<Value>& args) {
810
11
  ReadFloatGeneric<float, kBigEndian>(args);
811
11
}
812
813
814
19
void ReadDoubleLE(const FunctionCallbackInfo<Value>& args) {
815
19
  ReadFloatGeneric<double, kLittleEndian>(args);
816
19
}
817
818
819
17
void ReadDoubleBE(const FunctionCallbackInfo<Value>& args) {
820
17
  ReadFloatGeneric<double, kBigEndian>(args);
821
17
}
822
823
824
template <typename T, enum Endianness endianness>
825
50
void WriteFloatGeneric(const FunctionCallbackInfo<Value>& args) {
826
50
  Environment* env = Environment::GetCurrent(args);
827
828
50
  bool should_assert = args.Length() < 4;
829
830
50
  if (should_assert) {
831
103
    THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
832
  }
833
834
98
  Local<Uint8Array> ts_obj = args[0].As<Uint8Array>();
835
98
  ArrayBuffer::Contents ts_obj_c = ts_obj->Buffer()->GetContents();
836
49
  const size_t ts_obj_offset = ts_obj->ByteOffset();
837
49
  const size_t ts_obj_length = ts_obj->ByteLength();
838
  char* const ts_obj_data =
839
49
      static_cast<char*>(ts_obj_c.Data()) + ts_obj_offset;
840
49
  if (ts_obj_length > 0)
841
49
    CHECK_NE(ts_obj_data, nullptr);
842
843
196
  T val = args[1]->NumberValue(env->context()).FromMaybe(0);
844
196
  size_t offset = args[2]->IntegerValue(env->context()).FromMaybe(0);
845
846
49
  size_t memcpy_num = sizeof(T);
847
848
49
  if (should_assert) {
849
45
    CHECK_NOT_OOB(offset + memcpy_num >= memcpy_num);
850
45
    CHECK_NOT_OOB(offset + memcpy_num <= ts_obj_length);
851
  }
852
853
39
  if (offset + memcpy_num > ts_obj_length)
854
4
    memcpy_num = ts_obj_length - offset;
855
856
  union NoAlias {
857
    T val;
858
    char bytes[sizeof(T)];
859
  };
860
861
39
  union NoAlias na = { val };
862
39
  char* ptr = static_cast<char*>(ts_obj_data) + offset;
863
39
  if (endianness != GetEndianness())
864
    Swizzle(na.bytes, sizeof(na.bytes));
865
39
  memcpy(ptr, na.bytes, memcpy_num);
866
}
867
868
869
19
void WriteFloatLE(const FunctionCallbackInfo<Value>& args) {
870
19
  WriteFloatGeneric<float, kLittleEndian>(args);
871
19
}
872
873
874
9
void WriteFloatBE(const FunctionCallbackInfo<Value>& args) {
875
9
  WriteFloatGeneric<float, kBigEndian>(args);
876
9
}
877
878
879
13
void WriteDoubleLE(const FunctionCallbackInfo<Value>& args) {
880
13
  WriteFloatGeneric<double, kLittleEndian>(args);
881
13
}
882
883
884
9
void WriteDoubleBE(const FunctionCallbackInfo<Value>& args) {
885
9
  WriteFloatGeneric<double, kBigEndian>(args);
886
9
}
887
888
889
30502
void ByteLengthUtf8(const FunctionCallbackInfo<Value> &args) {
890
61004
  CHECK(args[0]->IsString());
891
892
  // Fast case: avoid StringBytes on UTF8 string. Jump to v8.
893
122008
  args.GetReturnValue().Set(args[0].As<String>()->Utf8Length());
894
30502
}
895
896
// Normalize val to be an integer in the range of [1, -1] since
897
// implementations of memcmp() can vary by platform.
898
static int normalizeCompareVal(int val, size_t a_length, size_t b_length) {
899
310
  if (val == 0) {
900
290
    if (a_length > b_length)
901
      return 1;
902
282
    else if (a_length < b_length)
903
      return -1;
904
  } else {
905
20
    if (val > 0)
906
      return 1;
907
    else
908
      return -1;
909
  }
910
  return val;
911
}
912
913
21
void CompareOffset(const FunctionCallbackInfo<Value> &args) {
914
21
  Environment* env = Environment::GetCurrent(args);
915
916
42
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
917
42
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
918
84
  SPREAD_ARG(args[0], ts_obj);
919
84
  SPREAD_ARG(args[1], target);
920
921
  size_t target_start;
922
  size_t source_start;
923
  size_t source_end;
924
  size_t target_end;
925
926
21
  CHECK_NOT_OOB(ParseArrayIndex(args[2], 0, &target_start));
927
21
  CHECK_NOT_OOB(ParseArrayIndex(args[3], 0, &source_start));
928
21
  CHECK_NOT_OOB(ParseArrayIndex(args[4], target_length, &target_end));
929
21
  CHECK_NOT_OOB(ParseArrayIndex(args[5], ts_obj_length, &source_end));
930
931
21
  if (source_start > ts_obj_length)
932
    return env->ThrowRangeError("out of range index");
933
21
  if (target_start > target_length)
934
    return env->ThrowRangeError("out of range index");
935
936
21
  CHECK_LE(source_start, source_end);
937
21
  CHECK_LE(target_start, target_end);
938
939
21
  size_t to_cmp = MIN(MIN(source_end - source_start,
940
                      target_end - target_start),
941
                      ts_obj_length - source_start);
942
943
42
  int val = normalizeCompareVal(to_cmp > 0 ?
944
21
                                  memcmp(ts_obj_data + source_start,
945
                                         target_data + target_start,
946
                                         to_cmp) : 0,
947
                                source_end - source_start,
948
21
                                target_end - target_start);
949
950
42
  args.GetReturnValue().Set(val);
951
}
952
953
291
void Compare(const FunctionCallbackInfo<Value> &args) {
954
291
  Environment* env = Environment::GetCurrent(args);
955
956
584
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
957
578
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[1]);
958
1156
  SPREAD_ARG(args[0], obj_a);
959
1156
  SPREAD_ARG(args[1], obj_b);
960
961
289
  size_t cmp_length = MIN(obj_a_length, obj_b_length);
962
963
289
  int val = normalizeCompareVal(cmp_length > 0 ?
964
                                memcmp(obj_a_data, obj_b_data, cmp_length) : 0,
965
289
                                obj_a_length, obj_b_length);
966
578
  args.GetReturnValue().Set(val);
967
}
968
969
970
// Computes the offset for starting an indexOf or lastIndexOf search.
971
// Returns either a valid offset in [0...<length - 1>], ie inside the Buffer,
972
// or -1 to signal that there is no possible match.
973
int64_t IndexOfOffset(size_t length, int64_t offset_i64, bool is_forward) {
974
1106
  int64_t length_i64 = static_cast<int64_t>(length);
975
1106
  if (length_i64 == 0) {
976
    // Empty buffer, no match.
977
    return -1;
978
  }
979
1106
  if (offset_i64 < 0) {
980
77
    if (offset_i64 + length_i64 >= 0) {
981
      // Negative offsets count backwards from the end of the buffer.
982
      return length_i64 + offset_i64;
983
18
    } else if (is_forward) {
984
      // indexOf from before the start of the buffer: search the whole buffer.
985
      return 0;
986
    } else {
987
      // lastIndexOf from before the start of the buffer: no match.
988
      return -1;
989
    }
990
  } else {
991
1029
    if (offset_i64 < length_i64) {
992
      // Valid positive offset.
993
      return offset_i64;
994
25
    } else if (is_forward) {
995
      // indexOf from past the end of the buffer: no match.
996
      return -1;
997
    } else {
998
      // lastIndexOf from past the end of the buffer: search the whole buffer.
999
11
      return length_i64 - 1;
1000
    }
1001
  }
1002
}
1003
1004
861
void IndexOfString(const FunctionCallbackInfo<Value>& args) {
1005
1722
  ASSERT(args[1]->IsString());
1006
861
  ASSERT(args[2]->IsNumber());
1007
861
  ASSERT(args[4]->IsBoolean());
1008
1009
1722
  enum encoding enc = ParseEncoding(args.GetIsolate(),
1010
                                    args[3],
1011
861
                                    UTF8);
1012
1013
1755
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
1014
3444
  SPREAD_ARG(args[0], ts_obj);
1015
1016
1722
  Local<String> needle = args[1].As<String>();
1017
861
  int64_t offset_i64 = args[2]->IntegerValue();
1018
861
  bool is_forward = args[4]->IsTrue();
1019
1020
861
  const char* haystack = ts_obj_data;
1021
  // Round down to the nearest multiple of 2 in case of UCS2.
1022
  const size_t haystack_length = (enc == UCS2) ?
1023
861
      ts_obj_length &~ 1 : ts_obj_length;  // NOLINT(whitespace/operators)
1024
1025
  const size_t needle_length =
1026
1722
      StringBytes::Size(args.GetIsolate(), needle, enc);
1027
1028
861
  if (needle_length == 0 || haystack_length == 0) {
1029
16
    return args.GetReturnValue().Set(-1);
1030
  }
1031
1032
1706
  int64_t opt_offset = IndexOfOffset(haystack_length, offset_i64, is_forward);
1033
853
  if (opt_offset <= -1) {
1034
18
    return args.GetReturnValue().Set(-1);
1035
  }
1036
844
  size_t offset = static_cast<size_t>(opt_offset);
1037
844
  CHECK_LT(offset, haystack_length);
1038
844
  if ((is_forward && needle_length + offset > haystack_length) ||
1039
      needle_length > haystack_length) {
1040
32
    return args.GetReturnValue().Set(-1);
1041
  }
1042
1043
828
  size_t result = haystack_length;
1044
1045
828
  if (enc == UCS2) {
1046
170
    String::Value needle_value(needle);
1047
85
    if (*needle_value == nullptr)
1048
      return args.GetReturnValue().Set(-1);
1049
1050
85
    if (haystack_length < 2 || needle_value.length() < 1) {
1051
      return args.GetReturnValue().Set(-1);
1052
    }
1053
1054
85
    if (IsBigEndian()) {
1055
      StringBytes::InlineDecoder decoder;
1056
      decoder.Decode(Environment::GetCurrent(args), needle, args[3], UCS2);
1057
      const uint16_t* decoded_string =
1058
          reinterpret_cast<const uint16_t*>(decoder.out());
1059
1060
      if (decoded_string == nullptr)
1061
        return args.GetReturnValue().Set(-1);
1062
1063
      result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
1064
                            haystack_length / 2,
1065
                            decoded_string,
1066
                            decoder.size() / 2,
1067
                            offset / 2,
1068
                            is_forward);
1069
    } else {
1070
255
      result = SearchString(reinterpret_cast<const uint16_t*>(haystack),
1071
                            haystack_length / 2,
1072
85
                            reinterpret_cast<const uint16_t*>(*needle_value),
1073
85
                            needle_value.length(),
1074
                            offset / 2,
1075
85
                            is_forward);
1076
    }
1077
85
    result *= 2;
1078
743
  } else if (enc == UTF8) {
1079
1462
    String::Utf8Value needle_value(needle);
1080
731
    if (*needle_value == nullptr)
1081
      return args.GetReturnValue().Set(-1);
1082
1083
731
    result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
1084
                          haystack_length,
1085
731
                          reinterpret_cast<const uint8_t*>(*needle_value),
1086
                          needle_length,
1087
                          offset,
1088
731
                          is_forward);
1089
12
  } else if (enc == LATIN1) {
1090
12
    uint8_t* needle_data = static_cast<uint8_t*>(malloc(needle_length));
1091
12
    if (needle_data == nullptr) {
1092
      return args.GetReturnValue().Set(-1);
1093
    }
1094
12
    needle->WriteOneByte(
1095
12
        needle_data, 0, needle_length, String::NO_NULL_TERMINATION);
1096
1097
12
    result = SearchString(reinterpret_cast<const uint8_t*>(haystack),
1098
                          haystack_length,
1099
                          needle_data,
1100
                          needle_length,
1101
                          offset,
1102
12
                          is_forward);
1103
12
    free(needle_data);
1104
  }
1105
1106
1656
  args.GetReturnValue().Set(
1107
828
      result == haystack_length ? -1 : static_cast<int>(result));
1108
}
1109
1110
215
void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
1111
215
  ASSERT(args[1]->IsObject());
1112
215
  ASSERT(args[2]->IsNumber());
1113
215
  ASSERT(args[4]->IsBoolean());
1114
1115
430
  enum encoding enc = ParseEncoding(args.GetIsolate(),
1116
                                    args[3],
1117
215
                                    UTF8);
1118
1119
460
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
1120
430
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[1]);
1121
860
  SPREAD_ARG(args[0], ts_obj);
1122
860
  SPREAD_ARG(args[1], buf);
1123
215
  int64_t offset_i64 = args[2]->IntegerValue();
1124
215
  bool is_forward = args[4]->IsTrue();
1125
1126
215
  const char* haystack = ts_obj_data;
1127
215
  const size_t haystack_length = ts_obj_length;
1128
215
  const char* needle = buf_data;
1129
215
  const size_t needle_length = buf_length;
1130
1131
215
  if (needle_length == 0 || haystack_length == 0) {
1132
24
    return args.GetReturnValue().Set(-1);
1133
  }
1134
1135
406
  int64_t opt_offset = IndexOfOffset(haystack_length, offset_i64, is_forward);
1136
203
  if (opt_offset <= -1) {
1137
18
    return args.GetReturnValue().Set(-1);
1138
  }
1139
194
  size_t offset = static_cast<size_t>(opt_offset);
1140
194
  CHECK_LT(offset, haystack_length);
1141
194
  if ((is_forward && needle_length + offset > haystack_length) ||
1142
      needle_length > haystack_length) {
1143
14
    return args.GetReturnValue().Set(-1);
1144
  }
1145
1146
187
  size_t result = haystack_length;
1147
1148
187
  if (enc == UCS2) {
1149
58
    if (haystack_length < 2 || needle_length < 2) {
1150
4
      return args.GetReturnValue().Set(-1);
1151
    }
1152
56
    result = SearchString(
1153
        reinterpret_cast<const uint16_t*>(haystack),
1154
        haystack_length / 2,
1155
        reinterpret_cast<const uint16_t*>(needle),
1156
        needle_length / 2,
1157
        offset / 2,
1158
56
        is_forward);
1159
56
    result *= 2;
1160
  } else {
1161
129
    result = SearchString(
1162
        reinterpret_cast<const uint8_t*>(haystack),
1163
        haystack_length,
1164
        reinterpret_cast<const uint8_t*>(needle),
1165
        needle_length,
1166
        offset,
1167
129
        is_forward);
1168
  }
1169
1170
370
  args.GetReturnValue().Set(
1171
185
      result == haystack_length ? -1 : static_cast<int>(result));
1172
}
1173
1174
51
void IndexOfNumber(const FunctionCallbackInfo<Value>& args) {
1175
51
  ASSERT(args[1]->IsNumber());
1176
51
  ASSERT(args[2]->IsNumber());
1177
51
  ASSERT(args[3]->IsBoolean());
1178
1179
107
  THROW_AND_RETURN_UNLESS_BUFFER(Environment::GetCurrent(args), args[0]);
1180
200
  SPREAD_ARG(args[0], ts_obj);
1181
1182
50
  uint32_t needle = args[1]->Uint32Value();
1183
50
  int64_t offset_i64 = args[2]->IntegerValue();
1184
50
  bool is_forward = args[3]->IsTrue();
1185
1186
100
  int64_t opt_offset = IndexOfOffset(ts_obj_length, offset_i64, is_forward);
1187
50
  if (opt_offset <= -1) {
1188
8
    return args.GetReturnValue().Set(-1);
1189
  }
1190
46
  size_t offset = static_cast<size_t>(opt_offset);
1191
46
  CHECK_LT(offset, ts_obj_length);
1192
1193
  const void* ptr;
1194
46
  if (is_forward) {
1195
76
    ptr = memchr(ts_obj_data + offset, needle, ts_obj_length - offset);
1196
  } else {
1197
16
    ptr = node::stringsearch::MemrchrFill(ts_obj_data, needle, offset + 1);
1198
  }
1199
46
  const char* ptr_char = static_cast<const char*>(ptr);
1200
92
  args.GetReturnValue().Set(ptr ? static_cast<int>(ptr_char - ts_obj_data)
1201
46
                                : -1);
1202
}
1203
1204
1205
2
void Swap16(const FunctionCallbackInfo<Value>& args) {
1206
2
  Environment* env = Environment::GetCurrent(args);
1207
4
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1208
8
  SPREAD_ARG(args[0], ts_obj);
1209
1210
2
  CHECK_EQ(ts_obj_length % 2, 0);
1211
1212
2
  int align = reinterpret_cast<uintptr_t>(ts_obj_data) % sizeof(uint16_t);
1213
1214
2
  if (align == 0) {
1215
1
    uint16_t* data16 = reinterpret_cast<uint16_t*>(ts_obj_data);
1216
1
    size_t len16 = ts_obj_length / 2;
1217
513
    for (size_t i = 0; i < len16; i++) {
1218
512
      data16[i] = BSWAP_INTRINSIC_2(data16[i]);
1219
    }
1220
  } else {
1221
2047
    for (size_t i = 0; i < ts_obj_length; i += 2) {
1222
2046
      std::swap(ts_obj_data[i], ts_obj_data[i + 1]);
1223
    }
1224
  }
1225
1226
6
  args.GetReturnValue().Set(args[0]);
1227
}
1228
1229
1230
2
void Swap32(const FunctionCallbackInfo<Value>& args) {
1231
2
  Environment* env = Environment::GetCurrent(args);
1232
4
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1233
8
  SPREAD_ARG(args[0], ts_obj);
1234
1235
2
  CHECK_EQ(ts_obj_length % 4, 0);
1236
1237
2
  int align = reinterpret_cast<uintptr_t>(ts_obj_data) % sizeof(uint32_t);
1238
1239
2
  if (align == 0) {
1240
1
    uint32_t* data32 = reinterpret_cast<uint32_t*>(ts_obj_data);
1241
1
    size_t len32 = ts_obj_length / 4;
1242
257
    for (size_t i = 0; i < len32; i++) {
1243
256
      data32[i] = BSWAP_INTRINSIC_4(data32[i]);
1244
    }
1245
  } else {
1246
1023
    for (size_t i = 0; i < ts_obj_length; i += 4) {
1247
1022
      std::swap(ts_obj_data[i], ts_obj_data[i + 3]);
1248
1022
      std::swap(ts_obj_data[i + 1], ts_obj_data[i + 2]);
1249
    }
1250
  }
1251
1252
6
  args.GetReturnValue().Set(args[0]);
1253
}
1254
1255
1256
2
void Swap64(const FunctionCallbackInfo<Value>& args) {
1257
2
  Environment* env = Environment::GetCurrent(args);
1258
4
  THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
1259
8
  SPREAD_ARG(args[0], ts_obj);
1260
1261
2
  CHECK_EQ(ts_obj_length % 8, 0);
1262
1263
2
  int align = reinterpret_cast<uintptr_t>(ts_obj_data) % sizeof(uint64_t);
1264
1265
2
  if (align == 0) {
1266
1
    uint64_t* data64 = reinterpret_cast<uint64_t*>(ts_obj_data);
1267
1
    size_t len32 = ts_obj_length / 8;
1268
257
    for (size_t i = 0; i < len32; i++) {
1269
256
      data64[i] = BSWAP_INTRINSIC_8(data64[i]);
1270
    }
1271
  } else {
1272
511
    for (size_t i = 0; i < ts_obj_length; i += 8) {
1273
510
      std::swap(ts_obj_data[i], ts_obj_data[i + 7]);
1274
510
      std::swap(ts_obj_data[i + 1], ts_obj_data[i + 6]);
1275
510
      std::swap(ts_obj_data[i + 2], ts_obj_data[i + 5]);
1276
510
      std::swap(ts_obj_data[i + 3], ts_obj_data[i + 4]);
1277
    }
1278
  }
1279
1280
6
  args.GetReturnValue().Set(args[0]);
1281
}
1282
1283
1284
// pass Buffer object to load prototype methods
1285
1561
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
1286
1561
  Environment* env = Environment::GetCurrent(args);
1287
1288
1561
  CHECK(args[0]->IsObject());
1289
3122
  Local<Object> proto = args[0].As<Object>();
1290
1561
  env->set_buffer_prototype_object(proto);
1291
1292
1561
  env->SetMethod(proto, "asciiSlice", AsciiSlice);
1293
1561
  env->SetMethod(proto, "base64Slice", Base64Slice);
1294
1561
  env->SetMethod(proto, "latin1Slice", Latin1Slice);
1295
1561
  env->SetMethod(proto, "hexSlice", HexSlice);
1296
1561
  env->SetMethod(proto, "ucs2Slice", Ucs2Slice);
1297
1561
  env->SetMethod(proto, "utf8Slice", Utf8Slice);
1298
1299
1561
  env->SetMethod(proto, "asciiWrite", AsciiWrite);
1300
1561
  env->SetMethod(proto, "base64Write", Base64Write);
1301
1561
  env->SetMethod(proto, "latin1Write", Latin1Write);
1302
1561
  env->SetMethod(proto, "hexWrite", HexWrite);
1303
1561
  env->SetMethod(proto, "ucs2Write", Ucs2Write);
1304
1561
  env->SetMethod(proto, "utf8Write", Utf8Write);
1305
1306
1561
  env->SetMethod(proto, "copy", Copy);
1307
1308
1561
  if (auto zero_fill_field = env->isolate_data()->zero_fill_field()) {
1309
1561
    CHECK(args[1]->IsObject());
1310
3122
    auto binding_object = args[1].As<Object>();
1311
    auto array_buffer = ArrayBuffer::New(env->isolate(),
1312
                                         zero_fill_field,
1313
1561
                                         sizeof(*zero_fill_field));
1314
1561
    auto name = FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill");
1315
1561
    auto value = Uint32Array::New(array_buffer, 0, 1);
1316
6244
    CHECK(binding_object->Set(env->context(), name, value).FromJust());
1317
  }
1318
1561
}
1319
1320
1321
1561
void Initialize(Local<Object> target,
1322
                Local<Value> unused,
1323
                Local<Context> context) {
1324
1561
  Environment* env = Environment::GetCurrent(context);
1325
1326
1561
  env->SetMethod(target, "setupBufferJS", SetupBufferJS);
1327
1561
  env->SetMethod(target, "createFromString", CreateFromString);
1328
1329
1561
  env->SetMethod(target, "byteLengthUtf8", ByteLengthUtf8);
1330
1561
  env->SetMethod(target, "compare", Compare);
1331
1561
  env->SetMethod(target, "compareOffset", CompareOffset);
1332
1561
  env->SetMethod(target, "fill", Fill);
1333
1561
  env->SetMethod(target, "indexOfBuffer", IndexOfBuffer);
1334
1561
  env->SetMethod(target, "indexOfNumber", IndexOfNumber);
1335
1561
  env->SetMethod(target, "indexOfString", IndexOfString);
1336
1337
1561
  env->SetMethod(target, "readDoubleBE", ReadDoubleBE);
1338
1561
  env->SetMethod(target, "readDoubleLE", ReadDoubleLE);
1339
1561
  env->SetMethod(target, "readFloatBE", ReadFloatBE);
1340
1561
  env->SetMethod(target, "readFloatLE", ReadFloatLE);
1341
1342
1561
  env->SetMethod(target, "writeDoubleBE", WriteDoubleBE);
1343
1561
  env->SetMethod(target, "writeDoubleLE", WriteDoubleLE);
1344
1561
  env->SetMethod(target, "writeFloatBE", WriteFloatBE);
1345
1561
  env->SetMethod(target, "writeFloatLE", WriteFloatLE);
1346
1347
1561
  env->SetMethod(target, "swap16", Swap16);
1348
1561
  env->SetMethod(target, "swap32", Swap32);
1349
1561
  env->SetMethod(target, "swap64", Swap64);
1350
1351
3122
  target->Set(env->context(),
1352
              FIXED_ONE_BYTE_STRING(env->isolate(), "kMaxLength"),
1353
9366
              Integer::NewFromUnsigned(env->isolate(), kMaxLength)).FromJust();
1354
1355
3122
  target->Set(env->context(),
1356
              FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
1357
9366
              Integer::New(env->isolate(), String::kMaxLength)).FromJust();
1358
1561
}
1359
1360
1361
}  // namespace Buffer
1362
}  // namespace node
1363
1364
1566
NODE_MODULE_CONTEXT_AWARE_BUILTIN(buffer, node::Buffer::Initialize)