1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmlscript.hxx"
26 
27 #include "osl/diagnose.h"
28 #include "osl/mutex.hxx"
29 #include "rtl/ustrbuf.hxx"
30 #include "cppuhelper/factory.hxx"
31 #include "cppuhelper/implementationentry.hxx"
32 #include "cppuhelper/implbase1.hxx"
33 #include "cppuhelper/implbase3.hxx"
34 #include "xmlscript/xml_import.hxx"
35 
36 #include "com/sun/star/xml/input/XAttributes.hpp"
37 #include "com/sun/star/lang/XInitialization.hpp"
38 #include "com/sun/star/uno/XComponentContext.hpp"
39 
40 #include <vector>
41 #include <hash_map>
42 
43 #include <memory>
44 
45 
46 using namespace ::rtl;
47 using namespace ::osl;
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::uno;
50 
51 namespace xmlscript
52 {
53 
54 const sal_Int32 UID_UNKNOWN = -1;
55 
56 Sequence< OUString > getSupportedServiceNames_DocumentHandlerImpl()
57 {
58     OUString name( RTL_CONSTASCII_USTRINGPARAM(
59                        "com.sun.star.xml.input.SaxDocumentHandler") );
60     return Sequence< OUString >( &name, 1 );
61 }
62 
63 OUString getImplementationName_DocumentHandlerImpl()
64 {
65     return OUString( RTL_CONSTASCII_USTRINGPARAM(
66                          "com.sun.star.comp.xml.input.SaxDocumentHandler") );
67 }
68 
69 typedef ::std::hash_map< OUString, sal_Int32, OUStringHash > t_OUString2LongMap;
70 typedef ::std::hash_map< sal_Int32, OUString > t_Long2OUStringMap;
71 
72 struct PrefixEntry
73 {
74     ::std::vector< sal_Int32 > m_Uids;
75 
76     inline PrefixEntry() SAL_THROW( () )
77         { m_Uids.reserve( 4 ); }
78 };
79 
80 typedef ::std::hash_map<
81     OUString, PrefixEntry *, OUStringHash > t_OUString2PrefixMap;
82 
83 struct ElementEntry
84 {
85     Reference< xml::input::XElement > m_xElement;
86     ::std::vector< OUString > m_prefixes;
87 
88     inline ElementEntry()
89         { m_prefixes.reserve( 2 ); }
90 };
91 
92 typedef ::std::vector< ElementEntry * > t_ElementVector;
93 
94 class ExtendedAttributes;
95 
96 //==============================================================================
97 struct MGuard
98 {
99     Mutex * m_pMutex;
100     explicit MGuard( Mutex * pMutex )
101         : m_pMutex( pMutex )
102         { if (m_pMutex) m_pMutex->acquire(); }
103     ~MGuard() throw ()
104         { if (m_pMutex) m_pMutex->release(); }
105 };
106 
107 //==============================================================================
108 class DocumentHandlerImpl :
109     public ::cppu::WeakImplHelper3< xml::sax::XDocumentHandler,
110                                     xml::input::XNamespaceMapping,
111                                     lang::XInitialization >
112 {
113     friend class ExtendedAttributes;
114 
115     Reference< xml::input::XRoot > m_xRoot;
116 
117     t_OUString2LongMap m_URI2Uid;
118     sal_Int32 m_uid_count;
119 
120     OUString m_sXMLNS_PREFIX_UNKNOWN;
121     OUString m_sXMLNS;
122 
123     sal_Int32 m_nLastURI_lookup;
124     OUString m_aLastURI_lookup;
125 
126     t_OUString2PrefixMap m_prefixes;
127     sal_Int32 m_nLastPrefix_lookup;
128     OUString m_aLastPrefix_lookup;
129 
130     t_ElementVector m_elements;
131     sal_Int32 m_nSkipElements;
132 
133     Mutex * m_pMutex;
134 
135     inline Reference< xml::input::XElement > getCurrentElement() const;
136 
137     inline sal_Int32 getUidByURI( OUString const & rURI );
138     inline sal_Int32 getUidByPrefix( OUString const & rPrefix );
139 
140     inline void pushPrefix(
141         OUString const & rPrefix, OUString const & rURI );
142     inline void popPrefix( OUString const & rPrefix );
143 
144     inline void getElementName(
145         OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName );
146 
147 public:
148     DocumentHandlerImpl(
149         Reference< xml::input::XRoot > const & xRoot,
150         bool bSingleThreadedUse );
151     virtual ~DocumentHandlerImpl() throw ();
152 
153     // XServiceInfo
154     virtual OUString SAL_CALL getImplementationName()
155         throw (RuntimeException);
156     virtual sal_Bool SAL_CALL supportsService(
157         OUString const & servicename )
158         throw (RuntimeException);
159     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
160         throw (RuntimeException);
161 
162     // XInitialization
163     virtual void SAL_CALL initialize(
164         Sequence< Any > const & arguments )
165         throw (Exception);
166 
167     // XDocumentHandler
168     virtual void SAL_CALL startDocument()
169         throw (xml::sax::SAXException, RuntimeException);
170     virtual void SAL_CALL endDocument()
171         throw (xml::sax::SAXException, RuntimeException);
172     virtual void SAL_CALL startElement(
173         OUString const & rQElementName,
174         Reference< xml::sax::XAttributeList > const & xAttribs )
175         throw (xml::sax::SAXException, RuntimeException);
176     virtual void SAL_CALL endElement(
177         OUString const & rQElementName )
178         throw (xml::sax::SAXException, RuntimeException);
179     virtual void SAL_CALL characters(
180         OUString const & rChars )
181         throw (xml::sax::SAXException, RuntimeException);
182     virtual void SAL_CALL ignorableWhitespace(
183         OUString const & rWhitespaces )
184         throw (xml::sax::SAXException, RuntimeException);
185     virtual void SAL_CALL processingInstruction(
186         OUString const & rTarget, OUString const & rData )
187         throw (xml::sax::SAXException, RuntimeException);
188     virtual void SAL_CALL setDocumentLocator(
189         Reference< xml::sax::XLocator > const & xLocator )
190         throw (xml::sax::SAXException, RuntimeException);
191 
192     // XNamespaceMapping
193     virtual sal_Int32 SAL_CALL getUidByUri( OUString const & Uri )
194         throw (RuntimeException);
195     virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid )
196         throw (container::NoSuchElementException, RuntimeException);
197 };
198 
199 //______________________________________________________________________________
200 DocumentHandlerImpl::DocumentHandlerImpl(
201     Reference< xml::input::XRoot > const & xRoot,
202     bool bSingleThreadedUse )
203     : m_xRoot( xRoot ),
204       m_uid_count( 0 ),
205       m_sXMLNS_PREFIX_UNKNOWN(
206           RTL_CONSTASCII_USTRINGPARAM("<<< unknown prefix >>>") ),
207       m_sXMLNS( RTL_CONSTASCII_USTRINGPARAM("xmlns") ),
208       m_nLastURI_lookup( UID_UNKNOWN ),
209       m_aLastURI_lookup( RTL_CONSTASCII_USTRINGPARAM("<<< unknown URI >>>") ),
210       m_nLastPrefix_lookup( UID_UNKNOWN ),
211       m_aLastPrefix_lookup(
212           RTL_CONSTASCII_USTRINGPARAM("<<< unknown URI >>>") ),
213       m_nSkipElements( 0 ),
214       m_pMutex( 0 )
215 {
216     m_elements.reserve( 10 );
217 
218     if (! bSingleThreadedUse)
219         m_pMutex = new Mutex();
220 }
221 
222 //______________________________________________________________________________
223 DocumentHandlerImpl::~DocumentHandlerImpl() throw ()
224 {
225     if (m_pMutex != 0)
226     {
227         delete m_pMutex;
228 #if OSL_DEBUG_LEVEL == 0
229         m_pMutex = 0;
230 #endif
231     }
232 }
233 
234 //______________________________________________________________________________
235 inline Reference< xml::input::XElement >
236 DocumentHandlerImpl::getCurrentElement() const
237 {
238     MGuard aGuard( m_pMutex );
239     if (m_elements.empty())
240         return Reference< xml::input::XElement >();
241     else
242         return m_elements.back()->m_xElement;
243 }
244 
245 //______________________________________________________________________________
246 inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString const & rURI )
247 {
248     MGuard guard( m_pMutex );
249     if (m_nLastURI_lookup == UID_UNKNOWN || m_aLastURI_lookup != rURI)
250     {
251         t_OUString2LongMap::const_iterator iFind( m_URI2Uid.find( rURI ) );
252         if (iFind != m_URI2Uid.end()) // id found
253         {
254             m_nLastURI_lookup = iFind->second;
255             m_aLastURI_lookup = rURI;
256         }
257         else
258         {
259             m_nLastURI_lookup = m_uid_count;
260             ++m_uid_count;
261             m_URI2Uid[ rURI ] = m_nLastURI_lookup;
262             m_aLastURI_lookup = rURI;
263         }
264     }
265     return m_nLastURI_lookup;
266 }
267 
268 //______________________________________________________________________________
269 inline sal_Int32 DocumentHandlerImpl::getUidByPrefix(
270     OUString const & rPrefix )
271 {
272     // commonly the last added prefix is used often for several tags...
273     // good guess
274     if (m_nLastPrefix_lookup == UID_UNKNOWN || m_aLastPrefix_lookup != rPrefix)
275     {
276         t_OUString2PrefixMap::const_iterator iFind(
277             m_prefixes.find( rPrefix ) );
278         if (iFind != m_prefixes.end())
279         {
280             const PrefixEntry & rPrefixEntry = *iFind->second;
281             OSL_ASSERT( ! rPrefixEntry.m_Uids.empty() );
282             m_nLastPrefix_lookup = rPrefixEntry.m_Uids.back();
283             m_aLastPrefix_lookup = rPrefix;
284         }
285         else
286         {
287             m_nLastPrefix_lookup = UID_UNKNOWN;
288             m_aLastPrefix_lookup = m_sXMLNS_PREFIX_UNKNOWN;
289         }
290     }
291     return m_nLastPrefix_lookup;
292 }
293 
294 //______________________________________________________________________________
295 inline void DocumentHandlerImpl::pushPrefix(
296     OUString const & rPrefix, OUString const & rURI )
297 {
298     // lookup id for URI
299     sal_Int32 nUid = getUidByURI( rURI );
300 
301     // mark prefix with id
302     t_OUString2PrefixMap::const_iterator iFind( m_prefixes.find( rPrefix ) );
303     if (iFind == m_prefixes.end()) // unused prefix
304     {
305         PrefixEntry * pEntry = new PrefixEntry();
306         pEntry->m_Uids.push_back( nUid ); // latest id for prefix
307         m_prefixes[ rPrefix ] = pEntry;
308     }
309     else
310     {
311         PrefixEntry * pEntry = iFind->second;
312         OSL_ASSERT( ! pEntry->m_Uids.empty() );
313         pEntry->m_Uids.push_back( nUid );
314     }
315 
316     m_aLastPrefix_lookup = rPrefix;
317     m_nLastPrefix_lookup = nUid;
318 }
319 
320 //______________________________________________________________________________
321 inline void DocumentHandlerImpl::popPrefix(
322     OUString const & rPrefix )
323 {
324     t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) );
325     if (iFind != m_prefixes.end()) // unused prefix
326     {
327         PrefixEntry * pEntry = iFind->second;
328         pEntry->m_Uids.pop_back(); // pop last id for prefix
329         if (pEntry->m_Uids.empty()) // erase prefix key
330         {
331             m_prefixes.erase( iFind );
332             delete pEntry;
333         }
334     }
335 
336     m_nLastPrefix_lookup = UID_UNKNOWN;
337     m_aLastPrefix_lookup = m_sXMLNS_PREFIX_UNKNOWN;
338 }
339 
340 //______________________________________________________________________________
341 inline void DocumentHandlerImpl::getElementName(
342     OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName )
343 {
344     sal_Int32 nColonPos = rQName.indexOf( (sal_Unicode)':' );
345     *pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName);
346     *pUid = getUidByPrefix(
347         nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() );
348 }
349 
350 
351 //==============================================================================
352 class ExtendedAttributes :
353     public ::cppu::WeakImplHelper1< xml::input::XAttributes >
354 {
355     sal_Int32 m_nAttributes;
356     sal_Int32 * m_pUids;
357     OUString * m_pPrefixes;
358     OUString * m_pLocalNames;
359     OUString * m_pQNames;
360     OUString * m_pValues;
361 
362     DocumentHandlerImpl * m_pHandler;
363 
364 public:
365     inline ExtendedAttributes(
366         sal_Int32 nAttributes,
367         sal_Int32 * pUids, OUString * pPrefixes,
368         OUString * pLocalNames, OUString * pQNames,
369         Reference< xml::sax::XAttributeList > const & xAttributeList,
370         DocumentHandlerImpl * pHandler );
371     virtual ~ExtendedAttributes() throw ();
372 
373     // XAttributes
374     virtual sal_Int32 SAL_CALL getLength()
375         throw (RuntimeException);
376     virtual sal_Int32 SAL_CALL getIndexByQName(
377         OUString const & rQName )
378         throw (RuntimeException);
379     virtual sal_Int32 SAL_CALL getIndexByUidName(
380         sal_Int32 nUid, OUString const & rLocalName )
381         throw (RuntimeException);
382     virtual OUString SAL_CALL getQNameByIndex(
383         sal_Int32 nIndex )
384         throw (RuntimeException);
385     virtual sal_Int32 SAL_CALL getUidByIndex(
386         sal_Int32 nIndex )
387         throw (RuntimeException);
388     virtual OUString SAL_CALL getLocalNameByIndex(
389         sal_Int32 nIndex )
390         throw (RuntimeException);
391     virtual OUString SAL_CALL getValueByIndex(
392         sal_Int32 nIndex )
393         throw (RuntimeException);
394     virtual OUString SAL_CALL getValueByUidName(
395         sal_Int32 nUid, OUString const & rLocalName )
396         throw (RuntimeException);
397     virtual OUString SAL_CALL getTypeByIndex(
398         sal_Int32 nIndex )
399         throw (RuntimeException);
400 };
401 
402 //______________________________________________________________________________
403 inline ExtendedAttributes::ExtendedAttributes(
404     sal_Int32 nAttributes,
405     sal_Int32 * pUids, OUString * pPrefixes,
406     OUString * pLocalNames, OUString * pQNames,
407     Reference< xml::sax::XAttributeList > const & xAttributeList,
408     DocumentHandlerImpl * pHandler )
409     : m_nAttributes( nAttributes )
410     , m_pUids( pUids )
411     , m_pPrefixes( pPrefixes )
412     , m_pLocalNames( pLocalNames )
413     , m_pQNames( pQNames )
414     , m_pValues( new OUString[ nAttributes ] )
415     , m_pHandler( pHandler )
416 {
417     m_pHandler->acquire();
418 
419     for ( sal_Int16 nPos = 0; nPos < nAttributes; ++nPos )
420     {
421         m_pValues[ nPos ] = xAttributeList->getValueByIndex( nPos );
422     }
423 }
424 
425 //______________________________________________________________________________
426 ExtendedAttributes::~ExtendedAttributes() throw ()
427 {
428     m_pHandler->release();
429 
430     delete [] m_pUids;
431     delete [] m_pPrefixes;
432     delete [] m_pLocalNames;
433     delete [] m_pQNames;
434     delete [] m_pValues;
435 }
436 
437 
438 //##############################################################################
439 
440 // XServiceInfo
441 
442 //______________________________________________________________________________
443 OUString DocumentHandlerImpl::getImplementationName()
444     throw (RuntimeException)
445 {
446     return getImplementationName_DocumentHandlerImpl();
447 }
448 
449 //______________________________________________________________________________
450 sal_Bool DocumentHandlerImpl::supportsService(
451     OUString const & servicename )
452     throw (RuntimeException)
453 {
454     Sequence< OUString > names( getSupportedServiceNames_DocumentHandlerImpl() );
455     for ( sal_Int32 nPos = names.getLength(); nPos--; )
456     {
457         if (names[ nPos ].equals( servicename ))
458             return sal_True;
459     }
460     return sal_False;
461 }
462 
463 //______________________________________________________________________________
464 Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames()
465     throw (RuntimeException)
466 {
467     return getSupportedServiceNames_DocumentHandlerImpl();
468 }
469 
470 // XInitialization
471 
472 //______________________________________________________________________________
473 void DocumentHandlerImpl::initialize(
474     Sequence< Any > const & arguments )
475     throw (Exception)
476 {
477     MGuard guard( m_pMutex );
478     Reference< xml::input::XRoot > xRoot;
479     if (arguments.getLength() == 1 &&
480         (arguments[ 0 ] >>= xRoot) &&
481         xRoot.is())
482     {
483         m_xRoot = xRoot;
484     }
485     else
486     {
487         throw RuntimeException(
488             OUString( RTL_CONSTASCII_USTRINGPARAM(
489                           "missing root instance!") ),
490             Reference< XInterface >() );
491     }
492 }
493 
494 
495 // XNamespaceMapping
496 
497 //______________________________________________________________________________
498 sal_Int32 DocumentHandlerImpl::getUidByUri( OUString const & Uri )
499     throw (RuntimeException)
500 {
501     sal_Int32 uid = getUidByURI( Uri );
502     OSL_ASSERT( uid != UID_UNKNOWN );
503     return uid;
504 }
505 
506 //______________________________________________________________________________
507 OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid )
508     throw (container::NoSuchElementException, RuntimeException)
509 {
510     MGuard guard( m_pMutex );
511     t_OUString2LongMap::const_iterator iPos( m_URI2Uid.begin() );
512     t_OUString2LongMap::const_iterator const iEnd( m_URI2Uid.end() );
513     for ( ; iPos != iEnd; ++iPos )
514     {
515         if (iPos->second == Uid)
516             return iPos->first;
517     }
518     throw container::NoSuchElementException(
519         OUString( RTL_CONSTASCII_USTRINGPARAM("no such xmlns uid!") ),
520         static_cast< OWeakObject * >(this) );
521 }
522 
523 
524 // XDocumentHandler
525 
526 //______________________________________________________________________________
527 void DocumentHandlerImpl::startDocument()
528     throw (xml::sax::SAXException, RuntimeException)
529 {
530     m_xRoot->startDocument(
531         static_cast< xml::input::XNamespaceMapping * >( this ) );
532 }
533 
534 //______________________________________________________________________________
535 void DocumentHandlerImpl::endDocument()
536     throw (xml::sax::SAXException, RuntimeException)
537 {
538     m_xRoot->endDocument();
539 }
540 
541 //______________________________________________________________________________
542 void DocumentHandlerImpl::startElement(
543     OUString const & rQElementName,
544     Reference< xml::sax::XAttributeList > const & xAttribs )
545     throw (xml::sax::SAXException, RuntimeException)
546 {
547     Reference< xml::input::XElement > xCurrentElement;
548     Reference< xml::input::XAttributes > xAttributes;
549     sal_Int32 nUid;
550     OUString aLocalName;
551     ::std::auto_ptr< ElementEntry > elementEntry( new ElementEntry );
552 
553     { // guard start:
554     MGuard aGuard( m_pMutex );
555     // currently skipping elements and waiting for end tags?
556     if (m_nSkipElements > 0)
557     {
558         ++m_nSkipElements; // wait for another end tag
559 #if OSL_DEBUG_LEVEL > 1
560         OString aQName(
561             OUStringToOString( rQElementName, RTL_TEXTENCODING_ASCII_US ) );
562         OSL_TRACE( "### no context given on createChildElement() "
563                    "=> ignoring element \"%s\" ...", aQName.getStr() );
564 #endif
565         return;
566     }
567 
568     sal_Int16 nAttribs = xAttribs->getLength();
569 
570     // save all namespace ids
571     sal_Int32 * pUids = new sal_Int32[ nAttribs ];
572     OUString * pPrefixes = new OUString[ nAttribs ];
573     OUString * pLocalNames = new OUString[ nAttribs ];
574     OUString * pQNames = new OUString[ nAttribs ];
575 
576     // first recognize all xmlns attributes
577     sal_Int16 nPos;
578     for ( nPos = 0; nPos < nAttribs; ++nPos )
579     {
580         // mark attribute to be collected further
581         // on with attribute's uid and current prefix
582         pUids[ nPos ] = 0; // modified
583 
584         pQNames[ nPos ] = xAttribs->getNameByIndex( nPos );
585         OUString const & rQAttributeName = pQNames[ nPos ];
586 
587         if (rQAttributeName.compareTo( m_sXMLNS, 5 ) == 0)
588         {
589             if (rQAttributeName.getLength() == 5) // set default namespace
590             {
591                 OUString aDefNamespacePrefix;
592                 pushPrefix(
593                     aDefNamespacePrefix,
594                     xAttribs->getValueByIndex( nPos ) );
595                 elementEntry->m_prefixes.push_back( aDefNamespacePrefix );
596                 pUids[ nPos ]          = UID_UNKNOWN;
597                 pPrefixes[ nPos ]      = m_sXMLNS;
598                 pLocalNames[ nPos ]    = aDefNamespacePrefix;
599             }
600             else if ((sal_Unicode)':' == rQAttributeName[ 5 ]) // set prefix
601             {
602                 OUString aPrefix( rQAttributeName.copy( 6 ) );
603                 pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) );
604                 elementEntry->m_prefixes.push_back( aPrefix );
605                 pUids[ nPos ]          = UID_UNKNOWN;
606                 pPrefixes[ nPos ]      = m_sXMLNS;
607                 pLocalNames[ nPos ]    = aPrefix;
608             }
609             // else just a name starting with xmlns, but no prefix
610         }
611     }
612 
613     // now read out attribute prefixes (all namespace prefixes have been set)
614     for ( nPos = 0; nPos < nAttribs; ++nPos )
615     {
616         if (pUids[ nPos ] >= 0) // no xmlns: attribute
617         {
618             OUString const & rQAttributeName = pQNames[ nPos ];
619             OSL_ENSURE(
620                 rQAttributeName.compareToAscii(
621                     RTL_CONSTASCII_STRINGPARAM("xmlns:") ) != 0,
622                 "### unexpected xmlns!" );
623 
624             // collect attribute's uid and current prefix
625             sal_Int32 nColonPos = rQAttributeName.indexOf( (sal_Unicode) ':' );
626             if (nColonPos >= 0)
627             {
628                 pPrefixes[ nPos ] = rQAttributeName.copy( 0, nColonPos );
629                 pLocalNames[ nPos ] = rQAttributeName.copy( nColonPos +1 );
630             }
631             else
632             {
633                 pPrefixes[ nPos ] = OUString();
634                 pLocalNames[ nPos ] = rQAttributeName;
635                 // leave local names unmodified
636             }
637             pUids[ nPos ] = getUidByPrefix( pPrefixes[ nPos ] );
638         }
639     }
640     // ownership of arrays belongs to attribute list
641     xAttributes = static_cast< xml::input::XAttributes * >(
642         new ExtendedAttributes(
643             nAttribs, pUids, pPrefixes, pLocalNames, pQNames,
644             xAttribs, this ) );
645 
646     getElementName( rQElementName, &nUid, &aLocalName );
647 
648     // create new child context and append to list
649     if (! m_elements.empty())
650         xCurrentElement = m_elements.back()->m_xElement;
651     } // :guard end
652 
653     if (xCurrentElement.is())
654     {
655         elementEntry->m_xElement =
656             xCurrentElement->startChildElement( nUid, aLocalName, xAttributes );
657     }
658     else
659     {
660         elementEntry->m_xElement =
661             m_xRoot->startRootElement( nUid, aLocalName, xAttributes );
662     }
663 
664     {
665     MGuard aGuard( m_pMutex );
666     if (elementEntry->m_xElement.is())
667     {
668         m_elements.push_back( elementEntry.release() );
669     }
670     else
671     {
672         ++m_nSkipElements;
673 #if OSL_DEBUG_LEVEL > 1
674         OString aQName(
675             OUStringToOString( rQElementName, RTL_TEXTENCODING_ASCII_US ) );
676         OSL_TRACE(
677             "### no context given on createChildElement() => "
678             "ignoring element \"%s\" ...", aQName.getStr() );
679 #endif
680     }
681     }
682 }
683 
684 //______________________________________________________________________________
685 void DocumentHandlerImpl::endElement(
686     OUString const & rQElementName )
687     throw (xml::sax::SAXException, RuntimeException)
688 {
689     Reference< xml::input::XElement > xCurrentElement;
690     {
691     MGuard aGuard( m_pMutex );
692     if (m_nSkipElements)
693     {
694         --m_nSkipElements;
695 #if OSL_DEBUG_LEVEL > 1
696         OString aQName(
697             OUStringToOString( rQElementName, RTL_TEXTENCODING_ASCII_US ) );
698         OSL_TRACE( "### received endElement() for \"%s\".", aQName.getStr() );
699 #endif
700         static_cast<void>(rQElementName);
701         return;
702     }
703 
704     // popping context
705     OSL_ASSERT( ! m_elements.empty() );
706     ElementEntry * pEntry = m_elements.back();
707     xCurrentElement = pEntry->m_xElement;
708 
709 #if OSL_DEBUG_LEVEL > 0
710     sal_Int32 nUid;
711     OUString aLocalName;
712     getElementName( rQElementName, &nUid, &aLocalName );
713     OSL_ASSERT( xCurrentElement->getLocalName() == aLocalName );
714     OSL_ASSERT( xCurrentElement->getUid() == nUid );
715 #endif
716 
717     // pop prefixes
718     for ( sal_Int32 nPos = pEntry->m_prefixes.size(); nPos--; )
719     {
720         popPrefix( pEntry->m_prefixes[ nPos ] );
721     }
722     m_elements.pop_back();
723     delete pEntry;
724     }
725     xCurrentElement->endElement();
726 }
727 
728 //______________________________________________________________________________
729 void DocumentHandlerImpl::characters( OUString const & rChars )
730     throw (xml::sax::SAXException, RuntimeException)
731 {
732     Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
733     if (xCurrentElement.is())
734         xCurrentElement->characters( rChars );
735 }
736 
737 //______________________________________________________________________________
738 void DocumentHandlerImpl::ignorableWhitespace(
739     OUString const & rWhitespaces )
740     throw (xml::sax::SAXException, RuntimeException)
741 {
742     Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
743     if (xCurrentElement.is())
744         xCurrentElement->ignorableWhitespace( rWhitespaces );
745 }
746 
747 //______________________________________________________________________________
748 void DocumentHandlerImpl::processingInstruction(
749     OUString const & rTarget, OUString const & rData )
750     throw (xml::sax::SAXException, RuntimeException)
751 {
752     Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
753     if (xCurrentElement.is())
754         xCurrentElement->processingInstruction( rTarget, rData );
755     else
756         m_xRoot->processingInstruction( rTarget, rData );
757 }
758 
759 //______________________________________________________________________________
760 void DocumentHandlerImpl::setDocumentLocator(
761     Reference< xml::sax::XLocator > const & xLocator )
762     throw (xml::sax::SAXException, RuntimeException)
763 {
764     m_xRoot->setDocumentLocator( xLocator );
765 }
766 
767 //##############################################################################
768 
769 // XAttributes
770 
771 //______________________________________________________________________________
772 sal_Int32 ExtendedAttributes::getIndexByQName( OUString const & rQName )
773     throw (RuntimeException)
774 {
775     for ( sal_Int32 nPos = m_nAttributes; nPos--; )
776     {
777         if (m_pQNames[ nPos ].equals( rQName ))
778         {
779             return nPos;
780         }
781     }
782     return -1;
783 }
784 
785 //______________________________________________________________________________
786 sal_Int32 ExtendedAttributes::getLength()
787     throw (RuntimeException)
788 {
789     return m_nAttributes;
790 }
791 
792 //______________________________________________________________________________
793 OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex )
794     throw (RuntimeException)
795 {
796     if (nIndex < m_nAttributes)
797         return m_pLocalNames[ nIndex ];
798     else
799         return OUString();
800 }
801 
802 //______________________________________________________________________________
803 OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex )
804     throw (RuntimeException)
805 {
806     if (nIndex < m_nAttributes)
807         return m_pQNames[ nIndex ];
808     else
809         return OUString();
810 }
811 
812 //______________________________________________________________________________
813 OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex )
814     throw (RuntimeException)
815 {
816     static_cast<void>(nIndex);
817     OSL_ASSERT( nIndex < m_nAttributes );
818     return OUString(); // unsupported
819 }
820 
821 //______________________________________________________________________________
822 OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex )
823     throw (RuntimeException)
824 {
825     if (nIndex < m_nAttributes)
826         return m_pValues[ nIndex ];
827     else
828         return OUString();
829 }
830 
831 //______________________________________________________________________________
832 sal_Int32 ExtendedAttributes::getIndexByUidName(
833     sal_Int32 nUid, OUString const & rLocalName )
834     throw (RuntimeException)
835 {
836     for ( sal_Int32 nPos = m_nAttributes; nPos--; )
837     {
838         if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
839         {
840             return nPos;
841         }
842     }
843     return -1;
844 }
845 
846 //______________________________________________________________________________
847 sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex )
848     throw (RuntimeException)
849 {
850     if (nIndex < m_nAttributes)
851         return m_pUids[ nIndex ];
852     else
853         return -1;
854 }
855 
856 //______________________________________________________________________________
857 OUString ExtendedAttributes::getValueByUidName(
858     sal_Int32 nUid, OUString const & rLocalName )
859     throw (RuntimeException)
860 {
861     for ( sal_Int32 nPos = m_nAttributes; nPos--; )
862     {
863         if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
864         {
865             return m_pValues[ nPos ];
866         }
867     }
868     return OUString();
869 }
870 
871 
872 //##############################################################################
873 
874 
875 //==============================================================================
876 Reference< xml::sax::XDocumentHandler > SAL_CALL createDocumentHandler(
877     Reference< xml::input::XRoot > const & xRoot,
878     bool bSingleThreadedUse )
879     SAL_THROW( () )
880 {
881     OSL_ASSERT( xRoot.is() );
882     if (xRoot.is())
883     {
884         return static_cast< xml::sax::XDocumentHandler * >(
885             new DocumentHandlerImpl( xRoot, bSingleThreadedUse ) );
886     }
887     return Reference< xml::sax::XDocumentHandler >();
888 }
889 
890 //------------------------------------------------------------------------------
891 Reference< XInterface > SAL_CALL create_DocumentHandlerImpl(
892     Reference< XComponentContext > const & )
893     SAL_THROW( (Exception) )
894 {
895     return static_cast< ::cppu::OWeakObject * >(
896         new DocumentHandlerImpl(
897             Reference< xml::input::XRoot >(), false /* mt use */ ) );
898 }
899 
900 }
901