Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/unoxml/source/dom/element.cxx
Line
Count
Source
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 "element.hxx"
21
22
#include <string.h>
23
24
#include <memory>
25
26
#include <osl/diagnose.h>
27
#include <rtl/ustrbuf.hxx>
28
29
#include <com/sun/star/xml/dom/DOMException.hpp>
30
#include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
31
#include <com/sun/star/xml/sax/FastToken.hpp>
32
33
#include <comphelper/attributelist.hxx>
34
#include <comphelper/servicehelper.hxx>
35
36
#include <eventdispatcher.hxx>
37
#include <node.hxx>
38
#include "attr.hxx"
39
#include "elementlist.hxx"
40
#include "attributesmap.hxx"
41
#include "document.hxx"
42
43
using namespace css::uno;
44
using namespace css::xml::dom;
45
using namespace css::xml::dom::events;
46
using namespace css::xml::sax;
47
48
namespace DOM
49
{
50
51
    CElement::CElement(CDocument const& rDocument, ::osl::Mutex const& rMutex,
52
            xmlNodePtr const pNode)
53
2.00M
        : CElement_Base(rDocument, rMutex, NodeType_ELEMENT_NODE, pNode)
54
2.00M
    {
55
2.00M
    }
56
57
    void CElement::saxify(const Reference< XDocumentHandler >& i_xHandler)
58
276
    {
59
276
        if (!i_xHandler.is()) throw RuntimeException();
60
276
        rtl::Reference<comphelper::AttributeList> pAttrs =
61
276
            new comphelper::AttributeList();
62
        // add namespace definitions to attributes
63
2.96k
        for (xmlNsPtr pNs = m_aNodePtr->nsDef; pNs != nullptr; pNs = pNs->next) {
64
2.69k
            const xmlChar *pPrefix = pNs->prefix ? pNs->prefix : reinterpret_cast<const xmlChar*>("");
65
2.69k
            OUString prefix(reinterpret_cast<const char*>(pPrefix),
66
2.69k
                strlen(reinterpret_cast<const char*>(pPrefix)),
67
2.69k
                RTL_TEXTENCODING_UTF8);
68
2.69k
            OUString name = (prefix.isEmpty())
69
2.69k
                ? u"xmlns"_ustr : "xmlns:" + prefix;
70
2.69k
            const xmlChar *pHref = pNs->href;
71
2.69k
            OUString val(reinterpret_cast<const char*>(pHref),
72
2.69k
                strlen(reinterpret_cast<const char*>(pHref)),
73
2.69k
                RTL_TEXTENCODING_UTF8);
74
2.69k
            pAttrs->AddAttribute(name, val);
75
2.69k
        }
76
        // add attributes
77
276
        for (xmlAttrPtr pAttr = m_aNodePtr->properties;
78
414
                        pAttr != nullptr; pAttr = pAttr->next) {
79
138
            ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
80
138
                    reinterpret_cast<xmlNodePtr>(pAttr));
81
138
            OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
82
138
            OUString prefix = pNode->getPrefix();
83
138
            OUString name = (prefix.isEmpty())
84
138
                ? pNode->getLocalName()
85
138
                : prefix + ":" + pNode->getLocalName();
86
138
            OUString val  = pNode->getNodeValue();
87
138
            pAttrs->AddAttribute(name, val);
88
138
        }
89
276
        OUString prefix = getPrefix();
90
276
        OUString name = (prefix.isEmpty())
91
276
            ? getLocalName()
92
276
            : prefix + ":" + getLocalName();
93
276
        i_xHandler->startElement(name, pAttrs);
94
        // recurse
95
276
        for (xmlNodePtr pChild = m_aNodePtr->children;
96
552
                        pChild != nullptr; pChild = pChild->next) {
97
276
            ::rtl::Reference<CNode> const pNode(
98
276
                    GetOwnerDocument().GetCNode(pChild));
99
276
            OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
100
276
            pNode->saxify(i_xHandler);
101
276
        }
102
276
        i_xHandler->endElement(name);
103
276
    }
104
105
    void CElement::fastSaxify( Context& i_rContext )
