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