blob: d2d1e63c542fcc3054e40d7fc6ca5bbf7caed699 [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_readonlymemorystream.h"
#include "core/fxcrt/fx_codepage.h"
#include "core/fxcrt/fx_extension.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 "core/fxge/fx_font.h"
#include "fxjs/gc/container_trace.h"
#include "fxjs/xfa/cfxjse_engine.h"
#include "fxjs/xfa/cfxjse_value.h"
#include "fxjs/xfa/cjx_node.h"
#include "third_party/base/check.h"
#include "third_party/base/compiler_specific.h"
#include "third_party/base/notreached.h"
#include "third_party/base/span.h"
#include "third_party/base/stl_util.h"
#include "xfa/fde/cfde_textout.h"
#include "xfa/fgas/crt/cfgas_decimal.h"
#include "xfa/fgas/crt/locale_iface.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_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_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_builder.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_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_traversestrategy_xfanode.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,
};
inline uint8_t GetInvBase64(uint8_t x) {
return (x & 128) == 0 ? g_inv_base64[x] : 255;
}
std::vector<uint8_t, FxAllocAllocator<uint8_t>> XFA_RemoveBase64Whitespace(
pdfium::span<const uint8_t> spStr) {
std::vector<uint8_t, FxAllocAllocator<uint8_t>> result;
result.reserve(spStr.size());
for (uint8_t ch : spStr) {
if (GetInvBase64(ch) != 255 || ch == '=')
result.push_back(ch);
}
return result;
}
std::vector<uint8_t, FxAllocAllocator<uint8_t>> XFA_Base64Decode(
const ByteString& bsStr) {
std::vector<uint8_t, FxAllocAllocator<uint8_t>> result;
if (bsStr.IsEmpty())
return result;
std::vector<uint8_t, FxAllocAllocator<uint8_t>> buffer =
XFA_RemoveBase64Whitespace(bsStr.raw_span());
result.reserve(3 * (buffer.size() / 4));
uint32_t dwLimb = 0;
for (size_t i = 0; i + 3 < buffer.size(); i += 4) {
if (buffer[i] == '=' || buffer[i + 1] == '=' || buffer[i + 2] == '=' ||
buffer[i + 3] == '=') {
if (buffer[i] == '=' || buffer[i + 1] == '=') {
break;
}
if (buffer[i + 2] == '=') {
dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 6) |
((uint32_t)g_inv_base64[buffer[i + 1]]);
result.push_back((uint8_t)(dwLimb >> 4) & 0xFF);
} else {
dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 12) |
((uint32_t)g_inv_base64[buffer[i + 1]] << 6) |
((uint32_t)g_inv_base64[buffer[i + 2]]);
result.push_back((uint8_t)(dwLimb >> 10) & 0xFF);
result.push_back((uint8_t)(dwLimb >> 2) & 0xFF);
}
} else {
dwLimb = ((uint32_t)g_inv_base64[buffer[i]] << 18) |
((uint32_t)g_inv_base64[buffer[i + 1]] << 12) |
((uint32_t)g_inv_base64[buffer[i + 2]] << 6) |
((uint32_t)g_inv_base64[buffer[i + 3]]);
result.push_back((uint8_t)(dwLimb >> 16) & 0xff);
result.push_back((uint8_t)(dwLimb >> 8) & 0xff);
result.push_back((uint8_t)(dwLimb)&0xff);
}
}
return result;
}
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());
ByteString bsData; // Must outlive |pImageFileRead|.
// Must outlive |pImageFileRead|.
std::vector<uint8_t, FxAllocAllocator<uint8_t>> buffer;
RetainPtr<IFX_SeekableReadStream> pImageFileRead;
if (wsImage.GetLength() > 0) {
XFA_AttributeValue iEncoding = pImage->GetTransferEncoding();
if (iEncoding == XFA_AttributeValue::Base64) {
bsData = wsImage.ToUTF8();
buffer = XFA_Base64Decode(bsData);
if (!buffer.empty())
pImageFileRead = pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(buffer);
} else {
bsData = wsImage.ToDefANSI();
pImageFileRead =
pdfium::MakeRetain<CFX_ReadOnlyMemoryStream>(bsData.raw_span());
}
} else {
WideString wsURL = wsHref;
if (!(wsURL.First(7).EqualsASCII("http://") ||
wsURL.First(6).EqualsASCII("ftp://"))) {
RetainPtr<CFX_DIBitmap> pBitmap =
pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi);
if (pBitmap) {
bNameImage = true;
return pBitmap;
}
}
pImageFileRead = pDoc->OpenLinkedFile(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.First(nSplitIndex.value());
if (!wsDate.IsEmpty()) {
if (!std::any_of(wsDate.begin(), wsDate.end(),
[](wchar_t c) { return FXSYS_IsDecimalDigit(c); })) {
return false;
}
}
wsTime = wsDateTime.Last(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;
}
// Stack allocated. Using containers of members would be correct here
// if advanced GC worked with STL.
using NodeSet = std::set<cppgc::Member<CXFA_Node>>;
using NodeSetPair = std::pair<NodeSet, NodeSet>;
using NodeSetPairMap = std::map<uint32_t, NodeSetPair>;
using NodeSetPairMapMap = std::map<CXFA_Node*, NodeSetPairMap>;
using NodeVector = std::vector<cppgc::Member<CXFA_Node>>;
NodeVector NodesSortedByDocumentIdx(const NodeSet& rgNodeSet) {
if (rgNodeSet.empty())
return NodeVector();
NodeVector rgNodeArray;
CXFA_Node* pCommonParent = (*rgNodeSet.begin())->GetParent();
for (CXFA_Node* pNode = pCommonParent->GetFirstChild(); pNode;
pNode = pNode->GetNextSibling()) {
if (pdfium::Contains(rgNodeSet, pNode))
rgNodeArray.push_back(pNode);
}
return rgNodeArray;
}
NodeSetPair* NodeSetPairForNode(CXFA_Node* pNode, NodeSetPairMapMap* pMap) {
CXFA_Node* pParentNode = pNode->GetParent();
uint32_t dwNameHash = pNode->GetNameHash();
if (!pParentNode || !dwNameHash)
return nullptr;
return &((*pMap)[pParentNode][dwNameHash]);
}
void ReorderDataNodes(const NodeSet& sSet1,
const NodeSet& sSet2,
bool bInsertBefore) {
NodeSetPairMapMap rgMap;
for (CXFA_Node* pNode : sSet1) {
NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap);
if (pNodeSetPair)
pNodeSetPair->first.insert(pNode);
}
for (CXFA_Node* pNode : sSet2) {
NodeSetPair* pNodeSetPair = NodeSetPairForNode(pNode, &rgMap);
if (pNodeSetPair) {
if (pdfium::Contains(pNodeSetPair->first, pNode))
pNodeSetPair->first.erase(pNode);
else
pNodeSetPair->second.insert(pNode);
}
}
for (auto& iter1 : rgMap) {
NodeSetPairMap* pNodeSetPairMap = &iter1.second;
for (auto& iter2 : *pNodeSetPairMap) {
NodeSetPair* pNodeSetPair = &iter2.second;
if (!pNodeSetPair->first.empty() && !pNodeSetPair->second.empty()) {
NodeVector rgNodeArray1 = NodesSortedByDocumentIdx(pNodeSetPair->first);
NodeVector 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->RemoveChildAndNotify(pCurNode, true);
pParentNode->InsertChildAndNotify(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.Last(wsSrcNum.GetLength() - dot_index.value() - 1);
}
if (bNeg)
return pLocale->GetMinusSymbol() + wsOutput;
return wsOutput;
}
CXFA_Node* FindFirstSiblingNamedInList(CXFA_Node* parent,
uint32_t dwNameHash,
uint32_t dwFilter);
CXFA_Node* FindFirstSiblingOfClassInList(CXFA_Node* parent,
XFA_Element element,
uint32_t dwFilter);
CXFA_Node* FindFirstSiblingNamed(CXFA_Node* parent, uint32_t dwNameHash) {
CXFA_Node* result = FindFirstSiblingNamedInList(parent, dwNameHash,
XFA_NODEFILTER_Properties);
if (result)
return result;
return FindFirstSiblingNamedInList(parent, dwNameHash,
XFA_NODEFILTER_Children);
}
CXFA_Node* FindFirstSiblingNamedInList(CXFA_Node* parent,
uint32_t dwNameHash,
uint32_t dwFilter) {
for (CXFA_Node* child : parent->GetNodeListWithFilter(dwFilter)) {
if (child->GetNameHash() == dwNameHash)
return child;
CXFA_Node* result = FindFirstSiblingNamed(child, dwNameHash);
if (result)
return result;
}
return nullptr;
}
CXFA_Node* FindFirstSiblingOfClass(CXFA_Node* parent, XFA_Element element) {
CXFA_Node* result =
FindFirstSiblingOfClassInList(parent, element, XFA_NODEFILTER_Properties);
if (result)
return result;
return FindFirstSiblingOfClassInList(parent, element,
XFA_NODEFILTER_Children);
}
CXFA_Node* FindFirstSiblingOfClassInList(CXFA_Node* parent,
XFA_Element element,
uint32_t dwFilter) {
for (CXFA_Node* child : parent->GetNodeListWithFilter(dwFilter)) {
if (child->GetElementType() == element)
return child;
CXFA_Node* result = FindFirstSiblingOfClass(child, element);
if (result)
return result;
}
return nullptr;
}
WideString GetNameExpressionSinglePath(CXFA_Node* pNode) {
const bool bIsProperty = pNode->IsProperty();
const bool bIsClassIndex =
pNode->IsUnnamed() ||
(bIsProperty && pNode->GetElementType() != XFA_Element::PageSet);
const wchar_t* pszFormat;
WideString ws;
if (bIsClassIndex) {
pszFormat = L"#%ls[%zu]";
ws = WideString::FromASCII(pNode->GetClassName());
} else {
pszFormat = L"%ls[%zu]";
ws = pNode->JSObject()->GetCData(XFA_Attribute::Name);
ws.Replace(L".", L"\\.");
}
return WideString::Format(pszFormat, ws.c_str(),
pNode->GetIndex(bIsProperty, bIsClassIndex));
}
void TraverseSiblings(CXFA_Node* parent,
uint32_t dwNameHash,
std::vector<CXFA_Node*>* pSiblings,
bool bIsClassName,
bool bIsFindProperty) {
DCHECK(parent);
DCHECK(pSiblings);
if (bIsFindProperty) {
for (CXFA_Node* child :
parent->GetNodeListWithFilter(XFA_NODEFILTER_Properties)) {
if (bIsClassName) {
if (child->GetClassHashCode() == dwNameHash)
pSiblings->push_back(child);
} else {
if (child->GetNameHash() == dwNameHash) {
if (child->GetElementType() != XFA_Element::PageSet &&
child->GetElementType() != XFA_Element::Extras &&
child->GetElementType() != XFA_Element::Items) {
pSiblings->push_back(child);
}
}
}
if (child->IsUnnamed() &&
child->GetElementType() == XFA_Element::PageSet) {
TraverseSiblings(child, dwNameHash, pSiblings, bIsClassName, false);
}
}
if (!pSiblings->empty())
return;
}
for (CXFA_Node* child :
parent->GetNodeListWithFilter(XFA_NODEFILTER_Children)) {
if (child->GetElementType() == XFA_Element::Variables)
continue;
if (bIsClassName) {
if (child->GetClassHashCode() == dwNameHash)
pSiblings->push_back(child);
} else {
if (child->GetNameHash() == dwNameHash)
pSiblings->push_back(child);
}
if (child->IsTransparent() &&
child->GetElementType() != XFA_Element::PageSet) {
TraverseSiblings(child, dwNameHash, pSiblings, bIsClassName, false);
}
}
}
} // namespace
class CXFA_WidgetLayoutData
: public cppgc::GarbageCollected<CXFA_WidgetLayoutData> {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
virtual ~CXFA_WidgetLayoutData() = default;
virtual void Trace(cppgc::Visitor* visitor) const {}
virtual CXFA_FieldLayoutData* AsFieldLayoutData() { return nullptr; }
virtual CXFA_ImageLayoutData* AsImageLayoutData() { return nullptr; }
virtual CXFA_TextLayoutData* AsTextLayoutData() { return nullptr; }
float m_fWidgetHeight = -1.0f;
protected:
CXFA_WidgetLayoutData() = default;
};
class CXFA_TextLayoutData final : public CXFA_WidgetLayoutData {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
~CXFA_TextLayoutData() override = default;
void Trace(cppgc::Visitor* visitor) const override {
CXFA_WidgetLayoutData::Trace(visitor);
visitor->Trace(m_pTextLayout);
visitor->Trace(m_pTextProvider);
}
CXFA_TextLayoutData* AsTextLayoutData() override { return this; }
CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout; }
CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider; }
void LoadText(CXFA_FFDoc* doc, CXFA_Node* pNode) {
if (m_pTextLayout)
return;
m_pTextProvider = cppgc::MakeGarbageCollected<CXFA_TextProvider>(
doc->GetHeap()->GetAllocationHandle(), pNode,
XFA_TEXTPROVIDERTYPE_Text);
m_pTextLayout = cppgc::MakeGarbageCollected<CXFA_TextLayout>(
doc->GetHeap()->GetAllocationHandle(), doc, m_pTextProvider);
}
private:
CXFA_TextLayoutData() = default;
cppgc::Member<CXFA_TextLayout> m_pTextLayout;
cppgc::Member<CXFA_TextProvider> m_pTextProvider;
};
class CXFA_ImageLayoutData final : public CXFA_WidgetLayoutData {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
~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;
private:
CXFA_ImageLayoutData() = default;
};
class CXFA_FieldLayoutData : public CXFA_WidgetLayoutData {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
~CXFA_FieldLayoutData() override = default;
void Trace(cppgc::Visitor* visitor) const override {
CXFA_WidgetLayoutData::Trace(visitor);
visitor->Trace(m_pCapTextLayout);
visitor->Trace(m_pCapTextProvider);
}
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 = cppgc::MakeGarbageCollected<CXFA_TextProvider>(
doc->GetHeap()->GetAllocationHandle(), pNode,
XFA_TEXTPROVIDERTYPE_Caption);
m_pCapTextLayout = cppgc::MakeGarbageCollected<CXFA_TextLayout>(
doc->GetHeap()->GetAllocationHandle(), doc, m_pCapTextProvider);
return true;
}
cppgc::Member<CXFA_TextLayout> m_pCapTextLayout;
cppgc::Member<CXFA_TextProvider> m_pCapTextProvider;
std::unique_ptr<CFDE_TextOut> m_pTextOut;
std::vector<float> m_FieldSplitArray;
protected:
CXFA_FieldLayoutData() = default;
};
class CXFA_TextEditData final : public CXFA_FieldLayoutData {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
~CXFA_TextEditData() override = default;
CXFA_TextEditData* AsTextEditData() override { return this; }
protected:
CXFA_TextEditData() = default;
};
class CXFA_ImageEditData final : public CXFA_FieldLayoutData {
public:
CONSTRUCT_VIA_MAKE_GARBAGE_COLLECTED;
~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;
private:
CXFA_ImageEditData() = default;
};
CXFA_Node::CXFA_Node(CXFA_Document* pDoc,
XFA_PacketType ePacket,
uint32_t validPackets,
XFA_ObjectType oType,
XFA_Element eType,
pdfium::span<const PropertyData> properties,
pdfium::span<const AttributeData> attributes,
CJX_Object* js_object)
: CXFA_Object(pDoc, oType, eType, js_object),
m_Properties(properties),
m_Attributes(attributes),
m_ValidPackets(validPackets),
m_ePacket(ePacket) {
DCHECK(m_pDocument);
}
CXFA_Node::~CXFA_Node() = default;
void CXFA_Node::Trace(cppgc::Visitor* visitor) const {
CXFA_Object::Trace(visitor);
GCedTreeNodeMixin<CXFA_Node>::Trace(visitor);
visitor->Trace(m_pAuxNode);
ContainerTrace(visitor, binding_nodes_);
visitor->Trace(m_pLayoutData);
visitor->Trace(ui_);
}
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 =
GetXMLDocument()->CreateNode<CFX_XMLElement>(wsName);
WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
if (!wsValue.IsEmpty()) {
auto* text = GetXMLDocument()->CreateNode<CFX_XMLText>(wsValue);
pCloneXMLElement->AppendLastChild(text);
}
pCloneXML = pCloneXMLElement;
pClone->JSObject()->SetEnum(XFA_Attribute::Contains,
XFA_AttributeValue::Unknown, false);
} else {
pCloneXML = xml_node_->Clone(GetXMLDocument());
}
pClone->SetXMLMappingNode(pCloneXML);
}
if (bRecursive) {
for (CXFA_Node* pChild = GetFirstChild(); pChild;
pChild = pChild->GetNextSibling()) {
pClone->InsertChildAndNotify(pChild->Clone(bRecursive), nullptr);
}
}
pClone->SetFlagAndNotify(XFA_NodeFlag_Initialized);
pClone->SetBindingNode(nullptr);
return pClone;
}
CXFA_Node* CXFA_Node::GetNextContainerSibling() const {
for (auto* pNode = GetNextSibling(); pNode; pNode = pNode->GetNextSibling()) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetPrevContainerSibling() const {
for (auto* pNode = GetPrevSibling(); pNode; pNode = pNode->GetPrevSibling()) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetFirstContainerChild() const {
for (auto* pNode = GetFirstChild(); pNode; pNode = pNode->GetNextSibling()) {
if (pNode->GetObjectType() == XFA_ObjectType::ContainerNode)
return pNode;
}
return nullptr;
}
CXFA_Node* CXFA_Node::GetContainerParent() const {
for (auto* pNode = GetParent(); pNode; pNode = pNode->GetParent()) {
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 {
DCHECK(property != XFA_Element::Unknown);
for (const auto& prop : m_Properties) {
if (prop.property == property)
return &prop;
}
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;
}
std::pair<CXFA_Node*, int32_t> CXFA_Node::GetProperty(
int32_t index,
XFA_Element eProperty) const {
if (index < 0 || index >= PropertyOccuranceCount(eProperty))
return {nullptr, 0};
int32_t iCount = 0;
for (CXFA_Node* pNode = GetFirstChild(); pNode;
pNode = pNode->GetNextSibling()) {
if (pNode->GetElementType() == eProperty) {
iCount++;
if (iCount > index)
return {pNode, iCount};
}
}
return {nullptr, iCount};
}
CXFA_Node* CXFA_Node::GetOrCreateProperty(int32_t index,
XFA_Element eProperty) {
if (index < 0 || index >= PropertyOccuranceCount(eProperty))
return nullptr;
int32_t iCount = 0;
CXFA_Node* node;
std::tie(node, iCount) = GetProperty(index, eProperty);
if (node)
return node;
if (HasPropertyFlags(eProperty, XFA_PROPERTYFLAG_OneOf)) {
for (CXFA_Node* pNode = GetFirstChild(); pNode;
pNode = pNode->GetNextSibling()) {
if (HasPropertyFlags(pNode->GetElementType(), XFA_PROPERTYFLAG_OneOf)) {
return nullptr;
}
}
}
CXFA_Node* pNewNode = nullptr;
for (; iCount <= index; ++iCount) {
pNewNode = GetDocument()->CreateNode(GetPacketType(), eProperty);
if (!pNewNode)
return nullptr;
InsertChildAndNotify(pNewNode, nullptr);
pNewNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
}
return pNewNode;
}
Optional<XFA_Element> CXFA_Node::GetFirstPropertyWithFlag(uint8_t flag) const {
for (const auto& prop : m_Properties) {
if (prop.flags & flag)
return prop.property;
}
return {};
}
const CXFA_Node::AttributeData* CXFA_Node::GetAttributeData(
XFA_Attribute attr) const {
DCHECK(attr != XFA_Attribute::Unknown);
for (const auto& cur_attr : m_Attributes) {
if (cur_attr.attribute == attr)
return &cur_attr;
}
return nullptr;
}
bool CXFA_Node::HasAttribute(XFA_Attribute attr) const {
return !!GetAttributeData(attr);
}
XFA_Attribute CXFA_Node::GetAttribute(size_t i) const {
return i < m_Attributes.size() ? m_Attributes[i].attribute
: XFA_Attribute::Unknown;
}
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::GetNodeListForType(XFA_Element eTypeFilter) {
std::vector<CXFA_Node*> nodes;
for (CXFA_Node* pChild = GetFirstChild(); pChild;
pChild = pChild->GetNextSibling()) {
if (pChild->GetElementType() == eTypeFilter)
nodes.push_back(pChild);
}
return nodes;
}
std::vector<CXFA_Node*> CXFA_Node::GetNodeListWithFilter(
uint32_t dwTypeFilter) {
std::vector<CXFA_Node*> nodes;
if (dwTypeFilter == (XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties)) {
for (CXFA_Node* pChild = GetFirstChild(); pChild;
pChild = pChild->GetNextSibling())
nodes.push_back(pChild);
return nodes;
}
if (dwTypeFilter == 0)
return nodes;
bool bFilterChildren = !!(dwTypeFilter & XFA_NODEFILTER_Children);
bool bFilterProperties = !!(dwTypeFilter & XFA_NODEFILTER_Properties);
bool bFilterOneOfProperties = !!(dwTypeFilter & XFA_NODEFILTER_OneOfProperty);
for (CXFA_Node* pChild = GetFirstChild(); pChild;
pChild = pChild->GetNextSibling()) {
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;
Optional<XFA_Element> property =
GetFirstPropertyWithFlag(XFA_PROPERTYFLAG_DefaultOneOf);
if (!property.has_value())
return nodes;
CXFA_Node* pNewNode =
m_pDocument->CreateNode(GetPacketType(), property.value());
if (pNewNode) {
InsertChildAndNotify(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);
if (!pNode)
return nullptr;
pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
return pNode;
}
CXFA_Node* CXFA_Node::CloneTemplateToForm(bool bRecursive) {
DCHECK(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->InsertChildAndNotify(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() {
DCHECK(GetPacketType() == XFA_PacketType::Form);
return GetBindingNode();
}
std::vector<CXFA_Node*> CXFA_Node::GetBindItemsCopy() const {
return std::vector<CXFA_Node*>(binding_nodes_.begin(), binding_nodes_.end());
}
void CXFA_Node::AddBindItem(CXFA_Node* pFormNode) {
DCHECK(pFormNode);
if (BindsFormItems()) {
if (!pdfium::Contains(binding_nodes_, pFormNode))
binding_nodes_.emplace_back(pFormNode);
return;
}
CXFA_Node* pOldFormItem = GetBindingNode();
if (!pOldFormItem) {
SetBindingNode(pFormNode);
return;
}
if (pOldFormItem == pFormNode)
return;
binding_nodes_.clear();
binding_nodes_.push_back(pOldFormItem);
binding_nodes_.push_back(pFormNode);
m_uNodeFlags |= XFA_NodeFlag_BindFormItems;
}
bool 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 true;
}
return !binding_nodes_.empty();
}
CXFA_Node* pOldFormItem = GetBindingNode();
if (pOldFormItem != pFormNode)
return !!pOldFormItem;
SetBindingNode(nullptr);
return false;
}
bool CXFA_Node::HasBindItem() const {
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->GetBindItemsCopy()) {
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;
}
GCedLocaleIface* 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 = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Form));
if (!pForm)
return pdfium::nullopt;
CXFA_Subform* pTopSubform =
pForm->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
if (!pTopSubform)
return pdfium::nullopt;
Optional<WideString> localeName;
CXFA_Node* pLocaleNode = this;
do {
localeName =
pLocaleNode->JSObject()->TryCData(XFA_Attribute::Locale, false);
if (localeName.has_value())
return localeName;
pLocaleNode = pLocaleNode->GetParent();
} while (pLocaleNode && pLocaleNode != pTopSubform);
CXFA_Node* pConfig = ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Config));
localeName = GetDocument()->GetLocaleMgr()->GetConfigLocaleName(pConfig);
if (localeName.has_value())
return localeName;
if (pTopSubform) {
localeName =
pTopSubform->JSObject()->TryCData(XFA_Attribute::Locale, false);
if (localeName.has_value())
return localeName;
}
LocaleIface* pLocale = GetDocument()->GetLocaleMgr()->GetDefLocale();
if (!pLocale)
return pdfium::nullopt;
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;
}
}
WideString CXFA_Node::GetNameExpression() {
WideString wsName = GetNameExpressionSinglePath(this);
CXFA_Node* parent = GetParent();
while (parent) {
WideString wsParent = GetNameExpressionSinglePath(parent);
wsParent += L".";
wsParent += wsName;
wsName = std::move(wsParent);
parent = parent->GetParent();
}
return wsName;
}
CXFA_Node* CXFA_Node::GetDataDescriptionNode() {
if (m_ePacket == XFA_PacketType::Datasets)
return m_pAuxNode;
return nullptr;
}
void CXFA_Node::SetDataDescriptionNode(CXFA_Node* pDataDescriptionNode) {
DCHECK(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 = GetFirstChild(); 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) const {
size_t count = 0;
for (CXFA_Node* pNode = GetFirstChild(); 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::InsertChildAndNotify(int32_t index, CXFA_Node* pNode) {
InsertChildAndNotify(pNode, GetNthChild(index));
}
void CXFA_Node::InsertChildAndNotify(CXFA_Node* pNode, CXFA_Node* pBeforeNode) {
CHECK(!pNode->GetParent());
CHECK(!pBeforeNode || pBeforeNode->GetParent() == this);
pNode->ClearFlag(XFA_NodeFlag_HasRemovedChildren);
InsertBefore(pNode, pBeforeNode);
CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
if (pNotify)
pNotify->OnChildAdded(this);
if (!IsNeedSavingXMLNode() || !pNode->xml_node_)
return;
DCHECK(!pNode->xml_node_->GetParent());
xml_node_->InsertBefore(pNode->xml_node_.Get(),
pBeforeNode ? pBeforeNode->xml_node_.Get() : nullptr);
}
void CXFA_Node::RemoveChildAndNotify(CXFA_Node* pNode, bool bNotify) {
CHECK(pNode);
if (pNode->GetParent() != this)
return;
pNode->SetFlag(XFA_NodeFlag_HasRemovedChildren);
GCedTreeNodeMixin<CXFA_Node>::RemoveChild(pNode);
OnRemoved(bNotify);
if (!IsNeedSavingXMLNode() || !pNode->xml_node_)
return;
if (!pNode->IsAttributeInXML()) {
xml_node_->RemoveChild(pNode->xml_node_.Get());
return;
}
DCHECK(pNode->xml_node_ == xml_node_);
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 = GetXMLDocument()->CreateNode<CFX_XMLElement>(wsName);
WideString wsValue = JSObject()->GetCData(XFA_Attribute::Value);
if (!wsValue.IsEmpty()) {
auto* text = GetXMLDocument()->CreateNode<CFX_XMLText>(wsValue);
pNewXMLElement->AppendLastChild(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::GetOneChildNamed(WideStringView wsName) {
return FindFirstSiblingNamed(this, FX_HashCode_GetW(wsName, false));
}
CXFA_Node* CXFA_Node::GetOneChildOfClass(WideStringView wsClass) {
XFA_Element element = XFA_GetElementByName(wsClass);
if (element == XFA_Element::Unknown)
return nullptr;
return FindFirstSiblingOfClass(this, element);
}
std::vector<CXFA_Node*> CXFA_Node::GetSiblings(bool bIsClassName) {
std::vector<CXFA_Node*> siblings;
CXFA_Node* parent = GetParent();
if (!parent)
return siblings;
if (!parent->HasProperty(GetElementType())) {
parent = GetTransparentParent();
if (!parent)
return siblings;
}
uint32_t dwNameHash = bIsClassName ? GetClassHashCode() : GetNameHash();
TraverseSiblings(parent, dwNameHash, &siblings, bIsClassName, true);
return siblings;
}
size_t CXFA_Node::GetIndex(bool bIsProperty, bool bIsClassIndex) {
CXFA_Node* parent = GetParent();
if (!parent)
return 0;
if (!bIsProperty) {
parent = GetTransparentParent();
if (!parent)
return 0;
}
uint32_t dwHashName = bIsClassIndex ? GetClassHashCode() : GetNameHash();
std::vector<CXFA_Node*> siblings;
TraverseSiblings(parent, dwHashName, &siblings, bIsClassIndex, true);
for (size_t i = 0; i < siblings.size(); ++i) {
if (siblings[i] == this)
return i;
}
return 0;
}
size_t CXFA_Node::GetIndexByName() {
return GetIndex(IsProperty(), /*bIsClassIndex=*/false);
}
size_t CXFA_Node::GetIndexByClassName() {
return GetIndex(IsProperty(), /*bIsClassIndex=*/true);
}
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.Last(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 GetParent() && GetParent()->HasFlag(dwFlag);
return false;
}
void CXFA_Node::SetFlagAndNotify(uint32_t dwFlag) {
DCHECK(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) const {
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_ = GetXMLDocument()->CreateNode<CFX_XMLElement>(
JSObject()->GetCData(XFA_Attribute::Name));
}
return xml_node_.Get();
}
bool CXFA_Node::IsNeedSavingXMLNode() const {
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.Last(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.Last(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()->InsertChildAndNotify(pNewInstance, pNextSibling);
if (bMoveDataBindingNodes) {
NodeSet sNew;
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)
sNew.insert(pDataNode);
}
NodeSet sAfter;
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)
sAfter.insert(pDataNode);
}
ReorderDataNodes(sNew, sAfter, false);
}
} else {
CXFA_Node* pBeforeInstance = GetItemIfExists(iPos);
if (!pBeforeInstance) {
// TODO(dsinclair): What should happen here?
return;
}
GetParent()->InsertChildAndNotify(pNewInstance, pBeforeInstance);
if (bMoveDataBindingNodes) {
NodeSet sNew;
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)
sNew.insert(pDataNode);
}
NodeSet sBefore;
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)
sBefore.insert(pDataNode);
}
ReorderDataNodes(sNew, sBefore, true);
}
}
}
void CXFA_Node::RemoveItem(CXFA_Node* pRemoveInstance,
bool bRemoveDataBinding) {
GetParent()->RemoveChildAndNotify(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)) {
if (CXFA_Node* pDataParent = pDataNode->GetParent()) {
pDataParent->RemoveChildAndNotify(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));
DCHECK(pDataScope);
}
CXFA_Node* pInstance = pDocument->DataMerge_CopyContainer(
pTemplateNode, pFormParent, pDataScope, true, bDataMerge, true);
if (pInstance) {
pDocument->DataMerge_UpdateBindingRelations(pInstance);
pFormParent->RemoveChildAndNotify(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_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:
pNotify->OnContainerChanged(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)
pNotify->OnContainerChanged(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() const {
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() const {
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;
}
XFA_EventError CXFA_Node::ProcessEvent(CXFA_FFDocView* pDocView,
XFA_AttributeValue iActivity,
CXFA_EventParam* pEventParam) {
if (GetElementType() == XFA_Element::Draw)
return XFA_EventError::kNotExist;
std::vector<CXFA_Event*> eventArray =
GetEventByActivity(iActivity, pEventParam->m_bIsFormReady);
bool first = true;
XFA_EventError iRet = XFA_EventError::kNotExist;
for (CXFA_Event* event : eventArray) {
XFA_EventError result =
ProcessEventInternal(pDocView, iActivity, event, pEventParam);
if (first || result == XFA_EventError::kSuccess)
iRet = result;
first = false;
}
return iRet;
}
XFA_EventError CXFA_Node::ProcessEventInternal(CXFA_FFDocView* pDocView,
XFA_AttributeValue iActivity,
CXFA_Event* event,
CXFA_EventParam* pEventParam) {
if (!event)
return XFA_EventError::kNotExist;
switch (event->GetEventType()) {
case XFA_Element::Execute:
break;
case XFA_Element::Script:
if (iActivity == XFA_AttributeValue::DocClose) {
// Too late, scripting engine already gone.
return XFA_EventError::kNotExist;
}
return ExecuteScript(pDocView, 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::kNotExist;
return pDocView->GetDoc()->GetDocEnvironment()->Submit(pDocView->GetDoc(),
submit);
#else
return XFA_EventError::kDisabled;
#endif // PDF_XFA_ELEMENT_SUBMIT_ENABLED
}
default:
break;
}
return XFA_EventError::kNotExist;
}
XFA_EventError CXFA_Node::ProcessCalculate(CXFA_FFDocView* pDocView) {
if (GetElementType() == XFA_Element::Draw)
return XFA_EventError::kNotExist;
CXFA_Calculate* calc = GetCalculateIfExists();
if (!calc)
return XFA_EventError::kNotExist;
if (IsUserInteractive())
return XFA_EventError::kDisabled;
CXFA_EventParam EventParam;
EventParam.m_eType = XFA_EVENT_Calculate;
XFA_EventError iRet =
ExecuteScript(pDocView, calc->GetScriptIfExists(), &EventParam);
if (iRet != XFA_EventError::kSuccess)
return iRet;
if (GetRawValue() != EventParam.m_wsResult) {
SetValue(XFA_VALUEPICTURE_Raw, EventParam.m_wsResult);
pDocView->UpdateUIDisplay(this, nullptr);
}
return XFA_EventError::kSuccess;
}
void CXFA_Node::ProcessScriptTestValidate(CXFA_FFDocView* pDocView,
CXFA_Validate* validate,
XFA_EventError iRet,
bool bRetValue,
bool bVersionFlag) {
if (iRet != XFA_EventError::kSuccess)
return;
if (bRetValue)
return;
IXFA_AppProvider* pAppProvider =
pDocView->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));
}
XFA_EventError CXFA_Node::ProcessFormatTestValidate(CXFA_FFDocView* pDocView,
CXFA_Validate* validate,
bool bVersionFlag) {
WideString wsPicture = validate->GetPicture();
if (wsPicture.IsEmpty())
return XFA_EventError::kNotExist;
WideString wsRawValue = GetRawValue();
if (wsRawValue.IsEmpty())
return XFA_EventError::kError;
GCedLocaleIface* pLocale = GetLocale();
if (!pLocale)
return XFA_EventError::kNotExist;
CXFA_LocaleValue lcValue = XFA_GetLocaleValue(this);
if (lcValue.ValidateValue(lcValue.GetValue(), wsPicture, pLocale, nullptr))
return XFA_EventError::kSuccess;
IXFA_AppProvider* pAppProvider =
pDocView->GetDoc()->GetApp()->GetAppProvider();
if (!pAppProvider)
return XFA_EventError::kNotExist;
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::kError;
}
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::kError;
}
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::kError;
}
XFA_EventError CXFA_Node::ProcessNullTestValidate(CXFA_FFDocView* pDocView,
CXFA_Validate* validate,
int32_t iFlags,
bool bVersionFlag) {
if (!GetValue(XFA_VALUEPICTURE_Raw).IsEmpty())
return XFA_EventError::kSuccess;
if (m_bIsNull && m_bPreNull)
return XFA_EventError::kSuccess;
XFA_AttributeValue eNullTest = validate->GetNullTest();
WideString wsNullMsg = validate->GetNullMessageText();
if (iFlags & 0x01) {
XFA_EventError iRet = XFA_EventError::kSuccess;
if (eNullTest != XFA_AttributeValue::Disabled)
iRet = XFA_EventError::kError;
if (wsNullMsg.IsEmpty())
return iRet;
if (eNullTest != XFA_AttributeValue::Disabled) {
pDocView->m_NullTestMsgArray.push_back(wsNullMsg);
return XFA_EventError::kError;
}
return XFA_EventError::kSuccess;
}
if (wsNullMsg.IsEmpty() && bVersionFlag &&
eNullTest != XFA_AttributeValue::Disabled) {
return XFA_EventError::kError;
}
IXFA_AppProvider* pAppProvider =
pDocView->GetDoc()->GetApp()->GetAppProvider();
if (!pAppProvider)
return XFA_EventError::kNotExist;
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::kError;
}
case XFA_AttributeValue::Warning: {
if (IsUserInteractive())
return XFA_EventError::kSuccess;
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::kError;
}
case XFA_AttributeValue::Disabled:
default:
break;
}
return XFA_EventError::kSuccess;
}
XFA_EventError CXFA_Node::ProcessValidate(CXFA_FFDocView* pDocView,
int32_t iFlags) {
if (GetElementType() == XFA_Element::Draw)
return XFA_EventError::kNotExist;
CXFA_Validate* validate = GetValidateIfExists();
if (!validate)
return XFA_EventError::kNotExist;
bool bInitDoc = validate->NeedsInitApp();
bool bStatus = pDocView->GetLayoutStatus() < XFA_DOCVIEW_LAYOUTSTATUS_End;
XFA_EventError iFormat = XFA_EventError::kNotExist;
XFA_EventError iRet = XFA_EventError::kNotExist;
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(pDocView, script, &eParam);
}
XFA_VERSION version = pDocView->GetDoc()->GetXFADoc()->GetCurVersionMode();
bool bVersionFlag = version < XFA_VERSION_208;
if (bInitDoc) {
validate->ClearFlag(XFA_NodeFlag_NeedsInitApp);
} else {
iFormat = ProcessFormatTestValidate(pDocView, validate, bVersionFlag);
if (!bVersionFlag)
bVersionFlag = pDocView->GetDoc()->GetXFADoc()->is_scripting();
XFA_EventErrorAccumulate(
&iRet,
ProcessNullTestValidate(pDocView, validate, iFlags, bVersionFlag));
}
if (iFormat != XFA_EventError::kSuccess && hasBoolResult)
ProcessScriptTestValidate(pDocView, validate, iRet, bRet, bVersionFlag);
XFA_EventErrorAccumulate(&iRet, iFormat);
return iRet;
}
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 = captionText->GetContent();
}
}
}
if (!wsCaptionName.IsEmpty())
return wsCaptionName;
return JSObject()->GetCData(XFA_Attribute::Name);
}
WideString CXFA_Node::GetValidateMessage(bool bError, bool bVersionFlag) {
WideString wsCaptionName = GetValidateCaptionName(bVersionFlag);
if (bVersionFlag)
return wsCaptionName + L" validation failed";
WideString result =
L"The value you entered for " + wsCaptionName + L" is invalid.";
if (!bError) {
result +=
L" To ignore validations for " + wsCaptionName + L", click Ignore.";
}
return result;
}
XFA_EventError CXFA_Node::ExecuteScript(CXFA_FFDocView* pDocView,
CXFA_Script* script,
CXFA_EventParam* pEventParam) {
return ExecuteBoolScript(pDocView, script, pEventParam).first;
}
std::pair<XFA_EventError, bool> CXFA_Node::ExecuteBoolScript(
CXFA_FFDocView* pDocView,
CXFA_Script* script,
CXFA_EventParam* pEventParam) {
if (m_ExecuteRecursionDepth > kMaxExecuteRecursion)
return {XFA_EventError::kSuccess, false};
DCHECK(pEventParam);
if (!script)
return {XFA_EventError::kNotExist, false};
if (script->GetRunAt() == XFA_AttributeValue::Server)
return {XFA_EventError::kDisabled, false};
WideString wsExpression = script->GetExpression();
if (wsExpression.IsEmpty())
return {XFA_EventError::kNotExist, false};
CXFA_Script::Type eScriptType = script->GetContentType();
if (eScriptType == CXFA_Script::Type::Unknown)
return {XFA_EventError::kSuccess, false};
CXFA_FFDoc* pDoc = pDocView->GetDoc();
CFXJSE_Engine* pContext = pDoc->GetXFADoc()->GetScriptContext();
pContext->SetEventParam(pEventParam);
pContext->SetRunAtType(script->GetRunAt());
std::vector<cppgc::Persistent<CXFA_Node>> refNodes;
if (pEventParam->m_eType == XFA_EVENT_InitCalculate ||
pEventParam->m_eType == XFA_EVENT_Calculate) {
pContext->SetNodesOfRunScript(&refNodes);
}
auto pTmpRetValue = std::make_unique<CFXJSE_Value>(pContext->GetIsolate());
bool bRet = false;
{
AutoRestorer<uint8_t> restorer(&m_ExecuteRecursionDepth);
++m_ExecuteRecursionDepth;
bRet = pContext->RunScript(eScriptType, wsExpression.AsStringView(),
pTmpRetValue.get(), this);
}
XFA_EventError iRet = XFA_EventError::kError;
if (bRet) {
iRet = XFA_EventError::kSuccess;
if (pEventParam->m_eType == XFA_EVENT_Calculate ||
pEventParam->m_eType == XFA_EVENT_InitCalculate) {
if (!pTmpRetValue->IsUndefined()) {
if (!pTmpRetValue->IsNull())
pEventParam->m_wsResult = pTmpRetValue->ToWideString();
iRet = XFA_EventError::kSuccess;
} else {
iRet = XFA_EventError::kError;
}
if (pEventParam->m_eType == XFA_EVENT_InitCalculate) {
if ((iRet == XFA_EventError::kSuccess) &&
(GetRawValue() != pEventParam->m_wsResult)) {
SetValue(XFA_VALUEPICTURE_Raw, pEventParam->m_wsResult);
pDocView->AddValidateNode(this);
}
}
for (CXFA_Node* pRefNode : refNodes) {
if (pRefNode == this)
continue;
CJX_Object::CalcData* pGlobalData =
pRefNode->JSObject()->GetOrCreateCalcData(pDoc->GetHeap());
if (!pdfium::Contains(pGlobalData->m_Globals, this))
pGlobalData->m_Globals.push_back(this);
}
}
}
pContext->SetNodesOfRunScript(nullptr);
pContext->SetEventParam(nullptr);
return {iRet, pTmpRetValue->IsBoolean() && pTmpRetValue->ToBoolean()};
}
std::pair<XFA_FFWidgetType, CXFA_Ui*>
CXFA_Node::CreateChildUIAndValueNodesIfNeeded() {
XFA_Element eType = GetElementType();
DCHECK(eType == XFA_Element::Field || eType == XFA_Element::Draw);
// Both Field and Draw have a UI property. We should always be able to
// retrieve or create the UI element. If we can't something is wrong.
CXFA_Ui* pUI = JSObject()->GetOrCreateProperty<CXFA_Ui>(0, XFA_Element::Ui);
DCHECK(pUI);
CXFA_Node* pUIChild = nullptr;
// Search through the children of the UI node to see if we have any of our
// One-Of entries. If so, that is the node associated with our UI.
for (CXFA_Node* pChild = pUI->GetFirstChild(); pChild;
pChild = pChild->GetNextSibling()) {
if (pUI->IsAOneOfChild(pChild)) {
pUIChild = pChild;
break;
}
}