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