|
|
const ascii = require('./lib/ascii') |
|
|
const base64 = require('./lib/base64') |
|
|
const hex = require('./lib/hex') |
|
|
const utf8 = require('./lib/utf8') |
|
|
const utf16le = require('./lib/utf16le') |
|
|
|
|
|
const LE = new Uint8Array(Uint16Array.of(0xff).buffer)[0] === 0xff |
|
|
|
|
|
function codecFor (encoding) { |
|
|
switch (encoding) { |
|
|
case 'ascii': |
|
|
return ascii |
|
|
case 'base64': |
|
|
return base64 |
|
|
case 'hex': |
|
|
return hex |
|
|
case 'utf8': |
|
|
case 'utf-8': |
|
|
case undefined: |
|
|
case null: |
|
|
return utf8 |
|
|
case 'ucs2': |
|
|
case 'ucs-2': |
|
|
case 'utf16le': |
|
|
case 'utf-16le': |
|
|
return utf16le |
|
|
default: |
|
|
throw new Error(`Unknown encoding: ${encoding}`) |
|
|
} |
|
|
} |
|
|
|
|
|
function isBuffer (value) { |
|
|
return value instanceof Uint8Array |
|
|
} |
|
|
|
|
|
function isEncoding (encoding) { |
|
|
try { |
|
|
codecFor(encoding) |
|
|
return true |
|
|
} catch { |
|
|
return false |
|
|
} |
|
|
} |
|
|
|
|
|
function alloc (size, fill, encoding) { |
|
|
const buffer = new Uint8Array(size) |
|
|
if (fill !== undefined) exports.fill(buffer, fill, 0, buffer.byteLength, encoding) |
|
|
return buffer |
|
|
} |
|
|
|
|
|
function allocUnsafe (size) { |
|
|
return new Uint8Array(size) |
|
|
} |
|
|
|
|
|
function allocUnsafeSlow (size) { |
|
|
return new Uint8Array(size) |
|
|
} |
|
|
|
|
|
function byteLength (string, encoding) { |
|
|
return codecFor(encoding).byteLength(string) |
|
|
} |
|
|
|
|
|
function compare (a, b) { |
|
|
if (a === b) return 0 |
|
|
|
|
|
const len = Math.min(a.byteLength, b.byteLength) |
|
|
|
|
|
a = new DataView(a.buffer, a.byteOffset, a.byteLength) |
|
|
b = new DataView(b.buffer, b.byteOffset, b.byteLength) |
|
|
|
|
|
let i = 0 |
|
|
|
|
|
for (let n = len - (len % 4); i < n; i += 4) { |
|
|
const x = a.getUint32(i, LE) |
|
|
const y = b.getUint32(i, LE) |
|
|
if (x !== y) break |
|
|
} |
|
|
|
|
|
for (; i < len; i++) { |
|
|
const x = a.getUint8(i) |
|
|
const y = b.getUint8(i) |
|
|
if (x < y) return -1 |
|
|
if (x > y) return 1 |
|
|
} |
|
|
|
|
|
return a.byteLength > b.byteLength ? 1 : a.byteLength < b.byteLength ? -1 : 0 |
|
|
} |
|
|
|
|
|
function concat (buffers, totalLength) { |
|
|
if (totalLength === undefined) { |
|
|
totalLength = buffers.reduce((len, buffer) => len + buffer.byteLength, 0) |
|
|
} |
|
|
|
|
|
const result = new Uint8Array(totalLength) |
|
|
|
|
|
let offset = 0 |
|
|
for (const buffer of buffers) { |
|
|
if (offset + buffer.byteLength > result.byteLength) { |
|
|
const sub = buffer.subarray(0, result.byteLength - offset) |
|
|
result.set(sub, offset) |
|
|
return result |
|
|
} |
|
|
result.set(buffer, offset) |
|
|
offset += buffer.byteLength |
|
|
} |
|
|
|
|
|
return result |
|
|
} |
|
|
|
|
|
function copy (source, target, targetStart = 0, start = 0, end = source.byteLength) { |
|
|
if (end > 0 && end < start) return 0 |
|
|
if (end === start) return 0 |
|
|
if (source.byteLength === 0 || target.byteLength === 0) return 0 |
|
|
|
|
|
if (targetStart < 0) throw new RangeError('targetStart is out of range') |
|
|
if (start < 0 || start >= source.byteLength) throw new RangeError('sourceStart is out of range') |
|
|
if (end < 0) throw new RangeError('sourceEnd is out of range') |
|
|
|
|
|
if (targetStart >= target.byteLength) targetStart = target.byteLength |
|
|
if (end > source.byteLength) end = source.byteLength |
|
|
if (target.byteLength - targetStart < end - start) { |
|
|
end = target.length - targetStart + start |
|
|
} |
|
|
|
|
|
const len = end - start |
|
|
|
|
|
if (source === target) { |
|
|
target.copyWithin(targetStart, start, end) |
|
|
} else { |
|
|
target.set(source.subarray(start, end), targetStart) |
|
|
} |
|
|
|
|
|
return len |
|
|
} |
|
|
|
|
|
function equals (a, b) { |
|
|
if (a === b) return true |
|
|
if (a.byteLength !== b.byteLength) return false |
|
|
|
|
|
const len = a.byteLength |
|
|
|
|
|
a = new DataView(a.buffer, a.byteOffset, a.byteLength) |
|
|
b = new DataView(b.buffer, b.byteOffset, b.byteLength) |
|
|
|
|
|
let i = 0 |
|
|
|
|
|
for (let n = len - (len % 4); i < n; i += 4) { |
|
|
if (a.getUint32(i, LE) !== b.getUint32(i, LE)) return false |
|
|
} |
|
|
|
|
|
for (; i < len; i++) { |
|
|
if (a.getUint8(i) !== b.getUint8(i)) return false |
|
|
} |
|
|
|
|
|
return true |
|
|
} |
|
|
|
|
|
function fill (buffer, value, offset, end, encoding) { |
|
|
if (typeof value === 'string') { |
|
|
|
|
|
if (typeof offset === 'string') { |
|
|
encoding = offset |
|
|
offset = 0 |
|
|
end = buffer.byteLength |
|
|
|
|
|
|
|
|
} else if (typeof end === 'string') { |
|
|
encoding = end |
|
|
end = buffer.byteLength |
|
|
} |
|
|
} else if (typeof value === 'number') { |
|
|
value = value & 0xff |
|
|
} else if (typeof value === 'boolean') { |
|
|
value = +value |
|
|
} |
|
|
|
|
|
if (offset < 0 || buffer.byteLength < offset || buffer.byteLength < end) { |
|
|
throw new RangeError('Out of range index') |
|
|
} |
|
|
|
|
|
if (offset === undefined) offset = 0 |
|
|
if (end === undefined) end = buffer.byteLength |
|
|
|
|
|
if (end <= offset) return buffer |
|
|
|
|
|
if (!value) value = 0 |
|
|
|
|
|
if (typeof value === 'number') { |
|
|
for (let i = offset; i < end; ++i) { |
|
|
buffer[i] = value |
|
|
} |
|
|
} else { |
|
|
value = isBuffer(value) ? value : from(value, encoding) |
|
|
|
|
|
const len = value.byteLength |
|
|
|
|
|
for (let i = 0; i < end - offset; ++i) { |
|
|
buffer[i + offset] = value[i % len] |
|
|
} |
|
|
} |
|
|
|
|
|
return buffer |
|
|
} |
|
|
|
|
|
function from (value, encodingOrOffset, length) { |
|
|
|
|
|
if (typeof value === 'string') return fromString(value, encodingOrOffset) |
|
|
|
|
|
|
|
|
if (Array.isArray(value)) return fromArray(value) |
|
|
|
|
|
|
|
|
if (ArrayBuffer.isView(value)) return fromBuffer(value) |
|
|
|
|
|
|
|
|
return fromArrayBuffer(value, encodingOrOffset, length) |
|
|
} |
|
|
|
|
|
function fromString (string, encoding) { |
|
|
const codec = codecFor(encoding) |
|
|
const buffer = new Uint8Array(codec.byteLength(string)) |
|
|
codec.write(buffer, string, 0, buffer.byteLength) |
|
|
return buffer |
|
|
} |
|
|
|
|
|
function fromArray (array) { |
|
|
const buffer = new Uint8Array(array.length) |
|
|
buffer.set(array) |
|
|
return buffer |
|
|
} |
|
|
|
|
|
function fromBuffer (buffer) { |
|
|
const copy = new Uint8Array(buffer.byteLength) |
|
|
copy.set(buffer) |
|
|
return copy |
|
|
} |
|
|
|
|
|
function fromArrayBuffer (arrayBuffer, byteOffset, length) { |
|
|
return new Uint8Array(arrayBuffer, byteOffset, length) |
|
|
} |
|
|
|
|
|
function includes (buffer, value, byteOffset, encoding) { |
|
|
return indexOf(buffer, value, byteOffset, encoding) !== -1 |
|
|
} |
|
|
|
|
|
function bidirectionalIndexOf (buffer, value, byteOffset, encoding, first) { |
|
|
if (buffer.byteLength === 0) return -1 |
|
|
|
|
|
if (typeof byteOffset === 'string') { |
|
|
encoding = byteOffset |
|
|
byteOffset = 0 |
|
|
} else if (byteOffset === undefined) { |
|
|
byteOffset = first ? 0 : (buffer.length - 1) |
|
|
} else if (byteOffset < 0) { |
|
|
byteOffset += buffer.byteLength |
|
|
} |
|
|
|
|
|
if (byteOffset >= buffer.byteLength) { |
|
|
if (first) return -1 |
|
|
else byteOffset = buffer.byteLength - 1 |
|
|
} else if (byteOffset < 0) { |
|
|
if (first) byteOffset = 0 |
|
|
else return -1 |
|
|
} |
|
|
|
|
|
if (typeof value === 'string') { |
|
|
value = from(value, encoding) |
|
|
} else if (typeof value === 'number') { |
|
|
value = value & 0xff |
|
|
|
|
|
if (first) { |
|
|
return buffer.indexOf(value, byteOffset) |
|
|
} else { |
|
|
return buffer.lastIndexOf(value, byteOffset) |
|
|
} |
|
|
} |
|
|
|
|
|
if (value.byteLength === 0) return -1 |
|
|
|
|
|
if (first) { |
|
|
let foundIndex = -1 |
|
|
|
|
|
for (let i = byteOffset; i < buffer.byteLength; i++) { |
|
|
if (buffer[i] === value[foundIndex === -1 ? 0 : i - foundIndex]) { |
|
|
if (foundIndex === -1) foundIndex = i |
|
|
if (i - foundIndex + 1 === value.byteLength) return foundIndex |
|
|
} else { |
|
|
if (foundIndex !== -1) i -= i - foundIndex |
|
|
foundIndex = -1 |
|
|
} |
|
|
} |
|
|
} else { |
|
|
if (byteOffset + value.byteLength > buffer.byteLength) { |
|
|
byteOffset = buffer.byteLength - value.byteLength |
|
|
} |
|
|
|
|
|
for (let i = byteOffset; i >= 0; i--) { |
|
|
let found = true |
|
|
|
|
|
for (let j = 0; j < value.byteLength; j++) { |
|
|
if (buffer[i + j] !== value[j]) { |
|
|
found = false |
|
|
break |
|
|
} |
|
|
} |
|
|
|
|
|
if (found) return i |
|
|
} |
|
|
} |
|
|
|
|
|
return -1 |
|
|
} |
|
|
|
|
|
function indexOf (buffer, value, byteOffset, encoding) { |
|
|
return bidirectionalIndexOf(buffer, value, byteOffset, encoding, true ) |
|
|
} |
|
|
|
|
|
function lastIndexOf (buffer, value, byteOffset, encoding) { |
|
|
return bidirectionalIndexOf(buffer, value, byteOffset, encoding, false ) |
|
|
} |
|
|
|
|
|
function swap (buffer, n, m) { |
|
|
const i = buffer[n] |
|
|
buffer[n] = buffer[m] |
|
|
buffer[m] = i |
|
|
} |
|
|
|
|
|
function swap16 (buffer) { |
|
|
const len = buffer.byteLength |
|
|
|
|
|
if (len % 2 !== 0) throw new RangeError('Buffer size must be a multiple of 16-bits') |
|
|
|
|
|
for (let i = 0; i < len; i += 2) swap(buffer, i, i + 1) |
|
|
|
|
|
return buffer |
|
|
} |
|
|
|
|
|
function swap32 (buffer) { |
|
|
const len = buffer.byteLength |
|
|
|
|
|
if (len % 4 !== 0) throw new RangeError('Buffer size must be a multiple of 32-bits') |
|
|
|
|
|
for (let i = 0; i < len; i += 4) { |
|
|
swap(buffer, i, i + 3) |
|
|
swap(buffer, i + 1, i + 2) |
|
|
} |
|
|
|
|
|
return buffer |
|
|
} |
|
|
|
|
|
function swap64 (buffer) { |
|
|
const len = buffer.byteLength |
|
|
|
|
|
if (len % 8 !== 0) throw new RangeError('Buffer size must be a multiple of 64-bits') |
|
|
|
|
|
for (let i = 0; i < len; i += 8) { |
|
|
swap(buffer, i, i + 7) |
|
|
swap(buffer, i + 1, i + 6) |
|
|
swap(buffer, i + 2, i + 5) |
|
|
swap(buffer, i + 3, i + 4) |
|
|
} |
|
|
|
|
|
return buffer |
|
|
} |
|
|
|
|
|
function toBuffer (buffer) { |
|
|
return buffer |
|
|
} |
|
|
|
|
|
function toString (buffer, encoding, start = 0, end = buffer.byteLength) { |
|
|
const len = buffer.byteLength |
|
|
|
|
|
if (start >= len) return '' |
|
|
if (end <= start) return '' |
|
|
if (start < 0) start = 0 |
|
|
if (end > len) end = len |
|
|
|
|
|
if (start !== 0 || end < len) buffer = buffer.subarray(start, end) |
|
|
|
|
|
return codecFor(encoding).toString(buffer) |
|
|
} |
|
|
|
|
|
function write (buffer, string, offset, length, encoding) { |
|
|
|
|
|
if (offset === undefined) { |
|
|
encoding = 'utf8' |
|
|
|
|
|
|
|
|
} else if (length === undefined && typeof offset === 'string') { |
|
|
encoding = offset |
|
|
offset = undefined |
|
|
|
|
|
|
|
|
} else if (encoding === undefined && typeof length === 'string') { |
|
|
encoding = length |
|
|
length = undefined |
|
|
} |
|
|
|
|
|
return codecFor(encoding).write(buffer, string, offset, length) |
|
|
} |
|
|
|
|
|
function writeDoubleLE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setFloat64(offset, value, true) |
|
|
|
|
|
return offset + 8 |
|
|
} |
|
|
|
|
|
function writeFloatLE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setFloat32(offset, value, true) |
|
|
|
|
|
return offset + 4 |
|
|
} |
|
|
|
|
|
function writeUInt32LE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setUint32(offset, value, true) |
|
|
|
|
|
return offset + 4 |
|
|
} |
|
|
|
|
|
function writeInt32LE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setInt32(offset, value, true) |
|
|
|
|
|
return offset + 4 |
|
|
} |
|
|
|
|
|
function readDoubleLE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getFloat64(offset, true) |
|
|
} |
|
|
|
|
|
function readFloatLE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getFloat32(offset, true) |
|
|
} |
|
|
|
|
|
function readUInt32LE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getUint32(offset, true) |
|
|
} |
|
|
|
|
|
function readInt32LE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getInt32(offset, true) |
|
|
} |
|
|
|
|
|
function writeDoubleBE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setFloat64(offset, value, false) |
|
|
|
|
|
return offset + 8 |
|
|
} |
|
|
|
|
|
function writeFloatBE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setFloat32(offset, value, false) |
|
|
|
|
|
return offset + 4 |
|
|
} |
|
|
|
|
|
function writeUInt32BE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setUint32(offset, value, false) |
|
|
|
|
|
return offset + 4 |
|
|
} |
|
|
|
|
|
function writeInt32BE (buffer, value, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
view.setInt32(offset, value, false) |
|
|
|
|
|
return offset + 4 |
|
|
} |
|
|
|
|
|
function readDoubleBE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getFloat64(offset, false) |
|
|
} |
|
|
|
|
|
function readFloatBE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getFloat32(offset, false) |
|
|
} |
|
|
|
|
|
function readUInt32BE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getUint32(offset, false) |
|
|
} |
|
|
|
|
|
function readInt32BE (buffer, offset) { |
|
|
if (offset === undefined) offset = 0 |
|
|
|
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength) |
|
|
|
|
|
return view.getInt32(offset, false) |
|
|
} |
|
|
|
|
|
module.exports = exports = { |
|
|
isBuffer, |
|
|
isEncoding, |
|
|
alloc, |
|
|
allocUnsafe, |
|
|
allocUnsafeSlow, |
|
|
byteLength, |
|
|
compare, |
|
|
concat, |
|
|
copy, |
|
|
equals, |
|
|
fill, |
|
|
from, |
|
|
includes, |
|
|
indexOf, |
|
|
lastIndexOf, |
|
|
swap16, |
|
|
swap32, |
|
|
swap64, |
|
|
toBuffer, |
|
|
toString, |
|
|
write, |
|
|
writeDoubleLE, |
|
|
writeFloatLE, |
|
|
writeUInt32LE, |
|
|
writeInt32LE, |
|
|
readDoubleLE, |
|
|
readFloatLE, |
|
|
readUInt32LE, |
|
|
readInt32LE, |
|
|
writeDoubleBE, |
|
|
writeFloatBE, |
|
|
writeUInt32BE, |
|
|
writeInt32BE, |
|
|
readDoubleBE, |
|
|
readFloatBE, |
|
|
readUInt32BE, |
|
|
readInt32BE |
|
|
} |
|
|
|