'use strict'; const binding = process.binding('buffer'); const { ERR_BUFFER_OUT_OF_BOUNDS, ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE } = require('internal/errors').codes; const { setupBufferJS } = binding; // Remove from the binding so that function is only available as exported here. // (That is, for internal use only.) delete binding.setupBufferJS; // Temporary buffers to convert numbers. const float32Array = new Float32Array(1); const uInt8Float32Array = new Uint8Array(float32Array.buffer); const float64Array = new Float64Array(1); const uInt8Float64Array = new Uint8Array(float64Array.buffer); // Check endianness. float32Array[0] = -1; // 0xBF800000 // Either it is [0, 0, 128, 191] or [191, 128, 0, 0]. It is not possible to // check this with `os.endianness()` because that is determined at compile time. const bigEndian = uInt8Float32Array[3] === 0; function checkBounds(buf, offset, byteLength) { checkNumberType(offset); if (buf[offset] === undefined || buf[offset + byteLength] === undefined) boundsError(offset, buf.length - (byteLength + 1)); } function checkInt(value, min, max, buf, offset, byteLength) { if (value > max || value < min) { throw new ERR_OUT_OF_RANGE('value', `>= ${min} and <= ${max}`, value); } checkBounds(buf, offset, byteLength); } function checkNumberType(value, type) { if (typeof value !== 'number') { throw new ERR_INVALID_ARG_TYPE(type || 'offset', 'number', value); } } function boundsError(value, length, type) { if (Math.floor(value) !== value) { checkNumberType(value, type); throw new ERR_OUT_OF_RANGE(type || 'offset', 'an integer', value); } if (length < 0) throw new ERR_BUFFER_OUT_OF_BOUNDS(); throw new ERR_OUT_OF_RANGE(type || 'offset', `>= ${type ? 1 : 0} and <= ${length}`, value); } // Read integers. function readUIntLE(offset, byteLength) { if (offset === undefined) throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); if (byteLength === 6) return readUInt48LE(this, offset); if (byteLength === 5) return readUInt40LE(this, offset); if (byteLength === 3) return readUInt24LE(this, offset); if (byteLength === 4) return this.readUInt32LE(offset); if (byteLength === 2) return this.readUInt16LE(offset); if (byteLength === 1) return this.readUInt8(offset); boundsError(byteLength, 6, 'byteLength'); } function readUInt48LE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 6); return first + buf[++offset] * 2 ** 8 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 24 + (buf[++offset] + last * 2 ** 8) * 2 ** 32; } function readUInt40LE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 5); return first + buf[++offset] * 2 ** 8 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 24 + last * 2 ** 32; } function readUInt32LE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) boundsError(offset, this.length - 4); return first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + last * 2 ** 24; } function readUInt24LE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 3); return first + buf[++offset] * 2 ** 8 + last * 2 ** 16; } function readUInt16LE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) boundsError(offset, this.length - 2); return first + last * 2 ** 8; } function readUInt8(offset = 0) { checkNumberType(offset); const val = this[offset]; if (val === undefined) boundsError(offset, this.length - 1); return val; } function readUIntBE(offset, byteLength) { if (offset === undefined) throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); if (byteLength === 6) return readUInt48BE(this, offset); if (byteLength === 5) return readUInt40BE(this, offset); if (byteLength === 3) return readUInt24BE(this, offset); if (byteLength === 4) return this.readUInt32BE(offset); if (byteLength === 2) return this.readUInt16BE(offset); if (byteLength === 1) return this.readUInt8(offset); boundsError(byteLength, 6, 'byteLength'); } function readUInt48BE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 6); return (first * 2 ** 8 + buf[++offset]) * 2 ** 32 + buf[++offset] * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + last; } function readUInt40BE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 5); return first * 2 ** 32 + buf[++offset] * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + last; } function readUInt32BE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) boundsError(offset, this.length - 4); return first * 2 ** 24 + this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last; } function readUInt24BE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 3); return first * 2 ** 16 + buf[++offset] * 2 ** 8 + last; } function readUInt16BE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) boundsError(offset, this.length - 2); return first * 2 ** 8 + last; } function readIntLE(offset, byteLength) { if (offset === undefined) throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); if (byteLength === 6) return readInt48LE(this, offset); if (byteLength === 5) return readInt40LE(this, offset); if (byteLength === 3) return readInt24LE(this, offset); if (byteLength === 4) return this.readInt32LE(offset); if (byteLength === 2) return this.readInt16LE(offset); if (byteLength === 1) return this.readInt8(offset); boundsError(byteLength, 6, 'byteLength'); } function readInt48LE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 6); const val = buf[offset + 4] + last * 2 ** 8; return (val | (val & 2 ** 15) * 0x1fffe) * 2 ** 32 + first + buf[++offset] * 2 ** 8 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 24; } function readInt40LE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 5); return (last | (last & 2 ** 7) * 0x1fffffe) * 2 ** 32 + first + buf[++offset] * 2 ** 8 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 24; } function readInt32LE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) boundsError(offset, this.length - 4); return first + this[++offset] * 2 ** 8 + this[++offset] * 2 ** 16 + (last << 24); // Overflow } function readInt24LE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 3); const val = first + buf[++offset] * 2 ** 8 + last * 2 ** 16; return val | (val & 2 ** 23) * 0x1fe; } function readInt16LE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) boundsError(offset, this.length - 2); const val = first + last * 2 ** 8; return val | (val & 2 ** 15) * 0x1fffe; } function readInt8(offset = 0) { checkNumberType(offset); const val = this[offset]; if (val === undefined) boundsError(offset, this.length - 1); return val | (val & 2 ** 7) * 0x1fffffe; } function readIntBE(offset, byteLength) { if (offset === undefined) throw new ERR_INVALID_ARG_TYPE('offset', 'number', offset); if (byteLength === 6) return readInt48BE(this, offset); if (byteLength === 5) return readInt40BE(this, offset); if (byteLength === 3) return readInt24BE(this, offset); if (byteLength === 4) return this.readInt32BE(offset); if (byteLength === 2) return this.readInt16BE(offset); if (byteLength === 1) return this.readInt8(offset); boundsError(byteLength, 6, 'byteLength'); } function readInt48BE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 5]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 6); const val = buf[++offset] + first * 2 ** 8; return (val | (val & 2 ** 15) * 0x1fffe) * 2 ** 32 + buf[++offset] * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + last; } function readInt40BE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 4]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 5); return (first | (first & 2 ** 7) * 0x1fffffe) * 2 ** 32 + buf[++offset] * 2 ** 24 + buf[++offset] * 2 ** 16 + buf[++offset] * 2 ** 8 + last; } function readInt32BE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) boundsError(offset, this.length - 4); return (first << 24) + // Overflow this[++offset] * 2 ** 16 + this[++offset] * 2 ** 8 + last; } function readInt24BE(buf, offset = 0) { checkNumberType(offset); const first = buf[offset]; const last = buf[offset + 2]; if (first === undefined || last === undefined) boundsError(offset, buf.length - 3); const val = first * 2 ** 16 + buf[++offset] * 2 ** 8 + last; return val | (val & 2 ** 23) * 0x1fe; } function readInt16BE(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 1]; if (first === undefined || last === undefined) boundsError(offset, this.length - 2); const val = first * 2 ** 8 + last; return val | (val & 2 ** 15) * 0x1fffe; } // Read floats function readFloatBackwards(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) boundsError(offset, this.length - 4); uInt8Float32Array[3] = first; uInt8Float32Array[2] = this[++offset]; uInt8Float32Array[1] = this[++offset]; uInt8Float32Array[0] = last; return float32Array[0]; } function readFloatForwards(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 3]; if (first === undefined || last === undefined) boundsError(offset, this.length - 4); uInt8Float32Array[0] = first; uInt8Float32Array[1] = this[++offset]; uInt8Float32Array[2] = this[++offset]; uInt8Float32Array[3] = last; return float32Array[0]; } function readDoubleBackwards(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 7]; if (first === undefined || last === undefined) boundsError(offset, this.length - 8); uInt8Float64Array[7] = first; uInt8Float64Array[6] = this[++offset]; uInt8Float64Array[5] = this[++offset]; uInt8Float64Array[4] = this[++offset]; uInt8Float64Array[3] = this[++offset]; uInt8Float64Array[2] = this[++offset]; uInt8Float64Array[1] = this[++offset]; uInt8Float64Array[0] = last; return float64Array[0]; } function readDoubleForwards(offset = 0) { checkNumberType(offset); const first = this[offset]; const last = this[offset + 7]; if (first === undefined || last === undefined) boundsError(offset, this.length - 8); uInt8Float64Array[0] = first; uInt8Float64Array[1] = this[++offset]; uInt8Float64Array[2] = this[++offset]; uInt8Float64Array[3] = this[++offset]; uInt8Float64Array[4] = this[++offset]; uInt8Float64Array[5] = this[++offset]; uInt8Float64Array[6] = this[++offset]; uInt8Float64Array[7] = last; return float64Array[0]; } // Write integers. function writeUIntLE(value, offset, byteLength) { if (byteLength === 6) return writeU_Int48LE(this, value, offset, 0, 0xffffffffffff); if (byteLength === 5) return writeU_Int40LE(this, value, offset, 0, 0xffffffffff); if (byteLength === 3) return writeU_Int24LE(this, value, offset, 0, 0xffffff); if (byteLength === 4) return writeU_Int32LE(this, value, offset, 0, 0xffffffff); if (byteLength === 2) return writeU_Int16LE(this, value, offset, 0, 0xffff); if (byteLength === 1) return writeU_Int8(this, value, offset, 0, 0xff); boundsError(byteLength, 6, 'byteLength'); } function writeU_Int48LE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 5); const newVal = Math.floor(value * 2 ** -32); buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; buf[offset++] = newVal; buf[offset++] = (newVal >>> 8); return offset; } function writeU_Int40LE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 4); const newVal = value; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; buf[offset++] = Math.floor(newVal * 2 ** -32); return offset; } function writeU_Int32LE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 3); buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; return offset; } function writeUInt32LE(value, offset = 0) { return writeU_Int32LE(this, value, offset, 0, 0xffffffff); } function writeU_Int24LE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 2); buf[offset++] = value; value = value >>> 8; buf[offset++] = value; value = value >>> 8; buf[offset++] = value; return offset; } function writeU_Int16LE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 1); buf[offset++] = value; buf[offset++] = (value >>> 8); return offset; } function writeUInt16LE(value, offset = 0) { return writeU_Int16LE(this, value, offset, 0, 0xffff); } function writeU_Int8(buf, value, offset, min, max) { value = +value; // `checkInt()` can not be used here because it checks two entries. checkNumberType(offset); if (value > max || value < min) { throw new ERR_OUT_OF_RANGE('value', `>= ${min} and <= ${max}`, value); } if (buf[offset] === undefined) boundsError(offset, buf.length - 1); buf[offset] = value; return offset + 1; } function writeUInt8(value, offset = 0) { return writeU_Int8(this, value, offset, 0, 0xff); } function writeUIntBE(value, offset, byteLength) { if (byteLength === 6) return writeU_Int48BE(this, value, offset, 0, 0xffffffffffffff); if (byteLength === 5) return writeU_Int40BE(this, value, offset, 0, 0xffffffffff); if (byteLength === 3) return writeU_Int24BE(this, value, offset, 0, 0xffffff); if (byteLength === 4) return writeU_Int32BE(this, value, offset, 0, 0xffffffff); if (byteLength === 2) return writeU_Int16BE(this, value, offset, 0, 0xffff); if (byteLength === 1) return writeU_Int8(this, value, offset, 0, 0xff); boundsError(byteLength, 6, 'byteLength'); } function writeU_Int48BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 5); const newVal = Math.floor(value * 2 ** -32); buf[offset++] = (newVal >>> 8); buf[offset++] = newVal; buf[offset + 3] = value; value = value >>> 8; buf[offset + 2] = value; value = value >>> 8; buf[offset + 1] = value; value = value >>> 8; buf[offset] = value; return offset + 4; } function writeU_Int40BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 4); buf[offset++] = Math.floor(value * 2 ** -32); buf[offset + 3] = value; value = value >>> 8; buf[offset + 2] = value; value = value >>> 8; buf[offset + 1] = value; value = value >>> 8; buf[offset] = value; return offset + 4; } function writeU_Int32BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 3); buf[offset + 3] = value; value = value >>> 8; buf[offset + 2] = value; value = value >>> 8; buf[offset + 1] = value; value = value >>> 8; buf[offset] = value; return offset + 4; } function writeUInt32BE(value, offset = 0) { return writeU_Int32BE(this, value, offset, 0, 0xffffffff); } function writeU_Int24BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 2); buf[offset + 2] = value; value = value >>> 8; buf[offset + 1] = value; value = value >>> 8; buf[offset] = value; return offset + 3; } function writeU_Int16BE(buf, value, offset, min, max) { value = +value; checkInt(value, min, max, buf, offset, 1); buf[offset++] = (value >>> 8); buf[offset++] = value; return offset; } function writeUInt16BE(value, offset = 0) { return writeU_Int16BE(this, value, offset, 0, 0xffffffff); } function writeIntLE(value, offset, byteLength) { if (byteLength === 6) return writeU_Int48LE(this, value, offset, -0x800000000000, 0x7fffffffffff); if (byteLength === 5) return writeU_Int40LE(this, value, offset, -0x8000000000, 0x7fffffffff); if (byteLength === 3) return writeU_Int24LE(this, value, offset, -0x800000, 0x7fffff); if (byteLength === 4) return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff); if (byteLength === 2) return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff); if (byteLength === 1) return writeU_Int8(this, value, offset, -0x80, 0x7f); boundsError(byteLength, 6, 'byteLength'); } function writeInt32LE(value, offset = 0) { return writeU_Int32LE(this, value, offset, -0x80000000, 0x7fffffff); } function writeInt16LE(value, offset = 0) { return writeU_Int16LE(this, value, offset, -0x8000, 0x7fff); } function writeInt8(value, offset = 0) { return writeU_Int8(this, value, offset, -0x80, 0x7f); } function writeIntBE(value, offset, byteLength) { if (byteLength === 6) return writeU_Int48BE(this, value, offset, -0x800000000000, 0x7fffffffffff); if (byteLength === 5) return writeU_Int40BE(this, value, offset, -0x8000000000, 0x7fffffffff); if (byteLength === 3) return writeU_Int24BE(this, value, offset, -0x800000, 0x7fffff); if (byteLength === 4) return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff); if (byteLength === 2) return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff); if (byteLength === 1) return writeU_Int8(this, value, offset, -0x80, 0x7f); boundsError(byteLength, 6, 'byteLength'); } function writeInt32BE(value, offset = 0) { return writeU_Int32BE(this, value, offset, -0x80000000, 0x7fffffff); } function writeInt16BE(value, offset = 0) { return writeU_Int16BE(this, value, offset, -0x8000, 0x7fff); } // Write floats. function writeDoubleForwards(val, offset = 0) { val = +val; checkBounds(this, offset, 7); float64Array[0] = val; this[offset++] = uInt8Float64Array[0]; this[offset++] = uInt8Float64Array[1]; this[offset++] = uInt8Float64Array[2]; this[offset++] = uInt8Float64Array[3]; this[offset++] = uInt8Float64Array[4]; this[offset++] = uInt8Float64Array[5]; this[offset++] = uInt8Float64Array[6]; this[offset++] = uInt8Float64Array[7]; return offset; } function writeDoubleBackwards(val, offset = 0) { val = +val; checkBounds(this, offset, 7); float64Array[0] = val; this[offset++] = uInt8Float64Array[7]; this[offset++] = uInt8Float64Array[6]; this[offset++] = uInt8Float64Array[5]; this[offset++] = uInt8Float64Array[4]; this[offset++] = uInt8Float64Array[3]; this[offset++] = uInt8Float64Array[2]; this[offset++] = uInt8Float64Array[1]; this[offset++] = uInt8Float64Array[0]; return offset; } function writeFloatForwards(val, offset = 0) { val = +val; checkBounds(this, offset, 3); float32Array[0] = val; this[offset++] = uInt8Float32Array[0]; this[offset++] = uInt8Float32Array[1]; this[offset++] = uInt8Float32Array[2]; this[offset++] = uInt8Float32Array[3]; return offset; } function writeFloatBackwards(val, offset = 0) { val = +val; checkBounds(this, offset, 3); float32Array[0] = val; this[offset++] = uInt8Float32Array[3]; this[offset++] = uInt8Float32Array[2]; this[offset++] = uInt8Float32Array[1]; this[offset++] = uInt8Float32Array[0]; return offset; } // FastBuffer wil be inserted here by lib/buffer.js module.exports = { setupBufferJS, // Container to export all read write functions. readWrites: { readUIntLE, readUInt32LE, readUInt16LE, readUInt8, readUIntBE, readUInt32BE, readUInt16BE, readIntLE, readInt32LE, readInt16LE, readInt8, readIntBE, readInt32BE, readInt16BE, writeUIntLE, writeUInt32LE, writeUInt16LE, writeUInt8, writeUIntBE, writeUInt32BE, writeUInt16BE, writeIntLE, writeInt32LE, writeInt16LE, writeInt8, writeIntBE, writeInt32BE, writeInt16BE, readFloatLE: bigEndian ? readFloatBackwards : readFloatForwards, readFloatBE: bigEndian ? readFloatForwards : readFloatBackwards, readDoubleLE: bigEndian ? readDoubleBackwards : readDoubleForwards, readDoubleBE: bigEndian ? readDoubleForwards : readDoubleBackwards, writeFloatLE: bigEndian ? writeFloatBackwards : writeFloatForwards, writeFloatBE: bigEndian ? writeFloatForwards : writeFloatBackwards, writeDoubleLE: bigEndian ? writeDoubleBackwards : writeDoubleForwards, writeDoubleBE: bigEndian ? writeDoubleForwards : writeDoubleBackwards } };