106
556k
    {
107
556k
        if (!i_rContext.mxDocHandler.is()) throw RuntimeException();
108
556k
        pushContext(i_rContext);
109
556k
        addNamespaces(i_rContext,m_aNodePtr);
110
111
        // add attributes
112
556k
        i_rContext.mxAttribList->clear();
113
556k
        for (xmlAttrPtr pAttr = m_aNodePtr->properties;
114
1.22M
                        pAttr != nullptr; pAttr = pAttr->next) {
115
666k
            ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
116
666k
                    reinterpret_cast<xmlNodePtr>(pAttr));
117
666k
            OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
118
119
666k
            const xmlChar* pName = pAttr->name;
120
666k
            sal_Int32 nAttributeToken=FastToken::DONTKNOW;
121
122
666k
            if( pAttr->ns && strlen(reinterpret_cast<char const *>(pAttr->ns->prefix)) )
123
2.02k
                nAttributeToken = getTokenWithPrefix( i_rContext,
124
2.02k
                                                      reinterpret_cast<char const *>(pAttr->ns->prefix),
125
2.02k
                                                      reinterpret_cast<char const *>(pName) );
126
664k
            else
127
664k
                nAttributeToken = getToken( i_rContext, reinterpret_cast<char const *>(pName) );
128
129
666k
            if( nAttributeToken != FastToken::DONTKNOW )
130
665k
                i_rContext.mxAttribList->add( nAttributeToken,
131
665k
                                              OUStringToOString(pNode->getNodeValue(),
132
665k
                                                                RTL_TEXTENCODING_UTF8));
133
666k
        }
134
135
556k
        const xmlChar* pPrefix = (m_aNodePtr->ns && m_aNodePtr->ns->prefix) ? m_aNodePtr->ns->prefix : reinterpret_cast<const xmlChar*>("");
136
556k
        const xmlChar* pName = m_aNodePtr->name;
137
556k
        sal_Int32 nElementToken=FastToken::DONTKNOW;
138
556k
        if( strlen(reinterpret_cast<char const *>(pPrefix)) )
139
556k
            nElementToken = getTokenWithPrefix( i_rContext, reinterpret_cast<char const *>(pPrefix), reinterpret_cast<char const *>(pName) );
140
0
        else
141
0
            nElementToken = getToken( i_rContext, reinterpret_cast<char const *>(pName) );
142
143
556k
        Reference<XFastContextHandler> xParentHandler(i_rContext.mxCurrentHandler);
144
556k
        try
145
556k
        {
146
556k
            Reference< XFastAttributeList > xAttr( i_rContext.mxAttribList );
147
556k
            if( nElementToken == FastToken::DONTKNOW )
148
493
            {
149
493
                const OUString aNamespace;
150
493
                const OUString aElementName( reinterpret_cast<char const *>(pPrefix),
151
493
                                             strlen(reinterpret_cast<char const *>(pPrefix)),
152
493
                                             RTL_TEXTENCODING_UTF8 );
153
154
493
                if( xParentHandler.is() )
155
0
                    i_rContext.mxCurrentHandler = xParentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
156
493
                else
157
493
                    i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
158
159
493
                if( i_rContext.mxCurrentHandler.is() )
160
0
                    i_rContext.mxCurrentHandler->startUnknownElement( aNamespace, aElementName, xAttr );
161
493
            }
162
556k
            else
163
556k
            {
164
556k
                if( xParentHandler.is() )
165
529k
                    i_rContext.mxCurrentHandler = xParentHandler->createFastChildContext( nElementToken, xAttr );
166
26.6k
                else
167
26.6k
                    i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createFastChildContext( nElementToken, xAttr );
168
169
556k
                if( i_rContext.mxCurrentHandler.is() )
170
367k
                    i_rContext.mxCurrentHandler->startFastElement( nElementToken, xAttr );
171
556k
            }
172
556k
        }
173
556k
        catch( Exception& )
174
556k
        {}
175
176
        // recurse
177
556k
        for (xmlNodePtr pChild = m_aNodePtr->children;
178
1.38M
                        pChild != nullptr; pChild = pChild->next) {
179
830k
            ::rtl::Reference<CNode> const pNode(
180
830k
                    GetOwnerDocument().GetCNode(pChild));
181
830k
            OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
182
830k
            pNode->fastSaxify(i_rContext);
183
830k
        }
