UNPKG

ts-mls

Version:

[![CI](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml/badge.svg)](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [![npm version](https://badge.fury.io/js/ts-mls.svg)](https://badge.fury.io/js/ts-mls) [![Coverage Status](https://co

106 lines 3.75 kB
import { CodecError } from "../mlsError.js"; export const encodeVarLenData = (data) => { const lenBytes = encodeLength(data.length); const result = new Uint8Array(lenBytes.length + data.length); result.set(lenBytes, 0); result.set(data, lenBytes.length); return result; }; export function encodeLength(len) { if (len < 64) { // 1-byte length: 00xxxxxx return new Uint8Array([len & 0b00111111]); } else if (len < 16384) { // 2-byte length: 01xxxxxx xxxxxxxx return new Uint8Array([((len >> 8) & 0b00111111) | 0b01000000, len & 0xff]); } else if (len < 0x40000000) { // 4-byte length: 10xxxxxx xxxxxxxx xxxxxxxx xxxxxxxx return new Uint8Array([((len >> 24) & 0b00111111) | 0b10000000, (len >> 16) & 0xff, (len >> 8) & 0xff, len & 0xff]); } else { throw new CodecError("Length too large to encode (max is 2^30 - 1)"); } } export function determineLength(data, offset = 0) { if (offset >= data.length) { throw new CodecError("Offset beyond buffer"); } const firstByte = data[offset]; const prefix = firstByte >> 6; if (prefix === 0) { return { length: firstByte & 0b00111111, lengthFieldSize: 1 }; } else if (prefix === 1) { if (offset + 2 > data.length) throw new CodecError("Incomplete 2-byte length"); return { length: ((firstByte & 0b00111111) << 8) | data[offset + 1], lengthFieldSize: 2 }; } else if (prefix === 2) { if (offset + 4 > data.length) throw new CodecError("Incomplete 4-byte length"); return { length: ((firstByte & 0b00111111) << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3], lengthFieldSize: 4, }; } else { throw new CodecError("8-byte length not supported in this implementation"); } } export const decodeVarLenData = (buf, offset) => { if (offset >= buf.length) { throw new CodecError("Offset beyond buffer"); } const { length, lengthFieldSize } = determineLength(buf, offset); const totalBytes = lengthFieldSize + length; if (offset + totalBytes > buf.length) { throw new CodecError("Data length exceeds buffer"); } const data = buf.subarray(offset + lengthFieldSize, offset + totalBytes); return [data, totalBytes]; }; export function encodeVarLenType(enc) { return (data) => { const encodedParts = new Array(data.length); let dataLength = 0; for (let i = 0; i < data.length; i++) { const encoded = enc(data[i]); dataLength += encoded.byteLength; encodedParts[i] = encoded; } const lengthHeader = encodeLength(dataLength); const result = new Uint8Array(lengthHeader.length + dataLength); result.set(lengthHeader, 0); let offset = lengthHeader.length; for (const arr of encodedParts) { result.set(arr, offset); offset += arr.length; } return result; }; } export function decodeVarLenType(dec) { return (b, offset) => { const d = decodeVarLenData(b, offset); if (d === undefined) return; const [totalBytes, totalLength] = d; let cursor = 0; const result = []; while (cursor < totalBytes.length) { const item = dec(totalBytes, cursor); if (item === undefined) return undefined; const [value, len] = item; result.push(value); cursor += len; } return [result, totalLength]; }; } //# sourceMappingURL=variableLength.js.map