diff --git a/asn1.js b/asn1.js
index d157950..5dde9a3 100644
--- a/asn1.js
+++ b/asn1.js
@@ -348,6 +348,29 @@ function recurse(el, parser, maxLength) {
return d;
}
+class ASN1Tag {
+ constructor(stream) {
+ let buf = stream.get();
+ this.tagClass = buf >> 6;
+ this.tagConstructed = ((buf & 0x20) !== 0);
+ this.tagNumber = buf & 0x1F;
+ if (this.tagNumber == 0x1F) { // long tag
+ let n = new Int10();
+ do {
+ buf = stream.get();
+ n.mulAdd(128, buf & 0x7F);
+ } while (buf & 0x80);
+ this.tagNumber = n.simplify();
+ }
+ }
+ isUniversal() {
+ return this.tagClass === 0x00;
+ };
+ isEOC() {
+ return this.tagClass === 0x00 && this.tagNumber === 0x00;
+ };
+}
+
class ASN1 {
constructor(stream, header, length, tag, tagLen, sub) {
if (!(tag instanceof ASN1Tag)) throw 'Invalid tag value.';
@@ -519,7 +542,9 @@ class ASN1 {
buf = (buf * 256) + stream.get();
return buf;
};
- static decode(stream, offset) {
+ static decode(stream, offset, type = ASN1) {
+ if (!(type.prototype instanceof ASN1))
+ throw 'Must pass a class that extends ASN1';
if (!(stream instanceof Stream))
stream = new Stream(stream, offset || 0);
let streamStart = new Stream(stream),
@@ -537,14 +562,14 @@ class ASN1 {
if (end > stream.enc.length)
throw 'Container at offset ' + start + ' has a length of ' + len + ', which is past the end of the stream';
while (stream.pos < end)
- sub[sub.length] = ASN1.decode(stream);
+ sub[sub.length] = type.decode(stream);
if (stream.pos != end)
throw 'Content size is not correct for container at offset ' + start;
} else {
// undefined length
try {
for (;;) {
- let s = ASN1.decode(stream);
+ let s = type.decode(stream);
if (s.tag.isEOC())
break;
sub[sub.length] = s;
@@ -579,34 +604,11 @@ class ASN1 {
throw "We can't skip over an invalid tag with undefined length at offset " + start;
stream.pos = start + Math.abs(len);
}
- return new ASN1(streamStart, header, len, tag, tagLen, sub);
+ return new type(streamStart, header, len, tag, tagLen, sub);
};
}
-class ASN1Tag {
- constructor(stream) {
- let buf = stream.get();
- this.tagClass = buf >> 6;
- this.tagConstructed = ((buf & 0x20) !== 0);
- this.tagNumber = buf & 0x1F;
- if (this.tagNumber == 0x1F) { // long tag
- let n = new Int10();
- do {
- buf = stream.get();
- n.mulAdd(128, buf & 0x7F);
- } while (buf & 0x80);
- this.tagNumber = n.simplify();
- }
- }
- isUniversal() {
- return this.tagClass === 0x00;
- };
- isEOC() {
- return this.tagClass === 0x00 && this.tagNumber === 0x00;
- };
-}
-
return ASN1;
});
diff --git a/dom.js b/dom.js
index 6a474c3..f293eb4 100644
--- a/dom.js
+++ b/dom.js
@@ -14,8 +14,8 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
(typeof define != 'undefined' ? define : function (factory) { 'use strict';
- if (typeof module == 'object') factory(function (name) { return require(name); });
- else factory(function (name) { return window[name.substring(2)]; });
+ if (typeof module == 'object') module.exports = factory(function (name) { return require(name); });
+ else window.dom = factory(function (name) { return window[name.substring(2)]; });
})(function (require) {
'use strict';
@@ -57,166 +57,175 @@ const
}
};
-ASN1.prototype.toDOM = function (spaces) {
- spaces = spaces || '';
- let isOID = (typeof oids === 'object') && (this.tag.isUniversal() && (this.tag.tagNumber == 0x06) || (this.tag.tagNumber == 0x0D));
- let node = DOM.tag('div', 'node');
- node.asn1 = this;
- let head = DOM.tag('div', 'head');
- head.innerHTML = "" + spaces + '' + this.typeName().replace(/_/g, ' ');
- let content = this.content(contentLength);
- let oid;
- if (content !== null) {
- let preview = DOM.tag('span', 'preview'),
- shortContent;
- if (isOID)
- content = content.split('\n', 1)[0];
- shortContent = (content.length > lineLength) ? content.substring(0, lineLength) + DOM.ellipsis : content;
- preview.appendChild(DOM.space());
- preview.appendChild(DOM.text(shortContent));
- if (isOID) {
- oid = oids[content];
- if (oid) {
- if (oid.d) {
- preview.appendChild(DOM.space());
- let oidd = DOM.tag('span', 'oid description');
- oidd.appendChild(DOM.text(oid.d));
- preview.appendChild(oidd);
- }
- if (oid.c) {
- preview.appendChild(DOM.space());
- let oidc = DOM.tag('span', 'oid comment');
- oidc.appendChild(DOM.text('(' + oid.c + ')'));
- preview.appendChild(oidc);
+class ASN1DOM extends ASN1 {
+
+ toDOM(spaces) {
+ spaces = spaces || '';
+ let isOID = (typeof oids === 'object') && (this.tag.isUniversal() && (this.tag.tagNumber == 0x06) || (this.tag.tagNumber == 0x0D));
+ let node = DOM.tag('div', 'node');
+ node.asn1 = this;
+ let head = DOM.tag('div', 'head');
+ head.innerHTML = "" + spaces + '' + this.typeName().replace(/_/g, ' ');
+ let content = this.content(contentLength);
+ let oid;
+ if (content !== null) {
+ let preview = DOM.tag('span', 'preview'),
+ shortContent;
+ if (isOID)
+ content = content.split('\n', 1)[0];
+ shortContent = (content.length > lineLength) ? content.substring(0, lineLength) + DOM.ellipsis : content;
+ preview.appendChild(DOM.space());
+ preview.appendChild(DOM.text(shortContent));
+ if (isOID) {
+ oid = oids[content];
+ if (oid) {
+ if (oid.d) {
+ preview.appendChild(DOM.space());
+ let oidd = DOM.tag('span', 'oid description');
+ oidd.appendChild(DOM.text(oid.d));
+ preview.appendChild(oidd);
+ }
+ if (oid.c) {
+ preview.appendChild(DOM.space());
+ let oidc = DOM.tag('span', 'oid comment');
+ oidc.appendChild(DOM.text('(' + oid.c + ')'));
+ preview.appendChild(oidc);
+ }
}
}
+ head.appendChild(preview);
+ content = DOM.breakLines(content, lineLength);
+ content = content.replace(/');
}
- head.appendChild(preview);
- content = DOM.breakLines(content, lineLength);
- content = content.replace(/');
- }
- node.appendChild(head);
- this.node = node;
- this.head = head;
- let value = DOM.tag('div', 'value');
- let s = 'Offset: ' + this.stream.pos + '
';
- s += 'Length: ' + this.header + '+';
- if (this.length >= 0)
- s += this.length;
- else
- s += (-this.length) + ' (undefined)';
- if (this.tag.tagConstructed)
- s += '
(constructed)';
- else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null))
- s += '
(encapsulates)';
- //TODO if (this.tag.isUniversal() && this.tag.tagNumber == 0x03) s += "Unused bits: "
- if (content !== null) {
- s += '
Value:
' + content + '';
- if (isOID && oid) {
- if (oid.d) s += '
' + oid.d;
- if (oid.c) s += '
' + oid.c;
- if (oid.w) s += '
(warning!)';
+ node.appendChild(head);
+ this.node = node;
+ this.head = head;
+ let value = DOM.tag('div', 'value');
+ let s = 'Offset: ' + this.stream.pos + '
';
+ s += 'Length: ' + this.header + '+';
+ if (this.length >= 0)
+ s += this.length;
+ else
+ s += (-this.length) + ' (undefined)';
+ if (this.tag.tagConstructed)
+ s += '
(constructed)';
+ else if ((this.tag.isUniversal() && ((this.tag.tagNumber == 0x03) || (this.tag.tagNumber == 0x04))) && (this.sub !== null))
+ s += '
(encapsulates)';
+ //TODO if (this.tag.isUniversal() && this.tag.tagNumber == 0x03) s += "Unused bits: "
+ if (content !== null) {
+ s += '
Value:
' + content + '';
+ if (isOID && oid) {
+ if (oid.d) s += '
' + oid.d;
+ if (oid.c) s += '
' + oid.c;
+ if (oid.w) s += '
(warning!)';
+ }
}
- }
- value.innerHTML = s;
- node.appendChild(value);
- let sub = DOM.tag('div', 'sub');
- if (this.sub !== null) {
- spaces += '\xA0 ';
- for (let i = 0, max = this.sub.length; i < max; ++i)
- sub.appendChild(this.sub[i].toDOM(spaces));
- }
- node.appendChild(sub);
- head.onclick = function () {
- node.className = (node.className == 'node collapsed') ? 'node' : 'node collapsed';
- };
- return node;
-};
-ASN1.prototype.fakeHover = function (current) {
- this.node.className += ' hover';
- if (current)
- this.head.className += ' hover';
-};
-ASN1.prototype.fakeOut = function (current) {
- let re = / ?hover/;
- this.node.className = this.node.className.replace(re, '');
- if (current)
- this.head.className = this.head.className.replace(re, '');
-};
-ASN1.prototype.toHexDOM_sub = function (node, className, stream, start, end) {
- if (start >= end)
- return;
- let sub = DOM.tag('span', className);
- sub.appendChild(DOM.text(
- stream.hexDump(start, end)));
- node.appendChild(sub);
-};
-ASN1.prototype.toHexDOM = function (root) {
- let node = DOM.tag('span', 'hex');
- if (root === undefined) root = node;
- this.head.hexNode = node;
- this.head.onmouseover = function () { this.hexNode.className = 'hexCurrent'; };
- this.head.onmouseout = function () { this.hexNode.className = 'hex'; };
- node.asn1 = this;
- node.onmouseover = function () {
- let current = !root.selected;
- if (current) {
- root.selected = this.asn1;
- this.className = 'hexCurrent';
+ value.innerHTML = s;
+ node.appendChild(value);
+ let sub = DOM.tag('div', 'sub');
+ if (this.sub !== null) {
+ spaces += '\xA0 ';
+ for (let i = 0, max = this.sub.length; i < max; ++i)
+ sub.appendChild(this.sub[i].toDOM(spaces));
}
- this.asn1.fakeHover(current);
+ node.appendChild(sub);
+ head.onclick = function () {
+ node.className = (node.className == 'node collapsed') ? 'node' : 'node collapsed';
+ };
+ return node;
};
- node.onmouseout = function () {
- let current = (root.selected == this.asn1);
- this.asn1.fakeOut(current);
- if (current) {
- root.selected = null;
- this.className = 'hex';
- }
+ fakeHover(current) {
+ this.node.className += ' hover';
+ if (current)
+ this.head.className += ' hover';
+ };
+ fakeOut(current) {
+ let re = / ?hover/;
+ this.node.className = this.node.className.replace(re, '');
+ if (current)
+ this.head.className = this.head.className.replace(re, '');
};
- if (root == node) {
- let lineStart = this.posStart() & 0xF;
- if (lineStart != 0) {
- let skip = DOM.tag('span', 'skip');
- let skipStr = '';
- for (let j = lineStart; j > 0; --j)
- skipStr += ' ';
- if (lineStart >= 8)
- skipStr += ' ';
- skip.innerText = skipStr;
- node.appendChild(skip);
+ toHexDOM_sub(node, className, stream, start, end) {
+ if (start >= end)
+ return;
+ let sub = DOM.tag('span', className);
+ sub.appendChild(DOM.text(
+ stream.hexDump(start, end)));
+ node.appendChild(sub);
+ };
+ toHexDOM(root) {
+ let node = DOM.tag('span', 'hex');
+ if (root === undefined) root = node;
+ this.head.hexNode = node;
+ this.head.onmouseover = function () { this.hexNode.className = 'hexCurrent'; };
+ this.head.onmouseout = function () { this.hexNode.className = 'hex'; };
+ node.asn1 = this;
+ node.onmouseover = function () {
+ let current = !root.selected;
+ if (current) {
+ root.selected = this.asn1;
+ this.className = 'hexCurrent';
+ }
+ this.asn1.fakeHover(current);
+ };
+ node.onmouseout = function () {
+ let current = (root.selected == this.asn1);
+ this.asn1.fakeOut(current);
+ if (current) {
+ root.selected = null;
+ this.className = 'hex';
+ }
+ };
+ if (root == node) {
+ let lineStart = this.posStart() & 0xF;
+ if (lineStart != 0) {
+ let skip = DOM.tag('span', 'skip');
+ let skipStr = '';
+ for (let j = lineStart; j > 0; --j)
+ skipStr += ' ';
+ if (lineStart >= 8)
+ skipStr += ' ';
+ skip.innerText = skipStr;
+ node.appendChild(skip);
+ }
}
+ this.toHexDOM_sub(node, 'tag', this.stream, this.posStart(), this.posLen());
+ this.toHexDOM_sub(node, (this.length >= 0) ? 'dlen' : 'ulen', this.stream, this.posLen(), this.posContent());
+ if (this.sub === null) {
+ let start = this.posContent();
+ let end = this.posEnd();
+ if (end - start < 10 * 16)
+ node.appendChild(DOM.text(
+ this.stream.hexDump(start, end)));
+ else {
+ let end1 = start + 5 * 16 - (start & 0xF);
+ let start2 = end - 16 - (end & 0xF);
+ node.appendChild(DOM.text(
+ this.stream.hexDump(start, end1)));
+ let sub = DOM.tag('span', 'skip');
+ sub.appendChild(DOM.text('\u2026 skipping ' + (start2 - end1) + ' bytes \u2026\n'));
+ node.appendChild(sub);
+ node.appendChild(DOM.text(
+ this.stream.hexDump(start2, end)));
+ }
+ } else if (this.sub.length > 0) {
+ let first = this.sub[0];
+ let last = this.sub[this.sub.length - 1];
+ this.toHexDOM_sub(node, 'intro', this.stream, this.posContent(), first.posStart());
+ for (let i = 0, max = this.sub.length; i < max; ++i)
+ node.appendChild(this.sub[i].toHexDOM(root));
+ this.toHexDOM_sub(node, 'outro', this.stream, last.posEnd(), this.posEnd());
+ } else
+ this.toHexDOM_sub(node, 'outro', this.stream, this.posContent(), this.posEnd());
+ return node;
+ };
+ static decode(stream, offset) {
+ return ASN1.decode(stream, offset, ASN1DOM);
}
- this.toHexDOM_sub(node, 'tag', this.stream, this.posStart(), this.posLen());
- this.toHexDOM_sub(node, (this.length >= 0) ? 'dlen' : 'ulen', this.stream, this.posLen(), this.posContent());
- if (this.sub === null) {
- let start = this.posContent();
- let end = this.posEnd();
- if (end - start < 10 * 16)
- node.appendChild(DOM.text(
- this.stream.hexDump(start, end)));
- else {
- let end1 = start + 5 * 16 - (start & 0xF);
- let start2 = end - 16 - (end & 0xF);
- node.appendChild(DOM.text(
- this.stream.hexDump(start, end1)));
- let sub = DOM.tag('span', 'skip');
- sub.appendChild(DOM.text('\u2026 skipping ' + (start2 - end1) + ' bytes \u2026\n'));
- node.appendChild(sub);
- node.appendChild(DOM.text(
- this.stream.hexDump(start2, end)));
- }
- } else if (this.sub.length > 0) {
- let first = this.sub[0];
- let last = this.sub[this.sub.length - 1];
- this.toHexDOM_sub(node, 'intro', this.stream, this.posContent(), first.posStart());
- for (let i = 0, max = this.sub.length; i < max; ++i)
- node.appendChild(this.sub[i].toHexDOM(root));
- this.toHexDOM_sub(node, 'outro', this.stream, last.posEnd(), this.posEnd());
- } else
- this.toHexDOM_sub(node, 'outro', this.stream, this.posContent(), this.posEnd());
- return node;
-};
+
+}
+
+return ASN1DOM;
});