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>
24 #include <xmloff/xmluconv.hxx>
26 #include <com/sun/star/util/DateTime.hpp>
27 #include <com/sun/star/util/Date.hpp>
28 #include <rtl/ustrbuf.hxx>
29 #include <osl/diagnose.h>
30 #include <sal/log.hxx>
31 #include <xmloff/xmlement.hxx>
32 #include <xmloff/xmltoken.hxx>
33 #include <rtl/math.hxx>
35 #include <tools/date.hxx>
36 #include <tools/time.hxx>
37 #include <tools/fldunit.hxx>
39 #include <com/sun/star/drawing/Position3D.hpp>
40 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
41 #include <com/sun/star/style/NumberingType.hpp>
42 #include <com/sun/star/text/DefaultNumberingProvider.hpp>
43 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
44 #include <com/sun/star/text/XNumberingTypeInfo.hpp>
45 #include <com/sun/star/i18n/CharacterClassification.hpp>
46 #include <com/sun/star/i18n/UnicodeType.hpp>
47 #include <basegfx/vector/b3dvector.hxx>
49 #include <sax/tools/converter.hxx>
52 using namespace com::sun::star
;
53 using namespace com::sun::star::uno
;
54 using namespace com::sun::star::lang
;
55 using namespace com::sun::star::text
;
56 using namespace com::sun::star::style
;
57 using namespace ::com::sun::star::i18n
;
58 using namespace ::xmloff::token
;
61 const sal_Int8 XML_MAXDIGITSCOUNT_TIME
= 11;
62 #define XML_NULLDATE "NullDate"
64 struct SvXMLUnitConverter::Impl
66 sal_Int16 m_eCoreMeasureUnit
; /*css::util::MeasureUnit*/
67 sal_Int16 m_eXMLMeasureUnit
; /*css::util::MeasureUnit*/
68 util::Date m_aNullDate
;
69 mutable uno::Reference
< text::XNumberingTypeInfo
> m_xNumTypeInfo
;
70 mutable uno::Reference
< i18n::XCharacterClassification
> m_xCharClass
;
71 uno::Reference
< uno::XComponentContext
> m_xContext
;
73 Impl(uno::Reference
<uno::XComponentContext
> const& xContext
,
74 sal_Int16
const eCoreMeasureUnit
,
75 sal_Int16
const eXMLMeasureUnit
)
76 : m_eCoreMeasureUnit(eCoreMeasureUnit
)
77 , m_eXMLMeasureUnit(eXMLMeasureUnit
)
78 , m_aNullDate(30, 12, 1899)
79 , m_xContext(xContext
)
81 OSL_ENSURE( m_xContext
.is(), "got no service manager" );
84 void createNumTypeInfo() const;
88 void SvXMLUnitConverter::Impl::createNumTypeInfo() const
90 Reference
<XDefaultNumberingProvider
> xDefNum
= DefaultNumberingProvider::create(m_xContext
);
91 m_xNumTypeInfo
.set(xDefNum
, uno::UNO_QUERY
);
94 const uno::Reference
< text::XNumberingTypeInfo
>&
95 SvXMLUnitConverter::getNumTypeInfo() const
97 if (!m_pImpl
->m_xNumTypeInfo
.is())
99 m_pImpl
->createNumTypeInfo();
101 return m_pImpl
->m_xNumTypeInfo
;
104 void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16
const eCoreMeasureUnit
/*css::util::MeasureUnit*/)
106 m_pImpl
->m_eCoreMeasureUnit
= eCoreMeasureUnit
;
109 void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16
const eXMLMeasureUnit
/*css::util::MeasureUnit*/)
111 m_pImpl
->m_eXMLMeasureUnit
= eXMLMeasureUnit
;
114 sal_Int16
SvXMLUnitConverter::GetXMLMeasureUnit() const
116 return m_pImpl
->m_eXMLMeasureUnit
;
119 /** constructs a SvXMLUnitConverter. The core measure unit is the
120 default unit for numerical measures, the XML measure unit is
121 the default unit for textual measures
124 SvXMLUnitConverter::SvXMLUnitConverter(
125 const uno::Reference
<uno::XComponentContext
>& xContext
,
126 sal_Int16
const eCoreMeasureUnit
,
127 sal_Int16
const eXMLMeasureUnit
)
128 : m_pImpl(new Impl(xContext
, eCoreMeasureUnit
, eXMLMeasureUnit
))
132 SvXMLUnitConverter::~SvXMLUnitConverter()
136 sal_Int16
SvXMLUnitConverter::GetMeasureUnit(FieldUnit
const nFieldUnit
)
138 sal_Int16 eUnit
= util::MeasureUnit::INCH
;
142 eUnit
= util::MeasureUnit::MM
;
147 eUnit
= util::MeasureUnit::CM
;
149 case FieldUnit::TWIP
:
150 eUnit
= util::MeasureUnit::TWIP
;
152 case FieldUnit::POINT
:
153 case FieldUnit::PICA
:
154 eUnit
= util::MeasureUnit::POINT
;
156 case FieldUnit::MM_100TH
:
157 eUnit
= util::MeasureUnit::MM_100TH
;
159 case FieldUnit::INCH
:
160 eUnit
= util::MeasureUnit::INCH
;
169 /** convert string to measure using optional min and max values*/
170 bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32
& nValue
,
171 const OUString
& rString
,
172 sal_Int32 nMin
, sal_Int32 nMax
) const
174 return ::sax::Converter::convertMeasure( nValue
, rString
,
175 m_pImpl
->m_eCoreMeasureUnit
,
179 /** convert measure to string */
180 void SvXMLUnitConverter::convertMeasureToXML( OUStringBuffer
& rString
,
181 sal_Int32 nMeasure
) const
183 ::sax::Converter::convertMeasure( rString
, nMeasure
,
184 m_pImpl
->m_eCoreMeasureUnit
,
185 m_pImpl
->m_eXMLMeasureUnit
);
188 /** convert measure to string */
189 OUString
SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure
) const
192 ::sax::Converter::convertMeasure( s
, nMeasure
,
193 m_pImpl
->m_eCoreMeasureUnit
,
194 m_pImpl
->m_eXMLMeasureUnit
);
195 return s
.makeStringAndClear();
198 /** convert string to enum using given enum map, if the enum is
199 not found in the map, this method will return false
201 bool SvXMLUnitConverter::convertEnumImpl( sal_uInt16
& rEnum
,
202 const OUString
& rValue
,
203 const SvXMLEnumStringMapEntry
<sal_uInt16
> *pMap
)
205 while( pMap
->GetName() )
207 if( rValue
.equalsAsciiL( pMap
->GetName(), pMap
->GetNameLength() ) )
209 rEnum
= pMap
->GetValue();
218 /** convert string to enum using given token map, if the enum is
219 not found in the map, this method will return false */
220 bool SvXMLUnitConverter::convertEnumImpl(
222 const OUString
& rValue
,
223 const SvXMLEnumMapEntry
<sal_uInt16
> *pMap
)
225 while( pMap
->GetToken() != XML_TOKEN_INVALID
)
227 if( IsXMLToken( rValue
, pMap
->GetToken() ) )
229 rEnum
= pMap
->GetValue();
237 /** convert enum to string using given token map with an optional
238 default token. If the enum is not found in the map,
239 this method will either use the given default or return
240 false if no default is set */
241 bool SvXMLUnitConverter::convertEnumImpl(
242 OUStringBuffer
& rBuffer
,
244 const SvXMLEnumMapEntry
<sal_uInt16
> *pMap
,
245 enum XMLTokenEnum eDefault
)
247 enum XMLTokenEnum eTok
= eDefault
;
249 while( pMap
->GetToken() != XML_TOKEN_INVALID
)
251 if( pMap
->GetValue() == nValue
)
253 eTok
= pMap
->GetToken();
259 // the map may have contained XML_TOKEN_INVALID
260 if( eTok
== XML_TOKEN_INVALID
)
263 if( eTok
!= XML_TOKEN_INVALID
)
264 rBuffer
.append( GetXMLToken(eTok
) );
266 return (eTok
!= XML_TOKEN_INVALID
);
269 static int lcl_gethex( int nChar
)
271 if( nChar
>= '0' && nChar
<= '9' )
273 else if( nChar
>= 'a' && nChar
<= 'f' )
274 return nChar
- 'a' + 10;
275 else if( nChar
>= 'A' && nChar
<= 'F' )
276 return nChar
- 'A' + 10;
281 static const sal_Char aHexTab
[] = "0123456789abcdef";
284 /** convert double number to string (using ::rtl::math) */
285 void SvXMLUnitConverter::convertDouble(OUStringBuffer
& rBuffer
,
286 double fNumber
) const
288 ::sax::Converter::convertDouble(rBuffer
, fNumber
,
289 true/*bWriteUnits*/, m_pImpl
->m_eCoreMeasureUnit
, m_pImpl
->m_eXMLMeasureUnit
);
292 /** convert string to double number (using ::rtl::math) */
293 bool SvXMLUnitConverter::convertDouble(double& rValue
,
294 const OUString
& rString
) const
296 sal_Int16
const eSrcUnit
= ::sax::Converter::GetUnitFromString(
297 rString
, m_pImpl
->m_eCoreMeasureUnit
);
299 return ::sax::Converter::convertDouble(rValue
, rString
,
300 eSrcUnit
, m_pImpl
->m_eCoreMeasureUnit
);
303 /** get the Null Date of the XModel and set it to the UnitConverter */
304 bool SvXMLUnitConverter::setNullDate(const css::uno::Reference
<css::frame::XModel
>& xModel
)
306 css::uno::Reference
<css::util::XNumberFormatsSupplier
> xNumberFormatsSupplier (xModel
, css::uno::UNO_QUERY
);
307 if (xNumberFormatsSupplier
.is())
309 const css::uno::Reference
<css::beans::XPropertySet
> xPropertySet
= xNumberFormatsSupplier
->getNumberFormatSettings();
310 return xPropertySet
.is() && (xPropertySet
->getPropertyValue(XML_NULLDATE
) >>= m_pImpl
->m_aNullDate
);
315 /** convert double to ISO Date Time String */
316 void SvXMLUnitConverter::convertDateTime(OUStringBuffer
& rBuffer
,
317 const double& fDateTime
, bool const bAddTimeIf0AM
)
319 convertDateTime(rBuffer
, fDateTime
, m_pImpl
->m_aNullDate
, bAddTimeIf0AM
);
322 /** convert ISO Date Time String to double */
323 bool SvXMLUnitConverter::convertDateTime(double& fDateTime
,
324 const OUString
& rString
)
326 return convertDateTime(fDateTime
, rString
, m_pImpl
->m_aNullDate
);
329 /** convert double to ISO Date Time String */
330 void SvXMLUnitConverter::convertDateTime( OUStringBuffer
& rBuffer
,
331 const double& fDateTime
,
332 const css::util::Date
& aTempNullDate
,
335 double fValue
= fDateTime
;
336 const sal_Int32 nDays
= static_cast <sal_Int32
> (::rtl::math::approxFloor (fValue
));
337 Date
aDate (aTempNullDate
.Day
, aTempNullDate
.Month
, aTempNullDate
.Year
);
338 aDate
.AddDays( nDays
);
340 const bool bHasTime
= (fValue
> 0.0);
342 sal_Int16 nTempYear
= aDate
.GetYear();
343 assert(nTempYear
!= 0);
346 rBuffer
.append( '-');
347 nTempYear
= -nTempYear
;
349 if (nTempYear
< 1000)
350 rBuffer
.append( '0');
352 rBuffer
.append( '0');
354 rBuffer
.append( '0');
355 rBuffer
.append( sal_Int32( nTempYear
));
356 rBuffer
.append( '-');
357 sal_uInt16 nTemp
= aDate
.GetMonth();
358 assert(1 <= nTemp
&& nTemp
<= 12);
360 rBuffer
.append( '0');
361 rBuffer
.append( sal_Int32( nTemp
));
362 rBuffer
.append( '-');
363 nTemp
= aDate
.GetDay();
364 assert(1 <= nTemp
&& nTemp
<= 31);
366 rBuffer
.append( '0');
367 rBuffer
.append( sal_Int32( nTemp
));
368 if (bHasTime
|| bAddTimeIf0AM
)
372 fCount
= ::rtl::math::approxFloor (log10(static_cast<double>(nDays
))) + 1;
374 fCount
= ::rtl::math::approxFloor (log10(static_cast<double>(nDays
* -1))) + 1;
377 const int nDigits
= sal_Int16(fCount
) + 4; // +4 for *86400 in seconds
378 const int nFractionDecimals
= std::max( XML_MAXDIGITSCOUNT_TIME
- nDigits
, 0);
380 sal_uInt16 nHour
, nMinute
, nSecond
;
381 double fFractionOfSecond
;
382 // Pass the original date+time value for proper scaling and rounding.
383 tools::Time::GetClock( fDateTime
, nHour
, nMinute
, nSecond
, fFractionOfSecond
, nFractionDecimals
);
385 rBuffer
.append( 'T');
387 rBuffer
.append( '0');
388 rBuffer
.append( sal_Int32( nHour
));
389 rBuffer
.append( ':');
391 rBuffer
.append( '0');
392 rBuffer
.append( sal_Int32( nMinute
));
393 rBuffer
.append( ':');
395 rBuffer
.append( '0');
396 rBuffer
.append( sal_Int32( nSecond
));
397 if (nFractionDecimals
)
399 // nFractionDecimals+1 to not round up what GetClock() carefully
401 OUString
aFraction( ::rtl::math::doubleToUString( fFractionOfSecond
,
402 rtl_math_StringFormat_F
,
403 nFractionDecimals
+ 1, '.', true));
404 const sal_Int32 nLen
= aFraction
.getLength();
407 // Truncate nFractionDecimals+1 digit if it was not rounded to zero.
408 const sal_Int32 nCount
= nLen
- 2 - static_cast<int>(nLen
> nFractionDecimals
+ 2);
409 rBuffer
.append( '.');
410 rBuffer
.append( std::u16string_view(aFraction
).substr(2, nCount
)); // strip 0.
416 /** convert ISO Date Time String to double */
417 bool SvXMLUnitConverter::convertDateTime( double& fDateTime
,
418 const OUString
& rString
, const css::util::Date
& aTempNullDate
)
420 css::util::DateTime aDateTime
;
421 bool bSuccess
= ::sax::Converter::parseDateTime(aDateTime
, rString
);
425 const Date
aTmpNullDate(aTempNullDate
.Day
, aTempNullDate
.Month
, aTempNullDate
.Year
);
426 const Date
aTempDate(aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
427 const sal_Int32 nTage
= aTempDate
- aTmpNullDate
;
428 double fTempDateTime
= nTage
;
429 double Hour
= aDateTime
.Hours
;
430 double Min
= aDateTime
.Minutes
;
431 double Sec
= aDateTime
.Seconds
;
432 double NanoSec
= aDateTime
.NanoSeconds
;
433 fTempDateTime
+= Hour
/ ::tools::Time::hourPerDay
;
434 fTempDateTime
+= Min
/ ::tools::Time::minutePerDay
;
435 fTempDateTime
+= Sec
/ ::tools::Time::secondPerDay
;
436 fTempDateTime
+= NanoSec
/ ::tools::Time::nanoSecPerDay
;
437 fDateTime
= fTempDateTime
;
443 SvXMLTokenEnumerator::SvXMLTokenEnumerator( const OUString
& rString
, sal_Unicode cSeparator
/* = ' ' */ )
444 : maTokenString( rString
), mnNextTokenPos(0), mcSeparator( cSeparator
)
448 bool SvXMLTokenEnumerator::getNextToken( OUString
& rToken
)
450 if( -1 == mnNextTokenPos
)
453 int nTokenEndPos
= maTokenString
.indexOf( mcSeparator
, mnNextTokenPos
);
454 if( nTokenEndPos
!= -1 )
456 rToken
= maTokenString
.copy( mnNextTokenPos
,
457 nTokenEndPos
- mnNextTokenPos
);
458 mnNextTokenPos
= nTokenEndPos
+ 1;
460 // if the mnNextTokenPos is at the end of the string, we have
461 // to deliver an empty token
462 if( mnNextTokenPos
> maTokenString
.getLength() )
467 rToken
= maTokenString
.copy( mnNextTokenPos
);
474 static bool lcl_getPositions(const OUString
& _sValue
,OUString
& _rContentX
,OUString
& _rContentY
,OUString
& _rContentZ
)
476 if(_sValue
.isEmpty() || _sValue
[0] != '(')
480 sal_Int32 nFound
= _sValue
.indexOf(' ', nPos
);
482 if(nFound
== -1 || nFound
<= nPos
)
485 _rContentX
= _sValue
.copy(nPos
, nFound
- nPos
);
488 nFound
= _sValue
.indexOf(' ', nPos
);
490 if(nFound
== -1 || nFound
<= nPos
)
493 _rContentY
= _sValue
.copy(nPos
, nFound
- nPos
);
496 nFound
= _sValue
.indexOf(')', nPos
);
498 if(nFound
== -1 || nFound
<= nPos
)
501 _rContentZ
= _sValue
.copy(nPos
, nFound
- nPos
);
505 /** convert string to ::basegfx::B3DVector */
506 bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector
& rVector
, const OUString
& rValue
)
508 OUString aContentX
,aContentY
,aContentZ
;
509 if ( !lcl_getPositions(rValue
,aContentX
,aContentY
,aContentZ
) )
512 rtl_math_ConversionStatus eStatus
;
514 rVector
.setX(::rtl::math::stringToDouble(aContentX
, '.',
517 if( eStatus
!= rtl_math_ConversionStatus_Ok
)
520 rVector
.setY(::rtl::math::stringToDouble(aContentY
, '.',
523 if( eStatus
!= rtl_math_ConversionStatus_Ok
)
526 rVector
.setZ(::rtl::math::stringToDouble(aContentZ
, '.',
530 return ( eStatus
== rtl_math_ConversionStatus_Ok
);
533 /** convert ::basegfx::B3DVector to string */
534 void SvXMLUnitConverter::convertB3DVector( OUStringBuffer
&rBuffer
, const ::basegfx::B3DVector
& rVector
)
537 ::sax::Converter::convertDouble(rBuffer
, rVector
.getX());
539 ::sax::Converter::convertDouble(rBuffer
, rVector
.getY());
541 ::sax::Converter::convertDouble(rBuffer
, rVector
.getZ());
545 /** convert string to Position3D */
546 bool SvXMLUnitConverter::convertPosition3D( drawing::Position3D
& rPosition
,
547 const OUString
& rValue
)
549 OUString aContentX
,aContentY
,aContentZ
;
550 if ( !lcl_getPositions(rValue
,aContentX
,aContentY
,aContentZ
) )
553 if ( !convertDouble( rPosition
.PositionX
, aContentX
) )
555 if ( !convertDouble( rPosition
.PositionY
, aContentY
) )
557 return convertDouble( rPosition
.PositionZ
, aContentZ
);
560 /** convert Position3D to string */
561 void SvXMLUnitConverter::convertPosition3D( OUStringBuffer
&rBuffer
,
562 const drawing::Position3D
& rPosition
)
564 rBuffer
.append( '(' );
565 convertDouble( rBuffer
, rPosition
.PositionX
);
566 rBuffer
.append( ' ' );
567 convertDouble( rBuffer
, rPosition
.PositionY
);
568 rBuffer
.append( ' ' );
569 convertDouble( rBuffer
, rPosition
.PositionZ
);
570 rBuffer
.append( ')' );
573 bool SvXMLUnitConverter::convertNumFormat(
575 const OUString
& rNumFmt
,
576 const OUString
& rNumLetterSync
,
577 bool bNumberNone
) const
582 sal_Int32 nLen
= rNumFmt
.getLength();
586 rType
= NumberingType::NUMBER_NONE
;
594 case '1': rType
= NumberingType::ARABIC
; break;
595 case 'a': rType
= NumberingType::CHARS_LOWER_LETTER
; break;
596 case 'A': rType
= NumberingType::CHARS_UPPER_LETTER
; break;
597 case 'i': rType
= NumberingType::ROMAN_LOWER
; break;
598 case 'I': rType
= NumberingType::ROMAN_UPPER
; break;
599 default: bExt
= true; break;
601 if( !bExt
&& IsXMLToken( rNumLetterSync
, XML_TRUE
) )
605 case NumberingType::CHARS_LOWER_LETTER
:
606 rType
= NumberingType::CHARS_LOWER_LETTER_N
;
608 case NumberingType::CHARS_UPPER_LETTER
:
609 rType
= NumberingType::CHARS_UPPER_LETTER_N
;
620 Reference
< XNumberingTypeInfo
> xInfo
= getNumTypeInfo();
621 if( xInfo
.is() && xInfo
->hasNumberingType( rNumFmt
) )
623 rType
= xInfo
->getNumberingType( rNumFmt
);
627 rType
= NumberingType::ARABIC
;
634 void SvXMLUnitConverter::convertNumFormat( OUStringBuffer
& rBuffer
,
635 sal_Int16 nType
) const
637 enum XMLTokenEnum eFormat
= XML_TOKEN_INVALID
;
640 case NumberingType::CHARS_UPPER_LETTER
: eFormat
= XML_A_UPCASE
; break;
641 case NumberingType::CHARS_LOWER_LETTER
: eFormat
= XML_A
; break;
642 case NumberingType::ROMAN_UPPER
: eFormat
= XML_I_UPCASE
; break;
643 case NumberingType::ROMAN_LOWER
: eFormat
= XML_I
; break;
644 case NumberingType::ARABIC
: eFormat
= XML_1
; break;
645 case NumberingType::CHARS_UPPER_LETTER_N
: eFormat
= XML_A_UPCASE
; break;
646 case NumberingType::CHARS_LOWER_LETTER_N
: eFormat
= XML_A
; break;
647 case NumberingType::NUMBER_NONE
: eFormat
= XML__EMPTY
; break;
649 case NumberingType::CHAR_SPECIAL
:
650 case NumberingType::PAGE_DESCRIPTOR
:
651 case NumberingType::BITMAP
:
652 SAL_WARN_IF( eFormat
== XML_TOKEN_INVALID
, "xmloff", "invalid number format" );
658 if( eFormat
!= XML_TOKEN_INVALID
)
660 rBuffer
.append( GetXMLToken(eFormat
) );
664 Reference
< XNumberingTypeInfo
> xInfo
= getNumTypeInfo();
666 rBuffer
.append( xInfo
->getNumberingIdentifier( nType
) );
670 void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer
& rBuffer
,
673 enum XMLTokenEnum eSync
= XML_TOKEN_INVALID
;
676 case NumberingType::CHARS_UPPER_LETTER
:
677 case NumberingType::CHARS_LOWER_LETTER
:
678 case NumberingType::ROMAN_UPPER
:
679 case NumberingType::ROMAN_LOWER
:
680 case NumberingType::ARABIC
:
681 case NumberingType::NUMBER_NONE
:
684 case NumberingType::CHARS_UPPER_LETTER_N
:
685 case NumberingType::CHARS_LOWER_LETTER_N
:
689 case NumberingType::CHAR_SPECIAL
:
690 case NumberingType::PAGE_DESCRIPTOR
:
691 case NumberingType::BITMAP
:
692 SAL_WARN_IF( eSync
== XML_TOKEN_INVALID
, "xmloff", "invalid number format" );
695 if( eSync
!= XML_TOKEN_INVALID
)
696 rBuffer
.append( GetXMLToken(eSync
) );
699 void SvXMLUnitConverter::convertPropertySet(uno::Sequence
<beans::PropertyValue
>& rProps
,
700 const uno::Reference
<beans::XPropertySet
>& aProperties
)
702 uno::Reference
< beans::XPropertySetInfo
> xPropertySetInfo
= aProperties
->getPropertySetInfo();
703 if (xPropertySetInfo
.is())
705 const uno::Sequence
< beans::Property
> aProps
= xPropertySetInfo
->getProperties();
706 if (aProps
.hasElements())
708 rProps
.realloc(aProps
.getLength());
709 beans::PropertyValue
* pProps
= rProps
.getArray();
710 for (const auto& rProp
: aProps
)
712 pProps
->Name
= rProp
.Name
;
713 pProps
->Value
= aProperties
->getPropertyValue(rProp
.Name
);
720 void SvXMLUnitConverter::convertPropertySet(uno::Reference
<beans::XPropertySet
> const & rProperties
,
721 const uno::Sequence
<beans::PropertyValue
>& aProps
)
723 if (aProps
.hasElements())
725 uno::Reference
< beans::XPropertySetInfo
> xPropertySetInfo
= rProperties
->getPropertySetInfo();
726 if (xPropertySetInfo
.is())
728 for (const auto& rProp
: aProps
)
730 if (xPropertySetInfo
->hasPropertyByName(rProp
.Name
))
731 rProperties
->setPropertyValue(rProp
.Name
, rProp
.Value
);
738 OUString
SvXMLUnitConverter::encodeStyleName(
739 const OUString
& rName
,
740 bool *pEncoded
) const
745 sal_Int32 nLen
= rName
.getLength();
746 OUStringBuffer
aBuffer( nLen
*2 );
748 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
750 sal_Unicode c
= rName
[i
];
751 bool bValidChar
= false;
755 (c
>= 0x0041 && c
<= 0x005a) ||
756 (c
>= 0x0061 && c
<= 0x007a) ||
757 (c
>= 0x00c0 && c
<= 0x00d6) ||
758 (c
>= 0x00d8 && c
<= 0x00f6) ||
759 (c
>= 0x00f8 && c
<= 0x00ff) ||
760 ( i
> 0 && ( (c
>= 0x0030 && c
<= 0x0039) ||
761 c
== 0x00b7 || c
== '-' || c
== '.') );
765 if( (c
>= 0xf900U
&& c
<= 0xfffeU
) ||
766 (c
>= 0x20ddU
&& c
<= 0x20e0U
))
770 else if( (c
>= 0x02bbU
&& c
<= 0x02c1U
) || c
== 0x0559 ||
771 c
== 0x06e5 || c
== 0x06e6 )
775 else if( c
== 0x0387 )
781 if (!m_pImpl
->m_xCharClass
.is())
783 m_pImpl
->m_xCharClass
= CharacterClassification::create( m_pImpl
->m_xContext
);
785 sal_Int16 nType
= m_pImpl
->m_xCharClass
->getType(rName
, i
);
789 case UnicodeType::UPPERCASE_LETTER
: // Lu
790 case UnicodeType::LOWERCASE_LETTER
: // Ll
791 case UnicodeType::TITLECASE_LETTER
: // Lt
792 case UnicodeType::OTHER_LETTER
: // Lo
793 case UnicodeType::LETTER_NUMBER
: // Nl
796 case UnicodeType::NON_SPACING_MARK
: // Ms
797 case UnicodeType::ENCLOSING_MARK
: // Me
798 case UnicodeType::COMBINING_SPACING_MARK
: //Mc
799 case UnicodeType::MODIFIER_LETTER
: // Lm
800 case UnicodeType::DECIMAL_DIGIT_NUMBER
: // Nd
812 aBuffer
.append( '_' );
814 aBuffer
.append( static_cast< sal_Unicode
>(
815 aHexTab
[ (c
>> 12) & 0x0f ] ) );
817 aBuffer
.append( static_cast< sal_Unicode
>(
818 aHexTab
[ (c
>> 8) & 0x0f ] ) );
820 aBuffer
.append( static_cast< sal_Unicode
>(
821 aHexTab
[ (c
>> 4) & 0x0f ] ) );
822 aBuffer
.append( static_cast< sal_Unicode
>(
823 aHexTab
[ c
& 0x0f ] ) );
824 aBuffer
.append( '_' );
831 if( aBuffer
.getLength() > ((1<<15)-1) )
839 return aBuffer
.makeStringAndClear();
842 /** convert string (hex) to number (sal_uInt32) */
843 bool SvXMLUnitConverter::convertHex( sal_uInt32
& nVal
,
844 const OUString
& rValue
)
846 if( rValue
.getLength() != 8 )
850 for ( int i
= 0; i
< 8; i
++ )
853 | sal::static_int_cast
< sal_uInt32
>( lcl_gethex( rValue
[i
] ) );
859 /** convert number (sal_uInt32) to string (hex) */
860 void SvXMLUnitConverter::convertHex( OUStringBuffer
& rBuffer
,
863 for ( int i
= 0; i
< 8; i
++ )
865 rBuffer
.append( sal_Unicode( aHexTab
[ nVal
>> 28 ] ) );
870 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */