• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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