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