UNPKG

@syncfusion/ej2-pdf

Version:

Feature-rich JavaScript PDF library with built-in support for loading and manipulating PDF document.

1,202 lines (1,201 loc) 46 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); import { _PdfAbstractSyntaxElement } from './abstract-syntax'; import { _ConstructionType, _RealEncodingBase, _TagClassType, _UniversalType } from './enumerator'; import { _convertBytesToText } from './utils'; import { _PdfUniqueEncodingElement } from './unique-encoding-element'; import { _stringToBytes } from '../../../utils'; import { _PdfObjectIdentifier } from './identifier-mapping'; /** * Basic BER/DER encoding element providing encoding/decoding helpers for primitive and constructed types. * * @private */ var _PdfBasicEncodingElement = /** @class */ (function (_super) { __extends(_PdfBasicEncodingElement, _super); /** * Initializes a basic encoding element with optional tag class, construction, tag number and value. * * @private * @param {_TagClassType} tagClass The tag class for the element. * @param {_ConstructionType} construction Whether the element is primitive or constructed. * @param {number} tagNumber The numeric tag number. * @param {any} value Optional initial value to encode. */ function _PdfBasicEncodingElement(tagClass, construction, tagNumber, value) { if (tagClass === void 0) { tagClass = _TagClassType.universal; } if (construction === void 0) { construction = _ConstructionType.primitive; } if (tagNumber === void 0) { tagNumber = _UniversalType.endOfContent; } if (value === void 0) { value = undefined; } var _this = _super.call(this) || this; /** * Preferred length encoding to use when serializing this element. * * @private */ _this._lengthEncodingPreference = _EncodingLength.definite; /** * Internal storage for this element's value; may be raw bytes or child elements. */ _this._value = new Uint8Array(0); /** * ASCII code for period `.` used by string parsing helpers. * * @private */ _this._period = '.'.charCodeAt(0); /** * ASCII code for comma `,` used by string parsing helpers. * * @private */ _this._comma = ','.charCodeAt(0); /** * ASCII code for `Z` used by time/date parsing helpers. * * @private */ _this._z = 'Z'.charCodeAt(0); /** * ASCII code for plus `+` used by time/date parsing helpers. * * @private */ _this._plus = '+'.charCodeAt(0); /** * ASCII code for minus `-` used by time/date parsing helpers. * * @private */ _this._minus = '-'.charCodeAt(0); _this._encode(value); _this._tagClass = tagClass; _this._construction = construction; _this._setTagNumber(tagNumber); return _this; } /** * Returns the raw value bytes for this element, encoding constructed content if necessary. * * @private * @returns {Uint8Array} The raw value bytes. */ _PdfBasicEncodingElement.prototype._getValue = function () { if (this._value instanceof Uint8Array) { return this._value; } var bytes = this._encodeSequence(this._value); this._value = bytes; return bytes; }; /** * Sets the raw value bytes for this element and updates cached length. * * @private * @param {Uint8Array} value The value bytes to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setValue = function (value) { this._currentValueLength = value.length; this._value = value; }; /** * Decodes and returns the boolean value for this element. * * @private * @returns {boolean} The decoded boolean. */ _PdfBasicEncodingElement.prototype._getBooleanValue = function () { if (this._construction !== _ConstructionType.primitive) { throw new Error('boolean cannot be constructed.'); } return this._decodeBoolean(this._getValue()); }; /** * Encodes and sets a boolean value for this element. * * @private * @param {boolean} value The boolean to set. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setBooleanValue = function (value) { this._setValue(this._encodeBoolean(value)); }; /** * Returns the bit string content for this element, concatenating parts if constructed. * * @private * @returns {Uint8ClampedArray} The bit string. */ _PdfBasicEncodingElement.prototype._getBitString = function () { if (this._construction === _ConstructionType.primitive) { return this._decodeBitString(this._getValue()); } if ((this._recursionCount + 1) > this._nestingRecursionLimit) { throw new Error(); } var appendy = []; var substrings = this._getSequence(); for (var _i = 0, _a = substrings.slice(0, (substrings.length - 1)); _i < _a.length; _i++) { var substring = _a[_i]; var value = substring._getValue(); if (substring._construction === _ConstructionType.primitive && value.length > 0 && value[0] !== 0x00) { throw new Error('Only the final part of a multi-part bit string may start with a non-zero value.'); } } for (var _b = 0, substrings_1 = substrings; _b < substrings_1.length; _b++) { var substring = substrings_1[_b]; if (substring._tagClass !== this._tagClass) { throw new Error('Invalid tag class in recursively-encoded bit string.'); } if (substring._getTagNumber() !== this._getTagNumber()) { throw new Error('Invalid tag class in recursively-encoded bit string.'); } substring._recursionCount = (this._recursionCount + 1); appendy.push.apply(appendy, Array.from(substring._getBitString()).map(function (b) { return b !== 0; })); } return new Uint8ClampedArray(appendy.map(function (b) { return (b ? 1 : 0); })); }; /** * Encodes and sets a bit string value for this element. * * @private * @param {Uint8ClampedArray} value The bit string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setBitString = function (value) { this._setValue(this._encodeBitString(value)); }; /** * Returns the octet string bytes for this element. * * @private * @returns {Uint8Array} The octet string bytes. */ _PdfBasicEncodingElement.prototype._getOctetString = function () { return this._serialize('OCTET STRING'); }; /** * Sets the octet string value for this element. * * @private * @param {Uint8Array} value The octet string bytes to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setOctetString = function (value) { this._setValue(new Uint8Array(value)); }; /** * Returns the object descriptor string for this element. * * @private * @returns {string} The object descriptor. */ _PdfBasicEncodingElement.prototype._getObjectDescriptor = function () { var bytes = this._serialize('ObjectDescriptor'); return this._decodeObjectDescriptor(bytes); }; /** * Encodes and sets the object descriptor string for this element. * * @private * @param {string} value The descriptor to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setObjectDescriptor = function (value) { this._setValue(this._encodeObjectDescriptor(value)); }; /** * Returns the UTF-8 string value for this element. * * @private * @returns {string} The UTF-8 decoded string. */ _PdfBasicEncodingElement.prototype._getUtf8String = function () { return _convertBytesToText(this._serialize('UTF8String')); }; /** * Sets the UTF-8 string value for this element. * * @private * @param {string} value The UTF-8 string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setUtf8String = function (value) { this._setValue(_stringToBytes(value)); }; /** * Returns the sequence child elements for this constructed element. * * @private * @returns {_PdfAbstractSyntaxElement[]} The sequence elements. */ _PdfBasicEncodingElement.prototype._getSequence = function () { if (this._construction !== _ConstructionType.constructed) { throw new Error('Set or sequence cannot be primitively constructed.'); } if (Array.isArray(this._value)) { return this._value; } return this._decodedSequence(this._getValue()); }; /** * Sets the sequence child elements for this element and marks it constructed. * * @private * @param {_PdfAbstractSyntaxElement[]} value The sequence elements to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setSequence = function (value) { this._construct(value); this._construction = _ConstructionType.constructed; }; /** * Returns the elements for an abstract SET value after uniqueness validation. * * @private * @returns {_PdfAbstractSyntaxElement[]} The set elements. */ _PdfBasicEncodingElement.prototype._getAbstractSetValue = function () { var ret = this._getSequence(); if (!this._isUniquelyTagged(ret)) { throw new Error('Duplicate tag in Set.'); } return ret; }; /** * Sets the elements for an abstract SET value. * * @private * @param {_PdfAbstractSyntaxElement[]} value The set elements to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setAbstractSetValue = function (value) { this._setSequence(value); }; /** * Returns the elements when this is a `SEQUENCE OF`. * * @private * @returns {_PdfAbstractSyntaxElement[]} The sequence-of elements. */ _PdfBasicEncodingElement.prototype._getSequenceOf = function () { if (this._construction !== _ConstructionType.constructed) { throw new Error('Set or sequence cannot be primitively constructed.'); } if (Array.isArray(this._value)) { return this._value; } return this._decodedSequence(this._getValue()); }; /** * Sets the elements when this is a `SEQUENCE OF` and marks constructed. * * @private * @param {_PdfAbstractSyntaxElement[]} value The elements to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setSequenceOf = function (value) { this._construct(value); this._construction = _ConstructionType.constructed; }; /** * Returns the elements when this is a `SET OF`. * * @private * @returns {_PdfAbstractSyntaxElement[]} The set-of elements. */ _PdfBasicEncodingElement.prototype._getAbstractSetOf = function () { return this._getSequence(); }; /** * Sets the elements when this is a `SET OF`. * * @private * @param {_PdfAbstractSyntaxElement[]} value The elements to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setAbstractSetOf = function (value) { this._setSequence(value); }; /** * Returns the numeric string value for this element. * * @private * @returns {string} The numeric string. */ _PdfBasicEncodingElement.prototype._getNumericString = function () { var bytes = this._serialize('NumericString'); return this._decodeNumericString(bytes); }; /** * Sets the numeric string value for this element. * * @private * @param {string} value The numeric string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setNumericString = function (value) { this._setValue(this._encodeNumericString(value)); }; /** * Returns the printable string value for this element. * * @private * @returns {string} The printable string. */ _PdfBasicEncodingElement.prototype._getPrintableString = function () { var bytes = this._serialize('PrintableString'); return this._decodePrintableString(bytes); }; /** * Sets the printable string value for this element. * * @private * @param {string} value The printable string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setPrintableString = function (value) { this._setValue(this._encodePrintableString(value)); }; /** * Returns teleprinter (Teletex) text bytes for this element. * * @private * @returns {Uint8Array} The teleprinter bytes. */ _PdfBasicEncodingElement.prototype._getTeleprinterText = function () { return this._serialize('TeletexString'); }; /** * Sets teleprinter (Teletex) text bytes for this element. * * @private * @param {Uint8Array} value The bytes to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setTeleprinterText = function (value) { this._setValue(new Uint8Array(value)); }; /** * Returns videotex information bytes for this element. * * @private * @returns {Uint8Array} The videotex bytes. */ _PdfBasicEncodingElement.prototype._getVideoTextInformation = function () { return this._serialize('VideotexString'); }; /** * Sets videotex information bytes for this element. * * @private * @param {Uint8Array} value The bytes to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setVideoTextInformation = function (value) { this._setValue(new Uint8Array(value)); }; /** * Returns the IA5 (international alphabet) string for this element. * * @private * @returns {string} The IA5 string. */ _PdfBasicEncodingElement.prototype._getInternationalAlphabetString = function () { return _convertBytesToText(this._serialize('IA5String')); }; /** * Sets the IA5 (international alphabet) string for this element. * * @private * @param {string} value The IA5 string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setInternationalAlphabetString = function (value) { this._setValue(_stringToBytes(value)); }; /** * Returns the graphic string for this element. * * @private * @returns {string} The graphic string. */ _PdfBasicEncodingElement.prototype._getGraphicString = function () { var bytes = this._serialize('GraphicString'); return this._decodeGraphicString(bytes); }; /** * Sets the graphic string value for this element. * * @private * @param {string} value The graphic string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setGraphicString = function (value) { this._setValue(this._encodeGraphicString(value)); }; /** * Returns the visible string for this element. * * @private * @returns {string} The visible string. */ _PdfBasicEncodingElement.prototype._getVisibleString = function () { return this._decodeVisibleString(this._getValue()); }; /** * Sets the visible string value for this element. * * @private * @param {string} value The visible string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setVisibleString = function (value) { this._setValue(this._encodeVisibleString(value)); }; /** * Returns the general string for this element. * * @private * @returns {string} The general string. */ _PdfBasicEncodingElement.prototype._getGeneralString = function () { var bytes = this._serialize('GeneralString'); return this._decodeGeneralString(bytes); }; /** * Sets a character string (complex structure) for this element and marks it constructed. * * @private * @param {_PdfCharacterString} value The character string structure to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setCharacterString = function (value) { this._setValue(this._encodeCharacterString(value)); this._construction = _ConstructionType.constructed; }; /** * Returns the universal (UTF-32) string for this element. * * @private * @returns {string} The universal string. */ _PdfBasicEncodingElement.prototype._getUniversalString = function () { var valueBytes = this._serialize('UniversalString'); if (valueBytes.length % 4) { throw new Error('Unicode string encoded on non-mulitple of four bytes.'); } var ret = ''; for (var i = 0; i < valueBytes.length; i += 4) { ret += String.fromCharCode((valueBytes[i + 0] << 24) + (valueBytes[i + 1] << 16) + (valueBytes[i + 2] << 8) + (valueBytes[i + 3] << 0)); } return ret; }; /** * Sets the universal (UTF-32) string for this element. * * @private * @param {string} value The universal string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setUniversalString = function (value) { var buf = new Uint8Array(value.length << 2); for (var i = 0; i < value.length; i++) { buf[(i << 2)] = value.charCodeAt(i) >>> 24; buf[(i << 2) + 1] = value.charCodeAt(i) >>> 16; buf[(i << 2) + 2] = value.charCodeAt(i) >>> 8; buf[(i << 2) + 3] = value.charCodeAt(i); } this._setValue(buf); }; /** * Returns the BMP (UTF-16BE) string for this element. * * @private * @returns {string} The BMP string. */ _PdfBasicEncodingElement.prototype._getBmpString = function () { var valueBytes = this._serialize('BMPString'); if (valueBytes.length % 2 !== 0) { throw new Error('BMPString encoded on non-multiple of two bytes.'); } if (typeof TextDecoder !== 'undefined') { return new TextDecoder('utf-16be').decode(valueBytes); } var result = ''; for (var i = 0; i < valueBytes.length; i += 2) { var code = (valueBytes[i] << 8) | valueBytes[i + 1]; result += String.fromCharCode(code); } return result; }; /** * Sets the BMP (UTF-16BE) string for this element. * * @private * @param {string} value The BMP string to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setBmpString = function (value) { var buf = new Uint8Array(value.length << 1); for (var i = 0; i < value.length; i++) { var code = value.charCodeAt(i); buf[i << 1] = code >>> 8; buf[(i << 1) + 1] = code & 0xff; } this._setValue(buf); }; /** * Constructs this element from provided child elements (internal helper). * * @private * @param {_PdfAbstractSyntaxElement[]} els The child elements to set. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._construct = function (els) { this._currentValueLength = undefined; this._value = els; }; /** * Encodes a JavaScript value into the appropriate ASN.1 encoding for this element. * * @private * @param {any} value The value to encode. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._encode = function (value) { switch (typeof value) { case ('undefined'): { this._setValue(new Uint8Array(0)); break; } case ('boolean'): { this._setTagNumber(_UniversalType.abstractSyntaxBoolean); this._setBooleanValue(value); break; } case ('number'): { if (Number.isInteger(value)) { this._setTagNumber(_UniversalType.integer); this._setInteger(value); } break; } case ('string'): { this._setTagNumber(_UniversalType.utf8String); this._setUtf8String(value); break; } case ('object'): { if (!value) { this._setTagNumber(_UniversalType.nullValue); this._setValue(new Uint8Array(0)); } else if (value instanceof Uint8Array) { this._setTagNumber(_UniversalType.octetString); this._setOctetString(value); } else if (value instanceof Uint8ClampedArray) { this._setTagNumber(_UniversalType.bitString); this._setBitString(value); } else if (value instanceof _PdfAbstractSyntaxElement) { this._construction = _ConstructionType.constructed; this._setSequence([value]); } else if (Array.isArray(value) && value.every(function (v) { return v instanceof _PdfAbstractSyntaxElement; })) { this._construction = _ConstructionType.constructed; this._setAbstractSetValue(Array.from(value)); } else if (value instanceof _PdfObjectIdentifier) { this._setTagNumber(_UniversalType.objectIdentifier); this._setObjectIdentifier(value); } else if (Array.isArray(value)) { this._construction = _ConstructionType.constructed; this._setTagNumber(_UniversalType.sequence); this._setSequence(value.map(function (sub) { var ret = new _PdfBasicEncodingElement(); ret._encode(sub); return ret; })); } else { throw new Error("Cannot encode value of type " + value.constructor.name + "."); } break; } default: { throw new Error("Cannot encode value of type " + typeof value + "."); } } }; /** * Wraps a BER sequence into a `_PdfBasicEncodingElement` representing a SEQUENCE. * * @private * @param {_PdfAbstractSyntaxElement[]} sequence The sequence elements. * @returns {_PdfBasicEncodingElement} The constructed sequence element. */ _PdfBasicEncodingElement.prototype._fromBerSequence = function (sequence) { var ret = new _PdfBasicEncodingElement(_TagClassType.universal, _ConstructionType.constructed, _UniversalType.sequence); ret._setSequence(sequence.filter(function (element) { return Boolean(element); })); return ret; }; /** * Wraps a set of basic encoding elements into a `_PdfBasicEncodingElement` representing a SET. * * @private * @param {_PdfBasicEncodingElement[]} set The set elements. * @returns {_PdfBasicEncodingElement} The constructed set element. */ _PdfBasicEncodingElement.prototype._fromSet = function (set) { var ret = new _PdfBasicEncodingElement(_TagClassType.universal, _ConstructionType.constructed, _UniversalType.abstractSyntaxSet); ret._setAbstractSetValue(set.filter(function (element) { return Boolean(element); })); return ret; }; /** * Wraps a set-of elements into a `_PdfBasicEncodingElement` representing a SET OF. * * @private * @param {_PdfBasicEncodingElement[]} set The set-of elements. * @returns {_PdfBasicEncodingElement} The constructed set-of element. */ _PdfBasicEncodingElement.prototype._fromSetOf = function (set) { var ret = new _PdfBasicEncodingElement(_TagClassType.universal, _ConstructionType.constructed, _UniversalType.abstractSyntaxSet); ret._setAbstractSetOf(set.filter(function (element) { return Boolean(element); })); return ret; }; /** * Retrieves the single inner element for explicitly-encoded elements. * * @private * @param {boolean} [isCertificateParsing] Optional flag to relax trailing bytes validation. * @returns {_PdfAbstractSyntaxElement} The inner element. */ _PdfBasicEncodingElement.prototype._getInner = function (isCertificateParsing) { if (this._construction !== _ConstructionType.constructed) { throw new Error('An explicitly-encoded element cannot be encoded using ' + 'primitive construction.'); } if (Array.isArray(this._value)) { if (this._value.length !== 1) { throw new Error("An explicitly-encoding element contained " + this._value.length + " encoded elements."); } return this._value[0]; } var ret = new _PdfBasicEncodingElement(); var readBytes = ret._fromBytes(this._value); if (readBytes !== this._value.length && !isCertificateParsing) { throw new Error('An explicitly-encoding element contained more than one single ' + 'encoded element. The tag number of the first decoded ' + ("element was " + ret._getTagNumber() + ", and it was encoded on ") + (readBytes + " bytes.")); } return ret; }; /** * Sets a single inner element and marks this element as constructed. * * @private * @param {_PdfAbstractSyntaxElement} value The inner element to assign. * @returns {void} nothing. */ _PdfBasicEncodingElement.prototype._setInner = function (value) { this._construction = _ConstructionType.constructed; this._value = [value]; }; /** * Decodes this element from the provided BER/DER bytes and returns number of bytes consumed. * * @private * @param {Uint8Array} bytes The input bytes to decode. * @returns {number} The number of bytes consumed. */ _PdfBasicEncodingElement.prototype._fromBytes = function (bytes) { if (bytes.length < 2) { throw new Error('Tried to decode a BER element that is less than two bytes.'); } if ((this._recursionCount + 1) > this._nestingRecursionLimit) { throw new Error(); } var cursor = 0; var first = bytes[cursor]; switch (first & 192) { case 0: this._tagClass = _TagClassType.universal; break; case 64: this._tagClass = _TagClassType.application; break; case 128: this._tagClass = _TagClassType.context; break; case 192: this._tagClass = _TagClassType.abstractSyntaxPrivate; break; } this._construction = ((first & 32) ? _ConstructionType.constructed : _ConstructionType.primitive); var tagNumber = (first & 31); cursor++; if (tagNumber >= 31) { if (cursor >= bytes.length) { throw new Error('ASN1 tag number appears to have been truncated.'); } if (bytes[cursor] === 0x80) { throw new Error('Leading padding byte on long tag number encoding.'); } tagNumber = 0; var running = true; while (running) { if (cursor >= bytes.length) { throw new Error('ASN1 tag number appears to have been truncated.'); } var b = bytes[cursor++]; tagNumber = (tagNumber << 7) | (b & 0x7F); if ((b & 0x80) === 0) { running = false; } } if (tagNumber < 31) { throw new Error('ASN1 tag number could have been encoded in short form.'); } this._setTagNumber(tagNumber); } else { this._setTagNumber(tagNumber); } if (cursor >= bytes.length) { throw new Error('Element length bytes appear to have been truncated.'); } var lenOctet = bytes[cursor++]; if ((lenOctet & 0x80) === 0x80) { var numberOfLengthOctets = (lenOctet & 0x7F); if (numberOfLengthOctets === 0) { if (this._construction !== _ConstructionType.constructed) { throw new Error('Invalid format: indefinite-length elements must be constructed, not primitive.'); } var startOfValue = cursor; var sentinel = cursor; while (sentinel < bytes.length) { var child = new _PdfBasicEncodingElement(); sentinel += child._fromBytes(bytes.subarray(sentinel)); if (child._tagClass === _TagClassType.universal && child._construction === _ConstructionType.primitive && child._getTagNumber() === _UniversalType.endOfContent && child._getValue().length === 0) { break; } } if (sentinel === bytes.length && (bytes[sentinel - 1] !== 0x00 || bytes[sentinel - 2] !== 0x00)) { throw new Error('Invalid format: indefinite-length ASN1 elements must end with an End-of-Content marker'); } this._setValue(bytes.slice(startOfValue, sentinel - 2)); return sentinel; } var n = numberOfLengthOctets; if (cursor + n > bytes.length) { throw new Error('Element length bytes appear to have been truncated.'); } var length_1 = 0; for (var i = 0; i < n; i++) { length_1 = (length_1 << 8) | bytes[cursor + i]; } cursor += n; if ((cursor + length_1) < cursor) { throw new Error('ASN1 element too large.'); } if ((cursor + length_1) > bytes.length) { throw new Error('ASN1 element truncated.'); } this._setValue(bytes.slice(cursor, cursor + length_1)); return cursor + length_1; } else { var length_2 = (lenOctet & 0x7F); if ((cursor + length_2) > bytes.length) { throw new Error('ASN1 element was truncated.'); } this._setValue(bytes.slice(cursor, cursor + length_2)); return cursor + length_2; } }; /** * Computes the number of bytes required to encode the length field for a value length. * * @private * @param {number} [valueLength] Optional explicit value length to evaluate. * @returns {number} The number of bytes used to encode the length. */ _PdfBasicEncodingElement.prototype._lengthLength = function (valueLength) { if (this._lengthEncodingPreference === _EncodingLength.indefinite) { return 1; } var len = (valueLength !== null && typeof valueLength !== 'undefined') ? valueLength : this._valueLength(); if (len < 128) { return 1; } var n = 0; var v = len; while (v > 0) { n++; v >>>= 8; } return 1 + n; }; /** * Returns the length in bytes of this element's encoded value. * * @private * @returns {number} The value length. */ _PdfBasicEncodingElement.prototype._valueLength = function () { if (typeof this._currentValueLength !== 'undefined' && this._currentValueLength !== null && !Array.isArray(this._value)) { return this._currentValueLength; } if (!Array.isArray(this._value)) { var value = this._getValue(); this._currentValueLength = value.length; return value.length; } var len = 0; for (var _i = 0, _a = this._value; _i < _a.length; _i++) { var element = _a[_i]; len += element._tagValueLength(); // eslint-disable-line } this._currentValueLength = len; return len; }; /** * Produces the tag and length bytes for this element. * * @private * @returns {Uint8Array} The tag-and-length bytes. */ _PdfBasicEncodingElement.prototype._tagAndLengthBytes = function () { var tagBytes = [0x00]; tagBytes[0] |= (this._tagClass << 6); tagBytes[0] |= ((this._lengthEncodingPreference === _EncodingLength.indefinite) || this._construction === _ConstructionType.constructed) ? (1 << 5) : 0; var tagNumber = this._getTagNumber(); if (tagNumber < 31) { tagBytes[0] |= tagNumber; } else { tagBytes[0] |= 31; var number = tagNumber; var encodedNumber = []; do { encodedNumber.unshift(number & 0x7F); number >>>= 7; } while (number > 0); for (var i = 0; i < encodedNumber.length - 1; i++) { encodedNumber[i] |= 0x80; } tagBytes.push.apply(tagBytes, encodedNumber); } var lengthOctets = []; var valueLen = this._valueLength(); switch (this._lengthEncodingPreference) { case _EncodingLength.definite: { if (valueLen < 128) { lengthOctets = [valueLen]; } else { var octets = []; var v = valueLen; while (v > 0) { octets.unshift(v & 0xff); v >>>= 8; } lengthOctets = [0x80 | octets.length].concat(octets); } break; } case _EncodingLength.indefinite: { lengthOctets = [0x80]; break; } default: throw new Error('An unsupported length encoding preference was detected'); } var ret = new Uint8Array(tagBytes.length + lengthOctets.length); ret.set(tagBytes, 0); ret.set(lengthOctets, tagBytes.length); return ret; }; /** * Serializes this element into an array of buffers representing tag, length and value parts. * * @private * @returns {Uint8Array[]} Array of buffers. */ _PdfBasicEncodingElement.prototype._toBuffers = function () { var buffers = []; buffers.push(this._tagAndLengthBytes()); if (Array.isArray(this._value)) { for (var _i = 0, _a = this._value; _i < _a.length; _i++) { var el = _a[_i]; var subBuffers = el._toBuffers(); for (var _b = 0, subBuffers_1 = subBuffers; _b < subBuffers_1.length; _b++) { var buf = subBuffers_1[_b]; buffers.push(buf); } } } else { buffers.push(this._value); } if (this._lengthEncodingPreference === _EncodingLength.indefinite) { buffers.push(new Uint8Array(2)); } return buffers; }; /** * Serializes constructed content into a single value buffer for the provided data type hint. * * @private * @param {string} dataType A textual hint for the data type being serialized. * @returns {Uint8Array} The serialized value bytes. */ _PdfBasicEncodingElement.prototype._serialize = function (dataType) { if (this._construction === _ConstructionType.primitive) { return this._getValue(); } if ((this._recursionCount + 1) > this._nestingRecursionLimit) { throw new Error("Exceeded recursion limit while deconstructing " + dataType); } var parts = []; var substrings = this._getSequence(); var parentTag = this._getTagNumber(); for (var _i = 0, substrings_2 = substrings; _i < substrings_2.length; _i++) { var substring = substrings_2[_i]; if (parentTag === _UniversalType.octetString) { if (substring._tagClass !== _TagClassType.universal || substring._getTagNumber() !== _UniversalType.octetString) { throw new Error('Invalid constructed OCTET STRING: children must be OCTET STRING (tag 4).'); } } else { if (substring._tagClass !== this._tagClass || substring._getTagNumber() !== parentTag) { throw new Error("Invalid constructed " + dataType + ": children must be of the same type as the parent."); } } substring._recursionCount = this._recursionCount + 1; parts.push(substring._getValue()); } var totalLength = parts.reduce(function (sum, part) { return sum + part.length; }, 0); var result = new Uint8Array(totalLength); var offset = 0; for (var _a = 0, parts_1 = parts; _a < parts_1.length; _a++) { var part = parts_1[_a]; result.set(part, offset); offset += part.length; } return result; }; /** * Returns the component elements when this element represents constructed content. * * @private * @returns {_PdfAbstractSyntaxElement[]} Component elements. */ _PdfBasicEncodingElement.prototype._getComponents = function () { if (Array.isArray(this._value)) { return this._value; } var encodedElements = []; var i = 0; while (i < this._value.length) { var next = new _PdfBasicEncodingElement(); i += next._fromBytes(this._getValue().subarray(i)); encodedElements.push(next); } return encodedElements; }; /** * Decodes an ASN.1 BIT STRING from bytes into a bit array. * * @private * @param {Uint8Array} value The bytes to decode. * @returns {Uint8ClampedArray} The decoded bit array. */ _PdfBasicEncodingElement.prototype._decodeBitString = function (value) { if (value.length === 0) { throw new Error('ASN1 Bit String cannot be encoded on zero bytes!'); } if (value.length === 1 && value[0] !== 0) { throw new Error('ASN1 Bit String encoded with deceptive first byte!'); } if (value[0] > 7) { throw new Error('First byte of an ASN1 Bit String must be <= 7!'); } var ret = []; for (var i = 1; i < value.length; i++) { var values = value[i]; ret.push(((values & 128) ? 1 : 0), ((values & 64) ? 1 : 0), ((values & 32) ? 1 : 0), ((values & 16) ? 1 : 0), ((values & 8) ? 1 : 0), ((values & 4) ? 1 : 0), ((values & 2) ? 1 : 0), ((values & 1) ? 1 : 0)); } ret.length -= value[0]; return new Uint8ClampedArray(ret); }; /** * Decodes an ASN.1 BOOLEAN from bytes. * * @private * @param {Uint8Array} value The bytes to decode. * @returns {boolean} The decoded boolean. */ _PdfBasicEncodingElement.prototype._decodeBoolean = function (value) { if (value.length !== 1) { throw new Error('Invalid Boolean format: Boolean values must be exactly one byte.'); } return (value[0] !== 0); }; /** * Decodes a sequence of basic encoding elements from bytes. * * @private * @param {Uint8Array} value The bytes to decode. * @returns {_PdfBasicEncodingElement[]} Decoded elements. */ _PdfBasicEncodingElement.prototype._decodedSequence = function (value) { var encodedElements = []; var i = 0; while (i < value.length) { var next = new _PdfBasicEncodingElement(); i += next._fromBytes(value.subarray(i)); encodedElements.push(next); } return encodedElements; }; /** * Determines the numeric base used for REAL encoding from a control byte. * * @private * @param {number} byte The control byte to inspect. * @returns {number} The numeric base (2, 8, or 16). */ _PdfBasicEncodingElement.prototype._getRealEncodingBase = function (byte) { switch (byte & 48) { case _RealEncodingBase.base2: return 2; case _RealEncodingBase.base8: return 8; case _RealEncodingBase.base16: return 16; default: throw new Error('Impossible real encoding base encountered.'); } }; /** * Encodes a `_PdfCharacterString` structure into bytes suitable for this element. * * @private * @param {_PdfCharacterString} value The character-string structure to encode. * @returns {Uint8Array} The encoded bytes. */ _PdfBasicEncodingElement.prototype._encodeCharacterString = function (value) { return this._encodeSequence([ value._identification, new _PdfUniqueEncodingElement(_TagClassType.universal, _ConstructionType.primitive, _UniversalType.octetString, value._stringValue) ]); }; /** * Decodes a sequence of unique encoding elements from bytes. * * @private * @param {Uint8Array} value The bytes to decode. * @returns {_PdfUniqueEncodingElement[]} Decoded unique elements. */ _PdfBasicEncodingElement.prototype._decodeSequence = function (value) { if (value.length === 0) { return []; } var encodedElements = []; var i = 0; while (i < value.length) { var next = new _PdfUniqueEncodingElement(); var consumed = next._fromBytes(value.subarray(i)); i += consumed; encodedElements.push(next); } return encodedElements; }; /** * Wraps a sequence of abstract syntax elements into a unique encoding element. * * @private * @param {_PdfAbstractSyntaxElement[]} sequence The sequence elements. * @returns {_PdfUniqueEncodingElement} The wrapped unique element. */ _PdfBasicEncodingElement.prototype._fromSequence = function (sequence) { var ret = new _PdfUniqueEncodingElement(_TagClassType.universal, _ConstructionType.constructed, _UniversalType.sequence); ret._setSequence(sequence.filter(function (element) { return Boolean(element); })); return ret; }; /** * Returns the external encoding represented by an encoding element, mapping tag options to values. * * @private * @param {_PdfAbstractSyntaxElement} encodingElement The encoding element describing the external. * @returns {_PdfAbstractSyntaxElement|Uint8Array|Uint8ClampedArray} The decoded external payload. */ _PdfBasicEncodingElement.prototype._getExternalEncoding = function (encodingElement) { switch (encodingElement._getTagNumber()) { case 0: return encodingElement._getInner(); case 1: return encodingElement._getOctetString(); case 2: return encodingElement._getBitString(); default: throw new Error('external does not know of an encoding option ' + ("having tag number " + encodingElement._getTagNumber() + ".")); } }; /** * Returns the total encoded length of this element including tag and length fields. * * @private * @returns {number} The combined tag+length+value length in bytes. */ _PdfBasicEncodingElement.prototype._tagValueLength = function () { var value = this._valueLength(); return this._tagLength() + this._lengthLength(value) + value; }; return _PdfBasicEncodingElement; }(_PdfAbstractSyntaxElement)); export { _PdfBasicEncodingElement }; /** * Represents the internal encoding length type used for defining whether the structure * uses definite or indefinite length encoding. * * @private */ export var _EncodingLength; (function (_EncodingLength) { _EncodingLength[_EncodingLength["definite"] = 0] = "definite"; _EncodingLength[_EncodingLength["indefinite"] = 1] = "indefinite"; })(_EncodingLength || (_EncodingLength = {}));