184
185
556k
        if( i_rContext.mxCurrentHandler.is() ) try
186
367k
        {
187
367k
            if( nElementToken != FastToken::DONTKNOW )
188
367k
                i_rContext.mxCurrentHandler->endFastElement( nElementToken );
189
0
            else
190
0
            {
191
0
                const OUString aElementName( reinterpret_cast<char const *>(pPrefix),
192
0
                                             strlen(reinterpret_cast<char const *>(pPrefix)),
193
0
                                             RTL_TEXTENCODING_UTF8 );
194
195
0
                i_rContext.mxCurrentHandler->endUnknownElement( u""_ustr, aElementName );
196
0
            }
197
367k
        }
198
367k
        catch( Exception& )
199
367k
        {}
200
201
        // restore after children have been processed
202
556k
        i_rContext.mxCurrentHandler = std::move(xParentHandler);
203
556k
        popContext(i_rContext);
204
556k
    }
205
206
    bool CElement::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const)
207
792k
    {
208
792k
        switch (nodeType) {
209
572k
            case NodeType_ELEMENT_NODE:
210
792k
            case NodeType_TEXT_NODE:
211
792k
            case NodeType_COMMENT_NODE:
212
792k
            case NodeType_PROCESSING_INSTRUCTION_NODE:
213
792k
            case NodeType_CDATA_SECTION_NODE:
214
792k
            case NodeType_ENTITY_REFERENCE_NODE:
215
792k
                return true;
216
0
            case NodeType_ATTRIBUTE_NODE:
217
                /* this is not really allowed by the DOM spec, but this
218
                   implementation has evidently supported it (by special case
219
                   handling, so the attribute does not actually become a child)
220
                   so allow it for backward compatibility */
221
0
                return true;
222
0
            default:
223
0
                return false;
224
792k
        }
225
792k
    }
226
227
228
    /**
229
        Retrieves an attribute value by name.
230
        return empty string if attribute is not set
231
    */
232
    OUString SAL_CALL CElement::getAttribute(OUString const& name)
233
0
    {
234
0
        ::osl::MutexGuard const g(m_rMutex);
235
236
0
        if (nullptr == m_aNodePtr) {
237
0
            return OUString();
238
0
        }
239
        // search properties
240
0
        OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
241
0
        std::shared_ptr<xmlChar const> const pValue(
242
0
            xmlGetProp(m_aNodePtr, reinterpret_cast<xmlChar const *>(o1.getStr())), xmlFree);
243
0
        OUString const ret( pValue
244
0
            ?   OUString(reinterpret_cast<char const*>(pValue.get()),
245
0
                        strlen(reinterpret_cast<char const*>(pValue.get())),
246
0
                        RTL_TEXTENCODING_UTF8)
247
0
            :   OUString() );
248
0
        return ret;
249
0
    }
250
251
    /**
252
    Retrieves an attribute node by name.
253
    */
254
    Reference< XAttr > SAL_CALL CElement::getAttributeNode(OUString const& name)
255
0
    {
256
0
        ::osl::MutexGuard const g(m_rMutex);
257
258
0
        if (nullptr == m_aNodePtr) {
259
0
            return nullptr;
260
0
        }
261
0
        OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
262
0
        xmlChar const*const pName =
263
0
            reinterpret_cast<xmlChar const*>(o1.getStr());
264
0
        xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
265
0
        if (nullptr == pAttr) {
266
0
            return nullptr;
267
0
        }
268
0
        Reference< XAttr > const xRet(
269
0
            static_cast< XNode* >(GetOwnerDocument().GetCNode(
270
0
                    reinterpret_cast<xmlNodePtr>(pAttr)).get()),
271
0
            UNO_QUERY_THROW);
272
0
        return xRet;
273
0
    }
274
275
    /**
276
    Retrieves an Attr node by local name and namespace URI.
277
    */
278
    Reference< XAttr > SAL_CALL CElement::getAttributeNodeNS(
279
            const OUString& namespaceURI, const OUString& localName)
