1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <string_view>
23 
24 #include <xmloff/xmluconv.hxx>
25 
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>
34 
35 #include <tools/date.hxx>
36 #include <tools/time.hxx>
37 #include <tools/fldunit.hxx>
38 
39 #include <com/sun/star/drawing/Position3D.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
41 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
42 #include <com/sun/star/style/NumberingType.hpp>
43 #include <com/sun/star/text/DefaultNumberingProvider.hpp>
44 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
45 #include <com/sun/star/text/XNumberingTypeInfo.hpp>
46 #include <com/sun/star/i18n/CharacterClassification.hpp>
47 #include <com/sun/star/i18n/UnicodeType.hpp>
48 #include <basegfx/vector/b3dvector.hxx>
49 
50 #include <sax/tools/converter.hxx>
51 
52 
53 using namespace com::sun::star;
54 using namespace com::sun::star::uno;
55 using namespace com::sun::star::lang;
56 using namespace com::sun::star::text;
57 using namespace com::sun::star::style;
58 using namespace ::com::sun::star::i18n;
59 using namespace ::xmloff::token;
60 
61 
62 const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 11;
63 #define XML_NULLDATE "NullDate"
64 
65 struct SvXMLUnitConverter::Impl
66 {
67     sal_Int16 m_eCoreMeasureUnit; /*css::util::MeasureUnit*/
68     sal_Int16 m_eXMLMeasureUnit; /*css::util::MeasureUnit*/
69     SvtSaveOptions::ODFSaneDefaultVersion m_eODFVersion;
70     util::Date m_aNullDate;
71     mutable uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo;
72     mutable uno::Reference< i18n::XCharacterClassification > m_xCharClass;
73     uno::Reference< uno::XComponentContext > m_xContext;
74 
ImplSvXMLUnitConverter::Impl75     Impl(uno::Reference<uno::XComponentContext> const& xContext,
76             sal_Int16 const eCoreMeasureUnit,
77             sal_Int16 const eXMLMeasureUnit,
78             SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
79         : m_eCoreMeasureUnit(eCoreMeasureUnit)
80         , m_eXMLMeasureUnit(eXMLMeasureUnit)
81         , m_eODFVersion(nODFVersion)
82         , m_aNullDate(30, 12, 1899)
83         , m_xContext(xContext)
84     {
85         OSL_ENSURE( m_xContext.is(), "got no service manager" );
86     }
87 
88     void createNumTypeInfo() const;
89 };
90 
91 
createNumTypeInfo() const92 void SvXMLUnitConverter::Impl::createNumTypeInfo() const
93 {
94     Reference<XDefaultNumberingProvider> xDefNum = DefaultNumberingProvider::create(m_xContext);
95     m_xNumTypeInfo.set(xDefNum, uno::UNO_QUERY);
96 }
97 
98 const uno::Reference< text::XNumberingTypeInfo >&
getNumTypeInfo() const99 SvXMLUnitConverter::getNumTypeInfo() const
100 {
101     if (!m_pImpl->m_xNumTypeInfo.is())
102     {
103         m_pImpl->createNumTypeInfo();
104     }
105     return m_pImpl->m_xNumTypeInfo;
106 }
107 
SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit)108 void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit/*css::util::MeasureUnit*/)
109 {
110     m_pImpl->m_eCoreMeasureUnit = eCoreMeasureUnit;
111 }
112 
SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit)113 void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit/*css::util::MeasureUnit*/)
114 {
115     m_pImpl->m_eXMLMeasureUnit = eXMLMeasureUnit;
116 }
117 
GetXMLMeasureUnit() const118 sal_Int16 SvXMLUnitConverter::GetXMLMeasureUnit() const
119 {
120     return m_pImpl->m_eXMLMeasureUnit;
121 }
122 
getSaneDefaultVersion() const123 SvtSaveOptions::ODFSaneDefaultVersion SvXMLUnitConverter::getSaneDefaultVersion() const
124 {
125     return m_pImpl->m_eODFVersion;
126 }
127 
overrideSaneDefaultVersion(SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)128 void SvXMLUnitConverter::overrideSaneDefaultVersion(
129         SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
130 {
131     m_pImpl->m_eODFVersion = nODFVersion;
132 }
133 
134 /** constructs a SvXMLUnitConverter. The core measure unit is the
135     default unit for numerical measures, the XML measure unit is
136     the default unit for textual measures
137 */
138 
SvXMLUnitConverter(const uno::Reference<uno::XComponentContext> & xContext,sal_Int16 const eCoreMeasureUnit,sal_Int16 const eXMLMeasureUnit,SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)139 SvXMLUnitConverter::SvXMLUnitConverter(
140     const uno::Reference<uno::XComponentContext>& xContext,
141     sal_Int16 const eCoreMeasureUnit,
142     sal_Int16 const eXMLMeasureUnit,
143     SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
144 : m_pImpl(new Impl(xContext, eCoreMeasureUnit, eXMLMeasureUnit, nODFVersion))
145 {
146 }
147 
~SvXMLUnitConverter()148 SvXMLUnitConverter::~SvXMLUnitConverter()
149 {
150 }
151 
GetMeasureUnit(FieldUnit const nFieldUnit)152 sal_Int16 SvXMLUnitConverter::GetMeasureUnit(FieldUnit const nFieldUnit)
153 {
154     sal_Int16 eUnit = util::MeasureUnit::INCH;
155     switch( nFieldUnit )
156     {
157     case FieldUnit::MM:
158         eUnit = util::MeasureUnit::MM;
159         break;
160     case FieldUnit::CM:
161     case FieldUnit::M:
162     case FieldUnit::KM:
163         eUnit = util::MeasureUnit::CM;
164         break;
165     case FieldUnit::TWIP:
166         eUnit = util::MeasureUnit::TWIP;
167         break;
168     case FieldUnit::POINT:
169     case FieldUnit::PICA:
170         eUnit = util::MeasureUnit::POINT;
171         break;
172     case FieldUnit::MM_100TH:
173         eUnit = util::MeasureUnit::MM_100TH;
174         break;
175     case FieldUnit::INCH:
176         eUnit = util::MeasureUnit::INCH;
177         break;
178     default:
179         assert(false);
180         break;
181     }
182     return eUnit;
183 }
184 
185 /** convert string to measure using optional min and max values*/
convertMeasureToCore(sal_Int32 & nValue,std::u16string_view rString,sal_Int32 nMin,sal_Int32 nMax) const186 bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue,
187                                          std::u16string_view rString,
188                                          sal_Int32 nMin, sal_Int32 nMax ) const
189 {
190     return ::sax::Converter::convertMeasure( nValue, rString,
191                                                m_pImpl->m_eCoreMeasureUnit,
192                                                nMin, nMax );
193 }
194 
195 /** convert string to measure using optional min and max values*/
convertMeasureToCore(sal_Int32 & nValue,std::string_view rString,sal_Int32 nMin,sal_Int32 nMax) const196 bool SvXMLUnitConverter::convertMeasureToCore( sal_Int32& nValue,
197                                          std::string_view rString,
198                                          sal_Int32 nMin, sal_Int32 nMax ) const
199 {
200     return ::sax::Converter::convertMeasure( nValue, rString,
201                                                m_pImpl->m_eCoreMeasureUnit,
202                                                nMin, nMax );
203 }
204 
205 /** convert measure to string */
convertMeasureToXML(OUStringBuffer & rString,sal_Int32 nMeasure) const206 void SvXMLUnitConverter::convertMeasureToXML( OUStringBuffer& rString,
207                                          sal_Int32 nMeasure ) const
208 {
209     ::sax::Converter::convertMeasure( rString, nMeasure,
210                                         m_pImpl->m_eCoreMeasureUnit,
211                                         m_pImpl->m_eXMLMeasureUnit );
212 }
213 
214 /** convert measure to string */
convertMeasureToXML(sal_Int32 nMeasure) const215 OUString SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure ) const
216 {
217     OUStringBuffer s;
218     ::sax::Converter::convertMeasure( s, nMeasure,
219                                         m_pImpl->m_eCoreMeasureUnit,
220                                         m_pImpl->m_eXMLMeasureUnit );
221     return s.makeStringAndClear();
222 }
223 
224 /** convert string to enum using given enum map, if the enum is
225     not found in the map, this method will return false
226 */
convertEnumImpl(sal_uInt16 & rEnum,std::u16string_view rValue,const SvXMLEnumStringMapEntry<sal_uInt16> * pMap)227 bool SvXMLUnitConverter::convertEnumImpl( sal_uInt16& rEnum,
228                                       std::u16string_view rValue,
229                                       const SvXMLEnumStringMapEntry<sal_uInt16> *pMap )
230 {
231     while( pMap->GetName() )
232     {
233         auto nameLength = pMap->GetNameLength();
234         if( static_cast<sal_Int32>(rValue.size()) == nameLength &&
235             rtl_ustr_asciil_reverseEquals_WithLength(
236                     rValue.data(), pMap->GetName(), nameLength ) )
237         {
238             rEnum = pMap->GetValue();
239             return true;
240         }
241         ++pMap;
242     }
243 
244     return false;
245 }
246 
247 /** convert string to enum using given token map, if the enum is
248     not found in the map, this method will return false */
convertEnumImpl(sal_uInt16 & rEnum,std::u16string_view rValue,const SvXMLEnumMapEntry<sal_uInt16> * pMap)249 bool SvXMLUnitConverter::convertEnumImpl(
250     sal_uInt16& rEnum,
251     std::u16string_view rValue,
252     const SvXMLEnumMapEntry<sal_uInt16> *pMap )
253 {
254     while( pMap->GetToken() != XML_TOKEN_INVALID )
255     {
256         if( IsXMLToken( rValue, pMap->GetToken() ) )
257         {
258             rEnum = pMap->GetValue();
259             return true;
260         }
261         ++pMap;
262     }
263     return false;
264 }
265 
266 /** convert string to enum using given token map, if the enum is
267     not found in the map, this method will return false */
convertEnumImpl(sal_uInt16 & rEnum,std::string_view rValue,const SvXMLEnumMapEntry<sal_uInt16> * pMap)268 bool SvXMLUnitConverter::convertEnumImpl(
269     sal_uInt16& rEnum,
270     std::string_view rValue,
271     const SvXMLEnumMapEntry<sal_uInt16> *pMap )
272 {
273     while( pMap->GetToken() != XML_TOKEN_INVALID )
274     {
275         if( IsXMLToken( rValue, pMap->GetToken() ) )
276         {
277             rEnum = pMap->GetValue();
278             return true;
279         }
280         ++pMap;
281     }
282     return false;
283 }
284 
285 /** convert enum to string using given token map with an optional
286     default token. If the enum is not found in the map,
287     this method will either use the given default or return
288     false if no default is set */
convertEnumImpl(OUStringBuffer & rBuffer,sal_uInt16 nValue,const SvXMLEnumMapEntry<sal_uInt16> * pMap,enum XMLTokenEnum eDefault)289 bool SvXMLUnitConverter::convertEnumImpl(
290     OUStringBuffer& rBuffer,
291     sal_uInt16 nValue,
292     const SvXMLEnumMapEntry<sal_uInt16> *pMap,
293     enum XMLTokenEnum eDefault)
294 {
295     enum XMLTokenEnum eTok = eDefault;
296 
297     while( pMap->GetToken() != XML_TOKEN_INVALID )
298     {
299         if( pMap->GetValue() == nValue )
300         {
301             eTok = pMap->GetToken();
302             break;
303         }
304         ++pMap;
305     }
306 
307     // the map may have contained XML_TOKEN_INVALID
308     if( eTok == XML_TOKEN_INVALID )
309         eTok = eDefault;
310 
311     if( eTok != XML_TOKEN_INVALID )
312         rBuffer.append( GetXMLToken(eTok) );
313 
314     return (eTok != XML_TOKEN_INVALID);
315 }
316 
lcl_gethex(int nChar)317 static int lcl_gethex( int nChar )
318 {
319     if( nChar >= '0' && nChar <= '9' )
320         return nChar - '0';
321     else if( nChar >= 'a' && nChar <= 'f' )
322         return nChar - 'a' + 10;
323     else if( nChar >= 'A' && nChar <= 'F' )
324         return nChar - 'A' + 10;
325     else
326         return 0;
327 }
328 
329 const char aHexTab[] = "0123456789abcdef";
330 
331 
332 /** convert double number to string (using ::rtl::math) */
convertDouble(OUStringBuffer & rBuffer,double fNumber) const333 void SvXMLUnitConverter::convertDouble(OUStringBuffer& rBuffer,
334     double fNumber) const
335 {
336     ::sax::Converter::convertDouble(rBuffer, fNumber,
337         true/*bWriteUnits*/, m_pImpl->m_eCoreMeasureUnit, m_pImpl->m_eXMLMeasureUnit);
338 }
339 
340 /** convert string to double number (using ::rtl::math) */
convertDouble(double & rValue,std::u16string_view rString) const341 bool SvXMLUnitConverter::convertDouble(double& rValue,
342     std::u16string_view rString) const
343 {
344     sal_Int16 const eSrcUnit = ::sax::Converter::GetUnitFromString(
345             rString, m_pImpl->m_eCoreMeasureUnit);
346 
347     return ::sax::Converter::convertDouble(rValue, rString,
348         eSrcUnit, m_pImpl->m_eCoreMeasureUnit);
349 }
350 
351 /** get the Null Date of the XModel and set it to the UnitConverter */
setNullDate(const css::uno::Reference<css::frame::XModel> & xModel)352 bool SvXMLUnitConverter::setNullDate(const css::uno::Reference <css::frame::XModel>& xModel)
353 {
354     css::uno::Reference <css::util::XNumberFormatsSupplier> xNumberFormatsSupplier (xModel, css::uno::UNO_QUERY);
355     if (xNumberFormatsSupplier.is())
356     {
357         const css::uno::Reference <css::beans::XPropertySet> xPropertySet = xNumberFormatsSupplier->getNumberFormatSettings();
358         return xPropertySet.is() && (xPropertySet->getPropertyValue(XML_NULLDATE) >>= m_pImpl->m_aNullDate);
359     }
360     return false;
361 }
362 
363 /** convert double to ISO Date Time String */
convertDateTime(OUStringBuffer & rBuffer,const double & fDateTime,bool const bAddTimeIf0AM)364 void SvXMLUnitConverter::convertDateTime(OUStringBuffer& rBuffer,
365                      const double& fDateTime, bool const bAddTimeIf0AM)
366 {
367     convertDateTime(rBuffer, fDateTime, m_pImpl->m_aNullDate, bAddTimeIf0AM);
368 }
369 
370 /** convert ISO Date Time String to double */
convertDateTime(double & fDateTime,std::u16string_view rString)371 bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
372                      std::u16string_view rString)
373 {
374     return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
375 }
376 
377 /** convert ISO Date Time String to double */
convertDateTime(double & fDateTime,std::string_view rString)378 bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
379                      std::string_view rString)
380 {
381     return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
382 }
383 
384 /** convert double to ISO Date Time String */
convertDateTime(OUStringBuffer & rBuffer,const double & fDateTime,const css::util::Date & aTempNullDate,bool bAddTimeIf0AM)385 void SvXMLUnitConverter::convertDateTime( OUStringBuffer& rBuffer,
386         const double& fDateTime,
387         const css::util::Date& aTempNullDate,
388         bool bAddTimeIf0AM )
389 {
390     double fValue = fDateTime;
391     const sal_Int32 nDays = static_cast <sal_Int32> (::rtl::math::approxFloor (fValue));
392     Date aDate (aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
393     aDate.AddDays( nDays);
394     fValue -= nDays;
395     const bool bHasTime = (fValue > 0.0);
396 
397     sal_Int16 nTempYear = aDate.GetYear();
398     assert(nTempYear != 0);
399     if (nTempYear < 0)
400     {
401         rBuffer.append( '-');
402         nTempYear = -nTempYear;
403     }
404     if (nTempYear < 1000)
405         rBuffer.append( '0');
406     if (nTempYear < 100)
407         rBuffer.append( '0');
408     if (nTempYear < 10)
409         rBuffer.append( '0');
410     rBuffer.append( sal_Int32( nTempYear));
411     rBuffer.append( '-');
412     sal_uInt16 nTemp = aDate.GetMonth();
413     assert(1 <= nTemp && nTemp <= 12);
414     if (nTemp < 10)
415         rBuffer.append( '0');
416     rBuffer.append( sal_Int32( nTemp));
417     rBuffer.append( '-');
418     nTemp = aDate.GetDay();
419     assert(1 <= nTemp && nTemp <= 31);
420     if (nTemp < 10)
421         rBuffer.append( '0');
422     rBuffer.append( sal_Int32( nTemp));
423     if (!(bHasTime || bAddTimeIf0AM))
424         return;
425 
426     double fCount;
427     if (nDays > 0)
428         fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays))) + 1;
429     else if (nDays < 0)
430         fCount = ::rtl::math::approxFloor (log10(static_cast<double>(nDays * -1))) + 1;
431     else
432         fCount = 0.0;
433     const int nDigits = sal_Int16(fCount) + 4;  // +4 for *86400 in seconds
434     const int nFractionDecimals = std::max( XML_MAXDIGITSCOUNT_TIME - nDigits, 0);
435 
436     sal_uInt16 nHour, nMinute, nSecond;
437     double fFractionOfSecond;
438     // Pass the original date+time value for proper scaling and rounding.
439     tools::Time::GetClock( fDateTime, nHour, nMinute, nSecond, fFractionOfSecond, nFractionDecimals);
440 
441     rBuffer.append( 'T');
442     if (nHour < 10)
443         rBuffer.append( '0');
444     rBuffer.append( sal_Int32( nHour));
445     rBuffer.append( ':');
446     if (nMinute < 10)
447         rBuffer.append( '0');
448     rBuffer.append( sal_Int32( nMinute));
449     rBuffer.append( ':');
450     if (nSecond < 10)
451         rBuffer.append( '0');
452     rBuffer.append( sal_Int32( nSecond));
453     if (!nFractionDecimals)
454         return;
455 
456     // nFractionDecimals+1 to not round up what GetClock() carefully
457     // truncated.
458     OUString aFraction( ::rtl::math::doubleToUString( fFractionOfSecond,
459                 rtl_math_StringFormat_F,
460                 nFractionDecimals + 1, '.', true));
461     const sal_Int32 nLen = aFraction.getLength();
462     if ( nLen > 2 )
463     {
464         // Truncate nFractionDecimals+1 digit if it was not rounded to zero.
465         const sal_Int32 nCount = nLen - 2 - static_cast<int>(nLen > nFractionDecimals + 2);
466         rBuffer.append( '.');
467         rBuffer.append( aFraction.subView(2, nCount));     // strip 0.
468     }
469 }
470 
471 /** convert ISO Date Time String to double */
472 template<typename V>
lcl_convertDateTime(double & fDateTime,V rString,const css::util::Date & aTempNullDate)473 static bool lcl_convertDateTime( double& fDateTime,
474                             V rString, const css::util::Date& aTempNullDate)
475 {
476     css::util::DateTime aDateTime;
477     bool bSuccess = ::sax::Converter::parseDateTime(aDateTime, rString);
478 
479     if (bSuccess)
480     {
481         const Date aTmpNullDate(aTempNullDate.Day, aTempNullDate.Month, aTempNullDate.Year);
482         const Date aTempDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
483         const sal_Int32 nTage = aTempDate - aTmpNullDate;
484         double fTempDateTime = nTage;
485         double Hour = aDateTime.Hours;
486         double Min = aDateTime.Minutes;
487         double Sec = aDateTime.Seconds;
488         double NanoSec = aDateTime.NanoSeconds;
489         fTempDateTime += Hour    / ::tools::Time::hourPerDay;
490         fTempDateTime += Min     / ::tools::Time::minutePerDay;
491         fTempDateTime += Sec     / ::tools::Time::secondPerDay;
492         fTempDateTime += NanoSec / ::tools::Time::nanoSecPerDay;
493         fDateTime = fTempDateTime;
494     }
495     return bSuccess;
496 }
497 
convertDateTime(double & fDateTime,std::u16string_view rString,const css::util::Date & aTempNullDate)498 bool SvXMLUnitConverter::convertDateTime( double& fDateTime,
499                             std::u16string_view rString, const css::util::Date& aTempNullDate)
500 {
501     return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
502 }
503 /** convert ISO Date Time String to double */
convertDateTime(double & fDateTime,std::string_view rString,const css::util::Date & aTempNullDate)504 bool SvXMLUnitConverter::convertDateTime( double& fDateTime,
505                             std::string_view rString, const css::util::Date& aTempNullDate)
506 {
507     return lcl_convertDateTime(fDateTime, rString, aTempNullDate);
508 }
509 
510 
SvXMLTokenEnumerator(std::u16string_view rString,sal_Unicode cSeparator)511 SvXMLTokenEnumerator::SvXMLTokenEnumerator( std::u16string_view rString, sal_Unicode cSeparator /* = ' ' */ )
512 : maTokenString( rString ), mnNextTokenPos(0), mcSeparator( cSeparator )
513 {
514 }
515 
getNextToken(std::u16string_view & rToken)516 bool SvXMLTokenEnumerator::getNextToken( std::u16string_view& rToken )
517 {
518     if( std::u16string_view::npos == mnNextTokenPos )
519         return false;
520 
521     size_t nTokenEndPos = maTokenString.find( mcSeparator, mnNextTokenPos );
522     if( nTokenEndPos != std::u16string_view::npos )
523     {
524         rToken = maTokenString.substr( mnNextTokenPos,
525                                      nTokenEndPos - mnNextTokenPos );
526         mnNextTokenPos = nTokenEndPos + 1;
527 
528         // if the mnNextTokenPos is at the end of the string, we have
529         // to deliver an empty token
530         if( mnNextTokenPos > maTokenString.size() )
531             mnNextTokenPos = std::u16string_view::npos;
532     }
533     else
534     {
535         rToken = maTokenString.substr( mnNextTokenPos );
536         mnNextTokenPos = std::u16string_view::npos;
537     }
538 
539     return true;
540 }
541 
lcl_getPositions(std::u16string_view _sValue,OUString & _rContentX,OUString & _rContentY,OUString & _rContentZ)542 static bool lcl_getPositions(std::u16string_view _sValue, OUString& _rContentX, OUString& _rContentY, OUString& _rContentZ)
543 {
544     if(_sValue.empty() || _sValue[0] != '(')
545         return false;
546 
547     size_t nPos(1);
548     size_t nFound = _sValue.find(' ', nPos);
549 
550     if(nFound == std::u16string_view::npos || nFound <= nPos)
551         return false;
552 
553     _rContentX = _sValue.substr(nPos, nFound - nPos);
554 
555     nPos = nFound + 1;
556     nFound = _sValue.find(' ', nPos);
557 
558     if(nFound == std::u16string_view::npos || nFound <= nPos)
559         return false;
560 
561     _rContentY = _sValue.substr(nPos, nFound - nPos);
562 
563     nPos = nFound + 1;
564     nFound = _sValue.find(')', nPos);
565 
566     if(nFound == std::u16string_view::npos || nFound <= nPos)
567         return false;
568 
569     _rContentZ = _sValue.substr(nPos, nFound - nPos);
570     return true;
571 }
572 
lcl_getPositions(std::string_view _sValue,OUString & _rContentX,OUString & _rContentY,OUString & _rContentZ)573 static bool lcl_getPositions(std::string_view _sValue,OUString& _rContentX,OUString& _rContentY,OUString& _rContentZ)
574 {
575     if(_sValue.empty() || _sValue[0] != '(')
576         return false;
577 
578     size_t nPos(1);
579     size_t nFound = _sValue.find(' ', nPos);
580 
581     if(nFound == std::string_view::npos || nFound <= nPos)
582         return false;
583 
584     _rContentX = OUString::fromUtf8(_sValue.substr(nPos, nFound - nPos));
585 
586     nPos = nFound + 1;
587     nFound = _sValue.find(' ', nPos);
588 
589     if(nFound == std::string_view::npos || nFound <= nPos)
590         return false;
591 
592     _rContentY = OUString::fromUtf8(_sValue.substr(nPos, nFound - nPos));
593 
594     nPos = nFound + 1;
595     nFound = _sValue.find(')', nPos);
596 
597     if(nFound == std::string_view::npos || nFound <= nPos)
598         return false;
599 
600     _rContentZ = OUString::fromUtf8(_sValue.substr(nPos, nFound - nPos));
601     return true;
602 
603 }
604 
605 /** convert string to ::basegfx::B3DVector */
convertB3DVector(::basegfx::B3DVector & rVector,std::u16string_view rValue)606 bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector& rVector, std::u16string_view rValue )
607 {
608     OUString aContentX,aContentY,aContentZ;
609     if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
610         return false;
611 
612     rtl_math_ConversionStatus eStatus;
613 
614     rVector.setX(::rtl::math::stringToDouble(aContentX, '.',
615             ',', &eStatus));
616 
617     if( eStatus != rtl_math_ConversionStatus_Ok )
618         return false;
619 
620     rVector.setY(::rtl::math::stringToDouble(aContentY, '.',
621             ',', &eStatus));
622 
623     if( eStatus != rtl_math_ConversionStatus_Ok )
624         return false;
625 
626     rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.',
627             ',', &eStatus));
628 
629 
630     return ( eStatus == rtl_math_ConversionStatus_Ok );
631 }
632 
633 /** convert string to ::basegfx::B3DVector */
convertB3DVector(::basegfx::B3DVector & rVector,std::string_view rValue)634 bool SvXMLUnitConverter::convertB3DVector( ::basegfx::B3DVector& rVector, std::string_view rValue )
635 {
636     OUString aContentX,aContentY,aContentZ;
637     if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
638         return false;
639 
640     rtl_math_ConversionStatus eStatus;
641 
642     rVector.setX(::rtl::math::stringToDouble(aContentX, '.',
643             ',', &eStatus));
644 
645     if( eStatus != rtl_math_ConversionStatus_Ok )
646         return false;
647 
648     rVector.setY(::rtl::math::stringToDouble(aContentY, '.',
649             ',', &eStatus));
650 
651     if( eStatus != rtl_math_ConversionStatus_Ok )
652         return false;
653 
654     rVector.setZ(::rtl::math::stringToDouble(aContentZ, '.',
655             ',', &eStatus));
656 
657 
658     return ( eStatus == rtl_math_ConversionStatus_Ok );
659 }
660 
661 /** convert ::basegfx::B3DVector to string */
convertB3DVector(OUStringBuffer & rBuffer,const::basegfx::B3DVector & rVector)662 void SvXMLUnitConverter::convertB3DVector( OUStringBuffer &rBuffer, const ::basegfx::B3DVector& rVector )
663 {
664     rBuffer.append('(');
665     ::sax::Converter::convertDouble(rBuffer, rVector.getX());
666     rBuffer.append(' ');
667     ::sax::Converter::convertDouble(rBuffer, rVector.getY());
668     rBuffer.append(' ');
669     ::sax::Converter::convertDouble(rBuffer, rVector.getZ());
670     rBuffer.append(')');
671 }
672 
673 /** convert string to Position3D */
convertPosition3D(drawing::Position3D & rPosition,std::string_view rValue)674 bool SvXMLUnitConverter::convertPosition3D( drawing::Position3D& rPosition,
675     std::string_view rValue )
676 {
677     OUString aContentX,aContentY,aContentZ;
678     if ( !lcl_getPositions(rValue,aContentX,aContentY,aContentZ) )
679         return false;
680 
681     if ( !convertDouble( rPosition.PositionX, aContentX ) )
682         return false;
683     if ( !convertDouble( rPosition.PositionY, aContentY ) )
684         return false;
685     return convertDouble( rPosition.PositionZ, aContentZ );
686 }
687 
688 /** convert Position3D to string */
convertPosition3D(OUStringBuffer & rBuffer,const drawing::Position3D & rPosition)689 void SvXMLUnitConverter::convertPosition3D( OUStringBuffer &rBuffer,
690                                            const drawing::Position3D& rPosition )
691 {
692     rBuffer.append( '(' );
693     convertDouble( rBuffer, rPosition.PositionX );
694     rBuffer.append( ' ' );
695     convertDouble( rBuffer, rPosition.PositionY );
696     rBuffer.append( ' ' );
697     convertDouble( rBuffer, rPosition.PositionZ );
698     rBuffer.append( ')' );
699 }
700 
convertNumFormat(sal_Int16 & rType,const OUString & rNumFmt,std::u16string_view rNumLetterSync,bool bNumberNone) const701 bool SvXMLUnitConverter::convertNumFormat(
702         sal_Int16& rType,
703         const OUString& rNumFmt,
704         std::u16string_view rNumLetterSync,
705         bool bNumberNone ) const
706 {
707     bool bRet = true;
708     bool bExt = false;
709 
710     sal_Int32 nLen = rNumFmt.getLength();
711     if( 0 == nLen )
712     {
713         if( bNumberNone )
714             rType = NumberingType::NUMBER_NONE;
715         else
716             bRet = false;
717     }
718     else if( 1 == nLen )
719     {
720         switch( rNumFmt[0] )
721         {
722         case '1':  rType = NumberingType::ARABIC;          break;
723         case 'a':  rType = NumberingType::CHARS_LOWER_LETTER;  break;
724         case 'A':  rType = NumberingType::CHARS_UPPER_LETTER;  break;
725         case 'i':  rType = NumberingType::ROMAN_LOWER; break;
726         case 'I':  rType = NumberingType::ROMAN_UPPER; break;
727         default:                bExt = true; break;
728         }
729         if( !bExt && IsXMLToken( rNumLetterSync, XML_TRUE ) )
730         {
731             switch( rType )
732             {
733             case NumberingType::CHARS_LOWER_LETTER:
734                 rType = NumberingType::CHARS_LOWER_LETTER_N;
735                 break;
736             case NumberingType::CHARS_UPPER_LETTER:
737                 rType = NumberingType::CHARS_UPPER_LETTER_N;
738                 break;
739             }
740         }
741     }
742     else
743     {
744         bExt = true;
745     }
746     if( bExt )
747     {
748         Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
749         if( xInfo.is() && xInfo->hasNumberingType( rNumFmt ) )
750         {
751             rType = xInfo->getNumberingType( rNumFmt );
752         }
753         else
754         {
755             rType = NumberingType::ARABIC;
756         }
757     }
758 
759     return bRet;
760 }
761 
convertNumFormat(OUStringBuffer & rBuffer,sal_Int16 nType) const762 void SvXMLUnitConverter::convertNumFormat( OUStringBuffer& rBuffer,
763                            sal_Int16 nType ) const
764 {
765     enum XMLTokenEnum eFormat = XML_TOKEN_INVALID;
766     switch( nType )
767     {
768     case NumberingType::CHARS_UPPER_LETTER:     eFormat = XML_A_UPCASE; break;
769     case NumberingType::CHARS_LOWER_LETTER:     eFormat = XML_A; break;
770     case NumberingType::ROMAN_UPPER:            eFormat = XML_I_UPCASE; break;
771     case NumberingType::ROMAN_LOWER:            eFormat = XML_I; break;
772     case NumberingType::ARABIC:                 eFormat = XML_1; break;
773     case NumberingType::CHARS_UPPER_LETTER_N:   eFormat = XML_A_UPCASE; break;
774     case NumberingType::CHARS_LOWER_LETTER_N:   eFormat = XML_A; break;
775     case NumberingType::NUMBER_NONE:            eFormat = XML__EMPTY; break;
776 
777     case NumberingType::CHAR_SPECIAL:
778     case NumberingType::PAGE_DESCRIPTOR:
779     case NumberingType::BITMAP:
780         SAL_WARN_IF( eFormat == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
781         break;
782     default:
783         break;
784     }
785 
786     if( eFormat != XML_TOKEN_INVALID )
787     {
788         rBuffer.append( GetXMLToken(eFormat) );
789     }
790     else
791     {
792         Reference < XNumberingTypeInfo > xInfo = getNumTypeInfo();
793         if( xInfo.is() )
794             rBuffer.append( xInfo->getNumberingIdentifier( nType ) );
795     }
796 }
797 
convertNumLetterSync(OUStringBuffer & rBuffer,sal_Int16 nType)798 void SvXMLUnitConverter::convertNumLetterSync( OUStringBuffer& rBuffer,
799                                sal_Int16 nType )
800 {
801     enum XMLTokenEnum eSync = XML_TOKEN_INVALID;
802     switch( nType )
803     {
804     case NumberingType::CHARS_UPPER_LETTER:
805     case NumberingType::CHARS_LOWER_LETTER:
806     case NumberingType::ROMAN_UPPER:
807     case NumberingType::ROMAN_LOWER:
808     case NumberingType::ARABIC:
809     case NumberingType::NUMBER_NONE:
810         break;
811 
812     case NumberingType::CHARS_UPPER_LETTER_N:
813     case NumberingType::CHARS_LOWER_LETTER_N:
814         eSync = XML_TRUE;
815         break;
816 
817     case NumberingType::CHAR_SPECIAL:
818     case NumberingType::PAGE_DESCRIPTOR:
819     case NumberingType::BITMAP:
820         SAL_WARN_IF( eSync == XML_TOKEN_INVALID, "xmloff", "invalid number format" );
821         break;
822     }
823     if( eSync != XML_TOKEN_INVALID )
824         rBuffer.append( GetXMLToken(eSync) );
825 }
826 
convertPropertySet(uno::Sequence<beans::PropertyValue> & rProps,const uno::Reference<beans::XPropertySet> & aProperties)827 void SvXMLUnitConverter::convertPropertySet(uno::Sequence<beans::PropertyValue>& rProps,
828                     const uno::Reference<beans::XPropertySet>& aProperties)
829 {
830     uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = aProperties->getPropertySetInfo();
831     if (!xPropertySetInfo.is())
832         return;
833 
834     const uno::Sequence< beans::Property > aProps = xPropertySetInfo->getProperties();
835     if (aProps.hasElements())
836     {
837         rProps.realloc(aProps.getLength());
838         beans::PropertyValue* pProps = rProps.getArray();
839         for (const auto& rProp : aProps)
840         {
841             pProps->Name = rProp.Name;
842             pProps->Value = aProperties->getPropertyValue(rProp.Name);
843             ++pProps;
844         }
845     }
846 }
847 
convertPropertySet(uno::Reference<beans::XPropertySet> const & rProperties,const uno::Sequence<beans::PropertyValue> & aProps)848 void SvXMLUnitConverter::convertPropertySet(uno::Reference<beans::XPropertySet> const & rProperties,
849                     const uno::Sequence<beans::PropertyValue>& aProps)
850 {
851     if (aProps.hasElements())
852     {
853         uno::Reference< beans::XPropertySetInfo > xPropertySetInfo = rProperties->getPropertySetInfo();
854         if (xPropertySetInfo.is())
855         {
856             for (const auto& rProp : aProps)
857             {
858                 if (xPropertySetInfo->hasPropertyByName(rProp.Name))
859                     rProperties->setPropertyValue(rProp.Name, rProp.Value);
860             }
861         }
862     }
863 }
864 
865 
encodeStyleName(const OUString & rName,bool * pEncoded) const866 OUString SvXMLUnitConverter::encodeStyleName(
867         const OUString& rName,
868         bool *pEncoded ) const
869 {
870     if( pEncoded )
871         *pEncoded = false;
872 
873     sal_Int32 nLen = rName.getLength();
874     OUStringBuffer aBuffer( nLen*2 );
875 
876     for( sal_Int32 i = 0; i < nLen; i++ )
877     {
878         sal_Unicode c = rName[i];
879         bool bValidChar = false;
880         if( c < 0x00ffU )
881         {
882             bValidChar =
883                 (c >= 0x0041 && c <= 0x005a) ||
884                 (c >= 0x0061 && c <= 0x007a) ||
885                 (c >= 0x00c0 && c <= 0x00d6) ||
886                 (c >= 0x00d8 && c <= 0x00f6) ||
887                 (c >= 0x00f8 && c <= 0x00ff) ||
888                 ( i > 0 && ( (c >= 0x0030 && c <= 0x0039) ||
889                              c == 0x00b7 || c == '-' || c == '.') );
890         }
891         else
892         {
893             if( (c >= 0xf900U && c <= 0xfffeU) ||
894                  (c >= 0x20ddU && c <= 0x20e0U))
895             {
896                 bValidChar = false;
897             }
898             else if( (c >= 0x02bbU && c <= 0x02c1U) || c == 0x0559 ||
899                      c == 0x06e5 || c == 0x06e6 )
900             {
901                 bValidChar = true;
902             }
903             else if( c == 0x0387 )
904             {
905                 bValidChar = i > 0;
906             }
907             else
908             {
909                 if (!m_pImpl->m_xCharClass.is())
910                 {
911                     m_pImpl->m_xCharClass = CharacterClassification::create( m_pImpl->m_xContext );
912                 }
913                 sal_Int16 nType = m_pImpl->m_xCharClass->getType(rName, i);
914 
915                 switch( nType )
916                 {
917                 case UnicodeType::UPPERCASE_LETTER:     // Lu
918                 case UnicodeType::LOWERCASE_LETTER:     // Ll
919                 case UnicodeType::TITLECASE_LETTER:     // Lt
920                 case UnicodeType::OTHER_LETTER:         // Lo
921                 case UnicodeType::LETTER_NUMBER:        // Nl
922                     bValidChar = true;
923                     break;
924                 case UnicodeType::NON_SPACING_MARK:     // Ms
925                 case UnicodeType::ENCLOSING_MARK:       // Me
926                 case UnicodeType::COMBINING_SPACING_MARK:   //Mc
927                 case UnicodeType::MODIFIER_LETTER:      // Lm
928                 case UnicodeType::DECIMAL_DIGIT_NUMBER: // Nd
929                     bValidChar = i > 0;
930                     break;
931                 }
932             }
933         }
934         if( bValidChar )
935         {
936             aBuffer.append( c );
937         }
938         else
939         {
940             aBuffer.append( '_' );
941             if( c > 0x0fff )
942                 aBuffer.append( static_cast< sal_Unicode >(
943                             aHexTab[ (c >> 12) & 0x0f ]  ) );
944             if( c > 0x00ff )
945                 aBuffer.append( static_cast< sal_Unicode >(
946                         aHexTab[ (c >> 8) & 0x0f ] ) );
947             if( c > 0x000f )
948                 aBuffer.append( static_cast< sal_Unicode >(
949                         aHexTab[ (c >> 4) & 0x0f ] ) );
950             aBuffer.append( static_cast< sal_Unicode >(
951                         aHexTab[ c & 0x0f ] ) );
952             aBuffer.append( '_' );
953             if( pEncoded )
954                 *pEncoded = true;
955         }
956     }
957 
958     // check for length
959     if( aBuffer.getLength() > ((1<<15)-1) )
960     {
961         aBuffer = rName;
962         if( pEncoded )
963             *pEncoded = false;
964     }
965 
966 
967     return aBuffer.makeStringAndClear();
968 }
969 
970 /** convert string (hex) to number (sal_uInt32) */
convertHex(sal_uInt32 & nVal,std::u16string_view rValue)971 bool SvXMLUnitConverter::convertHex( sal_uInt32& nVal, std::u16string_view rValue )
972 {
973     if( rValue.size() != 8 )
974         return false;
975 
976     nVal = 0;
977     for ( int i = 0; i < 8; i++ )
978     {
979         nVal = ( nVal << 4 )
980             | sal::static_int_cast< sal_uInt32 >( lcl_gethex( rValue[i] ) );
981     }
982 
983     return true;
984 }
985 
986 /** convert number (sal_uInt32) to string (hex) */
convertHex(OUStringBuffer & rBuffer,sal_uInt32 nVal)987 void SvXMLUnitConverter::convertHex( OUStringBuffer& rBuffer,
988                                         sal_uInt32 nVal )
989 {
990     for ( int i = 0; i < 8; i++ )
991     {
992         rBuffer.append( sal_Unicode( aHexTab[ nVal >> 28 ] ) );
993         nVal <<= 4;
994     }
995 }
996 
997 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
998