ts-mls
Version:
[](https://github.com/LukaJCB/ts-mls/actions/workflows/ci.yml) [](https://badge.fury.io/js/ts-mls) [ => {
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