280
0
    {
281
0
        ::osl::MutexGuard const g(m_rMutex);
282
283
0
        if (nullptr == m_aNodePtr) {
284
0
            return nullptr;
285
0
        }
286
0
        OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
287
0
        xmlChar const*const pName =
288
0
            reinterpret_cast<xmlChar const*>(o1.getStr());
289
0
        OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
290
0
        xmlChar const*const pNS =
291
0
            reinterpret_cast<xmlChar const*>(o2.getStr());
292
0
        xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pNS);
293
0
        if (nullptr == pAttr) {
294
0
            return nullptr;
295
0
        }
296
0
        Reference< XAttr > const xRet(
297
0
            static_cast< XNode* >(GetOwnerDocument().GetCNode(
298
0
                    reinterpret_cast<xmlNodePtr>(pAttr)).get()),
299
0
            UNO_QUERY_THROW);
300
0
        return xRet;
301
0
    }
302
303
    /**
304
    Retrieves an attribute value by local name and namespace URI.
305
    return empty string if attribute is not set
306
    */
307
    OUString SAL_CALL
308
    CElement::getAttributeNS(
309
            OUString const& namespaceURI, OUString const& localName)
310
111k
    {
311
111k
        ::osl::MutexGuard const g(m_rMutex);
312
313
111k
        if (nullptr == m_aNodePtr) {
314
0
            return OUString();
315
0
        }
316
111k
        OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
317
111k
        xmlChar const*const pName =
318
111k
            reinterpret_cast<xmlChar const*>(o1.getStr());
319
111k
        OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
320
111k
        xmlChar const*const pNS =
321
111k
            reinterpret_cast<xmlChar const*>(o2.getStr());
322
111k
        std::shared_ptr<xmlChar const> const pValue(
323
111k
                xmlGetNsProp(m_aNodePtr, pName, pNS), xmlFree);
324
111k
        if (nullptr == pValue) {
325
80.4k
            return OUString();
326
80.4k
        }
327
30.9k
        OUString const ret(reinterpret_cast<char const*>(pValue.get()),
328
30.9k
                        strlen(reinterpret_cast<char const*>(pValue.get())),
329
30.9k
                        RTL_TEXTENCODING_UTF8);
330
30.9k
        return ret;
331
111k
    }
332
333
    /**
334
    Returns a NodeList of all descendant Elements with a given tag name,
335
    in the order in which they are
336
    encountered in a preorder traversal of this Element tree.
337
    */
338
    Reference< XNodeList > SAL_CALL
339
    CElement::getElementsByTagName(OUString const& rLocalName)
340
0
    {
341
0
        ::osl::MutexGuard const g(m_rMutex);
342
343
0
        Reference< XNodeList > const xList(
344
0
                new CElementList(this, m_rMutex, rLocalName));
345
0
        return xList;
346
0
    }
347
348
    /**
349
    Returns a NodeList of all the descendant Elements with a given local
350
    name and namespace URI in the order in which they are encountered in
351
    a preorder traversal of this Element tree.
352
    */
353
    Reference< XNodeList > SAL_CALL
354
    CElement::getElementsByTagNameNS(
355
            OUString const& rNamespaceURI, OUString const& rLocalName)
356
0
    {
357
0
        ::osl::MutexGuard const g(m_rMutex);
358
359
0
        Reference< XNodeList > const xList(
360
0
            new CElementList(this, m_rMutex, rLocalName, &rNamespaceURI));
361
0
        return xList;
362
0
    }
363
364
    /**
365
    The name of the element.
366
    */
367
    OUString SAL_CALL CElement::getTagName()
368
97.0k
    {
369
97.0k
        ::osl::MutexGuard const g(m_rMutex);
370
371
97.0k
        if (nullptr == m_aNodePtr) {
372
0
            return OUString();
373
0
        }
374
97.0k
        OUString const ret(reinterpret_cast<char const *>(m_aNodePtr->name),
375
97.0k
                strlen(reinterpret_cast<char const *>(m_aNodePtr->name)), RTL_TEXTENCODING_UTF8);
376
97.0k
        return ret;
377
97.0k
    }
