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