diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2018-04-05 18:32:35 +0000 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2018-04-05 18:32:35 +0000 |
commit | 4a979709304592be8511458793463aa2570bd7af (patch) | |
tree | 8ffc233f5d7852a998f460d5359fb97d3c5ffad7 /xfa/fxfa | |
parent | b948046fe797880295d0706f80831d279db75b5a (diff) | |
download | pdfium-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')
-rw-r--r-- | xfa/fxfa/parser/cxfa_document.cpp | 1431 | ||||
-rw-r--r-- | xfa/fxfa/parser/xfa_document_datamerger_imp.cpp | 1454 | ||||
-rw-r--r-- | xfa/fxfa/parser/xfa_document_datamerger_imp.h | 2 |
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, |