378
379
380
    /**
381
    Returns true when an attribute with a given name is specified on this
382
    element or has a default value, false otherwise.
383
    */
384
    sal_Bool SAL_CALL CElement::hasAttribute(OUString const& name)
385
0
    {
386
0
        ::osl::MutexGuard const g(m_rMutex);
387
388
0
        OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
389
0
        xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
390
0
        return (m_aNodePtr != nullptr && xmlHasProp(m_aNodePtr, pName) != nullptr);
391
0
    }
392
393
    /**
394
    Returns true when an attribute with a given local name and namespace
395
    URI is specified on this element or has a default value, false otherwise.
396
    */
397
    sal_Bool SAL_CALL CElement::hasAttributeNS(
398
            OUString const& namespaceURI, OUString const& localName)
399
0
    {
400
0
        ::osl::MutexGuard const g(m_rMutex);
401
402
0
        OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
403
0
        xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
404
0
        OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
405
0
        xmlChar const *pNs = reinterpret_cast<xmlChar const *>(o2.getStr());
406
0
        return (m_aNodePtr != nullptr && xmlHasNsProp(m_aNodePtr, pName, pNs) != nullptr);
407
0
    }
408
409
    /**
410
    Removes an attribute by name.
411
    */
412
    void SAL_CALL CElement::removeAttribute(OUString const& name)
413
0
    {
414
0
        ::osl::MutexGuard const g(m_rMutex);
415
416
0
        if (nullptr == m_aNodePtr) {
417
0
            return;
418
0
        }
419
0
        OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
420
0
        xmlChar const*const pName =
421
0
            reinterpret_cast<xmlChar const*>(o1.getStr());
422
0
        xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
423
0
        if (0 == xmlUnsetProp(m_aNodePtr, pName)) {
424
0
            ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
425
0
                    reinterpret_cast<xmlNodePtr>(pAttr), false));
426
0
            if (pCNode.is()) {
427
0
                pCNode->invalidate(); // freed by xmlUnsetProp
428
0
            }
429
0
        }
430
0
    }
431
432
    /**
433
    Removes an attribute by local name and namespace URI.
434
    */
435
    void SAL_CALL CElement::removeAttributeNS(
436
            OUString const& namespaceURI, OUString const& localName)
437
0
    {
438
0
        ::osl::MutexGuard const g(m_rMutex);
439
440
0
        if (nullptr == m_aNodePtr) {
441
0
            return;
442
0
        }
443
0
        OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
444
0
        xmlChar const*const pName =
445
0
            reinterpret_cast<xmlChar const*>(o1.getStr());
446
0
        OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
447
0
        xmlChar const*const pURI =
448
0
            reinterpret_cast<xmlChar const*>(o2.getStr());
449
0
        xmlNsPtr const pNs =
450
0
            xmlSearchNsByHref(m_aNodePtr->doc, m_aNodePtr, pURI);
451
0
        xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pURI);
452
0
        if (0 == xmlUnsetNsProp(m_aNodePtr, pNs, pName)) {
453
0
            ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
454
0
                    reinterpret_cast<xmlNodePtr>(pAttr), false));
455
0
            if (pCNode.is()) {
456
0
                pCNode->invalidate(); // freed by xmlUnsetNsProp
457
0
            }
458
0
        }
459
0
    }
460
461
    /**
462
    Removes the specified attribute node.
463
    */
464
    Reference< XAttr > SAL_CALL
465
    CElement::removeAttributeNode(Reference< XAttr > const& oldAttr)
