Home | History | Annotate | Download | only in parser
      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