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_extension.h" 10 #include "fxjs/cfxjse_engine.h" 11 #include "fxjs/xfa/cjx_object.h" 12 #include "xfa/fxfa/parser/cxfa_document.h" 13 #include "xfa/fxfa/parser/cxfa_localemgr.h" 14 #include "xfa/fxfa/parser/cxfa_node.h" 15 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h" 16 #include "xfa/fxfa/parser/xfa_utils.h" 17 18 CXFA_NodeHelper::CXFA_NodeHelper() 19 : m_eLastCreateType(XFA_Element::DataValue), 20 m_pCreateParent(nullptr), 21 m_iCreateCount(0), 22 m_iCreateFlag(XFA_ResolveNode_RSType_CreateNodeOne), 23 m_iCurAllStart(-1), 24 m_pAllStartParent(nullptr) {} 25 26 CXFA_NodeHelper::~CXFA_NodeHelper() {} 27 28 CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetOneChild(CXFA_Node* parent, 29 const wchar_t* pwsName, 30 bool bIsClassName) { 31 if (!parent) 32 return nullptr; 33 34 std::vector<CXFA_Node*> siblings; 35 uint32_t uNameHash = FX_HashCode_GetW(WideStringView(pwsName), false); 36 NodeAcc_TraverseAnySiblings(parent, uNameHash, &siblings, bIsClassName); 37 return !siblings.empty() ? siblings[0] : nullptr; 38 } 39 40 int32_t CXFA_NodeHelper::CountSiblings(CXFA_Node* pNode, 41 XFA_LOGIC_TYPE eLogicType, 42 std::vector<CXFA_Node*>* pSiblings, 43 bool bIsClassName) { 44 if (!pNode) 45 return 0; 46 CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent); 47 if (!parent) 48 return 0; 49 if (!parent->HasProperty(pNode->GetElementType()) && 50 eLogicType == XFA_LOGIC_Transparent) { 51 parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent); 52 if (!parent) 53 return 0; 54 } 55 if (bIsClassName) { 56 return NodeAcc_TraverseSiblings(parent, pNode->GetClassHashCode(), 57 pSiblings, eLogicType, bIsClassName); 58 } 59 return NodeAcc_TraverseSiblings(parent, pNode->GetNameHash(), pSiblings, 60 eLogicType, bIsClassName); 61 } 62 63 int32_t CXFA_NodeHelper::NodeAcc_TraverseAnySiblings( 64 CXFA_Node* parent, 65 uint32_t dNameHash, 66 std::vector<CXFA_Node*>* pSiblings, 67 bool bIsClassName) { 68 if (!parent || !pSiblings) 69 return 0; 70 71 int32_t nCount = 0; 72 for (CXFA_Node* child : 73 parent->GetNodeList(XFA_NODEFILTER_Properties, XFA_Element::Unknown)) { 74 if (bIsClassName) { 75 if (child->GetClassHashCode() == dNameHash) { 76 pSiblings->push_back(child); 77 nCount++; 78 } 79 } else { 80 if (child->GetNameHash() == dNameHash) { 81 pSiblings->push_back(child); 82 nCount++; 83 } 84 } 85 if (nCount > 0) 86 return nCount; 87 88 nCount += 89 NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName); 90 } 91 for (CXFA_Node* child : 92 parent->GetNodeList(XFA_NODEFILTER_Children, XFA_Element::Unknown)) { 93 if (bIsClassName) { 94 if (child->GetClassHashCode() == dNameHash) { 95 pSiblings->push_back(child); 96 nCount++; 97 } 98 } else { 99 if (child->GetNameHash() == dNameHash) { 100 pSiblings->push_back(child); 101 nCount++; 102 } 103 } 104 if (nCount > 0) 105 return nCount; 106 107 nCount += 108 NodeAcc_TraverseAnySiblings(child, dNameHash, pSiblings, bIsClassName); 109 } 110 return nCount; 111 } 112 113 int32_t CXFA_NodeHelper::NodeAcc_TraverseSiblings( 114 CXFA_Node* parent, 115 uint32_t dNameHash, 116 std::vector<CXFA_Node*>* pSiblings, 117 XFA_LOGIC_TYPE eLogicType, 118 bool bIsClassName, 119 bool bIsFindProperty) { 120 if (!parent || !pSiblings) 121 return 0; 122 123 int32_t nCount = 0; 124 if (bIsFindProperty) { 125 for (CXFA_Node* child : 126 parent->GetNodeList(XFA_NODEFILTER_Properties, XFA_Element::Unknown)) { 127 if (bIsClassName) { 128 if (child->GetClassHashCode() == dNameHash) { 129 pSiblings->push_back(child); 130 nCount++; 131 } 132 } else { 133 if (child->GetNameHash() == dNameHash) { 134 if (child->GetElementType() != XFA_Element::PageSet && 135 child->GetElementType() != XFA_Element::Extras && 136 child->GetElementType() != XFA_Element::Items) { 137 pSiblings->push_back(child); 138 nCount++; 139 } 140 } 141 } 142 if (child->IsUnnamed() && 143 child->GetElementType() == XFA_Element::PageSet) { 144 nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings, 145 eLogicType, bIsClassName, false); 146 } 147 } 148 if (nCount > 0) 149 return nCount; 150 } 151 for (CXFA_Node* child : 152 parent->GetNodeList(XFA_NODEFILTER_Children, XFA_Element::Unknown)) { 153 if (child->GetElementType() == XFA_Element::Variables) 154 continue; 155 156 if (bIsClassName) { 157 if (child->GetClassHashCode() == dNameHash) { 158 pSiblings->push_back(child); 159 nCount++; 160 } 161 } else { 162 if (child->GetNameHash() == dNameHash) { 163 pSiblings->push_back(child); 164 nCount++; 165 } 166 } 167 if (eLogicType == XFA_LOGIC_NoTransparent) 168 continue; 169 170 if (NodeIsTransparent(child) && 171 child->GetElementType() != XFA_Element::PageSet) { 172 nCount += NodeAcc_TraverseSiblings(child, dNameHash, pSiblings, 173 eLogicType, bIsClassName, false); 174 } 175 } 176 return nCount; 177 } 178 179 CXFA_Node* CXFA_NodeHelper::ResolveNodes_GetParent(CXFA_Node* pNode, 180 XFA_LOGIC_TYPE eLogicType) { 181 if (!pNode) { 182 return nullptr; 183 } 184 if (eLogicType == XFA_LOGIC_NoTransparent) { 185 return pNode->GetParent(); 186 } 187 CXFA_Node* parent; 188 CXFA_Node* node = pNode; 189 while (true) { 190 parent = ResolveNodes_GetParent(node); 191 if (!parent) { 192 break; 193 } 194 XFA_Element parentType = parent->GetElementType(); 195 if ((!parent->IsUnnamed() && parentType != XFA_Element::SubformSet) || 196 parentType == XFA_Element::Variables) { 197 break; 198 } 199 node = parent; 200 } 201 return parent; 202 } 203 204 int32_t CXFA_NodeHelper::GetIndex(CXFA_Node* pNode, 205 XFA_LOGIC_TYPE eLogicType, 206 bool bIsProperty, 207 bool bIsClassIndex) { 208 CXFA_Node* parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_NoTransparent); 209 if (!parent) { 210 return 0; 211 } 212 if (!bIsProperty && eLogicType == XFA_LOGIC_Transparent) { 213 parent = ResolveNodes_GetParent(pNode, XFA_LOGIC_Transparent); 214 if (!parent) { 215 return 0; 216 } 217 } 218 uint32_t dwHashName = pNode->GetNameHash(); 219 if (bIsClassIndex) { 220 dwHashName = pNode->GetClassHashCode(); 221 } 222 std::vector<CXFA_Node*> siblings; 223 int32_t iSize = NodeAcc_TraverseSiblings(parent, dwHashName, &siblings, 224 eLogicType, bIsClassIndex); 225 for (int32_t i = 0; i < iSize; ++i) { 226 CXFA_Node* child = siblings[i]; 227 if (child == pNode) { 228 return i; 229 } 230 } 231 return 0; 232 } 233 234 WideString CXFA_NodeHelper::GetNameExpression(CXFA_Node* refNode, 235 bool bIsAllPath, 236 XFA_LOGIC_TYPE eLogicType) { 237 WideString wsName; 238 if (bIsAllPath) { 239 wsName = GetNameExpression(refNode, false, eLogicType); 240 WideString wsParent; 241 CXFA_Node* parent = 242 ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent); 243 while (parent) { 244 wsParent = GetNameExpression(parent, false, eLogicType); 245 wsParent += L"."; 246 wsParent += wsName; 247 wsName = wsParent; 248 parent = ResolveNodes_GetParent(parent, XFA_LOGIC_NoTransparent); 249 } 250 return wsName; 251 } 252 253 WideString ws; 254 bool bIsProperty = NodeIsProperty(refNode); 255 if (refNode->IsUnnamed() || 256 (bIsProperty && refNode->GetElementType() != XFA_Element::PageSet)) { 257 ws = refNode->GetClassName(); 258 return WideString::Format(L"#%ls[%d]", ws.c_str(), 259 GetIndex(refNode, eLogicType, bIsProperty, true)); 260 } 261 ws = refNode->JSObject()->GetCData(XFA_Attribute::Name); 262 ws.Replace(L".", L"\\."); 263 return WideString::Format(L"%ls[%d]", ws.c_str(), 264 GetIndex(refNode, eLogicType, bIsProperty, false)); 265 } 266 267 bool CXFA_NodeHelper::NodeIsTransparent(CXFA_Node* refNode) { 268 if (!refNode) 269 return false; 270 271 XFA_Element refNodeType = refNode->GetElementType(); 272 return (refNode->IsUnnamed() && refNode->IsContainerNode()) || 273 refNodeType == XFA_Element::SubformSet || 274 refNodeType == XFA_Element::Area || refNodeType == XFA_Element::Proto; 275 } 276 277 bool CXFA_NodeHelper::CreateNode_ForCondition(WideString& wsCondition) { 278 int32_t iLen = wsCondition.GetLength(); 279 WideString wsIndex(L"0"); 280 bool bAll = false; 281 if (iLen == 0) { 282 m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne; 283 return false; 284 } 285 if (wsCondition[0] != '[') 286 return false; 287 288 int32_t i = 1; 289 for (; i < iLen; ++i) { 290 wchar_t ch = wsCondition[i]; 291 if (ch == ' ') 292 continue; 293 294 if (ch == '*') 295 bAll = true; 296 break; 297 } 298 if (bAll) { 299 wsIndex = L"1"; 300 m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeAll; 301 } else { 302 m_iCreateFlag = XFA_ResolveNode_RSType_CreateNodeOne; 303 wsIndex = wsCondition.Mid(i, iLen - 1 - i); 304 } 305 int32_t iIndex = wsIndex.GetInteger(); 306 m_iCreateCount = iIndex; 307 return true; 308 } 309 310 bool CXFA_NodeHelper::ResolveNodes_CreateNode(WideString wsName, 311 WideString wsCondition, 312 bool bLastNode, 313 CFXJSE_Engine* pScriptContext) { 314 if (!m_pCreateParent) { 315 return false; 316 } 317 bool bIsClassName = false; 318 bool bResult = false; 319 if (wsName[0] == '!') { 320 wsName = wsName.Right(wsName.GetLength() - 1); 321 m_pCreateParent = ToNode( 322 pScriptContext->GetDocument()->GetXFAObject(XFA_HASHCODE_Datasets)); 323 } 324 if (wsName[0] == '#') { 325 bIsClassName = true; 326 wsName = wsName.Right(wsName.GetLength() - 1); 327 } 328 if (m_iCreateCount == 0) { 329 CreateNode_ForCondition(wsCondition); 330 } 331 if (bIsClassName) { 332 XFA_Element eType = CXFA_Node::NameToElement(wsName); 333 if (eType == XFA_Element::Unknown) 334 return false; 335 336 for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) { 337 CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eType); 338 if (pNewNode) { 339 m_pCreateParent->InsertChild(pNewNode, nullptr); 340 if (iIndex == m_iCreateCount - 1) { 341 m_pCreateParent = pNewNode; 342 } 343 bResult = true; 344 } 345 } 346 } else { 347 XFA_Element eClassType = XFA_Element::DataGroup; 348 if (bLastNode) { 349 eClassType = m_eLastCreateType; 350 } 351 for (int32_t iIndex = 0; iIndex < m_iCreateCount; iIndex++) { 352 CXFA_Node* pNewNode = m_pCreateParent->CreateSamePacketNode(eClassType); 353 if (pNewNode) { 354 pNewNode->JSObject()->SetAttribute(XFA_Attribute::Name, 355 wsName.AsStringView(), false); 356 pNewNode->CreateXMLMappingNode(); 357 m_pCreateParent->InsertChild(pNewNode, nullptr); 358 if (iIndex == m_iCreateCount - 1) { 359 m_pCreateParent = pNewNode; 360 } 361 bResult = true; 362 } 363 } 364 } 365 if (!bResult) { 366 m_pCreateParent = nullptr; 367 } 368 return bResult; 369 } 370 371 void CXFA_NodeHelper::SetCreateNodeType(CXFA_Node* refNode) { 372 if (!refNode) 373 return; 374 375 if (refNode->GetElementType() == XFA_Element::Subform) { 376 m_eLastCreateType = XFA_Element::DataGroup; 377 } else if (refNode->GetElementType() == XFA_Element::Field) { 378 m_eLastCreateType = XFA_FieldIsMultiListBox(refNode) 379 ? XFA_Element::DataGroup 380 : XFA_Element::DataValue; 381 } else if (refNode->GetElementType() == XFA_Element::ExclGroup) { 382 m_eLastCreateType = XFA_Element::DataValue; 383 } 384 } 385 386 bool CXFA_NodeHelper::NodeIsProperty(CXFA_Node* refNode) { 387 CXFA_Node* parent = ResolveNodes_GetParent(refNode, XFA_LOGIC_NoTransparent); 388 return parent && refNode && parent->HasProperty(refNode->GetElementType()); 389 } 390