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