protodef
Version:
A simple yet powerful way to define binary protocols
132 lines (117 loc) • 4.2 kB
JavaScript
const { PartialReadError } = require('../utils')
class SignedBigInt extends Array {
valueOf () { return BigInt.asIntN(64, BigInt(this[0]) << 32n) | BigInt.asUintN(32, BigInt(this[1])) }
toString () { return this.valueOf().toString() }
[Symbol.for('nodejs.util.inspect.custom')] () { return this.valueOf() }
}
class UnsignedBigInt extends Array {
valueOf () { return BigInt.asUintN(64, BigInt(this[0]) << 32n) | BigInt.asUintN(32, BigInt(this[1])) }
toString () { return this.valueOf().toString() }
[Symbol.for('nodejs.util.inspect.custom')] () { return this.valueOf() }
}
function readI64 (buffer, offset) {
if (offset + 8 > buffer.length) { throw new PartialReadError() }
return {
value: new SignedBigInt(buffer.readInt32BE(offset), buffer.readInt32BE(offset + 4)),
size: 8
}
}
function writeI64 (value, buffer, offset) {
if (typeof value === 'bigint') {
buffer.writeBigInt64BE(value, offset)
} else {
buffer.writeInt32BE(value[0], offset)
buffer.writeInt32BE(value[1], offset + 4)
}
return offset + 8
}
function readLI64 (buffer, offset) {
if (offset + 8 > buffer.length) { throw new PartialReadError() }
return {
value: new SignedBigInt(buffer.readInt32LE(offset + 4), buffer.readInt32LE(offset)),
size: 8
}
}
function writeLI64 (value, buffer, offset) {
if (typeof value === 'bigint') {
buffer.writeBigInt64LE(value, offset)
} else {
buffer.writeInt32LE(value[0], offset + 4)
buffer.writeInt32LE(value[1], offset)
}
return offset + 8
}
function readU64 (buffer, offset) {
if (offset + 8 > buffer.length) { throw new PartialReadError() }
return {
value: new UnsignedBigInt(buffer.readUInt32BE(offset), buffer.readUInt32BE(offset + 4)),
size: 8
}
}
function writeU64 (value, buffer, offset) {
if (typeof value === 'bigint') {
buffer.writeBigUInt64BE(value, offset)
} else {
buffer.writeUInt32BE(value[0], offset)
buffer.writeUInt32BE(value[1], offset + 4)
}
return offset + 8
}
function readLU64 (buffer, offset) {
if (offset + 8 > buffer.length) { throw new PartialReadError() }
return {
value: new UnsignedBigInt(buffer.readUInt32LE(offset + 4), buffer.readUInt32LE(offset)),
size: 8
}
}
function writeLU64 (value, buffer, offset) {
if (typeof value === 'bigint') {
buffer.writeBigUInt64LE(value, offset)
} else {
buffer.writeUInt32LE(value[0], offset + 4)
buffer.writeUInt32LE(value[1], offset)
}
return offset + 8
}
function generateFunctions (bufferReader, bufferWriter, size, schema) {
const reader = (buffer, offset) => {
if (offset + size > buffer.length) { throw new PartialReadError() }
const value = buffer[bufferReader](offset)
return {
value,
size
}
}
const writer = (value, buffer, offset) => {
buffer[bufferWriter](value, offset)
return offset + size
}
return [reader, writer, size, schema]
}
const nums = {
i8: ['readInt8', 'writeInt8', 1],
u8: ['readUInt8', 'writeUInt8', 1],
i16: ['readInt16BE', 'writeInt16BE', 2],
u16: ['readUInt16BE', 'writeUInt16BE', 2],
i32: ['readInt32BE', 'writeInt32BE', 4],
u32: ['readUInt32BE', 'writeUInt32BE', 4],
f32: ['readFloatBE', 'writeFloatBE', 4],
f64: ['readDoubleBE', 'writeDoubleBE', 8],
li8: ['readInt8', 'writeInt8', 1],
lu8: ['readUInt8', 'writeUInt8', 1],
li16: ['readInt16LE', 'writeInt16LE', 2],
lu16: ['readUInt16LE', 'writeUInt16LE', 2],
li32: ['readInt32LE', 'writeInt32LE', 4],
lu32: ['readUInt32LE', 'writeUInt32LE', 4],
lf32: ['readFloatLE', 'writeFloatLE', 4],
lf64: ['readDoubleLE', 'writeDoubleLE', 8]
}
const types = Object.keys(nums).reduce((types, num) => {
types[num] = generateFunctions(nums[num][0], nums[num][1], nums[num][2], require('../../ProtoDef/schemas/numeric.json')[num])
return types
}, {})
types.i64 = [readI64, writeI64, 8, require('../../ProtoDef/schemas/numeric.json').i64]
types.li64 = [readLI64, writeLI64, 8, require('../../ProtoDef/schemas/numeric.json').li64]
types.u64 = [readU64, writeU64, 8, require('../../ProtoDef/schemas/numeric.json').u64]
types.lu64 = [readLU64, writeLU64, 8, require('../../ProtoDef/schemas/numeric.json').lu64]
module.exports = types