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