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 <utility>
10 
11 #include "core/fxcrt/fx_extension.h"
12 #include "fxjs/xfa/cfxjse_engine.h"
13 #include "fxjs/xfa/cjx_object.h"
14 #include "xfa/fxfa/parser/cxfa_document.h"
15 #include "xfa/fxfa/parser/cxfa_localemgr.h"
16 #include "xfa/fxfa/parser/cxfa_node.h"
17 #include "xfa/fxfa/parser/xfa_basic_data.h"
18 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
19 #include "xfa/fxfa/parser/xfa_utils.h"
20 
21 CXFA_NodeHelper::CXFA_NodeHelper() = default;
22 
23 CXFA_NodeHelper::~CXFA_NodeHelper() = default;
24 
CreateNodeForCondition(const WideString & wsCondition)25 bool CXFA_NodeHelper::CreateNodeForCondition(const WideString& wsCondition) {
26   size_t szLen = wsCondition.GetLength();
27   WideString wsIndex(L"0");
28   bool bAll = false;
29   if (szLen == 0) {
30     m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne;
31     return false;
32   }
33   if (wsCondition[0] != '[')
34     return false;
35 
36   size_t i = 1;
37   for (; i < szLen; ++i) {
38     wchar_t ch = wsCondition[i];
39     if (ch == ' ')
40       continue;
41 
42     if (ch == '*')
43       bAll = true;
44     break;
45   }
46   if (bAll) {
47     wsIndex = L"1";
48     m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeAll;
49   } else {
50     m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne;
51     wsIndex = wsCondition.Substr(i, szLen - 1 - i);
52   }
53   int32_t iCount = wsIndex.GetInteger();
54   if (iCount < 0)
55     return false;
56 
57   m_iCreateCount = iCount;
58   return true;
59 }
60 
CreateNode(const WideString & wsName,const WideString & wsCondition,bool bLastNode,CFXJSE_Engine * pScriptContext)61 bool CXFA_NodeHelper::CreateNode(const WideString& wsName,
62                                  const WideString& wsCondition,
63                                  bool bLastNode,
64                                  CFXJSE_Engine* pScriptContext) {
65   if (!m_pCreateParent)
66     return false;
67 
68   WideStringView wsNameView = wsName.AsStringView();
69   bool bIsClassName = false;
70   bool bResult = false;
71   if (!wsNameView.IsEmpty() && wsNameView[0] == '!') {
72     wsNameView = wsNameView.Last(wsNameView.GetLength() - 1);
73     m_pCreateParent = ToNode(
74         pScriptContext->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets));
75   }
76   if (!wsNameView.IsEmpty() && wsNameView[0] == '#') {
77     bIsClassName = true;
78     wsNameView = wsNameView.Last(wsNameView.GetLength() - 1);
79   }
80   if (wsNameView.IsEmpty())
81     return false;
82 
83   if (m_iCreateCount == 0)
84     CreateNodeForCondition(wsCondition);
85 
86   if (bIsClassName) {
87     XFA_Element eType = XFA_GetElementByName(wsNameView);
88     if (eType == XFA_Element::Unknown)
89       return false;
90 
91     for (size_t i = 0; i < m_iCreateCount; ++i) {
92       CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eType);
93       if (pNewNode) {
94         m_pCreateParent->InsertChildAndNotify(pNewNode, nullptr);
95         if (i == m_iCreateCount - 1) {
96           m_pCreateParent = pNewNode;
97         }
98         bResult = true;
99       }
100     }
101   } else {
102     XFA_Element eClassType = XFA_Element::DataGroup;
103     if (bLastNode) {
104       eClassType = m_eLastCreateType;
105     }
106     for (size_t i = 0; i < m_iCreateCount; ++i) {
107       CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType);
108       if (pNewNode) {
109         pNewNode->JSObject()->SetAttribute(XFA_Attribute::Name, wsNameView,
110                                            false);
111         pNewNode->CreateXMLMappingNode();
112         m_pCreateParent->InsertChildAndNotify(pNewNode, nullptr);
113         if (i == m_iCreateCount - 1) {
114           m_pCreateParent = pNewNode;
115         }
116         bResult = true;
117       }
118     }
119   }
120   if (!bResult)
121     m_pCreateParent = nullptr;
122 
123   return bResult;
124 }
125 
SetCreateNodeType(CXFA_Node * refNode)126 void CXFA_NodeHelper::SetCreateNodeType(CXFA_Node* refNode) {
127   if (!refNode)
128     return;
129 
130   if (refNode->GetElementType() == XFA_Element::Subform) {
131     m_eLastCreateType = XFA_Element::DataGroup;
132   } else if (refNode->GetElementType() == XFA_Element::Field) {
133     m_eLastCreateType = XFA_FieldIsMultiListBox(refNode)
134                             ? XFA_Element::DataGroup
135                             : XFA_Element::DataValue;
136   } else if (refNode->GetElementType() == XFA_Element::ExclGroup) {
137     m_eLastCreateType = XFA_Element::DataValue;
138   }
139 }
140