/src/libreoffice/unoxml/source/dom/attr.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 "attr.hxx" |
21 | | |
22 | | #include <string.h> |
23 | | |
24 | | #include <memory> |
25 | | #include <libxml/entities.h> |
26 | | |
27 | | #include <osl/diagnose.h> |
28 | | #include <sal/log.hxx> |
29 | | |
30 | | #include <com/sun/star/xml/dom/events/XMutationEvent.hpp> |
31 | | |
32 | | #include "document.hxx" |
33 | | |
34 | | using namespace css::uno; |
35 | | using namespace css::xml::dom; |
36 | | using namespace css::xml::dom::events; |
37 | | |
38 | | namespace DOM |
39 | | { |
40 | | CAttr::CAttr(CDocument const& rDocument, ::osl::Mutex const& rMutex, |
41 | | xmlAttrPtr const pAttr) |
42 | 710k | : CAttr_Base(rDocument, rMutex, |
43 | 710k | NodeType_ATTRIBUTE_NODE, reinterpret_cast<xmlNodePtr>(pAttr)) |
44 | 710k | , m_aAttrPtr(pAttr) |
45 | 710k | { |
46 | 710k | } |
47 | | |
48 | | xmlNsPtr CAttr::GetNamespace(xmlNodePtr const pNode) |
49 | 0 | { |
50 | 0 | if (!m_oNamespace) |
51 | 0 | { |
52 | 0 | return nullptr; |
53 | 0 | } |
54 | 0 | xmlChar const*const pUri(reinterpret_cast<xmlChar const*>( |
55 | 0 | m_oNamespace->first.getStr())); |
56 | 0 | xmlChar const*const pPrefix(reinterpret_cast<xmlChar const*>( |
57 | 0 | m_oNamespace->second.getStr())); |
58 | 0 | xmlNsPtr pNs = xmlSearchNs(pNode->doc, pNode, pPrefix); |
59 | 0 | if (pNs && (0 != xmlStrcmp(pNs->href, pUri))) { |
60 | 0 | return pNs; |
61 | 0 | } |
62 | 0 | pNs = xmlNewNs(pNode, pUri, pPrefix); |
63 | 0 | if (pNs) { |
64 | 0 | return pNs; |
65 | 0 | } |
66 | 0 | pNs = xmlSearchNsByHref(pNode->doc, pNode, pUri); |
67 | | // if (!pNs) hmm... now what? throw? |
68 | 0 | if (!pNs) { |
69 | 0 | SAL_WARN("unoxml", "CAttr: cannot create namespace"); |
70 | 0 | } |
71 | 0 | return pNs; |
72 | 0 | } |
73 | | |
74 | | bool CAttr::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const) |
75 | 0 | { |
76 | 0 | switch (nodeType) { |
77 | 0 | case NodeType_TEXT_NODE: |
78 | 0 | case NodeType_ENTITY_REFERENCE_NODE: |
79 | 0 | return true; |
80 | 0 | default: |
81 | 0 | return false; |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | | OUString SAL_CALL CAttr::getNodeName() |
86 | 0 | { |
87 | 0 | return getName(); |
88 | 0 | } |
89 | | OUString SAL_CALL CAttr::getNodeValue() |
90 | 710k | { |
91 | 710k | return getValue(); |
92 | 710k | } |
93 | | OUString SAL_CALL CAttr::getLocalName() |
94 | 46 | { |
95 | 46 | return getName(); |
96 | 46 | } |
97 | | |
98 | | |
99 | | /** |
100 | | Returns the name of this attribute. |
101 | | */ |
102 | | OUString SAL_CALL CAttr::getName() |
103 | 46 | { |
104 | 46 | ::osl::MutexGuard const g(m_rMutex); |
105 | | |
106 | 46 | if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) { |
107 | 0 | return OUString(); |
108 | 0 | } |
109 | 46 | OUString const aName(reinterpret_cast<char const *>(m_aAttrPtr->name), |
110 | 46 | strlen(reinterpret_cast<char const *>(m_aAttrPtr->name)), RTL_TEXTENCODING_UTF8); |
111 | 46 | return aName; |
112 | 46 | } |
113 | | |
114 | | /** |
115 | | The Element node this attribute is attached to or null if this |
116 | | attribute is not in use. |
117 | | */ |
118 | | Reference< XElement > SAL_CALL CAttr::getOwnerElement() |
119 | 0 | { |
120 | 0 | ::osl::MutexGuard const g(m_rMutex); |
121 | |
|
122 | 0 | if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) { |
123 | 0 | return nullptr; |
124 | 0 | } |
125 | 0 | if (nullptr == m_aAttrPtr->parent) { |
126 | 0 | return nullptr; |
127 | 0 | } |
128 | 0 | Reference< XElement > const xRet( |
129 | 0 | static_cast< XNode* >(GetOwnerDocument().GetCNode( |
130 | 0 | m_aAttrPtr->parent).get()), |
131 | 0 | UNO_QUERY_THROW); |
132 | 0 | return xRet; |
133 | 0 | } |
134 | | |
135 | | /** |
136 | | If this attribute was explicitly given a value in the original |
137 | | document, this is true; otherwise, it is false. |
138 | | */ |
139 | | sal_Bool SAL_CALL CAttr::getSpecified() |
140 | 0 | { |
141 | | // FIXME if this DOM implementation supported DTDs it would need |
142 | | // to check that this attribute is not default or something |
143 | 0 | return true; |
144 | 0 | } |
145 | | |
146 | | /** |
147 | | On retrieval, the value of the attribute is returned as a string. |
148 | | */ |
149 | | OUString SAL_CALL CAttr::getValue() |
150 | 710k | { |
151 | 710k | ::osl::MutexGuard const g(m_rMutex); |
152 | | |
153 | 710k | if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) { |
154 | 0 | return OUString(); |
155 | 0 | } |
156 | 710k | if (nullptr == m_aAttrPtr->children) { |
157 | 0 | return OUString(); |
158 | 0 | } |
159 | 710k | char const*const pContent(reinterpret_cast<char const*>(m_aAttrPtr->children->content)); |
160 | 710k | return OUString(pContent, strlen(pContent), RTL_TEXTENCODING_UTF8); |
161 | 710k | } |
162 | | |
163 | | /** |
164 | | Sets the value of the attribute from a string. |
165 | | */ |
166 | | void SAL_CALL CAttr::setValue(const OUString& value) |
167 | 0 | { |
168 | 0 | ::osl::ClearableMutexGuard guard(m_rMutex); |
169 | |
|
170 | 0 | if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) { |
171 | 0 | return; |
172 | 0 | } |
173 | | |
174 | | // remember old value (for mutation event) |
175 | 0 | OUString sOldValue = getValue(); |
176 | |
|
177 | 0 | OString o1 = OUStringToOString(value, RTL_TEXTENCODING_UTF8); |
178 | 0 | xmlChar const * pValue = reinterpret_cast<xmlChar const *>(o1.getStr()); |
179 | | // this does not work if the attribute was created anew |
180 | | // xmlNodePtr pNode = m_aAttrPtr->parent; |
181 | | // xmlSetProp(pNode, m_aAttrPtr->name, pValue); |
182 | 0 | std::shared_ptr<xmlChar const> const buffer( |
183 | 0 | xmlEncodeEntitiesReentrant(m_aAttrPtr->doc, pValue), xmlFree); |
184 | 0 | xmlFreeNodeList(m_aAttrPtr->children); |
185 | 0 | m_aAttrPtr->children = |
186 | 0 | xmlStringGetNodeList(m_aAttrPtr->doc, buffer.get()); |
187 | 0 | xmlNodePtr tmp = m_aAttrPtr->children; |
188 | 0 | while (tmp != nullptr) { |
189 | 0 | tmp->parent = m_aNodePtr; |
190 | 0 | tmp->doc = m_aAttrPtr->doc; |
191 | 0 | if (tmp->next == nullptr) |
192 | 0 | m_aNodePtr->last = tmp; |
193 | 0 | tmp = tmp->next; |
194 | 0 | } |
195 | | |
196 | | // dispatch DOM events to signal change in attribute value |
197 | | // dispatch DomAttrModified + DOMSubtreeModified |
198 | 0 | OUString sEventName( u"DOMAttrModified"_ustr ); |
199 | 0 | Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); |
200 | 0 | Reference< XMutationEvent > event(docevent->createEvent(sEventName),UNO_QUERY); |
201 | 0 | event->initMutationEvent( |
202 | 0 | sEventName, true, false, |
203 | 0 | Reference<XNode>( static_cast<XAttr*>( this ) ), |
204 | 0 | sOldValue, value, getName(), AttrChangeType_MODIFICATION ); |
205 | |
|
206 | 0 | guard.clear(); // release mutex before calling event handlers |
207 | |
|
208 | 0 | dispatchEvent(event); |
209 | 0 | dispatchSubtreeModified(); |
210 | 0 | } |
211 | | |
212 | | void SAL_CALL CAttr::setPrefix(const OUString& prefix) |
213 | 0 | { |
214 | 0 | ::osl::MutexGuard const g(m_rMutex); |
215 | |
|
216 | 0 | if (!m_aNodePtr) { return; } |
217 | | |
218 | 0 | if (m_oNamespace) |
219 | 0 | { |
220 | 0 | OSL_ASSERT(!m_aNodePtr->parent); |
221 | 0 | m_oNamespace->second = |
222 | 0 | OUStringToOString(prefix, RTL_TEXTENCODING_UTF8); |
223 | 0 | } |
224 | 0 | else |
225 | 0 | { |
226 | 0 | CNode::setPrefix(prefix); |
227 | 0 | } |
228 | 0 | } |
229 | | |
230 | | OUString SAL_CALL CAttr::getPrefix() |
231 | 46 | { |
232 | 46 | ::osl::MutexGuard const g(m_rMutex); |
233 | | |
234 | 46 | if (!m_aNodePtr) { return OUString(); } |
235 | | |
236 | 46 | if (m_oNamespace) |
237 | 0 | { |
238 | 0 | OSL_ASSERT(!m_aNodePtr->parent); |
239 | 0 | OUString const ret(OStringToOUString( |
240 | 0 | m_oNamespace->second, RTL_TEXTENCODING_UTF8)); |
241 | 0 | return ret; |
242 | 0 | } |
243 | 46 | else |
244 | 46 | { |
245 | 46 | return CNode::getPrefix(); |
246 | 46 | } |
247 | 46 | } |
248 | | |
249 | | OUString SAL_CALL CAttr::getNamespaceURI() |
250 | 0 | { |
251 | 0 | ::osl::MutexGuard const g(m_rMutex); |
252 | |
|
253 | 0 | if (!m_aNodePtr) { return OUString(); } |
254 | | |
255 | 0 | if (m_oNamespace) |
256 | 0 | { |
257 | 0 | OSL_ASSERT(!m_aNodePtr->parent); |
258 | 0 | OUString const ret(OStringToOUString( |
259 | 0 | m_oNamespace->first, RTL_TEXTENCODING_UTF8)); |
260 | 0 | return ret; |
261 | 0 | } |
262 | 0 | else |
263 | 0 | { |
264 | 0 | return CNode::getNamespaceURI(); |
265 | 0 | } |
266 | 0 | } |
267 | | } |
268 | | |
269 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |