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/src/foxitlib.h"
8 #include "xfa/src/fxfa/src/common/xfa_utils.h"
9 #include "xfa/src/fxfa/src/common/xfa_object.h"
10 #include "xfa/src/fxfa/src/common/xfa_document.h"
11 #include "xfa/src/fxfa/src/common/xfa_parser.h"
12 #include "xfa/src/fxfa/src/common/xfa_script.h"
13 #include "xfa/src/fxfa/src/common/xfa_docdata.h"
14 #include "xfa/src/fxfa/src/common/xfa_doclayout.h"
15 #include "xfa/src/fxfa/src/common/xfa_localemgr.h"
16 #include "xfa/src/fxfa/src/common/xfa_fm2jsapi.h"
17 #include "xfa_script_nodehelper.h"
18 #include "xfa_script_imp.h"
CXFA_NodeHelper(void)19 CXFA_NodeHelper::CXFA_NodeHelper(void)
20     : m_eLastCreateType(XFA_ELEMENT_DataValue),
21       m_pCreateParent(NULL),
22       m_iCreateCount(0),
23       m_iCreateFlag(XFA_RESOLVENODE_RSTYPE_CreateNodeOne),
24       m_iCurAllStart(-1),
25       m_pAllStartParent(NULL) {}
~CXFA_NodeHelper(void)26 CXFA_NodeHelper::~CXFA_NodeHelper(void) {}
XFA_ResolveNodes_GetOneChild(CXFA_Node * parent,const FX_WCHAR * pwsName,FX_BOOL bIsClassName)27 CXFA_Node* CXFA_NodeHelper::XFA_ResolveNodes_GetOneChild(
28     CXFA_Node* parent,
29     const FX_WCHAR* pwsName,
30     FX_BOOL bIsClassName) {
31   if (parent == NULL) {
32     return NULL;
33   }
34   CXFA_NodeArray siblings;
35   uint32_t uNameHash = FX_HashCode_String_GetW(pwsName, FXSYS_wcslen(pwsName));
36   XFA_NodeAcc_TraverseAnySiblings(parent, uNameHash, &siblings, bIsClassName);
37   if (siblings.GetSize() == 0) {
38     return NULL;
39   }
40   return siblings[0];
41 }
XFA_CountSiblings(CXFA_Node * pNode,XFA_LOGIC_TYPE eLogicType,CXFA_NodeArray * pSiblings,FX_BOOL bIsClassName)42 int32_t CXFA_NodeHelper::XFA_CountSiblings(CXFA_Node* pNode,
43                                            XFA_LOGIC_TYPE eLogicType,
44                                            CXFA_NodeArray* pSiblings,
45                                            FX_BOOL bIsClassName) {
46   CXFA_Node* parent =
47       XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);
48   if (parent == NULL) {
49     return 0;
50   }
51   XFA_LPCPROPERTY pPropert = XFA_GetPropertyOfElement(
52       parent->GetClassID(), pNode->GetClassID(), XFA_XDPPACKET_UNKNOWN);
53   if (!pPropert && eLogicType == XFA_LOGIC_Transparent) {
54     parent = XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);
55     if (parent == NULL) {
56       return 0;
57     }
58   }
59   if (bIsClassName) {
60     return XFA_NodeAcc_TraverseSiblings(parent, pNode->GetClassHashCode(),
61                                         pSiblings, eLogicType, bIsClassName);
62   } else {
63     return XFA_NodeAcc_TraverseSiblings(parent, pNode->GetNameHash(), pSiblings,
64                                         eLogicType, bIsClassName);
65   }
66 }
XFA_NodeAcc_TraverseAnySiblings(CXFA_Node * parent,FX_DWORD dNameHash,CXFA_NodeArray * pSiblings,FX_BOOL bIsClassName)67 int32_t CXFA_NodeHelper::XFA_NodeAcc_TraverseAnySiblings(
68     CXFA_Node* parent,
69     FX_DWORD dNameHash,
70     CXFA_NodeArray* pSiblings,
71     FX_BOOL bIsClassName) {
72   if (parent == NULL || pSiblings == NULL) {
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 += XFA_NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings,
97                                               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 += XFA_NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings,
123                                               bIsClassName);
124   }
125   return nCount;
126 }
XFA_NodeAcc_TraverseSiblings(CXFA_Node * parent,FX_DWORD dNameHash,CXFA_NodeArray * pSiblings,XFA_LOGIC_TYPE eLogicType,FX_BOOL bIsClassName,FX_BOOL bIsFindProperty)127 int32_t CXFA_NodeHelper::XFA_NodeAcc_TraverseSiblings(CXFA_Node* parent,
128                                                       FX_DWORD dNameHash,
129                                                       CXFA_NodeArray* pSiblings,
130                                                       XFA_LOGIC_TYPE eLogicType,
131                                                       FX_BOOL bIsClassName,
132                                                       FX_BOOL bIsFindProperty) {
133   if (parent == NULL || pSiblings == NULL) {
134     return 0;
135   }
136   int32_t nCount = 0;
137   int32_t i = 0;
138   if (bIsFindProperty) {
139     CXFA_NodeArray properties;
140     parent->GetNodeList(properties, XFA_NODEFILTER_Properties);
141     int32_t nProperties = properties.GetSize();
142     for (i = 0; i < nProperties; ++i) {
143       CXFA_Node* child = properties[i];
144       if (bIsClassName) {
145         if (child->GetClassHashCode() == dNameHash) {
146           pSiblings->Add(child);
147           nCount++;
148         }
149       } else {
150         if (child->GetNameHash() == dNameHash) {
151           if (child->GetClassID() != XFA_ELEMENT_PageSet &&
152               child->GetClassID() != XFA_ELEMENT_Extras &&
153               child->GetClassID() != XFA_ELEMENT_Items) {
154             pSiblings->Add(child);
155             nCount++;
156           }
157         }
158       }
159       if (child->IsUnnamed() && child->GetClassID() == XFA_ELEMENT_PageSet) {
160         nCount += XFA_NodeAcc_TraverseSiblings(child, dNameHash, pSiblings,
161                                                eLogicType, bIsClassName, FALSE);
162       }
163     }
164     if (nCount > 0) {
165       return nCount;
166     }
167   }
168   CXFA_NodeArray children;
169   parent->GetNodeList(children, XFA_NODEFILTER_Children);
170   int32_t nChildren = children.GetSize();
171   for (i = 0; i < nChildren; i++) {
172     CXFA_Node* child = children[i];
173     if (child->GetClassID() == XFA_ELEMENT_Variables) {
174       continue;
175     }
176     if (bIsClassName) {
177       if (child->GetClassHashCode() == dNameHash) {
178         if (pSiblings) {
179           pSiblings->Add(child);
180         }
181         nCount++;
182       }
183     } else {
184       if (child->GetNameHash() == dNameHash) {
185         if (pSiblings) {
186           pSiblings->Add(child);
187         }
188         nCount++;
189       }
190     }
191     if (eLogicType == XFA_LOGIC_NoTransparent) {
192       continue;
193     }
194     if (XFA_NodeIsTransparent(child) &&
195         child->GetClassID() != XFA_ELEMENT_PageSet) {
196       nCount += XFA_NodeAcc_TraverseSiblings(child, dNameHash, pSiblings,
197                                              eLogicType, bIsClassName, FALSE);
198     }
199   }
200   return nCount;
201 }
XFA_ResolveNodes_GetParent(CXFA_Node * pNode,XFA_LOGIC_TYPE eLogicType)202 CXFA_Node* CXFA_NodeHelper::XFA_ResolveNodes_GetParent(
203     CXFA_Node* pNode,
204     XFA_LOGIC_TYPE eLogicType) {
205   if (!pNode) {
206     return NULL;
207   }
208   if (eLogicType == XFA_LOGIC_NoTransparent) {
209     return pNode->GetNodeItem(XFA_NODEITEM_Parent);
210   }
211   CXFA_Node* parent;
212   CXFA_Node* node = pNode;
213   while (TRUE) {
214     parent = XFA_ResolveNodes_GetParent(node);
215     if (parent == NULL) {
216       break;
217     }
218     XFA_ELEMENT parentElement = parent->GetClassID();
219     if ((!parent->IsUnnamed() && parentElement != XFA_ELEMENT_SubformSet) ||
220         parentElement == XFA_ELEMENT_Variables) {
221       break;
222     }
223     node = parent;
224   }
225   return parent;
226 }
XFA_GetIndex(CXFA_Node * pNode,XFA_LOGIC_TYPE eLogicType,FX_BOOL bIsProperty,FX_BOOL bIsClassIndex)227 int32_t CXFA_NodeHelper::XFA_GetIndex(CXFA_Node* pNode,
228                                       XFA_LOGIC_TYPE eLogicType,
229                                       FX_BOOL bIsProperty,
230                                       FX_BOOL bIsClassIndex) {
231   CXFA_Node* parent =
232       XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);
233   if (parent == NULL) {
234     return 0;
235   }
236   if (!bIsProperty && eLogicType == XFA_LOGIC_Transparent) {
237     parent = XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);
238     if (parent == NULL) {
239       return 0;
240     }
241   }
242   FX_DWORD dwHashName = pNode->GetNameHash();
243   if (bIsClassIndex) {
244     dwHashName = pNode->GetClassHashCode();
245   }
246   CXFA_NodeArray siblings;
247   int32_t iSize = XFA_NodeAcc_TraverseSiblings(parent, dwHashName, &siblings,
248                                                eLogicType, bIsClassIndex);
249   for (int32_t i = 0; i < iSize; ++i) {
250     CXFA_Node* child = siblings[i];
251     if (child == pNode) {
252       return i;
253     }
254   }
255   return 0;
256 }
XFA_GetNameExpression(CXFA_Node * refNode,CFX_WideString & wsName,FX_BOOL bIsAllPath,XFA_LOGIC_TYPE eLogicType)257 void CXFA_NodeHelper::XFA_GetNameExpression(CXFA_Node* refNode,
258                                             CFX_WideString& wsName,
259                                             FX_BOOL bIsAllPath,
260                                             XFA_LOGIC_TYPE eLogicType) {
261   wsName.Empty();
262   if (bIsAllPath) {
263     XFA_GetNameExpression(refNode, wsName, FALSE, eLogicType);
264     CFX_WideString wsParent;
265     CXFA_Node* parent =
266         XFA_ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);
267     while (parent != NULL) {
268       XFA_GetNameExpression(parent, wsParent, FALSE, eLogicType);
269       wsParent += L".";
270       wsParent += wsName;
271       wsName = wsParent;
272       parent = XFA_ResolveNodes_GetParent(parent, XFA_LOGIC_NoTransparent);
273     }
274     return;
275   } else {
276     CFX_WideStringC wsTagName;
277     CFX_WideString ws;
278     FX_BOOL bIsProperty = XFA_NodeIsProperty(refNode);
279     if (refNode->IsUnnamed() ||
280         (bIsProperty && refNode->GetClassID() != XFA_ELEMENT_PageSet)) {
281       refNode->GetClassName(wsTagName);
282       ws = wsTagName;
283       wsName.Format(L"#%s[%d]", (const FX_WCHAR*)ws,
284                     XFA_GetIndex(refNode, eLogicType, bIsProperty, TRUE));
285       return;
286     }
287     ws = refNode->GetCData(XFA_ATTRIBUTE_Name);
288     ws.Replace(L".", L"\\.");
289     wsName.Format(L"%s[%d]", (const FX_WCHAR*)ws,
290                   XFA_GetIndex(refNode, eLogicType, bIsProperty, FALSE));
291   }
292 }
XFA_NodeIsTransparent(CXFA_Node * refNode)293 FX_BOOL CXFA_NodeHelper::XFA_NodeIsTransparent(CXFA_Node* refNode) {
294   if (refNode == NULL) {
295     return FALSE;
296   }
297   XFA_ELEMENT eRefNode = refNode->GetClassID();
298   if ((refNode->IsUnnamed() && refNode->IsContainerNode()) ||
299       eRefNode == XFA_ELEMENT_SubformSet || eRefNode == XFA_ELEMENT_Area ||
300       eRefNode == XFA_ELEMENT_Proto) {
301     return TRUE;
302   }
303   return FALSE;
304 }
XFA_CreateNode_ForCondition(CFX_WideString & wsCondition)305 FX_BOOL CXFA_NodeHelper::XFA_CreateNode_ForCondition(
306     CFX_WideString& wsCondition) {
307   int32_t iLen = wsCondition.GetLength();
308   CFX_WideString wsIndex = FX_WSTRC(L"0");
309   ;
310   FX_BOOL bAll = FALSE;
311   if (iLen == 0) {
312     m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;
313     return FALSE;
314   }
315   if (wsCondition.GetAt(0) == '[') {
316     int32_t i = 1;
317     for (; i < iLen; ++i) {
318       FX_WCHAR ch = wsCondition[i];
319       if (ch == ' ') {
320         continue;
321       }
322       if (ch == '+' || ch == '-') {
323         break;
324       } else if (ch == '*') {
325         bAll = TRUE;
326         break;
327       } else {
328         break;
329       }
330     }
331     if (bAll) {
332       wsIndex = FX_WSTRC(L"1");
333       m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeAll;
334     } else {
335       m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;
336       wsIndex = wsCondition.Mid(i, iLen - 1 - i);
337     }
338     int32_t iIndex = wsIndex.GetInteger();
339     m_iCreateCount = iIndex;
340     return TRUE;
341   }
342   return FALSE;
343 }
XFA_ResolveNodes_CreateNode(CFX_WideString wsName,CFX_WideString wsCondition,FX_BOOL bLastNode,CXFA_ScriptContext * pScriptContext)344 FX_BOOL CXFA_NodeHelper::XFA_ResolveNodes_CreateNode(
345     CFX_WideString wsName,
346     CFX_WideString wsCondition,
347     FX_BOOL bLastNode,
348     CXFA_ScriptContext* pScriptContext) {
349   if (m_pCreateParent == NULL) {
350     return FALSE;
351   }
352   FX_BOOL bIsClassName = FALSE;
353   FX_BOOL bResult = FALSE;
354   if (wsName.GetAt(0) == '!') {
355     wsName = wsName.Right(wsName.GetLength() - 1);
356     m_pCreateParent = (CXFA_Node*)pScriptContext->GetDocument()->GetXFANode(
357         XFA_HASHCODE_Datasets);
358   }
359   if (wsName.GetAt(0) == '#') {
360     bIsClassName = TRUE;
361     wsName = wsName.Right(wsName.GetLength() - 1);
362   }
363   if (m_iCreateCount == 0) {
364     XFA_CreateNode_ForCondition(wsCondition);
365   }
366   if (bIsClassName) {
367     XFA_LPCELEMENTINFO lpElement = XFA_GetElementByName(wsName);
368     if (lpElement == NULL) {
369       return FALSE;
370     }
371     for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) {
372       CXFA_Node* pNewNode =
373           m_pCreateParent->CreateSamePacketNode(lpElement->eName);
374       if (pNewNode) {
375         m_pCreateParent->InsertChild(pNewNode);
376         if (iIndex == m_iCreateCount - 1) {
377           m_pCreateParent = pNewNode;
378         }
379         bResult = TRUE;
380       }
381     }
382   } else {
383     XFA_ELEMENT eClassType = XFA_ELEMENT_DataGroup;
384     if (bLastNode) {
385       eClassType = m_eLastCreateType;
386     }
387     for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) {
388       CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType);
389       if (pNewNode) {
390         pNewNode->SetAttribute(XFA_ATTRIBUTE_Name, wsName);
391         pNewNode->CreateXMLMappingNode();
392         m_pCreateParent->InsertChild(pNewNode);
393         if (iIndex == m_iCreateCount - 1) {
394           m_pCreateParent = pNewNode;
395         }
396         bResult = TRUE;
397       }
398     }
399   }
400   if (!bResult) {
401     m_pCreateParent = NULL;
402   }
403   return bResult;
404 }
XFA_SetCreateNodeType(CXFA_Node * refNode)405 void CXFA_NodeHelper::XFA_SetCreateNodeType(CXFA_Node* refNode) {
406   if (refNode == NULL) {
407     return;
408   }
409   if (refNode->GetClassID() == XFA_ELEMENT_Subform) {
410     m_eLastCreateType = XFA_ELEMENT_DataGroup;
411   } else if (refNode->GetClassID() == XFA_ELEMENT_Field) {
412     m_eLastCreateType = XFA_FieldIsMultiListBox(refNode)
413                             ? XFA_ELEMENT_DataGroup
414                             : XFA_ELEMENT_DataValue;
415   } else if (refNode->GetClassID() == XFA_ELEMENT_ExclGroup) {
416     m_eLastCreateType = XFA_ELEMENT_DataValue;
417   }
418 }
XFA_NodeIsProperty(CXFA_Node * refNode)419 FX_BOOL CXFA_NodeHelper::XFA_NodeIsProperty(CXFA_Node* refNode) {
420   FX_BOOL bRes = FALSE;
421   CXFA_Node* parent =
422       XFA_ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);
423   if (parent != NULL && refNode != NULL) {
424     XFA_LPCPROPERTY pPropert = XFA_GetPropertyOfElement(
425         parent->GetClassID(), refNode->GetClassID(), XFA_XDPPACKET_UNKNOWN);
426     if (pPropert) {
427       bRes = TRUE;
428     }
429   }
430   return bRes;
431 }
432