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