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