564 lines
13 KiB
JavaScript
564 lines
13 KiB
JavaScript
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, length) {
|
|
if (length === undefined) {
|
|
length = buffers.reduce((len, buffer) => len + buffer.byteLength, 0)
|
|
}
|
|
|
|
const result = new Uint8Array(length)
|
|
|
|
let offset = 0
|
|
|
|
for (const buffer of buffers) {
|
|
if (offset + buffer.byteLength > result.byteLength) {
|
|
result.set(buffer.subarray(0, result.byteLength - offset), offset)
|
|
return result
|
|
}
|
|
|
|
result.set(buffer, offset)
|
|
offset += buffer.byteLength
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
function copy(
|
|
source,
|
|
target,
|
|
targetStart = 0,
|
|
sourceStart = 0,
|
|
sourceEnd = source.byteLength
|
|
) {
|
|
if (targetStart < 0) targetStart = 0
|
|
if (targetStart >= target.byteLength) return 0
|
|
|
|
const targetLength = target.byteLength - targetStart
|
|
|
|
if (sourceStart < 0) sourceStart = 0
|
|
if (sourceStart >= source.byteLength) return 0
|
|
|
|
if (sourceEnd <= sourceStart) return 0
|
|
if (sourceEnd > source.byteLength) sourceEnd = source.byteLength
|
|
|
|
if (sourceEnd - sourceStart > targetLength) {
|
|
sourceEnd = sourceStart + targetLength
|
|
}
|
|
|
|
const sourceLength = sourceEnd - sourceStart
|
|
|
|
if (source === target) {
|
|
target.copyWithin(targetStart, sourceStart, sourceEnd)
|
|
} else {
|
|
if (sourceStart !== 0 || sourceEnd !== source.byteLength) {
|
|
source = source.subarray(sourceStart, sourceEnd)
|
|
}
|
|
|
|
target.set(source, targetStart)
|
|
}
|
|
|
|
return sourceLength
|
|
}
|
|
|
|
function equals(a, b) {
|
|
if (a === b) return true
|
|
if (a.byteLength !== b.byteLength) return false
|
|
|
|
return compare(a, b) === 0
|
|
}
|
|
|
|
function fill(
|
|
buffer,
|
|
value,
|
|
offset = 0,
|
|
end = buffer.byteLength,
|
|
encoding = 'utf8'
|
|
) {
|
|
if (typeof value === 'string') {
|
|
if (typeof offset === 'string') {
|
|
// fill(string, encoding)
|
|
encoding = offset
|
|
offset = 0
|
|
end = buffer.byteLength
|
|
} else if (typeof end === 'string') {
|
|
// fill(string, offset, encoding)
|
|
encoding = end
|
|
end = buffer.byteLength
|
|
}
|
|
} else if (typeof value === 'number') {
|
|
value = value & 0xff
|
|
} else if (typeof value === 'boolean') {
|
|
value = +value
|
|
}
|
|
|
|
if (offset < 0) offset = 0
|
|
if (offset >= buffer.byteLength) return buffer
|
|
|
|
if (end <= offset) return buffer
|
|
if (end > buffer.byteLength) end = buffer.byteLength
|
|
|
|
if (typeof value === 'number') return buffer.fill(value, offset, end)
|
|
|
|
if (typeof value === 'string') value = exports.from(value, encoding)
|
|
|
|
const len = value.byteLength
|
|
|
|
for (let i = 0, n = end - offset; i < n; ++i) {
|
|
buffer[i + offset] = value[i % len]
|
|
}
|
|
|
|
return buffer
|
|
}
|
|
|
|
function from(value, encodingOrOffset, length) {
|
|
// from(string, encoding)
|
|
if (typeof value === 'string') return fromString(value, encodingOrOffset)
|
|
|
|
// from(array)
|
|
if (Array.isArray(value)) return fromArray(value)
|
|
|
|
// from(buffer)
|
|
if (ArrayBuffer.isView(value)) return fromBuffer(value)
|
|
|
|
// from(arrayBuffer[, byteOffset[, length]])
|
|
return fromArrayBuffer(value, encodingOrOffset, length)
|
|
}
|
|
|
|
function fromString(string, encoding) {
|
|
const codec = codecFor(encoding)
|
|
const buffer = new Uint8Array(codec.byteLength(string))
|
|
codec.write(buffer, string)
|
|
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 indexOf(buffer, value, byteOffset, encoding) {
|
|
return bidirectionalIndexOf(
|
|
buffer,
|
|
value,
|
|
byteOffset,
|
|
encoding,
|
|
true /* first */
|
|
)
|
|
}
|
|
|
|
function lastIndexOf(buffer, value, byteOffset, encoding) {
|
|
return bidirectionalIndexOf(
|
|
buffer,
|
|
value,
|
|
byteOffset,
|
|
encoding,
|
|
false /* last */
|
|
)
|
|
}
|
|
|
|
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 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 = 'utf8',
|
|
start = 0,
|
|
end = buffer.byteLength
|
|
) {
|
|
// toString(buffer)
|
|
if (arguments.length === 1) return utf8.toString(buffer)
|
|
|
|
// toString(buffer, encoding)
|
|
if (arguments.length === 2) return codecFor(encoding).toString(buffer)
|
|
|
|
if (start < 0) start = 0
|
|
if (start >= buffer.byteLength) return ''
|
|
|
|
if (end <= start) return ''
|
|
if (end > buffer.byteLength) end = buffer.byteLength
|
|
|
|
if (start !== 0 || end !== buffer.byteLength) {
|
|
buffer = buffer.subarray(start, end)
|
|
}
|
|
|
|
return codecFor(encoding).toString(buffer)
|
|
}
|
|
|
|
function write(buffer, string, offset, length, encoding) {
|
|
// write(buffer, string)
|
|
if (arguments.length === 2) return utf8.write(buffer, string)
|
|
|
|
if (typeof offset === 'string') {
|
|
// write(buffer, string, encoding)
|
|
encoding = offset
|
|
offset = 0
|
|
length = buffer.byteLength
|
|
} else if (typeof length === 'string') {
|
|
// write(buffer, string, offset, encoding)
|
|
encoding = length
|
|
length = buffer.byteLength - offset
|
|
}
|
|
|
|
length = Math.min(length, exports.byteLength(string, encoding))
|
|
|
|
let start = offset
|
|
if (start < 0) start = 0
|
|
if (start >= buffer.byteLength) return 0
|
|
|
|
let end = offset + length
|
|
if (end <= start) return 0
|
|
if (end > buffer.byteLength) end = buffer.byteLength
|
|
|
|
if (start !== 0 || end !== buffer.byteLength) {
|
|
buffer = buffer.subarray(start, end)
|
|
}
|
|
|
|
return codecFor(encoding).write(buffer, string)
|
|
}
|
|
|
|
function readDoubleBE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getFloat64(offset, false)
|
|
}
|
|
|
|
function readDoubleLE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getFloat64(offset, true)
|
|
}
|
|
|
|
function readFloatBE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getFloat32(offset, false)
|
|
}
|
|
|
|
function readFloatLE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getFloat32(offset, true)
|
|
}
|
|
|
|
function readInt32BE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getInt32(offset, false)
|
|
}
|
|
|
|
function readInt32LE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getInt32(offset, true)
|
|
}
|
|
|
|
function readUInt32BE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getUint32(offset, false)
|
|
}
|
|
|
|
function readUInt32LE(buffer, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
return view.getUint32(offset, true)
|
|
}
|
|
|
|
function writeDoubleBE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setFloat64(offset, value, false)
|
|
return offset + 8
|
|
}
|
|
|
|
function writeDoubleLE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setFloat64(offset, value, true)
|
|
return offset + 8
|
|
}
|
|
|
|
function writeFloatBE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setFloat32(offset, value, false)
|
|
return offset + 4
|
|
}
|
|
|
|
function writeFloatLE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setFloat32(offset, value, true)
|
|
return offset + 4
|
|
}
|
|
|
|
function writeInt32BE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setInt32(offset, value, false)
|
|
return offset + 4
|
|
}
|
|
|
|
function writeInt32LE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setInt32(offset, value, true)
|
|
return offset + 4
|
|
}
|
|
|
|
function writeUInt32BE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setUint32(offset, value, false)
|
|
return offset + 4
|
|
}
|
|
|
|
function writeUInt32LE(buffer, value, offset = 0) {
|
|
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength)
|
|
view.setUint32(offset, value, true)
|
|
return offset + 4
|
|
}
|
|
|
|
module.exports = exports = {
|
|
isBuffer,
|
|
isEncoding,
|
|
alloc,
|
|
allocUnsafe,
|
|
allocUnsafeSlow,
|
|
byteLength,
|
|
compare,
|
|
concat,
|
|
copy,
|
|
equals,
|
|
fill,
|
|
from,
|
|
includes,
|
|
indexOf,
|
|
lastIndexOf,
|
|
swap16,
|
|
swap32,
|
|
swap64,
|
|
toBuffer,
|
|
toString,
|
|
write,
|
|
readDoubleBE,
|
|
readDoubleLE,
|
|
readFloatBE,
|
|
readFloatLE,
|
|
readInt32BE,
|
|
readInt32LE,
|
|
readUInt32BE,
|
|
readUInt32LE,
|
|
writeDoubleBE,
|
|
writeDoubleLE,
|
|
writeFloatBE,
|
|
writeFloatLE,
|
|
writeInt32BE,
|
|
writeInt32LE,
|
|
writeUInt32BE,
|
|
writeUInt32LE
|
|
}
|