...following up on 314f15bff0
"Extend
loplugin:external to warn about enums".
Cases where free functions were moved into an unnamed namespace along with a
class, to not break ADL, are in:
filter/source/svg/svgexport.cxx
sc/source/filter/excel/xelink.cxx
sc/source/filter/excel/xilink.cxx
svx/source/sdr/contact/viewobjectcontactofunocontrol.cxx
All other free functions mentioning moved classes appear to be harmless and not
give rise to (silent, even) ADL breakage. (One remaining TODO in
compilerplugins/clang/external.cxx is that derived classes are not covered by
computeAffectedTypes, even though they could also be affected by ADL-breakage---
but don't seem to be in any acutal case across the code base.)
For friend declarations using elaborate type specifiers, like
class C1 {};
class C2 { friend class C1; };
* If C2 (but not C1) is moved into an unnamed namespace, the friend declaration
must be changed to not use an elaborate type specifier (i.e., "friend C1;"; see
C++17 [namespace.memdef]/3: "If the name in a friend declaration is neither
qualified nor a template-id and the declaration is a function or an
elaborated-type-specifier, the lookup to determine whether the entity has been
previously declared shall not consider any scopes outside the innermost
enclosing namespace.")
* If C1 (but not C2) is moved into an unnamed namespace, the friend declaration
must be changed too, see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71882>
"elaborated-type-specifier friend not looked up in unnamed namespace".
Apart from that, to keep changes simple and mostly mechanical (which should help
avoid regressions), out-of-line definitions of class members have been left in
the enclosing (named) namespace. But explicit specializations of class
templates had to be moved into the unnamed namespace to appease
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92598> "explicit specialization of
template from unnamed namespace using unqualified-id in enclosing namespace".
Also, accompanying declarations (of e.g. typedefs or static variables) that
could arguably be moved into the unnamed namespace too have been left alone.
And in some cases, mention of affected types in blacklists in other loplugins
needed to be adapted.
And sc/qa/unit/mark_test.cxx uses a hack of including other .cxx, one of which
is sc/source/core/data/segmenttree.cxx where e.g. ScFlatUInt16SegmentsImpl is
not moved into an unnamed namespace (because it is declared in
sc/inc/segmenttree.hxx), but its base ScFlatSegmentsImpl is. GCC warns about
such combinations with enabled-by-default -Wsubobject-linkage, but "The compiler
doesn’t give this warning for types defined in the main .C file, as those are
unlikely to have multiple definitions."
(<https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/Warning-Options.html>) The
warned-about classes also don't have multiple definitions in the given test, so
disable the warning when including the .cxx.
Change-Id: Ib694094c0d8168be68f8fe90dfd0acbb66a3f1e4
Reviewed-on: https://gerrit.libreoffice.org/83239
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
730 lines
22 KiB
C++
730 lines
22 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
|
|
#include <unoservices.hxx>
|
|
#include <xml_import.hxx>
|
|
|
|
#include <cppuhelper/implbase.hxx>
|
|
#include <cppuhelper/supportsservice.hxx>
|
|
#include <com/sun/star/container/NoSuchElementException.hpp>
|
|
#include <com/sun/star/xml/input/XAttributes.hpp>
|
|
#include <com/sun/star/lang/XInitialization.hpp>
|
|
#include <com/sun/star/uno/XComponentContext.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
#include <sal/log.hxx>
|
|
|
|
#include <memory>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
using namespace ::osl;
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::uno;
|
|
|
|
namespace xmlscript
|
|
{
|
|
|
|
const sal_Int32 UID_UNKNOWN = -1;
|
|
|
|
Sequence< OUString > getSupportedServiceNames_DocumentHandlerImpl()
|
|
{
|
|
return Sequence< OUString > { "com.sun.star.xml.input.SaxDocumentHandler" };
|
|
}
|
|
|
|
OUString getImplementationName_DocumentHandlerImpl()
|
|
{
|
|
return "com.sun.star.comp.xml.input.SaxDocumentHandler";
|
|
}
|
|
|
|
typedef std::unordered_map< OUString, sal_Int32 > t_OUString2LongMap;
|
|
|
|
namespace {
|
|
|
|
struct PrefixEntry
|
|
{
|
|
::std::vector< sal_Int32 > m_Uids;
|
|
|
|
PrefixEntry()
|
|
{ m_Uids.reserve( 4 ); }
|
|
};
|
|
|
|
}
|
|
|
|
typedef std::unordered_map<
|
|
OUString, std::unique_ptr<PrefixEntry> > t_OUString2PrefixMap;
|
|
|
|
namespace {
|
|
|
|
struct ElementEntry
|
|
{
|
|
Reference< xml::input::XElement > m_xElement;
|
|
::std::vector< OUString > m_prefixes;
|
|
|
|
ElementEntry()
|
|
{ m_prefixes.reserve( 2 ); }
|
|
};
|
|
|
|
class ExtendedAttributes;
|
|
|
|
class MGuard
|
|
{
|
|
Mutex * m_pMutex;
|
|
public:
|
|
explicit MGuard( std::unique_ptr<Mutex> const & pMutex )
|
|
: m_pMutex( pMutex.get() )
|
|
{ if (m_pMutex) m_pMutex->acquire(); }
|
|
~MGuard() throw ()
|
|
{ if (m_pMutex) m_pMutex->release(); }
|
|
};
|
|
|
|
class DocumentHandlerImpl :
|
|
public ::cppu::WeakImplHelper< xml::sax::XDocumentHandler,
|
|
xml::input::XNamespaceMapping,
|
|
lang::XInitialization,
|
|
css::lang::XServiceInfo >
|
|
{
|
|
friend class ExtendedAttributes;
|
|
|
|
Reference< xml::input::XRoot > m_xRoot;
|
|
|
|
t_OUString2LongMap m_URI2Uid;
|
|
sal_Int32 m_uid_count;
|
|
|
|
sal_Int32 m_nLastURI_lookup;
|
|
OUString m_aLastURI_lookup;
|
|
|
|
t_OUString2PrefixMap m_prefixes;
|
|
sal_Int32 m_nLastPrefix_lookup;
|
|
OUString m_aLastPrefix_lookup;
|
|
|
|
std::vector< ElementEntry > m_elements;
|
|
sal_Int32 m_nSkipElements;
|
|
|
|
std::unique_ptr<Mutex> m_pMutex;
|
|
|
|
inline Reference< xml::input::XElement > getCurrentElement() const;
|
|
|
|
inline sal_Int32 getUidByURI( OUString const & rURI );
|
|
inline sal_Int32 getUidByPrefix( OUString const & rPrefix );
|
|
|
|
inline void pushPrefix(
|
|
OUString const & rPrefix, OUString const & rURI );
|
|
inline void popPrefix( OUString const & rPrefix );
|
|
|
|
inline void getElementName(
|
|
OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName );
|
|
|
|
public:
|
|
DocumentHandlerImpl(
|
|
Reference< xml::input::XRoot > const & xRoot,
|
|
bool bSingleThreadedUse );
|
|
|
|
// XServiceInfo
|
|
virtual OUString SAL_CALL getImplementationName() override;
|
|
virtual sal_Bool SAL_CALL supportsService(
|
|
OUString const & servicename ) override;
|
|
virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
|
|
|
|
// XInitialization
|
|
virtual void SAL_CALL initialize(
|
|
Sequence< Any > const & arguments ) override;
|
|
|
|
// XDocumentHandler
|
|
virtual void SAL_CALL startDocument() override;
|
|
virtual void SAL_CALL endDocument() override;
|
|
virtual void SAL_CALL startElement(
|
|
OUString const & rQElementName,
|
|
Reference< xml::sax::XAttributeList > const & xAttribs ) override;
|
|
virtual void SAL_CALL endElement(
|
|
OUString const & rQElementName ) override;
|
|
virtual void SAL_CALL characters(
|
|
OUString const & rChars ) override;
|
|
virtual void SAL_CALL ignorableWhitespace(
|
|
OUString const & rWhitespaces ) override;
|
|
virtual void SAL_CALL processingInstruction(
|
|
OUString const & rTarget, OUString const & rData ) override;
|
|
virtual void SAL_CALL setDocumentLocator(
|
|
Reference< xml::sax::XLocator > const & xLocator ) override;
|
|
|
|
// XNamespaceMapping
|
|
virtual sal_Int32 SAL_CALL getUidByUri( OUString const & Uri ) override;
|
|
virtual OUString SAL_CALL getUriByUid( sal_Int32 Uid ) override;
|
|
};
|
|
|
|
}
|
|
|
|
static OUString const g_sXMLNS_PREFIX_UNKNOWN( "<<< unknown prefix >>>" );
|
|
static OUString const g_sXMLNS( "xmlns" );
|
|
|
|
|
|
DocumentHandlerImpl::DocumentHandlerImpl(
|
|
Reference< xml::input::XRoot > const & xRoot,
|
|
bool bSingleThreadedUse )
|
|
: m_xRoot( xRoot ),
|
|
m_uid_count( 0 ),
|
|
m_nLastURI_lookup( UID_UNKNOWN ),
|
|
m_aLastURI_lookup( "<<< unknown URI >>>" ),
|
|
m_nLastPrefix_lookup( UID_UNKNOWN ),
|
|
m_aLastPrefix_lookup( "<<< unknown URI >>>" ),
|
|
m_nSkipElements( 0 )
|
|
{
|
|
m_elements.reserve( 10 );
|
|
|
|
if (! bSingleThreadedUse)
|
|
m_pMutex.reset(new Mutex);
|
|
}
|
|
|
|
inline Reference< xml::input::XElement >
|
|
DocumentHandlerImpl::getCurrentElement() const
|
|
{
|
|
MGuard aGuard( m_pMutex );
|
|
if (m_elements.empty())
|
|
return Reference< xml::input::XElement >();
|
|
else
|
|
return m_elements.back().m_xElement;
|
|
}
|
|
|
|
inline sal_Int32 DocumentHandlerImpl::getUidByURI( OUString const & rURI )
|
|
{
|
|
MGuard guard( m_pMutex );
|
|
if (m_nLastURI_lookup == UID_UNKNOWN || m_aLastURI_lookup != rURI)
|
|
{
|
|
t_OUString2LongMap::const_iterator iFind( m_URI2Uid.find( rURI ) );
|
|
if (iFind != m_URI2Uid.end()) // id found
|
|
{
|
|
m_nLastURI_lookup = iFind->second;
|
|
m_aLastURI_lookup = rURI;
|
|
}
|
|
else
|
|
{
|
|
m_nLastURI_lookup = m_uid_count;
|
|
++m_uid_count;
|
|
m_URI2Uid[ rURI ] = m_nLastURI_lookup;
|
|
m_aLastURI_lookup = rURI;
|
|
}
|
|
}
|
|
return m_nLastURI_lookup;
|
|
}
|
|
|
|
inline sal_Int32 DocumentHandlerImpl::getUidByPrefix(
|
|
OUString const & rPrefix )
|
|
{
|
|
// commonly the last added prefix is used often for several tags...
|
|
// good guess
|
|
if (m_nLastPrefix_lookup == UID_UNKNOWN || m_aLastPrefix_lookup != rPrefix)
|
|
{
|
|
t_OUString2PrefixMap::const_iterator iFind(
|
|
m_prefixes.find( rPrefix ) );
|
|
if (iFind != m_prefixes.end())
|
|
{
|
|
const PrefixEntry & rPrefixEntry = *iFind->second;
|
|
SAL_WARN_IF( rPrefixEntry.m_Uids.empty(), "xmlscript.xmlhelper", "rPrefixEntry.m_Uids is empty" );
|
|
m_nLastPrefix_lookup = rPrefixEntry.m_Uids.back();
|
|
m_aLastPrefix_lookup = rPrefix;
|
|
}
|
|
else
|
|
{
|
|
m_nLastPrefix_lookup = UID_UNKNOWN;
|
|
m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN;
|
|
}
|
|
}
|
|
return m_nLastPrefix_lookup;
|
|
}
|
|
|
|
inline void DocumentHandlerImpl::pushPrefix(
|
|
OUString const & rPrefix, OUString const & rURI )
|
|
{
|
|
// lookup id for URI
|
|
sal_Int32 nUid = getUidByURI( rURI );
|
|
|
|
// mark prefix with id
|
|
t_OUString2PrefixMap::const_iterator iFind( m_prefixes.find( rPrefix ) );
|
|
if (iFind == m_prefixes.end()) // unused prefix
|
|
{
|
|
PrefixEntry * pEntry = new PrefixEntry();
|
|
pEntry->m_Uids.push_back( nUid ); // latest id for prefix
|
|
m_prefixes[rPrefix].reset(pEntry);
|
|
}
|
|
else
|
|
{
|
|
PrefixEntry& rEntry = *iFind->second;
|
|
SAL_WARN_IF(rEntry.m_Uids.empty(), "xmlscript.xmlhelper", "pEntry->m_Uids is empty");
|
|
rEntry.m_Uids.push_back(nUid);
|
|
}
|
|
|
|
m_aLastPrefix_lookup = rPrefix;
|
|
m_nLastPrefix_lookup = nUid;
|
|
}
|
|
|
|
inline void DocumentHandlerImpl::popPrefix(
|
|
OUString const & rPrefix )
|
|
{
|
|
t_OUString2PrefixMap::iterator iFind( m_prefixes.find( rPrefix ) );
|
|
if (iFind != m_prefixes.end()) // unused prefix
|
|
{
|
|
PrefixEntry& rEntry = *iFind->second;
|
|
rEntry.m_Uids.pop_back(); // pop last id for prefix
|
|
if (rEntry.m_Uids.empty()) // erase prefix key
|
|
{
|
|
m_prefixes.erase(iFind);
|
|
}
|
|
}
|
|
|
|
m_nLastPrefix_lookup = UID_UNKNOWN;
|
|
m_aLastPrefix_lookup = g_sXMLNS_PREFIX_UNKNOWN;
|
|
}
|
|
|
|
inline void DocumentHandlerImpl::getElementName(
|
|
OUString const & rQName, sal_Int32 * pUid, OUString * pLocalName )
|
|
{
|
|
sal_Int32 nColonPos = rQName.indexOf( ':' );
|
|
*pLocalName = (nColonPos >= 0 ? rQName.copy( nColonPos +1 ) : rQName);
|
|
*pUid = getUidByPrefix(
|
|
nColonPos >= 0 ? rQName.copy( 0, nColonPos ) : OUString() );
|
|
}
|
|
|
|
namespace {
|
|
|
|
class ExtendedAttributes :
|
|
public ::cppu::WeakImplHelper< xml::input::XAttributes >
|
|
{
|
|
sal_Int32 const m_nAttributes;
|
|
std::unique_ptr<sal_Int32[]> m_pUids;
|
|
std::unique_ptr<OUString[]> m_pLocalNames;
|
|
std::unique_ptr<OUString[]> m_pQNames;
|
|
std::unique_ptr<OUString[]> m_pValues;
|
|
|
|
public:
|
|
inline ExtendedAttributes(
|
|
sal_Int32 nAttributes,
|
|
std::unique_ptr<sal_Int32[]> pUids,
|
|
std::unique_ptr<OUString[]> pLocalNames,
|
|
std::unique_ptr<OUString[]> pQNames,
|
|
Reference< xml::sax::XAttributeList > const & xAttributeList );
|
|
|
|
// XAttributes
|
|
virtual sal_Int32 SAL_CALL getLength() override;
|
|
virtual sal_Int32 SAL_CALL getIndexByQName(
|
|
OUString const & rQName ) override;
|
|
virtual sal_Int32 SAL_CALL getIndexByUidName(
|
|
sal_Int32 nUid, OUString const & rLocalName ) override;
|
|
virtual OUString SAL_CALL getQNameByIndex(
|
|
sal_Int32 nIndex ) override;
|
|
virtual sal_Int32 SAL_CALL getUidByIndex(
|
|
sal_Int32 nIndex ) override;
|
|
virtual OUString SAL_CALL getLocalNameByIndex(
|
|
sal_Int32 nIndex ) override;
|
|
virtual OUString SAL_CALL getValueByIndex(
|
|
sal_Int32 nIndex ) override;
|
|
virtual OUString SAL_CALL getValueByUidName(
|
|
sal_Int32 nUid, OUString const & rLocalName ) override;
|
|
virtual OUString SAL_CALL getTypeByIndex(
|
|
sal_Int32 nIndex ) override;
|
|
};
|
|
|
|
}
|
|
|
|
inline ExtendedAttributes::ExtendedAttributes(
|
|
sal_Int32 nAttributes,
|
|
std::unique_ptr<sal_Int32[]> pUids,
|
|
std::unique_ptr<OUString[]> pLocalNames, std::unique_ptr<OUString[]> pQNames,
|
|
Reference< xml::sax::XAttributeList > const & xAttributeList )
|
|
: m_nAttributes( nAttributes )
|
|
, m_pUids( std::move(pUids) )
|
|
, m_pLocalNames( std::move(pLocalNames) )
|
|
, m_pQNames( std::move(pQNames) )
|
|
, m_pValues( new OUString[ nAttributes ] )
|
|
{
|
|
for ( sal_Int32 nPos = 0; nPos < nAttributes; ++nPos )
|
|
{
|
|
m_pValues[ nPos ] = xAttributeList->getValueByIndex( nPos );
|
|
}
|
|
}
|
|
|
|
// XServiceInfo
|
|
|
|
OUString DocumentHandlerImpl::getImplementationName()
|
|
{
|
|
return getImplementationName_DocumentHandlerImpl();
|
|
}
|
|
|
|
sal_Bool DocumentHandlerImpl::supportsService( OUString const & servicename )
|
|
{
|
|
return cppu::supportsService(this, servicename);
|
|
}
|
|
|
|
Sequence< OUString > DocumentHandlerImpl::getSupportedServiceNames()
|
|
{
|
|
return getSupportedServiceNames_DocumentHandlerImpl();
|
|
}
|
|
|
|
// XInitialization
|
|
|
|
void DocumentHandlerImpl::initialize(
|
|
Sequence< Any > const & arguments )
|
|
{
|
|
MGuard guard( m_pMutex );
|
|
Reference< xml::input::XRoot > xRoot;
|
|
if (arguments.getLength() != 1 ||
|
|
!(arguments[ 0 ] >>= xRoot) ||
|
|
!xRoot.is())
|
|
{
|
|
throw RuntimeException( "missing root instance!" );
|
|
}
|
|
m_xRoot = xRoot;
|
|
}
|
|
|
|
// XNamespaceMapping
|
|
|
|
sal_Int32 DocumentHandlerImpl::getUidByUri( OUString const & Uri )
|
|
{
|
|
sal_Int32 uid = getUidByURI( Uri );
|
|
SAL_WARN_IF( uid == UID_UNKNOWN, "xmlscript.xmlhelper", "uid UNKNOWN");
|
|
return uid;
|
|
}
|
|
|
|
OUString DocumentHandlerImpl::getUriByUid( sal_Int32 Uid )
|
|
{
|
|
MGuard guard( m_pMutex );
|
|
for (const auto& rURIUid : m_URI2Uid)
|
|
{
|
|
if (rURIUid.second == Uid)
|
|
return rURIUid.first;
|
|
}
|
|
throw container::NoSuchElementException( "no such xmlns uid!" , static_cast< OWeakObject * >(this) );
|
|
}
|
|
|
|
// XDocumentHandler
|
|
|
|
void DocumentHandlerImpl::startDocument()
|
|
{
|
|
m_xRoot->startDocument( static_cast< xml::input::XNamespaceMapping * >( this ) );
|
|
}
|
|
|
|
void DocumentHandlerImpl::endDocument()
|
|
{
|
|
m_xRoot->endDocument();
|
|
}
|
|
|
|
void DocumentHandlerImpl::startElement(
|
|
OUString const & rQElementName,
|
|
Reference< xml::sax::XAttributeList > const & xAttribs )
|
|
{
|
|
Reference< xml::input::XElement > xCurrentElement;
|
|
Reference< xml::input::XAttributes > xAttributes;
|
|
sal_Int32 nUid;
|
|
OUString aLocalName;
|
|
ElementEntry elementEntry;
|
|
|
|
{ // guard start:
|
|
MGuard aGuard( m_pMutex );
|
|
// currently skipping elements and waiting for end tags?
|
|
if (m_nSkipElements > 0)
|
|
{
|
|
++m_nSkipElements; // wait for another end tag
|
|
SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ...");
|
|
return;
|
|
}
|
|
|
|
sal_Int16 nAttribs = xAttribs->getLength();
|
|
|
|
// save all namespace ids
|
|
std::unique_ptr<sal_Int32[]> pUids(new sal_Int32[ nAttribs ]);
|
|
std::unique_ptr<OUString[]> pPrefixes(new OUString[ nAttribs ]);
|
|
std::unique_ptr<OUString[]> pLocalNames(new OUString[ nAttribs ]);
|
|
std::unique_ptr<OUString[]> pQNames(new OUString[ nAttribs ]);
|
|
|
|
// first recognize all xmlns attributes
|
|
sal_Int16 nPos;
|
|
for ( nPos = 0; nPos < nAttribs; ++nPos )
|
|
{
|
|
// mark attribute to be collected further
|
|
// on with attribute's uid and current prefix
|
|
pUids[ nPos ] = 0; // modified
|
|
|
|
pQNames[ nPos ] = xAttribs->getNameByIndex( nPos );
|
|
OUString const & rQAttributeName = pQNames[ nPos ];
|
|
|
|
if (rQAttributeName.startsWith( g_sXMLNS ))
|
|
{
|
|
if (rQAttributeName.getLength() == 5) // set default namespace
|
|
{
|
|
OUString aDefNamespacePrefix;
|
|
pushPrefix(
|
|
aDefNamespacePrefix,
|
|
xAttribs->getValueByIndex( nPos ) );
|
|
elementEntry.m_prefixes.push_back( aDefNamespacePrefix );
|
|
pUids[ nPos ] = UID_UNKNOWN;
|
|
pPrefixes[ nPos ] = g_sXMLNS;
|
|
pLocalNames[ nPos ] = aDefNamespacePrefix;
|
|
}
|
|
else if (':' == rQAttributeName[ 5 ]) // set prefix
|
|
{
|
|
OUString aPrefix( rQAttributeName.copy( 6 ) );
|
|
pushPrefix( aPrefix, xAttribs->getValueByIndex( nPos ) );
|
|
elementEntry.m_prefixes.push_back( aPrefix );
|
|
pUids[ nPos ] = UID_UNKNOWN;
|
|
pPrefixes[ nPos ] = g_sXMLNS;
|
|
pLocalNames[ nPos ] = aPrefix;
|
|
}
|
|
// else just a name starting with xmlns, but no prefix
|
|
}
|
|
}
|
|
|
|
// now read out attribute prefixes (all namespace prefixes have been set)
|
|
for ( nPos = 0; nPos < nAttribs; ++nPos )
|
|
{
|
|
if (pUids[ nPos ] >= 0) // no xmlns: attribute
|
|
{
|
|
OUString const & rQAttributeName = pQNames[ nPos ];
|
|
SAL_WARN_IF(rQAttributeName.startsWith( "xmlns:" ), "xmlscript.xmlhelper", "### unexpected xmlns!" );
|
|
|
|
// collect attribute's uid and current prefix
|
|
sal_Int32 nColonPos = rQAttributeName.indexOf( ':' );
|
|
if (nColonPos >= 0)
|
|
{
|
|
pPrefixes[ nPos ] = rQAttributeName.copy( 0, nColonPos );
|
|
pLocalNames[ nPos ] = rQAttributeName.copy( nColonPos +1 );
|
|
}
|
|
else
|
|
{
|
|
pPrefixes[ nPos ].clear();
|
|
pLocalNames[ nPos ] = rQAttributeName;
|
|
// leave local names unmodified
|
|
}
|
|
pUids[ nPos ] = getUidByPrefix( pPrefixes[ nPos ] );
|
|
}
|
|
}
|
|
pPrefixes.reset();
|
|
// ownership of arrays belongs to attribute list
|
|
xAttributes = new ExtendedAttributes(nAttribs, std::move(pUids), std::move(pLocalNames),
|
|
std::move(pQNames), xAttribs);
|
|
|
|
getElementName( rQElementName, &nUid, &aLocalName );
|
|
|
|
// create new child context and append to list
|
|
if (! m_elements.empty())
|
|
xCurrentElement = m_elements.back().m_xElement;
|
|
} // :guard end
|
|
|
|
if (xCurrentElement.is())
|
|
{
|
|
elementEntry.m_xElement =
|
|
xCurrentElement->startChildElement( nUid, aLocalName, xAttributes );
|
|
}
|
|
else
|
|
{
|
|
elementEntry.m_xElement =
|
|
m_xRoot->startRootElement( nUid, aLocalName, xAttributes );
|
|
}
|
|
|
|
{
|
|
MGuard aGuard( m_pMutex );
|
|
if (elementEntry.m_xElement.is())
|
|
{
|
|
m_elements.push_back( std::move(elementEntry) );
|
|
}
|
|
else
|
|
{
|
|
++m_nSkipElements;
|
|
|
|
// pop prefixes
|
|
for (sal_Int32 nPos = elementEntry.m_prefixes.size(); nPos--;)
|
|
popPrefix(elementEntry.m_prefixes[nPos]);
|
|
|
|
SAL_INFO("xmlscript.xmlhelper", " no context given on createChildElement() => ignoring element \"" << rQElementName << "\" ...");
|
|
}
|
|
}
|
|
}
|
|
|
|
void DocumentHandlerImpl::endElement(
|
|
OUString const & rQElementName )
|
|
{
|
|
Reference< xml::input::XElement > xCurrentElement;
|
|
{
|
|
MGuard aGuard( m_pMutex );
|
|
if (m_nSkipElements)
|
|
{
|
|
--m_nSkipElements;
|
|
SAL_INFO("xmlscript.xmlhelper", "### received endElement() for \"" << rQElementName << "\".");
|
|
return;
|
|
}
|
|
|
|
// popping context
|
|
SAL_WARN_IF( m_elements.empty(), "xmlscript.xmlhelper", "m_elements is empty" );
|
|
ElementEntry& rEntry = m_elements.back();
|
|
xCurrentElement = rEntry.m_xElement;
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
sal_Int32 nUid;
|
|
OUString aLocalName;
|
|
getElementName( rQElementName, &nUid, &aLocalName );
|
|
SAL_WARN_IF( xCurrentElement->getLocalName() != aLocalName, "xmlscript.xmlhelper", "xCurrentElement->getLocalName() != aLocalName" );
|
|
SAL_WARN_IF( xCurrentElement->getUid() != nUid, "xmlscript.xmlhelper", "xCurrentElement->getUid() != nUid" );
|
|
#endif
|
|
|
|
// pop prefixes
|
|
for ( sal_Int32 nPos = rEntry.m_prefixes.size(); nPos--; )
|
|
{
|
|
popPrefix( rEntry.m_prefixes[ nPos ] );
|
|
}
|
|
m_elements.pop_back();
|
|
}
|
|
xCurrentElement->endElement();
|
|
}
|
|
|
|
void DocumentHandlerImpl::characters( OUString const & rChars )
|
|
{
|
|
Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
|
|
if (xCurrentElement.is())
|
|
xCurrentElement->characters( rChars );
|
|
}
|
|
|
|
void DocumentHandlerImpl::ignorableWhitespace(
|
|
OUString const & rWhitespaces )
|
|
{
|
|
Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
|
|
if (xCurrentElement.is())
|
|
xCurrentElement->ignorableWhitespace( rWhitespaces );
|
|
}
|
|
|
|
void DocumentHandlerImpl::processingInstruction(
|
|
OUString const & rTarget, OUString const & rData )
|
|
{
|
|
Reference< xml::input::XElement > xCurrentElement( getCurrentElement() );
|
|
if (xCurrentElement.is())
|
|
xCurrentElement->processingInstruction( rTarget, rData );
|
|
else
|
|
m_xRoot->processingInstruction( rTarget, rData );
|
|
}
|
|
|
|
void DocumentHandlerImpl::setDocumentLocator(
|
|
Reference< xml::sax::XLocator > const & xLocator )
|
|
{
|
|
m_xRoot->setDocumentLocator( xLocator );
|
|
}
|
|
|
|
// XAttributes
|
|
|
|
sal_Int32 ExtendedAttributes::getIndexByQName( OUString const & rQName )
|
|
{
|
|
for ( sal_Int32 nPos = m_nAttributes; nPos--; )
|
|
{
|
|
if (m_pQNames[ nPos ] == rQName)
|
|
{
|
|
return nPos;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
sal_Int32 ExtendedAttributes::getLength()
|
|
{
|
|
return m_nAttributes;
|
|
}
|
|
|
|
OUString ExtendedAttributes::getLocalNameByIndex( sal_Int32 nIndex )
|
|
{
|
|
if (nIndex < m_nAttributes)
|
|
return m_pLocalNames[ nIndex ];
|
|
else
|
|
return OUString();
|
|
}
|
|
|
|
OUString ExtendedAttributes::getQNameByIndex( sal_Int32 nIndex )
|
|
{
|
|
if (nIndex < m_nAttributes)
|
|
return m_pQNames[ nIndex ];
|
|
else
|
|
return OUString();
|
|
}
|
|
|
|
OUString ExtendedAttributes::getTypeByIndex( sal_Int32 nIndex )
|
|
{
|
|
SAL_WARN_IF( nIndex >= m_nAttributes , "xmlscript.xmlhelper", "nIndex is bigger then m_nAttributes");
|
|
return OUString(); // unsupported
|
|
}
|
|
|
|
OUString ExtendedAttributes::getValueByIndex( sal_Int32 nIndex )
|
|
{
|
|
if (nIndex < m_nAttributes)
|
|
return m_pValues[ nIndex ];
|
|
else
|
|
return OUString();
|
|
}
|
|
|
|
sal_Int32 ExtendedAttributes::getIndexByUidName(
|
|
sal_Int32 nUid, OUString const & rLocalName )
|
|
{
|
|
for ( sal_Int32 nPos = m_nAttributes; nPos--; )
|
|
{
|
|
if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
|
|
{
|
|
return nPos;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
sal_Int32 ExtendedAttributes::getUidByIndex( sal_Int32 nIndex )
|
|
{
|
|
if (nIndex < m_nAttributes)
|
|
return m_pUids[ nIndex ];
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
OUString ExtendedAttributes::getValueByUidName(
|
|
sal_Int32 nUid, OUString const & rLocalName )
|
|
{
|
|
for ( sal_Int32 nPos = m_nAttributes; nPos--; )
|
|
{
|
|
if (m_pUids[ nPos ] == nUid && m_pLocalNames[ nPos ] == rLocalName)
|
|
{
|
|
return m_pValues[ nPos ];
|
|
}
|
|
}
|
|
return OUString();
|
|
}
|
|
|
|
Reference< xml::sax::XDocumentHandler > createDocumentHandler(
|
|
Reference< xml::input::XRoot > const & xRoot )
|
|
{
|
|
SAL_WARN_IF( !xRoot.is(), "xmlscript.xmlhelper", "xRoot is NULL" );
|
|
if (xRoot.is())
|
|
{
|
|
return new DocumentHandlerImpl(xRoot, true /* mt use */);
|
|
}
|
|
return Reference< xml::sax::XDocumentHandler >();
|
|
}
|
|
|
|
Reference< XInterface > create_DocumentHandlerImpl(
|
|
SAL_UNUSED_PARAMETER Reference< XComponentContext > const & )
|
|
{
|
|
return static_cast< ::cppu::OWeakObject * >(
|
|
new DocumentHandlerImpl(
|
|
Reference< xml::input::XRoot >(), false /* mt use */ ) );
|
|
}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|