Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ndn/tlv

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ndn/tlv - npm Package Compare versions

Comparing version 0.0.20210930 to 0.0.20220501

LICENSE

37

lib/decoder_browser.js

@@ -1,4 +0,3 @@

import { Encoder } from "./mod_browser.js";
import { asDataView, fromUtf8 } from "@ndn/util";
import { NNI } from "./nni_browser.js";
import { fromUtf8 } from "./string_browser.js";
class DecodedTlv {

@@ -51,3 +50,3 @@ constructor(type, buf, offsetT, offsetV, offsetE) {

this.offset = 0;
this.dv = Encoder.asDataView(input);
this.dv = asDataView(input);
}

@@ -61,8 +60,10 @@ /** Determine whether end of input has been reached. */

const offsetT = this.offset;
const type = this.readType();
const length = this.readLength();
const type = this.readVarNum();
const length = this.readVarNum();
const offsetV = this.offset;
this.skipValue(length);
const offsetE = this.offset;
return new DecodedTlv(type, this.input, offsetT, offsetV, offsetE);
if (length === undefined || (this.offset += length) > this.input.length) {
throw new Error(`TLV at offset ${offsetT} is incomplete`);
}
// length!==undefined implies type!==undefined
return new DecodedTlv(type, this.input, offsetT, offsetV, this.offset);
}

@@ -98,22 +99,2 @@ /** Read a Decodable object. */

}
readType() {
const n = this.readVarNum();
if (n === undefined) {
throw new Error(`TLV-TYPE is missing near offset ${this.offset}`);
}
return n;
}
readLength() {
const n = this.readVarNum();
if (n === undefined) {
throw new Error(`TLV-LENGTH is missing near offset ${this.offset}`);
}
return n;
}
skipValue(length) {
this.offset += length;
if (this.offset > this.input.length) {
throw new Error(`TLV-VALUE is incomplete near offset ${this.offset}`);
}
}
}

@@ -1,4 +0,3 @@

import { Encoder } from "./mod_node.js";
import { asDataView, fromUtf8 } from "@ndn/util";
import { NNI } from "./nni_node.js";
import { fromUtf8 } from "./string_node.js";
class DecodedTlv {

@@ -51,3 +50,3 @@ constructor(type, buf, offsetT, offsetV, offsetE) {

this.offset = 0;
this.dv = Encoder.asDataView(input);
this.dv = asDataView(input);
}

@@ -61,8 +60,10 @@ /** Determine whether end of input has been reached. */

const offsetT = this.offset;
const type = this.readType();
const length = this.readLength();
const type = this.readVarNum();
const length = this.readVarNum();
const offsetV = this.offset;
this.skipValue(length);
const offsetE = this.offset;
return new DecodedTlv(type, this.input, offsetT, offsetV, offsetE);
if (length === undefined || (this.offset += length) > this.input.length) {
throw new Error(`TLV at offset ${offsetT} is incomplete`);
}
// length!==undefined implies type!==undefined
return new DecodedTlv(type, this.input, offsetT, offsetV, this.offset);
}

@@ -98,22 +99,2 @@ /** Read a Decodable object. */

}
readType() {
const n = this.readVarNum();
if (n === undefined) {
throw new Error(`TLV-TYPE is missing near offset ${this.offset}`);
}
return n;
}
readLength() {
const n = this.readVarNum();
if (n === undefined) {
throw new Error(`TLV-LENGTH is missing near offset ${this.offset}`);
}
return n;
}
skipValue(length) {
this.offset += length;
if (this.offset > this.input.length) {
throw new Error(`TLV-VALUE is incomplete near offset ${this.offset}`);
}
}
}

@@ -17,5 +17,2 @@ export interface Decodable<R> {

private readVarNum;
private readType;
private readLength;
private skipValue;
}

