'use strict'; const { EMPTY_BUFFER } = require('./constants'); /** * Merges an array of buffers into a new buffer. * * @param {Buffer[]} list The array of buffers to concat * @param {Number} totalLength The total length of buffers in the list * @return {Buffer} The resulting buffer * @public */ function concat(list, totalLength) { if (list.length === 0) return EMPTY_BUFFER; if (list.length === 1) return list[0]; const target = Buffer.allocUnsafe(totalLength); let offset = 0; for (let i = 0; i < list.length; i++) { const buf = list[i]; target.set(buf, offset); offset += buf.length; } if (offset < totalLength) return target.slice(0, offset); return target; } /** * Masks a buffer using the given mask. * * @param {Buffer} source The buffer to mask * @param {Buffer} mask The mask to use * @param {Buffer} output The buffer where to store the result * @param {Number} offset The offset at which to start writing * @param {Number} length The number of bytes to mask. * @public */ function _mask(source, mask, output, offset, length) { for (let i = 0; i < length; i++) { output[offset + i] = source[i] ^ mask[i & 3]; } } /** * Unmasks a buffer using the given mask. * * @param {Buffer} buffer The buffer to unmask * @param {Buffer} mask The mask to use * @public */ function _unmask(buffer, mask) { // Required until https://github.com/nodejs/node/issues/9006 is resolved. const length = buffer.length; for (let i = 0; i < length; i++) { buffer[i] ^= mask[i & 3]; } } /** * Converts a buffer to an `ArrayBuffer`. * * @param {Buffer} buf The buffer to convert * @return {ArrayBuffer} Converted buffer * @public */ function toArrayBuffer(buf) { if (buf.byteLength === buf.buffer.byteLength) { return buf.buffer; } return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); } /** * Converts `data` to a `Buffer`. * * @param {*} data The data to convert * @return {Buffer} The buffer * @throws {TypeError} * @public */ function toBuffer(data) { toBuffer.readOnly = true; if (Buffer.isBuffer(data)) return data; let buf; if (data instanceof ArrayBuffer) { buf = Buffer.from(data); } else if (ArrayBuffer.isView(data)) { buf = Buffer.from(data.buffer, data.byteOffset, data.byteLength); } else { buf = Buffer.from(data); toBuffer.readOnly = false; } return buf; } try { const bufferUtil = require('bufferutil'); const bu = bufferUtil.BufferUtil || bufferUtil; module.exports = { concat, mask(source, mask, output, offset, length) { if (length < 48) _mask(source, mask, output, offset, length); else bu.mask(source, mask, output, offset, length); }, toArrayBuffer, toBuffer, unmask(buffer, mask) { if (buffer.length < 32) _unmask(buffer, mask); else bu.unmask(buffer, mask); } }; } catch (e) /* istanbul ignore next */ { module.exports = { concat, mask: _mask, toArrayBuffer, toBuffer, unmask: _unmask }; }