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_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