node-custom-tlv
Version:
parser for custom tlv structure
205 lines (161 loc) • 4.65 kB
JavaScript
const {
validateArgs,
deleteWhiteSpaces,
createLengthParams,
makeToUpperCase,
computeCustomByteLengths,
makeStringFromBuffer,
checkForParity,
BYTE_FACTOR
} = require("./helpers/helpers");
let finalJson = {};
class NestedContext {
context;
constructor(parentTag, length) {
this.context = {
parentTag,
parentLength: length
};
}
get context() {
return this.context;
}
}
class NodeCustomTlv {
dictionary = {};
baseTagLength = BYTE_FACTOR * 2;
baseLengthTlvLength = BYTE_FACTOR * 1;
customByteLengths = null;
customByteLengthComputed = [];
constructor(settings) {
if (!validateArgs(settings)) {
return;
}
this.dictionary = settings.dictionary;
this.baseTagLength = BYTE_FACTOR * settings.baseTagLength;
this.baseLengthTlvLength = BYTE_FACTOR * settings.baseLengthTlvLength;
this.customByteLengths = settings.customByteLengths;
finalJson = {};
}
parseTlv(data, nestedContext = null) {
let str;
if (typeof data == "string") {
str = data;
} else if (Buffer.isBuffer(data)) {
str = makeStringFromBuffer(buffer);
} else {
console.error("wrong first argument: " + data);
return;
}
str = deleteWhiteSpaces(str);
str = makeToUpperCase(str);
let initialStr;
if (!checkForParity(str.length)) {
console.error("fail of string parity, length: " + str.length);
return;
}
if (!nestedContext) {
initialStr = str;
if (this.customByteLengths && this.customByteLengths.length) {
this.customByteLengthComputed = computeCustomByteLengths(
this.customByteLengths,
this.baseTagLength
);
}
}
if (nestedContext && !(nestedContext instanceof NestedContext)) {
console.error("wrong second argument: " + nestedContext);
return;
}
const k = this.baseTagLength;
let help_nested = {};
for (let i = 0; i < str.length; ) {
const help_obj = {};
let tagObj;
let value;
let fullTag;
let tagName;
const tag = str.substr(i, k);
if (
nestedContext &&
nestedContext.context &&
nestedContext.context.parentTag
) {
fullTag = nestedContext.context.parentTag + tag;
} else {
fullTag = tag;
}
tagObj = this.dictionary[fullTag];
if (!tagObj) {
tagName = fullTag;
} else {
tagName = tagObj.name;
}
const lenthByte = str.substring(
i + this.baseTagLength,
i + this.baseTagLength + this.baseLengthTlvLength
);
const createLengthPayload = {
baselengthByte: lenthByte,
i,
str,
baseTagLength: this.baseTagLength,
baseLengthTlvLength: this.baseLengthTlvLength,
customByteLengthComputed: this.customByteLengthComputed
? this.customByteLengthComputed
: null
};
const { length, differ } = createLengthParams(createLengthPayload);
if (tagObj && tagObj.nested) {
value = str.substring(i + differ, i + differ + length);
const parentTag = `${fullTag}-`;
const nestedContext = new NestedContext(parentTag, length);
help_obj[tagName] = this.parseTlv(value, nestedContext);
}
if (
(tagObj && !tagObj.nested && !nestedContext) ||
(!tagObj && !nestedContext)
) {
value = str.substring(i + differ, i + differ + length);
help_obj[tagName] = parseInt(value, 16);
finalJson = { ...finalJson, ...help_obj };
}
if (
nestedContext &&
nestedContext.context &&
nestedContext.context.parentTag &&
tagObj &&
!tagObj.nested
) {
value = str.substring(i + differ, i + differ + length);
help_obj[tagName] = parseInt(value, 16);
help_nested = { ...help_nested, ...help_obj };
}
if (
nestedContext &&
nestedContext.context &&
nestedContext.context.parentTag &&
tagObj &&
tagObj.nested
) {
help_nested = { ...help_nested, ...help_obj };
}
if (!nestedContext && tagObj && tagObj.nested) {
finalJson = { ...finalJson, ...help_obj };
}
if (!nestedContext && initialStr.length - 1 <= i + differ + length) {
return finalJson;
}
i = i + differ + length;
}
if (
nestedContext &&
nestedContext.context &&
nestedContext.context.parentTag &&
nestedContext.context.parentLength
) {
return help_nested;
}
}
}
module.exports = NodeCustomTlv;