Buffer(缓冲器)

源码

'use strict';const {Array,ArrayIsArray,Error,MathFloor,MathMin,MathTrunc,NumberIsNaN,NumberMAX_SAFE_INTEGER,NumberMIN_SAFE_INTEGER,ObjectCreate,ObjectDefineProperties,ObjectDefineProperty,ObjectGetOwnPropertyDescriptor,ObjectGetPrototypeOf,ObjectSetPrototypeOf,SymbolSpecies,SymbolToPrimitive,Uint8ArrayPrototype,
} = primordials;const {byteLengthUtf8,compare: _compare,compareOffset,createFromString,fill: bindingFill,indexOfBuffer,indexOfNumber,indexOfString,swap16: _swap16,swap32: _swap32,swap64: _swap64,kMaxLength,kStringMaxLength,zeroFill: bindingZeroFill
} = internalBinding('buffer');
const {getOwnNonIndexProperties,propertyFilter: {ALL_PROPERTIES,ONLY_ENUMERABLE},
} = internalBinding('util');
const {customInspectSymbol,isInsideNodeModules,normalizeEncoding,kIsEncodingSymbol
} = require('internal/util');
const {isAnyArrayBuffer,isArrayBufferView,isUint8Array
} = require('internal/util/types');
const {inspect: utilInspect
} = require('internal/util/inspect');
const { encodings } = internalBinding('string_decoder');const {codes: {ERR_BUFFER_OUT_OF_BOUNDS,ERR_INVALID_ARG_TYPE,ERR_INVALID_ARG_VALUE,ERR_INVALID_BUFFER_SIZE,ERR_INVALID_OPT_VALUE,ERR_OUT_OF_RANGE,ERR_UNKNOWN_ENCODING},hideStackFrames
} = require('internal/errors');
const {validateBuffer,validateInteger,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
} = require('internal/buffer');const TypedArrayPrototype = ObjectGetPrototypeOf(Uint8ArrayPrototype);const TypedArrayProto_byteLength =ObjectGetOwnPropertyDescriptor(TypedArrayPrototype,'byteLength').get;
const TypedArrayFill = TypedArrayPrototype.fill;FastBuffer.prototype.constructor = Buffer;
Buffer.prototype = FastBuffer.prototype;
addBufferPrototypeMethods(Buffer.prototype);const constants = ObjectDefineProperties({}, {MAX_LENGTH: {value: kMaxLength,writable: false,enumerable: true},MAX_STRING_LENGTH: {value: kStringMaxLength,writable: false,enumerable: true}
});Buffer.poolSize = 8 * 1024;
let poolSize, poolOffset, allocPool;// A toggle used to access the zero fill setting of the array buffer allocator
// in C++.
// |zeroFill| can be undefined when running inside an isolate where we
// do not own the ArrayBuffer allocator.  Zero fill is always on in that case.
const zeroFill = bindingZeroFill || [0];const encodingsMap = ObjectCreate(null);
for (let i = 0; i < encodings.length; ++i)encodingsMap[encodings[i]] = i;function createUnsafeBuffer(size) {zeroFill[0] = 0;try {return new FastBuffer(size);} finally {zeroFill[0] = 1;}
}function createPool() {poolSize = Buffer.poolSize;allocPool = createUnsafeBuffer(poolSize).buffer;markAsUntransferable(allocPool);poolOffset = 0;
}
createPool();function alignPool() {// Ensure aligned slicesif (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())) {// 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`.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 _copy(source, target, targetStart, sourceStart, sourceEnd) {if (!isUint8Array(source))throw new ERR_INVALID_ARG_TYPE('source', ['Buffer', 'Uint8Array'], source);if (!isUint8Array(target))throw new ERR_INVALID_ARG_TYPE('target', ['Buffer', 'Uint8Array'], target);if (targetStart === undefined) {targetStart = 0;} else {targetStart = toInteger(targetStart, 0);if (targetStart < 0)throw new ERR_OUT_OF_RANGE('targetStart', '>= 0', targetStart);}if (sourceStart === undefined) {sourceStart = 0;} else {sourceStart = toInteger(sourceStart, 0);if (sourceStart < 0)throw new ERR_OUT_OF_RANGE('sourceStart', '>= 0', sourceStart);}if (sourceEnd === undefined) {sourceEnd = source.length;} else {sourceEnd = toInteger(sourceEnd, 0);if (sourceEnd < 0)throw new ERR_OUT_OF_RANGE('sourceEnd', '>= 0', sourceEnd);}if (targetStart >= target.length || sourceStart >= sourceEnd)return 0;if (sourceStart > source.length) {throw new ERR_OUT_OF_RANGE('sourceStart',`<= ${source.length}`,sourceStart);}return _copyActual(source, target, targetStart, sourceStart, sourceEnd);
}function _copyActual(source, target, targetStart, sourceStart, sourceEnd) {if (sourceEnd - sourceStart > target.length - targetStart)sourceEnd = sourceStart + target.length - targetStart;let nb = sourceEnd - sourceStart;const targetLen = target.length - targetStart;const sourceLen = source.length - sourceStart;if (nb > targetLen)nb = targetLen;if (nb > sourceLen)nb = sourceLen;if (sourceStart !== 0 || sourceEnd < source.length)source = new Uint8Array(source.buffer, source.byteOffset + sourceStart, nb);target.set(source, targetStart);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*/
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, {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]])*/
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);
};// 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 newObj = createUnsafeBuffer(items.length);for (let k = 0; k < items.length; k++)newObj[k] = items[k];return newObj;
};
Buffer.of = of;ObjectSetPrototypeOf(Buffer, Uint8Array);// The 'assertSize' method will remove itself from the callstack when an error
// occurs. This is done simply to keep the internal details of the
// implementation from bleeding out to users.
const assertSize = hideStackFrames((size) => {if (typeof size !== 'number') {throw new ERR_INVALID_ARG_TYPE('size', 'number', size);}if (!(size >= 0 && size <= kMaxLength)) {throw new ERR_INVALID_OPT_VALUE.RangeError('size', size);}
});/*** Creates a new filled Buffer instance.* alloc(size[, fill[, encoding]])*/
Buffer.alloc = function alloc(size, fill, encoding) {assertSize(size);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.*/
Buffer.allocUnsafe = function allocUnsafe(size) {assertSize(size);return allocate(size);
};/*** Equivalent to SlowBuffer(num), 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.*/
Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) {assertSize(size);return createUnsafeBuffer(size);
};// If --zero-fill-buffers command line argument is set, a zero-filled
// buffer is returned.
function SlowBuffer(length) {assertSize(length);return createUnsafeBuffer(length);
}ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8Array.prototype);
ObjectSetPrototypeOf(SlowBuffer, Uint8Array);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 length = ops.byteLength(string);if (length >= (Buffer.poolSize >>> 1))return createFromString(string, ops.encodingVal);if (length > (poolSize - poolOffset))createPool();let b = new FastBuffer(allocPool, poolOffset, length);const actual = ops.write(b, string, 0, length);if (actual !== length) {// byteLength() may overestimate. That's a rare case, though.b = new FastBuffer(allocPool, poolOffset, actual);}poolOffset += actual;alignPool();return b;
}function fromString(string, encoding) {let ops;if (typeof encoding !== 'string' || encoding.length === 0) {if (string.length === 0)return new FastBuffer();ops = encodingOps.utf8;encoding = undefined;} else {ops = getEncodingOps(encoding);if (ops === undefined)throw new ERR_UNKNOWN_ENCODING(encoding);if (string.length === 0)return new FastBuffer();}return fromStringFast(string, ops);
}function fromArrayBuffer(obj, byteOffset, length) {// Convert byteOffset to integerif (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) {length = maxLength;} else {// 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) {if (obj.length <= 0)return new FastBuffer();if (obj.length < (Buffer.poolSize >>> 1)) {if (obj.length > (poolSize - poolOffset))createPool();const b = new FastBuffer(allocPool, poolOffset, obj.length);b.set(obj, 0);poolOffset += obj.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 methodsBuffer.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) {if (!ArrayIsArray(list)) {throw new ERR_INVALID_ARG_TYPE('list', 'Array', list);}if (list.length === 0)return new FastBuffer();if (length === undefined) {length = 0;for (let i = 0; i < list.length; i++) {if (list[i].length) {length += list[i].length;}}} else {validateOffset(length, 'length');}const buffer = Buffer.allocUnsafe(length);let pos = 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'], list[i]);}pos += _copyActual(buf, buffer, pos, 0, buf.length);}// Note: `length` is always equal to `buffer.length` at this pointif (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.TypedArrayFill.call(buffer, 0, pos, length);}return buffer;
};function base64ByteLength(str, bytes) {// Handle paddingif (str.charCodeAt(bytes - 1) === 0x3D)bytes--;if (bytes > 1 && str.charCodeAt(bytes - 1) === 0x3D)bytes--;// Base64 ratio: 3/4return (bytes * 3) >>> 2;
}const encodingOps = {utf8: {encoding: 'utf8',encodingVal: encodingsMap.utf8,byteLength: byteLengthUtf8,write: (buf, string, offset, len) => buf.utf8Write(string, offset, len),slice: (buf, start, end) => buf.utf8Slice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir)},ucs2: {encoding: 'ucs2',encodingVal: encodingsMap.utf16le,byteLength: (string) => string.length * 2,write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),slice: (buf, start, end) => buf.ucs2Slice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir)},utf16le: {encoding: 'utf16le',encodingVal: encodingsMap.utf16le,byteLength: (string) => string.length * 2,write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),slice: (buf, start, end) => buf.ucs2Slice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir)},latin1: {encoding: 'latin1',encodingVal: encodingsMap.latin1,byteLength: (string) => string.length,write: (buf, string, offset, len) => buf.latin1Write(string, offset, len),slice: (buf, start, end) => buf.latin1Slice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir)},ascii: {encoding: 'ascii',encodingVal: encodingsMap.ascii,byteLength: (string) => string.length,write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len),slice: (buf, start, end) => buf.asciiSlice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfBuffer(buf,fromStringFast(val, encodingOps.ascii),byteOffset,encodingsMap.ascii,dir)},base64: {encoding: 'base64',encodingVal: encodingsMap.base64,byteLength: (string) => base64ByteLength(string, string.length),write: (buf, string, offset, len) => buf.base64Write(string, offset, len),slice: (buf, start, end) => buf.base64Slice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfBuffer(buf,fromStringFast(val, encodingOps.base64),byteOffset,encodingsMap.base64,dir)},hex: {encoding: 'hex',encodingVal: encodingsMap.hex,byteLength: (string) => string.length >>> 1,write: (buf, string, offset, len) => buf.hexWrite(string, offset, len),slice: (buf, start, end) => buf.hexSlice(start, end),indexOf: (buf, val, byteOffset, dir) =>indexOfBuffer(buf,fromStringFast(val, encodingOps.hex),byteOffset,encodingsMap.hex,dir)}
};
function getEncodingOps(encoding) {encoding += '';switch (encoding.length) {case 4:if (encoding === 'utf8') return encodingOps.utf8;if (encoding === 'ucs2') return encodingOps.ucs2;encoding = encoding.toLowerCase();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 = encoding.toLowerCase();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' || encoding.toLowerCase() === 'utf16le')return encodingOps.utf16le;break;case 8:if (encoding === 'utf-16le' || encoding.toLowerCase() === 'utf-16le')return encodingOps.utf16le;break;case 6:if (encoding === 'latin1' || encoding === 'binary')return encodingOps.latin1;if (encoding === 'base64') return encodingOps.base64;encoding = encoding.toLowerCase();if (encoding === 'latin1' || encoding === 'binary')return encodingOps.latin1;if (encoding === 'base64') return encodingOps.base64;break;case 3:if (encoding === 'hex' || encoding.toLowerCase() === 'hex')return encodingOps.hex;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;const mustMatch = (arguments.length > 2 && arguments[2] === true);if (!mustMatch && len === 0)return 0;if (!encoding)return (mustMatch ? -1 : byteLengthUtf8(string));const ops = getEncodingOps(encoding);if (ops === undefined)return (mustMatch ? -1 : byteLengthUtf8(string));return ops.byteLength(string);
}Buffer.byteLength = byteLength;// For backwards compatibility.
ObjectDefineProperty(Buffer.prototype, 'parent', {enumerable: true,get() {if (!(this instanceof Buffer))return undefined;return this.buffer;}
});
ObjectDefineProperty(Buffer.prototype, 'offset', {enumerable: true,get() {if (!(this instanceof Buffer))return undefined;return this.byteOffset;}
});Buffer.prototype.copy =function copy(target, targetStart, sourceStart, sourceEnd) {return _copy(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 this.utf8Slice(0, this.length);}const len = this.length;if (start <= 0)start = 0;else if (start >= len)return '';elsestart |= 0;if (end === undefined || end > len)end = len;elseend |= 0;if (end <= start)return '';if (encoding === undefined)return this.utf8Slice(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;if (this.byteLength !== otherBuffer.byteLength)return false;return this.byteLength === 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 = this.hexSlice(0, actualMax).replace(/(.{2})/g, '$1 ').trim();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 = getOwnNonIndexProperties(this, filter).reduce((obj, key) => {extras = true;obj[key] = this[key];return obj;}, ObjectCreate(null));if (extras) {if (this.length !== 0)str += ', ';// '[Object: null prototype] {'.length === 26// This is guarded with a test.str += utilInspect(obj, {...ctx,breakLength: Infinity,compact: true}).slice(27, -2);}}return `<${this.constructor.name} ${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;elsevalidateOffset(targetStart, 'targetStart');if (targetEnd === undefined)targetEnd = target.length;elsevalidateOffset(targetEnd, 'targetEnd', 0, target.length);if (sourceStart === undefined)sourceStart = 0;elsevalidateOffset(sourceStart, 'sourceStart');if (sourceEnd === undefined)sourceEnd = this.length;elsevalidateOffset(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
// - encoding - an optional encoding, relevant if val is a string
// - dir - true for indexOf, false for lastIndexOf
function bidirectionalIndexOf(buffer, val, byteOffset, 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);let ops;if (encoding === undefined)ops = encodingOps.utf8;elseops = getEncodingOps(encoding);if (typeof val === 'string') {if (ops === undefined)throw new ERR_UNKNOWN_ENCODING(encoding);return ops.indexOf(buffer, val, byteOffset, dir);}if (isUint8Array(val)) {const encodingVal =(ops === undefined ? encodingsMap.utf8 : ops.encodingVal);return indexOfBuffer(buffer, val, byteOffset, encodingVal, dir);}throw new ERR_INVALID_ARG_TYPE('value', ['number', 'string', 'Buffer', 'Uint8Array'], val);
}Buffer.prototype.indexOf = function indexOf(val, byteOffset, encoding) {return bidirectionalIndexOf(this, val, byteOffset, encoding, true);
};Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {return bidirectionalIndexOf(this, val, byteOffset, encoding, false);
};Buffer.prototype.includes = function includes(val, byteOffset, encoding) {return this.indexOf(val, byteOffset, encoding) !== -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.if (normalizedEncoding === 'utf8') {const code = value.charCodeAt(0);if (code < 128) {value = code;}} else if (normalizedEncoding === 'latin1') {value = value.charCodeAt(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 checkconst byteLen = TypedArrayProto_byteLength.call(buf);const fillLength = end - offset;if (offset > end || fillLength + offset > byteLen)throw new ERR_BUFFER_OUT_OF_BOUNDS();TypedArrayFill.call(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) {// Buffer#write(string);if (offset === undefined) {return this.utf8Write(string, 0, this.length);}// Buffer#write(string, encoding)if (length === undefined && typeof offset === 'string') {encoding = offset;length = this.length;offset = 0;// Buffer#write(string, offset[, length][, encoding])} else {validateOffset(offset, 'offset', 0, this.length);const remaining = this.length - offset;if (length === undefined) {length = remaining;} else if (typeof length === 'string') {encoding = length;length = remaining;} else {validateOffset(length, 'length', 0, this.length);if (length > remaining)length = remaining;}}if (!encoding)return this.utf8Write(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() {if (this.length > 0) {const data = new Array(this.length);for (let i = 0; i < this.length; ++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.slice = function slice(start, end) {const srcLength = this.length;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);
};function swap(b, n, m) {const i = b[n];b[n] = b[m];b[m] = i;
}Buffer.prototype.swap16 = function swap16() {// For Buffer.length < 128, it's generally faster to// do the swap in javascript. For larger buffers,// dropping down to the native code is faster.const len = this.length;if (len % 2 !== 0)throw new ERR_INVALID_BUFFER_SIZE('16-bits');if (len < 128) {for (let i = 0; i < len; i += 2)swap(this, i, i + 1);return this;}return _swap16(this);
};Buffer.prototype.swap32 = function swap32() {// For Buffer.length < 192, it's generally faster to// do the swap in javascript. For larger buffers,// dropping down to the native code is faster.const len = this.length;if (len % 4 !== 0)throw new ERR_INVALID_BUFFER_SIZE('32-bits');if (len < 192) {for (let i = 0; i < len; i += 4) {swap(this, i, i + 3);swap(this, i + 1, i + 2);}return this;}return _swap32(this);
};Buffer.prototype.swap64 = function swap64() {// For Buffer.length < 192, it's generally faster to// do the swap in javascript. For larger buffers,// dropping down to the native code is faster.const len = this.length;if (len % 8 !== 0)throw new ERR_INVALID_BUFFER_SIZE('64-bits');if (len < 192) {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;}return _swap64(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 Buffer.alloc(0);fromEncoding = normalizeEncoding(fromEncoding) || fromEncoding;toEncoding = normalizeEncoding(toEncoding) || toEncoding;const result = _transcode(source, fromEncoding, toEncoding);if (typeof result !== 'number')return result;const code = icuErrName(result);// eslint-disable-next-line no-restricted-syntaxconst err = new Error(`Unable to transcode Buffer [${code}]`);err.code = code;err.errno = result;throw err;};
}module.exports = {Buffer,SlowBuffer,transcode,// LegacykMaxLength,kStringMaxLength
};ObjectDefineProperties(module.exports, {constants: {configurable: false,enumerable: true,value: constants},INSPECT_MAX_BYTES: {configurable: true,enumerable: true,get() { return INSPECT_MAX_BYTES; },set(val) { INSPECT_MAX_BYTES = val; }}
});
  • Buffer对象用于表示固定长度的字节序列
  • Buffer类是JavaScript的Uint8Array类的子类,且继承时带上了涵盖外用例的方法
  • Buffer类在全局作用域中,因此无需使用require(‘buffer’).Buffer
// 创建一个长度为 10 的 Buffer,
// 其中填充了全部值为 `1` 的字节。
const buf1 = Buffer.alloc(10);// 创建一个长度为 10、且用 0x1 填充的 Buffer。
const buf2 = Buffer.alloc(10, 1);// 创建一个长度为 10、且未初始化的 Buffer。
// 这个方法比调用 Buffer.alloc() 更快,
// 但返回的 Buffer 实例可能包含旧数据,
// 因此需要使用 fill()、write() 或其他能填充 Buffer 的内容的函数进行重写。
const buf3 = Buffer.allocUnsafe(10);// 创建一个包含字节 [1, 2, 3] 的 Buffer。
const buf4 = Buffer.from([1, 2, 3]);// 创建一个包含字节 [1, 1, 1, 1] 的 Buffer,
// 其中所有条目均使用 `(value & 255)` 进行截断以符合 0-255 的范围。
const buf5 = Buffer.from([257, 257.5, -255, '1']);// 创建一个 Buffer,其中包含字符串 'tést' 的 UTF-8 编码字节:
// [0x74, 0xc3, 0xa9, 0x73, 0x74](以十六进制表示)
// [116, 195, 169, 115, 116](以十进制表示)
const buf6 = Buffer.from('tést');// 创建一个包含 Latin-1 字节 [0x74, 0xe9, 0x73, 0x74] 的 Buffer。
const buf7 = Buffer.from('tést', 'latin1');

Buffer与字符编码

  • 当在Buffer和字符串之间转换时,可以指定字符编码,如果未指定字符编码,则使用UTF-8作为默认值
const buf = Buffer.from('hello world', 'utf8');console.log(buf.toString('hex'));
// 打印: 68656c6c6f20776f726c64
console.log(buf.toString('base64'));
// 打印: aGVsbG8gd29ybGQ=console.log(Buffer.from('fhqwhgads', 'utf8'));
// 打印: <Buffer 66 68 71 77 68 67 61 64 73>
console.log(Buffer.from('fhqwhgads', 'utf16le'));
// 打印: <Buffer 66 00 68 00 71 00 77 00 68 00 67 00 61 00 64 00 73 00>

  • ‘utf8’: 多字节编码的 Unicode 字符。 许多网页和其他文档格式都使用 UTF-8。 这是默认的字符编码。 当将 Buffer 解码为不专门包含有效 UTF-8 数据的字符串时,则会使用 Unicode 替换字符 U+FFFD来表示这些错误。
  • ‘utf16le’: 多字节编码的 Unicode 字符。 与 ‘utf8’ 不同,字符串中的每个字符都会使用 2 个或 4 个字节进行编码。 Node.js 仅支持 UTF-16 的小端序变体。
  • 'latin1: Latin-1 代表 ISO-8859-1。 此字符编码仅支持从U+0000到 U+00FF的 Unicode 字符。 每个字符使用单个字节进行编码。 超出该范围的字符会被截断,并映射成该范围内的字符。

使用以上方法之一将 Buffer 转换为字符串,称为解码;将字符串转换为Buffer,称为编码。

Buffer.from('1ag', 'hex');
// 打印 <Buffer 1a>,当遇到第一个非十六进制的值('g')时,则数据会被截断。Buffer.from('1a7g', 'hex');
// 打印 <Buffer 1a>,当数据以一个数字('7')结尾时,则数据会被截断。Buffer.from('1634', 'hex');
// 打印 <Buffer 16 34>,所有数据均可用。

Buffer与TypedArry

Buffer实例也是在JavaScript的Uint8Arry和TypeArray实例,所有的TypeArray方法在Buffer上也可用,但是,Buffer的API和TypedArray的API之间存在细微的不兼容

主要表现

  • TypedArray#slice()会创建TypeArray的片段的拷贝,而Buffer#slice()是在现有的Buffer上创建视图而不进行拷贝,此行为可能产生意外,并且仅用旧版的兼容性,TypedArray#subarray()可用于在Buffer和其它TypedArray上实现Buffer#slice()的行为
  • buf.tpString()与它在TypedArray上的等价物并不兼容

两种方法可以从一个Buffer创建新的TypeArray实例

  • 将Buffer传给TypeArray的构造函数,则会拷贝Buffer的内容(会被解析为整数数组,而不是目标类型的字节序列)

    const buf = Buffer.from([1, 2, 3, 4]);
    const uint32array = new Uint32Array(buf);console.log(uint32array);
    
  • 传入Buffer底层的ArrayBuffer,则会创建与Buffer共享其内存的TypedArray

    const buf = Buffer.from('hello', 'utf16le');
    const uint16array = new Uint16Array(buf.buffer,buf.byteOffset,buf.length / Uint16Array.BYTES_PER_ELEMENT);console.log(uint16array);
    

  • 通过使用TypedArray对象的.buffer属性,以相同的方式来创建一个与TypedArray实例共享相同分配内存的新Buffer,在这种情况下,Buffer.from()的行为类似于new Uint8Array()

    const arr = new Uint16Array(2);arr[0] = 5000;
    arr[1] = 4000;// 拷贝 `arr` 的内容。
    const buf1 = Buffer.from(arr);// 与 `arr` 共享内存。
    const buf2 = Buffer.from(arr.buffer);console.log(buf1);
    // 打印: <Buffer 88 a0>
    console.log(buf2);
    // 打印: <Buffer 88 13 a0 0f>arr[1] = 6000;console.log(buf1);
    // 打印: <Buffer 88 a0>
    console.log(buf2);
    

当使用TypedArray的.buffer创建Buffer时,也可以通过传入byteOffset和length参数只使用底层ArrayBuffer的一部分

const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);console.log(buf.length);

注意:Buffer.from()与TypedArray.from()有着不同的实现,具体来说,TypedArray可以接受第二个函数作为映射函数,在类型数组的每个元素上调用

  • TypedArray.from(source[, mapFn[, thisArg]])

Buffer与迭代器

Buffer实例可以使用for…of语法进行迭代

const buf = Buffer.from([1, 2, 3]);for (const b of buf) {console.log(b);
}const buf = Buffer.from('hello', 'utf16le');const uint16array = new Uint16Array(buf.buffer,buf.byteOffset,buf.length / Uint16Array.BYTES_PER_ELEMENT);console.log(uint16array);

  • 通过使用TypedArray对象的.buffer属性,以相同的方式来创建一个与TypedArray实例共享相同分配内存的新Buffer,在这种情况下,Buffer.from()的行为类似于new Uint8Array()

    const arr = new Uint16Array(2);arr[0] = 5000;
    arr[1] = 4000;// 拷贝 `arr` 的内容。
    const buf1 = Buffer.from(arr);// 与 `arr` 共享内存。
    const buf2 = Buffer.from(arr.buffer);console.log(buf1);
    // 打印: <Buffer 88 a0>
    console.log(buf2);
    // 打印: <Buffer 88 13 a0 0f>arr[1] = 6000;console.log(buf1);
    // 打印: <Buffer 88 a0>
    console.log(buf2);
    

当使用TypedArray的.buffer创建Buffer时,也可以通过传入byteOffset和length参数只使用底层ArrayBuffer的一部分

const arr = new Uint16Array(20);
const buf = Buffer.from(arr.buffer, 0, 16);console.log(buf.length);

注意:Buffer.from()与TypedArray.from()有着不同的实现,具体来说,TypedArray可以接受第二个函数作为映射函数,在类型数组的每个元素上调用

  • TypedArray.from(source[, mapFn[, thisArg]])

Buffer与迭代器

Buffer实例可以使用for…of语法进行迭代

const buf = Buffer.from([1, 2, 3]);for (const b of buf) {console.log(b);
}

Buffer(缓冲器)相关推荐

  1. 二十五、Node中的Buffer缓冲器和EventEmitter事件触发器

    @Author:Runsen @Date:2020/6/5 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...

  2. golang bytes.buffer 字节缓冲器 简介

    目录 创建 Buffer缓冲器 NewBuffer NewBufferString 向 Buffer 中写入数据 Write WriteString WriteByte WriteRune 完整示例 ...

  3. 时钟BUFFER 介绍 核芯CLB53156 替代SI53156国产替代

    时钟是所有电子产品设备的基本模块,同步数字电路中的每一次data transition都有一个时钟来对寄存器进行控制.数字电路.AD/DA.通信接口等得以正常工作都需要时钟.大多数系统通过晶体或者陶瓷 ...

  4. java 二进制模块_深入Node模块Buffer-学会操作二进制

    Buffer 作为 nodejs 中重要的概念和功能,为开发者提供了操作二进制的能力.本文记录了几个问题,来加深对 Buffer 的理解和使用: 认识缓冲器 如何申请堆外内存 如何计算字节长度 如何计 ...

  5. java nio 写事件_Java NIO

    java Nio Selector 选择器 Buffer 缓冲器 Channel 通道 Selector是NIO的核心,是channel的管理者,通过执行select()阻塞方式,监听是否有chann ...

  6. File-nodejs

    文件系统模块是一个简单包装的标准 POSIX 文件 I/O 操作方法集.您可以通过调用require('fs')来获取该模块.文件系统模块中的所有方法均有异步和同步版本. 文件系统模块中的异步方法需要 ...

  7. Proteus原理图元器件库详细说明

    Proteus原理图元器件库详细说明 当你在用Proteus的时候,你是否真的清楚它们的元件库呢?如果你不清楚的话,也许这个对你有点用!! PROTEUS原理图元器件库详细说明 Device.lib  ...

  8. 约束理论学习随笔(2)---DBR系统

    今天花了些时间看了一下OPT的计划与控制,可以说基于TOC理论的生产排程关键在于识别瓶颈资源,而实际的排程也是根据瓶颈资源设计的.在这里不得不提一下DBR系统(Drum,Buffer,Rope),DB ...

  9. 我的前端教程,不断整理,反复学习,记录着那些年大学奋斗的青春

    @Author:Runsen @Date:2020/6/1 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严重,专业排名 ...

最新文章

  1. eBay:大数据和人工智能是2017年电商发展关键因素
  2. POJ - 3476 A Game with Colored Balls---优先队列+链表(用数组模拟)
  3. 【赠送】IT技术视频教程,白拿不谢!思科、华为、红帽、数据库、云计算等等
  4. oracle数据库pfile文件,Oracle pfile/spfile参数文件详解
  5. Opencl 并行求和
  6. ios 使用webview 查找_iOS开发WKWebView与JS的交互
  7. SQL 智能提示工具
  8. 每位初级开发都应该知道的六件大事
  9. linux 光纤网卡 软路由,请教关于配置双网卡软路由的问题
  10. [转]SSH框架搭建
  11. 数理化计算机电子 武大水平,全方位比较南开大学、武汉大学——以数据为基础.doc...
  12. 自绘LISTVIEW的滚动条(Delphi实现)
  13. 浏览器主页被劫持成360导航.每次打开都是360导航https://hao.360.cn/?src=lmls=n36a7f6a197
  14. PHP初中高级学习在线文档下载
  15. HTML页面如何引入其他HTML页面
  16. php error allowed,ThinkPHP提示错误Fatal error: Allowed memory size的解决方法
  17. 关于flash强制更新:早上上班,多台电脑提示未安装flash
  18. 【实战】通过命令行调用360杀毒软件接口对指定文件或文件夹杀毒
  19. 百度地图、高德地图的数据下载
  20. cesium 泛光 bloom效果

热门文章

  1. [iOS][转]iOS 架构模式 - 简述 MVC, MVP, MVVM 和 VIPER (译)
  2. 快乐共享(By Robinvane Suen)
  3. HHTC第十二届程序设计竞赛
  4. 软考下午常见问题——个人笔记
  5. 阿尔法α-贝塔β剪枝
  6. sklearn+机器学习
  7. Double 保留至小数点后两位
  8. Word Rotator‘s Distance——WRD算法应用
  9. 转载:一位顶级黑客编写的最强反编译器
  10. 普通索引 唯一索引 主键索引 组合索引 全文索引