UNPKG

@codianz/emv-tools

Version:
255 lines 9.65 kB
"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