466
0
    {
467
0
        ::osl::MutexGuard const g(m_rMutex);
468
469
0
        if (nullptr == m_aNodePtr) {
470
0
            return nullptr;
471
0
        }
472
473
0
        ::rtl::Reference<CNode> const pCNode(
474
0
            dynamic_cast<CNode*>(oldAttr.get()));
475
0
        if (!pCNode.is()) { throw RuntimeException(); }
476
477
0
        xmlNodePtr const pNode = pCNode->GetNodePtr();
478
0
        xmlAttrPtr const pAttr = reinterpret_cast<xmlAttrPtr>(pNode);
479
0
        if (!pAttr) { throw RuntimeException(); }
480
481
0
        if (pAttr->parent != m_aNodePtr)
482
0
        {
483
0
            DOMException e;
484
0
            e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
485
0
            throw e;
486
0
        }
487
0
        if (pAttr->doc != m_aNodePtr->doc)
488
0
        {
489
0
            DOMException e;
490
0
            e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
491
0
            throw e;
492
0
        }
493
494
0
        Reference< XAttr > aAttr;
495
0
        if (!oldAttr->getNamespaceURI().isEmpty()) {
496
0
            OUStringBuffer qname(oldAttr->getPrefix());
497
0
            if (!qname.isEmpty()) {
498
0
                qname.append(':');
499
0
            }
500
0
            qname.append(oldAttr->getName());
501
0
            aAttr = GetOwnerDocument().createAttributeNS(
502
0
                oldAttr->getNamespaceURI(), qname.makeStringAndClear());
503
0
        } else {
504
0
            aAttr = GetOwnerDocument().createAttribute(oldAttr->getName());
505
0
        }
506
0
        aAttr->setValue(oldAttr->getValue());
507
0
        xmlRemoveProp(pAttr);
508
0
        pCNode->invalidate(); // freed by xmlRemoveProp
509
510
0
        return aAttr;
511
0
    }
512
513
    /**
514
    Adds a new attribute node.
515
    */
516
    Reference< XAttr >
517
    CElement::setAttributeNode_Impl_Lock(
518
            Reference< XAttr > const& xNewAttr, bool const bNS)
519
0
    {
520
0
        if (xNewAttr->getOwnerDocument() != getOwnerDocument()) {
521
0
            DOMException e;
522
0
            e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
523
0
            throw e;
524
0
        }
525
526
0
        ::osl::ClearableMutexGuard guard(m_rMutex);
527
528
0
        if (nullptr == m_aNodePtr) {
529
0
            throw RuntimeException();
530
0
        }
531
532
        // get the implementation
533
0
        CAttr *const pCAttr = dynamic_cast<CAttr*>(xNewAttr.get());
534
0
        if (!pCAttr) { throw RuntimeException(); }
535
0
        xmlAttrPtr const pAttr =
536
0
            reinterpret_cast<xmlAttrPtr>(pCAttr->GetNodePtr());
537
0
        if (!pAttr) { throw RuntimeException(); }
538
539
        // check whether the attribute is not in use by another element
540
0
        if (pAttr->parent) {
541
0
            DOMException e;
542
0
            e.Code = DOMExceptionType_INUSE_ATTRIBUTE_ERR;
543
0
            throw e;
544
0
        }
545
546
0
        xmlAttrPtr res = nullptr;
547
0
        xmlChar const*const pContent(
548
0
                (pAttr->children) ? pAttr->children->content : nullptr);
549
550
0
        if (bNS) {
551
0
            xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) );
552
0
            res = xmlNewNsProp(m_aNodePtr, pNs, pAttr->name, pContent);
553
0
        } else {
554
0
            res = xmlNewProp(m_aNodePtr, pAttr->name, pContent);
555
0
        }
556
557
        // get the new attr node
558
0
        Reference< XAttr > const xAttr(
559
0
            static_cast< XNode* >(GetOwnerDocument().GetCNode(
560
0
                    reinterpret_cast<xmlNodePtr>(res)).get()),
561
0
            UNO_QUERY_THROW);
562
563
        // attribute addition event
564
        // dispatch DOMAttrModified event
565
0
        Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
566
0
        Reference< XMutationEvent > event(docevent->createEvent(
567
0
            u"DOMAttrModified"_ustr), UNO_QUERY);
568
0
        event->initMutationEvent(u"DOMAttrModified"_ustr,
569
0
            true, false, xAttr,
570
0
            OUString(), xAttr->getValue(), xAttr->getName(),
571
0
            AttrChangeType_ADDITION);
572
573
0
        guard.clear(); // release mutex before calling event handlers
574
575
0
        dispatchEvent(event);
576
0
        dispatchSubtreeModified();
577
578
0
        return xAttr;
579
0
    }
580
581
    Reference< XAttr >
582
    CElement::setAttributeNode(const Reference< XAttr >& newAttr)
