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