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 "core/fxcrt/fx_ext.h"
      8 #include "xfa/fxfa/app/xfa_ffnotify.h"
      9 #include "xfa/fxfa/parser/cscript_datawindow.h"
     10 #include "xfa/fxfa/parser/cscript_eventpseudomodel.h"
     11 #include "xfa/fxfa/parser/cscript_hostpseudomodel.h"
     12 #include "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
     13 #include "xfa/fxfa/parser/cscript_logpseudomodel.h"
     14 #include "xfa/fxfa/parser/cscript_signaturepseudomodel.h"
     15 #include "xfa/fxfa/parser/cxfa_document.h"
     16 #include "xfa/fxfa/parser/cxfa_document_parser.h"
     17 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
     18 #include "xfa/fxfa/parser/cxfa_scriptcontext.h"
     19 #include "xfa/fxfa/parser/xfa_localemgr.h"
     20 #include "xfa/fxfa/parser/xfa_object.h"
     21 #include "xfa/fxfa/parser/xfa_resolvenode_rs.h"
     22 #include "xfa/fxfa/parser/xfa_utils.h"
     23 
     24 namespace {
     25 
     26 void MergeNodeRecurse(CXFA_Document* pDocument,
     27                       CXFA_Node* pDestNodeParent,
     28                       CXFA_Node* pProtoNode) {
     29   CXFA_Node* pExistingNode = nullptr;
     30   for (CXFA_Node* pFormChild =
     31            pDestNodeParent->GetNodeItem(XFA_NODEITEM_FirstChild);
     32        pFormChild;
     33        pFormChild = pFormChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
     34     if (pFormChild->GetElementType() == pProtoNode->GetElementType() &&
     35         pFormChild->GetNameHash() == pProtoNode->GetNameHash() &&
     36         pFormChild->IsUnusedNode()) {
     37       pFormChild->ClearFlag(XFA_NodeFlag_UnusedNode);
     38       pExistingNode = pFormChild;
     39       break;
     40     }
     41   }
     42 
     43   if (pExistingNode) {
     44     pExistingNode->SetTemplateNode(pProtoNode);
     45     for (CXFA_Node* pTemplateChild =
     46              pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
     47          pTemplateChild; pTemplateChild = pTemplateChild->GetNodeItem(
     48                              XFA_NODEITEM_NextSibling)) {
     49       MergeNodeRecurse(pDocument, pExistingNode, pTemplateChild);
     50     }
     51     return;
     52   }
     53   CXFA_Node* pNewNode = pProtoNode->Clone(true);
     54   pNewNode->SetTemplateNode(pProtoNode);
     55   pDestNodeParent->InsertChild(pNewNode, nullptr);
     56 }
     57 
     58 void MergeNode(CXFA_Document* pDocument,
     59                CXFA_Node* pDestNode,
     60                CXFA_Node* pProtoNode) {
     61   {
     62     CXFA_NodeIterator sIterator(pDestNode);
     63     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
     64          pNode = sIterator.MoveToNext()) {
     65       pNode->SetFlag(XFA_NodeFlag_UnusedNode, true);
     66     }
     67   }
     68   pDestNode->SetTemplateNode(pProtoNode);
     69   for (CXFA_Node* pTemplateChild =
     70            pProtoNode->GetNodeItem(XFA_NODEITEM_FirstChild);
     71        pTemplateChild;
     72        pTemplateChild = pTemplateChild->GetNodeItem(XFA_NODEITEM_NextSibling)) {
     73     MergeNodeRecurse(pDocument, pDestNode, pTemplateChild);
     74   }
     75   {
     76     CXFA_NodeIterator sIterator(pDestNode);
     77     for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
     78          pNode = sIterator.MoveToNext()) {
     79       pNode->ClearFlag(XFA_NodeFlag_UnusedNode);
     80     }
     81   }
     82 }
     83 
     84 }  // namespace
     85 
     86 CXFA_Document::CXFA_Document(CXFA_DocumentParser* pParser)
     87     : m_pParser(pParser),
     88       m_pScriptContext(nullptr),
     89       m_pLayoutProcessor(nullptr),
     90       m_pRootNode(nullptr),
     91       m_pLocalMgr(nullptr),
     92       m_pScriptDataWindow(nullptr),
     93       m_pScriptEvent(nullptr),
     94       m_pScriptHost(nullptr),
     95       m_pScriptLog(nullptr),
     96       m_pScriptLayout(nullptr),
     97       m_pScriptSignature(nullptr),
     98       m_eCurVersionMode(XFA_VERSION_DEFAULT),
     99       m_dwDocFlags(0) {
    100   ASSERT(m_pParser);
    101 }
    102 
    103 CXFA_Document::~CXFA_Document() {
    104   delete m_pRootNode;
    105   PurgeNodes();
    106 }
    107 
    108 CXFA_LayoutProcessor* CXFA_Document::GetLayoutProcessor() {
    109   if (!m_pLayoutProcessor)
    110     m_pLayoutProcessor = new CXFA_LayoutProcessor(this);
    111   return m_pLayoutProcessor;
    112 }
    113 
    114 CXFA_LayoutProcessor* CXFA_Document::GetDocLayout() {
    115   return GetLayoutProcessor();
    116 }
    117 
    118 void CXFA_Document::ClearLayoutData() {
    119   delete m_pLayoutProcessor;
    120   m_pLayoutProcessor = nullptr;
    121   delete m_pScriptContext;
    122   m_pScriptContext = nullptr;
    123   delete m_pLocalMgr;
    124   m_pLocalMgr = nullptr;
    125   delete m_pScriptDataWindow;
    126   m_pScriptDataWindow = nullptr;
    127   delete m_pScriptEvent;
    128   m_pScriptEvent = nullptr;
    129   delete m_pScriptHost;
    130   m_pScriptHost = nullptr;
    131   delete m_pScriptLog;
    132   m_pScriptLog = nullptr;
    133   delete m_pScriptLayout;
    134   m_pScriptLayout = nullptr;
    135   delete m_pScriptSignature;
    136   m_pScriptSignature = nullptr;
    137 }
    138 
    139 void CXFA_Document::SetRoot(CXFA_Node* pNewRoot) {
    140   if (m_pRootNode)
    141     AddPurgeNode(m_pRootNode);
    142 
    143   m_pRootNode = pNewRoot;
    144   RemovePurgeNode(pNewRoot);
    145 }
    146 
    147 CFDE_XMLDoc* CXFA_Document::GetXMLDoc() const {
    148   return m_pParser->GetXMLDoc();
    149 }
    150 
    151 CXFA_FFNotify* CXFA_Document::GetNotify() const {
    152   return m_pParser->GetNotify();
    153 }
    154 
    155 CXFA_Object* CXFA_Document::GetXFAObject(XFA_HashCode dwNodeNameHash) {
    156   switch (dwNodeNameHash) {
    157     case XFA_HASHCODE_Data: {
    158       CXFA_Node* pDatasetsNode = ToNode(GetXFAObject(XFA_HASHCODE_Datasets));
    159       if (!pDatasetsNode)
    160         return nullptr;
    161 
    162       for (CXFA_Node* pDatasetsChild =
    163                pDatasetsNode->GetFirstChildByClass(XFA_Element::DataGroup);
    164            pDatasetsChild;
    165            pDatasetsChild = pDatasetsChild->GetNextSameClassSibling(
    166                XFA_Element::DataGroup)) {
    167         if (pDatasetsChild->GetNameHash() != XFA_HASHCODE_Data)
    168           continue;
    169 
    170         CFX_WideString wsNamespaceURI;
    171         if (!pDatasetsChild->TryNamespace(wsNamespaceURI))
    172           continue;
    173 
    174         CFX_WideString wsDatasetsURI;
    175         if (!pDatasetsNode->TryNamespace(wsDatasetsURI))
    176           continue;
    177         if (wsNamespaceURI == wsDatasetsURI)
    178           return pDatasetsChild;
    179       }
    180       return nullptr;
    181     }
    182     case XFA_HASHCODE_Record: {
    183       CXFA_Node* pData = ToNode(GetXFAObject(XFA_HASHCODE_Data));
    184       return pData ? pData->GetFirstChildByClass(XFA_Element::DataGroup)
    185                    : nullptr;
    186     }
    187     case XFA_HASHCODE_DataWindow: {
    188       if (!m_pScriptDataWindow)
    189         m_pScriptDataWindow = new CScript_DataWindow(this);
    190       return m_pScriptDataWindow;
    191     }
    192     case XFA_HASHCODE_Event: {
    193       if (!m_pScriptEvent)
    194         m_pScriptEvent = new CScript_EventPseudoModel(this);
    195       return m_pScriptEvent;
    196     }
    197     case XFA_HASHCODE_Host: {
    198       if (!m_pScriptHost)
    199         m_pScriptHost = new CScript_HostPseudoModel(this);
    200       return m_pScriptHost;
    201     }
    202     case XFA_HASHCODE_Log: {
    203       if (!m_pScriptLog)
    204         m_pScriptLog = new CScript_LogPseudoModel(this);
    205       return m_pScriptLog;
    206     }
    207     case XFA_HASHCODE_Signature: {
    208       if (!m_pScriptSignature)
    209         m_pScriptSignature = new CScript_SignaturePseudoModel(this);
    210       return m_pScriptSignature;
    211     }
    212     case XFA_HASHCODE_Layout: {
    213       if (!m_pScriptLayout)
    214         m_pScriptLayout = new CScript_LayoutPseudoModel(this);
    215       return m_pScriptLayout;
    216     }
    217     default:
    218       return m_pRootNode->GetFirstChildByName(dwNodeNameHash);
    219   }
    220 }
    221 
    222 CXFA_Node* CXFA_Document::CreateNode(uint32_t dwPacket, XFA_Element eElement) {
    223   return CreateNode(XFA_GetPacketByID(dwPacket), eElement);
    224 }
    225 
    226 CXFA_Node* CXFA_Document::CreateNode(const XFA_PACKETINFO* pPacket,
    227                                      XFA_Element eElement) {
    228   if (!pPacket)
    229     return nullptr;
    230 
    231   const XFA_ELEMENTINFO* pElement = XFA_GetElementByID(eElement);
    232   if (pElement && (pElement->dwPackets & pPacket->eName)) {
    233     CXFA_Node* pNode =
    234         new CXFA_Node(this, pPacket->eName, pElement->eObjectType,
    235                       pElement->eName, pElement->pName);
    236     AddPurgeNode(pNode);
    237     return pNode;
    238   }
    239 
    240   return nullptr;
    241 }
    242 
    243 void CXFA_Document::AddPurgeNode(CXFA_Node* pNode) {
    244   m_PurgeNodes.insert(pNode);
    245 }
    246 
    247 bool CXFA_Document::RemovePurgeNode(CXFA_Node* pNode) {
    248   return !!m_PurgeNodes.erase(pNode);
    249 }
    250 
    251 void CXFA_Document::PurgeNodes() {
    252   for (CXFA_Node* pNode : m_PurgeNodes)
    253     delete pNode;
    254 
    255   m_PurgeNodes.clear();
    256 }
    257 
    258 void CXFA_Document::SetFlag(uint32_t dwFlag, bool bOn) {
    259   if (bOn)
    260     m_dwDocFlags |= dwFlag;
    261   else
    262     m_dwDocFlags &= ~dwFlag;
    263 }
    264 
    265 bool CXFA_Document::IsInteractive() {
    266   if (m_dwDocFlags & XFA_DOCFLAG_HasInteractive)
    267     return !!(m_dwDocFlags & XFA_DOCFLAG_Interactive);
    268 
    269   CXFA_Node* pConfig = ToNode(GetXFAObject(XFA_HASHCODE_Config));
    270   if (!pConfig)
    271     return false;
    272 
    273   CFX_WideString wsInteractive;
    274   CXFA_Node* pPresent = pConfig->GetFirstChildByClass(XFA_Element::Present);
    275   if (!pPresent)
    276     return false;
    277 
    278   CXFA_Node* pPDF = pPresent->GetFirstChildByClass(XFA_Element::Pdf);
    279   if (!pPDF)
    280     return false;
    281 
    282   CXFA_Node* pFormFiller = pPDF->GetChild(0, XFA_Element::Interactive);
    283   if (pFormFiller) {
    284     m_dwDocFlags |= XFA_DOCFLAG_HasInteractive;
    285     if (pFormFiller->TryContent(wsInteractive) && wsInteractive == L"1") {
    286       m_dwDocFlags |= XFA_DOCFLAG_Interactive;
    287       return true;
    288     }
    289   }
    290   return false;
    291 }
    292 
    293 CXFA_LocaleMgr* CXFA_Document::GetLocalMgr() {
    294   if (!m_pLocalMgr) {
    295     m_pLocalMgr =
    296         new CXFA_LocaleMgr(ToNode(GetXFAObject(XFA_HASHCODE_LocaleSet)),
    297                            GetNotify()->GetAppProvider()->GetLanguage());
    298   }
    299   return m_pLocalMgr;
    300 }
    301 
    302 CXFA_ScriptContext* CXFA_Document::InitScriptContext(v8::Isolate* pIsolate) {
    303   if (!m_pScriptContext)
    304     m_pScriptContext = new CXFA_ScriptContext(this);
    305   m_pScriptContext->Initialize(pIsolate);
    306   return m_pScriptContext;
    307 }
    308 
    309 CXFA_ScriptContext* CXFA_Document::GetScriptContext() {
    310   if (!m_pScriptContext)
    311     m_pScriptContext = new CXFA_ScriptContext(this);
    312   return m_pScriptContext;
    313 }
    314 
    315 XFA_VERSION CXFA_Document::RecognizeXFAVersionNumber(
    316     CFX_WideString& wsTemplateNS) {
    317   CFX_WideStringC wsTemplateURIPrefix =
    318       XFA_GetPacketByIndex(XFA_PACKET_Template)->pURI;
    319   FX_STRSIZE nPrefixLength = wsTemplateURIPrefix.GetLength();
    320   if (CFX_WideStringC(wsTemplateNS.c_str(), wsTemplateNS.GetLength()) !=
    321       wsTemplateURIPrefix) {
    322     return XFA_VERSION_UNKNOWN;
    323   }
    324   FX_STRSIZE nDotPos = wsTemplateNS.Find('.', nPrefixLength);
    325   if (nDotPos == (FX_STRSIZE)-1)
    326     return XFA_VERSION_UNKNOWN;
    327 
    328   int8_t iMajor = FXSYS_wtoi(
    329       wsTemplateNS.Mid(nPrefixLength, nDotPos - nPrefixLength).c_str());
    330   int8_t iMinor = FXSYS_wtoi(
    331       wsTemplateNS.Mid(nDotPos + 1, wsTemplateNS.GetLength() - nDotPos - 2)
    332           .c_str());
    333   XFA_VERSION eVersion = (XFA_VERSION)((int32_t)iMajor * 100 + iMinor);
    334   if (eVersion < XFA_VERSION_MIN || eVersion > XFA_VERSION_MAX)
    335     return XFA_VERSION_UNKNOWN;
    336 
    337   m_eCurVersionMode = eVersion;
    338   return eVersion;
    339 }
    340 
    341 CXFA_Node* CXFA_Document::GetNodeByID(CXFA_Node* pRoot,
    342                                       const CFX_WideStringC& wsID) {
    343   if (!pRoot || wsID.IsEmpty())
    344     return nullptr;
    345 
    346   CXFA_NodeIterator sIterator(pRoot);
    347   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
    348        pNode = sIterator.MoveToNext()) {
    349     CFX_WideStringC wsIDVal;
    350     if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
    351       if (wsIDVal == wsID)
    352         return pNode;
    353     }
    354   }
    355   return nullptr;
    356 }
    357 
    358 void CXFA_Document::DoProtoMerge() {
    359   CXFA_Node* pTemplateRoot = ToNode(GetXFAObject(XFA_HASHCODE_Template));
    360   if (!pTemplateRoot)
    361     return;
    362 
    363   std::map<uint32_t, CXFA_Node*> mIDMap;
    364   CXFA_NodeSet sUseNodes;
    365   CXFA_NodeIterator sIterator(pTemplateRoot);
    366   for (CXFA_Node* pNode = sIterator.GetCurrent(); pNode;
    367        pNode = sIterator.MoveToNext()) {
    368     CFX_WideStringC wsIDVal;
    369     if (pNode->TryCData(XFA_ATTRIBUTE_Id, wsIDVal) && !wsIDVal.IsEmpty()) {
    370       mIDMap[FX_HashCode_GetW(wsIDVal, false)] = pNode;
    371     }
    372     CFX_WideStringC wsUseVal;
    373     if (pNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) && !wsUseVal.IsEmpty()) {
    374       sUseNodes.insert(pNode);
    375     } else if (pNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
    376                !wsUseVal.IsEmpty()) {
    377       sUseNodes.insert(pNode);
    378     }
    379   }
    380 
    381   for (CXFA_Node* pUseHrefNode : sUseNodes) {
    382     CFX_WideString wsUseVal;
    383     CFX_WideStringC wsURI, wsID, wsSOM;
    384     if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Usehref, wsUseVal) &&
    385         !wsUseVal.IsEmpty()) {
    386       FX_STRSIZE uSharpPos = wsUseVal.Find('#');
    387       if (uSharpPos < 0) {
    388         wsURI = wsUseVal.AsStringC();
    389       } else {
    390         wsURI = CFX_WideStringC(wsUseVal.c_str(), uSharpPos);
    391         FX_STRSIZE uLen = wsUseVal.GetLength();
    392         if (uLen >= uSharpPos + 5 &&
    393             CFX_WideStringC(wsUseVal.c_str() + uSharpPos, 5) == L"#som(" &&
    394             wsUseVal[uLen - 1] == ')') {
    395           wsSOM = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 5,
    396                                   uLen - 1 - uSharpPos - 5);
    397         } else {
    398           wsID = CFX_WideStringC(wsUseVal.c_str() + uSharpPos + 1,
    399                                  uLen - uSharpPos - 1);
    400         }
    401       }
    402     } else if (pUseHrefNode->TryCData(XFA_ATTRIBUTE_Use, wsUseVal) &&
    403                !wsUseVal.IsEmpty()) {
    404       if (wsUseVal[0] == '#')
    405         wsID = CFX_WideStringC(wsUseVal.c_str() + 1, wsUseVal.GetLength() - 1);
    406       else
    407         wsSOM = CFX_WideStringC(wsUseVal.c_str(), wsUseVal.GetLength());
    408     }
    409 
    410     if (!wsURI.IsEmpty() && wsURI != L".")
    411       continue;
    412 
    413     CXFA_Node* pProtoNode = nullptr;
    414     if (!wsSOM.IsEmpty()) {
    415       uint32_t dwFlag = XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
    416                         XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
    417                         XFA_RESOLVENODE_Siblings;
    418       XFA_RESOLVENODE_RS resoveNodeRS;
    419       int32_t iRet = m_pScriptContext->ResolveObjects(pUseHrefNode, wsSOM,
    420                                                       resoveNodeRS, dwFlag);
    421       if (iRet > 0 && resoveNodeRS.nodes[0]->IsNode())
    422         pProtoNode = resoveNodeRS.nodes[0]->AsNode();
    423     } else if (!wsID.IsEmpty()) {
    424       auto it = mIDMap.find(FX_HashCode_GetW(wsID, false));
    425       if (it == mIDMap.end())
    426         continue;
    427       pProtoNode = it->second;
    428     }
    429     if (!pProtoNode)
    430       continue;
    431 
    432     MergeNode(this, pUseHrefNode, pProtoNode);
    433   }
    434 }
    435