LibreOffice Module xmloff (master)  1
xmlnumfe.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 <comphelper/sequence.hxx>
21 #include <comphelper/string.hxx>
22 #include <svl/zforlist.hxx>
23 #include <svl/zformat.hxx>
24 #include <svl/numuno.hxx>
25 #include <i18nlangtag/mslangid.hxx>
27 #include <tools/debug.hxx>
28 #include <rtl/math.hxx>
30 #include <unotools/charclass.hxx>
31 #include <com/sun/star/lang/Locale.hpp>
32 #include <rtl/ustrbuf.hxx>
33 #include <sal/log.hxx>
34 #include <osl/diagnose.h>
35 #include <tools/color.hxx>
36 #include <sax/tools/converter.hxx>
37 
38 #include <com/sun/star/i18n/NativeNumberXmlAttributes2.hpp>
39 
40 #include <xmloff/xmlnumfe.hxx>
41 #include <xmloff/xmlnamespace.hxx>
42 #include <xmloff/xmlnumfi.hxx>
43 
44 #include <svl/nfsymbol.hxx>
45 #include <xmloff/xmltoken.hxx>
46 #include <xmloff/xmlexp.hxx>
47 
48 #include <float.h>
49 #include <set>
50 #include <string_view>
51 #include <vector>
52 
53 using namespace ::com::sun::star;
54 using namespace ::xmloff::token;
55 using namespace ::svt;
56 
57 typedef std::set< sal_uInt32 > SvXMLuInt32Set;
58 
59 namespace {
60 
61 struct SvXMLEmbeddedTextEntry
62 {
63  sal_uInt16 nSourcePos; // position in NumberFormat (to skip later)
64  sal_Int32 nFormatPos; // resulting position in embedded-text element
65  OUString aText;
66 
67  SvXMLEmbeddedTextEntry( sal_uInt16 nSP, sal_Int32 nFP, const OUString& rT ) :
68  nSourcePos(nSP), nFormatPos(nFP), aText(rT) {}
69 };
70 
71 }
72 
74 {
75  typedef std::vector<SvXMLEmbeddedTextEntry> DataType;
76  DataType maData;
77 
78 public:
79 
80  void push_back( SvXMLEmbeddedTextEntry const& r )
81  {
82  maData.push_back(r);
83  }
84 
85  const SvXMLEmbeddedTextEntry& operator[] ( size_t i ) const
86  {
87  return maData[i];
88  }
89 
90  size_t size() const
91  {
92  return maData.size();
93  }
94 };
95 
97 {
100  SvXMLuInt32Set::iterator aCurrentUsedPos;
101  sal_uInt32 nUsedCount;
102  sal_uInt32 nWasUsedCount;
103 
104 public:
106 
107  void SetUsed( sal_uInt32 nKey );
108  bool IsUsed( sal_uInt32 nKey ) const;
109  bool IsWasUsed( sal_uInt32 nKey ) const;
110  void Export();
111 
112  bool GetFirstUsed(sal_uInt32& nKey);
113  bool GetNextUsed(sal_uInt32& nKey);
114 
115  uno::Sequence<sal_Int32> GetWasUsed() const;
116  void SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed);
117 };
118 
120 
122  nUsedCount(0),
123  nWasUsedCount(0)
124 {
125 }
126 
127 void SvXMLNumUsedList_Impl::SetUsed( sal_uInt32 nKey )
128 {
129  if ( !IsWasUsed(nKey) )
130  {
131  std::pair<SvXMLuInt32Set::iterator, bool> aPair = aUsed.insert( nKey );
132  if (aPair.second)
133  nUsedCount++;
134  }
135 }
136 
137 bool SvXMLNumUsedList_Impl::IsUsed( sal_uInt32 nKey ) const
138 {
139  SvXMLuInt32Set::const_iterator aItr = aUsed.find(nKey);
140  return (aItr != aUsed.end());
141 }
142 
143 bool SvXMLNumUsedList_Impl::IsWasUsed( sal_uInt32 nKey ) const
144 {
145  SvXMLuInt32Set::const_iterator aItr = aWasUsed.find(nKey);
146  return (aItr != aWasUsed.end());
147 }
148 
150 {
151  SvXMLuInt32Set::const_iterator aItr = aUsed.begin();
152  while (aItr != aUsed.end())
153  {
154  std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( *aItr );
155  if (aPair.second)
156  nWasUsedCount++;
157  ++aItr;
158  }
159  aUsed.clear();
160  nUsedCount = 0;
161 }
162 
164 {
165  bool bRet(false);
166  aCurrentUsedPos = aUsed.begin();
167  if(nUsedCount)
168  {
169  DBG_ASSERT(aCurrentUsedPos != aUsed.end(), "something went wrong");
170  nKey = *aCurrentUsedPos;
171  bRet = true;
172  }
173  return bRet;
174 }
175 
177 {
178  bool bRet(false);
179  if (aCurrentUsedPos != aUsed.end())
180  {
181  ++aCurrentUsedPos;
182  if (aCurrentUsedPos != aUsed.end())
183  {
184  nKey = *aCurrentUsedPos;
185  bRet = true;
186  }
187  }
188  return bRet;
189 }
190 
191 uno::Sequence<sal_Int32> SvXMLNumUsedList_Impl::GetWasUsed() const
192 {
193  return comphelper::containerToSequence<sal_Int32>(aWasUsed);
194 }
195 
196 void SvXMLNumUsedList_Impl::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
197 {
198  DBG_ASSERT(nWasUsedCount == 0, "WasUsed should be empty");
199  for (const auto nWasUsed : rWasUsed)
200  {
201  std::pair<SvXMLuInt32Set::const_iterator, bool> aPair = aWasUsed.insert( nWasUsed );
202  if (aPair.second)
203  nWasUsedCount++;
204  }
205 }
206 
208  SvXMLExport& rExp,
209  const uno::Reference< util::XNumberFormatsSupplier >& rSupp ) :
210  rExport( rExp ),
211  sPrefix( OUString("N") ),
212  pFormatter( nullptr )
213 {
214  // supplier must be SvNumberFormatsSupplierObj
216  comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>( rSupp );
217  if (pObj)
218  pFormatter = pObj->GetNumberFormatter();
219 
220  if ( pFormatter )
221  {
222  pCharClass.reset( new CharClass( pFormatter->GetComponentContext(),
223  pFormatter->GetLanguageTag() ) );
224  pLocaleData.reset( new LocaleDataWrapper( pFormatter->GetComponentContext(),
225  pFormatter->GetLanguageTag() ) );
226  }
227  else
228  {
229  LanguageTag aLanguageTag( MsLangId::getSystemLanguage() );
230 
231  pCharClass.reset( new CharClass( rExport.getComponentContext(), aLanguageTag ) );
232  pLocaleData.reset( new LocaleDataWrapper( rExport.getComponentContext(), aLanguageTag ) );
233  }
234 
235  pUsedList.reset(new SvXMLNumUsedList_Impl);
236 }
237 
239  SvXMLExport& rExp,
240  const css::uno::Reference< css::util::XNumberFormatsSupplier >& rSupp,
241  const OUString& rPrefix ) :
242  rExport( rExp ),
243  sPrefix( rPrefix ),
244  pFormatter( nullptr )
245 {
246  // supplier must be SvNumberFormatsSupplierObj
248  comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>( rSupp );
249  if (pObj)
250  pFormatter = pObj->GetNumberFormatter();
251 
252  if ( pFormatter )
253  {
255  pFormatter->GetLanguageTag() ) );
257  pFormatter->GetLanguageTag() ) );
258  }
259  else
260  {
261  LanguageTag aLanguageTag( MsLangId::getSystemLanguage() );
262 
263  pCharClass.reset( new CharClass( rExport.getComponentContext(), aLanguageTag ) );
264  pLocaleData.reset( new LocaleDataWrapper( rExport.getComponentContext(), aLanguageTag ) );
265  }
266 
267  pUsedList.reset(new SvXMLNumUsedList_Impl);
268 }
269 
271 {
272 }
273 
274 // helper methods
275 
276 static OUString lcl_CreateStyleName( sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, const OUString& rPrefix )
277 {
278  OUStringBuffer aFmtName(10);
279  aFmtName.append( rPrefix );
280  aFmtName.append( nKey );
281  if (!bDefPart)
282  {
283  aFmtName.append( 'P' );
284  aFmtName.append( nPart );
285  }
286  return aFmtName.makeStringAndClear();
287 }
288 
289 void SvXMLNumFmtExport::AddCalendarAttr_Impl( const OUString& rCalendar )
290 {
291  if ( !rCalendar.isEmpty() )
292  {
294  }
295 }
296 
298 {
299  if ( bLong ) // short is default
300  {
302  }
303 }
304 
306 {
307  if ( nLang != LANGUAGE_SYSTEM )
308  {
310  LanguageTag( nLang), false);
311  }
312 }
313 
314 // methods to write individual elements within a format
315 
316 void SvXMLNumFmtExport::AddToTextElement_Impl( const OUString& rString )
317 {
318  // append to sTextContent, write element in FinishTextElement_Impl
319  // to avoid several text elements following each other
320 
321  sTextContent.append( rString );
322 }
323 
325 {
326  if ( !sTextContent.isEmpty() )
327  {
328  sal_uInt16 nNS = bUseExtensionNS ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER;
329  SvXMLElementExport aElem( rExport, nNS, XML_TEXT,
330  true, false );
331  rExport.Characters( sTextContent.makeStringAndClear() );
332  }
333 }
334 
336 {
338 
339  OUStringBuffer aColStr( 7 );
340  ::sax::Converter::convertColor( aColStr, rColor );
342  aColStr.makeStringAndClear() );
343 
345  true, false );
346 }
347 
348 void SvXMLNumFmtExport::WriteCurrencyElement_Impl( const OUString& rString,
349  const OUString& rExt )
350 {
352 
353  if ( !rExt.isEmpty() )
354  {
355  // rExt should be a 16-bit hex value max FFFF which may contain a
356  // leading "-" separator (that is not a minus sign, but toInt32 can be
357  // used to parse it, with post-processing as necessary):
358  sal_Int32 nLang = rExt.toInt32(16);
359  if ( nLang < 0 )
360  nLang = -nLang;
361  AddLanguageAttr_Impl( LanguageType(nLang) ); // adds to pAttrList
362  }
363 
366  true, false );
367  rExport.Characters( rString );
368 }
369 
371 {
373 
375  true, false );
376 }
377 
379 {
381 
383  true, false );
384 }
385 
386 // date elements
387 
388 void SvXMLNumFmtExport::WriteDayElement_Impl( const OUString& rCalendar, bool bLong )
389 {
391 
392  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
393  AddStyleAttr_Impl( bLong ); // adds to pAttrList
394 
396  true, false );
397 }
398 
399 void SvXMLNumFmtExport::WriteMonthElement_Impl( const OUString& rCalendar, bool bLong, bool bText )
400 {
402 
403  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
404  AddStyleAttr_Impl( bLong ); // adds to pAttrList
405  if ( bText )
406  {
408  }
409 
411  true, false );
412 }
413 
414 void SvXMLNumFmtExport::WriteYearElement_Impl( const OUString& rCalendar, bool bLong )
415 {
417 
418  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
419  AddStyleAttr_Impl( bLong ); // adds to pAttrList
420 
422  true, false );
423 }
424 
425 void SvXMLNumFmtExport::WriteEraElement_Impl( const OUString& rCalendar, bool bLong )
426 {
428 
429  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
430  AddStyleAttr_Impl( bLong ); // adds to pAttrList
431 
433  true, false );
434 }
435 
436 void SvXMLNumFmtExport::WriteDayOfWeekElement_Impl( const OUString& rCalendar, bool bLong )
437 {
439 
440  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
441  AddStyleAttr_Impl( bLong ); // adds to pAttrList
442 
444  true, false );
445 }
446 
447 void SvXMLNumFmtExport::WriteWeekElement_Impl( const OUString& rCalendar )
448 {
450 
451  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
452 
454  true, false );
455 }
456 
457 void SvXMLNumFmtExport::WriteQuarterElement_Impl( const OUString& rCalendar, bool bLong )
458 {
460 
461  AddCalendarAttr_Impl( rCalendar ); // adds to pAttrList
462  AddStyleAttr_Impl( bLong ); // adds to pAttrList
463 
465  true, false );
466 }
467 
468 // time elements
469 
471 {
473 
474  AddStyleAttr_Impl( bLong ); // adds to pAttrList
475 
477  true, false );
478 }
479 
481 {
483 
484  AddStyleAttr_Impl( bLong ); // adds to pAttrList
485 
487  true, false );
488 }
489 
491 {
492  // Export only for 1.2 with extensions or 1.3 and later.
494  if (eVersion > SvtSaveOptions::ODFSVER_012)
495  {
497  // OFFICE-3765 For 1.2+ use loext namespace, for 1.3 use number namespace.
500  XML_FILL_CHARACTER, true, false );
501  rExport.Characters( OUString( nChar ) );
502  }
503 }
504 
505 void SvXMLNumFmtExport::WriteSecondsElement_Impl( bool bLong, sal_uInt16 nDecimals )
506 {
508 
509  AddStyleAttr_Impl( bLong ); // adds to pAttrList
510  if ( nDecimals > 0 )
511  {
513  OUString::number( nDecimals ) );
514  }
515 
517  true, false );
518 }
519 
521 {
523 
525  true, false );
526 }
527 
528 // numbers
529 
531  sal_Int32 nDecimals, sal_Int32 nMinDecimals,
532  sal_Int32 nInteger, const OUString& rDashStr,
533  bool bGrouping, sal_Int32 nTrailingThousands,
534  const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries )
535 {
537 
538  // decimals
539  if ( nDecimals >= 0 ) // negative = automatic
540  {
542  OUString::number( nDecimals ) );
543  }
544 
545  if ( nMinDecimals >= 0 ) // negative = automatic
546  {
547  // Export only for 1.2 with extensions or 1.3 and later.
549  if (eVersion > SvtSaveOptions::ODFSVER_012)
550  {
551  // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
555  OUString::number( nMinDecimals ) );
556  }
557  }
558 
559  // integer digits
560  if ( nInteger >= 0 ) // negative = automatic
561  {
563  OUString::number( nInteger ) );
564  }
565 
566  // decimal replacement (dashes) or variable decimals (#)
567  if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals )
568  {
569  // full variable decimals means an empty replacement string
571  rDashStr );
572  }
573 
574  // (automatic) grouping separator
575  if ( bGrouping )
576  {
578  }
579 
580  // display-factor if there are trailing thousands separators
581  if ( nTrailingThousands )
582  {
583  // each separator character removes three digits
584  double fFactor = ::rtl::math::pow10Exp( 1.0, 3 * nTrailingThousands );
585 
586  OUStringBuffer aFactStr;
587  ::sax::Converter::convertDouble( aFactStr, fFactor );
588  rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DISPLAY_FACTOR, aFactStr.makeStringAndClear() );
589  }
590 
592  true, true );
593 
594  // number:embedded-text as child elements
595 
596  auto nEntryCount = rEmbeddedEntries.size();
597  for (decltype(nEntryCount) nEntry=0; nEntry < nEntryCount; ++nEntry)
598  {
599  const SvXMLEmbeddedTextEntry *const pObj = &rEmbeddedEntries[nEntry];
600 
601  // position attribute
603  OUString::number( pObj->nFormatPos ) );
605  true, false );
606 
607  // text as element content
608  OUStringBuffer aContent( pObj->aText );
609  while ( nEntry+1 < nEntryCount && rEmbeddedEntries[nEntry+1].nFormatPos == pObj->nFormatPos )
610  {
611  // The array can contain several elements for the same position in the number
612  // (for example, literal text and space from underscores). They must be merged
613  // into a single embedded-text element.
614  aContent.append(rEmbeddedEntries[nEntry+1].aText);
615  ++nEntry;
616  }
617  rExport.Characters( aContent.makeStringAndClear() );
618  }
619 }
620 
622  sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger,
623  bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign )
624 {
626 
627  // decimals
628  if ( nDecimals >= 0 ) // negative = automatic
629  {
631  OUString::number( nDecimals ) );
632  }
633 
635  if ( nMinDecimals >= 0 ) // negative = automatic
636  {
637  // Export only for 1.2 with extensions or 1.3 and later.
638  if (eVersion > SvtSaveOptions::ODFSVER_012)
639  {
640  // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
644  OUString::number( nMinDecimals ) );
645  }
646  }
647 
648  // integer digits
649  if ( nInteger >= 0 ) // negative = automatic
650  {
652  OUString::number( nInteger ) );
653  }
654 
655  // (automatic) grouping separator
656  if ( bGrouping )
657  {
659  }
660 
661  // exponent digits
662  if ( nExp >= 0 )
663  {
665  OUString::number( nExp ) );
666  }
667 
668  // exponent interval for engineering notation
669  if ( nExpInterval >= 0 )
670  {
671  // Export only for 1.2 with extensions or 1.3 and later.
672  if (eVersion > SvtSaveOptions::ODFSVER_012)
673  {
674  // OFFICE-1828 For 1.2+ use loext namespace, for 1.3 use number namespace.
677  XML_EXPONENT_INTERVAL, OUString::number( nExpInterval ) );
678  }
679  }
680 
681  // exponent sign
682  // Export only for 1.2 with extensions or 1.3 and later.
683  if (eVersion > SvtSaveOptions::ODFSVER_012)
684  {
685  // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace.
689  bExpSign? XML_TRUE : XML_FALSE );
690  }
691 
694  true, false );
695 }
696 
698  sal_Int32 nInteger, bool bGrouping,
699  const SvNumberformat& rFormat, sal_uInt16 nPart )
700 {
702  const OUString aNumeratorString = rFormat.GetNumeratorString( nPart );
703  const OUString aDenominatorString = rFormat.GetDenominatorString( nPart );
704  const OUString aIntegerFractionDelimiterString = rFormat.GetIntegerFractionDelimiterString( nPart );
705  sal_Int32 nMaxNumeratorDigits = aNumeratorString.getLength();
706  // Count '0' as '?'
707  sal_Int32 nMinNumeratorDigits = aNumeratorString.replaceAll("0","?").indexOf('?');
708  sal_Int32 nZerosNumeratorDigits = aNumeratorString.indexOf('0');
709  if ( nMinNumeratorDigits >= 0 )
710  nMinNumeratorDigits = nMaxNumeratorDigits - nMinNumeratorDigits;
711  else
712  nMinNumeratorDigits = 0;
713  if ( nZerosNumeratorDigits >= 0 )
714  nZerosNumeratorDigits = nMaxNumeratorDigits - nZerosNumeratorDigits;
715  else
716  nZerosNumeratorDigits = 0;
717  sal_Int32 nMaxDenominatorDigits = aDenominatorString.getLength();
718  sal_Int32 nMinDenominatorDigits = aDenominatorString.replaceAll("0","?").indexOf('?');
719  sal_Int32 nZerosDenominatorDigits = aDenominatorString.indexOf('0');
720  if ( nMinDenominatorDigits >= 0 )
721  nMinDenominatorDigits = nMaxDenominatorDigits - nMinDenominatorDigits;
722  else
723  nMinDenominatorDigits = 0;
724  if ( nZerosDenominatorDigits >= 0 )
725  nZerosDenominatorDigits = nMaxDenominatorDigits - nZerosDenominatorDigits;
726  else
727  nZerosDenominatorDigits = 0;
728  sal_Int32 nDenominator = aDenominatorString.toInt32();
729 
730  // integer digits
731  if ( nInteger >= 0 ) // negative = default (no integer part)
732  {
734  OUString::number( nInteger ) );
735  }
736 
737  // (automatic) grouping separator
738  if ( bGrouping )
739  {
741  }
742 
743  // integer/fraction delimiter
745  if ( !aIntegerFractionDelimiterString.isEmpty() && aIntegerFractionDelimiterString != " "
746  && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
747  { // Export only for 1.2/1.3 with extensions.
749  aIntegerFractionDelimiterString );
750  }
751 
752  // numerator digits
753  if ( nMinNumeratorDigits == 0 ) // at least one digit to keep compatibility with previous versions
754  nMinNumeratorDigits++;
756  OUString::number( nMinNumeratorDigits ) );
757  // Export only for 1.2/1.3 with extensions.
758  if ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0)
759  {
760  // For extended ODF use loext namespace
762  OUString::number( nMaxNumeratorDigits ) );
763  }
764  if ( nZerosNumeratorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
766  OUString::number( nZerosNumeratorDigits ) );
767 
768  if ( nDenominator )
769  {
771  OUString::number( nDenominator) );
772  }
773  // it's not necessary to export nDenominatorDigits
774  // if we have a forced denominator
775  else
776  {
777  if ( nMinDenominatorDigits == 0 ) // at least one digit to keep compatibility with previous versions
778  nMinDenominatorDigits++;
780  OUString::number( nMinDenominatorDigits ) );
781  if (eVersion > SvtSaveOptions::ODFSVER_012)
782  {
783  // OFFICE-3695 For 1.2+ use loext namespace, for 1.3 use number namespace.
787  OUString::number( pow ( 10.0, nMaxDenominatorDigits ) - 1 ) ); // 9, 99 or 999
788  }
789  if ( nZerosDenominatorDigits && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) )
791  OUString::number( nZerosDenominatorDigits ) );
792  }
793 
795  true, false );
796 }
797 
798 // mapping (condition)
799 
800 void SvXMLNumFmtExport::WriteMapElement_Impl( sal_Int32 nOp, double fLimit,
801  sal_Int32 nKey, sal_Int32 nPart )
802 {
804 
805  if ( nOp == NUMBERFORMAT_OP_NO )
806  return;
807 
808  // style namespace
809 
810  OUStringBuffer aCondStr(20);
811  aCondStr.append( "value()" );
812  switch ( nOp )
813  {
814  case NUMBERFORMAT_OP_EQ: aCondStr.append( '=' ); break;
815  case NUMBERFORMAT_OP_NE: aCondStr.append( "!=" ); break;
816  case NUMBERFORMAT_OP_LT: aCondStr.append( '<' ); break;
817  case NUMBERFORMAT_OP_LE: aCondStr.append( "<=" ); break;
818  case NUMBERFORMAT_OP_GT: aCondStr.append( '>' ); break;
819  case NUMBERFORMAT_OP_GE: aCondStr.append( ">=" ); break;
820  default:
821  OSL_FAIL("unknown operator");
822  }
823  ::rtl::math::doubleToUStringBuffer( aCondStr, fLimit,
824  rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
825  '.', true );
826 
828  aCondStr.makeStringAndClear() );
829 
831  rExport.EncodeStyleName( lcl_CreateStyleName( nKey, nPart, false,
832  sPrefix ) ) );
833 
835  true, false );
836 }
837 
838 // for old (automatic) currency formats: parse currency symbol from text
839 
840 static sal_Int32 lcl_FindSymbol( const OUString& sUpperStr, std::u16string_view sCurString )
841 {
842  // search for currency symbol
843  // Quoting as in ImpSvNumberformatScan::Symbol_Division
844 
845  sal_Int32 nCPos = 0;
846  while (nCPos >= 0)
847  {
848  nCPos = sUpperStr.indexOf( sCurString, nCPos );
849  if (nCPos >= 0)
850  {
851  // in Quotes?
852  sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sUpperStr, nCPos );
853  if ( nQ < 0 )
854  {
855  // dm can be escaped as "dm or \d
856  sal_Unicode c;
857  if ( nCPos == 0 )
858  return nCPos; // found
859  c = sUpperStr[nCPos-1];
860  if ( c != '"' && c != '\\')
861  {
862  return nCPos; // found
863  }
864  else
865  {
866  nCPos++; // continue
867  }
868  }
869  else
870  {
871  nCPos = nQ + 1; // continue after quote end
872  }
873  }
874  }
875  return -1;
876 }
877 
878 bool SvXMLNumFmtExport::WriteTextWithCurrency_Impl( const OUString& rString,
879  const css::lang::Locale& rLocale )
880 {
881  // returns true if currency element was written
882 
883  bool bRet = false;
884 
885  LanguageTag aLanguageTag( rLocale );
886  pFormatter->ChangeIntl( aLanguageTag.getLanguageType( false) );
887  OUString sCurString, sDummy;
888  pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
889 
890  pCharClass->setLanguageTag( aLanguageTag );
891  OUString sUpperStr = pCharClass->uppercase(rString);
892  sal_Int32 nPos = lcl_FindSymbol( sUpperStr, sCurString );
893  if ( nPos >= 0 )
894  {
895  sal_Int32 nLength = rString.getLength();
896  sal_Int32 nCurLen = sCurString.getLength();
897  sal_Int32 nCont = nPos + nCurLen;
898 
899  // text before currency symbol
900  if ( nPos > 0 )
901  {
902  AddToTextElement_Impl( rString.copy( 0, nPos ) );
903  }
904  // currency symbol (empty string -> default)
905  WriteCurrencyElement_Impl( "", "" );
906  bRet = true;
907 
908  // text after currency symbol
909  if ( nCont < nLength )
910  {
911  AddToTextElement_Impl( rString.copy( nCont, nLength-nCont ) );
912  }
913  }
914  else
915  {
916  AddToTextElement_Impl( rString ); // simple text
917  }
918 
919  return bRet; // true: currency element written
920 }
921 
922 static OUString lcl_GetDefaultCalendar( SvNumberFormatter const * pFormatter, LanguageType nLang )
923 {
924  // get name of first non-gregorian calendar for the language
925 
926  OUString aCalendar;
927  CalendarWrapper* pCalendar = pFormatter->GetCalendar();
928  if (pCalendar)
929  {
930  lang::Locale aLocale( LanguageTag::convertToLocale( nLang ) );
931 
932  uno::Sequence<OUString> aCals = pCalendar->getAllCalendars( aLocale );
933  auto pCal = std::find_if(aCals.begin(), aCals.end(),
934  [](const OUString& rCal) { return rCal != "gregorian"; });
935  if (pCal != aCals.end())
936  aCalendar = *pCal;
937  }
938  return aCalendar;
939 }
940 
941 static bool lcl_IsInEmbedded( const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries, sal_uInt16 nPos )
942 {
943  auto nCount = rEmbeddedEntries.size();
944  for (decltype(nCount) i=0; i<nCount; i++)
945  if ( rEmbeddedEntries[i].nSourcePos == nPos )
946  return true;
947 
948  return false; // not found
949 }
950 
951 static bool lcl_IsDefaultDateFormat( const SvNumberformat& rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn )
952 {
953  // make an extra loop to collect date elements, to check if it is a default format
954  // before adding the automatic-order attribute
955 
963  bool bDateNoDefault = false;
964 
965  sal_uInt16 nPos = 0;
966  bool bEnd = false;
967  short nLastType = 0;
968  while (!bEnd)
969  {
970  short nElemType = rFormat.GetNumForType( 0, nPos );
971  switch ( nElemType )
972  {
973  case 0:
974  if ( nLastType == NF_SYMBOLTYPE_STRING )
975  bDateNoDefault = true; // text at the end -> no default date format
976  bEnd = true; // end of format reached
977  break;
982  // text is ignored, except at the end
983  break;
984  // same mapping as in SvXMLNumFormatContext::AddNfKeyword:
985  case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
986  case NF_KEY_NNN:
987  case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
988  case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
989  case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
990  case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
991  case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
992  case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
993  case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
994  case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
995  case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
996  case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
997  case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
998  case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
999  case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1000  case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1001  case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1002  case NF_KEY_AP:
1003  case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1004  default:
1005  bDateNoDefault = true; // any other element -> no default format
1006  }
1007  nLastType = nElemType;
1008  ++nPos;
1009  }
1010 
1011  if ( bDateNoDefault )
1012  return false; // additional elements
1013  else
1014  {
1016  eDateDOW, eDateDay, eDateMonth, eDateYear, eDateHours, eDateMins, eDateSecs, bSystemDate ));
1017 
1018  return ( eFound == eBuiltIn );
1019  }
1020 }
1021 
1022 // export one part (condition)
1023 
1024 void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey,
1025  sal_uInt16 nPart, bool bDefPart )
1026 {
1028 
1029  // element name
1030 
1031  NfIndexTableOffset eBuiltIn = pFormatter->GetIndexTableOffset( nRealKey );
1032 
1033  SvNumFormatType nFmtType = SvNumFormatType::ALL;
1034  bool bThousand = false;
1035  sal_uInt16 nPrecision = 0;
1036  sal_uInt16 nLeading = 0;
1037  rFormat.GetNumForInfo( nPart, nFmtType, bThousand, nPrecision, nLeading);
1038  nFmtType &= ~SvNumFormatType::DEFINED;
1039 
1040  // special treatment of builtin formats that aren't detected by normal parsing
1041  // (the same formats that get the type set in SvNumberFormatter::ImpGenerateFormats)
1042  if ( eBuiltIn == NF_NUMBER_STANDARD )
1043  nFmtType = SvNumFormatType::NUMBER;
1044  else if ( eBuiltIn == NF_BOOLEAN )
1045  nFmtType = SvNumFormatType::LOGICAL;
1046  else if ( eBuiltIn == NF_TEXT )
1047  nFmtType = SvNumFormatType::TEXT;
1048 
1049  // #101606# An empty subformat is a valid number-style resulting in an
1050  // empty display string for the condition of the subformat.
1051 
1053  switch ( nFmtType )
1054  {
1055  // Type UNDEFINED likely is a crappy format string for that we could
1056  // not decide on any format type (and maybe could try harder?), but the
1057  // resulting XMLTokenEnum should be something valid, so make that
1058  // number-style.
1059  case SvNumFormatType::UNDEFINED:
1060  SAL_WARN("xmloff.style","UNDEFINED number format: '" << rFormat.GetFormatstring() << "'");
1061  [[fallthrough]];
1062  // Type is 0 if a format contains no recognized elements
1063  // (like text only) - this is handled as a number-style.
1064  case SvNumFormatType::ALL:
1065  case SvNumFormatType::EMPTY:
1066  case SvNumFormatType::NUMBER:
1067  case SvNumFormatType::SCIENTIFIC:
1068  case SvNumFormatType::FRACTION:
1069  eType = XML_NUMBER_STYLE;
1070  break;
1071  case SvNumFormatType::PERCENT:
1072  eType = XML_PERCENTAGE_STYLE;
1073  break;
1074  case SvNumFormatType::CURRENCY:
1075  eType = XML_CURRENCY_STYLE;
1076  break;
1077  case SvNumFormatType::DATE:
1078  case SvNumFormatType::DATETIME:
1079  eType = XML_DATE_STYLE;
1080  break;
1081  case SvNumFormatType::TIME:
1082  eType = XML_TIME_STYLE;
1083  break;
1084  case SvNumFormatType::TEXT:
1085  eType = XML_TEXT_STYLE;
1086  break;
1087  case SvNumFormatType::LOGICAL:
1088  eType = XML_BOOLEAN_STYLE;
1089  break;
1090  default: break;
1091  }
1092  SAL_WARN_IF( eType == XML_TOKEN_INVALID, "xmloff.style", "unknown format type" );
1093 
1094  OUString sAttrValue;
1095  bool bUserDef( rFormat.GetType() & SvNumFormatType::DEFINED );
1096 
1097  // common attributes for format
1098 
1099  // format name (generated from key) - style namespace
1101  lcl_CreateStyleName( nKey, nPart, bDefPart, sPrefix ) );
1102 
1103  // "volatile" attribute for styles used only in maps
1104  if ( !bDefPart )
1106 
1107  // language / country
1108  LanguageType nLang = rFormat.GetLanguage();
1109  AddLanguageAttr_Impl( nLang ); // adds to pAttrList
1110 
1111  // title (comment)
1112  // titles for builtin formats are not written
1113  sAttrValue = rFormat.GetComment();
1114  if ( !sAttrValue.isEmpty() && bUserDef && bDefPart )
1115  {
1117  }
1118 
1119  // automatic ordering for currency and date formats
1120  // only used for some built-in formats
1121  bool bAutoOrder = ( eBuiltIn == NF_CURRENCY_1000INT || eBuiltIn == NF_CURRENCY_1000DEC2 ||
1122  eBuiltIn == NF_CURRENCY_1000INT_RED || eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1123  eBuiltIn == NF_CURRENCY_1000DEC2_DASHED ||
1124  eBuiltIn == NF_DATE_SYSTEM_SHORT || eBuiltIn == NF_DATE_SYSTEM_LONG ||
1125  eBuiltIn == NF_DATE_SYS_MMYY || eBuiltIn == NF_DATE_SYS_DDMMM ||
1126  eBuiltIn == NF_DATE_SYS_DDMMYYYY || eBuiltIn == NF_DATE_SYS_DDMMYY ||
1127  eBuiltIn == NF_DATE_SYS_DMMMYY || eBuiltIn == NF_DATE_SYS_DMMMYYYY ||
1128  eBuiltIn == NF_DATE_SYS_DMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNDMMMYY ||
1129  eBuiltIn == NF_DATE_SYS_NNDMMMMYYYY || eBuiltIn == NF_DATE_SYS_NNNNDMMMMYYYY ||
1130  eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM || eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMM ||
1131  eBuiltIn == NF_DATETIME_SYS_DDMMYYYY_HHMMSS );
1132 
1133  // format source (for date and time formats)
1134  // only used for some built-in formats
1135  bool bSystemDate = ( eBuiltIn == NF_DATE_SYSTEM_SHORT ||
1136  eBuiltIn == NF_DATE_SYSTEM_LONG ||
1137  eBuiltIn == NF_DATETIME_SYSTEM_SHORT_HHMM );
1138  bool bLongSysDate = ( eBuiltIn == NF_DATE_SYSTEM_LONG );
1139 
1140  // check if the format definition matches the key
1141  if ( bAutoOrder && ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) &&
1142  !lcl_IsDefaultDateFormat( rFormat, bSystemDate, eBuiltIn ) )
1143  {
1144  bAutoOrder = bSystemDate = bLongSysDate = false; // don't write automatic-order attribute then
1145  }
1146 
1147  if ( bAutoOrder &&
1148  ( nFmtType == SvNumFormatType::CURRENCY || nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) )
1149  {
1150  // #85109# format type must be checked to avoid dtd errors if
1151  // locale data contains other format types at the built-in positions
1152 
1154  XML_TRUE );
1155  }
1156 
1157  if ( bSystemDate && bAutoOrder &&
1158  ( nFmtType == SvNumFormatType::DATE || nFmtType == SvNumFormatType::DATETIME ) )
1159  {
1160  // #85109# format type must be checked to avoid dtd errors if
1161  // locale data contains other format types at the built-in positions
1162 
1164  XML_LANGUAGE );
1165  }
1166 
1167  // overflow for time formats as in [hh]:mm
1168  // controlled by bThousand from number format info
1169  // default for truncate-on-overflow is true
1170  if ( nFmtType == SvNumFormatType::TIME && bThousand )
1171  {
1173  XML_FALSE );
1174  }
1175 
1176  // Native number transliteration
1177  css::i18n::NativeNumberXmlAttributes2 aAttr;
1178  rFormat.GetNatNumXml( aAttr, nPart );
1179  if ( !aAttr.Format.isEmpty() )
1180  {
1181  assert(aAttr.Spellout.isEmpty()); // mutually exclusive
1182 
1183  /* FIXME-BCP47: ODF defines no transliteration-script or
1184  * transliteration-rfc-language-tag */
1185  LanguageTag aLanguageTag( aAttr.Locale);
1186  OUString aLanguage, aScript, aCountry;
1187  aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
1189  aAttr.Format );
1191  aLanguage );
1193  aCountry );
1195  aAttr.Style );
1196  }
1197 
1198  if ( !aAttr.Spellout.isEmpty() )
1199  {
1200  const bool bWriteSpellout = aAttr.Format.isEmpty();
1201  assert(bWriteSpellout); // mutually exclusive
1202 
1203  // Export only for 1.2 with extensions or 1.3 and later.
1205  // Also ensure that duplicated transliteration-language and
1206  // transliteration-country attributes never escape into the wild with
1207  // releases.
1208  if (eVersion > SvtSaveOptions::ODFSVER_012 && bWriteSpellout)
1209  {
1210  /* FIXME-BCP47: ODF defines no transliteration-script or
1211  * transliteration-rfc-language-tag */
1212  LanguageTag aLanguageTag( aAttr.Locale);
1213  OUString aLanguage, aScript, aCountry;
1214  aLanguageTag.getIsoLanguageScriptCountry( aLanguage, aScript, aCountry);
1215  // For 1.2/1.3+ use loext namespace.
1216  rExport.AddAttribute( /*((eVersion < SvtSaveOptions::ODFSVER_)
1217  ? */ XML_NAMESPACE_LO_EXT /*: XML_NAMESPACE_NUMBER)*/,
1218  XML_TRANSLITERATION_SPELLOUT, aAttr.Spellout );
1220  aLanguage );
1222  aCountry );
1223  }
1224  }
1225 
1226  // The element
1228  true, true );
1229 
1230  // color (properties element)
1231 
1232  const Color* pCol = rFormat.GetColor( nPart );
1233  if (pCol)
1234  WriteColorElement_Impl(*pCol);
1235 
1236  // detect if there is "real" content, excluding color and maps
1238  bool bAnyContent = false;
1239 
1240  // format elements
1241 
1242  SvXMLEmbeddedTextEntryArr aEmbeddedEntries;
1243  if ( eBuiltIn == NF_NUMBER_STANDARD )
1244  {
1245  // default number format contains just one number element
1246  WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries );
1247  bAnyContent = true;
1248  }
1249  else if ( eBuiltIn == NF_BOOLEAN )
1250  {
1251  // boolean format contains just one boolean element
1253  bAnyContent = true;
1254  }
1255  else
1256  {
1257  // first loop to collect attributes
1258 
1259  bool bDecDashes = false;
1260  bool bExpFound = false;
1261  bool bCurrFound = false;
1262  bool bInInteger = true;
1263  bool bExpSign = true;
1264  bool bDecAlign = false; // decimal alignment with "?"
1265  sal_Int32 nExpDigits = 0;
1266  sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#"
1267  sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits
1268  sal_Int32 nMinDecimals = nPrecision;
1269  OUString sCurrExt;
1270  OUString aCalendar;
1271  sal_uInt16 nPos = 0;
1272  bool bEnd = false;
1273  while (!bEnd)
1274  {
1275  short nElemType = rFormat.GetNumForType( nPart, nPos );
1276  const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1277 
1278  switch ( nElemType )
1279  {
1280  case 0:
1281  bEnd = true; // end of format reached
1282  break;
1283  case NF_SYMBOLTYPE_DIGIT:
1284  if ( bExpFound && pElemStr )
1285  nExpDigits += pElemStr->getLength();
1286  else if ( !bDecDashes && pElemStr && (*pElemStr)[0] == '-' )
1287  {
1288  bDecDashes = true;
1289  nMinDecimals = 0;
1290  }
1291  else if ( !bInInteger && pElemStr )
1292  {
1293  for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- )
1294  {
1295  sal_Unicode aChar = (*pElemStr)[i];
1296  if ( aChar == '#' || aChar == '?' )
1297  {
1298  nMinDecimals --;
1299  if ( aChar == '?' )
1300  bDecAlign = true;
1301  }
1302  else
1303  break;
1304  }
1305  }
1306  if ( bInInteger && pElemStr )
1307  nIntegerSymbols += pElemStr->getLength();
1308  nTrailingThousands = 0;
1309  break;
1310  case NF_SYMBOLTYPE_DECSEP:
1311  bInInteger = false;
1312  break;
1313  case NF_SYMBOLTYPE_THSEP:
1314  if (pElemStr)
1315  nTrailingThousands += pElemStr->getLength(); // is reset to 0 if digits follow
1316  break;
1317  case NF_SYMBOLTYPE_EXP:
1318  bExpFound = true; // following digits are exponent digits
1319  bInInteger = false;
1320  if ( pElemStr && ( pElemStr->getLength() == 1
1321  || ( pElemStr->getLength() == 2 && (*pElemStr)[1] == '-' ) ) )
1322  bExpSign = false; // for 0.00E0 or 0.00E-00
1323  break;
1325  bCurrFound = true;
1326  break;
1327  case NF_SYMBOLTYPE_CURREXT:
1328  if (pElemStr)
1329  sCurrExt = *pElemStr;
1330  break;
1331 
1332  // E, EE, R, RR: select non-gregorian calendar
1333  // AAA, AAAA: calendar is switched at the position of the element
1334  case NF_KEY_EC:
1335  case NF_KEY_EEC:
1336  case NF_KEY_R:
1337  case NF_KEY_RR:
1338  if (aCalendar.isEmpty())
1339  aCalendar = lcl_GetDefaultCalendar( pFormatter, nLang );
1340  break;
1341  }
1342  ++nPos;
1343  }
1344 
1345  // collect strings for embedded-text (must be known before number element is written)
1346 
1347  bool bAllowEmbedded = ( nFmtType == SvNumFormatType::ALL || nFmtType == SvNumFormatType::NUMBER ||
1348  nFmtType == SvNumFormatType::CURRENCY ||
1349  nFmtType == SvNumFormatType::PERCENT );
1350  if ( bAllowEmbedded )
1351  {
1352  sal_Int32 nDigitsPassed = 0;
1353  nPos = 0;
1354  bEnd = false;
1355  while (!bEnd)
1356  {
1357  short nElemType = rFormat.GetNumForType( nPart, nPos );
1358  const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1359 
1360  switch ( nElemType )
1361  {
1362  case 0:
1363  bEnd = true; // end of format reached
1364  break;
1365  case NF_SYMBOLTYPE_DIGIT:
1366  if ( pElemStr )
1367  nDigitsPassed += pElemStr->getLength();
1368  break;
1369  case NF_SYMBOLTYPE_STRING:
1370  case NF_SYMBOLTYPE_BLANK:
1371  case NF_SYMBOLTYPE_PERCENT:
1372  if ( nDigitsPassed > 0 && nDigitsPassed < nIntegerSymbols && pElemStr )
1373  {
1374  // text (literal or underscore) within the integer part of a number:number element
1375 
1376  OUString aEmbeddedStr;
1377  if ( nElemType == NF_SYMBOLTYPE_STRING || nElemType == NF_SYMBOLTYPE_PERCENT )
1378  {
1379  aEmbeddedStr = *pElemStr;
1380  }
1381  else if (pElemStr->getLength() >= 2)
1382  {
1383  SvNumberformat::InsertBlanks( aEmbeddedStr, 0, (*pElemStr)[1] );
1384  }
1385  sal_Int32 nEmbedPos = nIntegerSymbols - nDigitsPassed;
1386 
1387  aEmbeddedEntries.push_back(
1388  SvXMLEmbeddedTextEntry(nPos, nEmbedPos, aEmbeddedStr));
1389  }
1390  break;
1391  }
1392  ++nPos;
1393  }
1394  }
1395 
1396  // final loop to write elements
1397 
1398  bool bNumWritten = false;
1399  bool bCurrencyWritten = false;
1400  short nPrevType = 0;
1401  nPos = 0;
1402  bEnd = false;
1403  while (!bEnd)
1404  {
1405  short nElemType = rFormat.GetNumForType( nPart, nPos );
1406  const OUString* pElemStr = rFormat.GetNumForString( nPart, nPos );
1407 
1408  switch ( nElemType )
1409  {
1410  case 0:
1411  bEnd = true; // end of format reached
1412  break;
1413  case NF_SYMBOLTYPE_STRING:
1414  case NF_SYMBOLTYPE_DATESEP:
1415  case NF_SYMBOLTYPE_TIMESEP:
1417  case NF_SYMBOLTYPE_PERCENT:
1418  if (pElemStr)
1419  {
1420  if ( ( nPrevType == NF_KEY_S || nPrevType == NF_KEY_SS ) &&
1421  ( nElemType == NF_SYMBOLTYPE_TIME100SECSEP ) &&
1422  nPrecision > 0 )
1423  {
1424  // decimal separator after seconds is implied by
1425  // "decimal-places" attribute and must not be written
1426  // as text element
1428  }
1429  else if ( lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1430  {
1431  // text is written as embedded-text child of the number,
1432  // don't create a text element
1433  }
1434  else if ( nFmtType == SvNumFormatType::CURRENCY && !bCurrFound && !bCurrencyWritten )
1435  {
1436  // automatic currency symbol is implemented as part of
1437  // normal text -> search for the symbol
1438  bCurrencyWritten = WriteTextWithCurrency_Impl( *pElemStr,
1439  LanguageTag::convertToLocale( nLang ) );
1440  bAnyContent = true;
1441  }
1442  else
1443  AddToTextElement_Impl( *pElemStr );
1444  }
1445  break;
1446  case NF_SYMBOLTYPE_BLANK:
1447  if ( pElemStr && !lcl_IsInEmbedded( aEmbeddedEntries, nPos ) )
1448  {
1449  // turn "_x" into the number of spaces used for x in InsertBlanks in the NumberFormat
1450  // (#i20396# the spaces may also be in embedded-text elements)
1451 
1452  OUString aBlanks;
1453  if (pElemStr->getLength() >= 2)
1454  SvNumberformat::InsertBlanks( aBlanks, 0, (*pElemStr)[1] );
1455  AddToTextElement_Impl( aBlanks );
1456  }
1457  break;
1458  case NF_KEY_GENERAL :
1459  WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries );
1460  break;
1461  case NF_KEY_CCC:
1462  if (pElemStr)
1463  {
1464  if ( bCurrencyWritten )
1465  AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1466  else
1467  {
1470  // pElemStr is "CCC"
1471 
1472  WriteCurrencyElement_Impl( *pElemStr, OUString() );
1473  bAnyContent = true;
1474  bCurrencyWritten = true;
1475  }
1476  }
1477  break;
1479  if (pElemStr)
1480  {
1481  if ( bCurrencyWritten )
1482  AddToTextElement_Impl( *pElemStr ); // never more than one currency element
1483  else
1484  {
1485  WriteCurrencyElement_Impl( *pElemStr, sCurrExt );
1486  bAnyContent = true;
1487  bCurrencyWritten = true;
1488  }
1489  }
1490  break;
1491  case NF_SYMBOLTYPE_DIGIT:
1492  if (!bNumWritten) // write number part
1493  {
1494  switch ( nFmtType )
1495  {
1496  // for type 0 (not recognized as a special type),
1497  // write a "normal" number
1498  case SvNumFormatType::ALL:
1499  case SvNumFormatType::NUMBER:
1500  case SvNumFormatType::CURRENCY:
1501  case SvNumFormatType::PERCENT:
1502  {
1503  // decimals
1504  // only some built-in formats have automatic decimals
1505  sal_Int32 nDecimals = nPrecision; // from GetFormatSpecialInfo
1506  if ( eBuiltIn == NF_NUMBER_STANDARD ||
1507  eBuiltIn == NF_CURRENCY_1000DEC2 ||
1508  eBuiltIn == NF_CURRENCY_1000DEC2_RED ||
1509  eBuiltIn == NF_CURRENCY_1000DEC2_CCC ||
1510  eBuiltIn == NF_CURRENCY_1000DEC2_DASHED )
1511  nDecimals = -1;
1512 
1513  // integer digits
1514  // only one built-in format has automatic integer digits
1515  sal_Int32 nInteger = nLeading;
1516  if ( eBuiltIn == NF_NUMBER_SYSTEM )
1517  nInteger = -1;
1518 
1519  // string for decimal replacement
1520  // has to be taken from nPrecision
1521  // (positive number even for automatic decimals)
1522  OUStringBuffer sDashStr;
1523  if (bDecDashes && nPrecision > 0)
1524  comphelper::string::padToLength(sDashStr, nPrecision, '-');
1525  // "?" in decimal part are replaced by space character
1526  if (bDecAlign && nPrecision > 0)
1527  sDashStr = " ";
1528 
1529  WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, sDashStr.makeStringAndClear(),
1530  bThousand, nTrailingThousands, aEmbeddedEntries);
1531  bAnyContent = true;
1532  }
1533  break;
1534  case SvNumFormatType::SCIENTIFIC:
1535  // #i43959# for scientific numbers, count all integer symbols ("0" and "#")
1536  // as integer digits: use nIntegerSymbols instead of nLeading
1537  // nIntegerSymbols represents exponent interval (for engineering notation)
1538  WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, bThousand, nExpDigits, nIntegerSymbols, bExpSign );
1539  bAnyContent = true;
1540  break;
1541  case SvNumFormatType::FRACTION:
1542  {
1543  sal_Int32 nInteger = nLeading;
1544  if ( rFormat.GetNumForNumberElementCount( nPart ) == 3 )
1545  {
1546  // If there is only two numbers + fraction in format string
1547  // the fraction doesn't have an integer part, and no
1548  // min-integer-digits attribute must be written.
1549  nInteger = -1;
1550  }
1551  WriteFractionElement_Impl( nInteger, bThousand, rFormat, nPart );
1552  bAnyContent = true;
1553  }
1554  break;
1555  default: break;
1556  }
1557 
1558  bNumWritten = true;
1559  }
1560  break;
1561  case NF_SYMBOLTYPE_DECSEP:
1562  if ( pElemStr && nPrecision == 0 )
1563  {
1564  // A decimal separator after the number, without following decimal digits,
1565  // isn't modelled as part of the number element, so it's written as text
1566  // (the distinction between a quoted and non-quoted, locale-dependent
1567  // character is lost here).
1568 
1569  AddToTextElement_Impl( *pElemStr );
1570  }
1571  break;
1572  case NF_SYMBOLTYPE_DEL:
1573  if ( pElemStr && *pElemStr == "@" )
1574  {
1576  bAnyContent = true;
1577  }
1578  break;
1579 
1581  if ( pElemStr )
1582  aCalendar = *pElemStr;
1583  break;
1584 
1585  // date elements:
1586 
1587  case NF_KEY_D:
1588  case NF_KEY_DD:
1589  {
1590  bool bLong = ( nElemType == NF_KEY_DD );
1591  WriteDayElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1592  bAnyContent = true;
1593  }
1594  break;
1595  case NF_KEY_DDD:
1596  case NF_KEY_DDDD:
1597  case NF_KEY_NN:
1598  case NF_KEY_NNN:
1599  case NF_KEY_NNNN:
1600  case NF_KEY_AAA:
1601  case NF_KEY_AAAA:
1602  {
1603  OUString aCalAttr = aCalendar;
1604  if ( nElemType == NF_KEY_AAA || nElemType == NF_KEY_AAAA )
1605  {
1606  // calendar attribute for AAA and AAAA is switched only for this element
1607  if (aCalAttr.isEmpty())
1608  aCalAttr = lcl_GetDefaultCalendar( pFormatter, nLang );
1609  }
1610 
1611  bool bLong = ( nElemType == NF_KEY_NNN || nElemType == NF_KEY_NNNN ||
1612  nElemType == NF_KEY_DDDD || nElemType == NF_KEY_AAAA );
1613  WriteDayOfWeekElement_Impl( aCalAttr, ( bSystemDate ? bLongSysDate : bLong ) );
1614  bAnyContent = true;
1615  if ( nElemType == NF_KEY_NNNN )
1616  {
1617  // write additional text element for separator
1618  pLocaleData->setLanguageTag( LanguageTag( nLang ) );
1619  AddToTextElement_Impl( pLocaleData->getLongDateDayOfWeekSep() );
1620  }
1621  }
1622  break;
1623  case NF_KEY_M:
1624  case NF_KEY_MM:
1625  case NF_KEY_MMM:
1626  case NF_KEY_MMMM:
1627  case NF_KEY_MMMMM:
1628  {
1629  bool bLong = ( nElemType == NF_KEY_MM || nElemType == NF_KEY_MMMM );
1630  bool bText = ( nElemType == NF_KEY_MMM || nElemType == NF_KEY_MMMM ||
1631  nElemType == NF_KEY_MMMMM );
1632  WriteMonthElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ), bText );
1633  bAnyContent = true;
1634  }
1635  break;
1636  case NF_KEY_YY:
1637  case NF_KEY_YYYY:
1638  case NF_KEY_EC:
1639  case NF_KEY_EEC:
1640  case NF_KEY_R:
1641  {
1643  // calendar attribute for E and EE and R is set in first loop
1644  bool bLong = ( nElemType == NF_KEY_YYYY || nElemType == NF_KEY_EEC ||
1645  nElemType == NF_KEY_R );
1646  WriteYearElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1647  bAnyContent = true;
1648  }
1649  break;
1650  case NF_KEY_G:
1651  case NF_KEY_GG:
1652  case NF_KEY_GGG:
1653  case NF_KEY_RR:
1654  {
1656  bool bLong = ( nElemType == NF_KEY_GGG || nElemType == NF_KEY_RR );
1657  WriteEraElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1658  bAnyContent = true;
1659  if ( nElemType == NF_KEY_RR )
1660  {
1661  // calendar attribute for RR is set in first loop
1662  WriteYearElement_Impl( aCalendar, ( bSystemDate || bLongSysDate ) );
1663  }
1664  }
1665  break;
1666  case NF_KEY_Q:
1667  case NF_KEY_QQ:
1668  {
1669  bool bLong = ( nElemType == NF_KEY_QQ );
1670  WriteQuarterElement_Impl( aCalendar, ( bSystemDate ? bLongSysDate : bLong ) );
1671  bAnyContent = true;
1672  }
1673  break;
1674  case NF_KEY_WW:
1675  WriteWeekElement_Impl( aCalendar );
1676  bAnyContent = true;
1677  break;
1678 
1679  // time elements (bSystemDate is not used):
1680 
1681  case NF_KEY_H:
1682  case NF_KEY_HH:
1683  WriteHoursElement_Impl( nElemType == NF_KEY_HH );
1684  bAnyContent = true;
1685  break;
1686  case NF_KEY_MI:
1687  case NF_KEY_MMI:
1688  WriteMinutesElement_Impl( nElemType == NF_KEY_MMI );
1689  bAnyContent = true;
1690  break;
1691  case NF_KEY_S:
1692  case NF_KEY_SS:
1693  WriteSecondsElement_Impl( ( nElemType == NF_KEY_SS ), nPrecision );
1694  bAnyContent = true;
1695  break;
1696  case NF_KEY_AMPM:
1697  case NF_KEY_AP:
1698  WriteAMPMElement_Impl(); // short/long?
1699  bAnyContent = true;
1700  break;
1701  case NF_SYMBOLTYPE_STAR :
1702  // export only if ODF 1.2 extensions are enabled
1704  {
1705  if ( pElemStr && pElemStr->getLength() > 1 )
1706  WriteRepeatedElement_Impl( (*pElemStr)[1] );
1707  }
1708  break;
1709  }
1710  nPrevType = nElemType;
1711  ++nPos;
1712  }
1713  }
1714 
1715  if ( !sTextContent.isEmpty() )
1716  bAnyContent = true; // element written in FinishTextElement_Impl
1717 
1718  FinishTextElement_Impl(); // final text element - before maps
1719 
1720  if ( !bAnyContent )
1721  {
1722  // for an empty format, write an empty text element
1724  true, false );
1725  }
1726 
1727  // mapping (conditions) must be last elements
1728 
1729  if (!bDefPart)
1730  return;
1731 
1732  SvNumberformatLimitOps eOp1, eOp2;
1733  double fLimit1, fLimit2;
1734  rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1735 
1736  WriteMapElement_Impl( eOp1, fLimit1, nKey, 0 );
1737  WriteMapElement_Impl( eOp2, fLimit2, nKey, 1 );
1738 
1739  if ( !rFormat.HasTextFormat() )
1740  return;
1741 
1742  // 4th part is for text -> make an "all other numbers" condition for the 3rd part
1743  // by reversing the 2nd condition.
1744  // For a trailing text format like 0;@ that has no conditions
1745  // use a "less or equal than biggest" condition for the number
1746  // part, ODF can't store subformats (style maps) without
1747  // conditions.
1748 
1750  double fLimit3 = fLimit2;
1751  sal_uInt16 nLastPart = 2;
1752  SvNumberformatLimitOps eOpLast = eOp2;
1753  if (eOp2 == NUMBERFORMAT_OP_NO)
1754  {
1755  eOpLast = eOp1;
1756  fLimit3 = fLimit1;
1757  nLastPart = (eOp1 == NUMBERFORMAT_OP_NO) ? 0 : 1;
1758  }
1759  switch ( eOpLast )
1760  {
1761  case NUMBERFORMAT_OP_EQ: eOp3 = NUMBERFORMAT_OP_NE; break;
1762  case NUMBERFORMAT_OP_NE: eOp3 = NUMBERFORMAT_OP_EQ; break;
1763  case NUMBERFORMAT_OP_LT: eOp3 = NUMBERFORMAT_OP_GE; break;
1764  case NUMBERFORMAT_OP_LE: eOp3 = NUMBERFORMAT_OP_GT; break;
1765  case NUMBERFORMAT_OP_GT: eOp3 = NUMBERFORMAT_OP_LE; break;
1766  case NUMBERFORMAT_OP_GE: eOp3 = NUMBERFORMAT_OP_LT; break;
1767  case NUMBERFORMAT_OP_NO: eOp3 = NUMBERFORMAT_OP_LE; fLimit3 = DBL_MAX; break;
1768  }
1769 
1770  if ( fLimit1 == fLimit2 &&
1771  ( ( eOp1 == NUMBERFORMAT_OP_LT && eOp2 == NUMBERFORMAT_OP_GT ) ||
1772  ( eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_LT ) ) )
1773  {
1774  // For <x and >x, add =x as last condition
1775  // (just for readability, <=x would be valid, too)
1776 
1777  eOp3 = NUMBERFORMAT_OP_EQ;
1778  }
1779 
1780  WriteMapElement_Impl( eOp3, fLimit3, nKey, nLastPart );
1781 }
1782 
1783 // export one format
1784 
1785 void SvXMLNumFmtExport::ExportFormat_Impl( const SvNumberformat& rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey )
1786 {
1787  const sal_uInt16 XMLNUM_MAX_PARTS = 4;
1788  bool bParts[XMLNUM_MAX_PARTS] = { false, false, false, false };
1789  sal_uInt16 nUsedParts = 0;
1790  for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart)
1791  {
1792  if (rFormat.GetNumForInfoScannedType( nPart) != SvNumFormatType::UNDEFINED)
1793  {
1794  bParts[nPart] = true;
1795  nUsedParts = nPart + 1;
1796  }
1797  }
1798 
1799  SvNumberformatLimitOps eOp1, eOp2;
1800  double fLimit1, fLimit2;
1801  rFormat.GetConditions( eOp1, fLimit1, eOp2, fLimit2 );
1802 
1803  // if conditions are set, even empty formats must be written
1804 
1805  if ( eOp1 != NUMBERFORMAT_OP_NO )
1806  {
1807  bParts[1] = true;
1808  if (nUsedParts < 2)
1809  nUsedParts = 2;
1810  }
1811  if ( eOp2 != NUMBERFORMAT_OP_NO )
1812  {
1813  bParts[2] = true;
1814  if (nUsedParts < 3)
1815  nUsedParts = 3;
1816  }
1817  if ( rFormat.HasTextFormat() )
1818  {
1819  bParts[3] = true;
1820  if (nUsedParts < 4)
1821  nUsedParts = 4;
1822  }
1823 
1824  for (sal_uInt16 nPart=0; nPart<XMLNUM_MAX_PARTS; ++nPart)
1825  {
1826  if (bParts[nPart])
1827  {
1828  bool bDefault = ( nPart+1 == nUsedParts ); // last = default
1829  ExportPart_Impl( rFormat, nKey, nRealKey, nPart, bDefault );
1830  }
1831  }
1832 }
1833 
1834 // export method called by application
1835 
1836 void SvXMLNumFmtExport::Export( bool bIsAutoStyle )
1837 {
1838  if ( !pFormatter )
1839  return; // no formatter -> no entries
1840 
1841  sal_uInt32 nKey;
1842  const SvNumberformat* pFormat = nullptr;
1843  bool bNext(pUsedList->GetFirstUsed(nKey));
1844  while(bNext)
1845  {
1846  // ODF has its notation of system formats, so obtain the "real" already
1847  // substituted format but use the original key for style name.
1848  sal_uInt32 nRealKey = nKey;
1849  pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey);
1850  if(pFormat)
1851  ExportFormat_Impl( *pFormat, nKey, nRealKey );
1852  bNext = pUsedList->GetNextUsed(nKey);
1853  }
1854  if (!bIsAutoStyle)
1855  {
1856  std::vector<LanguageType> aLanguages;
1857  pFormatter->GetUsedLanguages( aLanguages );
1858  for (const auto& nLang : aLanguages)
1859  {
1860  sal_uInt32 nDefaultIndex = 0;
1862  SvNumFormatType::DEFINED, nDefaultIndex, nLang );
1863  for (const auto& rTableEntry : rTable)
1864  {
1865  nKey = rTableEntry.first;
1866  pFormat = rTableEntry.second;
1867  if (!pUsedList->IsUsed(nKey))
1868  {
1869  DBG_ASSERT((pFormat->GetType() & SvNumFormatType::DEFINED), "a not user defined numberformat found");
1870  sal_uInt32 nRealKey = nKey;
1871  if (pFormat->IsSubstituted())
1872  {
1873  pFormat = pFormatter->GetSubstitutedEntry( nKey, nRealKey); // export the "real" format
1874  assert(pFormat);
1875  }
1876  // user-defined and used formats are exported
1877  ExportFormat_Impl( *pFormat, nKey, nRealKey );
1878  // if it is a user-defined Format it will be added else nothing will happen
1879  pUsedList->SetUsed(nKey);
1880  }
1881  }
1882  }
1883  }
1884  pUsedList->Export();
1885 }
1886 
1887 OUString SvXMLNumFmtExport::GetStyleName( sal_uInt32 nKey )
1888 {
1889  if(pUsedList->IsUsed(nKey) || pUsedList->IsWasUsed(nKey))
1890  return lcl_CreateStyleName( nKey, 0, true, sPrefix );
1891  else
1892  {
1893  OSL_FAIL("There is no written Data-Style");
1894  return OUString();
1895  }
1896 }
1897 
1898 void SvXMLNumFmtExport::SetUsed( sal_uInt32 nKey )
1899 {
1900  SAL_WARN_IF( pFormatter == nullptr, "xmloff.style", "missing formatter" );
1901  if( !pFormatter )
1902  return;
1903 
1904  if (pFormatter->GetEntry(nKey))
1905  pUsedList->SetUsed( nKey );
1906  else {
1907  OSL_FAIL("no existing Numberformat found with this key");
1908  }
1909 }
1910 
1911 uno::Sequence<sal_Int32> SvXMLNumFmtExport::GetWasUsed() const
1912 {
1913  if (pUsedList)
1914  return pUsedList->GetWasUsed();
1915  return uno::Sequence<sal_Int32>();
1916 }
1917 
1918 void SvXMLNumFmtExport::SetWasUsed(const uno::Sequence<sal_Int32>& rWasUsed)
1919 {
1920  if (pUsedList)
1921  pUsedList->SetWasUsed(rWasUsed);
1922 }
1923 
1924 static const SvNumberformat* lcl_GetFormat( SvNumberFormatter const * pFormatter,
1925  sal_uInt32 nKey )
1926 {
1927  return ( pFormatter != nullptr ) ? pFormatter->GetEntry( nKey ) : nullptr;
1928 }
1929 
1930 sal_uInt32 SvXMLNumFmtExport::ForceSystemLanguage( sal_uInt32 nKey )
1931 {
1932  sal_uInt32 nRet = nKey;
1933 
1934  const SvNumberformat* pFormat = lcl_GetFormat( pFormatter, nKey );
1935  if( pFormat != nullptr )
1936  {
1937  SAL_WARN_IF( pFormatter == nullptr, "xmloff.style", "format without formatter?" );
1938 
1939  SvNumFormatType nType = pFormat->GetType();
1940 
1941  sal_uInt32 nNewKey = pFormatter->GetFormatForLanguageIfBuiltIn(
1942  nKey, LANGUAGE_SYSTEM );
1943 
1944  if( nNewKey != nKey )
1945  {
1946  nRet = nNewKey;
1947  }
1948  else
1949  {
1950  OUString aFormatString( pFormat->GetFormatstring() );
1951  sal_Int32 nErrorPos;
1953  aFormatString,
1954  nErrorPos, nType, nNewKey,
1955  pFormat->GetLanguage(), LANGUAGE_SYSTEM, true);
1956 
1957  // success? Then use new key.
1958  if( nErrorPos == 0 )
1959  nRet = nNewKey;
1960  }
1961  }
1962 
1963  return nRet;
1964 }
1965 
1966 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
NF_KEY_NN
NF_KEY_RR
void GetNumForInfo(sal_uInt16 nNumFor, SvNumFormatType &rScannedType, bool &bThousand, sal_uInt16 &nPrecision, sal_uInt16 &nLeadingCnt) const
NF_SYMBOLTYPE_DEL
NUMBERFORMAT_OP_GT
sal_uInt32 GetFormatForLanguageIfBuiltIn(sal_uInt32 nFormat, LanguageType eLnge=LANGUAGE_DONTKNOW)
size_t size() const
Definition: xmlnumfe.cxx:90
NF_SYMBOLTYPE_BLANK
bool IsWasUsed(sal_uInt32 nKey) const
Definition: xmlnumfe.cxx:143
std::unique_ptr< LocaleDataWrapper > pLocaleData
Definition: xmlnumfe.hxx:56
NF_KEY_AMPM
NF_KEY_G
NF_KEY_MI
SAL_DLLPRIVATE void WriteSecondsElement_Impl(bool bLong, sal_uInt16 nDecimals)
Definition: xmlnumfe.cxx:505
short GetNumForType(sal_uInt16 nNumFor, sal_uInt16 nPos) const
NF_KEY_R
SvXMLuInt32Set::iterator aCurrentUsedPos
Definition: xmlnumfe.cxx:100
SAL_DLLPRIVATE void WriteMinutesElement_Impl(bool bLong)
Definition: xmlnumfe.cxx:480
NF_KEY_YY
NF_CURRENCY_1000DEC2
NF_KEY_NNNN
SAL_DLLPRIVATE void AddStyleAttr_Impl(bool bLong)
Definition: xmlnumfe.cxx:297
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:127
static OUString lcl_CreateStyleName(sal_Int32 nKey, sal_Int32 nPart, bool bDefPart, const OUString &rPrefix)
Definition: xmlnumfe.cxx:276
NF_DATE_SYS_NNDMMMMYYYY
NF_SYMBOLTYPE_DATESEP
LanguageType getLanguageType(bool bResolveSystem=true) const
NF_DATETIME_SYS_DDMMYYYY_HHMMSS
NF_KEY_D
uno::Sequence< sal_Int32 > GetWasUsed() const
Definition: xmlnumfe.cxx:191
void GetCompatibilityCurrency(OUString &rSymbol, OUString &rAbbrev) const
SAL_DLLPRIVATE void AddToTextElement_Impl(const OUString &rString)
Definition: xmlnumfe.cxx:316
void push_back(SvXMLEmbeddedTextEntry const &r)
Definition: xmlnumfe.cxx:80
OUString GetIntegerFractionDelimiterString(sal_uInt16 nNumFor) const
NF_KEY_EC
bool IsUsed(sal_uInt32 nKey) const
Definition: xmlnumfe.cxx:137
void GetConditions(SvNumberformatLimitOps &rOper1, double &rVal1, SvNumberformatLimitOps &rOper2, double &rVal2) const
NF_SYMBOLTYPE_TIMESEP
NUMBERFORMAT_OP_NO
NF_CURRENCY_1000DEC2_DASHED
static sal_Int32 GetQuoteEnd(const OUString &rString, sal_Int32 nPos, sal_Unicode cQuote= '"', sal_Unicode cEscIn = '\0' )
NfIndexTableOffset GetIndexTableOffset(sal_uInt32 nFormat) const
constexpr sal_uInt16 XML_NAMESPACE_LO_EXT
NF_KEY_QQ
SAL_DLLPRIVATE void WriteMapElement_Impl(sal_Int32 nOp, double fLimit, sal_Int32 nKey, sal_Int32 nPart)
Definition: xmlnumfe.cxx:800
SAL_DLLPRIVATE void WriteCurrencyElement_Impl(const OUString &rString, const OUString &rExt)
Definition: xmlnumfe.cxx:348
NF_CURRENCY_1000INT_RED
NF_KEY_NNN
SAL_DLLPRIVATE void ExportFormat_Impl(const SvNumberformat &rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey)
Definition: xmlnumfe.cxx:1785
NF_KEY_DD
constexpr sal_uInt16 XML_NAMESPACE_NUMBER
const OUString & GetFormatstring() const
void getIsoLanguageScriptCountry(OUString &rLanguage, OUString &rScript, OUString &rCountry) const
NF_DATE_SYS_DDMMM
OUString GetDenominatorString(sal_uInt16 nNumFor) const
NF_DATE_SYS_DDMMYY
OUString GetStyleName(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1887
static void convertDouble(OUStringBuffer &rBuffer, double fNumber, bool bWriteUnits, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
OUString sPrefix
Definition: xmlnumfe.hxx:51
NF_NUMBER_STANDARD
sal_uInt16 sal_Unicode
SAL_DLLPRIVATE void WriteWeekElement_Impl(const OUString &rCalendar)
Definition: xmlnumfe.cxx:447
SAL_DLLPRIVATE void WriteAMPMElement_Impl()
Definition: xmlnumfe.cxx:520
void Export(bool bIsAutoStyle)
Definition: xmlnumfe.cxx:1836
SvXMLuInt32Set aUsed
Definition: xmlnumfe.cxx:98
NF_KEY_S
NF_KEY_GENERAL
NF_KEY_MMMM
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
void AddLanguageTagAttributes(sal_uInt16 nPrefix, sal_uInt16 nPrefixRfc, const css::lang::Locale &rLocale, bool bWriteEmpty)
Add language tag attributes, deciding which are necessary.
Definition: xmlexp.cxx:959
css::uno::Sequence< sal_Int32 > GetWasUsed() const
Definition: xmlnumfe.cxx:1911
int nCount
void SetWasUsed(const css::uno::Sequence< sal_Int32 > &rWasUsed)
Definition: xmlnumfe.cxx:1918
void AddAttribute(sal_uInt16 nPrefix, const char *pName, const OUString &rValue)
Definition: xmlexp.cxx:909
sal_uInt32 nUsedCount
Definition: xmlnumfe.cxx:101
NF_SYMBOLTYPE_DECSEP
NfIndexTableOffset
bool GetNextUsed(sal_uInt32 &nKey)
Definition: xmlnumfe.cxx:176
NF_KEY_M
static OUString lcl_GetDefaultCalendar(SvNumberFormatter const *pFormatter, LanguageType nLang)
Definition: xmlnumfe.cxx:922
NUMBERFORMAT_OP_LT
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:49
CalendarWrapper * GetCalendar() const
DocumentType eType
static const SvNumberformat * lcl_GetFormat(SvNumberFormatter const *pFormatter, sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1924
SvNumberformatLimitOps
SvXMLNumFmtExport(SvXMLExport &rExport, const css::uno::Reference< css::util::XNumberFormatsSupplier > &rSupp)
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
returns the deterministic version for odf export
Definition: xmlexp.cxx:2297
OUString sPrefix
static LanguageType getSystemLanguage()
const LanguageTag & GetLanguageTag() const
SAL_DLLPRIVATE void WriteColorElement_Impl(const Color &rColor)
Definition: xmlnumfe.cxx:335
NF_BOOLEAN
SvNumFormatType GetType() const
NF_SYMBOLTYPE_DIGIT
SAL_DLLPRIVATE void AddLanguageAttr_Impl(LanguageType nLang)
Definition: xmlnumfe.cxx:305
bool HasTextFormat() const
NF_KEY_EEC
SvXMLNumUsedList_Impl()
SvXMLNumUsedList_Impl should be optimized!
Definition: xmlnumfe.cxx:121
constexpr sal_uInt16 XML_NAMESPACE_FO
std::map< sal_uInt32, SvNumberformat * > SvNumberFormatTable
#define DBG_ASSERT(sCon, aError)
NF_DATE_SYS_DMMMYYYY
int i
NF_KEY_MM
bool PutandConvertEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge, LanguageType eNewLnge, bool bConvertDateOrder)
NF_KEY_DDDD
NF_KEY_SS
const SvNumberformat * GetSubstitutedEntry(sal_uInt32 nKey, sal_uInt32 &o_rNewKey) const
SvXMLDateElementAttributes
Definition: xmlnumfi.hxx:49
#define LANGUAGE_SYSTEM
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
Definition: xmlexp.hxx:520
SAL_DLLPRIVATE void WriteNumberElement_Impl(sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, const OUString &rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries)
Definition: xmlnumfe.cxx:530
NF_KEY_GG
NF_DATETIME_SYS_DDMMYYYY_HHMM
sal_uInt32 ForceSystemLanguage(sal_uInt32 nKey)
obtain number format with system language for a given key
Definition: xmlnumfe.cxx:1930
NF_TEXT
SvNumFormatType
NF_CURRENCY_1000DEC2_RED
NF_DATE_SYS_DDMMYYYY
NF_SYMBOLTYPE_STRING
const OUString & GetComment() const
static sal_Int32 InsertBlanks(OUString &r, sal_Int32 nPos, sal_Unicode c)
SAL_DLLPRIVATE void AddCalendarAttr_Impl(const OUString &rCalendar)
Definition: xmlnumfe.cxx:289
static bool lcl_IsInEmbedded(const SvXMLEmbeddedTextEntryArr &rEmbeddedEntries, sal_uInt16 nPos)
Definition: xmlnumfe.cxx:941
NF_KEY_AAA
NF_KEY_MMI
NF_SYMBOLTYPE_TIME100SECSEP
const css::uno::Reference< css::uno::XComponentContext > & GetComponentContext() const
SvNumberFormatter * pFormatter
Definition: xmlnumfe.hxx:52
NF_NUMBER_SYSTEM
NF_KEY_GGG
SAL_DLLPRIVATE void WriteMonthElement_Impl(const OUString &rCalendar, bool bLong, bool bText)
Definition: xmlnumfe.cxx:399
NF_KEY_H
NUMBERFORMAT_OP_NE
NF_KEY_MMMMM
NF_SYMBOLTYPE_THSEP
OUString EncodeStyleName(const OUString &rName, bool *pEncoded=nullptr) const
Definition: xmlexp.cxx:1954
const Color * GetColor(sal_uInt16 nNumFor) const
SAL_DLLPRIVATE void WriteQuarterElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:457
NF_SYMBOLTYPE_PERCENT
std::unique_ptr< SvXMLNumUsedList_Impl > pUsedList
Definition: xmlnumfe.hxx:54
NF_KEY_MMM
NF_SYMBOLTYPE_EXP
NF_KEY_YYYY
NUMBERFORMAT_OP_EQ
NUMBERFORMAT_OP_GE
OUString GetNumeratorString(sal_uInt16 nNumFor) const
void ChangeIntl(LanguageType eLnge)
NF_KEY_CCC
NF_DATE_SYSTEM_LONG
#define SAL_WARN_IF(condition, area, stream)
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
static bool convertColor(sal_Int32 &rColor, const OUString &rValue)
NF_SYMBOLTYPE_CURRENCY
NF_DATE_SYS_NNNNDMMMMYYYY
Handling of tokens in XML:
SAL_DLLPRIVATE void WriteRepeatedElement_Impl(sal_Unicode ch)
Definition: xmlnumfe.cxx:490
SvXMLExport & rExport
Definition: xmlnumfe.hxx:50
void Characters(const OUString &rChars)
Definition: xmlexp.cxx:2158
SAL_DLLPRIVATE void ExportPart_Impl(const SvNumberformat &rFormat, sal_uInt32 nKey, sal_uInt32 nRealKey, sal_uInt16 nPart, bool bDefPart)
Definition: xmlnumfe.cxx:1024
NF_DATE_SYS_DMMMYY
OUStringBuffer sTextContent
Definition: xmlnumfe.hxx:53
SAL_DLLPRIVATE bool WriteTextWithCurrency_Impl(const OUString &rString, const css::lang::Locale &rLocale)
Definition: xmlnumfe.cxx:878
SAL_DLLPRIVATE void FinishTextElement_Impl(bool bUseExtensionNS=false)
Definition: xmlnumfe.cxx:324
NF_DATE_SYSTEM_SHORT
static sal_uInt16 GetDefaultDateFormat(SvXMLDateElementAttributes eDOW, SvXMLDateElementAttributes eDay, SvXMLDateElementAttributes eMonth, SvXMLDateElementAttributes eYear, SvXMLDateElementAttributes eHours, SvXMLDateElementAttributes eMins, SvXMLDateElementAttributes eSecs, bool bSystem)
Definition: xmlnumfi.cxx:1084
NF_DATE_SYS_MMYY
void SetWasUsed(const uno::Sequence< sal_Int32 > &rWasUsed)
Definition: xmlnumfe.cxx:196
const OUString * GetNumForString(sal_uInt16 nNumFor, sal_uInt16 nPos, bool bString=false) const
SvNumberFormatter * GetNumberFormatter() const
SAL_DLLPRIVATE void WriteYearElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:414
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfe.cxx:1898
SAL_DLLPRIVATE void WriteScientificElement_Impl(sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign)
Definition: xmlnumfe.cxx:621
SAL_DLLPRIVATE void WriteBooleanElement_Impl()
Definition: xmlnumfe.cxx:370
NF_CURRENCY_1000INT
SAL_DLLPRIVATE void WriteTextContentElement_Impl()
Definition: xmlnumfe.cxx:378
QPRO_FUNC_TYPE nType
NF_KEY_WW
static sal_Int32 lcl_FindSymbol(const OUString &sUpperStr, std::u16string_view sCurString)
Definition: xmlnumfe.cxx:840
static bool lcl_IsDefaultDateFormat(const SvNumberformat &rFormat, bool bSystemDate, NfIndexTableOffset eBuiltIn)
Definition: xmlnumfe.cxx:951
SvXMLuInt32Set aWasUsed
Definition: xmlnumfe.cxx:99
void GetUsedLanguages(std::vector< LanguageType > &rList)
NF_KEY_AAAA
sal_uInt16 GetNumForNumberElementCount(sal_uInt16 nNumFor) const
NF_SYMBOLTYPE_CALENDAR
NF_DATE_SYS_NNDMMMYY
sal_uInt32 nWasUsedCount
Definition: xmlnumfe.cxx:102
SAL_DLLPRIVATE void WriteDayOfWeekElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:436
NF_DATETIME_SYSTEM_SHORT_HHMM
#define SAL_WARN(area, stream)
SvNumFormatType GetNumForInfoScannedType(sal_uInt16 nNumFor) const
SAL_DLLPRIVATE void WriteEraElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:425
NF_KEY_AP
sal_Int32 nLength
Definition: xmltoken.cxx:36
NF_CURRENCY_1000DEC2_CCC
SAL_DLLPRIVATE void WriteFractionElement_Impl(sal_Int32 nInteger, bool bGrouping, const SvNumberformat &rFormat, sal_uInt16 nPart)
Definition: xmlnumfe.cxx:697
const SvXMLEmbeddedTextEntry & operator[](size_t i) const
Definition: xmlnumfe.cxx:85
std::set< sal_uInt32 > SvXMLuInt32Set
Definition: xmlnumfe.cxx:57
bool GetFirstUsed(sal_uInt32 &nKey)
Definition: xmlnumfe.cxx:163
NF_KEY_Q
std::vector< SvXMLEmbeddedTextEntry > DataType
Definition: xmlnumfe.cxx:75
void GetNatNumXml(css::i18n::NativeNumberXmlAttributes2 &rAttr, sal_uInt16 nNumFor) const
std::unique_ptr< CharClass > pCharClass
Definition: xmlnumfe.hxx:55
css::uno::Sequence< OUString > getAllCalendars(const css::lang::Locale &rLocale) const
SAL_DLLPRIVATE void WriteDayElement_Impl(const OUString &rCalendar, bool bLong)
Definition: xmlnumfe.cxx:388
SvNumberFormatTable & GetEntryTable(SvNumFormatType eType, sal_uInt32 &FIndex, LanguageType eLnge)
NF_SYMBOLTYPE_STAR
NF_KEY_HH
css::uno::Any const SvXMLExport & rExport
Definition: ImageStyle.hxx:38
NF_KEY_DDD
NF_SYMBOLTYPE_CURREXT
bool IsSubstituted() const
constexpr sal_uInt16 XML_NAMESPACE_STYLE
NUMBERFORMAT_OP_LE
LanguageType GetLanguage() const
sal_uInt16 nPos
SAL_DLLPRIVATE void WriteHoursElement_Impl(bool bLong)
Definition: xmlnumfe.cxx:470
NF_DATE_SYS_DMMMMYYYY
static css::lang::Locale convertToLocale(LanguageType nLangID, bool bResolveSystem=true)
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill= '\0')