• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "xfa/fxfa/parser/cxfa_document.h"
8 
9 #include <set>
10 #include <utility>
11 
12 #include "core/fxcrt/check.h"
13 #include "core/fxcrt/check_op.h"
14 #include "core/fxcrt/fx_extension.h"
15 #include "core/fxcrt/notreached.h"
16 #include "core/fxcrt/stl_util.h"
17 #include "core/fxcrt/xml/cfx_xmldocument.h"
18 #include "core/fxcrt/xml/cfx_xmlelement.h"
19 #include "fxjs/gc/container_trace.h"
20 #include "fxjs/xfa/cfxjse_engine.h"
21 #include "fxjs/xfa/cfxjse_resolveprocessor.h"
22 #include "fxjs/xfa/cjx_object.h"
23 #include "xfa/fxfa/cxfa_ffdoc.h"
24 #include "xfa/fxfa/cxfa_ffnotify.h"
25 #include "xfa/fxfa/parser/cscript_datawindow.h"
26 #include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
27 #include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
28 #include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
29 #include "xfa/fxfa/parser/cscript_logpseudomodel.h"
30 #include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
31 #include "xfa/fxfa/parser/cxfa_bind.h"
32 #include "xfa/fxfa/parser/cxfa_datagroup.h"
33 #include "xfa/fxfa/parser/cxfa_exdata.h"
34 #include "xfa/fxfa/parser/cxfa_form.h"
35 #include "xfa/fxfa/parser/cxfa_image.h"
36 #include "xfa/fxfa/parser/cxfa_interactive.h"
37 #include "xfa/fxfa/parser/cxfa_items.h"
38 #include "xfa/fxfa/parser/cxfa_localemgr.h"
39 #include "xfa/fxfa/parser/cxfa_node.h"
40 #include "xfa/fxfa/parser/cxfa_occur.h"
41 #include "xfa/fxfa/parser/cxfa_pageset.h"
42 #include "xfa/fxfa/parser/cxfa_pdf.h"
43 #include "xfa/fxfa/parser/cxfa_present.h"
44 #include "xfa/fxfa/parser/cxfa_subform.h"
45 #include "xfa/fxfa/parser/cxfa_template.h"
46 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfacontainernode.h"
47 #include "xfa/fxfa/parser/cxfa_traversestrategy_xfanode.h"
48 #include "xfa/fxfa/parser/cxfa_value.h"
49 #include "xfa/fxfa/parser/xfa_document_datamerger_imp.h"
50 #include "xfa/fxfa/parser/xfa_utils.h"
51 
52 namespace {
53 
54 const wchar_t kTemplateNS[] = L"http://www.xfa.org/schema/xfa-template/";
55 
56 struct RecurseRecord {
57   cppgc::Persistent<CXFA_Node> pTemplateChild;
58   cppgc::Persistent<CXFA_Node> pDataChild;
59 };
60 
61 class CXFA_TraverseStrategy_DDGroup {
62  public:
GetFirstChild(CXFA_Node * pDDGroupNode)63   static CXFA_Node* GetFirstChild(CXFA_Node* pDDGroupNode) {
64     return pDDGroupNode->GetFirstChildByName(XFA_HASHCODE_Group);
65   }
GetNextSibling(CXFA_Node * pDDGroupNode)66   static CXFA_Node* GetNextSibling(CXFA_Node* pDDGroupNode) {
67     return pDDGroupNode->GetNextSameNameSibling(XFA_HASHCODE_Group);
68   }
GetParent(CXFA_Node * pDDGroupNode)69   static CXFA_Node* GetParent(CXFA_Node* pDDGroupNode) {
70     return pDDGroupNode->GetParent();
71   }
72 };
73 
FormValueNode_MatchNoneCreateChild(CXFA_Node * pFormNode)74 void FormValueNode_MatchNoneCreateChild(CXFA_Node* pFormNode) {
75   DCHECK(pFormNode->IsWidgetReady());
76   // GetUIChildNode has the side effect of creating the UI child.
77   pFormNode->GetUIChildNode();
78 }
79 
FormValueNode_CreateChild(CXFA_Node * pValueNode,XFA_Element iType)80 CXFA_Node* FormValueNode_CreateChild(CXFA_Node* pValueNode, XFA_Element iType) {
81   CXFA_Node* pChildNode = pValueNode->GetFirstChild();
82   if (!pChildNode) {
83     if (iType == XFA_Element::Unknown)
84       return nullptr;
85 
86     pChildNode =
87         pValueNode->JSObject()->GetOrCreateProperty<CXFA_Node>(0, iType);
88   }
89   return pChildNode;
90 }
91 
FormValueNode_SetChildContent(CXFA_Node * pValueNode,const WideString & wsContent,XFA_Element iType)92 void FormValueNode_SetChildContent(CXFA_Node* pValueNode,
93                                    const WideString& wsContent,
94                                    XFA_Element iType) {
95   if (!pValueNode)
96     return;
97 
98   DCHECK_EQ(pValueNode->GetPacketType(), XFA_PacketType::Form);
99   CXFA_Node* pChildNode = FormValueNode_CreateChild(pValueNode, iType);
100   if (!pChildNode)
101     return;
102 
103   switch (pChildNode->GetObjectType()) {
104     case XFA_ObjectType::ContentNode: {
105       CXFA_Node* pContentRawDataNode = pChildNode->GetFirstChild();
106       if (!pContentRawDataNode) {
107         XFA_Element element = XFA_Element::Sharptext;
108         if (pChildNode->GetElementType() == XFA_Element::ExData) {
109           std::optional<WideString> contentType =
110               pChildNode->JSObject()->TryAttribute(XFA_Attribute::ContentType,
111                                                    false);
112           if (contentType.has_value()) {
113             if (contentType.value().EqualsASCII("text/html"))
114               element = XFA_Element::SharpxHTML;
115             else if (contentType.value().EqualsASCII("text/xml"))
116               element = XFA_Element::Sharpxml;
117           }
118         }
119         pContentRawDataNode = pChildNode->CreateSamePacketNode(element);
120         pChildNode->InsertChildAndNotify(pContentRawDataNode, nullptr);
121       }
122       pContentRawDataNode->JSObject()->SetCData(XFA_Attribute::Value,
123                                                 wsContent);
124       break;
125     }
126     case XFA_ObjectType::NodeC:
127     case XFA_ObjectType::TextNode:
128     case XFA_ObjectType::NodeV: {
129       pChildNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent);
130       break;
131     }
132     default:
133       break;
134   }
135 }
136 
MergeNodeRecurse(CXFA_Node * pDestNodeParent,CXFA_Node * pProtoNode)137 void MergeNodeRecurse(CXFA_Node* pDestNodeParent, CXFA_Node* pProtoNode) {
138   CXFA_Node* pExistingNode = nullptr;
139   for (CXFA_Node* pFormChild = pDestNodeParent->GetFirstChild(); pFormChild;
140        pFormChild = pFormChild->GetNextSibling()) {
141     if (pFormChild->GetElementType() == pProtoNode->GetElementType() &&
142         pFormChild->GetNameHash() == pProtoNode->GetNameHash() &&
143         pFormChild->IsUnusedNode()) {
144       pFormChild->ClearFlag(XFA_NodeFlag::kUnusedNode);
145       pExistingNode = pFormChild;
146       break;
147     }
148   }
149 
150   if (pExistingNode) {
151     pExistingNode->SetTemplateNode(pProtoNode);
152     for (CXFA_Node* pTemplateChild = pProtoNode->GetFirstChild();
153          pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
154       MergeNodeRecurse(pExistingNode, pTemplateChild);
155     }
156     return;
157   }
158   CXFA_Node* pNewNode = pProtoNode->Clone(true);
159   pNewNode->SetTemplateNode(pProtoNode);
160   pDestNodeParent->InsertChildAndNotify(pNewNode, nullptr);
161 }
162 
MergeNode(CXFA_Node * pDestNode,CXFA_Node * pProtoNode)163 void MergeNode(CXFA_Node* pDestNode, CXFA_Node* pProtoNode) {
164   {
165     CXFA_NodeIterator sIterator(pDestNode);
166     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
167          pNode = sIterator.MoveToNext()) {
168       pNode->SetFlag(XFA_NodeFlag::kUnusedNode);
169     }
170   }
171   pDestNode->SetTemplateNode(pProtoNode);
172   for (CXFA_Node* pTemplateChild = pProtoNode->GetFirstChild(); pTemplateChild;
173        pTemplateChild = pTemplateChild->GetNextSibling()) {
174     MergeNodeRecurse(pDestNode, pTemplateChild);
175   }
176   {
177     CXFA_NodeIterator sIterator(pDestNode);
178     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
179          pNode = sIterator.MoveToNext()) {
180       pNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
181     }
182   }
183 }
184 
CloneOrMergeInstanceManager(CXFA_Document * pDocument,CXFA_Node * pFormParent,CXFA_Node * pTemplateNode,std::vector<CXFA_Node * > * subforms)185 CXFA_Node* CloneOrMergeInstanceManager(CXFA_Document* pDocument,
186                                        CXFA_Node* pFormParent,
187                                        CXFA_Node* pTemplateNode,
188                                        std::vector<CXFA_Node*>* subforms) {
189   WideString wsSubformName =
190       pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
191   WideString wsInstMgrNodeName = L"_" + wsSubformName;
192   uint32_t dwInstNameHash = FX_HashCode_GetW(wsInstMgrNodeName.AsStringView());
193   CXFA_Node* pExistingNode = XFA_DataMerge_FindFormDOMInstance(
194       pDocument, XFA_Element::InstanceManager, dwInstNameHash, pFormParent);
195   if (pExistingNode) {
196     uint32_t dwNameHash = pTemplateNode->GetNameHash();
197     for (CXFA_Node* pNode = pExistingNode->GetNextSibling(); pNode;) {
198       XFA_Element eCurType = pNode->GetElementType();
199       if (eCurType == XFA_Element::InstanceManager)
200         break;
201 
202       if ((eCurType != XFA_Element::Subform) &&
203           (eCurType != XFA_Element::SubformSet)) {
204         pNode = pNode->GetNextSibling();
205         continue;
206       }
207       if (dwNameHash != pNode->GetNameHash())
208         break;
209 
210       CXFA_Node* pNextNode = pNode->GetNextSibling();
211       pFormParent->RemoveChildAndNotify(pNode, true);
212       subforms->push_back(pNode);
213       pNode = pNextNode;
214     }
215     pFormParent->RemoveChildAndNotify(pExistingNode, true);
216     pFormParent->InsertChildAndNotify(pExistingNode, nullptr);
217     pExistingNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
218     pExistingNode->SetTemplateNode(pTemplateNode);
219     return pExistingNode;
220   }
221 
222   CXFA_Node* pNewNode =
223       pDocument->CreateNode(XFA_PacketType::Form, XFA_Element::InstanceManager);
224   wsInstMgrNodeName =
225       L"_" + pTemplateNode->JSObject()->GetCData(XFA_Attribute::Name);
226   pNewNode->JSObject()->SetCData(XFA_Attribute::Name, wsInstMgrNodeName);
227   pFormParent->InsertChildAndNotify(pNewNode, nullptr);
228   pNewNode->SetTemplateNode(pTemplateNode);
229   return pNewNode;
230 }
231 
SortRecurseRecord(std::vector<RecurseRecord> * rgRecords,CXFA_Node * pDataScope,bool bChoiceMode)232 void SortRecurseRecord(std::vector<RecurseRecord>* rgRecords,
233                        CXFA_Node* pDataScope,
234                        bool bChoiceMode) {
235   std::vector<RecurseRecord> rgResultRecord;
236   for (CXFA_Node* pNode = pDataScope->GetFirstChild(); pNode;
237        pNode = pNode->GetNextSibling()) {
238     auto it = std::find_if(rgRecords->begin(), rgRecords->end(),
239                            [pNode](const RecurseRecord& record) {
240                              return pNode == record.pDataChild;
241                            });
242     if (it != rgRecords->end()) {
243       rgResultRecord.push_back(*it);
244       rgRecords->erase(it);
245       if (bChoiceMode)
246         break;
247     }
248   }
249   if (rgResultRecord.empty())
250     return;
251 
252   if (!bChoiceMode) {
253     rgResultRecord.insert(rgResultRecord.end(), rgRecords->begin(),
254                           rgRecords->end());
255   }
256   *rgRecords = rgResultRecord;
257 }
258 
ScopeMatchGlobalBinding(CXFA_Node * pDataScope,uint32_t dwNameHash,XFA_Element eMatchDataNodeType,bool bUpLevel)259 CXFA_Node* ScopeMatchGlobalBinding(CXFA_Node* pDataScope,
260                                    uint32_t dwNameHash,
261                                    XFA_Element eMatchDataNodeType,
262                                    bool bUpLevel) {
263   for (CXFA_Node *pCurDataScope = pDataScope, *pLastDataScope = nullptr;
264        pCurDataScope &&
265        pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
266        pLastDataScope = pCurDataScope,
267                  pCurDataScope = pCurDataScope->GetParent()) {
268     for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
269          pDataChild;
270          pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
271       if (pDataChild == pLastDataScope ||
272           (eMatchDataNodeType != XFA_Element::DataModel &&
273            pDataChild->GetElementType() != eMatchDataNodeType) ||
274           pDataChild->HasBindItem()) {
275         continue;
276       }
277       return pDataChild;
278     }
279 
280     for (CXFA_DataGroup* pDataChild =
281              pCurDataScope->GetFirstChildByClass<CXFA_DataGroup>(
282                  XFA_Element::DataGroup);
283          pDataChild;
284          pDataChild = pDataChild->GetNextSameClassSibling<CXFA_DataGroup>(
285              XFA_Element::DataGroup)) {
286       CXFA_Node* pDataNode = ScopeMatchGlobalBinding(pDataChild, dwNameHash,
287                                                      eMatchDataNodeType, false);
288       if (pDataNode)
289         return pDataNode;
290     }
291     if (!bUpLevel)
292       break;
293   }
294   return nullptr;
295 }
296 
FindGlobalDataNode(CXFA_Document * pDocument,const WideString & wsName,CXFA_Node * pDataScope,XFA_Element eMatchNodeType)297 CXFA_Node* FindGlobalDataNode(CXFA_Document* pDocument,
298                               const WideString& wsName,
299                               CXFA_Node* pDataScope,
300                               XFA_Element eMatchNodeType) {
301   if (wsName.IsEmpty())
302     return nullptr;
303 
304   uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView());
305   CXFA_Node* pBounded = pDocument->GetGlobalBinding(dwNameHash);
306   if (!pBounded) {
307     pBounded =
308         ScopeMatchGlobalBinding(pDataScope, dwNameHash, eMatchNodeType, true);
309     if (pBounded)
310       pDocument->RegisterGlobalBinding(dwNameHash, pBounded);
311   }
312   return pBounded;
313 }
314 
FindOnceDataNode(const WideString & wsName,CXFA_Node * pDataScope,XFA_Element eMatchNodeType)315 CXFA_Node* FindOnceDataNode(const WideString& wsName,
316                             CXFA_Node* pDataScope,
317                             XFA_Element eMatchNodeType) {
318   if (wsName.IsEmpty())
319     return nullptr;
320 
321   uint32_t dwNameHash = FX_HashCode_GetW(wsName.AsStringView());
322   CXFA_Node* pLastDataScope = nullptr;
323   for (CXFA_Node* pCurDataScope = pDataScope;
324        pCurDataScope &&
325        pCurDataScope->GetPacketType() == XFA_PacketType::Datasets;
326        pCurDataScope = pCurDataScope->GetParent()) {
327     for (CXFA_Node* pDataChild = pCurDataScope->GetFirstChildByName(dwNameHash);
328          pDataChild;
329          pDataChild = pDataChild->GetNextSameNameSibling(dwNameHash)) {
330       if (pDataChild == pLastDataScope || pDataChild->HasBindItem() ||
331           (eMatchNodeType != XFA_Element::DataModel &&
332            pDataChild->GetElementType() != eMatchNodeType)) {
333         continue;
334       }
335       return pDataChild;
336     }
337     pLastDataScope = pCurDataScope;
338   }
339   return nullptr;
340 }
341 
FindDataRefDataNode(CXFA_Document * pDocument,const WideString & wsRef,CXFA_Node * pDataScope,XFA_Element eMatchNodeType,CXFA_Node * pTemplateNode,bool bForceBind,bool bUpLevel)342 CXFA_Node* FindDataRefDataNode(CXFA_Document* pDocument,
343                                const WideString& wsRef,
344                                CXFA_Node* pDataScope,
345                                XFA_Element eMatchNodeType,
346                                CXFA_Node* pTemplateNode,
347                                bool bForceBind,
348                                bool bUpLevel) {
349   Mask<XFA_ResolveFlag> dwFlags = {XFA_ResolveFlag::kChildren,
350                                    XFA_ResolveFlag::kBindNew};
351   if (bUpLevel || !wsRef.EqualsASCII("name")) {
352     dwFlags |= XFA_ResolveFlag::kParent;
353     dwFlags |= XFA_ResolveFlag::kSiblings;
354   }
355   std::optional<CFXJSE_Engine::ResolveResult> maybeResult =
356       pDocument->GetScriptContext()->ResolveObjectsWithBindNode(
357           pDataScope, wsRef.AsStringView(), dwFlags, pTemplateNode);
358   if (!maybeResult.has_value())
359     return nullptr;
360 
361   if (maybeResult.value().type ==
362           CFXJSE_Engine::ResolveResult::Type::kCreateNodeAll ||
363       maybeResult.value().type ==
364           CFXJSE_Engine::ResolveResult::Type::kCreateNodeMidAll ||
365       maybeResult.value().objects.size() > 1) {
366     return pDocument->GetNotBindNode(maybeResult.value().objects);
367   }
368 
369   if (maybeResult.value().type ==
370       CFXJSE_Engine::ResolveResult::Type::kCreateNodeOne) {
371     CXFA_Object* pObject = !maybeResult.value().objects.empty()
372                                ? maybeResult.value().objects.front().Get()
373                                : nullptr;
374     CXFA_Node* pNode = ToNode(pObject);
375     return (bForceBind || !pNode || !pNode->HasBindItem()) ? pNode : nullptr;
376   }
377   return nullptr;
378 }
379 
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_AttributeValue & eBindMatch,bool bUpLevel)380 CXFA_Node* FindMatchingDataNode(
381     CXFA_Document* pDocument,
382     CXFA_Node* pTemplateNode,
383     CXFA_Node* pDataScope,
384     bool& bAccessedDataDOM,
385     bool bForceBind,
386     CXFA_NodeIteratorTemplate<CXFA_Node,
387                               CXFA_TraverseStrategy_XFAContainerNode>*
388         pIterator,
389     bool& bSelfMatch,
390     XFA_AttributeValue& eBindMatch,
391     bool bUpLevel) {
392   CXFA_Node* pResult = nullptr;
393   CXFA_Node* pCurTemplateNode = pIterator->GetCurrent();
394   while (pCurTemplateNode) {
395     XFA_Element eMatchNodeType;
396     switch (pCurTemplateNode->GetElementType()) {
397       case XFA_Element::Subform:
398         eMatchNodeType = XFA_Element::DataGroup;
399         break;
400       case XFA_Element::Field: {
401         eMatchNodeType = XFA_FieldIsMultiListBox(pCurTemplateNode)
402                              ? XFA_Element::DataGroup
403                              : XFA_Element::DataValue;
404       } break;
405       case XFA_Element::ExclGroup:
406         eMatchNodeType = XFA_Element::DataValue;
407         break;
408       default:
409         pCurTemplateNode = pIterator->MoveToNext();
410         continue;
411     }
412 
413     CXFA_Occur* pTemplateNodeOccur =
414         pCurTemplateNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
415     if (pTemplateNodeOccur) {
416       auto [iMin, iMax, iInit] = pTemplateNodeOccur->GetOccurInfo();
417       if (iMax == 0) {
418         pCurTemplateNode = pIterator->MoveToNext();
419         continue;
420       }
421     }
422 
423     CXFA_Bind* pTemplateNodeBind =
424         pCurTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind);
425     XFA_AttributeValue eMatch =
426         pTemplateNodeBind
427             ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
428             : XFA_AttributeValue::Once;
429     eBindMatch = eMatch;
430     switch (eMatch) {
431       case XFA_AttributeValue::None:
432         pCurTemplateNode = pIterator->MoveToNext();
433         continue;
434       case XFA_AttributeValue::Global:
435         bAccessedDataDOM = true;
436         if (!bForceBind) {
437           pCurTemplateNode = pIterator->MoveToNext();
438           continue;
439         }
440         if (eMatchNodeType == XFA_Element::DataValue ||
441             (eMatchNodeType == XFA_Element::DataGroup &&
442              XFA_FieldIsMultiListBox(pTemplateNodeBind))) {
443           CXFA_Node* pGlobalBindNode = FindGlobalDataNode(
444               pDocument,
445               pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
446               pDataScope, eMatchNodeType);
447           if (!pGlobalBindNode) {
448             pCurTemplateNode = pIterator->MoveToNext();
449             continue;
450           }
451           pResult = pGlobalBindNode;
452           break;
453         }
454         [[fallthrough]];
455       case XFA_AttributeValue::Once: {
456         bAccessedDataDOM = true;
457         CXFA_Node* pOnceBindNode = FindOnceDataNode(
458             pCurTemplateNode->JSObject()->GetCData(XFA_Attribute::Name),
459             pDataScope, eMatchNodeType);
460         if (!pOnceBindNode) {
461           pCurTemplateNode = pIterator->MoveToNext();
462           continue;
463         }
464         pResult = pOnceBindNode;
465         break;
466       }
467       case XFA_AttributeValue::DataRef: {
468         bAccessedDataDOM = true;
469         CXFA_Node* pDataRefBindNode = FindDataRefDataNode(
470             pDocument,
471             pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref),
472             pDataScope, eMatchNodeType, pTemplateNode, bForceBind, bUpLevel);
473         if (pDataRefBindNode &&
474             pDataRefBindNode->GetElementType() == eMatchNodeType) {
475           pResult = pDataRefBindNode;
476         }
477         if (!pResult) {
478           pCurTemplateNode = pIterator->SkipChildrenAndMoveToNext();
479           continue;
480         }
481         break;
482       }
483       default:
484         break;
485     }
486     if (pCurTemplateNode == pTemplateNode && pResult)
487       bSelfMatch = true;
488     break;
489   }
490   return pResult;
491 }
492 
CreateDataBinding(CXFA_Node * pFormNode,CXFA_Node * pDataNode,bool bDataToForm)493 void CreateDataBinding(CXFA_Node* pFormNode,
494                        CXFA_Node* pDataNode,
495                        bool bDataToForm) {
496   pFormNode->SetBindingNode(pDataNode);
497   pDataNode->AddBindItem(pFormNode);
498   XFA_Element eType = pFormNode->GetElementType();
499   if (eType != XFA_Element::Field && eType != XFA_Element::ExclGroup)
500     return;
501 
502   DCHECK(pFormNode->IsWidgetReady());
503   auto* defValue = pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
504       0, XFA_Element::Value);
505   if (!bDataToForm) {
506     WideString wsValue;
507     switch (pFormNode->GetFFWidgetType()) {
508       case XFA_FFWidgetType::kImageEdit: {
509         CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
510         WideString wsContentType;
511         WideString wsHref;
512         if (image) {
513           wsValue = image->GetContent();
514           wsContentType = image->GetContentType();
515           wsHref = image->GetHref();
516         }
517         CFX_XMLElement* pXMLDataElement =
518             ToXMLElement(pDataNode->GetXMLMappingNode());
519         DCHECK(pXMLDataElement);
520         pDataNode->JSObject()->SetAttributeValue(
521             wsValue, pFormNode->GetFormatDataValue(wsValue));
522         pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
523                                         wsContentType);
524         if (!wsHref.IsEmpty())
525           pXMLDataElement->SetAttribute(L"href", wsHref);
526 
527         break;
528       }
529       case XFA_FFWidgetType::kChoiceList:
530         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
531         if (pFormNode->IsChoiceListMultiSelect()) {
532           std::vector<WideString> wsSelTextArray =
533               pFormNode->GetSelectedItemsValue();
534           if (!wsSelTextArray.empty()) {
535             for (const auto& text : wsSelTextArray) {
536               CXFA_Node* pValue =
537                   pDataNode->CreateSamePacketNode(XFA_Element::DataValue);
538               pValue->JSObject()->SetCData(XFA_Attribute::Name, L"value");
539               pValue->CreateXMLMappingNode();
540               pDataNode->InsertChildAndNotify(pValue, nullptr);
541               pValue->JSObject()->SetCData(XFA_Attribute::Value, text);
542             }
543           } else {
544             CFX_XMLElement* pElement =
545                 ToXMLElement(pDataNode->GetXMLMappingNode());
546             pElement->SetAttribute(L"xfa:dataNode", L"dataGroup");
547           }
548         } else if (!wsValue.IsEmpty()) {
549           pDataNode->JSObject()->SetAttributeValue(
550               wsValue, pFormNode->GetFormatDataValue(wsValue));
551         }
552         break;
553       case XFA_FFWidgetType::kCheckButton:
554         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
555         if (wsValue.IsEmpty())
556           break;
557 
558         pDataNode->JSObject()->SetAttributeValue(
559             wsValue, pFormNode->GetFormatDataValue(wsValue));
560         break;
561       case XFA_FFWidgetType::kExclGroup: {
562         CXFA_Node* pChecked = nullptr;
563         CXFA_Node* pChild = pFormNode->GetFirstChild();
564         for (; pChild; pChild = pChild->GetNextSibling()) {
565           if (pChild->GetElementType() != XFA_Element::Field)
566             continue;
567 
568           auto* pValue =
569               pChild->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
570           if (!pValue)
571             continue;
572 
573           wsValue = pValue->GetChildValueContent();
574           if (wsValue.IsEmpty())
575             continue;
576 
577           CXFA_Items* pItems =
578               pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
579           if (!pItems)
580             continue;
581 
582           CXFA_Node* pText = pItems->GetFirstChild();
583           if (!pText)
584             continue;
585 
586           WideString wsContent = pText->JSObject()->GetContent(false);
587           if (wsContent == wsValue) {
588             pChecked = pChild;
589             pDataNode->JSObject()->SetAttributeValue(wsValue, wsValue);
590             pFormNode->JSObject()->SetCData(XFA_Attribute::Value, wsContent);
591             break;
592           }
593         }
594         if (!pChecked)
595           break;
596 
597         pChild = pFormNode->GetFirstChild();
598         for (; pChild; pChild = pChild->GetNextSibling()) {
599           if (pChild == pChecked)
600             continue;
601           if (pChild->GetElementType() != XFA_Element::Field)
602             continue;
603 
604           CXFA_Value* pValue =
605               pChild->JSObject()->GetOrCreateProperty<CXFA_Value>(
606                   0, XFA_Element::Value);
607           CXFA_Items* pItems =
608               pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
609           CXFA_Node* pText = pItems ? pItems->GetFirstChild() : nullptr;
610           if (pText)
611             pText = pText->GetNextSibling();
612 
613           WideString wsContent;
614           if (pText)
615             wsContent = pText->JSObject()->GetContent(false);
616 
617           FormValueNode_SetChildContent(pValue, wsContent, XFA_Element::Text);
618         }
619         break;
620       }
621       case XFA_FFWidgetType::kNumericEdit: {
622         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
623         if (wsValue.IsEmpty())
624           break;
625 
626         wsValue = pFormNode->NormalizeNumStr(wsValue);
627         pDataNode->JSObject()->SetAttributeValue(
628             wsValue, pFormNode->GetFormatDataValue(wsValue));
629         CXFA_Value* pValue =
630             pFormNode->JSObject()->GetOrCreateProperty<CXFA_Value>(
631                 0, XFA_Element::Value);
632         FormValueNode_SetChildContent(pValue, wsValue, XFA_Element::Float);
633         break;
634       }
635       default:
636         wsValue = defValue ? defValue->GetChildValueContent() : WideString();
637         if (wsValue.IsEmpty())
638           break;
639 
640         pDataNode->JSObject()->SetAttributeValue(
641             wsValue, pFormNode->GetFormatDataValue(wsValue));
642         break;
643     }
644     return;
645   }
646 
647   WideString wsXMLValue = pDataNode->JSObject()->GetContent(false);
648   WideString wsNormalizeValue = pFormNode->GetNormalizeDataValue(wsXMLValue);
649 
650   pDataNode->JSObject()->SetAttributeValue(wsNormalizeValue, wsXMLValue);
651   switch (pFormNode->GetFFWidgetType()) {
652     case XFA_FFWidgetType::kImageEdit: {
653       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
654                                     XFA_Element::Image);
655       CXFA_Image* image = defValue ? defValue->GetImageIfExists() : nullptr;
656       if (image) {
657         CFX_XMLElement* pXMLDataElement =
658             ToXMLElement(pDataNode->GetXMLMappingNode());
659         WideString wsContentType =
660             pXMLDataElement->GetAttribute(L"xfa:contentType");
661         if (!wsContentType.IsEmpty()) {
662           pDataNode->JSObject()->SetCData(XFA_Attribute::ContentType,
663                                           wsContentType);
664           image->SetContentType(wsContentType);
665         }
666 
667         WideString wsHref = pXMLDataElement->GetAttribute(L"href");
668         if (!wsHref.IsEmpty())
669           image->SetHref(wsHref);
670       }
671       break;
672     }
673     case XFA_FFWidgetType::kChoiceList:
674       if (pFormNode->IsChoiceListMultiSelect()) {
675         std::vector<CXFA_Node*> items = pDataNode->GetNodeListWithFilter(
676             {XFA_NodeFilter::kChildren, XFA_NodeFilter::kProperties});
677         if (!items.empty()) {
678           bool single = items.size() == 1;
679           wsNormalizeValue.clear();
680 
681           for (CXFA_Node* pNode : items) {
682             WideString wsItem = pNode->JSObject()->GetContent(false);
683             if (single)
684               wsItem += L"\n";
685 
686             wsNormalizeValue += wsItem;
687           }
688           CXFA_ExData* exData =
689               defValue ? defValue->GetExDataIfExists() : nullptr;
690           if (exData)
691             exData->SetContentType(single ? L"text/plain" : L"text/xml");
692         }
693         FormValueNode_SetChildContent(defValue, wsNormalizeValue,
694                                       XFA_Element::ExData);
695       } else {
696         FormValueNode_SetChildContent(defValue, wsNormalizeValue,
697                                       XFA_Element::Text);
698       }
699       break;
700     case XFA_FFWidgetType::kExclGroup: {
701       pFormNode->SetSelectedMemberByValue(wsNormalizeValue.AsStringView(),
702                                           false, false, false);
703       break;
704     }
705     case XFA_FFWidgetType::kDateTimeEdit:
706       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
707                                     XFA_Element::DateTime);
708       break;
709     case XFA_FFWidgetType::kNumericEdit: {
710       WideString wsPicture =
711           pFormNode->GetPictureContent(XFA_ValuePicture::kDataBind);
712       if (wsPicture.IsEmpty())
713         wsNormalizeValue = pFormNode->NormalizeNumStr(wsNormalizeValue);
714 
715       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
716                                     XFA_Element::Float);
717       break;
718     }
719     default:
720       FormValueNode_SetChildContent(defValue, wsNormalizeValue,
721                                     XFA_Element::Text);
722       break;
723   }
724 }
725 
MaybeCreateDataNode(CXFA_Document * pDocument,CXFA_Node * pDataParent,XFA_Element eNodeType,const WideString & wsName)726 CXFA_Node* MaybeCreateDataNode(CXFA_Document* pDocument,
727                                CXFA_Node* pDataParent,
728                                XFA_Element eNodeType,
729                                const WideString& wsName) {
730   if (!pDataParent)
731     return nullptr;
732 
733   CXFA_Node* pParentDDNode = pDataParent->GetDataDescriptionNode();
734   if (!pParentDDNode) {
735     CXFA_Node* pDataNode =
736         pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
737     pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName);
738     pDataNode->CreateXMLMappingNode();
739     pDataParent->InsertChildAndNotify(pDataNode, nullptr);
740     pDataNode->SetFlag(XFA_NodeFlag::kInitialized);
741     return pDataNode;
742   }
743 
744   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup> sIterator(
745       pParentDDNode);
746   for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
747        pDDGroupNode = sIterator.MoveToNext()) {
748     if (pDDGroupNode != pParentDDNode) {
749       if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
750         continue;
751 
752       std::optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
753       if (!ns.has_value() ||
754           !ns.value().EqualsASCII("http://ns.adobe.com/data-description/")) {
755         continue;
756       }
757     }
758 
759     CXFA_Node* pDDNode =
760         pDDGroupNode->GetFirstChildByName(wsName.AsStringView());
761     if (!pDDNode)
762       continue;
763     if (pDDNode->GetElementType() != eNodeType)
764       break;
765 
766     CXFA_Node* pDataNode =
767         pDocument->CreateNode(XFA_PacketType::Datasets, eNodeType);
768     pDataNode->JSObject()->SetCData(XFA_Attribute::Name, wsName);
769     pDataNode->CreateXMLMappingNode();
770     if (eNodeType == XFA_Element::DataValue &&
771         pDDNode->JSObject()->GetEnum(XFA_Attribute::Contains) ==
772             XFA_AttributeValue::MetaData) {
773       pDataNode->JSObject()->SetEnum(XFA_Attribute::Contains,
774                                      XFA_AttributeValue::MetaData, false);
775     }
776     pDataParent->InsertChildAndNotify(pDataNode, nullptr);
777     pDataNode->SetDataDescriptionNode(pDDNode);
778     pDataNode->SetFlag(XFA_NodeFlag::kInitialized);
779     return pDataNode;
780   }
781   return nullptr;
782 }
783 
CopyContainer_Field(CXFA_Document * pDocument,CXFA_Node * pTemplateNode,CXFA_Node * pFormNode,CXFA_Node * pDataScope,bool bDataMerge,bool bUpLevel)784 CXFA_Node* CopyContainer_Field(CXFA_Document* pDocument,
785                                CXFA_Node* pTemplateNode,
786                                CXFA_Node* pFormNode,
787                                CXFA_Node* pDataScope,
788                                bool bDataMerge,
789                                bool bUpLevel) {
790   CXFA_Node* pFieldNode = XFA_NodeMerge_CloneOrMergeContainer(
791       pDocument, pFormNode, pTemplateNode, false, nullptr);
792   DCHECK(pFieldNode);
793   for (CXFA_Node* pTemplateChildNode = pTemplateNode->GetFirstChild();
794        pTemplateChildNode;
795        pTemplateChildNode = pTemplateChildNode->GetNextSibling()) {
796     if (XFA_DataMerge_NeedGenerateForm(pTemplateChildNode, true)) {
797       XFA_NodeMerge_CloneOrMergeContainer(pDocument, pFieldNode,
798                                           pTemplateChildNode, true, nullptr);
799     } else if (pTemplateNode->GetElementType() == XFA_Element::ExclGroup &&
800                pTemplateChildNode->IsContainerNode()) {
801       if (pTemplateChildNode->GetElementType() == XFA_Element::Field) {
802         CopyContainer_Field(pDocument, pTemplateChildNode, pFieldNode, nullptr,
803                             false, true);
804       }
805     }
806   }
807   if (bDataMerge) {
808     bool bAccessedDataDOM = false;
809     bool bSelfMatch = false;
810     XFA_AttributeValue eBindMatch;
811     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
812         sNodeIter(pTemplateNode);
813     CXFA_Node* pDataNode = FindMatchingDataNode(
814         pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, true,
815         &sNodeIter, bSelfMatch, eBindMatch, bUpLevel);
816     if (pDataNode)
817       CreateDataBinding(pFieldNode, pDataNode, true);
818   } else {
819     FormValueNode_MatchNoneCreateChild(pFieldNode);
820   }
821   return pFieldNode;
822 }
823 
CopyContainer_SubformSet(CXFA_Document * pDocument,CXFA_Node * pTemplateNode,CXFA_Node * pFormParentNode,CXFA_Node * pDataScope,bool bOneInstance,bool bDataMerge)824 CXFA_Node* CopyContainer_SubformSet(CXFA_Document* pDocument,
825                                     CXFA_Node* pTemplateNode,
826                                     CXFA_Node* pFormParentNode,
827                                     CXFA_Node* pDataScope,
828                                     bool bOneInstance,
829                                     bool bDataMerge) {
830   XFA_Element eType = pTemplateNode->GetElementType();
831   CXFA_Node* pOccurNode = nullptr;
832   CXFA_Node* pFirstInstance = nullptr;
833   bool bUseInstanceManager =
834       pFormParentNode->GetElementType() != XFA_Element::Area;
835   CXFA_Node* pInstMgrNode = nullptr;
836   std::vector<CXFA_Node*> subformArray;
837   std::vector<CXFA_Node*>* pSearchArray = nullptr;
838   if (!bOneInstance &&
839       (eType == XFA_Element::SubformSet || eType == XFA_Element::Subform)) {
840     pInstMgrNode = bUseInstanceManager ? CloneOrMergeInstanceManager(
841                                              pDocument, pFormParentNode,
842                                              pTemplateNode, &subformArray)
843                                        : nullptr;
844     if (CXFA_Occur* pOccurTemplateNode =
845             pTemplateNode->GetFirstChildByClass<CXFA_Occur>(
846                 XFA_Element::Occur)) {
847       pOccurNode = pInstMgrNode ? XFA_NodeMerge_CloneOrMergeContainer(
848                                       pDocument, pInstMgrNode,
849                                       pOccurTemplateNode, false, nullptr)
850                                 : pOccurTemplateNode;
851     } else if (pInstMgrNode) {
852       pOccurNode =
853           pInstMgrNode->GetFirstChildByClass<CXFA_Occur>(XFA_Element::Occur);
854       if (pOccurNode)
855         pOccurNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
856     }
857     if (pInstMgrNode) {
858       pInstMgrNode->SetInitializedFlagAndNotify();
859       pSearchArray = &subformArray;
860       if (pFormParentNode->GetElementType() == XFA_Element::PageArea) {
861         bOneInstance = true;
862         if (subformArray.empty())
863           pSearchArray = nullptr;
864       } else if (pTemplateNode->GetNameHash() == 0 && subformArray.empty()) {
865         pSearchArray = nullptr;
866       }
867     }
868   }
869 
870   int32_t iMax = 1;
871   int32_t iInit = 1;
872   int32_t iMin = 1;
873   if (!bOneInstance && pOccurNode) {
874     std::tie(iMin, iMax, iInit) =
875         static_cast<CXFA_Occur*>(pOccurNode)->GetOccurInfo();
876   }
877 
878   XFA_AttributeValue eRelation =
879       eType == XFA_Element::SubformSet
880           ? pTemplateNode->JSObject()->GetEnum(XFA_Attribute::Relation)
881           : XFA_AttributeValue::Ordered;
882   int32_t iCurRepeatIndex = 0;
883   XFA_AttributeValue eParentBindMatch = XFA_AttributeValue::None;
884   if (bDataMerge) {
885     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFAContainerNode>
886         sNodeIterator(pTemplateNode);
887     bool bAccessedDataDOM = false;
888     if (eType == XFA_Element::SubformSet || eType == XFA_Element::Area) {
889       sNodeIterator.MoveToNext();
890     } else {
891       std::map<CXFA_Node*, CXFA_Node*> subformMapArray;
892       std::vector<CXFA_Node*> nodeArray;
893       for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
894         bool bSelfMatch = false;
895         XFA_AttributeValue eBindMatch = XFA_AttributeValue::None;
896         CXFA_Node* pDataNode = FindMatchingDataNode(
897             pDocument, pTemplateNode, pDataScope, bAccessedDataDOM, false,
898             &sNodeIterator, bSelfMatch, eBindMatch, true);
899         if (!pDataNode || sNodeIterator.GetCurrent() != pTemplateNode)
900           break;
901 
902         eParentBindMatch = eBindMatch;
903         CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
904             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
905         if (!pFirstInstance)
906           pFirstInstance = pSubformNode;
907 
908         CreateDataBinding(pSubformNode, pDataNode, true);
909         DCHECK(pSubformNode);
910         subformMapArray[pSubformNode] = pDataNode;
911         nodeArray.push_back(pSubformNode);
912       }
913 
914       for (CXFA_Node* pSubform : nodeArray) {
915         CXFA_Node* pDataNode = nullptr;
916         auto it = subformMapArray.find(pSubform);
917         if (it != subformMapArray.end())
918           pDataNode = it->second;
919         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
920              pTemplateChild;
921              pTemplateChild = pTemplateChild->GetNextSibling()) {
922           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
923                                              bUseInstanceManager)) {
924             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubform,
925                                                 pTemplateChild, true, nullptr);
926           } else if (pTemplateChild->IsContainerNode()) {
927             pDocument->DataMerge_CopyContainer(pTemplateChild, pSubform,
928                                                pDataNode, false, true, false);
929           }
930         }
931       }
932       subformMapArray.clear();
933     }
934 
935     for (; iMax < 0 || iCurRepeatIndex < iMax; iCurRepeatIndex++) {
936       bool bSelfMatch = false;
937       XFA_AttributeValue eBindMatch = XFA_AttributeValue::None;
938       if (!FindMatchingDataNode(pDocument, pTemplateNode, pDataScope,
939                                 bAccessedDataDOM, false, &sNodeIterator,
940                                 bSelfMatch, eBindMatch, true)) {
941         break;
942       }
943       if (eBindMatch == XFA_AttributeValue::DataRef &&
944           eParentBindMatch == XFA_AttributeValue::DataRef) {
945         break;
946       }
947 
948       if (eRelation == XFA_AttributeValue::Choice ||
949           eRelation == XFA_AttributeValue::Unordered) {
950         CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
951             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
952         DCHECK(pSubformSetNode);
953         if (!pFirstInstance)
954           pFirstInstance = pSubformSetNode;
955 
956         std::vector<RecurseRecord> rgItemMatchList;
957         std::vector<CXFA_Node*> rgItemUnmatchList;
958         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
959              pTemplateChild;
960              pTemplateChild = pTemplateChild->GetNextSibling()) {
961           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
962                                              bUseInstanceManager)) {
963             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
964                                                 pTemplateChild, true, nullptr);
965           } else if (pTemplateChild->IsContainerNode()) {
966             bSelfMatch = false;
967             eBindMatch = XFA_AttributeValue::None;
968             if (eRelation != XFA_AttributeValue::Ordered) {
969               CXFA_NodeIteratorTemplate<CXFA_Node,
970                                         CXFA_TraverseStrategy_XFAContainerNode>
971                   sChildIter(pTemplateChild);
972               CXFA_Node* pDataMatch = FindMatchingDataNode(
973                   pDocument, pTemplateChild, pDataScope, bAccessedDataDOM,
974                   false, &sChildIter, bSelfMatch, eBindMatch, true);
975               if (pDataMatch) {
976                 RecurseRecord sNewRecord = {pTemplateChild, pDataMatch};
977                 if (bSelfMatch)
978                   rgItemMatchList.insert(rgItemMatchList.begin(), sNewRecord);
979                 else
980                   rgItemMatchList.push_back(sNewRecord);
981               } else {
982                 rgItemUnmatchList.push_back(pTemplateChild);
983               }
984             } else {
985               rgItemUnmatchList.push_back(pTemplateChild);
986             }
987           }
988         }
989 
990         switch (eRelation) {
991           case XFA_AttributeValue::Choice: {
992             DCHECK(!rgItemMatchList.empty());
993             SortRecurseRecord(&rgItemMatchList, pDataScope, true);
994             pDocument->DataMerge_CopyContainer(
995                 rgItemMatchList.front().pTemplateChild, pSubformSetNode,
996                 pDataScope, false, true, true);
997             break;
998           }
999           case XFA_AttributeValue::Unordered: {
1000             if (!rgItemMatchList.empty()) {
1001               SortRecurseRecord(&rgItemMatchList, pDataScope, false);
1002               for (const auto& matched : rgItemMatchList) {
1003                 pDocument->DataMerge_CopyContainer(matched.pTemplateChild,
1004                                                    pSubformSetNode, pDataScope,
1005                                                    false, true, true);
1006               }
1007             }
1008             for (auto* unmatched : rgItemUnmatchList) {
1009               pDocument->DataMerge_CopyContainer(unmatched, pSubformSetNode,
1010                                                  pDataScope, false, true, true);
1011             }
1012             break;
1013           }
1014           default:
1015             break;
1016         }
1017       } else {
1018         CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
1019             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
1020         DCHECK(pSubformSetNode);
1021         if (!pFirstInstance)
1022           pFirstInstance = pSubformSetNode;
1023 
1024         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
1025              pTemplateChild;
1026              pTemplateChild = pTemplateChild->GetNextSibling()) {
1027           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
1028                                              bUseInstanceManager)) {
1029             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
1030                                                 pTemplateChild, true, nullptr);
1031           } else if (pTemplateChild->IsContainerNode()) {
1032             pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
1033                                                pDataScope, false, true, true);
1034           }
1035         }
1036       }
1037     }
1038 
1039     if (iCurRepeatIndex == 0 && !bAccessedDataDOM) {
1040       int32_t iLimit = iMax;
1041       if (pInstMgrNode && pTemplateNode->GetNameHash() == 0) {
1042         iLimit = fxcrt::CollectionSize<int32_t>(subformArray);
1043         if (iLimit < iMin)
1044           iLimit = iInit;
1045       }
1046 
1047       for (; (iLimit < 0 || iCurRepeatIndex < iLimit); iCurRepeatIndex++) {
1048         if (pInstMgrNode) {
1049           if (pSearchArray && pSearchArray->empty()) {
1050             if (pTemplateNode->GetNameHash() != 0)
1051               break;
1052             pSearchArray = nullptr;
1053           }
1054         } else if (!XFA_DataMerge_FindFormDOMInstance(
1055                        pDocument, pTemplateNode->GetElementType(),
1056                        pTemplateNode->GetNameHash(), pFormParentNode)) {
1057           break;
1058         }
1059         CXFA_Node* pSubformNode = XFA_NodeMerge_CloneOrMergeContainer(
1060             pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
1061         DCHECK(pSubformNode);
1062         if (!pFirstInstance)
1063           pFirstInstance = pSubformNode;
1064 
1065         for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
1066              pTemplateChild;
1067              pTemplateChild = pTemplateChild->GetNextSibling()) {
1068           if (XFA_DataMerge_NeedGenerateForm(pTemplateChild,
1069                                              bUseInstanceManager)) {
1070             XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformNode,
1071                                                 pTemplateChild, true, nullptr);
1072           } else if (pTemplateChild->IsContainerNode()) {
1073             pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformNode,
1074                                                pDataScope, false, true, true);
1075           }
1076         }
1077       }
1078     }
1079   }
1080 
1081   int32_t iMinimalLimit = iCurRepeatIndex == 0 ? iInit : iMin;
1082   for (; iCurRepeatIndex < iMinimalLimit; iCurRepeatIndex++) {
1083     CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
1084         pDocument, pFormParentNode, pTemplateNode, false, pSearchArray);
1085     DCHECK(pSubformSetNode);
1086     if (!pFirstInstance)
1087       pFirstInstance = pSubformSetNode;
1088 
1089     bool bFound = false;
1090     for (CXFA_Node* pTemplateChild = pTemplateNode->GetFirstChild();
1091          pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
1092       if (pTemplateChild->GetPacketType() != XFA_PacketType::Template) {
1093         continue;
1094       }
1095       if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, bUseInstanceManager)) {
1096         XFA_NodeMerge_CloneOrMergeContainer(pDocument, pSubformSetNode,
1097                                             pTemplateChild, true, nullptr);
1098       } else if (pTemplateChild->IsContainerNode()) {
1099         if (bFound && eRelation == XFA_AttributeValue::Choice)
1100           continue;
1101 
1102         pDocument->DataMerge_CopyContainer(pTemplateChild, pSubformSetNode,
1103                                            pDataScope, false, bDataMerge, true);
1104         bFound = true;
1105       }
1106     }
1107   }
1108   return pFirstInstance;
1109 }
1110 
UpdateBindingRelations(CXFA_Document * pDocument,CXFA_Node * pFormNode,CXFA_Node * pDataScope,bool bDataRef,bool bParentDataRef)1111 void UpdateBindingRelations(CXFA_Document* pDocument,
1112                             CXFA_Node* pFormNode,
1113                             CXFA_Node* pDataScope,
1114                             bool bDataRef,
1115                             bool bParentDataRef) {
1116   bool bMatchRef = true;
1117   XFA_Element eType = pFormNode->GetElementType();
1118   CXFA_Node* pDataNode = pFormNode->GetBindData();
1119   if (eType == XFA_Element::Subform || eType == XFA_Element::ExclGroup ||
1120       eType == XFA_Element::Field) {
1121     CXFA_Node* pTemplateNode = pFormNode->GetTemplateNodeIfExists();
1122     CXFA_Bind* pTemplateNodeBind =
1123         pTemplateNode
1124             ? pTemplateNode->GetFirstChildByClass<CXFA_Bind>(XFA_Element::Bind)
1125             : nullptr;
1126     XFA_AttributeValue eMatch =
1127         pTemplateNodeBind
1128             ? pTemplateNodeBind->JSObject()->GetEnum(XFA_Attribute::Match)
1129             : XFA_AttributeValue::Once;
1130     switch (eMatch) {
1131       case XFA_AttributeValue::None:
1132         if (!bDataRef || bParentDataRef)
1133           FormValueNode_MatchNoneCreateChild(pFormNode);
1134         break;
1135       case XFA_AttributeValue::Once:
1136         if (!bDataRef || bParentDataRef) {
1137           if (!pDataNode) {
1138             if (pFormNode->GetNameHash() != 0 &&
1139                 pFormNode->JSObject()->GetEnum(XFA_Attribute::Scope) !=
1140                     XFA_AttributeValue::None) {
1141               XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
1142                                            XFA_FieldIsMultiListBox(pFormNode))
1143                                               ? XFA_Element::DataGroup
1144                                               : XFA_Element::DataValue;
1145               pDataNode = MaybeCreateDataNode(
1146                   pDocument, pDataScope, eDataNodeType,
1147                   WideString(
1148                       pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
1149               if (pDataNode)
1150                 CreateDataBinding(pFormNode, pDataNode, false);
1151             }
1152             if (!pDataNode)
1153               FormValueNode_MatchNoneCreateChild(pFormNode);
1154 
1155           } else {
1156             CXFA_Node* pDataParent = pDataNode->GetParent();
1157             if (pDataParent != pDataScope) {
1158               DCHECK(pDataParent);
1159               pDataParent->RemoveChildAndNotify(pDataNode, true);
1160               pDataScope->InsertChildAndNotify(pDataNode, nullptr);
1161             }
1162           }
1163         }
1164         break;
1165       case XFA_AttributeValue::Global:
1166         if (!bDataRef || bParentDataRef) {
1167           uint32_t dwNameHash = pFormNode->GetNameHash();
1168           if (dwNameHash != 0 && !pDataNode) {
1169             pDataNode = pDocument->GetGlobalBinding(dwNameHash);
1170             if (!pDataNode) {
1171               XFA_Element eDataNodeType = (eType == XFA_Element::Subform ||
1172                                            XFA_FieldIsMultiListBox(pFormNode))
1173                                               ? XFA_Element::DataGroup
1174                                               : XFA_Element::DataValue;
1175               CXFA_Node* pRecordNode =
1176                   ToNode(pDocument->GetXFAObject(XFA_HASHCODE_Record));
1177               pDataNode = MaybeCreateDataNode(
1178                   pDocument, pRecordNode, eDataNodeType,
1179                   WideString(
1180                       pFormNode->JSObject()->GetCData(XFA_Attribute::Name)));
1181               if (pDataNode) {
1182                 CreateDataBinding(pFormNode, pDataNode, false);
1183                 pDocument->RegisterGlobalBinding(pFormNode->GetNameHash(),
1184                                                  pDataNode);
1185               }
1186             } else {
1187               CreateDataBinding(pFormNode, pDataNode, true);
1188             }
1189           }
1190           if (!pDataNode)
1191             FormValueNode_MatchNoneCreateChild(pFormNode);
1192         }
1193         break;
1194       case XFA_AttributeValue::DataRef: {
1195         bMatchRef = bDataRef;
1196         bParentDataRef = true;
1197         if (!pDataNode && bDataRef) {
1198           WideString wsRef =
1199               pTemplateNodeBind
1200                   ? pTemplateNodeBind->JSObject()->GetCData(XFA_Attribute::Ref)
1201                   : WideString();
1202           const Mask<XFA_ResolveFlag> kFlags = {XFA_ResolveFlag::kChildren,
1203                                                 XFA_ResolveFlag::kCreateNode};
1204           std::optional<CFXJSE_Engine::ResolveResult> maybeResult =
1205               pDocument->GetScriptContext()->ResolveObjectsWithBindNode(
1206                   pDataScope, wsRef.AsStringView(), kFlags, pTemplateNode);
1207           CXFA_Object* pObject =
1208               maybeResult.has_value() && !maybeResult.value().objects.empty()
1209                   ? maybeResult.value().objects.front().Get()
1210                   : nullptr;
1211           pDataNode = ToNode(pObject);
1212           if (pDataNode) {
1213             CreateDataBinding(
1214                 pFormNode, pDataNode,
1215                 maybeResult.value().type ==
1216                     CFXJSE_Engine::ResolveResult::Type::kExistNodes);
1217           } else {
1218             FormValueNode_MatchNoneCreateChild(pFormNode);
1219           }
1220         }
1221         break;
1222       }
1223       default:
1224         break;
1225     }
1226   }
1227 
1228   if (bMatchRef &&
1229       (eType == XFA_Element::Subform || eType == XFA_Element::SubformSet ||
1230        eType == XFA_Element::Area || eType == XFA_Element::PageArea ||
1231        eType == XFA_Element::PageSet)) {
1232     for (CXFA_Node* pFormChild = pFormNode->GetFirstChild(); pFormChild;
1233          pFormChild = pFormChild->GetNextSibling()) {
1234       if (!pFormChild->IsContainerNode())
1235         continue;
1236       if (pFormChild->IsUnusedNode())
1237         continue;
1238 
1239       UpdateBindingRelations(pDocument, pFormChild,
1240                              pDataNode ? pDataNode : pDataScope, bDataRef,
1241                              bParentDataRef);
1242     }
1243   }
1244 }
1245 
UpdateDataRelation(CXFA_Node * pDataNode,CXFA_Node * pDataDescriptionNode)1246 void UpdateDataRelation(CXFA_Node* pDataNode, CXFA_Node* pDataDescriptionNode) {
1247   DCHECK(pDataDescriptionNode);
1248   for (CXFA_Node* pDataChild = pDataNode->GetFirstChild(); pDataChild;
1249        pDataChild = pDataChild->GetNextSibling()) {
1250     uint32_t dwNameHash = pDataChild->GetNameHash();
1251     if (!dwNameHash)
1252       continue;
1253 
1254     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_DDGroup>
1255         sIterator(pDataDescriptionNode);
1256     for (CXFA_Node* pDDGroupNode = sIterator.GetCurrent(); pDDGroupNode;
1257          pDDGroupNode = sIterator.MoveToNext()) {
1258       if (pDDGroupNode != pDataDescriptionNode) {
1259         if (pDDGroupNode->GetElementType() != XFA_Element::DataGroup)
1260           continue;
1261 
1262         std::optional<WideString> ns = pDDGroupNode->JSObject()->TryNamespace();
1263         if (!ns.has_value() ||
1264             !ns.value().EqualsASCII("http://ns.adobe.com/data-description/")) {
1265           continue;
1266         }
1267       }
1268 
1269       CXFA_Node* pDDNode = pDDGroupNode->GetFirstChildByName(dwNameHash);
1270       if (!pDDNode)
1271         continue;
1272       if (pDDNode->GetElementType() != pDataChild->GetElementType())
1273         break;
1274 
1275       pDataChild->SetDataDescriptionNode(pDDNode);
1276       UpdateDataRelation(pDataChild, pDDNode);
1277       break;
1278     }
1279   }
1280 }
1281 
1282 }  // namespace
1283 
CXFA_Document(CXFA_FFNotify * notify,cppgc::Heap * heap,LayoutProcessorIface * pLayout)1284 CXFA_Document::CXFA_Document(CXFA_FFNotify* notify,
1285                              cppgc::Heap* heap,
1286                              LayoutProcessorIface* pLayout)
1287     : heap_(heap),
1288       notify_(notify),
1289       node_owner_(cppgc::MakeGarbageCollected<CXFA_NodeOwner>(
1290           heap->GetAllocationHandle())),
1291       m_pLayoutProcessor(pLayout) {
1292   if (m_pLayoutProcessor)
1293     m_pLayoutProcessor->SetDocument(this);
1294 }
1295 
1296 CXFA_Document::~CXFA_Document() = default;
1297 
Trace(cppgc::Visitor * visitor) const1298 void CXFA_Document::Trace(cppgc::Visitor* visitor) const {
1299   visitor->Trace(notify_);
1300   visitor->Trace(node_owner_);
1301   visitor->Trace(m_pRootNode);
1302   visitor->Trace(m_pLocaleMgr);
1303   visitor->Trace(m_pLayoutProcessor);
1304   visitor->Trace(m_pScriptDataWindow);
1305   visitor->Trace(m_pScriptEvent);
1306   visitor->Trace(m_pScriptHost);
1307   visitor->Trace(m_pScriptLog);
1308   visitor->Trace(m_pScriptLayout);
1309   visitor->Trace(m_pScriptSignature);
1310   ContainerTrace(visitor, m_rgGlobalBinding);
1311   ContainerTrace(visitor, m_pPendingPageSet);
1312 }
1313 
ClearLayoutData()1314 void CXFA_Document::ClearLayoutData() {
1315   m_pLayoutProcessor = nullptr;
1316   m_pScriptContext.reset();
1317   m_pLocaleMgr.Clear();
1318   m_pScriptDataWindow = nullptr;
1319   m_pScriptEvent = nullptr;
1320   m_pScriptHost = nullptr;
1321   m_pScriptLog = nullptr;
1322   m_pScriptLayout = nullptr;
1323   m_pScriptSignature = nullptr;
1324 }
1325 
GetXFAObject(XFA_HashCode dwNodeNameHash)1326 CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
1327   switch (dwNodeNameHash) {
1328     case XFA_HASHCODE_Data: {
1329       CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
1330       if (!pDatasetsNode)
1331         return nullptr;
1332 
1333       for (CXFA_DataGroup* pDatasetsChild =
1334                pDatasetsNode->GetFirstChildByClass<CXFA_DataGroup>(
1335                    XFA_Element::DataGroup);
1336            pDatasetsChild;
1337            pDatasetsChild =
1338                pDatasetsChild->GetNextSameClassSibling<CXFA_DataGroup>(
1339                    XFA_Element::DataGroup)) {
1340         if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data)
1341           continue;
1342 
1343         std::optional<WideString> namespaceURI =
1344             pDatasetsChild->JSObject()->TryNamespace();
1345         if (!namespaceURI.has_value())
1346           continue;
1347 
1348         std::optional<WideString> datasetsURI =
1349             pDatasetsNode->JSObject()->TryNamespace();
1350         if (!datasetsURI.has_value())
1351           continue;
1352         if (namespaceURI.value() == datasetsURI.value())
1353           return pDatasetsChild;
1354       }
1355       return nullptr;
1356     }
1357     case XFA_HASHCODE_Record: {
1358       CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data));
1359       return pData ? pData->GetFirstChildByClass<CXFA_DataGroup>(
1360                          XFA_Element::DataGroup)
1361                    : nullptr;
1362     }
1363     case XFA_HASHCODE_DataWindow: {
1364       if (!m_pScriptDataWindow)
1365         m_pScriptDataWindow = cppgc::MakeGarbageCollected<CScript_DataWindow>(
1366             GetHeap()->GetAllocationHandle(), this);
1367       return m_pScriptDataWindow;
1368     }
1369     case XFA_HASHCODE_Event: {
1370       if (!m_pScriptEvent)
1371         m_pScriptEvent = cppgc::MakeGarbageCollected<CScript_EventPseudoModel>(
1372             GetHeap()->GetAllocationHandle(), this);
1373       return m_pScriptEvent;
1374     }
1375     case XFA_HASHCODE_Host: {
1376       if (!m_pScriptHost)
1377         m_pScriptHost = cppgc::MakeGarbageCollected<CScript_HostPseudoModel>(
1378             GetHeap()->GetAllocationHandle(), this);
1379       return m_pScriptHost;
1380     }
1381     case XFA_HASHCODE_Log: {
1382       if (!m_pScriptLog)
1383         m_pScriptLog = cppgc::MakeGarbageCollected<CScript_LogPseudoModel>(
1384             GetHeap()->GetAllocationHandle(), this);
1385       return m_pScriptLog;
1386     }
1387     case XFA_HASHCODE_Signature: {
1388       if (!m_pScriptSignature)
1389         m_pScriptSignature =
1390             cppgc::MakeGarbageCollected<CScript_SignaturePseudoModel>(
1391                 GetHeap()->GetAllocationHandle(), this);
1392       return m_pScriptSignature;
1393     }
1394     case XFA_HASHCODE_Layout: {
1395       if (!m_pScriptLayout)
1396         m_pScriptLayout =
1397             cppgc::MakeGarbageCollected<CScript_LayoutPseudoModel>(
1398                 GetHeap()->GetAllocationHandle(), this);
1399       return m_pScriptLayout;
1400     }
1401     default:
1402       return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
1403   }
1404 }
1405 
CreateNode(XFA_PacketType packet,XFA_Element eElement)1406 CXFA_Node* CXFA_Document::CreateNode(XFA_PacketType packet,
1407                                      XFA_Element eElement) {
1408   if (eElement == XFA_Element::Unknown)
1409     return nullptr;
1410 
1411   return CXFA_Node::Create(this, eElement, packet);
1412 }
1413 
IsInteractive()1414 bool CXFA_Document::IsInteractive() {
1415   if (m_Interactive.has_value())
1416     return m_Interactive.value();
1417 
1418   CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
1419   if (!pConfig)
1420     return false;
1421 
1422   CXFA_Present* pPresent =
1423       pConfig->GetFirstChildByClass<CXFA_Present>(XFA_Element::Present);
1424   if (!pPresent)
1425     return false;
1426 
1427   CXFA_Pdf* pPDF = pPresent->GetFirstChildByClass<CXFA_Pdf>(XFA_Element::Pdf);
1428   if (!pPDF)
1429     return false;
1430 
1431   CXFA_Interactive* pFormFiller =
1432       pPDF->GetChild<CXFA_Interactive>(0, XFA_Element::Interactive, false);
1433   if (!pFormFiller)
1434     return false;
1435 
1436   WideString wsInteractive = pFormFiller->JSObject()->GetContent(false);
1437   bool bInteractive = wsInteractive.EqualsASCII("1");
1438   m_Interactive = bInteractive;
1439   return bInteractive;
1440 }
1441 
GetLocaleMgr()1442 CXFA_LocaleMgr* CXFA_Document::GetLocaleMgr() {
1443   if (!m_pLocaleMgr) {
1444     m_pLocaleMgr = cppgc::MakeGarbageCollected<CXFA_LocaleMgr>(
1445         heap_->GetAllocationHandle(), heap_,
1446         ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)),
1447         GetNotify()->GetAppProvider()->GetLanguage());
1448   }
1449   return m_pLocaleMgr;
1450 }
1451 
GetHeap() const1452 cppgc::Heap* CXFA_Document::GetHeap() const {
1453   return heap_;
1454 }
1455 
InitScriptContext(CJS_Runtime * fxjs_runtime)1456 CFXJSE_Engine* CXFA_Document::InitScriptContext(CJS_Runtime* fxjs_runtime) {
1457   DCHECK(!m_pScriptContext);
1458   m_pScriptContext = std::make_unique<CFXJSE_Engine>(this, fxjs_runtime);
1459   return m_pScriptContext.get();
1460 }
1461 
GetScriptContext() const1462 CFXJSE_Engine* CXFA_Document::GetScriptContext() const {
1463   DCHECK(m_pScriptContext);
1464   return m_pScriptContext.get();
1465 }
1466 
RecognizeXFAVersionNumber(const WideString & wsTemplateNS)1467 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
1468     const WideString& wsTemplateNS) {
1469   XFA_VERSION eVersion = ParseXFAVersion(wsTemplateNS);
1470   if (eVersion != XFA_VERSION_UNKNOWN)
1471     m_eCurVersionMode = eVersion;
1472 
1473   return eVersion;
1474 }
1475 
1476 // static
ParseXFAVersion(const WideString & wsTemplateNS)1477 XFA_VERSION CXFA_Document::ParseXFAVersion(const WideString& wsTemplateNS) {
1478   WideStringView wsTemplateURIPrefix(kTemplateNS);
1479   if (wsTemplateNS.GetLength() <= wsTemplateURIPrefix.GetLength())
1480     return XFA_VERSION_UNKNOWN;
1481 
1482   size_t prefixLength = wsTemplateURIPrefix.GetLength();
1483   if (wsTemplateNS.AsStringView().First(prefixLength) != wsTemplateURIPrefix)
1484     return XFA_VERSION_UNKNOWN;
1485 
1486   auto nDotPos = wsTemplateNS.Find('.', prefixLength);
1487   if (!nDotPos.has_value())
1488     return XFA_VERSION_UNKNOWN;
1489 
1490   int8_t iMajor = FXSYS_wtoi(
1491       wsTemplateNS.Substr(prefixLength, nDotPos.value() - prefixLength)
1492           .c_str());
1493   int8_t iMinor = FXSYS_wtoi(wsTemplateNS.Substr(nDotPos.value() + 1).c_str());
1494   XFA_VERSION eVersion =
1495       static_cast<XFA_VERSION>(static_cast<int32_t>(iMajor) * 100 + iMinor);
1496   if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
1497     return XFA_VERSION_UNKNOWN;
1498 
1499   return eVersion;
1500 }
1501 
GetFormType() const1502 FormType CXFA_Document::GetFormType() const {
1503   return GetNotify()->GetFFDoc()->GetFormType();
1504 }
1505 
GetNodeByID(CXFA_Node * pRoot,WideStringView wsID) const1506 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
1507                                       WideStringView wsID) const {
1508   if (!pRoot || wsID.IsEmpty())
1509     return nullptr;
1510 
1511   CXFA_NodeIterator sIterator(pRoot);
1512   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1513        pNode = sIterator.MoveToNext()) {
1514     WideString wsIDVal = pNode->JSObject()->GetCData(XFA_Attribute::Id);
1515     if (!wsIDVal.IsEmpty() && wsIDVal == wsID)
1516       return pNode;
1517   }
1518   return nullptr;
1519 }
1520 
DoProtoMerge()1521 void CXFA_Document::DoProtoMerge() {
1522   CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template));
1523   if (!pTemplateRoot)
1524     return;
1525 
1526   std::map<uint32_t, CXFA_Node*> mIDMap;
1527   std::set<CXFA_Node*> sUseNodes;
1528   CXFA_NodeIterator sIterator(pTemplateRoot);
1529   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1530        pNode = sIterator.MoveToNext()) {
1531     WideString wsIDVal = pNode->JSObject()->GetCData(XFA_Attribute::Id);
1532     if (!wsIDVal.IsEmpty())
1533       mIDMap[FX_HashCode_GetW(wsIDVal.AsStringView())] = pNode;
1534 
1535     WideString wsUseVal = pNode->JSObject()->GetCData(XFA_Attribute::Use);
1536     if (!wsUseVal.IsEmpty()) {
1537       sUseNodes.insert(pNode);
1538     } else {
1539       wsUseVal = pNode->JSObject()->GetCData(XFA_Attribute::Usehref);
1540       if (!wsUseVal.IsEmpty())
1541         sUseNodes.insert(pNode);
1542     }
1543   }
1544 
1545   for (CXFA_Node* pUseHrefNode : sUseNodes) {
1546     // Must outlive the WideStringViews below.
1547     WideString wsUseVal =
1548         pUseHrefNode->JSObject()->GetCData(XFA_Attribute::Usehref);
1549     WideStringView wsURI;
1550     WideStringView wsID;
1551     WideStringView wsSOM;
1552     if (!wsUseVal.IsEmpty()) {
1553       ParseUseHref(wsUseVal, wsURI, wsID, wsSOM);
1554       if (!wsURI.IsEmpty() && !wsURI.EqualsASCII("."))
1555         continue;
1556     } else {
1557       wsUseVal = pUseHrefNode->JSObject()->GetCData(XFA_Attribute::Use);
1558       ParseUse(wsUseVal, wsID, wsSOM);
1559     }
1560 
1561     CXFA_Node* pProtoNode = nullptr;
1562     if (!wsSOM.IsEmpty()) {
1563       std::optional<CFXJSE_Engine::ResolveResult> maybeResult =
1564           m_pScriptContext->ResolveObjects(
1565               pUseHrefNode, wsSOM,
1566               Mask<XFA_ResolveFlag>{
1567                   XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
1568                   XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
1569                   XFA_ResolveFlag::kSiblings});
1570       if (maybeResult.has_value()) {
1571         auto* pFirstObject = maybeResult.value().objects.front().Get();
1572         if (pFirstObject && pFirstObject->IsNode())
1573           pProtoNode = pFirstObject->AsNode();
1574       }
1575     } else if (!wsID.IsEmpty()) {
1576       auto it = mIDMap.find(FX_HashCode_GetW(wsID));
1577       if (it == mIDMap.end())
1578         continue;
1579       pProtoNode = it->second;
1580     }
1581     if (!pProtoNode)
1582       continue;
1583 
1584     MergeNode(pUseHrefNode, pProtoNode);
1585   }
1586 }
1587 
1588 // static
ParseUseHref(const WideString & wsUseVal,WideStringView & wsURI,WideStringView & wsID,WideStringView & wsSOM)1589 void CXFA_Document::ParseUseHref(const WideString& wsUseVal,
1590                                  WideStringView& wsURI,
1591                                  WideStringView& wsID,
1592                                  WideStringView& wsSOM) {
1593   if (wsUseVal.IsEmpty())
1594     return;
1595 
1596   auto uSharpPos = wsUseVal.Find('#');
1597   if (!uSharpPos.has_value()) {
1598     wsURI = wsUseVal.AsStringView();
1599     return;
1600   }
1601   wsURI = wsUseVal.AsStringView().First(uSharpPos.value());
1602   if (wsUseVal.AsStringView().Substr(uSharpPos.value(), 5) == L"#som(" &&
1603       wsUseVal.Back() == ')') {
1604     wsSOM = wsUseVal.AsStringView().Substr(
1605         uSharpPos.value() + 5,
1606         wsUseVal.GetLength() - 1 - uSharpPos.value() - 5);
1607     return;
1608   }
1609   wsID = wsUseVal.AsStringView().Substr(uSharpPos.value() + 1);
1610 }
1611 
1612 // static
ParseUse(const WideString & wsUseVal,WideStringView & wsID,WideStringView & wsSOM)1613 void CXFA_Document::ParseUse(const WideString& wsUseVal,
1614                              WideStringView& wsID,
1615                              WideStringView& wsSOM) {
1616   if (wsUseVal.IsEmpty())
1617     return;
1618 
1619   if (wsUseVal[0] == '#') {
1620     wsID = wsUseVal.AsStringView().Substr(1);
1621     return;
1622   }
1623   wsSOM = wsUseVal.AsStringView();
1624 }
1625 
DataMerge_CopyContainer(CXFA_Node * pTemplateNode,CXFA_Node * pFormNode,CXFA_Node * pDataScope,bool bOneInstance,bool bDataMerge,bool bUpLevel)1626 CXFA_Node* CXFA_Document::DataMerge_CopyContainer(CXFA_Node* pTemplateNode,
1627                                                   CXFA_Node* pFormNode,
1628                                                   CXFA_Node* pDataScope,
1629                                                   bool bOneInstance,
1630                                                   bool bDataMerge,
1631                                                   bool bUpLevel) {
1632   CHECK(pTemplateNode->IsContainerNode());
1633   switch (pTemplateNode->GetElementType()) {
1634     case XFA_Element::Area:
1635     case XFA_Element::PageArea:
1636     case XFA_Element::Subform:
1637     case XFA_Element::SubformSet:
1638       return CopyContainer_SubformSet(this, pTemplateNode, pFormNode,
1639                                       pDataScope, bOneInstance, bDataMerge);
1640     case XFA_Element::ContentArea:
1641     case XFA_Element::Draw:
1642     case XFA_Element::ExclGroup:
1643     case XFA_Element::Field:
1644       return CopyContainer_Field(this, pTemplateNode, pFormNode, pDataScope,
1645                                  bDataMerge, bUpLevel);
1646     case XFA_Element::PageSet:
1647     case XFA_Element::Variables:
1648       return nullptr;
1649     default:
1650       NOTREACHED_NORETURN();
1651   }
1652 }
1653 
DataMerge_UpdateBindingRelations(CXFA_Node * pFormUpdateRoot)1654 void CXFA_Document::DataMerge_UpdateBindingRelations(
1655     CXFA_Node* pFormUpdateRoot) {
1656   CXFA_Node* pDataScope =
1657       XFA_DataMerge_FindDataScope(pFormUpdateRoot->GetParent());
1658   if (!pDataScope)
1659     return;
1660 
1661   UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, false, false);
1662   UpdateBindingRelations(this, pFormUpdateRoot, pDataScope, true, false);
1663 }
1664 
GetNotBindNode(pdfium::span<cppgc::Member<CXFA_Object>> arrayObjects) const1665 CXFA_Node* CXFA_Document::GetNotBindNode(
1666     pdfium::span<cppgc::Member<CXFA_Object>> arrayObjects) const {
1667   for (auto& pObject : arrayObjects) {
1668     CXFA_Node* pNode = pObject->AsNode();
1669     if (pNode && !pNode->HasBindItem())
1670       return pNode;
1671   }
1672   return nullptr;
1673 }
1674 
DoDataMerge()1675 void CXFA_Document::DoDataMerge() {
1676   CXFA_Node* pDatasetsRoot = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
1677   if (!pDatasetsRoot) {
1678     // Ownership will be passed in the AppendChild below to the XML tree.
1679     auto* pDatasetsXMLNode =
1680         notify_->GetFFDoc()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
1681             L"xfa:datasets");
1682     pDatasetsXMLNode->SetAttribute(L"xmlns:xfa",
1683                                    L"http://www.xfa.org/schema/xfa-data/1.0/");
1684     pDatasetsRoot =
1685         CreateNode(XFA_PacketType::Datasets, XFA_Element::DataModel);
1686     pDatasetsRoot->JSObject()->SetCData(XFA_Attribute::Name, L"datasets");
1687 
1688     m_pRootNode->GetXMLMappingNode()->AppendLastChild(pDatasetsXMLNode);
1689     m_pRootNode->InsertChildAndNotify(pDatasetsRoot, nullptr);
1690     pDatasetsRoot->SetXMLMappingNode(pDatasetsXMLNode);
1691   }
1692 
1693   CXFA_Node* pDataRoot = nullptr;
1694   CXFA_Node* pDDRoot = nullptr;
1695   WideString wsDatasetsURI =
1696       pDatasetsRoot->JSObject()->TryNamespace().value_or(WideString());
1697   for (CXFA_Node* pChildNode = pDatasetsRoot->GetFirstChild(); pChildNode;
1698        pChildNode = pChildNode->GetNextSibling()) {
1699     if (pChildNode->GetElementType() != XFA_Element::DataGroup)
1700       continue;
1701 
1702     if (!pDDRoot && pChildNode->GetNameHash() == XFA_HASHCODE_DataDescription) {
1703       std::optional<WideString> namespaceURI =
1704           pChildNode->JSObject()->TryNamespace();
1705       if (!namespaceURI.has_value())
1706         continue;
1707       if (namespaceURI.value().EqualsASCII(
1708               "http://ns.adobe.com/data-description/")) {
1709         pDDRoot = pChildNode;
1710       }
1711     } else if (!pDataRoot && pChildNode->GetNameHash() == XFA_HASHCODE_Data) {
1712       std::optional<WideString> namespaceURI =
1713           pChildNode->JSObject()->TryNamespace();
1714       if (!namespaceURI.has_value())
1715         continue;
1716       if (namespaceURI == wsDatasetsURI)
1717         pDataRoot = pChildNode;
1718     }
1719     if (pDataRoot && pDDRoot)
1720       break;
1721   }
1722 
1723   if (!pDataRoot) {
1724     pDataRoot = CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup);
1725     pDataRoot->JSObject()->SetCData(XFA_Attribute::Name, L"data");
1726 
1727     auto* elem =
1728         notify_->GetFFDoc()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
1729             L"xfa:data");
1730     pDataRoot->SetXMLMappingNode(elem);
1731     pDatasetsRoot->InsertChildAndNotify(pDataRoot, nullptr);
1732   }
1733 
1734   CXFA_DataGroup* pDataTopLevel =
1735       pDataRoot->GetFirstChildByClass<CXFA_DataGroup>(XFA_Element::DataGroup);
1736   uint32_t dwNameHash = pDataTopLevel ? pDataTopLevel->GetNameHash() : 0;
1737   CXFA_Template* pTemplateRoot =
1738       m_pRootNode->GetFirstChildByClass<CXFA_Template>(XFA_Element::Template);
1739   if (!pTemplateRoot)
1740     return;
1741 
1742   CXFA_Node* pTemplateChosen =
1743       dwNameHash != 0 ? pTemplateRoot->GetFirstChildByName(dwNameHash)
1744                       : nullptr;
1745   if (!pTemplateChosen ||
1746       pTemplateChosen->GetElementType() != XFA_Element::Subform) {
1747     pTemplateChosen =
1748         pTemplateRoot->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1749   }
1750   if (!pTemplateChosen)
1751     return;
1752 
1753   CXFA_Form* pFormRoot =
1754       m_pRootNode->GetFirstChildByClass<CXFA_Form>(XFA_Element::Form);
1755   bool bEmptyForm = false;
1756   if (!pFormRoot) {
1757     bEmptyForm = true;
1758     pFormRoot = static_cast<CXFA_Form*>(
1759         CreateNode(XFA_PacketType::Form, XFA_Element::Form));
1760     DCHECK(pFormRoot);
1761     pFormRoot->JSObject()->SetCData(XFA_Attribute::Name, L"form");
1762     m_pRootNode->InsertChildAndNotify(pFormRoot, nullptr);
1763   } else {
1764     CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode>
1765         sIterator(pFormRoot);
1766     for (CXFA_Node* pNode = sIterator.MoveToNext(); pNode;
1767          pNode = sIterator.MoveToNext()) {
1768       pNode->SetFlag(XFA_NodeFlag::kUnusedNode);
1769     }
1770   }
1771 
1772   CXFA_Node* pSubformSetNode = XFA_NodeMerge_CloneOrMergeContainer(
1773       this, pFormRoot, pTemplateChosen, false, nullptr);
1774   DCHECK(pSubformSetNode);
1775   if (!pDataTopLevel) {
1776     WideString wsFormName =
1777         pSubformSetNode->JSObject()->GetCData(XFA_Attribute::Name);
1778     WideString wsDataTopLevelName(wsFormName.IsEmpty() ? L"form" : wsFormName);
1779 
1780     pDataTopLevel = static_cast<CXFA_DataGroup*>(
1781         CreateNode(XFA_PacketType::Datasets, XFA_Element::DataGroup));
1782     pDataTopLevel->JSObject()->SetCData(XFA_Attribute::Name,
1783                                         wsDataTopLevelName);
1784 
1785     auto* elem =
1786         notify_->GetFFDoc()->GetXMLDocument()->CreateNode<CFX_XMLElement>(
1787             wsDataTopLevelName);
1788     pDataTopLevel->SetXMLMappingNode(elem);
1789 
1790     CXFA_Node* pBeforeNode = pDataRoot->GetFirstChild();
1791     pDataRoot->InsertChildAndNotify(pDataTopLevel, pBeforeNode);
1792   }
1793 
1794   DCHECK(pDataTopLevel);
1795   CreateDataBinding(pSubformSetNode, pDataTopLevel, true);
1796   for (CXFA_Node* pTemplateChild = pTemplateChosen->GetFirstChild();
1797        pTemplateChild; pTemplateChild = pTemplateChild->GetNextSibling()) {
1798     if (XFA_DataMerge_NeedGenerateForm(pTemplateChild, true)) {
1799       XFA_NodeMerge_CloneOrMergeContainer(this, pSubformSetNode, pTemplateChild,
1800                                           true, nullptr);
1801     } else if (pTemplateChild->IsContainerNode()) {
1802       DataMerge_CopyContainer(pTemplateChild, pSubformSetNode, pDataTopLevel,
1803                               false, true, true);
1804     }
1805   }
1806   if (pDDRoot)
1807     UpdateDataRelation(pDataRoot, pDDRoot);
1808 
1809   DataMerge_UpdateBindingRelations(pSubformSetNode);
1810   CXFA_PageSet* pPageSetNode =
1811       pSubformSetNode->GetFirstChildByClass<CXFA_PageSet>(XFA_Element::PageSet);
1812   while (pPageSetNode) {
1813     m_pPendingPageSet.push_back(pPageSetNode);
1814     CXFA_PageSet* pNextPageSetNode =
1815         pPageSetNode->GetNextSameClassSibling<CXFA_PageSet>(
1816             XFA_Element::PageSet);
1817     pSubformSetNode->RemoveChildAndNotify(pPageSetNode, true);
1818     pPageSetNode = pNextPageSetNode;
1819   }
1820 
1821   if (bEmptyForm)
1822     return;
1823 
1824   CXFA_NodeIteratorTemplate<CXFA_Node, CXFA_TraverseStrategy_XFANode> sIterator(
1825       pFormRoot);
1826   CXFA_Node* pNode = sIterator.MoveToNext();
1827   while (pNode) {
1828     if (pNode->IsUnusedNode()) {
1829       if (pNode->IsContainerNode() ||
1830           pNode->GetElementType() == XFA_Element::InstanceManager) {
1831         CXFA_Node* pNext = sIterator.SkipChildrenAndMoveToNext();
1832         pNode->GetParent()->RemoveChildAndNotify(pNode, true);
1833         pNode = pNext;
1834       } else {
1835         pNode->ClearFlag(XFA_NodeFlag::kUnusedNode);
1836         pNode->SetInitializedFlagAndNotify();
1837         pNode = sIterator.MoveToNext();
1838       }
1839     } else {
1840       pNode->SetInitializedFlagAndNotify();
1841       pNode = sIterator.MoveToNext();
1842     }
1843   }
1844 }
1845 
DoDataRemerge()1846 void CXFA_Document::DoDataRemerge() {
1847   CXFA_Node* pFormRoot = ToNode(GetXFAObject(XFA_HASHCODE_Form));
1848   if (pFormRoot) {
1849     while (CXFA_Node* pNode = pFormRoot->GetFirstChild())
1850       pFormRoot->RemoveChildAndNotify(pNode, true);
1851 
1852     pFormRoot->SetBindingNode(nullptr);
1853   }
1854   m_rgGlobalBinding.clear();
1855   DoDataMerge();
1856   GetLayoutProcessor()->SetForceRelayout();
1857 }
1858 
GetGlobalBinding(uint32_t dwNameHash)1859 CXFA_Node* CXFA_Document::GetGlobalBinding(uint32_t dwNameHash) {
1860   auto it = m_rgGlobalBinding.find(dwNameHash);
1861   return it != m_rgGlobalBinding.end() ? it->second : nullptr;
1862 }
1863 
RegisterGlobalBinding(uint32_t dwNameHash,CXFA_Node * pDataNode)1864 void CXFA_Document::RegisterGlobalBinding(uint32_t dwNameHash,
1865                                           CXFA_Node* pDataNode) {
1866   m_rgGlobalBinding[dwNameHash] = pDataNode;
1867 }
1868 
GetPendingNodesCount() const1869 size_t CXFA_Document::GetPendingNodesCount() const {
1870   return m_pPendingPageSet.size();
1871 }
1872 
GetPendingNodeAtIndex(size_t index) const1873 CXFA_Node* CXFA_Document::GetPendingNodeAtIndex(size_t index) const {
1874   return m_pPendingPageSet[index];
1875 }
1876 
AppendPendingNode(CXFA_Node * node)1877 void CXFA_Document::AppendPendingNode(CXFA_Node* node) {
1878   m_pPendingPageSet.push_back(node);
1879 }
1880 
ClearPendingNodes()1881 void CXFA_Document::ClearPendingNodes() {
1882   m_pPendingPageSet.clear();
1883 }
1884 
SetPendingNodesUnusedAndUnbound()1885 void CXFA_Document::SetPendingNodesUnusedAndUnbound() {
1886   for (CXFA_Node* pPageNode : m_pPendingPageSet) {
1887     CXFA_NodeIterator sIterator(pPageNode);
1888     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
1889          pNode = sIterator.MoveToNext()) {
1890       if (pNode->IsContainerNode()) {
1891         CXFA_Node* pBindNode = pNode->GetBindData();
1892         if (pBindNode) {
1893           pBindNode->RemoveBindItem(pNode);
1894           pNode->SetBindingNode(nullptr);
1895         }
1896       }
1897       pNode->SetFlag(XFA_NodeFlag::kUnusedNode);
1898     }
1899   }
1900 }
1901 
1902 CXFA_Document::LayoutProcessorIface::LayoutProcessorIface() = default;
1903 
1904 CXFA_Document::LayoutProcessorIface::~LayoutProcessorIface() = default;
1905 
Trace(cppgc::Visitor * visitor) const1906 void CXFA_Document::LayoutProcessorIface::Trace(cppgc::Visitor* visitor) const {
1907   visitor->Trace(m_pDocument);
1908 }
1909