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