1 // Copyright 2014 PDFium Authors. All rights reserved.
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_nodehelper.h"
8
9 #include "core/fxcrt/fx_ext.h"
10 #include "xfa/fxfa/parser/cxfa_document.h"
11 #include "xfa/fxfa/parser/cxfa_scriptcontext.h"
12 #include "xfa/fxfa/parser/xfa_localemgr.h"
13 #include "xfa/fxfa/parser/xfa_object.h"
14 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
15 #include "xfa/fxfa/parser/xfa_utils.h"
16
CXFA_NodeHelper()17 CXFA_NodeHelper::CXFA_NodeHelper()
18 : m_eLastCreateType(XFA_Element::DataValue),
19 m_pCreateParent(nullptr),
20 m_iCreateCount(0),
21 m_iCreateFlag(XFA_RESOLVENODE_RSTYPE_CreateNodeOne),
22 m_iCurAllStart(-1),
23 m_pAllStartParent(nullptr) {}
24
~CXFA_NodeHelper()25 CXFA_NodeHelper::~CXFA_NodeHelper() {}
26
ResolveNodes_GetOneChild(CXFA_Node * parent,const FX_WCHAR * pwsName,bool bIsClassName)27 CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetOneChild(CXFA_Node* parent,
28 const FX_WCHAR* pwsName,
29 bool bIsClassName) {
30 if (!parent) {
31 return nullptr;
32 }
33 CXFA_NodeArray siblings;
34 uint32_t uNameHash = FX_HashCode_GetW(CFX_WideStringC(pwsName), false);
35 NodeAcc_TraverseAnySiblings(parent, uNameHash, &siblings, bIsClassName);
36 if (siblings.GetSize() == 0) {
37 return nullptr;
38 }
39 return siblings[0];
40 }
41
CountSiblings(CXFA_Node * pNode,XFA_LOGIC_TYPE eLogicType,CXFA_NodeArray * pSiblings,bool bIsClassName)42 int32_t CXFA_NodeHelper::CountSiblings(CXFA_Node* pNode,
43 XFA_LOGIC_TYPE eLogicType,
44 CXFA_NodeArray* pSiblings,
45 bool bIsClassName) {
46 if (!pNode)
47 return 0;
48 CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);
49 if (!parent)
50 return 0;
51 const XFA_PROPERTY* pProperty = XFA_GetPropertyOfElement(
52 parent->GetElementType(), pNode->GetElementType(), XFA_XDPPACKET_UNKNOWN);
53 if (!pProperty && eLogicType == XFA_LOGIC_Transparent) {
54 parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);
55 if (!parent) {
56 return 0;
57 }
58 }
59 if (bIsClassName) {
60 return NodeAcc_TraverseSiblings(parent, pNode->GetClassHashCode(),
61 pSiblings, eLogicType, bIsClassName);
62 } else {
63 return NodeAcc_TraverseSiblings(parent, pNode->GetNameHash(), pSiblings,
64 eLogicType, bIsClassName);
65 }
66 }
67
NodeAcc_TraverseAnySiblings(CXFA_Node * parent,uint32_t dNameHash,CXFA_NodeArray * pSiblings,bool bIsClassName)68 int32_t CXFA_NodeHelper::NodeAcc_TraverseAnySiblings(CXFA_Node* parent,
69 uint32_t dNameHash,
70 CXFA_NodeArray* pSiblings,
71 bool bIsClassName) {
72 if (!parent || !pSiblings) {
73 return 0;
74 }
75 int32_t nCount = 0;
76 int32_t i = 0;
77 CXFA_NodeArray properties;
78 parent->GetNodeList(properties, XFA_NODEFILTER_Properties);
79 int32_t nProperties = properties.GetSize();
80 for (i = 0; i < nProperties; ++i) {
81 CXFA_Node* child = properties[i];
82 if (bIsClassName) {
83 if (child->GetClassHashCode() == dNameHash) {
84 pSiblings->Add(child);
85 nCount++;
86 }
87 } else {
88 if (child->GetNameHash() == dNameHash) {
89 pSiblings->Add(child);
90 nCount++;
91 }
92 }
93 if (nCount > 0) {
94 return nCount;
95 }
96 nCount +=
97 NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName);
98 }
99 CXFA_NodeArray children;
100 parent->GetNodeList(children, XFA_NODEFILTER_Children);
101 int32_t nChildren = children.GetSize();
102 for (i = 0; i < nChildren; i++) {
103 CXFA_Node* child = children[i];
104 if (bIsClassName) {
105 if (child->GetClassHashCode() == dNameHash) {
106 if (pSiblings) {
107 pSiblings->Add(child);
108 }
109 nCount++;
110 }
111 } else {
112 if (child->GetNameHash() == dNameHash) {
113 if (pSiblings) {
114 pSiblings->Add(child);
115 }
116 nCount++;
117 }
118 }
119 if (nCount > 0) {
120 return nCount;
121 }
122 nCount +=
123 NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName);
124 }
125 return nCount;
126 }
127
NodeAcc_TraverseSiblings(CXFA_Node * parent,uint32_t dNameHash,CXFA_NodeArray * pSiblings,XFA_LOGIC_TYPE eLogicType,bool bIsClassName,bool bIsFindProperty)128 int32_t CXFA_NodeHelper::NodeAcc_TraverseSiblings(CXFA_Node* parent,
129 uint32_t dNameHash,
130 CXFA_NodeArray* pSiblings,
131 XFA_LOGIC_TYPE eLogicType,
132 bool bIsClassName,
133 bool bIsFindProperty) {
134 if (!parent || !pSiblings) {
135 return 0;
136 }
137 int32_t nCount = 0;
138 int32_t i = 0;
139 if (bIsFindProperty) {
140 CXFA_NodeArray properties;
141 parent->GetNodeList(properties, XFA_NODEFILTER_Properties);
142 int32_t nProperties = properties.GetSize();
143 for (i = 0; i < nProperties; ++i) {
144 CXFA_Node* child = properties[i];
145 if (bIsClassName) {
146 if (child->GetClassHashCode() == dNameHash) {
147 pSiblings->Add(child);
148 nCount++;
149 }
150 } else {
151 if (child->GetNameHash() == dNameHash) {
152 if (child->GetElementType() != XFA_Element::PageSet &&
153 child->GetElementType() != XFA_Element::Extras &&
154 child->GetElementType() != XFA_Element::Items) {
155 pSiblings->Add(child);
156 nCount++;
157 }
158 }
159 }
160 if (child->IsUnnamed() &&
161 child->GetElementType() == XFA_Element::PageSet) {
162 nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings,
163 eLogicType, bIsClassName, false);
164 }
165 }
166 if (nCount > 0) {
167 return nCount;
168 }
169 }
170 CXFA_NodeArray children;
171 parent->GetNodeList(children, XFA_NODEFILTER_Children);
172 int32_t nChildren = children.GetSize();
173 for (i = 0; i < nChildren; i++) {
174 CXFA_Node* child = children[i];
175 if (child->GetElementType() == XFA_Element::Variables) {
176 continue;
177 }
178 if (bIsClassName) {
179 if (child->GetClassHashCode() == dNameHash) {
180 if (pSiblings) {
181 pSiblings->Add(child);
182 }
183 nCount++;
184 }
185 } else {
186 if (child->GetNameHash() == dNameHash) {
187 if (pSiblings) {
188 pSiblings->Add(child);
189 }
190 nCount++;
191 }
192 }
193 if (eLogicType == XFA_LOGIC_NoTransparent) {
194 continue;
195 }
196 if (NodeIsTransparent(child) &&
197 child->GetElementType() != XFA_Element::PageSet) {
198 nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings,
199 eLogicType, bIsClassName, false);
200 }
201 }
202 return nCount;
203 }
204
ResolveNodes_GetParent(CXFA_Node * pNode,XFA_LOGIC_TYPE eLogicType)205 CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetParent(CXFA_Node* pNode,
206 XFA_LOGIC_TYPE eLogicType) {
207 if (!pNode) {
208 return nullptr;
209 }
210 if (eLogicType == XFA_LOGIC_NoTransparent) {
211 return pNode->GetNodeItem(XFA_NODEITEM_Parent);
212 }
213 CXFA_Node* parent;
214 CXFA_Node* node = pNode;
215 while (true) {
216 parent = ResolveNodes_GetParent(node);
217 if (!parent) {
218 break;
219 }
220 XFA_Element parentType = parent->GetElementType();
221 if ((!parent->IsUnnamed() && parentType != XFA_Element::SubformSet) ||
222 parentType == XFA_Element::Variables) {
223 break;
224 }
225 node = parent;
226 }
227 return parent;
228 }
229
GetIndex(CXFA_Node * pNode,XFA_LOGIC_TYPE eLogicType,bool bIsProperty,bool bIsClassIndex)230 int32_t CXFA_NodeHelper::GetIndex(CXFA_Node* pNode,
231 XFA_LOGIC_TYPE eLogicType,
232 bool bIsProperty,
233 bool bIsClassIndex) {
234 CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);
235 if (!parent) {
236 return 0;
237 }
238 if (!bIsProperty && eLogicType == XFA_LOGIC_Transparent) {
239 parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);
240 if (!parent) {
241 return 0;
242 }
243 }
244 uint32_t dwHashName = pNode->GetNameHash();
245 if (bIsClassIndex) {
246 dwHashName = pNode->GetClassHashCode();
247 }
248 CXFA_NodeArray siblings;
249 int32_t iSize = NodeAcc_TraverseSiblings(parent, dwHashName, &siblings,
250 eLogicType, bIsClassIndex);
251 for (int32_t i = 0; i < iSize; ++i) {
252 CXFA_Node* child = siblings[i];
253 if (child == pNode) {
254 return i;
255 }
256 }
257 return 0;
258 }
259
GetNameExpression(CXFA_Node * refNode,CFX_WideString & wsName,bool bIsAllPath,XFA_LOGIC_TYPE eLogicType)260 void CXFA_NodeHelper::GetNameExpression(CXFA_Node* refNode,
261 CFX_WideString& wsName,
262 bool bIsAllPath,
263 XFA_LOGIC_TYPE eLogicType) {
264 wsName.clear();
265 if (bIsAllPath) {
266 GetNameExpression(refNode, wsName, false, eLogicType);
267 CFX_WideString wsParent;
268 CXFA_Node* parent =
269 ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);
270 while (parent) {
271 GetNameExpression(parent, wsParent, false, eLogicType);
272 wsParent += L".";
273 wsParent += wsName;
274 wsName = wsParent;
275 parent = ResolveNodes_GetParent(parent, XFA_LOGIC_NoTransparent);
276 }
277 return;
278 }
279
280 CFX_WideString ws;
281 bool bIsProperty = NodeIsProperty(refNode);
282 if (refNode->IsUnnamed() ||
283 (bIsProperty && refNode->GetElementType() != XFA_Element::PageSet)) {
284 ws = refNode->GetClassName();
285 wsName.Format(L"#%s[%d]", ws.c_str(),
286 GetIndex(refNode, eLogicType, bIsProperty, true));
287 return;
288 }
289 ws = refNode->GetCData(XFA_ATTRIBUTE_Name);
290 ws.Replace(L".", L"\\.");
291 wsName.Format(L"%s[%d]", ws.c_str(),
292 GetIndex(refNode, eLogicType, bIsProperty, false));
293 }
294
NodeIsTransparent(CXFA_Node * refNode)295 bool CXFA_NodeHelper::NodeIsTransparent(CXFA_Node* refNode) {
296 if (!refNode) {
297 return false;
298 }
299 XFA_Element refNodeType = refNode->GetElementType();
300 if ((refNode->IsUnnamed() && refNode->IsContainerNode()) ||
301 refNodeType == XFA_Element::SubformSet ||
302 refNodeType == XFA_Element::Area || refNodeType == XFA_Element::Proto) {
303 return true;
304 }
305 return false;
306 }
307
CreateNode_ForCondition(CFX_WideString & wsCondition)308 bool CXFA_NodeHelper::CreateNode_ForCondition(CFX_WideString& wsCondition) {
309 int32_t iLen = wsCondition.GetLength();
310 CFX_WideString wsIndex(L"0");
311 bool bAll = false;
312 if (iLen == 0) {
313 m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;
314 return false;
315 }
316 if (wsCondition.GetAt(0) == '[') {
317 int32_t i = 1;
318 for (; i < iLen; ++i) {
319 FX_WCHAR ch = wsCondition[i];
320 if (ch == ' ') {
321 continue;
322 }
323 if (ch == '+' || ch == '-') {
324 break;
325 } else if (ch == '*') {
326 bAll = true;
327 break;
328 } else {
329 break;
330 }
331 }
332 if (bAll) {
333 wsIndex = L"1";
334 m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeAll;
335 } else {
336 m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;
337 wsIndex = wsCondition.Mid(i, iLen - 1 - i);
338 }
339 int32_t iIndex = wsIndex.GetInteger();
340 m_iCreateCount = iIndex;
341 return true;
342 }
343 return false;
344 }
345
ResolveNodes_CreateNode(CFX_WideString wsName,CFX_WideString wsCondition,bool bLastNode,CXFA_ScriptContext * pScriptContext)346 bool CXFA_NodeHelper::ResolveNodes_CreateNode(
347 CFX_WideString wsName,
348 CFX_WideString wsCondition,
349 bool bLastNode,
350 CXFA_ScriptContext* pScriptContext) {
351 if (!m_pCreateParent) {
352 return false;
353 }
354 bool bIsClassName = false;
355 bool bResult = false;
356 if (wsName.GetAt(0) == '!') {
357 wsName = wsName.Right(wsName.GetLength() - 1);
358 m_pCreateParent = ToNode(
359 pScriptContext->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets));
360 }
361 if (wsName.GetAt(0) == '#') {
362 bIsClassName = true;
363 wsName = wsName.Right(wsName.GetLength() - 1);
364 }
365 if (m_iCreateCount == 0) {
366 CreateNode_ForCondition(wsCondition);
367 }
368 if (bIsClassName) {
369 XFA_Element eType = XFA_GetElementTypeForName(wsName.AsStringC());
370 if (eType == XFA_Element::Unknown)
371 return false;
372
373 for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) {
374 CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eType);
375 if (pNewNode) {
376 m_pCreateParent->InsertChild(pNewNode);
377 if (iIndex == m_iCreateCount - 1) {
378 m_pCreateParent = pNewNode;
379 }
380 bResult = true;
381 }
382 }
383 } else {
384 XFA_Element eClassType = XFA_Element::DataGroup;
385 if (bLastNode) {
386 eClassType = m_eLastCreateType;
387 }
388 for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) {
389 CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType);
390 if (pNewNode) {
391 pNewNode->SetAttribute(XFA_ATTRIBUTE_Name, wsName.AsStringC());
392 pNewNode->CreateXMLMappingNode();
393 m_pCreateParent->InsertChild(pNewNode);
394 if (iIndex == m_iCreateCount - 1) {
395 m_pCreateParent = pNewNode;
396 }
397 bResult = true;
398 }
399 }
400 }
401 if (!bResult) {
402 m_pCreateParent = nullptr;
403 }
404 return bResult;
405 }
406
SetCreateNodeType(CXFA_Node * refNode)407 void CXFA_NodeHelper::SetCreateNodeType(CXFA_Node* refNode) {
408 if (!refNode) {
409 return;
410 }
411 if (refNode->GetElementType() == XFA_Element::Subform) {
412 m_eLastCreateType = XFA_Element::DataGroup;
413 } else if (refNode->GetElementType() == XFA_Element::Field) {
414 m_eLastCreateType = XFA_FieldIsMultiListBox(refNode)
415 ? XFA_Element::DataGroup
416 : XFA_Element::DataValue;
417 } else if (refNode->GetElementType() == XFA_Element::ExclGroup) {
418 m_eLastCreateType = XFA_Element::DataValue;
419 }
420 }
421
NodeIsProperty(CXFA_Node * refNode)422 bool CXFA_NodeHelper::NodeIsProperty(CXFA_Node* refNode) {
423 CXFA_Node* parent = ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);
424 return parent && refNode &&
425 XFA_GetPropertyOfElement(parent->GetElementType(),
426 refNode->GetElementType(),
427 XFA_XDPPACKET_UNKNOWN);
428 }
429