xref: /trunk/main/xmlscript/source/xml_helper/xml_impctx.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 "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 
getSupportedServiceNames_DocumentHandlerImpl()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 
getImplementationName_DocumentHandlerImpl()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 
ElementEntryxmlscript::ElementEntry88     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;
MGuardxmlscript::MGuard100     explicit MGuard( Mutex * pMutex )
101         : m_pMutex( pMutex )
102         { if (m_pMutex) m_pMutex->acquire(); }
~MGuardxmlscript::MGuard103     ~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     virtual sal_Bool SAL_CALL supportsService(
156         OUString const & servicename );
157     virtual Sequence< OUString > SAL_CALL getSupportedServiceNames();
158 
159     // XInitialization
160     virtual void SAL_CALL initialize(
161         Sequence< Any > const & arguments );
162 
163     // XDocumentHandler
164     virtual void SAL_CALL startDocument();
165     virtual void SAL_CALL endDocument();
166     virtual void SAL_CALL startElement(
167         OUString const & rQElementName,
168         Reference< xml::sax::XAttributeList > const & xAttribs );
169     virtual void SAL_CALL endElement(
170         OUString const & rQElementName );
171     virtual void SAL_CALL characters(
172         OUString const & rChars );
173     virtual void SAL_CALL ignorableWhitespace(
174         OUString const & rWhitespaces );
175     virtual void SAL_CALL processingInstruction(
176         OUString const & rTarget, OUString const & rData );
177     virtual void SAL_CALL setDocumentLocator(
178         Reference< xml::sax::XLocator > const & xLocator );
179 
180     // XNamespaceMapping
181     virtual sal_Int32 SAL_CALL getUidByUri( OUString const & Uri );
182     virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid );
183 };
184 
185 //______________________________________________________________________________
DocumentHandlerImpl(Reference<xml::input::XRoot> const & xRoot,bool bSingleThreadedUse)186 DocumentHandlerImpl::DocumentHandlerImpl(
187     Reference< xml::input::XRoot > const & xRoot,
188     bool bSingleThreadedUse )
189     : m_xRoot( xRoot ),
190       m_uid_count( 0 ),
191       m_sXMLNS_PREFIX_UNKNOWN(
192           RTL_CONSTASCII_USTRINGPARAM("<<< unknown prefix >>>") ),
193       m_sXMLNS( RTL_CONSTASCII_USTRINGPARAM("xmlns") ),
194       m_nLastURI_lookup( UID_UNKNOWN ),
195       m_aLastURI_lookup( RTL_CONSTASCII_USTRINGPARAM("<<< unknown URI >>>") ),
196       m_nLastPrefix_lookup( UID_UNKNOWN ),
197       m_aLastPrefix_lookup(
198           RTL_CONSTASCII_USTRINGPARAM("<<< unknown URI >>>") ),
199       m_nSkipElements( 0 ),
200       m_pMutex( 0 )
201 {
202     m_elements.reserve( 10 );
203 
204     if (! bSingleThreadedUse)
205         m_pMutex = new Mutex();
206 }
207 
208 //______________________________________________________________________________
~DocumentHandlerImpl()209 DocumentHandlerImpl::~DocumentHandlerImpl() throw ()
210 {
211     if (m_pMutex != 0)
212     {
213         delete m_pMutex;
214 #if OSL_DEBUG_LEVEL == 0
215         m_pMutex = 0;
216 #endif
217     }
218 }
219 
220 //______________________________________________________________________________
221 inline Reference< xml::input::XElement >
getCurrentElement() const222 DocumentHandlerImpl::getCurrentElement() const
223 {
224     MGuard aGuard( m_pMutex );
225     if (m_elements.empty())
226         return Reference< xml::input::XElement >();
227     else
228         return m_elements.back()->m_xElement;
229 }
230 
231 //______________________________________________________________________________
getUidByURI(OUString const & rURI)232 inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString const & rURI )
233 {
234     MGuard guard( m_pMutex );
235     if (m_nLastURI_lookup == UID_UNKNOWN || m_aLastURI_lookup != rURI)
236     {
237         t_OUString2LongMap::const_iterator iFind( m_URI2Uid.find( rURI ) );
238         if (iFind != m_URI2Uid.end()) // id found
239         {
240             m_nLastURI_lookup = iFind->second;
241             m_aLastURI_lookup = rURI;
242         }
243         else
244         {
245             m_nLastURI_lookup = m_uid_count;
246             ++m_uid_count;
247             m_URI2Uid[ rURI ] = m_nLastURI_lookup;
248             m_aLastURI_lookup = rURI;
249         }
250     }
251     return m_nLastURI_lookup;
252 }
253 
254 //______________________________________________________________________________
getUidByPrefix(OUString const & rPrefix)255 inline sal_Int32 DocumentHandlerImpl::getUidByPrefix(
256     OUString const & rPrefix )
257 {
258     // commonly the last added prefix is used often for several tags...
259     // good guess
260     if (m_nLastPrefix_lookup == UID_UNKNOWN || m_aLastPrefix_lookup != rPrefix)
261     {
262         t_OUString2PrefixMap::const_iterator iFind(
263             m_prefixes.find( rPrefix ) );
264         if (iFind != m_prefixes.end())
265         {
266             const PrefixEntry & rPrefixEntry = *iFind->second;
267             OSL_ASSERT( ! rPrefixEntry.m_Uids.empty() );
268             m_nLastPrefix_lookup = rPrefixEntry.m_Uids.back();
269             m_aLastPrefix_lookup = rPrefix;
270         }
271         else
272         {
273             m_nLastPrefix_lookup = UID_UNKNOWN;
274             m_aLastPrefix_lookup = m_sXMLNS_PREFIX_UNKNOWN;
275         }
276     }
277     return m_nLastPrefix_lookup;
278 }
279 
280 //______________________________________________________________________________
pushPrefix(OUString const & rPrefix,OUString const & rURI)281 inline void DocumentHandlerImpl::pushPrefix(
282     OUString const & rPrefix, OUString const & rURI )
283 {
284     // lookup id for URI
285     sal_Int32 nUid = getUidByURI( rURI );
286 
287     // mark prefix with id
288     t_OUString2PrefixMap::const_iterator iFind( m_prefixes.find( rPrefix ) );
289     if (iFind == m_prefixes.end()) // unused prefix
290     {
291         PrefixEntry * pEntry = new PrefixEntry();
292         pEntry->m_Uids.push_back( nUid ); // latest id for prefix
293         m_prefixes[ rPrefix ] = pEntry;
294     }
295     else
296     {
297         PrefixEntry * pEntry = iFind->second;
298         OSL_ASSERT( ! pEntry->m_Uids.empty() );
299         pEntry->m_Uids.push_back( nUid );
300     }
301 
302     m_aLastPrefix_lookup = rPrefix;
303     m_nLastPrefix_lookup = nUid;
304 }
305 
306 //______________________________________________________________________________
popPrefix(OUString const & rPrefix)307 inline void DocumentHandlerImpl::popPrefix(
308     OUString const & rPrefix )
309 {
310     t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) );
311     if (iFind != m_prefixes.end()) // unused prefix
312     {
313         PrefixEntry * pEntry = iFind->second;
314         pEntry->m_Uids.pop_back(); // pop last id for prefix
315         if (pEntry->m_Uids.empty()) // erase prefix key
316         {
317             m_prefixes.erase( iFind );
318             delete pEntry;
319         }
320     }
321 
322     m_nLastPrefix_lookup = UID_UNKNOWN;
323     m_aLastPrefix_lookup = m_sXMLNS_PREFIX_UNKNOWN;
324 }
325 
326 //______________________________________________________________________________
getElementName(OUString const & rQName,sal_Int32 * pUid,OUString * pLocalName)327 inline void DocumentHandlerImpl::getElementName(
328     OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName )
329 {
330     sal_Int32 nColonPos = rQName.indexOf( (sal_Unicode)':' );
331     *pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName);
332     *pUid = getUidByPrefix(
333         nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() );
334 }
335 
336 
337 //==============================================================================
338 class ExtendedAttributes :
339     public ::cppu::WeakImplHelper1< xml::input::XAttributes >
340 {
341     sal_Int32 m_nAttributes;
342     sal_Int32 * m_pUids;
343     OUString * m_pPrefixes;
344     OUString * m_pLocalNames;
345     OUString * m_pQNames;
346     OUString * m_pValues;
347 
348     DocumentHandlerImpl * m_pHandler;
349 
350 public:
351     inline ExtendedAttributes(
352         sal_Int32 nAttributes,
353         sal_Int32 * pUids, OUString * pPrefixes,
354         OUString * pLocalNames, OUString * pQNames,
355         Reference< xml::sax::XAttributeList > const & xAttributeList,
356         DocumentHandlerImpl * pHandler );
357     virtual ~ExtendedAttributes() throw ();
358 
359     // XAttributes
360     virtual sal_Int32 SAL_CALL getLength();
361     virtual sal_Int32 SAL_CALL getIndexByQName(
362         OUString const & rQName );
363     virtual sal_Int32 SAL_CALL getIndexByUidName(
364         sal_Int32 nUid, OUString const & rLocalName );
365     virtual OUString SAL_CALL getQNameByIndex(
366         sal_Int32 nIndex );
367     virtual sal_Int32 SAL_CALL getUidByIndex(
368         sal_Int32 nIndex );
369     virtual OUString SAL_CALL getLocalNameByIndex(
370         sal_Int32 nIndex );
371     virtual OUString SAL_CALL getValueByIndex(
372         sal_Int32 nIndex );
373     virtual OUString SAL_CALL getValueByUidName(
374         sal_Int32 nUid, OUString const & rLocalName );
375     virtual OUString SAL_CALL getTypeByIndex(
376         sal_Int32 nIndex );
377 };
378 
379 //______________________________________________________________________________
ExtendedAttributes(sal_Int32 nAttributes,sal_Int32 * pUids,OUString * pPrefixes,OUString * pLocalNames,OUString * pQNames,Reference<xml::sax::XAttributeList> const & xAttributeList,DocumentHandlerImpl * pHandler)380 inline ExtendedAttributes::ExtendedAttributes(
381     sal_Int32 nAttributes,
382     sal_Int32 * pUids, OUString * pPrefixes,
383     OUString * pLocalNames, OUString * pQNames,
384     Reference< xml::sax::XAttributeList > const & xAttributeList,
385     DocumentHandlerImpl * pHandler )
386     : m_nAttributes( nAttributes )
387     , m_pUids( pUids )
388     , m_pPrefixes( pPrefixes )
389     , m_pLocalNames( pLocalNames )
390     , m_pQNames( pQNames )
391     , m_pValues( new OUString[ nAttributes ] )
392     , m_pHandler( pHandler )
393 {
394     m_pHandler->acquire();
395 
396     for ( sal_Int16 nPos = 0; nPos < nAttributes; ++nPos )
397     {
398         m_pValues[ nPos ] = xAttributeList->getValueByIndex( nPos );
399     }
400 }
401 
402 //______________________________________________________________________________
~ExtendedAttributes()403 ExtendedAttributes::~ExtendedAttributes() throw ()
404 {
405     m_pHandler->release();
406 
407     delete [] m_pUids;
408     delete [] m_pPrefixes;
409     delete [] m_pLocalNames;
410     delete [] m_pQNames;
411     delete [] m_pValues;
412 }
413 
414 
415 //##############################################################################
416 
417 // XServiceInfo
418 
419 //______________________________________________________________________________
getImplementationName()420 OUString DocumentHandlerImpl::getImplementationName()
421 {
422     return getImplementationName_DocumentHandlerImpl();
423 }
424 
425 //______________________________________________________________________________
supportsService(OUString const & servicename)426 sal_Bool DocumentHandlerImpl::supportsService(
427     OUString const & servicename )
428 {
429     Sequence< OUString > names( getSupportedServiceNames_DocumentHandlerImpl() );
430     for ( sal_Int32 nPos = names.getLength(); nPos--; )
431     {
432         if (names[ nPos ].equals( servicename ))
433             return sal_True;
434     }
435     return sal_False;
436 }
437 
438 //______________________________________________________________________________
getSupportedServiceNames()439 Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames()
440 {
441     return getSupportedServiceNames_DocumentHandlerImpl();
442 }
443 
444 // XInitialization
445 
446 //______________________________________________________________________________
initialize(Sequence<Any> const & arguments)447 void DocumentHandlerImpl::initialize(
448     Sequence< Any > const & arguments )
449 {
450     MGuard guard( m_pMutex );
451     Reference< xml::input::XRoot > xRoot;
452     if (arguments.getLength() == 1 &&
453         (arguments[ 0 ] >>= xRoot) &&
454         xRoot.is())
455     {
456         m_xRoot = xRoot;
457     }
458     else
459     {
460         throw RuntimeException(
461             OUString( RTL_CONSTASCII_USTRINGPARAM(
462                           "missing root instance!") ),
463             Reference< XInterface >() );
464     }
465 }
466 
467 
468 // XNamespaceMapping
469 
470 //______________________________________________________________________________
getUidByUri(OUString const & Uri)471 sal_Int32 DocumentHandlerImpl::getUidByUri( OUString const & Uri )
472 {
473     sal_Int32 uid = getUidByURI( Uri );
474     OSL_ASSERT( uid != UID_UNKNOWN );
475     return uid;
476 }
477 
478 //______________________________________________________________________________
getUriByUid(sal_Int32 Uid)479 OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid )
480 {
481     MGuard guard( m_pMutex );
482     t_OUString2LongMap::const_iterator iPos( m_URI2Uid.begin() );
483     t_OUString2LongMap::const_iterator const iEnd( m_URI2Uid.end() );
484     for ( ; iPos != iEnd; ++iPos )
485     {
486         if (iPos->second == Uid)
487             return iPos->first;
488     }
489     throw container::NoSuchElementException(
490         OUString( RTL_CONSTASCII_USTRINGPARAM("no such xmlns uid!") ),
491         static_cast< OWeakObject * >(this) );
492 }
493 
494 
495 // XDocumentHandler
496 
497 //______________________________________________________________________________
startDocument()498 void DocumentHandlerImpl::startDocument()
499 {
500     m_xRoot->startDocument(
501         static_cast< xml::input::XNamespaceMapping * >( this ) );
502 }
503 
504 //______________________________________________________________________________
endDocument()505 void DocumentHandlerImpl::endDocument()
506 {
507     m_xRoot->endDocument();
508 }
509 
510 //______________________________________________________________________________
startElement(OUString const & rQElementName,Reference<xml::sax::XAttributeList> const & xAttribs)511 void DocumentHandlerImpl::startElement(
512     OUString const & rQElementName,
513     Reference< xml::sax::XAttributeList > const & xAttribs )
514 {
515     Reference< xml::input::XElement > xCurrentElement;
516     Reference< xml::input::XAttributes > xAttributes;
517     sal_Int32 nUid;
518     OUString aLocalName;
519     ::std::auto_ptr< ElementEntry > elementEntry( new ElementEntry );
520 
521     { // guard start:
522     MGuard aGuard( m_pMutex );
523     // currently skipping elements and waiting for end tags?
524     if (m_nSkipElements > 0)
525     {
526         ++m_nSkipElements; // wait for another end tag
527 #if OSL_DEBUG_LEVEL > 1
528         OString aQName(
529             OUStringToOString( rQElementName, RTL_TEXTENCODING_ASCII_US ) );
530         OSL_TRACE( "### no context given on createChildElement() "
531                    "=> ignoring element \"%s\" ...", aQName.getStr() );
532 #endif
533         return;
534     }
535 
536     sal_Int16 nAttribs = xAttribs->getLength();
537 
538     // save all namespace ids
539     sal_Int32 * pUids = new sal_Int32[ nAttribs ];
540     OUString * pPrefixes = new OUString[ nAttribs ];
541     OUString * pLocalNames = new OUString[ nAttribs ];
542     OUString * pQNames = new OUString[ nAttribs ];
543 
544     // first recognize all xmlns attributes
545     sal_Int16 nPos;
546     for ( nPos = 0; nPos < nAttribs; ++nPos )
547     {
548         // mark attribute to be collected further
549         // on with attribute's uid and current prefix
550         pUids[ nPos ] = 0; // modified
551 
552         pQNames[ nPos ] = xAttribs->getNameByIndex( nPos );
553         OUString const & rQAttributeName = pQNames[ nPos ];
554 
555         if (rQAttributeName.compareTo( m_sXMLNS, 5 ) == 0)
556         {
557             if (rQAttributeName.getLength() == 5) // set default namespace
558             {
559                 OUString aDefNamespacePrefix;
560                 pushPrefix(
561                     aDefNamespacePrefix,
562                     xAttribs->getValueByIndex( nPos ) );
563                 elementEntry->m_prefixes.push_back( aDefNamespacePrefix );
564                 pUids[ nPos ]          = UID_UNKNOWN;
565                 pPrefixes[ nPos ]      = m_sXMLNS;
566                 pLocalNames[ nPos ]    = aDefNamespacePrefix;
567             }
568             else if ((sal_Unicode)':' == rQAttributeName[ 5 ]) // set prefix
569             {
570                 OUString aPrefix( rQAttributeName.copy( 6 ) );
571                 pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) );
572                 elementEntry->m_prefixes.push_back( aPrefix );
573                 pUids[ nPos ]          = UID_UNKNOWN;
574                 pPrefixes[ nPos ]      = m_sXMLNS;
575                 pLocalNames[ nPos ]    = aPrefix;
576             }
577             // else just a name starting with xmlns, but no prefix
578         }
579     }
580 
581     // now read out attribute prefixes (all namespace prefixes have been set)
582     for ( nPos = 0; nPos < nAttribs; ++nPos )
583     {
584         if (pUids[ nPos ] >= 0) // no xmlns: attribute
585         {
586             OUString const & rQAttributeName = pQNames[ nPos ];
587             OSL_ENSURE(
588                 rQAttributeName.compareToAscii(
589                     RTL_CONSTASCII_STRINGPARAM("xmlns:") ) != 0,
590                 "### unexpected xmlns!" );
591 
592             // collect attribute's uid and current prefix
593             sal_Int32 nColonPos = rQAttributeName.indexOf( (sal_Unicode) ':' );
594             if (nColonPos >= 0)
595             {
596                 pPrefixes[ nPos ] = rQAttributeName.copy( 0, nColonPos );
597                 pLocalNames[ nPos ] = rQAttributeName.copy( nColonPos +1 );
598             }
599             else
600             {
601                 pPrefixes[ nPos ] = OUString();
602                 pLocalNames[ nPos ] = rQAttributeName;
603                 // leave local names unmodified
604             }
605             pUids[ nPos ] = getUidByPrefix( pPrefixes[ nPos ] );
606         }
607     }
608     // ownership of arrays belongs to attribute list
609     xAttributes = static_cast< xml::input::XAttributes * >(
610         new ExtendedAttributes(
611             nAttribs, pUids, pPrefixes, pLocalNames, pQNames,
612             xAttribs, this ) );
613 
614     getElementName( rQElementName, &nUid, &aLocalName );
615 
616     // create new child context and append to list
617     if (! m_elements.empty())
618         xCurrentElement = m_elements.back()->m_xElement;
619     } // :guard end
620 
621     if (xCurrentElement.is())
622     {
623         elementEntry->m_xElement =
624             xCurrentElement->startChildElement( nUid, aLocalName, xAttributes );
625     }
626     else
627     {
628         elementEntry->m_xElement =
629             m_xRoot->startRootElement( nUid, aLocalName, xAttributes );
630     }
631 
632     {
633     MGuard aGuard( m_pMutex );
634     if (elementEntry->m_xElement.is())
635     {
636         m_elements.push_back( elementEntry.release() );
637     }
638     else
639     {
640         ++m_nSkipElements;
641 #if OSL_DEBUG_LEVEL > 1
642         OString aQName(
643             OUStringToOString( rQElementName, RTL_TEXTENCODING_ASCII_US ) );
644         OSL_TRACE(
645             "### no context given on createChildElement() => "
646             "ignoring element \"%s\" ...", aQName.getStr() );
647 #endif
648     }
649     }
650 }
651 
652 //______________________________________________________________________________
endElement(OUString const & rQElementName)653 void DocumentHandlerImpl::endElement(
654     OUString const & rQElementName )
655 {
656     Reference< xml::input::XElement > xCurrentElement;
657     {
658     MGuard aGuard( m_pMutex );
659     if (m_nSkipElements)
660     {
661         --m_nSkipElements;
662 #if OSL_DEBUG_LEVEL > 1
663         OString aQName(
664             OUStringToOString( rQElementName, RTL_TEXTENCODING_ASCII_US ) );
665         OSL_TRACE( "### received endElement() for \"%s\".", aQName.getStr() );
666 #endif
667         static_cast<void>(rQElementName);
668         return;
669     }
670 
671     // popping context
672     OSL_ASSERT( ! m_elements.empty() );
673     ElementEntry * pEntry = m_elements.back();
674     xCurrentElement = pEntry->m_xElement;
675 
676 #if OSL_DEBUG_LEVEL > 0
677     sal_Int32 nUid;
678     OUString aLocalName;
679     getElementName( rQElementName, &nUid, &aLocalName );
680     OSL_ASSERT( xCurrentElement->getLocalName() == aLocalName );
681     OSL_ASSERT( xCurrentElement->getUid() == nUid );
682 #endif
683 
684     // pop prefixes
685     for ( sal_Int32 nPos = pEntry->m_prefixes.size(); nPos--; )
686     {
687         popPrefix( pEntry->m_prefixes[ nPos ] );
688     }
689     m_elements.pop_back();
690     delete pEntry;
691     }
692     xCurrentElement->endElement();
693 }
694 
695 //______________________________________________________________________________
characters(OUString const & rChars)696 void DocumentHandlerImpl::characters( OUString const & rChars )
697 {
698     Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
699     if (xCurrentElement.is())
700         xCurrentElement->characters( rChars );
701 }
702 
703 //______________________________________________________________________________
ignorableWhitespace(OUString const & rWhitespaces)704 void DocumentHandlerImpl::ignorableWhitespace(
705     OUString const & rWhitespaces )
706 {
707     Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
708     if (xCurrentElement.is())
709         xCurrentElement->ignorableWhitespace( rWhitespaces );
710 }
711 
712 //______________________________________________________________________________
processingInstruction(OUString const & rTarget,OUString const & rData)713 void DocumentHandlerImpl::processingInstruction(
714     OUString const & rTarget, OUString const & rData )
715 {
716     Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
717     if (xCurrentElement.is())
718         xCurrentElement->processingInstruction( rTarget, rData );
719     else
720         m_xRoot->processingInstruction( rTarget, rData );
721 }
722 
723 //______________________________________________________________________________
setDocumentLocator(Reference<xml::sax::XLocator> const & xLocator)724 void DocumentHandlerImpl::setDocumentLocator(
725     Reference< xml::sax::XLocator > const & xLocator )
726 {
727     m_xRoot->setDocumentLocator( xLocator );
728 }
729 
730 //##############################################################################
731 
732 // XAttributes
733 
734 //______________________________________________________________________________
getIndexByQName(OUString const & rQName)735 sal_Int32 ExtendedAttributes::getIndexByQName( OUString const & rQName )
736 {
737     for ( sal_Int32 nPos = m_nAttributes; nPos--; )
738     {
739         if (m_pQNames[ nPos ].equals( rQName ))
740         {
741             return nPos;
742         }
743     }
744     return -1;
745 }
746 
747 //______________________________________________________________________________
getLength()748 sal_Int32 ExtendedAttributes::getLength()
749 {
750     return m_nAttributes;
751 }
752 
753 //______________________________________________________________________________
getLocalNameByIndex(sal_Int32 nIndex)754 OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex )
755 {
756     if (nIndex < m_nAttributes)
757         return m_pLocalNames[ nIndex ];
758     else
759         return OUString();
760 }
761 
762 //______________________________________________________________________________
getQNameByIndex(sal_Int32 nIndex)763 OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex )
764 {
765     if (nIndex < m_nAttributes)
766         return m_pQNames[ nIndex ];
767     else
768         return OUString();
769 }
770 
771 //______________________________________________________________________________
getTypeByIndex(sal_Int32 nIndex)772 OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex )
773 {
774     static_cast<void>(nIndex);
775     OSL_ASSERT( nIndex < m_nAttributes );
776     return OUString(); // unsupported
777 }
778 
779 //______________________________________________________________________________
getValueByIndex(sal_Int32 nIndex)780 OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex )
781 {
782     if (nIndex < m_nAttributes)
783         return m_pValues[ nIndex ];
784     else
785         return OUString();
786 }
787 
788 //______________________________________________________________________________
getIndexByUidName(sal_Int32 nUid,OUString const & rLocalName)789 sal_Int32 ExtendedAttributes::getIndexByUidName(
790     sal_Int32 nUid, OUString const & rLocalName )
791 {
792     for ( sal_Int32 nPos = m_nAttributes; nPos--; )
793     {
794         if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
795         {
796             return nPos;
797         }
798     }
799     return -1;
800 }
801 
802 //______________________________________________________________________________
getUidByIndex(sal_Int32 nIndex)803 sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex )
804 {
805     if (nIndex < m_nAttributes)
806         return m_pUids[ nIndex ];
807     else
808         return -1;
809 }
810 
811 //______________________________________________________________________________
getValueByUidName(sal_Int32 nUid,OUString const & rLocalName)812 OUString ExtendedAttributes::getValueByUidName(
813     sal_Int32 nUid, OUString const & rLocalName )
814 {
815     for ( sal_Int32 nPos = m_nAttributes; nPos--; )
816     {
817         if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
818         {
819             return m_pValues[ nPos ];
820         }
821     }
822     return OUString();
823 }
824 
825 
826 //##############################################################################
827 
828 
829 //==============================================================================
createDocumentHandler(Reference<xml::input::XRoot> const & xRoot,bool bSingleThreadedUse)830 Reference< xml::sax::XDocumentHandler > SAL_CALL createDocumentHandler(
831     Reference< xml::input::XRoot > const & xRoot,
832     bool bSingleThreadedUse )
833     SAL_THROW( () )
834 {
835     OSL_ASSERT( xRoot.is() );
836     if (xRoot.is())
837     {
838         return static_cast< xml::sax::XDocumentHandler * >(
839             new DocumentHandlerImpl( xRoot, bSingleThreadedUse ) );
840     }
841     return Reference< xml::sax::XDocumentHandler >();
842 }
843 
844 //------------------------------------------------------------------------------
create_DocumentHandlerImpl(Reference<XComponentContext> const &)845 Reference< XInterface > SAL_CALL create_DocumentHandlerImpl(
846     Reference< XComponentContext > const & )
847 {
848     return static_cast< ::cppu::OWeakObject * >(
849         new DocumentHandlerImpl(
850             Reference< xml::input::XRoot >(), false /* mt use */ ) );
851 }
852 
853 }
854