summaryrefslogtreecommitdiffstats
path: root/xmloff/source/core/xmluconv.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'xmloff/source/core/xmluconv.cxx')
-rw-r--r--xmloff/source/core/xmluconv.cxx949
1 files changed, 949 insertions, 0 deletions
diff --git a/xmloff/source/core/xmluconv.cxx b/xmloff/source/core/xmluconv.cxx
new file mode 100644
index 000000000..07e0e0c0b
--- /dev/null
+++ b/xmloff/source/core/xmluconv.cxx
@@ -0,0 +1,949 @@
+/* -*- 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 <string_view>
+
+#include <xmloff/xmluconv.hxx>
+
+#include <com/sun/star/util/DateTime.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <xmloff/xmlement.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <rtl/math.hxx>
+
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <tools/fldunit.hxx>
+
+#include <com/sun/star/drawing/Position3D.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/style/NumberingType.hpp>
+#include <com/sun/star/text/DefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XDefaultNumberingProvider.hpp>
+#include <com/sun/star/text/XNumberingTypeInfo.hpp>
+#include <com/sun/star/i18n/CharacterClassification.hpp>
+#include <com/sun/star/i18n/UnicodeType.hpp>
+#include <basegfx/vector/b3dvector.hxx>
+
+#include <sax/tools/converter.hxx>
+
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::text;
+using namespace com::sun::star::style;
+using namespace ::com::sun::star::i18n;
+using namespace ::xmloff::token;
+
+
+const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 11;
+constexpr OUStringLiteral XML_NULLDATE = u"NullDate";
+
+struct SvXMLUnitConverter::Impl
+{
+ sal_Int16 m_eCoreMeasureUnit; /*css::util::MeasureUnit*/
+ sal_Int16 m_eXMLMeasureUnit; /*css::util::MeasureUnit*/
+ SvtSaveOptions::ODFSaneDefaultVersion m_eODFVersion;
+ util::Date m_aNullDate;
+ mutable uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo;
+ mutable uno::Reference< i18n::XCharacterClassification > m_xCharClass;
+ uno::Reference< uno::XComponentContext > m_xContext;
+
+ Impl(uno::Reference<uno::XComponentContext> const& xContext,
+ sal_Int16 const eCoreMeasureUnit,
+ sal_Int16 const eXMLMeasureUnit,
+ SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
+ : m_eCoreMeasureUnit(eCoreMeasureUnit)
+ , m_eXMLMeasureUnit(eXMLMeasureUnit)
+ , m_eODFVersion(nODFVersion)
+ , m_aNullDate(30, 12, 1899)
+ , m_xContext(xContext)
+ {
+ OSL_ENSURE( m_xContext.is(), "got no service manager" );
+ }
+
+ void createNumTypeInfo() const;
+};
+
+
+void SvXMLUnitConverter::Impl::createNumTypeInfo() const
+{
+ Reference<XDefaultNumberingProvider> xDefNum = DefaultNumberingProvider::create(m_xContext);
+ m_xNumTypeInfo.set(xDefNum, uno::UNO_QUERY);
+}
+
+const uno::Reference< text::XNumberingTypeInfo >&
+SvXMLUnitConverter::getNumTypeInfo() const
+{
+ if (!m_pImpl->m_xNumTypeInfo.is())
+ {
+ m_pImpl->createNumTypeInfo();
+ }
+ return m_pImpl->m_xNumTypeInfo;
+}
+
+void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit/*css::util::MeasureUnit*/)
+{
+ m_pImpl->m_eCoreMeasureUnit = eCoreMeasureUnit;
+}
+
+void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit/*css::util::MeasureUnit*/)
+{
+ m_pImpl->m_eXMLMeasureUnit = eXMLMeasureUnit;
+}
+
+sal_Int16 SvXMLUnitConverter::GetXMLMeasureUnit() const
+{
+ return m_pImpl->m_eXMLMeasureUnit;
+}
+
+SvtSaveOptions::ODFSaneDefaultVersion SvXMLUnitConverter::getSaneDefaultVersion() const
+{
+ return m_pImpl->m_eODFVersion;
+}
+
+void SvXMLUnitConverter::overrideSaneDefaultVersion(
+ SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
+{
+ m_pImpl->m_eODFVersion = nODFVersion;
+}
+
+/** constructs a SvXMLUnitConverter. The core measure unit is the
+ default unit for numerical measures, the XML measure unit is
+ the default unit for textual measures
+*/
+
+SvXMLUnitConverter::SvXMLUnitConverter(
+ const uno::Reference<uno::XComponentContext>& xContext,
+ sal_Int16 const eCoreMeasureUnit,
+ sal_Int16 const eXMLMeasureUnit,
+ SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
+: m_pImpl(new Impl(xContext, eCoreMeasureUnit, eXMLMeasureUnit, nODFVersion))
+{
+}
+
+SvXMLUnitConverter::~SvXMLUnitConverter()
+{
+}
+
+sal_Int16 SvXMLUnitConverter::GetMeasureUnit(FieldUnit const nFieldUnit)
+{
+ sal_Int16 eUnit = util::MeasureUnit::INCH;
+ switch( nFieldUnit )
+ {
+ case FieldUnit::MM:
+ eUnit = util::MeasureUnit::MM;
+ break;
+ case FieldUnit::CM:
+ case FieldUnit::M:
+ case FieldUnit::KM:
+ eUnit = util::MeasureUnit::CM;
+ break;
+ case FieldUnit::TWIP:
+ eUnit = util::MeasureUnit::TWIP;
+ break;
+ case FieldUnit::POINT:
+ case FieldUnit::PICA:
+ eUnit = util::MeasureUnit::POINT;
+ break;
+ case FieldUnit::MM_100TH:
+ eUnit = util::MeasureUnit::MM_100TH;
+ break;
+ case FieldUnit::INCH:
+ eUnit = util::MeasureUnit::INCH;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ return eUnit;
+}
+
+/** convert string to measure using optional min and max values*/
+bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue,
+ std::u16string_view rString,
+ sal_Int32 nMin, sal_Int32 nMax ) const
+{
+ return ::sax::Converter::convertMeasure( nValue, rString,
+ m_pImpl->m_eCoreMeasureUnit,
+ nMin, nMax );
+}
+
+/** convert string to measure using optional min and max values*/
+bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue,
+ std::string_view rString,
+ sal_Int32 nMin, sal_Int32 nMax ) const
+{
+ return ::sax::Converter::convertMeasure( nValue, rString,
+ m_pImpl->m_eCoreMeasureUnit,
+ nMin, nMax );
+}
+
+/** convert measure to string */
+void SvXMLUnitConverter::convertMeasureToXML( OUStringBuffer& rString,
+ sal_Int32 nMeasure ) const
+{
+ ::sax::Converter::convertMeasure( rString, nMeasure,
+ m_pImpl->m_eCoreMeasureUnit,
+ m_pImpl->m_eXMLMeasureUnit );
+}
+
+/** convert measure to string */
+OUString SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure ) const
+{
+ OUStringBuffer s;
+ ::sax::Converter::convertMeasure( s, nMeasure,
+ m_pImpl->m_eCoreMeasureUnit,
+ m_pImpl->m_eXMLMeasureUnit );
+ return s.makeStringAndClear();
+}
+
+/** convert string to enum using given enum map, if the enum is
+ not found in the map, this method will return false
+*/
+bool SvXMLUnitConverter::convertEnumImpl( sal_uInt16& rEnum,
+ std::u16string_view rValue,
+ const SvXMLEnumStringMapEntry<sal_uInt16> *pMap )
+{
+ while( pMap->GetName() )
+ {
+ auto nameLength = pMap->GetNameLength();
+ if( static_cast<sal_Int32>(rValue.size()) == nameLength &&
+ rtl_ustr_asciil_reverseEquals_WithLength(
+ rValue.data(), pMap->GetName(), nameLength ) )
+ {
+ rEnum = pMap->GetValue();
+ return true;
+ }
+ ++pMap;
+ }
+
+ return false;
+}
+
+/** convert string to enum using given token map, if the enum is
+ not found in the map, this method will return false */
+bool SvXMLUnitConverter::convertEnumImpl(
+ sal_uInt16& rEnum,
+ std::u16string_view rValue,
+ const SvXMLEnumMapEntry<sal_uInt16> *pMap )
+{
+ while( pMap->GetToken() != XML_TOKEN_INVALID )
+ {
+ if( IsXMLToken( rValue, pMap->GetToken() ) )
+ {
+ rEnum = pMap->GetValue();
+ return true;
+ }
+ ++pMap;
+ }
+ return false;
+}
+
+/** convert string to enum using given token map, if the enum is
+ not found in the map, this method will return false */
+bool SvXMLUnitConverter::convertEnumImpl(
+ sal_uInt16& rEnum,
+ std::string_view rValue,
+ const SvXMLEnumMapEntry<sal_uInt16> *pMap )
+{
+ while( pMap->GetToken() != XML_TOKEN_INVALID )
+ {
+ if( IsXMLToken( rValue, pMap->GetToken() ) )
+ {
+ rEnum = pMap->GetValue();
+ return true;
+ }
+ ++pMap;
+ }
+ return false;
+}
+
+/** convert enum to string using given token map with an optional
+ default token. If the enum is not found in the map,
+ this method will either use the given default or return
+ false if no default is set */
+bool SvXMLUnitConverter::convertEnumImpl(
+ OUStringBuffer& rBuffer,
+ sal_uInt16 nValue,
+ const SvXMLEnumMapEntry<sal_uInt16> *pMap,
+ enum XMLTokenEnum eDefault)
+{
+ enum XMLTokenEnum eTok = eDefault;
+
+ while( pMap->GetToken() != XML_TOKEN_INVALID )
+ {
+ if( pMap->GetValue() == nValue )
+ {
+ eTok = pMap->GetToken();
+ break;
+ }
+ ++pMap;
+ }
+
+ // the map may have contained XML_TOKEN_INVALID
+ if( eTok == XML_TOKEN_INVALID )
+ eTok = eDefault;
+
+ if( eTok != XML_TOKEN_INVALID )
+ rBuffer.append( GetXMLToken(eTok) );
+
+ return (eTok != XML_TOKEN_INVALID);
+}
+
+static int lcl_gethex( int nChar )
+{
+ if( nChar >= '0' && nChar <= '9' )
+ return nChar - '0';
+ else if( nChar >= 'a' && nChar <= 'f' )
+ return nChar - 'a' + 10;
+ else if( nChar >= 'A' && nChar <= 'F' )
+ return nChar - 'A' + 10;
+ else
+ return 0;
+}
+
+const char aHexTab[] = "0123456789abcdef";
+
+
+/** convert double number to string (using ::rtl::math) */
+void SvXMLUnitConverter::convertDouble(OUStringBuffer& rBuffer,
+ double fNumber) const
+{
+ ::sax::Converter::convertDouble(rBuffer, fNumber,
+ true/*bWriteUnits*/, m_pImpl->m_eCoreMeasureUnit, m_pImpl->m_eXMLMeasureUnit);
+}
+
+/** convert string to double number (using ::rtl::math) */
+bool SvXMLUnitConverter::convertDouble(double& rValue,
+ std::u16string_view rString) const
+{
+ sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
+ rString, m_pImpl->m_eCoreMeasureUnit);
+
+ return ::sax::Converter::convertDouble(rValue, rString,
+ eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
+}
+
+/** convert string to double number (using ::rtl::math) */
+bool SvXMLUnitConverter::convertDouble(double& rValue,
+ std::string_view rString) const
+{
+ sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
+ rString, m_pImpl->m_eCoreMeasureUnit);
+
+ return ::sax::Converter::convertDouble(rValue, rString,
+ eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
+}
+
+/** get the Null Date of the XModel and set it to the UnitConverter */
+bool SvXMLUnitConverter::setNullDate(const css::uno::Reference <css::frame::XModel>& xModel)
+{
+ css::uno::Reference <css::util::XNumberFormatsSupplier> xNumberFormatsSupplier (xModel, css::uno::UNO_QUERY);
+ if (xNumberFormatsSupplier.is())
+ {
+ const css::uno::Reference <css::beans::XPropertySet> xPropertySet = xNumberFormatsSupplier->getNumberFormatSettings();
+ return xPropertySet.is() && (xPropertySet->getPropertyValue(XML_NULLDATE) >>= m_pImpl->m_aNullDate);
+ }
+ return false;
+}
+
+/** convert double to ISO Date Time String */
+void SvXMLUnitConverter::convertDateTime(OUStringBuffer& rBuffer,
+ const double& fDateTime, bool const bAddTimeIf0AM)
+{
+ convertDateTime(rBuffer, fDateTime, m_pImpl->m_aNullDate, bAddTimeIf0AM);
+}
+
+/** convert ISO Date Time String to double */
+bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
+ std::u16string_view rString) const
+{
+ return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
+}
+
+/** convert ISO Date Time String to double */
+bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
+ std::string_view rString) const
+{
+ return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
+}
+
+/** convert double to ISO Date Time String */
+void SvXMLUnitConverter::convertDateTime( OUStringBuffer& rBuffer,
+ const double& fDateTime,
+ const css::util::Date& aTempNullDate,
+ bool bAddTimeIf0AM )
+{
+ double fValue = fDateTime;
+ const sal_Int32 nDays = static_cast <sal_Int32> (::rtl::math::approxFloor (fValue));
+ Date aDate (aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
+ aDate.AddDays( nDays);
+ fValue -= nDays;
+ const bool bHasTime = (fValue > 0.0);
+
+ sal_Int16 nTempYear = aDate.GetYear();
+ assert(nTempYear != 0);
+ if (nTempYear < 0)
+ {
+ rBuffer.append( '-');
+ nTempYear = -nTempYear;
+ }
+ if (nTempYear < 1000)
+ rBuffer.append( '0');
+ if (nTempYear < 100)
+ rBuffer.append( '0');
+ if (nTempYear < 10)
+ rBuffer.append( '0');
+ rBuffer.append( sal_Int32( nTempYear));
+ rBuffer.append( '-');
+ sal_uInt16 nTemp = aDate.GetMonth();
+ assert(1 <= nTemp && nTemp <= 12);
+ if (nTemp < 10)
+ rBuffer.append( '0');
+ rBuffer.append( sal_Int32( nTemp));
+ rBuffer.append( '-');
+ nTemp = aDate.GetDay();
+ assert(1 <= nTemp && nTemp <= 31);
+ if (nTemp < 10)
+ rBuffer.append( '0');
+ rBuffer.append( sal_Int32( nTemp));
+ if (!(bHasTime || bAddTimeIf0AM))
+ return;
+
+ double fCount;
+ if (nDays > 0)
+ fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays))) + 1;
+ else if (nDays < 0)
+ fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays * -1))) + 1;
+ else
+ fCount = 0.0;
+ const int nDigits = sal_Int16(fCount) + 4; // +4 for *86400 in seconds
+ const int nFractionDecimals = std::max( XML_MAXDIGITSCOUNT_TIME - nDigits, 0);
+
+ sal_uInt16 nHour, nMinute, nSecond;
+ double fFractionOfSecond;
+ // Pass the original date+time value for proper scaling and rounding.
+ tools::Time::GetClock( fDateTime, nHour, nMinute, nSecond, fFractionOfSecond, nFractionDecimals);
+
+ rBuffer.append( 'T');
+ if (nHour < 10)
+ rBuffer.append( '0');
+ rBuffer.append( sal_Int32( nHour));
+ rBuffer.append( ':');
+ if (nMinute < 10)
+ rBuffer.append( '0');
+ rBuffer.append( sal_Int32( nMinute));
+ rBuffer.append( ':');
+ if (nSecond < 10)
+ rBuffer.append( '0');
+ rBuffer.append( sal_Int32( nSecond));
+ if (!nFractionDecimals)
+ return;
+
+ // nFractionDecimals+1 to not round up what GetClock() carefully
+ // truncated.
+ OUString aFraction( ::rtl::math::doubleToUString( fFractionOfSecond,
+ rtl_math_StringFormat_F,
+ nFractionDecimals + 1, '.', true));
+ const sal_Int32 nLen = aFraction.getLength();
+ if ( nLen > 2 )
+ {
+ // Truncate nFractionDecimals+1 digit if it was not rounded to zero.
+ const sal_Int32 nCount = nLen - 2 - static_cast<int>(nLen > nFractionDecimals + 2);
+ rBuffer.append( '.');
+ rBuffer.append( aFraction.subView(2, nCount)); // strip 0.
+ }
+}
+
+/** convert ISO Date Time String to double */
+template<typename V>
+static bool lcl_convertDateTime( double& fDateTime,
+ V rString, const css::util::Date& aTempNullDate)
+{
+ css::util::DateTime aDateTime;
+ bool bSuccess = ::sax::Converter::parseDateTime(aDateTime, rString);
+
+ if (bSuccess)
+ {
+ const Date aTmpNullDate(aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
+ const Date aTempDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
+ const sal_Int32 nTage = aTempDate - aTmpNullDate;
+ double fTempDateTime = nTage;
+ double Hour = aDateTime.Hours;
+ double Min = aDateTime.Minutes;
+ double Sec = aDateTime.Seconds;
+ double NanoSec = aDateTime.NanoSeconds;
+ fTempDateTime += Hour / ::tools::Time::hourPerDay;
+ fTempDateTime += Min / ::tools::Time::minutePerDay;
+ fTempDateTime += Sec / ::tools::Time::secondPerDay;
+ fTempDateTime += NanoSec / ::tools::Time::nanoSecPerDay;
+ fDateTime = fTempDateTime;
+ }
+ return bSuccess;
+}
+
+bool SvXMLUnitConverter::convertDateTime( double& fDateTime,
+ std::u16string_view rString, const css::util::Date& aTempNullDate)
+{
+ return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
+}
+/** convert ISO Date Time String to double */
+bool SvXMLUnitConverter::convertDateTime( double& fDateTime,
+ std::string_view rString, const css::util::Date& aTempNullDate)
+{
+ return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
+}
+
+
+SvXMLTokenEnumerator::SvXMLTokenEnumerator( std::u16string_view rString, sal_Unicode cSeparator /* = ' ' */ )
+: maTokenString( rString ), mnNextTokenPos(0), mcSeparator( cSeparator )
+{
+}
+
+bool SvXMLTokenEnumerator::getNextToken( std::u16string_view& rToken )
+{
+ if( std::u16string_view::npos == mnNextTokenPos )
+ return false;
+
+ size_t nTokenEndPos = maTokenString.find( mcSeparator, mnNextTokenPos );
+ if( nTokenEndPos != std::u16string_view::npos )
+ {
+ rToken = maTokenString.substr( mnNextTokenPos,
+ nTokenEndPos - mnNextTokenPos );
+ mnNextTokenPos = nTokenEndPos + 1;
+
+ // if the mnNextTokenPos is at the end of the string, we have
+ // to deliver an empty token
+ if( mnNextTokenPos > maTokenString.size() )
+ mnNextTokenPos = std::u16string_view::npos;
+ }
+ else
+ {
+ rToken = maTokenString.substr( mnNextTokenPos );
+ mnNextTokenPos = std::u16string_view::npos;
+ }
+
+ return true;
+}
+
+static bool lcl_getPositions(std::string_view _sValue, std::string_view& _rContentX, std::string_view& _rContentY, std::string_view& _rContentZ)
+{
+ if(_sValue.empty() || _sValue[0] != '(')
+ return false;
+
+ size_t nPos(1);
+ size_t nFound = _sValue.find(' ', nPos);
+
+ if(nFound == std::string_view::npos || nFound <= nPos)
+ return false;
+
+ _rContentX = _sValue.substr(nPos, nFound - nPos);
+
+ nPos = nFound + 1;
+ nFound = _sValue.find(' ', nPos);
+
+ if(nFound == std::string_view::npos || nFound <= nPos)
+ return false;
+
+ _rContentY = _sValue.substr(nPos, nFound - nPos);
+
+ nPos = nFound + 1;
+ nFound = _sValue.find(')', nPos);
+
+ if(nFound == std::string_view::npos || nFound <= nPos)
+ return false;
+
+ _rContentZ = _sValue.substr(nPos, nFound - nPos);
+ return true;
+
+}
+
+/** convert string to ::basegfx::B3DVector */
+bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector& rVector, std::string_view rValue )
+{
+ std::string_view aContentX,aContentY,aContentZ;
+ if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
+ return false;
+
+ rtl_math_ConversionStatus eStatus;
+
+ rVector.setX(::rtl::math::stringToDouble(aContentX, '.',
+ ',', &eStatus));
+
+ if( eStatus != rtl_math_ConversionStatus_Ok )
+ return false;
+
+ rVector.setY(::rtl::math::stringToDouble(aContentY, '.',
+ ',', &eStatus));
+
+ if( eStatus != rtl_math_ConversionStatus_Ok )
+ return false;
+
+ rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.',
+ ',', &eStatus));
+
+
+ return ( eStatus == rtl_math_ConversionStatus_Ok );
+}
+
+/** convert ::basegfx::B3DVector to string */
+void SvXMLUnitConverter::convertB3DVector( OUStringBuffer &rBuffer, const ::basegfx::B3DVector& rVector )
+{
+ rBuffer.append('(');
+ ::sax::Converter::convertDouble(rBuffer, rVector.getX());
+ rBuffer.append(' ');
+ ::sax::Converter::convertDouble(rBuffer, rVector.getY());
+ rBuffer.append(' ');
+ ::sax::Converter::convertDouble(rBuffer, rVector.getZ());
+ rBuffer.append(')');
+}
+
+/** convert string to Position3D */
+bool SvXMLUnitConverter::convertPosition3D( drawing::Position3D& rPosition,
+ std::string_view rValue ) const
+{
+ std::string_view aContentX,aContentY,aContentZ;
+ if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
+ return false;
+
+ if ( !convertDouble( rPosition.PositionX, aContentX ) )
+ return false;
+ if ( !convertDouble( rPosition.PositionY, aContentY ) )
+ return false;
+ return convertDouble( rPosition.PositionZ, aContentZ );
+}
+
+/** convert Position3D to string */
+void SvXMLUnitConverter::convertPosition3D( OUStringBuffer &rBuffer,
+ const drawing::Position3D& rPosition )
+{
+ rBuffer.append( '(' );
+ convertDouble( rBuffer, rPosition.PositionX );
+ rBuffer.append( ' ' );
+ convertDouble( rBuffer, rPosition.PositionY );
+ rBuffer.append( ' ' );
+ convertDouble( rBuffer, rPosition.PositionZ );
+ rBuffer.append( ')' );
+}
+
+bool SvXMLUnitConverter::convertNumFormat(
+ sal_Int16& rType,
+ const OUString& rNumFmt,
+ std::u16string_view rNumLetterSync,
+ bool bNumberNone ) const
+{
+ bool bRet = true;
+ bool bExt = false;
+
+ sal_Int32 nLen = rNumFmt.getLength();
+ if( 0 == nLen )
+ {
+ if( bNumberNone )
+ rType = NumberingType::NUMBER_NONE;
+ else
+ bRet = false;
+ }
+ else if( 1 == nLen )
+ {
+ switch( rNumFmt[0] )
+ {
+ case '1': rType = NumberingType::ARABIC; break;
+ case 'a': rType = NumberingType::CHARS_LOWER_LETTER; break;
+ case 'A': rType = NumberingType::CHARS_UPPER_LETTER; break;
+ case 'i': rType = NumberingType::ROMAN_LOWER; break;
+ case 'I': rType = NumberingType::ROMAN_UPPER; break;
+ default: bExt = true; break;
+ }
+ if( !bExt && IsXMLToken( rNumLetterSync, XML_TRUE ) )
+ {
+ switch( rType )
+ {
+ case NumberingType::CHARS_LOWER_LETTER:
+ rType = NumberingType::CHARS_LOWER_LETTER_N;
+ break;
+ case NumberingType::CHARS_UPPER_LETTER:
+ rType = NumberingType::CHARS_UPPER_LETTER_N;
+ break;
+ }
+ }
+ }
+ else
+ {
+ bExt = true;
+ }
+ if( bExt )
+ {
+ Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
+ if( xInfo.is() && xInfo->hasNumberingType( rNumFmt ) )
+ {
+ rType = xInfo->getNumberingType( rNumFmt );
+ }
+ else
+ {
+ rType = NumberingType::ARABIC;
+ }
+ }
+
+ return bRet;
+}
+
+void SvXMLUnitConverter::convertNumFormat( OUStringBuffer& rBuffer,
+ sal_Int16 nType ) const
+{
+ enum XMLTokenEnum eFormat = XML_TOKEN_INVALID;
+ switch( nType )
+ {
+ case NumberingType::CHARS_UPPER_LETTER: eFormat = XML_A_UPCASE; break;
+ case NumberingType::CHARS_LOWER_LETTER: eFormat = XML_A; break;
+ case NumberingType::ROMAN_UPPER: eFormat = XML_I_UPCASE; break;
+ case NumberingType::ROMAN_LOWER: eFormat = XML_I; break;
+ case NumberingType::ARABIC: eFormat = XML_1; break;
+ case NumberingType::CHARS_UPPER_LETTER_N: eFormat = XML_A_UPCASE; break;
+ case NumberingType::CHARS_LOWER_LETTER_N: eFormat = XML_A; break;
+ case NumberingType::NUMBER_NONE: eFormat = XML__EMPTY; break;
+
+ case NumberingType::CHAR_SPECIAL:
+ case NumberingType::PAGE_DESCRIPTOR:
+ case NumberingType::BITMAP:
+ SAL_WARN_IF( eFormat == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
+ break;
+ default:
+ break;
+ }
+
+ if( eFormat != XML_TOKEN_INVALID )
+ {
+ rBuffer.append( GetXMLToken(eFormat) );
+ }
+ else
+ {
+ Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
+ if( xInfo.is() )
+ rBuffer.append( xInfo->getNumberingIdentifier( nType ) );
+ }
+}
+
+void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer& rBuffer,
+ sal_Int16 nType )
+{
+ enum XMLTokenEnum eSync = XML_TOKEN_INVALID;
+ switch( nType )
+ {
+ case NumberingType::CHARS_UPPER_LETTER:
+ case NumberingType::CHARS_LOWER_LETTER:
+ case NumberingType::ROMAN_UPPER:
+ case NumberingType::ROMAN_LOWER:
+ case NumberingType::ARABIC:
+ case NumberingType::NUMBER_NONE:
+ break;
+
+ case NumberingType::CHARS_UPPER_LETTER_N:
+ case NumberingType::CHARS_LOWER_LETTER_N:
+ eSync = XML_TRUE;
+ break;
+
+ case NumberingType::CHAR_SPECIAL:
+ case NumberingType::PAGE_DESCRIPTOR:
+ case NumberingType::BITMAP:
+ SAL_WARN_IF( eSync == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
+ break;
+ }
+ if( eSync != XML_TOKEN_INVALID )
+ rBuffer.append( GetXMLToken(eSync) );
+}
+
+void SvXMLUnitConverter::convertPropertySet(uno::Sequence<beans::PropertyValue>& rProps,
+ const uno::Reference<beans::XPropertySet>& aProperties)
+{
+ uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = aProperties->getPropertySetInfo();
+ if (!xPropertySetInfo.is())
+ return;
+
+ const uno::Sequence< beans::Property > aProps = xPropertySetInfo->getProperties();
+ if (aProps.hasElements())
+ {
+ rProps.realloc(aProps.getLength());
+ beans::PropertyValue* pProps = rProps.getArray();
+ for (const auto& rProp : aProps)
+ {
+ pProps->Name = rProp.Name;
+ pProps->Value = aProperties->getPropertyValue(rProp.Name);
+ ++pProps;
+ }
+ }
+}
+
+void SvXMLUnitConverter::convertPropertySet(uno::Reference<beans::XPropertySet> const & rProperties,
+ const uno::Sequence<beans::PropertyValue>& aProps)
+{
+ if (aProps.hasElements())
+ {
+ uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = rProperties->getPropertySetInfo();
+ if (xPropertySetInfo.is())
+ {
+ for (const auto& rProp : aProps)
+ {
+ if (xPropertySetInfo->hasPropertyByName(rProp.Name))
+ rProperties->setPropertyValue(rProp.Name, rProp.Value);
+ }
+ }
+ }
+}
+
+
+OUString SvXMLUnitConverter::encodeStyleName(
+ const OUString& rName,
+ bool *pEncoded ) const
+{
+ if( pEncoded )
+ *pEncoded = false;
+
+ sal_Int32 nLen = rName.getLength();
+ OUStringBuffer aBuffer( nLen*2 );
+
+ for( sal_Int32 i = 0; i < nLen; i++ )
+ {
+ sal_Unicode c = rName[i];
+ bool bValidChar = false;
+ if( c < 0x00ffU )
+ {
+ bValidChar =
+ (c >= 0x0041 && c <= 0x005a) ||
+ (c >= 0x0061 && c <= 0x007a) ||
+ (c >= 0x00c0 && c <= 0x00d6) ||
+ (c >= 0x00d8 && c <= 0x00f6) ||
+ (c >= 0x00f8 && c <= 0x00ff) ||
+ ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) ||
+ c == 0x00b7 || c == '-' || c == '.') );
+ }
+ else
+ {
+ if( (c >= 0xf900U && c <= 0xfffeU) ||
+ (c >= 0x20ddU && c <= 0x20e0U))
+ {
+ bValidChar = false;
+ }
+ else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
+ c == 0x06e5 || c == 0x06e6 )
+ {
+ bValidChar = true;
+ }
+ else if( c == 0x0387 )
+ {
+ bValidChar = i > 0;
+ }
+ else
+ {
+ if (!m_pImpl->m_xCharClass.is())
+ {
+ m_pImpl->m_xCharClass = CharacterClassification::create( m_pImpl->m_xContext );
+ }
+ sal_Int16 nType = m_pImpl->m_xCharClass->getType(rName, i);
+
+ switch( nType )
+ {
+ case UnicodeType::UPPERCASE_LETTER: // Lu
+ case UnicodeType::LOWERCASE_LETTER: // Ll
+ case UnicodeType::TITLECASE_LETTER: // Lt
+ case UnicodeType::OTHER_LETTER: // Lo
+ case UnicodeType::LETTER_NUMBER: // Nl
+ bValidChar = true;
+ break;
+ case UnicodeType::NON_SPACING_MARK: // Ms
+ case UnicodeType::ENCLOSING_MARK: // Me
+ case UnicodeType::COMBINING_SPACING_MARK: //Mc
+ case UnicodeType::MODIFIER_LETTER: // Lm
+ case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd
+ bValidChar = i > 0;
+ break;
+ }
+ }
+ }
+ if( bValidChar )
+ {
+ aBuffer.append( c );
+ }
+ else
+ {
+ aBuffer.append( '_' );
+ if( c > 0x0fff )
+ aBuffer.append( static_cast< sal_Unicode >(
+ aHexTab[ (c >> 12) & 0x0f ] ) );
+ if( c > 0x00ff )
+ aBuffer.append( static_cast< sal_Unicode >(
+ aHexTab[ (c >> 8) & 0x0f ] ) );
+ if( c > 0x000f )
+ aBuffer.append( static_cast< sal_Unicode >(
+ aHexTab[ (c >> 4) & 0x0f ] ) );
+ aBuffer.append( static_cast< sal_Unicode >(
+ aHexTab[ c & 0x0f ] ) );
+ aBuffer.append( '_' );
+ if( pEncoded )
+ *pEncoded = true;
+ }
+ }
+
+ // check for length
+ if( aBuffer.getLength() > ((1<<15)-1) )
+ {
+ aBuffer = rName;
+ if( pEncoded )
+ *pEncoded = false;
+ }
+
+
+ return aBuffer.makeStringAndClear();
+}
+
+/** convert string (hex) to number (sal_uInt32) */
+bool SvXMLUnitConverter::convertHex( sal_uInt32& nVal, std::u16string_view rValue )
+{
+ if( rValue.size() != 8 )
+ return false;
+
+ nVal = 0;
+ for ( int i = 0; i < 8; i++ )
+ {
+ nVal = ( nVal << 4 )
+ | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) );
+ }
+
+ return true;
+}
+
+/** convert number (sal_uInt32) to string (hex) */
+void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer,
+ sal_uInt32 nVal )
+{
+ for ( int i = 0; i < 8; i++ )
+ {
+ rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) );
+ nVal <<= 4;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */