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