UNPKG

@syncfusion/ej2-pdf

Version:

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

3,777 lines 169 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 { _XmlWriter } from './xml-writer';
import { PdfAnnotation, PdfFileLinkAnnotation, PdfTextWebLinkAnnotation, PdfDocumentLinkAnnotation, Pdf3DAnnotation, PdfPopupAnnotation } from './../annotations/annotation';
import { PdfAnnotationFlag } from './../enumerator';
import { _PdfDictionary, _PdfName, _PdfReference } from './../pdf-primitives';
import { _PdfBaseStream, _PdfContentStream } from './../base-stream';
import { _hexStringToByteArray, _stringToAnnotationFlags, _convertToColor, _bytesToString, _hexStringToString, _getSpecialCharacter, _getLatinCharacter, _getInheritableProperty, _getNewGuidString, _byteArrayToHexString, _stringToBytes, _annotationFlagsToString, _encode, _compressStream } from './../utils';
import { PdfCheckBoxField, PdfComboBoxField, PdfListBoxField, PdfRadioButtonListField, PdfTextBoxField, PdfListField } from './../form/field';
/**
 * Provides common helpers for exporting and importing annotations and form fields across formats and manages shared state.
 *
 * @private
 */
var _ExportHelper = /** @class */ (function () {
    function _ExportHelper() {
        /**
         * Determines whether export logic should strictly follow the PDF
         * specification for field and annotation serialization.
         *
         * @private
         */
        this._asPerSpecification = false;
        /**
         * File name used during export operations.
         *
         * @private
         */
        this._fileName = '';
        /**
         * Auxiliary form key appended to rich text values.
         *
         * @private
         */
        this._formKey = '';
        /**
         * When true, export fields even when empty.
         *
         * @private
         */
        this._exportEmptyFields = false;
        /**
         * Group name to reference mapping used during export/import.
         *
         * @private
         */
        this._groupReferences = new Map();
        /**
         * Holders for grouped dictionaries queued during processing.
         *
         * @private
         */
        this._groupHolders = [];
        /**
         * Prefix used for embedding rich text payloads.
         *
         * @private
         */
        this._richTextPrefix = '<?xml version="1.0"?>';
        /**
         * Temporary table mapping field names to exported values.
         *
         * @private
         */
        this._table = new Map(); // eslint-disable-line
        /**
         * Internal map of field name to value arrays gathered during export.
         *
         * @private
         */
        this._fields = new Map();
        /**
         * Rich text values keyed by field name.
         *
         * @private
         */
        this._richTextValues = new Map();
        /**
         * Working JSON data buffer used during conversion.
         *
         * @private
         */
        this._jsonData = [];
        /**
         * ASCII code for '{'
         *
         * @private
         */
        this._openingBrace = 123;
        /**
         * ASCII code for '['
         *
         * @private
         */
        this._openingBracket = 91;
        /**
         * ASCII code for '}'
         *
         * @private
         */
        this._closingBrace = 125;
        /**
         * ASCII code for ']'
         *
         * @private
         */
        this._closingBracket = 93;
        /**
         * ASCII code for ':'
         *
         * @private
         */
        this._colon = 58;
        /**
         * ASCII code for '"'
         *
         * @private
         */
        this._doubleQuotes = 34;
        /**
         * ASCII code for ','
         *
         * @private
         */
        this._comma = 44;
        /**
         * ASCII code for space
         *
         * @private
         */
        this._space = 32;
        this.fdfString = '';
        /**
         * True when parsing XFDF into the document.
         *
         * @private
         */
        this._xmlImport = false;
    }
    /**
     * Reads a form field value and stores it in the table using the field name key.
     *
     * @private
     * @param {PdfField} field Field to export.
     * @returns {string | string[]} Exported value as string or list of strings.
     */
    _ExportHelper.prototype._exportFormFieldsData = function (field) {
        var textValue = '';
        var encodedValue;
        if (field !== null && typeof field !== 'undefined' && field.export) {
            var type = _getInheritableProperty(field._dictionary, 'FT', false, true, 'Parent');
            if (type && type.name !== null && typeof type.name !== 'undefined') {
                var font = this._getEncodedFontDictionary(field._dictionary);
                var fieldName = field.name;
                if (font !== null && typeof font !== 'undefined') {
                    var encodedName = this._getEncodedValue(fieldName, font);
                    fieldName = typeof encodedName === 'string' ? encodedName : fieldName;
                }
                var value = void 0; // eslint-disable-line
                var selectedValue = void 0;
                switch (type.name) {
                    case 'Tx':
                        textValue = _getInheritableProperty(field._dictionary, 'V', false, true, 'Parent');
                        if (textValue !== null && typeof textValue !== 'undefined') {
                            encodedValue = this._getEncodedValue(textValue, font);
                            textValue = typeof encodedValue === 'string' ? encodedValue : textValue;
                            this._table.set(fieldName, textValue);
                        }
                        else if (this._exportEmptyFields) {
                            textValue = '';
                            this._table.set(fieldName, textValue);
                        }
                        break;
                    case 'Ch':
                        value = _getInheritableProperty(field._dictionary, 'V', true, true, 'Parent');
                        if (value !== null && typeof value !== 'undefined') {
                            selectedValue = this._getExportValue(value);
                        }
                        if (!value && field._dictionary.has('I') && (field instanceof PdfListBoxField || field instanceof PdfComboBoxField)) {
                            selectedValue = field._obtainSelectedValue();
                        }
                        if (selectedValue !== null && typeof selectedValue !== 'undefined') {
                            if (typeof selectedValue === 'string' && selectedValue !== '') {
                                encodedValue = this._getEncodedValue(selectedValue, font);
                                textValue = typeof encodedValue === 'string' ? encodedValue : selectedValue;
                                this._table.set(fieldName, textValue);
                            }
                            else if (selectedValue instanceof Array && selectedValue.length > 0) {
                                var values = [];
                                for (var i = 0; i < selectedValue.length; i++) {
                                    encodedValue = this._getEncodedValue(selectedValue[i], font);
                                    values.push(typeof encodedValue === 'string' ? encodedValue : selectedValue[i]);
                                }
                                this._table.set(fieldName, values);
                                return values;
                            }
                        }
                        else if (this._exportEmptyFields) {
                            textValue = '';
                            this._table.set(fieldName, textValue);
                        }
                        break;
                    case 'Btn':
                        value = _getInheritableProperty(field._dictionary, 'V', false, true, 'Parent');
                        if (value !== null && typeof value !== 'undefined') {
                            var text = this._getExportValue(value, field);
                            if (text !== null && typeof text !== 'undefined' && text !== '') {
                                var radioButton = void 0;
                                if (field instanceof PdfRadioButtonListField) {
                                    radioButton = field;
                                }
                                if (!field._dictionary.has('Opt') ||
                                    (radioButton !== null &&
                                        typeof radioButton !== 'undefined'
                                        && radioButton.selectedIndex === -1)) {
                                    encodedValue = this._getEncodedValue(text, font);
                                    text = typeof encodedValue === 'string' ? encodedValue : text;
                                    textValue = text;
                                    this._table.set(fieldName, textValue);
                                }
                                else {
                                    if (field._dictionary.has('Opt')) {
                                        var options = field._dictionary.getArray('Opt');
                                        var index = Number(text);
                                        if (index === null || typeof index === 'undefined' || Number.isNaN(index)) {
                                            index = 0;
                                        }
                                        if (options !== null && typeof options !== 'undefined') {
                                            var current = void 0;
                                            if (radioButton) {
                                                current = options[radioButton.selectedIndex];
                                            }
                                            else {
                                                current = options[index];
                                            }
                                            if (current !== null && typeof current !== 'undefined') {
                                                text = current;
                                            }
                                            if (text !== null && typeof text !== 'undefined' && text !== '') {
                                                encodedValue = this._getEncodedValue(text, font);
                                                text = typeof encodedValue === 'string' ? encodedValue : text;
                                                textValue = text;
                                                this._table.set(fieldName, textValue);
                                            }
                                        }
                                    }
                                }
                            }
                            else if (field instanceof PdfRadioButtonListField || field instanceof PdfCheckBoxField) {
                                if (this._exportEmptyFields) {
                                    textValue = text;
                                }
                                else {
                                    textValue = 'Off';
                                }
                                this._table.set(fieldName, textValue);
                            }
                        }
                        else {
                            if (field instanceof PdfRadioButtonListField) {
                                textValue = field._getAppearanceStateValue();
                                if (!textValue) {
                                    if (this._exportEmptyFields) {
                                        textValue = '';
                                    }
                                    else {
                                        textValue = 'Off';
                                    }
                                }
                                this._table.set(fieldName, textValue);
                            }
                            else {
                                var widget = field.itemAt(field._defaultIndex);
                                var dictionary = void 0;
                                if (widget) {
                                    dictionary = widget._dictionary;
                                }
                                else {
                                    dictionary = field._dictionary;
                                }
                                if (dictionary && dictionary.has('AS')) {
                                    textValue = dictionary.get('AS').name;
                                    this._table.set(fieldName, textValue);
                                }
                                else if (this._exportEmptyFields) {
                                    textValue = '';
                                    this._table.set(fieldName, textValue);
                                }
                            }
                        }
                        break;
                }
            }
        }
        return textValue;
    };
    /**
     * Exports a single form field and writes its value into the table honoring format rules.
     *
     * @private
     * @param {PdfField} field Field to export.
     * @returns {void}
     */
    _ExportHelper.prototype._exportFormFieldData = function (field) {
        var type = _getInheritableProperty(field._dictionary, 'FT', false, true, 'Parent');
        var encodedName;
        var encodedValue;
        if (type && type.name !== null && typeof type.name !== 'undefined') {
            var font = this._getEncodedFontDictionary(field._dictionary);
            var fieldName = field.name;
            if (font !== null && typeof font !== 'undefined') {
                encodedName = this._getEncodedValue(fieldName, font);
                fieldName = typeof encodedName === 'string' ? encodedName : fieldName;
            }
            var textValue = void 0;
            var value = void 0; // eslint-disable-line
            switch (type.name) {
                case 'Tx':
                    textValue = _getInheritableProperty(field._dictionary, 'V', false, true, 'Parent');
                    if (this._asPerSpecification) {
                        if (field._dictionary.has('RV')) {
                            textValue = _getInheritableProperty(field._dictionary, 'RV', false, true, 'Parent');
                            if (textValue !== null && typeof textValue !== 'undefined') {
                                textValue += this._key;
                                this._formKey = this._key;
                                this._table.set(fieldName, textValue);
                            }
                        }
                        else if (textValue !== null && typeof textValue !== 'undefined') {
                            encodedValue = this._getEncodedValue(textValue, font);
                            textValue = typeof encodedValue === 'string' ? encodedValue : textValue;
                            var replaceValue = textValue;
                            if (field instanceof PdfTextBoxField && field.multiLine) {
                                replaceValue = replaceValue.replace('\n', '');
                                replaceValue = replaceValue.replace('\r', '\r\n');
                                textValue = replaceValue;
                            }
                            this._table.set(fieldName, textValue);
                        }
                    }
                    else {
                        if (textValue !== null && typeof textValue !== 'undefined') {
                            encodedValue = this._getEncodedValue(textValue, font);
                            textValue = typeof encodedValue === 'string' ? encodedValue : textValue;
                            this._table.set(fieldName, textValue);
                        }
                        else if (this._exportEmptyFields) {
                            this._table.set(fieldName, '');
                        }
                    }
                    break;
                case 'Ch':
                    value = _getInheritableProperty(field._dictionary, 'V', true, true, 'Parent');
                    if (this._asPerSpecification) {
                        if (field instanceof PdfListField) {
                            if (Array.isArray(value)) {
                                this._table.set(fieldName, value);
                            }
                            else {
                                if (typeof value === 'string') {
                                    encodedValue = this._getEncodedValue(value, font);
                                    value = typeof encodedValue === 'string' ? encodedValue : value;
                                    this._table.set(fieldName, value);
                                }
                                else if ((value === null || typeof value === 'undefined') && field._dictionary.has('I')) {
                                    var selectedValue = field._obtainSelectedValue();
                                    if (selectedValue !== null && typeof selectedValue !== 'undefined') {
                                        if (typeof selectedValue === 'string' && selectedValue !== '') {
                                            encodedValue = this._getEncodedValue(selectedValue, font);
                                            selectedValue = typeof encodedValue === 'string' ? encodedValue : selectedValue;
                                            this._table.set(fieldName, textValue);
                                        }
                                        else if (selectedValue instanceof Array && selectedValue.length > 0) {
                                            var values = [];
                                            for (var i = 0; i < selectedValue.length; i++) {
                                                encodedValue = this._getEncodedValue(selectedValue[i], font);
                                                values.push(typeof encodedValue === 'string' ? encodedValue : selectedValue[i]);
                                            }
                                            this._table.set(fieldName, values);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    else {
                        var selectedValue = void 0;
                        if (value !== null && typeof value !== 'undefined') {
                            selectedValue = this._getExportValue(value);
                        }
                        if (!value && field._dictionary.has('I') && (field instanceof PdfListBoxField || field instanceof PdfComboBoxField)) {
                            selectedValue = field._obtainSelectedValue();
                        }
                        if (selectedValue !== null && typeof selectedValue !== 'undefined') {
                            if (typeof selectedValue === 'string' && selectedValue !== '') {
                                encodedValue = this._getEncodedValue(selectedValue, font);
                                selectedValue = typeof encodedValue === 'string' ? encodedValue : selectedValue;
                                this._table.set(fieldName, selectedValue);
                            }
                            else if (selectedValue instanceof Array && selectedValue.length > 0) {
                                var values = [];
                                for (var i = 0; i < selectedValue.length; i++) {
                                    encodedValue = this._getEncodedValue(selectedValue[i], font);
                                    values.push(typeof encodedValue === 'string' ? encodedValue : selectedValue[i]);
                                }
                                this._table.set(fieldName, values);
                            }
                            else if (this._exportEmptyFields) {
                                this._table.set(fieldName, '');
                            }
                        }
                        else if (this._exportEmptyFields) {
                            this._table.set(fieldName, '');
                        }
                    }
                    break;
                case 'Btn':
                    value = _getInheritableProperty(field._dictionary, 'V', false, true, 'Parent');
                    if (value !== null && typeof value !== 'undefined') {
                        var text = this._getExportValue(value, field);
                        if (text !== null && typeof text !== 'undefined' && text !== '') {
                            if (this._asPerSpecification && this._format !== 'XML') {
                                text = _hexStringToString(text);
                            }
                            var radioButton = void 0;
                            if (field instanceof PdfRadioButtonListField) {
                                radioButton = field;
                            }
                            if (!field._dictionary.has('Opt') ||
                                (radioButton !== null &&
                                    typeof radioButton !== 'undefined'
                                    && radioButton.selectedIndex === -1)) {
                                encodedValue = this._getEncodedValue(text, font);
                                text = typeof encodedValue === 'string' ? encodedValue : text;
                                this._table.set(fieldName, text);
                            }
                            else {
                                if (field._dictionary.has('Opt')) {
                                    var options = field._dictionary.getArray('Opt');
                                    var index = Number(text);
                                    if (index === null || typeof index === 'undefined' || Number.isNaN(index)) {
                                        index = 0;
                                    }
                                    if (options !== null && typeof options !== 'undefined') {
                                        var current = void 0;
                                        if (radioButton) {
                                            current = options[radioButton.selectedIndex];
                                        }
                                        else {
                                            current = options[index];
                                        }
                                        if (current !== null && typeof current !== 'undefined') {
                                            text = current;
                                        }
                                        if (text !== null && typeof text !== 'undefined' && text !== '') {
                                            encodedValue = this._getEncodedValue(text, font);
                                            text = typeof encodedValue === 'string' ? encodedValue : text;
                                            this._table.set(fieldName, text);
                                        }
                                    }
                                }
                            }
                        }
                        else if (field instanceof PdfRadioButtonListField || field instanceof PdfCheckBoxField) {
                            if (this._exportEmptyFields) {
                                this._table.set(fieldName, text);
                            }
                            else {
                                this._table.set(fieldName, 'Off');
                            }
                        }
                    }
                    else {
                        if (field instanceof PdfRadioButtonListField) {
                            var text = field._getAppearanceStateValue();
                            if (!text) {
                                if (this._exportEmptyFields) {
                                    text = '';
                                }
                                else {
                                    text = 'Off';
                                }
                            }
                            this._table.set(fieldName, text);
                        }
                        else {
                            var widget = field.itemAt(field._defaultIndex);
                            var dictionary = void 0;
                            if (widget) {
                                dictionary = widget._dictionary;
                            }
                            else {
                                dictionary = field._dictionary;
                            }
                            if (dictionary && dictionary.has('AS')) {
                                this._table.set(fieldName, dictionary.get('AS').name);
                            }
                            else if (this._exportEmptyFields) {
                                this._table.set(fieldName, '');
                            }
                        }
                    }
                    break;
            }
        }
    };
    /**
     * Gets the annotation subtype name from a dictionary.
     *
     * @private
     * @param {_PdfDictionary} dictionary Annotation dictionary to inspect.
     * @returns {string} Subtype name or empty string.
     */
    _ExportHelper.prototype._getAnnotationType = function (dictionary) {
        var type = '';
        if (dictionary && dictionary.has('Subtype')) {
            var subtype = dictionary.get('Subtype');
            if (subtype) {
                type = subtype.name;
            }
        }
        return type;
    };
    /**
     * Converts a PDF primitive into a string suitable for attribute or JSON output.
     *
     * @private
     * @param {any} primitive Primitive to convert.
     * @param {boolean} [isJson=false] When true emits boolean as true or false otherwise yes or no.
     * @returns {string} Converted text.
     */
    _ExportHelper.prototype._getValue = function (primitive, isJson) {
        if (isJson === void 0) { isJson = false; }
        var value = '';
        if (typeof primitive !== 'undefined' && primitive !== null) {
            if (primitive instanceof _PdfName) {
                value = primitive.name;
            }
            else if (typeof primitive === 'boolean') {
                value = primitive ? isJson ? 'true' : 'yes' : isJson ? 'false' : 'no';
            }
            else if (typeof primitive === 'string') {
                value = this._getValidString(primitive);
            }
            else if (Array.isArray(primitive)) {
                var colorArray = primitive; // eslint-disable-line
                if (colorArray.length > 0) {
                    value = this._getValue(colorArray[0], isJson);
                }
                for (var i = 1; i < colorArray.length; i++) {
                    value += ',' + this._getValue(colorArray[i], isJson);
                }
            }
            else if (typeof primitive === 'number') {
                value = primitive.toString();
            }
            else if (primitive instanceof _PdfReference) {
                value = this._getValue(this._crossReference._fetch(primitive), isJson);
            }
        }
        return value;
    };
    /**
     * Converts an RGB array into a hex color string.
     *
     * @private
     * @param {any} primitive Source color array with three numeric components in the zero to one range.
     * @returns {string} Hex color string or empty string.
     */
    _ExportHelper.prototype._getColor = function (primitive) {
        var color = '';
        if (primitive && Array.isArray(primitive) && primitive.length >= 3) {
            var r = Math.round(primitive[0] * 255).toString(16).toUpperCase();
            var g = Math.round(primitive[1] * 255).toString(16).toUpperCase();
            var b = Math.round(primitive[2] * 255).toString(16).toUpperCase();
            color = '#' + (r.length === 1 ? ('0' + r) : r) + (g.length === 1 ? ('0' + g) : g) + (b.length === 1 ? ('0' + b) : b);
        }
        return color;
    };
    /**
     * Escapes newline and carriage return characters for safe text output.
     *
     * @private
     * @param {string} value Input string to sanitize.
     * @returns {string} Sanitized string.
     */
    _ExportHelper.prototype._getValidString = function (value) {
        if (value.indexOf('\n') !== -1) {
            value = value.replace(/\n/g, '\\n');
        }
        if (value.indexOf('\r') !== -1) {
            value = value.replace(/\r/g, '\\r');
        }
        return value;
    };
    /**
     * Attempts to resolve a font dictionary used by an annotation appearance for encoding decisions.
     *
     * @private
     * @param {_PdfDictionary} source Source dictionary that may contain appearance resources.
     * @returns {_PdfDictionary} Font dictionary when found otherwise undefined.
     */
    _ExportHelper.prototype._getEncodedFontDictionary = function (source) {
        var font;
        var kids; // eslint-disable-line
        if (source.has('Kids') && !source.has('AP')) {
            kids = source.getArray('Kids');
        }
        if (source.has('AP') || (kids !== null && typeof kids !== 'undefined' && Array.isArray(kids))) {
            var appearance = void 0;
            if (kids !== null && typeof kids !== 'undefined' && kids.length > 0) {
                var kid = kids[0];
                if (kid !== null && typeof kid !== 'undefined' && kid.has('AP')) {
                    appearance = kid.get('AP');
                }
            }
            else {
                appearance = source.get('AP');
            }
            if (appearance !== null && typeof appearance !== 'undefined' && appearance.has('N')) {
                var normal = appearance.get('N');
                if (normal !== null && typeof normal !== 'undefined' && normal instanceof _PdfBaseStream && normal.dictionary.has('Resources')) {
                    var resource = normal.dictionary.get('Resources');
                    if (resource !== null && typeof resource !== 'undefined' && resource.has('Font')) {
                        font = resource.get('Font');
                    }
                }
            }
        }
        return font;
    };
    /**
     * Encodes a text value using font encoding or document level PDFDocEncoding when available.
     *
     * @private
     * @param {string} value Text to encode.
     * @param {_PdfDictionary} [dictionary] Optional font resource dictionary to guide encoding.
     * @returns {string} Encoded text or original text.
     */
    _ExportHelper.prototype._getEncodedValue = function (value, dictionary) {
        var _this = this;
        var text = value;
        var structure;
        if (this._encodeDictionary !== null && typeof this._encodeDictionary !== 'undefined') {
            structure = new _FontStructure(this._encodeDictionary);
            return this._replaceNotUsedCharacters(text, structure);
        }
        else {
            var root = this._document.form._dictionary;
            if (root !== null && typeof root !== 'undefined' && root.has('DR')) {
                var resource = root.get('DR');
                if (resource !== null && typeof resource !== 'undefined' && resource.has('Encoding')) {
                    var encoding = resource.get('Encoding');
                    if (encoding !== null && typeof encoding !== 'undefined' && encoding.has('PDFDocEncoding')) {
                        var pdfEncoding = encoding.get('PDFDocEncoding');
                        if (pdfEncoding !== null && typeof pdfEncoding !== 'undefined' && pdfEncoding.has('Differences')) {
                            var encodingDictionary = new _PdfDictionary(this._crossReference);
                            encodingDictionary.set('Differences', pdfEncoding.get('Differences'));
                            var reference = this._crossReference._getNextReference();
                            this._crossReference._cacheMap.set(reference, encodingDictionary);
                            var fontEncodeDictionary = new _PdfDictionary(this._crossReference);
                            fontEncodeDictionary.set('Subtype', _PdfName.get('Type1'));
                            fontEncodeDictionary.set('Encoding', reference);
                            structure = new _FontStructure(fontEncodeDictionary);
                            if (structure !== null &&
                                typeof structure !== 'undefined' &&
                                structure.differencesDictionary !== null &&
                                typeof structure.differencesDictionary !== 'undefined' &&
                                structure.differencesDictionary.size > 0) {
                                this._encodeDictionary = fontEncodeDictionary;
                                return this._replaceNotUsedCharacters(text, structure);
                            }
                        }
                    }
                }
            }
            if (value !== null &&
                typeof value !== 'undefined' &&
                dictionary !== null &&
                typeof dictionary !== 'undefined' &&
                dictionary.size > 0) {
                var result_1;
                var isSkip_1 = false;
                dictionary.forEach(function (key, value) {
                    if (!isSkip_1 && value !== null && typeof value !== 'undefined') {
                        var fontDictionary = void 0;
                        if (value instanceof _PdfDictionary) {
                            fontDictionary = value;
                        }
                        else if (value instanceof _PdfReference) {
                            var holder = _this._crossReference._fetch(value); // eslint-disable-line
                            if (holder !== null && typeof holder !== 'undefined' && holder instanceof _PdfDictionary) {
                                fontDictionary = holder;
                            }
                        }
                        if (fontDictionary) {
                            structure = new _FontStructure(fontDictionary);
                            result_1 = _this._replaceNotUsedCharacters(text, structure);
                            isSkip_1 = true;
                        }
                    }
                });
                if (!isSkip_1) {
                    return result_1;
                }
            }
            return text;
        }
    };
    /**
     * Replaces characters based on differences mapping and font traits to preserve intended glyphs.
     *
     * @private
     * @param {string} input Input text to process.
     * @param {_FontStructure} structure Font structure containing differences and encoding info.
     * @returns {string} Updated text after replacement.
     */
    _ExportHelper.prototype._replaceNotUsedCharacters = function (input, structure) {
        var updatedString = '';
        var differencesDictionary = structure.differencesDictionary;
        for (var i = 0; i < input.length; i++) {
            var text = input[i];
            var code = input.charCodeAt(i);
            if (differencesDictionary.has(text)) {
                var difference = differencesDictionary.get(text);
                if ((difference.length > 1 && structure._fontType !== 'Type3') ||
                    (code > 127 && code <= 255 && structure._fontType === 'Type1' &&
                        structure._baseFontEncoding !== 'WinAnsiEncoding' &&
                        structure._fontEncoding === 'Encoding' && structure._fontName === 'ZapfDingbats')) {
                    updatedString += text;
                }
                else {
                    updatedString += difference;
                }
            }
            else {
                updatedString += text;
            }
        }
        return updatedString;
    };
    /**
     * Extracts export value from a primitive or array and adapts it for radio or checkbox fields.
     *
     * @private
     * @param {any} primitive Source primitive to read.
     * @param {PdfField} [field] Optional field for context such as radio button selection.
     * @returns {string | string[]} Export value as string or list of strings.
     */
    _ExportHelper.prototype._getExportValue = function (primitive, field) {
        var value;
        if (primitive !== null && typeof primitive !== 'undefined') {
            if (field !== null && typeof field !== 'undefined') {
                if (primitive instanceof _PdfName) {
                    value = primitive.name;
                }
                else if (typeof primitive === 'string') {
                    value = primitive;
                }
                if (value !== null &&
                    typeof value !== 'undefined' &&
                    value !== '' &&
                    field instanceof PdfRadioButtonListField &&
                    field.selectedIndex !== -1) {
                    var item = field.itemAt(field.selectedIndex);
                    if (item !== null && typeof item !== 'undefined' && item.value === value) {
                        value = item.value;
                    }
                }
            }
            else {
                if (primitive instanceof _PdfName) {
                    value = primitive.name;
                }
                else if (typeof primitive === 'string') {
                    value = primitive;
                }
                else if (Array.isArray(primitive)) {
                    var values_1 = [];
                    primitive.forEach(function (element) {
                        if (element instanceof _PdfName) {
                            values_1.push(element.name);
                        }
                        else if (typeof element === 'string') {
                            values_1.push(element);
                        }
                    });
                    return values_1;
                }
            }
        }
        return value;
    };
    /**
     * Registers a reference under a named group and wires reply chains using the NM and IRT entries.
     *
     * @private
     * @param {_PdfReference} reference Reference assigned to the current annotation.
     * @param {_PdfDictionary} dictionary Annotation dictionary providing NM or IRT entries.
     * @returns {void}
     */
    _ExportHelper.prototype._addReferenceToGroup = function (reference, dictionary) {
        var name = dictionary.get('NM');
        if (name && name !== '') {
            this._groupReferences.set(name, reference);
            if (dictionary.has('IRT')) {
                this._groupHolders.push(dictionary);
            }
        }
        else if (!name && dictionary.has('IRT')) {
            name = dictionary.get('IRT');
            if (name && name !== '' && this._groupReferences.has(name)) {
                dictionary.update('IRT', this._groupReferences.get(name));
            }
        }
    };
    /**
     * Ensures popup annotations are linked to their parent annotation and updates page collections.
     *
     * @private
     * @param {PdfAnnotationCollection} annotations Annotation collection of the page.
     * @param {_PdfReference} reference Reference of the parent annotation.
     * @param {_PdfDictionary} annotationDictionary Parent annotation dictionary.
     * @param {_PdfDictionary} pageDictionary Page dictionary to update.
     * @returns {void}
     */
    _ExportHelper.prototype._handlePopup = function (annotations, reference, annotationDictionary, pageDictionary) {
        if (annotationDictionary && annotationDictionary.has('Popup')) {
            var popupReference = annotationDictionary.getRaw('Popup');
            var popup = annotationDictionary.get('Popup');
            if (popup && popup instanceof _PdfDictionary) {
                if (popupReference && popup) {
                    popup.update('Parent', reference);
                }
                var popupAnnotation = annotations._parseAnnotation(popup);
                var index = annotations._annotations.length;
                pageDictionary.set('Annots', annotations._annotations);
                pageDictionary._updated = true;
                annotations._parsedAnnotations.set(index, popupAnnotation);
            }
        }
    };
    /**
     * Applies collected field values into the document form fields and writes rich text when present.
     *
     * @private
     * @returns {void}
     */
    _ExportHelper.prototype._importField = function () {
        var _this = this;
        var form = this._document.form;
        var count = form.count;
        if (count) {
            this._fields.forEach(function (value, key) {
                var richTextValue;
                if (_this._richTextValues.size > 0 && _this._richTextValues.has(key)) {
                    richTextValue = _this._richTextValues.get(key);
                }
                var index = form._getFieldIndex(key);
                if (index !== -1 && index < count) {
                    var field = form.fieldAt(index);
                    if (field && field !== null && typeof field !== 'undefined') {
                        if (richTextValue && richTextValue !== '') {
                            field._dictionary.update('RV', richTextValue);
                        }
                        _this._importFieldData(field, value);
                    }
                }
            });
        }
    };
    /**
     * Imports a single form field value or list of values into the target field.
     *
     * @private
     * @param {PdfField} field Target field to update.
     * @param {string[]} values Values to apply to the field.
     * @returns {void}
     */
    _ExportHelper.prototype._importFieldData = function (field, values) {
        if (values !== null &&
            typeof values !== 'undefined' &&
            values.length > 0 &&
            field !== null &&
            typeof field !== 'undefined' &&
            !field.readOnly) {
            var value = values[0];
            if (field instanceof PdfTextBoxField) {
                if (value !== null && typeof value !== 'undefined') {
                    if (field instanceof PdfTextBoxField && field.multiLine) {
                        value = value.replace('\r\n', '\r');
                        value = value.replace('\n', '\r');
                    }
                    field.text = value;
                }
            }
            else if (field instanceof PdfListBoxField || field instanceof PdfComboBoxField) {
                var selectedValues_1;
                if (values.length > 1) {
                    selectedValues_1 = values;
                }
                else {
                    if (this._xmlImport) {
                        selectedValues_1 = (value.indexOf(',') !== -1 ? value.split(',') : [value]);
                    }
                    else {
                        selectedValues_1 = [value.indexOf(',') !== -1 ? value.split(',')[0] : value];
                    }
                }
                var indexes_1 = [];
                var options_1 = field._options;
                if (options_1 && options_1.length > 0) {
                    options_1.forEach(function (option) {
                        if (selectedValues_1.indexOf(option[0]) !== -1 || selectedValues_1.indexOf(option[1]) !== -1) {
                            indexes_1.push(options_1.indexOf(option));
                        }
                    });
                }
                if (indexes_1.length > 0) {
                    field.selectedIndex = indexes_1;
                    if (field instanceof PdfComboBoxField && this._asPerSpecification && field._dictionary.has('AP')) {
                        delete field._dictionary._map.AP;
                        field._dictionary._updated = true;
                    }
                }
            }
            else if (field instanceof PdfCheckBoxField) {
                var lowerCase = value.toLowerCase();
                if (this._containsExportValue(value, field) || lowerCase === 'on' || lowerCase === 'yes') {
                    field.checked = true;
                }
                else {
                    field.checked = false;
                }
            }
            else if (field instanceof PdfRadioButtonListField) {
                var index = -1;
                for (var i = 0; i < field._kidsCount; i++) {
                    var item = field.itemAt(i);
                    if (item && item.value && item.value === value) {
                        index = i;
                        break;
                    }
                }
                if (index !== -1 && field.selectedIndex !== index) {
                    field.selectedIndex = index;
                }
            }
        }
    };
    /**
     * Checks whether a checkbox field contains a matching export value.
     *
     * @private
     * @param {string} value Value to test against the field export states.
     * @param {PdfCheckBoxField} field Target checkbox field.
     * @returns {boolean} True when the export value is present.
     */
    _ExportHelper.prototype._containsExportValue = function (value, field) {
        var result = false;
        if (field._kidsCount > 0) {
            for (var i = 0; i < field._kidsCount; i++) {
                var kid = field.itemAt(i);
                if (kid && this._checkSelected(kid._dictionary, value)) {
                    field._defaultIndex = i;
                    return true;
                }
            }
        }
        else {
            result = this._checkSelected(field._dictionary, value);
            if (!result && this._asPerSpecification && field._dictionary.has('AS')) {
                var asEntry = field._dictionary.get('AS');
                if (asEntry && (asEntry.name === 'Off' || asEntry.name === 'No')) {
                    if (field._dictionary.has('Opt')) {
                        var options = field._dictionary.getArray('Opt');
                        if (options && options.length > 0) {
                            options.forEach(function (option) {
                                if (option === value) {
                                    result = true;
                                }
                            });
                        }
                    }
                }
                else {
                    result = true;
                }
            }
        }
        return result;
    };
    /**
     * Checks whether a widget dictionary has an appearance state matching the given value.
     *
     * @private
     * @param {_PdfDictionary} dictionary Widget or field dictionary with appearance states.
     * @param {string} value Appearance state name to test.
     * @returns {boolean} True when a matching state exists.
     */
    _ExportHelper.prototype._checkSelected = function (dictionary, value) {
        if (dictionary && dictionary.has('AP')) {
            var appearance = dictionary.get('AP');
            if (appearance && appearance instanceof _PdfDictionary && appearance.has('N')) {
                var normalTemplate = appearance.get('N');
                if (normalTemplate &&
                    normalTemplate instanceof _PdfDictionary &&
                    normalTemplate.has(value) &&
                    !(value.toLocaleLowerCase() === 'off' || value.toLocaleLowerCase() === 'no')) {
                    return true;
                }
            }
        }
        return false;
    };
    /**
     * Clears all temporary export and import state objects and resets helper properties.
     *
     * @private
     * @returns {void} Clears internal fields used during processing.
     */
    _ExportHelper.prototype._dispose = function () {
        this.exportAppearance = undefined;
        this._asPerSpecification = undefined;
        this._skipBorderStyle = undefined;
        this._fileName = undefined;
        this._document = undefined;
        this._crossReference = undefined;
        this._isAnnotationExport = undefined;
        this._isAnnotationImport = undefined;
        this._key = undefined;
        this._formKey = undefined;
        this._exportEmptyFields = undefined;
        this._groupReferences = undefined;
        this._groupHolders = undefined;
        this._encodeDictionary = undefined;
        this._annotationTypes = undefined;
        this._annotationAttributes = undefined;
        this._xmlDocument = undefined;
        this._parser = undefined;
        this._table = undefined;
        this._fields = undefined;
        this._richTextValues = undefined;
        this._jsonData = undefined;
    };
    return _ExportHelper;
}());
export { _ExportHelper };
/**
 * Provides XFDF based export and import utilities for annotations and form fields with XML serialization.
 *
 * @private
 */
var _XfdfDocument = /** @class */ (function (_super) {
    __extends(_XfdfDocument, _super);
    /**
     * Initializes the XFDF helper with optional file name for export context.
     *
     * @private
     * @param {string} [fileName] Source or target file name used in XFDF payload.
     */
    function _XfdfDocument(fileName) {
        var _this = _super.call(this) || this;
        /**
         * Indicates whether color-space values are included or processed
         * in the XFDF structure.
         *
         * @private
         */
        _this._isColoSpace = false;
        if (fileName !== null && typeof fileName !== 'undefined') {
            _this._fileName = fileName;
        }
        return _this;
    }
    // #region Export Annotations
    /**
     * Prepares and exports annotations from the document as an XFDF byte array.
     *
     * @private
     * @param {PdfDocument} document Source PDF document to read annotations.
     * @returns {Uint8Array} Generated XFDF payload containing exported annotations.
     */
    _XfdfDocument.prototype._exportAnnotations = function (document) {
        this._document = document;
        this._crossReference = document._crossReference;
        this._isAnnotationExport = true;
        return this._save();
    };
    /**
     * Prepares and exports form fields from the document as an XFDF byte array.
     *
     * @private
     * @param {PdfDocument} document Source PDF document to read form fields.
     * @returns {Uint8Array} Generated XFDF payload containing exported form fields.
     */
    _XfdfDocument.prototype._exportFormFields = function (document) {
        this._document = document;
        this._crossReference = document._crossReference;
        this._isAnnotationExport = false;
        this._key = _getNewGuidString();
        return this._save();
    };
    /**
     * Serializes the current XFDF document into bytes writing annotations or fields as configured.
     *
     * @private
     * @returns {Uint8Array} Serialized XFDF data.
     */
    _XfdfDocument.prototype._save = function () {
        var writer = new _XmlWriter();
        writer._writeStartDocument();
        writer._writeStartElement('xfdf');
        writer._writeAttributeString(null, 'http://ns.adobe.com/xfdf/', 'xmlns', null);
        writer._writeAttributeString('space', 'preserve', 'xml', null);
        if (this._isAnnotationExport) {
            writer._writeStartElement('annots');
            if (this._document) {
                for (var i = 0; i < this._document.pageCount; i++) {
                    var page = this._document.getPage(i);
                    var annotations = page.annotations;
                    for (var j = 0; j < annotations.count; j++) {
                        var annotation = annotations.at(j);
                        if (annotation instanceof PdfPopupAnnotation && annotation._dictionary.has('Parent')) {
                            continue;
                        }
                        if (annotation && (!this._annotationTypes ||
                            this._annotationTypes.length === 0 ||
                            (this._annotationTypes && this._annotationTypes.length > 0 && this._checkAnnotationType(annotation)))) {
                            this._exportAnnotationData(annotation, writer, i);
                        }
                    }
                }
            }
            writer._writeEndElement();
        }
        else {
            var form = this._document.form;
            if (form !== null && typeof form !== 'undefined') {
                this._exportEmptyFields = form.exportEmptyFields;
                var count = this._document.form.count;
                for (var i = 0; i < count; i++) {
                    var field = this._document.form.fieldAt(i);
                    if (field !== null && typeof field !== 'undefined' && field.export) {
                        this._exportFormFieldData(field);
                    }
                }
                this._writeFormFieldData(writer, this._asPerSpecification);
            }
        }
        if (!this._asPerSpecification) {
            writer._writeStartElement('f');
            writer._writeAttributeString('href', this._fileName);
        }
        var result = writer._save();
        writer._destroy();
        return result;
    };
    /**
     * Writes form field entries into the XML writer honoring Acrobat specification mode.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {boolean} [isAcrobat=false] Indicates Acrobat specific structure should be used.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeFormFieldData = function (writer, isAcrobat) {
        var _this = this;
        if (isAcrobat === void 0) { isAcrobat = false; }
        if (isAcrobat) {
            writer._writeStartElement('f');
            writer._writeAttributeString('href', this._fileName);
            writer._writeEndElement();
            var elements = this._getElements(this._table); // eslint-disable-line
            if (elements && elements.size > 0) {
                writer._writeStartElement('fields');
                var flag_1 = false;
                elements.forEach(function (value, key) {
                    writer._writeStartElement('field');
                    writer._writeAttributeString('name', key.toString());
                    if (Array.isArray(value)) {
                        value.forEach(function (item) {
                            writer._writeStartElement('value');
                            writer._writeString(item.toString());
                            writer._writeEndElement();
                            flag_1 = true;
                        });
                    }
                    if (value instanceof Map) {
                        _this._writeFieldName(value, writer);
                    }
                    else if (!flag_1 && !value.toString().endsWith(_this._formKey) || (!flag_1 && _this._formKey === '')) {
                        writer._writeStartElement('value');
                        writer._writeString(value.toString());
                        writer._writeEndElement();
                    }
                    else if (_this._formKey !== '' && value.toString().endsWith(_this._formKey)) {
                        writer._writeStartElement('value-richtext');
                        var text = value.toString();
                        if (text.startsWith('<?xml version="1.0"?>')) {
                            text = text.substring(21);
                        }
                        var start = text.length - _this._formKey.length;
                        text = text.substring(0, start) + text.substring(start + _this._formKey.length);
                        writer._writeRaw(text);
                        writer._writeEndElement();
                    }
                    writer._writeEndElement();
                    flag_1 = false;
                });
                writer._writeEndElement();
            }
            writer._writeStartElement('ids');
            var hasId = false;
            if (this._crossReference._root.has('ID')) {
                var id = this._crossReference._root.getArray('ID');
                if (id && id.length >= 1) {
                    writer._writeAttributeString('original', id[0]);
                    writer._writeAttributeString('modified', id[1]);
                    hasId = true;
                }
            }
            if (!hasId) {
                writer._writeAttributeString('original', '');
                writer._writeAttributeString('modified', '');
            }
            writer._writeEndElement();
        }
        else {
            writer._writeStartElement('fields');
            this._table.forEach(function (value, key) {
                writer._writeStartElement('field');
                writer._writeAttributeString('name', key.toString());
                if (Array.isArray(value)) {
                    value.forEach(function (item) {
                        writer._writeStartElement('value');
                        writer._writeString(item.toString());
                        writer._writeEndElement();
                    });
                }
                else {
                    writer._writeStartElement('value');
                    writer._writeString(value.toString());
                    writer._writeEndElement();
                }
                writer._writeEndElement();
            });
            writer._writeEndElement();
        }
    };
    /**
     * Recursively writes nested field elements and their values into the XML writer.
     *
     * @private
     * @param {Map<any, any>} value Nested field map to serialize.
     * @param {_XmlWriter} writer Target XML writer.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeFieldName = function (value, writer) {
        var _this = this;
        value.forEach(function (value, key) {
            if (value instanceof Map) {
                writer._writeStartElement('field');
                writer._writeAttributeString('name', key.toString());
                _this._writeFieldName(value, writer);
                writer._writeEndElement();
            }
            else {
                writer._writeStartElement('field');
                writer._writeAttributeString('name', key.toString());
                if (Array.isArray(value)) {
                    value.forEach(function (item) {
                        writer._writeStartElement('value');
                        writer._writeString(item.toString());
                        writer._writeEndElement();
                    });
                }
                else {
                    if (!value.toString().endsWith(_this._formKey) || _this._formKey === '') {
                        writer._writeStartElement('value');
                        writer._writeString(value.toString());
                    }
                    else {
                        writer._writeStartElement('value-richtext');
                        var text = value.toString();
                        if (text.startsWith('<?xml version="1.0"?>')) {
                            text = text.substring(21);
                        }
                        var start = text.length - _this._formKey.length;
                        text = text.substring(0, start) + text.substring(start + _this._formKey.length);
                        writer._writeRaw(text);
                    }
                    writer._writeEndElement();
                }
                writer._writeEndElement();
            }
        });
    };
    /**
     * Builds a hierarchical representation of dot separated field names.
     *
     * @private
     * @param {Map<any, any>} table Flat table of field names to values.
     * @returns {Map<any, any>} Nested map of field groups and values.
     */
    _XfdfDocument.prototype._getElements = function (table) {
        var _this = this;
        var elements = new Map(); // eslint-disable-line
        table.forEach(function (value, key) {
            var parentElements = elements; // eslint-disable-line
            if (key.toString().indexOf('.') !== -1) {
                var values_2 = key.toString().split('.');
                values_2.forEach(function (element, i) {
                    if (parentElements.has(element)) {
                        _this._getElements(parentElements.get(element));
                        parentElements = parentElements.get(element);
                    }
                    else {
                        if (i === values_2.length - 1) {
                            parentElements.set(element, value);
                        }
                        else {
                            var newTable = new Map(); // eslint-disable-line
                            parentElements.set(element, newTable);
                            parentElements = newTable;
                        }
                    }
                });
            }
            else {
                parentElements.set(key, value);
            }
        });
        return elements;
    };
    /**
     * Checks whether an annotation matches any requested annotation types.
     *
     * @private
     * @param {PdfAnnotation} annotation Annotation to check.
     * @returns {boolean} True when the annotation type is allowed.
     */
    _XfdfDocument.prototype._checkAnnotationType = function (annotation) {
        return (typeof annotation._type !== 'undefined' && this._annotationTypes.indexOf(annotation._type) !== -1);
    };
    /**
     * Exports a single annotation if it is supported and not a link or uri type.
     *
     * @private
     * @param {PdfAnnotation} annotation Source annotation to export.
     * @param {_XmlWriter} writer Target XML writer.
     * @param {number} pageIndex Page index of the annotation.
     * @returns {void}
     */
    _XfdfDocument.prototype._exportAnnotationData = function (annotation, writer, pageIndex) {
        if (annotation._dictionary &&
            !(annotation instanceof PdfFileLinkAnnotation ||
                annotation instanceof PdfTextWebLinkAnnotation ||
                annotation instanceof PdfDocumentLinkAnnotation ||
                annotation instanceof Pdf3DAnnotation)) {
            this._writeAnnotationData(writer, pageIndex, annotation);
        }
    };
    _XfdfDocument.prototype._writeAnnotationData = function (writer, pageIndex, source) {
        var hasAppearance = false;
        var annotation;
        var dictionary;
        if (source instanceof PdfAnnotation) {
            annotation = source;
            dictionary = source._dictionary;
        }
        else {
            dictionary = source;
        }
        var type = this._getAnnotationType(dictionary);
        this._skipBorderStyle = false;
        if (type && type !== '') {
            this._annotationAttributes = [];
            writer._writeStartElement(type.toLowerCase());
            writer._writeAttributeString('page', pageIndex.toString());
            this._annotationAttributes.push('page');
            var lineAnnotation = void 0;
            var points = void 0;
            switch (type) {
                case 'Line':
                    lineAnnotation = annotation;
                    points = lineAnnotation.linePoints;
                    writer._writeAttributeString('start', points[0].x.toString() + ',' + points[0].y.toString());
                    writer._writeAttributeString('end', points[1].x.toString() + ',' + points[1].y.toString());
                    break;
                case 'Stamp':
                    hasAppearance = true;
                    break;
                case 'Square':
                    hasAppearance = true;
                    break;
            }
            if (dictionary && dictionary.has('BE') && dictionary.has('BS')) {
                var borderEffect = dictionary.get('BE');
                if (borderEffect && borderEffect.has('S')) {
                    this._skipBorderStyle = true;
                }
            }
            this._writeDictionary(dictionary, pageIndex, writer, hasAppearance);
            writer._writeEndElement();
            this._annotationAttributes = [];
        }
    };
    /**
     * Writes supported dictionary attributes and nested structures into XML for the current annotation.
     *
     * @private
     * @param {_PdfDictionary} dictionary Annotation dictionary to serialize.
     * @param {number} pageIndex Page index of the annotation.
     * @param {_XmlWriter} writer Target XML writer.
     * @param {boolean} hasAppearance Indicates whether appearance streams should be included.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeDictionary = function (dictionary, pageIndex, writer, hasAppearance) {
        var _this = this;
        var isBorderStyle = false;
        if (dictionary.has('Type')) {
            var type = dictionary.get('Type');
            isBorderStyle = (type && type.name === 'Border' && this._skipBorderStyle);
        }
        dictionary.forEach(function (key, value) {
            if (!((!hasAppearance && key === 'AP') || key === 'P' || key === 'Parent'
                || key === 'Measure' || key === 'Popup') && key.indexOf(':') === -1) {
                var entry = void 0; // eslint-disable-line
                if (value instanceof _PdfReference) {
                    entry = dictionary.get(key);
                }
                else {
                    entry = value;
                }
                if (entry && entry instanceof _PdfDictionary) {
                    switch (key) {
                        case 'BS':
                        case 'BE':
                            _this._writeDictionary(entry, pageIndex, writer, false);
                            break;
                        case 'IRT':
                            if (entry.has('NM')) {
                                writer._writeAttributeString('inreplyto', _this._getValue(entry.get('NM')));
                            }
                            break;
                        default:
                            _this._writeDictionary(entry, pageIndex, writer, false);
                            break;
                    }
                }
                else if ((!isBorderStyle) || (isBorderStyle && key !== 'S')) {
                    _this._writeAttribute(writer, key, entry);
                }
            }
        });
        if ((this.exportAppearance || hasAppearance) && dictionary.has('AP')) {
            var stream = this._getAppearanceString(dictionary.get('AP'));
            if (stream && stream.length > 0) {
                writer._writeStartElement('appearance');
                writer._writeRaw(_encode(stream));
                writer._writeEndElement();
            }
        }
        if (dictionary.has('Measure')) {
            this._exportMeasureDictionary(dictionary.get('Measure'), writer);
        }
        if (dictionary.has('Sound')) {
            var sound = dictionary.get('Sound');
            if (sound && sound.dictionary) {
                var soundDictionary = sound.dictionary;
                if (soundDictionary.has('B')) {
                    writer._writeAttributeString('bits', this._getValue(soundDictionary.get('B')));
                }
                if (soundDictionary.has('C')) {
                    writer._writeAttributeString('channels', this._getValue(soundDictionary.get('C')));
                }
                if (soundDictionary.has('E')) {
                    writer._writeAttributeString('encoding', this._getValue(soundDictionary.get('E')));
                }
                if (soundDictionary.has('R')) {
                    writer._writeAttributeString('rate', this._getValue(soundDictionary.get('R')));
                }
                if (soundDictionary.has('Length') && soundDictionary.get('Length') > 0) {
                    var data = _byteArrayToHexString(sound.getBytes());
                    if (data && data !== '') {
                        writer._writeStartElement('data');
                        writer._writeAttributeString('MODE', 'raw');
                        writer._writeAttributeString('encoding', 'hex');
                        if (soundDictionary.has('Length')) {
                            writer._writeAttributeString('length', this._getValue(soundDictionary.get('Length')));
                        }
                        if (soundDictionary.has('Filter')) {
                            writer._writeAttributeString('filter', this._getValue(soundDictionary.get('Filter')));
                        }
                        writer._writeRaw(data);
                        writer._writeEndElement();
                    }
                }
            }
        }
        else if (dictionary.has('FS')) {
            writer._writeStartElement('data');
            var fsDictionary = dictionary.get('FS');
            if (fsDictionary) {
                if (fsDictionary.has('F')) {
                    writer._writeAttributeString('file', this._getValue(fsDictionary.get('F')));
                }
                if (fsDictionary.has('EF')) {
                    var efDictionary = fsDictionary.get('EF');
                    if (efDictionary && efDictionary.has('F')) {
                        var fStream = efDictionary.get('F');
                        if (fStream && fStream.dictionary) {
                            var fDictionary = fStream.dictionary;
                            if (fDictionary.has('Params')) {
                                var paramsDictionary = fDictionary.get('Params');
                                if (paramsDictionary) {
                                    if (paramsDictionary.has('CreationDate')) {
                                        var value = this._getValue(paramsDictionary.get('CreationDate'));
                                        writer._writeAttributeString('creation', value);
                                    }
                                    if (paramsDictionary.has('ModificationDate')) {
                                        var value = this._getValue(paramsDictionary.get('ModificationDate'));
                                        writer._writeAttributeString('modification', value);
                                    }
                                    if (paramsDictionary.has('Size')) {
                                        writer._writeAttributeString('size', this._getValue(paramsDictionary.get('Size')));
                                    }
                                    if (paramsDictionary.has('CheckSum')) {
                                        var value = this._getValue(paramsDictionary.get('CheckSum'));
                                        var checksum = _stringToBytes(value);
                                        var hexString = _byteArrayToHexString(checksum);
                                        writer._writeAttributeString('checksum', hexString);
                                    }
                                }
                            }
                            var data = _byteArrayToHexString(fStream.getBytes());
                            if (data && data !== '') {
                                writer._writeStartElement('data');
                                writer._writeAttributeString('MODE', 'raw');
                                writer._writeAttributeString('encoding', 'hex');
                                if (fDictionary.has('Length')) {
                                    writer._writeAttributeString('length', this._getValue(fDictionary.get('Length')));
                                }
                                if (fDictionary.has('Filter')) {
                                    writer._writeAttributeString('filter', this._getValue(fDictionary.get('Filter')));
                                }
                                writer._writeRaw(data);
                                writer._writeEndElement();
                            }
                        }
                    }
                }
            }
            writer._writeEndElement();
        }
        if (dictionary.has('Vertices')) {
            writer._writeStartElement('vertices');
            var vertices = dictionary.getArray('Vertices');
            if (vertices && vertices.length > 0) {
                var elementCount = vertices.length;
                if (elementCount % 2 === 0) {
                    var value = '';
                    for (var i = 0; i < elementCount - 1; i++) {
                        value += this._getValue(vertices[i]) + (i % 2 !== 0 ? ';' : ',');
                    }
                    value += this._getValue(vertices[elementCount - 1]);
                    if (value && value !== '') {
                        writer._writeRaw(value);
                    }
                }
            }
            writer._writeEndElement();
        }
        if (dictionary.has('Popup')) {
            var popup = dictionary.get('Popup');
            if (popup) {
                this._writeAnnotationData(writer, pageIndex, popup);
            }
        }
        if (dictionary.has('DA')) {
            var defaultAppearance = dictionary.get('DA');
            if (defaultAppearance) {
                this._writeRawData(writer, 'defaultappearance', defaultAppearance);
            }
        }
        if (dictionary.has('DS')) {
            var defaultStyle = dictionary.get('DS');
            if (defaultStyle) {
                this._writeRawData(writer, 'defaultstyle', defaultStyle);
            }
        }
        if (dictionary.has('InkList')) {
            var inkList = dictionary.getArray('InkList');
            if (inkList && inkList.length > 0) {
                writer._writeStartElement('inklist');
                for (var j = 0; j < inkList.length; j++) {
                    writer._writeElementString('gesture', this._getValue(inkList[j]));
                }
                writer._writeEndElement();
            }
        }
        if (dictionary.has('RC')) {
            var value = dictionary.get('RC');
            if (value && value !== '') {
                var index = value.indexOf('<body');
                if (index > 0) {
                    value = value.substring(index);
                }
                this._writeRawData(writer, 'contents-richtext', value);
            }
        }
        if (dictionary.has('Contents')) {
            var value = dictionary.get('Contents');
            if (value && value.length > 0) {
                writer._writeStartElement('contents');
                writer._writeString(value);
                writer._writeEndElement();
            }
        }
    };
    /**
     * Serializes the AP dictionary as a compact XML buffer for embedding in XFDF.
     *
     * @private
     * @param {_PdfDictionary} appearance Appearance dictionary to serialize.
     * @returns {Uint8Array} XML bytes representing the appearance content.
     */
    _XfdfDocument.prototype._getAppearanceString = function (appearance) {
        var textWriter = new _XmlWriter(true);
        textWriter._writeStartElement('DICT');
        textWriter._writeAttributeString('KEY', 'AP');
        this._writeAppearanceDictionary(textWriter, appearance);
        textWriter._writeEndElement();
        var buffer = textWriter.buffer;
        textWriter._destroy();
        return buffer;
    };
    /**
     * Traverses an appearance dictionary and writes its content into the XML writer.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {_PdfDictionary} dictionary Appearance dictionary to traverse.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeAppearanceDictionary = function (writer, dictionary) {
        var _this = this;
        if (dictionary && dictionary.size > 0) {
            dictionary.forEach(function (key, value) {
                _this._writeObject(writer, value instanceof _PdfReference ? dictionary.get(key) : value, dictionary, key);
            });
        }
    };
    /**
     * Writes a PDF primitive as a typed XML node handling arrays dictionaries streams names numbers strings and booleans.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {any} primitive Primitive value to serialize.
     * @param {_PdfDictionary} dictionary Context dictionary for resolving references.
     * @param {string} [key] Optional key associated with the primitive.
     * @param {boolean} [isNewReference] Indicates a newly created reference for stream handling.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeObject = function (writer, primitive, dictionary, key, isNewReference) {
        if (primitive !== null && typeof primitive !== 'undefined') {
            if (primitive instanceof _PdfName) {
                this._writePrefix(writer, 'NAME', key);
                writer._writeAttributeString('VAL', primitive.name);
                writer._writeEndElement();
            }
            else if (Array.isArray(primitive)) {
                this._writePrefix(writer, 'ARRAY', key);
                if (key && key === 'ColorSpace') {
                    this._isColoSpace = true;
                }
                if (dictionary.has(key)) {
                    this._writeArray(writer, dictionary.getArray(key), dictionary);
                }
                else {
                    this._writeArray(writer, primitive, dictionary);
                }
                this._isColoSpace = false;
                writer._writeEndElement();
            }
            else if (typeof primitive === 'string') {
                this._writePrefix(writer, 'STRING', key);
                if (this._isColoSpace) {
                    var bytes = _stringToBytes(primitive);
                    writer._writeAttributeString('VAL', _byteArrayToHexString(bytes));
                    writer._writeEndElement();
                }
                else {
                    writer._writeAttributeString('VAL', primitive);
                    writer._writeEndElement();
                }
            }
            else if (typeof primitive === 'number') {
                if (Number.isInteger(primitive)) {
                    this._writePrefix(writer, 'INT', key);
                    writer._writeAttributeString('VAL', primitive.toString());
                }
                else {
                    this._writePrefix(writer, 'FIXED', key);
                    writer._writeAttributeString('VAL', primitive.toFixed(6));
                }
                writer._writeEndElement();
            }
            else if (typeof primitive === 'boolean') {
                this._writePrefix(writer, 'BOOL', key);
                writer._writeAttributeString('VAL', primitive ? 'true' : 'false');
                writer._writeEndElement();
            }
            else if (primitive instanceof _PdfDictionary) {
                this._writePrefix(writer, 'DICT', key);
                this._writeAppearanceDictionary(writer, primitive);
                writer._writeEndElement();
            }
            else if (primitive instanceof _PdfBaseStream && primitive.dictionary) {
                var streamDictionary = primitive.dictionary;
                this._writePrefix(writer, 'STREAM', key);
                writer._writeAttributeString('DEFINE', '');
                if ((streamDictionary.has('Subtype') &&
                    (this._getValue(streamDictionary.get('Subtype')) === 'Image' ||
                        this._getValue(streamDictionary.get('Subtype')) === 'Form')) ||
                    (!streamDictionary.has('Type') && !streamDictionary.has('Subtype')) && key !== 'ToUnicode') {
                    var data = void 0;
                    if (isNewReference) {
                        if ((streamDictionary.has('Filter') && streamDictionary.get('Filter').name === 'DCTDecode') ||
                            (streamDictionary.has('Subtype') && streamDictionary.get('Subtype').name === 'Form')) {
                            data = primitive.getString(true);
                        }
                        else {
                            data = _compressStream(primitive, true);
                        }
                    }
                    else {
                        data = primitive.getString(true);
                    }
                    if (!streamDictionary.has('Length') && data && data !== '') {
                        streamDictionary.update('Length', primitive.length);
                    }
                    this._writeAppearanceDictionary(writer, streamDictionary);
                    writer._writeStartElement('DATA');
                    writer._writeAttributeString('MODE', 'RAW');
                    writer._writeAttributeString('ENCODING', 'HEX');
                    if (data && data !== '') {
                        writer._writeRaw(data);
                    }
                }
                else {
                    var data = primitive.getString();
                    if (!streamDictionary.has('Length') && data && data !== '') {
                        streamDictionary.update('Length', primitive.length);
                    }
                    data = data.replace(/</g, '&lt;');
                    data = data.replace(/>/g, '&gt;');
                    this._writeAppearanceDictionary(writer, streamDictionary);
                    writer._writeStartElement('DATA');
                    writer._writeAttributeString('MODE', 'FILTERED');
                    writer._writeAttributeString('ENCODING', 'ASCII');
                    if (data && data !== '') {
                        writer._writeRaw(data);
                    }
                }
                writer._writeEndElement();
                writer._writeEndElement();
            }
            else if (primitive instanceof _PdfReference && this._crossReference) {
                this._writeObject(writer, this._crossReference._fetch(primitive), dictionary, key, primitive._isNew);
            }
        }
    };
    /**
     * Starts an XML element for a typed primitive and emits the KEY attribute when present.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {string} name Element name that represents the primitive type.
     * @param {string} [key] Optional key attribute to write.
     * @returns {void}
     */
    _XfdfDocument.prototype._writePrefix = function (writer, name, key) {
        writer._writeStartElement(name);
        if (key) {
            writer._writeAttributeString('KEY', key);
        }
    };
    /**
     * Writes an array of primitives as typed XML nodes.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {any[]} array Source array of primitives.
     * @param {_PdfDictionary} dictionary Context dictionary for resolving references.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeArray = function (writer, array, dictionary) {
        var _this = this;
        array.forEach(function (entry) {
            if (_this._isColoSpace && typeof entry === 'string') {
                var bytes = _stringToBytes(entry);
                var hex = _byteArrayToHexString(bytes);
                writer._writeStartElement('DATA');
                writer._writeAttributeString('MODE', 'RAW');
                writer._writeAttributeString('ENCODING', 'HEX');
                writer._writeRaw(hex);
                writer._writeEndElement();
            }
            else {
                _this._writeObject(writer, entry, dictionary);
            }
        });
    };
    /**
     * Normalizes special characters for XML content depending on direction of conversion.
     *
     * @private
     * @param {string} value Input string to normalize.
     * @param {boolean} [isParsing=false] True when normalizing from XML to plain text.
     * @returns {string} Normalized string with suitable entity substitutions.
     */
    _XfdfDocument.prototype._getFormatedString = function (value, isParsing) {
        if (isParsing === void 0) { isParsing = false; }
        if (isParsing) {
            value = value.replace('&amp;', '&');
            value = value.replace('&lt;', '<');
            value = value.replace('&gt;', '>');
        }
        else {
            value = value.replace('&', '&amp;');
            value = value.replace('<', '&lt;');
            value = value.replace('>', '&gt;');
        }
        return value;
    };
    /**
     * Maps a dictionary entry into XML attributes writing known keys and formats.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {string} key Dictionary key to process.
     * @param {any} primitive Source primitive value.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeAttribute = function (writer, key, primitive) {
        var bytes;
        if (this._annotationAttributes && this._annotationAttributes.indexOf(key) === -1) {
            switch (key) {
                case 'C':
                    this._writeColor(writer, primitive, 'color', 'c');
                    break;
                case 'OC':
                    this._writeColor(writer, primitive, 'oc');
                    break;
                case 'AFC':
                    this._writeColor(writer, primitive, 'afc');
                    break;
                case 'IC':
                    this._writeColor(writer, primitive, 'interior-color');
                    break;
                case 'M':
                    this._writeAttributeString(writer, 'date', primitive);
                    break;
                case 'NM':
                    this._writeAttributeString(writer, 'name', primitive);
                    break;
                case 'Name':
                    this._writeAttributeString(writer, 'icon', primitive);
                    break;
                case 'Subj':
                    this._writeAttributeString(writer, 'subject', primitive);
                    break;
                case 'T':
                    this._writeAttributeString(writer, 'title', primitive);
                    break;
                case 'Rotate':
                    this._writeAttributeString(writer, 'rotation', primitive);
                    break;
                case 'W':
                    this._writeAttributeString(writer, 'width', primitive);
                    break;
                case 'LE':
                    if (primitive && Array.isArray(primitive)) {
                        if (primitive.length === 2) {
                            writer._writeAttributeString('head', this._getValue(primitive[0]));
                            writer._writeAttributeString('tail', this._getValue(primitive[1]));
                        }
                    }
                    else if (primitive instanceof _PdfName) {
                        this._writeAttributeString(writer, 'head', primitive);
                    }
                    break;
                case 'S':
                    if (this._annotationAttributes.indexOf('style') === -1) {
                        switch (this._getValue(primitive)) {
                            case 'D':
                                writer._writeAttributeString('style', 'dash');
                                break;
                            case 'C':
                                writer._writeAttributeString('style', 'cloudy');
                                break;
                            case 'S':
                                writer._writeAttributeString('style', 'solid');
                                break;
                            case 'B':
                                writer._writeAttributeString('style', 'bevelled');
                                break;
                            case 'I':
                                writer._writeAttributeString('style', 'inset');
                                break;
                            case 'U':
                                writer._writeAttributeString('style', 'underline');
                                break;
                        }
                        this._annotationAttributes.push('style');
                    }
                    break;
                case 'D':
                    this._writeAttributeString(writer, 'dashes', primitive);
                    break;
                case 'I':
                    this._writeAttributeString(writer, 'intensity', primitive);
                    break;
                case 'RD':
                    this._writeAttributeString(writer, 'fringe', primitive);
                    break;
                case 'IT':
                    this._writeAttributeString(writer, 'IT', primitive);
                    break;
                case 'RT':
                    this._writeAttributeString(writer, 'replyType', primitive, true);
                    break;
                case 'LL':
                    this._writeAttributeString(writer, 'leaderLength', primitive);
                    break;
                case 'LLE':
                    this._writeAttributeString(writer, 'leaderExtend', primitive);
                    break;
                case 'Cap':
                    this._writeAttributeString(writer, 'caption', primitive);
                    break;
                case 'Q':
                    this._writeAttributeString(writer, 'justification', primitive);
                    break;
                case 'CP':
                    this._writeAttributeString(writer, 'caption-style', primitive);
                    break;
                case 'CL':
                    this._writeAttributeString(writer, 'callout', primitive);
                    break;
                case 'QuadPoints':
                    this._writeAttributeString(writer, 'coords', primitive);
                    break;
                case 'CA':
                    this._writeAttributeString(writer, 'opacity', primitive);
                    break;
                case 'F':
                    if (typeof primitive === 'number' && this._annotationAttributes.indexOf('flags') === -1) {
                        var flag = _annotationFlagsToString(primitive);
                        writer._writeAttributeString('flags', flag);
                        this._annotationAttributes.push('flags');
                    }
                    break;
                case 'InkList':
                case 'Type':
                case 'Subtype':
                case 'P':
                case 'Parent':
                case 'L':
                case 'Contents':
                case 'RC':
                case 'DA':
                case 'DS':
                case 'FS':
                case 'MeasurementTypes':
                case 'Vertices':
                case 'GroupNesting':
                case 'ITEx':
                    break;
                case 'TextMarkupContent':
                    bytes = _stringToBytes(primitive);
                    this._writeAttributeString(writer, key.toLowerCase(), _byteArrayToHexString(bytes));
                    break;
                case 'AllowedInteractions':
                case 'AnnotationSelectorSettings':
                    this._writeAttributeString(writer, key, primitive);
                    break;
                default:
                    this._writeAttributeString(writer, key.toLowerCase(), primitive);
                    break;
            }
        }
    };
    /**
     * Writes a single attribute with string conversion and optional lowercase normalization.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {string} attribute Attribute name to write.
     * @param {any} primitive Source primitive value.
     * @param {boolean} [isLowerCase=false] When true writes value in lowercase.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeAttributeString = function (writer, attribute, primitive, isLowerCase) {
        if (isLowerCase === void 0) { isLowerCase = false; }
        if (this._annotationAttributes.indexOf(attribute) === -1) {
            var value = this._getValue(primitive);
            writer._writeAttributeString(attribute, isLowerCase ? value.toLowerCase() : value);
            this._annotationAttributes.push(attribute);
        }
    };
    /**
     * Writes an element with raw XML content when value is already formatted.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {string} name Element name to create.
     * @param {string} value Raw XML content to inject.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeRawData = function (writer, name, value) {
        if (value && value !== '') {
            writer._writeStartElement(name);
            writer._writeRaw(value);
            writer._writeEndElement();
        }
    };
    /**
     * Writes color attributes and optional numeric component into the XML writer.
     *
     * @private
     * @param {_XmlWriter} writer Target XML writer.
     * @param {any} primitive Source color primitive array number or name.
     * @param {string} attribute Attribute name for color output.
     * @param {string} [tag] Optional attribute for numeric component.
     * @returns {void}
     */
    _XfdfDocument.prototype._writeColor = function (writer, primitive, attribute, tag) {
        var color = this._getColor(primitive);
        if (typeof primitive === 'number' && tag) {
            var c = this._getValue(primitive);
            if (c && c !== '' && this._annotationAttributes.indexOf(tag) === -1) {
                writer._writeAttributeString(tag, c);
                this._annotationAttributes.push(tag);
            }
        }
        if (color && color !== '' && this._annotationAttributes.indexOf(attribute) === -1) {
            writer._writeAttributeString(attribute, color);
            this._annotationAttributes.push(attribute);
        }
    };
    /**
     * Exports measurement dictionary properties and writes formatted sub dictionaries to XML.
     *
     * @private
     * @param {_PdfDictionary} dictionary Source measure dictionary to export.
     * @param {_XmlWriter} writer Target XML writer.
     * @returns {void}
     */
    _XfdfDocument.prototype._exportMeasureDictionary = function (dictionary, writer) {
        writer._writeStartElement('measure');
        if (dictionary) {
            if (dictionary.has('R')) {
                writer._writeAttributeString('rateValue', this._getValue(dictionary.get('R')));
            }
            if (dictionary.has('A')) {
                var array = dictionary.getArray('A');
                writer._writeStartElement('area');
                this._exportMeasureFormatDetails(array[0], writer);
                writer._writeEndElement();
            }
            if (dictionary.has('D')) {
                var array = dictionary.getArray('D');
                writer._writeStartElement('distance');
                this._exportMeasureFormatDetails(array[0], writer);
                writer._writeEndElement();
            }
            if (dictionary.has('X')) {
                var array = dictionary.getArray('X');
                writer._writeStartElement('xformat');
                this._exportMeasureFormatDetails(array[0], writer);
                writer._writeEndElement();
            }
        }
        writer._writeEndElement();
    };
    /**
     * Writes a single measurement sub dictionary as attribute set into the XML writer.
     *
     * @private
     * @param {_PdfDictionary} measurementDetails Measurement dictionary to serialize.
     * @param {_XmlWriter} writer Target XML writer.
     * @returns {void}
     */
    _XfdfDocument.prototype._exportMeasureFormatDetails = function (measurementDetails, writer) {
        if (measurementDetails.has('C')) {
            writer._writeAttributeString('c', this._getValue(measurementDetails.get('C')));
        }
        if (measurementDetails.has('F')) {
            writer._writeAttributeString('f', this._getValue(measurementDetails.get('F')));
        }
        if (measurementDetails.has('D')) {
            writer._writeAttributeString('d', this._getValue(measurementDetails.get('D')));
        }
        if (measurementDetails.has('RD')) {
            writer._writeAttributeString('rd', this._getValue(measurementDetails.get('RD')));
        }
        if (measurementDetails.has('U')) {
            writer._writeAttributeString('u', this._getValue(measurementDetails.get('U')));
        }
        if (measurementDetails.has('RT')) {
            writer._writeAttributeString('rt', this._getValue(measurementDetails.get('RT')));
        }
        if (measurementDetails.has('SS')) {
            writer._writeAttributeString('ss', this._getValue(measurementDetails.get('SS')));
        }
        if (measurementDetails.has('FD')) {
            writer._writeAttributeString('fd', this._getValue(measurementDetails.get('FD')));
        }
    };
    //#endregion Export Annotations
    //#region Import Annotations
    /**
     * Imports annotations from XFDF bytes and appends them to the document.
     *
     * @private
     * @param {PdfDocument} document Target PDF document to receive annotations.
     * @param {Uint8Array} data UTF8 encoded XFDF bytes.
     * @returns {void}
     */
    _XfdfDocument.prototype._importAnnotations = function (document, data) {
        this._document = document;
        this._crossReference = document._crossReference;
        this._isAnnotationExport = false;
        var xml = _bytesToString(data, true);
        this._xmlDocument = (new DOMParser()).parseFromString(xml, 'text/xml');
        this._isAnnotationImport = true;
        this._readXmlData(this._xmlDocument.documentElement);
    };
    /**
     * Imports form field values from XFDF bytes and applies them to the document form.
     *
     * @private
     * @param {PdfDocument} document Target PDF document to receive form values.
     * @param {Uint8Array} data UTF8 encoded XFDF bytes.
     * @returns {void}
     */
    _XfdfDocument.prototype._importFormData = function (document, data) {
        this._document = document;
        this._crossReference = document._crossReference;
        this._isAnnotationExport = false;
        this._xmlDocument = (new DOMParser()).parseFromString(_bytesToString(data, true), 'text/xml');
        this._readXmlData(this._xmlDocument.documentElement);
    };
    /**
     * Reads the root XML element and routes to annotation or form import handlers.
     *
     * @private
     * @param {HTMLElement} root Root element of the XFDF document.
     * @returns {void}
     */
    _XfdfDocument.prototype._readXmlData = function (root) {
        var _this = this;
        if (root && root.nodeType === 1) {
            this._checkXfdf(root);
            if (this._isAnnotationImport) {
                var xList = root.getElementsByTagName('annots');
                if (xList && xList.length > 0) {
                    for (var i = 0; i < xList.length; i++) {
                        var child = xList.item(i);
                        if (child && child.localName === 'annots' && child.hasChildNodes()) {
                            var childeNodes = child.childNodes;
                            for (var j = 0; j < childeNodes.length; j++) {
                                var childNode = childeNodes.item(j);
                                if (childNode && childNode.nodeType === 1) {
                                    var element = childNode;
                                    if (element && element.nodeType === 1) {
                                        this._parseAnnotationData(element);
                                    }
                                }
                            }
                        }
                    }
                }
                if (this._groupHolders.length > 0) {
                    this._groupHolders.forEach(function (dictionary) {
                        var inReplyTo = dictionary.get('IRT');
                        if (inReplyTo && inReplyTo !== '') {
                            if (_this._groupReferences.has(inReplyTo)) {
                                dictionary.update('IRT', _this._groupReferences.get(inReplyTo));
                            }
                            else {
                                delete dictionary._map.IRT;
                            }
                        }
                    });
                }
                this._groupHolders = [];
                this._groupReferences = new Map();
            }
            else {
                this._parseFormData(root);
            }
        }
        this._dispose();
    };
    /**
     * Validates the root XFDF element name.
     *
     * @private
     * @param {HTMLElement} element Root element to validate.
     * @returns {void}
     * @throws {Error} When the file is not a valid XFDF document.
     */
    _XfdfDocument.prototype._checkXfdf = function (element) {
        if (element.nodeName !== 'xfdf') {
            throw new Error('Invalid XFDF file.');
        }
    };
    /**
     * Parses XFDF form data section and populates the internal fields table.
     *
     * @private
     * @param {HTMLElement} root Root element containing form fields.
     * @returns {void}
     */
    _XfdfDocument.prototype._parseFormData = function (root) {
        var list = root.getElementsByTagName('f');
        if (list && list.length > 0) {
            var fileNameElement = list.item(0);
            if (fileNameElement && fileNameElement.localName === 'f' && fileNameElement.hasAttribute('href')) {
                var fileName = fileNameElement.getAttribute('href');
                if (fileName && fileName !== '') {
                    this._fileName = fileName;
                }
            }
        }
        list = root.getElementsByTagName('ids');
        if (list && list.length > 0) {
            this._asPerSpecification = true;
        }
        var child = root.childNodes;
        if (child && child.length > 0) {
            for (var i = 0; i < child.length; i++) {
                var childNode = child.item(i);
                if (childNode && childNode.nodeType === 1) {
                    var element = childNode;
                    if (element && element.localName === 'fields' && element.hasChildNodes()) {
                        var fieldList = element.childNodes;
                        var elements = [];
                        for (var j = 0; j < fieldList.length; j++) {
                            var field = fieldList.item(j);
                            if (field && field.nodeType === 1) {
                                var filedElement = field;
                                if (filedElement && filedElement.localName === 'field') {
                                    elements.push(filedElement);
                                }
                            }
                        }
                        this._importFormNodes(elements);
                    }
                }
            }
        }
        this._importField();
    };
    /**
     * Flattens a list of nested field elements into the internal fields table with full names.
     *
     * @private
     * @param {Element[]} list List of field elements to parse.
     * @returns {void}
     */
    _XfdfDocument.prototype._importFormNodes = function (list) {
        var _this = this;
        list.forEach(function (child) {
            if (!child || child.localName !== 'field') {
                return;
            }
            var childFields = [];
            for (var i = 0; i < child.children.length; i++) {
                var el = child.children[i];
                if (el.localName === 'field') {
                    childFields.push(el);
                }
            }
            if (childFields.length > 0) {
                _this._importFormNodes(childFields);
                return;
            }
            var fieldName = _this._getFieldName(child);
            var dataValues = _this._fields.get(fieldName) || [];
            var values = child.getElementsByTagName('value');
            if (values && values.length > 0) {
                for (var i = 0; i < values.length; i++) {
                    dataValues.push(values[i].textContent || '');
                }
                _this._fields.set(fieldName, dataValues);
                return;
            }
            values = child.getElementsByTagName('value-richtext');
            if (values && values.length > 0) {
                var element = values.item(0);
                var richText = element.textContent || '';
                if (element.childNodes.length > 0) {
                    var body = element.childNodes[0];
                    if (body && body.hasChildNodes()) {
                        richText = '';
                        for (var j = 0; j < body.childNodes.length; j++) {
                            var node = body.childNodes[j];
                            richText += (node.textContent || '') + '\r';
                        }
                        richText = richText.length
                            ? richText.substring(0, richText.length - 1)
                            : element.textContent || '';
                    }
                }
                dataValues.push(richText);
                _this._fields.set(fieldName, dataValues);
                if (!_this._richTextValues.has(fieldName)) {
                    _this._richTextValues.set(fieldName, element.innerHTML);
                }
            }
        });
    };
    /**
     * Builds the fully qualified field name by walking up the form field hierarchy.
     *
     * @private
     * @param {Element} node Field element from which to derive the full name.
     * @returns {string} Fully qualified field name (e.g., "parent.child.subchild").
     */
    _XfdfDocument.prototype._getFieldName = function (node) {
        var textName = '';
        var current = node;
        while (current && current.localName !== 'fields') {
            if (textName.length > 0) {
                textName = '.' + textName;
            }
            if (current.hasAttribute('name') && current.getAttribute('name') !== '') {
                textName = current.getAttribute('name') + textName;
            }
            else {
                textName = current.localName + textName;
            }
            current = current.parentElement;
        }
        return textName;
    };
    /**
     * Parses a single annotation element and adds it to the corresponding page.
     *
     * @private
     * @param {Element} element Annotation element to parse.
     * @returns {void}
     */
    _XfdfDocument.prototype._parseAnnotationData = function (element) {
        if (element) {
            var pageIndex = -1;
            if (element.hasAttributes && element.hasAttribute('page')) {
                pageIndex = Number(element.getAttribute('page'));
                if (pageIndex >= 0 && pageIndex < this._document.pageCount) {
                    var page = this._document.getPage(pageIndex);
                    var annotationDictionary = this._getAnnotationDictionary(page, element);
                    if (annotationDictionary && annotationDictionary.size > 0) {
                        var pageDictionary = page._pageDictionary;
                        if (pageDictionary) {
                            var annotations = page.annotations;
                            var annotation = annotations._parseAnnotation(annotationDictionary);
                            if (annotation) {
                                annotation._isImported = true;
                                var reference = this._crossReference._getNextReference();
                                this._crossReference._cacheMap.set(reference, annotationDictionary);
                                if (annotationDictionary.has('NM') || annotationDictionary.has('IRT')) {
                                    this._addReferenceToGroup(reference, annotationDictionary);
                                }
                                annotation._ref = reference;
                                var index = annotations._annotations.length;
                                annotations._annotations.push(reference);
                                if (annotationDictionary.has('Popup')) {
                                    annotations._annotations.push(annotationDictionary.getRaw('Popup'));
                                }
                                if (annotations._comments && annotations._comments.length > 0) {
                                    annotations._comments = [];
                                }
                                pageDictionary.set('Annots', annotations._annotations);
                                pageDictionary._updated = true;
                                annotations._parsedAnnotations.set(index, annotation);
                                this._handlePopup(annotations, reference, annotationDictionary, pageDictionary);
                            }
                        }
                    }
                }
            }
        }
    };
    /**
     * Builds an annotation dictionary from an XML element and its attributes and children.
     *
     * @private
     * @param {PdfPage} page Page that will host the annotation.
     * @param {Element} element Annotation element to convert.
     * @returns {_PdfDictionary} Constructed annotation dictionary or empty on unsupported type.
     */
    _XfdfDocument.prototype._getAnnotationDictionary = function (page, element) {
        var dictionary = new _PdfDictionary(this._crossReference);
        dictionary.update('Type', _PdfName.get('Annot'));
        var isValidType = true;
        switch (element.localName.toLowerCase()) {
            case 'line':
                dictionary.update('Subtype', _PdfName.get('Line'));
                if (element.hasAttribute('start') && element.hasAttribute('end')) {
                    var points = element.getAttribute('start').split(',').map(function (value) { return Number.parseFloat(value); }).concat(element.getAttribute('end').split(',').map(function (value) { return Number.parseFloat(value); }));
                    if (points.length === 4) {
                        dictionary.update('L', points);
                    }
                }
                this._addLineEndStyle(dictionary, element);
                break;
            case 'circle':
                dictionary.update('Subtype', _PdfName.get('Circle'));
                break;
            case 'square':
                dictionary.update('Subtype', _PdfName.get('Square'));
                break;
            case 'polyline':
                dictionary.update('Subtype', _PdfName.get('PolyLine'));
                this._addLineEndStyle(dictionary, element);
                break;
            case 'polygon':
                dictionary.update('Subtype', _PdfName.get('Polygon'));
                this._addLineEndStyle(dictionary, element);
                break;
            case 'ink':
                dictionary.update('Subtype', _PdfName.get('Ink'));
                break;
            case 'popup':
                dictionary.update('Subtype', _PdfName.get('Popup'));
                break;
            case 'text':
                dictionary.update('Subtype', _PdfName.get('Text'));
                break;
            case 'freetext':
                dictionary.update('Subtype', _PdfName.get('FreeText'));
                this._addLineEndStyle(dictionary, element);
                break;
            case 'stamp':
                dictionary.update('Subtype', _PdfName.get('Stamp'));
                break;
            case 'highlight':
                dictionary.update('Subtype', _PdfName.get('Highlight'));
                break;
            case 'squiggly':
                dictionary.update('Subtype', _PdfName.get('Squiggly'));
                break;
            case 'underline':
                dictionary.update('Subtype', _PdfName.get('Underline'));
                break;
            case 'strikeout':
                dictionary.update('Subtype', _PdfName.get('StrikeOut'));
                break;
            case 'fileattachment':
                dictionary.update('Subtype', _PdfName.get('FileAttachment'));
                break;
            case 'sound':
                dictionary.update('Subtype', _PdfName.get('Sound'));
                break;
            case 'caret':
                dictionary.update('Subtype', _PdfName.get('Caret'));
                break;
            case 'redact':
                dictionary.update('Subtype', _PdfName.get('Redact'));
                break;
            case 'link':
                dictionary.update('Subtype', _PdfName.get('Link'));
                break;
            default:
                isValidType = false;
                break;
        }
        if (isValidType) {
            this._addAnnotationData(dictionary, element, page);
        }
        return dictionary;
    };
    /**
     * Adds general annotation attributes border style inner elements and measure data to a dictionary.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination dictionary to update.
     * @param {Element} element Source annotation element.
     * @param {PdfPage} page Page that will host the annotation.
     * @returns {void}
     */
    _XfdfDocument.prototype._addAnnotationData = function (dictionary, element, page) {
        this._addBorderStyle(dictionary, element);
        this._applyAttributeValues(dictionary, element.attributes);
        this._parseInnerElements(dictionary, element, page);
        this._addMeasureDictionary(dictionary, element);
    };
    /**
     * Applies border style attributes from an element to the annotation dictionary.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} element Source annotation element with style attributes.
     * @returns {void}
     */
    _XfdfDocument.prototype._addBorderStyle = function (dictionary, element) {
        var borderEffectDictionary = new _PdfDictionary(this._crossReference);
        var borderStyleDictionary = new _PdfDictionary(this._crossReference);
        if (element.hasAttribute('width')) {
            borderStyleDictionary.update('W', Number.parseFloat(element.getAttribute('width')));
        }
        var isBasicStyle = true;
        if (element.hasAttribute('style')) {
            var style = '';
            switch (element.getAttribute('style')) {
                case 'dash':
                    style = 'D';
                    break;
                case 'solid':
                    style = 'S';
                    break;
                case 'bevelled':
                    style = 'B';
                    break;
                case 'inset':
                    style = 'I';
                    break;
                case 'underline':
                    style = 'U';
                    break;
                case 'cloudy':
                    style = 'C';
                    isBasicStyle = false;
                    break;
            }
            if (style !== '') {
                (isBasicStyle ? borderStyleDictionary : borderEffectDictionary).update('S', _PdfName.get(style));
                if (!isBasicStyle && element.hasAttribute('intensity')) {
                    borderEffectDictionary.update('I', Number.parseFloat(element.getAttribute('intensity')));
                }
                else if (element.hasAttribute('dashes')) {
                    var dashes = element.getAttribute('dashes').split(',').map(function (value) { return Number.parseFloat(value); });
                    borderStyleDictionary.update('D', dashes);
                }
            }
        }
        if (borderEffectDictionary.size > 0) {
            dictionary.update('BE', borderEffectDictionary);
        }
        if (borderStyleDictionary.size > 0) {
            borderStyleDictionary.update('Type', 'Border');
            dictionary.update('BS', borderStyleDictionary);
        }
    };
    /**
     * Converts element attributes into corresponding dictionary entries for supported keys.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {NamedNodeMap} attributes Attribute collection from the source element.
     * @returns {void}
     */
    _XfdfDocument.prototype._applyAttributeValues = function (dictionary, attributes) {
        var _this = this;
        Array.from(attributes).forEach(function (attribute) {
            var _a;
            var value = attribute.value;
            var values;
            var rect;
            var leaderExtend;
            switch (attribute.name.toLowerCase()) {
                case 'page':
                case 'start':
                case 'end':
                case 'width':
                case 'head':
                case 'tail':
                case 'style':
                case 'intensity':
                case 'itex':
                    break;
                case 'state':
                    _this._addString(dictionary, 'State', value);
                    break;
                case 'statemodel':
                    _this._addString(dictionary, 'StateModel', value);
                    break;
                case 'replytype':
                    if (value === 'group') {
                        dictionary.update('RT', _PdfName.get('Group'));
                    }
                    break;
                case 'inreplyto':
                    _this._addString(dictionary, 'IRT', value);
                    break;
                case 'rect':
                    rect = _this._obtainPoints(value);
                    if (rect && rect.length === 4) {
                        dictionary.update('Rect', rect);
                    }
                    break;
                case 'color':
                    values = _convertToColor(value);
                    if (values) {
                        dictionary.update('C', [values.r / 255, values.g / 255, values.b / 255]);
                    }
                    break;
                case 'oc':
                    if (value && dictionary.get('Subtype').name === 'Redact') {
                        values = _convertToColor(value);
                        if (values) {
                            dictionary.update('OC', [values.r / 255, values.g / 255, values.b / 255]);
                        }
                    }
                    break;
                case 'afc':
                    if (value && dictionary.get('Subtype').name === 'Redact') {
                        values = _convertToColor(value);
                        if (values) {
                            dictionary.update('AFC', [values.r / 255, values.g / 255, values.b / 255]);
                        }
                    }
                    break;
                case 'interior-color':
                    values = _convertToColor(value);
                    if (values) {
                        dictionary.update('IC', [values.r / 255, values.g / 255, values.b / 255]);
                    }
                    break;
                case 'date':
                    _this._addString(dictionary, 'M', value);
                    break;
                case 'creationdate':
                    _this._addString(dictionary, 'CreationDate', value);
                    break;
                case 'name':
                    _this._addString(dictionary, 'NM', value);
                    break;
                case 'uri':
                    if (value) {
                        var actionDictionary = new _PdfDictionary(_this._crossReference);
                        actionDictionary.update('Type', new _PdfName('Action'));
                        actionDictionary.update('S', new _PdfName('URI'));
                        actionDictionary.update('URI', value);
                        var actionRef = _this._crossReference._getNextReference();
                        _this._crossReference._cacheMap.set(actionRef, actionDictionary);
                        dictionary.update('A', actionRef);
                    }
                    break;
                case 'icon':
                    if (value && value !== '') {
                        dictionary.update('Name', _PdfName.get(value));
                    }
                    break;
                case 'subject':
                    _this._addString(dictionary, 'Subj', _this._getFormatedString(value, true));
                    break;
                case 'title':
                    _this._addString(dictionary, 'T', _this._getFormatedString(value, true));
                    break;
                case 'rotation':
                    _this._addInt(dictionary, 'Rotate', value);
                    break;
                case 'justification':
                    _this._addInt(dictionary, 'Q', value);
                    break;
                case 'fringe':
                    _this._addFloatPoints(dictionary, _this._obtainPoints(value), 'RD');
                    break;
                case 'it':
                    if (value && value !== '') {
                        dictionary.update('IT', _PdfName.get(value));
                    }
                    break;
                case 'leaderlength':
                    _this._addFloat(dictionary, 'LL', value);
                    break;
                case 'leaderextend':
                    leaderExtend = Number.parseFloat(value);
                    if (typeof leaderExtend !== 'undefined') {
                        dictionary.update('LLE', leaderExtend);
                    }
                    break;
                case 'caption':
                    if (value && value !== '') {
                        dictionary.update('Cap', value.toLowerCase() === 'yes' ? true : false);
                    }
                    break;
                case 'caption-style':
                    if (value && value !== '') {
                        dictionary.update('CP', _PdfName.get(value));
                    }
                    break;
                case 'callout':
                    _this._addFloatPoints(dictionary, _this._obtainPoints(value), 'CL');
                    break;
                case 'coords':
                    _this._addFloatPoints(dictionary, _this._obtainPoints(value), 'QuadPoints');
                    break;
                case 'border':
                    _this._addFloatPoints(dictionary, _this._obtainPoints(value), 'Border');
                    break;
                case 'opacity':
                    _this._addFloat(dictionary, 'CA', value);
                    break;
                case 'flags':
                    if (value && value !== '') {
                        var annotFlag_1 = PdfAnnotationFlag.default;
                        var flags = value.split(',');
                        flags.forEach(function (flag, index) {
                            var flagType = _stringToAnnotationFlags(flag);
                            if (index === 0) {
                                annotFlag_1 = flagType;
                            }
                            else {
                                annotFlag_1 |= flagType;
                            }
                        });
                        dictionary.update('F', annotFlag_1);
                    }
                    break;
                case 'open':
                    if (value && value !== '') {
                        dictionary.update('Open', (value === 'true' || value === 'yes') ? true : false);
                    }
                    break;
                case 'calibrate':
                    _this._addString(dictionary, 'Calibrate', value);
                    break;
                case 'customdata':
                    _this._addString(dictionary, 'CustomData', value);
                    break;
                case 'overlaytext':
                    dictionary.update('OverlayText', value);
                    break;
                case 'repeat':
                    dictionary.update('Repeat', (value === 'true' || value === 'yes') ? true : false);
                    break;
                default:
                    if (_this._document._allowImportCustomData) {
                        var customValue = void 0;
                        if (typeof value === 'string' && value.indexOf(':') !== -1 && !value.startsWith('{')
                            && !value.endsWith('}')) {
                            var parts = value.split(':');
                            if (Array.isArray(parts) && parts.length === 2) {
                                customValue = JSON.stringify((_a = {}, _a[parts[0]] = parts[1], _a));
                            }
                            else {
                                customValue = value;
                            }
                        }
                        else {
                            customValue = typeof value === 'string' ? value : JSON.stringify(value);
                        }
                        _this._addString(dictionary, attribute.name, customValue);
                    }
                    break;
            }
        });
    };
    /**
     * Parses a comma separated numeric list into an array of numbers.
     *
     * @private
     * @param {string} value Comma separated numeric list.
     * @returns {number[]} Parsed numeric array.
     */
    _XfdfDocument.prototype._obtainPoints = function (value) {
        return value.split(',').map(function (value) { return Number.parseFloat(value); });
    };
    /**
     * Parses child nodes like popup contents appearance inklist vertices and embedded data.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} element Source annotation element to inspect.
     * @param {PdfPage} page Page context used for nested annotation parsing.
     * @returns {void}
     */
    _XfdfDocument.prototype._parseInnerElements = function (dictionary, element, page) {
        var _this = this;
        if (element.hasChildNodes) {
            var children = element.childNodes;
            Array.from(children).forEach(function (child) {
                if (child.nodeType === 1) {
                    var childElement = child;
                    var textContent = child.textContent;
                    var innerHTML = childElement.innerHTML;
                    switch (child.nodeName.toLowerCase()) {
                        case 'popup':
                            if (childElement && childElement.hasAttributes) {
                                var popupDictionary = _this._getAnnotationDictionary(page, childElement);
                                if (popupDictionary.size > 0) {
                                    var reference = _this._crossReference._getNextReference();
                                    _this._crossReference._cacheMap.set(reference, popupDictionary);
                                    dictionary.update('Popup', reference);
                                    if (popupDictionary.has('NM')) {
                                        _this._addReferenceToGroup(reference, popupDictionary);
                                    }
                                }
                            }
                            break;
                        case 'contents':
                            if (textContent && textContent !== '') {
                                dictionary.update('Contents', _this._getFormatedString(textContent, true));
                            }
                            break;
                        case 'contents-richtext':
                            if (innerHTML && innerHTML !== '') {
                                dictionary.update('RC', _this._richTextPrefix + innerHTML);
                            }
                            break;
                        case 'defaultstyle':
                            _this._addString(dictionary, 'DS', textContent);
                            break;
                        case 'defaultappearance':
                            _this._addString(dictionary, 'DA', textContent);
                            break;
                        case 'vertices':
                            if (textContent && textContent !== '') {
                                var vertices_1 = [];
                                textContent.split(',').forEach(function (value) {
                                    if (value.indexOf(';') !== -1) {
                                        value.split(';').forEach(function (innerValue) {
                                            vertices_1.push(innerValue);
                                        });
                                    }
                                    else {
                                        vertices_1.push(value);
                                    }
                                });
                                if (vertices_1.length > 0) {
                                    var verticesArray = vertices_1.map(function (value) { return Number.parseFloat(value); });
                                    dictionary.update('Vertices', verticesArray);
                                }
                            }
                            break;
                        case 'appearance':
                            _this._addAppearanceData(child, dictionary);
                            break;
                        case 'inklist':
                            if (child.hasChildNodes) {
                                var inkListCollection_1 = [];
                                var childNodes = child.childNodes;
                                Array.from(childNodes).forEach(function (inkChild) {
                                    if (inkChild && inkChild.nodeType === 1) {
                                        var inkChildElement = inkChild;
                                        if (inkChildElement.nodeName.toLowerCase() === 'gesture') {
                                            if (inkChildElement.textContent && inkChildElement.textContent !== '') {
                                                var points_1 = [];
                                                inkChildElement.textContent.split(',').forEach(function (value) {
                                                    if (value.indexOf(';') !== -1) {
                                                        value.split(';').forEach(function (innerValue) {
                                                            points_1.push(innerValue);
                                                        });
                                                    }
                                                    else {
                                                        points_1.push(value);
                                                    }
                                                });
                                                if (points_1.length > 0) {
                                                    var pointsArray = points_1.map(function (value) { return Number.parseFloat(value); });
                                                    inkListCollection_1.push(pointsArray);
                                                }
                                            }
                                        }
                                    }
                                });
                                dictionary.update('InkList', inkListCollection_1);
                            }
                            break;
                        case 'data':
                            _this._addStreamData(child, dictionary, element);
                            break;
                    }
                }
            });
        }
    };
    /**
     * Adds embedded stream data for sound or file attachment annotations.
     *
     * @private
     * @param {Node} child Data node that contains stream bytes.
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} parent Parent annotation element for attribute context.
     * @returns {void}
     */
    _XfdfDocument.prototype._addStreamData = function (child, dictionary, parent) {
        if (child && child.textContent && child.textContent !== '') {
            var raw = _hexStringToByteArray(child.textContent, true);
            if (raw && raw.length > 0) {
                if (dictionary.has('Subtype')) {
                    var subtype = dictionary.get('Subtype');
                    if (subtype && subtype.name === 'FileAttachment') {
                        this._addFileAttachment(dictionary, parent, raw);
                    }
                    else if (subtype && subtype.name === 'Sound') {
                        this._addSound(dictionary, parent, raw);
                    }
                }
            }
        }
    };
    /**
     * Creates a sound stream and links it to the annotation dictionary using provided attributes.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} element Data element with sound attributes.
     * @param {number[]} raw Raw byte array for sound data.
     * @returns {void}
     */
    _XfdfDocument.prototype._addSound = function (dictionary, element, raw) {
        var soundStream = new _PdfContentStream(raw);
        soundStream.dictionary._crossReference = this._crossReference;
        soundStream.dictionary.update('Type', _PdfName.get('Sound'));
        if (element.hasAttribute('bits')) {
            this._addInt(soundStream.dictionary, 'B', element.getAttribute('bits'));
        }
        if (element.hasAttribute('rate')) {
            this._addInt(soundStream.dictionary, 'R', element.getAttribute('rate'));
        }
        if (element.hasAttribute('channels')) {
            this._addInt(soundStream.dictionary, 'C', element.getAttribute('channels'));
        }
        if (element.hasAttribute('encoding')) {
            var value = element.getAttribute('encoding');
            if (value && value !== '') {
                soundStream.dictionary.update('E', _PdfName.get(value));
            }
        }
        if (element.hasAttribute('filter')) {
            soundStream.dictionary.update('Filter', _PdfName.get('FlateDecode'));
        }
        var soundReference = this._crossReference._getNextReference();
        this._crossReference._cacheMap.set(soundReference, soundStream);
        dictionary.update('Sound', soundReference);
    };
    /**
     * Creates an embedded file stream and filespec dictionary and links them to the annotation.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} element Data element with file attributes.
     * @param {number[]} raw Raw byte array for file data.
     * @returns {void}
     */
    _XfdfDocument.prototype._addFileAttachment = function (dictionary, element, raw) {
        var fileDictionary = new _PdfDictionary(this._crossReference);
        fileDictionary.update('Type', _PdfName.get('Filespec'));
        if (element.hasAttribute('file')) {
            var value = element.getAttribute('file');
            this._addString(fileDictionary, 'F', value);
            this._addString(fileDictionary, 'UF', value);
        }
        var fileStream = new _PdfContentStream(raw);
        fileStream.dictionary._crossReference = this._crossReference;
        var param = new _PdfDictionary(this._crossReference);
        if (element.hasAttribute('size')) {
            var size = Number(element.getAttribute('size'));
            if (typeof size !== 'undefined') {
                param.update('Size', size);
                fileStream.dictionary.update('DL', size);
            }
        }
        if (element.hasAttribute('modification')) {
            this._addString(param, 'ModDate', element.getAttribute('modification'));
        }
        if (element.hasAttribute('creation')) {
            this._addString(param, 'CreationDate', element.getAttribute('creation'));
        }
        fileStream.dictionary.update('Params', param);
        if (element.hasAttribute('mimetype')) {
            this._addString(fileStream.dictionary, 'Subtype', element.getAttribute('mimetype'));
        }
        fileStream.dictionary.update('Filter', _PdfName.get('FlateDecode'));
        var embeddedFile = new _PdfDictionary(this._crossReference);
        var reference = this._crossReference._getNextReference();
        this._crossReference._cacheMap.set(reference, fileStream);
        embeddedFile.update('F', reference);
        fileDictionary.update('EF', embeddedFile);
        var fileReference = this._crossReference._getNextReference();
        this._crossReference._cacheMap.set(fileReference, fileDictionary);
        dictionary.update('FS', fileReference);
    };
    /**
     * Decodes appearance XML from base64 and assigns it to the annotation AP dictionary.
     *
     * @private
     * @param {Node} element * @param {Node} element Appearance element containing encoded XML.
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @returns {void}
     */
    _XfdfDocument.prototype._addAppearanceData = function (element, dictionary) {
        var _this = this;
        var innerText = element.textContent;
        if (innerText && innerText !== '') {
            var document_1 = (new DOMParser()).parseFromString(atob(innerText), 'text/xml');
            if (document_1 && document_1.hasChildNodes) {
                var childNodes = document_1.childNodes;
                if (childNodes && childNodes.length === 1) {
                    var rootNode = childNodes[0];
                    if (rootNode && rootNode.nodeType === 1) {
                        var rootElement = rootNode;
                        if (rootElement.nodeName.toUpperCase() === 'DICT' && rootElement.hasAttribute('KEY')) {
                            var key = rootElement.getAttribute('KEY');
                            if (key && key === 'AP' && rootElement.hasChildNodes) {
                                var appearance_1 = new _PdfDictionary(this._crossReference);
                                childNodes = rootElement.childNodes;
                                Array.from(childNodes).forEach(function (childNode) {
                                    _this._getAppearance(appearance_1, childNode);
                                });
                                if (appearance_1.size > 0) {
                                    dictionary.update('AP', appearance_1);
                                }
                            }
                        }
                    }
                }
            }
        }
    };
    /**
     * Parses a typed appearance node and adds the resulting primitive to the target dictionary or stream.
     *
     * @private
     * @param {_PdfDictionary|_PdfContentStream} source Destination dictionary or content stream.
     * @param {Node} child Typed node to parse such as STREAM DICT ARRAY DATA or scalar.
     * @returns {void}
     */
    _XfdfDocument.prototype._getAppearance = function (source, child) {
        var appearance = source instanceof _PdfDictionary ? source : source.dictionary;
        if (child && child.nodeType === 1) {
            var element = child;
            if (element && element.localName) {
                var stream = void 0;
                var dictionary = void 0;
                var data = void 0;
                switch (element.localName) {
                    case 'STREAM':
                        stream = this._getStream(element);
                        if (stream) {
                            var reference = this._crossReference._getNextReference();
                            this._crossReference._cacheMap.set(reference, stream);
                            this._addKey(reference, appearance, element);
                        }
                        break;
                    case 'DICT':
                        dictionary = this._getDictionary(element);
                        if (dictionary) {
                            var reference = this._crossReference._getNextReference();
                            this._crossReference._cacheMap.set(reference, dictionary);
                            this._addKey(reference, appearance, element);
                        }
                        break;
                    case 'ARRAY':
                        this._addKey(this._getArray(element), appearance, element);
                        break;
                    case 'FIXED':
                        this._addKey(this._getFixed(element), appearance, element);
                        break;
                    case 'INT':
                        this._addKey(this._getInt(element), appearance, element);
                        break;
                    case 'STRING':
                        this._addKey(this._getString(element), appearance, element);
                        break;
                    case 'NAME':
                        this._addKey(this._getName(element), appearance, element);
                        break;
                    case 'BOOL':
                        this._addKey(this._getBoolean(element), appearance, element);
                        break;
                    case 'DATA':
                        data = this._getData(element);
                        if (data && data.length > 0 && source instanceof _PdfContentStream) {
                            source._bytes = data;
                            var isImage = false;
                            if (appearance && appearance.has('Subtype')) {
                                var type = appearance.get('Subtype');
                                isImage = type && type.name === 'Image';
                            }
                            if (isImage) {
                                source._isCompress = true;
                            }
                            else {
                                if (source.dictionary.has('Length')) {
                                    delete source.dictionary._map.Length;
                                }
                                if (source.dictionary.has('Filter')) {
                                    delete source.dictionary._map.Filter;
                                }
                            }
                        }
                        break;
                }
            }
        }
    };
    /**
     * Creates an empty content stream and populates it with parsed appearance entries.
     *
     * @private
     * @param {Element} element Stream element to parse.
     * @returns {_PdfContentStream} Constructed content stream.
     */
    _XfdfDocument.prototype._getStream = function (element) {
        var _this = this;
        var stream = new _PdfContentStream([]);
        stream.dictionary._crossReference = this._crossReference;
        if (element.hasChildNodes) {
            var childNodes = element.childNodes;
            Array.from(childNodes).forEach(function (child) {
                if (child.nodeType === 1) {
                    _this._getAppearance(stream, child);
                }
            });
        }
        return stream;
    };
    /**
     * Creates a dictionary and populates it with parsed appearance entries.
     *
     * @private
     * @param {Element} element Dictionary element to parse.
     * @returns {_PdfDictionary} Constructed dictionary.
     */
    _XfdfDocument.prototype._getDictionary = function (element) {
        var _this = this;
        var dictionary = new _PdfDictionary(this._crossReference);
        if (element.hasChildNodes) {
            var childNodes = element.childNodes;
            Array.from(childNodes).forEach(function (child) {
                if (child.nodeType === 1) {
                    _this._getAppearance(dictionary, child);
                }
            });
        }
        return dictionary;
    };
    /**
     * Parses an ARRAY node into a JavaScript array of primitives and references.
     *
     * @private
     * @param {Element} element Array element to parse.
     * @returns {any} Parsed array value.
     */
    _XfdfDocument.prototype._getArray = function (element) {
        var _this = this;
        var array = []; // eslint-disable-line
        if (element.hasChildNodes) {
            var childNodes = element.childNodes;
            Array.from(childNodes).forEach(function (child) {
                if (child.nodeType === 1) {
                    _this._addArrayElements(array, child);
                }
            });
        }
        return array;
    };
    /**
     * Parses a DATA node into a raw byte array based on declared mode and encoding.
     *
     * @private
     * @param {Element} element Data node with MODE and ENCODING attributes.
     * @returns {number[]} Parsed byte array.
     */
    _XfdfDocument.prototype._getData = function (element) {
        var data = [];
        if (element && element.textContent &&
            element.textContent !== '' &&
            element.hasAttribute('MODE') && element.hasAttribute('ENCODING')) {
            var mode = element.getAttribute('MODE');
            var encoding = element.getAttribute('ENCODING');
            if (mode && encoding) {
                var innerText = this._getFormatedString(element.textContent, true);
                if (mode === 'FILTERED' && encoding === 'ASCII') {
                    data = _stringToBytes(innerText, true);
                }
                else if (mode === 'RAW' && encoding === 'HEX') {
                    data = _hexStringToByteArray(innerText, true);
                }
            }
        }
        return data;
    };
    /**
     * Appends a typed child element value into the given array.
     *
     * @private
     * @param {any} array Destination array for parsed items.
     * @param {Node} child Typed node to parse and append.
     * @returns {void}
     */
    _XfdfDocument.prototype._addArrayElements = function (array, child) {
        if (child && child.nodeType === 1) {
            var element = child;
            var stream = void 0;
            var dictionary = void 0;
            var value = void 0; // eslint-disable-line
            var floatValue = void 0;
            var intValue = void 0;
            var name_1;
            var bool = void 0;
            var originalString = void 0;
            var data = void 0;
            switch (element.localName) {
                case 'DATA':
                    data = this._getData(element);
                    originalString = _bytesToString(new Uint8Array(data), true);
                    if (originalString && originalString.length > 0) {
                        array.push(originalString);
                    }
                    break;
                case 'STREAM':
                    stream = this._getStream(element);
                    if (stream) {
                        var reference = this._crossReference._getNextReference();
                        stream.reference = reference;
                        this._crossReference._cacheMap.set(reference, stream);
                        array.push(reference);
                    }
                    break;
                case 'DICT':
                    dictionary = this._getDictionary(element);
                    if (dictionary) {
                        var reference = this._crossReference._getNextReference();
                        this._crossReference._cacheMap.set(reference, dictionary);
                        array.push(reference);
                    }
                    break;
                case 'ARRAY':
                    value = this._getArray(element);
                    if (value) {
                        array.push(value);
                    }
                    break;
                case 'FIXED':
                    floatValue = this._getFixed(element);
                    if (typeof floatValue !== 'undefined' && !isNaN(floatValue)) {
                        array.push(floatValue);
                    }
                    break;
                case 'INT':
                    intValue = this._getInt(element);
                    if (typeof intValue !== 'undefined' && !isNaN(intValue)) {
                        array.push(intValue);
                    }
                    break;
                case 'NAME':
                    name_1 = this._getName(element);
                    if (name_1) {
                        array.push(name_1);
                    }
                    break;
                case 'BOOL':
                    bool = this._getBoolean(element);
                    if (typeof bool !== 'undefined' && bool !== null) {
                        array.push(bool);
                    }
                    break;
            }
        }
    };
    /**
     * Reads a FIXED element into a number.
     *
     * @private
     * @param {Element} element Fixed element with VAL attribute.
     * @returns {number} Parsed floating point value.
     */
    _XfdfDocument.prototype._getFixed = function (element) {
        var value;
        if (element && element.hasAttribute('VAL')) {
            value = Number.parseFloat(element.getAttribute('VAL'));
        }
        return value;
    };
    /**
     * Reads an INT element into a number.
     *
     * @private
     * @param {Element} element Int element with VAL attribute.
     * @returns {number} Parsed integer value.
     */
    _XfdfDocument.prototype._getInt = function (element) {
        var value;
        if (element && element.hasAttribute('VAL')) {
            value = Number(element.getAttribute('VAL'));
        }
        return value;
    };
    /**
     * Reads a STRING element into a text value.
     *
     * @private
     * @param {Element} element String element with VAL attribute.
     * @returns {string} Parsed string value.
     */
    _XfdfDocument.prototype._getString = function (element) {
        var value;
        if (element && element.hasAttribute('VAL')) {
            value = element.getAttribute('VAL');
        }
        return value;
    };
    /**
     * Reads a NAME element into a PDF name object.
     *
     * @private
     * @param {Element} element Name element with VAL attribute.
     * @returns {_PdfName} Parsed name object.
     */
    _XfdfDocument.prototype._getName = function (element) {
        var value;
        if (element && element.hasAttribute('VAL')) {
            value = _PdfName.get(element.getAttribute('VAL'));
        }
        return value;
    };
    /**
     * Reads a BOOL element into a boolean value.
     *
     * @private
     * @param {Element} element Bool element with VAL attribute.
     * @returns {boolean} Parsed boolean value.
     */
    _XfdfDocument.prototype._getBoolean = function (element) {
        var value;
        if (element && element.hasAttribute('VAL')) {
            value = element.getAttribute('VAL') === 'true' ? true : false;
        }
        return value;
    };
    /**
     * Builds and attaches the Measure dictionary to the annotation based on nested measure elements.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} element Annotation element containing measure data.
     * @returns {void}
     */
    _XfdfDocument.prototype._addMeasureDictionary = function (dictionary, element) {
        var measurement;
        var area;
        var distance;
        var xformat;
        if (element.hasChildNodes) {
            var childNodes = element.childNodes;
            for (var i = 0; i < childNodes.length; i++) {
                var childElement = childNodes[i];
                if (childElement && childElement.localName === 'measure') {
                    measurement = childElement;
                    break;
                }
            }
        }
        var measureDictionary = new _PdfDictionary(this._crossReference);
        var dDict = new _PdfDictionary(this._crossReference);
        var aDict = new _PdfDictionary(this._crossReference);
        var xDict = new _PdfDictionary(this._crossReference);
        var dArray = [];
        var aArray = [];
        var xArray = [];
        if (measurement) {
            measureDictionary.update('Type', _PdfName.get('Measure'));
            if (measurement.hasAttribute('rateValue')) {
                var attribute = measurement.getAttribute('rateValue');
                if (attribute && attribute !== '') {
                    measureDictionary.update('R', attribute);
                }
            }
            if (measurement.hasChildNodes) {
                var childNodes = measurement.childNodes;
                Array.from(childNodes).forEach(function (child) {
                    if (child && child.nodeType === 1) {
                        var childElement = child;
                        switch (childElement.nodeName.toLowerCase()) {
                            case 'distance':
                                distance = childElement;
                                break;
                            case 'area':
                                area = childElement;
                                break;
                            case 'xformat':
                                xformat = childElement;
                                break;
                        }
                    }
                });
            }
        }
        if (xformat) {
            this._addElements(xformat, xDict);
            xArray.push(xDict);
        }
        if (distance) {
            this._addElements(distance, dDict);
            dArray.push(dDict);
        }
        if (area) {
            this._addElements(area, aDict);
            aArray.push(aDict);
        }
        measureDictionary.set('A', aArray);
        measureDictionary.set('D', dArray);
        measureDictionary.set('X', xArray);
        if (measureDictionary.size > 0 && measureDictionary.has('Type')) {
            var reference = this._crossReference._getNextReference();
            this._crossReference._cacheMap.set(reference, measureDictionary);
            dictionary.update('Measure', reference);
        }
    };
    /**
     * Copies supported measurement attributes from an element into a measurement dictionary.
     *
     * @private
     * @param {Element} element Measurement element containing attributes.
     * @param {_PdfDictionary} dictionary Destination measurement dictionary.
     * @returns {void}
     */
    _XfdfDocument.prototype._addElements = function (element, dictionary) {
        if (element.hasAttribute('d')) {
            this._addFloat(dictionary, 'D', element.getAttribute('d'));
        }
        if (element.hasAttribute('c')) {
            this._addFloat(dictionary, 'C', element.getAttribute('c'));
        }
        if (element.hasAttribute('rt')) {
            dictionary.update('RT', element.getAttribute('rt'));
        }
        if (element.hasAttribute('rd')) {
            dictionary.update('RD', element.getAttribute('rt'));
        }
        if (element.hasAttribute('ss')) {
            dictionary.update('SS', element.getAttribute('ss'));
        }
        if (element.hasAttribute('u')) {
            dictionary.update('U', element.getAttribute('u'));
        }
        if (element.hasAttribute('f')) {
            dictionary.update('F', _PdfName.get(element.getAttribute('f')));
        }
        if (element.hasAttribute('fd')) {
            dictionary.update('FD', element.getAttribute('fd') === 'yes' ? true : false);
        }
    };
    /**
     * Updates a dictionary with a string value when present.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination dictionary to update.
     * @param {string} key Entry key to set.
     * @param {string} value String value to store.
     * @returns {void}
     */
    _XfdfDocument.prototype._addString = function (dictionary, key, value) {
        if (value && value !== '') {
            dictionary.update(key, value);
        }
    };
    /**
     * Updates a dictionary with an integer value when present.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination dictionary to update.
     * @param {string} key Entry key to set.
     * @param {string} value String numeric text to convert.
     * @returns {void}
     */
    _XfdfDocument.prototype._addInt = function (dictionary, key, value) {
        var intValue = Number(value);
        if (typeof intValue !== 'undefined') {
            dictionary.update(key, intValue);
        }
    };
    /**
     * Updates a dictionary with a floating point value when present.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination dictionary to update.
     * @param {string} key Entry key to set.
     * @param {string} value String numeric text to convert.
     * @returns {void}
     */
    _XfdfDocument.prototype._addFloat = function (dictionary, key, value) {
        var floatValue = Number.parseFloat(value);
        if (typeof floatValue !== 'undefined') {
            dictionary.update(key, floatValue);
        }
    };
    /**
     * Updates a dictionary with an array of numbers when present.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination dictionary to update.
     * @param {number[]} points Numeric array to store.
     * @param {string} key Entry key to set.
     * @returns {void}
     */
    _XfdfDocument.prototype._addFloatPoints = function (dictionary, points, key) {
        if (points && points.length > 0) {
            dictionary.update(key, points);
        }
    };
    /**
     * Adds a parsed primitive to a dictionary using the KEY attribute of the XML element.
     *
     * @private
     * @param {any} primitive Parsed primitive to store.
     * @param {_PdfDictionary} dictionary Destination dictionary to update.
     * @param {Element} element Source element containing the KEY attribute.
     * @returns {void}
     */
    _XfdfDocument.prototype._addKey = function (primitive, dictionary, element) {
        if (typeof primitive !== 'undefined' && primitive !== null && element.hasAttribute('KEY')) {
            dictionary.update(element.getAttribute('KEY'), primitive);
        }
    };
    /**
     * Applies line ending styles from attributes head and tail to the annotation dictionary.
     *
     * @private
     * @param {_PdfDictionary} dictionary Destination annotation dictionary.
     * @param {Element} element Source annotation element with head and tail.
     * @returns {void}
     */
    _XfdfDocument.prototype._addLineEndStyle = function (dictionary, element) {
        var beginLineStyle = '';
        if (element.hasAttribute('head')) {
            beginLineStyle = element.getAttribute('head');
        }
        var endLineStyle = '';
        if (element.hasAttribute('tail')) {
            endLineStyle = element.getAttribute('tail');
        }
        if (beginLineStyle && beginLineStyle !== '') {
            if (endLineStyle && endLineStyle !== '') {
                var lineEndingStyles = [];
                lineEndingStyles.push(_PdfName.get(beginLineStyle));
                lineEndingStyles.push(_PdfName.get(endLineStyle));
                dictionary.update('LE', lineEndingStyles);
            }
            else {
                dictionary.update('LE', _PdfName.get(beginLineStyle));
            }
        }
        else if (endLineStyle && endLineStyle !== '') {
            dictionary.update('LE', _PdfName.get(endLineStyle));
        }
    };
    return _XfdfDocument;
}(_ExportHelper));
export { _XfdfDocument };
/**
 * Extracts font metadata and encoding details from a font dictionary and provides convenient accessors.
 *
 * @private
 */
var _FontStructure = /** @class */ (function () {
    /**
     * Creates a font structure helper bound to a font dictionary.
     *
     * @private
     *
     * @param {_PdfDictionary} dictionary Source font dictionary.
     */
    function _FontStructure(dictionary) {
        /**
         * Base encoding name when present on the font's encoding dictionary.
         *
         * @private
         */
        this._baseFontEncoding = '';
        this._dictionary = dictionary;
        this._fontType = this._dictionary.get('Subtype').name;
    }
    Object.defineProperty(_FontStructure.prototype, "differencesDictionary", {
        get: function () {
            if (!this._differencesDictionary) {
                this._differencesDictionary = this._getDifferencesDictionary();
            }
            return this._differencesDictionary;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_FontStructure.prototype, "baseFontEncoding", {
        get: function () {
            return this._baseFontEncoding;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_FontStructure.prototype, "fontEncoding", {
        get: function () {
            if (!this._fontEncoding) {
                this._fontEncoding = this._getFontEncoding();
            }
            return this._fontEncoding;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(_FontStructure.prototype, "fontName", {
        get: function () {
            if (!this._fontName) {
                this._fontName = this._getFontName();
            }
            return this._fontName;
        },
        enumerable: true,
        configurable: true
    });
    /**
     * Resolves the font encoding from the font dictionary and normalizes identity encodings.
     *
     * @private
     * @returns {string} Resolved encoding name.
     */
    _FontStructure.prototype._getFontEncoding = function () {
        var encoding = '';
        if (this._dictionary !== null && typeof this._dictionary !== 'undefined' && this._dictionary.has('Encoding')) {
            var baseFont = this._dictionary.get('Encoding'); // eslint-disable-line
            if (baseFont instanceof _PdfName) {
                encoding = baseFont.name;
            }
            else if (baseFont instanceof _PdfDictionary) {
                if (baseFont.has('BaseEncoding')) {
                    var baseFontEncoding = baseFont.get('BaseEncoding');
                    if (baseFontEncoding && baseFontEncoding instanceof _PdfName) {
                        this._baseFontEncoding = baseFontEncoding.name;
                    }
                }
                if (baseFont.has('Type')) {
                    var fontEncoding = baseFont.get('Type');
                    if (fontEncoding !== null && typeof fontEncoding !== 'undefined') {
                        encoding = fontEncoding.name;
                    }
                }
            }
        }
        if (encoding.toString() === 'identity#2dh' || encoding === 'CMap') {
            encoding = 'Identity-H';
        }
        return encoding;
    };
    /**
     * Builds a differences dictionary mapping character codes to characters using the font encoding.
     *
     * @private
     * @returns {Map<string, string>} Differences dictionary.
     */
    _FontStructure.prototype._getDifferencesDictionary = function () {
        var _this = this;
        var result = new Map();
        if (this._dictionary !== null && typeof this._dictionary !== 'undefined' && this._dictionary.has('Encoding')) {
            var encoding = this._dictionary.get('Encoding');
            if (encoding !== null &&
                typeof encoding !== 'undefined' &&
                encoding instanceof _PdfDictionary &&
                encoding.has('Differences')) {
                var differences = encoding.getArray('Differences'); // eslint-disable-line
                var count_1 = 0;
                if (differences !== null && typeof differences !== 'undefined') {
                    differences.forEach(function (item) {
                        var text = '';
                        if (typeof item === 'number') {
                            text = item.toString();
                            count_1 = Number(text);
                        }
                        else if (item instanceof _PdfName) {
                            text = item.name;
                            if (_this._fontType === 'Type1' && text === '.notdef') {
                                text = ' ';
                                result.set(count_1.toString(), _getLatinCharacter(text));
                            }
                            else {
                                text = _getLatinCharacter(text);
                                text = _getSpecialCharacter(text);
                                if (!result.has(count_1.toString())) {
                                    result.set(count_1.toString(), _getLatinCharacter(text));
                                }
                                count_1++;
                            }
                        }
                    });
                }
            }
        }
        return result;
    };
    /**
     * Extracts and normalizes the font name by removing subsets styles and hex sequences.
     *
     * @private
     * @returns {string} Normalized font name.
     */
    _FontStructure.prototype._getFontName = function () {
        var fontName = '';
        if (this._dictionary !== null && typeof this._dictionary !== 'undefined' && this._dictionary.has('BaseFont')) {
            var baseFont = this._dictionary.get('BaseFont');
            var font = baseFont.name;
            if (font.indexOf('#20') !== -1 && font.indexOf('+') === -1) {
                var index = font.lastIndexOf('#20');
                font = font.substring(0, index);
                font += '+';
            }
            if (baseFont.name.indexOf('+') !== -1) {
                fontName = baseFont.name.split('+')[1];
            }
            else {
                fontName = baseFont.name;
            }
            if (fontName.indexOf('-') !== -1) {
                fontName = fontName.split('-')[0];
            }
            else if (fontName.indexOf(',') !== -1) {
                fontName = fontName.split(',')[0];
            }
            if (fontName.indexOf('MT') !== -1) {
                fontName = fontName.replace('MT', '');
            }
            if (fontName.indexOf('#20') !== -1) {
                fontName = fontName.replace('#20', ' ');
            }
            if (fontName.indexOf('#') !== -1) {
                fontName = this._decodeHexFontName(fontName);
            }
        }
        return fontName;
    };
    /**
     * Decodes hex escape sequences in a font name into unicode characters.
     *
     * @private
     * @param {string} fontName Encoded font name containing hash based hex sequences.
     * @returns {string} Decoded font name.
     */
    _FontStructure.prototype._decodeHexFontName = function (fontName) {
        var result = fontName;
        for (var i = 0; i < fontName.length; i++) {
            if (fontName[i] === '#') {
                var hexValue = fontName[i + 1] + fontName[i + 2];
                var value = Number.parseInt(hexValue, 16);
                if (value !== 0) {
                    result = result.replace("#" + hexValue, String.fromCharCode(value));
                    i += 2;
                }
                if (result.indexOf('#') === -1) {
                    break;
                }
            }
        }
        return result;
    };
    return _FontStructure;
}());
export { _FontStructure };