JavaScript generic ASN.1 parser (mirror)

Add JSDoc comments. (by `qwen3-coder:30b`)

+83 -7
+83 -7
asn1.js
··· 521 521 } 522 522 } 523 523 524 + /** 525 + * ASN1 class for parsing ASN.1 encoded data. 526 + * Instances of this class represent an ASN.1 element and provides methods to parse and display its content. 527 + */ 524 528 export class ASN1 { 529 + /** 530 + * Creates an ASN1 parser object. 531 + * @param {Stream} stream - The stream containing the ASN.1 data. 532 + * @param {number} header - The header length. 533 + * @param {number} length - The length of the data. 534 + * @param {ASN1Tag} tag - The ASN.1 tag. 535 + * @param {number} tagLen - The length of the tag. 536 + * @param {Array} sub - The sub-elements. 537 + */ 525 538 constructor(stream, header, length, tag, tagLen, sub) { 526 539 if (!(tag instanceof ASN1Tag)) throw new Error('Invalid tag value.'); 527 540 this.stream = stream; ··· 531 544 this.tagLen = tagLen; 532 545 this.sub = sub; 533 546 } 547 + 548 + /** 549 + * Get the type name of the ASN.1 element. 550 + * @returns {string} The type name. 551 + */ 534 552 typeName() { 535 553 switch (this.tag.tagClass) { 536 554 case 0: // universal ··· 570 588 case 3: return 'Private_' + this.tag.tagNumber.toString(); 571 589 } 572 590 } 573 - /** A string preview of the content (intended for humans). */ 591 + 592 + /** 593 + * Get a string preview of the content (intended for humans). 594 + * @param {number} maxLength - The maximum length of the content. 595 + * @returns {string|null} The content preview or null if not supported. 596 + */ 574 597 content(maxLength) { 575 598 if (this.tag === undefined) 576 599 return null; ··· 638 661 } 639 662 return null; 640 663 } 664 + 665 + /** 666 + * Get a string representation of the ASN.1 element. 667 + * @returns {string} The string representation. 668 + */ 641 669 toString() { 642 670 return this.typeName() + '@' + this.stream.pos + '[header:' + this.header + ',length:' + this.length + ',sub:' + ((this.sub === null) ? 'null' : this.sub.length) + ']'; 643 671 } 672 + 673 + /** 674 + * Get a pretty string representation of the ASN.1 element. 675 + * @param {string} indent - The indentation string. 676 + * @returns {string} The pretty string representation. 677 + */ 644 678 toPrettyString(indent) { 645 679 if (indent === undefined) indent = ''; 646 680 let s = indent; ··· 671 705 } 672 706 return s; 673 707 } 708 + 709 + /** 710 + * Get the starting position of the element in the stream. 711 + * @returns {number} The starting position. 712 + */ 674 713 posStart() { 675 714 return this.stream.pos; 676 715 } 716 + 717 + /** 718 + * Get the position of the content in the stream. 719 + * @returns {number} The content position. 720 + */ 677 721 posContent() { 678 722 return this.stream.pos + this.header; 679 723 } 724 + 725 + /** 726 + * Get the ending position of the element in the stream. 727 + * @returns {number} The ending position. 728 + */ 680 729 posEnd() { 681 730 return this.stream.pos + this.header + Math.abs(this.length); 682 731 } 683 - /** Position of the length. */ 732 + 733 + /** 734 + * Get the position of the length in the stream. 735 + * @returns {number} The length position. 736 + */ 684 737 posLen() { 685 738 return this.stream.pos + this.tagLen; 686 739 } 687 - /** Hexadecimal dump of the node. 688 - * @param type 'raw', 'byte' or 'dump' */ 740 + 741 + /** 742 + * Get a hexadecimal dump of the node. 743 + * @param {string} [type='raw'] - The dump type: 'raw', 'byte', or 'dump'. 744 + * @returns {string} The hexadecimal dump. 745 + */ 689 746 toHexString(type = 'raw') { 690 747 return this.stream.hexDump(this.posStart(), this.posEnd(), type); 691 748 } 692 - /** Base64url dump of the node (according to RFC 4648 section 5). 693 - * @param {string} type 'url' (default, section 5 without padding) or 'std' (section 4 with padding) 694 - */ 749 + 750 + /** 751 + * Get a base64url dump of the node (according to RFC 4648 section 5). 752 + * @param {string} [type='url'] - The dump type: 'url' (section 5 without padding) or 'std' (section 4 with padding). 753 + * @returns {string} The base64 encoded representation. 754 + */ 695 755 toB64String(type = 'url') { 696 756 return this.stream.b64Dump(this.posStart(), this.posEnd(), type); 697 757 } 758 + 759 + /** 760 + * Decode the length field of an ASN.1 element. 761 + * @param {Stream} stream - The stream to read from. 762 + * @returns {number|null} The decoded length, or null for indefinite length. 763 + * @throws {Error} If the length is invalid or exceeds 48 bits. 764 + */ 698 765 static decodeLength(stream) { 699 766 const buf = stream.get(), 700 767 len = buf & 0x7F; ··· 709 776 value = (value << 8) | stream.get(); 710 777 return value; 711 778 } 779 + 780 + /** 781 + * Decode an ASN.1 element from a stream. 782 + * @param {Stream|array|string} stream - The input data. 783 + * @param {number} [offset=0] - The offset to start decoding from. 784 + * @param {Function} [type=ASN1] - The class to instantiate. 785 + * @returns {ASN1} The decoded ASN.1 element. 786 + * @throws {Error} If the decoding fails. 787 + */ 712 788 static decode(stream, offset, type = ASN1) { 713 789 if (!(type == ASN1 || type.prototype instanceof ASN1)) 714 790 throw new Error('Must pass a class that extends ASN1');