1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include <com/sun/star/uno/Sequence.h> 25 26 #include "document.hxx" 27 #include "attr.hxx" 28 #include "element.hxx" 29 #include "cdatasection.hxx" 30 #include "documentfragment.hxx" 31 #include "text.hxx" 32 #include "cdatasection.hxx" 33 #include "comment.hxx" 34 #include "processinginstruction.hxx" 35 #include "entityreference.hxx" 36 #include "documenttype.hxx" 37 #include "elementlist.hxx" 38 #include "domimplementation.hxx" 39 #include <entity.hxx> 40 #include <notation.hxx> 41 42 #include "../events/event.hxx" 43 #include "../events/mutationevent.hxx" 44 #include "../events/uievent.hxx" 45 #include "../events/mouseevent.hxx" 46 #include "../events/eventdispatcher.hxx" 47 48 #include <string.h> 49 50 #include <com/sun/star/xml/sax/FastToken.hpp> 51 #include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp> 52 53 namespace DOM 54 { lcl_getDocumentType(xmlDocPtr const i_pDocument)55 static xmlNodePtr lcl_getDocumentType(xmlDocPtr const i_pDocument) 56 { 57 // find the doc type 58 xmlNodePtr cur = i_pDocument->children; 59 while (cur != NULL) 60 { 61 if ((cur->type == XML_DOCUMENT_TYPE_NODE) || 62 (cur->type == XML_DTD_NODE)) { 63 return cur; 64 } 65 } 66 return 0; 67 } 68 69 /// get the pointer to the root element node of the document lcl_getDocumentRootPtr(xmlDocPtr const i_pDocument)70 static xmlNodePtr lcl_getDocumentRootPtr(xmlDocPtr const i_pDocument) 71 { 72 // find the document element 73 xmlNodePtr cur = i_pDocument->children; 74 while (cur != NULL) 75 { 76 if (cur->type == XML_ELEMENT_NODE) 77 break; 78 cur = cur->next; 79 } 80 return cur; 81 } 82 CDocument(xmlDocPtr const pDoc)83 CDocument::CDocument(xmlDocPtr const pDoc) 84 : CDocument_Base(*this, m_Mutex, 85 NodeType_DOCUMENT_NODE, reinterpret_cast<xmlNodePtr>(pDoc)) 86 , m_aDocPtr(pDoc) 87 , m_streamListeners() 88 , m_pEventDispatcher(new events::CEventDispatcher()) 89 { 90 } 91 CreateCDocument(xmlDocPtr const pDoc)92 ::rtl::Reference<CDocument> CDocument::CreateCDocument(xmlDocPtr const pDoc) 93 { 94 ::rtl::Reference<CDocument> const xDoc(new CDocument(pDoc)); 95 // add the doc itself to its nodemap! 96 xDoc->m_NodeMap.insert( 97 nodemap_t::value_type(reinterpret_cast<xmlNodePtr>(pDoc), 98 ::std::make_pair( 99 WeakReference<XNode>(static_cast<XDocument*>(xDoc.get())), 100 xDoc.get()))); 101 return xDoc; 102 } 103 ~CDocument()104 CDocument::~CDocument() 105 { 106 ::osl::MutexGuard const g(m_Mutex); 107 #ifdef DBG_UTIL 108 // node map must be empty now, otherwise CDocument must not die! 109 for (nodemap_t::iterator i = m_NodeMap.begin(); 110 i != m_NodeMap.end(); ++i) 111 { 112 Reference<XNode> const xNode(i->second.first); 113 OSL_ENSURE(!xNode.is(), 114 "CDocument::~CDocument(): ERROR: live node in document node map!"); 115 } 116 #endif 117 xmlFreeDoc(m_aDocPtr); 118 } 119 120 GetEventDispatcher()121 events::CEventDispatcher & CDocument::GetEventDispatcher() 122 { 123 return *m_pEventDispatcher; 124 } 125 GetDocumentElement()126 ::rtl::Reference< CElement > CDocument::GetDocumentElement() 127 { 128 xmlNodePtr const pNode = lcl_getDocumentRootPtr(m_aDocPtr); 129 ::rtl::Reference< CElement > const xRet( 130 dynamic_cast<CElement*>(GetCNode(pNode).get())); 131 return xRet; 132 } 133 134 void RemoveCNode(xmlNodePtr const pNode,CNode const * const pCNode)135 CDocument::RemoveCNode(xmlNodePtr const pNode, CNode const*const pCNode) 136 { 137 nodemap_t::iterator const i = m_NodeMap.find(pNode); 138 if (i != m_NodeMap.end()) { 139 // #i113681# consider this scenario: 140 // T1 calls ~CNode 141 // T2 calls getCNode: lookup will find i->second->first invalid 142 // so a new CNode is created and inserted 143 // T1 calls removeCNode: i->second->second now points to a 144 // different CNode instance! 145 // 146 // check that the CNode is the right one 147 CNode *const pCurrent = i->second.second; 148 if (pCurrent == pCNode) { 149 m_NodeMap.erase(i); 150 } 151 } 152 } 153 154 /** NB: this is the CNode factory. 155 it is the only place where CNodes may be instantiated. 156 all CNodes must be registered at the m_NodeMap. 157 */ 158 ::rtl::Reference<CNode> GetCNode(xmlNodePtr const pNode,bool const bCreate)159 CDocument::GetCNode(xmlNodePtr const pNode, bool const bCreate) 160 { 161 if (0 == pNode) { 162 return 0; 163 } 164 //check whether there is already an instance for this node 165 nodemap_t::const_iterator const i = m_NodeMap.find(pNode); 166 if (i != m_NodeMap.end()) { 167 // #i113681# check that the CNode is still alive 168 uno::Reference<XNode> const xNode(i->second.first); 169 if (xNode.is()) 170 { 171 ::rtl::Reference<CNode> ret(i->second.second); 172 OSL_ASSERT(ret.is()); 173 return ret; 174 } 175 } 176 177 if (!bCreate) { return 0; } 178 179 // there is not yet an instance wrapping this node, 180 // create it and store it in the map 181 182 ::rtl::Reference<CNode> pCNode; 183 switch (pNode->type) 184 { 185 case XML_ELEMENT_NODE: 186 // m_aNodeType = NodeType::ELEMENT_NODE; 187 pCNode = static_cast< CNode* >( 188 new CElement(*this, m_Mutex, pNode)); 189 break; 190 case XML_TEXT_NODE: 191 // m_aNodeType = NodeType::TEXT_NODE; 192 pCNode = static_cast< CNode* >( 193 new CText(*this, m_Mutex, pNode)); 194 break; 195 case XML_CDATA_SECTION_NODE: 196 // m_aNodeType = NodeType::CDATA_SECTION_NODE; 197 pCNode = static_cast< CNode* >( 198 new CCDATASection(*this, m_Mutex, pNode)); 199 break; 200 case XML_ENTITY_REF_NODE: 201 // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE; 202 pCNode = static_cast< CNode* >( 203 new CEntityReference(*this, m_Mutex, pNode)); 204 break; 205 case XML_ENTITY_NODE: 206 // m_aNodeType = NodeType::ENTITY_NODE; 207 pCNode = static_cast< CNode* >(new CEntity(*this, m_Mutex, 208 reinterpret_cast<xmlEntityPtr>(pNode))); 209 break; 210 case XML_PI_NODE: 211 // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE; 212 pCNode = static_cast< CNode* >( 213 new CProcessingInstruction(*this, m_Mutex, pNode)); 214 break; 215 case XML_COMMENT_NODE: 216 // m_aNodeType = NodeType::COMMENT_NODE; 217 pCNode = static_cast< CNode* >( 218 new CComment(*this, m_Mutex, pNode)); 219 break; 220 case XML_DOCUMENT_NODE: 221 // m_aNodeType = NodeType::DOCUMENT_NODE; 222 OSL_ENSURE(false, "CDocument::GetCNode is not supposed to" 223 " create a CDocument!!!"); 224 pCNode = static_cast< CNode* >(new CDocument( 225 reinterpret_cast<xmlDocPtr>(pNode))); 226 break; 227 case XML_DOCUMENT_TYPE_NODE: 228 case XML_DTD_NODE: 229 // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE; 230 pCNode = static_cast< CNode* >(new CDocumentType(*this, m_Mutex, 231 reinterpret_cast<xmlDtdPtr>(pNode))); 232 break; 233 case XML_DOCUMENT_FRAG_NODE: 234 // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE; 235 pCNode = static_cast< CNode* >( 236 new CDocumentFragment(*this, m_Mutex, pNode)); 237 break; 238 case XML_NOTATION_NODE: 239 // m_aNodeType = NodeType::NOTATION_NODE; 240 pCNode = static_cast< CNode* >(new CNotation(*this, m_Mutex, 241 reinterpret_cast<xmlNotationPtr>(pNode))); 242 break; 243 case XML_ATTRIBUTE_NODE: 244 // m_aNodeType = NodeType::ATTRIBUTE_NODE; 245 pCNode = static_cast< CNode* >(new CAttr(*this, m_Mutex, 246 reinterpret_cast<xmlAttrPtr>(pNode))); 247 break; 248 // unsupported node types 249 case XML_HTML_DOCUMENT_NODE: 250 case XML_ELEMENT_DECL: 251 case XML_ATTRIBUTE_DECL: 252 case XML_ENTITY_DECL: 253 case XML_NAMESPACE_DECL: 254 default: 255 break; 256 } 257 258 if (pCNode != 0) { 259 bool const bInserted = m_NodeMap.insert( 260 nodemap_t::value_type(pNode, 261 ::std::make_pair(WeakReference<XNode>(pCNode.get()), 262 pCNode.get())) 263 ).second; 264 OSL_ASSERT(bInserted); 265 if (!bInserted) { 266 // if insertion failed, delete new instance and return null 267 return 0; 268 } 269 } 270 271 OSL_ENSURE(pCNode.is(), "no node produced during CDocument::GetCNode!"); 272 return pCNode; 273 } 274 275 GetOwnerDocument()276 CDocument & CDocument::GetOwnerDocument() 277 { 278 return *this; 279 } 280 saxify(const Reference<XDocumentHandler> & i_xHandler)281 void CDocument::saxify(const Reference< XDocumentHandler >& i_xHandler) 282 { 283 i_xHandler->startDocument(); 284 for (xmlNodePtr pChild = m_aNodePtr->children; 285 pChild != 0; pChild = pChild->next) { 286 ::rtl::Reference<CNode> const pNode = GetCNode(pChild); 287 OSL_ENSURE(pNode != 0, "CNode::get returned 0"); 288 pNode->saxify(i_xHandler); 289 } 290 i_xHandler->endDocument(); 291 } 292 fastSaxify(Context & rContext)293 void CDocument::fastSaxify( Context& rContext ) 294 { 295 rContext.mxDocHandler->startDocument(); 296 for (xmlNodePtr pChild = m_aNodePtr->children; 297 pChild != 0; pChild = pChild->next) { 298 ::rtl::Reference<CNode> const pNode = GetCNode(pChild); 299 OSL_ENSURE(pNode != 0, "CNode::get returned 0"); 300 pNode->fastSaxify(rContext); 301 } 302 rContext.mxDocHandler->endDocument(); 303 } 304 IsChildTypeAllowed(NodeType const nodeType)305 bool CDocument::IsChildTypeAllowed(NodeType const nodeType) 306 { 307 switch (nodeType) { 308 case NodeType_PROCESSING_INSTRUCTION_NODE: 309 case NodeType_COMMENT_NODE: 310 return true; 311 case NodeType_ELEMENT_NODE: 312 // there may be only one! 313 return 0 == lcl_getDocumentRootPtr(m_aDocPtr); 314 case NodeType_DOCUMENT_TYPE_NODE: 315 // there may be only one! 316 return 0 == lcl_getDocumentType(m_aDocPtr); 317 default: 318 return false; 319 } 320 } 321 322 addListener(const Reference<XStreamListener> & aListener)323 void SAL_CALL CDocument::addListener(const Reference< XStreamListener >& aListener ) 324 throw (RuntimeException) 325 { 326 ::osl::MutexGuard const g(m_Mutex); 327 328 m_streamListeners.insert(aListener); 329 } 330 removeListener(const Reference<XStreamListener> & aListener)331 void SAL_CALL CDocument::removeListener(const Reference< XStreamListener >& aListener ) 332 throw (RuntimeException) 333 { 334 ::osl::MutexGuard const g(m_Mutex); 335 336 m_streamListeners.erase(aListener); 337 } 338 339 // IO context functions for libxml2 interaction 340 typedef struct { 341 Reference< XOutputStream > stream; 342 bool allowClose; 343 } IOContext; 344 345 extern "C" { 346 // write callback 347 // int xmlOutputWriteCallback (void * context, const char * buffer, int len) writeCallback(void * context,const char * buffer,int len)348 static int writeCallback(void *context, const char* buffer, int len){ 349 // create a sequence and write it to the stream 350 IOContext *pContext = static_cast<IOContext*>(context); 351 Sequence<sal_Int8> bs(reinterpret_cast<const sal_Int8*>(buffer), len); 352 pContext->stream->writeBytes(bs); 353 return len; 354 } 355 356 // clsoe callback 357 //int xmlOutputCloseCallback (void * context) closeCallback(void * context)358 static int closeCallback(void *context) 359 { 360 IOContext *pContext = static_cast<IOContext*>(context); 361 if (pContext->allowClose) { 362 pContext->stream->closeOutput(); 363 } 364 return 0; 365 } 366 } // extern "C" 367 start()368 void SAL_CALL CDocument::start() 369 throw (RuntimeException) 370 { 371 listenerlist_t streamListeners; 372 { 373 ::osl::MutexGuard const g(m_Mutex); 374 375 if (! m_rOutputStream.is()) { throw RuntimeException(); } 376 streamListeners = m_streamListeners; 377 } 378 379 // notify listeners about start 380 listenerlist_t::const_iterator iter1 = streamListeners.begin(); 381 while (iter1 != streamListeners.end()) { 382 Reference< XStreamListener > aListener = *iter1; 383 aListener->started(); 384 iter1++; 385 } 386 387 { 388 ::osl::MutexGuard const g(m_Mutex); 389 390 // check again! could have been reset... 391 if (! m_rOutputStream.is()) { throw RuntimeException(); } 392 393 // setup libxml IO and write data to output stream 394 IOContext ioctx = {m_rOutputStream, false}; 395 xmlOutputBufferPtr pOut = xmlOutputBufferCreateIO( 396 writeCallback, closeCallback, &ioctx, NULL); 397 xmlSaveFileTo(pOut, m_aNodePtr->doc, NULL); 398 } 399 400 // call listeners 401 listenerlist_t::const_iterator iter2 = streamListeners.begin(); 402 while (iter2 != streamListeners.end()) { 403 Reference< XStreamListener > aListener = *iter2; 404 aListener->closed(); 405 iter2++; 406 } 407 } 408 terminate()409 void SAL_CALL CDocument::terminate() 410 throw (RuntimeException) 411 { 412 // not supported 413 } 414 setOutputStream(const Reference<XOutputStream> & aStream)415 void SAL_CALL CDocument::setOutputStream( const Reference< XOutputStream >& aStream ) 416 throw (RuntimeException) 417 { 418 ::osl::MutexGuard const g(m_Mutex); 419 420 m_rOutputStream = aStream; 421 } 422 getOutputStream()423 Reference< XOutputStream > SAL_CALL CDocument::getOutputStream() throw (RuntimeException) 424 { 425 ::osl::MutexGuard const g(m_Mutex); 426 427 return m_rOutputStream; 428 } 429 430 // Creates an Attr of the given name. createAttribute(const OUString & name)431 Reference< XAttr > SAL_CALL CDocument::createAttribute(const OUString& name) 432 throw (RuntimeException, DOMException) 433 { 434 ::osl::MutexGuard const g(m_Mutex); 435 436 OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); 437 xmlChar *xName = (xmlChar*)o1.getStr(); 438 xmlAttrPtr const pAttr = xmlNewDocProp(m_aDocPtr, xName, NULL); 439 ::rtl::Reference< CAttr > const pCAttr( 440 dynamic_cast< CAttr* >(GetCNode( 441 reinterpret_cast<xmlNodePtr>(pAttr)).get())); 442 pCAttr->m_bUnlinked = true; 443 return pCAttr.get(); 444 }; 445 446 // Creates an attribute of the given qualified name and namespace URI. createAttributeNS(const OUString & ns,const OUString & qname)447 Reference< XAttr > SAL_CALL CDocument::createAttributeNS( 448 const OUString& ns, const OUString& qname) 449 throw (RuntimeException, DOMException) 450 { 451 ::osl::MutexGuard const g(m_Mutex); 452 453 // libxml does not allow a NS definition to be attached to an 454 // attribute node - which is a good thing, since namespaces are 455 // only defined as parts of element nodes 456 // thus the namespace data is stored in CAttr::m_pNamespace 457 sal_Int32 i = qname.indexOf(':'); 458 OString oPrefix, oName, oUri; 459 if (i != -1) 460 { 461 oPrefix = OUStringToOString(qname.copy(0, i), RTL_TEXTENCODING_UTF8); 462 oName = OUStringToOString(qname.copy(i+1, qname.getLength()-i-1), RTL_TEXTENCODING_UTF8); 463 } 464 else 465 { 466 oName = OUStringToOString(qname, RTL_TEXTENCODING_UTF8); 467 } 468 oUri = OUStringToOString(ns, RTL_TEXTENCODING_UTF8); 469 xmlAttrPtr const pAttr = xmlNewDocProp(m_aDocPtr, 470 reinterpret_cast<xmlChar const*>(oName.getStr()), 0); 471 ::rtl::Reference< CAttr > const pCAttr( 472 dynamic_cast< CAttr* >(GetCNode( 473 reinterpret_cast<xmlNodePtr>(pAttr)).get())); 474 if (!pCAttr.is()) { throw RuntimeException(); } 475 // store the namespace data! 476 pCAttr->m_pNamespace.reset( new stringpair_t(oUri, oPrefix) ); 477 pCAttr->m_bUnlinked = true; 478 479 return pCAttr.get(); 480 }; 481 482 // Creates a CDATASection node whose value is the specified string. createCDATASection(const OUString & data)483 Reference< XCDATASection > SAL_CALL CDocument::createCDATASection(const OUString& data) 484 throw (RuntimeException) 485 { 486 ::osl::MutexGuard const g(m_Mutex); 487 488 OString const oData( 489 ::rtl::OUStringToOString(data, RTL_TEXTENCODING_UTF8)); 490 xmlChar const*const pData = 491 reinterpret_cast<xmlChar const*>(oData.getStr()); 492 xmlNodePtr const pText = 493 xmlNewCDataBlock(m_aDocPtr, pData, strlen(oData.getStr())); 494 Reference< XCDATASection > const xRet( 495 static_cast< XNode* >(GetCNode(pText).get()), 496 UNO_QUERY_THROW); 497 return xRet; 498 } 499 500 // Creates a Comment node given the specified string. createComment(const OUString & data)501 Reference< XComment > SAL_CALL CDocument::createComment(const OUString& data) 502 throw (RuntimeException) 503 { 504 ::osl::MutexGuard const g(m_Mutex); 505 506 OString o1 = OUStringToOString(data, RTL_TEXTENCODING_UTF8); 507 xmlChar *xData = (xmlChar*)o1.getStr(); 508 xmlNodePtr pComment = xmlNewDocComment(m_aDocPtr, xData); 509 Reference< XComment > const xRet( 510 static_cast< XNode* >(GetCNode(pComment).get()), 511 UNO_QUERY_THROW); 512 return xRet; 513 } 514 515 //Creates an empty DocumentFragment object. createDocumentFragment()516 Reference< XDocumentFragment > SAL_CALL CDocument::createDocumentFragment() 517 throw (RuntimeException) 518 { 519 ::osl::MutexGuard const g(m_Mutex); 520 521 xmlNodePtr pFrag = xmlNewDocFragment(m_aDocPtr); 522 Reference< XDocumentFragment > const xRet( 523 static_cast< XNode* >(GetCNode(pFrag).get()), 524 UNO_QUERY_THROW); 525 return xRet; 526 } 527 528 // Creates an element of the type specified. createElement(const OUString & tagName)529 Reference< XElement > SAL_CALL CDocument::createElement(const OUString& tagName) 530 throw (RuntimeException, DOMException) 531 { 532 ::osl::MutexGuard const g(m_Mutex); 533 534 OString o1 = OUStringToOString(tagName, RTL_TEXTENCODING_UTF8); 535 xmlChar *xName = (xmlChar*)o1.getStr(); 536 xmlNodePtr const pNode = xmlNewDocNode(m_aDocPtr, NULL, xName, NULL); 537 Reference< XElement > const xRet( 538 static_cast< XNode* >(GetCNode(pNode).get()), 539 UNO_QUERY_THROW); 540 return xRet; 541 } 542 543 // Creates an element of the given qualified name and namespace URI. createElementNS(const OUString & ns,const OUString & qname)544 Reference< XElement > SAL_CALL CDocument::createElementNS( 545 const OUString& ns, const OUString& qname) 546 throw (RuntimeException, DOMException) 547 { 548 ::osl::MutexGuard const g(m_Mutex); 549 550 sal_Int32 i = qname.indexOf(':'); 551 if (ns.getLength() == 0) throw RuntimeException(); 552 xmlChar *xPrefix; 553 xmlChar *xName; 554 OString o1, o2, o3; 555 if ( i != -1) { 556 o1 = OUStringToOString(qname.copy(0, i), RTL_TEXTENCODING_UTF8); 557 xPrefix = (xmlChar*)o1.getStr(); 558 o2 = OUStringToOString(qname.copy(i+1, qname.getLength()-i-1), RTL_TEXTENCODING_UTF8); 559 xName = (xmlChar*)o2.getStr(); 560 } else { 561 // default prefix 562 xPrefix = (xmlChar*)""; 563 o2 = OUStringToOString(qname, RTL_TEXTENCODING_UTF8); 564 xName = (xmlChar*)o2.getStr(); 565 } 566 o3 = OUStringToOString(ns, RTL_TEXTENCODING_UTF8); 567 xmlChar *xUri = (xmlChar*)o3.getStr(); 568 569 // xmlNsPtr aNsPtr = xmlNewReconciledNs? 570 // xmlNsPtr aNsPtr = xmlNewGlobalNs? 571 xmlNodePtr const pNode = xmlNewDocNode(m_aDocPtr, NULL, xName, NULL); 572 xmlNsPtr const pNs = xmlNewNs(pNode, xUri, xPrefix); 573 xmlSetNs(pNode, pNs); 574 Reference< XElement > const xRet( 575 static_cast< XNode* >(GetCNode(pNode).get()), 576 UNO_QUERY_THROW); 577 return xRet; 578 } 579 580 //Creates an EntityReference object. createEntityReference(const OUString & name)581 Reference< XEntityReference > SAL_CALL CDocument::createEntityReference(const OUString& name) 582 throw (RuntimeException, DOMException) 583 { 584 ::osl::MutexGuard const g(m_Mutex); 585 586 OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8); 587 xmlChar *xName = (xmlChar*)o1.getStr(); 588 xmlNodePtr const pNode = xmlNewReference(m_aDocPtr, xName); 589 Reference< XEntityReference > const xRet( 590 static_cast< XNode* >(GetCNode(pNode).get()), 591 UNO_QUERY_THROW); 592 return xRet; 593 } 594 595 // Creates a ProcessingInstruction node given the specified name and 596 // data strings. createProcessingInstruction(const OUString & target,const OUString & data)597 Reference< XProcessingInstruction > SAL_CALL CDocument::createProcessingInstruction( 598 const OUString& target, const OUString& data) 599 throw (RuntimeException, DOMException) 600 { 601 ::osl::MutexGuard const g(m_Mutex); 602 603 OString o1 = OUStringToOString(target, RTL_TEXTENCODING_UTF8); 604 xmlChar *xTarget = (xmlChar*)o1.getStr(); 605 OString o2 = OUStringToOString(data, RTL_TEXTENCODING_UTF8); 606 xmlChar *xData = (xmlChar*)o2.getStr(); 607 xmlNodePtr const pNode = xmlNewDocPI(m_aDocPtr, xTarget, xData); 608 pNode->doc = m_aDocPtr; 609 Reference< XProcessingInstruction > const xRet( 610 static_cast< XNode* >(GetCNode(pNode).get()), 611 UNO_QUERY_THROW); 612 return xRet; 613 } 614 615 // Creates a Text node given the specified string. createTextNode(const OUString & data)616 Reference< XText > SAL_CALL CDocument::createTextNode(const OUString& data) 617 throw (RuntimeException) 618 { 619 ::osl::MutexGuard const g(m_Mutex); 620 621 OString o1 = OUStringToOString(data, RTL_TEXTENCODING_UTF8); 622 xmlChar *xData = (xmlChar*)o1.getStr(); 623 xmlNodePtr const pNode = xmlNewDocText(m_aDocPtr, xData); 624 Reference< XText > const xRet( 625 static_cast< XNode* >(GetCNode(pNode).get()), 626 UNO_QUERY_THROW); 627 return xRet; 628 } 629 630 // The Document Type Declaration (see DocumentType) associated with this 631 // document. getDoctype()632 Reference< XDocumentType > SAL_CALL CDocument::getDoctype() 633 throw (RuntimeException) 634 { 635 ::osl::MutexGuard const g(m_Mutex); 636 637 xmlNodePtr const pDocType(lcl_getDocumentType(m_aDocPtr)); 638 Reference< XDocumentType > const xRet( 639 static_cast< XNode* >(GetCNode(pDocType).get()), 640 UNO_QUERY); 641 return xRet; 642 } 643 644 // This is a convenience attribute that allows direct access to the child 645 // node that is the root element of the document. getDocumentElement()646 Reference< XElement > SAL_CALL CDocument::getDocumentElement() 647 throw (RuntimeException) 648 { 649 ::osl::MutexGuard const g(m_Mutex); 650 651 xmlNodePtr const pNode = lcl_getDocumentRootPtr(m_aDocPtr); 652 if (!pNode) { return 0; } 653 Reference< XElement > const xRet( 654 static_cast< XNode* >(GetCNode(pNode).get()), 655 UNO_QUERY); 656 return xRet; 657 } 658 659 static xmlNodePtr lcl_search_element_by_id(const xmlNodePtr cur,const xmlChar * id)660 lcl_search_element_by_id(const xmlNodePtr cur, const xmlChar* id) 661 { 662 if (cur == NULL) 663 return NULL; 664 // look in current node 665 if (cur->type == XML_ELEMENT_NODE) 666 { 667 xmlAttrPtr a = cur->properties; 668 while (a != NULL) 669 { 670 if (a->atype == XML_ATTRIBUTE_ID) { 671 if (strcmp((char*)a->children->content, (char*)id) == 0) 672 return cur; 673 } 674 a = a->next; 675 } 676 } 677 // look in children 678 xmlNodePtr result = lcl_search_element_by_id(cur->children, id); 679 if (result != NULL) 680 return result; 681 result = lcl_search_element_by_id(cur->next, id); 682 return result; 683 } 684 685 // Returns the Element whose ID is given by elementId. 686 Reference< XElement > SAL_CALL getElementById(const OUString & elementId)687 CDocument::getElementById(const OUString& elementId) 688 throw (RuntimeException) 689 { 690 ::osl::MutexGuard const g(m_Mutex); 691 692 // search the tree for an element with the given ID 693 OString o1 = OUStringToOString(elementId, RTL_TEXTENCODING_UTF8); 694 xmlChar *xId = (xmlChar*)o1.getStr(); 695 xmlNodePtr const pStart = lcl_getDocumentRootPtr(m_aDocPtr); 696 if (!pStart) { return 0; } 697 xmlNodePtr const pNode = lcl_search_element_by_id(pStart, xId); 698 Reference< XElement > const xRet( 699 static_cast< XNode* >(GetCNode(pNode).get()), 700 UNO_QUERY); 701 return xRet; 702 } 703 704 705 Reference< XNodeList > SAL_CALL getElementsByTagName(OUString const & rTagname)706 CDocument::getElementsByTagName(OUString const& rTagname) 707 throw (RuntimeException) 708 { 709 ::osl::MutexGuard const g(m_Mutex); 710 711 Reference< XNodeList > const xRet( 712 new CElementList(this->GetDocumentElement(), m_Mutex, rTagname)); 713 return xRet; 714 } 715 getElementsByTagNameNS(OUString const & rNamespaceURI,OUString const & rLocalName)716 Reference< XNodeList > SAL_CALL CDocument::getElementsByTagNameNS( 717 OUString const& rNamespaceURI, OUString const& rLocalName) 718 throw (RuntimeException) 719 { 720 ::osl::MutexGuard const g(m_Mutex); 721 722 Reference< XNodeList > const xRet( 723 new CElementList(this->GetDocumentElement(), m_Mutex, 724 rLocalName, &rNamespaceURI)); 725 return xRet; 726 } 727 getImplementation()728 Reference< XDOMImplementation > SAL_CALL CDocument::getImplementation() 729 throw (RuntimeException) 730 { 731 // does not need mutex currently 732 return Reference< XDOMImplementation >(CDOMImplementation::get()); 733 } 734 735 // helper function to recursively import siblings lcl_ImportSiblings(Reference<XDocument> const & xTargetDocument,Reference<XNode> const & xTargetParent,Reference<XNode> const & xChild)736 static void lcl_ImportSiblings( 737 Reference< XDocument > const& xTargetDocument, 738 Reference< XNode > const& xTargetParent, 739 Reference< XNode > const& xChild) 740 { 741 Reference< XNode > xSibling = xChild; 742 while (xSibling.is()) 743 { 744 Reference< XNode > const xTmp( 745 xTargetDocument->importNode(xSibling, sal_True)); 746 xTargetParent->appendChild(xTmp); 747 xSibling = xSibling->getNextSibling(); 748 } 749 } 750 751 static Reference< XNode > lcl_ImportNode(Reference<XDocument> const & xDocument,Reference<XNode> const & xImportedNode,sal_Bool deep)752 lcl_ImportNode( Reference< XDocument > const& xDocument, 753 Reference< XNode > const& xImportedNode, sal_Bool deep) 754 { 755 Reference< XNode > xNode; 756 NodeType aNodeType = xImportedNode->getNodeType(); 757 switch (aNodeType) 758 { 759 case NodeType_ATTRIBUTE_NODE: 760 { 761 Reference< XAttr > const xAttr(xImportedNode, UNO_QUERY_THROW); 762 Reference< XAttr > const xNew = 763 xDocument->createAttribute(xAttr->getName()); 764 xNew->setValue(xAttr->getValue()); 765 xNode.set(xNew, UNO_QUERY); 766 break; 767 } 768 case NodeType_CDATA_SECTION_NODE: 769 { 770 Reference< XCDATASection > const xCData(xImportedNode, 771 UNO_QUERY_THROW); 772 Reference< XCDATASection > const xNewCData = 773 xDocument->createCDATASection(xCData->getData()); 774 xNode.set(xNewCData, UNO_QUERY); 775 break; 776 } 777 case NodeType_COMMENT_NODE: 778 { 779 Reference< XComment > const xComment(xImportedNode, 780 UNO_QUERY_THROW); 781 Reference< XComment > const xNewComment = 782 xDocument->createComment(xComment->getData()); 783 xNode.set(xNewComment, UNO_QUERY); 784 break; 785 } 786 case NodeType_DOCUMENT_FRAGMENT_NODE: 787 { 788 Reference< XDocumentFragment > const xFrag(xImportedNode, 789 UNO_QUERY_THROW); 790 Reference< XDocumentFragment > const xNewFrag = 791 xDocument->createDocumentFragment(); 792 xNode.set(xNewFrag, UNO_QUERY); 793 break; 794 } 795 case NodeType_ELEMENT_NODE: 796 { 797 Reference< XElement > const xElement(xImportedNode, 798 UNO_QUERY_THROW); 799 OUString const aNsUri = xImportedNode->getNamespaceURI(); 800 OUString const aNsPrefix = xImportedNode->getPrefix(); 801 OUString aQName = xElement->getTagName(); 802 Reference< XElement > xNewElement; 803 if (aNsUri.getLength() > 0) 804 { 805 if (aNsPrefix.getLength() > 0) { 806 aQName = aNsPrefix + OUString::createFromAscii(":") 807 + aQName; 808 } 809 xNewElement = xDocument->createElementNS(aNsUri, aQName); 810 } else { 811 xNewElement = xDocument->createElement(aQName); 812 } 813 814 // get attributes 815 if (xElement->hasAttributes()) 816 { 817 Reference< XNamedNodeMap > attribs = xElement->getAttributes(); 818 for (sal_Int32 i = 0; i < attribs->getLength(); i++) 819 { 820 Reference< XAttr > const curAttr(attribs->item(i), 821 UNO_QUERY_THROW); 822 OUString const aAttrUri = curAttr->getNamespaceURI(); 823 OUString const aAttrPrefix = curAttr->getPrefix(); 824 OUString aAttrName = curAttr->getName(); 825 OUString const sValue = curAttr->getValue(); 826 if (aAttrUri.getLength() > 0) 827 { 828 if (aAttrPrefix.getLength() > 0) { 829 aAttrName = aAttrPrefix + 830 OUString::createFromAscii(":") + aAttrName; 831 } 832 xNewElement->setAttributeNS( 833 aAttrUri, aAttrName, sValue); 834 } else { 835 xNewElement->setAttribute(aAttrName, sValue); 836 } 837 } 838 } 839 xNode.set(xNewElement, UNO_QUERY); 840 break; 841 } 842 case NodeType_ENTITY_REFERENCE_NODE: 843 { 844 Reference< XEntityReference > const xRef(xImportedNode, 845 UNO_QUERY_THROW); 846 Reference< XEntityReference > const xNewRef( 847 xDocument->createEntityReference(xRef->getNodeName())); 848 xNode.set(xNewRef, UNO_QUERY); 849 break; 850 } 851 case NodeType_PROCESSING_INSTRUCTION_NODE: 852 { 853 Reference< XProcessingInstruction > const xPi(xImportedNode, 854 UNO_QUERY_THROW); 855 Reference< XProcessingInstruction > const xNewPi( 856 xDocument->createProcessingInstruction( 857 xPi->getTarget(), xPi->getData())); 858 xNode.set(xNewPi, UNO_QUERY); 859 break; 860 } 861 case NodeType_TEXT_NODE: 862 { 863 Reference< XText > const xText(xImportedNode, UNO_QUERY_THROW); 864 Reference< XText > const xNewText( 865 xDocument->createTextNode(xText->getData())); 866 xNode.set(xNewText, UNO_QUERY); 867 break; 868 } 869 case NodeType_ENTITY_NODE: 870 case NodeType_DOCUMENT_NODE: 871 case NodeType_DOCUMENT_TYPE_NODE: 872 case NodeType_NOTATION_NODE: 873 default: 874 // can't be imported 875 throw RuntimeException(); 876 877 } 878 if (deep) 879 { 880 // get children and import them 881 Reference< XNode > const xChild = xImportedNode->getFirstChild(); 882 if (xChild.is()) 883 { 884 lcl_ImportSiblings(xDocument, xNode, xChild); 885 } 886 } 887 888 /* DOMNodeInsertedIntoDocument 889 * Fired when a node is being inserted into a document, 890 * either through direct insertion of the Node or insertion of a 891 * subtree in which it is contained. This event is dispatched after 892 * the insertion has taken place. The target of this event is the node 893 * being inserted. If the Node is being directly inserted the DOMNodeInserted 894 * event will fire before the DOMNodeInsertedIntoDocument event. 895 * Bubbles: No 896 * Cancelable: No 897 * Context Info: None 898 */ 899 if (xNode.is()) 900 { 901 Reference< XDocumentEvent > const xDocevent(xDocument, UNO_QUERY); 902 Reference< XMutationEvent > const event(xDocevent->createEvent( 903 OUString::createFromAscii("DOMNodeInsertedIntoDocument")), 904 UNO_QUERY_THROW); 905 event->initMutationEvent( 906 OUString::createFromAscii("DOMNodeInsertedIntoDocument") 907 , sal_True, sal_False, Reference< XNode >(), 908 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 909 Reference< XEventTarget > const xDocET(xDocument, UNO_QUERY); 910 xDocET->dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 911 } 912 913 return xNode; 914 } 915 importNode(Reference<XNode> const & xImportedNode,sal_Bool deep)916 Reference< XNode > SAL_CALL CDocument::importNode( 917 Reference< XNode > const& xImportedNode, sal_Bool deep) 918 throw (RuntimeException, DOMException) 919 { 920 if (!xImportedNode.is()) { throw RuntimeException(); } 921 922 // NB: this whole operation inherently accesses 2 distinct documents. 923 // The imported node could even be from a different DOM implementation, 924 // so this implementation cannot make any assumptions about the 925 // locking strategy of the imported node. 926 // So the import takes no lock on this document; 927 // it only calls UNO methods on this document that temporarily 928 // lock the document, and UNO methods on the imported node that 929 // may temporarily lock the other document. 930 // As a consequence, the import is not atomic with regard to 931 // concurrent modifications of either document, but it should not 932 // deadlock. 933 // To ensure that no members are accessed, the implementation is in 934 // static non-member functions. 935 936 Reference< XDocument > const xDocument(this); 937 // already in doc? 938 if (xImportedNode->getOwnerDocument() == xDocument) { 939 return xImportedNode; 940 } 941 942 Reference< XNode > const xNode( 943 lcl_ImportNode(xDocument, xImportedNode, deep) ); 944 return xNode; 945 } 946 947 getNodeName()948 OUString SAL_CALL CDocument::getNodeName()throw (RuntimeException) 949 { 950 // does not need mutex currently 951 return OUString::createFromAscii("#document"); 952 } 953 getNodeValue()954 OUString SAL_CALL CDocument::getNodeValue() throw (RuntimeException) 955 { 956 // does not need mutex currently 957 return OUString(); 958 } 959 cloneNode(sal_Bool bDeep)960 Reference< XNode > SAL_CALL CDocument::cloneNode(sal_Bool bDeep) 961 throw (RuntimeException) 962 { 963 ::osl::MutexGuard const g(m_rMutex); 964 965 OSL_ASSERT(0 != m_aNodePtr); 966 if (0 == m_aNodePtr) { 967 return 0; 968 } 969 xmlDocPtr const pClone(xmlCopyDoc(m_aDocPtr, (bDeep) ? 1 : 0)); 970 if (0 == pClone) { return 0; } 971 Reference< XNode > const xRet( 972 static_cast<CNode*>(CDocument::CreateCDocument(pClone).get())); 973 return xRet; 974 } 975 createEvent(const OUString & aType)976 Reference< XEvent > SAL_CALL CDocument::createEvent(const OUString& aType) throw (RuntimeException) 977 { 978 // does not need mutex currently 979 events::CEvent *pEvent = 0; 980 if ( 981 aType.compareToAscii("DOMSubtreeModified") == 0|| 982 aType.compareToAscii("DOMNodeInserted") == 0|| 983 aType.compareToAscii("DOMNodeRemoved") == 0|| 984 aType.compareToAscii("DOMNodeRemovedFromDocument") == 0|| 985 aType.compareToAscii("DOMNodeInsertedIntoDocument") == 0|| 986 aType.compareToAscii("DOMAttrModified") == 0|| 987 aType.compareToAscii("DOMCharacterDataModified") == 0) 988 { 989 pEvent = new events::CMutationEvent; 990 991 } else if ( 992 aType.compareToAscii("DOMFocusIn") == 0|| 993 aType.compareToAscii("DOMFocusOut") == 0|| 994 aType.compareToAscii("DOMActivate") == 0) 995 { 996 pEvent = new events::CUIEvent; 997 } else if ( 998 aType.compareToAscii("click") == 0|| 999 aType.compareToAscii("mousedown") == 0|| 1000 aType.compareToAscii("mouseup") == 0|| 1001 aType.compareToAscii("mouseover") == 0|| 1002 aType.compareToAscii("mousemove") == 0|| 1003 aType.compareToAscii("mouseout") == 0 ) 1004 { 1005 pEvent = new events::CMouseEvent; 1006 } 1007 else // generic event 1008 { 1009 pEvent = new events::CEvent; 1010 } 1011 return Reference< XEvent >(pEvent); 1012 } 1013 1014 // ::com::sun::star::xml::sax::XSAXSerializable serialize(const Reference<XDocumentHandler> & i_xHandler,const Sequence<beans::StringPair> & i_rNamespaces)1015 void SAL_CALL CDocument::serialize( 1016 const Reference< XDocumentHandler >& i_xHandler, 1017 const Sequence< beans::StringPair >& i_rNamespaces) 1018 throw (RuntimeException, SAXException) 1019 { 1020 ::osl::MutexGuard const g(m_Mutex); 1021 1022 // add new namespaces to root node 1023 xmlNodePtr const pRoot = lcl_getDocumentRootPtr(m_aDocPtr); 1024 if (0 != pRoot) { 1025 const beans::StringPair * pSeq = i_rNamespaces.getConstArray(); 1026 for (const beans::StringPair *pNsDef = pSeq; 1027 pNsDef < pSeq + i_rNamespaces.getLength(); ++pNsDef) { 1028 OString prefix = OUStringToOString(pNsDef->First, 1029 RTL_TEXTENCODING_UTF8); 1030 OString href = OUStringToOString(pNsDef->Second, 1031 RTL_TEXTENCODING_UTF8); 1032 // this will only add the ns if it does not exist already 1033 xmlNewNs(pRoot, reinterpret_cast<const xmlChar*>(href.getStr()), 1034 reinterpret_cast<const xmlChar*>(prefix.getStr())); 1035 } 1036 // eliminate duplicate namespace declarations 1037 nscleanup(pRoot->children, pRoot); 1038 } 1039 saxify(i_xHandler); 1040 } 1041 1042 // ::com::sun::star::xml::sax::XFastSAXSerializable fastSerialize(const Reference<XFastDocumentHandler> & i_xHandler,const Reference<XFastTokenHandler> & i_xTokenHandler,const Sequence<beans::StringPair> & i_rNamespaces,const Sequence<beans::Pair<rtl::OUString,sal_Int32>> & i_rRegisterNamespaces)1043 void SAL_CALL CDocument::fastSerialize( const Reference< XFastDocumentHandler >& i_xHandler, 1044 const Reference< XFastTokenHandler >& i_xTokenHandler, 1045 const Sequence< beans::StringPair >& i_rNamespaces, 1046 const Sequence< beans::Pair< rtl::OUString, sal_Int32 > >& i_rRegisterNamespaces ) 1047 throw (SAXException, RuntimeException) 1048 { 1049 ::osl::MutexGuard const g(m_Mutex); 1050 1051 // add new namespaces to root node 1052 xmlNodePtr const pRoot = lcl_getDocumentRootPtr(m_aDocPtr); 1053 if (0 != pRoot) { 1054 const beans::StringPair * pSeq = i_rNamespaces.getConstArray(); 1055 for (const beans::StringPair *pNsDef = pSeq; 1056 pNsDef < pSeq + i_rNamespaces.getLength(); ++pNsDef) { 1057 OString prefix = OUStringToOString(pNsDef->First, 1058 RTL_TEXTENCODING_UTF8); 1059 OString href = OUStringToOString(pNsDef->Second, 1060 RTL_TEXTENCODING_UTF8); 1061 // this will only add the ns if it does not exist already 1062 xmlNewNs(pRoot, reinterpret_cast<const xmlChar*>(href.getStr()), 1063 reinterpret_cast<const xmlChar*>(prefix.getStr())); 1064 } 1065 // eliminate duplicate namespace declarations 1066 nscleanup(pRoot->children, pRoot); 1067 } 1068 1069 Context aContext(i_xHandler, 1070 i_xTokenHandler); 1071 1072 // register namespace ids 1073 const beans::Pair<OUString,sal_Int32>* pSeq = i_rRegisterNamespaces.getConstArray(); 1074 for (const beans::Pair<OUString,sal_Int32>* pNs = pSeq; 1075 pNs < pSeq + i_rRegisterNamespaces.getLength(); ++pNs) 1076 { 1077 OSL_ENSURE(pNs->Second >= FastToken::NAMESPACE, 1078 "CDocument::fastSerialize(): invalid NS token id"); 1079 aContext.maNamespaceMap[ pNs->First ] = pNs->Second; 1080 } 1081 1082 fastSaxify(aContext); 1083 } 1084 } 1085