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