@codianz/emv-tools
Version:
255 lines • 9.65 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tlv = exports.TLV = void 0;
const data_chunk_holder_1 = require("./data_chunk_holder");
const data_chunk_1 = require("./data_chunk");
const emv_tags_1 = require("./emv_tags");
var TLV;
(function (TLV) {
let class_type;
(function (class_type) {
class_type[class_type["invalid"] = 255] = "invalid";
class_type[class_type["universal"] = 0] = "universal";
class_type[class_type["application"] = 64] = "application";
class_type[class_type["context_specific"] = 128] = "context_specific";
class_type[class_type["private_use"] = 192] = "private_use";
})(class_type = TLV.class_type || (TLV.class_type = {}));
class tag extends data_chunk_holder_1.data_chunk_holder {
constructor(data) {
super(data);
}
static create_from_data_chunk(src) {
do {
if (!src.valid)
break;
let idx = 0;
const _0 = src.get_byte(idx);
if (_0 === undefined)
break;
idx++;
if ((_0 & 0x1F) != 0x1F) {
return new tag(src.get_range(0, 1));
}
while (true) {
const d = src.get_byte(idx);
if (d === undefined)
break;
idx++;
if ((d & 0x80) == 0) {
return new tag(src.get_range(0, idx));
}
}
} while (false);
return new tag();
}
static create_from_uint8array(src, offset, length) {
return tag.create_from_data_chunk(data_chunk_1.data_chunk.create_from_uint8array(src, 0, src.length));
}
static create_from_hex_string(str) {
return tag.create_from_data_chunk(data_chunk_1.data_chunk.create_from_hex_string(str));
}
get class_type() {
if (!this.valid)
return class_type.invalid;
const _0 = this.data_chunk.get_byte(0);
if (_0 === undefined)
return class_type.invalid;
return _0 & 0xC0;
}
get is_constructed() {
if (!this.valid)
return false;
const _0 = this.data_chunk.get_byte(0);
if (_0 === undefined)
return false;
return (_0 & 0x20) != 0;
}
get is_primitive() {
return !this.is_constructed;
}
}
TLV.tag = tag;
class length extends data_chunk_holder_1.data_chunk_holder {
constructor(data, value_length) {
super(data);
this.m_value_length = 0;
this.m_value_length = value_length !== null && value_length !== void 0 ? value_length : 0;
}
static create_from_tag_and_data_chunk(tag, src) {
do {
if (!tag.valid)
break;
if (!src.valid)
break;
return this.craete_from_data_chunk(src.get_range(tag.size, src.size - tag.size));
} while (false);
return new length();
}
static craete_from_data_chunk(src) {
do {
if (!src.valid)
break;
let idx = 0;
const _0 = src.get_byte(idx);
if (_0 === undefined)
break;
idx++;
if ((_0 & 0x80) == 0) {
return new length(src.get_range(0, 1), _0);
}
const _length = _0 & 0x7F;
if (_length == 0)
break;
if (_length > 8)
break;
let value_length = 0;
for (let i = 0; i < _length; i++) {
const d = src.get_byte(idx);
if (d === undefined)
break;
idx++;
value_length = (value_length << 8) | d;
}
return new length(src.get_range(0, idx), value_length);
} while (false);
return new length();
}
get value_length() {
return this.m_value_length;
}
}
TLV.length = length;
class value extends data_chunk_holder_1.data_chunk_holder {
constructor(data) {
super(data);
}
static create_from_tag_and_length_and_data_chunk(tag, length, src) {
do {
if (!tag.valid)
break;
if (!length.valid)
break;
if (!src.valid)
break;
if (src.size < (tag.size + length.size + length.value_length))
break;
return new value(src.get_range(tag.size + length.size, length.value_length));
} while (false);
return new value();
}
}
TLV.value = value;
})(TLV = exports.TLV || (exports.TLV = {})); /* namespace tlv */
class tlv {
constructor(tag, length, value) {
this.m_children = [];
this.m_tag = tag !== null && tag !== void 0 ? tag : new TLV.tag();
this.m_length = length !== null && length !== void 0 ? length : new TLV.length();
this.m_value = value !== null && value !== void 0 ? value : new TLV.value();
if (this.valid && this.tag.is_constructed) {
let idx = 0;
const src = this.value.data_chunk;
while (idx < src.size) {
const child = tlv.create_from_data_chunk(src.get_range(idx, src.size - idx));
this.m_children.push(child);
if (!child.valid)
break;
idx += child.size;
}
}
}
static create_from_data_chunk(src) {
if (!src.valid)
return new tlv();
const tag = TLV.tag.create_from_data_chunk(src);
const length = TLV.length.create_from_tag_and_data_chunk(tag, src);
const value = TLV.value.create_from_tag_and_length_and_data_chunk(tag, length, src);
return new tlv(tag, length, value);
}
get valid() {
return this.m_tag.valid && this.m_length.valid && this.m_value.valid;
}
get size() {
return this.m_tag.size + this.m_length.size + this.m_value.size;
}
get tag() {
return this.m_tag;
}
get length() {
return this.m_length;
}
get value() {
return this.m_value;
}
get children() {
return this.m_children;
}
find_children(tag) {
const result = [];
for (const child of this.m_children) {
if (child.tag.equals(tag))
result.push(child);
}
return result;
}
find_first_child(tag) {
for (const child of this.m_children) {
if (child.tag.equals(tag))
return child;
}
return new tlv();
}
to_string(indent = 0, parentTag) {
const _i = " ".repeat(indent);
if (!this.valid)
return _i + "(invalid tlv)";
// const class_type_to_string = (class_type: TLV.class_type): string => {
// switch(class_type) {
// case TLV.class_type.invalid: return "invalid";
// case TLV.class_type.universal: return "universal";
// case TLV.class_type.application: return "application";
// case TLV.class_type.context_specific: return "context_specific";
// case TLV.class_type.private_use: return "private_use";
// }
// };
const tag_name = (() => {
const infos = emv_tags_1.EmvTags.Instance.findByTag(this.tag.to_hex_string());
if (infos.length == 0) {
return this.tag.is_constructed ? "unknown template" : "unknown value";
}
const target = infos.find(info => {
if (info.length) {
if (info.length != this.length.value_length)
return false;
}
return info.template.find(x => x == (parentTag === null || parentTag === void 0 ? void 0 : parentTag.to_hex_string())) != undefined;
});
if (target)
return target.name;
if (parentTag === undefined)
return infos[0].name;
return `${infos[0].name} (?)`;
})();
const value_string = (() => {
const s = this.value.to_string_if_printable();
return s ? `"${s}"` : "";
})();
let result = "";
result += _i + `tag: ${this.tag.data_chunk.to_hex_string()} (${tag_name})\n`;
// result += _i + ` - class_type: ${class_type_to_string(this.tag.class_type)}\n`;
// result += _i + ` - is_constructed: ${this.tag.is_constructed}\n`;
// result += _i + ` - is_premitive: ${this.tag.is_primitive}\n`;
result += _i + `length: ${this.length.data_chunk.to_hex_string()} (${this.length.value_length})\n`;
result += _i + `value: ${this.value.data_chunk.to_hex_string()} ${value_string}\n`;
if (this.children.length == 0)
return result;
result += _i + "children:\n";
for (let i = 0; i < this.children.length; i++) {
result += _i + `[${i}]\n`;
result += this.children[i].to_string(indent + 1, this.tag);
}
return result;
}
}
exports.tlv = tlv;
//# sourceMappingURL=tlv.js.map