@@ -22,0 +19,0 @@ export declare namespace Decoder {

@@ -0,1 +1,2 @@

import { asDataView } from "@ndn/util";
function sizeofVarNum(n) {

@@ -11,3 +12,3 @@ if (n < 0xFD) {

}
// JavaScript cannot reliably represent 64-bit integers
// 64-bit integers may lose precision in Number type, and it's rarely useful
throw new Error("VAR-NUMBER is too large");

@@ -21,14 +22,12 @@ }

room[off++] = 0xFD;
Encoder.asDataView(room).setUint16(off, n);
asDataView(room).setUint16(off, n);
}
else {
room[off++] = 0xFE;
Encoder.asDataView(room).setUint32(off, n);
asDataView(room).setUint32(off, n);
}
}
const BUF_INIT_SIZE = 2048;
const BUF_GROW_SIZE = 2048;
/** TLV encoder that accepts objects in reverse order. */
export class Encoder {
constructor(initSize = BUF_INIT_SIZE) {
constructor(initSize = 2048) {
this.buf = new ArrayBuffer(initSize);

@@ -47,6 +46,2 @@ this.off = initSize;

slice(start = 0, length) {
if (length === undefined) {
// iOS would interpret length=undefined as length=0, so we need a conditional
return new Uint8Array(this.buf, this.off + start);
}
return new Uint8Array(this.buf, this.off + start, length);

@@ -80,17 +75,6 @@ }

}
/**
* Prepend TLV structure.
* @param tlvType TLV-TYPE number.
* @param omitEmpty omit TLV altogether if set to Encoder.OmitEmpty
* @param tlvValue TLV-VALUE objects.
*/
prependTlv(tlvType, omitEmpty, ...tlvValue) {
let hasOmitEmpty = false;
if (omitEmpty) {
if (omitEmpty === Encoder.OmitEmpty) {
hasOmitEmpty = true;
}
else {
tlvValue.unshift(omitEmpty);
}
const hasOmitEmpty = omitEmpty === Encoder.OmitEmpty;
if (!hasOmitEmpty) {
tlvValue.unshift(omitEmpty);
}

@@ -125,49 +109,13 @@ const sizeBefore = this.size;

grow(sizeofRoom) {
const sizeofGrow = BUF_GROW_SIZE + sizeofRoom;
const buf = new ArrayBuffer(sizeofGrow + this.size);
new Uint8Array(buf, sizeofGrow).set(this.output);
const sizeofGrowth = 2048 + sizeofRoom;
const buf = new ArrayBuffer(sizeofGrowth + this.size);
new Uint8Array(buf, sizeofGrowth).set(this.output);
this.buf = buf;
this.off = sizeofGrow;
this.off = sizeofGrowth;
}
}
(function (Encoder) {
/** Create a DataView over a Uint8Array. */
function asDataView(a) {
return new DataView(a.buffer, a.byteOffset, a.byteLength);
}
Encoder.asDataView = asDataView;
let DataViewPolyfill;
(function (DataViewPolyfill) {
function getBigUint64(dv, byteOffset, littleEndian) {
if (littleEndian) {
return (BigInt(dv.getUint32(byteOffset + 4, true)) << 32n) | BigInt(dv.getUint32(byteOffset, true));
}
return BigInt(dv.getUint32(byteOffset + 4)) | (BigInt(dv.getUint32(byteOffset)) << 32n);
}
DataViewPolyfill.getBigUint64 = getBigUint64;
function setBigUint64(dv, byteOffset, value, littleEndian) {
if (littleEndian) {
dv.setUint32(byteOffset + 4, Number(value >> 32n), true);
dv.setUint32(byteOffset, Number(value & 0xffffffffn), true);
}
else {
dv.setUint32(byteOffset + 4, Number(value & 0xffffffffn));
dv.setUint32(byteOffset, Number(value >> 32n));
}
}
DataViewPolyfill.setBigUint64 = setBigUint64;
})(DataViewPolyfill = Encoder.DataViewPolyfill || (Encoder.DataViewPolyfill = {}));
/** DataView.prototype.getBigUint64 with polyfill for iOS 14. */
Encoder.getBigUint64 = typeof DataView.prototype.getBigUint64 === "function" ?
(dv, byteOffset, littleEndian) => dv.getBigUint64(byteOffset, littleEndian) :
/* istanbul ignore next */
DataViewPolyfill.getBigUint64;
/** DataView.prototype.setBigUint64 with polyfill for iOS 14. */
Encoder.setBigUint64 = typeof DataView.prototype.setBigUint64 === "function" ?
(dv, byteOffset, value, littleEndian) => dv.setBigUint64(byteOffset, value, littleEndian) :
/* istanbul ignore next */
DataViewPolyfill.setBigUint64;
Encoder.OmitEmpty = Symbol("OmitEmpty");
/** Encode a single object into Uint8Array. */
function encode(obj, initBufSize = BUF_INIT_SIZE) {
function encode(obj, initBufSize) {
const encoder = new Encoder(initBufSize);

@@ -174,0 +122,0 @@ encoder.encode(obj);

@@ -0,1 +1,2 @@

import { asDataView } from "@ndn/util";
function sizeofVarNum(n) {

@@ -11,3 +12,3 @@ if (n < 0xFD) {

}
// JavaScript cannot reliably represent 64-bit integers
// 64-bit integers may lose precision in Number type, and it's rarely useful
throw new Error("VAR-NUMBER is too large");

@@ -21,14 +22,12 @@ }

room[off++] = 0xFD;
Encoder.asDataView(room).setUint16(off, n);
asDataView(room).setUint16(off, n);
}
else {
room[off++] = 0xFE;
Encoder.asDataView(room).setUint32(off, n);
asDataView(room).setUint32(off, n);
}
}
const BUF_INIT_SIZE = 2048;
const BUF_GROW_SIZE = 2048;
/** TLV encoder that accepts objects in reverse order. */
export class Encoder {
constructor(initSize = BUF_INIT_SIZE) {
constructor(initSize = 2048) {
this.buf = new ArrayBuffer(initSize);

@@ -47,6 +46,2 @@ this.off = initSize;

slice(start = 0, length) {
if (length === undefined) {
// iOS would interpret length=undefined as length=0, so we need a conditional
return new Uint8Array(this.buf, this.off + start);
}
return new Uint8Array(this.buf, this.off + start, length);

@@ -80,17 +75,6 @@ }

}
/**
* Prepend TLV structure.
* @param tlvType TLV-TYPE number.
* @param omitEmpty omit TLV altogether if set to Encoder.OmitEmpty
* @param tlvValue TLV-VALUE objects.
*/
prependTlv(tlvType, omitEmpty, ...tlvValue) {
let hasOmitEmpty = false;
if (omitEmpty) {
if (omitEmpty === Encoder.OmitEmpty) {
hasOmitEmpty = true;
}
else {
tlvValue.unshift(omitEmpty);
}
const hasOmitEmpty = omitEmpty === Encoder.OmitEmpty;
if (!hasOmitEmpty) {
tlvValue.unshift(omitEmpty);
}

@@ -125,49 +109,13 @@ const sizeBefore = this.size;

grow(sizeofRoom) {
const sizeofGrow = BUF_GROW_SIZE + sizeofRoom;
const buf = new ArrayBuffer(sizeofGrow + this.size);
new Uint8Array(buf, sizeofGrow).set(this.output);
const sizeofGrowth = 2048 + sizeofRoom;
const buf = new ArrayBuffer(sizeofGrowth + this.size);
new Uint8Array(buf, sizeofGrowth).set(this.output);
this.buf = buf;
this.off = sizeofGrow;
this.off = sizeofGrowth;
}
}
(function (Encoder) {
/** Create a DataView over a Uint8Array. */
function asDataView(a) {
return new DataView(a.buffer, a.byteOffset, a.byteLength);
}
Encoder.asDataView = asDataView;
let DataViewPolyfill;
(function (DataViewPolyfill) {
function getBigUint64(dv, byteOffset, littleEndian) {
if (littleEndian) {
return (BigInt(dv.getUint32(byteOffset + 4, true)) << 32n) | BigInt(dv.getUint32(byteOffset, true));
}
return BigInt(dv.getUint32(byteOffset + 4)) | (BigInt(dv.getUint32(byteOffset)) << 32n);
}
DataViewPolyfill.getBigUint64 = getBigUint64;
function setBigUint64(dv, byteOffset, value, littleEndian) {
if (littleEndian) {
dv.setUint32(byteOffset + 4, Number(value >> 32n), true);
dv.setUint32(byteOffset, Number(value & 0xffffffffn), true);
}
else {
dv.setUint32(byteOffset + 4, Number(value & 0xffffffffn));
dv.setUint32(byteOffset, Number(value >> 32n));
}
}
DataViewPolyfill.setBigUint64 = setBigUint64;
})(DataViewPolyfill = Encoder.DataViewPolyfill || (Encoder.DataViewPolyfill = {}));
/** DataView.prototype.getBigUint64 with polyfill for iOS 14. */
Encoder.getBigUint64 = typeof DataView.prototype.getBigUint64 === "function" ?
(dv, byteOffset, littleEndian) => dv.getBigUint64(byteOffset, littleEndian) :
/* istanbul ignore next */
DataViewPolyfill.getBigUint64;
/** DataView.prototype.setBigUint64 with polyfill for iOS 14. */
Encoder.setBigUint64 = typeof DataView.prototype.setBigUint64 === "function" ?
(dv, byteOffset, value, littleEndian) => dv.setBigUint64(byteOffset, value, littleEndian) :
/* istanbul ignore next */
DataViewPolyfill.setBigUint64;
Encoder.OmitEmpty = Symbol("OmitEmpty");
/** Encode a single object into Uint8Array. */
function encode(obj, initBufSize = BUF_INIT_SIZE) {
function encode(obj, initBufSize) {
const encoder = new Encoder(initBufSize);

@@ -174,0 +122,0 @@ encoder.encode(obj);

@@ -12,3 +12,3 @@ /** An object that knows how to prepend itself to an Encoder. */

*/
export declare type EncodableTlv = [number, ...any[]];
export declare type EncodableTlv = [number, ...Encodable[]] | [number, typeof Encoder.OmitEmpty, ...Encodable[]];
/** An object acceptable to Encoder.encode(). */

@@ -37,9 +37,6 @@ export declare type Encodable = Uint8Array | undefined | EncodableObj | EncodableTlv;

prependValue(...tlvValue: Encodable[]): void;
/**
* Prepend TLV structure.
* @param tlvType TLV-TYPE number.
* @param omitEmpty omit TLV altogether if set to Encoder.OmitEmpty
* @param tlvValue TLV-VALUE objects.
*/
prependTlv(tlvType: number, omitEmpty?: typeof Encoder.OmitEmpty | Encodable, ...tlvValue: Encodable[]): void;
/** Prepend TLV structure. */
prependTlv(tlvType: number, ...tlvValue: Encodable[]): void;
/** Prepend TLV structure, but skip if TLV-VALUE is empty. */
prependTlv(tlvType: number, omitEmpty: typeof Encoder.OmitEmpty, ...tlvValue: Encodable[]): void;
/** Prepend an Encodable object. */

@@ -50,12 +47,2 @@ encode(obj: Encodable | readonly Encodable[]): void;

export declare namespace Encoder {
/** Create a DataView over a Uint8Array. */
function asDataView(a: Uint8Array): DataView;
namespace DataViewPolyfill {
function getBigUint64(dv: DataView, byteOffset: number, littleEndian?: boolean): bigint;
function setBigUint64(dv: DataView, byteOffset: number, value: bigint, littleEndian?: boolean): void;
}
/** DataView.prototype.getBigUint64 with polyfill for iOS 14. */
const getBigUint64: (dv: DataView, byteOffset: number, littleEndian?: boolean) => bigint;
/** DataView.prototype.setBigUint64 with polyfill for iOS 14. */
const setBigUint64: (dv: DataView, byteOffset: number, value: bigint, littleEndian?: boolean) => void;
const OmitEmpty: unique symbol;

@@ -62,0 +49,0 @@ /** Encode a single object into Uint8Array. */

@@ -0,1 +1,2 @@

import { assert } from "@ndn/util";
import { printTT } from "./string_browser.js";

@@ -19,15 +20,10 @@ const AUTO_ORDER_SKIP = 100;

this.rules = new Map();
this.requiredTlvTypes = new Set();
this.requiredTT = new Set();
this.nextOrder = AUTO_ORDER_SKIP;
this.isCriticalCb = isCritical;
/** Callbacks to receive top-level TLV before decoding TLV-VALUE. */
this.beforeTopCallbacks = [];
this.isCritical = isCritical;
/** Callbacks before decoding TLV-VALUE. */
this.beforeValueCallbacks = [];
this.beforeObservers = [];
/** Callbacks after decoding TLV-VALUE. */
this.afterValueCallbacks = [];
/** Callbacks to receive top-level TLV after decoding TLV-VALUE. */
this.afterTopCallbacks = [];
this.afterObservers = [];
this.topTT = Array.isArray(topTT) ? topTT : [topTT];
this.unknownCb = () => false;
}

@@ -37,20 +33,15 @@ /**

* @param tt TLV-TYPE to match this rule.
* @param cb callback to handle element TLV.
* @param cb callback or nested EvDecoder to handle element TLV.
* @param options additional rule options.
*/
add(tt, cb, options) {
if (this.rules.has(tt)) {
throw new Error(`TLV-TYPE ${printTT(tt)} already has a rule`);
}
const rule = {
add(tt, cb, { order = (this.nextOrder += AUTO_ORDER_SKIP), required = false, repeat = false, } = {}) {
assert(!this.rules.has(tt), "duplicate rule for same TLV-TYPE");
this.rules.set(tt, {
cb: cb instanceof EvDecoder ? nest(cb) : cb,
order: this.nextOrder,
required: false,
repeat: false,
...options,
};
this.nextOrder += AUTO_ORDER_SKIP;
this.rules.set(tt, rule);
if (rule.required) {
this.requiredTlvTypes.add(tt);
order,
required,
repeat,
});
if (required) {
this.requiredTT.add(tt);
}

@@ -61,3 +52,3 @@ return this;

setIsCritical(cb) {
this.isCriticalCb = cb;
this.isCritical = cb;
return this;

@@ -67,3 +58,3 @@ }

setUnknown(cb) {
this.unknownCb = cb;
this.unknownHandler = cb;
return this;

@@ -78,26 +69,21 @@ }

}
for (const cb of this.beforeTopCallbacks) {
cb(target, topTlv);
}
this.decodeValue(target, vd);
for (const cb of this.afterTopCallbacks) {
cb(target, topTlv);
}
return target;
return this.decodeV(target, vd, topTlv);
}
/** Decode TLV-VALUE to target object. */
decodeValue(target, vd) {
for (const cb of this.beforeValueCallbacks) {
cb(target);
return this.decodeV(target, vd);
}
decodeV(target, vd, topTlv) {
for (const cb of this.beforeObservers) {
cb(target, topTlv);
}
let currentOrder = 0;
let currentCount = 0;
const missingTlvTypes = new Set(this.requiredTlvTypes);
const foundTT = new Set();
const missingTT = new Set(this.requiredTT);
while (!vd.eof) {
const tlv = vd.read();
const tt = tlv.type;
missingTlvTypes.delete(tt);
const rule = this.rules.get(tt);
if (rule === undefined) {
if (!this.unknownCb(target, tlv, currentOrder)) {
if (!rule) {
if (!this.unknownHandler?.(target, tlv, currentOrder)) {
this.handleUnrecognized(tt, "unknown");

@@ -111,17 +97,15 @@ }

}
if (currentOrder < rule.order) {
currentOrder = rule.order;
currentCount = 0;
}
++currentCount;
if (!rule.repeat && currentCount > 1) {
currentOrder = rule.order;
if (!rule.repeat && foundTT.has(tt)) {
throw new Error(`TLV-TYPE ${printTT(tt)} cannot repeat in ${this.typeName}`);
}
foundTT.add(tt);
missingTT.delete(tt);
rule.cb(target, tlv);
}
if (missingTlvTypes.size > 0) {
throw new Error(`TLV-TYPE ${Array.from(missingTlvTypes).map(printTT).join(",")} ${missingTlvTypes.size === 1 ? "is" : "are"} missing in ${this.typeName}`);
if (missingTT.size > 0) {
throw new Error(`TLV-TYPE ${Array.from(missingTT, printTT).join(",")} missing in ${this.typeName}`);
}
for (const cb of this.afterValueCallbacks) {
cb(target);
for (const cb of this.afterObservers) {
cb(target, topTlv);
}

@@ -131,3 +115,3 @@ return target;

handleUnrecognized(tt, reason) {
if (this.isCriticalCb(tt)) {
if (this.isCritical(tt)) {
throw new Error(`TLV-TYPE ${printTT(tt)} is ${reason} in ${this.typeName}`);

@@ -134,0 +118,0 @@ }

@@ -0,1 +1,2 @@

import { assert } from "@ndn/util";
import { printTT } from "./string_node.js";

@@ -19,15 +20,10 @@ const AUTO_ORDER_SKIP = 100;

this.rules = new Map();
this.requiredTlvTypes = new Set();
this.requiredTT = new Set();
this.nextOrder = AUTO_ORDER_SKIP;
this.isCriticalCb = isCritical;
/** Callbacks to receive top-level TLV before decoding TLV-VALUE. */
this.beforeTopCallbacks = [];
this.isCritical = isCritical;
/** Callbacks before decoding TLV-VALUE. */
this.beforeValueCallbacks = [];
this.beforeObservers = [];
/** Callbacks after decoding TLV-VALUE. */
this.afterValueCallbacks = [];
/** Callbacks to receive top-level TLV after decoding TLV-VALUE. */
this.afterTopCallbacks = [];
this.afterObservers = [];
this.topTT = Array.isArray(topTT) ? topTT : [topTT];
this.unknownCb = () => false;
}

@@ -37,20 +33,15 @@ /**

* @param tt TLV-TYPE to match this rule.
* @param cb callback to handle element TLV.
* @param cb callback or nested EvDecoder to handle element TLV.
* @param options additional rule options.
*/
add(tt, cb, options) {
if (this.rules.has(tt)) {
throw new Error(`TLV-TYPE ${printTT(tt)} already has a rule`);
}
const rule = {
add(tt, cb, { order = (this.nextOrder += AUTO_ORDER_SKIP), required = false, repeat = false, } = {}) {
assert(!this.rules.has(tt), "duplicate rule for same TLV-TYPE");
this.rules.set(tt, {
cb: cb instanceof EvDecoder ? nest(cb) : cb,
order: this.nextOrder,
required: false,
repeat: false,
...options,
};
this.nextOrder += AUTO_ORDER_SKIP;
this.rules.set(tt, rule);
if (rule.required) {
this.requiredTlvTypes.add(tt);
order,
required,
repeat,
});
if (required) {
this.requiredTT.add(tt);
}

@@ -61,3 +52,3 @@ return this;

setIsCritical(cb) {
this.isCriticalCb = cb;
this.isCritical = cb;
return this;

@@ -67,3 +58,3 @@ }

setUnknown(cb) {
this.unknownCb = cb;
this.unknownHandler = cb;
return this;

@@ -78,26 +69,21 @@ }

}
for (const cb of this.beforeTopCallbacks) {
cb(target, topTlv);
}
this.decodeValue(target, vd);
for (const cb of this.afterTopCallbacks) {
cb(target, topTlv);
}
return target;
return this.decodeV(target, vd, topTlv);
}
/** Decode TLV-VALUE to target object. */
decodeValue(target, vd) {
for (const cb of this.beforeValueCallbacks) {
cb(target);
return this.decodeV(target, vd);
}
decodeV(target, vd, topTlv) {
for (const cb of this.beforeObservers) {
cb(target, topTlv);
}
let currentOrder = 0;
let currentCount = 0;
const missingTlvTypes = new Set(this.requiredTlvTypes);
const foundTT = new Set();
const missingTT = new Set(this.requiredTT);
while (!vd.eof) {
const tlv = vd.read();
const tt = tlv.type;
missingTlvTypes.delete(tt);
const rule = this.rules.get(tt);
if (rule === undefined) {
if (!this.unknownCb(target, tlv, currentOrder)) {
if (!rule) {
if (!this.unknownHandler?.(target, tlv, currentOrder)) {
this.handleUnrecognized(tt, "unknown");

@@ -111,17 +97,15 @@ }

}
if (currentOrder < rule.order) {
currentOrder = rule.order;
currentCount = 0;
}
++currentCount;
if (!rule.repeat && currentCount > 1) {
currentOrder = rule.order;
if (!rule.repeat && foundTT.has(tt)) {
throw new Error(`TLV-TYPE ${printTT(tt)} cannot repeat in ${this.typeName}`);
}
foundTT.add(tt);
missingTT.delete(tt);
rule.cb(target, tlv);
}
if (missingTlvTypes.size > 0) {
throw new Error(`TLV-TYPE ${Array.from(missingTlvTypes).map(printTT).join(",")} ${missingTlvTypes.size === 1 ? "is" : "are"} missing in ${this.typeName}`);
if (missingTT.size > 0) {
throw new Error(`TLV-TYPE ${Array.from(missingTT, printTT).join(",")} missing in ${this.typeName}`);
}
for (const cb of this.afterValueCallbacks) {
cb(target);
for (const cb of this.afterObservers) {
cb(target, topTlv);
}

@@ -131,3 +115,3 @@ return target;

handleUnrecognized(tt, reason) {
if (this.isCriticalCb(tt)) {
if (this.isCritical(tt)) {
throw new Error(`TLV-TYPE ${printTT(tt)} is ${reason} in ${this.typeName}`);

@@ -134,0 +118,0 @@ }

@@ -7,14 +7,10 @@ import type { Decoder } from "./decoder";

private readonly rules;
private readonly requiredTlvTypes;
private readonly requiredTT;
private nextOrder;
private isCriticalCb;
private unknownCb;
/** Callbacks to receive top-level TLV before decoding TLV-VALUE. */
readonly beforeTopCallbacks: Array<EvDecoder.TopElementCallback<T>>;
private isCritical;
private unknownHandler?;
/** Callbacks before decoding TLV-VALUE. */
readonly beforeValueCallbacks: Array<EvDecoder.TargetCallback<T>>;
readonly beforeObservers: Array<EvDecoder.TlvObserver<T>>;
/** Callbacks after decoding TLV-VALUE. */
readonly afterValueCallbacks: Array<EvDecoder.TargetCallback<T>>;
/** Callbacks to receive top-level TLV after decoding TLV-VALUE. */
readonly afterTopCallbacks: Array<EvDecoder.TopElementCallback<T>>;
readonly afterObservers: Array<EvDecoder.TlvObserver<T>>;
/**

@@ -29,10 +25,10 @@ * Constructor.

* @param tt TLV-TYPE to match this rule.
* @param cb callback to handle element TLV.
* @param cb callback or nested EvDecoder to handle element TLV.
* @param options additional rule options.
*/
add(tt: number, cb: EvDecoder.ElementCallback<T> | EvDecoder<T>, options?: Partial<EvDecoder.RuleOptions>): this;
add(tt: number, cb: EvDecoder.ElementDecoder<T> | EvDecoder<T>, { order, required, repeat, }?: Partial<EvDecoder.RuleOptions>): this;
/** Set callback to determine whether TLV-TYPE is critical. */
setIsCritical(cb: EvDecoder.IsCriticalCallback): this;
setIsCritical(cb: EvDecoder.IsCritical): this;
/** Set callback to handle unknown elements. */
setUnknown(cb: EvDecoder.UnknownElementCallback<T>): this;
setUnknown(cb: EvDecoder.UnknownElementHandler<T>): this;
/** Decode TLV to target object. */

@@ -42,2 +38,3 @@ decode<R extends T = T>(target: R, decoder: Decoder): R;

decodeValue<R extends T = T>(target: R, vd: Decoder): R;
private decodeV;
private handleUnrecognized;

@@ -47,12 +44,19 @@ }

/** Invoked when a matching TLV element is found. */
type ElementCallback<T> = (target: T, tlv: Decoder.Tlv) => void;
type ElementDecoder<T> = (target: T, tlv: Decoder.Tlv) => void;
interface RuleOptions {
/**
* Expected order of appearance.
* When using this option, it should be specified for all rules in a EvDecoder.
* Default to the order in which rules were added to EvDecoder.
*/
order: number;
/** Whether TLV element must appear at least once. */
/**
* Whether TLV element must appear at least once.
* Default is false.
*/
required: boolean;
/** Whether TLV element may appear more than once. */
/**
* Whether TLV element may appear more than once.
* Default is false.
*/
repeat: boolean;

@@ -65,6 +69,14 @@ }

*/
type UnknownElementCallback<T> = (target: T, tlv: Decoder.Tlv, order: number) => boolean;
type IsCriticalCallback = (tt: number) => boolean;
type TopElementCallback<T> = (target: T, tlv: Decoder.Tlv) => void;
type TargetCallback<T> = (target: T) => void;
type UnknownElementHandler<T> = (target: T, tlv: Decoder.Tlv, order: number) => boolean;
/**
* Function to determine whether a TLV-TYPE number is "critical".
* Unrecognized or out-of-order TLV element with a critical TLV-TYPE number causes decoding error.
*/
type IsCritical = (tt: number) => boolean;
/**
* Callback before or after decoding TLV-VALUE.
* @param target target object.
* @param topTlv top-level TLV element, available in EVD.decode but unavailable in EVD.decodeValue.
*/
type TlvObserver<T> = (target: T, topTlv?: Decoder.Tlv) => void;
}

@@ -1,3 +0,2 @@

import { Encoder } from "./encoder_browser.js";
import { toHex } from "./string_browser.js";
import { asDataView, toHex } from "@ndn/util";
class Nni1 {

@@ -16,3 +15,3 @@ constructor(n) {

encodeTo(encoder) {
Encoder.asDataView(encoder.prependRoom(2)).setUint16(0, this.n);
asDataView(encoder.prependRoom(2)).setUint16(0, this.n);
}

@@ -25,3 +24,3 @@ }

encodeTo(encoder) {
Encoder.asDataView(encoder.prependRoom(4)).setUint32(0, this.n);
asDataView(encoder.prependRoom(4)).setUint32(0, this.n);
}

@@ -34,5 +33,5 @@ }

encodeTo(encoder) {
const dv = Encoder.asDataView(encoder.prependRoom(8));
const dv = asDataView(encoder.prependRoom(8));
dv.setUint32(0, this.n / 0x100000000);
dv.setUint32(4, this.n % 0x100000000);
dv.setUint32(4, this.n);
}

@@ -45,4 +44,3 @@ }

encodeTo(encoder) {
const dv = Encoder.asDataView(encoder.prependRoom(8));
Encoder.setBigUint64(dv, 0, this.n);
asDataView(encoder.prependRoom(8)).setBigUint64(0, this.n);
}

@@ -114,5 +112,5 @@ }

}
const dv = Encoder.asDataView(value);
const dv = asDataView(value);
if (big) {
return dv.byteLength === 8 ? Encoder.getBigUint64(dv, 0) : BigInt(decode32(dv));
return dv.byteLength === 8 ? dv.getBigUint64(0) : BigInt(decode32(dv));
}

@@ -131,8 +129,8 @@ if (dv.byteLength === 8) {

const [min = 0, max = Number.MAX_SAFE_INTEGER] = typeof limit1 === "number" ? [limit0, limit1] : [0, limit0];
if (n < min || n > max) {
if (!(n >= min && n <= max)) {
throw new RangeError(`${n} is out of ${typeName} valid range`);
}
return Math.floor(n);
return Math.trunc(n);
}
NNI.constrain = constrain;
})(NNI || (NNI = {}));

@@ -1,3 +0,2 @@

import { Encoder } from "./encoder_node.js";
import { toHex } from "./string_node.js";
import { asDataView, toHex } from "@ndn/util";
class Nni1 {

@@ -16,3 +15,3 @@ constructor(n) {

encodeTo(encoder) {
Encoder.asDataView(encoder.prependRoom(2)).setUint16(0, this.n);
asDataView(encoder.prependRoom(2)).setUint16(0, this.n);
}

@@ -25,3 +24,3 @@ }

encodeTo(encoder) {
Encoder.asDataView(encoder.prependRoom(4)).setUint32(0, this.n);
asDataView(encoder.prependRoom(4)).setUint32(0, this.n);
}

@@ -34,5 +33,5 @@ }

encodeTo(encoder) {
const dv = Encoder.asDataView(encoder.prependRoom(8));
const dv = asDataView(encoder.prependRoom(8));
dv.setUint32(0, this.n / 0x100000000);
dv.setUint32(4, this.n % 0x100000000);
dv.setUint32(4, this.n);
}

@@ -45,4 +44,3 @@ }

encodeTo(encoder) {
const dv = Encoder.asDataView(encoder.prependRoom(8));
Encoder.setBigUint64(dv, 0, this.n);
asDataView(encoder.prependRoom(8)).setBigUint64(0, this.n);
}

@@ -114,5 +112,5 @@ }

}
const dv = Encoder.asDataView(value);
const dv = asDataView(value);
if (big) {
return dv.byteLength === 8 ? Encoder.getBigUint64(dv, 0) : BigInt(decode32(dv));
return dv.byteLength === 8 ? dv.getBigUint64(0) : BigInt(decode32(dv));
}

@@ -131,8 +129,8 @@ if (dv.byteLength === 8) {

const [min = 0, max = Number.MAX_SAFE_INTEGER] = typeof limit1 === "number" ? [limit0, limit1] : [0, limit0];
if (n < min || n > max) {
if (!(n >= min && n <= max)) {
throw new RangeError(`${n} is out of ${typeName} valid range`);
}
return Math.floor(n);
return Math.trunc(n);
}
NNI.constrain = constrain;
})(NNI || (NNI = {}));

@@ -1,2 +0,2 @@

import { Encodable, Encoder } from "./encoder";
import { type Encodable, Encoder } from "./encoder";
declare class Nni1 {

@@ -3,0 +3,0 @@ private readonly n;

@@ -12,33 +12,1 @@ /** Pretty-print TLV-TYPE number. */

}
const INT2HEX = [];
const HEX2INT = {};
for (let b = 0; b <= 0xFF; ++b) {
const s = b.toString(16).padStart(2, "0").toUpperCase();
INT2HEX.push(s);
HEX2INT[s] = b;
}
/** Convert byte array to upper-case hexadecimal string. */
export function toHex(buf) {
return Array.from(buf, (b) => INT2HEX[b]).join("");
}
/**
* Convert hexadecimal string to byte array.
*
* This function lacks error handling. Use on trusted input only.
*/
export function fromHex(s) {
s = s.toUpperCase();
const b = new Uint8Array(s.length / 2);
for (let i = 0; i < b.length; ++i) {
b[i] = HEX2INT[s.slice(i * 2, (i + 1) * 2)];
}
return b;
}
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
export function toUtf8(s) {
return textEncoder.encode(s);
}
export function fromUtf8(buf) {
return textDecoder.decode(buf);
}

@@ -12,33 +12,1 @@ /** Pretty-print TLV-TYPE number. */

}
const INT2HEX = [];
const HEX2INT = {};
for (let b = 0; b <= 0xFF; ++b) {
const s = b.toString(16).padStart(2, "0").toUpperCase();
INT2HEX.push(s);
HEX2INT[s] = b;
}
/** Convert byte array to upper-case hexadecimal string. */
export function toHex(buf) {
return Array.from(buf, (b) => INT2HEX[b]).join("");
}
/**
* Convert hexadecimal string to byte array.
*
* This function lacks error handling. Use on trusted input only.
*/
export function fromHex(s) {
s = s.toUpperCase();
const b = new Uint8Array(s.length / 2);
for (let i = 0; i < b.length; ++i) {
b[i] = HEX2INT[s.slice(i * 2, (i + 1) * 2)];
}
return b;
}
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
export function toUtf8(s) {
return textEncoder.encode(s);
}
export function fromUtf8(buf) {
return textDecoder.decode(buf);
}
/** Pretty-print TLV-TYPE number. */
export declare function printTT(tlvType: number): string;
/** Convert byte array to upper-case hexadecimal string. */
export declare function toHex(buf: Uint8Array): string;
/**
* Convert hexadecimal string to byte array.
*
* This function lacks error handling. Use on trusted input only.
*/
export declare function fromHex(s: string): Uint8Array;
export declare function toUtf8(s: string): Uint8Array;
export declare function fromUtf8(buf: Uint8Array): string;
{
"name": "@ndn/tlv",
"version": "0.0.20210930",
"version": "0.0.20220501",
"description": "NDNts: TLV",

@@ -25,9 +25,8 @@ "keywords": [

"dependencies": {
"mnemonist": "^0.38.4",
"tslib": "^2.3.1"
"@ndn/util": "0.0.20220501",
"mnemonist": "^0.39.1",
"tslib": "^2.4.0"
},
"engines": {
"node": "^14.17.0 || ^16.8.0"
},
"types": "lib/mod.d.ts"
"types": "lib/mod.d.ts",
"readme": "# @ndn/tlv\n\nThis package is part of [NDNts](https://yoursunny.com/p/NDNts/), Named Data Networking libraries for the modern web.\n\nThis package implements Type-Length-Value structure encoder and decoder as specified in [NDN Packet Format v0.3](https://named-data.net/doc/NDN-packet-spec/0.3/tlv.html).\nIt has full support for TLV evolvability guidelines.\n\n```ts\nimport { Encoder, Decoder, EvDecoder, NNI } from \"@ndn/tlv\";\n\n// other imports for examples\nimport { Name, TT as nameTT } from \"@ndn/packet\";\nimport { strict as assert } from \"node:assert\";\n```\n\n## Encoder\n\nThe **Encoder** has an internal buffer of `Uint8Array` type.\nIt prepends any encodable items to the internal buffer, and reallocates a larger buffer when necessary.\n\n```ts\n// Encode TLV object that implements EncodableObj interface:\nlet encoder = new Encoder();\nencoder.encode(new Name(\"/A\"));\n// Look at the output:\nassert.deepEqual(encoder.output, Uint8Array.of(0x07, 0x03, 0x08, 0x01, 0x41));\n\n// Prepend a TLV structure with specified TLV-TYPE and TLV-VALUE:\nencoder = new Encoder();\nencoder.encode([0xB0, Uint8Array.of(0xC0, 0xC1)]);\nassert.deepEqual(encoder.output, Uint8Array.of(0xB0, 0x02, 0xC0, 0xC1));\n\n// Prepend a non-negative integer\nencoder.encode(NNI(0x200110));\n// We are using the same Encoder instance, so it gets prepended:\nassert.deepEqual(encoder.output, Uint8Array.of(0x00, 0x20, 0x01, 0x10, 0xB0, 0x02, 0xC0, 0xC1));\n\n// Put multiple encodable items in TLV-VALUE:\nencoder = new Encoder();\nencoder.encode([0xB0, Uint8Array.of(0xC0, 0xC1), new Name(\"/A\")]);\nassert.deepEqual(encoder.output,\n Uint8Array.of(0xB0, 0x07, 0xC0, 0xC1, 0x07, 0x03, 0x08, 0x01, 0x41));\n```\n\n## Decoder\n\nThe **Decoder** is a basic sequential decoder.\n\n```ts\n// Read Type-Length-Value manually:\nlet decoder = new Decoder(Uint8Array.of(0x08, 0x01, 0x41, 0xFF));\nconst { type, length, value } = decoder.read();\nassert.equal(type, 0x08);\nassert.equal(length, 1);\nassert.deepEqual(value, Uint8Array.of(0x41));\n// The remaining [0xFF] is still in the buffer.\n// If you continue reading, you get an error due to incomplete TLV.\nassert.throws(() => decoder.read());\n\n// Decode into TLV object:\ndecoder = new Decoder(Uint8Array.of(0x07, 0x03, 0x08, 0x01, 0x41));\nconst name = decoder.decode(Name);\nassert(name instanceof Name);\nassert.equal(name.toString(), \"/8=A\");\n```\n\n## EvDecoder\n\nThe **EvDecoder** is a decoder that is aware of TLV evolvability guidelines.\nIt's used to implement decoding functions of TLV objects, such as `Interest.decodeFrom`.\n\nSuppose we want to decode [NLSR's LSDB Dataset](https://redmine.named-data.net/projects/nlsr/wiki/LSDB_DataSet/11):\n\n```abnf\nAdjacency = ADJACENCY-TYPE TLV-LENGTH\n Name\n Uri\n Cost\nUri = URI-TYPE TLV-LENGTH *VCHAR\nCost = COST-TYPE TLV-LENGTH nonNegativeInteger\n\nADJACENCY-TYPE = 0x84\nURI-TYPE = 0x8D\nCOST-TYPE = 0x8C\n```\n\n```ts\n// Declare a class to represent this type.\nclass Adjacency {\n public name = new Name();\n public uri = \"\";\n public cost = 0;\n}\n\n// Declare constants for TLV-TYPE numbers.\nconst TT = {\n ...nameTT,\n Adjacency: 0x84,\n Cost: 0x8C,\n Uri: 0x8D,\n};\n\n// Create the decoder.\nconst EVD = new EvDecoder<Adjacency>(\"Adjacency\", TT.Adjacency)\n .add(TT.Name, (t, { decoder }) => t.name = decoder.decode(Name), { required: true })\n .add(TT.Uri, (t, { text }) => t.uri = text, { required: true })\n .add(TT.Cost, (t, { nni }) => t.cost = nni, { required: true });\n// Each rule declares a possible sub TLV.\n// They are added in the order of expected appearance.\n// The callback receives two arguments:\n// (1) the target object we are decoding into, so that EVD instances are reusable;\n// (2) a Decoder.Tlv structure, where we can selectively access just the TLV-VALUE, the whole TLV,\n// the TLV-VALUE as a Decoder, the whole TLV as a Decoder, etc.\n\n// Suppose we receive this encoded TLV:\nconst adjacencyWire = Uint8Array.of(\n 0x84, 0x0D,\n 0x07, 0x03, 0x08, 0x01, 0x41, // Name\n 0x8D, 0x01, 0x42, // Uri\n 0xF0, 0x00, // unrecognized non-critical TLV-TYPE, ignored\n 0x8C, 0x01, 0x80, // Cost\n);\nconst adjacencyDecoder = new Decoder(adjacencyWire);\n\n// We can decode it with the EVD.\nconst adjacency = EVD.decode(new Adjacency(), adjacencyDecoder);\nassert.equal(adjacency.name.toString(), \"/8=A\");\nassert.equal(adjacency.uri, \"B\");\nassert.equal(adjacency.cost, 128);\n```\n"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc