Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/unoxml/source/dom/elementlist.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 "elementlist.hxx"
21
22
#include <string.h>
23
#include <string_view>
24
25
#include <cppuhelper/implbase.hxx>
26
#include <o3tl/safeint.hxx>
27
#include <utility>
28
#include <comphelper/diagnose_ex.hxx>
29
#include <unotools/weakref.hxx>
30
31
#include "element.hxx"
32
#include "document.hxx"
33
34
using namespace css::uno;
35
using namespace css::xml::dom;
36
using namespace css::xml::dom::events;
37
namespace DOM { class CElementListImpl; }
38
39
namespace DOM
40
{
41
    class WeakEventListener : public ::cppu::WeakImplHelper<css::xml::dom::events::XEventListener>
42
    {
43
    private:
44
        unotools::WeakReference<DOM::CElementListImpl> mxOwner;
45
46
    public:
47
        explicit WeakEventListener(const rtl::Reference<DOM::CElementListImpl>& rOwner)
48
0
            : mxOwner(rOwner)
49
0
        {
50
0
        }
51
52
        virtual void SAL_CALL handleEvent(const css::uno::Reference<css::xml::dom::events::XEvent>& rEvent) override
53
0
        {
54
0
            rtl::Reference<DOM::CElementListImpl> xOwner(mxOwner);
55
0
            if (xOwner)
56
0
                xOwner->handleEvent(rEvent);
57
0
        }
58
    };
59
}
60
61
namespace DOM
62
{
63
64
    static xmlChar* lcl_initXmlString(std::u16string_view rString)
65
0
    {
66
0
        OString const os =
67
0
            OUStringToOString(rString, RTL_TEXTENCODING_UTF8);
68
0
        xmlChar *const pRet = new xmlChar[os.getLength() + 1];
69
0
        strcpy(reinterpret_cast<char*>(pRet), os.getStr());
70
0
        return pRet;
71
0
    }
72
73
    CElementList::CElementList(::rtl::Reference<CElement> const& pElement,
74
            ::osl::Mutex & rMutex,
75
            std::u16string_view rName, OUString const*const pURI)
76
0
        : m_xImpl(new CElementListImpl(pElement, rMutex, rName, pURI))
77
0
    {
78
0
        if (pElement.is()) {
79
0
            m_xImpl->registerListener(*pElement);
80
0
        }
81
0
    }
82
83
    CElementListImpl::CElementListImpl(::rtl::Reference<CElement> pElement,
84
            ::osl::Mutex & rMutex,
85
            std::u16string_view rName, OUString const*const pURI)
86
0
        : m_pElement(std::move(pElement))
87
0
        , m_rMutex(rMutex)
88
0
        , m_pName(lcl_initXmlString(rName))
89
0
        , m_pURI(pURI ? lcl_initXmlString(*pURI) : nullptr)
90
0
        , m_bRebuild(true)
91
0
    {
92
0
    }
93
94
    CElementListImpl::~CElementListImpl()
95
0
    {
96
0
        if (m_xEventListener.is() && m_pElement.is())
97
0
            m_pElement->removeEventListener(u"DOMSubtreeModified"_ustr, m_xEventListener, false/*capture*/);
98
0
    }
99
100
    void CElementListImpl::registerListener(CElement & rElement)
101
0
    {
102
0
        try {
103
0
            Reference< XEventTarget > const xTarget(
104
0
                    static_cast<XElement*>(& rElement), UNO_QUERY_THROW);
105
0
            m_xEventListener = new WeakEventListener(this);
106
0
            xTarget->addEventListener(u"DOMSubtreeModified"_ustr, m_xEventListener, false/*capture*/);
107
0
        } catch (const Exception &){
108
0
            TOOLS_WARN_EXCEPTION( "unoxml", "Exception caught while registering NodeList as listener");
109
0
        }
110
0
    }
111
112
    void CElementListImpl::buildlist(xmlNodePtr pNode, bool start)
113
0
    {
114
        // bail out if no rebuild is needed
115
0
        if (start) {
116
0
            if (!m_bRebuild)
117
0
            {
118
0
                return;
119
0
            } else {
120
0
                m_nodevector.clear();
121
0
                m_bRebuild = false; // don't rebuild until tree is mutated
122
0
            }
123
0
        }
124
125
0
        while (pNode != nullptr )
126
0
        {
127
0
            if (pNode->type == XML_ELEMENT_NODE &&
128
0
                (strcmp(reinterpret_cast<char const *>(pNode->name), reinterpret_cast<char*>(m_pName.get())) == 0))
129
0
            {
130
0
                if (!m_pURI) {
131
0
                    m_nodevector.push_back(pNode);
132
0
                } else {
133
0
                    if (pNode->ns != nullptr && (0 ==
134
0
                         strcmp(reinterpret_cast<char const *>(pNode->ns->href), reinterpret_cast<char*>(m_pURI.get()))))
135
0
                    {
136
0
                        m_nodevector.push_back(pNode);
137
0
                    }
138
0
                }
139
0
            }
140
0
            if (pNode->children != nullptr) buildlist(pNode->children, false);
141
142
0
            if (!start) pNode = pNode->next;
143
0
            else break; // fold back
144
0
        }
145
0
    }
146
147
    /**
148
    The number of nodes in the list.
149
    */
150
    sal_Int32 SAL_CALL CElementListImpl::getLength()
151
0
    {
152
0
        ::osl::MutexGuard const g(m_rMutex);
153
154
0
        if (!m_pElement.is()) { return 0; }
155
156
        // this has to be 'live'
157
0
        buildlist(m_pElement->GetNodePtr());
158
0
        return m_nodevector.size();
159
0
    }
160
    /**
161
    Returns the indexth item in the collection.
162
    */
163
    Reference< XNode > SAL_CALL CElementListImpl::item(sal_Int32 index)
164
0
    {
165
0
        if (index < 0) throw RuntimeException();
166
167
0
        ::osl::MutexGuard const g(m_rMutex);
168
169
0
        if (!m_pElement.is()) { return nullptr; }
170
171
0
        buildlist(m_pElement->GetNodePtr());
172
0
        if (m_nodevector.size() <= o3tl::make_unsigned(index)) {
173
0
            throw RuntimeException();
174
0
        }
175
0
        return m_pElement->GetOwnerDocument().GetCNode(m_nodevector[index]);
176
0
    }
177
178
    // tree mutations can change the list
179
    void SAL_CALL CElementListImpl::handleEvent(Reference< XEvent > const&)
180
0
    {
181
0
        ::osl::MutexGuard const g(m_rMutex);
182
183
0
        m_bRebuild = true;
184
0
    }
185
}
186
187
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */