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) } } }