Merge to XFA: Use stdint.h types throughout PDFium.
[pdfium.git] / xfa / src / fxfa / src / parser / xfa_script_nodehelper.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../foxitlib.h"\r
8 #include "../common/xfa_utils.h"\r
9 #include "../common/xfa_object.h"\r
10 #include "../common/xfa_document.h"\r
11 #include "../common/xfa_parser.h"\r
12 #include "../common/xfa_script.h"\r
13 #include "../common/xfa_docdata.h"\r
14 #include "../common/xfa_doclayout.h"\r
15 #include "../common/xfa_debug.h"\r
16 #include "../common/xfa_localemgr.h"\r
17 #include "../common/xfa_fm2jsapi.h"\r
18 #include "xfa_debug_parser.h"\r
19 #include "xfa_script_nodehelper.h"\r
20 #include "xfa_script_imp.h"\r
21 CXFA_NodeHelper::CXFA_NodeHelper(void)\r
22     : m_eLastCreateType(XFA_ELEMENT_DataValue), m_pCreateParent(NULL)\r
23     , m_iCreateCount(0), m_iCreateFlag(XFA_RESOLVENODE_RSTYPE_CreateNodeOne)\r
24     , m_iCurAllStart(-1), m_pAllStartParent(NULL)\r
25 {\r
26 }\r
27 CXFA_NodeHelper::~CXFA_NodeHelper(void)\r
28 {\r
29 }\r
30 CXFA_Node*  CXFA_NodeHelper::XFA_ResolveNodes_GetOneChild(CXFA_Node* parent, FX_LPCWSTR pwsName, FX_BOOL bIsClassName)\r
31 {\r
32     if(parent == NULL) {\r
33         return NULL;\r
34     }\r
35     CXFA_NodeArray siblings;\r
36     uint32_t uNameHash = FX_HashCode_String_GetW(pwsName, FXSYS_wcslen(pwsName));\r
37     XFA_NodeAcc_TraverseAnySiblings(parent, uNameHash, &siblings, bIsClassName);\r
38     if (siblings.GetSize() == 0) {\r
39         return NULL;\r
40     }\r
41     return siblings[0];\r
42 }\r
43 int32_t  CXFA_NodeHelper::XFA_CountSiblings(CXFA_Node* pNode, XFA_LOGIC_TYPE eLogicType, CXFA_NodeArray *pSiblings, FX_BOOL bIsClassName)\r
44 {\r
45     CXFA_Node* parent = XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);\r
46     if(parent == NULL) {\r
47         return 0;\r
48     }\r
49     XFA_LPCPROPERTY pPropert = XFA_GetPropertyOfElement(parent->GetClassID(), pNode->GetClassID(), XFA_XDPPACKET_UNKNOWN);\r
50     if(!pPropert && eLogicType == XFA_LOGIC_Transparent) {\r
51         parent = XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);\r
52         if (parent == NULL) {\r
53             return 0;\r
54         }\r
55     }\r
56     if(bIsClassName) {\r
57         return XFA_NodeAcc_TraverseSiblings(parent, pNode->GetClassHashCode(), pSiblings, eLogicType, bIsClassName);\r
58     } else {\r
59         return  XFA_NodeAcc_TraverseSiblings(parent, pNode->GetNameHash(), pSiblings, eLogicType, bIsClassName);\r
60     }\r
61 }\r
62 int32_t CXFA_NodeHelper::XFA_NodeAcc_TraverseAnySiblings(CXFA_Node* parent, FX_DWORD dNameHash, CXFA_NodeArray* pSiblings, FX_BOOL bIsClassName )\r
63 {\r
64     if(parent == NULL || pSiblings == NULL) {\r
65         return 0;\r
66     }\r
67     int32_t nCount = 0;\r
68     int32_t i = 0;\r
69     CXFA_NodeArray properties;\r
70     parent->GetNodeList(properties, XFA_NODEFILTER_Properties);\r
71     int32_t nProperties = properties.GetSize();\r
72     for (i = 0; i < nProperties; ++i) {\r
73         CXFA_Node* child = properties[i];\r
74         if(bIsClassName) {\r
75             if (child->GetClassHashCode() == dNameHash) {\r
76                 pSiblings->Add(child);\r
77                 nCount ++;\r
78             }\r
79         } else {\r
80             if (child->GetNameHash() == dNameHash) {\r
81                 pSiblings->Add(child);\r
82                 nCount ++;\r
83             }\r
84         }\r
85         if(nCount > 0) {\r
86             return nCount;\r
87         }\r
88         nCount += XFA_NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName);\r
89     }\r
90     CXFA_NodeArray children;\r
91     parent->GetNodeList(children, XFA_NODEFILTER_Children);\r
92     int32_t nChildren = children.GetSize();\r
93     for (i = 0; i < nChildren; i ++) {\r
94         CXFA_Node* child = children[i];\r
95         if(bIsClassName) {\r
96             if (child->GetClassHashCode() == dNameHash) {\r
97                 if (pSiblings) {\r
98                     pSiblings->Add(child);\r
99                 }\r
100                 nCount ++;\r
101             }\r
102         } else {\r
103             if (child->GetNameHash() == dNameHash) {\r
104                 if (pSiblings) {\r
105                     pSiblings->Add(child);\r
106                 }\r
107                 nCount ++;\r
108             }\r
109         }\r
110         if(nCount > 0) {\r
111             return nCount;\r
112         }\r
113         nCount += XFA_NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName);\r
114     }\r
115     return nCount;\r
116 }\r
117 int32_t  CXFA_NodeHelper::XFA_NodeAcc_TraverseSiblings(CXFA_Node* parent, FX_DWORD dNameHash, CXFA_NodeArray* pSiblings, XFA_LOGIC_TYPE eLogicType, FX_BOOL bIsClassName, FX_BOOL bIsFindProperty)\r
118 {\r
119     if (parent == NULL || pSiblings == NULL) {\r
120         return 0;\r
121     }\r
122     int32_t nCount = 0;\r
123     int32_t i = 0;\r
124     if(bIsFindProperty) {\r
125         CXFA_NodeArray properties;\r
126         parent->GetNodeList(properties, XFA_NODEFILTER_Properties);\r
127         int32_t nProperties = properties.GetSize();\r
128         for (i = 0; i < nProperties; ++i) {\r
129             CXFA_Node* child = properties[i];\r
130             if(bIsClassName) {\r
131                 if (child->GetClassHashCode() == dNameHash) {\r
132                     pSiblings->Add(child);\r
133                     nCount ++;\r
134                 }\r
135             } else {\r
136                 if (child->GetNameHash() == dNameHash) {\r
137                     if(child->GetClassID() != XFA_ELEMENT_PageSet && child->GetClassID() != XFA_ELEMENT_Extras\r
138                             && child->GetClassID() != XFA_ELEMENT_Items) {\r
139                         pSiblings->Add(child);\r
140                         nCount ++;\r
141                     }\r
142                 }\r
143             }\r
144             if (child->IsUnnamed() && child->GetClassID() == XFA_ELEMENT_PageSet) {\r
145                 nCount += XFA_NodeAcc_TraverseSiblings(child, dNameHash, pSiblings, eLogicType, bIsClassName, FALSE);\r
146             }\r
147         }\r
148         if(nCount > 0) {\r
149             return nCount;\r
150         }\r
151     }\r
152     CXFA_NodeArray children;\r
153     parent->GetNodeList(children, XFA_NODEFILTER_Children);\r
154     int32_t nChildren = children.GetSize();\r
155     for (i = 0; i < nChildren; i ++) {\r
156         CXFA_Node* child = children[i];\r
157         if(child->GetClassID() == XFA_ELEMENT_Variables) {\r
158             continue;\r
159         }\r
160         if(bIsClassName) {\r
161             if (child->GetClassHashCode() == dNameHash) {\r
162                 if (pSiblings) {\r
163                     pSiblings->Add(child);\r
164                 }\r
165                 nCount ++;\r
166             }\r
167         } else {\r
168             if (child->GetNameHash() == dNameHash) {\r
169                 if (pSiblings) {\r
170                     pSiblings->Add(child);\r
171                 }\r
172                 nCount ++;\r
173             }\r
174         }\r
175         if (eLogicType == XFA_LOGIC_NoTransparent) {\r
176             continue;\r
177         }\r
178         if (XFA_NodeIsTransparent(child) && child->GetClassID() != XFA_ELEMENT_PageSet) {\r
179             nCount += XFA_NodeAcc_TraverseSiblings(child, dNameHash, pSiblings, eLogicType, bIsClassName, FALSE);\r
180         }\r
181     }\r
182     return nCount;\r
183 }\r
184 CXFA_Node*  CXFA_NodeHelper::XFA_ResolveNodes_GetParent(CXFA_Node* pNode, XFA_LOGIC_TYPE eLogicType)\r
185 {\r
186     if (!pNode) {\r
187         return NULL;\r
188     }\r
189     if (eLogicType == XFA_LOGIC_NoTransparent) {\r
190         return pNode->GetNodeItem(XFA_NODEITEM_Parent);\r
191     }\r
192     CXFA_Node* parent;\r
193     CXFA_Node* node = pNode;\r
194     while (TRUE) {\r
195         parent = XFA_ResolveNodes_GetParent(node);\r
196         if (parent == NULL) {\r
197             break;\r
198         }\r
199         XFA_ELEMENT parentElement = parent->GetClassID();\r
200         if ((!parent->IsUnnamed() && parentElement != XFA_ELEMENT_SubformSet) || parentElement == XFA_ELEMENT_Variables) {\r
201             break;\r
202         }\r
203         node = parent;\r
204     }\r
205     return parent;\r
206 }\r
207 int32_t  CXFA_NodeHelper::XFA_GetIndex(CXFA_Node* pNode, XFA_LOGIC_TYPE eLogicType, FX_BOOL bIsProperty , FX_BOOL bIsClassIndex )\r
208 {\r
209     CXFA_Node* parent = XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent);\r
210     if(parent == NULL) {\r
211         return 0;\r
212     }\r
213     if(!bIsProperty && eLogicType == XFA_LOGIC_Transparent) {\r
214         parent = XFA_ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent);\r
215         if (parent == NULL) {\r
216             return 0;\r
217         }\r
218     }\r
219     FX_DWORD dwHashName = pNode->GetNameHash();\r
220     if(bIsClassIndex) {\r
221         dwHashName = pNode->GetClassHashCode();\r
222     }\r
223     CXFA_NodeArray siblings;\r
224     int32_t iSize = XFA_NodeAcc_TraverseSiblings(parent, dwHashName, &siblings, eLogicType, bIsClassIndex);\r
225     for (int32_t i = 0; i < iSize; ++i) {\r
226         CXFA_Node* child = siblings[i];\r
227         if (child == pNode) {\r
228             return i;\r
229         }\r
230     }\r
231     return 0;\r
232 }\r
233 void CXFA_NodeHelper::XFA_GetNameExpression(CXFA_Node* refNode, CFX_WideString &wsName, FX_BOOL bIsAllPath, XFA_LOGIC_TYPE eLogicType)\r
234 {\r
235     wsName.Empty();\r
236     if (bIsAllPath) {\r
237         XFA_GetNameExpression(refNode, wsName, FALSE, eLogicType);\r
238         CFX_WideString wsParent;\r
239         CXFA_Node* parent = XFA_ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);\r
240         while (parent != NULL) {\r
241             XFA_GetNameExpression(parent, wsParent, FALSE, eLogicType);\r
242             wsParent += L".";\r
243             wsParent += wsName;\r
244             wsName = wsParent;\r
245             parent = XFA_ResolveNodes_GetParent(parent, XFA_LOGIC_NoTransparent);\r
246         }\r
247         return;\r
248     } else {\r
249         CFX_WideStringC wsTagName;\r
250         CFX_WideString ws;\r
251         FX_BOOL bIsProperty = XFA_NodeIsProperty(refNode);\r
252         if (refNode->IsUnnamed() || (bIsProperty && refNode->GetClassID() != XFA_ELEMENT_PageSet)) {\r
253             refNode->GetClassName(wsTagName);\r
254             ws = wsTagName;\r
255             wsName.Format(L"#%s[%d]", (FX_LPCWSTR)ws, XFA_GetIndex(refNode, eLogicType, bIsProperty, TRUE));\r
256             return;\r
257         }\r
258         ws = refNode->GetCData(XFA_ATTRIBUTE_Name);\r
259         ws.Replace(L".", L"\\.");\r
260         wsName.Format(L"%s[%d]", (FX_LPCWSTR)ws, XFA_GetIndex(refNode, eLogicType, bIsProperty, FALSE));\r
261     }\r
262 }\r
263 FX_BOOL CXFA_NodeHelper::XFA_NodeIsTransparent(CXFA_Node* refNode)\r
264 {\r
265     if(refNode == NULL) {\r
266         return FALSE;\r
267     }\r
268     XFA_ELEMENT eRefNode = refNode->GetClassID();\r
269     if((refNode->IsUnnamed() && refNode->IsContainerNode()) || eRefNode == XFA_ELEMENT_SubformSet\r
270             || eRefNode == XFA_ELEMENT_Area || eRefNode == XFA_ELEMENT_Proto) {\r
271         return TRUE;\r
272     }\r
273     return FALSE;\r
274 }\r
275 FX_BOOL CXFA_NodeHelper::XFA_CreateNode_ForCondition(CFX_WideString & wsCondition)\r
276 {\r
277     int32_t iLen = wsCondition.GetLength();\r
278     CFX_WideString wsIndex = FX_WSTRC(L"0");;\r
279     FX_BOOL bAll = FALSE;\r
280     if(iLen == 0) {\r
281         m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;\r
282         return FALSE;\r
283     }\r
284     if(wsCondition.GetAt(0) == '[') {\r
285         int32_t i = 1;\r
286         for (; i < iLen; ++i) {\r
287             FX_WCHAR ch = wsCondition[i];\r
288             if (ch == ' ') {\r
289                 continue;\r
290             }\r
291             if (ch == '+' || ch == '-') {\r
292                 break;\r
293             } else if (ch == '*') {\r
294                 bAll = TRUE;\r
295                 break;\r
296             } else {\r
297                 break;\r
298             }\r
299         }\r
300         if(bAll) {\r
301             wsIndex = FX_WSTRC(L"1");\r
302             m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeAll;\r
303         } else {\r
304             m_iCreateFlag = XFA_RESOLVENODE_RSTYPE_CreateNodeOne;\r
305             wsIndex = wsCondition.Mid(i, iLen - 1 - i);\r
306         }\r
307         int32_t iIndex = wsIndex.GetInteger();\r
308         m_iCreateCount = iIndex;\r
309         return TRUE;\r
310     }\r
311     return FALSE;\r
312 }\r
313 FX_BOOL CXFA_NodeHelper::XFA_ResolveNodes_CreateNode(CFX_WideString wsName, CFX_WideString wsCondition, FX_BOOL bLastNode, CXFA_ScriptContext* pScriptContext)\r
314 {\r
315     if(m_pCreateParent == NULL) {\r
316         return FALSE;\r
317     }\r
318     FX_BOOL bIsClassName = FALSE;\r
319     FX_BOOL bResult = FALSE;\r
320     if(wsName.GetAt(0) == '!') {\r
321         wsName = wsName.Right(wsName.GetLength() - 1);\r
322         m_pCreateParent =  (CXFA_Node*)pScriptContext->GetDocument()->GetXFANode(XFA_HASHCODE_Datasets);\r
323     }\r
324     if(wsName.GetAt(0) == '#') {\r
325         bIsClassName = TRUE;\r
326         wsName = wsName.Right(wsName.GetLength() - 1);\r
327     }\r
328     if(m_iCreateCount == 0) {\r
329         XFA_CreateNode_ForCondition(wsCondition);\r
330     }\r
331     if(bIsClassName) {\r
332         XFA_LPCELEMENTINFO lpElement = XFA_GetElementByName(wsName);\r
333         if(lpElement == NULL) {\r
334             return FALSE;\r
335         }\r
336         for(int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex ++) {\r
337             CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(lpElement->eName);\r
338             if(pNewNode) {\r
339                 m_pCreateParent->InsertChild(pNewNode);\r
340                 if(iIndex == m_iCreateCount - 1) {\r
341                     m_pCreateParent = pNewNode;\r
342                 }\r
343                 bResult = TRUE;\r
344             }\r
345         }\r
346     } else {\r
347         XFA_ELEMENT eClassType = XFA_ELEMENT_DataGroup;\r
348         if(bLastNode) {\r
349             eClassType = m_eLastCreateType;\r
350         }\r
351         for(int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex ++) {\r
352             CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType);\r
353             if(pNewNode) {\r
354                 pNewNode->SetAttribute(XFA_ATTRIBUTE_Name, wsName);\r
355                 pNewNode->CreateXMLMappingNode();\r
356                 m_pCreateParent->InsertChild(pNewNode);\r
357                 if(iIndex == m_iCreateCount - 1) {\r
358                     m_pCreateParent = pNewNode;\r
359                 }\r
360                 bResult = TRUE;\r
361             }\r
362         }\r
363     }\r
364     if(!bResult) {\r
365         m_pCreateParent = NULL;\r
366     }\r
367     return bResult;\r
368 }\r
369 void CXFA_NodeHelper::XFA_SetCreateNodeType(CXFA_Node* refNode)\r
370 {\r
371     if(refNode == NULL) {\r
372         return;\r
373     }\r
374     if(refNode->GetClassID() == XFA_ELEMENT_Subform) {\r
375         m_eLastCreateType = XFA_ELEMENT_DataGroup;\r
376     } else if(refNode->GetClassID() == XFA_ELEMENT_Field) {\r
377         m_eLastCreateType = XFA_FieldIsMultiListBox(refNode) ? XFA_ELEMENT_DataGroup : XFA_ELEMENT_DataValue;\r
378     } else if(refNode->GetClassID() == XFA_ELEMENT_ExclGroup) {\r
379         m_eLastCreateType = XFA_ELEMENT_DataValue;\r
380     }\r
381 }\r
382 FX_BOOL CXFA_NodeHelper::XFA_NodeIsProperty(CXFA_Node* refNode)\r
383 {\r
384     FX_BOOL bRes = FALSE;\r
385     CXFA_Node* parent = XFA_ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent);\r
386     if(parent != NULL && refNode != NULL) {\r
387         XFA_LPCPROPERTY pPropert = XFA_GetPropertyOfElement(parent->GetClassID(), refNode->GetClassID(), XFA_XDPPACKET_UNKNOWN);\r
388         if(pPropert) {\r
389             bRes = TRUE;\r
390         }\r
391     }\r
392     return bRes;\r
393 }\r