@levischuck/tiny-cbor
Version:
Tiny CBOR library
112 lines (111 loc) • 3.56 kB
JavaScript
export function decodeLength(data, argument, index) {
if (argument < 24) {
return [argument, 1];
}
const remainingDataLength = data.byteLength - index - 1;
const view = new DataView(data.buffer, index + 1);
let output;
let bytes = 0;
switch (argument) {
case 24: {
if (remainingDataLength > 0) {
output = view.getUint8(0);
bytes = 2;
}
break;
}
case 25: {
if (remainingDataLength > 1) {
output = view.getUint16(0, false);
bytes = 3;
}
break;
}
case 26: {
if (remainingDataLength > 3) {
output = view.getUint32(0, false);
bytes = 5;
}
break;
}
case 27: {
if (remainingDataLength > 7) {
const bigOutput = view.getBigUint64(0, false);
// Bound it to [24, MAX_SAFE_INTEGER], where it is safe
// to encode as a javascript number
if (bigOutput >= 24n && bigOutput <= Number.MAX_SAFE_INTEGER) {
return [Number(bigOutput), 9];
}
}
break;
}
}
if (output && output >= 24) {
return [output, bytes];
}
throw new Error("Length not supported or not well formed");
}
export const MAJOR_TYPE_UNSIGNED_INTEGER = 0;
export const MAJOR_TYPE_NEGATIVE_INTEGER = 1;
export const MAJOR_TYPE_BYTE_STRING = 2;
export const MAJOR_TYPE_TEXT_STRING = 3;
export const MAJOR_TYPE_ARRAY = 4;
export const MAJOR_TYPE_MAP = 5;
export const MAJOR_TYPE_TAG = 6;
export const MAJOR_TYPE_SIMPLE_OR_FLOAT = 7;
export function encodeLength(major, argument) {
const majorEncoded = major << 5;
if (argument < 0) {
throw new Error("CBOR Data Item argument must not be negative");
}
// Convert to bigint first.
// Encode integers around and above 32 bits in big endian / network byte order
// is unreliable in javascript.
// https://tc39.es/ecma262/#sec-bitwise-shift-operators
// Bit shifting operations result in 32 bit signed numbers
let bigintArgument;
if (typeof argument == "number") {
if (!Number.isInteger(argument)) {
throw new Error("CBOR Data Item argument must be an integer");
}
bigintArgument = BigInt(argument);
}
else {
bigintArgument = argument;
}
// Negative 0 is not a thing
if (major == MAJOR_TYPE_NEGATIVE_INTEGER) {
if (bigintArgument == 0n) {
throw new Error("CBOR Data Item argument cannot be zero when negative");
}
bigintArgument = bigintArgument - 1n;
}
if (bigintArgument > 18446744073709551615n) {
throw new Error("CBOR number out of range");
}
// Encode into 64 bits and extract the tail
const buffer = new Uint8Array(8);
const view = new DataView(buffer.buffer);
view.setBigUint64(0, bigintArgument, false);
if (bigintArgument <= 23) {
return [majorEncoded | buffer[7]];
}
else if (bigintArgument <= 255) {
return [majorEncoded | 24, buffer[7]];
}
else if (bigintArgument <= 65535) {
return [majorEncoded | 25, ...buffer.slice(6)];
}
else if (bigintArgument <= 4294967295) {
return [
majorEncoded | 26,
...buffer.slice(4),
];
}
else {
return [
majorEncoded | 27,
...buffer,
];
}
}