1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
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
;
159 eUnit
= util::MeasureUnit::MM
;
164 eUnit
= util::MeasureUnit::CM
;
166 case FieldUnit::TWIP
:
167 eUnit
= util::MeasureUnit::TWIP
;
169 case FieldUnit::POINT
:
170 case FieldUnit::PICA
:
171 eUnit
= util::MeasureUnit::POINT
;
173 case FieldUnit::MM_100TH
:
174 eUnit
= util::MeasureUnit::MM_100TH
;
176 case FieldUnit::INCH
:
177 eUnit
= util::MeasureUnit::INCH
;
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
,
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
,
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
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();
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(
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();
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(
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();
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
,
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();
308 // the map may have contained XML_TOKEN_INVALID
309 if( eTok
== XML_TOKEN_INVALID
)
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' )
322 else if( nChar
>= 'a' && nChar
<= 'f' )
323 return nChar
- 'a' + 10;
324 else if( nChar
>= 'A' && nChar
<= 'F' )
325 return nChar
- 'A' + 10;
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
);
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
,
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
);
407 const bool bHasTime
= (fValue
> 0.0);
409 sal_Int16 nTempYear
= aDate
.GetYear();
410 assert(nTempYear
!= 0);
413 rBuffer
.append( '-');
414 nTempYear
= -nTempYear
;
416 if (nTempYear
< 1000)
417 rBuffer
.append( '0');
419 rBuffer
.append( '0');
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);
427 rBuffer
.append( '0');
428 rBuffer
.append( sal_Int32( nTemp
));
429 rBuffer
.append( '-');
430 nTemp
= aDate
.GetDay();
431 assert(1 <= nTemp
&& nTemp
<= 31);
433 rBuffer
.append( '0');
434 rBuffer
.append( sal_Int32( nTemp
));
435 if (!(bHasTime
|| bAddTimeIf0AM
))
440 fCount
= ::rtl::math::approxFloor (log10(static_cast<double>(nDays
))) + 1;
442 fCount
= ::rtl::math::approxFloor (log10(static_cast<double>(nDays
* -1))) + 1;
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
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');
465 rBuffer
.append( '0');
466 rBuffer
.append( sal_Int32( nHour
));
467 rBuffer
.append( ':');
469 rBuffer
.append( '0');
470 rBuffer
.append( sal_Int32( nMinute
));
471 rBuffer
.append( ':');
473 rBuffer
.append( '0');
474 rBuffer
.append( sal_Int32( nSecond
));
475 if (!nFractionDecimals
)
478 // nFractionDecimals+1 to not round up what GetClock() carefully
480 OUString
aFraction( ::rtl::math::doubleToUString( fFractionOfSecond
,
481 rtl_math_StringFormat_F
,
482 nFractionDecimals
+ 1, '.', true));
483 const sal_Int32 nLen
= aFraction
.getLength();
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 */
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
);
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
;
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
)
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
;
557 rToken
= maTokenString
.substr( mnNextTokenPos
);
558 mnNextTokenPos
= std::u16string_view::npos
;
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] != '(')
570 size_t nFound
= _sValue
.find(' ', nPos
);
572 if(nFound
== std::string_view::npos
|| nFound
<= nPos
)
575 _rContentX
= _sValue
.substr(nPos
, nFound
- nPos
);
578 nFound
= _sValue
.find(' ', nPos
);
580 if(nFound
== std::string_view::npos
|| nFound
<= nPos
)
583 _rContentY
= _sValue
.substr(nPos
, nFound
- nPos
);
586 nFound
= _sValue
.find(')', nPos
);
588 if(nFound
== std::string_view::npos
|| nFound
<= nPos
)
591 _rContentZ
= _sValue
.substr(nPos
, nFound
- nPos
);
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
) )
603 rtl_math_ConversionStatus eStatus
;
605 rVector
.setX(::rtl::math::stringToDouble(aContentX
, '.',
608 if( eStatus
!= rtl_math_ConversionStatus_Ok
)
611 rVector
.setY(::rtl::math::stringToDouble(aContentY
, '.',
614 if( eStatus
!= rtl_math_ConversionStatus_Ok
)
617 rVector
.setZ(::rtl::math::stringToDouble(aContentZ
, '.',
621 return ( eStatus
== rtl_math_ConversionStatus_Ok
);
624 /** convert ::basegfx::B3DVector to string */
625 void SvXMLUnitConverter::convertB3DVector( OUStringBuffer
&rBuffer
, const ::basegfx::B3DVector
& rVector
)
628 ::sax::Converter::convertDouble(rBuffer
, rVector
.getX());
630 ::sax::Converter::convertDouble(rBuffer
, rVector
.getY());
632 ::sax::Converter::convertDouble(rBuffer
, rVector
.getZ());
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
) )
644 if ( !convertDouble( rPosition
.PositionX
, aContentX
) )
646 if ( !convertDouble( rPosition
.PositionY
, aContentY
) )
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(
666 const OUString
& rNumFmt
,
667 std::u16string_view rNumLetterSync
,
668 bool bNumberNone
) const
673 sal_Int32 nLen
= rNumFmt
.getLength();
677 rType
= NumberingType::NUMBER_NONE
;
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
) )
696 case NumberingType::CHARS_LOWER_LETTER
:
697 rType
= NumberingType::CHARS_LOWER_LETTER_N
;
699 case NumberingType::CHARS_UPPER_LETTER
:
700 rType
= NumberingType::CHARS_UPPER_LETTER_N
;
711 Reference
< XNumberingTypeInfo
> xInfo
= getNumTypeInfo();
712 if( xInfo
.is() && xInfo
->hasNumberingType( rNumFmt
) )
714 rType
= xInfo
->getNumberingType( rNumFmt
);
718 rType
= NumberingType::ARABIC
;
725 void SvXMLUnitConverter::convertNumFormat( OUStringBuffer
& rBuffer
,
726 sal_Int16 nType
) const
728 enum XMLTokenEnum eFormat
= XML_TOKEN_INVALID
;
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" );
749 if( eFormat
!= XML_TOKEN_INVALID
)
751 rBuffer
.append( GetXMLToken(eFormat
) );
755 Reference
< XNumberingTypeInfo
> xInfo
= getNumTypeInfo();
757 rBuffer
.append( xInfo
->getNumberingIdentifier( nType
) );
761 void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer
& rBuffer
,
764 enum XMLTokenEnum eSync
= XML_TOKEN_INVALID
;
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
:
775 case NumberingType::CHARS_UPPER_LETTER_N
:
776 case NumberingType::CHARS_LOWER_LETTER_N
:
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" );
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())
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())
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
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;
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
== '.') );
868 if( (c
>= 0xf900U
&& c
<= 0xfffeU
) ||
869 (c
>= 0x20ddU
&& c
<= 0x20e0U
))
873 else if( (c
>= 0x02bbU
&& c
<= 0x02c1U
) || c
== 0x0559 ||
874 c
== 0x06e5 || c
== 0x06e6 )
878 else if( c
== 0x0387 )
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
);
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
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
915 aBuffer
.append( '_' );
917 aBuffer
.append( static_cast< sal_Unicode
>(
918 aHexTab
[ (c
>> 12) & 0x0f ] ) );
920 aBuffer
.append( static_cast< sal_Unicode
>(
921 aHexTab
[ (c
>> 8) & 0x0f ] ) );
923 aBuffer
.append( static_cast< sal_Unicode
>(
924 aHexTab
[ (c
>> 4) & 0x0f ] ) );
926 OUStringChar(static_cast< sal_Unicode
>( aHexTab
[ c
& 0x0f ] ) )
934 if( aBuffer
.getLength() > ((1<<15)-1) )
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 )
952 for ( int i
= 0; i
< 8; i
++ )
955 | sal::static_int_cast
< sal_uInt32
>( lcl_gethex( rValue
[i
] ) );
961 /** convert number (sal_uInt32) to string (hex) */
962 void SvXMLUnitConverter::convertHex( OUStringBuffer
& rBuffer
,
965 for ( int i
= 0; i
< 8; i
++ )
967 rBuffer
.append( sal_Unicode( aHexTab
[ nVal
>> 28 ] ) );
972 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */