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
17CXFA_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
25CXFA_NodeHelper::~CXFA_NodeHelper() {}
26
27CXFA_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
42int32_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
68int32_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
128int32_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
205CXFA_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
230int32_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
260void 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
295bool 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
308bool 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
346bool 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
407void 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
422bool 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