LibreOffice Module xmloff (master)  1
xmluconv.cxx
Go to the documentation of this file.
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>
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 
63 #define XML_NULLDATE "NullDate"
64 
66 {
67  sal_Int16 m_eCoreMeasureUnit; /*css::util::MeasureUnit*/
68  sal_Int16 m_eXMLMeasureUnit; /*css::util::MeasureUnit*/
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 
75  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 
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 >&
100 {
101  if (!m_pImpl->m_xNumTypeInfo.is())
102  {
103  m_pImpl->createNumTypeInfo();
104  }
105  return m_pImpl->m_xNumTypeInfo;
106 }
107 
108 void SvXMLUnitConverter::SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit/*css::util::MeasureUnit*/)
109 {
110  m_pImpl->m_eCoreMeasureUnit = eCoreMeasureUnit;
111 }
112 
113 void SvXMLUnitConverter::SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit/*css::util::MeasureUnit*/)
114 {
115  m_pImpl->m_eXMLMeasureUnit = eXMLMeasureUnit;
116 }
117 
119 {
120  return m_pImpl->m_eXMLMeasureUnit;
121 }
122 
124 {
125  return m_pImpl->m_eODFVersion;
126 }
127 
129  SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
130 {
131  m_pImpl->m_eODFVersion = nODFVersion;
132 }
133 
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 
149 {
150 }
151 
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 
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 
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 
206 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 
215 OUString SvXMLUnitConverter::convertMeasureToXML( sal_Int32 nMeasure ) const
216 {
217  OUStringBuffer s;
219  m_pImpl->m_eCoreMeasureUnit,
220  m_pImpl->m_eXMLMeasureUnit );
221  return s.makeStringAndClear();
222 }
223 
227 bool SvXMLUnitConverter::convertEnumImpl( sal_uInt16& rEnum,
228  std::u16string_view rValue,
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 
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 
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 
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 
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 
333 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 
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 
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 
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 
371 bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
372  std::u16string_view rString)
373 {
374  return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
375 }
376 
378 bool SvXMLUnitConverter::convertDateTime(double& fDateTime,
379  std::string_view rString)
380 {
381  return convertDateTime(fDateTime, rString, m_pImpl->m_aNullDate);
382 }
383 
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 
472 template<typename V>
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 
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 }
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 
511 SvXMLTokenEnumerator::SvXMLTokenEnumerator( std::u16string_view rString, sal_Unicode cSeparator /* = ' ' */ )
512 : maTokenString( rString ), mnNextTokenPos(0), mcSeparator( cSeparator )
513 {
514 }
515 
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 
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 
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 
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 
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 
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 
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 
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 
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  {
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 
762 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  {
793  if( xInfo.is() )
794  rBuffer.append( xInfo->getNumberingIdentifier( nType ) );
795  }
796 }
797 
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 
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 
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 
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 
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 
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: */
SvtSaveOptions::ODFSaneDefaultVersion m_eODFVersion
Definition: xmluconv.cxx:69
static const sal_Int64 hourPerDay
FieldUnit
bool convertMeasureToCore(sal_Int32 &rValue, std::u16string_view rString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32) const
convert string to measure with meCoreMeasureUnit, using optional min and max values ...
Definition: xmluconv.cxx:186
void convertDouble(OUStringBuffer &rBuffer, double fNumber) const
convert double number to string (using ::rtl::math) and DO convert to export MapUnit using meCoreMeas...
Definition: xmluconv.cxx:333
sal_Int16 GetXMLMeasureUnit() const
gets the default unit for textual measures
Definition: xmluconv.cxx:118
const char aHexTab[]
Definition: xmluconv.cxx:329
#define XML_NULLDATE
Definition: xmluconv.cxx:63
signed char sal_Int8
static int lcl_gethex(int nChar)
Definition: xmluconv.cxx:317
std::u16string_view maTokenString
Definition: xmluconv.hxx:59
static bool convertB3DVector(::basegfx::B3DVector &rVector, std::u16string_view rValue)
convert string to basegfx::B3DVector
Definition: xmluconv.cxx:606
sal_Unicode mcSeparator
Definition: xmluconv.hxx:61
static const sal_Int64 minutePerDay
void SetXMLMeasureUnit(sal_Int16 const eXMLMeasureUnit)
sets the default unit for textual measures
Definition: xmluconv.cxx:113
bool IsXMLToken(std::u16string_view rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3485
static bool parseDateTime(css::util::DateTime &rDateTime, std::u16string_view rString)
uno::Reference< text::XNumberingTypeInfo > m_xNumTypeInfo
Definition: xmluconv.cxx:71
sal_Int16 m_eCoreMeasureUnit
Definition: xmluconv.cxx:67
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
sal_uInt16 sal_Unicode
void SetCoreMeasureUnit(sal_Int16 const eCoreMeasureUnit)
sets the default unit for numerical measures
Definition: xmluconv.cxx:108
int nCount
Impl(uno::Reference< uno::XComponentContext > const &xContext, sal_Int16 const eCoreMeasureUnit, sal_Int16 const eXMLMeasureUnit, SvtSaveOptions::ODFSaneDefaultVersion const nODFVersion)
Definition: xmluconv.cxx:75
void setZ(double fZ)
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:49
bool convertNumFormat(sal_Int16 &rType, const OUString &rNumFormat, std::u16string_view rNumLetterSync, bool bNumberNone=false) const
convert num-format and num-letter-sync values to NumberingType
Definition: xmluconv.cxx:701
SvXMLTokenEnumerator(std::u16string_view rString, sal_Unicode cSeparator=u' ')
Definition: xmluconv.cxx:511
Map a const char* (with length) to a sal_uInt16 value.
Definition: xmlement.hxx:70
int i
uno::Reference< uno::XComponentContext > m_xContext
Definition: xmluconv.cxx:73
void setY(double fY)
const char * GetName() const
Definition: xmlement.hxx:79
bool getNextToken(std::u16string_view &rToken)
Definition: xmluconv.cxx:516
static bool convertMeasure(sal_Int32 &rValue, std::u16string_view rString, sal_Int16 nTargetUnit=css::util::MeasureUnit::MM_100TH, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
void convertDateTime(OUStringBuffer &rBuffer, const double &fDateTime, bool const bAddTimeIf0AM=false)
convert double to ISO Date Time String
Definition: xmluconv.cxx:364
sal_Int16 m_eXMLMeasureUnit
Definition: xmluconv.cxx:68
bool setNullDate(const css::uno::Reference< css::frame::XModel > &xModel)
get the Null Date of the XModel and set it to the UnitConverter
Definition: xmluconv.cxx:352
const uno::Reference< uno::XComponentContext > m_xContext
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
ODF version, only when exporting.
Definition: xmluconv.cxx:123
bool convertPosition3D(css::drawing::Position3D &rPosition, std::string_view rValue)
convert string to Position3D
static bool lcl_convertDateTime(double &fDateTime, V rString, const css::util::Date &aTempNullDate)
convert ISO Date Time String to double
Definition: xmluconv.cxx:473
static void convertNumLetterSync(OUStringBuffer &rBuffer, sal_Int16 nType)
Definition: xmluconv.cxx:798
std::unique_ptr< char[]> aBuffer
static sal_Int16 GetMeasureUnit(FieldUnit const nFieldUnit)
Definition: xmluconv.cxx:152
static void GetClock(double fTimeInDays, sal_uInt16 &nHour, sal_uInt16 &nMinute, sal_uInt16 &nSecond, double &fFractionOfSecond, int nFractionDecimals)
static bool lcl_getPositions(std::u16string_view _sValue, OUString &_rContentX, OUString &_rContentY, OUString &_rContentZ)
Definition: xmluconv.cxx:542
#define SAL_WARN_IF(condition, area, stream)
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3429
const sal_Int8 XML_MAXDIGITSCOUNT_TIME
Definition: xmluconv.cxx:62
static bool convertEnumImpl(sal_uInt16 &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< sal_uInt16 > *pMap)
convert string to enum using given token map, if the enum is not found in the map, this method will return false
Definition: xmluconv.cxx:249
Handling of tokens in XML:
static sal_Int16 GetUnitFromString(std::u16string_view rString, sal_Int16 nDefaultUnit)
uno::Reference< i18n::XCharacterClassification > m_xCharClass
Definition: xmluconv.cxx:72
QPRO_FUNC_TYPE nType
EnumT GetValue() const
Definition: xmlement.hxx:81
static void convertPropertySet(css::uno::Sequence< css::beans::PropertyValue > &rProps, const css::uno::Reference< css::beans::XPropertySet > &aProperties)
void setX(double fX)
OUString encodeStyleName(const OUString &rName, bool *pEncoded=nullptr) const
Definition: xmluconv.cxx:866
sal_Int32 GetNameLength() const
Definition: xmlement.hxx:80
static const sal_Int64 nanoSecPerDay
const css::uno::Reference< css::text::XNumberingTypeInfo > & getNumTypeInfo() const
gets XNumberingTypeInfo
Definition: xmluconv.cxx:99
::std::unique_ptr< XmlIdRegistry_Impl > m_pImpl
SvXMLUnitConverter(const SvXMLUnitConverter &)=delete
void convertMeasureToXML(OUStringBuffer &rBuffer, sal_Int32 nMeasure) const
convert measure to string: from meCoreMeasureUnit to meXMLMeasureUnit
Definition: xmluconv.cxx:206
sal_uInt16 nPos
void overrideSaneDefaultVersion(SvtSaveOptions::ODFSaneDefaultVersion const)
Definition: xmluconv.cxx:128
static bool convertHex(sal_uInt32 &nVal, std::u16string_view rValue)
convert string (hex) to number (sal_uInt32)
Definition: xmluconv.cxx:971
void createNumTypeInfo() const
Definition: xmluconv.cxx:92
::std::unique_ptr< Impl > m_pImpl
Definition: xmluconv.hxx:89
static const sal_Int64 secondPerDay