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