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