Avoid potential negative array index access to cached text.
[LibreOffice.git] / xmloff / source / core / xmluconv.cxx
blob544bea50d3c532fb28479f57c71866f0b3ec32df
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <utility>
25 #include <xmloff/xmluconv.hxx>
27 #include <com/sun/star/util/DateTime.hpp>
28 #include <com/sun/star/util/Date.hpp>
29 #include <rtl/ustrbuf.hxx>
30 #include <osl/diagnose.h>
31 #include <sal/log.hxx>
32 #include <xmloff/xmlement.hxx>
33 #include <xmloff/xmltoken.hxx>
34 #include <rtl/math.hxx>
36 #include <tools/date.hxx>
37 #include <tools/time.hxx>
38 #include <tools/fldunit.hxx>
40 #include <com/sun/star/drawing/Position3D.hpp>
41 #include <com/sun/star/frame/XModel.hpp>
42 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
43 #include <com/sun/star/style/NumberingType.hpp>
44 #include <com/sun/star/text/DefaultNumberingProvider.hpp>
45 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
46 #include <com/sun/star/text/XNumberingTypeInfo.hpp>
47 #include <com/sun/star/i18n/CharacterClassification.hpp>
48 #include <com/sun/star/i18n/UnicodeType.hpp>
49 #include <basegfx/vector/b3dvector.hxx>
51 #include <sax/tools/converter.hxx>
52 #include <comphelper/sequence.hxx>
55 using namespace com::sun::star;
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::lang;
58 using namespace com::sun::star::text;
59 using namespace com::sun::star::style;
60 using namespace ::com::sun::star::i18n;
61 using namespace ::xmloff::token;
64 constexpr OUStringLiteral XML_NULLDATE = u"NullDate";
66 struct SvXMLUnitConverter::Impl
68 sal_Int16 m_eCoreMeasureUnit; /*css::util::MeasureUnit*/
69 sal_Int16 m_eXMLMeasureUnit; /*css::util::MeasureUnit*/
70 SvtSaveOptions::ODFSaneDefaultVersion m_eODFVersion;
71 util::Date m_aNullDate;
72 mutable uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo;
73 mutable uno::Reference< i18n::XCharacterClassification > m_xCharClass;
74 uno::Reference< uno::XComponentContext > m_xContext;
76 Impl(uno::Reference<uno::XComponentContext> xContext,
77 sal_Int16 const eCoreMeasureUnit,
78 sal_Int16 const eXMLMeasureUnit,
79 SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
80 : m_eCoreMeasureUnit(eCoreMeasureUnit)
81 , m_eXMLMeasureUnit(eXMLMeasureUnit)
82 , m_eODFVersion(nODFVersion)
83 , m_aNullDate(30, 12, 1899)
84 , m_xContext(std::move(xContext))
86 OSL_ENSURE( m_xContext.is(), "got no service manager" );
89 void createNumTypeInfo() const;
93 void SvXMLUnitConverter::Impl::createNumTypeInfo() const
95 Reference<XDefaultNumberingProvider> xDefNum = DefaultNumberingProvider::create(m_xContext);
96 m_xNumTypeInfo.set(xDefNum, uno::UNO_QUERY);
99 const uno::Reference< text::XNumberingTypeInfo >&
100 SvXMLUnitConverter::getNumTypeInfo() const
102 if (!m_pImpl->m_xNumTypeInfo.is())
104 m_pImpl->createNumTypeInfo();
106 return m_pImpl->m_xNumTypeInfo;
109 void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit/*css::util::MeasureUnit*/)
111 m_pImpl->m_eCoreMeasureUnit = eCoreMeasureUnit;
114 void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit/*css::util::MeasureUnit*/)
116 m_pImpl->m_eXMLMeasureUnit = eXMLMeasureUnit;
119 sal_Int16 SvXMLUnitConverter::GetXMLMeasureUnit() const
121 return m_pImpl->m_eXMLMeasureUnit;
124 SvtSaveOptions::ODFSaneDefaultVersion SvXMLUnitConverter::getSaneDefaultVersion() const
126 return m_pImpl->m_eODFVersion;
129 void SvXMLUnitConverter::overrideSaneDefaultVersion(
130 SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
132 m_pImpl->m_eODFVersion = nODFVersion;
135 /** constructs a SvXMLUnitConverter. The core measure unit is the
136 default unit for numerical measures, the XML measure unit is
137 the default unit for textual measures
140 SvXMLUnitConverter::SvXMLUnitConverter(
141 const uno::Reference<uno::XComponentContext>& xContext,
142 sal_Int16 const eCoreMeasureUnit,
143 sal_Int16 const eXMLMeasureUnit,
144 SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
145 : m_pImpl(new Impl(xContext, eCoreMeasureUnit, eXMLMeasureUnit, nODFVersion))
149 SvXMLUnitConverter::~SvXMLUnitConverter()
153 sal_Int16 SvXMLUnitConverter::GetMeasureUnit(FieldUnit const nFieldUnit)
155 sal_Int16 eUnit = util::MeasureUnit::INCH;
156 switch( nFieldUnit )
158 case FieldUnit::MM:
159 eUnit = util::MeasureUnit::MM;
160 break;
161 case FieldUnit::CM:
162 case FieldUnit::M:
163 case FieldUnit::KM:
164 eUnit = util::MeasureUnit::CM;
165 break;
166 case FieldUnit::TWIP:
167 eUnit = util::MeasureUnit::TWIP;
168 break;
169 case FieldUnit::POINT:
170 case FieldUnit::PICA:
171 eUnit = util::MeasureUnit::POINT;
172 break;
173 case FieldUnit::MM_100TH:
174 eUnit = util::MeasureUnit::MM_100TH;
175 break;
176 case FieldUnit::INCH:
177 eUnit = util::MeasureUnit::INCH;
178 break;
179 default:
180 assert(false);
181 break;
183 return eUnit;
186 /** convert string to measure using optional min and max values*/
187 bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue,
188 std::u16string_view rString,
189 sal_Int32 nMin, sal_Int32 nMax ) const
191 return ::sax::Converter::convertMeasure( nValue, rString,
192 m_pImpl->m_eCoreMeasureUnit,
193 nMin, nMax );
196 /** convert string to measure using optional min and max values*/
197 bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue,
198 std::string_view rString,
199 sal_Int32 nMin, sal_Int32 nMax ) const
201 return ::sax::Converter::convertMeasure( nValue, rString,
202 m_pImpl->m_eCoreMeasureUnit,
203 nMin, nMax );
206 /** convert measure to string */
207 void SvXMLUnitConverter::convertMeasureToXML( OUStringBuffer& rString,
208 sal_Int32 nMeasure ) const
210 ::sax::Converter::convertMeasure( rString, nMeasure,
211 m_pImpl->m_eCoreMeasureUnit,
212 m_pImpl->m_eXMLMeasureUnit );
215 /** convert measure to string */
216 OUString SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure ) const
218 OUStringBuffer s;
219 ::sax::Converter::convertMeasure( s, nMeasure,
220 m_pImpl->m_eCoreMeasureUnit,
221 m_pImpl->m_eXMLMeasureUnit );
222 return s.makeStringAndClear();
225 /** convert string to enum using given enum map, if the enum is
226 not found in the map, this method will return false
228 bool SvXMLUnitConverter::convertEnumImpl( sal_uInt16& rEnum,
229 std::u16string_view rValue,
230 const SvXMLEnumStringMapEntry<sal_uInt16> *pMap )
232 while( pMap->GetName() )
234 auto nameLength = pMap->GetNameLength();
235 if( static_cast<sal_Int32>(rValue.size()) == nameLength &&
236 rtl_ustr_asciil_reverseEquals_WithLength(
237 rValue.data(), pMap->GetName(), nameLength ) )
239 rEnum = pMap->GetValue();
240 return true;
242 ++pMap;
245 return false;
248 /** convert string to enum using given token map, if the enum is
249 not found in the map, this method will return false */
250 bool SvXMLUnitConverter::convertEnumImpl(
251 sal_uInt16& rEnum,
252 std::u16string_view rValue,
253 const SvXMLEnumMapEntry<sal_uInt16> *pMap )
255 while( pMap->GetToken() != XML_TOKEN_INVALID )
257 if( IsXMLToken( rValue, pMap->GetToken() ) )
259 rEnum = pMap->GetValue();
260 return true;
262 ++pMap;
264 return false;
267 /** convert string to enum using given token map, if the enum is
268 not found in the map, this method will return false */
269 bool SvXMLUnitConverter::convertEnumImpl(
270 sal_uInt16& rEnum,
271 std::string_view rValue,
272 const SvXMLEnumMapEntry<sal_uInt16> *pMap )
274 while( pMap->GetToken() != XML_TOKEN_INVALID )
276 if( IsXMLToken( rValue, pMap->GetToken() ) )
278 rEnum = pMap->GetValue();
279 return true;
281 ++pMap;
283 return false;
286 /** convert enum to string using given token map with an optional
287 default token. If the enum is not found in the map,
288 this method will either use the given default or return
289 false if no default is set */
290 bool SvXMLUnitConverter::convertEnumImpl(
291 OUStringBuffer& rBuffer,
292 sal_uInt16 nValue,
293 const SvXMLEnumMapEntry<sal_uInt16> *pMap,
294 enum XMLTokenEnum eDefault)
296 enum XMLTokenEnum eTok = eDefault;
298 while( pMap->GetToken() != XML_TOKEN_INVALID )
300 if( pMap->GetValue() == nValue )
302 eTok = pMap->GetToken();
303 break;
305 ++pMap;
308 // the map may have contained XML_TOKEN_INVALID
309 if( eTok == XML_TOKEN_INVALID )
310 eTok = eDefault;
312 if( eTok != XML_TOKEN_INVALID )
313 rBuffer.append( GetXMLToken(eTok) );
315 return (eTok != XML_TOKEN_INVALID);
318 static int lcl_gethex( int nChar )
320 if( nChar >= '0' && nChar <= '9' )
321 return nChar - '0';
322 else if( nChar >= 'a' && nChar <= 'f' )
323 return nChar - 'a' + 10;
324 else if( nChar >= 'A' && nChar <= 'F' )
325 return nChar - 'A' + 10;
326 else
327 return 0;
330 const char aHexTab[] = "0123456789abcdef";
333 /** convert double number to string (using ::rtl::math) */
334 void SvXMLUnitConverter::convertDouble(OUStringBuffer& rBuffer,
335 double fNumber) const
337 ::sax::Converter::convertDouble(rBuffer, fNumber,
338 true/*bWriteUnits*/, m_pImpl->m_eCoreMeasureUnit, m_pImpl->m_eXMLMeasureUnit);
341 /** convert string to double number (using ::rtl::math) */
342 bool SvXMLUnitConverter::convertDouble(double& rValue,
343 std::u16string_view rString) const
345 sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
346 rString, m_pImpl->m_eCoreMeasureUnit);
348 return ::sax::Converter::convertDouble(rValue, rString,
349 eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
352 /** convert string to double number (using ::rtl::math) */
353 bool SvXMLUnitConverter::convertDouble(double& rValue,
354 std::string_view rString) const
356 sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
357 rString, m_pImpl->m_eCoreMeasureUnit);
359 return ::sax::Converter::convertDouble(rValue, rString,
360 eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
363 /** get the Null Date of the XModel and set it to the UnitConverter */
364 bool SvXMLUnitConverter::setNullDate(const css::uno::Reference <css::frame::XModel>& xModel)
366 css::uno::Reference <css::util::XNumberFormatsSupplier> xNumberFormatsSupplier (xModel, css::uno::UNO_QUERY);
367 if (xNumberFormatsSupplier.is())
369 const css::uno::Reference <css::beans::XPropertySet> xPropertySet = xNumberFormatsSupplier->getNumberFormatSettings();
370 return xPropertySet.is() && (xPropertySet->getPropertyValue(XML_NULLDATE) >>= m_pImpl->m_aNullDate);
372 return false;
375 /** convert double to ISO Date Time String */
376 void SvXMLUnitConverter::convertDateTime(OUStringBuffer& rBuffer,
377 const double& fDateTime, bool const bAddTimeIf0AM)
379 convertDateTime(rBuffer, fDateTime, m_pImpl->m_aNullDate, bAddTimeIf0AM);
382 /** convert ISO Date Time String to double */
383 bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
384 std::u16string_view rString) const
386 return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
389 /** convert ISO Date Time String to double */
390 bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
391 std::string_view rString) const
393 return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
396 /** convert double to ISO Date Time String */
397 void SvXMLUnitConverter::convertDateTime( OUStringBuffer& rBuffer,
398 const double& fDateTime,
399 const css::util::Date& aTempNullDate,
400 bool bAddTimeIf0AM )
402 double fValue = fDateTime;
403 const sal_Int32 nDays = static_cast <sal_Int32> (::rtl::math::approxFloor (fValue));
404 Date aDate (aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
405 aDate.AddDays( nDays);
406 fValue -= nDays;
407 const bool bHasTime = (fValue > 0.0);
409 sal_Int16 nTempYear = aDate.GetYear();
410 assert(nTempYear != 0);
411 if (nTempYear < 0)
413 rBuffer.append( '-');
414 nTempYear = -nTempYear;
416 if (nTempYear < 1000)
417 rBuffer.append( '0');
418 if (nTempYear < 100)
419 rBuffer.append( '0');
420 if (nTempYear < 10)
421 rBuffer.append( '0');
422 rBuffer.append( sal_Int32( nTempYear));
423 rBuffer.append( '-');
424 sal_uInt16 nTemp = aDate.GetMonth();
425 assert(1 <= nTemp && nTemp <= 12);
426 if (nTemp < 10)
427 rBuffer.append( '0');
428 rBuffer.append( sal_Int32( nTemp));
429 rBuffer.append( '-');
430 nTemp = aDate.GetDay();
431 assert(1 <= nTemp && nTemp <= 31);
432 if (nTemp < 10)
433 rBuffer.append( '0');
434 rBuffer.append( sal_Int32( nTemp));
435 if (!(bHasTime || bAddTimeIf0AM))
436 return;
438 double fCount;
439 if (nDays > 0)
440 fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays))) + 1;
441 else if (nDays < 0)
442 fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays * -1))) + 1;
443 else
444 fCount = 0.0;
445 const int nDigits = sal_Int16(fCount) + 4; // +4 for *86400 in seconds
447 // Since the beginning from initial source code import this was 11 without
448 // further explanation, effectively limiting fractions in ~current
449 // date+time to 2 decimals (maybe because old class Time code had a
450 // resolution of only 100th seconds). Preserve at least milliseconds, but
451 // strive for more.
452 // NOTE: sax/source/tools/converter.cxx uses 14-5 in a different context
453 // rounding nanoseconds and fractions of seconds.
454 constexpr int XML_MAXDIGITSCOUNT_TIME = 14;
456 const int nFractionDecimals = std::max( XML_MAXDIGITSCOUNT_TIME - nDigits, 0);
458 sal_uInt16 nHour, nMinute, nSecond;
459 double fFractionOfSecond;
460 // Pass the original date+time value for proper scaling and rounding.
461 tools::Time::GetClock( fDateTime, nHour, nMinute, nSecond, fFractionOfSecond, nFractionDecimals);
463 rBuffer.append( 'T');
464 if (nHour < 10)
465 rBuffer.append( '0');
466 rBuffer.append( sal_Int32( nHour));
467 rBuffer.append( ':');
468 if (nMinute < 10)
469 rBuffer.append( '0');
470 rBuffer.append( sal_Int32( nMinute));
471 rBuffer.append( ':');
472 if (nSecond < 10)
473 rBuffer.append( '0');
474 rBuffer.append( sal_Int32( nSecond));
475 if (!nFractionDecimals)
476 return;
478 // nFractionDecimals+1 to not round up what GetClock() carefully
479 // truncated.
480 OUString aFraction( ::rtl::math::doubleToUString( fFractionOfSecond,
481 rtl_math_StringFormat_F,
482 nFractionDecimals + 1, '.', true));
483 const sal_Int32 nLen = aFraction.getLength();
484 if ( nLen > 2 )
486 // Truncate nFractionDecimals+1 digit if it was not rounded to zero.
487 const sal_Int32 nCount = nLen - 2 - static_cast<int>(nLen > nFractionDecimals + 2);
488 rBuffer.append( '.');
489 rBuffer.append( aFraction.subView(2, nCount)); // strip 0.
493 /** convert ISO Date Time String to double */
494 template<typename V>
495 static bool lcl_convertDateTime( double& fDateTime,
496 V rString, const css::util::Date& aTempNullDate)
498 css::util::DateTime aDateTime;
499 bool bSuccess = ::sax::Converter::parseDateTime(aDateTime, rString);
501 if (bSuccess)
503 const Date aTmpNullDate(aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
504 const Date aTempDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
505 const sal_Int32 nTage = aTempDate - aTmpNullDate;
506 double fTempDateTime = nTage;
507 double Hour = aDateTime.Hours;
508 double Min = aDateTime.Minutes;
509 double Sec = aDateTime.Seconds;
510 double NanoSec = aDateTime.NanoSeconds;
511 fTempDateTime += Hour / ::tools::Time::hourPerDay;
512 fTempDateTime += Min / ::tools::Time::minutePerDay;
513 fTempDateTime += Sec / ::tools::Time::secondPerDay;
514 fTempDateTime += NanoSec / ::tools::Time::nanoSecPerDay;
515 fDateTime = fTempDateTime;
517 return bSuccess;
520 bool SvXMLUnitConverter::convertDateTime( double& fDateTime,
521 std::u16string_view rString, const css::util::Date& aTempNullDate)
523 return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
525 /** convert ISO Date Time String to double */
526 bool SvXMLUnitConverter::convertDateTime( double& fDateTime,
527 std::string_view rString, const css::util::Date& aTempNullDate)
529 return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
533 SvXMLTokenEnumerator::SvXMLTokenEnumerator( std::u16string_view rString, sal_Unicode cSeparator /* = ' ' */ )
534 : maTokenString( rString ), mnNextTokenPos(0), mcSeparator( cSeparator )
538 bool SvXMLTokenEnumerator::getNextToken( std::u16string_view& rToken )
540 if( std::u16string_view::npos == mnNextTokenPos )
541 return false;
543 size_t nTokenEndPos = maTokenString.find( mcSeparator, mnNextTokenPos );
544 if( nTokenEndPos != std::u16string_view::npos )
546 rToken = maTokenString.substr( mnNextTokenPos,
547 nTokenEndPos - mnNextTokenPos );
548 mnNextTokenPos = nTokenEndPos + 1;
550 // if the mnNextTokenPos is at the end of the string, we have
551 // to deliver an empty token
552 if( mnNextTokenPos > maTokenString.size() )
553 mnNextTokenPos = std::u16string_view::npos;
555 else
557 rToken = maTokenString.substr( mnNextTokenPos );
558 mnNextTokenPos = std::u16string_view::npos;
561 return true;
564 static bool lcl_getPositions(std::string_view _sValue, std::string_view& _rContentX, std::string_view& _rContentY, std::string_view& _rContentZ)
566 if(_sValue.empty() || _sValue[0] != '(')
567 return false;
569 size_t nPos(1);
570 size_t nFound = _sValue.find(' ', nPos);
572 if(nFound == std::string_view::npos || nFound <= nPos)
573 return false;
575 _rContentX = _sValue.substr(nPos, nFound - nPos);
577 nPos = nFound + 1;
578 nFound = _sValue.find(' ', nPos);
580 if(nFound == std::string_view::npos || nFound <= nPos)
581 return false;
583 _rContentY = _sValue.substr(nPos, nFound - nPos);
585 nPos = nFound + 1;
586 nFound = _sValue.find(')', nPos);
588 if(nFound == std::string_view::npos || nFound <= nPos)
589 return false;
591 _rContentZ = _sValue.substr(nPos, nFound - nPos);
592 return true;
596 /** convert string to ::basegfx::B3DVector */
597 bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector& rVector, std::string_view rValue )
599 std::string_view aContentX,aContentY,aContentZ;
600 if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
601 return false;
603 rtl_math_ConversionStatus eStatus;
605 rVector.setX(::rtl::math::stringToDouble(aContentX, '.',
606 ',', &eStatus));
608 if( eStatus != rtl_math_ConversionStatus_Ok )
609 return false;
611 rVector.setY(::rtl::math::stringToDouble(aContentY, '.',
612 ',', &eStatus));
614 if( eStatus != rtl_math_ConversionStatus_Ok )
615 return false;
617 rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.',
618 ',', &eStatus));
621 return ( eStatus == rtl_math_ConversionStatus_Ok );
624 /** convert ::basegfx::B3DVector to string */
625 void SvXMLUnitConverter::convertB3DVector( OUStringBuffer &rBuffer, const ::basegfx::B3DVector& rVector )
627 rBuffer.append('(');
628 ::sax::Converter::convertDouble(rBuffer, rVector.getX());
629 rBuffer.append(' ');
630 ::sax::Converter::convertDouble(rBuffer, rVector.getY());
631 rBuffer.append(' ');
632 ::sax::Converter::convertDouble(rBuffer, rVector.getZ());
633 rBuffer.append(')');
636 /** convert string to Position3D */
637 bool SvXMLUnitConverter::convertPosition3D( drawing::Position3D& rPosition,
638 std::string_view rValue ) const
640 std::string_view aContentX,aContentY,aContentZ;
641 if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
642 return false;
644 if ( !convertDouble( rPosition.PositionX, aContentX ) )
645 return false;
646 if ( !convertDouble( rPosition.PositionY, aContentY ) )
647 return false;
648 return convertDouble( rPosition.PositionZ, aContentZ );
651 /** convert Position3D to string */
652 void SvXMLUnitConverter::convertPosition3D( OUStringBuffer &rBuffer,
653 const drawing::Position3D& rPosition )
655 rBuffer.append( '(' );
656 convertDouble( rBuffer, rPosition.PositionX );
657 rBuffer.append( ' ' );
658 convertDouble( rBuffer, rPosition.PositionY );
659 rBuffer.append( ' ' );
660 convertDouble( rBuffer, rPosition.PositionZ );
661 rBuffer.append( ')' );
664 bool SvXMLUnitConverter::convertNumFormat(
665 sal_Int16& rType,
666 const OUString& rNumFmt,
667 std::u16string_view rNumLetterSync,
668 bool bNumberNone ) const
670 bool bRet = true;
671 bool bExt = false;
673 sal_Int32 nLen = rNumFmt.getLength();
674 if( 0 == nLen )
676 if( bNumberNone )
677 rType = NumberingType::NUMBER_NONE;
678 else
679 bRet = false;
681 else if( 1 == nLen )
683 switch( rNumFmt[0] )
685 case '1': rType = NumberingType::ARABIC; break;
686 case 'a': rType = NumberingType::CHARS_LOWER_LETTER; break;
687 case 'A': rType = NumberingType::CHARS_UPPER_LETTER; break;
688 case 'i': rType = NumberingType::ROMAN_LOWER; break;
689 case 'I': rType = NumberingType::ROMAN_UPPER; break;
690 default: bExt = true; break;
692 if( !bExt && IsXMLToken( rNumLetterSync, XML_TRUE ) )
694 switch( rType )
696 case NumberingType::CHARS_LOWER_LETTER:
697 rType = NumberingType::CHARS_LOWER_LETTER_N;
698 break;
699 case NumberingType::CHARS_UPPER_LETTER:
700 rType = NumberingType::CHARS_UPPER_LETTER_N;
701 break;
705 else
707 bExt = true;
709 if( bExt )
711 Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
712 if( xInfo.is() && xInfo->hasNumberingType( rNumFmt ) )
714 rType = xInfo->getNumberingType( rNumFmt );
716 else
718 rType = NumberingType::ARABIC;
722 return bRet;
725 void SvXMLUnitConverter::convertNumFormat( OUStringBuffer& rBuffer,
726 sal_Int16 nType ) const
728 enum XMLTokenEnum eFormat = XML_TOKEN_INVALID;
729 switch( nType )
731 case NumberingType::CHARS_UPPER_LETTER: eFormat = XML_A_UPCASE; break;
732 case NumberingType::CHARS_LOWER_LETTER: eFormat = XML_A; break;
733 case NumberingType::ROMAN_UPPER: eFormat = XML_I_UPCASE; break;
734 case NumberingType::ROMAN_LOWER: eFormat = XML_I; break;
735 case NumberingType::ARABIC: eFormat = XML_1; break;
736 case NumberingType::CHARS_UPPER_LETTER_N: eFormat = XML_A_UPCASE; break;
737 case NumberingType::CHARS_LOWER_LETTER_N: eFormat = XML_A; break;
738 case NumberingType::NUMBER_NONE: eFormat = XML__EMPTY; break;
740 case NumberingType::CHAR_SPECIAL:
741 case NumberingType::PAGE_DESCRIPTOR:
742 case NumberingType::BITMAP:
743 SAL_WARN_IF( eFormat == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
744 break;
745 default:
746 break;
749 if( eFormat != XML_TOKEN_INVALID )
751 rBuffer.append( GetXMLToken(eFormat) );
753 else
755 Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
756 if( xInfo.is() )
757 rBuffer.append( xInfo->getNumberingIdentifier( nType ) );
761 void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer& rBuffer,
762 sal_Int16 nType )
764 enum XMLTokenEnum eSync = XML_TOKEN_INVALID;
765 switch( nType )
767 case NumberingType::CHARS_UPPER_LETTER:
768 case NumberingType::CHARS_LOWER_LETTER:
769 case NumberingType::ROMAN_UPPER:
770 case NumberingType::ROMAN_LOWER:
771 case NumberingType::ARABIC:
772 case NumberingType::NUMBER_NONE:
773 break;
775 case NumberingType::CHARS_UPPER_LETTER_N:
776 case NumberingType::CHARS_LOWER_LETTER_N:
777 eSync = XML_TRUE;
778 break;
780 case NumberingType::CHAR_SPECIAL:
781 case NumberingType::PAGE_DESCRIPTOR:
782 case NumberingType::BITMAP:
783 SAL_WARN_IF( eSync == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
784 break;
786 if( eSync != XML_TOKEN_INVALID )
787 rBuffer.append( GetXMLToken(eSync) );
790 void SvXMLUnitConverter::convertPropertySet(uno::Sequence<beans::PropertyValue>& rProps,
791 const uno::Reference<beans::XPropertySet>& aProperties,
792 const std::initializer_list<std::u16string_view>* pOmitFalseValues)
794 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = aProperties->getPropertySetInfo();
795 if (!xPropertySetInfo.is())
796 return;
798 const uno::Sequence< beans::Property > aProps = xPropertySetInfo->getProperties();
799 if (aProps.hasElements())
801 std::vector<beans::PropertyValue> aPropsVec;
802 for (const auto& rProp : aProps)
804 uno::Any aPropertyValue = aProperties->getPropertyValue(rProp.Name);
805 if (pOmitFalseValues && aPropertyValue.has<bool>() && !aPropertyValue.get<bool>())
807 const std::initializer_list<std::u16string_view>& rOmitFalseValues = *pOmitFalseValues;
808 if (std::find(rOmitFalseValues.begin(), rOmitFalseValues.end(), rProp.Name) != rOmitFalseValues.end())
810 continue;
814 beans::PropertyValue aValue;
815 aValue.Name = rProp.Name;
816 aValue.Value = aPropertyValue;
817 aPropsVec.push_back(aValue);
819 rProps = comphelper::containerToSequence(aPropsVec);
823 void SvXMLUnitConverter::convertPropertySet(uno::Reference<beans::XPropertySet> const & rProperties,
824 const uno::Sequence<beans::PropertyValue>& aProps)
826 if (aProps.hasElements())
828 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = rProperties->getPropertySetInfo();
829 if (xPropertySetInfo.is())
831 for (const auto& rProp : aProps)
833 if (xPropertySetInfo->hasPropertyByName(rProp.Name))
834 rProperties->setPropertyValue(rProp.Name, rProp.Value);
841 OUString SvXMLUnitConverter::encodeStyleName(
842 const OUString& rName,
843 bool *pEncoded ) const
845 if( pEncoded )
846 *pEncoded = false;
848 sal_Int32 nLen = rName.getLength();
849 OUStringBuffer aBuffer( nLen*2 );
851 for( sal_Int32 i = 0; i < nLen; i++ )
853 sal_Unicode c = rName[i];
854 bool bValidChar = false;
855 if( c < 0x00ffU )
857 bValidChar =
858 (c >= 0x0041 && c <= 0x005a) ||
859 (c >= 0x0061 && c <= 0x007a) ||
860 (c >= 0x00c0 && c <= 0x00d6) ||
861 (c >= 0x00d8 && c <= 0x00f6) ||
862 (c >= 0x00f8 && c <= 0x00ff) ||
863 ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) ||
864 c == 0x00b7 || c == '-' || c == '.') );
866 else
868 if( (c >= 0xf900U && c <= 0xfffeU) ||
869 (c >= 0x20ddU && c <= 0x20e0U))
871 bValidChar = false;
873 else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
874 c == 0x06e5 || c == 0x06e6 )
876 bValidChar = true;
878 else if( c == 0x0387 )
880 bValidChar = i > 0;
882 else
884 if (!m_pImpl->m_xCharClass.is())
886 m_pImpl->m_xCharClass = CharacterClassification::create( m_pImpl->m_xContext );
888 sal_Int16 nType = m_pImpl->m_xCharClass->getType(rName, i);
890 switch( nType )
892 case UnicodeType::UPPERCASE_LETTER: // Lu
893 case UnicodeType::LOWERCASE_LETTER: // Ll
894 case UnicodeType::TITLECASE_LETTER: // Lt
895 case UnicodeType::OTHER_LETTER: // Lo
896 case UnicodeType::LETTER_NUMBER: // Nl
897 bValidChar = true;
898 break;
899 case UnicodeType::NON_SPACING_MARK: // Ms
900 case UnicodeType::ENCLOSING_MARK: // Me
901 case UnicodeType::COMBINING_SPACING_MARK: //Mc
902 case UnicodeType::MODIFIER_LETTER: // Lm
903 case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd
904 bValidChar = i > 0;
905 break;
909 if( bValidChar )
911 aBuffer.append( c );
913 else
915 aBuffer.append( '_' );
916 if( c > 0x0fff )
917 aBuffer.append( static_cast< sal_Unicode >(
918 aHexTab[ (c >> 12) & 0x0f ] ) );
919 if( c > 0x00ff )
920 aBuffer.append( static_cast< sal_Unicode >(
921 aHexTab[ (c >> 8) & 0x0f ] ) );
922 if( c > 0x000f )
923 aBuffer.append( static_cast< sal_Unicode >(
924 aHexTab[ (c >> 4) & 0x0f ] ) );
925 aBuffer.append(
926 OUStringChar(static_cast< sal_Unicode >( aHexTab[ c & 0x0f ] ) )
927 + "_" );
928 if( pEncoded )
929 *pEncoded = true;
933 // check for length
934 if( aBuffer.getLength() > ((1<<15)-1) )
936 aBuffer = rName;
937 if( pEncoded )
938 *pEncoded = false;
942 return aBuffer.makeStringAndClear();
945 /** convert string (hex) to number (sal_uInt32) */
946 bool SvXMLUnitConverter::convertHex( sal_uInt32& nVal, std::u16string_view rValue )
948 if( rValue.size() != 8 )
949 return false;
951 nVal = 0;
952 for ( int i = 0; i < 8; i++ )
954 nVal = ( nVal << 4 )
955 | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) );
958 return true;
961 /** convert number (sal_uInt32) to string (hex) */
962 void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer,
963 sal_uInt32 nVal )
965 for ( int i = 0; i < 8; i++ )
967 rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) );
968 nVal <<= 4;
972 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */