summaryrefslogtreecommitdiff
path: root/xfa/fxfa/parser
diff options
context:
space:
mode:
authorDan Sinclair <dsinclair@chromium.org>2018-04-05 18:32:35 +0000
committerChromium commit bot <commit-bot@chromium.org>2018-04-05 18:32:35 +0000
commit4a979709304592be8511458793463aa2570bd7af (patch)
tree8ffc233f5d7852a998f460d5359fb97d3c5ffad7 /xfa/fxfa/parser
parentb948046fe797880295d0706f80831d279db75b5a (diff)
downloadpdfium-4a979709304592be8511458793463aa2570bd7af.tar.xz
Move document data merge code into CXFA_Document file
This CL moves the CXFA_Document methods from xfa_document_datamerger_imp into the cxfa_document.cpp file. Change-Id: Idcb0696d2488bff5a4882675b3b876e0ec9e38bb Reviewed-on: https://pdfium-review.googlesource.com/29851 Reviewed-by: Ryan Harrison <rharrison@chromium.org> Commit-Queue: dsinclair <dsinclair@chromium.org>
Diffstat (limited to 'xfa/fxfa/parser')
-rw-r--r--xfa/fxfa/parser/cxfa_document.cpp1431
-rw-r--r--xfa/fxfa/parser/xfa_document_datamerger_imp.cpp1454
-rw-r--r--xfa/fxfa/parser/xfa_document_datamerger_imp.h2
3 files changed, 1437 insertions, 1450 deletions
diff --git a/xfa/fxfa/parser/cxfa_document.cpp b/xfa/fxfa/parser/cxfa_document.cpp
index cf6f3ccbc4..1160a8ad2e 100644
--- a/xfa/fxfa/parser/cxfa_document.cpp
+++ b/xfa/fxfa/parser/cxfa_document.cpp
@@ -9,6 +9,7 @@
#include <set>
#include "core/fxcrt/fx_extension.h"
+#include "core/fxcrt/fx_fallthrough.h"
#include "fxjs/cfxjse_engine.h"
#include "xfa/fxfa/cxfa_ffnotify.h"
#include "xfa/fxfa/parser/cscript_datawindow.h"
@@ -17,15 +18,27 @@
#include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
#include "xfa/fxfa/parser/cscript_logpseudomodel.h"
#include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
+#include "xfa/fxfa/parser/cxfa_bind.h"
#include "xfa/fxfa/parser/cxfa_datagroup.h"
#include "xfa/fxfa/parser/cxfa_document_parser.h"
+#include "xfa/fxfa/parser/cxfa_exdata.h"
+#include "xfa/fxfa/parser/cxfa_form.h"
+#include "xfa/fxfa/parser/cxfa_image.h"
#include "xfa/fxfa/parser/cxfa_interactive.h"
+#include "xfa/fxfa/parser/cxfa_items.h"
#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
#include "xfa/fxfa/parser/cxfa_localemgr.h"
#include "xfa/fxfa/parser/cxfa_node.h"
+#include "xfa/fxfa/parser/cxfa_occur.h"
+#include "xfa/fxfa/parser/cxfa_pageset.h"
#include "xfa/fxfa/parser/cxfa_pdf.h"
#include "xfa/fxfa/parser/cxfa_present.h"
+#include "xfa/fxfa/parser/cxfa_subform.h"
+#include "xfa/fxfa/parser/cxfa_template.h"
+#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
+#include "xfa/fxfa/parser/cxfa_value.h"
+#include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
#include "xfa/fxfa/parser/xfa_utils.h"
@@ -34,6 +47,95 @@ namespace {
constexpr const wchar_t kTemplateNS[] =
L"http://www.xfa.org/schema/xfa-template/";
+struct RecurseRecord {
+ CXFA_Node* pTemplateChild;
+ CXFA_Node* pDataChild;
+};
+
+class CXFA_TraverseStrategy_DDGroup {
+ public:
+ static CXFA_Node* GetFirstChild(CXFA_Node* pDDGroupNode) {
+ return pDDGroupNode->GetFirstChildByName(XFA_HASHCODE_Group);
+ }
+ static CXFA_Node* GetNextSibling(CXFA_Node* pDDGroupNode) {
+ return pDDGroupNode->GetNextSameNameSibling(XFA_HASHCODE_Group);
+ }
+ static CXFA_Node* GetParent(CXFA_Node* pDDGroupNode) {
+ return pDDGroupNode->GetParent();
+ }
+};
+
+void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
+ ASSERT(pFormNode->IsWidgetReady());
+ // GetUIChildNode has the side effect of creating the UI child.
+ pFormNode->GetUIChildNode();
+}
+
+CXFA_Node* FormValueNode_CreateChild(CXFA_Node* pValueNode, XFA_Element iType) {
+ CXFA_Node* pChildNode = pValueNode->GetFirstChild();
+ if (!pChildNode) {
+ if (iType == XFA_Element::Unknown)
+ return nullptr;
+
+ pChildNode =
+ pValueNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, iType);
+ }
+ return pChildNode;
+}
+
+bool FormValueNode_SetChildContent(CXFA_Node* pValueNode,
+ const WideString& wsContent,
+ XFA_Element iType = XFA_Element::Unknown) {
+ if (!pValueNode)
+ return false;
+
+ ASSERT(pValueNode->GetPacketType() == XFA_PacketType::Form);
+ CXFA_Node* pChildNode = FormValueNode_CreateChild(pValueNode, iType);
+ if (!pChildNode)
+ return false;
+
+ switch (pChildNode->GetObjectType()) {
+ case XFA_ObjectType::ContentNode: {
+ CXFA_Node* pContentRawDataNode = pChildNode->GetFirstChild();
+ if (!pContentRawDataNode) {
+ XFA_Element element = XFA_Element::Sharptext;
+ if (pChildNode->GetElementType() == XFA_Element::ExData) {
+ Optional<WideString> contentType =
+ pChildNode->JSObject()->TryAttribute(XFA_Attribute::ContentType,
+ false);
+ if (contentType) {
+ if (*contentType == L"text/html")
+ element = XFA_Element::SharpxHTML;
+ else if (*contentType == L"text/xml")
+ element = XFA_Element::Sharpxml;
+ }
+ }
+ pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
+ pChildNode->InsertChild(pContentRawDataNode, nullptr);
+ }
+ pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
+ false, false);
+ break;
+ }
+ case XFA_ObjectType::NodeC:
+ case XFA_ObjectType::TextNode:
+ case XFA_ObjectType::NodeV: {
+ pChildNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent, false,
+ false);
+ break;
+ }
+ default:
+ NOTREACHED();
+ break;
+ }
+ return true;
+}
+
+CXFA_Node* GetGlobalBinding(CXFA_Document* pDocument, uint32_t dwNameHash) {
+ auto it = pDocument->m_rgGlobalBinding.find(dwNameHash);
+ return it != pDocument->m_rgGlobalBinding.end() ? it->second : nullptr;
+}
+
void MergeNodeRecurse(CXFA_Document* pDocument,
CXFA_Node* pDestNodeParent,
CXFA_Node* pProtoNode) {
@@ -86,6 +188,1106 @@ void MergeNode(CXFA_Document* pDocument,
}
}
+CXFA_Node* CloneOrMergeInstanceManager(CXFA_Document* pDocument,
+ CXFA_Node* pFormParent,
+ CXFA_Node* pTemplateNode,
+ std::vector<CXFA_Node*>* subforms) {
+ WideString wsSubformName =
+ pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
+ WideString wsInstMgrNodeName = L"_" + wsSubformName;
+ uint32_t dwInstNameHash =
+ FX_HashCode_GetW(wsInstMgrNodeName.AsStringView(), false);
+ CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
+ pDocument, XFA_Element::InstanceManager, dwInstNameHash, pFormParent);
+ if (pExistingNode) {
+ uint32_t dwNameHash = pTemplateNode->GetNameHash();
+ for (CXFA_Node* pNode = pExistingNode->GetNextSibling(); pNode;) {
+ XFA_Element eCurType = pNode->GetElementType();
+ if (eCurType == XFA_Element::InstanceManager)
+ break;
+
+ if ((eCurType != XFA_Element::Subform) &&
+ (eCurType != XFA_Element::SubformSet)) {
+ pNode = pNode->GetNextSibling();
+ continue;
+ }
+ if (dwNameHash != pNode->GetNameHash())
+ break;
+
+ CXFA_Node* pNextNode = pNode->GetNextSibling();
+ pFormParent->RemoveChild(pNode, true);
+ subforms->push_back(pNode);
+ pNode = pNextNode;
+ }
+ pFormParent->RemoveChild(pExistingNode, true);
+ pFormParent->InsertChild(pExistingNode, nullptr);
+ pExistingNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+ pExistingNode->SetTemplateNode(pTemplateNode);
+ return pExistingNode;
+ }
+
+ CXFA_Node* pNewNode =
+ pDocument->CreateNode(XFA_PacketType::Form, XFA_Element::InstanceManager);
+ wsInstMgrNodeName =
+ L"_" + pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
+ pNewNode->JSObject()->SetCData(XFA_Attribute::Name, wsInstMgrNodeName, false,
+ false);
+ pFormParent->InsertChild(pNewNode, nullptr);
+ pNewNode->SetTemplateNode(pTemplateNode);
+ return pNewNode;
+}
+
+void SortRecurseRecord(std::vector<RecurseRecord>* rgRecords,
+ CXFA_Node* pDataScope,
+ bool bChoiceMode) {
+ std::vector<RecurseRecord> rgResultRecord;
+ for (CXFA_Node* pNode = pDataScope->GetFirstChild(); pNode;
+ pNode = pNode->GetNextSibling()) {
+ auto it = std::find_if(rgRecords->begin(), rgRecords->end(),
+ [pNode](const RecurseRecord& record) {
+ return pNode == record.pDataChild;
+ });
+ if (it != rgRecords->end()) {
+ rgResultRecord.push_back(*it);
+ rgRecords->erase(it);
+ if (bChoiceMode)
+ break;
+ }
+ }
+ if (rgResultRecord.empty())
+ return;
+
+ if (!bChoiceMode) {
+ rgResultRecord.insert(rgResultRecord.end(), rgRecords->begin(),
+ rgRecords->end());
+ }
+ *rgRecords = rgResultRecord;
+}
+
+CXFA_Node* ScopeMatchGlobalBinding(CXFA_Node* pDataScope,
+ uint32_t dwNameHash,
+ XFA_Element eMatchDataNodeType,
+ bool bUpLevel) {
+ for (CXFA_Node *pCurDataScope = pDataScope, *pLastDataScope = nullptr;
+ pCurDataScope &&
+ pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
+ pLastDataScope = pCurDataScope,
+ pCurDataScope = pCurDataScope->GetParent()) {
+ for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
+ pDataChild;
+ pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
+ if (pDataChild == pLastDataScope ||
+ (eMatchDataNodeType != XFA_Element::DataModel &&
+ pDataChild->GetElementType() != eMatchDataNodeType) ||
+ pDataChild->HasBindItem()) {
+ continue;
+ }
+ return pDataChild;
+ }
+
+ for (CXFA_DataGroup* pDataChild =
+ pCurDataScope->GetFirstChildByClass<CXFA_DataGroup>(
+ XFA_Element::DataGroup);
+ pDataChild;
+ pDataChild = pDataChild->GetNextSameClassSibling<CXFA_DataGroup>(
+ XFA_Element::DataGroup)) {
+ CXFA_Node* pDataNode = ScopeMatchGlobalBinding(pDataChild, dwNameHash,
+ eMatchDataNodeType, false);
+ if (pDataNode)
+ return pDataNode;
+ }
+ if (!bUpLevel)
+ break;
+ }
+ return nullptr;
+}
+
+void RegisterGlobalBinding(CXFA_Document* pDocument,
+ uint32_t dwNameHash,
+ CXFA_Node* pDataNode) {
+ pDocument->m_rgGlobalBinding[dwNameHash] = pDataNode;
+}
+
+CXFA_Node* FindGlobalDataNode(CXFA_Document* pDocument,
+ const WideString& wsName,
+ CXFA_Node* pDataScope,
+ XFA_Element eMatchNodeType) {
+ if (wsName.IsEmpty())
+ return nullptr;
+
+ uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
+ CXFA_Node* pBounded = GetGlobalBinding(pDocument, dwNameHash);
+ if (!pBounded) {
+ pBounded =
+ ScopeMatchGlobalBinding(pDataScope, dwNameHash, eMatchNodeType, true);
+ if (pBounded)
+ RegisterGlobalBinding(pDocument, dwNameHash, pBounded);
+ }
+ return pBounded;
+}
+
+CXFA_Node* FindOnceDataNode(CXFA_Document* pDocument,
+ const WideString& wsName,
+ CXFA_Node* pDataScope,
+ XFA_Element eMatchNodeType) {
+ if (wsName.IsEmpty())
+ return nullptr;
+
+ uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
+ CXFA_Node* pLastDataScope = nullptr;
+ for (CXFA_Node* pCurDataScope = pDataScope;
+ pCurDataScope &&
+ pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
+ pCurDataScope = pCurDataScope->GetParent()) {
+ for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
+ pDataChild;
+ pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
+ if (pDataChild == pLastDataScope || pDataChild->HasBindItem() ||
+ (eMatchNodeType != XFA_Element::DataModel &&
+ pDataChild->GetElementType() != eMatchNodeType)) {
+ continue;
+ }
+ return pDataChild;
+ }
+ pLastDataScope = pCurDataScope;
+ }
+ return nullptr;
+}
+
+CXFA_Node* FindDataRefDataNode(CXFA_Document* pDocument,
+ const WideString& wsRef,
+ CXFA_Node* pDataScope,
+ XFA_Element eMatchNodeType,
+ CXFA_Node* pTemplateNode,
+ bool bForceBind,
+ bool bUpLevel) {
+ uint32_t dFlags = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_BindNew;
+ if (bUpLevel || wsRef != L"name")
+ dFlags |= (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
+
+ XFA_RESOLVENODE_RS rs;
+ pDocument->GetScriptContext()->ResolveObjects(
+ pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
+ if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeAll ||
+ rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeMidAll ||
+ rs.objects.size() > 1) {
+ return pDocument->GetNotBindNode(rs.objects);
+ }
+
+ if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeOne) {
+ CXFA_Object* pObject = !rs.objects.empty() ? rs.objects.front() : nullptr;
+ CXFA_Node* pNode = ToNode(pObject);
+ return (bForceBind || !pNode || !pNode->HasBindItem()) ? pNode : nullptr;
+ }
+ return nullptr;
+}
+
+CXFA_Node* FindMatchingDataNode(
+ CXFA_Document* pDocument,
+ CXFA_Node* pTemplateNode,
+ CXFA_Node* pDataScope,
+ bool& bAccessedDataDOM,
+ bool bForceBind,
+ CXFA_NodeIteratorTemplate<CXFA_Node,
+ CXFA_TraverseStrategy_XFAContainerNode>*
+ pIterator,
+ bool& bSelfMatch,
+ XFA_AttributeEnum& eBindMatch,
+ bool bUpLevel) {
+ CXFA_Node* pResult = nullptr;
+ CXFA_Node* pCurTemplateNode = pIterator->GetCurrent();
+ while (pCurTemplateNode) {
+ XFA_Element eMatchNodeType;
+ switch (pCurTemplateNode->GetElementType()) {
+ case XFA_Element::Subform:
+ eMatchNodeType = XFA_Element::DataGroup;
+ break;
+ case XFA_Element::Field: {
+ eMatchNodeType = XFA_FieldIsMultiListBox(pCurTemplateNode)
+ ? XFA_Element::DataGroup
+ : XFA_Element::DataValue;
+ } break;
+ case XFA_Element::ExclGroup:
+ eMatchNodeType = XFA_Element::DataValue;
+ break;
+ default:
+ pCurTemplateNode = pIterator->MoveToNext();
+ continue;
+ }
+
+ CXFA_Occur* pTemplateNodeOccur =
+ pCurTemplateNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+ if (pTemplateNodeOccur) {
+ int32_t iMin;
+ int32_t iMax;
+ int32_t iInit;
+ std::tie(iMin, iMax, iInit) = pTemplateNodeOccur->GetOccurInfo();
+ if (iMax == 0) {
+ pCurTemplateNode = pIterator->MoveToNext();
+ continue;
+ }
+ }
+
+ CXFA_Bind* pTemplateNodeBind =
+ pCurTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind);
+ XFA_AttributeEnum eMatch =
+ pTemplateNodeBind
+ ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
+ : XFA_AttributeEnum::Once;
+ eBindMatch = eMatch;
+ switch (eMatch) {
+ case XFA_AttributeEnum::None:
+ pCurTemplateNode = pIterator->MoveToNext();
+ continue;
+ case XFA_AttributeEnum::Global:
+ bAccessedDataDOM = true;
+ if (!bForceBind) {
+ pCurTemplateNode = pIterator->MoveToNext();
+ continue;
+ }
+ if (eMatchNodeType == XFA_Element::DataValue ||
+ (eMatchNodeType == XFA_Element::DataGroup &&
+ XFA_FieldIsMultiListBox(pTemplateNodeBind))) {
+ CXFA_Node* pGlobalBindNode = FindGlobalDataNode(
+ pDocument,
+ pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
+ pDataScope, eMatchNodeType);
+ if (!pGlobalBindNode) {
+ pCurTemplateNode = pIterator->MoveToNext();
+ continue;
+ }
+ pResult = pGlobalBindNode;
+ break;
+ }
+ FX_FALLTHROUGH;
+ case XFA_AttributeEnum::Once: {
+ bAccessedDataDOM = true;
+ CXFA_Node* pOnceBindNode = FindOnceDataNode(
+ pDocument,
+ pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
+ pDataScope, eMatchNodeType);
+ if (!pOnceBindNode) {
+ pCurTemplateNode = pIterator->MoveToNext();
+ continue;
+ }
+ pResult = pOnceBindNode;
+ break;
+ }
+ case XFA_AttributeEnum::DataRef: {
+ bAccessedDataDOM = true;
+ CXFA_Node* pDataRefBindNode = FindDataRefDataNode(
+ pDocument,
+ pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref),
+ pDataScope, eMatchNodeType, pTemplateNode, bForceBind, bUpLevel);
+ if (pDataRefBindNode &&
+ pDataRefBindNode->GetElementType() == eMatchNodeType) {
+ pResult = pDataRefBindNode;
+ }
+ if (!pResult) {
+ pCurTemplateNode = pIterator->SkipChildrenAndMoveToNext();
+ continue;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (pCurTemplateNode == pTemplateNode && pResult)
+ bSelfMatch = true;
+ break;
+ }
+ return pResult;
+}
+
+void CreateDataBinding(CXFA_Node* pFormNode,
+ CXFA_Node* pDataNode,
+ bool bDataToForm) {
+ pFormNode->SetBindingNode(pDataNode);
+ pDataNode->AddBindItem(pFormNode);
+ XFA_Element eType = pFormNode->GetElementType();
+ if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
+ return;
+
+ ASSERT(pFormNode->IsWidgetReady());
+ auto* defValue = pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
+ 0, XFA_Element::Value);
+ if (!bDataToForm) {
+ WideString wsValue;
+ switch (pFormNode->GetFFWidgetType()) {
+ case XFA_FFWidgetType::kImageEdit: {
+ CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
+ WideString wsContentType;
+ WideString wsHref;
+ if (image) {
+ wsValue = image->GetContent();
+ wsContentType = image->GetContentType();
+ wsHref = image->GetHref();
+ }
+ CFX_XMLElement* pXMLDataElement =
+ static_cast<CFX_XMLElement*>(pDataNode->GetXMLMappingNode());
+ ASSERT(pXMLDataElement);
+
+ pDataNode->JSObject()->SetAttributeValue(
+ wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+ pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
+ wsContentType, false, false);
+ if (!wsHref.IsEmpty())
+ pXMLDataElement->SetString(L"href", wsHref);
+
+ break;
+ }
+ case XFA_FFWidgetType::kChoiceList:
+ wsValue = defValue ? defValue->GetChildValueContent() : L"";
+ if (pFormNode->IsChoiceListMultiSelect()) {
+ std::vector<WideString> wsSelTextArray =
+ pFormNode->GetSelectedItemsValue();
+ if (!wsSelTextArray.empty()) {
+ for (const auto& text : wsSelTextArray) {
+ CXFA_Node* pValue =
+ pDataNode->CreateSamePacketNode(XFA_Element::DataValue);
+ pValue->JSObject()->SetCData(XFA_Attribute::Name, L"value", false,
+ false);
+ pValue->CreateXMLMappingNode();
+ pDataNode->InsertChild(pValue, nullptr);
+ pValue->JSObject()->SetCData(XFA_Attribute::Value, text, false,
+ false);
+ }
+ } else {
+ CFX_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
+ ASSERT(pXMLNode->GetType() == FX_XMLNODE_Element);
+ static_cast<CFX_XMLElement*>(pXMLNode)->SetString(L"xfa:dataNode",
+ L"dataGroup");
+ }
+ } else if (!wsValue.IsEmpty()) {
+ pDataNode->JSObject()->SetAttributeValue(
+ wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+ }
+ break;
+ case XFA_FFWidgetType::kCheckButton:
+ wsValue = defValue ? defValue->GetChildValueContent() : L"";
+ if (wsValue.IsEmpty())
+ break;
+
+ pDataNode->JSObject()->SetAttributeValue(
+ wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+ break;
+ case XFA_FFWidgetType::kExclGroup: {
+ CXFA_Node* pChecked = nullptr;
+ CXFA_Node* pChild = pFormNode->GetFirstChild();
+ for (; pChild; pChild = pChild->GetNextSibling()) {
+ if (pChild->GetElementType() != XFA_Element::Field)
+ continue;
+
+ auto* pValue =
+ pChild->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
+ if (!pValue)
+ continue;
+
+ wsValue = pValue->GetChildValueContent();
+ if (wsValue.IsEmpty())
+ continue;
+
+ CXFA_Items* pItems =
+ pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+ if (!pItems)
+ continue;
+
+ CXFA_Node* pText = pItems->GetFirstChild();
+ if (!pText)
+ continue;
+
+ WideString wsContent = pText->JSObject()->GetContent(false);
+ if (wsContent == wsValue) {
+ pChecked = pChild;
+ pDataNode->JSObject()->SetAttributeValue(wsValue, wsValue, false,
+ false);
+ pFormNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
+ false, false);
+ break;
+ }
+ }
+ if (!pChecked)
+ break;
+
+ pChild = pFormNode->GetFirstChild();
+ for (; pChild; pChild = pChild->GetNextSibling()) {
+ if (pChild == pChecked)
+ continue;
+ if (pChild->GetElementType() != XFA_Element::Field)
+ continue;
+
+ CXFA_Value* pValue =
+ pChild->JSObject()->GetOrCreateProperty<CXFA_Value>(
+ 0, XFA_Element::Value);
+ CXFA_Items* pItems =
+ pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
+ CXFA_Node* pText = pItems ? pItems->GetFirstChild() : nullptr;
+ if (pText)
+ pText = pText->GetNextSibling();
+
+ WideString wsContent;
+ if (pText)
+ wsContent = pText->JSObject()->GetContent(false);
+
+ FormValueNode_SetChildContent(pValue, wsContent, XFA_Element::Text);
+ }
+ break;
+ }
+ case XFA_FFWidgetType::kNumericEdit: {
+ wsValue = defValue ? defValue->GetChildValueContent() : L"";
+ if (wsValue.IsEmpty())
+ break;
+
+ wsValue = pFormNode->NormalizeNumStr(wsValue);
+ pDataNode->JSObject()->SetAttributeValue(
+ wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+ CXFA_Value* pValue =
+ pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
+ 0, XFA_Element::Value);
+ FormValueNode_SetChildContent(pValue, wsValue, XFA_Element::Float);
+ break;
+ }
+ default:
+ wsValue = defValue ? defValue->GetChildValueContent() : L"";
+ if (wsValue.IsEmpty())
+ break;
+
+ pDataNode->JSObject()->SetAttributeValue(
+ wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
+ break;
+ }
+ return;
+ }
+
+ WideString wsXMLValue = pDataNode->JSObject()->GetContent(false);
+ WideString wsNormalizeValue = pFormNode->GetNormalizeDataValue(wsXMLValue);
+
+ pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue, false,
+ false);
+ switch (pFormNode->GetFFWidgetType()) {
+ case XFA_FFWidgetType::kImageEdit: {
+ FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+ XFA_Element::Image);
+ CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
+ if (image) {
+ CFX_XMLElement* pXMLDataElement =
+ static_cast<CFX_XMLElement*>(pDataNode->GetXMLMappingNode());
+ ASSERT(pXMLDataElement);
+
+ WideString wsContentType =
+ pXMLDataElement->GetString(L"xfa:contentType");
+ if (!wsContentType.IsEmpty()) {
+ pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
+ wsContentType, false, false);
+ image->SetContentType(wsContentType);
+ }
+
+ WideString wsHref = pXMLDataElement->GetString(L"href");
+ if (!wsHref.IsEmpty())
+ image->SetHref(wsHref);
+ }
+ break;
+ }
+ case XFA_FFWidgetType::kChoiceList:
+ if (pFormNode->IsChoiceListMultiSelect()) {
+ std::vector<CXFA_Node*> items = pDataNode->GetNodeList(
+ XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties,
+ XFA_Element::Unknown);
+ if (!items.empty()) {
+ bool single = items.size() == 1;
+ wsNormalizeValue.clear();
+
+ for (CXFA_Node* pNode : items) {
+ WideString wsItem = pNode->JSObject()->GetContent(false);
+ if (single)
+ wsItem += L"\n";
+
+ wsNormalizeValue += wsItem;
+ }
+ CXFA_ExData* exData =
+ defValue ? defValue->GetExDataIfExists() : nullptr;
+ ASSERT(exData);
+
+ exData->SetContentType(single ? L"text/plain" : L"text/xml");
+ }
+ FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+ XFA_Element::ExData);
+ } else {
+ FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+ XFA_Element::Text);
+ }
+ break;
+ case XFA_FFWidgetType::kExclGroup: {
+ pFormNode->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
+ false, false, false);
+ break;
+ }
+ case XFA_FFWidgetType::kDateTimeEdit:
+ FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+ XFA_Element::DateTime);
+ break;
+ case XFA_FFWidgetType::kNumericEdit: {
+ WideString wsPicture =
+ pFormNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
+ if (wsPicture.IsEmpty())
+ wsNormalizeValue = pFormNode->NormalizeNumStr(wsNormalizeValue);
+
+ FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+ XFA_Element::Float);
+ break;
+ }
+ default:
+ FormValueNode_SetChildContent(defValue, wsNormalizeValue,
+ XFA_Element::Text);
+ break;
+ }
+}
+
+CXFA_Node* MaybeCreateDataNode(CXFA_Document* pDocument,
+ CXFA_Node* pDataParent,
+ XFA_Element eNodeType,
+ const WideString& wsName) {
+ if (!pDataParent)
+ return nullptr;
+
+ CXFA_Node* pParentDDNode = pDataParent->GetDataDescriptionNode();
+ if (!pParentDDNode) {
+ CXFA_Node* pDataNode =
+ pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
+ pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
+ pDataNode->CreateXMLMappingNode();
+ pDataParent->InsertChild(pDataNode, nullptr);
+ pDataNode->SetFlag(XFA_NodeFlag_Initialized);
+ return pDataNode;
+ }
+
+ CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup> sIterator(
+ pParentDDNode);
+ for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
+ pDDGroupNode = sIterator.MoveToNext()) {
+ if (pDDGroupNode != pParentDDNode) {
+ if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
+ continue;
+
+ Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
+ if (!ns || *ns != L"http://ns.adobe.com/data-description/")
+ continue;
+ }
+
+ CXFA_Node* pDDNode =
+ pDDGroupNode->GetFirstChildByName(wsName.AsStringView());
+ if (!pDDNode)
+ continue;
+ if (pDDNode->GetElementType() != eNodeType)
+ break;
+
+ CXFA_Node* pDataNode =
+ pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
+ pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
+ pDataNode->CreateXMLMappingNode();
+ if (eNodeType == XFA_Element::DataValue &&
+ pDDNode->JSObject()->GetEnum(XFA_Attribute::Contains) ==
+ XFA_AttributeEnum::MetaData) {
+ pDataNode->JSObject()->SetEnum(XFA_Attribute::Contains,
+ XFA_AttributeEnum::MetaData, false);
+ }
+ pDataParent->InsertChild(pDataNode, nullptr);
+ pDataNode->SetDataDescriptionNode(pDDNode);
+ pDataNode->SetFlag(XFA_NodeFlag_Initialized);
+ return pDataNode;
+ }
+ return nullptr;
+}
+
+CXFA_Node* CopyContainer_Field(CXFA_Document* pDocument,
+ CXFA_Node* pTemplateNode,
+ CXFA_Node* pFormNode,
+ CXFA_Node* pDataScope,
+ bool bDataMerge,
+ bool bUpLevel) {
+ CXFA_Node* pFieldNode = XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pFormNode, pTemplateNode, false, nullptr);
+ ASSERT(pFieldNode);
+ for (CXFA_Node* pTemplateChildNode = pTemplateNode->GetFirstChild();
+ pTemplateChildNode;
+ pTemplateChildNode = pTemplateChildNode->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChildNode, true)) {
+ XFA_NodeMerge_CloneOrMergeContainer(pDocument, pFieldNode,
+ pTemplateChildNode, true, nullptr);
+ } else if (pTemplateNode->GetElementType() == XFA_Element::ExclGroup &&
+ pTemplateChildNode->IsContainerNode()) {
+ if (pTemplateChildNode->GetElementType() == XFA_Element::Field) {
+ CopyContainer_Field(pDocument, pTemplateChildNode, pFieldNode, nullptr,
+ false, true);
+ }
+ }
+ }
+ if (bDataMerge) {
+ bool bAccessedDataDOM = false;
+ bool bSelfMatch = false;
+ XFA_AttributeEnum eBindMatch;
+ CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
+ sNodeIter(pTemplateNode);
+ CXFA_Node* pDataNode = FindMatchingDataNode(
+ pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, true,
+ &sNodeIter, bSelfMatch, eBindMatch, bUpLevel);
+ if (pDataNode)
+ CreateDataBinding(pFieldNode, pDataNode, true);
+ } else {
+ FormValueNode_MatchNoneCreateChild(pFieldNode);
+ }
+ return pFieldNode;
+}
+
+CXFA_Node* CopyContainer_SubformSet(CXFA_Document* pDocument,
+ CXFA_Node* pTemplateNode,
+ CXFA_Node* pFormParentNode,
+ CXFA_Node* pDataScope,
+ bool bOneInstance,
+ bool bDataMerge) {
+ XFA_Element eType = pTemplateNode->GetElementType();
+ CXFA_Node* pOccurNode = nullptr;
+ CXFA_Node* pFirstInstance = nullptr;
+ bool bUseInstanceManager =
+ pFormParentNode->GetElementType() != XFA_Element::Area;
+ CXFA_Node* pInstMgrNode = nullptr;
+ std::vector<CXFA_Node*> subformArray;
+ std::vector<CXFA_Node*>* pSearchArray = nullptr;
+ if (!bOneInstance &&
+ (eType == XFA_Element::SubformSet || eType == XFA_Element::Subform)) {
+ pInstMgrNode = bUseInstanceManager ? CloneOrMergeInstanceManager(
+ pDocument, pFormParentNode,
+ pTemplateNode, &subformArray)
+ : nullptr;
+ if (CXFA_Occur* pOccurTemplateNode =
+ pTemplateNode->GetFirstChildByClass<CXFA_Occur>(
+ XFA_Element::Occur)) {
+ pOccurNode = pInstMgrNode ? XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pInstMgrNode,
+ pOccurTemplateNode, false, nullptr)
+ : pOccurTemplateNode;
+ } else if (pInstMgrNode) {
+ pOccurNode =
+ pInstMgrNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
+ if (pOccurNode)
+ pOccurNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+ }
+ if (pInstMgrNode) {
+ pInstMgrNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+ pSearchArray = &subformArray;
+ if (pFormParentNode->GetElementType() == XFA_Element::PageArea) {
+ bOneInstance = true;
+ if (subformArray.empty())
+ pSearchArray = nullptr;
+ } else if (pTemplateNode->GetNameHash() == 0 && subformArray.empty()) {
+ pSearchArray = nullptr;
+ }
+ }
+ }
+
+ int32_t iMax = 1;
+ int32_t iInit = 1;
+ int32_t iMin = 1;
+ if (!bOneInstance && pOccurNode) {
+ std::tie(iMin, iMax, iInit) =
+ static_cast<CXFA_Occur*>(pOccurNode)->GetOccurInfo();
+ }
+
+ XFA_AttributeEnum eRelation =
+ eType == XFA_Element::SubformSet
+ ? pTemplateNode->JSObject()->GetEnum(XFA_Attribute::Relation)
+ : XFA_AttributeEnum::Ordered;
+ int32_t iCurRepeatIndex = 0;
+ XFA_AttributeEnum eParentBindMatch = XFA_AttributeEnum::None;
+ if (bDataMerge) {
+ CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
+ sNodeIterator(pTemplateNode);
+ bool bAccessedDataDOM = false;
+ if (eType == XFA_Element::SubformSet || eType == XFA_Element::Area) {
+ sNodeIterator.MoveToNext();
+ } else {
+ std::map<CXFA_Node*, CXFA_Node*> subformMapArray;
+ std::vector<CXFA_Node*> nodeArray;
+ for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
+ bool bSelfMatch = false;
+ XFA_AttributeEnum eBindMatch = XFA_AttributeEnum::None;
+ CXFA_Node* pDataNode = FindMatchingDataNode(
+ pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, false,
+ &sNodeIterator, bSelfMatch, eBindMatch, true);
+ if (!pDataNode || sNodeIterator.GetCurrent() != pTemplateNode)
+ break;
+
+ eParentBindMatch = eBindMatch;
+ CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+ if (!pFirstInstance)
+ pFirstInstance = pSubformNode;
+
+ CreateDataBinding(pSubformNode, pDataNode, true);
+ ASSERT(pSubformNode);
+ subformMapArray[pSubformNode] = pDataNode;
+ nodeArray.push_back(pSubformNode);
+ }
+
+ for (CXFA_Node* pSubform : nodeArray) {
+ CXFA_Node* pDataNode = nullptr;
+ auto it = subformMapArray.find(pSubform);
+ if (it != subformMapArray.end())
+ pDataNode = it->second;
+ for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+ pTemplateChild;
+ pTemplateChild = pTemplateChild->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+ bUseInstanceManager)) {
+ XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubform,
+ pTemplateChild, true, nullptr);
+ } else if (pTemplateChild->IsContainerNode()) {
+ pDocument->DataMerge_CopyContainer(pTemplateChild, pSubform,
+ pDataNode, false, true, false);
+ }
+ }
+ }
+ subformMapArray.clear();
+ }
+
+ for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
+ bool bSelfMatch = false;
+ XFA_AttributeEnum eBindMatch = XFA_AttributeEnum::None;
+ if (!FindMatchingDataNode(pDocument, pTemplateNode, pDataScope,
+ bAccessedDataDOM, false, &sNodeIterator,
+ bSelfMatch, eBindMatch, true)) {
+ break;
+ }
+ if (eBindMatch == XFA_AttributeEnum::DataRef &&
+ eParentBindMatch == XFA_AttributeEnum::DataRef) {
+ break;
+ }
+
+ if (eRelation == XFA_AttributeEnum::Choice ||
+ eRelation == XFA_AttributeEnum::Unordered) {
+ CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+ ASSERT(pSubformSetNode);
+ if (!pFirstInstance)
+ pFirstInstance = pSubformSetNode;
+
+ std::vector<RecurseRecord> rgItemMatchList;
+ std::vector<CXFA_Node*> rgItemUnmatchList;
+ for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+ pTemplateChild;
+ pTemplateChild = pTemplateChild->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+ bUseInstanceManager)) {
+ XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
+ pTemplateChild, true, nullptr);
+ } else if (pTemplateChild->IsContainerNode()) {
+ bSelfMatch = false;
+ eBindMatch = XFA_AttributeEnum::None;
+ if (eRelation != XFA_AttributeEnum::Ordered) {
+ CXFA_NodeIteratorTemplate<CXFA_Node,
+ CXFA_TraverseStrategy_XFAContainerNode>
+ sChildIter(pTemplateChild);
+ CXFA_Node* pDataMatch = FindMatchingDataNode(
+ pDocument, pTemplateChild, pDataScope, bAccessedDataDOM,
+ false, &sChildIter, bSelfMatch, eBindMatch, true);
+ if (pDataMatch) {
+ RecurseRecord sNewRecord = {pTemplateChild, pDataMatch};
+ if (bSelfMatch)
+ rgItemMatchList.insert(rgItemMatchList.begin(), sNewRecord);
+ else
+ rgItemMatchList.push_back(sNewRecord);
+ } else {
+ rgItemUnmatchList.push_back(pTemplateChild);
+ }
+ } else {
+ rgItemUnmatchList.push_back(pTemplateChild);
+ }
+ }
+ }
+
+ switch (eRelation) {
+ case XFA_AttributeEnum::Choice: {
+ ASSERT(!rgItemMatchList.empty());
+ SortRecurseRecord(&rgItemMatchList, pDataScope, true);
+ pDocument->DataMerge_CopyContainer(
+ rgItemMatchList.front().pTemplateChild, pSubformSetNode,
+ pDataScope, false, true, true);
+ break;
+ }
+ case XFA_AttributeEnum::Unordered: {
+ if (!rgItemMatchList.empty()) {
+ SortRecurseRecord(&rgItemMatchList, pDataScope, false);
+ for (const auto& matched : rgItemMatchList) {
+ pDocument->DataMerge_CopyContainer(matched.pTemplateChild,
+ pSubformSetNode, pDataScope,
+ false, true, true);
+ }
+ }
+ for (auto* unmatched : rgItemUnmatchList) {
+ pDocument->DataMerge_CopyContainer(unmatched, pSubformSetNode,
+ pDataScope, false, true, true);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ } else {
+ CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+ ASSERT(pSubformSetNode);
+ if (!pFirstInstance)
+ pFirstInstance = pSubformSetNode;
+
+ for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+ pTemplateChild;
+ pTemplateChild = pTemplateChild->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+ bUseInstanceManager)) {
+ XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
+ pTemplateChild, true, nullptr);
+ } else if (pTemplateChild->IsContainerNode()) {
+ pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
+ pDataScope, false, true, true);
+ }
+ }
+ }
+ }
+
+ if (iCurRepeatIndex == 0 && bAccessedDataDOM == false) {
+ int32_t iLimit = iMax;
+ if (pInstMgrNode && pTemplateNode->GetNameHash() == 0) {
+ iLimit = pdfium::CollectionSize<int32_t>(subformArray);
+ if (iLimit < iMin)
+ iLimit = iInit;
+ }
+
+ for (; (iLimit < 0 || iCurRepeatIndex < iLimit); iCurRepeatIndex++) {
+ if (pInstMgrNode) {
+ if (pSearchArray && pSearchArray->empty()) {
+ if (pTemplateNode->GetNameHash() != 0)
+ break;
+ pSearchArray = nullptr;
+ }
+ } else if (!XFA_DataMerge_FindFormDOMInstance(
+ pDocument, pTemplateNode->GetElementType(),
+ pTemplateNode->GetNameHash(), pFormParentNode)) {
+ break;
+ }
+ CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+ ASSERT(pSubformNode);
+ if (!pFirstInstance)
+ pFirstInstance = pSubformNode;
+
+ for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+ pTemplateChild;
+ pTemplateChild = pTemplateChild->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
+ bUseInstanceManager)) {
+ XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformNode,
+ pTemplateChild, true, nullptr);
+ } else if (pTemplateChild->IsContainerNode()) {
+ pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformNode,
+ pDataScope, false, true, true);
+ }
+ }
+ }
+ }
+ }
+
+ int32_t iMinimalLimit = iCurRepeatIndex == 0 ? iInit : iMin;
+ for (; iCurRepeatIndex < iMinimalLimit; iCurRepeatIndex++) {
+ CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+ pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
+ ASSERT(pSubformSetNode);
+ if (!pFirstInstance)
+ pFirstInstance = pSubformSetNode;
+
+ bool bFound = false;
+ for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
+ pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
+ XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
+ pTemplateChild, true, nullptr);
+ } else if (pTemplateChild->IsContainerNode()) {
+ if (bFound && eRelation == XFA_AttributeEnum::Choice)
+ continue;
+
+ pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
+ pDataScope, false, bDataMerge, true);
+ bFound = true;
+ }
+ }
+ }
+ return pFirstInstance;
+}
+
+void UpdateBindingRelations(CXFA_Document* pDocument,
+ CXFA_Node* pFormNode,
+ CXFA_Node* pDataScope,
+ bool bDataRef,
+ bool bParentDataRef) {
+ bool bMatchRef = true;
+ XFA_Element eType = pFormNode->GetElementType();
+ CXFA_Node* pDataNode = pFormNode->GetBindData();
+ if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup ||
+ eType == XFA_Element::Field) {
+ CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
+ CXFA_Bind* pTemplateNodeBind =
+ pTemplateNode
+ ? pTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind)
+ : nullptr;
+ XFA_AttributeEnum eMatch =
+ pTemplateNodeBind
+ ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
+ : XFA_AttributeEnum::Once;
+ switch (eMatch) {
+ case XFA_AttributeEnum::None:
+ if (!bDataRef || bParentDataRef)
+ FormValueNode_MatchNoneCreateChild(pFormNode);
+ break;
+ case XFA_AttributeEnum::Once:
+ if (!bDataRef || bParentDataRef) {
+ if (!pDataNode) {
+ if (pFormNode->GetNameHash() != 0 &&
+ pFormNode->JSObject()->GetEnum(XFA_Attribute::Scope) !=
+ XFA_AttributeEnum::None) {
+ XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
+ XFA_FieldIsMultiListBox(pFormNode))
+ ? XFA_Element::DataGroup
+ : XFA_Element::DataValue;
+ pDataNode = MaybeCreateDataNode(
+ pDocument, pDataScope, eDataNodeType,
+ WideString(
+ pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
+ if (pDataNode)
+ CreateDataBinding(pFormNode, pDataNode, false);
+ }
+ if (!pDataNode)
+ FormValueNode_MatchNoneCreateChild(pFormNode);
+
+ } else {
+ CXFA_Node* pDataParent = pDataNode->GetParent();
+ if (pDataParent != pDataScope) {
+ ASSERT(pDataParent);
+ pDataParent->RemoveChild(pDataNode, true);
+ pDataScope->InsertChild(pDataNode, nullptr);
+ }
+ }
+ }
+ break;
+ case XFA_AttributeEnum::Global:
+ if (!bDataRef || bParentDataRef) {
+ uint32_t dwNameHash = pFormNode->GetNameHash();
+ if (dwNameHash != 0 && !pDataNode) {
+ pDataNode = GetGlobalBinding(pDocument, dwNameHash);
+ if (!pDataNode) {
+ XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
+ XFA_FieldIsMultiListBox(pFormNode))
+ ? XFA_Element::DataGroup
+ : XFA_Element::DataValue;
+ CXFA_Node* pRecordNode =
+ ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
+ pDataNode = MaybeCreateDataNode(
+ pDocument, pRecordNode, eDataNodeType,
+ WideString(
+ pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
+ if (pDataNode) {
+ CreateDataBinding(pFormNode, pDataNode, false);
+ RegisterGlobalBinding(pDocument, pFormNode->GetNameHash(),
+ pDataNode);
+ }
+ } else {
+ CreateDataBinding(pFormNode, pDataNode, true);
+ }
+ }
+ if (!pDataNode)
+ FormValueNode_MatchNoneCreateChild(pFormNode);
+ }
+ break;
+ case XFA_AttributeEnum::DataRef: {
+ bMatchRef = bDataRef;
+ bParentDataRef = true;
+ if (!pDataNode && bDataRef) {
+ WideString wsRef =
+ pTemplateNodeBind
+ ? pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref)
+ : L"";
+ uint32_t dFlags =
+ XFA_RESOLVENODE_Children | XFA_RESOLVENODE_CreateNode;
+ XFA_RESOLVENODE_RS rs;
+ pDocument->GetScriptContext()->ResolveObjects(
+ pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
+ CXFA_Object* pObject =
+ !rs.objects.empty() ? rs.objects.front() : nullptr;
+ pDataNode = ToNode(pObject);
+ if (pDataNode) {
+ CreateDataBinding(pFormNode, pDataNode,
+ rs.dwFlags == XFA_ResolveNode_RSType_ExistNodes);
+ } else {
+ FormValueNode_MatchNoneCreateChild(pFormNode);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (bMatchRef &&
+ (eType == XFA_Element::Subform || eType == XFA_Element::SubformSet ||
+ eType == XFA_Element::Area || eType == XFA_Element::PageArea ||
+ eType == XFA_Element::PageSet)) {
+ for (CXFA_Node* pFormChild = pFormNode->GetFirstChild(); pFormChild;
+ pFormChild = pFormChild->GetNextSibling()) {
+ if (!pFormChild->IsContainerNode())
+ continue;
+ if (pFormChild->IsUnusedNode())
+ continue;
+
+ UpdateBindingRelations(pDocument, pFormChild,
+ pDataNode ? pDataNode : pDataScope, bDataRef,
+ bParentDataRef);
+ }
+ }
+}
+
+void UpdateDataRelation(CXFA_Node* pDataNode, CXFA_Node* pDataDescriptionNode) {
+ ASSERT(pDataDescriptionNode);
+ for (CXFA_Node* pDataChild = pDataNode->GetFirstChild(); pDataChild;
+ pDataChild = pDataChild->GetNextSibling()) {
+ uint32_t dwNameHash = pDataChild->GetNameHash();
+ if (!dwNameHash)
+ continue;
+
+ CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup>
+ sIterator(pDataDescriptionNode);
+ for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
+ pDDGroupNode = sIterator.MoveToNext()) {
+ if (pDDGroupNode != pDataDescriptionNode) {
+ if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
+ continue;
+
+ Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
+ if (!ns || *ns != L"http://ns.adobe.com/data-description/")
+ continue;
+ }
+
+ CXFA_Node* pDDNode = pDDGroupNode->GetFirstChildByName(dwNameHash);
+ if (!pDDNode)
+ continue;
+ if (pDDNode->GetElementType() != pDataChild->GetElementType())
+ break;
+
+ pDataChild->SetDataDescriptionNode(pDDNode);
+ UpdateDataRelation(pDataChild, pDDNode);
+ break;
+ }
+ }
+}
+
} // namespace
CXFA_Document::CXFA_Document(CXFA_FFNotify* notify)
@@ -385,3 +1587,232 @@ void CXFA_Document::DoProtoMerge() {
MergeNode(this, pUseHrefNode, pProtoNode);
}
}
+
+CXFA_Node* CXFA_Document::DataMerge_CopyContainer(CXFA_Node* pTemplateNode,
+ CXFA_Node* pFormNode,
+ CXFA_Node* pDataScope,
+ bool bOneInstance,
+ bool bDataMerge,
+ bool bUpLevel) {
+ switch (pTemplateNode->GetElementType()) {
+ case XFA_Element::SubformSet:
+ case XFA_Element::Subform:
+ case XFA_Element::Area:
+ case XFA_Element::PageArea:
+ return CopyContainer_SubformSet(this, pTemplateNode, pFormNode,
+ pDataScope, bOneInstance, bDataMerge);
+ case XFA_Element::ExclGroup:
+ case XFA_Element::Field:
+ case XFA_Element::Draw:
+ case XFA_Element::ContentArea:
+ return CopyContainer_Field(this, pTemplateNode, pFormNode, pDataScope,
+ bDataMerge, bUpLevel);
+ case XFA_Element::PageSet:
+ case XFA_Element::Variables:
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return nullptr;
+}
+
+void CXFA_Document::DataMerge_UpdateBindingRelations(
+ CXFA_Node* pFormUpdateRoot) {
+ CXFA_Node* pDataScope =
+ XFA_DataMerge_FindDataScope(pFormUpdateRoot->GetParent());
+ if (!pDataScope)
+ return;
+
+ UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, false, false);
+ UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, true, false);
+}
+
+CXFA_Node* CXFA_Document::GetNotBindNode(
+ const std::vector<CXFA_Object*>& arrayObjects) const {
+ for (CXFA_Object* pObject : arrayObjects) {
+ CXFA_Node* pNode = pObject->AsNode();
+ if (pNode && !pNode->HasBindItem())
+ return pNode;
+ }
+ return nullptr;
+}
+
+void CXFA_Document::DoDataMerge() {
+ CXFA_Node* pDatasetsRoot = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
+ if (!pDatasetsRoot) {
+ // Ownership will be passed in the AppendChild below to the XML tree.
+ auto pDatasetsXMLNode = pdfium::MakeUnique<CFX_XMLElement>(L"xfa:datasets");
+ pDatasetsXMLNode->SetString(L"xmlns:xfa",
+ L"http://www.xfa.org/schema/xfa-data/1.0/");
+ pDatasetsRoot =
+ CreateNode(XFA_PacketType::Datasets, XFA_Element::DataModel);
+ pDatasetsRoot->JSObject()->SetCData(XFA_Attribute::Name, L"datasets", false,
+ false);
+
+ CFX_XMLElement* ref = pDatasetsXMLNode.get();
+ m_pRootNode->GetXMLMappingNode()->AppendChild(pDatasetsXMLNode.release());
+ m_pRootNode->InsertChild(pDatasetsRoot, nullptr);
+ pDatasetsRoot->SetXMLMappingNode(ref);
+ }
+
+ CXFA_Node *pDataRoot = nullptr, *pDDRoot = nullptr;
+ WideString wsDatasetsURI =
+ pDatasetsRoot->JSObject()->TryNamespace().value_or(WideString());
+ for (CXFA_Node* pChildNode = pDatasetsRoot->GetFirstChild(); pChildNode;
+ pChildNode = pChildNode->GetNextSibling()) {
+ if (pChildNode->GetElementType() != XFA_Element::DataGroup)
+ continue;
+
+ if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
+ Optional<WideString> namespaceURI =
+ pChildNode->JSObject()->TryNamespace();
+ if (!namespaceURI)
+ continue;
+ if (*namespaceURI == L"http://ns.adobe.com/data-description/")
+ pDDRoot = pChildNode;
+ } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
+ Optional<WideString> namespaceURI =
+ pChildNode->JSObject()->TryNamespace();
+ if (!namespaceURI)
+ continue;
+ if (*namespaceURI == wsDatasetsURI)
+ pDataRoot = pChildNode;
+ }
+ if (pDataRoot && pDDRoot)
+ break;
+ }
+
+ if (!pDataRoot) {
+ pDataRoot = CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
+ pDataRoot->JSObject()->SetCData(XFA_Attribute::Name, L"data", false, false);
+ pDataRoot->SetXMLMappingNode(
+ pdfium::MakeUnique<CFX_XMLElement>(L"xfa:data"));
+ pDatasetsRoot->InsertChild(pDataRoot, nullptr);
+ }
+
+ CXFA_DataGroup* pDataTopLevel =
+ pDataRoot->GetFirstChildByClass<CXFA_DataGroup>(XFA_Element::DataGroup);
+ uint32_t dwNameHash = pDataTopLevel ? pDataTopLevel->GetNameHash() : 0;
+ CXFA_Template* pTemplateRoot =
+ m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
+ if (!pTemplateRoot)
+ return;
+
+ CXFA_Node* pTemplateChosen =
+ dwNameHash != 0 ? pTemplateRoot->GetFirstChildByName(dwNameHash)
+ : nullptr;
+ if (!pTemplateChosen ||
+ pTemplateChosen->GetElementType() != XFA_Element::Subform) {
+ pTemplateChosen =
+ pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
+ }
+ if (!pTemplateChosen)
+ return;
+
+ CXFA_Form* pFormRoot =
+ m_pRootNode->GetFirstChildByClass<CXFA_Form>(XFA_Element::Form);
+ bool bEmptyForm = false;
+ if (!pFormRoot) {
+ bEmptyForm = true;
+ pFormRoot = static_cast<CXFA_Form*>(
+ CreateNode(XFA_PacketType::Form, XFA_Element::Form));
+ ASSERT(pFormRoot);
+ pFormRoot->JSObject()->SetCData(XFA_Attribute::Name, L"form", false, false);
+ m_pRootNode->InsertChild(pFormRoot, nullptr);
+ } else {
+ CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
+ sIterator(pFormRoot);
+ for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
+ pNode = sIterator.MoveToNext()) {
+ pNode->SetFlag(XFA_NodeFlag_UnusedNode);
+ }
+ }
+
+ CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
+ this, pFormRoot, pTemplateChosen, false, nullptr);
+ ASSERT(pSubformSetNode);
+ if (!pDataTopLevel) {
+ WideString wsFormName =
+ pSubformSetNode->JSObject()->GetCData(XFA_Attribute::Name);
+ WideString wsDataTopLevelName(wsFormName.IsEmpty() ? L"form" : wsFormName);
+
+ pDataTopLevel = static_cast<CXFA_DataGroup*>(
+ CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup));
+ pDataTopLevel->JSObject()->SetCData(XFA_Attribute::Name, wsDataTopLevelName,
+ false, false);
+ pDataTopLevel->SetXMLMappingNode(
+ pdfium::MakeUnique<CFX_XMLElement>(wsDataTopLevelName));
+
+ CXFA_Node* pBeforeNode = pDataRoot->GetFirstChild();
+ pDataRoot->InsertChild(pDataTopLevel, pBeforeNode);
+ }
+
+ ASSERT(pDataTopLevel);
+ CreateDataBinding(pSubformSetNode, pDataTopLevel, true);
+ for (CXFA_Node* pTemplateChild = pTemplateChosen->GetFirstChild();
+ pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
+ XFA_NodeMerge_CloneOrMergeContainer(this, pSubformSetNode, pTemplateChild,
+ true, nullptr);
+ } else if (pTemplateChild->IsContainerNode()) {
+ DataMerge_CopyContainer(pTemplateChild, pSubformSetNode, pDataTopLevel,
+ false, true, true);
+ }
+ }
+ if (pDDRoot)
+ UpdateDataRelation(pDataRoot, pDDRoot);
+
+ DataMerge_UpdateBindingRelations(pSubformSetNode);
+ CXFA_PageSet* pPageSetNode =
+ pSubformSetNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
+ while (pPageSetNode) {
+ m_pPendingPageSet.push_back(pPageSetNode);
+ CXFA_PageSet* pNextPageSetNode =
+ pPageSetNode->GetNextSameClassSibling<CXFA_PageSet>(
+ XFA_Element::PageSet);
+ pSubformSetNode->RemoveChild(pPageSetNode, true);
+ pPageSetNode = pNextPageSetNode;
+ }
+
+ if (bEmptyForm)
+ return;
+
+ CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
+ pFormRoot);
+ CXFA_Node* pNode = sIterator.MoveToNext();
+ while (pNode) {
+ if (pNode->IsUnusedNode()) {
+ if (pNode->IsContainerNode() ||
+ pNode->GetElementType() == XFA_Element::InstanceManager) {
+ CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
+ pNode->GetParent()->RemoveChild(pNode, true);
+ pNode = pNext;
+ } else {
+ pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
+ pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+ pNode = sIterator.MoveToNext();
+ }
+ } else {
+ pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
+ pNode = sIterator.MoveToNext();
+ }
+ }
+}
+
+void CXFA_Document::DoDataRemerge(bool bDoDataMerge) {
+ CXFA_Node* pFormRoot = ToNode(GetXFAObject(XFA_HASHCODE_Form));
+ if (pFormRoot) {
+ while (CXFA_Node* pNode = pFormRoot->GetFirstChild())
+ pFormRoot->RemoveChild(pNode, true);
+
+ pFormRoot->SetBindingNode(nullptr);
+ }
+ m_rgGlobalBinding.clear();
+
+ if (bDoDataMerge)
+ DoDataMerge();
+
+ CXFA_LayoutProcessor* pLayoutProcessor = GetLayoutProcessor();
+ pLayoutProcessor->SetForceReLayout(true);
+}
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
index ac14731bb1..c63a8e24e4 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.cpp
@@ -6,493 +6,10 @@
#include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
-#include <map>
-#include <utility>
-#include <vector>
-
-#include "core/fxcrt/fx_extension.h"
-#include "core/fxcrt/fx_fallthrough.h"
-#include "core/fxcrt/xml/cfx_xmlelement.h"
-#include "core/fxcrt/xml/cfx_xmlnode.h"
-#include "fxjs/cfxjse_engine.h"
-#include "fxjs/xfa/cjx_object.h"
-#include "third_party/base/logging.h"
-#include "third_party/base/stl_util.h"
-#include "xfa/fxfa/parser/cxfa_bind.h"
-#include "xfa/fxfa/parser/cxfa_datagroup.h"
-#include "xfa/fxfa/parser/cxfa_document.h"
-#include "xfa/fxfa/parser/cxfa_exdata.h"
-#include "xfa/fxfa/parser/cxfa_form.h"
-#include "xfa/fxfa/parser/cxfa_image.h"
-#include "xfa/fxfa/parser/cxfa_items.h"
-#include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
-#include "xfa/fxfa/parser/cxfa_localemgr.h"
#include "xfa/fxfa/parser/cxfa_node.h"
-#include "xfa/fxfa/parser/cxfa_nodeiteratortemplate.h"
-#include "xfa/fxfa/parser/cxfa_occur.h"
-#include "xfa/fxfa/parser/cxfa_pageset.h"
-#include "xfa/fxfa/parser/cxfa_subform.h"
-#include "xfa/fxfa/parser/cxfa_template.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
-#include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
-#include "xfa/fxfa/parser/cxfa_value.h"
-#include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
-#include "xfa/fxfa/parser/xfa_utils.h"
-
-namespace {
-
-class CXFA_TraverseStrategy_DDGroup {
- public:
- static CXFA_Node* GetFirstChild(CXFA_Node* pDDGroupNode) {
- return pDDGroupNode->GetFirstChildByName(XFA_HASHCODE_Group);
- }
- static CXFA_Node* GetNextSibling(CXFA_Node* pDDGroupNode) {
- return pDDGroupNode->GetNextSameNameSibling(XFA_HASHCODE_Group);
- }
- static CXFA_Node* GetParent(CXFA_Node* pDDGroupNode) {
- return pDDGroupNode->GetParent();
- }
-};
-
-struct RecurseRecord {
- CXFA_Node* pTemplateChild;
- CXFA_Node* pDataChild;
-};
-
-CXFA_Node* FormValueNode_CreateChild(CXFA_Node* pValueNode, XFA_Element iType) {
- CXFA_Node* pChildNode = pValueNode->GetFirstChild();
- if (!pChildNode) {
- if (iType == XFA_Element::Unknown)
- return nullptr;
-
- pChildNode =
- pValueNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, iType);
- }
- return pChildNode;
-}
-
-void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
- ASSERT(pFormNode->IsWidgetReady());
- // GetUIChildNode has the side effect of creating the UI child.
- pFormNode->GetUIChildNode();
-}
-
-bool FormValueNode_SetChildContent(CXFA_Node* pValueNode,
- const WideString& wsContent,
- XFA_Element iType = XFA_Element::Unknown) {
- if (!pValueNode)
- return false;
-
- ASSERT(pValueNode->GetPacketType() == XFA_PacketType::Form);
- CXFA_Node* pChildNode = FormValueNode_CreateChild(pValueNode, iType);
- if (!pChildNode)
- return false;
-
- switch (pChildNode->GetObjectType()) {
- case XFA_ObjectType::ContentNode: {
- CXFA_Node* pContentRawDataNode = pChildNode->GetFirstChild();
- if (!pContentRawDataNode) {
- XFA_Element element = XFA_Element::Sharptext;
- if (pChildNode->GetElementType() == XFA_Element::ExData) {
- Optional<WideString> contentType =
- pChildNode->JSObject()->TryAttribute(XFA_Attribute::ContentType,
- false);
- if (contentType) {
- if (*contentType == L"text/html")
- element = XFA_Element::SharpxHTML;
- else if (*contentType == L"text/xml")
- element = XFA_Element::Sharpxml;
- }
- }
- pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
- pChildNode->InsertChild(pContentRawDataNode, nullptr);
- }
- pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
- false, false);
- break;
- }
- case XFA_ObjectType::NodeC:
- case XFA_ObjectType::TextNode:
- case XFA_ObjectType::NodeV: {
- pChildNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent, false,
- false);
- break;
- }
- default:
- NOTREACHED();
- break;
- }
- return true;
-}
-
-void CreateDataBinding(CXFA_Node* pFormNode,
- CXFA_Node* pDataNode,
- bool bDataToForm) {
- pFormNode->SetBindingNode(pDataNode);
- pDataNode->AddBindItem(pFormNode);
- XFA_Element eType = pFormNode->GetElementType();
- if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
- return;
-
- ASSERT(pFormNode->IsWidgetReady());
- auto* defValue = pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
- 0, XFA_Element::Value);
- if (!bDataToForm) {
- WideString wsValue;
- switch (pFormNode->GetFFWidgetType()) {
- case XFA_FFWidgetType::kImageEdit: {
- CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
- WideString wsContentType;
- WideString wsHref;
- if (image) {
- wsValue = image->GetContent();
- wsContentType = image->GetContentType();
- wsHref = image->GetHref();
- }
- CFX_XMLElement* pXMLDataElement =
- static_cast<CFX_XMLElement*>(pDataNode->GetXMLMappingNode());
- ASSERT(pXMLDataElement);
-
- pDataNode->JSObject()->SetAttributeValue(
- wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
- pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
- wsContentType, false, false);
- if (!wsHref.IsEmpty())
- pXMLDataElement->SetString(L"href", wsHref);
-
- break;
- }
- case XFA_FFWidgetType::kChoiceList:
- wsValue = defValue ? defValue->GetChildValueContent() : L"";
- if (pFormNode->IsChoiceListMultiSelect()) {
- std::vector<WideString> wsSelTextArray =
- pFormNode->GetSelectedItemsValue();
- if (!wsSelTextArray.empty()) {
- for (const auto& text : wsSelTextArray) {
- CXFA_Node* pValue =
- pDataNode->CreateSamePacketNode(XFA_Element::DataValue);
- pValue->JSObject()->SetCData(XFA_Attribute::Name, L"value", false,
- false);
- pValue->CreateXMLMappingNode();
- pDataNode->InsertChild(pValue, nullptr);
- pValue->JSObject()->SetCData(XFA_Attribute::Value, text, false,
- false);
- }
- } else {
- CFX_XMLNode* pXMLNode = pDataNode->GetXMLMappingNode();
- ASSERT(pXMLNode->GetType() == FX_XMLNODE_Element);
- static_cast<CFX_XMLElement*>(pXMLNode)->SetString(L"xfa:dataNode",
- L"dataGroup");
- }
- } else if (!wsValue.IsEmpty()) {
- pDataNode->JSObject()->SetAttributeValue(
- wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
- }
- break;
- case XFA_FFWidgetType::kCheckButton:
- wsValue = defValue ? defValue->GetChildValueContent() : L"";
- if (wsValue.IsEmpty())
- break;
-
- pDataNode->JSObject()->SetAttributeValue(
- wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
- break;
- case XFA_FFWidgetType::kExclGroup: {
- CXFA_Node* pChecked = nullptr;
- CXFA_Node* pChild = pFormNode->GetFirstChild();
- for (; pChild; pChild = pChild->GetNextSibling()) {
- if (pChild->GetElementType() != XFA_Element::Field)
- continue;
-
- auto* pValue =
- pChild->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
- if (!pValue)
- continue;
-
- wsValue = pValue->GetChildValueContent();
- if (wsValue.IsEmpty())
- continue;
-
- CXFA_Items* pItems =
- pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
- if (!pItems)
- continue;
-
- CXFA_Node* pText = pItems->GetFirstChild();
- if (!pText)
- continue;
-
- WideString wsContent = pText->JSObject()->GetContent(false);
- if (wsContent == wsValue) {
- pChecked = pChild;
- pDataNode->JSObject()->SetAttributeValue(wsValue, wsValue, false,
- false);
- pFormNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent,
- false, false);
- break;
- }
- }
- if (!pChecked)
- break;
-
- pChild = pFormNode->GetFirstChild();
- for (; pChild; pChild = pChild->GetNextSibling()) {
- if (pChild == pChecked)
- continue;
- if (pChild->GetElementType() != XFA_Element::Field)
- continue;
-
- CXFA_Value* pValue =
- pChild->JSObject()->GetOrCreateProperty<CXFA_Value>(
- 0, XFA_Element::Value);
- CXFA_Items* pItems =
- pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
- CXFA_Node* pText = pItems ? pItems->GetFirstChild() : nullptr;
- if (pText)
- pText = pText->GetNextSibling();
-
- WideString wsContent;
- if (pText)
- wsContent = pText->JSObject()->GetContent(false);
-
- FormValueNode_SetChildContent(pValue, wsContent, XFA_Element::Text);
- }
- break;
- }
- case XFA_FFWidgetType::kNumericEdit: {
- wsValue = defValue ? defValue->GetChildValueContent() : L"";
- if (wsValue.IsEmpty())
- break;
-
- wsValue = pFormNode->NormalizeNumStr(wsValue);
- pDataNode->JSObject()->SetAttributeValue(
- wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
- CXFA_Value* pValue =
- pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
- 0, XFA_Element::Value);
- FormValueNode_SetChildContent(pValue, wsValue, XFA_Element::Float);
- break;
- }
- default:
- wsValue = defValue ? defValue->GetChildValueContent() : L"";
- if (wsValue.IsEmpty())
- break;
-
- pDataNode->JSObject()->SetAttributeValue(
- wsValue, pFormNode->GetFormatDataValue(wsValue), false, false);
- break;
- }
- return;
- }
-
- WideString wsXMLValue = pDataNode->JSObject()->GetContent(false);
- WideString wsNormalizeValue = pFormNode->GetNormalizeDataValue(wsXMLValue);
-
- pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue, false,
- false);
- switch (pFormNode->GetFFWidgetType()) {
- case XFA_FFWidgetType::kImageEdit: {
- FormValueNode_SetChildContent(defValue, wsNormalizeValue,
- XFA_Element::Image);
- CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
- if (image) {
- CFX_XMLElement* pXMLDataElement =
- static_cast<CFX_XMLElement*>(pDataNode->GetXMLMappingNode());
- ASSERT(pXMLDataElement);
-
- WideString wsContentType =
- pXMLDataElement->GetString(L"xfa:contentType");
- if (!wsContentType.IsEmpty()) {
- pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
- wsContentType, false, false);
- image->SetContentType(wsContentType);
- }
-
- WideString wsHref = pXMLDataElement->GetString(L"href");
- if (!wsHref.IsEmpty())
- image->SetHref(wsHref);
- }
- break;
- }
- case XFA_FFWidgetType::kChoiceList:
- if (pFormNode->IsChoiceListMultiSelect()) {
- std::vector<CXFA_Node*> items = pDataNode->GetNodeList(
- XFA_NODEFILTER_Children | XFA_NODEFILTER_Properties,
- XFA_Element::Unknown);
- if (!items.empty()) {
- bool single = items.size() == 1;
- wsNormalizeValue.clear();
-
- for (CXFA_Node* pNode : items) {
- WideString wsItem = pNode->JSObject()->GetContent(false);
- if (single)
- wsItem += L"\n";
-
- wsNormalizeValue += wsItem;
- }
- CXFA_ExData* exData =
- defValue ? defValue->GetExDataIfExists() : nullptr;
- ASSERT(exData);
-
- exData->SetContentType(single ? L"text/plain" : L"text/xml");
- }
- FormValueNode_SetChildContent(defValue, wsNormalizeValue,
- XFA_Element::ExData);
- } else {
- FormValueNode_SetChildContent(defValue, wsNormalizeValue,
- XFA_Element::Text);
- }
- break;
- case XFA_FFWidgetType::kExclGroup: {
- pFormNode->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
- false, false, false);
- break;
- }
- case XFA_FFWidgetType::kDateTimeEdit:
- FormValueNode_SetChildContent(defValue, wsNormalizeValue,
- XFA_Element::DateTime);
- break;
- case XFA_FFWidgetType::kNumericEdit: {
- WideString wsPicture =
- pFormNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
- if (wsPicture.IsEmpty())
- wsNormalizeValue = pFormNode->NormalizeNumStr(wsNormalizeValue);
-
- FormValueNode_SetChildContent(defValue, wsNormalizeValue,
- XFA_Element::Float);
- break;
- }
- default:
- FormValueNode_SetChildContent(defValue, wsNormalizeValue,
- XFA_Element::Text);
- break;
- }
-}
-CXFA_Node* GetGlobalBinding(CXFA_Document* pDocument, uint32_t dwNameHash) {
- auto it = pDocument->m_rgGlobalBinding.find(dwNameHash);
- return it != pDocument->m_rgGlobalBinding.end() ? it->second : nullptr;
-}
-
-void RegisterGlobalBinding(CXFA_Document* pDocument,
- uint32_t dwNameHash,
- CXFA_Node* pDataNode) {
- pDocument->m_rgGlobalBinding[dwNameHash] = pDataNode;
-}
-
-CXFA_Node* ScopeMatchGlobalBinding(CXFA_Node* pDataScope,
- uint32_t dwNameHash,
- XFA_Element eMatchDataNodeType,
- bool bUpLevel) {
- for (CXFA_Node *pCurDataScope = pDataScope, *pLastDataScope = nullptr;
- pCurDataScope &&
- pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
- pLastDataScope = pCurDataScope,
- pCurDataScope = pCurDataScope->GetParent()) {
- for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
- pDataChild;
- pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
- if (pDataChild == pLastDataScope ||
- (eMatchDataNodeType != XFA_Element::DataModel &&
- pDataChild->GetElementType() != eMatchDataNodeType) ||
- pDataChild->HasBindItem()) {
- continue;
- }
- return pDataChild;
- }
-
- for (CXFA_DataGroup* pDataChild =
- pCurDataScope->GetFirstChildByClass<CXFA_DataGroup>(
- XFA_Element::DataGroup);
- pDataChild;
- pDataChild = pDataChild->GetNextSameClassSibling<CXFA_DataGroup>(
- XFA_Element::DataGroup)) {
- CXFA_Node* pDataNode = ScopeMatchGlobalBinding(pDataChild, dwNameHash,
- eMatchDataNodeType, false);
- if (pDataNode)
- return pDataNode;
- }
- if (!bUpLevel)
- break;
- }
- return nullptr;
-}
-
-CXFA_Node* FindGlobalDataNode(CXFA_Document* pDocument,
- const WideString& wsName,
- CXFA_Node* pDataScope,
- XFA_Element eMatchNodeType) {
- if (wsName.IsEmpty())
- return nullptr;
-
- uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
- CXFA_Node* pBounded = GetGlobalBinding(pDocument, dwNameHash);
- if (!pBounded) {
- pBounded =
- ScopeMatchGlobalBinding(pDataScope, dwNameHash, eMatchNodeType, true);
- if (pBounded)
- RegisterGlobalBinding(pDocument, dwNameHash, pBounded);
- }
- return pBounded;
-}
-
-CXFA_Node* FindOnceDataNode(CXFA_Document* pDocument,
- const WideString& wsName,
- CXFA_Node* pDataScope,
- XFA_Element eMatchNodeType) {
- if (wsName.IsEmpty())
- return nullptr;
-
- uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView(), false);
- CXFA_Node* pLastDataScope = nullptr;
- for (CXFA_Node* pCurDataScope = pDataScope;
- pCurDataScope &&
- pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
- pCurDataScope = pCurDataScope->GetParent()) {
- for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
- pDataChild;
- pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
- if (pDataChild == pLastDataScope || pDataChild->HasBindItem() ||
- (eMatchNodeType != XFA_Element::DataModel &&
- pDataChild->GetElementType() != eMatchNodeType)) {
- continue;
- }
- return pDataChild;
- }
- pLastDataScope = pCurDataScope;
- }
- return nullptr;
-}
-
-CXFA_Node* FindDataRefDataNode(CXFA_Document* pDocument,
- const WideString& wsRef,
- CXFA_Node* pDataScope,
- XFA_Element eMatchNodeType,
- CXFA_Node* pTemplateNode,
- bool bForceBind,
- bool bUpLevel) {
- uint32_t dFlags = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_BindNew;
- if (bUpLevel || wsRef != L"name")
- dFlags |= (XFA_RESOLVENODE_Parent | XFA_RESOLVENODE_Siblings);
-
- XFA_RESOLVENODE_RS rs;
- pDocument->GetScriptContext()->ResolveObjects(
- pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
- if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeAll ||
- rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeMidAll ||
- rs.objects.size() > 1) {
- return pDocument->GetNotBindNode(rs.objects);
- }
-
- if (rs.dwFlags == XFA_ResolveNode_RSType_CreateNodeOne) {
- CXFA_Object* pObject = !rs.objects.empty() ? rs.objects.front() : nullptr;
- CXFA_Node* pNode = ToNode(pObject);
- return (bForceBind || !pNode || !pNode->HasBindItem()) ? pNode : nullptr;
- }
- return nullptr;
-}
-
-bool NeedGenerateForm(CXFA_Node* pTemplateChild, bool bUseInstanceManager) {
+bool XFA_DataMerge_NeedGenerateForm(CXFA_Node* pTemplateChild,
+ bool bUseInstanceManager) {
XFA_Element eType = pTemplateChild->GetElementType();
if (eType == XFA_Element::Variables)
return true;
@@ -505,741 +22,6 @@ bool NeedGenerateForm(CXFA_Node* pTemplateChild, bool bUseInstanceManager) {
return true;
}
-CXFA_Node* CloneOrMergeInstanceManager(CXFA_Document* pDocument,
- CXFA_Node* pFormParent,
- CXFA_Node* pTemplateNode,
- std::vector<CXFA_Node*>* subforms) {
- WideString wsSubformName =
- pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
- WideString wsInstMgrNodeName = L"_" + wsSubformName;
- uint32_t dwInstNameHash =
- FX_HashCode_GetW(wsInstMgrNodeName.AsStringView(), false);
- CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
- pDocument, XFA_Element::InstanceManager, dwInstNameHash, pFormParent);
- if (pExistingNode) {
- uint32_t dwNameHash = pTemplateNode->GetNameHash();
- for (CXFA_Node* pNode = pExistingNode->GetNextSibling(); pNode;) {
- XFA_Element eCurType = pNode->GetElementType();
- if (eCurType == XFA_Element::InstanceManager)
- break;
-
- if ((eCurType != XFA_Element::Subform) &&
- (eCurType != XFA_Element::SubformSet)) {
- pNode = pNode->GetNextSibling();
- continue;
- }
- if (dwNameHash != pNode->GetNameHash())
- break;
-
- CXFA_Node* pNextNode = pNode->GetNextSibling();
- pFormParent->RemoveChild(pNode, true);
- subforms->push_back(pNode);
- pNode = pNextNode;
- }
- pFormParent->RemoveChild(pExistingNode, true);
- pFormParent->InsertChild(pExistingNode, nullptr);
- pExistingNode->ClearFlag(XFA_NodeFlag_UnusedNode);
- pExistingNode->SetTemplateNode(pTemplateNode);
- return pExistingNode;
- }
-
- CXFA_Node* pNewNode =
- pDocument->CreateNode(XFA_PacketType::Form, XFA_Element::InstanceManager);
- wsInstMgrNodeName =
- L"_" + pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
- pNewNode->JSObject()->SetCData(XFA_Attribute::Name, wsInstMgrNodeName, false,
- false);
- pFormParent->InsertChild(pNewNode, nullptr);
- pNewNode->SetTemplateNode(pTemplateNode);
- return pNewNode;
-}
-
-CXFA_Node* FindMatchingDataNode(
- CXFA_Document* pDocument,
- CXFA_Node* pTemplateNode,
- CXFA_Node* pDataScope,
- bool& bAccessedDataDOM,
- bool bForceBind,
- CXFA_NodeIteratorTemplate<CXFA_Node,
- CXFA_TraverseStrategy_XFAContainerNode>*
- pIterator,
- bool& bSelfMatch,
- XFA_AttributeEnum& eBindMatch,
- bool bUpLevel) {
- CXFA_Node* pResult = nullptr;
- CXFA_Node* pCurTemplateNode = pIterator->GetCurrent();
- while (pCurTemplateNode) {
- XFA_Element eMatchNodeType;
- switch (pCurTemplateNode->GetElementType()) {
- case XFA_Element::Subform:
- eMatchNodeType = XFA_Element::DataGroup;
- break;
- case XFA_Element::Field: {
- eMatchNodeType = XFA_FieldIsMultiListBox(pCurTemplateNode)
- ? XFA_Element::DataGroup
- : XFA_Element::DataValue;
- } break;
- case XFA_Element::ExclGroup:
- eMatchNodeType = XFA_Element::DataValue;
- break;
- default:
- pCurTemplateNode = pIterator->MoveToNext();
- continue;
- }
-
- CXFA_Occur* pTemplateNodeOccur =
- pCurTemplateNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
- if (pTemplateNodeOccur) {
- int32_t iMin;
- int32_t iMax;
- int32_t iInit;
- std::tie(iMin, iMax, iInit) = pTemplateNodeOccur->GetOccurInfo();
- if (iMax == 0) {
- pCurTemplateNode = pIterator->MoveToNext();
- continue;
- }
- }
-
- CXFA_Bind* pTemplateNodeBind =
- pCurTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind);
- XFA_AttributeEnum eMatch =
- pTemplateNodeBind
- ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
- : XFA_AttributeEnum::Once;
- eBindMatch = eMatch;
- switch (eMatch) {
- case XFA_AttributeEnum::None:
- pCurTemplateNode = pIterator->MoveToNext();
- continue;
- case XFA_AttributeEnum::Global:
- bAccessedDataDOM = true;
- if (!bForceBind) {
- pCurTemplateNode = pIterator->MoveToNext();
- continue;
- }
- if (eMatchNodeType == XFA_Element::DataValue ||
- (eMatchNodeType == XFA_Element::DataGroup &&
- XFA_FieldIsMultiListBox(pTemplateNodeBind))) {
- CXFA_Node* pGlobalBindNode = FindGlobalDataNode(
- pDocument,
- pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
- pDataScope, eMatchNodeType);
- if (!pGlobalBindNode) {
- pCurTemplateNode = pIterator->MoveToNext();
- continue;
- }
- pResult = pGlobalBindNode;
- break;
- }
- FX_FALLTHROUGH;
- case XFA_AttributeEnum::Once: {
- bAccessedDataDOM = true;
- CXFA_Node* pOnceBindNode = FindOnceDataNode(
- pDocument,
- pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
- pDataScope, eMatchNodeType);
- if (!pOnceBindNode) {
- pCurTemplateNode = pIterator->MoveToNext();
- continue;
- }
- pResult = pOnceBindNode;
- break;
- }
- case XFA_AttributeEnum::DataRef: {
- bAccessedDataDOM = true;
- CXFA_Node* pDataRefBindNode = FindDataRefDataNode(
- pDocument,
- pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref),
- pDataScope, eMatchNodeType, pTemplateNode, bForceBind, bUpLevel);
- if (pDataRefBindNode &&
- pDataRefBindNode->GetElementType() == eMatchNodeType) {
- pResult = pDataRefBindNode;
- }
- if (!pResult) {
- pCurTemplateNode = pIterator->SkipChildrenAndMoveToNext();
- continue;
- }
- break;
- }
- default:
- break;
- }
- if (pCurTemplateNode == pTemplateNode && pResult)
- bSelfMatch = true;
- break;
- }
- return pResult;
-}
-
-void SortRecurseRecord(std::vector<RecurseRecord>* rgRecords,
- CXFA_Node* pDataScope,
- bool bChoiceMode) {
- std::vector<RecurseRecord> rgResultRecord;
- for (CXFA_Node* pNode = pDataScope->GetFirstChild(); pNode;
- pNode = pNode->GetNextSibling()) {
- auto it = std::find_if(rgRecords->begin(), rgRecords->end(),
- [pNode](const RecurseRecord& record) {
- return pNode == record.pDataChild;
- });
- if (it != rgRecords->end()) {
- rgResultRecord.push_back(*it);
- rgRecords->erase(it);
- if (bChoiceMode)
- break;
- }
- }
- if (rgResultRecord.empty())
- return;
-
- if (!bChoiceMode) {
- rgResultRecord.insert(rgResultRecord.end(), rgRecords->begin(),
- rgRecords->end());
- }
- *rgRecords = rgResultRecord;
-}
-
-CXFA_Node* CopyContainer_SubformSet(CXFA_Document* pDocument,
- CXFA_Node* pTemplateNode,
- CXFA_Node* pFormParentNode,
- CXFA_Node* pDataScope,
- bool bOneInstance,
- bool bDataMerge) {
- XFA_Element eType = pTemplateNode->GetElementType();
- CXFA_Node* pOccurNode = nullptr;
- CXFA_Node* pFirstInstance = nullptr;
- bool bUseInstanceManager =
- pFormParentNode->GetElementType() != XFA_Element::Area;
- CXFA_Node* pInstMgrNode = nullptr;
- std::vector<CXFA_Node*> subformArray;
- std::vector<CXFA_Node*>* pSearchArray = nullptr;
- if (!bOneInstance &&
- (eType == XFA_Element::SubformSet || eType == XFA_Element::Subform)) {
- pInstMgrNode = bUseInstanceManager ? CloneOrMergeInstanceManager(
- pDocument, pFormParentNode,
- pTemplateNode, &subformArray)
- : nullptr;
- if (CXFA_Occur* pOccurTemplateNode =
- pTemplateNode->GetFirstChildByClass<CXFA_Occur>(
- XFA_Element::Occur)) {
- pOccurNode = pInstMgrNode ? XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pInstMgrNode,
- pOccurTemplateNode, false, nullptr)
- : pOccurTemplateNode;
- } else if (pInstMgrNode) {
- pOccurNode =
- pInstMgrNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
- if (pOccurNode)
- pOccurNode->ClearFlag(XFA_NodeFlag_UnusedNode);
- }
- if (pInstMgrNode) {
- pInstMgrNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
- pSearchArray = &subformArray;
- if (pFormParentNode->GetElementType() == XFA_Element::PageArea) {
- bOneInstance = true;
- if (subformArray.empty())
- pSearchArray = nullptr;
- } else if (pTemplateNode->GetNameHash() == 0 && subformArray.empty()) {
- pSearchArray = nullptr;
- }
- }
- }
-
- int32_t iMax = 1;
- int32_t iInit = 1;
- int32_t iMin = 1;
- if (!bOneInstance && pOccurNode) {
- std::tie(iMin, iMax, iInit) =
- static_cast<CXFA_Occur*>(pOccurNode)->GetOccurInfo();
- }
-
- XFA_AttributeEnum eRelation =
- eType == XFA_Element::SubformSet
- ? pTemplateNode->JSObject()->GetEnum(XFA_Attribute::Relation)
- : XFA_AttributeEnum::Ordered;
- int32_t iCurRepeatIndex = 0;
- XFA_AttributeEnum eParentBindMatch = XFA_AttributeEnum::None;
- if (bDataMerge) {
- CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
- sNodeIterator(pTemplateNode);
- bool bAccessedDataDOM = false;
- if (eType == XFA_Element::SubformSet || eType == XFA_Element::Area) {
- sNodeIterator.MoveToNext();
- } else {
- std::map<CXFA_Node*, CXFA_Node*> subformMapArray;
- std::vector<CXFA_Node*> nodeArray;
- for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
- bool bSelfMatch = false;
- XFA_AttributeEnum eBindMatch = XFA_AttributeEnum::None;
- CXFA_Node* pDataNode = FindMatchingDataNode(
- pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, false,
- &sNodeIterator, bSelfMatch, eBindMatch, true);
- if (!pDataNode || sNodeIterator.GetCurrent() != pTemplateNode)
- break;
-
- eParentBindMatch = eBindMatch;
- CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
- if (!pFirstInstance)
- pFirstInstance = pSubformNode;
-
- CreateDataBinding(pSubformNode, pDataNode, true);
- ASSERT(pSubformNode);
- subformMapArray[pSubformNode] = pDataNode;
- nodeArray.push_back(pSubformNode);
- }
-
- for (CXFA_Node* pSubform : nodeArray) {
- CXFA_Node* pDataNode = nullptr;
- auto it = subformMapArray.find(pSubform);
- if (it != subformMapArray.end())
- pDataNode = it->second;
- for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
- pTemplateChild;
- pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
- XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubform,
- pTemplateChild, true, nullptr);
- } else if (pTemplateChild->IsContainerNode()) {
- pDocument->DataMerge_CopyContainer(pTemplateChild, pSubform,
- pDataNode, false, true, false);
- }
- }
- }
- subformMapArray.clear();
- }
-
- for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
- bool bSelfMatch = false;
- XFA_AttributeEnum eBindMatch = XFA_AttributeEnum::None;
- if (!FindMatchingDataNode(pDocument, pTemplateNode, pDataScope,
- bAccessedDataDOM, false, &sNodeIterator,
- bSelfMatch, eBindMatch, true)) {
- break;
- }
- if (eBindMatch == XFA_AttributeEnum::DataRef &&
- eParentBindMatch == XFA_AttributeEnum::DataRef) {
- break;
- }
-
- if (eRelation == XFA_AttributeEnum::Choice ||
- eRelation == XFA_AttributeEnum::Unordered) {
- CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
- ASSERT(pSubformSetNode);
- if (!pFirstInstance)
- pFirstInstance = pSubformSetNode;
-
- std::vector<RecurseRecord> rgItemMatchList;
- std::vector<CXFA_Node*> rgItemUnmatchList;
- for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
- pTemplateChild;
- pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
- XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
- pTemplateChild, true, nullptr);
- } else if (pTemplateChild->IsContainerNode()) {
- bSelfMatch = false;
- eBindMatch = XFA_AttributeEnum::None;
- if (eRelation != XFA_AttributeEnum::Ordered) {
- CXFA_NodeIteratorTemplate<CXFA_Node,
- CXFA_TraverseStrategy_XFAContainerNode>
- sChildIter(pTemplateChild);
- CXFA_Node* pDataMatch = FindMatchingDataNode(
- pDocument, pTemplateChild, pDataScope, bAccessedDataDOM,
- false, &sChildIter, bSelfMatch, eBindMatch, true);
- if (pDataMatch) {
- RecurseRecord sNewRecord = {pTemplateChild, pDataMatch};
- if (bSelfMatch)
- rgItemMatchList.insert(rgItemMatchList.begin(), sNewRecord);
- else
- rgItemMatchList.push_back(sNewRecord);
- } else {
- rgItemUnmatchList.push_back(pTemplateChild);
- }
- } else {
- rgItemUnmatchList.push_back(pTemplateChild);
- }
- }
- }
-
- switch (eRelation) {
- case XFA_AttributeEnum::Choice: {
- ASSERT(!rgItemMatchList.empty());
- SortRecurseRecord(&rgItemMatchList, pDataScope, true);
- pDocument->DataMerge_CopyContainer(
- rgItemMatchList.front().pTemplateChild, pSubformSetNode,
- pDataScope, false, true, true);
- break;
- }
- case XFA_AttributeEnum::Unordered: {
- if (!rgItemMatchList.empty()) {
- SortRecurseRecord(&rgItemMatchList, pDataScope, false);
- for (const auto& matched : rgItemMatchList) {
- pDocument->DataMerge_CopyContainer(matched.pTemplateChild,
- pSubformSetNode, pDataScope,
- false, true, true);
- }
- }
- for (auto* unmatched : rgItemUnmatchList) {
- pDocument->DataMerge_CopyContainer(unmatched, pSubformSetNode,
- pDataScope, false, true, true);
- }
- break;
- }
- default:
- break;
- }
- } else {
- CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
- ASSERT(pSubformSetNode);
- if (!pFirstInstance)
- pFirstInstance = pSubformSetNode;
-
- for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
- pTemplateChild;
- pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
- XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
- pTemplateChild, true, nullptr);
- } else if (pTemplateChild->IsContainerNode()) {
- pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
- pDataScope, false, true, true);
- }
- }
- }
- }
-
- if (iCurRepeatIndex == 0 && bAccessedDataDOM == false) {
- int32_t iLimit = iMax;
- if (pInstMgrNode && pTemplateNode->GetNameHash() == 0) {
- iLimit = pdfium::CollectionSize<int32_t>(subformArray);
- if (iLimit < iMin)
- iLimit = iInit;
- }
-
- for (; (iLimit < 0 || iCurRepeatIndex < iLimit); iCurRepeatIndex++) {
- if (pInstMgrNode) {
- if (pSearchArray && pSearchArray->empty()) {
- if (pTemplateNode->GetNameHash() != 0)
- break;
- pSearchArray = nullptr;
- }
- } else if (!XFA_DataMerge_FindFormDOMInstance(
- pDocument, pTemplateNode->GetElementType(),
- pTemplateNode->GetNameHash(), pFormParentNode)) {
- break;
- }
- CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
- ASSERT(pSubformNode);
- if (!pFirstInstance)
- pFirstInstance = pSubformNode;
-
- for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
- pTemplateChild;
- pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
- XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformNode,
- pTemplateChild, true, nullptr);
- } else if (pTemplateChild->IsContainerNode()) {
- pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformNode,
- pDataScope, false, true, true);
- }
- }
- }
- }
- }
-
- int32_t iMinimalLimit = iCurRepeatIndex == 0 ? iInit : iMin;
- for (; iCurRepeatIndex < iMinimalLimit; iCurRepeatIndex++) {
- CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
- ASSERT(pSubformSetNode);
- if (!pFirstInstance)
- pFirstInstance = pSubformSetNode;
-
- bool bFound = false;
- for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
- pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
- XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
- pTemplateChild, true, nullptr);
- } else if (pTemplateChild->IsContainerNode()) {
- if (bFound && eRelation == XFA_AttributeEnum::Choice)
- continue;
-
- pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
- pDataScope, false, bDataMerge, true);
- bFound = true;
- }
- }
- }
- return pFirstInstance;
-}
-
-CXFA_Node* CopyContainer_Field(CXFA_Document* pDocument,
- CXFA_Node* pTemplateNode,
- CXFA_Node* pFormNode,
- CXFA_Node* pDataScope,
- bool bDataMerge,
- bool bUpLevel) {
- CXFA_Node* pFieldNode = XFA_NodeMerge_CloneOrMergeContainer(
- pDocument, pFormNode, pTemplateNode, false, nullptr);
- ASSERT(pFieldNode);
- for (CXFA_Node* pTemplateChildNode = pTemplateNode->GetFirstChild();
- pTemplateChildNode;
- pTemplateChildNode = pTemplateChildNode->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChildNode, true)) {
- XFA_NodeMerge_CloneOrMergeContainer(pDocument, pFieldNode,
- pTemplateChildNode, true, nullptr);
- } else if (pTemplateNode->GetElementType() == XFA_Element::ExclGroup &&
- pTemplateChildNode->IsContainerNode()) {
- if (pTemplateChildNode->GetElementType() == XFA_Element::Field) {
- CopyContainer_Field(pDocument, pTemplateChildNode, pFieldNode, nullptr,
- false, true);
- }
- }
- }
- if (bDataMerge) {
- bool bAccessedDataDOM = false;
- bool bSelfMatch = false;
- XFA_AttributeEnum eBindMatch;
- CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
- sNodeIter(pTemplateNode);
- CXFA_Node* pDataNode = FindMatchingDataNode(
- pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, true,
- &sNodeIter, bSelfMatch, eBindMatch, bUpLevel);
- if (pDataNode)
- CreateDataBinding(pFieldNode, pDataNode, true);
- } else {
- FormValueNode_MatchNoneCreateChild(pFieldNode);
- }
- return pFieldNode;
-}
-
-CXFA_Node* MaybeCreateDataNode(CXFA_Document* pDocument,
- CXFA_Node* pDataParent,
- XFA_Element eNodeType,
- const WideString& wsName) {
- if (!pDataParent)
- return nullptr;
-
- CXFA_Node* pParentDDNode = pDataParent->GetDataDescriptionNode();
- if (!pParentDDNode) {
- CXFA_Node* pDataNode =
- pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
- pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
- pDataNode->CreateXMLMappingNode();
- pDataParent->InsertChild(pDataNode, nullptr);
- pDataNode->SetFlag(XFA_NodeFlag_Initialized);
- return pDataNode;
- }
-
- CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup> sIterator(
- pParentDDNode);
- for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
- pDDGroupNode = sIterator.MoveToNext()) {
- if (pDDGroupNode != pParentDDNode) {
- if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
- continue;
-
- Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
- if (!ns || *ns != L"http://ns.adobe.com/data-description/")
- continue;
- }
-
- CXFA_Node* pDDNode =
- pDDGroupNode->GetFirstChildByName(wsName.AsStringView());
- if (!pDDNode)
- continue;
- if (pDDNode->GetElementType() != eNodeType)
- break;
-
- CXFA_Node* pDataNode =
- pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
- pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName, false, false);
- pDataNode->CreateXMLMappingNode();
- if (eNodeType == XFA_Element::DataValue &&
- pDDNode->JSObject()->GetEnum(XFA_Attribute::Contains) ==
- XFA_AttributeEnum::MetaData) {
- pDataNode->JSObject()->SetEnum(XFA_Attribute::Contains,
- XFA_AttributeEnum::MetaData, false);
- }
- pDataParent->InsertChild(pDataNode, nullptr);
- pDataNode->SetDataDescriptionNode(pDDNode);
- pDataNode->SetFlag(XFA_NodeFlag_Initialized);
- return pDataNode;
- }
- return nullptr;
-}
-
-void UpdateBindingRelations(CXFA_Document* pDocument,
- CXFA_Node* pFormNode,
- CXFA_Node* pDataScope,
- bool bDataRef,
- bool bParentDataRef) {
- bool bMatchRef = true;
- XFA_Element eType = pFormNode->GetElementType();
- CXFA_Node* pDataNode = pFormNode->GetBindData();
- if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup ||
- eType == XFA_Element::Field) {
- CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
- CXFA_Bind* pTemplateNodeBind =
- pTemplateNode
- ? pTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind)
- : nullptr;
- XFA_AttributeEnum eMatch =
- pTemplateNodeBind
- ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
- : XFA_AttributeEnum::Once;
- switch (eMatch) {
- case XFA_AttributeEnum::None:
- if (!bDataRef || bParentDataRef)
- FormValueNode_MatchNoneCreateChild(pFormNode);
- break;
- case XFA_AttributeEnum::Once:
- if (!bDataRef || bParentDataRef) {
- if (!pDataNode) {
- if (pFormNode->GetNameHash() != 0 &&
- pFormNode->JSObject()->GetEnum(XFA_Attribute::Scope) !=
- XFA_AttributeEnum::None) {
- XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
- XFA_FieldIsMultiListBox(pFormNode))
- ? XFA_Element::DataGroup
- : XFA_Element::DataValue;
- pDataNode = MaybeCreateDataNode(
- pDocument, pDataScope, eDataNodeType,
- WideString(
- pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
- if (pDataNode)
- CreateDataBinding(pFormNode, pDataNode, false);
- }
- if (!pDataNode)
- FormValueNode_MatchNoneCreateChild(pFormNode);
-
- } else {
- CXFA_Node* pDataParent = pDataNode->GetParent();
- if (pDataParent != pDataScope) {
- ASSERT(pDataParent);
- pDataParent->RemoveChild(pDataNode, true);
- pDataScope->InsertChild(pDataNode, nullptr);
- }
- }
- }
- break;
- case XFA_AttributeEnum::Global:
- if (!bDataRef || bParentDataRef) {
- uint32_t dwNameHash = pFormNode->GetNameHash();
- if (dwNameHash != 0 && !pDataNode) {
- pDataNode = GetGlobalBinding(pDocument, dwNameHash);
- if (!pDataNode) {
- XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
- XFA_FieldIsMultiListBox(pFormNode))
- ? XFA_Element::DataGroup
- : XFA_Element::DataValue;
- CXFA_Node* pRecordNode =
- ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
- pDataNode = MaybeCreateDataNode(
- pDocument, pRecordNode, eDataNodeType,
- WideString(
- pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
- if (pDataNode) {
- CreateDataBinding(pFormNode, pDataNode, false);
- RegisterGlobalBinding(pDocument, pFormNode->GetNameHash(),
- pDataNode);
- }
- } else {
- CreateDataBinding(pFormNode, pDataNode, true);
- }
- }
- if (!pDataNode)
- FormValueNode_MatchNoneCreateChild(pFormNode);
- }
- break;
- case XFA_AttributeEnum::DataRef: {
- bMatchRef = bDataRef;
- bParentDataRef = true;
- if (!pDataNode && bDataRef) {
- WideString wsRef =
- pTemplateNodeBind
- ? pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref)
- : L"";
- uint32_t dFlags =
- XFA_RESOLVENODE_Children | XFA_RESOLVENODE_CreateNode;
- XFA_RESOLVENODE_RS rs;
- pDocument->GetScriptContext()->ResolveObjects(
- pDataScope, wsRef.AsStringView(), &rs, dFlags, pTemplateNode);
- CXFA_Object* pObject =
- !rs.objects.empty() ? rs.objects.front() : nullptr;
- pDataNode = ToNode(pObject);
- if (pDataNode) {
- CreateDataBinding(pFormNode, pDataNode,
- rs.dwFlags == XFA_ResolveNode_RSType_ExistNodes);
- } else {
- FormValueNode_MatchNoneCreateChild(pFormNode);
- }
- }
- break;
- }
- default:
- break;
- }
- }
-
- if (bMatchRef &&
- (eType == XFA_Element::Subform || eType == XFA_Element::SubformSet ||
- eType == XFA_Element::Area || eType == XFA_Element::PageArea ||
- eType == XFA_Element::PageSet)) {
- for (CXFA_Node* pFormChild = pFormNode->GetFirstChild(); pFormChild;
- pFormChild = pFormChild->GetNextSibling()) {
- if (!pFormChild->IsContainerNode())
- continue;
- if (pFormChild->IsUnusedNode())
- continue;
-
- UpdateBindingRelations(pDocument, pFormChild,
- pDataNode ? pDataNode : pDataScope, bDataRef,
- bParentDataRef);
- }
- }
-}
-
-void UpdateDataRelation(CXFA_Node* pDataNode, CXFA_Node* pDataDescriptionNode) {
- ASSERT(pDataDescriptionNode);
- for (CXFA_Node* pDataChild = pDataNode->GetFirstChild(); pDataChild;
- pDataChild = pDataChild->GetNextSibling()) {
- uint32_t dwNameHash = pDataChild->GetNameHash();
- if (!dwNameHash)
- continue;
-
- CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup>
- sIterator(pDataDescriptionNode);
- for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
- pDDGroupNode = sIterator.MoveToNext()) {
- if (pDDGroupNode != pDataDescriptionNode) {
- if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
- continue;
-
- Optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
- if (!ns || *ns != L"http://ns.adobe.com/data-description/")
- continue;
- }
-
- CXFA_Node* pDDNode = pDDGroupNode->GetFirstChildByName(dwNameHash);
- if (!pDDNode)
- continue;
- if (pDDNode->GetElementType() != pDataChild->GetElementType())
- break;
-
- pDataChild->SetDataDescriptionNode(pDDNode);
- UpdateDataRelation(pDataChild, pDDNode);
- break;
- }
- }
-}
-
-} // namespace
CXFA_Node* XFA_DataMerge_FindFormDOMInstance(CXFA_Document* pDocument,
XFA_Element eType,
@@ -1282,7 +64,7 @@ CXFA_Node* XFA_NodeMerge_CloneOrMergeContainer(
if (bRecursive && pExistingNode->GetElementType() != XFA_Element::Items) {
for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, true)) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
XFA_NodeMerge_CloneOrMergeContainer(
pDocument, pExistingNode, pTemplateChild, bRecursive, nullptr);
}
@@ -1297,7 +79,7 @@ CXFA_Node* XFA_NodeMerge_CloneOrMergeContainer(
if (bRecursive) {
for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, true)) {
+ if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
CXFA_Node* pNewChild = pTemplateChild->CloneTemplateToForm(true);
pNewNode->InsertChild(pNewChild, nullptr);
}
@@ -1318,231 +100,3 @@ CXFA_Node* XFA_DataMerge_FindDataScope(CXFA_Node* pParentFormNode) {
pParentFormNode->GetDocument()->GetXFAObject(XFA_HASHCODE_Data));
}
-CXFA_Node* CXFA_Document::DataMerge_CopyContainer(CXFA_Node* pTemplateNode,
- CXFA_Node* pFormNode,
- CXFA_Node* pDataScope,
- bool bOneInstance,
- bool bDataMerge,
- bool bUpLevel) {
- switch (pTemplateNode->GetElementType()) {
- case XFA_Element::SubformSet:
- case XFA_Element::Subform:
- case XFA_Element::Area:
- case XFA_Element::PageArea:
- return CopyContainer_SubformSet(this, pTemplateNode, pFormNode,
- pDataScope, bOneInstance, bDataMerge);
- case XFA_Element::ExclGroup:
- case XFA_Element::Field:
- case XFA_Element::Draw:
- case XFA_Element::ContentArea:
- return CopyContainer_Field(this, pTemplateNode, pFormNode, pDataScope,
- bDataMerge, bUpLevel);
- case XFA_Element::PageSet:
- case XFA_Element::Variables:
- break;
- default:
- NOTREACHED();
- break;
- }
- return nullptr;
-}
-
-void CXFA_Document::DataMerge_UpdateBindingRelations(
- CXFA_Node* pFormUpdateRoot) {
- CXFA_Node* pDataScope =
- XFA_DataMerge_FindDataScope(pFormUpdateRoot->GetParent());
- if (!pDataScope)
- return;
-
- UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, false, false);
- UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, true, false);
-}
-
-CXFA_Node* CXFA_Document::GetNotBindNode(
- const std::vector<CXFA_Object*>& arrayObjects) const {
- for (CXFA_Object* pObject : arrayObjects) {
- CXFA_Node* pNode = pObject->AsNode();
- if (pNode && !pNode->HasBindItem())
- return pNode;
- }
- return nullptr;
-}
-
-void CXFA_Document::DoDataMerge() {
- CXFA_Node* pDatasetsRoot = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
- if (!pDatasetsRoot) {
- // Ownership will be passed in the AppendChild below to the XML tree.
- auto pDatasetsXMLNode = pdfium::MakeUnique<CFX_XMLElement>(L"xfa:datasets");
- pDatasetsXMLNode->SetString(L"xmlns:xfa",
- L"http://www.xfa.org/schema/xfa-data/1.0/");
- pDatasetsRoot =
- CreateNode(XFA_PacketType::Datasets, XFA_Element::DataModel);
- pDatasetsRoot->JSObject()->SetCData(XFA_Attribute::Name, L"datasets", false,
- false);
-
- CFX_XMLElement* ref = pDatasetsXMLNode.get();
- m_pRootNode->GetXMLMappingNode()->AppendChild(pDatasetsXMLNode.release());
- m_pRootNode->InsertChild(pDatasetsRoot, nullptr);
- pDatasetsRoot->SetXMLMappingNode(ref);
- }
-
- CXFA_Node *pDataRoot = nullptr, *pDDRoot = nullptr;
- WideString wsDatasetsURI =
- pDatasetsRoot->JSObject()->TryNamespace().value_or(WideString());
- for (CXFA_Node* pChildNode = pDatasetsRoot->GetFirstChild(); pChildNode;
- pChildNode = pChildNode->GetNextSibling()) {
- if (pChildNode->GetElementType() != XFA_Element::DataGroup)
- continue;
-
- if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
- Optional<WideString> namespaceURI =
- pChildNode->JSObject()->TryNamespace();
- if (!namespaceURI)
- continue;
- if (*namespaceURI == L"http://ns.adobe.com/data-description/")
- pDDRoot = pChildNode;
- } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
- Optional<WideString> namespaceURI =
- pChildNode->JSObject()->TryNamespace();
- if (!namespaceURI)
- continue;
- if (*namespaceURI == wsDatasetsURI)
- pDataRoot = pChildNode;
- }
- if (pDataRoot && pDDRoot)
- break;
- }
-
- if (!pDataRoot) {
- pDataRoot = CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
- pDataRoot->JSObject()->SetCData(XFA_Attribute::Name, L"data", false, false);
- pDataRoot->SetXMLMappingNode(
- pdfium::MakeUnique<CFX_XMLElement>(L"xfa:data"));
- pDatasetsRoot->InsertChild(pDataRoot, nullptr);
- }
-
- CXFA_DataGroup* pDataTopLevel =
- pDataRoot->GetFirstChildByClass<CXFA_DataGroup>(XFA_Element::DataGroup);
- uint32_t dwNameHash = pDataTopLevel ? pDataTopLevel->GetNameHash() : 0;
- CXFA_Template* pTemplateRoot =
- m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
- if (!pTemplateRoot)
- return;
-
- CXFA_Node* pTemplateChosen =
- dwNameHash != 0 ? pTemplateRoot->GetFirstChildByName(dwNameHash)
- : nullptr;
- if (!pTemplateChosen ||
- pTemplateChosen->GetElementType() != XFA_Element::Subform) {
- pTemplateChosen =
- pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
- }
- if (!pTemplateChosen)
- return;
-
- CXFA_Form* pFormRoot =
- m_pRootNode->GetFirstChildByClass<CXFA_Form>(XFA_Element::Form);
- bool bEmptyForm = false;
- if (!pFormRoot) {
- bEmptyForm = true;
- pFormRoot = static_cast<CXFA_Form*>(
- CreateNode(XFA_PacketType::Form, XFA_Element::Form));
- ASSERT(pFormRoot);
- pFormRoot->JSObject()->SetCData(XFA_Attribute::Name, L"form", false, false);
- m_pRootNode->InsertChild(pFormRoot, nullptr);
- } else {
- CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
- sIterator(pFormRoot);
- for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
- pNode = sIterator.MoveToNext()) {
- pNode->SetFlag(XFA_NodeFlag_UnusedNode);
- }
- }
-
- CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
- this, pFormRoot, pTemplateChosen, false, nullptr);
- ASSERT(pSubformSetNode);
- if (!pDataTopLevel) {
- WideString wsFormName =
- pSubformSetNode->JSObject()->GetCData(XFA_Attribute::Name);
- WideString wsDataTopLevelName(wsFormName.IsEmpty() ? L"form" : wsFormName);
-
- pDataTopLevel = static_cast<CXFA_DataGroup*>(
- CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup));
- pDataTopLevel->JSObject()->SetCData(XFA_Attribute::Name, wsDataTopLevelName,
- false, false);
- pDataTopLevel->SetXMLMappingNode(
- pdfium::MakeUnique<CFX_XMLElement>(wsDataTopLevelName));
-
- CXFA_Node* pBeforeNode = pDataRoot->GetFirstChild();
- pDataRoot->InsertChild(pDataTopLevel, pBeforeNode);
- }
-
- ASSERT(pDataTopLevel);
- CreateDataBinding(pSubformSetNode, pDataTopLevel, true);
- for (CXFA_Node* pTemplateChild = pTemplateChosen->GetFirstChild();
- pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
- if (NeedGenerateForm(pTemplateChild, true)) {
- XFA_NodeMerge_CloneOrMergeContainer(this, pSubformSetNode, pTemplateChild,
- true, nullptr);
- } else if (pTemplateChild->IsContainerNode()) {
- DataMerge_CopyContainer(pTemplateChild, pSubformSetNode, pDataTopLevel,
- false, true, true);
- }
- }
- if (pDDRoot)
- UpdateDataRelation(pDataRoot, pDDRoot);
-
- DataMerge_UpdateBindingRelations(pSubformSetNode);
- CXFA_PageSet* pPageSetNode =
- pSubformSetNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
- while (pPageSetNode) {
- m_pPendingPageSet.push_back(pPageSetNode);
- CXFA_PageSet* pNextPageSetNode =
- pPageSetNode->GetNextSameClassSibling<CXFA_PageSet>(
- XFA_Element::PageSet);
- pSubformSetNode->RemoveChild(pPageSetNode, true);
- pPageSetNode = pNextPageSetNode;
- }
-
- if (bEmptyForm)
- return;
-
- CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
- pFormRoot);
- CXFA_Node* pNode = sIterator.MoveToNext();
- while (pNode) {
- if (pNode->IsUnusedNode()) {
- if (pNode->IsContainerNode() ||
- pNode->GetElementType() == XFA_Element::InstanceManager) {
- CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
- pNode->GetParent()->RemoveChild(pNode, true);
- pNode = pNext;
- } else {
- pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
- pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
- pNode = sIterator.MoveToNext();
- }
- } else {
- pNode->SetFlagAndNotify(XFA_NodeFlag_Initialized);
- pNode = sIterator.MoveToNext();
- }
- }
-}
-
-void CXFA_Document::DoDataRemerge(bool bDoDataMerge) {
- CXFA_Node* pFormRoot = ToNode(GetXFAObject(XFA_HASHCODE_Form));
- if (pFormRoot) {
- while (CXFA_Node* pNode = pFormRoot->GetFirstChild())
- pFormRoot->RemoveChild(pNode, true);
-
- pFormRoot->SetBindingNode(nullptr);
- }
- m_rgGlobalBinding.clear();
-
- if (bDoDataMerge)
- DoDataMerge();
-
- CXFA_LayoutProcessor* pLayoutProcessor = GetLayoutProcessor();
- pLayoutProcessor->SetForceReLayout(true);
-}
diff --git a/xfa/fxfa/parser/xfa_document_datamerger_imp.h b/xfa/fxfa/parser/xfa_document_datamerger_imp.h
index 9e58678867..d2c84d3778 100644
--- a/xfa/fxfa/parser/xfa_document_datamerger_imp.h
+++ b/xfa/fxfa/parser/xfa_document_datamerger_imp.h
@@ -14,6 +14,8 @@
class CXFA_Document;
class CXFA_Node;
+bool XFA_DataMerge_NeedGenerateForm(CXFA_Node* pTemplateChild,
+ bool bUseInstanceManager);
CXFA_Node* XFA_NodeMerge_CloneOrMergeContainer(
CXFA_Document* pDocument,
CXFA_Node* pFormParent,