blob: c70d31b26929b269f6fc21c4ecb0b876b8f28e63 [file] [log] [blame]
// Copyright 2016 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "xfa/fxfa/parser/cxfa_node.h"
#include <algorithm>
#include <map>
#include <memory>
#include <set>
#include <utility>
#include <vector>
#include "core/fxcrt/autorestorer.h"
#include "core/fxcrt/cfx_decimal.h"
#include "core/fxcrt/cfx_readonlymemorystream.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/locale_iface.h"
#include "core/fxcrt/xml/cfx_xmldocument.h"
#include "core/fxcrt/xml/cfx_xmlelement.h"
#include "core/fxcrt/xml/cfx_xmlnode.h"
#include "core/fxcrt/xml/cfx_xmltext.h"
#include "core/fxge/dib/cfx_dibitmap.h"
#include "fxjs/xfa/cfxjse_engine.h"
#include "fxjs/xfa/cfxjse_value.h"
#include "fxjs/xfa/cjx_node.h"
#include "third_party/base/compiler_specific.h"
#include "third_party/base/logging.h"
#include "third_party/base/ptr_util.h"
#include "third_party/base/span.h"
#include "third_party/base/stl_util.h"
#include "xfa/fde/cfde_textout.h"
#include "xfa/fgas/font/cfgas_fontmgr.h"
#include "xfa/fgas/font/cfgas_gefont.h"
#include "xfa/fxfa/cxfa_eventparam.h"
#include "xfa/fxfa/cxfa_ffapp.h"
#include "xfa/fxfa/cxfa_ffdocview.h"
#include "xfa/fxfa/cxfa_ffnotify.h"
#include "xfa/fxfa/cxfa_ffwidget.h"
#include "xfa/fxfa/cxfa_fontmgr.h"
#include "xfa/fxfa/cxfa_textprovider.h"
#include "xfa/fxfa/parser/cxfa_accessiblecontent.h"
#include "xfa/fxfa/parser/cxfa_acrobat.h"
#include "xfa/fxfa/parser/cxfa_acrobat7.h"
#include "xfa/fxfa/parser/cxfa_adbe_jsconsole.h"
#include "xfa/fxfa/parser/cxfa_adbe_jsdebugger.h"
#include "xfa/fxfa/parser/cxfa_addsilentprint.h"
#include "xfa/fxfa/parser/cxfa_addviewerpreferences.h"
#include "xfa/fxfa/parser/cxfa_adjustdata.h"
#include "xfa/fxfa/parser/cxfa_adobeextensionlevel.h"
#include "xfa/fxfa/parser/cxfa_agent.h"
#include "xfa/fxfa/parser/cxfa_alwaysembed.h"
#include "xfa/fxfa/parser/cxfa_amd.h"
#include "xfa/fxfa/parser/cxfa_appearancefilter.h"
#include "xfa/fxfa/parser/cxfa_arc.h"
#include "xfa/fxfa/parser/cxfa_area.h"
#include "xfa/fxfa/parser/cxfa_arraynodelist.h"
#include "xfa/fxfa/parser/cxfa_assist.h"
#include "xfa/fxfa/parser/cxfa_attachnodelist.h"
#include "xfa/fxfa/parser/cxfa_attributes.h"
#include "xfa/fxfa/parser/cxfa_autosave.h"
#include "xfa/fxfa/parser/cxfa_barcode.h"
#include "xfa/fxfa/parser/cxfa_base.h"
#include "xfa/fxfa/parser/cxfa_batchoutput.h"
#include "xfa/fxfa/parser/cxfa_behavioroverride.h"
#include "xfa/fxfa/parser/cxfa_bind.h"
#include "xfa/fxfa/parser/cxfa_binditems.h"
#include "xfa/fxfa/parser/cxfa_bookend.h"
#include "xfa/fxfa/parser/cxfa_boolean.h"
#include "xfa/fxfa/parser/cxfa_border.h"
#include "xfa/fxfa/parser/cxfa_break.h"
#include "xfa/fxfa/parser/cxfa_breakafter.h"
#include "xfa/fxfa/parser/cxfa_breakbefore.h"
#include "xfa/fxfa/parser/cxfa_button.h"
#include "xfa/fxfa/parser/cxfa_cache.h"
#include "xfa/fxfa/parser/cxfa_calculate.h"
#include "xfa/fxfa/parser/cxfa_calendarsymbols.h"
#include "xfa/fxfa/parser/cxfa_caption.h"
#include "xfa/fxfa/parser/cxfa_certificate.h"
#include "xfa/fxfa/parser/cxfa_certificates.h"
#include "xfa/fxfa/parser/cxfa_change.h"
#include "xfa/fxfa/parser/cxfa_checkbutton.h"
#include "xfa/fxfa/parser/cxfa_choicelist.h"
#include "xfa/fxfa/parser/cxfa_color.h"
#include "xfa/fxfa/parser/cxfa_comb.h"
#include "xfa/fxfa/parser/cxfa_command.h"
#include "xfa/fxfa/parser/cxfa_common.h"
#include "xfa/fxfa/parser/cxfa_compress.h"
#include "xfa/fxfa/parser/cxfa_compression.h"
#include "xfa/fxfa/parser/cxfa_compresslogicalstructure.h"
#include "xfa/fxfa/parser/cxfa_compressobjectstream.h"
#include "xfa/fxfa/parser/cxfa_config.h"
#include "xfa/fxfa/parser/cxfa_conformance.h"
#include "xfa/fxfa/parser/cxfa_connect.h"
#include "xfa/fxfa/parser/cxfa_connectionset.h"
#include "xfa/fxfa/parser/cxfa_connectstring.h"
#include "xfa/fxfa/parser/cxfa_contentarea.h"
#include "xfa/fxfa/parser/cxfa_contentcopy.h"
#include "xfa/fxfa/parser/cxfa_copies.h"
#include "xfa/fxfa/parser/cxfa_corner.h"
#include "xfa/fxfa/parser/cxfa_creator.h"
#include "xfa/fxfa/parser/cxfa_currencysymbol.h"
#include "xfa/fxfa/parser/cxfa_currencysymbols.h"
#include "xfa/fxfa/parser/cxfa_currentpage.h"
#include "xfa/fxfa/parser/cxfa_data.h"
#include "xfa/fxfa/parser/cxfa_datagroup.h"
#include "xfa/fxfa/parser/cxfa_datamodel.h"
#include "xfa/fxfa/parser/cxfa_datavalue.h"
#include "xfa/fxfa/parser/cxfa_date.h"
#include "xfa/fxfa/parser/cxfa_datepattern.h"
#include "xfa/fxfa/parser/cxfa_datepatterns.h"
#include "xfa/fxfa/parser/cxfa_datetime.h"
#include "xfa/fxfa/parser/cxfa_datetimeedit.h"
#include "xfa/fxfa/parser/cxfa_datetimesymbols.h"
#include "xfa/fxfa/parser/cxfa_day.h"
#include "xfa/fxfa/parser/cxfa_daynames.h"
#include "xfa/fxfa/parser/cxfa_debug.h"
#include "xfa/fxfa/parser/cxfa_decimal.h"
#include "xfa/fxfa/parser/cxfa_defaulttypeface.h"
#include "xfa/fxfa/parser/cxfa_defaultui.h"
#include "xfa/fxfa/parser/cxfa_delete.h"
#include "xfa/fxfa/parser/cxfa_delta.h"
#include "xfa/fxfa/parser/cxfa_deltas.h"
#include "xfa/fxfa/parser/cxfa_desc.h"
#include "xfa/fxfa/parser/cxfa_destination.h"
#include "xfa/fxfa/parser/cxfa_digestmethod.h"
#include "xfa/fxfa/parser/cxfa_digestmethods.h"
#include "xfa/fxfa/parser/cxfa_document.h"
#include "xfa/fxfa/parser/cxfa_document_parser.h"
#include "xfa/fxfa/parser/cxfa_documentassembly.h"
#include "xfa/fxfa/parser/cxfa_draw.h"
#include "xfa/fxfa/parser/cxfa_driver.h"
#include "xfa/fxfa/parser/cxfa_dsigdata.h"
#include "xfa/fxfa/parser/cxfa_duplexoption.h"
#include "xfa/fxfa/parser/cxfa_dynamicrender.h"
#include "xfa/fxfa/parser/cxfa_edge.h"
#include "xfa/fxfa/parser/cxfa_effectiveinputpolicy.h"
#include "xfa/fxfa/parser/cxfa_effectiveoutputpolicy.h"
#include "xfa/fxfa/parser/cxfa_embed.h"
#include "xfa/fxfa/parser/cxfa_encoding.h"
#include "xfa/fxfa/parser/cxfa_encodings.h"
#include "xfa/fxfa/parser/cxfa_encrypt.h"
#include "xfa/fxfa/parser/cxfa_encryption.h"
#include "xfa/fxfa/parser/cxfa_encryptionlevel.h"
#include "xfa/fxfa/parser/cxfa_encryptionmethod.h"
#include "xfa/fxfa/parser/cxfa_encryptionmethods.h"
#include "xfa/fxfa/parser/cxfa_enforce.h"
#include "xfa/fxfa/parser/cxfa_equate.h"
#include "xfa/fxfa/parser/cxfa_equaterange.h"
#include "xfa/fxfa/parser/cxfa_era.h"
#include "xfa/fxfa/parser/cxfa_eranames.h"
#include "xfa/fxfa/parser/cxfa_event.h"
#include "xfa/fxfa/parser/cxfa_exclgroup.h"
#include "xfa/fxfa/parser/cxfa_exclude.h"
#include "xfa/fxfa/parser/cxfa_excludens.h"
#include "xfa/fxfa/parser/cxfa_exdata.h"
#include "xfa/fxfa/parser/cxfa_execute.h"
#include "xfa/fxfa/parser/cxfa_exobject.h"
#include "xfa/fxfa/parser/cxfa_extras.h"
#include "xfa/fxfa/parser/cxfa_field.h"
#include "xfa/fxfa/parser/cxfa_fill.h"
#include "xfa/fxfa/parser/cxfa_filter.h"
#include "xfa/fxfa/parser/cxfa_fliplabel.h"
#include "xfa/fxfa/parser/cxfa_float.h"
#include "xfa/fxfa/parser/cxfa_font.h"
#include "xfa/fxfa/parser/cxfa_fontinfo.h"
#include "xfa/fxfa/parser/cxfa_form.h"
#include "xfa/fxfa/parser/cxfa_format.h"
#include "xfa/fxfa/parser/cxfa_formfieldfilling.h"
#include "xfa/fxfa/parser/cxfa_groupparent.h"
#include "xfa/fxfa/parser/cxfa_handler.h"
#include "xfa/fxfa/parser/cxfa_hyphenation.h"
#include "xfa/fxfa/parser/cxfa_ifempty.h"
#include "xfa/fxfa/parser/cxfa_image.h"
#include "xfa/fxfa/parser/cxfa_imageedit.h"
#include "xfa/fxfa/parser/cxfa_includexdpcontent.h"
#include "xfa/fxfa/parser/cxfa_incrementalload.h"
#include "xfa/fxfa/parser/cxfa_incrementalmerge.h"
#include "xfa/fxfa/parser/cxfa_insert.h"
#include "xfa/fxfa/parser/cxfa_instancemanager.h"
#include "xfa/fxfa/parser/cxfa_integer.h"
#include "xfa/fxfa/parser/cxfa_interactive.h"
#include "xfa/fxfa/parser/cxfa_issuers.h"
#include "xfa/fxfa/parser/cxfa_items.h"
#include "xfa/fxfa/parser/cxfa_jog.h"
#include "xfa/fxfa/parser/cxfa_keep.h"
#include "xfa/fxfa/parser/cxfa_keyusage.h"
#include "xfa/fxfa/parser/cxfa_labelprinter.h"
#include "xfa/fxfa/parser/cxfa_layout.h"
#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
#include "xfa/fxfa/parser/cxfa_level.h"
#include "xfa/fxfa/parser/cxfa_line.h"
#include "xfa/fxfa/parser/cxfa_linear.h"
#include "xfa/fxfa/parser/cxfa_linearized.h"
#include "xfa/fxfa/parser/cxfa_locale.h"
#include "xfa/fxfa/parser/cxfa_localeset.h"
#include "xfa/fxfa/parser/cxfa_localevalue.h"
#include "xfa/fxfa/parser/cxfa_lockdocument.h"
#include "xfa/fxfa/parser/cxfa_log.h"
#include "xfa/fxfa/parser/cxfa_manifest.h"
#include "xfa/fxfa/parser/cxfa_map.h"
#include "xfa/fxfa/parser/cxfa_margin.h"
#include "xfa/fxfa/parser/cxfa_mdp.h"
#include "xfa/fxfa/parser/cxfa_measurement.h"
#include "xfa/fxfa/parser/cxfa_medium.h"
#include "xfa/fxfa/parser/cxfa_mediuminfo.h"
#include "xfa/fxfa/parser/cxfa_meridiem.h"
#include "xfa/fxfa/parser/cxfa_meridiemnames.h"
#include "xfa/fxfa/parser/cxfa_message.h"
#include "xfa/fxfa/parser/cxfa_messaging.h"
#include "xfa/fxfa/parser/cxfa_mode.h"
#include "xfa/fxfa/parser/cxfa_modifyannots.h"
#include "xfa/fxfa/parser/cxfa_month.h"
#include "xfa/fxfa/parser/cxfa_monthnames.h"
#include "xfa/fxfa/parser/cxfa_msgid.h"
#include "xfa/fxfa/parser/cxfa_nameattr.h"
#include "xfa/fxfa/parser/cxfa_neverembed.h"
#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
#include "xfa/fxfa/parser/cxfa_numberofcopies.h"
#include "xfa/fxfa/parser/cxfa_numberpattern.h"
#include "xfa/fxfa/parser/cxfa_numberpatterns.h"
#include "xfa/fxfa/parser/cxfa_numbersymbol.h"
#include "xfa/fxfa/parser/cxfa_numbersymbols.h"
#include "xfa/fxfa/parser/cxfa_numericedit.h"
#include "xfa/fxfa/parser/cxfa_occur.h"
#include "xfa/fxfa/parser/cxfa_oid.h"
#include "xfa/fxfa/parser/cxfa_oids.h"
#include "xfa/fxfa/parser/cxfa_openaction.h"
#include "xfa/fxfa/parser/cxfa_operation.h"
#include "xfa/fxfa/parser/cxfa_output.h"
#include "xfa/fxfa/parser/cxfa_outputbin.h"
#include "xfa/fxfa/parser/cxfa_outputxsl.h"
#include "xfa/fxfa/parser/cxfa_overflow.h"
#include "xfa/fxfa/parser/cxfa_overprint.h"
#include "xfa/fxfa/parser/cxfa_packet.h"
#include "xfa/fxfa/parser/cxfa_packets.h"
#include "xfa/fxfa/parser/cxfa_pagearea.h"
#include "xfa/fxfa/parser/cxfa_pageoffset.h"
#include "xfa/fxfa/parser/cxfa_pagerange.h"
#include "xfa/fxfa/parser/cxfa_pageset.h"
#include "xfa/fxfa/parser/cxfa_pagination.h"
#include "xfa/fxfa/parser/cxfa_paginationoverride.h"
#include "xfa/fxfa/parser/cxfa_para.h"
#include "xfa/fxfa/parser/cxfa_part.h"
#include "xfa/fxfa/parser/cxfa_password.h"
#include "xfa/fxfa/parser/cxfa_passwordedit.h"
#include "xfa/fxfa/parser/cxfa_pattern.h"
#include "xfa/fxfa/parser/cxfa_pcl.h"
#include "xfa/fxfa/parser/cxfa_pdf.h"
#include "xfa/fxfa/parser/cxfa_pdfa.h"
#include "xfa/fxfa/parser/cxfa_permissions.h"
#include "xfa/fxfa/parser/cxfa_picktraybypdfsize.h"
#include "xfa/fxfa/parser/cxfa_picture.h"
#include "xfa/fxfa/parser/cxfa_plaintextmetadata.h"
#include "xfa/fxfa/parser/cxfa_presence.h"
#include "xfa/fxfa/parser/cxfa_present.h"
#include "xfa/fxfa/parser/cxfa_print.h"
#include "xfa/fxfa/parser/cxfa_printername.h"
#include "xfa/fxfa/parser/cxfa_printhighquality.h"
#include "xfa/fxfa/parser/cxfa_printscaling.h"
#include "xfa/fxfa/parser/cxfa_producer.h"
#include "xfa/fxfa/parser/cxfa_proto.h"
#include "xfa/fxfa/parser/cxfa_ps.h"
#include "xfa/fxfa/parser/cxfa_psmap.h"
#include "xfa/fxfa/parser/cxfa_query.h"
#include "xfa/fxfa/parser/cxfa_radial.h"
#include "xfa/fxfa/parser/cxfa_range.h"
#include "xfa/fxfa/parser/cxfa_reason.h"
#include "xfa/fxfa/parser/cxfa_reasons.h"
#include "xfa/fxfa/parser/cxfa_record.h"
#include "xfa/fxfa/parser/cxfa_recordset.h"
#include "xfa/fxfa/parser/cxfa_rectangle.h"
#include "xfa/fxfa/parser/cxfa_ref.h"
#include "xfa/fxfa/parser/cxfa_relevant.h"
#include "xfa/fxfa/parser/cxfa_rename.h"
#include "xfa/fxfa/parser/cxfa_renderpolicy.h"
#include "xfa/fxfa/parser/cxfa_rootelement.h"
#include "xfa/fxfa/parser/cxfa_runscripts.h"
#include "xfa/fxfa/parser/cxfa_script.h"
#include "xfa/fxfa/parser/cxfa_scriptmodel.h"
#include "xfa/fxfa/parser/cxfa_select.h"
#include "xfa/fxfa/parser/cxfa_setproperty.h"
#include "xfa/fxfa/parser/cxfa_severity.h"
#include "xfa/fxfa/parser/cxfa_sharptext.h"
#include "xfa/fxfa/parser/cxfa_sharpxhtml.h"
#include "xfa/fxfa/parser/cxfa_sharpxml.h"
#include "xfa/fxfa/parser/cxfa_signature.h"
#include "xfa/fxfa/parser/cxfa_signatureproperties.h"
#include "xfa/fxfa/parser/cxfa_signdata.h"
#include "xfa/fxfa/parser/cxfa_signing.h"
#include "xfa/fxfa/parser/cxfa_silentprint.h"
#include "xfa/fxfa/parser/cxfa_soapaction.h"
#include "xfa/fxfa/parser/cxfa_soapaddress.h"
#include "xfa/fxfa/parser/cxfa_solid.h"
#include "xfa/fxfa/parser/cxfa_source.h"
#include "xfa/fxfa/parser/cxfa_sourceset.h"
#include "xfa/fxfa/parser/cxfa_speak.h"
#include "xfa/fxfa/parser/cxfa_staple.h"
#include "xfa/fxfa/parser/cxfa_startnode.h"
#include "xfa/fxfa/parser/cxfa_startpage.h"
#include "xfa/fxfa/parser/cxfa_stipple.h"
#include "xfa/fxfa/parser/cxfa_stroke.h"
#include "xfa/fxfa/parser/cxfa_subform.h"
#include "xfa/fxfa/parser/cxfa_subformset.h"
#include "xfa/fxfa/parser/cxfa_subjectdn.h"
#include "xfa/fxfa/parser/cxfa_subjectdns.h"
#include "xfa/fxfa/parser/cxfa_submit.h"
#include "xfa/fxfa/parser/cxfa_submitformat.h"
#include "xfa/fxfa/parser/cxfa_submiturl.h"
#include "xfa/fxfa/parser/cxfa_subsetbelow.h"
#include "xfa/fxfa/parser/cxfa_suppressbanner.h"
#include "xfa/fxfa/parser/cxfa_tagged.h"
#include "xfa/fxfa/parser/cxfa_template.h"
#include "xfa/fxfa/parser/cxfa_templatecache.h"
#include "xfa/fxfa/parser/cxfa_text.h"
#include "xfa/fxfa/parser/cxfa_textedit.h"
#include "xfa/fxfa/parser/cxfa_threshold.h"
#include "xfa/fxfa/parser/cxfa_time.h"
#include "xfa/fxfa/parser/cxfa_timepattern.h"
#include "xfa/fxfa/parser/cxfa_timepatterns.h"
#include "xfa/fxfa/parser/cxfa_timestamp.h"
#include "xfa/fxfa/parser/cxfa_to.h"
#include "xfa/fxfa/parser/cxfa_tooltip.h"
#include "xfa/fxfa/parser/cxfa_trace.h"
#include "xfa/fxfa/parser/cxfa_transform.h"
#include "xfa/fxfa/parser/cxfa_traversal.h"
#include "xfa/fxfa/parser/cxfa_traverse.h"
#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
#include "xfa/fxfa/parser/cxfa_type.h"
#include "xfa/fxfa/parser/cxfa_typeface.h"
#include "xfa/fxfa/parser/cxfa_typefaces.h"
#include "xfa/fxfa/parser/cxfa_ui.h"
#include "xfa/fxfa/parser/cxfa_update.h"
#include "xfa/fxfa/parser/cxfa_uri.h"
#include "xfa/fxfa/parser/cxfa_user.h"
#include "xfa/fxfa/parser/cxfa_validate.h"
#include "xfa/fxfa/parser/cxfa_validateapprovalsignatures.h"
#include "xfa/fxfa/parser/cxfa_validationmessaging.h"
#include "xfa/fxfa/parser/cxfa_value.h"
#include "xfa/fxfa/parser/cxfa_variables.h"
#include "xfa/fxfa/parser/cxfa_version.h"
#include "xfa/fxfa/parser/cxfa_versioncontrol.h"
#include "xfa/fxfa/parser/cxfa_viewerpreferences.h"
#include "xfa/fxfa/parser/cxfa_webclient.h"
#include "xfa/fxfa/parser/cxfa_whitespace.h"
#include "xfa/fxfa/parser/cxfa_window.h"
#include "xfa/fxfa/parser/cxfa_wsdladdress.h"
#include "xfa/fxfa/parser/cxfa_wsdlconnection.h"
#include "xfa/fxfa/parser/cxfa_xdc.h"
#include "xfa/fxfa/parser/cxfa_xdp.h"
#include "xfa/fxfa/parser/cxfa_xfa.h"
#include "xfa/fxfa/parser/cxfa_xmlconnection.h"
#include "xfa/fxfa/parser/cxfa_xsdconnection.h"
#include "xfa/fxfa/parser/cxfa_xsl.h"
#include "xfa/fxfa/parser/cxfa_zpl.h"
#include "xfa/fxfa/parser/xfa_basic_data.h"
#include "xfa/fxfa/parser/xfa_utils.h"
class CXFA_FieldLayoutData;
class CXFA_ImageEditData;
class CXFA_ImageLayoutData;
class CXFA_TextEditData;
class CXFA_TextLayoutData;
namespace {
constexpr uint8_t kMaxExecuteRecursion = 2;
constexpr uint8_t g_inv_base64[128] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255,
255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255,
};
uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) {
uint8_t* pCP;
int32_t i = 0, j = 0;
if (iLen == 0) {
iLen = strlen((char*)pStr);
}
pCP = FX_Alloc(uint8_t, iLen + 1);
for (; i < iLen; i++) {
if ((pStr[i] & 128) == 0) {
if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') {
pCP[j++] = pStr[i];
}
}
}
pCP[j] = '\0';
return pCP;
}
int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) {
if (!pStr) {
return 0;
}
uint8_t* pBuffer =
XFA_RemoveBase64Whitespace((uint8_t*)pStr, strlen((char*)pStr));
if (!pBuffer) {
return 0;
}
int32_t iLen = strlen((char*)pBuffer);
int32_t i = 0, j = 0;
uint32_t dwLimb = 0;
for (; i + 3 < iLen; i += 4) {
if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' ||
pBuffer[i + 3] == '=') {
if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') {
break;
}
if (pBuffer[i + 2] == '=') {
dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) |
((uint32_t)g_inv_base64[pBuffer[i + 1]]);
pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF;
j++;
} else {
dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) |
((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) |
((uint32_t)g_inv_base64[pBuffer[i + 2]]);
pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF;
pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF;
j += 2;
}
} else {
dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) |
((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) |
((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) |
((uint32_t)g_inv_base64[pBuffer[i + 3]]);
pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff;
pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff;
pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff;
j += 3;
}
}
FX_Free(pBuffer);
return j;
}
FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) {
WideString wsContentType(wsType);
if (wsContentType.EqualsASCIINoCase("image/jpg"))
return FXCODEC_IMAGE_JPG;
#ifdef PDF_ENABLE_XFA_BMP
if (wsContentType.EqualsASCIINoCase("image/bmp"))
return FXCODEC_IMAGE_BMP;
#endif // PDF_ENABLE_XFA_BMP
#ifdef PDF_ENABLE_XFA_GIF
if (wsContentType.EqualsASCIINoCase("image/gif"))
return FXCODEC_IMAGE_GIF;
#endif // PDF_ENABLE_XFA_GIF
#ifdef PDF_ENABLE_XFA_PNG
if (wsContentType.EqualsASCIINoCase("image/png"))
return FXCODEC_IMAGE_PNG;
#endif // PDF_ENABLE_XFA_PNG
#ifdef PDF_ENABLE_XFA_TIFF
if (wsContentType.EqualsASCII("image/tif"))
return FXCODEC_IMAGE_TIFF;
#endif // PDF_ENABLE_XFA_TIFF
return FXCODEC_IMAGE_UNKNOWN;
}
RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc,
CXFA_Image* pImage,
bool& bNameImage,
int32_t& iImageXDpi,
int32_t& iImageYDpi) {
WideString wsHref = pImage->GetHref();
WideString wsImage = pImage->GetContent();
if (wsHref.IsEmpty() && wsImage.IsEmpty())
return nullptr;
FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
std::vector<uint8_t> buffer;
RetainPtr<IFX_SeekableReadStream> pImageFileRead;
if (wsImage.GetLength() > 0) {
XFA_AttributeValue iEncoding = pImage->GetTransferEncoding();
if (iEncoding == XFA_AttributeValue::Base64) {
ByteString bsData = wsImage.ToUTF8();
buffer.resize(bsData.GetLength());
int32_t iRead = XFA_Base64Decode(bsData.c_str(), buffer.data());
if (iRead > 0) {
pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
pdfium::make_span(buffer.data(), iRead));
}
} else {
pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(
wsImage.ToDefANSI().AsRawSpan());
}
} else {
WideString wsURL = wsHref;
if (!(wsURL.Left(7).EqualsASCII("http://") ||
wsURL.Left(6).EqualsASCII("ftp://"))) {
RetainPtr<CFX_DIBitmap> pBitmap =
pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi);
if (pBitmap) {
bNameImage = true;
return pBitmap;
}
}
pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL);
}
if (!pImageFileRead)
return nullptr;
bNameImage = false;
RetainPtr<CFX_DIBitmap> pBitmap =
XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi);
return pBitmap;
}
bool SplitDateTime(const WideString& wsDateTime,
WideString& wsDate,
WideString& wsTime) {
wsDate.clear();
wsTime.clear();
if (wsDateTime.IsEmpty())
return false;
auto nSplitIndex = wsDateTime.Find('T');
if (!nSplitIndex.has_value())
nSplitIndex = wsDateTime.Find(' ');
if (!nSplitIndex.has_value())
return false;
wsDate = wsDateTime.Left(nSplitIndex.value());
if (!wsDate.IsEmpty()) {
if (!std::any_of(wsDate.begin(), wsDate.end(),
[](wchar_t c) { return FXSYS_IsDecimalDigit(c); })) {
return false;
}
}
wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex.value() - 1);
if (!wsTime.IsEmpty()) {
if (!std::any_of(wsTime.begin(), wsTime.end(),
[](wchar_t c) { return FXSYS_IsDecimalDigit(c); })) {
return false;
}
}
return true;
}
std::vector<CXFA_Node*> NodesSortedByDocumentIdx(
const std::set<CXFA_Node*>& rgNodeSet) {
if (rgNodeSet.empty())
return std::vector<CXFA_Node*>();
std::vector<CXFA_Node*> rgNodeArray;
CXFA_Node* pCommonParent = (*rgNodeSet.begin())->GetParent();
for (CXFA_Node* pNode = pCommonParent->GetFirstChild(); pNode;
pNode = pNode->GetNextSibling()) {
if (pdfium::ContainsValue(rgNodeSet, pNode))
rgNodeArray.push_back(pNode);
}
return rgNodeArray;
}
using CXFA_NodeSetPair = std::pair<std::set<CXFA_Node*>, std::set<CXFA_Node*>>;
using CXFA_NodeSetPairMap =
std::map<uint32_t, std::unique_ptr<CXFA_NodeSetPair>>;
using CXFA_NodeSetPairMapMap =
std::map<CXFA_Node*, std::unique_ptr<CXFA_NodeSetPairMap>>;
CXFA_NodeSetPair* NodeSetPairForNode(CXFA_Node* pNode,
CXFA_NodeSetPairMapMap* pMap) {
CXFA_Node* pParentNode = pNode->GetParent();
uint32_t dwNameHash = pNode->GetNameHash();
if (!pParentNode || !dwNameHash)
return nullptr;
if (!(*pMap)[pParentNode])
(*pMap)[pParentNode] = pdfium::MakeUnique<CXFA_NodeSetPairMap>();
CXFA_NodeSetPairMap* pNodeSetPairMap = (*pMap)[pParentNode].get();
if (!(*pNodeSetPairMap)[dwNameHash])
(*pNodeSetPairMap)[dwNameHash] = pdfium::MakeUnique<CXFA_NodeSetPair>();
return (*pNodeSetPairMap)[dwNameHash].get();
}
void ReorderDataNodes(const std::set<CXFA_Node*>& sSet1,
const std::set<CXFA_Node*>& sSet2,
bool bInsertBefore) {
CXFA_NodeSetPairMapMap rgMap;
for (CXFA_Node* pNode : sSet1) {
CXFA_NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap);
if (pNodeSetPair)
pNodeSetPair->first.insert(pNode);
}
for (CXFA_Node* pNode : sSet2) {
CXFA_NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap);
if (pNodeSetPair) {
if (pdfium::ContainsValue(pNodeSetPair->first, pNode))
pNodeSetPair->first.erase(pNode);
else
pNodeSetPair->second.insert(pNode);
}
}
for (const auto& iter1 : rgMap) {
CXFA_NodeSetPairMap* pNodeSetPairMap = iter1.second.get();
if (!pNodeSetPairMap)
continue;
for (const auto& iter2 : *pNodeSetPairMap) {
CXFA_NodeSetPair* pNodeSetPair = iter2.second.get();
if (!pNodeSetPair)
continue;
if (!pNodeSetPair->first.empty() && !pNodeSetPair->second.empty()) {
std::vector<CXFA_Node*> rgNodeArray1 =
NodesSortedByDocumentIdx(pNodeSetPair->first);
std::vector<CXFA_Node*> rgNodeArray2 =
NodesSortedByDocumentIdx(pNodeSetPair->second);
CXFA_Node* pParentNode = nullptr;
CXFA_Node* pBeforeNode = nullptr;
if (bInsertBefore) {
pBeforeNode = rgNodeArray2.front();
pParentNode = pBeforeNode->GetParent();
} else {
CXFA_Node* pLastNode = rgNodeArray2.back();
pParentNode = pLastNode->GetParent();
pBeforeNode = pLastNode->GetNextSibling();
}
for (auto* pCurNode : rgNodeArray1) {
pParentNode->RemoveChild(pCurNode, true);
pParentNode->InsertChild(pCurNode, pBeforeNode);
}
}
}
pNodeSetPairMap->clear();
}
}
float GetEdgeThickness(const std::vector<CXFA_Stroke*>& strokes,
bool b3DStyle,
int32_t nIndex) {
float fThickness = 0.0f;
CXFA_Stroke* stroke = strokes[nIndex * 2 + 1];
if (stroke->IsVisible()) {
if (nIndex == 0)
fThickness += 2.5f;
fThickness += stroke->GetThickness() * (b3DStyle ? 4 : 2);
}
return fThickness;
}
WideString FormatNumStr(const WideString& wsValue, LocaleIface* pLocale) {
if (wsValue.IsEmpty())
return WideString();
WideString wsSrcNum = wsValue;
WideString wsGroupSymbol = pLocale->GetGroupingSymbol();
bool bNeg = false;
if (wsSrcNum[0] == '-') {
bNeg = true;
wsSrcNum.Delete(0, 1);
}
auto dot_index = wsSrcNum.Find('.');
dot_index = !dot_index.has_value() ? wsSrcNum.GetLength() : dot_index;
if (dot_index.value() < 1)
return WideString();
size_t nPos = dot_index.value() % 3;
WideString wsOutput;
for (size_t i = 0; i < dot_index.value(); i++) {
if (i % 3 == nPos && i != 0)
wsOutput += wsGroupSymbol;
wsOutput += wsSrcNum[i];
}
if (dot_index.value() < wsSrcNum.GetLength()) {
wsOutput += pLocale->GetDecimalSymbol();
wsOutput += wsSrcNum.Right(wsSrcNum.GetLength() - dot_index.value() - 1);
}
if (bNeg)
return pLocale->GetMinusSymbol() + wsOutput;
return wsOutput;
}
} // namespace
class CXFA_WidgetLayoutData {
public:
CXFA_WidgetLayoutData() = default;
virtual ~CXFA_WidgetLayoutData() = default;
virtual CXFA_FieldLayoutData* AsFieldLayoutData() { return nullptr; }
virtual CXFA_ImageLayoutData* AsImageLayoutData() { return nullptr; }
virtual CXFA_TextLayoutData* AsTextLayoutData() { return nullptr; }
float m_fWidgetHeight = -1.0f;
};
class CXFA_TextLayoutData final : public CXFA_WidgetLayoutData {
public:
CXFA_TextLayoutData() = default;
~CXFA_TextLayoutData() override = default;
CXFA_TextLayoutData* AsTextLayoutData() override { return this; }
CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout.get(); }
CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider.get(); }
void LoadText(CXFA_FFDoc* doc, CXFA_Node* pNode) {
if (m_pTextLayout)
return;
m_pTextProvider =
pdfium::MakeUnique<CXFA_TextProvider>(pNode, XFA_TEXTPROVIDERTYPE_Text);
m_pTextLayout =
pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pTextProvider.get());
}
private:
std::unique_ptr<CXFA_TextLayout> m_pTextLayout;
std::unique_ptr<CXFA_TextProvider> m_pTextProvider;
};
class CXFA_ImageLayoutData final : public CXFA_WidgetLayoutData {
public:
CXFA_ImageLayoutData() = default;
~CXFA_ImageLayoutData() override = default;
CXFA_ImageLayoutData* AsImageLayoutData() override { return this; }
bool LoadImageData(CXFA_FFDoc* doc, CXFA_Node* pNode) {
if (m_pDIBitmap)
return true;
CXFA_Value* value = pNode->GetFormValueIfExists();
if (!value)
return false;
CXFA_Image* image = value->GetImageIfExists();
if (!image)
return false;
pNode->SetImageImage(XFA_LoadImageData(doc, image, m_bNamedImage,
m_iImageXDpi, m_iImageYDpi));
return !!m_pDIBitmap;
}
bool m_bNamedImage = false;
int32_t m_iImageXDpi = 0;
int32_t m_iImageYDpi = 0;
RetainPtr<CFX_DIBitmap> m_pDIBitmap;
};
class CXFA_FieldLayoutData : public CXFA_WidgetLayoutData {
public:
CXFA_FieldLayoutData() = default;
~CXFA_FieldLayoutData() override = default;
CXFA_FieldLayoutData* AsFieldLayoutData() override { return this; }
virtual CXFA_ImageEditData* AsImageEditData() { return nullptr; }
virtual CXFA_TextEditData* AsTextEditData() { return nullptr; }
bool LoadCaption(CXFA_FFDoc* doc, CXFA_Node* pNode) {
if (m_pCapTextLayout)
return true;
CXFA_Caption* caption = pNode->GetCaptionIfExists();
if (!caption || caption->IsHidden())
return false;
m_pCapTextProvider = pdfium::MakeUnique<CXFA_TextProvider>(
pNode, XFA_TEXTPROVIDERTYPE_Caption);
m_pCapTextLayout =
pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pCapTextProvider.get());
return true;
}
std::unique_ptr<CXFA_TextLayout> m_pCapTextLayout;
std::unique_ptr<CXFA_TextProvider> m_pCapTextProvider;
std::unique_ptr<CFDE_TextOut> m_pTextOut;
std::vector<float> m_FieldSplitArray;
};
class CXFA_TextEditData final : public CXFA_FieldLayoutData {
public:
CXFA_TextEditData() = default;
~CXFA_TextEditData() override = default;
CXFA_TextEditData* AsTextEditData() override { return this; }
};
class CXFA_ImageEditData final : public CXFA_FieldLayoutData {
public:
CXFA_ImageEditData() = default;
~CXFA_ImageEditData() override = default;
CXFA_ImageEditData* AsImageEditData() override { return this; }
bool LoadImageData(CXFA_FFDoc* doc, CXFA_Node* pNode) {
if (m_pDIBitmap)
return true;
CXFA_Value* value = pNode->GetFormValueIfExists();
if (!value)
return false;
CXFA_Image* image = value->GetImageIfExists();
if (!image)
return false;
pNode->SetImageEditImage(XFA_LoadImageData(doc, image, m_bNamedImage,
m_iImageXDpi, m_iImageYDpi));
return !!m_pDIBitmap;
}
bool m_bNamedImage = false;
int32_t m_iImageXDpi = 0;
int32_t m_iImageYDpi = 0;
RetainPtr<CFX_DIBitmap> m_pDIBitmap;
};
CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
XFA_PacketType ePacket,
uint32_t validPackets,
XFA_ObjectType oType,
XFA_Element eType,
const PropertyData* properties,
const AttributeData* attributes,
std::unique_ptr<CJX_Object> js_node)
: CXFA_Object(pDoc, oType, eType, std::move(js_node)),
m_Properties(properties),
m_Attributes(attributes),
m_ValidPackets(validPackets),
m_ePacket(ePacket) {
ASSERT(m_pDocument);
}
CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
XFA_PacketType ePacket,
uint32_t validPackets,
XFA_ObjectType oType,
XFA_Element eType,
const PropertyData* properties,
const AttributeData* attributes)
: CXFA_Node(pDoc,
ePacket,
validPackets,
oType,
eType,
properties,
attributes,
pdfium::MakeUnique<CJX_Node>(this)) {}
CXFA_Node::~CXFA_Node() = default;
CXFA_Node* CXFA_Node::Clone(bool bRecursive) {
CXFA_Node* pClone = m_pDocument->CreateNode(m_ePacket, m_elementType);
if (!pClone)
return nullptr;
JSObject()->MergeAllData(pClone);
pClone->UpdateNameHash();
if (IsNeedSavingXMLNode()) {
CFX_XMLNode* pCloneXML;
if (IsAttributeInXML()) {
WideString wsName = JSObject()
->TryAttribute(XFA_Attribute::Name, false)
.value_or(WideString());
auto* pCloneXMLElement = GetDocument()
->GetNotify()
->GetHDOC()
->GetXMLDocument()
->CreateNode<CFX_XMLElement>(wsName);
WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
if (!wsValue.IsEmpty()) {
auto* text = GetDocument()
->GetNotify()
->GetHDOC()
->GetXMLDocument()
->CreateNode<CFX_XMLText>(wsValue);
pCloneXMLElement->AppendChild(text);
}
pCloneXML = pCloneXMLElement;
pClone->JSObject()->SetEnum(XFA_Attribute::Contains,
XFA_AttributeValue::Unknown, false);
} else {
pCloneXML = xml_node_->Clone(
GetDocument()->GetNotify()->GetHDOC()->GetXMLDocument());
}
pClone->SetXMLMappingNode(pCloneXML);
}
if (bRecursive) {
for (CXFA_Node* pChild = GetFirstChild(); pChild;
pChild = pChild->GetNextSibling()) {
pClone->InsertChild(pChild->Clone(bRecursive), nullptr);
}
}
pClone->SetFlagAndNotify(XFA_NodeFlag_Initialized);
pClone->SetBindingNode(nullptr);
return pClone;
}
CXFA_Node* CXFA_Node::GetNextContainerSibling() const {
for (auto* pNode = next_sibling_; pNode; pNode = pNode->next_sibling_) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetPrevContainerSibling() const {
for (auto* pNode = prev_sibling_; pNode; pNode = pNode->prev_sibling_) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetFirstContainerChild() const {
for (auto* pNode = first_child_; pNode; pNode = pNode->next_sibling_) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetContainerParent() const {
for (auto* pNode = parent_; pNode; pNode = pNode->parent_) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
bool CXFA_Node::IsValidInPacket(XFA_PacketType packet) const {
return !!(m_ValidPackets & (1 << static_cast<uint8_t>(packet)));
}
const CXFA_Node::PropertyData* CXFA_Node::GetPropertyData(
XFA_Element property) const {
if (m_Properties == nullptr)
return nullptr;
for (size_t i = 0;; ++i) {
const PropertyData* data = m_Properties + i;
if (data->property == XFA_Element::Unknown)
break;
if (data->property == property)
return data;
}
return nullptr;
}
bool CXFA_Node::HasProperty(XFA_Element property) const {
return !!GetPropertyData(property);
}
bool CXFA_Node::HasPropertyFlags(XFA_Element property, uint8_t flags) const {
const PropertyData* data = GetPropertyData(property);
return data && !!(data->flags & flags);
}
uint8_t CXFA_Node::PropertyOccuranceCount(XFA_Element property) const {
const PropertyData* data = GetPropertyData(property);
return data ? data->occurance_count : 0;
}
Optional<XFA_Element> CXFA_Node::GetFirstPropertyWithFlag(uint8_t flag) {
if (m_Properties == nullptr)
return {};
for (size_t i = 0;; ++i) {
const PropertyData* data = m_Properties + i;
if (data->property == XFA_Element::Unknown)
break;
if (data->flags & flag)
return {data->property};
}
return {};
}
const CXFA_Node::AttributeData* CXFA_Node::GetAttributeData(
XFA_Attribute attr) const {
if (m_Attributes == nullptr)
return nullptr;
for (size_t i = 0;; ++i) {
const AttributeData* cur_attr = &m_Attributes[i];
if (cur_attr->attribute == XFA_Attribute::Unknown)
break;
if (cur_attr->attribute == attr)
return cur_attr;
}
return nullptr;
}
bool CXFA_Node::HasAttribute(XFA_Attribute attr) const {
return !!GetAttributeData(attr);
}
// Note: This Method assumes that i is a valid index ....
XFA_Attribute CXFA_Node::GetAttribute(size_t i) const {
if (m_Attributes == nullptr)
return XFA_Attribute::Unknown;
return m_Attributes[i].attribute;
}
XFA_AttributeType CXFA_Node::GetAttributeType(XFA_Attribute type) const {
const AttributeData* data = GetAttributeData(type);
return data ? data->type : XFA_AttributeType::CData;
}
std::vector<CXFA_Node*> CXFA_Node::GetNodeList(uint32_t dwTypeFilter,
XFA_Element eTypeFilter) {
if (eTypeFilter != XFA_Element::Unknown) {
std::vector<CXFA_Node*> nodes;
for (CXFA_Node* pChild = first_child_; pChild;
pChild = pChild->next_sibling_) {
if (pChild->GetElementType() == eTypeFilter)
nodes.push_back(pChild);
}
return nodes;
}
if (dwTypeFilter == (XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties)) {
std::vector<CXFA_Node*> nodes;
for (CXFA_Node* pChild = first_child_; pChild;
pChild = pChild->next_sibling_)
nodes.push_back(pChild);
return nodes;
}
if (dwTypeFilter == 0)
return std::vector<CXFA_Node*>();
bool bFilterChildren = !!(dwTypeFilter & XFA_NODEFILTER_Children);
bool bFilterProperties = !!(dwTypeFilter & XFA_NODEFILTER_Properties);
bool bFilterOneOfProperties = !!(dwTypeFilter & XFA_NODEFILTER_OneOfProperty);
std::vector<CXFA_Node*> nodes;
for (CXFA_Node* pChild = first_child_; pChild;
pChild = pChild->next_sibling_) {
if (HasProperty(pChild->GetElementType())) {
if (bFilterProperties) {
nodes.push_back(pChild);
} else if (bFilterOneOfProperties &&
HasPropertyFlags(pChild->GetElementType(),
XFA_PROPERTYFLAG_OneOf)) {
nodes.push_back(pChild);
} else if (bFilterChildren &&
(pChild->GetElementType() == XFA_Element::Variables ||
pChild->GetElementType() == XFA_Element::PageSet)) {
nodes.push_back(pChild);
}
} else if (bFilterChildren) {
nodes.push_back(pChild);
}
}
if (!bFilterOneOfProperties || !nodes.empty())
return nodes;
if (m_Properties == nullptr)
return nodes;
Optional<XFA_Element> property =
GetFirstPropertyWithFlag(XFA_PROPERTYFLAG_DefaultOneOf);
if (!property)
return nodes;
CXFA_Node* pNewNode = m_pDocument->CreateNode(GetPacketType(), *property);
if (pNewNode) {
InsertChild(pNewNode, nullptr);
pNewNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
nodes.push_back(pNewNode);
}
return nodes;
}
CXFA_Node* CXFA_Node::CreateSamePacketNode(XFA_Element eType) {
CXFA_Node* pNode = m_pDocument->CreateNode(m_ePacket, eType);
pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
return pNode;
}
CXFA_Node* CXFA_Node::CloneTemplateToForm(bool bRecursive) {
ASSERT(m_ePacket == XFA_PacketType::Template);
CXFA_Node* pClone =
m_pDocument->CreateNode(XFA_PacketType::Form, m_elementType);
if (!pClone)
return nullptr;
pClone->SetTemplateNode(this);
pClone->UpdateNameHash();
pClone->SetXMLMappingNode(GetXMLMappingNode());
if (bRecursive) {
for (CXFA_Node* pChild = GetFirstChild(); pChild;
pChild = pChild->GetNextSibling()) {
pClone->InsertChild(pChild->CloneTemplateToForm(bRecursive), nullptr);
}
}
pClone->SetFlagAndNotify(XFA_NodeFlag_Initialized);
return pClone;
}
CXFA_Node* CXFA_Node::GetTemplateNodeIfExists() const {
return m_pAuxNode;
}
void CXFA_Node::SetTemplateNode(CXFA_Node* pTemplateNode) {
m_pAuxNode = pTemplateNode;
}
CXFA_Node* CXFA_Node::GetBindData() {
ASSERT(GetPacketType() == XFA_PacketType::Form);
return GetBindingNode();
}
int32_t CXFA_Node::AddBindItem(CXFA_Node* pFormNode) {
ASSERT(pFormNode);
if (BindsFormItems()) {
bool found = false;
for (auto* v : binding_nodes_) {
if (v == pFormNode) {
found = true;
break;
}
}
if (!found)
binding_nodes_.emplace_back(pFormNode);
return pdfium::CollectionSize<int32_t>(binding_nodes_);
}
CXFA_Node* pOldFormItem = GetBindingNode();
if (!pOldFormItem) {
SetBindingNode(pFormNode);
return 1;
}
if (pOldFormItem == pFormNode)
return 1;
std::vector<CXFA_Node*> items;
items.push_back(pOldFormItem);
items.push_back(pFormNode);
binding_nodes_ = std::move(items);
m_uNodeFlags |= XFA_NodeFlag_BindFormItems;
return 2;
}
int32_t CXFA_Node::RemoveBindItem(CXFA_Node* pFormNode) {
if (BindsFormItems()) {
auto it =
std::find(binding_nodes_.begin(), binding_nodes_.end(), pFormNode);
if (it != binding_nodes_.end())
binding_nodes_.erase(it);
if (binding_nodes_.size() == 1) {
m_uNodeFlags &= ~XFA_NodeFlag_BindFormItems;
return 1;
}
return pdfium::CollectionSize<int32_t>(binding_nodes_);
}
CXFA_Node* pOldFormItem = GetBindingNode();
if (pOldFormItem != pFormNode)
return pOldFormItem ? 1 : 0;
SetBindingNode(nullptr);
return 0;
}
bool CXFA_Node::HasBindItem() {
return GetPacketType() == XFA_PacketType::Datasets && GetBindingNode();
}
CXFA_Node* CXFA_Node::GetContainerNode() {
if (GetPacketType() != XFA_PacketType::Form)
return nullptr;
XFA_Element eType = GetElementType();
if (eType == XFA_Element::ExclGroup)
return nullptr;
CXFA_Node* pParentNode = GetParent();
if (pParentNode && pParentNode->GetElementType() == XFA_Element::ExclGroup)
return nullptr;
if (eType == XFA_Element::Field) {
if (IsChoiceListMultiSelect())
return nullptr;
WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
if (!wsPicture.IsEmpty())
return this;
CXFA_Node* pDataNode = GetBindData();
if (!pDataNode)
return nullptr;
CXFA_Node* pFieldNode = nullptr;
for (auto* pFormNode : *(pDataNode->GetBindItems())) {
if (!pFormNode || pFormNode->HasRemovedChildren())
continue;
pFieldNode = pFormNode->IsWidgetReady() ? pFormNode : nullptr;
if (pFieldNode)
wsPicture = pFieldNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
if (!wsPicture.IsEmpty())
break;
pFieldNode = nullptr;
}
return pFieldNode;
}
CXFA_Node* pGrandNode = pParentNode ? pParentNode->GetParent() : nullptr;
CXFA_Node* pValueNode =
(pParentNode && pParentNode->GetElementType() == XFA_Element::Value)
? pParentNode
: nullptr;
if (!pValueNode) {
pValueNode =
(pGrandNode && pGrandNode->GetElementType() == XFA_Element::Value)
? pGrandNode
: nullptr;
}
CXFA_Node* pParentOfValueNode =
pValueNode ? pValueNode->GetParent() : nullptr;
return pParentOfValueNode ? pParentOfValueNode->GetContainerNode() : nullptr;
}
LocaleIface* CXFA_Node::GetLocale() {
Optional<WideString> localeName = GetLocaleName();
if (!localeName.has_value())
return nullptr;
if (localeName.value().EqualsASCII("ambient"))
return GetDocument()->GetLocaleMgr()->GetDefLocale();
return GetDocument()->GetLocaleMgr()->GetLocaleByName(localeName.value());
}
Optional<WideString> CXFA_Node::GetLocaleName() {
CXFA_Node* pForm = GetDocument()->GetXFAObject(XFA_HASHCODE_Form)->AsNode();
CXFA_Subform* pTopSubform =
pForm->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
if (!pTopSubform)
return {};
CXFA_Node* pLocaleNode = this;
do {
Optional<WideString> localeName =
pLocaleNode->JSObject()->TryCData(XFA_Attribute::Locale, false);
if (localeName)
return localeName;
pLocaleNode = pLocaleNode->GetParent();
} while (pLocaleNode && pLocaleNode != pTopSubform);
CXFA_Node* pConfig = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
Optional<WideString> localeName = {
GetDocument()->GetLocaleMgr()->GetConfigLocaleName(pConfig)};
if (localeName && !localeName->IsEmpty())
return localeName;
if (pTopSubform) {
localeName =
pTopSubform->JSObject()->TryCData(XFA_Attribute::Locale, false);
if (localeName)
return localeName;
}
LocaleIface* pLocale = GetDocument()->GetLocaleMgr()->GetDefLocale();
if (!pLocale)
return {};
return {pLocale->GetName()};
}
XFA_AttributeValue CXFA_Node::GetIntact() {
CXFA_Keep* pKeep = GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
auto layout = JSObject()->TryEnum(XFA_Attribute::Layout, true);
XFA_AttributeValue eLayoutType =
layout.value_or(XFA_AttributeValue::Position);
if (pKeep) {
Optional<XFA_AttributeValue> intact = GetIntactFromKeep(pKeep, eLayoutType);
if (intact)
return *intact;
}
switch (GetElementType()) {
case XFA_Element::Subform:
switch (eLayoutType) {
case XFA_AttributeValue::Position:
case XFA_AttributeValue::Row:
return XFA_AttributeValue::ContentArea;
default:
return XFA_AttributeValue::None;
}
case XFA_Element::Field: {
CXFA_Node* parent = GetParent();
if (!parent || parent->GetElementType() == XFA_Element::PageArea)
return XFA_AttributeValue::ContentArea;
if (parent->GetIntact() != XFA_AttributeValue::None)
return XFA_AttributeValue::ContentArea;
auto value = parent->JSObject()->TryEnum(XFA_Attribute::Layout, true);
XFA_AttributeValue eParLayout =
value.value_or(XFA_AttributeValue::Position);
if (eParLayout == XFA_AttributeValue::Position ||
eParLayout == XFA_AttributeValue::Row ||
eParLayout == XFA_AttributeValue::Table) {
return XFA_AttributeValue::None;
}
XFA_VERSION version = m_pDocument->GetCurVersionMode();
if (eParLayout == XFA_AttributeValue::Tb && version < XFA_VERSION_208) {
Optional<CXFA_Measurement> measureH =
JSObject()->TryMeasure(XFA_Attribute::H, false);
if (measureH)
return XFA_AttributeValue::ContentArea;
}
return XFA_AttributeValue::None;
}
case XFA_Element::Draw:
return XFA_AttributeValue::ContentArea;
default:
return XFA_AttributeValue::None;
}
}
CXFA_Node* CXFA_Node::GetDataDescriptionNode() {
if (m_ePacket == XFA_PacketType::Datasets)
return m_pAuxNode;
return nullptr;
}
void CXFA_Node::SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode) {
ASSERT(m_ePacket == XFA_PacketType::Datasets);
m_pAuxNode = pDataDescriptionNode;
}
CXFA_Node* CXFA_Node::GetModelNode() {
switch (GetPacketType()) {
case XFA_PacketType::Xdp:
return m_pDocument->GetRoot();
case XFA_PacketType::Config:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Config));
case XFA_PacketType::Template:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Template));
case XFA_PacketType::Form:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Form));
case XFA_PacketType::Datasets:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Datasets));
case XFA_PacketType::LocaleSet:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_LocaleSet));
case XFA_PacketType::ConnectionSet:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_ConnectionSet));
case XFA_PacketType::SourceSet:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_SourceSet));
case XFA_PacketType::Xdc:
return ToNode(m_pDocument->GetXFAObject(XFA_HASHCODE_Xdc));
default:
return this;
}
}
size_t CXFA_Node::CountChildren(XFA_Element eType, bool bOnlyChild) {
size_t count = 0;
for (CXFA_Node* pNode = first_child_; pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown)
continue;
if (bOnlyChild && HasProperty(pNode->GetElementType()))
continue;
++count;
}
return count;
}
CXFA_Node* CXFA_Node::GetChildInternal(size_t index,
XFA_Element eType,
bool bOnlyChild) {
size_t count = 0;
for (CXFA_Node* pNode = first_child_; pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetElementType() != eType && eType != XFA_Element::Unknown)
continue;
if (bOnlyChild && HasProperty(pNode->GetElementType()))
continue;
if (count == index)
return pNode;
++count;
}
return nullptr;
}
void CXFA_Node::InsertChild(int32_t index, CXFA_Node* pNode) {
if (!pNode || pNode->parent_ != nullptr) {
PDFIUM_IMMEDIATE_CRASH();
}
pNode->parent_ = this;
pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren);
if (!first_child_) {
ASSERT(!last_child_);
pNode->prev_sibling_ = nullptr;
pNode->next_sibling_ = nullptr;
first_child_ = pNode;
last_child_ = pNode;
index = 0;
} else if (index == 0) {
pNode->prev_sibling_ = nullptr;
pNode->next_sibling_ = first_child_;
first_child_->prev_sibling_ = pNode;
first_child_ = pNode;
} else if (index < 0) {
pNode->prev_sibling_ = last_child_;
pNode->next_sibling_ = nullptr;
last_child_->next_sibling_ = pNode;
last_child_ = pNode;
} else {
CXFA_Node* pPrev = first_child_;
int32_t count = 0;
while (++count < index && pPrev->next_sibling_)
pPrev = pPrev->next_sibling_;
pNode->prev_sibling_ = pPrev;
pNode->next_sibling_ = pPrev->next_sibling_;
if (pPrev->next_sibling_)
pPrev->next_sibling_->prev_sibling_ = pNode;
pPrev->next_sibling_ = pNode;
// Move the last child pointer if needed.
if (pPrev == last_child_)
last_child_ = pNode;
index = count;
}
CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
if (pNotify)
pNotify->OnChildAdded(this);
if (!IsNeedSavingXMLNode() || !pNode->xml_node_)
return;
ASSERT(!pNode->xml_node_->GetParent());
xml_node_->InsertChildNode(pNode->xml_node_.Get(), index);
}
void CXFA_Node::InsertChild(CXFA_Node* pNode, CXFA_Node* pBeforeNode) {
if (pBeforeNode && pBeforeNode->parent_ != this) {
PDFIUM_IMMEDIATE_CRASH();
}
int32_t index = -1;
if (!first_child_ || pBeforeNode == first_child_) {
index = 0;
} else if (!pBeforeNode) {
index = -1;
} else {
index = 0;
CXFA_Node* prev = first_child_;
while (prev && prev != pBeforeNode) {
prev = prev->next_sibling_;
++index;
}
}
InsertChild(index, pNode);
}
void CXFA_Node::RemoveChild(CXFA_Node* pNode, bool bNotify) {
if (!pNode || pNode->parent_ != this) {
PDFIUM_IMMEDIATE_CRASH();
}
pNode->SetFlag(XFA_NodeFlag_HasRemovedChildren);
if (first_child_ == pNode && last_child_ == pNode) {
first_child_ = nullptr;
last_child_ = nullptr;
} else if (first_child_ == pNode) {
first_child_ = pNode->next_sibling_;
first_child_->prev_sibling_ = nullptr;
} else if (last_child_ == pNode) {
last_child_ = pNode->prev_sibling_;
last_child_->next_sibling_ = nullptr;
} else {
CXFA_Node* pPrev = pNode->prev_sibling_;
pPrev->next_sibling_ = pNode->next_sibling_;
pPrev->next_sibling_->prev_sibling_ = pPrev;
}
pNode->next_sibling_ = nullptr;
pNode->prev_sibling_ = nullptr;
pNode->parent_ = nullptr;
OnRemoved(bNotify);
if (!IsNeedSavingXMLNode() || !pNode->xml_node_)
return;
if (!pNode->IsAttributeInXML()) {
xml_node_->RemoveChildNode(pNode->xml_node_.Get());
return;
}
ASSERT(pNode->xml_node_.Get() == xml_node_.Get());
CFX_XMLElement* pXMLElement = ToXMLElement(pNode->xml_node_.Get());
if (pXMLElement) {
WideString wsAttributeName =
pNode->JSObject()->GetCData(XFA_Attribute::QualifiedName);
pXMLElement->RemoveAttribute(wsAttributeName);
}
WideString wsName = pNode->JSObject()
->TryAttribute(XFA_Attribute::Name, false)
.value_or(WideString());
auto* pNewXMLElement = GetDocument()
->GetNotify()
->GetHDOC()
->GetXMLDocument()
->CreateNode<CFX_XMLElement>(wsName);
WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
if (!wsValue.IsEmpty()) {
auto* text = GetDocument()
->GetNotify()
->GetHDOC()
->GetXMLDocument()
->CreateNode<CFX_XMLText>(wsValue);
pNewXMLElement->AppendChild(text);
}
pNode->xml_node_ = pNewXMLElement;
pNode->JSObject()->SetEnum(XFA_Attribute::Contains,
XFA_AttributeValue::Unknown, false);
}
CXFA_Node* CXFA_Node::GetFirstChildByName(WideStringView wsName) const {
return GetFirstChildByName(FX_HashCode_GetW(wsName, false));
}
CXFA_Node* CXFA_Node::GetFirstChildByName(uint32_t dwNameHash) const {
for (CXFA_Node* pNode = GetFirstChild(); pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetNameHash() == dwNameHash)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetFirstChildByClassInternal(XFA_Element eType) const {
for (CXFA_Node* pNode = GetFirstChild(); pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetElementType() == eType)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetNextSameNameSibling(uint32_t dwNameHash) const {
for (CXFA_Node* pNode = GetNextSibling(); pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetNameHash() == dwNameHash)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetNextSameNameSiblingInternal(
WideStringView wsNodeName) const {
return GetNextSameNameSibling(FX_HashCode_GetW(wsNodeName, false));
}
CXFA_Node* CXFA_Node::GetNextSameClassSiblingInternal(XFA_Element eType) const {
for (CXFA_Node* pNode = GetNextSibling(); pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetElementType() == eType)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetInstanceMgrOfSubform() {
CXFA_Node* pInstanceMgr = nullptr;
if (m_ePacket == XFA_PacketType::Form) {
CXFA_Node* pParentNode = GetParent();
if (!pParentNode || pParentNode->GetElementType() == XFA_Element::Area)
return pInstanceMgr;
for (CXFA_Node* pNode = GetPrevSibling(); pNode;
pNode = pNode->GetPrevSibling()) {
XFA_Element eType = pNode->GetElementType();
if ((eType == XFA_Element::Subform || eType == XFA_Element::SubformSet) &&
pNode->m_dwNameHash != m_dwNameHash) {
break;
}
if (eType == XFA_Element::InstanceManager) {
WideString wsName = JSObject()->GetCData(XFA_Attribute::Name);
WideString wsInstName =
pNode->JSObject()->GetCData(XFA_Attribute::Name);
if (wsInstName.GetLength() > 0 && wsInstName[0] == '_' &&
wsInstName.Right(wsInstName.GetLength() - 1) == wsName) {
pInstanceMgr = pNode;
}
break;
}
}
}
return pInstanceMgr;
}
CXFA_Occur* CXFA_Node::GetOccurIfExists() {
return GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
}
bool CXFA_Node::HasFlag(XFA_NodeFlag dwFlag) const {
if (m_uNodeFlags & dwFlag)
return true;
if (dwFlag == XFA_NodeFlag_HasRemovedChildren)
return parent_ && parent_->HasFlag(dwFlag);
return false;
}
void CXFA_Node::SetFlagAndNotify(uint32_t dwFlag) {
ASSERT(dwFlag == XFA_NodeFlag_Initialized);
if (!IsInitialized()) {
CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
if (pNotify) {
pNotify->OnNodeReady(this);
}
}
m_uNodeFlags |= dwFlag;
}
void CXFA_Node::SetFlag(uint32_t dwFlag) {
m_uNodeFlags |= dwFlag;
}
void CXFA_Node::ClearFlag(uint32_t dwFlag) {
m_uNodeFlags &= ~dwFlag;
}
bool CXFA_Node::IsAttributeInXML() {
return JSObject()->GetEnum(XFA_Attribute::Contains) ==
XFA_AttributeValue::MetaData;
}
void CXFA_Node::OnRemoved(bool bNotify) {
if (!bNotify)
return;
CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
if (pNotify)
pNotify->OnChildRemoved();
}
void CXFA_Node::UpdateNameHash() {
WideString wsName = JSObject()->GetCData(XFA_Attribute::Name);
m_dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
}
CFX_XMLNode* CXFA_Node::CreateXMLMappingNode() {
if (!xml_node_) {
xml_node_ = GetDocument()
->GetNotify()
->GetHDOC()
->GetXMLDocument()
->CreateNode<CFX_XMLElement>(
JSObject()->GetCData(XFA_Attribute::Name));
}
return xml_node_.Get();
}
bool CXFA_Node::IsNeedSavingXMLNode() {
return xml_node_ && (GetPacketType() == XFA_PacketType::Datasets ||
GetElementType() == XFA_Element::Xfa);
}
CXFA_Node* CXFA_Node::GetItemIfExists(int32_t iIndex) {
int32_t iCount = 0;
uint32_t dwNameHash = 0;
for (CXFA_Node* pNode = GetNextSibling(); pNode;
pNode = pNode->GetNextSibling()) {
XFA_Element eCurType = pNode->GetElementType();
if (eCurType == XFA_Element::InstanceManager)
break;
if ((eCurType != XFA_Element::Subform) &&
(eCurType != XFA_Element::SubformSet)) {
continue;
}
if (iCount == 0) {
WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
wsInstName.Right(wsInstName.GetLength() - 1) != wsName) {
return nullptr;
}
dwNameHash = pNode->GetNameHash();
}
if (dwNameHash != pNode->GetNameHash())
break;
iCount++;
if (iCount > iIndex)
return pNode;
}
return nullptr;
}
int32_t CXFA_Node::GetCount() {
int32_t iCount = 0;
uint32_t dwNameHash = 0;
for (CXFA_Node* pNode = GetNextSibling(); pNode;
pNode = pNode->GetNextSibling()) {
XFA_Element eCurType = pNode->GetElementType();
if (eCurType == XFA_Element::InstanceManager)
break;
if ((eCurType != XFA_Element::Subform) &&
(eCurType != XFA_Element::SubformSet)) {
continue;
}
if (iCount == 0) {
WideString wsName = pNode->JSObject()->GetCData(XFA_Attribute::Name);
WideString wsInstName = JSObject()->GetCData(XFA_Attribute::Name);
if (wsInstName.GetLength() < 1 || wsInstName[0] != '_' ||
wsInstName.Right(wsInstName.GetLength() - 1) != wsName) {
return iCount;
}
dwNameHash = pNode->GetNameHash();
}
if (dwNameHash != pNode->GetNameHash())
break;
iCount++;
}
return iCount;
}
void CXFA_Node::InsertItem(CXFA_Node* pNewInstance,
int32_t iPos,
int32_t iCount,
bool bMoveDataBindingNodes) {
if (iCount < 0)
iCount = GetCount();
if (iPos < 0)
iPos = iCount;
if (iPos == iCount) {
CXFA_Node* item = GetItemIfExists(iCount - 1);
if (!item)
return;
CXFA_Node* pNextSibling =
iCount > 0 ? item->GetNextSibling() : GetNextSibling();
GetParent()->InsertChild(pNewInstance, pNextSibling);
if (bMoveDataBindingNodes) {
std::set<CXFA_Node*> sNew;
std::set<CXFA_Node*> sAfter;
CXFA_NodeIteratorTemplate<CXFA_Node,
CXFA_TraverseStrategy_XFAContainerNode>
sIteratorNew(pNewInstance);
for (CXFA_Node* pNode = sIteratorNew.GetCurrent(); pNode;
pNode = sIteratorNew.MoveToNext()) {
CXFA_Node* pDataNode = pNode->GetBindData();
if (!pDataNode)
continue;
sNew.insert(pDataNode);
}
CXFA_NodeIteratorTemplate<CXFA_Node,
CXFA_TraverseStrategy_XFAContainerNode>
sIteratorAfter(pNextSibling);
for (CXFA_Node* pNode = sIteratorAfter.GetCurrent(); pNode;
pNode = sIteratorAfter.MoveToNext()) {
CXFA_Node* pDataNode = pNode->GetBindData();
if (!pDataNode)
continue;
sAfter.insert(pDataNode);
}
ReorderDataNodes(sNew, sAfter, false);
}
} else {
CXFA_Node* pBeforeInstance = GetItemIfExists(iPos);
if (!pBeforeInstance) {
// TODO(dsinclair): What should happen here?
return;
}
GetParent()->InsertChild(pNewInstance, pBeforeInstance);
if (bMoveDataBindingNodes) {
std::set<CXFA_Node*> sNew;
std::set<CXFA_Node*> sBefore;
CXFA_NodeIteratorTemplate<CXFA_Node,
CXFA_TraverseStrategy_XFAContainerNode>
sIteratorNew(pNewInstance);
for (CXFA_Node* pNode = sIteratorNew.GetCurrent(); pNode;
pNode = sIteratorNew.MoveToNext()) {
CXFA_Node* pDataNode = pNode->GetBindData();
if (!pDataNode)
continue;
sNew.insert(pDataNode);
}
CXFA_NodeIteratorTemplate<CXFA_Node,
CXFA_TraverseStrategy_XFAContainerNode>
sIteratorBefore(pBeforeInstance);
for (CXFA_Node* pNode = sIteratorBefore.GetCurrent(); pNode;
pNode = sIteratorBefore.MoveToNext()) {
CXFA_Node* pDataNode = pNode->GetBindData();
if (!pDataNode)
continue;
sBefore.insert(pDataNode);
}
ReorderDataNodes(sNew, sBefore, true);
}
}
}
void CXFA_Node::RemoveItem(CXFA_Node* pRemoveInstance,
bool bRemoveDataBinding) {
GetParent()->RemoveChild(pRemoveInstance, true);
if (!bRemoveDataBinding)
return;
CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
sIterator(pRemoveInstance);
for (CXFA_Node* pFormNode = sIterator.GetCurrent(); pFormNode;
pFormNode = sIterator.MoveToNext()) {
CXFA_Node* pDataNode = pFormNode->GetBindData();
if (!pDataNode)
continue;
if (pDataNode->RemoveBindItem(pFormNode) == 0) {
if (CXFA_Node* pDataParent = pDataNode->GetParent()) {
pDataParent->RemoveChild(pDataNode, true);
}
}
pFormNode->SetBindingNode(nullptr);
}
}
CXFA_Node* CXFA_Node::CreateInstanceIfPossible(bool bDataMerge) {
CXFA_Document* pDocument = GetDocument();
CXFA_Node* pTemplateNode = GetTemplateNodeIfExists();
if (!pTemplateNode)
return nullptr;
CXFA_Node* pFormParent = GetParent();
CXFA_Node* pDataScope = nullptr;
for (CXFA_Node* pRootBoundNode = pFormParent;
pRootBoundNode && pRootBoundNode->IsContainerNode();
pRootBoundNode = pRootBoundNode->GetParent()) {
pDataScope = pRootBoundNode->GetBindData();
if (pDataScope)
break;
}
if (!pDataScope) {
pDataScope = ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
ASSERT(pDataScope);
}
CXFA_Node* pInstance = pDocument->DataMerge_CopyContainer(
pTemplateNode, pFormParent, pDataScope, true, bDataMerge, true);
if (pInstance) {
pDocument->DataMerge_UpdateBindingRelations(pInstance);
pFormParent->RemoveChild(pInstance, true);
}
return pInstance;
}
Optional<bool> CXFA_Node::GetDefaultBoolean(XFA_Attribute attr) const {
Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Boolean);
if (!value)
return {};
return {!!*value};
}
Optional<int32_t> CXFA_Node::GetDefaultInteger(XFA_Attribute attr) const {
Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Integer);
if (!value)
return {};
return {static_cast<int32_t>(reinterpret_cast<uintptr_t>(*value))};
}
Optional<CXFA_Measurement> CXFA_Node::GetDefaultMeasurement(
XFA_Attribute attr) const {
Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Measure);
if (!value)
return {};
WideString str = WideString(static_cast<const wchar_t*>(*value));
return {CXFA_Measurement(str.AsStringView())};
}
Optional<WideString> CXFA_Node::GetDefaultCData(XFA_Attribute attr) const {
Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::CData);
if (!value)
return {};
return {WideString(static_cast<const wchar_t*>(*value))};
}
Optional<XFA_AttributeValue> CXFA_Node::GetDefaultEnum(
XFA_Attribute attr) const {
Optional<void*> value = GetDefaultValue(attr, XFA_AttributeType::Enum);
if (!value)
return {};
return {static_cast<XFA_AttributeValue>(reinterpret_cast<uintptr_t>(*value))};
}
Optional<void*> CXFA_Node::GetDefaultValue(XFA_Attribute attr,
XFA_AttributeType eType) const {
const AttributeData* data = GetAttributeData(attr);
if (!data)
return {};
if (data->type == eType)
return {data->default_value};
return {};
}
void CXFA_Node::SendAttributeChangeMessage(XFA_Attribute eAttribute,
bool bScriptModify) {
CXFA_LayoutProcessor* pLayoutPro = GetDocument()->GetLayoutProcessor();
if (!pLayoutPro)
return;
CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
if (!pNotify)
return;
if (GetPacketType() != XFA_PacketType::Form) {
pNotify->OnValueChanged(this, eAttribute, this, this);
return;
}
bool bNeedFindContainer = false;
switch (GetElementType()) {
case XFA_Element::Caption:
bNeedFindContainer = true;
pNotify->OnValueChanged(this, eAttribute, this, GetParent());
break;
case XFA_Element::Font:
case XFA_Element::Para: {
bNeedFindContainer = true;
CXFA_Node* pParentNode = GetParent();
if (pParentNode->GetElementType() == XFA_Element::Caption) {
pNotify->OnValueChanged(this, eAttribute, pParentNode,
pParentNode->GetParent());
} else {
pNotify->OnValueChanged(this, eAttribute, this, pParentNode);
}
break;
}
case XFA_Element::Margin: {
bNeedFindContainer = true;
CXFA_Node* pParentNode = GetParent();
XFA_Element eParentType = pParentNode->GetElementType();
if (pParentNode->IsContainerNode()) {
pNotify->OnValueChanged(this, eAttribute, this, pParentNode);
} else if (eParentType == XFA_Element::Caption) {
pNotify->OnValueChanged(this, eAttribute, pParentNode,
pParentNode->GetParent());
} else {
CXFA_Node* pNode = pParentNode->GetParent();
if (pNode && pNode->GetElementType() == XFA_Element::Ui)
pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetParent());
}
break;
}
case XFA_Element::Comb: {
CXFA_Node* pEditNode = GetParent();
XFA_Element eUIType = pEditNode->GetElementType();
if (pEditNode && (eUIType == XFA_Element::DateTimeEdit ||
eUIType == XFA_Element::NumericEdit ||
eUIType == XFA_Element::TextEdit)) {
CXFA_Node* pUINode = pEditNode->GetParent();
if (pUINode) {
pNotify->OnValueChanged(this, eAttribute, pUINode,
pUINode->GetParent());
}
}
break;
}
case XFA_Element::Button:
case XFA_Element::Barcode:
case XFA_Element::ChoiceList:
case XFA_Element::DateTimeEdit:
case XFA_Element::NumericEdit:
case XFA_Element::PasswordEdit:
case XFA_Element::TextEdit: {
CXFA_Node* pUINode = GetParent();
if (pUINode) {
pNotify->OnValueChanged(this, eAttribute, pUINode,
pUINode->GetParent());
}
break;
}
case XFA_Element::CheckButton: {
bNeedFindContainer = true;
CXFA_Node* pUINode = GetParent();
if (pUINode) {
pNotify->OnValueChanged(this, eAttribute, pUINode,
pUINode->GetParent());
}
break;
}
case XFA_Element::Keep:
case XFA_Element::Bookend:
case XFA_Element::Break:
case XFA_Element::BreakAfter:
case XFA_Element::BreakBefore:
case XFA_Element::Overflow:
bNeedFindContainer = true;
break;
case XFA_Element::Area:
case XFA_Element::Draw:
case XFA_Element::ExclGroup:
case XFA_Element::Field:
case XFA_Element::Subform:
case XFA_Element::SubformSet:
pLayoutPro->AddChangedContainer(this);
pNotify->OnValueChanged(this, eAttribute, this, this);
break;
case XFA_Element::Sharptext:
case XFA_Element::Sharpxml:
case XFA_Element::SharpxHTML: {
CXFA_Node* pTextNode = GetParent();
if (!pTextNode)
return;
CXFA_Node* pValueNode = pTextNode->GetParent();
if (!pValueNode)
return;
XFA_Element eType = pValueNode->GetElementType();
if (eType == XFA_Element::Value) {
bNeedFindContainer = true;
CXFA_Node* pNode = pValueNode->GetParent();
if (pNode && pNode->IsContainerNode()) {
if (bScriptModify)
pValueNode = pNode;
pNotify->OnValueChanged(this, eAttribute, pValueNode, pNode);
} else {
pNotify->OnValueChanged(this, eAttribute, pNode, pNode->GetParent());
}
} else {
if (eType == XFA_Element::Items) {
CXFA_Node* pNode = pValueNode->GetParent();
if (pNode && pNode->IsContainerNode()) {
pNotify->OnValueChanged(this, eAttribute, pValueNode, pNode);
}
}
}
break;
}
default:
break;
}
if (!bNeedFindContainer)
return;
CXFA_Node* pParent = this;
while (pParent && !pParent->IsContainerNode())
pParent = pParent->GetParent();
if (pParent)
pLayoutPro->AddChangedContainer(pParent);
}
void CXFA_Node::SyncValue(const WideString& wsValue, bool bNotify) {
WideString wsFormatValue = wsValue;
CXFA_Node* pContainerNode = GetContainerNode();
if (pContainerNode)
wsFormatValue = pContainerNode->GetFormatDataValue(wsValue);
JSObject()->SetContent(wsValue, wsFormatValue, bNotify, false, true);
}
WideString CXFA_Node::GetRawValue() {
return JSObject()->GetContent(false);
}
int32_t CXFA_Node::GetRotate() {
Optional<int32_t> degrees =
JSObject()->TryInteger(XFA_Attribute::Rotate, false);
return degrees ? XFA_MapRotation(*degrees) / 90 * 90 : 0;
}
CXFA_Border* CXFA_Node::GetBorderIfExists() const {
return JSObject()->GetProperty<CXFA_Border>(0, XFA_Element::Border);
}
CXFA_Border* CXFA_Node::GetOrCreateBorderIfPossible() {
return JSObject()->GetOrCreateProperty<CXFA_Border>(0, XFA_Element::Border);
}
CXFA_Caption* CXFA_Node::GetCaptionIfExists() const {
return JSObject()->GetProperty<CXFA_Caption>(0, XFA_Element::Caption);
}
CXFA_Font* CXFA_Node::GetOrCreateFontIfPossible() {
return JSObject()->GetOrCreateProperty<CXFA_Font>(0, XFA_Element::Font);
}
CXFA_Font* CXFA_Node::GetFontIfExists() const {
return JSObject()->GetProperty<CXFA_Font>(0, XFA_Element::Font);
}
float CXFA_Node::GetFontSize() const {
CXFA_Font* font = GetFontIfExists();
float fFontSize = font ? font->GetFontSize() : 10.0f;
return fFontSize < 0.1f ? 10.0f : fFontSize;
}
float CXFA_Node::GetLineHeight() const {
float fLineHeight = 0;
CXFA_Para* para = GetParaIfExists();
if (para)
fLineHeight = para->GetLineHeight();
if (fLineHeight < 1)
fLineHeight = GetFontSize() * 1.2f;
return fLineHeight;
}
FX_ARGB CXFA_Node::GetTextColor() const {
CXFA_Font* font = GetFontIfExists();
return font ? font->GetColor() : 0xFF000000;
}
CXFA_Margin* CXFA_Node::GetMarginIfExists() const {
return JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
}
CXFA_Para* CXFA_Node::GetParaIfExists() const {
return JSObject()->GetProperty<CXFA_Para>(0, XFA_Element::Para);
}
bool CXFA_Node::IsOpenAccess() {
for (auto* pNode = this; pNode; pNode = pNode->GetContainerParent()) {
XFA_AttributeValue iAcc = pNode->JSObject()->GetEnum(XFA_Attribute::Access);
if (iAcc != XFA_AttributeValue::Open)
return false;
}
return true;
}
CXFA_Value* CXFA_Node::GetDefaultValueIfExists() {
CXFA_Node* pTemNode = GetTemplateNodeIfExists();
return pTemNode ? pTemNode->JSObject()->GetProperty<CXFA_Value>(
0, XFA_Element::Value)
: nullptr;
}
CXFA_Value* CXFA_Node::GetFormValueIfExists() const {
return JSObject()->GetProperty<CXFA_Value>(0, XFA_Element::Value);
}
CXFA_Calculate* CXFA_Node::GetCalculateIfExists() const {
return JSObject()->GetProperty<CXFA_Calculate>(0, XFA_Element::Calculate);
}
CXFA_Validate* CXFA_Node::GetValidateIfExists() const {
return JSObject()->GetProperty<CXFA_Validate>(0, XFA_Element::Validate);
}
CXFA_Validate* CXFA_Node::GetOrCreateValidateIfPossible() {
return JSObject()->GetOrCreateProperty<CXFA_Validate>(0,
XFA_Element::Validate);
}
CXFA_Bind* CXFA_Node::GetBindIfExists() const {
return JSObject()->GetProperty<CXFA_Bind>(0, XFA_Element::Bind);
}
Optional<XFA_AttributeValue> CXFA_Node::GetIntactFromKeep(
const CXFA_Keep* pKeep,
XFA_AttributeValue eLayoutType) const {
Optional<XFA_AttributeValue> intact =
pKeep->JSObject()->TryEnum(XFA_Attribute::Intact, false);
if (!intact.has_value())
return {};
if (intact.value() != XFA_AttributeValue::None ||
eLayoutType != XFA_AttributeValue::Row ||
m_pDocument->GetCurVersionMode() >= XFA_VERSION_208) {
return intact;
}
CXFA_Node* pPreviewRow = GetPrevContainerSibling();
if (!pPreviewRow || pPreviewRow->JSObject()->GetEnum(XFA_Attribute::Layout) !=
XFA_AttributeValue::Row) {
return intact;
}
Optional<XFA_AttributeValue> value =
pKeep->JSObject()->TryEnum(XFA_Attribute::Previous, false);
if (value && (*value == XFA_AttributeValue::ContentArea ||
*value == XFA_AttributeValue::PageArea)) {
return XFA_AttributeValue::ContentArea;
}
CXFA_Keep* pNode =
pPreviewRow->GetFirstChildByClass<CXFA_Keep>(XFA_Element::Keep);
if (!pNode)
return intact;
Optional<XFA_AttributeValue> ret =
pNode->JSObject()->TryEnum(XFA_Attribute::Next, false);
if (!ret)
return intact;
return (*ret == XFA_AttributeValue::ContentArea ||
*ret == XFA_AttributeValue::PageArea)
? XFA_AttributeValue::ContentArea
: intact;
}
Optional<float> CXFA_Node::TryWidth() {
return JSObject()->TryMeasureAsFloat(XFA_Attribute::W);
}
Optional<float> CXFA_Node::TryHeight() {
return JSObject()->TryMeasureAsFloat(XFA_Attribute::H);
}
Optional<float> CXFA_Node::TryMinWidth() {
return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinW);
}
Optional<float> CXFA_Node::TryMinHeight() {
return JSObject()->TryMeasureAsFloat(XFA_Attribute::MinH);
}
Optional<float> CXFA_Node::TryMaxWidth() {
return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxW);
}
Optional<float> CXFA_Node::TryMaxHeight() {
return JSObject()->TryMeasureAsFloat(XFA_Attribute::MaxH);
}
CXFA_Node* CXFA_Node::GetExclGroupIfExists() {
CXFA_Node* pExcl = GetParent();
if (!pExcl || pExcl->GetElementType() != XFA_Element::ExclGroup)
return nullptr;
return pExcl;
}
int32_t CXFA_Node::ProcessEvent(CXFA_FFDocView* docView,
XFA_AttributeValue iActivity,
CXFA_EventParam* pEventParam) {
if (GetElementType() == XFA_Element::Draw)
return XFA_EVENTERROR_NotExist;
std::vector<CXFA_Event*> eventArray =
GetEventByActivity(iActivity, pEventParam->m_bIsFormReady);
bool first = true;
int32_t iRet = XFA_EVENTERROR_NotExist;
for (CXFA_Event* event : eventArray) {
int32_t result = ProcessEvent(docView, event, pEventParam);
if (first || result == XFA_EVENTERROR_Success)
iRet = result;
first = false;
}
return iRet;
}
int32_t CXFA_Node::ProcessEvent(CXFA_FFDocView* docView,
CXFA_Event* event,
CXFA_EventParam* pEventParam) {
if (!event)
return XFA_EVENTERROR_NotExist;
switch (event->GetEventType()) {
case XFA_Element::Execute:
break;
case XFA_Element::Script:
return ExecuteScript(docView, event->GetScriptIfExists(), pEventParam);
case XFA_Element::SignData:
break;
case XFA_Element::Submit: {
// TODO(crbug.com/867485): Submit is disabled for now. Fix it and reenable this
// code.
#ifdef PDF_XFA_ELEMENT_SUBMIT_ENABLED
CXFA_Submit* submit = event->GetSubmitIfExists();
if (!submit)
return XFA_EVENTERROR_NotExist;
return docView->GetDoc()->GetDocEnvironment()->Submit(docView->GetDoc(),
submit);
#else
return XFA_EVENTERROR_Disabled;
#endif // PDF_XFA_ELEMENT_SUBMIT_ENABLED
}
default:
break;
}
return XFA_EVENTERROR_NotExist;
}
int32_t CXFA_Node::ProcessCalculate(CXFA_FFDocView* docView) {
if (GetElementType() == XFA_Element::Draw)
return XFA_EVENTERROR_NotExist;
CXFA_Calculate* calc = GetCalculateIfExists();
if (!calc)
return XFA_EVENTERROR_NotExist;
if (IsUserInteractive())
return XFA_EVENTERROR_Disabled;
CXFA_EventParam EventParam;
EventParam.m_eType = XFA_EVENT_Calculate;
int32_t iRet = ExecuteScript(docView, calc->GetScriptIfExists(), &EventParam);
if (iRet != XFA_EVENTERROR_Success)
return iRet;
if (GetRawValue() != EventParam.m_wsResult) {
SetValue(XFA_VALUEPICTURE_Raw, EventParam.m_wsResult);
UpdateUIDisplay(docView, nullptr);
}
return XFA_EVENTERROR_Success;
}
void CXFA_Node::ProcessScriptTestValidate(CXFA_FFDocView* docView,
CXFA_Validate* validate,
int32_t iRet,
bool bRetValue,
bool bVersionFlag) {
if (iRet != XFA_EVENTERROR_Success)
return;
if (bRetValue)
return;
IXFA_AppProvider* pAppProvider =
docView->GetDoc()->GetApp()->GetAppProvider();
if (!pAppProvider)
return;
WideString wsTitle = pAppProvider->GetAppTitle();
WideString wsScriptMsg = validate->GetScriptMessageText();
if (validate->GetScriptTest() == XFA_AttributeValue::Warning) {
if (IsUserInteractive())
return;
if (wsScriptMsg.IsEmpty())
wsScriptMsg = GetValidateMessage(false, bVersionFlag);
if (bVersionFlag) {
pAppProvider->MsgBox(wsScriptMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kWarning),
static_cast<uint32_t>(AlertButton::kOK));
return;
}
if (pAppProvider->MsgBox(wsScriptMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kWarning),
static_cast<uint32_t>(AlertButton::kYesNo)) ==
static_cast<uint32_t>(AlertReturn::kYes)) {
SetFlag(XFA_NodeFlag_UserInteractive);
}
return;
}
if (wsScriptMsg.IsEmpty())
wsScriptMsg = GetValidateMessage(true, bVersionFlag);
pAppProvider->MsgBox(wsScriptMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kError),
static_cast<uint32_t>(AlertButton::kOK));
}
int32_t CXFA_Node::ProcessFormatTestValidate(CXFA_FFDocView* docView,
CXFA_Validate* validate,
bool bVersionFlag) {
WideString wsPicture = validate->GetPicture();
if (wsPicture.IsEmpty())
return XFA_EVENTERROR_NotExist;
WideString wsRawValue = GetRawValue();
if (wsRawValue.IsEmpty())
return XFA_EVENTERROR_Error;
LocaleIface* pLocale = GetLocale();
if (!pLocale)
return XFA_EVENTERROR_NotExist;
CXFA_LocaleValue lcValue = XFA_GetLocaleValue(this);
if (lcValue.ValidateValue(lcValue.GetValue(), wsPicture, pLocale, nullptr))
return XFA_EVENTERROR_Success;
IXFA_AppProvider* pAppProvider =
docView->GetDoc()->GetApp()->GetAppProvider();
if (!pAppProvider)
return XFA_EVENTERROR_NotExist;
WideString wsFormatMsg = validate->GetFormatMessageText();
WideString wsTitle = pAppProvider->GetAppTitle();
if (validate->GetFormatTest() == XFA_AttributeValue::Error) {
if (wsFormatMsg.IsEmpty())
wsFormatMsg = GetValidateMessage(true, bVersionFlag);
pAppProvider->MsgBox(wsFormatMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kError),
static_cast<uint32_t>(AlertButton::kOK));
return XFA_EVENTERROR_Error;
}
if (wsFormatMsg.IsEmpty())
wsFormatMsg = GetValidateMessage(false, bVersionFlag);
if (bVersionFlag) {
pAppProvider->MsgBox(wsFormatMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kWarning),
static_cast<uint32_t>(AlertButton::kOK));
return XFA_EVENTERROR_Error;
}
if (pAppProvider->MsgBox(wsFormatMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kWarning),
static_cast<uint32_t>(AlertButton::kYesNo)) ==
static_cast<uint32_t>(AlertReturn::kYes)) {
SetFlag(XFA_NodeFlag_UserInteractive);
}
return XFA_EVENTERROR_Error;
}
int32_t CXFA_Node::ProcessNullTestValidate(CXFA_FFDocView* docView,
CXFA_Validate* validate,
int32_t iFlags,
bool bVersionFlag) {
if (!GetValue(XFA_VALUEPICTURE_Raw).IsEmpty())
return XFA_EVENTERROR_Success;
if (m_bIsNull && m_bPreNull)
return XFA_EVENTERROR_Success;
XFA_AttributeValue eNullTest = validate->GetNullTest();
WideString wsNullMsg = validate->GetNullMessageText();
if (iFlags & 0x01) {
int32_t iRet = XFA_EVENTERROR_Success;
if (eNullTest != XFA_AttributeValue::Disabled)
iRet = XFA_EVENTERROR_Error;
if (!wsNullMsg.IsEmpty()) {
if (eNullTest != XFA_AttributeValue::Disabled) {
docView->m_arrNullTestMsg.push_back(wsNullMsg);
return XFA_EVENTERROR_Error;
}
return XFA_EVENTERROR_Success;
}
return iRet;
}
if (wsNullMsg.IsEmpty() && bVersionFlag &&
eNullTest != XFA_AttributeValue::Disabled) {
return XFA_EVENTERROR_Error;
}
IXFA_AppProvider* pAppProvider =
docView->GetDoc()->GetApp()->GetAppProvider();
if (!pAppProvider)
return XFA_EVENTERROR_NotExist;
WideString wsCaptionName;
WideString wsTitle = pAppProvider->GetAppTitle();
switch (eNullTest) {
case XFA_AttributeValue::Error: {
if (wsNullMsg.IsEmpty()) {
wsCaptionName = GetValidateCaptionName(bVersionFlag);
wsNullMsg = wsCaptionName + L" cannot be blank.";
}
pAppProvider->MsgBox(wsNullMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kStatus),
static_cast<uint32_t>(AlertButton::kOK));
return XFA_EVENTERROR_Error;
}
case XFA_AttributeValue::Warning: {
if (IsUserInteractive())
return true;
if (wsNullMsg.IsEmpty()) {
wsCaptionName = GetValidateCaptionName(bVersionFlag);
wsNullMsg = wsCaptionName +
L" cannot be blank. To ignore validations for " +
wsCaptionName + L", click Ignore.";
}
if (pAppProvider->MsgBox(wsNullMsg, wsTitle,
static_cast<uint32_t>(AlertIcon::kWarning),
static_cast<uint32_t>(AlertButton::kYesNo)) ==
static_cast<uint32_t>(AlertReturn::kYes)) {
SetFlag(XFA_NodeFlag_UserInteractive);
}
return XFA_EVENTERROR_Error;
}
case XFA_AttributeValue::Disabled:
default:
break;
}
return XFA_EVENTERROR_Success;
}
int32_t CXFA_Node::ProcessValidate(CXFA_FFDocView* docView, int32_t iFlags) {
if (GetElementType() == XFA_Element::Draw)
return XFA_EVENTERROR_NotExist;
CXFA_Validate* validate = GetValidateIfExists();
if (!validate)
return XFA_EVENTERROR_NotExist;
bool bInitDoc = validate->NeedsInitApp();
bool bStatus = docView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End;
int32_t iFormat = 0;
int32_t iRet = XFA_EVENTERROR_NotExist;
CXFA_Script* script = validate->GetScriptIfExists();
bool bRet = false;
bool hasBoolResult = (bInitDoc || bStatus) && GetRawValue().IsEmpty();
if (script) {
CXFA_EventParam eParam;
eParam.m_eType = XFA_EVENT_Validate;
eParam.m_pTarget = this;
std::tie(iRet, bRet) = ExecuteBoolScript(docView, script, &eParam);
}
XFA_VERSION version = docView->GetDoc()->GetXFADoc()->GetCurVersionMode();
bool bVersionFlag = false;
if (version < XFA_VERSION_208)
bVersionFlag = true;
if (bInitDoc) {
validate->ClearFlag(XFA_NodeFlag_NeedsInitApp);
} else {
iFormat = ProcessFormatTestValidate(docView, validate, bVersionFlag);
if (!bVersionFlag) {
bVersionFlag =
docView->GetDoc()->GetXFADoc()->HasFlag(XFA_DOCFLAG_Scripting);
}
iRet |= ProcessNullTestValidate(docView, validate, iFlags, bVersionFlag);
}
if (iFormat != XFA_EVENTERROR_Success && hasBoolResult)
ProcessScriptTestValidate(docView, validate, iRet, bRet, bVersionFlag);
return iRet | iFormat;
}
WideString CXFA_Node::GetValidateCaptionName(bool bVersionFlag) {
WideString wsCaptionName;
if (!bVersionFlag) {
CXFA_Caption* caption = GetCaptionIfExists();
if (caption) {
CXFA_Value* capValue = caption->GetValueIfExists();
if (capValue) {
CXFA_Text* captionText = capValue->GetTextIfExists();
if (captionText)
wsCaptionName