583
0
    {
584
0
        return setAttributeNode_Impl_Lock(newAttr, false);
585
0
    }
586
587
    /**
588
    Adds a new attribute.
589
    */
590
    Reference< XAttr >
591
    CElement::setAttributeNodeNS(const Reference< XAttr >& newAttr)
592
0
    {
593
0
        return setAttributeNode_Impl_Lock(newAttr, true);
594
0
    }
595
596
    /**
597
    Adds a new attribute.
598
    */
599
    void SAL_CALL
600
    CElement::setAttribute(OUString const& name, OUString const& value)
601
11.1k
    {
602
11.1k
        ::osl::ClearableMutexGuard guard(m_rMutex);
603
604
11.1k
        OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
605
11.1k
        xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
606
11.1k
        OString o2 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
607
11.1k
        xmlChar const *pValue = reinterpret_cast<xmlChar const *>(o2.getStr());
608
609
11.1k
        if (nullptr == m_aNodePtr) {
610
0
            throw RuntimeException();
611
0
        }
612
11.1k
        OUString oldValue;
613
11.1k
        AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
614
11.1k
        std::shared_ptr<xmlChar const> const pOld(
615
11.1k
            xmlGetProp(m_aNodePtr, pName), xmlFree);
616
11.1k
        if (pOld == nullptr) {
617
11.1k
            aChangeType = AttrChangeType_ADDITION;
618
11.1k
            xmlNewProp(m_aNodePtr, pName, pValue);
619
11.1k
        } else {
620
52
            oldValue = OUString(reinterpret_cast<char const*>(pOld.get()),
621
52
                        strlen(reinterpret_cast<char const*>(pOld.get())),
622
52
                        RTL_TEXTENCODING_UTF8);
623
52
            xmlSetProp(m_aNodePtr, pName, pValue);
624
52
        }
625
626
11.1k
        CDocument& rDocument(GetOwnerDocument());
627
11.1k
        if (rDocument.GetEventDispatcher().hasListeners())
628
0
        {
629
            // dispatch DOMAttrModified event
630
0
            Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
631
0
            Reference< XMutationEvent > event(docevent->createEvent(
632
0
                u"DOMAttrModified"_ustr), UNO_QUERY);
633
0
            event->initMutationEvent(u"DOMAttrModified"_ustr,
634
0
                true, false,
635
0
                getAttributeNode(name),
636
0
                oldValue, value, name, aChangeType);
637
638
0
            guard.clear(); // release mutex before calling event handlers
639
0
            dispatchEvent(event);
640
0
            dispatchSubtreeModified();
641
0
        }
642
11.1k
    }
643
644
    /**
645
    Adds a new attribute.
646
    */
647
    void SAL_CALL
648
    CElement::setAttributeNS(OUString const& namespaceURI,
649
            OUString const& qualifiedName, OUString const& value)
650
216k
    {
651
216k
        if (namespaceURI.isEmpty()) throw RuntimeException();
652
653
216k
        ::osl::ClearableMutexGuard guard(m_rMutex);
654
655
216k
        OString o1, o2, o3, o4, o5;
656
216k
        xmlChar const *pPrefix = nullptr;
657
216k
        xmlChar const *pLName = nullptr;
658
216k
        o1 = OUStringToOString(qualifiedName, RTL_TEXTENCODING_UTF8);
659
216k
        xmlChar const *pQName = reinterpret_cast<xmlChar const *>(o1.getStr());
660
216k
        sal_Int32 idx = qualifiedName.indexOf(':');
661
216k
        if (idx != -1)
662
216k
        {
663
216k
            o2 = OUStringToOString(
664
216k
                qualifiedName.subView(0,idx),
665
216k
                RTL_TEXTENCODING_UTF8);
666
216k
            pPrefix = reinterpret_cast<xmlChar const *>(o2.getStr());
667
216k
            o3 = OUStringToOString(
668
216k
                qualifiedName.subView(idx+1),
669
216k
                RTL_TEXTENCODING_UTF8);
670
216k
            pLName = reinterpret_cast<xmlChar const *>(o3.getStr());
671
216k
        }  else {
672
0
            pPrefix = reinterpret_cast<xmlChar const *>("");
673
0
            pLName = pQName;
674
0
        }
675
216k
        o4 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
676
216k
        o5 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
677
216k
        xmlChar const *pURI= reinterpret_cast<xmlChar const *>(o4.getStr());
678
216k
        xmlChar const *pValue = reinterpret_cast<xmlChar const *>(o5.getStr());
679
680
216k
        if (nullptr == m_aNodePtr) {
681
0
            throw RuntimeException();
682
0
        }
683
684
        //find the right namespace
685
216k
        xmlNsPtr pNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, pPrefix);
