/src/libreoffice/unoxml/source/dom/saxbuilder.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 "saxbuilder.hxx" |
21 | | |
22 | | #include <com/sun/star/xml/dom/DocumentBuilder.hpp> |
23 | | #include <com/sun/star/xml/sax/SAXException.hpp> |
24 | | #include <cppuhelper/supportsservice.hxx> |
25 | | #include <sax/fastattribs.hxx> |
26 | | #include <xmloff/xmlimp.hxx> |
27 | | |
28 | | using namespace css::lang; |
29 | | using namespace css::uno; |
30 | | using namespace css::xml::dom; |
31 | | using namespace css::xml::sax; |
32 | | |
33 | | namespace DOM |
34 | | { |
35 | | CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference< XComponentContext >& ctx) |
36 | 18.1k | : m_xContext(ctx) |
37 | 18.1k | , m_aState( SAXDocumentBuilderState_READY) |
38 | 18.1k | {} |
39 | | |
40 | | Sequence< OUString > SAL_CALL CSAXDocumentBuilder::getSupportedServiceNames() |
41 | 0 | { |
42 | 0 | return { u"com.sun.star.xml.dom.SAXDocumentBuilder"_ustr }; |
43 | 0 | } |
44 | | |
45 | | OUString SAL_CALL CSAXDocumentBuilder::getImplementationName() |
46 | 0 | { |
47 | 0 | return u"com.sun.star.comp.xml.dom.SAXDocumentBuilder"_ustr; |
48 | 0 | } |
49 | | |
50 | | sal_Bool SAL_CALL CSAXDocumentBuilder::supportsService(const OUString& aServiceName) |
51 | 0 | { |
52 | 0 | return cppu::supportsService(this, aServiceName); |
53 | 0 | } |
54 | | |
55 | | SAXDocumentBuilderState SAL_CALL CSAXDocumentBuilder::getState() |
56 | 0 | { |
57 | 0 | std::scoped_lock g(m_Mutex); |
58 | |
|
59 | 0 | return m_aState; |
60 | 0 | } |
61 | | |
62 | | void SAL_CALL CSAXDocumentBuilder::reset() |
63 | 0 | { |
64 | 0 | std::scoped_lock g(m_Mutex); |
65 | |
|
66 | 0 | m_aDocument.clear(); |
67 | 0 | m_aFragment.clear(); |
68 | 0 | while (!m_aNodeStack.empty()) m_aNodeStack.pop(); |
69 | 0 | m_aState = SAXDocumentBuilderState_READY; |
70 | 0 | } |
71 | | |
72 | | Reference< XDocument > SAL_CALL CSAXDocumentBuilder::getDocument() |
73 | 6.36k | { |
74 | 6.36k | std::scoped_lock g(m_Mutex); |
75 | | |
76 | 6.36k | if (m_aState != SAXDocumentBuilderState_DOCUMENT_FINISHED) |
77 | 0 | throw RuntimeException(); |
78 | | |
79 | 6.36k | return m_aDocument; |
80 | 6.36k | } |
81 | | |
82 | | Reference< XDocumentFragment > SAL_CALL CSAXDocumentBuilder::getDocumentFragment() |
83 | 0 | { |
84 | 0 | std::scoped_lock g(m_Mutex); |
85 | |
|
86 | 0 | if (m_aState != SAXDocumentBuilderState_FRAGMENT_FINISHED) |
87 | 0 | throw RuntimeException(); |
88 | 0 | return m_aFragment; |
89 | 0 | } |
90 | | |
91 | | void SAL_CALL CSAXDocumentBuilder::startDocumentFragment(const Reference< XDocument >& ownerDoc) |
92 | 0 | { |
93 | 0 | std::scoped_lock g(m_Mutex); |
94 | | |
95 | | // start a new document fragment and push it onto the stack |
96 | | // we have to be in a clean state to do this |
97 | 0 | if (m_aState != SAXDocumentBuilderState_READY) |
98 | 0 | throw RuntimeException(); |
99 | | |
100 | 0 | m_aDocument = ownerDoc; |
101 | 0 | Reference< XDocumentFragment > aFragment = m_aDocument->createDocumentFragment(); |
102 | 0 | m_aNodeStack.push(aFragment); |
103 | 0 | m_aFragment = std::move(aFragment); |
104 | 0 | m_aState = SAXDocumentBuilderState_BUILDING_FRAGMENT; |
105 | 0 | } |
106 | | |
107 | | void SAL_CALL CSAXDocumentBuilder::endDocumentFragment() |
108 | 0 | { |
109 | 0 | std::scoped_lock g(m_Mutex); |
110 | | |
111 | | // there should only be the document left on the node stack |
112 | 0 | if (m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
113 | 0 | throw RuntimeException(); |
114 | | |
115 | 0 | Reference< XNode > aNode = m_aNodeStack.top(); |
116 | 0 | if ( aNode->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE) |
117 | 0 | throw RuntimeException(); |
118 | 0 | m_aNodeStack.pop(); |
119 | 0 | m_aState = SAXDocumentBuilderState_FRAGMENT_FINISHED; |
120 | 0 | } |
121 | | |
122 | | //XFastDocumentHandler |
123 | | void SAL_CALL CSAXDocumentBuilder::startDocument() |
124 | 18.1k | { |
125 | 18.1k | std::scoped_lock g(m_Mutex); |
126 | | |
127 | | // start a new document and push it onto the stack |
128 | | // we have to be in a clean state to do this |
129 | 18.1k | if (m_aState != SAXDocumentBuilderState_READY) |
130 | 0 | throw SAXException(); |
131 | | |
132 | 18.1k | Reference< XDocumentBuilder > aBuilder(DocumentBuilder::create(m_xContext)); |
133 | 18.1k | Reference< XDocument > aDocument = aBuilder->newDocument(); |
134 | 18.1k | m_aNodeStack.push(aDocument); |
135 | 18.1k | m_aDocument = std::move(aDocument); |
136 | 18.1k | m_aState = SAXDocumentBuilderState_BUILDING_DOCUMENT; |
137 | 18.1k | } |
138 | | |
139 | | void SAL_CALL CSAXDocumentBuilder::endDocument() |
140 | 6.36k | { |
141 | 6.36k | std::scoped_lock g(m_Mutex); |
142 | | |
143 | | // there should only be the document left on the node stack |
144 | 6.36k | if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT) |
145 | 0 | throw SAXException(); |
146 | | |
147 | 6.36k | Reference< XNode > aNode = m_aNodeStack.top(); |
148 | 6.36k | if ( aNode->getNodeType() != NodeType_DOCUMENT_NODE) |
149 | 0 | throw SAXException(); |
150 | 6.36k | m_aNodeStack.pop(); |
151 | 6.36k | m_aState = SAXDocumentBuilderState_DOCUMENT_FINISHED; |
152 | 6.36k | } |
153 | | |
154 | | void SAL_CALL CSAXDocumentBuilder::processingInstruction( const OUString& rTarget, const OUString& rData ) |
155 | 0 | { |
156 | 0 | std::scoped_lock g(m_Mutex); |
157 | | |
158 | | // append PI node to the current top |
159 | 0 | if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && |
160 | 0 | m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
161 | 0 | throw SAXException(); |
162 | | |
163 | 0 | Reference< XProcessingInstruction > aInstruction = m_aDocument->createProcessingInstruction( |
164 | 0 | rTarget, rData); |
165 | 0 | m_aNodeStack.top()->appendChild(aInstruction); |
166 | 0 | } |
167 | | |
168 | | void SAL_CALL CSAXDocumentBuilder::setDocumentLocator( const Reference< XLocator >& ) |
169 | 0 | { |
170 | 0 | } |
171 | | |
172 | | void SAL_CALL CSAXDocumentBuilder::startFastElement( sal_Int32 nElement , const Reference< XFastAttributeList >& xAttribs ) |
173 | 166k | { |
174 | 166k | std::scoped_lock g(m_Mutex); |
175 | | |
176 | 166k | if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && |
177 | 1.75k | m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
178 | 1.75k | { |
179 | 1.75k | throw SAXException(); |
180 | 1.75k | } |
181 | | |
182 | 164k | Reference< XElement > aElement; |
183 | 164k | const OUString aPrefix(SvXMLImport::getNamespacePrefixFromToken(nElement, nullptr)); |
184 | 164k | const OUString aURI( SvXMLImport::getNamespaceURIFromToken( nElement ) ); |
185 | 164k | OUString aQualifiedName( SvXMLImport::getNameFromToken( nElement ) ); |
186 | 164k | if( !aPrefix.isEmpty() ) |
187 | 87.2k | aQualifiedName = aPrefix + SvXMLImport::aNamespaceSeparator + aQualifiedName; |
188 | | |
189 | 164k | if ( !aURI.isEmpty() ) |
190 | 87.2k | { |
191 | | // found a URI for prefix |
192 | | // qualified name |
193 | 87.2k | aElement = m_aDocument->createElementNS( aURI, aQualifiedName ); |
194 | 87.2k | } |
195 | 77.5k | else |
196 | 77.5k | { |
197 | | // no URI for prefix |
198 | 77.5k | aElement = m_aDocument->createElement( aQualifiedName ); |
199 | 77.5k | } |
200 | 164k | aElement.set( m_aNodeStack.top()->appendChild(aElement), UNO_QUERY); |
201 | 164k | m_aNodeStack.push(aElement); |
202 | | |
203 | 164k | if (xAttribs.is()) |
204 | 164k | setElementFastAttributes(aElement, xAttribs); |
205 | 164k | } |
206 | | |
207 | | // For arbitrary meta elements |
208 | | void SAL_CALL CSAXDocumentBuilder::startUnknownElement( const OUString& rNamespace, const OUString& rName, const Reference< XFastAttributeList >& xAttribs ) |
209 | 741k | { |
210 | 741k | std::scoped_lock g(m_Mutex); |
211 | | |
212 | 741k | if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && |
213 | 0 | m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
214 | 0 | { |
215 | 0 | throw SAXException(); |
216 | 0 | } |
217 | | |
218 | 741k | Reference< XElement > aElement; |
219 | 741k | if ( !rNamespace.isEmpty() ) |
220 | 90.3k | aElement = m_aDocument->createElementNS( rNamespace, rName ); |
221 | 650k | else |
222 | 650k | aElement = m_aDocument->createElement( rName ); |
223 | | |
224 | 741k | aElement.set( m_aNodeStack.top()->appendChild(aElement), UNO_QUERY); |
225 | 741k | m_aNodeStack.push(aElement); |
226 | | |
227 | 741k | if (!xAttribs.is()) |
228 | 0 | return; |
229 | | |
230 | 741k | setElementFastAttributes(aElement, xAttribs); |
231 | 741k | const Sequence< css::xml::Attribute > unknownAttribs = xAttribs->getUnknownAttributes(); |
232 | 741k | for ( const auto& rUnknownAttrib : unknownAttribs ) |
233 | 25.5k | { |
234 | 25.5k | const OUString& rAttrValue = rUnknownAttrib.Value; |
235 | 25.5k | const OUString& rAttrName = rUnknownAttrib.Name; |
236 | 25.5k | const OUString& rAttrNamespace = rUnknownAttrib.NamespaceURL; |
237 | 25.5k | if ( !rAttrNamespace.isEmpty() ) |
238 | 12.9k | aElement->setAttributeNS( rAttrNamespace, rAttrName, rAttrValue ); |
239 | 12.5k | else |
240 | 12.5k | aElement->setAttribute( rAttrName, rAttrValue ); |
241 | 25.5k | } |
242 | 741k | } |
243 | | |
244 | | void CSAXDocumentBuilder::setElementFastAttributes(const Reference< XElement >& aElement, const Reference< XFastAttributeList >& xAttribs) |
245 | 905k | { |
246 | 905k | for (auto &it : sax_fastparser::castToFastAttributeList( xAttribs )) |
247 | 70.7k | { |
248 | 70.7k | sal_Int32 nAttrToken = it.getToken(); |
249 | 70.7k | const OUString aAttrPrefix(SvXMLImport::getNamespacePrefixFromToken(nAttrToken, nullptr)); |
250 | 70.7k | const OUString aAttrURI( SvXMLImport::getNamespaceURIFromToken( nAttrToken ) ); |
251 | 70.7k | OUString aAttrQualifiedName( SvXMLImport::getNameFromToken( nAttrToken ) ); |
252 | 70.7k | if( !aAttrPrefix.isEmpty() ) |
253 | 69.6k | aAttrQualifiedName = aAttrPrefix + SvXMLImport::aNamespaceSeparator + aAttrQualifiedName; |
254 | | |
255 | 70.7k | if ( !aAttrURI.isEmpty() ) |
256 | 69.6k | aElement->setAttributeNS( aAttrURI, aAttrQualifiedName, it.toString() ); |
257 | 1.13k | else |
258 | 1.13k | aElement->setAttribute( aAttrQualifiedName, it.toString() ); |
259 | 70.7k | } |
260 | 905k | } |
261 | | |
262 | | void SAL_CALL CSAXDocumentBuilder::endFastElement( sal_Int32 nElement ) |
263 | 70.7k | { |
264 | 70.7k | std::scoped_lock g(m_Mutex); |
265 | | |
266 | | // pop the current element from the stack |
267 | 70.7k | if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && |
268 | 0 | m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
269 | 0 | throw SAXException(); |
270 | | |
271 | 70.7k | Reference< XNode > aNode(m_aNodeStack.top()); |
272 | 70.7k | if (aNode->getNodeType() != NodeType_ELEMENT_NODE) |
273 | 0 | throw SAXException(); |
274 | | |
275 | 70.7k | Reference< XElement > aElement(aNode, UNO_QUERY); |
276 | 70.7k | if( aElement->getPrefix() != SvXMLImport::getNamespacePrefixFromToken(nElement, nullptr) || |
277 | 70.6k | aElement->getTagName() != SvXMLImport::getNameFromToken( nElement ) ) // consistency check |
278 | 71 | throw SAXException(); |
279 | | |
280 | | // pop it |
281 | 70.6k | m_aNodeStack.pop(); |
282 | 70.6k | } |
283 | | |
284 | | |
285 | | void SAL_CALL CSAXDocumentBuilder::endUnknownElement( const OUString& /*rNamespace*/, const OUString& rName ) |
286 | 73.8k | { |
287 | 73.8k | std::scoped_lock g(m_Mutex); |
288 | | |
289 | | // pop the current element from the stack |
290 | 73.8k | if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && |
291 | 0 | m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
292 | 0 | throw SAXException(); |
293 | | |
294 | 73.8k | Reference< XNode > aNode(m_aNodeStack.top()); |
295 | 73.8k | if (aNode->getNodeType() != NodeType_ELEMENT_NODE) |
296 | 0 | throw SAXException(); |
297 | | |
298 | 73.8k | Reference< XElement > aElement(aNode, UNO_QUERY); |
299 | 73.8k | OUString aRefName; |
300 | 73.8k | const OUString aPrefix = aElement->getPrefix(); |
301 | 73.8k | if (!aPrefix.isEmpty()) |
302 | 14.5k | aRefName = aPrefix + SvXMLImport::aNamespaceSeparator + aElement->getTagName(); |
303 | 59.2k | else |
304 | 59.2k | aRefName = aElement->getTagName(); |
305 | 73.8k | if (aRefName != rName) // consistency check |
306 | 15.7k | throw SAXException(); |
307 | | |
308 | | // pop it |
309 | 58.0k | m_aNodeStack.pop(); |
310 | 58.0k | } |
311 | | |
312 | | Reference< XFastContextHandler > SAL_CALL CSAXDocumentBuilder::createFastChildContext( sal_Int32/* nElement */, const Reference< XFastAttributeList >&/* xAttribs */ ) |
313 | 0 | { |
314 | 0 | return nullptr; |
315 | 0 | } |
316 | | |
317 | | |
318 | | Reference< XFastContextHandler > SAL_CALL CSAXDocumentBuilder::createUnknownChildContext( const OUString&/* rNamespace */, const OUString&/* rName */, const Reference< XFastAttributeList >&/* xAttribs */ ) |
319 | 0 | { |
320 | 0 | return nullptr; |
321 | 0 | } |
322 | | |
323 | | void SAL_CALL CSAXDocumentBuilder::characters( const OUString& rChars ) |
324 | 303k | { |
325 | 303k | std::scoped_lock g(m_Mutex); |
326 | | |
327 | | // append text node to the current top element |
328 | 303k | if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT && |
329 | 0 | m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT) |
330 | 0 | throw SAXException(); |
331 | | |
332 | 303k | Reference< XText > aText = m_aDocument->createTextNode(rChars); |
333 | 303k | m_aNodeStack.top()->appendChild(aText); |
334 | 303k | } |
335 | | } |
336 | | |
337 | | extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* |
338 | | unoxml_CSAXDocumentBuilder_get_implementation( |
339 | | css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&) |
340 | 18.1k | { |
341 | 18.1k | return cppu::acquire(new DOM::CSAXDocumentBuilder(context)); |
342 | 18.1k | } |
343 | | |
344 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |