Optimize TokenMap and AttributeList in oox and xo
Shaves lots of string allocations, and uses optimized code paths Change-Id: I8e33e2aecdc7e0d2f2c31b774daa36304b3973ac Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173179 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
@@ -35,7 +35,7 @@ SvXMLAutoCorrectTokenHandler::~SvXMLAutoCorrectTokenHandler()
|
||||
|
||||
sal_Int32 SAL_CALL SvXMLAutoCorrectTokenHandler::getTokenFromUTF8( const Sequence< sal_Int8 >& Identifier )
|
||||
{
|
||||
return getTokenDirect( reinterpret_cast< const char* >( Identifier.getConstArray() ), Identifier.getLength() );
|
||||
return getTokenDirect( std::string_view(reinterpret_cast< const char* >( Identifier.getConstArray() ), Identifier.getLength()) );
|
||||
}
|
||||
|
||||
Sequence< sal_Int8 > SAL_CALL SvXMLAutoCorrectTokenHandler::getUTF8Identifier( sal_Int32 )
|
||||
@@ -43,11 +43,9 @@ Sequence< sal_Int8 > SAL_CALL SvXMLAutoCorrectTokenHandler::getUTF8Identifier( s
|
||||
return Sequence< sal_Int8 >();
|
||||
}
|
||||
|
||||
sal_Int32 SvXMLAutoCorrectTokenHandler::getTokenDirect( const char *pTag, sal_Int32 nLength ) const
|
||||
sal_Int32 SvXMLAutoCorrectTokenHandler::getTokenDirect(std::string_view token) const
|
||||
{
|
||||
if( !nLength )
|
||||
nLength = strlen( pTag );
|
||||
const struct xmltoken* pToken = Perfect_Hash::in_word_set( pTag, nLength );
|
||||
const struct xmltoken* pToken = Perfect_Hash::in_word_set(token.data(), token.size());
|
||||
return pToken ? pToken->nToken : XML_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ public:
|
||||
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getUTF8Identifier( sal_Int32 Token ) override;
|
||||
|
||||
// Much faster direct C++ shortcut to the method that matters
|
||||
virtual sal_Int32 getTokenDirect( const char *pToken, sal_Int32 nLength ) const override;
|
||||
virtual sal_Int32 getTokenDirect(std::string_view token) const override;
|
||||
};
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <sal/types.h>
|
||||
#include <sax/fastattribs.hxx>
|
||||
|
||||
namespace oox { class TokenMap; }
|
||||
|
||||
namespace oox::core {
|
||||
|
||||
|
||||
@@ -41,8 +39,7 @@ class OOX_DLLPUBLIC FastTokenHandler final :
|
||||
public cppu::ImplInheritanceHelper< sax_fastparser::FastTokenHandlerBase, css::lang::XServiceInfo >
|
||||
{
|
||||
public:
|
||||
explicit FastTokenHandler();
|
||||
virtual ~FastTokenHandler() override;
|
||||
explicit FastTokenHandler() = default;
|
||||
|
||||
// XServiceInfo
|
||||
virtual OUString SAL_CALL getImplementationName() override;
|
||||
@@ -54,10 +51,7 @@ public:
|
||||
virtual sal_Int32 SAL_CALL getTokenFromUTF8( const css::uno::Sequence< sal_Int8 >& Identifier ) override;
|
||||
|
||||
// Much faster direct C++ shortcut to the method that matters
|
||||
virtual sal_Int32 getTokenDirect( const char *pToken, sal_Int32 nLength ) const override;
|
||||
|
||||
private:
|
||||
const TokenMap& mrTokenMap; ///< Reference to global token map singleton.
|
||||
virtual sal_Int32 getTokenDirect(std::string_view token) const override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <com/sun/star/util/DateTime.hpp>
|
||||
#include <oox/dllapi.h>
|
||||
#include <rtl/ustring.hxx>
|
||||
#include <rtl/ref.hxx>
|
||||
#include <sal/types.h>
|
||||
#include <oox/drawingml/color.hxx>
|
||||
|
||||
@@ -83,10 +84,10 @@ class OOX_DLLPUBLIC AttributeList
|
||||
public:
|
||||
explicit AttributeList(
|
||||
const css::uno::Reference< css::xml::sax::XFastAttributeList >& rxAttribs );
|
||||
~AttributeList();
|
||||
|
||||
/** Returns the wrapped com.sun.star.xml.sax.XFastAttributeList object. */
|
||||
const css::uno::Reference< css::xml::sax::XFastAttributeList >&
|
||||
getFastAttributeList() const { return mxAttribs; }
|
||||
css::uno::Reference<css::xml::sax::XFastAttributeList> getFastAttributeList() const;
|
||||
|
||||
/** Returns true, if the specified attribute is present. */
|
||||
bool hasAttribute( sal_Int32 nAttrToken ) const;
|
||||
@@ -180,10 +181,12 @@ public:
|
||||
std::vector<sal_Int32> getTokenList(sal_Int32 nAttrToken) const;
|
||||
|
||||
private:
|
||||
css::uno::Reference< css::xml::sax::XFastAttributeList >
|
||||
mxAttribs;
|
||||
mutable sax_fastparser::FastAttributeList *mpAttribList;
|
||||
sax_fastparser::FastAttributeList *getAttribList() const;
|
||||
AttributeList(const AttributeList&) = delete;
|
||||
AttributeList(AttributeList&&) = delete;
|
||||
void operator=(const AttributeList&) = delete;
|
||||
void operator=(AttributeList&&) = delete;
|
||||
|
||||
rtl::Reference<sax_fastparser::FastAttributeList> mxAttribs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -35,70 +35,29 @@
|
||||
namespace oox {
|
||||
|
||||
|
||||
class TokenMap
|
||||
namespace TokenMap
|
||||
{
|
||||
public:
|
||||
explicit TokenMap();
|
||||
~TokenMap();
|
||||
/** Returns the token identifier for a UTF8 string passed in pToken */
|
||||
sal_Int32 getTokenFromUtf8(std::string_view token);
|
||||
|
||||
/** Returns the token identifier for the passed Unicode token name. */
|
||||
static sal_Int32 getTokenFromUnicode( std::u16string_view rUnicodeName );
|
||||
/** Returns the token identifier for the passed Unicode token name. */
|
||||
inline sal_Int32 getTokenFromUnicode(std::u16string_view rUnicodeName)
|
||||
{
|
||||
return getTokenFromUtf8(OUStringToOString(rUnicodeName, RTL_TEXTENCODING_UTF8));
|
||||
}
|
||||
|
||||
/** Returns the UTF8 name of the passed token identifier as byte sequence. */
|
||||
css::uno::Sequence< sal_Int8 > const &
|
||||
getUtf8TokenName( sal_Int32 nToken ) const
|
||||
{
|
||||
SAL_WARN_IF(nToken < 0 || nToken >= XML_TOKEN_COUNT, "oox", "Wrong nToken parameter");
|
||||
if (0 <= nToken && nToken < XML_TOKEN_COUNT)
|
||||
return maTokenNames[ nToken ];
|
||||
return EMPTY_BYTE_SEQ;
|
||||
}
|
||||
/** Returns the UTF8 name of the passed token identifier as byte sequence. */
|
||||
css::uno::Sequence<sal_Int8> const& getUtf8TokenName(sal_Int32 nToken);
|
||||
|
||||
/** Returns the token identifier for the passed UTF8 token name. */
|
||||
sal_Int32 getTokenFromUtf8(
|
||||
const css::uno::Sequence< sal_Int8 >& rUtf8Name ) const
|
||||
{
|
||||
return getTokenFromUTF8( reinterpret_cast< const char * >(
|
||||
rUtf8Name.getConstArray() ),
|
||||
rUtf8Name.getLength() );
|
||||
}
|
||||
|
||||
/** Returns the token identifier for a UTF8 string passed in pToken */
|
||||
sal_Int32 getTokenFromUTF8( const char *pToken, sal_Int32 nLength ) const
|
||||
{
|
||||
// 50% of OOXML tokens are primarily 1 lower-case character, a-z
|
||||
if( nLength == 1)
|
||||
{
|
||||
char c = pToken[0];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return mnAlphaTokens[ c - 'a' ];
|
||||
}
|
||||
return getTokenPerfectHash( pToken, nLength );
|
||||
}
|
||||
|
||||
/** Returns the name of the passed token identifier as OUString. */
|
||||
OUString getUnicodeTokenName(sal_Int32 nToken) const
|
||||
{
|
||||
SAL_WARN_IF(nToken < 0 || nToken >= XML_TOKEN_COUNT, "oox", "Wrong nToken parameter");
|
||||
OUString const ret((0 <= nToken && nToken < XML_TOKEN_COUNT)
|
||||
? rtl::OUString(reinterpret_cast<const char*>(maTokenNames[nToken].getConstArray()),
|
||||
maTokenNames[nToken].getLength(), RTL_TEXTENCODING_UTF8)
|
||||
: OUString());
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
static sal_Int32 getTokenPerfectHash( const char *pToken, sal_Int32 nLength );
|
||||
static const css::uno::Sequence< sal_Int8 > EMPTY_BYTE_SEQ;
|
||||
|
||||
std::vector< css::uno::Sequence< sal_Int8 > >
|
||||
maTokenNames;
|
||||
sal_Int32 mnAlphaTokens[26];
|
||||
/** Returns the name of the passed token identifier as OUString. */
|
||||
inline OUString getUnicodeTokenName(sal_Int32 nToken)
|
||||
{
|
||||
auto name = getUtf8TokenName(nToken);
|
||||
return OUString(reinterpret_cast<const char*>(name.getConstArray()), name.getLength(),
|
||||
RTL_TEXTENCODING_UTF8);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
TokenMap& StaticTokenMap();
|
||||
|
||||
} // namespace oox
|
||||
|
||||
#endif
|
||||
|
||||
@@ -56,7 +56,7 @@ class SAX_DLLPUBLIC FastTokenHandlerBase :
|
||||
{
|
||||
public:
|
||||
virtual ~FastTokenHandlerBase();
|
||||
virtual sal_Int32 getTokenDirect( const char *pToken, sal_Int32 nLength ) const = 0;
|
||||
virtual sal_Int32 getTokenDirect(std::string_view token) const = 0;
|
||||
|
||||
/**
|
||||
* Client method to attempt the use of this interface if possible.
|
||||
@@ -122,6 +122,7 @@ public:
|
||||
{
|
||||
return OStringToOUString(getAsViewByIndex(nTokenIndex), RTL_TEXTENCODING_UTF8);
|
||||
}
|
||||
sal_Int32 getValueTokenByIndex(sal_Int32 nTokenIndex) const;
|
||||
|
||||
// XFastAttributeList
|
||||
virtual sal_Bool SAL_CALL hasAttribute( ::sal_Int32 Token ) override;
|
||||
|
||||
@@ -30,9 +30,6 @@ public:
|
||||
CPPUNIT_TEST(test_roundTrip);
|
||||
CPPUNIT_TEST(test_roundTripUnicode);
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
private:
|
||||
TokenMap tokenMap;
|
||||
};
|
||||
|
||||
void TokenmapTest::test_roundTrip()
|
||||
@@ -40,10 +37,9 @@ void TokenmapTest::test_roundTrip()
|
||||
for ( sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken )
|
||||
{
|
||||
// check that the getIdentifier <-> getToken roundtrip works
|
||||
Sequence< sal_Int8 > rUtf8Name = tokenMap.getUtf8TokenName(nToken);
|
||||
sal_Int32 ret = tokenMap.getTokenFromUTF8(
|
||||
reinterpret_cast< const char * >(rUtf8Name.getConstArray()),
|
||||
rUtf8Name.getLength() );
|
||||
Sequence< sal_Int8 > rUtf8Name = TokenMap::getUtf8TokenName(nToken);
|
||||
sal_Int32 ret = TokenMap::getTokenFromUtf8(std::string_view(
|
||||
reinterpret_cast<const char*>(rUtf8Name.getConstArray()), rUtf8Name.getLength()));
|
||||
CPPUNIT_ASSERT_EQUAL(ret, nToken);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +49,7 @@ void TokenmapTest::test_roundTripUnicode()
|
||||
for (sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken)
|
||||
{
|
||||
// check that the getIdentifier <-> getToken roundtrip works for OUString
|
||||
OUString sName = tokenMap.getUnicodeTokenName(nToken);
|
||||
OUString sName = TokenMap::getUnicodeTokenName(nToken);
|
||||
sal_Int32 ret = oox::TokenMap::getTokenFromUnicode(sName);
|
||||
CPPUNIT_ASSERT_EQUAL(ret, nToken);
|
||||
}
|
||||
|
||||
@@ -29,15 +29,6 @@ namespace oox::core {
|
||||
|
||||
using namespace ::com::sun::star::uno;
|
||||
|
||||
FastTokenHandler::FastTokenHandler() :
|
||||
mrTokenMap( StaticTokenMap() )
|
||||
{
|
||||
}
|
||||
|
||||
FastTokenHandler::~FastTokenHandler()
|
||||
{
|
||||
}
|
||||
|
||||
// XServiceInfo
|
||||
OUString SAL_CALL FastTokenHandler::getImplementationName()
|
||||
{
|
||||
@@ -57,17 +48,18 @@ Sequence< OUString > SAL_CALL FastTokenHandler::getSupportedServiceNames()
|
||||
|
||||
Sequence< sal_Int8 > FastTokenHandler::getUTF8Identifier( sal_Int32 nToken )
|
||||
{
|
||||
return mrTokenMap.getUtf8TokenName( nToken );
|
||||
return TokenMap::getUtf8TokenName(nToken);
|
||||
}
|
||||
|
||||
sal_Int32 FastTokenHandler::getTokenFromUTF8( const Sequence< sal_Int8 >& rIdentifier )
|
||||
{
|
||||
return mrTokenMap.getTokenFromUtf8( rIdentifier );
|
||||
return TokenMap::getTokenFromUtf8(std::string_view(
|
||||
reinterpret_cast<const char*>(rIdentifier.getConstArray()), rIdentifier.getLength()));
|
||||
}
|
||||
|
||||
sal_Int32 FastTokenHandler::getTokenDirect( const char *pToken, sal_Int32 nLength ) const
|
||||
sal_Int32 FastTokenHandler::getTokenDirect(std::string_view token) const
|
||||
{
|
||||
return mrTokenMap.getTokenFromUTF8( pToken, nLength );
|
||||
return TokenMap::getTokenFromUtf8(token);
|
||||
}
|
||||
|
||||
} // namespace oox::core
|
||||
@@ -76,7 +68,7 @@ extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
|
||||
com_sun_star_comp_oox_core_FastTokenHandler_get_implementation(
|
||||
uno::XComponentContext* /*pCtx*/, uno::Sequence<uno::Any> const& /*rSeq*/)
|
||||
{
|
||||
return cppu::acquire(new oox::core::FastTokenHandler());
|
||||
return cppu::acquire(new oox::core::FastTokenHandler);
|
||||
}
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
return Sequence<sal_Int8>();
|
||||
}
|
||||
|
||||
virtual sal_Int32 getTokenDirect( const char * /* pToken */, sal_Int32 /* nLength */ ) const override
|
||||
virtual sal_Int32 getTokenDirect(std::string_view /* token */) const override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ CustomShapeProperties::CustomShapeProperties()
|
||||
|
||||
OUString CustomShapeProperties::getShapePresetTypeName() const
|
||||
{
|
||||
return StaticTokenMap().getUnicodeTokenName(mnShapePresetType);
|
||||
return TokenMap::getUnicodeTokenName(mnShapePresetType);
|
||||
}
|
||||
|
||||
bool CustomShapeProperties::representsDefaultShape() const
|
||||
|
||||
@@ -605,7 +605,7 @@ void TableCell::pushToXCell( const ::oox::core::XmlFilterBase& rFilterBase, cons
|
||||
else if ( getVertToken() != XML_horz && getVertToken() != XML_eaVert )
|
||||
{
|
||||
// put the vert value in the grab bag for roundtrip
|
||||
const OUString aTokenName(StaticTokenMap().getUnicodeTokenName(getVertToken()));
|
||||
const OUString aTokenName(TokenMap::getUnicodeTokenName(getVertToken()));
|
||||
Sequence<PropertyValue> aGrabBag;
|
||||
xPropSet->getPropertyValue(u"CellInteropGrabBag"_ustr) >>= aGrabBag;
|
||||
PropertyValue aPropertyValue = comphelper::makePropertyValue(u"mso-tcPr-vert-value"_ustr, aTokenName);
|
||||
|
||||
@@ -62,6 +62,19 @@ sal_Unicode lclGetXChar( const sal_Unicode*& rpcStr, const sal_Unicode* pcEnd )
|
||||
return *rpcStr++;
|
||||
}
|
||||
|
||||
template<typename C> sal_uInt32 decodeUnsigned_impl(std::basic_string_view<C> rValue)
|
||||
{
|
||||
return getLimitedValue<sal_uInt32, sal_Int64>(o3tl::toInt64(rValue), 0, SAL_MAX_UINT32);
|
||||
}
|
||||
|
||||
template <typename C> sal_Int32 decodeIntegerHex_impl(std::basic_string_view<C> rValue)
|
||||
{
|
||||
// It looks like all Office Open XML attributes containing hexadecimal
|
||||
// values are based on xsd:hexBinary and so use an unsigned representation:
|
||||
return static_cast<sal_Int32>(o3tl::toUInt32(rValue, 16));
|
||||
//TODO: Change this function to return sal_uInt32 and get rid of the
|
||||
// cast, but that will have a ripple effect
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#define STRING_TO_TOKEN(color) if (sColorName == u"" #color) return XML_##color
|
||||
@@ -98,12 +111,13 @@ OUString AttributeConversion::decodeXString( const OUString& rValue )
|
||||
// string shorter than one encoded character - no need to decode
|
||||
if( rValue.getLength() < XSTRING_ENCCHAR_LEN )
|
||||
return rValue;
|
||||
if (rValue.indexOf(u"_x") == -1)
|
||||
sal_Int32 index = rValue.indexOf(u"_x");
|
||||
if (index == -1)
|
||||
return rValue;
|
||||
|
||||
OUStringBuffer aBuffer;
|
||||
const sal_Unicode* pcStr = rValue.getStr();
|
||||
const sal_Unicode* pcEnd = pcStr + rValue.getLength();
|
||||
OUStringBuffer aBuffer(rValue.subView(0, index));
|
||||
const sal_Unicode* pcStr = rValue.getStr() + index;
|
||||
const sal_Unicode* pcEnd = rValue.getStr() + rValue.getLength();
|
||||
while( pcStr < pcEnd )
|
||||
aBuffer.append( lclGetXChar( pcStr, pcEnd ) );
|
||||
return comphelper::string::sanitizeStringSurrogates(aBuffer.makeStringAndClear());
|
||||
@@ -116,7 +130,7 @@ sal_Int32 AttributeConversion::decodeInteger( std::u16string_view rValue )
|
||||
|
||||
sal_uInt32 AttributeConversion::decodeUnsigned( std::u16string_view rValue )
|
||||
{
|
||||
return getLimitedValue< sal_uInt32, sal_Int64 >( o3tl::toInt64(rValue), 0, SAL_MAX_UINT32 );
|
||||
return decodeUnsigned_impl(rValue);
|
||||
}
|
||||
|
||||
sal_Int64 AttributeConversion::decodeHyper( std::u16string_view rValue )
|
||||
@@ -126,27 +140,19 @@ sal_Int64 AttributeConversion::decodeHyper( std::u16string_view rValue )
|
||||
|
||||
sal_Int32 AttributeConversion::decodeIntegerHex( std::u16string_view rValue )
|
||||
{
|
||||
// It looks like all Office Open XML attributes containing hexadecimal
|
||||
// values are based on xsd:hexBinary and so use an unsigned representation:
|
||||
return static_cast< sal_Int32 >(o3tl::toUInt32(rValue, 16));
|
||||
//TODO: Change this function to return sal_uInt32 and get rid of the
|
||||
// cast, but that will have a ripple effect
|
||||
return decodeIntegerHex_impl(rValue);
|
||||
}
|
||||
|
||||
AttributeList::AttributeList( const Reference< XFastAttributeList >& rxAttribs ) :
|
||||
mxAttribs( rxAttribs ),
|
||||
mpAttribList( nullptr )
|
||||
mxAttribs(&sax_fastparser::castToFastAttributeList(rxAttribs))
|
||||
{
|
||||
OSL_ENSURE( mxAttribs.is(), "AttributeList::AttributeList - missing attribute list interface" );
|
||||
}
|
||||
|
||||
sax_fastparser::FastAttributeList *AttributeList::getAttribList() const
|
||||
AttributeList::~AttributeList() = default;
|
||||
|
||||
css::uno::Reference<css::xml::sax::XFastAttributeList> AttributeList::getFastAttributeList() const
|
||||
{
|
||||
if( mpAttribList == nullptr )
|
||||
{
|
||||
mpAttribList = &sax_fastparser::castToFastAttributeList( mxAttribs );
|
||||
}
|
||||
return mpAttribList;
|
||||
return mxAttribs;
|
||||
}
|
||||
|
||||
bool AttributeList::hasAttribute( sal_Int32 nAttrToken ) const
|
||||
@@ -173,46 +179,43 @@ std::optional< sal_Int32 > AttributeList::getToken( sal_Int32 nAttrToken ) const
|
||||
std::optional< OUString > AttributeList::getString( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
// check if the attribute exists (empty string may be different to missing attribute)
|
||||
if( mxAttribs->hasAttribute( nAttrToken ) )
|
||||
return std::optional< OUString >( mxAttribs->getOptionalValue( nAttrToken ) );
|
||||
if (sal_Int32 index = mxAttribs->getAttributeIndex(nAttrToken); index >= 0)
|
||||
return mxAttribs->getValueByIndex(index);
|
||||
return std::optional< OUString >();
|
||||
}
|
||||
|
||||
OUString AttributeList::getStringDefaulted( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
// check if the attribute exists (empty string may be different to missing attribute)
|
||||
if( mxAttribs->hasAttribute( nAttrToken ) )
|
||||
return mxAttribs->getOptionalValue( nAttrToken );
|
||||
return OUString();
|
||||
return mxAttribs->getOptionalValue(nAttrToken);
|
||||
}
|
||||
|
||||
std::optional< OUString > AttributeList::getXString( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
// check if the attribute exists (empty string may be different to missing attribute)
|
||||
if( mxAttribs->hasAttribute( nAttrToken ) )
|
||||
return std::optional< OUString >( AttributeConversion::decodeXString( mxAttribs->getOptionalValue( nAttrToken ) ) );
|
||||
if (sal_Int32 index = mxAttribs->getAttributeIndex(nAttrToken); index >= 0)
|
||||
return AttributeConversion::decodeXString(mxAttribs->getValueByIndex(index));
|
||||
return std::optional< OUString >();
|
||||
}
|
||||
|
||||
std::optional< double > AttributeList::getDouble( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
double nValue;
|
||||
bool bValid = getAttribList()->getAsDouble( nAttrToken, nValue );
|
||||
bool bValid = mxAttribs->getAsDouble(nAttrToken, nValue);
|
||||
return bValid ? std::optional< double >( nValue ) : std::optional< double >();
|
||||
}
|
||||
|
||||
std::optional< sal_Int32 > AttributeList::getInteger( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
sal_Int32 nValue;
|
||||
bool bValid = getAttribList()->getAsInteger( nAttrToken, nValue );
|
||||
bool bValid = mxAttribs->getAsInteger(nAttrToken, nValue);
|
||||
return bValid ? std::optional< sal_Int32 >( nValue ) : std::optional< sal_Int32 >();
|
||||
}
|
||||
|
||||
std::optional< sal_uInt32 > AttributeList::getUnsigned( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
|
||||
bool bValid = !aValue.isEmpty();
|
||||
return bValid ? std::optional< sal_uInt32 >( AttributeConversion::decodeUnsigned( aValue ) ) : std::optional< sal_uInt32 >();
|
||||
std::string_view aValue = getView(nAttrToken);
|
||||
bool bValid = !aValue.empty();
|
||||
return bValid ? std::optional< sal_uInt32 >( decodeUnsigned_impl( aValue ) ) : std::optional< sal_uInt32 >();
|
||||
}
|
||||
|
||||
std::optional< sal_Int64 > AttributeList::getHyper( sal_Int32 nAttrToken ) const
|
||||
@@ -224,19 +227,19 @@ std::optional< sal_Int64 > AttributeList::getHyper( sal_Int32 nAttrToken ) const
|
||||
|
||||
std::optional< sal_Int32 > AttributeList::getIntegerHex( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
|
||||
bool bValid = !aValue.isEmpty();
|
||||
return bValid ? std::optional< sal_Int32 >( AttributeConversion::decodeIntegerHex( aValue ) ) : std::optional< sal_Int32 >();
|
||||
std::string_view aValue = getView(nAttrToken);
|
||||
bool bValid = !aValue.empty();
|
||||
return bValid ? std::optional< sal_Int32 >( decodeIntegerHex_impl( aValue ) ) : std::optional< sal_Int32 >();
|
||||
}
|
||||
|
||||
std::optional< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
std::string_view pAttr;
|
||||
sal_Int32 index = mxAttribs->getAttributeIndex(nAttrToken);
|
||||
if (index == -1)
|
||||
return std::optional< bool >();
|
||||
std::string_view pAttr = mxAttribs->getAsViewByIndex(index);
|
||||
|
||||
// catch the common cases as quickly as possible first
|
||||
bool bHasAttr = getAttribList()->getAsView( nAttrToken, pAttr );
|
||||
if( !bHasAttr )
|
||||
return std::optional< bool >();
|
||||
if( pAttr == "false" )
|
||||
return std::optional< bool >( false );
|
||||
if( pAttr == "true" )
|
||||
@@ -245,7 +248,7 @@ std::optional< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
|
||||
// now for all the crazy stuff
|
||||
|
||||
// boolean attributes may be "t", "f", "true", "false", "on", "off", "1", or "0"
|
||||
switch( getToken( nAttrToken, XML_TOKEN_INVALID ) )
|
||||
switch (mxAttribs->getValueTokenByIndex(index))
|
||||
{
|
||||
case XML_t: return std::optional< bool >( true ); // used in VML
|
||||
case XML_true: return std::optional< bool >( true );
|
||||
@@ -254,8 +257,7 @@ std::optional< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
|
||||
case XML_false: return std::optional< bool >( false );
|
||||
case XML_off: return std::optional< bool >( false );
|
||||
}
|
||||
std::optional< sal_Int32 > onValue = getInteger( nAttrToken );
|
||||
return onValue.has_value() ? std::optional< bool >( onValue.value() != 0 ) : std::optional< bool >();
|
||||
return std::optional<bool>(o3tl::toInt32(pAttr) != 0);
|
||||
}
|
||||
|
||||
std::optional< util::DateTime > AttributeList::getDateTime( sal_Int32 nAttrToken ) const
|
||||
@@ -288,17 +290,8 @@ sal_Int32 AttributeList::getToken( sal_Int32 nAttrToken, sal_Int32 nDefault ) co
|
||||
|
||||
OUString AttributeList::getString( sal_Int32 nAttrToken, const OUString& rDefault ) const
|
||||
{
|
||||
// try to avoid slow exception throw/catch if we can
|
||||
if (rDefault.isEmpty())
|
||||
return mxAttribs->getOptionalValue( nAttrToken );
|
||||
|
||||
try
|
||||
{
|
||||
return mxAttribs->getValue( nAttrToken );
|
||||
}
|
||||
catch( Exception& )
|
||||
{
|
||||
}
|
||||
if (sal_Int32 index = mxAttribs->getAttributeIndex(nAttrToken); index >= 0)
|
||||
return mxAttribs->getValueByIndex(index);
|
||||
return rDefault;
|
||||
}
|
||||
|
||||
@@ -310,7 +303,7 @@ OUString AttributeList::getXString( sal_Int32 nAttrToken, const OUString& rDefau
|
||||
std::string_view AttributeList::getView( sal_Int32 nAttrToken ) const
|
||||
{
|
||||
std::string_view p;
|
||||
getAttribList()->getAsView(nAttrToken, p);
|
||||
mxAttribs->getAsView(nAttrToken, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -357,12 +350,9 @@ util::DateTime AttributeList::getDateTime( sal_Int32 nAttrToken, const util::Dat
|
||||
std::vector<sal_Int32> AttributeList::getTokenList(sal_Int32 nAttrToken) const
|
||||
{
|
||||
std::vector<sal_Int32> aValues;
|
||||
OUString sValue = getString(nAttrToken, u""_ustr);
|
||||
sal_Int32 nIndex = 0;
|
||||
do
|
||||
{
|
||||
aValues.push_back(AttributeConversion::decodeToken(o3tl::getToken(sValue, 0, ' ', nIndex)));
|
||||
} while (nIndex >= 0);
|
||||
if (std::string_view sValue = getView(nAttrToken); !sValue.empty())
|
||||
for (size_t index = 0; index != std::string_view::npos;)
|
||||
aValues.push_back(TokenMap::getTokenFromUtf8(o3tl::getToken(sValue, ' ', index)));
|
||||
|
||||
return aValues;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ AttributeListBuilder::AttributeListBuilder( const uno::Reference< xml::sax::XFas
|
||||
|
||||
OString tokenToString( int token )
|
||||
{
|
||||
uno::Sequence< sal_Int8 > const & aTokenNameSeq = StaticTokenMap().getUtf8TokenName( token & TOKEN_MASK );
|
||||
uno::Sequence<sal_Int8> const& aTokenNameSeq = TokenMap::getUtf8TokenName(token & TOKEN_MASK);
|
||||
OString tokenname( reinterpret_cast< const char* >( aTokenNameSeq.getConstArray() ), aTokenNameSeq.getLength() );
|
||||
if( tokenname.isEmpty())
|
||||
tokenname = "???"_ostr;
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
||||
*/
|
||||
|
||||
#include <sal/config.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <oox/token/tokenmap.hxx>
|
||||
|
||||
#include <string.h>
|
||||
@@ -25,8 +29,6 @@
|
||||
|
||||
namespace oox {
|
||||
|
||||
using ::com::sun::star::uno::Sequence;
|
||||
|
||||
namespace {
|
||||
// include auto-generated Perfect_Hash
|
||||
#if defined __clang__
|
||||
@@ -42,55 +44,61 @@ namespace {
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
const css::uno::Sequence< sal_Int8 > TokenMap::EMPTY_BYTE_SEQ;
|
||||
|
||||
TokenMap::TokenMap() :
|
||||
maTokenNames( static_cast< size_t >( XML_TOKEN_COUNT ) )
|
||||
{
|
||||
static const char* sppcTokenNames[] =
|
||||
{
|
||||
// include auto-generated C array with token names as C strings
|
||||
#include <tokennames.inc>
|
||||
""
|
||||
};
|
||||
|
||||
const char* const* ppcTokenName = sppcTokenNames;
|
||||
for (auto & tokenName : maTokenNames)
|
||||
{
|
||||
OString aUtf8Token( *ppcTokenName );
|
||||
tokenName = Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( aUtf8Token.getStr() ), aUtf8Token.getLength() );
|
||||
++ppcTokenName;
|
||||
}
|
||||
|
||||
for (unsigned char c = 'a'; c <= 'z'; c++)
|
||||
{
|
||||
const struct xmltoken* pToken = Perfect_Hash::in_word_set(
|
||||
reinterpret_cast< const char* >( &c ), 1 );
|
||||
mnAlphaTokens[ c - 'a' ] = pToken ? pToken->nToken : XML_TOKEN_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
TokenMap::~TokenMap()
|
||||
{
|
||||
}
|
||||
|
||||
sal_Int32 TokenMap::getTokenFromUnicode( std::u16string_view rUnicodeName )
|
||||
{
|
||||
OString aUtf8Name = OUStringToOString( rUnicodeName, RTL_TEXTENCODING_UTF8 );
|
||||
const struct xmltoken* pToken = Perfect_Hash::in_word_set( aUtf8Name.getStr(), aUtf8Name.getLength() );
|
||||
return pToken ? pToken->nToken : XML_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
sal_Int32 TokenMap::getTokenPerfectHash( const char *pStr, sal_Int32 nLength )
|
||||
static sal_Int32 getTokenPerfectHash(const char* pStr, sal_Int32 nLength)
|
||||
{
|
||||
const struct xmltoken* pToken = Perfect_Hash::in_word_set( pStr, nLength );
|
||||
return pToken ? pToken->nToken : XML_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
TokenMap& StaticTokenMap()
|
||||
css::uno::Sequence<sal_Int8> const& TokenMap::getUtf8TokenName(sal_Int32 nToken)
|
||||
{
|
||||
static TokenMap SINGLETON;
|
||||
return SINGLETON;
|
||||
static const auto saTokenNames = []()
|
||||
{
|
||||
static constexpr std::string_view sppcTokenNames[] = {
|
||||
// include auto-generated C array with token names as C strings
|
||||
#include <tokennames.inc>
|
||||
};
|
||||
static_assert(std::size(sppcTokenNames) == XML_TOKEN_COUNT);
|
||||
|
||||
std::vector<css::uno::Sequence<sal_Int8>> aTokenNames;
|
||||
aTokenNames.reserve(std::size(sppcTokenNames));
|
||||
std::transform(
|
||||
std::begin(sppcTokenNames), std::end(sppcTokenNames), std::back_inserter(aTokenNames),
|
||||
[](auto aUtf8Token)
|
||||
{
|
||||
return css::uno::Sequence<sal_Int8>(
|
||||
reinterpret_cast<const sal_Int8*>(aUtf8Token.data()), aUtf8Token.size());
|
||||
});
|
||||
return aTokenNames;
|
||||
}();
|
||||
|
||||
SAL_WARN_IF(nToken < 0 || nToken >= XML_TOKEN_COUNT, "oox", "Wrong nToken parameter");
|
||||
if (0 <= nToken && nToken < XML_TOKEN_COUNT)
|
||||
return saTokenNames[nToken];
|
||||
static const css::uno::Sequence<sal_Int8> EMPTY_BYTE_SEQ;
|
||||
return EMPTY_BYTE_SEQ;
|
||||
}
|
||||
|
||||
|
||||
/** Returns the token identifier for a UTF8 string passed in pToken */
|
||||
sal_Int32 TokenMap::getTokenFromUtf8(std::string_view token)
|
||||
{
|
||||
static const auto snAlphaTokens = []()
|
||||
{
|
||||
std::array<sal_Int32, 26> nAlphaTokens{};
|
||||
for (char c = 'a'; c <= 'z'; c++)
|
||||
nAlphaTokens[c - 'a'] = getTokenPerfectHash(&c, 1);
|
||||
return nAlphaTokens;
|
||||
}();
|
||||
|
||||
// 50% of OOXML tokens are primarily 1 lower-case character, a-z
|
||||
if (token.size() == 1)
|
||||
{
|
||||
char c = token[0];
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return snAlphaTokens[c - 'a'];
|
||||
}
|
||||
return getTokenPerfectHash(token.data(), token.size());
|
||||
}
|
||||
|
||||
} // namespace oox
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
CPPUNIT_ASSERT_MESSAGE( "getUTF8Identifier: unexpected call", false );
|
||||
return uno::Sequence<sal_Int8>();
|
||||
}
|
||||
virtual sal_Int32 getTokenDirect( const char * /* pToken */, sal_Int32 /* nLength */ ) const override
|
||||
virtual sal_Int32 getTokenDirect(std::string_view /* token */) const override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ public:
|
||||
virtual Sequence< sal_Int8 > SAL_CALL getUTF8Identifier( sal_Int32 nToken ) override;
|
||||
virtual sal_Int32 SAL_CALL getTokenFromUTF8( const css::uno::Sequence< sal_Int8 >& Identifier ) override;
|
||||
//FastTokenHandlerBase
|
||||
virtual sal_Int32 getTokenDirect( const char *pToken, sal_Int32 nLength ) const override;
|
||||
virtual sal_Int32 getTokenDirect(std::string_view sToken) const override;
|
||||
};
|
||||
|
||||
const std::string_view DummyTokenHandler::tokens[] = {
|
||||
@@ -304,13 +304,12 @@ Sequence< sal_Int8 > DummyTokenHandler::getUTF8Identifier( sal_Int32 nToken )
|
||||
|
||||
sal_Int32 DummyTokenHandler::getTokenFromUTF8( const uno::Sequence< sal_Int8 >& rIdentifier )
|
||||
{
|
||||
return getTokenDirect( reinterpret_cast< const char* >(
|
||||
rIdentifier.getConstArray() ), rIdentifier.getLength() );
|
||||
return getTokenDirect(std::string_view(
|
||||
reinterpret_cast<const char*>(rIdentifier.getConstArray()), rIdentifier.getLength()));
|
||||
}
|
||||
|
||||
sal_Int32 DummyTokenHandler::getTokenDirect( const char* pToken, sal_Int32 nLength ) const
|
||||
sal_Int32 DummyTokenHandler::getTokenDirect(std::string_view sToken) const
|
||||
{
|
||||
std::string_view sToken( pToken, nLength );
|
||||
for( size_t i = 0; i < std::size(tokens); i++ )
|
||||
{
|
||||
if ( tokens[i] == sToken )
|
||||
|
||||
@@ -172,9 +172,7 @@ sal_Int32 FastAttributeList::getValueToken( ::sal_Int32 Token )
|
||||
{
|
||||
for (size_t i = 0, n = maAttributeTokens.size(); i < n; ++i)
|
||||
if (maAttributeTokens[i] == Token)
|
||||
return FastTokenHandlerBase::getTokenFromChars(
|
||||
mpTokenHandler,
|
||||
getAsViewByIndex(i) );
|
||||
return getValueTokenByIndex(i);
|
||||
|
||||
throw SAXException("FastAttributeList::getValueToken: unknown token " + OUString::number(Token), nullptr, Any());
|
||||
}
|
||||
@@ -183,9 +181,7 @@ sal_Int32 FastAttributeList::getOptionalValueToken( ::sal_Int32 Token, ::sal_Int
|
||||
{
|
||||
for (size_t i = 0, n = maAttributeTokens.size(); i < n; ++i)
|
||||
if (maAttributeTokens[i] == Token)
|
||||
return FastTokenHandlerBase::getTokenFromChars(
|
||||
mpTokenHandler,
|
||||
getAsViewByIndex(i) );
|
||||
return getValueTokenByIndex(i);
|
||||
|
||||
return Default;
|
||||
}
|
||||
@@ -246,6 +242,12 @@ OUString FastAttributeList::getOptionalValue( ::sal_Int32 Token )
|
||||
|
||||
return OUString();
|
||||
}
|
||||
|
||||
sal_Int32 FastAttributeList::getValueTokenByIndex(sal_Int32 nTokenIndex) const
|
||||
{
|
||||
return FastTokenHandlerBase::getTokenFromChars(mpTokenHandler, getAsViewByIndex(nTokenIndex));
|
||||
}
|
||||
|
||||
Sequence< Attribute > FastAttributeList::getUnknownAttributes( )
|
||||
{
|
||||
auto nSize = maUnknownAttributes.size();
|
||||
@@ -282,7 +284,7 @@ sal_Int32 FastTokenHandlerBase::getTokenFromChars(
|
||||
const FastTokenHandlerBase *pTokenHandler,
|
||||
std::string_view token )
|
||||
{
|
||||
return pTokenHandler->getTokenDirect(token.data(), token.size());
|
||||
return pTokenHandler->getTokenDirect(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
css::uno::Sequence< sal_Int8 > SAL_CALL getUTF8Identifier( sal_Int32 Token ) override;
|
||||
|
||||
//Much fast direct C++ shortcut to the method that matters
|
||||
virtual sal_Int32 getTokenDirect( const char *pTag, sal_Int32 nLength ) const override;
|
||||
virtual sal_Int32 getTokenDirect(std::string_view token) const override;
|
||||
};
|
||||
|
||||
enum SwXMLBlockListToken : sal_Int32
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
css::uno::Sequence< sal_Int8 > SAL_CALL getUTF8Identifier( sal_Int32 Token ) override;
|
||||
|
||||
//Much fast direct C++ shortcut to the method that matters
|
||||
virtual sal_Int32 getTokenDirect( const char *pTag, sal_Int32 nLength ) const override;
|
||||
virtual sal_Int32 getTokenDirect(std::string_view token) const override;
|
||||
};
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
||||
@@ -127,7 +127,7 @@ SwXMLTextBlockTokenHandler::~SwXMLTextBlockTokenHandler()
|
||||
|
||||
sal_Int32 SAL_CALL SwXMLTextBlockTokenHandler::getTokenFromUTF8( const Sequence< sal_Int8 >& Identifier )
|
||||
{
|
||||
return getTokenDirect( reinterpret_cast< const char* >( Identifier.getConstArray() ), Identifier.getLength() );
|
||||
return getTokenDirect( std::string_view(reinterpret_cast< const char* >( Identifier.getConstArray() ), Identifier.getLength()) );
|
||||
}
|
||||
|
||||
Sequence< sal_Int8 > SAL_CALL SwXMLTextBlockTokenHandler::getUTF8Identifier( sal_Int32 )
|
||||
@@ -135,11 +135,9 @@ Sequence< sal_Int8 > SAL_CALL SwXMLTextBlockTokenHandler::getUTF8Identifier( sal
|
||||
return Sequence< sal_Int8 >();
|
||||
}
|
||||
|
||||
sal_Int32 SwXMLTextBlockTokenHandler::getTokenDirect( const char *pTag, sal_Int32 nLength ) const
|
||||
sal_Int32 SwXMLTextBlockTokenHandler::getTokenDirect(std::string_view token) const
|
||||
{
|
||||
if( !nLength )
|
||||
nLength = strlen( pTag );
|
||||
const struct xmltoken* pToken = TextBlockTokens::in_word_set( pTag, nLength );
|
||||
const struct xmltoken* pToken = TextBlockTokens::in_word_set(token.data(), token.size());
|
||||
return pToken ? pToken->nToken : XML_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
@@ -153,7 +151,7 @@ SwXMLBlockListTokenHandler::~SwXMLBlockListTokenHandler()
|
||||
|
||||
sal_Int32 SAL_CALL SwXMLBlockListTokenHandler::getTokenFromUTF8( const Sequence< sal_Int8 >& Identifier )
|
||||
{
|
||||
return getTokenDirect( reinterpret_cast< const char* >( Identifier.getConstArray() ), Identifier.getLength() );
|
||||
return getTokenDirect( std::string_view(reinterpret_cast< const char* >( Identifier.getConstArray() ), Identifier.getLength()) );
|
||||
}
|
||||
|
||||
Sequence< sal_Int8 > SAL_CALL SwXMLBlockListTokenHandler::getUTF8Identifier( sal_Int32 )
|
||||
@@ -161,11 +159,9 @@ Sequence< sal_Int8 > SAL_CALL SwXMLBlockListTokenHandler::getUTF8Identifier( sal
|
||||
return Sequence< sal_Int8 >();
|
||||
}
|
||||
|
||||
sal_Int32 SwXMLBlockListTokenHandler::getTokenDirect( const char *pTag, sal_Int32 nLength ) const
|
||||
sal_Int32 SwXMLBlockListTokenHandler::getTokenDirect(std::string_view token) const
|
||||
{
|
||||
if( !nLength )
|
||||
nLength = strlen( pTag );
|
||||
const struct xmltoken* pToken = BlockListTokens::in_word_set( pTag, nLength );
|
||||
const struct xmltoken* pToken = BlockListTokens::in_word_set(token.data(), token.size());
|
||||
return pToken ? pToken->nToken : XML_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
|
||||
@@ -394,7 +394,7 @@ uno::Reference<uno::XComponentContext> OOXMLStreamImpl::getContext()
|
||||
uno::Reference <xml::sax::XFastTokenHandler> OOXMLStreamImpl::getFastTokenHandler()
|
||||
{
|
||||
if (! mxFastTokenHandler.is())
|
||||
mxFastTokenHandler.set(new oox::core::FastTokenHandler());
|
||||
mxFastTokenHandler.set(new oox::core::FastTokenHandler);
|
||||
|
||||
return mxFastTokenHandler;
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ struct TokenHandler : public sax_fastparser::FastTokenHandlerBase
|
||||
return uno::Sequence<sal_Int8>();
|
||||
}
|
||||
|
||||
virtual sal_Int32 getTokenDirect( const char * /* pToken */, sal_Int32 /* nLength */ ) const override
|
||||
virtual sal_Int32 getTokenDirect( std::string_view /* token */ ) const override
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -15,72 +15,29 @@
|
||||
|
||||
namespace xmloff::token {
|
||||
|
||||
class TokenMap
|
||||
namespace TokenMap
|
||||
{
|
||||
public:
|
||||
explicit TokenMap();
|
||||
~TokenMap();
|
||||
/** Returns the UTF-8 name of the passed token identifier as byte sequence. */
|
||||
css::uno::Sequence<sal_Int8> const& getUtf8TokenName(sal_Int32 nToken);
|
||||
|
||||
/** Returns the UTF-8 name of the passed token identifier as byte sequence. */
|
||||
css::uno::Sequence< sal_Int8 > const & getUtf8TokenName( sal_Int32 nToken ) const
|
||||
{
|
||||
SAL_WARN_IF(nToken < 0 || nToken >= XML_TOKEN_COUNT, "xmloff", "Wrong nToken parameter");
|
||||
if( 0 <= nToken && nToken < XML_TOKEN_COUNT )
|
||||
return maTokenNamesUtf8[ nToken ];
|
||||
return EMPTY_BYTE_SEQ;
|
||||
}
|
||||
|
||||
const OUString& getTokenName( sal_Int32 nToken ) const
|
||||
{
|
||||
SAL_WARN_IF(nToken < 0 || nToken >= XML_TOKEN_COUNT, "xmloff", "Wrong nToken parameter");
|
||||
if( 0 <= nToken && nToken < XML_TOKEN_COUNT )
|
||||
return maTokenNames[ nToken ];
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
||||
/** Returns the token identifier for the passed UTF-8 token name. */
|
||||
static sal_Int32 getTokenFromUtf8( const css::uno::Sequence< sal_Int8 >& rUtf8Name )
|
||||
{
|
||||
return getTokenFromUTF8( reinterpret_cast< const char* >(
|
||||
rUtf8Name.getConstArray() ), rUtf8Name.getLength() );
|
||||
}
|
||||
|
||||
/** Returns the token identifier for a UTF-8 string */
|
||||
static sal_Int32 getTokenFromUTF8( const char *pToken, sal_Int32 nLength )
|
||||
{
|
||||
return getTokenPerfectHash( pToken, nLength );
|
||||
}
|
||||
|
||||
private:
|
||||
static sal_Int32 getTokenPerfectHash( const char *pToken, sal_Int32 nLength );
|
||||
|
||||
std::vector< css::uno::Sequence< sal_Int8 > > maTokenNamesUtf8;
|
||||
std::vector< OUString > maTokenNames;
|
||||
|
||||
static const css::uno::Sequence< sal_Int8 > EMPTY_BYTE_SEQ;
|
||||
static const OUString EMPTY_STRING;
|
||||
/** Returns the token identifier for a UTF-8 string */
|
||||
sal_Int32 getTokenFromUtf8(std::string_view token);
|
||||
};
|
||||
|
||||
TokenMap& StaticTokenMap();
|
||||
|
||||
class FastTokenHandler final :
|
||||
public sax_fastparser::FastTokenHandlerBase
|
||||
{
|
||||
public:
|
||||
explicit FastTokenHandler();
|
||||
virtual ~FastTokenHandler() override;
|
||||
explicit FastTokenHandler() = default;
|
||||
|
||||
// XFastTokenHandler
|
||||
virtual css::uno::Sequence< sal_Int8 > SAL_CALL getUTF8Identifier( sal_Int32 nToken ) override;
|
||||
virtual sal_Int32 SAL_CALL getTokenFromUTF8( const css::uno::Sequence< sal_Int8 >& Identifier ) override;
|
||||
|
||||
const OUString & getIdentifier( sal_Int32 nToken ) const;
|
||||
static const OUString& getIdentifier(sal_Int32 nToken);
|
||||
|
||||
// Much faster direct C++ shortcut to the method that matters
|
||||
virtual sal_Int32 getTokenDirect( const char *pToken, sal_Int32 nLength ) const override;
|
||||
|
||||
private:
|
||||
TokenMap& mrTokenMap;
|
||||
virtual sal_Int32 getTokenDirect(std::string_view token) const override;
|
||||
};
|
||||
|
||||
} // namespace xmloff::token
|
||||
|
||||
@@ -23,9 +23,6 @@ namespace xmloff {
|
||||
class TokenmapTest: public CppUnit::TestFixture
|
||||
{
|
||||
public:
|
||||
|
||||
TokenmapTest();
|
||||
|
||||
void test_roundTrip();
|
||||
void test_listEquality();
|
||||
|
||||
@@ -35,25 +32,18 @@ public:
|
||||
CPPUNIT_TEST(test_listEquality);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
private:
|
||||
std::unique_ptr<token::TokenMap> pTokenMap;
|
||||
};
|
||||
|
||||
TokenmapTest::TokenmapTest() : pTokenMap(new token::TokenMap)
|
||||
{
|
||||
}
|
||||
|
||||
void TokenmapTest::test_roundTrip()
|
||||
{
|
||||
for ( sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken )
|
||||
{
|
||||
// check that the getIdentifier <-> getToken roundtrip works
|
||||
Sequence< sal_Int8 > rUtf8Name = pTokenMap->getUtf8TokenName(nToken);
|
||||
Sequence< sal_Int8 > rUtf8Name = token::TokenMap::getUtf8TokenName(nToken);
|
||||
CPPUNIT_ASSERT_MESSAGE("Token name sequence should not be empty", rUtf8Name.getLength());
|
||||
const char* pChar = reinterpret_cast< const char * >(rUtf8Name.getConstArray());
|
||||
CPPUNIT_ASSERT_MESSAGE("Token name sequence array pointer failed", pChar);
|
||||
sal_Int32 ret = token::TokenMap::getTokenFromUTF8( pChar, rUtf8Name.getLength() );
|
||||
sal_Int32 ret = token::TokenMap::getTokenFromUtf8( std::string_view(pChar, rUtf8Name.getLength()) );
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("No roundtrip for token", ret, nToken);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +55,7 @@ void TokenmapTest::test_listEquality()
|
||||
// aTokenList in xmloff/source/core/xmltoken.cxx, and xmloff/source/token/tokens.txt
|
||||
for ( sal_Int32 nToken = 0; nToken < XML_TOKEN_COUNT; ++nToken )
|
||||
{
|
||||
Sequence< sal_Int8 > rUtf8Name = pTokenMap->getUtf8TokenName(nToken);
|
||||
Sequence<sal_Int8> rUtf8Name = token::TokenMap::getUtf8TokenName(nToken);
|
||||
const OUString& rName = OUString( reinterpret_cast< const char* >(
|
||||
rUtf8Name.getConstArray() ), rUtf8Name.getLength(), RTL_TEXTENCODING_UTF8 );
|
||||
if ( rName.endsWith("_DUMMY") )
|
||||
@@ -78,7 +68,7 @@ void TokenmapTest::test_listEquality()
|
||||
nToken < xmloff::token::XMLTokenEnum::XML_TOKEN_END; ++nToken )
|
||||
{
|
||||
const OUString& rTokenName = GetXMLToken( static_cast<xmloff::token::XMLTokenEnum>(nToken) );
|
||||
Sequence< sal_Int8 > rUtf8Name = pTokenMap->getUtf8TokenName(nToken);
|
||||
Sequence<sal_Int8> rUtf8Name = token::TokenMap::getUtf8TokenName(nToken);
|
||||
const OUString& rName = OUString( reinterpret_cast< const char* >(
|
||||
rUtf8Name.getConstArray() ), rUtf8Name.getLength(), RTL_TEXTENCODING_UTF8 );
|
||||
if ( !rName.endsWith("_DUMMY") )
|
||||
|
||||
@@ -32,76 +32,73 @@ namespace token {
|
||||
|
||||
using namespace css;
|
||||
|
||||
TokenMap& StaticTokenMap()
|
||||
static sal_Int32 getTokenPerfectHash(const char* pStr, sal_Int32 nLength)
|
||||
{
|
||||
static TokenMap SINGLETON;
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
const css::uno::Sequence< sal_Int8 > TokenMap::EMPTY_BYTE_SEQ;
|
||||
const OUString TokenMap::EMPTY_STRING;
|
||||
|
||||
TokenMap::TokenMap() :
|
||||
maTokenNamesUtf8( static_cast< size_t >( XML_TOKEN_COUNT ) ),
|
||||
maTokenNames( static_cast< size_t >( XML_TOKEN_COUNT ) )
|
||||
{
|
||||
static const char* sppcTokenNames[] =
|
||||
{
|
||||
#include <tokennames.inc>
|
||||
""
|
||||
};
|
||||
|
||||
const char* const* ppcTokenName = sppcTokenNames;
|
||||
int i = 0;
|
||||
for( auto& rTokenName : maTokenNamesUtf8 )
|
||||
{
|
||||
std::string_view pStr = *ppcTokenName;
|
||||
rTokenName = uno::Sequence< sal_Int8 >(
|
||||
reinterpret_cast< const sal_Int8* >( pStr.data() ), pStr.length() );
|
||||
maTokenNames[i++] = OStringToOUString( pStr, RTL_TEXTENCODING_UTF8 );
|
||||
++ppcTokenName;
|
||||
}
|
||||
}
|
||||
|
||||
TokenMap::~TokenMap()
|
||||
{
|
||||
}
|
||||
|
||||
sal_Int32 TokenMap::getTokenPerfectHash( const char *pStr, sal_Int32 nLength )
|
||||
{
|
||||
const struct xmltoken *pToken = Perfect_Hash::in_word_set( pStr, nLength );
|
||||
const struct xmltoken* pToken = Perfect_Hash::in_word_set(pStr, nLength);
|
||||
return pToken ? pToken->nToken : xmloff::XML_TOKEN_INVALID;
|
||||
}
|
||||
|
||||
FastTokenHandler::FastTokenHandler() :
|
||||
mrTokenMap( StaticTokenMap() )
|
||||
static const std::pair<css::uno::Sequence<sal_Int8>, OUString>& getNames(sal_Int32 nToken)
|
||||
{
|
||||
static const auto saTokenNames = []()
|
||||
{
|
||||
static constexpr std::string_view sppcTokenNames[] = {
|
||||
#include <tokennames.inc>
|
||||
};
|
||||
static_assert(std::size(sppcTokenNames) == XML_TOKEN_COUNT);
|
||||
|
||||
std::vector<std::pair<css::uno::Sequence<sal_Int8>, OUString>> names;
|
||||
names.reserve(std::size(sppcTokenNames));
|
||||
std::transform(std::begin(sppcTokenNames), std::end(sppcTokenNames),
|
||||
std::back_inserter(names),
|
||||
[](auto token)
|
||||
{
|
||||
return std::make_pair(
|
||||
css::uno::Sequence<sal_Int8>(
|
||||
reinterpret_cast<const sal_Int8*>(token.data()), token.size()),
|
||||
OStringToOUString(token, RTL_TEXTENCODING_UTF8));
|
||||
});
|
||||
return names;
|
||||
}();
|
||||
|
||||
SAL_WARN_IF(nToken < 0 || nToken >= XML_TOKEN_COUNT, "xmloff", "Wrong nToken parameter");
|
||||
if (0 <= nToken && nToken < XML_TOKEN_COUNT)
|
||||
return saTokenNames[nToken];
|
||||
static const std::pair<css::uno::Sequence<sal_Int8>, OUString> EMPTY;
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
FastTokenHandler::~FastTokenHandler()
|
||||
css::uno::Sequence<sal_Int8> const& TokenMap::getUtf8TokenName(sal_Int32 nToken)
|
||||
{
|
||||
return getNames(nToken).first;
|
||||
}
|
||||
|
||||
sal_Int32 TokenMap::getTokenFromUtf8(std::string_view token)
|
||||
{
|
||||
return getTokenPerfectHash(token.data(), token.size());
|
||||
}
|
||||
|
||||
// XFastTokenHandler
|
||||
uno::Sequence< sal_Int8 > FastTokenHandler::getUTF8Identifier( sal_Int32 nToken )
|
||||
{
|
||||
return mrTokenMap.getUtf8TokenName( nToken );
|
||||
return TokenMap::getUtf8TokenName( nToken );
|
||||
}
|
||||
|
||||
const OUString& FastTokenHandler::getIdentifier( sal_Int32 nToken ) const
|
||||
const OUString& FastTokenHandler::getIdentifier(sal_Int32 nToken)
|
||||
{
|
||||
return mrTokenMap.getTokenName( nToken );
|
||||
return getNames(nToken).second;
|
||||
}
|
||||
|
||||
sal_Int32 FastTokenHandler::getTokenFromUTF8( const uno::Sequence< sal_Int8 >& rIdentifier )
|
||||
{
|
||||
return TokenMap::getTokenFromUtf8( rIdentifier );
|
||||
return TokenMap::getTokenFromUtf8(std::string_view(
|
||||
reinterpret_cast<const char*>(rIdentifier.getConstArray()), rIdentifier.getLength()));
|
||||
}
|
||||
|
||||
// Much faster direct C++ shortcut
|
||||
sal_Int32 FastTokenHandler::getTokenDirect( const char* pToken, sal_Int32 nLength ) const
|
||||
sal_Int32 FastTokenHandler::getTokenDirect(std::string_view token) const
|
||||
{
|
||||
return TokenMap::getTokenFromUTF8( pToken, nLength );
|
||||
return TokenMap::getTokenFromUtf8(token);
|
||||
}
|
||||
|
||||
} // namespace token
|
||||
|
||||
@@ -88,7 +88,7 @@ using namespace ::com::sun::star::container;
|
||||
using namespace ::com::sun::star::document;
|
||||
using namespace ::xmloff::token;
|
||||
|
||||
rtl::Reference< FastTokenHandler > SvXMLImport::xTokenHandler( new FastTokenHandler() );
|
||||
rtl::Reference<FastTokenHandler> SvXMLImport::xTokenHandler(new FastTokenHandler);
|
||||
std::unordered_map< sal_Int32, std::pair< OUString, OUString > > SvXMLImport::aNamespaceMap;
|
||||
std::unordered_map< OUString, OUString > SvXMLImport::aNamespaceURIPrefixMap;
|
||||
bool SvXMLImport::bIsNSMapsInitialized = false;
|
||||
@@ -1985,7 +1985,7 @@ bool SvXMLImport::embeddedFontAlreadyProcessed( const OUString& url )
|
||||
|
||||
const OUString & SvXMLImport::getNameFromToken( sal_Int32 nToken )
|
||||
{
|
||||
return xTokenHandler->getIdentifier( nToken & TOKEN_MASK );
|
||||
return FastTokenHandler::getIdentifier( nToken & TOKEN_MASK );
|
||||
}
|
||||
|
||||
OUString SvXMLImport::getPrefixAndNameFromToken( sal_Int32 nToken )
|
||||
@@ -1995,7 +1995,7 @@ OUString SvXMLImport::getPrefixAndNameFromToken( sal_Int32 nToken )
|
||||
auto aIter( aNamespaceMap.find( nNamespaceToken ) );
|
||||
if( aIter != aNamespaceMap.end() )
|
||||
rv = (*aIter).second.second + " " + aIter->second.first + ":";
|
||||
return rv + xTokenHandler->getIdentifier( nToken & TOKEN_MASK );
|
||||
return rv + FastTokenHandler::getIdentifier(nToken & TOKEN_MASK);
|
||||
}
|
||||
|
||||
OUString SvXMLImport::getNamespacePrefixFromToken(sal_Int32 nToken, const SvXMLNamespaceMap* pMap)
|
||||
|
||||
Reference in New Issue
Block a user