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