145 lines
3.1 KiB
JavaScript
145 lines
3.1 KiB
JavaScript
import { RootFakeUserID } from '../Util/RootID.js'
|
|
|
|
const bits7 = 0b1111111
|
|
const bits8 = 0b11111111
|
|
|
|
/**
|
|
* A BinaryEncoder handles the encoding to an ArrayBuffer
|
|
*/
|
|
export default class BinaryEncoder {
|
|
constructor () {
|
|
// TODO: implement chained Uint8Array buffers instead of Array buffer
|
|
this.data = []
|
|
}
|
|
|
|
/**
|
|
* The current length of the encoded data
|
|
*/
|
|
get length () {
|
|
return this.data.length
|
|
}
|
|
|
|
/**
|
|
* The current write pointer (the same as {@link length}).
|
|
*/
|
|
get pos () {
|
|
return this.data.length
|
|
}
|
|
|
|
/**
|
|
* Create an ArrayBuffer
|
|
*
|
|
* @return {Uint8Array}
|
|
*/
|
|
createBuffer () {
|
|
return Uint8Array.from(this.data).buffer
|
|
}
|
|
|
|
/**
|
|
* Write one byte as an unsigned integer
|
|
*
|
|
* @param {number} num The number that is to be encoded
|
|
*/
|
|
writeUint8 (num) {
|
|
this.data.push(num & bits8)
|
|
}
|
|
|
|
/**
|
|
* Write one byte as an unsigned Integer at a specific location
|
|
*
|
|
* @param {number} pos The location where the data will be written
|
|
* @param {number} num The number that is to
|
|
*/
|
|
setUint8 (pos, num) {
|
|
this.data[pos] = num & bits8
|
|
}
|
|
|
|
/**
|
|
* Write two bytes as an unsigned integer
|
|
*
|
|
* @param {number} pos The number that is to be encoded
|
|
*/
|
|
writeUint16 (num) {
|
|
this.data.push(num & bits8, (num >>> 8) & bits8)
|
|
}
|
|
/**
|
|
* Write two bytes as an unsigned integer at a specific location
|
|
*
|
|
* @param {number} pos The location where the data will be written
|
|
* @param {number} num The number that is to
|
|
*/
|
|
setUint16 (pos, num) {
|
|
this.data[pos] = num & bits8
|
|
this.data[pos + 1] = (num >>> 8) & bits8
|
|
}
|
|
|
|
/**
|
|
* Write two bytes as an unsigned integer
|
|
*
|
|
* @param {number} pos The number that is to be encoded
|
|
*/
|
|
writeUint32 (num) {
|
|
for (let i = 0; i < 4; i++) {
|
|
this.data.push(num & bits8)
|
|
num >>>= 8
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write two bytes as an unsigned integer at a specific location
|
|
*
|
|
* @param {number} pos The location where the data will be written
|
|
* @param {number} num The number that is to
|
|
*/
|
|
setUint32 (pos, num) {
|
|
for (let i = 0; i < 4; i++) {
|
|
this.data[pos + i] = num & bits8
|
|
num >>>= 8
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write a variable length unsigned integer
|
|
*
|
|
* @param {number} pos The number that is to be encoded
|
|
*/
|
|
writeVarUint (num) {
|
|
while (num >= 0b10000000) {
|
|
this.data.push(0b10000000 | (bits7 & num))
|
|
num >>>= 7
|
|
}
|
|
this.data.push(bits7 & num)
|
|
}
|
|
|
|
/**
|
|
* Write a variable length string.
|
|
*
|
|
* @param {number} pos The number that is to be encoded
|
|
*/
|
|
writeVarString (str) {
|
|
let encodedString = unescape(encodeURIComponent(str))
|
|
let bytes = encodedString.split('').map(c => c.codePointAt())
|
|
let len = bytes.length
|
|
this.writeVarUint(len)
|
|
for (let i = 0; i < len; i++) {
|
|
this.data.push(bytes[i])
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Write an ID at the current position
|
|
*
|
|
* @param {ID} id
|
|
*/
|
|
writeID (id) {
|
|
const user = id.user
|
|
this.writeVarUint(user)
|
|
if (user !== RootFakeUserID) {
|
|
this.writeVarUint(id.clock)
|
|
} else {
|
|
this.writeVarString(id.name)
|
|
this.writeVarUint(id.type)
|
|
}
|
|
}
|
|
}
|