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 ::com::sun::star
;
40 using namespace ::com::sun::star::uno
;
45 const sal_Int32 UID_UNKNOWN
= -1;
47 typedef std::unordered_map
< OUString
, sal_Int32
> t_OUString2LongMap
;
53 ::std::vector
< sal_Int32
> m_Uids
;
56 { m_Uids
.reserve( 4 ); }
61 typedef std::unordered_map
<
62 OUString
, std::unique_ptr
<PrefixEntry
> > t_OUString2PrefixMap
;
68 Reference
< xml::input::XElement
> m_xElement
;
69 ::std::vector
< OUString
> m_prefixes
;
72 { m_prefixes
.reserve( 2 ); }
75 class ExtendedAttributes
;
79 std::mutex
* m_pMutex
;
81 explicit MGuard( std::optional
<std::mutex
> & oMutex
)
82 : m_pMutex( oMutex
? &*oMutex
: nullptr )
83 { if (m_pMutex
) m_pMutex
->lock(); }
85 { if (m_pMutex
) m_pMutex
->unlock(); }
88 class DocumentHandlerImpl
:
89 public ::cppu::WeakImplHelper
< xml::sax::XDocumentHandler
,
90 xml::input::XNamespaceMapping
,
91 lang::XInitialization
,
92 css::lang::XServiceInfo
>
94 friend class ExtendedAttributes
;
96 Reference
< xml::input::XRoot
> m_xRoot
;
98 t_OUString2LongMap m_URI2Uid
;
99 sal_Int32 m_uid_count
;
101 sal_Int32 m_nLastURI_lookup
;
102 OUString m_aLastURI_lookup
;
104 t_OUString2PrefixMap m_prefixes
;
105 sal_Int32 m_nLastPrefix_lookup
;
106 OUString m_aLastPrefix_lookup
;
108 std::vector
< ElementEntry
> m_elements
;
109 sal_Int32 m_nSkipElements
;
111 mutable std::optional
<std::mutex
> m_oMutex
;
113 inline Reference
< xml::input::XElement
> getCurrentElement() const;
115 inline sal_Int32
getUidByURI( OUString
const & rURI
);
116 inline sal_Int32
getUidByPrefix( OUString
const & rPrefix
);
118 inline void pushPrefix(
119 OUString
const & rPrefix
, OUString
const & rURI
);
120 inline void popPrefix( OUString
const & rPrefix
);
122 inline void getElementName(
123 OUString
const & rQName
, sal_Int32
* pUid
, OUString
* pLocalName
);
127 Reference
< xml::input::XRoot
> const & xRoot
,
128 bool bSingleThreadedUse
);
131 virtual OUString SAL_CALL
getImplementationName() override
;
132 virtual sal_Bool SAL_CALL
supportsService(
133 OUString
const & servicename
) override
;
134 virtual Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
137 virtual void SAL_CALL
initialize(
138 Sequence
< Any
> const & arguments
) override
;
141 virtual void SAL_CALL
startDocument() override
;
142 virtual void SAL_CALL
endDocument() override
;
143 virtual void SAL_CALL
startElement(
144 OUString
const & rQElementName
,
145 Reference
< xml::sax::XAttributeList
> const & xAttribs
) override
;
146 virtual void SAL_CALL
endElement(
147 OUString
const & rQElementName
) override
;
148 virtual void SAL_CALL
characters(
149 OUString
const & rChars
) override
;
150 virtual void SAL_CALL
ignorableWhitespace(
151 OUString
const & rWhitespaces
) override
;
152 virtual void SAL_CALL
processingInstruction(
153 OUString
const & rTarget
, OUString
const & rData
) override
;
154 virtual void SAL_CALL
setDocumentLocator(
155 Reference
< xml::sax::XLocator
> const & xLocator
) override
;
158 virtual sal_Int32 SAL_CALL
getUidByUri( OUString
const & Uri
) override
;
159 virtual OUString SAL_CALL
getUriByUid( sal_Int32 Uid
) override
;
164 constexpr OUString
g_sXMLNS_PREFIX_UNKNOWN( u
"<<< unknown prefix >>>"_ustr
);
165 constexpr OUString
g_sXMLNS( u
"xmlns"_ustr
);
168 DocumentHandlerImpl::DocumentHandlerImpl(
169 Reference
< xml::input::XRoot
> const & xRoot
,
170 bool bSingleThreadedUse
)
173 m_nLastURI_lookup( UID_UNKNOWN
),
174 m_aLastURI_lookup( u
"<<< unknown URI >>>"_ustr
),
175 m_nLastPrefix_lookup( UID_UNKNOWN
),
176 m_aLastPrefix_lookup( u
"<<< unknown URI >>>"_ustr
),
179 m_elements
.reserve( 10 );
181 if (! bSingleThreadedUse
)
185 inline Reference
< xml::input::XElement
>
186 DocumentHandlerImpl::getCurrentElement() const
188 MGuard
aGuard( m_oMutex
);
189 if (m_elements
.empty())
190 return Reference
< xml::input::XElement
>();
192 return m_elements
.back().m_xElement
;
195 inline sal_Int32
DocumentHandlerImpl::getUidByURI( OUString
const & rURI
)
197 MGuard
guard( m_oMutex
);
198 if (m_nLastURI_lookup
== UID_UNKNOWN
|| m_aLastURI_lookup
!= rURI
)
200 t_OUString2LongMap::const_iterator
iFind( m_URI2Uid
.find( rURI
) );
201 if (iFind
!= m_URI2Uid
.end()) // id found
203 m_nLastURI_lookup
= iFind
->second
;
204 m_aLastURI_lookup
= rURI
;
208 m_nLastURI_lookup
= m_uid_count
;
210 m_URI2Uid
[ rURI
] = m_nLastURI_lookup
;
211 m_aLastURI_lookup
= rURI
;
214 return m_nLastURI_lookup
;
217 inline sal_Int32
DocumentHandlerImpl::getUidByPrefix(
218 OUString
const & rPrefix
)
220 // commonly the last added prefix is used often for several tags...
222 if (m_nLastPrefix_lookup
== UID_UNKNOWN
|| m_aLastPrefix_lookup
!= rPrefix
)
224 t_OUString2PrefixMap::const_iterator
iFind(
225 m_prefixes
.find( rPrefix
) );
226 if (iFind
!= m_prefixes
.end())
228 const PrefixEntry
& rPrefixEntry
= *iFind
->second
;
229 SAL_WARN_IF( rPrefixEntry
.m_Uids
.empty(), "xmlscript.xmlhelper", "rPrefixEntry.m_Uids is empty" );
230 m_nLastPrefix_lookup
= rPrefixEntry
.m_Uids
.back();
231 m_aLastPrefix_lookup
= rPrefix
;
235 m_nLastPrefix_lookup
= UID_UNKNOWN
;
236 m_aLastPrefix_lookup
= g_sXMLNS_PREFIX_UNKNOWN
;
239 return m_nLastPrefix_lookup
;
242 inline void DocumentHandlerImpl::pushPrefix(
243 OUString
const & rPrefix
, OUString
const & rURI
)
246 sal_Int32 nUid
= getUidByURI( rURI
);
248 // mark prefix with id
249 t_OUString2PrefixMap::const_iterator
iFind( m_prefixes
.find( rPrefix
) );
250 if (iFind
== m_prefixes
.end()) // unused prefix
252 PrefixEntry
* pEntry
= new PrefixEntry();
253 pEntry
->m_Uids
.push_back( nUid
); // latest id for prefix
254 m_prefixes
[rPrefix
].reset(pEntry
);
258 PrefixEntry
& rEntry
= *iFind
->second
;
259 SAL_WARN_IF(rEntry
.m_Uids
.empty(), "xmlscript.xmlhelper", "pEntry->m_Uids is empty");
260 rEntry
.m_Uids
.push_back(nUid
);
263 m_aLastPrefix_lookup
= rPrefix
;
264 m_nLastPrefix_lookup
= nUid
;
267 inline void DocumentHandlerImpl::popPrefix(
268 OUString
const & rPrefix
)
270 t_OUString2PrefixMap::iterator
iFind( m_prefixes
.find( rPrefix
) );
271 if (iFind
!= m_prefixes
.end()) // unused prefix
273 PrefixEntry
& rEntry
= *iFind
->second
;
274 rEntry
.m_Uids
.pop_back(); // pop last id for prefix
275 if (rEntry
.m_Uids
.empty()) // erase prefix key
277 m_prefixes
.erase(iFind
);
281 m_nLastPrefix_lookup
= UID_UNKNOWN
;
282 m_aLastPrefix_lookup
= g_sXMLNS_PREFIX_UNKNOWN
;
285 inline void DocumentHandlerImpl::getElementName(
286 OUString
const & rQName
, sal_Int32
* pUid
, OUString
* pLocalName
)
288 sal_Int32 nColonPos
= rQName
.indexOf( ':' );
289 *pLocalName
= (nColonPos
>= 0 ? rQName
.copy( nColonPos
+1 ) : rQName
);
290 *pUid
= getUidByPrefix(
291 nColonPos
>= 0 ? rQName
.copy( 0, nColonPos
) : OUString() );
296 class ExtendedAttributes
:
297 public ::cppu::WeakImplHelper
< xml::input::XAttributes
>
299 sal_Int32
const m_nAttributes
;
300 std::unique_ptr
<sal_Int32
[]> m_pUids
;
301 std::unique_ptr
<OUString
[]> m_pLocalNames
;
302 std::unique_ptr
<OUString
[]> m_pQNames
;
303 std::unique_ptr
<OUString
[]> m_pValues
;
306 inline ExtendedAttributes(
307 sal_Int32 nAttributes
,
308 std::unique_ptr
<sal_Int32
[]> pUids
,
309 std::unique_ptr
<OUString
[]> pLocalNames
,
310 std::unique_ptr
<OUString
[]> pQNames
,
311 Reference
< xml::sax::XAttributeList
> const & xAttributeList
);
314 virtual sal_Int32 SAL_CALL
getLength() override
;
315 virtual sal_Int32 SAL_CALL
getIndexByQName(
316 OUString
const & rQName
) override
;
317 virtual sal_Int32 SAL_CALL
getIndexByUidName(
318 sal_Int32 nUid
, OUString
const & rLocalName
) override
;
319 virtual OUString SAL_CALL
getQNameByIndex(
320 sal_Int32 nIndex
) override
;
321 virtual sal_Int32 SAL_CALL
getUidByIndex(
322 sal_Int32 nIndex
) override
;
323 virtual OUString SAL_CALL
getLocalNameByIndex(
324 sal_Int32 nIndex
) override
;
325 virtual OUString SAL_CALL
getValueByIndex(
326 sal_Int32 nIndex
) override
;
327 virtual OUString SAL_CALL
getValueByUidName(
328 sal_Int32 nUid
, OUString
const & rLocalName
) override
;
329 virtual OUString SAL_CALL
getTypeByIndex(
330 sal_Int32 nIndex
) override
;
335 inline ExtendedAttributes::ExtendedAttributes(
336 sal_Int32 nAttributes
,
337 std::unique_ptr
<sal_Int32
[]> pUids
,
338 std::unique_ptr
<OUString
[]> pLocalNames
, std::unique_ptr
<OUString
[]> pQNames
,
339 Reference
< xml::sax::XAttributeList
> const & xAttributeList
)
340 : m_nAttributes( nAttributes
)
341 , m_pUids( std::move(pUids
) )
342 , m_pLocalNames( std::move(pLocalNames
) )
343 , m_pQNames( std::move(pQNames
) )
344 , m_pValues( new OUString
[ nAttributes
] )
346 for ( sal_Int32 nPos
= 0; nPos
< nAttributes
; ++nPos
)
348 m_pValues
[ nPos
] = xAttributeList
->getValueByIndex( nPos
);
354 OUString
DocumentHandlerImpl::getImplementationName()
356 return u
"com.sun.star.comp.xml.input.SaxDocumentHandler"_ustr
;
359 sal_Bool
DocumentHandlerImpl::supportsService( OUString
const & servicename
)
361 return cppu::supportsService(this, servicename
);
364 Sequence
< OUString
> DocumentHandlerImpl::getSupportedServiceNames()
366 return { u
"com.sun.star.xml.input.SaxDocumentHandler"_ustr
};
371 void DocumentHandlerImpl::initialize(
372 Sequence
< Any
> const & arguments
)
374 MGuard
guard( m_oMutex
);
375 Reference
< xml::input::XRoot
> xRoot
;
376 if (arguments
.getLength() != 1 ||
377 !(arguments
[ 0 ] >>= xRoot
) ||
380 throw RuntimeException( u
"missing root instance!"_ustr
);
382 m_xRoot
= std::move(xRoot
);
387 sal_Int32
DocumentHandlerImpl::getUidByUri( OUString
const & Uri
)
389 sal_Int32 uid
= getUidByURI( Uri
);
390 SAL_WARN_IF( uid
== UID_UNKNOWN
, "xmlscript.xmlhelper", "uid UNKNOWN");
394 OUString
DocumentHandlerImpl::getUriByUid( sal_Int32 Uid
)
396 MGuard
guard( m_oMutex
);
397 for (const auto& rURIUid
: m_URI2Uid
)
399 if (rURIUid
.second
== Uid
)
400 return rURIUid
.first
;
402 throw container::NoSuchElementException( u
"no such xmlns uid!"_ustr
, getXWeak() );
407 void DocumentHandlerImpl::startDocument()
409 m_xRoot
->startDocument( static_cast< xml::input::XNamespaceMapping
* >( this ) );
412 void DocumentHandlerImpl::endDocument()
414 m_xRoot
->endDocument();
417 void DocumentHandlerImpl::startElement(
418 OUString
const & rQElementName
,
419 Reference
< xml::sax::XAttributeList
> const & xAttribs
)
421 Reference
< xml::input::XElement
> xCurrentElement
;
422 Reference
< xml::input::XAttributes
> xAttributes
;
425 ElementEntry elementEntry
;
428 MGuard
aGuard( m_oMutex
);
429 // currently skipping elements and waiting for end tags?
430 if (m_nSkipElements
> 0)
432 ++m_nSkipElements
; // wait for another end tag
433 SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName
<< "\" ...");
437 sal_Int16 nAttribs
= xAttribs
->getLength();
439 // save all namespace ids
440 std::unique_ptr
<sal_Int32
[]> pUids(new sal_Int32
[ nAttribs
]);
441 std::unique_ptr
<OUString
[]> pPrefixes(new OUString
[ nAttribs
]);
442 std::unique_ptr
<OUString
[]> pLocalNames(new OUString
[ nAttribs
]);
443 std::unique_ptr
<OUString
[]> pQNames(new OUString
[ nAttribs
]);
445 // first recognize all xmlns attributes
447 for ( nPos
= 0; nPos
< nAttribs
; ++nPos
)
449 // mark attribute to be collected further
450 // on with attribute's uid and current prefix
451 pUids
[ nPos
] = 0; // modified
453 pQNames
[ nPos
] = xAttribs
->getNameByIndex( nPos
);
454 OUString
const & rQAttributeName
= pQNames
[ nPos
];
456 if (rQAttributeName
.startsWith( g_sXMLNS
))
458 if (rQAttributeName
.getLength() == 5) // set default namespace
460 OUString aDefNamespacePrefix
;
463 xAttribs
->getValueByIndex( nPos
) );
464 elementEntry
.m_prefixes
.push_back( aDefNamespacePrefix
);
465 pUids
[ nPos
] = UID_UNKNOWN
;
466 pPrefixes
[ nPos
] = g_sXMLNS
;
467 pLocalNames
[ nPos
] = aDefNamespacePrefix
;
469 else if (':' == rQAttributeName
[ 5 ]) // set prefix
471 OUString
aPrefix( rQAttributeName
.copy( 6 ) );
472 pushPrefix( aPrefix
, xAttribs
->getValueByIndex( nPos
) );
473 elementEntry
.m_prefixes
.push_back( aPrefix
);
474 pUids
[ nPos
] = UID_UNKNOWN
;
475 pPrefixes
[ nPos
] = g_sXMLNS
;
476 pLocalNames
[ nPos
] = aPrefix
;
478 // else just a name starting with xmlns, but no prefix
482 // now read out attribute prefixes (all namespace prefixes have been set)
483 for ( nPos
= 0; nPos
< nAttribs
; ++nPos
)
485 if (pUids
[ nPos
] >= 0) // no xmlns: attribute
487 OUString
const & rQAttributeName
= pQNames
[ nPos
];
488 SAL_WARN_IF(rQAttributeName
.startsWith( "xmlns:" ), "xmlscript.xmlhelper", "### unexpected xmlns!" );
490 // collect attribute's uid and current prefix
491 sal_Int32 nColonPos
= rQAttributeName
.indexOf( ':' );
494 pPrefixes
[ nPos
] = rQAttributeName
.copy( 0, nColonPos
);
495 pLocalNames
[ nPos
] = rQAttributeName
.copy( nColonPos
+1 );
499 pPrefixes
[ nPos
].clear();
500 pLocalNames
[ nPos
] = rQAttributeName
;
501 // leave local names unmodified
503 pUids
[ nPos
] = getUidByPrefix( pPrefixes
[ nPos
] );
507 // ownership of arrays belongs to attribute list
508 xAttributes
= new ExtendedAttributes(nAttribs
, std::move(pUids
), std::move(pLocalNames
),
509 std::move(pQNames
), xAttribs
);
511 getElementName( rQElementName
, &nUid
, &aLocalName
);
513 // create new child context and append to list
514 if (! m_elements
.empty())
515 xCurrentElement
= m_elements
.back().m_xElement
;
518 if (xCurrentElement
.is())
520 elementEntry
.m_xElement
=
521 xCurrentElement
->startChildElement( nUid
, aLocalName
, xAttributes
);
525 elementEntry
.m_xElement
=
526 m_xRoot
->startRootElement( nUid
, aLocalName
, xAttributes
);
530 MGuard
aGuard( m_oMutex
);
531 if (elementEntry
.m_xElement
.is())
533 m_elements
.push_back( std::move(elementEntry
) );
540 for (sal_Int32 nPos
= elementEntry
.m_prefixes
.size(); nPos
--;)
541 popPrefix(elementEntry
.m_prefixes
[nPos
]);
543 SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName
<< "\" ...");
548 void DocumentHandlerImpl::endElement(
549 OUString
const & rQElementName
)
551 Reference
< xml::input::XElement
> xCurrentElement
;
553 MGuard
aGuard( m_oMutex
);
557 SAL_INFO("xmlscript.xmlhelper", "### received endElement() for \"" << rQElementName
<< "\".");
562 SAL_WARN_IF( m_elements
.empty(), "xmlscript.xmlhelper", "m_elements is empty" );
563 ElementEntry
& rEntry
= m_elements
.back();
564 xCurrentElement
= rEntry
.m_xElement
;
566 #if OSL_DEBUG_LEVEL > 0
569 getElementName( rQElementName
, &nUid
, &aLocalName
);
570 SAL_WARN_IF( xCurrentElement
->getLocalName() != aLocalName
, "xmlscript.xmlhelper", "xCurrentElement->getLocalName() != aLocalName" );
571 SAL_WARN_IF( xCurrentElement
->getUid() != nUid
, "xmlscript.xmlhelper", "xCurrentElement->getUid() != nUid" );
575 for ( sal_Int32 nPos
= rEntry
.m_prefixes
.size(); nPos
--; )
577 popPrefix( rEntry
.m_prefixes
[ nPos
] );
579 m_elements
.pop_back();
581 xCurrentElement
->endElement();
584 void DocumentHandlerImpl::characters( OUString
const & rChars
)
586 Reference
< xml::input::XElement
> xCurrentElement( getCurrentElement() );
587 if (xCurrentElement
.is())
588 xCurrentElement
->characters( rChars
);
591 void DocumentHandlerImpl::ignorableWhitespace(
592 OUString
const & rWhitespaces
)
594 Reference
< xml::input::XElement
> xCurrentElement( getCurrentElement() );
595 if (xCurrentElement
.is())
596 xCurrentElement
->ignorableWhitespace( rWhitespaces
);
599 void DocumentHandlerImpl::processingInstruction(
600 OUString
const & rTarget
, OUString
const & rData
)
602 Reference
< xml::input::XElement
> xCurrentElement( getCurrentElement() );
603 if (xCurrentElement
.is())
604 xCurrentElement
->processingInstruction( rTarget
, rData
);
606 m_xRoot
->processingInstruction( rTarget
, rData
);
609 void DocumentHandlerImpl::setDocumentLocator(
610 Reference
< xml::sax::XLocator
> const & xLocator
)
612 m_xRoot
->setDocumentLocator( xLocator
);
617 sal_Int32
ExtendedAttributes::getIndexByQName( OUString
const & rQName
)
619 for ( sal_Int32 nPos
= m_nAttributes
; nPos
--; )
621 if (m_pQNames
[ nPos
] == rQName
)
629 sal_Int32
ExtendedAttributes::getLength()
631 return m_nAttributes
;
634 OUString
ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex
)
636 if (nIndex
< m_nAttributes
)
637 return m_pLocalNames
[ nIndex
];
642 OUString
ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex
)
644 if (nIndex
< m_nAttributes
)
645 return m_pQNames
[ nIndex
];
650 OUString
ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex
)
652 SAL_WARN_IF( nIndex
>= m_nAttributes
, "xmlscript.xmlhelper", "nIndex is bigger then m_nAttributes");
653 return OUString(); // unsupported
656 OUString
ExtendedAttributes::getValueByIndex( sal_Int32 nIndex
)
658 if (nIndex
< m_nAttributes
)
659 return m_pValues
[ nIndex
];
664 sal_Int32
ExtendedAttributes::getIndexByUidName(
665 sal_Int32 nUid
, OUString
const & rLocalName
)
667 for ( sal_Int32 nPos
= m_nAttributes
; nPos
--; )
669 if (m_pUids
[ nPos
] == nUid
&& m_pLocalNames
[ nPos
] == rLocalName
)
677 sal_Int32
ExtendedAttributes::getUidByIndex( sal_Int32 nIndex
)
679 if (nIndex
< m_nAttributes
)
680 return m_pUids
[ nIndex
];
685 OUString
ExtendedAttributes::getValueByUidName(
686 sal_Int32 nUid
, OUString
const & rLocalName
)
688 for ( sal_Int32 nPos
= m_nAttributes
; nPos
--; )
690 if (m_pUids
[ nPos
] == nUid
&& m_pLocalNames
[ nPos
] == rLocalName
)
692 return m_pValues
[ nPos
];
698 Reference
< xml::sax::XDocumentHandler
> createDocumentHandler(
699 Reference
< xml::input::XRoot
> const & xRoot
)
701 SAL_WARN_IF( !xRoot
.is(), "xmlscript.xmlhelper", "xRoot is NULL" );
704 return new DocumentHandlerImpl(xRoot
, true /* mt use */);
706 return Reference
< xml::sax::XDocumentHandler
>();
711 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
712 com_sun_star_comp_xml_input_SaxDocumentHandler_get_implementation(
713 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const& )
715 return cppu::acquire(new xmlscript::DocumentHandlerImpl({}, false /* mt use */));
718 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */