• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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'use strict';
23
24const {
25  Array,
26  ArrayIsArray,
27  Error,
28  MathFloor,
29  MathMin,
30  MathTrunc,
31  NumberIsNaN,
32  NumberMAX_SAFE_INTEGER,
33  NumberMIN_SAFE_INTEGER,
34  ObjectCreate,
35  ObjectDefineProperties,
36  ObjectDefineProperty,
37  ObjectGetOwnPropertyDescriptor,
38  ObjectGetPrototypeOf,
39  ObjectSetPrototypeOf,
40  SymbolSpecies,
41  SymbolToPrimitive,
42  Uint8Array,
43  Uint8ArrayPrototype,
44} = primordials;
45
46const {
47  byteLengthUtf8,
48  compare: _compare,
49  compareOffset,
50  createFromString,
51  fill: bindingFill,
52  indexOfBuffer,
53  indexOfNumber,
54  indexOfString,
55  swap16: _swap16,
56  swap32: _swap32,
57  swap64: _swap64,
58  kMaxLength,
59  kStringMaxLength,
60  zeroFill: bindingZeroFill
61} = internalBinding('buffer');
62const {
63  getOwnNonIndexProperties,
64  propertyFilter: {
65    ALL_PROPERTIES,
66    ONLY_ENUMERABLE
67  },
68} = internalBinding('util');
69const {
70  customInspectSymbol,
71  isInsideNodeModules,
72  normalizeEncoding,
73  kIsEncodingSymbol
74} = require('internal/util');
75const {
76  isAnyArrayBuffer,
77  isArrayBufferView,
78  isUint8Array
79} = require('internal/util/types');
80const {
81  inspect: utilInspect
82} = require('internal/util/inspect');
83const { encodings } = internalBinding('string_decoder');
84
85const {
86  codes: {
87    ERR_BUFFER_OUT_OF_BOUNDS,
88    ERR_INVALID_ARG_TYPE,
89    ERR_INVALID_ARG_VALUE,
90    ERR_INVALID_BUFFER_SIZE,
91    ERR_INVALID_OPT_VALUE,
92    ERR_OUT_OF_RANGE,
93    ERR_UNKNOWN_ENCODING
94  },
95  hideStackFrames
96} = require('internal/errors');
97const {
98  validateBuffer,
99  validateInt32,
100  validateString
101} = require('internal/validators');
102
103const {
104  FastBuffer,
105  markAsUntransferable,
106  addBufferPrototypeMethods
107} = require('internal/buffer');
108
109const TypedArrayPrototype = ObjectGetPrototypeOf(Uint8ArrayPrototype);
110
111const TypedArrayProto_byteLength =
112      ObjectGetOwnPropertyDescriptor(TypedArrayPrototype,
113                                     'byteLength').get;
114const TypedArrayFill = TypedArrayPrototype.fill;
115
116FastBuffer.prototype.constructor = Buffer;
117Buffer.prototype = FastBuffer.prototype;
118addBufferPrototypeMethods(Buffer.prototype);
119
120const constants = ObjectDefineProperties({}, {
121  MAX_LENGTH: {
122    value: kMaxLength,
123    writable: false,
124    enumerable: true
125  },
126  MAX_STRING_LENGTH: {
127    value: kStringMaxLength,
128    writable: false,
129    enumerable: true
130  }
131});
132
133Buffer.poolSize = 8 * 1024;
134let poolSize, poolOffset, allocPool;
135
136// A toggle used to access the zero fill setting of the array buffer allocator
137// in C++.
138// |zeroFill| can be undefined when running inside an isolate where we
139// do not own the ArrayBuffer allocator.  Zero fill is always on in that case.
140const zeroFill = bindingZeroFill || [0];
141
142const encodingsMap = ObjectCreate(null);
143for (let i = 0; i < encodings.length; ++i)
144  encodingsMap[encodings[i]] = i;
145
146function createUnsafeBuffer(size) {
147  zeroFill[0] = 0;
148  try {
149    return new FastBuffer(size);
150  } finally {
151    zeroFill[0] = 1;
152  }
153}
154
155function createPool() {
156  poolSize = Buffer.poolSize;
157  allocPool = createUnsafeBuffer(poolSize).buffer;
158  markAsUntransferable(allocPool);
159  poolOffset = 0;
160}
161createPool();
162
163function alignPool() {
164  // Ensure aligned slices
165  if (poolOffset & 0x7) {
166    poolOffset |= 0x7;
167    poolOffset++;
168  }
169}
170
171let bufferWarningAlreadyEmitted = false;
172let nodeModulesCheckCounter = 0;
173const bufferWarning = 'Buffer() is deprecated due to security and usability ' +
174                      'issues. Please use the Buffer.alloc(), ' +
175                      'Buffer.allocUnsafe(), or Buffer.from() methods instead.';
176
177function showFlaggedDeprecation() {
178  if (bufferWarningAlreadyEmitted ||
179      ++nodeModulesCheckCounter > 10000 ||
180      (!require('internal/options').getOptionValue('--pending-deprecation') &&
181       isInsideNodeModules())) {
182    // We don't emit a warning, because we either:
183    // - Already did so, or
184    // - Already checked too many times whether a call is coming
185    //   from node_modules and want to stop slowing down things, or
186    // - We aren't running with `--pending-deprecation` enabled,
187    //   and the code is inside `node_modules`.
188    return;
189  }
190
191  process.emitWarning(bufferWarning, 'DeprecationWarning', 'DEP0005');
192  bufferWarningAlreadyEmitted = true;
193}
194
195function toInteger(n, defaultVal) {
196  n = +n;
197  if (!NumberIsNaN(n) &&
198      n >= NumberMIN_SAFE_INTEGER &&
199      n <= NumberMAX_SAFE_INTEGER) {
200    return ((n % 1) === 0 ? n : MathFloor(n));
201  }
202  return defaultVal;
203}
204
205function _copy(source, target, targetStart, sourceStart, sourceEnd) {
206  if (!isUint8Array(source))
207    throw new ERR_INVALID_ARG_TYPE('source', ['Buffer', 'Uint8Array'], source);
208  if (!isUint8Array(target))
209    throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target);
210
211  if (targetStart === undefined) {
212    targetStart = 0;
213  } else {
214    targetStart = toInteger(targetStart, 0);
215    if (targetStart < 0)
216      throw new ERR_OUT_OF_RANGE('targetStart', '>= 0', targetStart);
217  }
218
219  if (sourceStart === undefined) {
220    sourceStart = 0;
221  } else {
222    sourceStart = toInteger(sourceStart, 0);
223    if (sourceStart < 0)
224      throw new ERR_OUT_OF_RANGE('sourceStart', '>= 0', sourceStart);
225  }
226
227  if (sourceEnd === undefined) {
228    sourceEnd = source.length;
229  } else {
230    sourceEnd = toInteger(sourceEnd, 0);
231    if (sourceEnd < 0)
232      throw new ERR_OUT_OF_RANGE('sourceEnd', '>= 0', sourceEnd);
233  }
234
235  if (targetStart >= target.length || sourceStart >= sourceEnd)
236    return 0;
237
238  if (sourceStart > source.length) {
239    throw new ERR_OUT_OF_RANGE('sourceStart',
240                               `<= ${source.length}`,
241                               sourceStart);
242  }
243
244  return _copyActual(source, target, targetStart, sourceStart, sourceEnd);
245}
246
247function _copyActual(source, target, targetStart, sourceStart, sourceEnd) {
248  if (sourceEnd - sourceStart > target.length - targetStart)
249    sourceEnd = sourceStart + target.length - targetStart;
250
251  let nb = sourceEnd - sourceStart;
252  const targetLen = target.length - targetStart;
253  const sourceLen = source.length - sourceStart;
254  if (nb > targetLen)
255    nb = targetLen;
256  if (nb > sourceLen)
257    nb = sourceLen;
258
259  if (sourceStart !== 0 || sourceEnd < source.length)
260    source = new Uint8Array(source.buffer, source.byteOffset + sourceStart, nb);
261
262  target.set(source, targetStart);
263
264  return nb;
265}
266
267/**
268 * The Buffer() constructor is deprecated in documentation and should not be
269 * used moving forward. Rather, developers should use one of the three new
270 * factory APIs: Buffer.from(), Buffer.allocUnsafe() or Buffer.alloc() based on
271 * their specific needs. There is no runtime deprecation because of the extent
272 * to which the Buffer constructor is used in the ecosystem currently -- a
273 * runtime deprecation would introduce too much breakage at this time. It's not
274 * likely that the Buffer constructors would ever actually be removed.
275 * Deprecation Code: DEP0005
276 */
277function Buffer(arg, encodingOrOffset, length) {
278  showFlaggedDeprecation();
279  // Common case.
280  if (typeof arg === 'number') {
281    if (typeof encodingOrOffset === 'string') {
282      throw new ERR_INVALID_ARG_TYPE('string', 'string', arg);
283    }
284    return Buffer.alloc(arg);
285  }
286  return Buffer.from(arg, encodingOrOffset, length);
287}
288
289ObjectDefineProperty(Buffer, SymbolSpecies, {
290  enumerable: false,
291  configurable: true,
292  get() { return FastBuffer; }
293});
294
295/**
296 * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
297 * if value is a number.
298 * Buffer.from(str[, encoding])
299 * Buffer.from(array)
300 * Buffer.from(buffer)
301 * Buffer.from(arrayBuffer[, byteOffset[, length]])
302 */
303Buffer.from = function from(value, encodingOrOffset, length) {
304  if (typeof value === 'string')
305    return fromString(value, encodingOrOffset);
306
307  if (typeof value === 'object' && value !== null) {
308    if (isAnyArrayBuffer(value))
309      return fromArrayBuffer(value, encodingOrOffset, length);
310
311    const valueOf = value.valueOf && value.valueOf();
312    if (valueOf != null &&
313        valueOf !== value &&
314        (typeof valueOf === 'string' || typeof valueOf === 'object')) {
315      return from(valueOf, encodingOrOffset, length);
316    }
317
318    const b = fromObject(value);
319    if (b)
320      return b;
321
322    if (typeof value[SymbolToPrimitive] === 'function') {
323      const primitive = value[SymbolToPrimitive]('string');
324      if (typeof primitive === 'string') {
325        return fromString(primitive, encodingOrOffset);
326      }
327    }
328  }
329
330  throw new ERR_INVALID_ARG_TYPE(
331    'first argument',
332    ['string', 'Buffer', 'ArrayBuffer', 'Array', 'Array-like Object'],
333    value
334  );
335};
336
337// Identical to the built-in %TypedArray%.of(), but avoids using the deprecated
338// Buffer() constructor. Must use arrow function syntax to avoid automatically
339// adding a `prototype` property and making the function a constructor.
340//
341// Refs: https://tc39.github.io/ecma262/#sec-%typedarray%.of
342// Refs: https://esdiscuss.org/topic/isconstructor#content-11
343const of = (...items) => {
344  const newObj = createUnsafeBuffer(items.length);
345  for (let k = 0; k < items.length; k++)
346    newObj[k] = items[k];
347  return newObj;
348};
349Buffer.of = of;
350
351ObjectSetPrototypeOf(Buffer, Uint8Array);
352
353// The 'assertSize' method will remove itself from the callstack when an error
354// occurs. This is done simply to keep the internal details of the
355// implementation from bleeding out to users.
356const assertSize = hideStackFrames((size) => {
357  if (typeof size !== 'number') {
358    throw new ERR_INVALID_ARG_TYPE('size', 'number', size);
359  }
360  if (!(size >= 0 && size <= kMaxLength)) {
361    throw new ERR_INVALID_OPT_VALUE.RangeError('size', size);
362  }
363});
364
365/**
366 * Creates a new filled Buffer instance.
367 * alloc(size[, fill[, encoding]])
368 */
369Buffer.alloc = function alloc(size, fill, encoding) {
370  assertSize(size);
371  if (fill !== undefined && fill !== 0 && size > 0) {
372    const buf = createUnsafeBuffer(size);
373    return _fill(buf, fill, 0, buf.length, encoding);
374  }
375  return new FastBuffer(size);
376};
377
378/**
379 * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer
380 * instance. If `--zero-fill-buffers` is set, will zero-fill the buffer.
381 */
382Buffer.allocUnsafe = function allocUnsafe(size) {
383  assertSize(size);
384  return allocate(size);
385};
386
387/**
388 * Equivalent to SlowBuffer(num), by default creates a non-zero-filled
389 * Buffer instance that is not allocated off the pre-initialized pool.
390 * If `--zero-fill-buffers` is set, will zero-fill the buffer.
391 */
392Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) {
393  assertSize(size);
394  return createUnsafeBuffer(size);
395};
396
397// If --zero-fill-buffers command line argument is set, a zero-filled
398// buffer is returned.
399function SlowBuffer(length) {
400  assertSize(length);
401  return createUnsafeBuffer(length);
402}
403
404ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8ArrayPrototype);
405ObjectSetPrototypeOf(SlowBuffer, Uint8Array);
406
407function allocate(size) {
408  if (size <= 0) {
409    return new FastBuffer();
410  }
411  if (size < (Buffer.poolSize >>> 1)) {
412    if (size > (poolSize - poolOffset))
413      createPool();
414    const b = new FastBuffer(allocPool, poolOffset, size);
415    poolOffset += size;
416    alignPool();
417    return b;
418  }
419  return createUnsafeBuffer(size);
420}
421
422function fromStringFast(string, ops) {
423  const length = ops.byteLength(string);
424
425  if (length >= (Buffer.poolSize >>> 1))
426    return createFromString(string, ops.encodingVal);
427
428  if (length > (poolSize - poolOffset))
429    createPool();
430  let b = new FastBuffer(allocPool, poolOffset, length);
431  const actual = ops.write(b, string, 0, length);
432  if (actual !== length) {
433    // byteLength() may overestimate. That's a rare case, though.
434    b = new FastBuffer(allocPool, poolOffset, actual);
435  }
436  poolOffset += actual;
437  alignPool();
438  return b;
439}
440
441function fromString(string, encoding) {
442  let ops;
443  if (typeof encoding !== 'string' || encoding.length === 0) {
444    if (string.length === 0)
445      return new FastBuffer();
446    ops = encodingOps.utf8;
447    encoding = undefined;
448  } else {
449    ops = getEncodingOps(encoding);
450    if (ops === undefined)
451      throw new ERR_UNKNOWN_ENCODING(encoding);
452    if (string.length === 0)
453      return new FastBuffer();
454  }
455  return fromStringFast(string, ops);
456}
457
458function fromArrayBuffer(obj, byteOffset, length) {
459  // Convert byteOffset to integer
460  if (byteOffset === undefined) {
461    byteOffset = 0;
462  } else {
463    byteOffset = +byteOffset;
464    if (NumberIsNaN(byteOffset))
465      byteOffset = 0;
466  }
467
468  const maxLength = obj.byteLength - byteOffset;
469
470  if (maxLength < 0)
471    throw new ERR_BUFFER_OUT_OF_BOUNDS('offset');
472
473  if (length === undefined) {
474    length = maxLength;
475  } else {
476    // Convert length to non-negative integer.
477    length = +length;
478    if (length > 0) {
479      if (length > maxLength)
480        throw new ERR_BUFFER_OUT_OF_BOUNDS('length');
481    } else {
482      length = 0;
483    }
484  }
485
486  return new FastBuffer(obj, byteOffset, length);
487}
488
489function fromArrayLike(obj) {
490  if (obj.length <= 0)
491    return new FastBuffer();
492  if (obj.length < (Buffer.poolSize >>> 1)) {
493    if (obj.length > (poolSize - poolOffset))
494      createPool();
495    const b = new FastBuffer(allocPool, poolOffset, obj.length);
496    b.set(obj, 0);
497    poolOffset += obj.length;
498    alignPool();
499    return b;
500  }
501  return new FastBuffer(obj);
502}
503
504function fromObject(obj) {
505  if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) {
506    if (typeof obj.length !== 'number') {
507      return new FastBuffer();
508    }
509    return fromArrayLike(obj);
510  }
511
512  if (obj.type === 'Buffer' && ArrayIsArray(obj.data)) {
513    return fromArrayLike(obj.data);
514  }
515}
516
517// Static methods
518
519Buffer.isBuffer = function isBuffer(b) {
520  return b instanceof Buffer;
521};
522
523Buffer.compare = function compare(buf1, buf2) {
524  if (!isUint8Array(buf1)) {
525    throw new ERR_INVALID_ARG_TYPE('buf1', ['Buffer', 'Uint8Array'], buf1);
526  }
527
528  if (!isUint8Array(buf2)) {
529    throw new ERR_INVALID_ARG_TYPE('buf2', ['Buffer', 'Uint8Array'], buf2);
530  }
531
532  if (buf1 === buf2) {
533    return 0;
534  }
535
536  return _compare(buf1, buf2);
537};
538
539Buffer.isEncoding = function isEncoding(encoding) {
540  return typeof encoding === 'string' && encoding.length !== 0 &&
541         normalizeEncoding(encoding) !== undefined;
542};
543Buffer[kIsEncodingSymbol] = Buffer.isEncoding;
544
545Buffer.concat = function concat(list, length) {
546  if (!ArrayIsArray(list)) {
547    throw new ERR_INVALID_ARG_TYPE('list', 'Array', list);
548  }
549
550  if (list.length === 0)
551    return new FastBuffer();
552
553  if (length === undefined) {
554    length = 0;
555    for (let i = 0; i < list.length; i++) {
556      if (list[i].length) {
557        length += list[i].length;
558      }
559    }
560  } else {
561    validateInt32(length, 'length', 0);
562  }
563
564  const buffer = Buffer.allocUnsafe(length);
565  let pos = 0;
566  for (let i = 0; i < list.length; i++) {
567    const buf = list[i];
568    if (!isUint8Array(buf)) {
569      // TODO(BridgeAR): This should not be of type ERR_INVALID_ARG_TYPE.
570      // Instead, find the proper error code for this.
571      throw new ERR_INVALID_ARG_TYPE(
572        `list[${i}]`, ['Buffer', 'Uint8Array'], list[i]);
573    }
574    pos += _copyActual(buf, buffer, pos, 0, buf.length);
575  }
576
577  // Note: `length` is always equal to `buffer.length` at this point
578  if (pos < length) {
579    // Zero-fill the remaining bytes if the specified `length` was more than
580    // the actual total length, i.e. if we have some remaining allocated bytes
581    // there were not initialized.
582    TypedArrayFill.call(buffer, 0, pos, length);
583  }
584
585  return buffer;
586};
587
588function base64ByteLength(str, bytes) {
589  // Handle padding
590  if (str.charCodeAt(bytes - 1) === 0x3D)
591    bytes--;
592  if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3D)
593    bytes--;
594
595  // Base64 ratio: 3/4
596  return (bytes * 3) >>> 2;
597}
598
599const encodingOps = {
600  utf8: {
601    encoding: 'utf8',
602    encodingVal: encodingsMap.utf8,
603    byteLength: byteLengthUtf8,
604    write: (buf, string, offset, len) => buf.utf8Write(string, offset, len),
605    slice: (buf, start, end) => buf.utf8Slice(start, end),
606    indexOf: (buf, val, byteOffset, dir) =>
607      indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir)
608  },
609  ucs2: {
610    encoding: 'ucs2',
611    encodingVal: encodingsMap.utf16le,
612    byteLength: (string) => string.length * 2,
613    write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),
614    slice: (buf, start, end) => buf.ucs2Slice(start, end),
615    indexOf: (buf, val, byteOffset, dir) =>
616      indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir)
617  },
618  utf16le: {
619    encoding: 'utf16le',
620    encodingVal: encodingsMap.utf16le,
621    byteLength: (string) => string.length * 2,
622    write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),
623    slice: (buf, start, end) => buf.ucs2Slice(start, end),
624    indexOf: (buf, val, byteOffset, dir) =>
625      indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir)
626  },
627  latin1: {
628    encoding: 'latin1',
629    encodingVal: encodingsMap.latin1,
630    byteLength: (string) => string.length,
631    write: (buf, string, offset, len) => buf.latin1Write(string, offset, len),
632    slice: (buf, start, end) => buf.latin1Slice(start, end),
633    indexOf: (buf, val, byteOffset, dir) =>
634      indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir)
635  },
636  ascii: {
637    encoding: 'ascii',
638    encodingVal: encodingsMap.ascii,
639    byteLength: (string) => string.length,
640    write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len),
641    slice: (buf, start, end) => buf.asciiSlice(start, end),
642    indexOf: (buf, val, byteOffset, dir) =>
643      indexOfBuffer(buf,
644                    fromStringFast(val, encodingOps.ascii),
645                    byteOffset,
646                    encodingsMap.ascii,
647                    dir)
648  },
649  base64: {
650    encoding: 'base64',
651    encodingVal: encodingsMap.base64,
652    byteLength: (string) => base64ByteLength(string, string.length),
653    write: (buf, string, offset, len) => buf.base64Write(string, offset, len),
654    slice: (buf, start, end) => buf.base64Slice(start, end),
655    indexOf: (buf, val, byteOffset, dir) =>
656      indexOfBuffer(buf,
657                    fromStringFast(val, encodingOps.base64),
658                    byteOffset,
659                    encodingsMap.base64,
660                    dir)
661  },
662  hex: {
663    encoding: 'hex',
664    encodingVal: encodingsMap.hex,
665    byteLength: (string) => string.length >>> 1,
666    write: (buf, string, offset, len) => buf.hexWrite(string, offset, len),
667    slice: (buf, start, end) => buf.hexSlice(start, end),
668    indexOf: (buf, val, byteOffset, dir) =>
669      indexOfBuffer(buf,
670                    fromStringFast(val, encodingOps.hex),
671                    byteOffset,
672                    encodingsMap.hex,
673                    dir)
674  }
675};
676function getEncodingOps(encoding) {
677  encoding += '';
678  switch (encoding.length) {
679    case 4:
680      if (encoding === 'utf8') return encodingOps.utf8;
681      if (encoding === 'ucs2') return encodingOps.ucs2;
682      encoding = encoding.toLowerCase();
683      if (encoding === 'utf8') return encodingOps.utf8;
684      if (encoding === 'ucs2') return encodingOps.ucs2;
685      break;
686    case 5:
687      if (encoding === 'utf-8') return encodingOps.utf8;
688      if (encoding === 'ascii') return encodingOps.ascii;
689      if (encoding === 'ucs-2') return encodingOps.ucs2;
690      encoding = encoding.toLowerCase();
691      if (encoding === 'utf-8') return encodingOps.utf8;
692      if (encoding === 'ascii') return encodingOps.ascii;
693      if (encoding === 'ucs-2') return encodingOps.ucs2;
694      break;
695    case 7:
696      if (encoding === 'utf16le' || encoding.toLowerCase() === 'utf16le')
697        return encodingOps.utf16le;
698      break;
699    case 8:
700      if (encoding === 'utf-16le' || encoding.toLowerCase() === 'utf-16le')
701        return encodingOps.utf16le;
702      break;
703    case 6:
704      if (encoding === 'latin1' || encoding === 'binary')
705        return encodingOps.latin1;
706      if (encoding === 'base64') return encodingOps.base64;
707      encoding = encoding.toLowerCase();
708      if (encoding === 'latin1' || encoding === 'binary')
709        return encodingOps.latin1;
710      if (encoding === 'base64') return encodingOps.base64;
711      break;
712    case 3:
713      if (encoding === 'hex' || encoding.toLowerCase() === 'hex')
714        return encodingOps.hex;
715      break;
716  }
717}
718
719function byteLength(string, encoding) {
720  if (typeof string !== 'string') {
721    if (isArrayBufferView(string) || isAnyArrayBuffer(string)) {
722      return string.byteLength;
723    }
724
725    throw new ERR_INVALID_ARG_TYPE(
726      'string', ['string', 'Buffer', 'ArrayBuffer'], string
727    );
728  }
729
730  const len = string.length;
731  const mustMatch = (arguments.length > 2 && arguments[2] === true);
732  if (!mustMatch && len === 0)
733    return 0;
734
735  if (!encoding)
736    return (mustMatch ? -1 : byteLengthUtf8(string));
737
738  const ops = getEncodingOps(encoding);
739  if (ops === undefined)
740    return (mustMatch ? -1 : byteLengthUtf8(string));
741  return ops.byteLength(string);
742}
743
744Buffer.byteLength = byteLength;
745
746// For backwards compatibility.
747ObjectDefineProperty(Buffer.prototype, 'parent', {
748  enumerable: true,
749  get() {
750    if (!(this instanceof Buffer))
751      return undefined;
752    return this.buffer;
753  }
754});
755ObjectDefineProperty(Buffer.prototype, 'offset', {
756  enumerable: true,
757  get() {
758    if (!(this instanceof Buffer))
759      return undefined;
760    return this.byteOffset;
761  }
762});
763
764Buffer.prototype.copy =
765  function copy(target, targetStart, sourceStart, sourceEnd) {
766    return _copy(this, target, targetStart, sourceStart, sourceEnd);
767  };
768
769// No need to verify that "buf.length <= MAX_UINT32" since it's a read-only
770// property of a typed array.
771// This behaves neither like String nor Uint8Array in that we set start/end
772// to their upper/lower bounds if the value passed is out of range.
773Buffer.prototype.toString = function toString(encoding, start, end) {
774  if (arguments.length === 0) {
775    return this.utf8Slice(0, this.length);
776  }
777
778  const len = this.length;
779
780  if (start <= 0)
781    start = 0;
782  else if (start >= len)
783    return '';
784  else
785    start |= 0;
786
787  if (end === undefined || end > len)
788    end = len;
789  else
790    end |= 0;
791
792  if (end <= start)
793    return '';
794
795  if (encoding === undefined)
796    return this.utf8Slice(start, end);
797
798  const ops = getEncodingOps(encoding);
799  if (ops === undefined)
800    throw new ERR_UNKNOWN_ENCODING(encoding);
801
802  return ops.slice(this, start, end);
803};
804
805Buffer.prototype.equals = function equals(otherBuffer) {
806  if (!isUint8Array(otherBuffer)) {
807    throw new ERR_INVALID_ARG_TYPE(
808      'otherBuffer', ['Buffer', 'Uint8Array'], otherBuffer);
809  }
810
811  if (this === otherBuffer)
812    return true;
813
814  if (this.byteLength !== otherBuffer.byteLength)
815    return false;
816
817  return this.byteLength === 0 || _compare(this, otherBuffer) === 0;
818};
819
820let INSPECT_MAX_BYTES = 50;
821// Override how buffers are presented by util.inspect().
822Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) {
823  const max = INSPECT_MAX_BYTES;
824  const actualMax = MathMin(max, this.length);
825  const remaining = this.length - max;
826  let str = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();
827  if (remaining > 0)
828    str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
829  // Inspect special properties as well, if possible.
830  if (ctx) {
831    let extras = false;
832    const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
833    const obj = getOwnNonIndexProperties(this, filter).reduce((obj, key) => {
834      extras = true;
835      obj[key] = this[key];
836      return obj;
837    }, ObjectCreate(null));
838    if (extras) {
839      if (this.length !== 0)
840        str += ', ';
841      // '[Object: null prototype] {'.length === 26
842      // This is guarded with a test.
843      str += utilInspect(obj, {
844        ...ctx,
845        breakLength: Infinity,
846        compact: true
847      }).slice(27, -2);
848    }
849  }
850  return `<${this.constructor.name} ${str}>`;
851};
852Buffer.prototype.inspect = Buffer.prototype[customInspectSymbol];
853
854Buffer.prototype.compare = function compare(target,
855                                            targetStart,
856                                            targetEnd,
857                                            sourceStart,
858                                            sourceEnd) {
859  if (!isUint8Array(target)) {
860    throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target);
861  }
862  if (arguments.length === 1)
863    return _compare(this, target);
864
865  if (targetStart === undefined)
866    targetStart = 0;
867  else
868    validateInt32(targetStart, 'targetStart', 0);
869
870  if (targetEnd === undefined)
871    targetEnd = target.length;
872  else
873    validateInt32(targetEnd, 'targetEnd', 0, target.length);
874
875  if (sourceStart === undefined)
876    sourceStart = 0;
877  else
878    validateInt32(sourceStart, 'sourceStart', 0);
879
880  if (sourceEnd === undefined)
881    sourceEnd = this.length;
882  else
883    validateInt32(sourceEnd, 'sourceEnd', 0, this.length);
884
885  if (sourceStart >= sourceEnd)
886    return (targetStart >= targetEnd ? 0 : -1);
887  if (targetStart >= targetEnd)
888    return 1;
889
890  return compareOffset(this, target, targetStart, sourceStart, targetEnd,
891                       sourceEnd);
892};
893
894// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
895// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
896//
897// Arguments:
898// - buffer - a Buffer to search
899// - val - a string, Buffer, or number
900// - byteOffset - an index into `buffer`; will be clamped to an int32
901// - encoding - an optional encoding, relevant if val is a string
902// - dir - true for indexOf, false for lastIndexOf
903function bidirectionalIndexOf(buffer, val, byteOffset, encoding, dir) {
904  validateBuffer(buffer);
905
906  if (typeof byteOffset === 'string') {
907    encoding = byteOffset;
908    byteOffset = undefined;
909  } else if (byteOffset > 0x7fffffff) {
910    byteOffset = 0x7fffffff;
911  } else if (byteOffset < -0x80000000) {
912    byteOffset = -0x80000000;
913  }
914  // Coerce to Number. Values like null and [] become 0.
915  byteOffset = +byteOffset;
916  // If the offset is undefined, "foo", {}, coerces to NaN, search whole buffer.
917  if (NumberIsNaN(byteOffset)) {
918    byteOffset = dir ? 0 : (buffer.length || buffer.byteLength);
919  }
920  dir = !!dir;  // Cast to bool.
921
922  if (typeof val === 'number')
923    return indexOfNumber(buffer, val >>> 0, byteOffset, dir);
924
925  let ops;
926  if (encoding === undefined)
927    ops = encodingOps.utf8;
928  else
929    ops = getEncodingOps(encoding);
930
931  if (typeof val === 'string') {
932    if (ops === undefined)
933      throw new ERR_UNKNOWN_ENCODING(encoding);
934    return ops.indexOf(buffer, val, byteOffset, dir);
935  }
936
937  if (isUint8Array(val)) {
938    const encodingVal =
939      (ops === undefined ? encodingsMap.utf8 : ops.encodingVal);
940    return indexOfBuffer(buffer, val, byteOffset, encodingVal, dir);
941  }
942
943  throw new ERR_INVALID_ARG_TYPE(
944    'value', ['number', 'string', 'Buffer', 'Uint8Array'], val
945  );
946}
947
948Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {
949  return bidirectionalIndexOf(this, val, byteOffset, encoding, true);
950};
951
952Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {
953  return bidirectionalIndexOf(this, val, byteOffset, encoding, false);
954};
955
956Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
957  return this.indexOf(val, byteOffset, encoding) !== -1;
958};
959
960// Usage:
961//    buffer.fill(number[, offset[, end]])
962//    buffer.fill(buffer[, offset[, end]])
963//    buffer.fill(string[, offset[, end]][, encoding])
964Buffer.prototype.fill = function fill(value, offset, end, encoding) {
965  return _fill(this, value, offset, end, encoding);
966};
967
968function _fill(buf, value, offset, end, encoding) {
969  if (typeof value === 'string') {
970    if (offset === undefined || typeof offset === 'string') {
971      encoding = offset;
972      offset = 0;
973      end = buf.length;
974    } else if (typeof end === 'string') {
975      encoding = end;
976      end = buf.length;
977    }
978
979    const normalizedEncoding = normalizeEncoding(encoding);
980    if (normalizedEncoding === undefined) {
981      validateString(encoding, 'encoding');
982      throw new ERR_UNKNOWN_ENCODING(encoding);
983    }
984
985    if (value.length === 0) {
986      // If value === '' default to zero.
987      value = 0;
988    } else if (value.length === 1) {
989      // Fast path: If `value` fits into a single byte, use that numeric value.
990      if (normalizedEncoding === 'utf8') {
991        const code = value.charCodeAt(0);
992        if (code < 128) {
993          value = code;
994        }
995      } else if (normalizedEncoding === 'latin1') {
996        value = value.charCodeAt(0);
997      }
998    }
999  } else {
1000    encoding = undefined;
1001  }
1002
1003  if (offset === undefined) {
1004    offset = 0;
1005    end = buf.length;
1006  } else {
1007    validateInt32(offset, 'offset', 0);
1008    // Invalid ranges are not set to a default, so can range check early.
1009    if (end === undefined) {
1010      end = buf.length;
1011    } else {
1012      validateInt32(end, 'end', 0, buf.length);
1013    }
1014    if (offset >= end)
1015      return buf;
1016  }
1017
1018
1019  if (typeof value === 'number') {
1020    // OOB check
1021    const byteLen = TypedArrayProto_byteLength.call(buf);
1022    const fillLength = end - offset;
1023    if (offset > end || fillLength + offset > byteLen)
1024      throw new ERR_BUFFER_OUT_OF_BOUNDS();
1025
1026    TypedArrayFill.call(buf, value, offset, end);
1027  } else {
1028    const res = bindingFill(buf, value, offset, end, encoding);
1029    if (res < 0) {
1030      if (res === -1)
1031        throw new ERR_INVALID_ARG_VALUE('value', value);
1032      throw new ERR_BUFFER_OUT_OF_BOUNDS();
1033    }
1034  }
1035
1036  return buf;
1037}
1038
1039Buffer.prototype.write = function write(string, offset, length, encoding) {
1040  // Buffer#write(string);
1041  if (offset === undefined) {
1042    return this.utf8Write(string, 0, this.length);
1043  }
1044  // Buffer#write(string, encoding)
1045  if (length === undefined && typeof offset === 'string') {
1046    encoding = offset;
1047    length = this.length;
1048    offset = 0;
1049
1050  // Buffer#write(string, offset[, length][, encoding])
1051  } else {
1052    validateInt32(offset, 'offset', 0, this.length);
1053
1054    const remaining = this.length - offset;
1055
1056    if (length === undefined) {
1057      length = remaining;
1058    } else if (typeof length === 'string') {
1059      encoding = length;
1060      length = remaining;
1061    } else {
1062      validateInt32(length, 'length', 0, this.length);
1063      if (length > remaining)
1064        length = remaining;
1065    }
1066  }
1067
1068  if (!encoding)
1069    return this.utf8Write(string, offset, length);
1070
1071  const ops = getEncodingOps(encoding);
1072  if (ops === undefined)
1073    throw new ERR_UNKNOWN_ENCODING(encoding);
1074  return ops.write(this, string, offset, length);
1075};
1076
1077Buffer.prototype.toJSON = function toJSON() {
1078  if (this.length > 0) {
1079    const data = new Array(this.length);
1080    for (let i = 0; i < this.length; ++i)
1081      data[i] = this[i];
1082    return { type: 'Buffer', data };
1083  }
1084  return { type: 'Buffer', data: [] };
1085};
1086
1087function adjustOffset(offset, length) {
1088  // Use Math.trunc() to convert offset to an integer value that can be larger
1089  // than an Int32. Hence, don't use offset | 0 or similar techniques.
1090  offset = MathTrunc(offset);
1091  if (offset === 0) {
1092    return 0;
1093  }
1094  if (offset < 0) {
1095    offset += length;
1096    return offset > 0 ? offset : 0;
1097  }
1098  if (offset < length) {
1099    return offset;
1100  }
1101  return NumberIsNaN(offset) ? 0 : length;
1102}
1103
1104Buffer.prototype.slice = function slice(start, end) {
1105  const srcLength = this.length;
1106  start = adjustOffset(start, srcLength);
1107  end = end !== undefined ? adjustOffset(end, srcLength) : srcLength;
1108  const newLength = end > start ? end - start : 0;
1109  return new FastBuffer(this.buffer, this.byteOffset + start, newLength);
1110};
1111
1112function swap(b, n, m) {
1113  const i = b[n];
1114  b[n] = b[m];
1115  b[m] = i;
1116}
1117
1118Buffer.prototype.swap16 = function swap16() {
1119  // For Buffer.length < 128, it's generally faster to
1120  // do the swap in javascript. For larger buffers,
1121  // dropping down to the native code is faster.
1122  const len = this.length;
1123  if (len % 2 !== 0)
1124    throw new ERR_INVALID_BUFFER_SIZE('16-bits');
1125  if (len < 128) {
1126    for (let i = 0; i < len; i += 2)
1127      swap(this, i, i + 1);
1128    return this;
1129  }
1130  return _swap16(this);
1131};
1132
1133Buffer.prototype.swap32 = function swap32() {
1134  // For Buffer.length < 192, it's generally faster to
1135  // do the swap in javascript. For larger buffers,
1136  // dropping down to the native code is faster.
1137  const len = this.length;
1138  if (len % 4 !== 0)
1139    throw new ERR_INVALID_BUFFER_SIZE('32-bits');
1140  if (len < 192) {
1141    for (let i = 0; i < len; i += 4) {
1142      swap(this, i, i + 3);
1143      swap(this, i + 1, i + 2);
1144    }
1145    return this;
1146  }
1147  return _swap32(this);
1148};
1149
1150Buffer.prototype.swap64 = function swap64() {
1151  // For Buffer.length < 192, it's generally faster to
1152  // do the swap in javascript. For larger buffers,
1153  // dropping down to the native code is faster.
1154  const len = this.length;
1155  if (len % 8 !== 0)
1156    throw new ERR_INVALID_BUFFER_SIZE('64-bits');
1157  if (len < 192) {
1158    for (let i = 0; i < len; i += 8) {
1159      swap(this, i, i + 7);
1160      swap(this, i + 1, i + 6);
1161      swap(this, i + 2, i + 5);
1162      swap(this, i + 3, i + 4);
1163    }
1164    return this;
1165  }
1166  return _swap64(this);
1167};
1168
1169Buffer.prototype.toLocaleString = Buffer.prototype.toString;
1170
1171let transcode;
1172if (internalBinding('config').hasIntl) {
1173  const {
1174    icuErrName,
1175    transcode: _transcode
1176  } = internalBinding('icu');
1177
1178  // Transcodes the Buffer from one encoding to another, returning a new
1179  // Buffer instance.
1180  transcode = function transcode(source, fromEncoding, toEncoding) {
1181    if (!isUint8Array(source)) {
1182      throw new ERR_INVALID_ARG_TYPE('source',
1183                                     ['Buffer', 'Uint8Array'], source);
1184    }
1185    if (source.length === 0) return Buffer.alloc(0);
1186
1187    fromEncoding = normalizeEncoding(fromEncoding) || fromEncoding;
1188    toEncoding = normalizeEncoding(toEncoding) || toEncoding;
1189    const result = _transcode(source, fromEncoding, toEncoding);
1190    if (typeof result !== 'number')
1191      return result;
1192
1193    const code = icuErrName(result);
1194    // eslint-disable-next-line no-restricted-syntax
1195    const err = new Error(`Unable to transcode Buffer [${code}]`);
1196    err.code = code;
1197    err.errno = result;
1198    throw err;
1199  };
1200}
1201
1202module.exports = {
1203  Buffer,
1204  SlowBuffer,
1205  transcode,
1206  // Legacy
1207  kMaxLength,
1208  kStringMaxLength
1209};
1210
1211ObjectDefineProperties(module.exports, {
1212  constants: {
1213    configurable: false,
1214    enumerable: true,
1215    value: constants
1216  },
1217  INSPECT_MAX_BYTES: {
1218    configurable: true,
1219    enumerable: true,
1220    get() { return INSPECT_MAX_BYTES; },
1221    set(val) { INSPECT_MAX_BYTES = val; }
1222  }
1223});
1224