/* -*- 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 . */ #include #include "document.hxx" #include "attr.hxx" #include "element.hxx" #include "cdatasection.hxx" #include "documentfragment.hxx" #include "text.hxx" #include "comment.hxx" #include "processinginstruction.hxx" #include "entityreference.hxx" #include "documenttype.hxx" #include "elementlist.hxx" #include "domimplementation.hxx" #include #include #include "../events/event.hxx" #include "../events/mutationevent.hxx" #include "../events/uievent.hxx" #include "../events/mouseevent.hxx" #include "../events/eventdispatcher.hxx" #include #include #include namespace DOM { static xmlNodePtr lcl_getDocumentType(xmlDocPtr const i_pDocument) { // find the doc type xmlNodePtr cur = i_pDocument->children; while (cur != NULL) { if ((cur->type == XML_DOCUMENT_TYPE_NODE) || (cur->type == XML_DTD_NODE)) { return cur; } } return 0; } /// 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 != NULL) { if (cur->type == XML_ELEMENT_NODE) break; cur = cur->next; } return cur; } CDocument::CDocument(xmlDocPtr const pDoc) : CDocument_Base(*this, m_Mutex, NodeType_DOCUMENT_NODE, reinterpret_cast(pDoc)) , m_aDocPtr(pDoc) , m_streamListeners() , m_pEventDispatcher(new events::CEventDispatcher()) { } ::rtl::Reference CDocument::CreateCDocument(xmlDocPtr const pDoc) { ::rtl::Reference const xDoc(new CDocument(pDoc)); // add the doc itself to its nodemap! xDoc->m_NodeMap.insert( nodemap_t::value_type(reinterpret_cast(pDoc), ::std::make_pair( WeakReference(static_cast(xDoc.get())), xDoc.get()))); return xDoc; } CDocument::~CDocument() { ::osl::MutexGuard const g(m_Mutex); #ifdef DBG_UTIL // node map must be empty now, otherwise CDocument must not die! for (nodemap_t::iterator i = m_NodeMap.begin(); i != m_NodeMap.end(); ++i) { Reference const xNode(i->second.first); OSL_ENSURE(!xNode.is(), "CDocument::~CDocument(): ERROR: live node in document node map!"); } #endif xmlFreeDoc(m_aDocPtr); } events::CEventDispatcher & CDocument::GetEventDispatcher() { return *m_pEventDispatcher; } ::rtl::Reference< CElement > CDocument::GetDocumentElement() { xmlNodePtr const pNode = lcl_getDocumentRootPtr(m_aDocPtr); ::rtl::Reference< CElement > const xRet( dynamic_cast(GetCNode(pNode).get())); return xRet; } void CDocument::RemoveCNode(xmlNodePtr const pNode, CNode const*const pCNode) { nodemap_t::iterator const i = m_NodeMap.find(pNode); if (i != m_NodeMap.end()) { // #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 CDocument::GetCNode(xmlNodePtr const pNode, bool const bCreate) { if (0 == pNode) { return 0; } //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 uno::Reference const xNode(i->second.first); if (xNode.is()) { ::rtl::Reference ret(i->second.second); OSL_ASSERT(ret.is()); return ret; } } if (!bCreate) { return 0; } // there is not yet an instance wrapping this node, // create it and store it in the map ::rtl::Reference pCNode; switch (pNode->type) { case XML_ELEMENT_NODE: // m_aNodeType = NodeType::ELEMENT_NODE; pCNode = static_cast< CNode* >( new CElement(*this, m_Mutex, pNode)); break; case XML_TEXT_NODE: // m_aNodeType = NodeType::TEXT_NODE; pCNode = static_cast< CNode* >( new CText(*this, m_Mutex, pNode)); break; case XML_CDATA_SECTION_NODE: // m_aNodeType = NodeType::CDATA_SECTION_NODE; pCNode = static_cast< CNode* >( new CCDATASection(*this, m_Mutex, pNode)); break; case XML_ENTITY_REF_NODE: // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE; pCNode = static_cast< CNode* >( new CEntityReference(*this, m_Mutex, pNode)); break; case XML_ENTITY_NODE: // m_aNodeType = NodeType::ENTITY_NODE; pCNode = static_cast< CNode* >(new CEntity(*this, m_Mutex, reinterpret_cast(pNode))); break; case XML_PI_NODE: // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE; pCNode = static_cast< CNode* >( new CProcessingInstruction(*this, m_Mutex, pNode)); break; case XML_COMMENT_NODE: // m_aNodeType = NodeType::COMMENT_NODE; pCNode = static_cast< CNode* >( 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 = static_cast< CNode* >(new CDocument( reinterpret_cast(pNode))); break; case XML_DOCUMENT_TYPE_NODE: case XML_DTD_NODE: // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE; pCNode = static_cast< CNode* >(new CDocumentType(*this, m_Mutex, reinterpret_cast(pNode))); break; case XML_DOCUMENT_FRAG_NODE: // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE; pCNode = static_cast< CNode* >( new CDocumentFragment(*this, m_Mutex, pNode)); break; case XML_NOTATION_NODE: // m_aNodeType = NodeType::NOTATION_NODE; pCNode = static_cast< CNode* >(new CNotation(*this, m_Mutex, reinterpret_cast(pNode))); break; case XML_ATTRIBUTE_NODE: // m_aNodeType = NodeType::ATTRIBUTE_NODE; pCNode = static_cast< CNode* >(new CAttr(*this, m_Mutex, reinterpret_cast(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 != 0) { bool const bInserted = m_NodeMap.insert( nodemap_t::value_type(pNode, ::std::make_pair(WeakReference(pCNode.get()), pCNode.get())) ).second; OSL_ASSERT(bInserted); if (!bInserted) { // if insertion failed, delete new instance and return null return 0; } } OSL_ENSURE(pCNode.is(), "no node produced during CDocument::GetCNode!"); return pCNode; } CDocument & CDocument::GetOwnerDocument() { return *this; } void CDocument::saxify(const Reference< XDocumentHandler >& i_xHandler) { i_xHandler->startDocument(); for (xmlNodePtr pChild = m_aNodePtr->children; pChild != 0; pChild = pChild->next) { ::rtl::Reference const pNode = GetCNode(pChild); OSL_ENSURE(pNode != 0, "CNode::get returned 0"); pNode->saxify(i_xHandler); } i_xHandler->endDocument(); } void CDocument::fastSaxify( Context& rContext ) { rContext.mxDocHandler->startDocument(); for (xmlNodePtr pChild = m_aNodePtr->children; pChild != 0; pChild = pChild->next) { ::rtl::Reference const pNode = GetCNode(pChild); OSL_ENSURE(pNode != 0, "CNode::get returned 0"); pNode->fastSaxify(rContext); } rContext.mxDocHandler->endDocument(); } bool CDocument::IsChildTypeAllowed(NodeType const nodeType) { switch (nodeType) { case NodeType_PROCESSING_INSTRUCTION_NODE: case NodeType_COMMENT_NODE: return true; case NodeType_ELEMENT_NODE: // there may be only one! return 0 == lcl_getDocumentRootPtr(m_aDocPtr); case NodeType_DOCUMENT_TYPE_NODE: // there may be only one! return 0 == lcl_getDocumentType(m_aDocPtr); default: return false; } } void SAL_CALL CDocument::addListener(const Reference< XStreamListener >& aListener ) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); m_streamListeners.insert(aListener); } void SAL_CALL CDocument::removeListener(const Reference< XStreamListener >& aListener ) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); m_streamListeners.erase(aListener); } // IO context functions for libxml2 interaction typedef struct { Reference< XOutputStream > stream; bool allowClose; } IOContext; extern "C" { // write callback // int xmlOutputWriteCallback (void * context, const char * buffer, int len) static int writeCallback(void *context, const char* buffer, int len){ // create a sequence and write it to the stream IOContext *pContext = static_cast(context); Sequence bs(reinterpret_cast(buffer), len); pContext->stream->writeBytes(bs); return len; } // clsoe callback //int xmlOutputCloseCallback (void * context) static int closeCallback(void *context) { IOContext *pContext = static_cast(context); if (pContext->allowClose) { pContext->stream->closeOutput(); } return 0; } } // extern "C" void SAL_CALL CDocument::start() throw (RuntimeException) { listenerlist_t streamListeners; { ::osl::MutexGuard const g(m_Mutex); if (! m_rOutputStream.is()) { throw RuntimeException(); } streamListeners = m_streamListeners; } // notify listeners about start listenerlist_t::const_iterator iter1 = streamListeners.begin(); while (iter1 != streamListeners.end()) { Reference< XStreamListener > aListener = *iter1; aListener->started(); ++iter1; } { ::osl::MutexGuard const g(m_Mutex); // check again! could have been reset... if (! m_rOutputStream.is()) { throw RuntimeException(); } // setup libxml IO and write data to output stream IOContext ioctx = {m_rOutputStream, false}; xmlOutputBufferPtr pOut = xmlOutputBufferCreateIO( writeCallback, closeCallback, &ioctx, NULL); xmlSaveFileTo(pOut, m_aNodePtr->doc, NULL); } // call listeners listenerlist_t::const_iterator iter2 = streamListeners.begin(); while (iter2 != streamListeners.end()) { Reference< XStreamListener > aListener = *iter2; aListener->closed(); ++iter2; } } void SAL_CALL CDocument::terminate() throw (RuntimeException) { // not supported } void SAL_CALL CDocument::setOutputStream( const Reference< XOutputStream >& aStream ) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); m_rOutputStream = aStream; } Reference< XOutputStream > SAL_CALL CDocument::getOutputStream() throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); return m_rOutputStream; } // Creates an Attr of the given name. Reference< XAttr > SAL_CALL CDocument::createAttribute(const OUString& name) throw (RuntimeException, DOMException) { ::osl::MutexGuard const g(m_Mutex); OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); xmlChar *xName = (xmlChar*)o1.getStr(); xmlAttrPtr const pAttr = xmlNewDocProp(m_aDocPtr, xName, NULL); ::rtl::Reference< CAttr > const pCAttr( dynamic_cast< CAttr* >(GetCNode( reinterpret_cast(pAttr)).get())); pCAttr->m_bUnlinked = true; return pCAttr.get(); }; // Creates an attribute of the given qualified name and namespace URI. Reference< XAttr > SAL_CALL CDocument::createAttributeNS( const OUString& ns, const OUString& qname) throw (RuntimeException, DOMException) { ::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.copy(0, i), RTL_TEXTENCODING_UTF8); oName = OUStringToOString(qname.copy(i+1, qname.getLength()-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(oName.getStr()), 0); ::rtl::Reference< CAttr > const pCAttr( dynamic_cast< CAttr* >(GetCNode( reinterpret_cast(pAttr)).get())); if (!pCAttr.is()) { throw RuntimeException(); } // store the namespace data! pCAttr->m_pNamespace.reset( new stringpair_t(oUri, oPrefix) ); pCAttr->m_bUnlinked = true; return pCAttr.get(); }; // Creates a CDATASection node whose value is the specified string. Reference< XCDATASection > SAL_CALL CDocument::createCDATASection(const OUString& data) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); OString const oData( OUStringToOString(data, RTL_TEXTENCODING_UTF8)); xmlChar const*const pData = reinterpret_cast(oData.getStr()); xmlNodePtr const pText = xmlNewCDataBlock(m_aDocPtr, pData, strlen(oData.getStr())); Reference< XCDATASection > const xRet( static_cast< XNode* >(GetCNode(pText).get()), UNO_QUERY_THROW); return xRet; } // Creates a Comment node given the specified string. Reference< XComment > SAL_CALL CDocument::createComment(const OUString& data) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); OString o1 = OUStringToOString(data, RTL_TEXTENCODING_UTF8); xmlChar *xData = (xmlChar*)o1.getStr(); xmlNodePtr pComment = xmlNewDocComment(m_aDocPtr, xData); Reference< XComment > const xRet( static_cast< XNode* >(GetCNode(pComment).get()), UNO_QUERY_THROW); return xRet; } //Creates an empty DocumentFragment object. Reference< XDocumentFragment > SAL_CALL CDocument::createDocumentFragment() throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); xmlNodePtr pFrag = xmlNewDocFragment(m_aDocPtr); Reference< XDocumentFragment > const xRet( static_cast< XNode* >(GetCNode(pFrag).get()), UNO_QUERY_THROW); return xRet; } // Creates an element of the type specified. Reference< XElement > SAL_CALL CDocument::createElement(const OUString& tagName) throw (RuntimeException, DOMException) { ::osl::MutexGuard const g(m_Mutex); OString o1 = OUStringToOString(tagName, RTL_TEXTENCODING_UTF8); xmlChar *xName = (xmlChar*)o1.getStr(); xmlNodePtr const pNode = xmlNewDocNode(m_aDocPtr, NULL, xName, NULL); Reference< XElement > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY_THROW); return xRet; } // Creates an element of the given qualified name and namespace URI. Reference< XElement > SAL_CALL CDocument::createElementNS( const OUString& ns, const OUString& qname) throw (RuntimeException, DOMException) { ::osl::MutexGuard const g(m_Mutex); sal_Int32 i = qname.indexOf(':'); if (ns.isEmpty()) throw RuntimeException(); xmlChar *xPrefix; xmlChar *xName; OString o1, o2, o3; if ( i != -1) { o1 = OUStringToOString(qname.copy(0, i), RTL_TEXTENCODING_UTF8); xPrefix = (xmlChar*)o1.getStr(); o2 = OUStringToOString(qname.copy(i+1, qname.getLength()-i-1), RTL_TEXTENCODING_UTF8); xName = (xmlChar*)o2.getStr(); } else { // default prefix xPrefix = (xmlChar*)""; o2 = OUStringToOString(qname, RTL_TEXTENCODING_UTF8); xName = (xmlChar*)o2.getStr(); } o3 = OUStringToOString(ns, RTL_TEXTENCODING_UTF8); xmlChar *xUri = (xmlChar*)o3.getStr(); // xmlNsPtr aNsPtr = xmlNewReconciledNs? // xmlNsPtr aNsPtr = xmlNewGlobalNs? xmlNodePtr const pNode = xmlNewDocNode(m_aDocPtr, NULL, xName, NULL); xmlNsPtr const pNs = xmlNewNs(pNode, xUri, xPrefix); xmlSetNs(pNode, pNs); Reference< XElement > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY_THROW); return xRet; } //Creates an EntityReference object. Reference< XEntityReference > SAL_CALL CDocument::createEntityReference(const OUString& name) throw (RuntimeException, DOMException) { ::osl::MutexGuard const g(m_Mutex); OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); xmlChar *xName = (xmlChar*)o1.getStr(); xmlNodePtr const pNode = xmlNewReference(m_aDocPtr, xName); Reference< XEntityReference > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY_THROW); return xRet; } // Creates a ProcessingInstruction node given the specified name and // data strings. Reference< XProcessingInstruction > SAL_CALL CDocument::createProcessingInstruction( const OUString& target, const OUString& data) throw (RuntimeException, DOMException) { ::osl::MutexGuard const g(m_Mutex); OString o1 = OUStringToOString(target, RTL_TEXTENCODING_UTF8); xmlChar *xTarget = (xmlChar*)o1.getStr(); OString o2 = OUStringToOString(data, RTL_TEXTENCODING_UTF8); xmlChar *xData = (xmlChar*)o2.getStr(); xmlNodePtr const pNode = xmlNewDocPI(m_aDocPtr, xTarget, xData); pNode->doc = m_aDocPtr; Reference< XProcessingInstruction > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY_THROW); return xRet; } // Creates a Text node given the specified string. Reference< XText > SAL_CALL CDocument::createTextNode(const OUString& data) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); OString o1 = OUStringToOString(data, RTL_TEXTENCODING_UTF8); xmlChar *xData = (xmlChar*)o1.getStr(); xmlNodePtr const pNode = xmlNewDocText(m_aDocPtr, xData); Reference< XText > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY_THROW); return xRet; } // The Document Type Declaration (see DocumentType) associated with this // document. Reference< XDocumentType > SAL_CALL CDocument::getDoctype() throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); xmlNodePtr const pDocType(lcl_getDocumentType(m_aDocPtr)); Reference< XDocumentType > const xRet( static_cast< XNode* >(GetCNode(pDocType).get()), UNO_QUERY); return xRet; } // 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() throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); xmlNodePtr const pNode = lcl_getDocumentRootPtr(m_aDocPtr); if (!pNode) { return 0; } Reference< XElement > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY); return xRet; } static xmlNodePtr lcl_search_element_by_id(const xmlNodePtr cur, const xmlChar* id) { if (cur == NULL) return NULL; // look in current node if (cur->type == XML_ELEMENT_NODE) { xmlAttrPtr a = cur->properties; while (a != NULL) { if (a->atype == XML_ATTRIBUTE_ID) { if (strcmp((char*)a->children->content, (char*)id) == 0) return cur; } a = a->next; } } // look in children xmlNodePtr result = lcl_search_element_by_id(cur->children, id); if (result != NULL) 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) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); // search the tree for an element with the given ID OString o1 = OUStringToOString(elementId, RTL_TEXTENCODING_UTF8); xmlChar *xId = (xmlChar*)o1.getStr(); xmlNodePtr const pStart = lcl_getDocumentRootPtr(m_aDocPtr); if (!pStart) { return 0; } xmlNodePtr const pNode = lcl_search_element_by_id(pStart, xId); Reference< XElement > const xRet( static_cast< XNode* >(GetCNode(pNode).get()), UNO_QUERY); return xRet; } Reference< XNodeList > SAL_CALL CDocument::getElementsByTagName(OUString const& rTagname) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); Reference< XNodeList > const xRet( new CElementList(this->GetDocumentElement(), m_Mutex, rTagname)); return xRet; } Reference< XNodeList > SAL_CALL CDocument::getElementsByTagNameNS( OUString const& rNamespaceURI, OUString const& rLocalName) throw (RuntimeException) { ::osl::MutexGuard const g(m_Mutex); Reference< XNodeList > const xRet( new CElementList(this->GetDocumentElement(), m_Mutex, rLocalName, &rNamespaceURI)); return xRet; } Reference< XDOMImplementation > SAL_CALL CDocument::getImplementation() throw (RuntimeException) { // does not need mutex currently return Reference< XDOMImplementation >(CDOMImplementation::get()); } // helper function to recursively import siblings static void lcl_ImportSiblings( Reference< XDocument > const& xTargetDocument, Reference< XNode > const& xTargetParent, Reference< XNode > const& xChild) { Reference< XNode > xSibling = xChild; while (xSibling.is()) { Reference< XNode > const xTmp( xTargetDocument->importNode(xSibling, sal_True)); xTargetParent->appendChild(xTmp); xSibling = xSibling->getNextSibling(); } } static Reference< XNode > lcl_ImportNode( Reference< XDocument > const& xDocument, Reference< XNode > const& xImportedNode, sal_Bool deep) { Reference< XNode > xNode; NodeType aNodeType = xImportedNode->getNodeType(); switch (aNodeType) { case NodeType_ATTRIBUTE_NODE: { Reference< XAttr > const xAttr(xImportedNode, UNO_QUERY_THROW); Reference< XAttr > const xNew = xDocument->createAttribute(xAttr->getName()); xNew->setValue(xAttr->getValue()); xNode.set(xNew, UNO_QUERY); break; } case NodeType_CDATA_SECTION_NODE: { Reference< XCDATASection > const xCData(xImportedNode, UNO_QUERY_THROW); Reference< XCDATASection > const xNewCData = xDocument->createCDATASection(xCData->getData()); xNode.set(xNewCData, UNO_QUERY); break; } case NodeType_COMMENT_NODE: { Reference< XComment > const xComment(xImportedNode, UNO_QUERY_THROW); Reference< XComment > const xNewComment = xDocument->createComment(xComment->getData()); xNode.set(xNewComment, UNO_QUERY); break; } case NodeType_DOCUMENT_FRAGMENT_NODE: { Reference< XDocumentFragment > const xFrag(xImportedNode, UNO_QUERY_THROW); Reference< XDocumentFragment > const xNewFrag = xDocument->createDocumentFragment(); xNode.set(xNewFrag, UNO_QUERY); break; } case NodeType_ELEMENT_NODE: { Reference< XElement > const xElement(xImportedNode, UNO_QUERY_THROW); OUString const aNsUri = xImportedNode->getNamespaceURI(); OUString const aNsPrefix = xImportedNode->getPrefix(); OUString aQName = xElement->getTagName(); Reference< XElement > xNewElement; if (!aNsUri.isEmpty()) { if (!aNsPrefix.isEmpty()) { aQName = aNsPrefix + ":" + aQName; } xNewElement = xDocument->createElementNS(aNsUri, aQName); } else { xNewElement = xDocument->createElement(aQName); } // get attributes if (xElement->hasAttributes()) { Reference< XNamedNodeMap > attribs = xElement->getAttributes(); for (sal_Int32 i = 0; i < attribs->getLength(); i++) { Reference< XAttr > const curAttr(attribs->item(i), UNO_QUERY_THROW); OUString const aAttrUri = curAttr->getNamespaceURI(); OUString const aAttrPrefix = curAttr->getPrefix(); OUString aAttrName = curAttr->getName(); OUString const sValue = curAttr->getValue(); if (!aAttrUri.isEmpty()) { if (!aAttrPrefix.isEmpty()) { aAttrName = aAttrPrefix + ":" + aAttrName; } xNewElement->setAttributeNS( aAttrUri, aAttrName, sValue); } else { xNewElement->setAttribute(aAttrName, sValue); } } } xNode.set(xNewElement, UNO_QUERY); break; } case NodeType_ENTITY_REFERENCE_NODE: { Reference< XEntityReference > const xRef(xImportedNode, UNO_QUERY_THROW); Reference< XEntityReference > const xNewRef( xDocument->createEntityReference(xRef->getNodeName())); xNode.set(xNewRef, UNO_QUERY); break; } case NodeType_PROCESSING_INSTRUCTION_NODE: { Reference< XProcessingInstruction > const xPi(xImportedNode, UNO_QUERY_THROW); Reference< XProcessingInstruction > const xNewPi( xDocument->createProcessingInstruction( xPi->getTarget(), xPi->getData())); xNode.set(xNewPi, UNO_QUERY); break; } case NodeType_TEXT_NODE: { Reference< XText > const xText(xImportedNode, UNO_QUERY_THROW); Reference< XText > const xNewText( xDocument->createTextNode(xText->getData())); xNode.set(xNewText, UNO_QUERY); break; } case NodeType_ENTITY_NODE: case NodeType_DOCUMENT_NODE: case NodeType_DOCUMENT_TYPE_NODE: case NodeType_NOTATION_NODE: default: // can't be imported throw RuntimeException(); } 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( "DOMNodeInsertedIntoDocument"), UNO_QUERY_THROW); event->initMutationEvent( "DOMNodeInsertedIntoDocument", sal_True, sal_False, Reference< XNode >(), OUString(), OUString(), OUString(), (AttrChangeType)0 ); Reference< XEventTarget > const xDocET(xDocument, UNO_QUERY); xDocET->dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); } return xNode; } Reference< XNode > SAL_CALL CDocument::importNode( Reference< XNode > const& xImportedNode, sal_Bool deep) throw (RuntimeException, DOMException) { if (!xImportedNode.is()) { throw RuntimeException(); } // 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; } Reference< XNode > const xNode( lcl_ImportNode(xDocument, xImportedNode, deep) ); return xNode; } OUString SAL_CALL CDocument::getNodeName()throw (RuntimeException) { // does not need mutex currently return OUString("#document"); } OUString SAL_CALL CDocument::getNodeValue() throw (RuntimeException) { // does not need mutex currently return OUString(); } Reference< XNode > SAL_CALL CDocument::cloneNode(sal_Bool bDeep) throw (RuntimeException) { ::osl::MutexGuard const g(m_rMutex); OSL_ASSERT(0 != m_aNodePtr); if (0 == m_aNodePtr) { return 0; } xmlDocPtr const pClone(xmlCopyDoc(m_aDocPtr, (bDeep) ? 1 : 0)); if (0 == pClone) { return 0; } Reference< XNode > const xRet( static_cast(CDocument::CreateCDocument(pClone).get())); return xRet; } Reference< XEvent > SAL_CALL CDocument::createEvent(const OUString& aType) throw (RuntimeException) { // does not need mutex currently events::CEvent *pEvent = 0; if ( aType == "DOMSubtreeModified" || aType == "DOMNodeInserted" || aType == "DOMNodeRemoved" || aType == "DOMNodeRemovedFromDocument" || aType == "DOMNodeInsertedIntoDocument" || aType == "DOMAttrModified" || aType == "DOMCharacterDataModified") { pEvent = new events::CMutationEvent; } else if ( aType == "DOMFocusIn" || aType == "DOMFocusOut" || aType == "DOMActivate") { pEvent = new events::CUIEvent; } else if ( aType == "click" || aType == "mousedown" || aType == "mouseup" || aType == "mouseover" || aType == "mousemove" || aType == "mouseout" ) { pEvent = new events::CMouseEvent; } else // generic event { pEvent = new events::CEvent; } return Reference< XEvent >(pEvent); } // ::com::sun::star::xml::sax::XSAXSerializable void SAL_CALL CDocument::serialize( const Reference< XDocumentHandler >& i_xHandler, const Sequence< beans::StringPair >& i_rNamespaces) throw (RuntimeException, SAXException) { ::osl::MutexGuard const g(m_Mutex); // add new namespaces to root node xmlNodePtr const pRoot = lcl_getDocumentRootPtr(m_aDocPtr); if (0 != pRoot) { const beans::StringPair * pSeq = i_rNamespaces.getConstArray(); for (const beans::StringPair *pNsDef = pSeq; pNsDef < pSeq + i_rNamespaces.getLength(); ++pNsDef) { OString prefix = OUStringToOString(pNsDef->First, RTL_TEXTENCODING_UTF8); OString href = OUStringToOString(pNsDef->Second, RTL_TEXTENCODING_UTF8); // this will only add the ns if it does not exist already xmlNewNs(pRoot, reinterpret_cast(href.getStr()), reinterpret_cast(prefix.getStr())); } // eliminate duplicate namespace declarations nscleanup(pRoot->children, pRoot); } saxify(i_xHandler); } // ::com::sun::star::xml::sax::XFastSAXSerializable void SAL_CALL CDocument::fastSerialize( const Reference< XFastDocumentHandler >& i_xHandler, const Reference< XFastTokenHandler >& i_xTokenHandler, const Sequence< beans::StringPair >& i_rNamespaces, const Sequence< beans::Pair< OUString, sal_Int32 > >& i_rRegisterNamespaces ) throw (SAXException, RuntimeException) { ::osl::MutexGuard const g(m_Mutex); // add new namespaces to root node xmlNodePtr const pRoot = lcl_getDocumentRootPtr(m_aDocPtr); if (0 != pRoot) { const beans::StringPair * pSeq = i_rNamespaces.getConstArray(); for (const beans::StringPair *pNsDef = pSeq; pNsDef < pSeq + i_rNamespaces.getLength(); ++pNsDef) { OString prefix = OUStringToOString(pNsDef->First, RTL_TEXTENCODING_UTF8); OString href = OUStringToOString(pNsDef->Second, RTL_TEXTENCODING_UTF8); // this will only add the ns if it does not exist already xmlNewNs(pRoot, reinterpret_cast(href.getStr()), reinterpret_cast(prefix.getStr())); } // eliminate duplicate namespace declarations nscleanup(pRoot->children, pRoot); } Context aContext(i_xHandler, i_xTokenHandler); // register namespace ids const beans::Pair* pSeq = i_rRegisterNamespaces.getConstArray(); for (const beans::Pair* pNs = pSeq; pNs < pSeq + i_rRegisterNamespaces.getLength(); ++pNs) { OSL_ENSURE(pNs->Second >= FastToken::NAMESPACE, "CDocument::fastSerialize(): invalid NS token id"); aContext.maNamespaceMap[ pNs->First ] = pNs->Second; } fastSaxify(aContext); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */