/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
namespace DOM
{ static xmlNodePtr lcl_getDocumentType(xmlDocPtr const i_pDocument)
{ // find the doc type
xmlNodePtr cur = i_pDocument->children; while (cur != nullptr)
{ if ((cur->type == XML_DOCUMENT_TYPE_NODE) ||
(cur->type == XML_DTD_NODE)) { return cur;
}
cur = cur->next;
} return nullptr;
}
/// get the pointer to the root element node of the document static xmlNodePtr lcl_getDocumentRootPtr(xmlDocPtr const i_pDocument)
{ // find the document element
xmlNodePtr cur = i_pDocument->children; while (cur != nullptr)
{ if (cur->type == XML_ELEMENT_NODE) break;
cur = cur->next;
} return cur;
}
void
CDocument::RemoveCNode(xmlNodePtr const pNode, CNode const*const pCNode)
{
nodemap_t::iterator const i = m_NodeMap.find(pNode); if (i == m_NodeMap.end()) return;
// #i113681# consider this scenario: // T1 calls ~CNode // T2 calls getCNode: lookup will find i->second->first invalid // so a new CNode is created and inserted // T1 calls removeCNode: i->second->second now points to a // different CNode instance!
// check that the CNode is the right one
CNode *const pCurrent = i->second.second; if (pCurrent == pCNode) {
m_NodeMap.erase(i);
}
}
/** NB: this is the CNode factory. it is the only place where CNodes may be instantiated. all CNodes must be registered at the m_NodeMap.
*/
::rtl::Reference<CNode>
CDocument::GetCNode(xmlNodePtr const pNode, boolconst bCreate)
{ if (nullptr == pNode) { return nullptr;
} //check whether there is already an instance for this node
nodemap_t::const_iterator const i = m_NodeMap.find(pNode); if (i != m_NodeMap.end()) { // #i113681# check that the CNode is still alive
rtl::Reference<CNode> const xNode(i->second.first); if (xNode.is())
{ return xNode;
}
}
if (!bCreate) { return nullptr; }
// there is not yet an instance wrapping this node, // create it and store it in the map
::rtl::Reference<CNode> pCNode; switch (pNode->type)
{ case XML_ELEMENT_NODE: // m_aNodeType = NodeType::ELEMENT_NODE;
pCNode = new CElement(*this, m_Mutex, pNode); break; case XML_TEXT_NODE: // m_aNodeType = NodeType::TEXT_NODE;
pCNode = new CText(*this, m_Mutex, pNode); break; case XML_CDATA_SECTION_NODE: // m_aNodeType = NodeType::CDATA_SECTION_NODE;
pCNode = new CCDATASection(*this, m_Mutex, pNode); break; case XML_ENTITY_REF_NODE: // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE;
pCNode = new CEntityReference(*this, m_Mutex, pNode); break; case XML_ENTITY_NODE: // m_aNodeType = NodeType::ENTITY_NODE;
pCNode = new CEntity(*this, m_Mutex, reinterpret_cast<xmlEntityPtr>(pNode)); break; case XML_PI_NODE: // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE;
pCNode = new CProcessingInstruction(*this, m_Mutex, pNode); break; case XML_COMMENT_NODE: // m_aNodeType = NodeType::COMMENT_NODE;
pCNode = new CComment(*this, m_Mutex, pNode); break; case XML_DOCUMENT_NODE: // m_aNodeType = NodeType::DOCUMENT_NODE;
OSL_ENSURE(false, "CDocument::GetCNode is not supposed to" " create a CDocument!!!");
pCNode = new CDocument(reinterpret_cast<xmlDocPtr>(pNode)); break; case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE;
pCNode = new CDocumentType(*this, m_Mutex, reinterpret_cast<xmlDtdPtr>(pNode)); break; case XML_DOCUMENT_FRAG_NODE: // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE;
pCNode = new CDocumentFragment(*this, m_Mutex, pNode); break; case XML_NOTATION_NODE: // m_aNodeType = NodeType::NOTATION_NODE;
pCNode = new CNotation(*this, m_Mutex, reinterpret_cast<xmlNotationPtr>(pNode)); break; case XML_ATTRIBUTE_NODE: // m_aNodeType = NodeType::ATTRIBUTE_NODE;
pCNode = new CAttr(*this, m_Mutex, reinterpret_cast<xmlAttrPtr>(pNode)); break; // unsupported node types case XML_HTML_DOCUMENT_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_NAMESPACE_DECL: default: break;
}
if (pCNode != nullptr) { boolconst bInserted = m_NodeMap.emplace(
pNode,
::std::make_pair(pCNode.get(), pCNode.get())
).second;
OSL_ASSERT(bInserted); if (!bInserted) { // if insertion failed, delete new instance and return null return nullptr;
}
}
OSL_ENSURE(pCNode.is(), "no node produced during CDocument::GetCNode!"); return pCNode;
}
bool CDocument::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const pReplacedNodeType)
{ switch (nodeType) { case NodeType_PROCESSING_INSTRUCTION_NODE: case NodeType_COMMENT_NODE: returntrue; case NodeType_ELEMENT_NODE: // there may be only one! return (pReplacedNodeType && *pReplacedNodeType == nodeType)
|| nullptr == lcl_getDocumentRootPtr(m_aDocPtr); case NodeType_DOCUMENT_TYPE_NODE: // there may be only one! return (pReplacedNodeType && *pReplacedNodeType == nodeType)
|| nullptr == lcl_getDocumentType(m_aDocPtr); default: returnfalse;
}
}
// Creates an Attr of the given name.
Reference< XAttr > SAL_CALL CDocument::createAttribute(const OUString& name)
{
::osl::MutexGuard const g(m_Mutex);
// Creates an attribute of the given qualified name and namespace URI.
Reference< XAttr > SAL_CALL CDocument::createAttributeNS( const OUString& ns, const OUString& qname)
{
::osl::MutexGuard const g(m_Mutex);
// libxml does not allow a NS definition to be attached to an // attribute node - which is a good thing, since namespaces are // only defined as parts of element nodes // thus the namespace data is stored in CAttr::m_pNamespace
sal_Int32 i = qname.indexOf(':');
OString oPrefix, oName, oUri; if (i != -1)
{
oPrefix = OUStringToOString(qname.subView(0, i), RTL_TEXTENCODING_UTF8);
oName = OUStringToOString(qname.subView(i+1), RTL_TEXTENCODING_UTF8);
} else
{
oName = OUStringToOString(qname, RTL_TEXTENCODING_UTF8);
}
oUri = OUStringToOString(ns, RTL_TEXTENCODING_UTF8);
xmlAttrPtr const pAttr = xmlNewDocProp(m_aDocPtr, reinterpret_cast<xmlChar const*>(oName.getStr()), nullptr);
::rtl::Reference< CAttr > const pCAttr( dynamic_cast< CAttr* >(GetCNode( reinterpret_cast<xmlNodePtr>(pAttr)).get())); if (!pCAttr.is()) { throw RuntimeException(); } // store the namespace data!
pCAttr->m_oNamespace.emplace( oUri, oPrefix );
pCAttr->m_bUnlinked = true;
return pCAttr;
};
// Creates a CDATASection node whose value is the specified string.
Reference< XCDATASection > SAL_CALL CDocument::createCDATASection(const OUString& data)
{
::osl::MutexGuard const g(m_Mutex);
// Creates an element of the type specified.
Reference< XElement > SAL_CALL CDocument::createElement(const OUString& tagName)
{
::osl::MutexGuard const g(m_Mutex);
// Creates an element of the given qualified name and namespace URI.
Reference< XElement > SAL_CALL CDocument::createElementNS( const OUString& ns, const OUString& qname)
{
::osl::MutexGuard const g(m_Mutex);
// Creates a ProcessingInstruction node given the specified name and // data strings.
Reference< XProcessingInstruction > SAL_CALL CDocument::createProcessingInstruction( const OUString& target, const OUString& data)
{
::osl::MutexGuard const g(m_Mutex);
// Creates a Text node given the specified string.
Reference< XText > SAL_CALL CDocument::createTextNode(const OUString& data)
{
::osl::MutexGuard const g(m_Mutex);
// The Document Type Declaration (see DocumentType) associated with this // document.
Reference< XDocumentType > SAL_CALL CDocument::getDoctype()
{
::osl::MutexGuard const g(m_Mutex);
// This is a convenience attribute that allows direct access to the child // node that is the root element of the document.
Reference< XElement > SAL_CALL CDocument::getDocumentElement()
{
::osl::MutexGuard const g(m_Mutex);
static xmlNodePtr
lcl_search_element_by_id(const xmlNodePtr cur, const xmlChar* id)
{ if (cur == nullptr) return nullptr; // look in current node if (cur->type == XML_ELEMENT_NODE)
{
xmlAttrPtr a = cur->properties; while (a != nullptr)
{ if (a->atype == XML_ATTRIBUTE_ID) { if (strcmp(reinterpret_cast<char*>(a->children->content), reinterpret_cast<charconst *>(id)) == 0) return cur;
}
a = a->next;
}
} // look in children
xmlNodePtr result = lcl_search_element_by_id(cur->children, id); if (result != nullptr) return result;
result = lcl_search_element_by_id(cur->next, id); return result;
}
// Returns the Element whose ID is given by elementId.
Reference< XElement > SAL_CALL
CDocument::getElementById(const OUString& elementId)
{
::osl::MutexGuard const g(m_Mutex);
// search the tree for an element with the given ID
OString o1 = OUStringToOString(elementId, RTL_TEXTENCODING_UTF8);
xmlChar const *pId = reinterpret_cast<xmlChar const *>(o1.getStr());
xmlNodePtr const pStart = lcl_getDocumentRootPtr(m_aDocPtr); if (!pStart) { return nullptr; }
xmlNodePtr const pNode = lcl_search_element_by_id(pStart, pId);
Reference< XElement > const xRet( static_cast< XNode* >(GetCNode(pNode).get()),
UNO_QUERY); return xRet;
}
Reference< XDOMImplementation > SAL_CALL CDocument::getImplementation()
{ // does not need mutex currently return Reference< XDOMImplementation >(CDOMImplementation::get());
}
} if (deep)
{ // get children and import them
Reference< XNode > const xChild = xImportedNode->getFirstChild(); if (xChild.is())
{
lcl_ImportSiblings(xDocument, xNode, xChild);
}
}
/* DOMNodeInsertedIntoDocument * Fired when a node is being inserted into a document, * either through direct insertion of the Node or insertion of a * subtree in which it is contained. This event is dispatched after * the insertion has taken place. The target of this event is the node * being inserted. If the Node is being directly inserted the DOMNodeInserted * event will fire before the DOMNodeInsertedIntoDocument event. * Bubbles: No * Cancelable: No * Context Info: None
*/ if (xNode.is())
{
Reference< XDocumentEvent > const xDocevent(xDocument, UNO_QUERY);
Reference< XMutationEvent > const event(xDocevent->createEvent(
u"DOMNodeInsertedIntoDocument"_ustr), UNO_QUERY_THROW);
event->initMutationEvent(
u"DOMNodeInsertedIntoDocument"_ustr, true, false, Reference< XNode >(),
OUString(), OUString(), OUString(), AttrChangeType(0) );
Reference< XEventTarget > const xDocET(xDocument, UNO_QUERY);
xDocET->dispatchEvent(event);
}
// NB: this whole operation inherently accesses 2 distinct documents. // The imported node could even be from a different DOM implementation, // so this implementation cannot make any assumptions about the // locking strategy of the imported node. // So the import takes no lock on this document; // it only calls UNO methods on this document that temporarily // lock the document, and UNO methods on the imported node that // may temporarily lock the other document. // As a consequence, the import is not atomic with regard to // concurrent modifications of either document, but it should not // deadlock. // To ensure that no members are accessed, the implementation is in // static non-member functions.
Reference< XDocument > const xDocument(this); // already in doc? if (xImportedNode->getOwnerDocument() == xDocument) { return xImportedNode;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.