686
        // if no namespace found, create a new one
687
216k
        if (pNs == nullptr) {
688
3.04k
            pNs = xmlNewNs(m_aNodePtr, pURI, pPrefix);
689
3.04k
        }
690
691
216k
        if (strcmp(reinterpret_cast<char const *>(pNs->href), reinterpret_cast<char const *>(pURI)) != 0) {
692
            // ambiguous ns prefix
693
95
            throw RuntimeException();
694
95
        }
695
696
        // found namespace matches
697
698
215k
        OUString oldValue;
699
215k
        AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
700
215k
        std::shared_ptr<xmlChar const> const pOld(
701
215k
                xmlGetNsProp(m_aNodePtr, pLName, pNs->href), xmlFree);
702
215k
        if (pOld == nullptr) {
703
215k
            aChangeType = AttrChangeType_ADDITION;
704
215k
            xmlNewNsProp(m_aNodePtr, pNs, pLName, pValue);
705
215k
        } else {
706
0
            oldValue = OUString(reinterpret_cast<char const*>(pOld.get()),
707
0
                        strlen(reinterpret_cast<char const*>(pOld.get())),
708
0
                        RTL_TEXTENCODING_UTF8);
709
0
            xmlSetNsProp(m_aNodePtr, pNs, pLName, pValue);
710
0
        }
711
712
215k
        CDocument& rDocument(GetOwnerDocument());
713
215k
        if (rDocument.GetEventDispatcher().hasListeners())
714
0
        {
715
            // dispatch DOMAttrModified event
716
0
            Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
717
0
            Reference< XMutationEvent > event(docevent->createEvent(
718
0
                u"DOMAttrModified"_ustr), UNO_QUERY);
719
0
            event->initMutationEvent(
720
0
                u"DOMAttrModified"_ustr, true, false,
721
0
                getAttributeNodeNS(namespaceURI, OUString(reinterpret_cast<char const *>(pLName), strlen(reinterpret_cast<char const *>(pLName)), RTL_TEXTENCODING_UTF8)),
722
0
                oldValue, value, qualifiedName, aChangeType);
723
724
0
            guard.clear(); // release mutex before calling event handlers
725
0
            dispatchEvent(event);
726
0
            dispatchSubtreeModified();
727
0
        }
728
215k
    }
729
730
    Reference< XNamedNodeMap > SAL_CALL
731
    CElement::getAttributes()
732
0
    {
733
0
        ::osl::MutexGuard const g(m_rMutex);
734
735
0
        Reference< XNamedNodeMap > const xMap(
736
0
                new CAttributesMap(this, m_rMutex));
737
0
        return xMap;
738
0
    }
739
740
    OUString SAL_CALL CElement::getNodeName()
741
1.14M
    {
742
1.14M
        return getLocalName();
743
1.14M
    }
744
745
    OUString SAL_CALL CElement::getLocalName()
746
1.14M
    {
747
1.14M
        ::osl::MutexGuard const g(m_rMutex);
748
749
1.14M
        OUString aName;
750
1.14M
        if (m_aNodePtr != nullptr)
751
1.14M
        {
752
1.14M
            const xmlChar* pName = m_aNodePtr->name;
753
1.14M
            aName = OUString(reinterpret_cast<const char*>(pName), strlen(reinterpret_cast<const char*>(pName)), RTL_TEXTENCODING_UTF8);
754
1.14M
        }
755
1.14M
        return aName;
756
1.14M
    }
757
758
    OUString SAL_CALL CElement::getNodeValue()
759
0
    {
760
0
        return OUString();
761
0
    }
762
}
763
764
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */