repo_description: Node.js JavaScript runtime ✨🐢🚀✨
repo_topics: javascript js linux macos mit node nodejs runtime windows
code: // Copyright Joyent, Inc. and other Node contributors.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a
  // copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to permit
  // persons to whom the Software is furnished to do so, subject to the
  // following conditions:
  //
  // The above copyright notice and this permission notice shall be included
  // in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  // USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  'use strict';
  
  const {
    Array,
    ArrayBufferIsView,
    ArrayIsArray,
    ArrayPrototypeForEach,
    MathFloor,
    MathMin,
    MathTrunc,
    NumberIsInteger,
    NumberIsNaN,
    NumberMAX_SAFE_INTEGER,
    NumberMIN_SAFE_INTEGER,
    ObjectDefineProperties,
    ObjectDefineProperty,
    ObjectPrototypeHasOwnProperty,
    ObjectSetPrototypeOf,
    RegExpPrototypeSymbolReplace,
    StringPrototypeCharCodeAt,
    StringPrototypeSlice,
    StringPrototypeToLowerCase,
    StringPrototypeTrim,
    SymbolSpecies,
    SymbolToPrimitive,
    TypedArrayPrototypeFill,
    TypedArrayPrototypeGetBuffer,
    TypedArrayPrototypeGetByteLength,
    TypedArrayPrototypeGetByteOffset,
    TypedArrayPrototypeGetLength,
    TypedArrayPrototypeSet,
    TypedArrayPrototypeSubarray,
    Uint8Array,
  } = primordials;
  
  const {
    byteLengthUtf8,
    compare: _compare,
    compareOffset,
    copy: _copy,
    fill: bindingFill,
    isAscii: bindingIsAscii,
    isUtf8: bindingIsUtf8,
    indexOfBuffer,
    indexOfNumber,
    indexOfString,
    swap16: _swap16,
    swap32: _swap32,
    swap64: _swap64,
    kMaxLength,
    kStringMaxLength,
    atob: _atob,
    btoa: _btoa,
    asciiSlice,
    base64Slice,
    base64urlSlice,
    latin1Slice,
    hexSlice,
    ucs2Slice,
    utf8Slice,
    base64Write,
    base64urlWrite,
    hexWrite,
    ucs2Write,
  } = internalBinding('buffer');
  const {
    constants: {
      ALL_PROPERTIES,
      ONLY_ENUMERABLE,
    },
    getOwnNonIndexProperties,
    isInsideNodeModules,
  } = internalBinding('util');
  const {
    customInspectSymbol,
    lazyDOMException,
    normalizeEncoding,
    kIsEncodingSymbol,
    defineLazyProperties,
    encodingsMap,
  } = require('internal/util');
  const {
    isAnyArrayBuffer,
    isArrayBufferView,
    isUint8Array,
    isTypedArray,
  } = require('internal/util/types');
  const {
    inspect: utilInspect,
  } = require('internal/util/inspect');
  
  const {
    codes: {
      ERR_BUFFER_OUT_OF_BOUNDS,
      ERR_INVALID_ARG_TYPE,
      ERR_INVALID_ARG_VALUE,
      ERR_INVALID_BUFFER_SIZE,
      ERR_MISSING_ARGS,
      ERR_OUT_OF_RANGE,
      ERR_UNKNOWN_ENCODING,
    },
    genericNodeError,
  } = require('internal/errors');
  const {
    validateArray,
    validateBuffer,
    validateInteger,
    validateNumber,
    validateString,
  } = require('internal/validators');
  // Provide validateInteger() but with kMaxLength as the default maximum value.
  const validateOffset = (value, name, min = 0, max = kMaxLength) =>
    validateInteger(value, name, min, max);
  
  const {
    FastBuffer,
    markAsUntransferable,
    addBufferPrototypeMethods,
    createUnsafeBuffer,
    asciiWrite,
    latin1Write,
    utf8Write,
  } = require('internal/buffer');
  
  const {
    namespace: {
      addDeserializeCallback,
      isBuildingSnapshot,
    },
  } = require('internal/v8/startup_snapshot');
  
  FastBuffer.prototype.constructor = Buffer;
  Buffer.prototype = FastBuffer.prototype;
  addBufferPrototypeMethods(Buffer.prototype);
  
  const constants = ObjectDefineProperties({}, {
    MAX_LENGTH: {
      __proto__: null,
      value: kMaxLength,
      writable: false,
      enumerable: true,
    },
    MAX_STRING_LENGTH: {
      __proto__: null,
      value: kStringMaxLength,
      writable: false,
      enumerable: true,
    },
  });
  
  Buffer.poolSize = 8 * 1024;
  let poolSize, poolOffset, allocPool, allocBuffer;
  
  function createPool() {
    poolSize = Buffer.poolSize;
    allocBuffer = createUnsafeBuffer(poolSize);
    allocPool = allocBuffer.buffer;
    markAsUntransferable(allocPool);
    poolOffset = 0;
  }
  createPool();
  if (isBuildingSnapshot()) {
    addDeserializeCallback(() => {
      // TODO(legendecas): ArrayBuffer.[[ArrayBufferDetachKey]] is not been serialized.
      // Remove this callback when snapshot serialization supports it.
      createPool();
    });
  }
  
  function alignPool() {
    // Ensure aligned slices
    if (poolOffset & 0x7) {
      poolOffset |= 0x7;
      poolOffset++;
    }
  }
  
  let bufferWarningAlreadyEmitted = false;
  let nodeModulesCheckCounter = 0;
  const bufferWarning = 'Buffer() is deprecated due to security and usability ' +
                        'issues. Please use the Buffer.alloc(), ' +
                        'Buffer.allocUnsafe(), or Buffer.from() methods instead.';
  
  function showFlaggedDeprecation() {
    if (bufferWarningAlreadyEmitted ||
        ++nodeModulesCheckCounter > 10000 ||
        (!require('internal/options').getOptionValue('--pending-deprecation') &&
         isInsideNodeModules(3))) {
      // We don't emit a warning, because we either:
      // - Already did so, or
      // - Already checked too many times whether a call is coming
      //   from node_modules and want to stop slowing down things, or
      // - We aren't running with `--pending-deprecation` enabled,
      //   and the code is inside `node_modules`.
      // - If the topmost non-internal frame is not inside `node_modules`.
      return;
    }
  
    process.emitWarning(bufferWarning, 'DeprecationWarning', 'DEP0005');
    bufferWarningAlreadyEmitted = true;
  }
  
  function toInteger(n, defaultVal) {
    n = +n;
    if (!NumberIsNaN(n) &&
        n >= NumberMIN_SAFE_INTEGER &&
        n <= NumberMAX_SAFE_INTEGER) {
      return ((n % 1) === 0 ? n : MathFloor(n));
    }
    return defaultVal;
  }
  
  function copyImpl(source, target, targetStart, sourceStart, sourceEnd) {
    if (!ArrayBufferIsView(source))
      throw new ERR_INVALID_ARG_TYPE('source', ['Buffer', 'Uint8Array'], source);
    if (!ArrayBufferIsView(target))
      throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target);
  
    if (targetStart === undefined) {
      targetStart = 0;
    } else {
      targetStart = NumberIsInteger(targetStart) ? targetStart : toInteger(targetStart, 0);
      if (targetStart < 0)
        throw new ERR_OUT_OF_RANGE('targetStart', '>= 0', targetStart);
    }
  
    if (sourceStart === undefined) {
      sourceStart = 0;
    } else {
      sourceStart = NumberIsInteger(sourceStart) ? sourceStart : toInteger(sourceStart, 0);
      if (sourceStart < 0 || sourceStart > source.byteLength)
        throw new ERR_OUT_OF_RANGE('sourceStart', `>= 0 && <= ${source.byteLength}`, sourceStart);
    }
  
    if (sourceEnd === undefined) {
      sourceEnd = source.byteLength;
    } else {
      sourceEnd = NumberIsInteger(sourceEnd) ? sourceEnd : toInteger(sourceEnd, 0);
      if (sourceEnd < 0)
        throw new ERR_OUT_OF_RANGE('sourceEnd', '>= 0', sourceEnd);
    }
  
    if (targetStart >= target.byteLength || sourceStart >= sourceEnd)
      return 0;
  
    return _copyActual(source, target, targetStart, sourceStart, sourceEnd);
  }
  
  function _copyActual(source, target, targetStart, sourceStart, sourceEnd, isUint8Copy = false) {
    if (sourceEnd - sourceStart > target.byteLength - targetStart)
      sourceEnd = sourceStart + target.byteLength - targetStart;
  
    let nb = sourceEnd - sourceStart;
    const sourceLen = source.byteLength - sourceStart;
    if (nb > sourceLen)
      nb = sourceLen;
  
    if (nb <= 0)
      return 0;
  
    if (sourceStart === 0 && nb === sourceLen && (isUint8Copy || isUint8Array(target))) {
      TypedArrayPrototypeSet(target, source, targetStart);
    } else {
      _copy(source, target, targetStart, sourceStart, nb);
    }
  
    return nb;
  }
  
  /**
   * The Buffer() constructor is deprecated in documentation and should not be
   * used moving forward. Rather, developers should use one of the three new
   * factory APIs: Buffer.from(), Buffer.allocUnsafe() or Buffer.alloc() based on
   * their specific needs. There is no runtime deprecation because of the extent
   * to which the Buffer constructor is used in the ecosystem currently -- a
   * runtime deprecation would introduce too much breakage at this time. It's not
   * likely that the Buffer constructors would ever actually be removed.
   * Deprecation Code: DEP0005
   * @returns {Buffer}
   */
  function Buffer(arg, encodingOrOffset, length) {
    showFlaggedDeprecation();
    // Common case.
    if (typeof arg === 'number') {
      if (typeof encodingOrOffset === 'string') {
        throw new ERR_INVALID_ARG_TYPE('string', 'string', arg);
      }
      return Buffer.alloc(arg);
    }
    return Buffer.from(arg, encodingOrOffset, length);
  }
  
  ObjectDefineProperty(Buffer, SymbolSpecies, {
    __proto__: null,
    enumerable: false,
    configurable: true,
    get() { return FastBuffer; },
  });
  
  /**
   * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
   * if value is a number.
   * Buffer.from(str[, encoding])
   * Buffer.from(array)
   * Buffer.from(buffer)
   * Buffer.from(arrayBuffer[, byteOffset[, length]])
   * @param {any} value
   * @param {BufferEncoding|number} encodingOrOffset
   * @param {number} [length]
   * @returns {Buffer}
   */
  Buffer.from = function from(value, encodingOrOffset, length) {
    if (typeof value === 'string')
      return fromString(value, encodingOrOffset);
  
    if (typeof value === 'object' && value !== null) {
      if (isAnyArrayBuffer(value))
        return fromArrayBuffer(value, encodingOrOffset, length);
  
      const valueOf = value.valueOf && value.valueOf();
      if (valueOf != null &&
          valueOf !== value &&
          (typeof valueOf === 'string' || typeof valueOf === 'object')) {
        return from(valueOf, encodingOrOffset, length);
      }
  
      const b = fromObject(value);
      if (b)
        return b;
  
      if (typeof value[SymbolToPrimitive] === 'function') {
        const primitive = value[SymbolToPrimitive]('string');
        if (typeof primitive === 'string') {
          return fromString(primitive, encodingOrOffset);
        }
      }
    }
  
    throw new ERR_INVALID_ARG_TYPE(
      'first argument',
      ['string', 'Buffer', 'ArrayBuffer', 'Array', 'Array-like Object'],
      value,
    );
  };
  
  /**
   * Creates the Buffer as a copy of the underlying ArrayBuffer of the view
   * rather than the contents of the view.
   * @param {TypedArray} view
   * @param {number} [offset]
   * @param {number} [length]
   * @returns {Buffer}
   */
  Buffer.copyBytesFrom = function copyBytesFrom(view, offset, length) {
    if (!isTypedArray(view)) {
      throw new ERR_INVALID_ARG_TYPE('view', [ 'TypedArray' ], view);
    }
  
    const viewLength = TypedArrayPrototypeGetLength(view);
    if (viewLength === 0) {
      return new FastBuffer();
    }
  
    let start = 0;
    let end = viewLength;
  
    if (offset !== undefined) {
      validateInteger(offset, 'offset', 0);
      if (offset >= viewLength) return new FastBuffer();
      start = offset;
    }
  
    if (length !== undefined) {
      validateInteger(length, 'length', 0);
      // The old code used TypedArrayPrototypeSlice which clamps internally.
      end = MathMin(start + length, viewLength);
    }
  
    if (end <= start) return new FastBuffer();
  
    const viewByteLength = TypedArrayPrototypeGetByteLength(view);
    const elementSize = viewByteLength / viewLength;
    const srcByteOffset = TypedArrayPrototypeGetByteOffset(view) +
                          start * elementSize;
    const srcByteLength = (end - start) * elementSize;
  
    return fromArrayLike(new Uint8Array(
      TypedArrayPrototypeGetBuffer(view),
      srcByteOffset,
      srcByteLength));
  };
  
  // Identical to the built-in %TypedArray%.of(), but avoids using the deprecated
  // Buffer() constructor. Must use arrow function syntax to avoid automatically
  // adding a `prototype` property and making the function a constructor.
  //
  // Refs: https://tc39.github.io/ecma262/#sec-%typedarray%.of
  // Refs: https://esdiscuss.org/topic/isconstructor#content-11
  const of = (...items) => {
    const len = items.length;
    const newObj = new FastBuffer(len); // In heap for small sizes
    for (let k = 0; k < len; k++)
      newObj[k] = items[k];
    return newObj;
  };
  Buffer.of = of;
  
  ObjectSetPrototypeOf(Buffer, Uint8Array);
  
  /**
   * Creates a new filled Buffer instance.
   * alloc(size[, fill[, encoding]])
   * @returns {FastBuffer}
   */
  Buffer.alloc = function alloc(size, fill, encoding) {
    validateNumber(size, 'size', 0, kMaxLength);
    if (fill !== undefined && fill !== 0 && size > 0) {
      const buf = createUnsafeBuffer(size);
      return _fill(buf, fill, 0, buf.length, encoding);
    }
    return new FastBuffer(size);
  };
  
  /**
   * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer
   * instance. If `--zero-fill-buffers` is set, will zero-fill the buffer.
   * @returns {FastBuffer}
   */
  Buffer.allocUnsafe = function allocUnsafe(size) {
    validateNumber(size, 'size', 0, kMaxLength);
    return allocate(size);
  };
  
  /**
   * By default creates a non-zero-filled Buffer instance that is not allocated
   * off the pre-initialized pool. If `--zero-fill-buffers` is set, will zero-fill
   * the buffer.
   * @param {number} size
   * @returns {FastBuffer|undefined}
   */
  Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) {
    validateNumber(size, 'size', 0, kMaxLength);
    return createUnsafeBuffer(size);
  };
  
  function allocate(size) {
    if (size <= 0) {
      return new FastBuffer();
    }
    if (size < (Buffer.poolSize >>> 1)) {
      if (size > (poolSize - poolOffset))
        createPool();
      const b = new FastBuffer(allocPool, poolOffset, size);
      poolOffset += size;
      alignPool();
      return b;
    }
    return createUnsafeBuffer(size);
  }
  
  function fromStringFast(string, ops) {
    const maxLength = Buffer.poolSize >>> 1;
  
    let length = string.length; // Min length
  
    if (length >= maxLength)
      return createFromString(string, ops);
  
    length *= 4; // Max length (4 bytes per character)
  
    if (length >= maxLength)
      length = ops.byteLength(string); // Actual length
  
    if (length >= maxLength)
      return createFromString(string, ops, length);
  
    if (length > (poolSize - poolOffset))
      createPool();
  
    const actual = ops.write(allocBuffer, string, poolOffset, length);
    const b = new FastBuffer(allocPool, poolOffset, actual);
  
    poolOffset += actual;
    alignPool();
    return b;
  }
  
  function createFromString(string, ops, length = ops.byteLength(string)) {
    const buf = Buffer.allocUnsafeSlow(length);
    const actual = ops.write(buf, string, 0, length);
    return actual < length ? new FastBuffer(buf.buffer, 0, actual) : buf;
  }
  
  function fromString(string, encoding) {
    let ops;
    if (!encoding || encoding === 'utf8' || typeof encoding !== 'string') {
      ops = encodingOps.utf8;
    } else {
      ops = getEncodingOps(encoding);
      if (ops === undefined)
        throw new ERR_UNKNOWN_ENCODING(encoding);
    }
  
    return string.length === 0 ? new FastBuffer() : fromStringFast(string, ops);
  }
  
  function fromArrayBuffer(obj, byteOffset, length) {
    // Convert byteOffset to integer
    if (byteOffset === undefined) {
      byteOffset = 0;
    } else {
      byteOffset = +byteOffset;
      if (NumberIsNaN(byteOffset))
        byteOffset = 0;
    }
  
    const maxLength = obj.byteLength - byteOffset;
  
    if (maxLength < 0)
      throw new ERR_BUFFER_OUT_OF_BOUNDS('offset');
  
    if (length !== undefined) {
      // Convert length to non-negative integer.
      length = +length;
      if (length > 0) {
        if (length > maxLength)
          throw new ERR_BUFFER_OUT_OF_BOUNDS('length');
      } else {
        length = 0;
      }
    }
  
    return new FastBuffer(obj, byteOffset, length);
  }
  
  function fromArrayLike(obj) {
    const { length } = obj;
    if (length <= 0)
      return new FastBuffer();
    if (length < (Buffer.poolSize >>> 1)) {
      if (length > (poolSize - poolOffset))
        createPool();
      const b = new FastBuffer(allocPool, poolOffset, length);
      TypedArrayPrototypeSet(b, obj, 0);
      poolOffset += length;
      alignPool();
      return b;
    }
    return new FastBuffer(obj);
  }
  
  function fromObject(obj) {
    if (obj.length !== undefined || isAnyArrayBuffer(obj.buffer)) {
      if (typeof obj.length !== 'number') {
        return new FastBuffer();
      }
      return fromArrayLike(obj);
    }
  
    if (obj.type === 'Buffer' && ArrayIsArray(obj.data)) {
      return fromArrayLike(obj.data);
    }
  }
  
  // Static methods
  
  Buffer.isBuffer = function isBuffer(b) {
    return b instanceof Buffer;
  };
  
  Buffer.compare = function compare(buf1, buf2) {
    if (!isUint8Array(buf1)) {
      throw new ERR_INVALID_ARG_TYPE('buf1', ['Buffer', 'Uint8Array'], buf1);
    }
  
    if (!isUint8Array(buf2)) {
      throw new ERR_INVALID_ARG_TYPE('buf2', ['Buffer', 'Uint8Array'], buf2);
    }
  
    if (buf1 === buf2) {
      return 0;
    }
  
    return _compare(buf1, buf2);
  };
  
  Buffer.isEncoding = function isEncoding(encoding) {
    return typeof encoding === 'string' && encoding.length !== 0 &&
           normalizeEncoding(encoding) !== undefined;
  };
  Buffer[kIsEncodingSymbol] = Buffer.isEncoding;
  
  Buffer.concat = function concat(list, length) {
    validateArray(list, 'list');
  
    if (list.length === 0)
      return new FastBuffer();
  
    if (length === undefined) {
      length = 0;
      for (let i = 0; i < list.length; i++) {
        const buf = list[i];
        if (!isUint8Array(buf)) {
          // TODO(BridgeAR): This should not be of type ERR_INVALID_ARG_TYPE.
          // Instead, find the proper error code for this.
          throw new ERR_INVALID_ARG_TYPE(
            `list[${i}]`, ['Buffer', 'Uint8Array'], buf);
        }
        length += TypedArrayPrototypeGetByteLength(buf);
      }
  
      const buffer = allocate(length);
      let pos = 0;
      for (let i = 0; i < list.length; i++) {
        const buf = list[i];
        const bufLength = TypedArrayPrototypeGetByteLength(buf);
        TypedArrayPrototypeSet(buffer, buf, pos);
        pos += bufLength;
      }
  
      if (pos < length) {
        TypedArrayPrototypeFill(buffer, 0, pos, length);
      }
      return buffer;
    }
  
    validateOffset(length, 'length');
    for (let i = 0; i < list.length; i++) {
      if (!isUint8Array(list[i])) {
        // TODO(BridgeAR): This should not be of type ERR_INVALID_ARG_TYPE.
        // Instead, find the proper error code for this.
        throw new ERR_INVALID_ARG_TYPE(
          `list[${i}]`, ['Buffer', 'Uint8Array'], list[i]);
      }
    }
  
    const buffer = allocate(length);
    let pos = 0;
    for (let i = 0; i < list.length; i++) {
      const buf = list[i];
      const bufLength = TypedArrayPrototypeGetByteLength(buf);
      if (pos + bufLength > length) {
        TypedArrayPrototypeSet(buffer,
                               TypedArrayPrototypeSubarray(buf, 0, length - pos),
                               pos);
        pos = length;
        break;
      }
      TypedArrayPrototypeSet(buffer, buf, pos);
      pos += bufLength;
    }
  
    // Note: `length` is always equal to `buffer.length` at this point
    if (pos < length) {
      // Zero-fill the remaining bytes if the specified `length` was more than
      // the actual total length, i.e. if we have some remaining allocated bytes
      // there were not initialized.
      TypedArrayPrototypeFill(buffer, 0, pos, length);
    }
  
    return buffer;
  };
  
  function base64ByteLength(str, bytes) {
    // Handle padding
    if (StringPrototypeCharCodeAt(str, bytes - 1) === 0x3D)
      bytes--;
    if (bytes > 1 && StringPrototypeCharCodeAt(str, bytes - 1) === 0x3D)
      bytes--;
  
    // Base64 ratio: 3/4
    return (bytes * 3) >>> 2;
  }
  
  const encodingOps = {
    utf8: {
      encoding: 'utf8',
      encodingVal: encodingsMap.utf8,
      byteLength: byteLengthUtf8,
      write: utf8Write,
      slice: utf8Slice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir, end),
    },
    ucs2: {
      encoding: 'ucs2',
      encodingVal: encodingsMap.utf16le,
      byteLength: (string) => string.length * 2,
      write: ucs2Write,
      slice: ucs2Slice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir, end),
    },
    utf16le: {
      encoding: 'utf16le',
      encodingVal: encodingsMap.utf16le,
      byteLength: (string) => string.length * 2,
      write: ucs2Write,
      slice: ucs2Slice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir, end),
    },
    latin1: {
      encoding: 'latin1',
      encodingVal: encodingsMap.latin1,
      byteLength: (string) => string.length,
      write: latin1Write,
      slice: latin1Slice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir, end),
    },
    ascii: {
      encoding: 'ascii',
      encodingVal: encodingsMap.ascii,
      byteLength: (string) => string.length,
      write: asciiWrite,
      slice: asciiSlice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfBuffer(buf,
                      fromStringFast(val, encodingOps.ascii),
                      byteOffset,
                      encodingsMap.ascii,
                      dir,
                      end),
    },
    base64: {
      encoding: 'base64',
      encodingVal: encodingsMap.base64,
      byteLength: (string) => base64ByteLength(string, string.length),
      write: base64Write,
      slice: base64Slice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfBuffer(buf,
                      fromStringFast(val, encodingOps.base64),
                      byteOffset,
                      encodingsMap.base64,
                      dir,
                      end),
    },
    base64url: {
      encoding: 'base64url',
      encodingVal: encodingsMap.base64url,
      byteLength: (string) => base64ByteLength(string, string.length),
      write: base64urlWrite,
      slice: base64urlSlice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfBuffer(buf,
                      fromStringFast(val, encodingOps.base64url),
                      byteOffset,
                      encodingsMap.base64url,
                      dir,
                      end),
    },
    hex: {
      encoding: 'hex',
      encodingVal: encodingsMap.hex,
      byteLength: (string) => string.length >>> 1,
      write: hexWrite,
      slice: hexSlice,
      indexOf: (buf, val, byteOffset, dir, end) =>
        indexOfBuffer(buf,
                      fromStringFast(val, encodingOps.hex),
                      byteOffset,
                      encodingsMap.hex,
                      dir,
                      end),
    },
  };
  function getEncodingOps(encoding) {
    encoding += '';
    switch (encoding.length) {
      case 4:
        if (encoding === 'utf8') return encodingOps.utf8;
        if (encoding === 'ucs2') return encodingOps.ucs2;
        encoding = StringPrototypeToLowerCase(encoding);
        if (encoding === 'utf8') return encodingOps.utf8;
        if (encoding === 'ucs2') return encodingOps.ucs2;
        break;
      case 5:
        if (encoding === 'utf-8') return encodingOps.utf8;
        if (encoding === 'ascii') return encodingOps.ascii;
        if (encoding === 'ucs-2') return encodingOps.ucs2;
        encoding = StringPrototypeToLowerCase(encoding);
        if (encoding === 'utf-8') return encodingOps.utf8;
        if (encoding === 'ascii') return encodingOps.ascii;
        if (encoding === 'ucs-2') return encodingOps.ucs2;
        break;
      case 7:
        if (encoding === 'utf16le' ||
            StringPrototypeToLowerCase(encoding) === 'utf16le')
          return encodingOps.utf16le;
        break;
      case 8:
        if (encoding === 'utf-16le' ||
            StringPrototypeToLowerCase(encoding) === 'utf-16le')
          return encodingOps.utf16le;
        break;
      case 6:
        if (encoding === 'latin1' || encoding === 'binary')
          return encodingOps.latin1;
        if (encoding === 'base64') return encodingOps.base64;
        encoding = StringPrototypeToLowerCase(encoding);
        if (encoding === 'latin1' || encoding === 'binary')
          return encodingOps.latin1;
        if (encoding === 'base64') return encodingOps.base64;
        break;
      case 3:
        if (encoding === 'hex' || StringPrototypeToLowerCase(encoding) === 'hex')
          return encodingOps.hex;
        break;
      case 9:
        if (encoding === 'base64url' ||
            StringPrototypeToLowerCase(encoding) === 'base64url')
          return encodingOps.base64url;
        break;
    }
  }
  
  function byteLength(string, encoding) {
    if (typeof string !== 'string') {
      if (isArrayBufferView(string) || isAnyArrayBuffer(string)) {
        return string.byteLength;
      }
  
      throw new ERR_INVALID_ARG_TYPE(
        'string', ['string', 'Buffer', 'ArrayBuffer'], string,
      );
    }
  
    const len = string.length;
    if (len === 0)
      return 0;
  
    if (!encoding || encoding === 'utf8') {
      return byteLengthUtf8(string);
    }
  
    if (encoding === 'ascii') {
      return len;
    }
  
    const ops = getEncodingOps(encoding);
    if (ops === undefined) {
      // TODO (ronag): Makes more sense to throw here.
      // throw new ERR_UNKNOWN_ENCODING(encoding);
      return byteLengthUtf8(string);
    }
  
    return ops.byteLength(string);
  }
  
  Buffer.byteLength = byteLength;
  
  // For backwards compatibility.
  ObjectDefineProperty(Buffer.prototype, 'parent', {
    __proto__: null,
    enumerable: true,
    get() {
      if (!(this instanceof Buffer))
        return undefined;
      return this.buffer;
    },
  });
  ObjectDefineProperty(Buffer.prototype, 'offset', {
    __proto__: null,
    enumerable: true,
    get() {
      if (!(this instanceof Buffer))
        return undefined;
      return this.byteOffset;
    },
  });
  
  Buffer.prototype.copy =
    function copy(target, targetStart, sourceStart, sourceEnd) {
      return copyImpl(this, target, targetStart, sourceStart, sourceEnd);
    };
  
  // No need to verify that "buf.length <= MAX_UINT32" since it's a read-only
  // property of a typed array.
  // This behaves neither like String nor Uint8Array in that we set start/end
  // to their upper/lower bounds if the value passed is out of range.
  Buffer.prototype.toString = function toString(encoding, start, end) {
    if (arguments.length === 0) {
      return utf8Slice(this, 0, this.length);
    }
  
    const bufferLength = TypedArrayPrototypeGetLength(this);
  
    if (start <= 0)
      start = 0;
    else if (start >= bufferLength)
      return '';
    else
      start = MathTrunc(start) || 0;
  
    if (end === undefined || end > bufferLength)
      end = bufferLength;
    else
      end = MathTrunc(end) || 0;
  
    if (end <= start)
      return '';
  
    if (encoding === undefined)
      return utf8Slice(this, start, end);
  
    const ops = getEncodingOps(encoding);
    if (ops === undefined)
      throw new ERR_UNKNOWN_ENCODING(encoding);
  
    return ops.slice(this, start, end);
  };
  
  Buffer.prototype.equals = function equals(otherBuffer) {
    if (!isUint8Array(otherBuffer)) {
      throw new ERR_INVALID_ARG_TYPE(
        'otherBuffer', ['Buffer', 'Uint8Array'], otherBuffer);
    }
  
    if (this === otherBuffer)
      return true;
    const len = TypedArrayPrototypeGetByteLength(this);
    if (len !== TypedArrayPrototypeGetByteLength(otherBuffer))
      return false;
  
    return len === 0 || _compare(this, otherBuffer) === 0;
  };
  
  let INSPECT_MAX_BYTES = 50;
  // Override how buffers are presented by util.inspect().
  Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) {
    const max = INSPECT_MAX_BYTES;
    const actualMax = MathMin(max, this.length);
    const remaining = this.length - max;
    let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace(
      /(.{2})/g, hexSlice(this, 0, actualMax), '$1 '));
    if (remaining > 0)
      str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
    // Inspect special properties as well, if possible.
    if (ctx) {
      let extras = false;
      const filter = ctx.showHidden ? ALL_PROPERTIES : ONLY_ENUMERABLE;
      const obj = { __proto__: null };
      ArrayPrototypeForEach(getOwnNonIndexProperties(this, filter),
                            (key) => {
                              extras = true;
                              obj[key] = this[key];
                            });
      if (extras) {
        if (this.length !== 0)
          str += ', ';
        // '[Object: null prototype] {'.length === 26
        // This is guarded with a test.
        str += StringPrototypeSlice(utilInspect(obj, {
          ...ctx,
          breakLength: Infinity,
          compact: true,
        }), 27, -2);
      }
    }
    let constructorName = 'Buffer';
    try {
      const { constructor } = this;
      if (typeof constructor === 'function' && ObjectPrototypeHasOwnProperty(constructor, 'name')) {
        constructorName = constructor.name;
      }
    } catch { /* Ignore error and use default name */ }
    return `<${constructorName} ${str}>`;
  };
  Buffer.prototype.inspect = Buffer.prototype[customInspectSymbol];
  
  Buffer.prototype.compare = function compare(target,
                                              targetStart,
                                              targetEnd,
                                              sourceStart,
                                              sourceEnd) {
    if (!isUint8Array(target)) {
      throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target);
    }
    if (arguments.length === 1)
      return _compare(this, target);
  
    if (targetStart === undefined)
      targetStart = 0;
    else
      validateOffset(targetStart, 'targetStart');
  
    if (targetEnd === undefined)
      targetEnd = target.length;
    else
      validateOffset(targetEnd, 'targetEnd', 0, target.length);
  
    if (sourceStart === undefined)
      sourceStart = 0;
    else
      validateOffset(sourceStart, 'sourceStart');
  
    if (sourceEnd === undefined)
      sourceEnd = this.length;
    else
      validateOffset(sourceEnd, 'sourceEnd', 0, this.length);
  
    if (sourceStart >= sourceEnd)
      return (targetStart >= targetEnd ? 0 : -1);
    if (targetStart >= targetEnd)
      return 1;
  
    return compareOffset(this, target, targetStart, sourceStart, targetEnd,
                         sourceEnd);
  };
  
  // Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
  // OR the last index of `val` in `buffer` at offset <= `byteOffset`.
  //
  // Arguments:
  // - buffer - a Buffer to search
  // - val - a string, Buffer, or number
  // - byteOffset - an index into `buffer`; will be clamped to an int32
  // - end - absolute exclusive end of the search range
  // - encoding - an optional encoding, relevant if val is a string
  // - dir - true for indexOf, false for lastIndexOf
  function bidirectionalIndexOf(buffer, val, byteOffset, end, encoding, dir) {
    validateBuffer(buffer);
  
    if (typeof byteOffset === 'string') {
      encoding = byteOffset;
      byteOffset = undefined;
    } else if (byteOffset > 0x7fffffff) {
      byteOffset = 0x7fffffff;
    } else if (byteOffset < -0x80000000) {
      byteOffset = -0x80000000;
    }
    // Coerce to Number. Values like null and [] become 0.
    byteOffset = +byteOffset;
    // If the offset is undefined, "foo", {}, coerces to NaN, search whole buffer.
    if (NumberIsNaN(byteOffset)) {
      byteOffset = dir ? 0 : (buffer.length || buffer.byteLength);
    }
    dir = !!dir;  // Cast to bool.
  
    if (typeof val === 'number')
      return indexOfNumber(buffer, val >>> 0, byteOffset, dir, end);
  
    let ops;
    if (encoding === undefined)
      ops = encodingOps.utf8;
    else
      ops = getEncodingOps(encoding);
  
    if (typeof val === 'string') {
      if (ops === undefined)
        throw new ERR_UNKNOWN_ENCODING(encoding);
      return ops.indexOf(buffer, val, byteOffset, dir, end);
    }
  
    if (isUint8Array(val)) {
      const encodingVal =
        (ops === undefined ? encodingsMap.utf8 : ops.encodingVal);
      return indexOfBuffer(buffer, val, byteOffset, encodingVal, dir, end);
    }
  
    throw new ERR_INVALID_ARG_TYPE(
      'value', ['number', 'string', 'Buffer', 'Uint8Array'], val,
    );
  }
  
  Buffer.prototype.indexOf = function indexOf(val, offset, end, encoding) {
    if (typeof end === 'string') {
      encoding = end;
      end = this.length;
    } else if (end === undefined) {
      end = this.length;
    }
    return bidirectionalIndexOf(this, val, offset, end, encoding, true);
  };
  
  Buffer.prototype.lastIndexOf = function lastIndexOf(val, offset, end, encoding) {
    if (typeof end === 'string') {
      encoding = end;
      end = this.length;
    } else if (end === undefined) {
      end = this.length;
    }
    return bidirectionalIndexOf(this, val, offset, end, encoding, false);
  };
  
  Buffer.prototype.includes = function includes(val, offset, end, encoding) {
    if (typeof end === 'string') {
      encoding = end;
      end = this.length;
    } else if (end === undefined) {
      end = this.length;
    }
    return bidirectionalIndexOf(this, val, offset, end, encoding, true) !== -1;
  };
  
  // Usage:
  //    buffer.fill(number[, offset[, end]])
  //    buffer.fill(buffer[, offset[, end]])
  //    buffer.fill(string[, offset[, end]][, encoding])
  Buffer.prototype.fill = function fill(value, offset, end, encoding) {
    return _fill(this, value, offset, end, encoding);
  };
  
  function _fill(buf, value, offset, end, encoding) {
    if (typeof value === 'string') {
      if (offset === undefined || typeof offset === 'string') {
        encoding = offset;
        offset = 0;
        end = buf.length;
      } else if (typeof end === 'string') {
        encoding = end;
        end = buf.length;
      }
  
      const normalizedEncoding = normalizeEncoding(encoding);
      if (normalizedEncoding === undefined) {
        validateString(encoding, 'encoding');
        throw new ERR_UNKNOWN_ENCODING(encoding);
      }
  
      if (value.length === 0) {
        // If value === '' default to zero.
        value = 0;
      } else if (value.length === 1) {
        // Fast path: If `value` fits into a single byte, use that numeric value.
        // ASCII shares this branch with utf8 since code < 128 covers the full
        // ASCII range; anything outside falls through to C++ bindingFill.
        if (normalizedEncoding === 'utf8' || normalizedEncoding === 'ascii') {
          const code = StringPrototypeCharCodeAt(value, 0);
          if (code < 128) {
            value = code;
          }
        } else if (normalizedEncoding === 'latin1') {
          value = StringPrototypeCharCodeAt(value, 0);
        }
      }
    } else {
      encoding = undefined;
    }
  
    if (offset === undefined) {
      offset = 0;
      end = buf.length;
    } else {
      validateOffset(offset, 'offset');
      // Invalid ranges are not set to a default, so can range check early.
      if (end === undefined) {
        end = buf.length;
      } else {
        validateOffset(end, 'end', 0, buf.length);
      }
      if (offset >= end)
        return buf;
    }
  
  
    if (typeof value === 'number') {
      // OOB check
      const byteLen = TypedArrayPrototypeGetByteLength(buf);
      const fillLength = end - offset;
      if (offset > end || fillLength + offset > byteLen)
        throw new ERR_BUFFER_OUT_OF_BOUNDS();
  
      TypedArrayPrototypeFill(buf, value, offset, end);
    } else {
      const res = bindingFill(buf, value, offset, end, encoding);
      if (res < 0) {
        if (res === -1)
          throw new ERR_INVALID_ARG_VALUE('value', value);
        throw new ERR_BUFFER_OUT_OF_BOUNDS();
      }
    }
  
    return buf;
  }
  
  Buffer.prototype.write = function write(string, offset, length, encoding) {
    const bufferLength = TypedArrayPrototypeGetLength(this);
    // Buffer#write(string);
    if (offset === undefined) {
      return utf8Write(this, string, 0, bufferLength);
    }
    // Buffer#write(string, encoding)
    if (length === undefined && typeof offset === 'string') {
      encoding = offset;
      length = bufferLength;
      offset = 0;
  
    // Buffer#write(string, offset[, length][, encoding])
    } else {
      validateOffset(offset, 'offset', 0, bufferLength);
  
      const remaining = bufferLength - offset;
  
      if (length === undefined) {
        length = remaining;
      } else if (typeof length === 'string') {
        encoding = length;
        length = remaining;
      } else {
        validateOffset(length, 'length', 0, bufferLength);
        if (length > remaining)
          length = remaining;
      }
    }
  
    if (!encoding || encoding === 'utf8')
      return utf8Write(this, string, offset, length);
    if (encoding === 'ascii')
      return asciiWrite(this, string, offset, length);
  
    const ops = getEncodingOps(encoding);
    if (ops === undefined)
      throw new ERR_UNKNOWN_ENCODING(encoding);
    return ops.write(this, string, offset, length);
  };
  
  Buffer.prototype.toJSON = function toJSON() {
    const bufferLength = TypedArrayPrototypeGetLength(this);
    if (bufferLength > 0) {
      const data = new Array(bufferLength);
      for (let i = 0; i < bufferLength; ++i)
        data[i] = this[i];
      return { type: 'Buffer', data };
    }
    return { type: 'Buffer', data: [] };
  };
  
  function adjustOffset(offset, length) {
    // Use Math.trunc() to convert offset to an integer value that can be larger
    // than an Int32. Hence, don't use offset | 0 or similar techniques.
    offset = MathTrunc(offset);
    if (offset === 0) {
      return 0;
    }
    if (offset < 0) {
      offset += length;
      return offset > 0 ? offset : 0;
    }
    if (offset < length) {
      return offset;
    }
    return NumberIsNaN(offset) ? 0 : length;
  }
  
  Buffer.prototype.subarray = function subarray(start, end) {
    const srcLength = TypedArrayPrototypeGetLength(this);
    start = adjustOffset(start, srcLength);
    end = end !== undefined ? adjustOffset(end, srcLength) : srcLength;
    const newLength = end > start ? end - start : 0;
    return new FastBuffer(this.buffer, this.byteOffset + start, newLength);
  };
  
  Buffer.prototype.slice = function slice(start, end) {
    return this.subarray(start, end);
  };
  
  function swap(b, n, m) {
    const i = b[n];
    b[n] = b[m];
    b[m] = i;
  }
  
  Buffer.prototype.swap16 = function swap16() {
    // Ref: https://github.com/nodejs/node/pull/61871#discussion_r2889557696
    // For Buffer.length <= 32, it's generally faster to
    // do the swap in javascript. For larger buffers,
    // dropping down to the native code is faster.
    const len = TypedArrayPrototypeGetLength(this);
    if (len % 2 !== 0)
      throw new ERR_INVALID_BUFFER_SIZE('16-bits');
    if (len <= 32) {
      for (let i = 0; i < len; i += 2)
        swap(this, i, i + 1);
      return this;
    }
    _swap16(this);
    return this;
  };
  
  Buffer.prototype.swap32 = function swap32() {
    // Ref: https://github.com/nodejs/node/pull/61871#discussion_r2889557696
    // For Buffer.length <= 32, it's generally faster to
    // do the swap in javascript. For larger buffers,
    // dropping down to the native code is faster.
    const len = TypedArrayPrototypeGetLength(this);
    if (len % 4 !== 0)
      throw new ERR_INVALID_BUFFER_SIZE('32-bits');
    if (len <= 32) {
      for (let i = 0; i < len; i += 4) {
        swap(this, i, i + 3);
        swap(this, i + 1, i + 2);
      }
      return this;
    }
    _swap32(this);
    return this;
  };
  
  Buffer.prototype.swap64 = function swap64() {
    // Ref: https://github.com/nodejs/node/pull/61871#discussion_r2889557696
    // For Buffer.length < 48, it's generally faster to
    // do the swap in javascript. For larger buffers,
    // dropping down to the native code is faster.
    // Threshold differs from swap16/swap32 (<=32) because swap64's
    // crossover is between 40 and 48 (native wins at 48, loses at 40).
    const len = TypedArrayPrototypeGetLength(this);
    if (len % 8 !== 0)
      throw new ERR_INVALID_BUFFER_SIZE('64-bits');
    if (len < 48) {
      for (let i = 0; i < len; i += 8) {
        swap(this, i, i + 7);
        swap(this, i + 1, i + 6);
        swap(this, i + 2, i + 5);
        swap(this, i + 3, i + 4);
      }
      return this;
    }
    _swap64(this);
    return this;
  };
  
  Buffer.prototype.toLocaleString = Buffer.prototype.toString;
  
  let transcode;
  if (internalBinding('config').hasIntl) {
    const {
      icuErrName,
      transcode: _transcode,
    } = internalBinding('icu');
  
    // Transcodes the Buffer from one encoding to another, returning a new
    // Buffer instance.
    transcode = function transcode(source, fromEncoding, toEncoding) {
      if (!isUint8Array(source)) {
        throw new ERR_INVALID_ARG_TYPE('source',
                                       ['Buffer', 'Uint8Array'], source);
      }
      if (source.length === 0) return new FastBuffer();
  
      fromEncoding = normalizeEncoding(fromEncoding) || fromEncoding;
      toEncoding = normalizeEncoding(toEncoding) || toEncoding;
      const result = _transcode(source, fromEncoding, toEncoding);
      if (typeof result !== 'number')
        return result;
  
      const code = icuErrName(result);
      const err = genericNodeError(
        `Unable to transcode Buffer [${code}]`,
        { code: code, errno: result },
      );
      throw err;
    };
  }
  
  function btoa(input) {
    // The implementation here has not been performance optimized in any way and
    // should not be.
    // Refs: https://github.com/nodejs/node/pull/38433#issuecomment-[REDACTED_SSN]
    if (arguments.length === 0) {
      throw new ERR_MISSING_ARGS('input');
    }
    const result = _btoa(`${input}`);
    if (result === -1) {
      throw lazyDOMException('Invalid character', 'InvalidCharacterError');
    }
    return result;
  }
  
  function atob(input) {
    if (arguments.length === 0) {
      throw new ERR_MISSING_ARGS('input');
    }
  
    const result = _atob(`${input}`);
  
    switch (result) {
      case -2: // Invalid character
        throw lazyDOMException('Invalid character', 'InvalidCharacterError');
      case -1: // Single character remained
        throw lazyDOMException(
          'The string to be decoded is not correctly encoded.',
          'InvalidCharacterError');
      case -3: // Possible overflow
        // TODO(@anonrig): Throw correct error in here.
        throw lazyDOMException('The input causes overflow.', 'InvalidCharacterError');
      default:
        return result;
    }
  }
  
  function isUtf8(input) {
    if (isTypedArray(input) || isAnyArrayBuffer(input)) {
      return bindingIsUtf8(input);
    }
  
    throw new ERR_INVALID_ARG_TYPE('input', ['ArrayBuffer', 'Buffer', 'TypedArray'], input);
  }
  
  function isAscii(input) {
    if (isTypedArray(input) || isAnyArrayBuffer(input)) {
      return bindingIsAscii(input);
    }
  
    throw new ERR_INVALID_ARG_TYPE('input', ['ArrayBuffer', 'Buffer', 'TypedArray'], input);
  }
  
  module.exports = {
    Buffer,
    transcode,
    isUtf8,
    isAscii,
  
    // Legacy
    kMaxLength,
    kStringMaxLength,
    btoa,
    atob,
  };
  
  ObjectDefineProperties(module.exports, {
    constants: {
      __proto__: null,
      configurable: false,
      enumerable: true,
      value: constants,
    },
    INSPECT_MAX_BYTES: {
      __proto__: null,
      configurable: true,
      enumerable: true,
      get() { return INSPECT_MAX_BYTES; },
      set(val) {
        validateNumber(val, 'INSPECT_MAX_BYTES', 0);
        INSPECT_MAX_BYTES = val;
      },
    },
  });
  
  defineLazyProperties(
    module.exports,
    'internal/blob',
    ['Blob', 'resolveObjectURL'],
  );
  defineLazyProperties(
    module.exports,
    'internal/file',
    ['File'],
  );
  