1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <xml_import.hxx>
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>
36 #include <unordered_map>
39 using namespace ::osl
;
40 using namespace ::com::sun::star
;
41 using namespace ::com::sun::star::uno
;
46 const sal_Int32 UID_UNKNOWN
= -1;
48 typedef std::unordered_map
< OUString
, sal_Int32
> t_OUString2LongMap
;
54 ::std::vector
< sal_Int32
> m_Uids
;
57 { m_Uids
.reserve( 4 ); }
62 typedef std::unordered_map
<
63 OUString
, std::unique_ptr
<PrefixEntry
> > t_OUString2PrefixMap
;
69 Reference
< xml::input::XElement
> m_xElement
;
70 ::std::vector
< OUString
> m_prefixes
;
73 { m_prefixes
.reserve( 2 ); }
76 class ExtendedAttributes
;
80 std::mutex
* m_pMutex
;
82 explicit MGuard( std::optional
<std::mutex
> & oMutex
)
83 : m_pMutex( oMutex
? &*oMutex
: nullptr )
84 { if (m_pMutex
) m_pMutex
->lock(); }
86 { if (m_pMutex
) m_pMutex
->unlock(); }
89 class DocumentHandlerImpl
:
90 public ::cppu::WeakImplHelper
< xml::sax::XDocumentHandler
,
91 xml::input::XNamespaceMapping
,
92 lang::XInitialization
,
93 css::lang::XServiceInfo
>
95 friend class ExtendedAttributes
;
97 Reference
< xml::input::XRoot
> m_xRoot
;
99 t_OUString2LongMap m_URI2Uid
;
100 sal_Int32 m_uid_count
;
102 sal_Int32 m_nLastURI_lookup
;
103 OUString m_aLastURI_lookup
;
105 t_OUString2PrefixMap m_prefixes
;
106 sal_Int32 m_nLastPrefix_lookup
;
107 OUString m_aLastPrefix_lookup
;
109 std::vector
< ElementEntry
> m_elements
;
110 sal_Int32 m_nSkipElements
;
112 mutable std::optional
<std::mutex
> m_oMutex
;
114 inline Reference
< xml::input::XElement
> getCurrentElement() const;
116 inline sal_Int32
getUidByURI( OUString
const & rURI
);
117 inline sal_Int32
getUidByPrefix( OUString
const & rPrefix
);
119 inline void pushPrefix(
120 OUString
const & rPrefix
, OUString
const & rURI
);
121 inline void popPrefix( OUString
const & rPrefix
);
123 inline void getElementName(
124 OUString
const & rQName
, sal_Int32
* pUid
, OUString
* pLocalName
);
128 Reference
< xml::input::XRoot
> const & xRoot
,
129 bool bSingleThreadedUse
);
132 virtual OUString SAL_CALL
getImplementationName() override
;
133 virtual sal_Bool SAL_CALL
supportsService(
134 OUString
const & servicename
) override
;
135 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
138 virtual void SAL_CALL
initialize(
139 Sequence
< Any
> const & arguments
) override
;
142 virtual void SAL_CALL
startDocument() override
;
143 virtual void SAL_CALL
endDocument() override
;
144 virtual void SAL_CALL
startElement(
145 OUString
const & rQElementName
,
146 Reference
< xml::sax::XAttributeList
> const & xAttribs
) override
;
147 virtual void SAL_CALL
endElement(
148 OUString
const & rQElementName
) override
;
149 virtual void SAL_CALL
characters(
150 OUString
const & rChars
) override
;
151 virtual void SAL_CALL
ignorableWhitespace(
152 OUString
const & rWhitespaces
) override
;
153 virtual void SAL_CALL
processingInstruction(
154 OUString
const & rTarget
, OUString
const & rData
) override
;
155 virtual void SAL_CALL
setDocumentLocator(
156 Reference
< xml::sax::XLocator
> const & xLocator
) override
;
159 virtual sal_Int32 SAL_CALL
getUidByUri( OUString
const & Uri
) override
;
160 virtual OUString SAL_CALL
getUriByUid( sal_Int32 Uid
) override
;
165 constexpr OUStringLiteral
g_sXMLNS_PREFIX_UNKNOWN( u
"<<< unknown prefix >>>" );
166 constexpr OUStringLiteral
g_sXMLNS( u
"xmlns" );
169 DocumentHandlerImpl::DocumentHandlerImpl(
170 Reference
< xml::input::XRoot
> const & xRoot
,
171 bool bSingleThreadedUse
)
174 m_nLastURI_lookup( UID_UNKNOWN
),
175 m_aLastURI_lookup( "<<< unknown URI >>>" ),
176 m_nLastPrefix_lookup( UID_UNKNOWN
),
177 m_aLastPrefix_lookup( "<<< unknown URI >>>" ),
180 m_elements
.reserve( 10 );
182 if (! bSingleThreadedUse
)
186 inline Reference
< xml::input::XElement
>
187 DocumentHandlerImpl::getCurrentElement() const
189 MGuard
aGuard( m_oMutex
);
190 if (m_elements
.empty())
191 return Reference
< xml::input::XElement
>();
193 return m_elements
.back().m_xElement
;
196 inline sal_Int32
DocumentHandlerImpl::getUidByURI( OUString
const & rURI
)
198 MGuard
guard( m_oMutex
);
199 if (m_nLastURI_lookup
== UID_UNKNOWN
|| m_aLastURI_lookup
!= rURI
)
201 t_OUString2LongMap::const_iterator
iFind( m_URI2Uid
.find( rURI
) );
202 if (iFind
!= m_URI2Uid
.end()) // id found
204 m_nLastURI_lookup
= iFind
->second
;
205 m_aLastURI_lookup
= rURI
;
209 m_nLastURI_lookup
= m_uid_count
;
211 m_URI2Uid
[ rURI
] = m_nLastURI_lookup
;
212 m_aLastURI_lookup
= rURI
;
215 return m_nLastURI_lookup
;
218 inline sal_Int32
DocumentHandlerImpl::getUidByPrefix(
219 OUString
const & rPrefix
)
221 // commonly the last added prefix is used often for several tags...
223 if (m_nLastPrefix_lookup
== UID_UNKNOWN
|| m_aLastPrefix_lookup
!= rPrefix
)
225 t_OUString2PrefixMap::const_iterator
iFind(
226 m_prefixes
.find( rPrefix
) );
227 if (iFind
!= m_prefixes
.end())
229 const PrefixEntry
& rPrefixEntry
= *iFind
->second
;
230 SAL_WARN_IF( rPrefixEntry
.m_Uids
.empty(), "xmlscript.xmlhelper", "rPrefixEntry.m_Uids is empty" );
231 m_nLastPrefix_lookup
= rPrefixEntry
.m_Uids
.back();
232 m_aLastPrefix_lookup
= rPrefix
;
236 m_nLastPrefix_lookup
= UID_UNKNOWN
;
237 m_aLastPrefix_lookup
= g_sXMLNS_PREFIX_UNKNOWN
;
240 return m_nLastPrefix_lookup
;
243 inline void DocumentHandlerImpl::pushPrefix(
244 OUString
const & rPrefix
, OUString
const & rURI
)
247 sal_Int32 nUid
= getUidByURI( rURI
);
249 // mark prefix with id
250 t_OUString2PrefixMap::const_iterator
iFind( m_prefixes
.find( rPrefix
) );
251 if (iFind
== m_prefixes
.end()) // unused prefix
253 PrefixEntry
* pEntry
= new PrefixEntry();
254 pEntry
->m_Uids
.push_back( nUid
); // latest id for prefix
255 m_prefixes
[rPrefix
].reset(pEntry
);
259 PrefixEntry
& rEntry
= *iFind
->second
;
260 SAL_WARN_IF(rEntry
.m_Uids
.empty(), "xmlscript.xmlhelper", "pEntry->m_Uids is empty");
261 rEntry
.m_Uids
.push_back(nUid
);
264 m_aLastPrefix_lookup
= rPrefix
;
265 m_nLastPrefix_lookup
= nUid
;
268 inline void DocumentHandlerImpl::popPrefix(
269 OUString
const & rPrefix
)
271 t_OUString2PrefixMap::iterator
iFind( m_prefixes
.find( rPrefix
) );
272 if (iFind
!= m_prefixes
.end()) // unused prefix
274 PrefixEntry
& rEntry
= *iFind
->second
;
275 rEntry
.m_Uids
.pop_back(); // pop last id for prefix
276 if (rEntry
.m_Uids
.empty()) // erase prefix key
278 m_prefixes
.erase(iFind
);
282 m_nLastPrefix_lookup
= UID_UNKNOWN
;
283 m_aLastPrefix_lookup
= g_sXMLNS_PREFIX_UNKNOWN
;
286 inline void DocumentHandlerImpl::getElementName(
287 OUString
const & rQName
, sal_Int32
* pUid
, OUString
* pLocalName
)
289 sal_Int32 nColonPos
= rQName
.indexOf( ':' );
290 *pLocalName
= (nColonPos
>= 0 ? rQName
.copy( nColonPos
+1 ) : rQName
);
291 *pUid
= getUidByPrefix(
292 nColonPos
>= 0 ? rQName
.copy( 0, nColonPos
) : OUString() );
297 class ExtendedAttributes
:
298 public ::cppu::WeakImplHelper
< xml::input::XAttributes
>
300 sal_Int32
const m_nAttributes
;
301 std::unique_ptr
<sal_Int32
[]> m_pUids
;
302 std::unique_ptr
<OUString
[]> m_pLocalNames
;
303 std::unique_ptr
<OUString
[]> m_pQNames
;
304 std::unique_ptr
<OUString
[]> m_pValues
;
307 inline ExtendedAttributes(
308 sal_Int32 nAttributes
,
309 std::unique_ptr
<sal_Int32
[]> pUids
,
310 std::unique_ptr
<OUString
[]> pLocalNames
,
311 std::unique_ptr
<OUString
[]> pQNames
,
312 Reference
< xml::sax::XAttributeList
> const & xAttributeList
);
315 virtual sal_Int32 SAL_CALL
getLength() override
;
316 virtual sal_Int32 SAL_CALL
getIndexByQName(
317 OUString
const & rQName
) override
;
318 virtual sal_Int32 SAL_CALL
getIndexByUidName(
319 sal_Int32 nUid
, OUString
const & rLocalName
) override
;
320 virtual OUString SAL_CALL
getQNameByIndex(
321 sal_Int32 nIndex
) override
;
322 virtual sal_Int32 SAL_CALL
getUidByIndex(
323 sal_Int32 nIndex
) override
;
324 virtual OUString SAL_CALL
getLocalNameByIndex(
325 sal_Int32 nIndex
) override
;
326 virtual OUString SAL_CALL
getValueByIndex(
327 sal_Int32 nIndex
) override
;
328 virtual OUString SAL_CALL
getValueByUidName(
329 sal_Int32 nUid
, OUString
const & rLocalName
) override
;
330 virtual OUString SAL_CALL
getTypeByIndex(
331 sal_Int32 nIndex
) override
;
336 inline ExtendedAttributes::ExtendedAttributes(
337 sal_Int32 nAttributes
,
338 std::unique_ptr
<sal_Int32
[]> pUids
,
339 std::unique_ptr
<OUString
[]> pLocalNames
, std::unique_ptr
<OUString
[]> pQNames
,
340 Reference
< xml::sax::XAttributeList
> const & xAttributeList
)
341 : m_nAttributes( nAttributes
)
342 , m_pUids( std::move(pUids
) )
343 , m_pLocalNames( std::move(pLocalNames
) )
344 , m_pQNames( std::move(pQNames
) )
345 , m_pValues( new OUString
[ nAttributes
] )
347 for ( sal_Int32 nPos
= 0; nPos
< nAttributes
; ++nPos
)
349 m_pValues
[ nPos
] = xAttributeList
->getValueByIndex( nPos
);
355 OUString
DocumentHandlerImpl::getImplementationName()
357 return "com.sun.star.comp.xml.input.SaxDocumentHandler";
360 sal_Bool
DocumentHandlerImpl::supportsService( OUString
const & servicename
)
362 return cppu::supportsService(this, servicename
);
365 Sequence
< OUString
> DocumentHandlerImpl::getSupportedServiceNames()
367 return { "com.sun.star.xml.input.SaxDocumentHandler" };
372 void DocumentHandlerImpl::initialize(
373 Sequence
< Any
> const & arguments
)
375 MGuard
guard( m_oMutex
);
376 Reference
< xml::input::XRoot
> xRoot
;
377 if (arguments
.getLength() != 1 ||
378 !(arguments
[ 0 ] >>= xRoot
) ||
381 throw RuntimeException( "missing root instance!" );
388 sal_Int32
DocumentHandlerImpl::getUidByUri( OUString
const & Uri
)
390 sal_Int32 uid
= getUidByURI( Uri
);
391 SAL_WARN_IF( uid
== UID_UNKNOWN
, "xmlscript.xmlhelper", "uid UNKNOWN");
395 OUString
DocumentHandlerImpl::getUriByUid( sal_Int32 Uid
)
397 MGuard
guard( m_oMutex
);
398 for (const auto& rURIUid
: m_URI2Uid
)
400 if (rURIUid
.second
== Uid
)
401 return rURIUid
.first
;
403 throw container::NoSuchElementException( "no such xmlns uid!" , getXWeak() );
408 void DocumentHandlerImpl::startDocument()
410 m_xRoot
->startDocument( static_cast< xml::input::XNamespaceMapping
* >( this ) );
413 void DocumentHandlerImpl::endDocument()
415 m_xRoot
->endDocument();
418 void DocumentHandlerImpl::startElement(
419 OUString
const & rQElementName
,
420 Reference
< xml::sax::XAttributeList
> const & xAttribs
)
422 Reference
< xml::input::XElement
> xCurrentElement
;
423 Reference
< xml::input::XAttributes
> xAttributes
;
426 ElementEntry elementEntry
;
429 MGuard
aGuard( m_oMutex
);
430 // currently skipping elements and waiting for end tags?
431 if (m_nSkipElements
> 0)
433 ++m_nSkipElements
; // wait for another end tag
434 SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName
<< "\" ...");
438 sal_Int16 nAttribs
= xAttribs
->getLength();
440 // save all namespace ids
441 std::unique_ptr
<sal_Int32
[]> pUids(new sal_Int32
[ nAttribs
]);
442 std::unique_ptr
<OUString
[]> pPrefixes(new OUString
[ nAttribs
]);
443 std::unique_ptr
<OUString
[]> pLocalNames(new OUString
[ nAttribs
]);
444 std::unique_ptr
<OUString
[]> pQNames(new OUString
[ nAttribs
]);
446 // first recognize all xmlns attributes
448 for ( nPos
= 0; nPos
< nAttribs
; ++nPos
)
450 // mark attribute to be collected further
451 // on with attribute's uid and current prefix
452 pUids
[ nPos
] = 0; // modified
454 pQNames
[ nPos
] = xAttribs
->getNameByIndex( nPos
);
455 OUString
const & rQAttributeName
= pQNames
[ nPos
];
457 if (rQAttributeName
.startsWith( g_sXMLNS
))
459 if (rQAttributeName
.getLength() == 5) // set default namespace
461 OUString aDefNamespacePrefix
;
464 xAttribs
->getValueByIndex( nPos
) );
465 elementEntry
.m_prefixes
.push_back( aDefNamespacePrefix
);
466 pUids
[ nPos
] = UID_UNKNOWN
;
467 pPrefixes
[ nPos
] = g_sXMLNS
;
468 pLocalNames
[ nPos
] = aDefNamespacePrefix
;
470 else if (':' == rQAttributeName
[ 5 ]) // set prefix
472 OUString
aPrefix( rQAttributeName
.copy( 6 ) );
473 pushPrefix( aPrefix
, xAttribs
->getValueByIndex( nPos
) );
474 elementEntry
.m_prefixes
.push_back( aPrefix
);
475 pUids
[ nPos
] = UID_UNKNOWN
;
476 pPrefixes
[ nPos
] = g_sXMLNS
;
477 pLocalNames
[ nPos
] = aPrefix
;
479 // else just a name starting with xmlns, but no prefix
483 // now read out attribute prefixes (all namespace prefixes have been set)
484 for ( nPos
= 0; nPos
< nAttribs
; ++nPos
)
486 if (pUids
[ nPos
] >= 0) // no xmlns: attribute
488 OUString
const & rQAttributeName
= pQNames
[ nPos
];
489 SAL_WARN_IF(rQAttributeName
.startsWith( "xmlns:" ), "xmlscript.xmlhelper", "### unexpected xmlns!" );
491 // collect attribute's uid and current prefix
492 sal_Int32 nColonPos
= rQAttributeName
.indexOf( ':' );
495 pPrefixes
[ nPos
] = rQAttributeName
.copy( 0, nColonPos
);
496 pLocalNames
[ nPos
] = rQAttributeName
.copy( nColonPos
+1 );
500 pPrefixes
[ nPos
].clear();
501 pLocalNames
[ nPos
] = rQAttributeName
;
502 // leave local names unmodified
504 pUids
[ nPos
] = getUidByPrefix( pPrefixes
[ nPos
] );
508 // ownership of arrays belongs to attribute list
509 xAttributes
= new ExtendedAttributes(nAttribs
, std::move(pUids
), std::move(pLocalNames
),
510 std::move(pQNames
), xAttribs
);
512 getElementName( rQElementName
, &nUid
, &aLocalName
);
514 // create new child context and append to list
515 if (! m_elements
.empty())
516 xCurrentElement
= m_elements
.back().m_xElement
;
519 if (xCurrentElement
.is())
521 elementEntry
.m_xElement
=
522 xCurrentElement
->startChildElement( nUid
, aLocalName
, xAttributes
);
526 elementEntry
.m_xElement
=
527 m_xRoot
->startRootElement( nUid
, aLocalName
, xAttributes
);
531 MGuard
aGuard( m_oMutex
);
532 if (elementEntry
.m_xElement
.is())
534 m_elements
.push_back( std::move(elementEntry
) );
541 for (sal_Int32 nPos
= elementEntry
.m_prefixes
.size(); nPos
--;)
542 popPrefix(elementEntry
.m_prefixes
[nPos
]);
544 SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName
<< "\" ...");
549 void DocumentHandlerImpl::endElement(
550 OUString
const & rQElementName
)
552 Reference
< xml::input::XElement
> xCurrentElement
;
554 MGuard
aGuard( m_oMutex
);
558 SAL_INFO("xmlscript.xmlhelper", "### received endElement() for \"" << rQElementName
<< "\".");
563 SAL_WARN_IF( m_elements
.empty(), "xmlscript.xmlhelper", "m_elements is empty" );
564 ElementEntry
& rEntry
= m_elements
.back();
565 xCurrentElement
= rEntry
.m_xElement
;
567 #if OSL_DEBUG_LEVEL > 0
570 getElementName( rQElementName
, &nUid
, &aLocalName
);
571 SAL_WARN_IF( xCurrentElement
->getLocalName() != aLocalName
, "xmlscript.xmlhelper", "xCurrentElement->getLocalName() != aLocalName" );
572 SAL_WARN_IF( xCurrentElement
->getUid() != nUid
, "xmlscript.xmlhelper", "xCurrentElement->getUid() != nUid" );
576 for ( sal_Int32 nPos
= rEntry
.m_prefixes
.size(); nPos
--; )
578 popPrefix( rEntry
.m_prefixes
[ nPos
] );
580 m_elements
.pop_back();
582 xCurrentElement
->endElement();
585 void DocumentHandlerImpl::characters( OUString
const & rChars
)
587 Reference
< xml::input::XElement
> xCurrentElement( getCurrentElement() );
588 if (xCurrentElement
.is())
589 xCurrentElement
->characters( rChars
);
592 void DocumentHandlerImpl::ignorableWhitespace(
593 OUString
const & rWhitespaces
)
595 Reference
< xml::input::XElement
> xCurrentElement( getCurrentElement() );
596 if (xCurrentElement
.is())
597 xCurrentElement
->ignorableWhitespace( rWhitespaces
);
600 void DocumentHandlerImpl::processingInstruction(
601 OUString
const & rTarget
, OUString
const & rData
)
603 Reference
< xml::input::XElement
> xCurrentElement( getCurrentElement() );
604 if (xCurrentElement
.is())
605 xCurrentElement
->processingInstruction( rTarget
, rData
);
607 m_xRoot
->processingInstruction( rTarget
, rData
);
610 void DocumentHandlerImpl::setDocumentLocator(
611 Reference
< xml::sax::XLocator
> const & xLocator
)
613 m_xRoot
->setDocumentLocator( xLocator
);
618 sal_Int32
ExtendedAttributes::getIndexByQName( OUString
const & rQName
)
620 for ( sal_Int32 nPos
= m_nAttributes
; nPos
--; )
622 if (m_pQNames
[ nPos
] == rQName
)
630 sal_Int32
ExtendedAttributes::getLength()
632 return m_nAttributes
;
635 OUString
ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex
)
637 if (nIndex
< m_nAttributes
)
638 return m_pLocalNames
[ nIndex
];
643 OUString
ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex
)
645 if (nIndex
< m_nAttributes
)
646 return m_pQNames
[ nIndex
];
651 OUString
ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex
)
653 SAL_WARN_IF( nIndex
>= m_nAttributes
, "xmlscript.xmlhelper", "nIndex is bigger then m_nAttributes");
654 return OUString(); // unsupported
657 OUString
ExtendedAttributes::getValueByIndex( sal_Int32 nIndex
)
659 if (nIndex
< m_nAttributes
)
660 return m_pValues
[ nIndex
];
665 sal_Int32
ExtendedAttributes::getIndexByUidName(
666 sal_Int32 nUid
, OUString
const & rLocalName
)
668 for ( sal_Int32 nPos
= m_nAttributes
; nPos
--; )
670 if (m_pUids
[ nPos
] == nUid
&& m_pLocalNames
[ nPos
] == rLocalName
)
678 sal_Int32
ExtendedAttributes::getUidByIndex( sal_Int32 nIndex
)
680 if (nIndex
< m_nAttributes
)
681 return m_pUids
[ nIndex
];
686 OUString
ExtendedAttributes::getValueByUidName(
687 sal_Int32 nUid
, OUString
const & rLocalName
)
689 for ( sal_Int32 nPos
= m_nAttributes
; nPos
--; )
691 if (m_pUids
[ nPos
] == nUid
&& m_pLocalNames
[ nPos
] == rLocalName
)
693 return m_pValues
[ nPos
];
699 Reference
< xml::sax::XDocumentHandler
> createDocumentHandler(
700 Reference
< xml::input::XRoot
> const & xRoot
)
702 SAL_WARN_IF( !xRoot
.is(), "xmlscript.xmlhelper", "xRoot is NULL" );
705 return new DocumentHandlerImpl(xRoot
, true /* mt use */);
707 return Reference
< xml::sax::XDocumentHandler
>();
712 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
713 com_sun_star_comp_xml_input_SaxDocumentHandler_get_implementation(
714 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const& )
716 return cppu::acquire(new xmlscript::DocumentHandlerImpl({}, false /* mt use */));
719 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */