Bump version to 6.4.0.12
[LibreOffice.git] / xmloff / source / core / xmluconv.cxx
blobdfff05c31f7ef43e6c3643c322ae703054c4153f
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 <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;
139 switch( nFieldUnit )
141 case FieldUnit::MM:
142 eUnit = util::MeasureUnit::MM;
143 break;
144 case FieldUnit::CM:
145 case FieldUnit::M:
146 case FieldUnit::KM:
147 eUnit = util::MeasureUnit::CM;
148 break;
149 case FieldUnit::TWIP:
150 eUnit = util::MeasureUnit::TWIP;
151 break;
152 case FieldUnit::POINT:
153 case FieldUnit::PICA:
154 eUnit = util::MeasureUnit::POINT;
155 break;
156 case FieldUnit::MM_100TH:
157 eUnit = util::MeasureUnit::MM_100TH;
158 break;
159 case FieldUnit::INCH:
160 eUnit = util::MeasureUnit::INCH;
161 break;
162 default:
163 assert(false);
164 break;
166 return eUnit;
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,
176 nMin, nMax );
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
191 OUStringBuffer s;
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();
210 return true;
212 ++pMap;
215 return false;
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(
221 sal_uInt16& rEnum,
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();
230 return true;
232 ++pMap;
234 return false;
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,
243 sal_uInt16 nValue,
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();
254 break;
256 ++pMap;
259 // the map may have contained XML_TOKEN_INVALID
260 if( eTok == XML_TOKEN_INVALID )
261 eTok = eDefault;
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' )
272 return nChar - '0';
273 else if( nChar >= 'a' && nChar <= 'f' )
274 return nChar - 'a' + 10;
275 else if( nChar >= 'A' && nChar <= 'F' )
276 return nChar - 'A' + 10;
277 else
278 return 0;
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);
312 return false;
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,
333 bool bAddTimeIf0AM )
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);
339 fValue -= nDays;
340 const bool bHasTime = (fValue > 0.0);
342 sal_Int16 nTempYear = aDate.GetYear();
343 assert(nTempYear != 0);
344 if (nTempYear < 0)
346 rBuffer.append( '-');
347 nTempYear = -nTempYear;
349 if (nTempYear < 1000)
350 rBuffer.append( '0');
351 if (nTempYear < 100)
352 rBuffer.append( '0');
353 if (nTempYear < 10)
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);
359 if (nTemp < 10)
360 rBuffer.append( '0');
361 rBuffer.append( sal_Int32( nTemp));
362 rBuffer.append( '-');
363 nTemp = aDate.GetDay();
364 assert(1 <= nTemp && nTemp <= 31);
365 if (nTemp < 10)
366 rBuffer.append( '0');
367 rBuffer.append( sal_Int32( nTemp));
368 if (bHasTime || bAddTimeIf0AM)
370 double fCount;
371 if (nDays > 0)
372 fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays))) + 1;
373 else if (nDays < 0)
374 fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays * -1))) + 1;
375 else
376 fCount = 0.0;
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');
386 if (nHour < 10)
387 rBuffer.append( '0');
388 rBuffer.append( sal_Int32( nHour));
389 rBuffer.append( ':');
390 if (nMinute < 10)
391 rBuffer.append( '0');
392 rBuffer.append( sal_Int32( nMinute));
393 rBuffer.append( ':');
394 if (nSecond < 10)
395 rBuffer.append( '0');
396 rBuffer.append( sal_Int32( nSecond));
397 if (nFractionDecimals)
399 // nFractionDecimals+1 to not round up what GetClock() carefully
400 // truncated.
401 OUString aFraction( ::rtl::math::doubleToUString( fFractionOfSecond,
402 rtl_math_StringFormat_F,
403 nFractionDecimals + 1, '.', true));
404 const sal_Int32 nLen = aFraction.getLength();
405 if ( nLen > 2 )
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);
423 if (bSuccess)
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;
439 return bSuccess;
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 )
451 return false;
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() )
463 mnNextTokenPos = -1;
465 else
467 rToken = maTokenString.copy( mnNextTokenPos );
468 mnNextTokenPos = -1;
471 return true;
474 static bool lcl_getPositions(const OUString& _sValue,OUString& _rContentX,OUString& _rContentY,OUString& _rContentZ)
476 if(_sValue.isEmpty() || _sValue[0] != '(')
477 return false;
479 sal_Int32 nPos(1);
480 sal_Int32 nFound = _sValue.indexOf(' ', nPos);
482 if(nFound == -1 || nFound <= nPos)
483 return false;
485 _rContentX = _sValue.copy(nPos, nFound - nPos);
487 nPos = nFound + 1;
488 nFound = _sValue.indexOf(' ', nPos);
490 if(nFound == -1 || nFound <= nPos)
491 return false;
493 _rContentY = _sValue.copy(nPos, nFound - nPos);
495 nPos = nFound + 1;
496 nFound = _sValue.indexOf(')', nPos);
498 if(nFound == -1 || nFound <= nPos)
499 return false;
501 _rContentZ = _sValue.copy(nPos, nFound - nPos);
502 return true;
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) )
510 return false;
512 rtl_math_ConversionStatus eStatus;
514 rVector.setX(::rtl::math::stringToDouble(aContentX, '.',
515 ',', &eStatus));
517 if( eStatus != rtl_math_ConversionStatus_Ok )
518 return false;
520 rVector.setY(::rtl::math::stringToDouble(aContentY, '.',
521 ',', &eStatus));
523 if( eStatus != rtl_math_ConversionStatus_Ok )
524 return false;
526 rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.',
527 ',', &eStatus));
530 return ( eStatus == rtl_math_ConversionStatus_Ok );
533 /** convert ::basegfx::B3DVector to string */
534 void SvXMLUnitConverter::convertB3DVector( OUStringBuffer &rBuffer, const ::basegfx::B3DVector& rVector )
536 rBuffer.append('(');
537 ::sax::Converter::convertDouble(rBuffer, rVector.getX());
538 rBuffer.append(' ');
539 ::sax::Converter::convertDouble(rBuffer, rVector.getY());
540 rBuffer.append(' ');
541 ::sax::Converter::convertDouble(rBuffer, rVector.getZ());
542 rBuffer.append(')');
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) )
551 return false;
553 if ( !convertDouble( rPosition.PositionX, aContentX ) )
554 return false;
555 if ( !convertDouble( rPosition.PositionY, aContentY ) )
556 return false;
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(
574 sal_Int16& rType,
575 const OUString& rNumFmt,
576 const OUString& rNumLetterSync,
577 bool bNumberNone ) const
579 bool bRet = true;
580 bool bExt = false;
582 sal_Int32 nLen = rNumFmt.getLength();
583 if( 0 == nLen )
585 if( bNumberNone )
586 rType = NumberingType::NUMBER_NONE;
587 else
588 bRet = false;
590 else if( 1 == nLen )
592 switch( rNumFmt[0] )
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 ) )
603 switch( rType )
605 case NumberingType::CHARS_LOWER_LETTER:
606 rType = NumberingType::CHARS_LOWER_LETTER_N;
607 break;
608 case NumberingType::CHARS_UPPER_LETTER:
609 rType = NumberingType::CHARS_UPPER_LETTER_N;
610 break;
614 else
616 bExt = true;
618 if( bExt )
620 Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
621 if( xInfo.is() && xInfo->hasNumberingType( rNumFmt ) )
623 rType = xInfo->getNumberingType( rNumFmt );
625 else
627 rType = NumberingType::ARABIC;
631 return bRet;
634 void SvXMLUnitConverter::convertNumFormat( OUStringBuffer& rBuffer,
635 sal_Int16 nType ) const
637 enum XMLTokenEnum eFormat = XML_TOKEN_INVALID;
638 switch( nType )
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" );
653 break;
654 default:
655 break;
658 if( eFormat != XML_TOKEN_INVALID )
660 rBuffer.append( GetXMLToken(eFormat) );
662 else
664 Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
665 if( xInfo.is() )
666 rBuffer.append( xInfo->getNumberingIdentifier( nType ) );
670 void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer& rBuffer,
671 sal_Int16 nType )
673 enum XMLTokenEnum eSync = XML_TOKEN_INVALID;
674 switch( nType )
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:
682 break;
684 case NumberingType::CHARS_UPPER_LETTER_N:
685 case NumberingType::CHARS_LOWER_LETTER_N:
686 eSync = XML_TRUE;
687 break;
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" );
693 break;
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);
714 ++pProps;
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
742 if( pEncoded )
743 *pEncoded = false;
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;
752 if( c < 0x00ffU )
754 bValidChar =
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 == '.') );
763 else
765 if( (c >= 0xf900U && c <= 0xfffeU) ||
766 (c >= 0x20ddU && c <= 0x20e0U))
768 bValidChar = false;
770 else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
771 c == 0x06e5 || c == 0x06e6 )
773 bValidChar = true;
775 else if( c == 0x0387 )
777 bValidChar = i > 0;
779 else
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);
787 switch( nType )
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
794 bValidChar = true;
795 break;
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
801 bValidChar = i > 0;
802 break;
806 if( bValidChar )
808 aBuffer.append( c );
810 else
812 aBuffer.append( '_' );
813 if( c > 0x0fff )
814 aBuffer.append( static_cast< sal_Unicode >(
815 aHexTab[ (c >> 12) & 0x0f ] ) );
816 if( c > 0x00ff )
817 aBuffer.append( static_cast< sal_Unicode >(
818 aHexTab[ (c >> 8) & 0x0f ] ) );
819 if( c > 0x000f )
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( '_' );
825 if( pEncoded )
826 *pEncoded = true;
830 // check for length
831 if( aBuffer.getLength() > ((1<<15)-1) )
833 aBuffer = rName;
834 if( pEncoded )
835 *pEncoded = false;
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 )
847 return false;
849 nVal = 0;
850 for ( int i = 0; i < 8; i++ )
852 nVal = ( nVal << 4 )
853 | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) );
856 return true;
859 /** convert number (sal_uInt32) to string (hex) */
860 void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer,
861 sal_uInt32 nVal )
863 for ( int i = 0; i < 8; i++ )
865 rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) );
866 nVal <<= 4;
870 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */