/src/libreoffice/xmlscript/source/xml_helper/xml_impctx.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 <sal/config.h> |
21 | | |
22 | | #include <xml_import.hxx> |
23 | | |
24 | | #include <cppuhelper/implbase.hxx> |
25 | | #include <cppuhelper/supportsservice.hxx> |
26 | | #include <com/sun/star/container/NoSuchElementException.hpp> |
27 | | #include <com/sun/star/xml/input/XAttributes.hpp> |
28 | | #include <com/sun/star/lang/XInitialization.hpp> |
29 | | #include <com/sun/star/uno/XComponentContext.hpp> |
30 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
31 | | #include <sal/log.hxx> |
32 | | #include <rtl/ref.hxx> |
33 | | |
34 | | #include <memory> |
35 | | #include <mutex> |
36 | | #include <optional> |
37 | | #include <unordered_map> |
38 | | #include <vector> |
39 | | |
40 | | using namespace ::com::sun::star; |
41 | | using namespace ::com::sun::star::uno; |
42 | | |
43 | | namespace xmlscript |
44 | | { |
45 | | |
46 | | const sal_Int32 UID_UNKNOWN = -1; |
47 | | |
48 | | typedef std::unordered_map< OUString, sal_Int32 > t_OUString2LongMap; |
49 | | |
50 | | namespace { |
51 | | |
52 | | struct PrefixEntry |
53 | | { |
54 | | ::std::vector< sal_Int32 > m_Uids; |
55 | | |
56 | | PrefixEntry() |
57 | 0 | { m_Uids.reserve( 4 ); } |
58 | | }; |
59 | | |
60 | | } |
61 | | |
62 | | typedef std::unordered_map< OUString, PrefixEntry > t_OUString2PrefixMap; |
63 | | |
64 | | namespace { |
65 | | |
66 | | struct ElementEntry |
67 | | { |
68 | | Reference< xml::input::XElement > m_xElement; |
69 | | ::std::vector< OUString > m_prefixes; |
70 | | |
71 | | ElementEntry() |
72 | 0 | { m_prefixes.reserve( 2 ); } |
73 | | }; |
74 | | |
75 | | class ExtendedAttributes; |
76 | | |
77 | | class MGuard |
78 | | { |
79 | | std::mutex * m_pMutex; |
80 | | public: |
81 | | explicit MGuard( std::optional<std::mutex> & oMutex ) |
82 | 0 | : m_pMutex( oMutex ? &*oMutex : nullptr ) |
83 | 0 | { if (m_pMutex) m_pMutex->lock(); } |
84 | | ~MGuard() noexcept |
85 | 0 | { if (m_pMutex) m_pMutex->unlock(); } |
86 | | }; |
87 | | |
88 | | class DocumentHandlerImpl : |
89 | | public ::cppu::WeakImplHelper< xml::sax::XDocumentHandler, |
90 | | xml::input::XNamespaceMapping, |
91 | | lang::XInitialization, |
92 | | css::lang::XServiceInfo > |
93 | | { |
94 | | friend class ExtendedAttributes; |
95 | | |
96 | | Reference< xml::input::XRoot > m_xRoot; |
97 | | |
98 | | t_OUString2LongMap m_URI2Uid; |
99 | | sal_Int32 m_uid_count; |
100 | | |
101 | | sal_Int32 m_nLastURI_lookup; |
102 | | OUString m_aLastURI_lookup; |
103 | | |
104 | | t_OUString2PrefixMap m_prefixes; |
105 | | sal_Int32 m_nLastPrefix_lookup; |
106 | | OUString m_aLastPrefix_lookup; |
107 | | |
108 | | std::vector< ElementEntry > m_elements; |
109 | | sal_Int32 m_nSkipElements; |
110 | | |
111 | | mutable std::optional<std::mutex> m_oMutex; |
112 | | |
113 | | inline Reference< xml::input::XElement > getCurrentElement() const; |
114 | | |
115 | | inline sal_Int32 getUidByURI( OUString const & rURI ); |
116 | | inline sal_Int32 getUidByPrefix( OUString const & rPrefix ); |
117 | | |
118 | | inline void pushPrefix( |
119 | | OUString const & rPrefix, OUString const & rURI ); |
120 | | inline void popPrefix( OUString const & rPrefix ); |
121 | | |
122 | | inline void getElementName( |
123 | | OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName ); |
124 | | |
125 | | public: |
126 | | DocumentHandlerImpl( |
127 | | Reference< xml::input::XRoot > const & xRoot, |
128 | | bool bSingleThreadedUse ); |
129 | | |
130 | | // XServiceInfo |
131 | | virtual OUString SAL_CALL getImplementationName() override; |
132 | | virtual sal_Bool SAL_CALL supportsService( |
133 | | OUString const & servicename ) override; |
134 | | virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; |
135 | | |
136 | | // XInitialization |
137 | | virtual void SAL_CALL initialize( |
138 | | Sequence< Any > const & arguments ) override; |
139 | | |
140 | | // XDocumentHandler |
141 | | virtual void SAL_CALL startDocument() override; |
142 | | virtual void SAL_CALL endDocument() override; |
143 | | virtual void SAL_CALL startElement( |
144 | | OUString const & rQElementName, |
145 | | Reference< xml::sax::XAttributeList > const & xAttribs ) override; |
146 | | virtual void SAL_CALL endElement( |
147 | | OUString const & rQElementName ) override; |
148 | | virtual void SAL_CALL characters( |
149 | | OUString const & rChars ) override; |
150 | | virtual void SAL_CALL ignorableWhitespace( |
151 | | OUString const & rWhitespaces ) override; |
152 | | virtual void SAL_CALL processingInstruction( |
153 | | OUString const & rTarget, OUString const & rData ) override; |
154 | | virtual void SAL_CALL setDocumentLocator( |
155 | | Reference< xml::sax::XLocator > const & xLocator ) override; |
156 | | |
157 | | // XNamespaceMapping |
158 | | virtual sal_Int32 SAL_CALL getUidByUri( OUString const & Uri ) override; |
159 | | virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid ) override; |
160 | | }; |
161 | | |
162 | | } |
163 | | |
164 | | constexpr OUString g_sXMLNS_PREFIX_UNKNOWN( u"<<< unknown prefix >>>"_ustr ); |
165 | | constexpr OUString g_sXMLNS( u"xmlns"_ustr ); |
166 | | |
167 | | |
168 | | DocumentHandlerImpl::DocumentHandlerImpl( |
169 | | Reference< xml::input::XRoot > const & xRoot, |
170 | | bool bSingleThreadedUse ) |
171 | 0 | : m_xRoot( xRoot ), |
172 | 0 | m_uid_count( 0 ), |
173 | 0 | m_nLastURI_lookup( UID_UNKNOWN ), |
174 | 0 | m_aLastURI_lookup( u"<<< unknown URI >>>"_ustr ), |
175 | 0 | m_nLastPrefix_lookup( UID_UNKNOWN ), |
176 | 0 | m_aLastPrefix_lookup( u"<<< unknown URI >>>"_ustr ), |
177 | 0 | m_nSkipElements( 0 ) |
178 | 0 | { |
179 | 0 | m_elements.reserve( 10 ); |
180 | |
|
181 | 0 | if (! bSingleThreadedUse) |
182 | 0 | m_oMutex.emplace(); |
183 | 0 | } |
184 | | |
185 | | inline Reference< xml::input::XElement > |
186 | | DocumentHandlerImpl::getCurrentElement() const |
187 | 0 | { |
188 | 0 | MGuard aGuard( m_oMutex ); |
189 | 0 | if (m_elements.empty()) |
190 | 0 | return Reference< xml::input::XElement >(); |
191 | 0 | else |
192 | 0 | return m_elements.back().m_xElement; |
193 | 0 | } |
194 | | |
195 | | inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString const & rURI ) |
196 | 0 | { |
197 | 0 | MGuard guard( m_oMutex ); |
198 | 0 | if (m_nLastURI_lookup == UID_UNKNOWN || m_aLastURI_lookup != rURI) |
199 | 0 | { |
200 | 0 | t_OUString2LongMap::const_iterator iFind( m_URI2Uid.find( rURI ) ); |
201 | 0 | if (iFind != m_URI2Uid.end()) // id found |
202 | 0 | { |
203 | 0 | m_nLastURI_lookup = iFind->second; |
204 | 0 | m_aLastURI_lookup = rURI; |
205 | 0 | } |
206 | 0 | else |
207 | 0 | { |
208 | 0 | m_nLastURI_lookup = m_uid_count; |
209 | 0 | ++m_uid_count; |
210 | 0 | m_URI2Uid[ rURI ] = m_nLastURI_lookup; |
211 | 0 | m_aLastURI_lookup = rURI; |
212 | 0 | } |
213 | 0 | } |
214 | 0 | return m_nLastURI_lookup; |
215 | 0 | } |
216 | | |
217 | | inline sal_Int32 DocumentHandlerImpl::getUidByPrefix( |
218 | | OUString const & rPrefix ) |
219 | 0 | { |
220 | | // commonly the last added prefix is used often for several tags... |
221 | | // good guess |
222 | 0 | if (m_nLastPrefix_lookup == UID_UNKNOWN || m_aLastPrefix_lookup != rPrefix) |
223 | 0 | { |
224 | 0 | t_OUString2PrefixMap::const_iterator iFind( |
225 | 0 | m_prefixes.find( rPrefix ) ); |
226 | 0 | if (iFind != m_prefixes.end()) |
227 | 0 | { |
228 | 0 | const PrefixEntry & rPrefixEntry = iFind->second; |
229 | 0 | SAL_WARN_IF( rPrefixEntry.m_Uids.empty(), "xmlscript.xmlhelper", "rPrefixEntry.m_Uids is empty" ); |
230 | 0 | m_nLastPrefix_lookup = rPrefixEntry.m_Uids.back(); |
231 | 0 | m_aLastPrefix_lookup = rPrefix; |
232 | 0 | } |
233 | 0 | else |
234 | 0 | { |
235 | 0 | m_nLastPrefix_lookup = UID_UNKNOWN; |
236 | 0 | m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN; |
237 | 0 | } |
238 | 0 | } |
239 | 0 | return m_nLastPrefix_lookup; |
240 | 0 | } |
241 | | |
242 | | inline void DocumentHandlerImpl::pushPrefix( |
243 | | OUString const & rPrefix, OUString const & rURI ) |
244 | 0 | { |
245 | | // lookup id for URI |
246 | 0 | sal_Int32 nUid = getUidByURI( rURI ); |
247 | | |
248 | | // mark prefix with id |
249 | 0 | t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) ); |
250 | 0 | if (iFind == m_prefixes.end()) // unused prefix |
251 | 0 | { |
252 | 0 | PrefixEntry aEntry; |
253 | 0 | aEntry.m_Uids.push_back( nUid ); // latest id for prefix |
254 | 0 | m_prefixes[rPrefix] = std::move(aEntry); |
255 | 0 | } |
256 | 0 | else |
257 | 0 | { |
258 | 0 | PrefixEntry& rEntry = iFind->second; |
259 | 0 | SAL_WARN_IF(rEntry.m_Uids.empty(), "xmlscript.xmlhelper", "pEntry->m_Uids is empty"); |
260 | 0 | rEntry.m_Uids.push_back(nUid); |
261 | 0 | } |
262 | | |
263 | 0 | m_aLastPrefix_lookup = rPrefix; |
264 | 0 | m_nLastPrefix_lookup = nUid; |
265 | 0 | } |
266 | | |
267 | | inline void DocumentHandlerImpl::popPrefix( |
268 | | OUString const & rPrefix ) |
269 | 0 | { |
270 | 0 | t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) ); |
271 | 0 | if (iFind != m_prefixes.end()) // unused prefix |
272 | 0 | { |
273 | 0 | PrefixEntry& rEntry = iFind->second; |
274 | 0 | rEntry.m_Uids.pop_back(); // pop last id for prefix |
275 | 0 | if (rEntry.m_Uids.empty()) // erase prefix key |
276 | 0 | { |
277 | 0 | m_prefixes.erase(iFind); |
278 | 0 | } |
279 | 0 | } |
280 | |
|
281 | 0 | m_nLastPrefix_lookup = UID_UNKNOWN; |
282 | 0 | m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN; |
283 | 0 | } |
284 | | |
285 | | inline void DocumentHandlerImpl::getElementName( |
286 | | OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName ) |
287 | 0 | { |
288 | 0 | sal_Int32 nColonPos = rQName.indexOf( ':' ); |
289 | 0 | *pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName); |
290 | 0 | *pUid = getUidByPrefix( |
291 | 0 | nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() ); |
292 | 0 | } |
293 | | |
294 | | namespace { |
295 | | |
296 | | class ExtendedAttributes : |
297 | | public ::cppu::WeakImplHelper< xml::input::XAttributes > |
298 | | { |
299 | | sal_Int32 const m_nAttributes; |
300 | | std::unique_ptr<sal_Int32[]> m_pUids; |
301 | | std::unique_ptr<OUString[]> m_pLocalNames; |
302 | | std::unique_ptr<OUString[]> m_pQNames; |
303 | | std::unique_ptr<OUString[]> m_pValues; |
304 | | |
305 | | public: |
306 | | inline ExtendedAttributes( |
307 | | sal_Int32 nAttributes, |
308 | | std::unique_ptr<sal_Int32[]> pUids, |
309 | | std::unique_ptr<OUString[]> pLocalNames, |
310 | | std::unique_ptr<OUString[]> pQNames, |
311 | | Reference< xml::sax::XAttributeList > const & xAttributeList ); |
312 | | |
313 | | // XAttributes |
314 | | virtual sal_Int32 SAL_CALL getLength() override; |
315 | | virtual sal_Int32 SAL_CALL getIndexByQName( |
316 | | OUString const & rQName ) override; |
317 | | virtual sal_Int32 SAL_CALL getIndexByUidName( |
318 | | sal_Int32 nUid, OUString const & rLocalName ) override; |
319 | | virtual OUString SAL_CALL getQNameByIndex( |
320 | | sal_Int32 nIndex ) override; |
321 | | virtual sal_Int32 SAL_CALL getUidByIndex( |
322 | | sal_Int32 nIndex ) override; |
323 | | virtual OUString SAL_CALL getLocalNameByIndex( |
324 | | sal_Int32 nIndex ) override; |
325 | | virtual OUString SAL_CALL getValueByIndex( |
326 | | sal_Int32 nIndex ) override; |
327 | | virtual OUString SAL_CALL getValueByUidName( |
328 | | sal_Int32 nUid, OUString const & rLocalName ) override; |
329 | | virtual OUString SAL_CALL getTypeByIndex( |
330 | | sal_Int32 nIndex ) override; |
331 | | }; |
332 | | |
333 | | } |
334 | | |
335 | | inline ExtendedAttributes::ExtendedAttributes( |
336 | | sal_Int32 nAttributes, |
337 | | std::unique_ptr<sal_Int32[]> pUids, |
338 | | std::unique_ptr<OUString[]> pLocalNames, std::unique_ptr<OUString[]> pQNames, |
339 | | Reference< xml::sax::XAttributeList > const & xAttributeList ) |
340 | 0 | : m_nAttributes( nAttributes ) |
341 | 0 | , m_pUids( std::move(pUids) ) |
342 | 0 | , m_pLocalNames( std::move(pLocalNames) ) |
343 | 0 | , m_pQNames( std::move(pQNames) ) |
344 | 0 | , m_pValues( new OUString[ nAttributes ] ) |
345 | 0 | { |
346 | 0 | for ( sal_Int32 nPos = 0; nPos < nAttributes; ++nPos ) |
347 | 0 | { |
348 | 0 | m_pValues[ nPos ] = xAttributeList->getValueByIndex( nPos ); |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | // XServiceInfo |
353 | | |
354 | | OUString DocumentHandlerImpl::getImplementationName() |
355 | 0 | { |
356 | 0 | return u"com.sun.star.comp.xml.input.SaxDocumentHandler"_ustr; |
357 | 0 | } |
358 | | |
359 | | sal_Bool DocumentHandlerImpl::supportsService( OUString const & servicename ) |
360 | 0 | { |
361 | 0 | return cppu::supportsService(this, servicename); |
362 | 0 | } |
363 | | |
364 | | Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames() |
365 | 0 | { |
366 | 0 | return { u"com.sun.star.xml.input.SaxDocumentHandler"_ustr }; |
367 | 0 | } |
368 | | |
369 | | // XInitialization |
370 | | |
371 | | void DocumentHandlerImpl::initialize( |
372 | | Sequence< Any > const & arguments ) |
373 | 0 | { |
374 | 0 | MGuard guard( m_oMutex ); |
375 | 0 | Reference< xml::input::XRoot > xRoot; |
376 | 0 | if (arguments.getLength() != 1 || |
377 | 0 | !(arguments[ 0 ] >>= xRoot) || |
378 | 0 | !xRoot.is()) |
379 | 0 | { |
380 | 0 | throw RuntimeException( u"missing root instance!"_ustr ); |
381 | 0 | } |
382 | 0 | m_xRoot = std::move(xRoot); |
383 | 0 | } |
384 | | |
385 | | // XNamespaceMapping |
386 | | |
387 | | sal_Int32 DocumentHandlerImpl::getUidByUri( OUString const & Uri ) |
388 | 0 | { |
389 | 0 | sal_Int32 uid = getUidByURI( Uri ); |
390 | 0 | SAL_WARN_IF( uid == UID_UNKNOWN, "xmlscript.xmlhelper", "uid UNKNOWN"); |
391 | 0 | return uid; |
392 | 0 | } |
393 | | |
394 | | OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid ) |
395 | 0 | { |
396 | 0 | MGuard guard( m_oMutex ); |
397 | 0 | for (const auto& rURIUid : m_URI2Uid) |
398 | 0 | { |
399 | 0 | if (rURIUid.second == Uid) |
400 | 0 | return rURIUid.first; |
401 | 0 | } |
402 | 0 | throw container::NoSuchElementException( u"no such xmlns uid!"_ustr , getXWeak() ); |
403 | 0 | } |
404 | | |
405 | | // XDocumentHandler |
406 | | |
407 | | void DocumentHandlerImpl::startDocument() |
408 | 0 | { |
409 | 0 | m_xRoot->startDocument( static_cast< xml::input::XNamespaceMapping * >( this ) ); |
410 | 0 | } |
411 | | |
412 | | void DocumentHandlerImpl::endDocument() |
413 | 0 | { |
414 | 0 | m_xRoot->endDocument(); |
415 | 0 | } |
416 | | |
417 | | void DocumentHandlerImpl::startElement( |
418 | | OUString const & rQElementName, |
419 | | Reference< xml::sax::XAttributeList > const & xAttribs ) |
420 | 0 | { |
421 | 0 | Reference< xml::input::XElement > xCurrentElement; |
422 | 0 | rtl::Reference< ExtendedAttributes > xAttributes; |
423 | 0 | sal_Int32 nUid; |
424 | 0 | OUString aLocalName; |
425 | 0 | ElementEntry elementEntry; |
426 | |
|
427 | 0 | { // guard start: |
428 | 0 | MGuard aGuard( m_oMutex ); |
429 | | // currently skipping elements and waiting for end tags? |
430 | 0 | if (m_nSkipElements > 0) |
431 | 0 | { |
432 | 0 | ++m_nSkipElements; // wait for another end tag |
433 | 0 | SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ..."); |
434 | 0 | return; |
435 | 0 | } |
436 | | |
437 | 0 | sal_Int16 nAttribs = xAttribs->getLength(); |
438 | | |
439 | | // save all namespace ids |
440 | 0 | std::unique_ptr<sal_Int32[]> pUids(new sal_Int32[ nAttribs ]); |
441 | 0 | std::unique_ptr<OUString[]> pPrefixes(new OUString[ nAttribs ]); |
442 | 0 | std::unique_ptr<OUString[]> pLocalNames(new OUString[ nAttribs ]); |
443 | 0 | std::unique_ptr<OUString[]> pQNames(new OUString[ nAttribs ]); |
444 | | |
445 | | // first recognize all xmlns attributes |
446 | 0 | sal_Int16 nPos; |
447 | 0 | for ( nPos = 0; nPos < nAttribs; ++nPos ) |
448 | 0 | { |
449 | | // mark attribute to be collected further |
450 | | // on with attribute's uid and current prefix |
451 | 0 | pUids[ nPos ] = 0; // modified |
452 | |
|
453 | 0 | pQNames[ nPos ] = xAttribs->getNameByIndex( nPos ); |
454 | 0 | OUString const & rQAttributeName = pQNames[ nPos ]; |
455 | |
|
456 | 0 | if (rQAttributeName.startsWith( g_sXMLNS )) |
457 | 0 | { |
458 | 0 | if (rQAttributeName.getLength() == 5) // set default namespace |
459 | 0 | { |
460 | 0 | OUString aDefNamespacePrefix; |
461 | 0 | pushPrefix( |
462 | 0 | aDefNamespacePrefix, |
463 | 0 | xAttribs->getValueByIndex( nPos ) ); |
464 | 0 | elementEntry.m_prefixes.push_back( aDefNamespacePrefix ); |
465 | 0 | pUids[ nPos ] = UID_UNKNOWN; |
466 | 0 | pPrefixes[ nPos ] = g_sXMLNS; |
467 | 0 | pLocalNames[ nPos ] = aDefNamespacePrefix; |
468 | 0 | } |
469 | 0 | else if (':' == rQAttributeName[ 5 ]) // set prefix |
470 | 0 | { |
471 | 0 | OUString aPrefix( rQAttributeName.copy( 6 ) ); |
472 | 0 | pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) ); |
473 | 0 | elementEntry.m_prefixes.push_back( aPrefix ); |
474 | 0 | pUids[ nPos ] = UID_UNKNOWN; |
475 | 0 | pPrefixes[ nPos ] = g_sXMLNS; |
476 | 0 | pLocalNames[ nPos ] = aPrefix; |
477 | 0 | } |
478 | | // else just a name starting with xmlns, but no prefix |
479 | 0 | } |
480 | 0 | } |
481 | | |
482 | | // now read out attribute prefixes (all namespace prefixes have been set) |
483 | 0 | for ( nPos = 0; nPos < nAttribs; ++nPos ) |
484 | 0 | { |
485 | 0 | if (pUids[ nPos ] >= 0) // no xmlns: attribute |
486 | 0 | { |
487 | 0 | OUString const & rQAttributeName = pQNames[ nPos ]; |
488 | 0 | SAL_WARN_IF(rQAttributeName.startsWith( "xmlns:" ), "xmlscript.xmlhelper", "### unexpected xmlns!" ); |
489 | | |
490 | | // collect attribute's uid and current prefix |
491 | 0 | sal_Int32 nColonPos = rQAttributeName.indexOf( ':' ); |
492 | 0 | if (nColonPos >= 0) |
493 | 0 | { |
494 | 0 | pPrefixes[ nPos ] = rQAttributeName.copy( 0, nColonPos ); |
495 | 0 | pLocalNames[ nPos ] = rQAttributeName.copy( nColonPos +1 ); |
496 | 0 | } |
497 | 0 | else |
498 | 0 | { |
499 | 0 | pPrefixes[ nPos ].clear(); |
500 | 0 | pLocalNames[ nPos ] = rQAttributeName; |
501 | | // leave local names unmodified |
502 | 0 | } |
503 | 0 | pUids[ nPos ] = getUidByPrefix( pPrefixes[ nPos ] ); |
504 | 0 | } |
505 | 0 | } |
506 | 0 | pPrefixes.reset(); |
507 | | // ownership of arrays belongs to attribute list |
508 | 0 | xAttributes = new ExtendedAttributes(nAttribs, std::move(pUids), std::move(pLocalNames), |
509 | 0 | std::move(pQNames), xAttribs); |
510 | |
|
511 | 0 | getElementName( rQElementName, &nUid, &aLocalName ); |
512 | | |
513 | | // create new child context and append to list |
514 | 0 | if (! m_elements.empty()) |
515 | 0 | xCurrentElement = m_elements.back().m_xElement; |
516 | 0 | } // :guard end |
517 | | |
518 | 0 | if (xCurrentElement.is()) |
519 | 0 | { |
520 | 0 | elementEntry.m_xElement = |
521 | 0 | xCurrentElement->startChildElement( nUid, aLocalName, xAttributes ); |
522 | 0 | } |
523 | 0 | else |
524 | 0 | { |
525 | 0 | elementEntry.m_xElement = |
526 | 0 | m_xRoot->startRootElement( nUid, aLocalName, xAttributes ); |
527 | 0 | } |
528 | |
|
529 | 0 | { |
530 | 0 | MGuard aGuard( m_oMutex ); |
531 | 0 | if (elementEntry.m_xElement.is()) |
532 | 0 | { |
533 | 0 | m_elements.push_back( std::move(elementEntry) ); |
534 | 0 | } |
535 | 0 | else |
536 | 0 | { |
537 | 0 | ++m_nSkipElements; |
538 | | |
539 | | // pop prefixes |
540 | 0 | for (sal_Int32 nPos = elementEntry.m_prefixes.size(); nPos--;) |
541 | 0 | popPrefix(elementEntry.m_prefixes[nPos]); |
542 | |
|
543 | 0 | SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ..."); |
544 | 0 | } |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | void DocumentHandlerImpl::endElement( |
549 | | OUString const & rQElementName ) |
550 | 0 | { |
551 | 0 | Reference< xml::input::XElement > xCurrentElement; |
552 | 0 | { |
553 | 0 | MGuard aGuard( m_oMutex ); |
554 | 0 | if (m_nSkipElements) |
555 | 0 | { |
556 | 0 | --m_nSkipElements; |
557 | 0 | SAL_INFO("xmlscript.xmlhelper", "### received endElement() for \"" << rQElementName << "\"."); |
558 | 0 | return; |
559 | 0 | } |
560 | | |
561 | | // popping context |
562 | 0 | SAL_WARN_IF( m_elements.empty(), "xmlscript.xmlhelper", "m_elements is empty" ); |
563 | 0 | ElementEntry& rEntry = m_elements.back(); |
564 | 0 | xCurrentElement = rEntry.m_xElement; |
565 | |
|
566 | | #if OSL_DEBUG_LEVEL > 0 |
567 | | sal_Int32 nUid; |
568 | | OUString aLocalName; |
569 | | getElementName( rQElementName, &nUid, &aLocalName ); |
570 | | SAL_WARN_IF( xCurrentElement->getLocalName() != aLocalName, "xmlscript.xmlhelper", "xCurrentElement->getLocalName() != aLocalName" ); |
571 | | SAL_WARN_IF( xCurrentElement->getUid() != nUid, "xmlscript.xmlhelper", "xCurrentElement->getUid() != nUid" ); |
572 | | #endif |
573 | | |
574 | | // pop prefixes |
575 | 0 | for ( sal_Int32 nPos = rEntry.m_prefixes.size(); nPos--; ) |
576 | 0 | { |
577 | 0 | popPrefix( rEntry.m_prefixes[ nPos ] ); |
578 | 0 | } |
579 | 0 | m_elements.pop_back(); |
580 | 0 | } |
581 | 0 | xCurrentElement->endElement(); |
582 | 0 | } |
583 | | |
584 | | void DocumentHandlerImpl::characters( OUString const & rChars ) |
585 | 0 | { |
586 | 0 | Reference< xml::input::XElement > xCurrentElement( getCurrentElement() ); |
587 | 0 | if (xCurrentElement.is()) |
588 | 0 | xCurrentElement->characters( rChars ); |
589 | 0 | } |
590 | | |
591 | | void DocumentHandlerImpl::ignorableWhitespace( |
592 | | OUString const & rWhitespaces ) |
593 | 0 | { |
594 | 0 | Reference< xml::input::XElement > xCurrentElement( getCurrentElement() ); |
595 | 0 | if (xCurrentElement.is()) |
596 | 0 | xCurrentElement->ignorableWhitespace( rWhitespaces ); |
597 | 0 | } |
598 | | |
599 | | void DocumentHandlerImpl::processingInstruction( |
600 | | OUString const & rTarget, OUString const & rData ) |
601 | 0 | { |
602 | 0 | Reference< xml::input::XElement > xCurrentElement( getCurrentElement() ); |
603 | 0 | if (xCurrentElement.is()) |
604 | 0 | xCurrentElement->processingInstruction( rTarget, rData ); |
605 | 0 | else |
606 | 0 | m_xRoot->processingInstruction( rTarget, rData ); |
607 | 0 | } |
608 | | |
609 | | void DocumentHandlerImpl::setDocumentLocator( |
610 | | Reference< xml::sax::XLocator > const & xLocator ) |
611 | 0 | { |
612 | 0 | m_xRoot->setDocumentLocator( xLocator ); |
613 | 0 | } |
614 | | |
615 | | // XAttributes |
616 | | |
617 | | sal_Int32 ExtendedAttributes::getIndexByQName( OUString const & rQName ) |
618 | 0 | { |
619 | 0 | for ( sal_Int32 nPos = m_nAttributes; nPos--; ) |
620 | 0 | { |
621 | 0 | if (m_pQNames[ nPos ] == rQName) |
622 | 0 | { |
623 | 0 | return nPos; |
624 | 0 | } |
625 | 0 | } |
626 | 0 | return -1; |
627 | 0 | } |
628 | | |
629 | | sal_Int32 ExtendedAttributes::getLength() |
630 | 0 | { |
631 | 0 | return m_nAttributes; |
632 | 0 | } |
633 | | |
634 | | OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex ) |
635 | 0 | { |
636 | 0 | if (nIndex < m_nAttributes) |
637 | 0 | return m_pLocalNames[ nIndex ]; |
638 | 0 | else |
639 | 0 | return OUString(); |
640 | 0 | } |
641 | | |
642 | | OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex ) |
643 | 0 | { |
644 | 0 | if (nIndex < m_nAttributes) |
645 | 0 | return m_pQNames[ nIndex ]; |
646 | 0 | else |
647 | 0 | return OUString(); |
648 | 0 | } |
649 | | |
650 | | OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex ) |
651 | 0 | { |
652 | 0 | SAL_WARN_IF( nIndex >= m_nAttributes , "xmlscript.xmlhelper", "nIndex is bigger than m_nAttributes"); |
653 | 0 | return OUString(); // unsupported |
654 | 0 | } |
655 | | |
656 | | OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex ) |
657 | 0 | { |
658 | 0 | if (nIndex < m_nAttributes) |
659 | 0 | return m_pValues[ nIndex ]; |
660 | 0 | else |
661 | 0 | return OUString(); |
662 | 0 | } |
663 | | |
664 | | sal_Int32 ExtendedAttributes::getIndexByUidName( |
665 | | sal_Int32 nUid, OUString const & rLocalName ) |
666 | 0 | { |
667 | 0 | for ( sal_Int32 nPos = m_nAttributes; nPos--; ) |
668 | 0 | { |
669 | 0 | if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName) |
670 | 0 | { |
671 | 0 | return nPos; |
672 | 0 | } |
673 | 0 | } |
674 | 0 | return -1; |
675 | 0 | } |
676 | | |
677 | | sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex ) |
678 | 0 | { |
679 | 0 | if (nIndex < m_nAttributes) |
680 | 0 | return m_pUids[ nIndex ]; |
681 | 0 | else |
682 | 0 | return -1; |
683 | 0 | } |
684 | | |
685 | | OUString ExtendedAttributes::getValueByUidName( |
686 | | sal_Int32 nUid, OUString const & rLocalName ) |
687 | 0 | { |
688 | 0 | for ( sal_Int32 nPos = m_nAttributes; nPos--; ) |
689 | 0 | { |
690 | 0 | if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName) |
691 | 0 | { |
692 | 0 | return m_pValues[ nPos ]; |
693 | 0 | } |
694 | 0 | } |
695 | 0 | return OUString(); |
696 | 0 | } |
697 | | |
698 | | Reference< xml::sax::XDocumentHandler > createDocumentHandler( |
699 | | Reference< xml::input::XRoot > const & xRoot ) |
700 | 0 | { |
701 | 0 | SAL_WARN_IF( !xRoot.is(), "xmlscript.xmlhelper", "xRoot is NULL" ); |
702 | 0 | if (xRoot.is()) |
703 | 0 | { |
704 | 0 | return new DocumentHandlerImpl(xRoot, true /* mt use */); |
705 | 0 | } |
706 | 0 | return Reference< xml::sax::XDocumentHandler >(); |
707 | 0 | } |
708 | | |
709 | | } |
710 | | |
711 | | extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* |
712 | | com_sun_star_comp_xml_input_SaxDocumentHandler_get_implementation( |
713 | | css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& ) |
714 | 0 | { |
715 | 0 | return cppu::acquire(new xmlscript::DocumentHandlerImpl({}, false /* mt use */)); |
716 | 0 | } |
717 | | |
718 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |