@seriousme/opifex
Version:
MQTT client & server for Deno & NodeJS
62 lines • 2.09 kB
JavaScript
/**
* Encodes a number into a variable-length byte array using a modified base-128 encoding
* @param n The number to encode
* @returns Array of bytes representing the encoded number
* @throws Error if the encoded length is greater than 4 bytes
*/
export function encodeLength(n) {
const output = [];
let x = n;
do {
let encodedByte = x % 0x80;
x = Math.floor(x / 0x80);
if (x > 0) {
encodedByte = encodedByte | 0x80;
}
output.push(encodedByte);
} while (x > 0);
if (output.length > 4) {
throw Error("length encoding failed");
}
return output;
}
/**
* Decodes a variable-length encoded number from a byte array
* @param buf The byte array containing the encoded number
* @param start The starting position in the buffer to begin decoding
* @returns Object containing the decoded length and number of bytes used for encoding
* @throws Error if decoding fails
*/
export function decodeLength(buf, start) {
const decode = getLengthDecoder();
const lenBuf = buf.subarray(start);
for (const byte of lenBuf) {
const { done, length, numLengthBytes } = decode(byte);
if (done) {
return { length, numLengthBytes };
}
}
throw Error("length decoding failed");
}
/**
* Creates a stateful decoder function for processing variable-length encoded numbers
* @returns Function that processes one byte at a time and returns decoding status
* @throws Error if the encoded length is greater than 4 bytes
*/
export function getLengthDecoder() {
let numLengthBytes = 1;
let length = 0;
let multiplier = 1;
return function addLengthByte(encodedByte) {
length += (encodedByte & 0x7f) * multiplier;
multiplier *= 0x80;
if ((encodedByte & 0x80) === 0) {
return { done: true, length, numLengthBytes };
}
if (numLengthBytes++ >= 4) {
throw Error("length decoding failed");
}
return { done: false, length, numLengthBytes };
};
}
//# sourceMappingURL=length.js.map