LibreOffice Module xmloff (master)  1
xmlnumfi.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 <svl/zforlist.hxx>
21 
22 #include <svl/zformat.hxx>
23 #include <svl/numuno.hxx>
25 #include <tools/color.hxx>
26 #include <osl/diagnose.h>
27 #include <rtl/math.hxx>
28 #include <rtl/ustrbuf.hxx>
29 #include <sal/log.hxx>
30 
31 #include <sax/tools/converter.hxx>
32 
33 #include <xmloff/xmlement.hxx>
34 #include <xmloff/xmlnumfi.hxx>
35 #include <xmloff/xmltkmap.hxx>
36 #include <xmloff/xmlnamespace.hxx>
37 #include <xmloff/xmlictxt.hxx>
38 #include <xmloff/xmlimp.hxx>
39 #include <xmloff/xmluconv.hxx>
40 #include <xmloff/namespacemap.hxx>
41 #include <xmloff/families.hxx>
42 #include <xmloff/xmltoken.hxx>
44 
45 #include <memory>
46 #include <vector>
47 
48 using namespace ::com::sun::star;
49 using namespace ::xmloff::token;
50 
51 namespace {
52 
53 struct SvXMLNumFmtEntry
54 {
55  OUString aName;
56  sal_uInt32 nKey;
57  bool bRemoveAfterUse;
58 
59  SvXMLNumFmtEntry( const OUString& rN, sal_uInt32 nK, bool bR ) :
60  aName(rN), nKey(nK), bRemoveAfterUse(bR) {}
61 };
62 
63 }
64 
66 {
68  std::unique_ptr<LocaleDataWrapper> pLocaleData;
69  std::vector<SvXMLNumFmtEntry> m_NameEntries;
70 
71  uno::Reference< uno::XComponentContext > m_xContext;
72 
73 public:
75  SvNumberFormatter* pFmt,
76  const uno::Reference<uno::XComponentContext>& rxContext );
77 
80  sal_uInt32 GetKeyForName( const OUString& rName );
81  void AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse );
82  void SetUsed( sal_uInt32 nKey );
83  void RemoveVolatileFormats();
84 };
85 
87 {
88  sal_Int32 nDecimals = -1;
89  sal_Int32 nInteger = -1;
90  sal_Int32 nExpDigits = -1;
91  sal_Int32 nExpInterval = -1;
92  sal_Int32 nMinNumerDigits = -1;
93  sal_Int32 nMinDenomDigits = -1;
94  sal_Int32 nMaxNumerDigits = -1;
95  sal_Int32 nMaxDenomDigits = -1;
96  sal_Int32 nFracDenominator = -1;
97  sal_Int32 nMinDecimalDigits = -1;
98  sal_Int32 nZerosNumerDigits = -1;
99  sal_Int32 nZerosDenomDigits = -1;
100  bool bGrouping = false;
101  bool bDecReplace = false;
102  bool bExpSign = true;
103  bool bDecAlign = false;
104  double fDisplayFactor = 1.0;
106  std::map<sal_Int32, OUString> m_EmbeddedElements;
107 };
108 
109 namespace {
110 
111 enum class SvXMLStyleTokens;
112 
113 class SvXMLNumFmtElementContext : public SvXMLImportContext
114 {
115  SvXMLNumFormatContext& rParent;
117  OUStringBuffer aContent;
118  SvXMLNumberInfo aNumInfo;
119  LanguageType nElementLang;
120  bool bLong;
121  bool bTextual;
122  OUString sCalendar;
123 
124 public:
125  SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nElement,
126  SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType,
127  const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
128 
129  virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(
130  sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override;
131  virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/,
132  const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {}
133  virtual void SAL_CALL characters( const OUString& rChars ) override;
134  virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
135 
136  void AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent );
137 };
138 
139 class SvXMLNumFmtEmbeddedTextContext : public SvXMLImportContext
140 {
141  SvXMLNumFmtElementContext& rParent;
142  OUStringBuffer aContent;
143  sal_Int32 nTextPosition;
144 
145 public:
146  SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport, sal_Int32 nElement,
147  SvXMLNumFmtElementContext& rParentContext,
148  const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
149 
150  virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/,
151  const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {}
152  virtual void SAL_CALL characters( const OUString& rChars ) override;
153  virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
154 };
155 
156 class SvXMLNumFmtMapContext : public SvXMLImportContext
157 {
158  SvXMLNumFormatContext& rParent;
159  OUString sCondition;
160  OUString sName;
161 
162 public:
163  SvXMLNumFmtMapContext( SvXMLImport& rImport, sal_Int32 nElement,
164  SvXMLNumFormatContext& rParentContext,
165  const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
166 
167  virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/,
168  const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {}
169  virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
170 };
171 
172 class SvXMLNumFmtPropContext : public SvXMLImportContext
173 {
174  SvXMLNumFormatContext& rParent;
175  Color m_nColor;
176  bool bColSet;
177 
178 public:
179  SvXMLNumFmtPropContext( SvXMLImport& rImport, sal_Int32 nElement,
180  SvXMLNumFormatContext& rParentContext,
181  const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList );
182 
183  virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/,
184  const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {}
185  virtual void SAL_CALL endFastElement(sal_Int32 nElement) override;
186 };
187 
189 {
190  Text,
191  FillCharacter,
192  Number,
193  ScientificNumber,
194  Fraction,
195  CurrencySymbol,
196  Day,
197  Month,
198  Year,
199  Era,
200  DayOfWeek,
201  WeekOfYear,
202  Quarter,
203  Hours,
204  AmPm,
205  Minutes,
206  Seconds,
207  Boolean,
208  TextContent
209 };
210 
211 }
212 
213 // standard colors
214 
215 
216 #define XML_NUMF_COLORCOUNT 10
217 
219 {
220  COL_BLACK,
224  COL_LIGHTRED,
226  COL_BROWN,
227  COL_GRAY,
228  COL_YELLOW,
229  COL_WHITE
230 };
231 
232 
233 // token maps
234 
235 
236 // maps for SvXMLUnitConverter::convertEnum
237 
239 {
240  { XML_SHORT, false },
241  { XML_LONG, true },
242  { XML_TOKEN_INVALID, false }
243 };
244 
246 {
247  { XML_FIXED, false },
248  { XML_LANGUAGE, true },
249  { XML_TOKEN_INVALID, false }
250 };
251 
252 namespace {
253 
254 struct SvXMLDefaultDateFormat
255 {
256  NfIndexTableOffset eFormat;
264  bool bSystem;
265 };
266 
267 }
268 
269 const SvXMLDefaultDateFormat aDefaultDateFormats[] =
270 {
271  // format day-of-week day month year hours minutes seconds format-source
272 
288 };
289 
290 
291 // SvXMLNumImpData
292 
293 
295  SvNumberFormatter* pFmt,
296  const uno::Reference<uno::XComponentContext>& rxContext )
297 : pFormatter(pFmt),
298  m_xContext(rxContext)
299 {
300  SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" );
301 }
302 
303 sal_uInt32 SvXMLNumImpData::GetKeyForName( const OUString& rName )
304 {
305  for (const auto& rObj : m_NameEntries)
306  {
307  if (rObj.aName == rName)
308  return rObj.nKey; // found
309  }
311 }
312 
313 void SvXMLNumImpData::AddKey( sal_uInt32 nKey, const OUString& rName, bool bRemoveAfterUse )
314 {
315  if ( bRemoveAfterUse )
316  {
317  // if there is already an entry for this key without the bRemoveAfterUse flag,
318  // clear the flag for this entry, too
319 
320  for (const auto& rObj : m_NameEntries)
321  {
322  if (rObj.nKey == nKey && !rObj.bRemoveAfterUse)
323  {
324  bRemoveAfterUse = false; // clear flag for new entry
325  break;
326  }
327  }
328  }
329  else
330  {
331  // call SetUsed to clear the bRemoveAfterUse flag for other entries for this key
332  SetUsed( nKey );
333  }
334 
335  m_NameEntries.emplace_back(rName, nKey, bRemoveAfterUse);
336 }
337 
338 void SvXMLNumImpData::SetUsed( sal_uInt32 nKey )
339 {
340  for (auto& rObj : m_NameEntries)
341  {
342  if (rObj.nKey == nKey)
343  {
344  rObj.bRemoveAfterUse = false; // used -> don't remove
345 
346  // continue searching - there may be several entries for the same key
347  // (with different names), the format must not be deleted if any one of
348  // them is used
349  }
350  }
351 }
352 
354 {
355  // remove temporary (volatile) formats from NumberFormatter
356  // called at the end of each import (styles and content), so volatile formats
357  // from styles can't be used in content
358 
359  if ( !pFormatter )
360  return;
361 
362  for (const auto& rObj : m_NameEntries)
363  {
364  if (rObj.bRemoveAfterUse )
365  {
366  const SvNumberformat* pFormat = pFormatter->GetEntry(rObj.nKey);
367  if (pFormat && (pFormat->GetType() & SvNumFormatType::DEFINED))
368  pFormatter->DeleteEntry(rObj.nKey);
369  }
370  }
371 }
372 
374 {
375  if ( !pLocaleData )
376  pLocaleData = std::make_unique<LocaleDataWrapper>(
378  LanguageTag( nLang ) );
379  else
380  pLocaleData->setLanguageTag( LanguageTag( nLang ) );
381  return *pLocaleData;
382 }
383 
384 
385 // SvXMLNumFmtMapContext
386 
387 
388 SvXMLNumFmtMapContext::SvXMLNumFmtMapContext( SvXMLImport& rImport,
389  sal_Int32 /*nElement*/,
390  SvXMLNumFormatContext& rParentContext,
391  const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
392  SvXMLImportContext( rImport ),
393  rParent( rParentContext )
394 {
395  for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
396  {
397  OUString sValue = aIter.toString();
398  switch(aIter.getToken())
399  {
400  case XML_ELEMENT(STYLE, XML_CONDITION):
401  sCondition = sValue;
402  break;
403  case XML_ELEMENT(STYLE, XML_APPLY_STYLE_NAME):
404  sName = sValue;
405  break;
406  default:
407  SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << sValue);
408  }
409  }
410 }
411 
412 void SvXMLNumFmtMapContext::endFastElement(sal_Int32 )
413 {
414  rParent.AddCondition( sCondition, sName );
415 }
416 
417 
418 // SvXMLNumFmtPropContext
419 
420 
421 SvXMLNumFmtPropContext::SvXMLNumFmtPropContext( SvXMLImport& rImport,
422  sal_Int32 /*nElement*/,
423  SvXMLNumFormatContext& rParentContext,
424  const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
425  SvXMLImportContext( rImport ),
426  rParent( rParentContext ),
427  m_nColor( 0 ),
428  bColSet( false )
429 {
430  for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
431  {
432  OUString sValue = aIter.toString();
433  switch ( aIter.getToken())
434  {
435  case XML_ELEMENT(FO, XML_COLOR):
436  case XML_ELEMENT(FO_COMPAT, XML_COLOR):
437  bColSet = ::sax::Converter::convertColor( m_nColor, sValue );
438  break;
439  default:
440  SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << sValue);
441  }
442  }
443 }
444 
445 void SvXMLNumFmtPropContext::endFastElement(sal_Int32 )
446 {
447  if (bColSet)
448  rParent.AddColor( m_nColor );
449 }
450 
451 
452 // SvXMLNumFmtEmbeddedTextContext
453 
454 
455 SvXMLNumFmtEmbeddedTextContext::SvXMLNumFmtEmbeddedTextContext( SvXMLImport& rImport,
456  sal_Int32 /*nElement*/,
457  SvXMLNumFmtElementContext& rParentContext,
458  const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
459  SvXMLImportContext( rImport ),
460  rParent( rParentContext ),
461  nTextPosition( 0 )
462 {
463  sal_Int32 nAttrVal;
464 
465  for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
466  {
467  OUString sValue = aIter.toString();
468  if ( aIter.getToken() == XML_ELEMENT(NUMBER, XML_POSITION) )
469  {
470  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
471  nTextPosition = nAttrVal;
472  }
473  else
474  SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << sValue);
475  }
476 }
477 
478 void SvXMLNumFmtEmbeddedTextContext::characters( const OUString& rChars )
479 {
480  aContent.append( rChars );
481 }
482 
483 void SvXMLNumFmtEmbeddedTextContext::endFastElement(sal_Int32 )
484 {
485  rParent.AddEmbeddedElement( nTextPosition, aContent.makeStringAndClear() );
486 }
487 
488 static bool lcl_ValidChar( sal_Unicode cChar, const SvXMLNumFormatContext& rParent )
489 {
490  SvXMLStylesTokens nFormatType = rParent.GetType();
491 
492  // Treat space equal to non-breaking space separator.
493  const sal_Unicode cNBSP = 0x00A0;
494  sal_Unicode cTS;
495  if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE ||
496  nFormatType == SvXMLStylesTokens::CURRENCY_STYLE ||
497  nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) &&
498  (cChar == (cTS = rParent.GetLocaleData().getNumThousandSep()[0]) ||
499  (cChar == ' ' && cTS == cNBSP)) )
500  {
501  // #i22394# Extra occurrences of thousands separator must be quoted, so they
502  // aren't mis-interpreted as display-factor.
503  // This must be limited to the format types that can contain a number element,
504  // because the same character can be a date separator that should not be quoted
505  // in date formats.
506 
507  return false; // force quotes
508  }
509 
510  // see ImpSvNumberformatScan::Next_Symbol
511  if ( cChar == '-' )
512  return true; // all format types may content minus sign or delimiter
513  if ( ( cChar == ' ' ||
514  cChar == '/' ||
515  cChar == '.' ||
516  cChar == ',' ||
517  cChar == ':' ||
518  cChar == '\'' ) &&
519  ( nFormatType == SvXMLStylesTokens::CURRENCY_STYLE ||
520  nFormatType == SvXMLStylesTokens::DATE_STYLE ||
521  nFormatType == SvXMLStylesTokens::TIME_STYLE ) ) // other formats do not require delimiter tdf#97837
522  return true;
523 
524  // percent sign must be used without quotes for percentage styles only
525  if ( nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE && cChar == '%' )
526  return true;
527 
528  // don't put quotes around single parentheses (often used for negative numbers)
529  if ( ( nFormatType == SvXMLStylesTokens::NUMBER_STYLE ||
530  nFormatType == SvXMLStylesTokens::CURRENCY_STYLE ||
531  nFormatType == SvXMLStylesTokens::PERCENTAGE_STYLE ) &&
532  ( cChar == '(' || cChar == ')' ) )
533  return true;
534 
535  return false;
536 }
537 
538 static void lcl_EnquoteIfNecessary( OUStringBuffer& rContent, const SvXMLNumFormatContext& rParent )
539 {
540  bool bQuote = true;
541  sal_Int32 nLength = rContent.getLength();
542 
543  if ((nLength == 1 && lcl_ValidChar( rContent[0], rParent)) ||
544  (nLength == 2 &&
545  ((rContent[0] == ' ' && rContent[1] == '-') ||
546  (rContent[1] == ' ' && lcl_ValidChar( rContent[0], rParent)))))
547  {
548  // Don't quote single separator characters like space or percent,
549  // or separator characters followed by space (used in date formats).
550  // Or space followed by minus (used in currency formats) that would
551  // lead to almost duplicated formats with built-in formats just with
552  // the difference of quotes.
553  bQuote = false;
554  }
555  else if ( rParent.GetType() == SvXMLStylesTokens::PERCENTAGE_STYLE && nLength > 1 )
556  {
557  // the percent character in percentage styles must be left out of quoting
558  // (one occurrence is enough even if there are several percent characters in the string)
559 
560  OUString aString( rContent.toString() );
561  sal_Int32 nPos = aString.indexOf( '%' );
562  if ( nPos >= 0 )
563  {
564  if ( nPos + 1 < nLength )
565  {
566  if ( nPos + 2 == nLength && lcl_ValidChar( rContent[nPos + 1], rParent ) )
567  {
568  // single character that doesn't need quoting
569  }
570  else
571  {
572  // quote text behind percent character
573  rContent.insert( nPos + 1, '"' );
574  rContent.append( '"' );
575  }
576  }
577  if ( nPos > 0 )
578  {
579  if ( nPos == 1 && lcl_ValidChar( rContent[0], rParent ) )
580  {
581  // single character that doesn't need quoting
582  }
583  else
584  {
585  // quote text before percent character
586  rContent.insert( nPos, '"' );
587  rContent.insert( 0, '"' );
588  }
589  }
590  bQuote = false;
591  }
592  // else: normal quoting (below)
593  }
594 
595  if ( !bQuote )
596  return;
597 
598  // #i55469# quotes in the string itself have to be escaped
599  bool bEscape = ( rContent.indexOf( '"' ) >= 0 );
600  if ( bEscape )
601  {
602  // A quote is turned into "\"" - a quote to end quoted text, an escaped quote,
603  // and a quote to resume quoting.
604  OUString aInsert( "\"\\\"" );
605 
606  sal_Int32 nPos = 0;
607  while ( nPos < rContent.getLength() )
608  {
609  if ( rContent[nPos] == '"' )
610  {
611  rContent.insert( nPos, aInsert );
612  nPos += aInsert.getLength();
613  }
614  ++nPos;
615  }
616  }
617 
618  // quote string literals
619  rContent.insert( 0, '"' );
620  rContent.append( '"' );
621 
622  // remove redundant double quotes at start or end
623  if ( !bEscape )
624  return;
625 
626  if ( rContent.getLength() > 2 &&
627  rContent[0] == '"' &&
628  rContent[1] == '"' )
629  {
630  rContent.remove(0, 2);
631  }
632 
633  sal_Int32 nLen = rContent.getLength();
634  if ( nLen > 2 &&
635  rContent[nLen - 1] == '"' &&
636  rContent[nLen - 2] == '"' )
637  {
638  rContent.truncate(nLen - 2);
639  }
640 }
641 
642 
643 // SvXMLNumFmtElementContext
644 
645 
646 SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport,
647  sal_Int32 /*nElement*/,
648  SvXMLNumFormatContext& rParentContext, SvXMLStyleTokens nNewType,
649  const uno::Reference<xml::sax::XFastAttributeList>& xAttrList ) :
650  SvXMLImportContext( rImport ),
651  rParent( rParentContext ),
652  nType( nNewType ),
653  nElementLang( LANGUAGE_SYSTEM ),
654  bLong( false ),
655  bTextual( false )
656 {
657  LanguageTagODF aLanguageTagODF;
658  sal_Int32 nAttrVal;
659  bool bAttrBool(false);
660  bool bVarDecimals = false;
661  bool bIsMaxDenominator = false;
662  double fAttrDouble;
663 
664  for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
665  {
666  OUString sValue = aIter.toString();
667  switch (aIter.getToken())
668  {
669  case XML_ELEMENT(NUMBER, XML_DECIMAL_PLACES):
670  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
671  {
672  // fdo#58539 & gnome#627420: limit number of digits during import
673  aNumInfo.nDecimals = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS);
674  }
675  break;
676  case XML_ELEMENT(LO_EXT, XML_MIN_DECIMAL_PLACES):
678  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
679  aNumInfo.nMinDecimalDigits = nAttrVal;
680  break;
681  case XML_ELEMENT(NUMBER, XML_MIN_INTEGER_DIGITS):
682  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
683  aNumInfo.nInteger = nAttrVal;
684  break;
685  case XML_ELEMENT(NUMBER, XML_GROUPING):
686  if (::sax::Converter::convertBool( bAttrBool, sValue ))
687  aNumInfo.bGrouping = bAttrBool;
688  break;
689  case XML_ELEMENT(NUMBER, XML_DISPLAY_FACTOR):
690  if (::sax::Converter::convertDouble( fAttrDouble, sValue ))
691  aNumInfo.fDisplayFactor = fAttrDouble;
692  break;
693  case XML_ELEMENT(NUMBER, XML_DECIMAL_REPLACEMENT):
694  if ( sValue == " " )
695  {
696  aNumInfo.bDecAlign = true; // space replacement for "?"
697  bVarDecimals = true;
698  }
699  else
700  if ( sValue.isEmpty() )
701  bVarDecimals = true; // empty replacement string: variable decimals
702  else // all other strings
703  aNumInfo.bDecReplace = true; // decimal replacement with dashes
704  break;
705  case XML_ELEMENT(NUMBER, XML_MIN_EXPONENT_DIGITS):
706  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
707  aNumInfo.nExpDigits = std::min<sal_Int32>(nAttrVal, NF_MAX_FORMAT_SYMBOLS);
708  break;
709  case XML_ELEMENT(NUMBER, XML_EXPONENT_INTERVAL):
710  case XML_ELEMENT(LO_EXT, XML_EXPONENT_INTERVAL):
711  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
712  aNumInfo.nExpInterval = nAttrVal;
713  break;
716  if (::sax::Converter::convertBool( bAttrBool, sValue ))
717  aNumInfo.bExpSign = bAttrBool;
718  break;
720  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
721  aNumInfo.nMinNumerDigits = nAttrVal;
722  break;
724  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
725  aNumInfo.nMinDenomDigits = nAttrVal;
726  break;
728  if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 )) // at least one '#'
729  aNumInfo.nMaxNumerDigits = nAttrVal;
730  break;
731  case XML_ELEMENT(NUMBER, XML_DENOMINATOR_VALUE):
732  if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 )) // 0 is not valid
733  {
734  aNumInfo.nFracDenominator = nAttrVal;
735  bIsMaxDenominator = false;
736  }
737  break;
738  case XML_ELEMENT(NUMBER, XML_MAX_DENOMINATOR_VALUE): // part of ODF 1.3
740  if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 ) && aNumInfo.nFracDenominator <= 0)
741  { // if denominator value not yet defined
742  aNumInfo.nFracDenominator = nAttrVal;
743  bIsMaxDenominator = true;
744  }
745  break;
748  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
749  aNumInfo.nZerosNumerDigits = nAttrVal;
750  break;
753  if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 ))
754  aNumInfo.nZerosDenomDigits = nAttrVal;
755  break;
758  aNumInfo.aIntegerFractionDelimiter = sValue;
759  break;
760  case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG):
761  aLanguageTagODF.maRfcLanguageTag = sValue;
762  break;
763  case XML_ELEMENT(NUMBER, XML_LANGUAGE):
764  aLanguageTagODF.maLanguage = sValue;
765  break;
766  case XML_ELEMENT(NUMBER, XML_SCRIPT):
767  aLanguageTagODF.maScript = sValue;
768  break;
769  case XML_ELEMENT(NUMBER, XML_COUNTRY):
770  aLanguageTagODF.maCountry = sValue;
771  break;
772  case XML_ELEMENT(NUMBER, XML_STYLE):
773  SvXMLUnitConverter::convertEnum( bLong, sValue, aStyleValueMap );
774  break;
775  case XML_ELEMENT(NUMBER, XML_TEXTUAL):
776  if (::sax::Converter::convertBool( bAttrBool, sValue ))
777  bTextual = bAttrBool;
778  break;
779  case XML_ELEMENT(NUMBER, XML_CALENDAR):
780  sCalendar = sValue;
781  break;
782  default:
783  SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << sValue);
784  }
785  }
786  if ( aNumInfo.nMinDecimalDigits == -1)
787  {
788  if ( bVarDecimals || aNumInfo.bDecReplace )
789  aNumInfo.nMinDecimalDigits = 0;
790  else
791  aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals;
792  }
793  if ( aNumInfo.nZerosDenomDigits > 0 )
794  { // nMin = count of '0' and '?'
795  if ( aNumInfo.nMinDenomDigits < aNumInfo.nZerosDenomDigits )
796  aNumInfo.nMinDenomDigits = aNumInfo.nZerosDenomDigits;
797  }
798  else
799  aNumInfo.nZerosDenomDigits = 0;
800  if ( aNumInfo.nMinDenomDigits >= 0 )
801  if ( aNumInfo.nMaxDenomDigits < aNumInfo.nMinDenomDigits )
802  aNumInfo.nMaxDenomDigits = ( aNumInfo.nMinDenomDigits ? aNumInfo.nMinDenomDigits : 1 );
803  if ( aNumInfo.nZerosNumerDigits > 0 )
804  {
805  if ( aNumInfo.nMinNumerDigits < aNumInfo.nZerosNumerDigits )
806  aNumInfo.nMinNumerDigits = aNumInfo.nZerosNumerDigits;
807  }
808  else
809  aNumInfo.nZerosNumerDigits = 0;
810  if ( aNumInfo.nMinNumerDigits >= 0 )
811  if ( aNumInfo.nMaxNumerDigits < aNumInfo.nMinNumerDigits )
812  aNumInfo.nMaxNumerDigits = ( aNumInfo.nMinNumerDigits ? aNumInfo.nMinNumerDigits : 1 );
813  if ( bIsMaxDenominator && aNumInfo.nFracDenominator > 0 )
814  {
815  aNumInfo.nMaxDenomDigits = floor( log10( aNumInfo.nFracDenominator ) ) + 1;
816  aNumInfo.nFracDenominator = -1; // Max denominator value only gives number of digits at denominator
817  }
818  if ( aNumInfo.nMaxDenomDigits > 0 )
819  {
820  if ( aNumInfo.nMinDenomDigits < 0 )
821  aNumInfo.nMinDenomDigits = 0;
822  else if ( aNumInfo.nMinDenomDigits > aNumInfo.nMaxDenomDigits )
823  aNumInfo.nMinDenomDigits = aNumInfo.nMaxDenomDigits;
824  }
825 
826  if ( !aLanguageTagODF.isEmpty() )
827  {
828  nElementLang = aLanguageTagODF.getLanguageTag().getLanguageType( false);
829  if ( nElementLang == LANGUAGE_DONTKNOW )
830  nElementLang = LANGUAGE_SYSTEM;
831  }
832 
833  if ( aNumInfo.aIntegerFractionDelimiter.isEmpty() )
834  aNumInfo.aIntegerFractionDelimiter = " ";
835 }
836 
837 css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFmtElementContext::createFastChildContext(
838  sal_Int32 nElement,
839  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
840 {
841  // only number:number supports number:embedded-text child element
842 
843  if ( nType == SvXMLStyleTokens::Number &&
844  nElement == XML_ELEMENT(NUMBER, XML_EMBEDDED_TEXT) )
845  {
846  return new SvXMLNumFmtEmbeddedTextContext( GetImport(), nElement, *this, xAttrList );
847  }
848  else
849  SAL_WARN("xmloff", "unknown element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
850  return nullptr;
851 }
852 
853 void SvXMLNumFmtElementContext::characters( const OUString& rChars )
854 {
855  aContent.append( rChars );
856 }
857 
858 void SvXMLNumFmtElementContext::AddEmbeddedElement( sal_Int32 nFormatPos, const OUString& rContent )
859 {
860  if (rContent.isEmpty())
861  return;
862 
863  auto iterPair = aNumInfo.m_EmbeddedElements.emplace(nFormatPos, rContent);
864  if (!iterPair.second)
865  // there's already an element at this position - append text to existing element
866  iterPair.first->second += rContent;
867 }
868 
869 void SvXMLNumFmtElementContext::endFastElement(sal_Int32 )
870 {
871  bool bEffLong = bLong;
872  switch (nType)
873  {
874  case SvXMLStyleTokens::Text:
875  if ( rParent.HasLongDoW() &&
876  aContent.toString() == rParent.GetLocaleData().getLongDateDayOfWeekSep() )
877  {
878  // skip separator constant after long day of week
879  // (NF_KEY_NNNN contains the separator)
880 
881  if ( rParent.ReplaceNfKeyword( NF_KEY_NNN, NF_KEY_NNNN ) )
882  {
883  aContent.truncate();
884  }
885 
886  rParent.SetHasLongDoW( false ); // only once
887  }
888  if ( !aContent.isEmpty() )
889  {
890  lcl_EnquoteIfNecessary( aContent, rParent );
891  rParent.AddToCode( aContent.makeStringAndClear() );
892  }
893  break;
894 
895  case SvXMLStyleTokens::Number:
896  rParent.AddNumber( aNumInfo );
897  break;
898 
899  case SvXMLStyleTokens::CurrencySymbol:
900  rParent.AddCurrency( aContent.makeStringAndClear(), nElementLang );
901  break;
902 
903  case SvXMLStyleTokens::TextContent:
904  rParent.AddToCode( '@');
905  break;
906  case SvXMLStyleTokens::FillCharacter:
907  if ( !aContent.isEmpty() )
908  {
909  rParent.AddToCode( '*' );
910  rParent.AddToCode( aContent[0] );
911  }
912  break;
913  case SvXMLStyleTokens::Boolean:
914  // ignored - only default boolean format is supported
915  break;
916 
917  case SvXMLStyleTokens::Day:
918  rParent.UpdateCalendar( sCalendar );
920 
921  rParent.AddNfKeyword(
922  sal::static_int_cast< sal_uInt16 >(
923  bEffLong ? NF_KEY_DD : NF_KEY_D ) );
924  break;
925  case SvXMLStyleTokens::Month:
926  rParent.UpdateCalendar( sCalendar );
928 
929  rParent.AddNfKeyword(
930  sal::static_int_cast< sal_uInt16 >(
931  bTextual
932  ? ( bEffLong ? NF_KEY_MMMM : NF_KEY_MMM )
933  : ( bEffLong ? NF_KEY_MM : NF_KEY_M ) ) );
934  break;
935  case SvXMLStyleTokens::Year:
937  {
938  // Y after G (era) is replaced by E for a secondary calendar.
939  // Do not replace for default calendar.
940  // Also replace Y by E if we're switching to the secondary
941  // calendar of a locale if it is known to implicitly use E.
942  bool bImplicitEC = (!sCalendar.isEmpty() &&
943  rParent.GetLocaleData().doesSecondaryCalendarUseEC( sCalendar));
944  if (bImplicitEC || (!sCalendar.isEmpty() && rParent.HasEra()))
945  {
946  // If E or EE is the first format keyword, passing
947  // bImplicitEC=true suppresses the superfluous calendar
948  // modifier for this format. This does not help for
949  // something like [~cal]DD/MM/EE but so far only YMD order
950  // is used with such calendars. Live with the modifier if
951  // other keywords precede this.
952  rParent.UpdateCalendar( sCalendar, bImplicitEC);
953  rParent.AddNfKeyword(
954  sal::static_int_cast< sal_uInt16 >(
955  bEffLong ? NF_KEY_EEC : NF_KEY_EC ) );
956  }
957  else
958  {
959  rParent.UpdateCalendar( sCalendar );
960  rParent.AddNfKeyword(
961  sal::static_int_cast< sal_uInt16 >(
962  bEffLong ? NF_KEY_YYYY : NF_KEY_YY ) );
963  }
964  }
965  break;
966  case SvXMLStyleTokens::Era:
967  rParent.UpdateCalendar( sCalendar );
969  rParent.AddNfKeyword(
970  sal::static_int_cast< sal_uInt16 >(
971  bEffLong ? NF_KEY_GGG : NF_KEY_G ) );
972  // HasEra flag is set
973  break;
974  case SvXMLStyleTokens::DayOfWeek:
975  rParent.UpdateCalendar( sCalendar );
977  rParent.AddNfKeyword(
978  sal::static_int_cast< sal_uInt16 >(
979  bEffLong ? NF_KEY_NNNN : NF_KEY_NN ) );
980  break;
981  case SvXMLStyleTokens::WeekOfYear:
982  rParent.UpdateCalendar( sCalendar );
983  rParent.AddNfKeyword( NF_KEY_WW );
984  break;
985  case SvXMLStyleTokens::Quarter:
986  rParent.UpdateCalendar( sCalendar );
987  rParent.AddNfKeyword(
988  sal::static_int_cast< sal_uInt16 >(
989  bEffLong ? NF_KEY_QQ : NF_KEY_Q ) );
990  break;
991  case SvXMLStyleTokens::Hours:
992  rParent.AddNfKeyword(
993  sal::static_int_cast< sal_uInt16 >(
994  bEffLong ? NF_KEY_HH : NF_KEY_H ) );
995  break;
996  case SvXMLStyleTokens::AmPm:
998  rParent.AddNfKeyword( NF_KEY_AMPM );
999  break;
1000  case SvXMLStyleTokens::Minutes:
1001  rParent.AddNfKeyword(
1002  sal::static_int_cast< sal_uInt16 >(
1003  bEffLong ? NF_KEY_MMI : NF_KEY_MI ) );
1004  break;
1005  case SvXMLStyleTokens::Seconds:
1006  rParent.AddNfKeyword(
1007  sal::static_int_cast< sal_uInt16 >(
1008  bEffLong ? NF_KEY_SS : NF_KEY_S ) );
1009  if ( aNumInfo.nDecimals > 0 )
1010  {
1011  // manually add the decimal places
1012  rParent.AddToCode(rParent.GetLocaleData().getNumDecimalSep());
1013  for (sal_Int32 i=0; i<aNumInfo.nDecimals; i++)
1014  {
1015  rParent.AddToCode( '0');
1016  }
1017  }
1018  break;
1019 
1020  case SvXMLStyleTokens::Fraction:
1021  {
1022  if ( aNumInfo.nInteger >= 0 )
1023  {
1024  // add integer part only if min-integer-digits attribute is there
1025  aNumInfo.nDecimals = 0;
1026  rParent.AddNumber( aNumInfo ); // number without decimals
1027  OUStringBuffer sIntegerFractionDelimiter = aNumInfo.aIntegerFractionDelimiter;
1028  lcl_EnquoteIfNecessary( sIntegerFractionDelimiter, rParent );
1029  rParent.AddToCode( sIntegerFractionDelimiter.makeStringAndClear() ); // default is ' '
1030  }
1031 
1033 
1034  sal_Int32 i;
1035  for (i=aNumInfo.nMaxNumerDigits; i > 0; i--)
1036  {
1037  if ( i > aNumInfo.nMinNumerDigits )
1038  rParent.AddToCode( '#' );
1039  else if ( i > aNumInfo.nZerosNumerDigits )
1040  rParent.AddToCode( '?' );
1041  else
1042  rParent.AddToCode( '0' );
1043  }
1044  rParent.AddToCode( '/' );
1045  if ( aNumInfo.nFracDenominator > 0 )
1046  {
1047  rParent.AddToCode( OUString::number( aNumInfo.nFracDenominator ) );
1048  }
1049  else
1050  {
1051  for (i=aNumInfo.nMaxDenomDigits; i > 0 ; i--)
1052  {
1053  if ( i > aNumInfo.nMinDenomDigits )
1054  rParent.AddToCode( '#' );
1055  else if ( i > aNumInfo.nZerosDenomDigits )
1056  rParent.AddToCode( '?' );
1057  else
1058  rParent.AddToCode( '0' );
1059  }
1060  }
1061  }
1062  break;
1063 
1064  case SvXMLStyleTokens::ScientificNumber:
1065  {
1066  // exponential interval for engineering notation
1067  if( !aNumInfo.bGrouping && aNumInfo.nExpInterval > aNumInfo.nInteger )
1068  {
1069  for (sal_Int32 i=aNumInfo.nInteger; i<aNumInfo.nExpInterval; i++)
1070  {
1071  rParent.AddToCode( '#' );
1072  }
1073  }
1074  rParent.AddNumber( aNumInfo ); // simple number
1075 
1076  if ( aNumInfo.bExpSign )
1077  rParent.AddToCode( "E+" );
1078  else
1079  rParent.AddToCode( "E" );
1080  for (sal_Int32 i=0; i<aNumInfo.nExpDigits; i++)
1081  {
1082  rParent.AddToCode( '0' );
1083  }
1084  }
1085  break;
1086 
1087  default:
1088  assert(false && "invalid element ID");
1089  }
1090 }
1091 
1096  bool bSystem )
1097 {
1098  for (const auto & rEntry : aDefaultDateFormats)
1099  {
1100  if ( bSystem == rEntry.bSystem &&
1101  ( eDOW == rEntry.eDOW || ( rEntry.eDOW == XML_DEA_ANY && eDOW != XML_DEA_NONE ) ) &&
1102  ( eDay == rEntry.eDay || ( rEntry.eDay == XML_DEA_ANY && eDay != XML_DEA_NONE ) ) &&
1103  ( eMonth == rEntry.eMonth || ( rEntry.eMonth == XML_DEA_ANY && eMonth != XML_DEA_NONE ) ) &&
1104  ( eYear == rEntry.eYear || ( rEntry.eYear == XML_DEA_ANY && eYear != XML_DEA_NONE ) ) &&
1105  ( eHours == rEntry.eHours || ( rEntry.eHours == XML_DEA_ANY && eHours != XML_DEA_NONE ) ) &&
1106  ( eMins == rEntry.eMins || ( rEntry.eMins == XML_DEA_ANY && eMins != XML_DEA_NONE ) ) &&
1107  ( eSecs == rEntry.eSecs || ( rEntry.eSecs == XML_DEA_ANY && eSecs != XML_DEA_NONE ) ) )
1108  {
1109  return sal::static_int_cast< sal_uInt16 >(rEntry.eFormat);
1110  }
1111  }
1112 
1113  return NF_INDEX_TABLE_ENTRIES; // invalid
1114 }
1115 
1116 
1117 // SvXMLNumFormatContext
1118 
1120  sal_Int32 /*nElement*/,
1121  SvXMLNumImpData* pNewData, SvXMLStylesTokens nNewType,
1122  const uno::Reference<xml::sax::XFastAttributeList>& xAttrList,
1123  SvXMLStylesContext& rStyles ) :
1124  SvXMLStyleContext( rImport ),
1125  pData( pNewData ),
1126  pStyles( &rStyles ),
1127  aMyConditions(),
1128  nType( nNewType ),
1129  nKey(-1),
1130  nFormatLang( LANGUAGE_SYSTEM ),
1131  bAutoOrder( false ),
1132  bFromSystem( false ),
1133  bTruncate( true ),
1134  bAutoDec( false ),
1135  bAutoInt( false ),
1136  bHasExtraText( false ),
1137  bHasLongDoW( false ),
1138  bHasEra( false ),
1139  bHasDateTime( false ),
1140  bRemoveAfterUse( false ),
1141  eDateDOW( XML_DEA_NONE ),
1142  eDateDay( XML_DEA_NONE ),
1143  eDateMonth( XML_DEA_NONE ),
1144  eDateYear( XML_DEA_NONE ),
1145  eDateHours( XML_DEA_NONE ),
1146  eDateMins( XML_DEA_NONE ),
1147  eDateSecs( XML_DEA_NONE ),
1148  bDateNoDefault( false )
1149 {
1150  LanguageTagODF aLanguageTagODF;
1151  css::i18n::NativeNumberXmlAttributes aNatNumAttr;
1152  OUString aSpellout;
1153  bool bAttrBool(false);
1154 
1155  for( auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList ) )
1156  {
1157  OUString sValue = aIter.toString();
1158  switch (aIter.getToken())
1159  {
1160  // attributes for a style
1161  case XML_ELEMENT(STYLE, XML_NAME):
1162  break;
1163  case XML_ELEMENT(NUMBER, XML_RFC_LANGUAGE_TAG):
1164  aLanguageTagODF.maRfcLanguageTag = sValue;
1165  break;
1166  case XML_ELEMENT(NUMBER, XML_LANGUAGE):
1167  aLanguageTagODF.maLanguage = sValue;
1168  break;
1169  case XML_ELEMENT(NUMBER, XML_SCRIPT):
1170  aLanguageTagODF.maScript = sValue;
1171  break;
1172  case XML_ELEMENT(NUMBER, XML_COUNTRY):
1173  aLanguageTagODF.maCountry = sValue;
1174  break;
1175  case XML_ELEMENT(NUMBER, XML_TITLE):
1176  sFormatTitle = sValue;
1177  break;
1178  case XML_ELEMENT(NUMBER, XML_AUTOMATIC_ORDER):
1179  if (::sax::Converter::convertBool( bAttrBool, sValue ))
1180  bAutoOrder = bAttrBool;
1181  break;
1182  case XML_ELEMENT(NUMBER, XML_FORMAT_SOURCE):
1183  SvXMLUnitConverter::convertEnum( bFromSystem, sValue, aFormatSourceMap );
1184  break;
1185  case XML_ELEMENT(NUMBER, XML_TRUNCATE_ON_OVERFLOW):
1186  if (::sax::Converter::convertBool( bAttrBool, sValue ))
1187  bTruncate = bAttrBool;
1188  break;
1189  case XML_ELEMENT(STYLE, XML_VOLATILE):
1190  // volatile formats can be removed after importing
1191  // if not used in other styles
1192  if (::sax::Converter::convertBool( bAttrBool, sValue ))
1193  bRemoveAfterUse = bAttrBool;
1194  break;
1196  aNatNumAttr.Format = sValue;
1197  break;
1200  aSpellout = sValue;
1201  break;
1203  aNatNumAttr.Locale.Language = sValue;
1204  break;
1206  aNatNumAttr.Locale.Country = sValue;
1207  break;
1208  case XML_ELEMENT(NUMBER, XML_TRANSLITERATION_STYLE):
1209  aNatNumAttr.Style = sValue;
1210  break;
1211  default:
1212  SAL_WARN("xmloff", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << sValue);
1213  }
1214  }
1215 
1216  if (!aLanguageTagODF.isEmpty())
1217  {
1218  nFormatLang = aLanguageTagODF.getLanguageTag().getLanguageType( false);
1219  if ( nFormatLang == LANGUAGE_DONTKNOW )
1220  nFormatLang = LANGUAGE_SYSTEM;
1221  }
1222 
1223  if (aNatNumAttr.Format.isEmpty() && aSpellout.isEmpty())
1224  return;
1225 
1226  LanguageTag aLanguageTag( OUString(), aNatNumAttr.Locale.Language,
1227  OUString(), aNatNumAttr.Locale.Country);
1228  aNatNumAttr.Locale = aLanguageTag.getLocale( false);
1229 
1230  // NatNum12 spell out formula (cardinal, ordinal, ordinal-feminine etc.)
1231  if ( !aSpellout.isEmpty() )
1232  {
1233  aFormatCode.append( "[NatNum12 " );
1234  aFormatCode.append( aSpellout );
1235  } else {
1236  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1237  if ( !pFormatter ) return;
1238 
1239  sal_Int32 nNatNum = pFormatter->GetNatNum()->convertFromXmlAttributes( aNatNumAttr );
1240  aFormatCode.append( "[NatNum" );
1241  aFormatCode.append( nNatNum );
1242  }
1243 
1244  LanguageType eLang = aLanguageTag.getLanguageType( false );
1245  if ( eLang == LANGUAGE_DONTKNOW )
1246  eLang = LANGUAGE_SYSTEM;
1247  if ( eLang != nFormatLang && eLang != LANGUAGE_SYSTEM )
1248  {
1249  aFormatCode.append( "][$-" );
1250  // language code in upper hex:
1251  aFormatCode.append(OUString::number(static_cast<sal_uInt16>(eLang), 16).toAsciiUpperCase());
1252  }
1253  aFormatCode.append( ']' );
1254 }
1255 
1257  const OUString& rName,
1258  const uno::Reference<xml::sax::XFastAttributeList>& /*xAttrList*/,
1259  const sal_Int32 nTempKey, LanguageType nLang,
1260  SvXMLStylesContext& rStyles ) :
1262  pData( nullptr ),
1263  pStyles( &rStyles ),
1264  aMyConditions(),
1266  nKey(nTempKey),
1267  nFormatLang( nLang ),
1268  bAutoOrder( false ),
1269  bFromSystem( false ),
1270  bTruncate( true ),
1271  bAutoDec( false ),
1272  bAutoInt( false ),
1273  bHasExtraText( false ),
1274  bHasLongDoW( false ),
1275  bHasEra( false ),
1276  bHasDateTime( false ),
1277  bRemoveAfterUse( false ),
1278  eDateDOW( XML_DEA_NONE ),
1279  eDateDay( XML_DEA_NONE ),
1280  eDateMonth( XML_DEA_NONE ),
1281  eDateYear( XML_DEA_NONE ),
1282  eDateHours( XML_DEA_NONE ),
1283  eDateMins( XML_DEA_NONE ),
1284  eDateSecs( XML_DEA_NONE ),
1285  bDateNoDefault( false )
1286 {
1287  SetAttribute(XML_NAMESPACE_STYLE, GetXMLToken(XML_NAME), rName);
1288 }
1289 
1291 {
1292 }
1293 
1294 css::uno::Reference< css::xml::sax::XFastContextHandler > SvXMLNumFormatContext::createFastChildContext(
1295  sal_Int32 nElement,
1296  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
1297 {
1298  SvXMLImportContext* pContext = nullptr;
1299 
1300  switch (nElement)
1301  {
1302  case XML_ELEMENT(LO_EXT, XML_TEXT):
1303  case XML_ELEMENT(NUMBER, XML_TEXT):
1304  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1305  *this, SvXMLStyleTokens::Text, xAttrList );
1306  break;
1307  case XML_ELEMENT(LO_EXT, XML_FILL_CHARACTER):
1309  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1310  *this, SvXMLStyleTokens::FillCharacter, xAttrList );
1311  break;
1312  case XML_ELEMENT(NUMBER, XML_NUMBER):
1313  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1314  *this, SvXMLStyleTokens::Number, xAttrList );
1315  break;
1317  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1318  *this, SvXMLStyleTokens::ScientificNumber, xAttrList );
1319  break;
1321  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1322  *this, SvXMLStyleTokens::Fraction, xAttrList );
1323  break;
1325  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1326  *this, SvXMLStyleTokens::CurrencySymbol, xAttrList );
1327  break;
1328  case XML_ELEMENT(NUMBER, XML_DAY):
1329  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1330  *this, SvXMLStyleTokens::Day, xAttrList );
1331  break;
1332  case XML_ELEMENT(NUMBER, XML_MONTH):
1333  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1334  *this, SvXMLStyleTokens::Month, xAttrList );
1335  break;
1336  case XML_ELEMENT(NUMBER, XML_YEAR):
1337  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1338  *this, SvXMLStyleTokens::Year, xAttrList );
1339  break;
1340  case XML_ELEMENT(NUMBER, XML_ERA):
1341  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1342  *this, SvXMLStyleTokens::Era, xAttrList );
1343  break;
1345  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1346  *this, SvXMLStyleTokens::DayOfWeek, xAttrList );
1347  break;
1349  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1350  *this, SvXMLStyleTokens::WeekOfYear, xAttrList );
1351  break;
1353  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1354  *this, SvXMLStyleTokens::Quarter, xAttrList );
1355  break;
1356  case XML_ELEMENT(NUMBER, XML_HOURS):
1357  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1358  *this, SvXMLStyleTokens::Hours, xAttrList );
1359  break;
1360  case XML_ELEMENT(NUMBER, XML_AM_PM):
1361  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1362  *this, SvXMLStyleTokens::AmPm, xAttrList );
1363  break;
1365  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1366  *this, SvXMLStyleTokens::Minutes, xAttrList );
1367  break;
1369  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1370  *this, SvXMLStyleTokens::Seconds, xAttrList );
1371  break;
1373  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1374  *this, SvXMLStyleTokens::Boolean, xAttrList );
1375  break;
1377  pContext = new SvXMLNumFmtElementContext( GetImport(), nElement,
1378  *this, SvXMLStyleTokens::TextContent, xAttrList );
1379  break;
1380 
1382  pContext = new SvXMLNumFmtPropContext( GetImport(), nElement,
1383  *this, xAttrList );
1384  break;
1385  case XML_ELEMENT(STYLE, XML_MAP):
1386  {
1387  // SvXMLNumFmtMapContext::EndElement adds to aMyConditions,
1388  // so there's no need for an extra flag
1389  pContext = new SvXMLNumFmtMapContext( GetImport(), nElement,
1390  *this, xAttrList );
1391  }
1392  break;
1393  }
1394 
1395  if( !pContext )
1396  {
1397  SAL_WARN("xmloff.core", "No context for unknown-element " << SvXMLImport::getPrefixAndNameFromToken(nElement));
1398  pContext = new SvXMLImportContext(GetImport());
1399  }
1400 
1401  return pContext;
1402 }
1403 
1405 {
1406  if (nKey > -1)
1407  {
1408  if (bRemoveAfterUse)
1409  {
1410  // format is used -> don't remove
1411  bRemoveAfterUse = false;
1412  if (pData)
1413  pData->SetUsed(nKey);
1414 
1415  // Add to import's list of keys now - CreateAndInsert didn't add
1416  // the style if bRemoveAfterUse was set.
1418  }
1419  return nKey;
1420  }
1421  else
1422  {
1423  // reset bRemoveAfterUse before CreateAndInsert, so AddKey is called without bRemoveAfterUse set
1424  bRemoveAfterUse = false;
1425  CreateAndInsert(true);
1426  return nKey;
1427  }
1428 }
1429 
1431 {
1432  // used for map elements in CreateAndInsert - don't reset bRemoveAfterUse flag
1433 
1434  if (nKey > -1)
1435  return nKey;
1436  else
1437  {
1438  CreateAndInsert(true);
1439  return nKey;
1440  }
1441 }
1442 
1443 sal_Int32 SvXMLNumFormatContext::CreateAndInsert( css::uno::Reference< css::util::XNumberFormatsSupplier > const & xFormatsSupplier )
1444 {
1445  if (nKey <= -1)
1446  {
1447  SvNumberFormatter* pFormatter = nullptr;
1449  comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>( xFormatsSupplier );
1450  if (pObj)
1451  pFormatter = pObj->GetNumberFormatter();
1452 
1453  if ( pFormatter )
1454  return CreateAndInsert( pFormatter );
1455  else
1456  return -1;
1457  }
1458  else
1459  return nKey;
1460 }
1461 
1463 {
1464  if (nKey <= -1)
1466 }
1467 
1469 {
1470  if (!pFormatter)
1471  {
1472  OSL_FAIL("no number formatter");
1473  return -1;
1474  }
1475 
1476  sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1477 
1478  for (size_t i = 0; i < aMyConditions.size(); i++)
1479  {
1481  XmlStyleFamily::DATA_STYLE, aMyConditions[i].sMapName)));
1482  if (this == pStyle)
1483  {
1484  SAL_INFO("xmloff.style", "invalid style:map references containing style");
1485  pStyle = nullptr;
1486  }
1487  if (pStyle)
1488  {
1489  if (pStyle->PrivateGetKey() > -1) // don't reset pStyle's bRemoveAfterUse flag
1490  AddCondition(i);
1491  }
1492  }
1493 
1494  if ( aFormatCode.isEmpty() )
1495  {
1496  // insert empty format as empty string (with quotes)
1497  // #93901# this check has to be done before inserting the conditions
1498  aFormatCode.append("\"\""); // ""
1499  }
1500 
1501  aFormatCode.insert( 0, aConditions.makeStringAndClear() );
1502  OUString sFormat = aFormatCode.makeStringAndClear();
1503 
1504  // test special cases
1505 
1506  if ( bAutoDec ) // automatic decimal places
1507  {
1508  // #99391# adjust only if the format contains no text elements, no conditions
1509  // and no color definition (detected by the '[' at the start)
1510 
1512  aMyConditions.empty() && sFormat.toChar() != '[' )
1513  nIndex = pFormatter->GetStandardIndex( nFormatLang );
1514  }
1515  if ( bAutoInt ) // automatic integer digits
1516  {
1518 
1520  aMyConditions.empty() && sFormat.toChar() != '[' )
1521  nIndex = pFormatter->GetFormatIndex( NF_NUMBER_SYSTEM, nFormatLang );
1522  }
1523 
1524  // boolean is always the builtin boolean format
1525  // (no other boolean formats are implemented)
1527  nIndex = pFormatter->GetFormatIndex( NF_BOOLEAN, nFormatLang );
1528 
1529  // check for default date formats
1531  {
1535  if ( eFormat < NF_INDEX_TABLE_RESERVED_START )
1536  {
1537  // #109651# if a date format has the automatic-order attribute and
1538  // contains exactly the elements of one of the default date formats,
1539  // use that default format, with the element order and separators
1540  // from the current locale settings
1541 
1542  nIndex = pFormatter->GetFormatIndex( eFormat, nFormatLang );
1543  }
1544  }
1545 
1546  if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND && !sFormat.isEmpty() )
1547  {
1548  // insert by format string
1549 
1550  OUString aFormatStr( sFormat );
1551  nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1552  if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1553  {
1554  sal_Int32 nErrPos = 0;
1555  SvNumFormatType l_nType = SvNumFormatType::ALL;
1556  bool bOk = pFormatter->PutEntry( aFormatStr, nErrPos, l_nType, nIndex, nFormatLang );
1557  if ( !bOk && nErrPos == 0 && aFormatStr != sFormat )
1558  {
1559  // if the string was modified by PutEntry, look for an existing format
1560  // with the modified string
1561  nIndex = pFormatter->GetEntryKey( aFormatStr, nFormatLang );
1562  if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1563  bOk = true;
1564  }
1565  if (!bOk)
1567  }
1568  }
1569 
1571  if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND && !bAutoOrder )
1572  {
1573  // use fixed-order formats instead of SYS... if bAutoOrder is false
1574  // (only if the format strings are equal for the locale)
1575 
1576  NfIndexTableOffset eOffset = pFormatter->GetIndexTableOffset( nIndex );
1577  if ( eOffset == NF_DATE_SYS_DMMMYYYY )
1578  {
1579  sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMYYYY, nFormatLang );
1580  const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1581  const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1582  if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1583  nIndex = nNewIndex;
1584  }
1585  else if ( eOffset == NF_DATE_SYS_DMMMMYYYY )
1586  {
1587  sal_uInt32 nNewIndex = pFormatter->GetFormatIndex( NF_DATE_DIN_DMMMMYYYY, nFormatLang );
1588  const SvNumberformat* pOldEntry = pFormatter->GetEntry( nIndex );
1589  const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewIndex );
1590  if ( pOldEntry && pNewEntry && pOldEntry->GetFormatstring() == pNewEntry->GetFormatstring() )
1591  nIndex = nNewIndex;
1592  }
1593  }
1594 
1595  if ((nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND) && !sFormatTitle.isEmpty())
1596  {
1597  SvNumberformat* pFormat = const_cast<SvNumberformat*>(pFormatter->GetEntry( nIndex ));
1598  if (pFormat)
1599  {
1600  pFormat->SetComment(sFormatTitle);
1601  }
1602  }
1603 
1604  if ( nIndex == NUMBERFORMAT_ENTRY_NOT_FOUND )
1605  {
1606  OSL_FAIL("invalid number format");
1607  nIndex = pFormatter->GetStandardIndex( nFormatLang );
1608  }
1609 
1610  pData->AddKey( nIndex, GetName(), bRemoveAfterUse );
1611  nKey = nIndex;
1612 
1613  // Add to import's list of keys (shared between styles and content import)
1614  // only if not volatile - formats are removed from NumberFormatter at the
1615  // end of each import (in SvXMLNumFmtHelper dtor).
1616  // If bRemoveAfterUse is reset later in GetKey, AddNumberStyle is called there.
1617 
1618  if (!bRemoveAfterUse)
1620 
1621  return nKey;
1622 }
1623 
1625 {
1626  return pData->GetLocaleData( nFormatLang );
1627 }
1628 
1630 {
1631  aFormatCode.append( c );
1632  bHasExtraText = true;
1633 }
1634 
1635 void SvXMLNumFormatContext::AddToCode( const OUString& rString )
1636 {
1637  aFormatCode.append( rString );
1638  bHasExtraText = true;
1639 }
1640 
1642 {
1643  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1644  if (!pFormatter)
1645  return;
1646 
1647  // store special conditions
1648  bAutoDec = ( rInfo.nDecimals < 0 );
1649  bAutoInt = ( rInfo.nInteger < 0 );
1650 
1651  sal_uInt16 nPrec = 0;
1652  sal_uInt16 nLeading = 0;
1653  if ( rInfo.nDecimals >= 0 ) // < 0 : Default
1654  nPrec = static_cast<sal_uInt16>(rInfo.nDecimals);
1655  if ( rInfo.nInteger >= 0 ) // < 0 : Default
1656  nLeading = static_cast<sal_uInt16>(rInfo.nInteger);
1657 
1658  if ( bAutoDec )
1659  {
1661  {
1662  // for currency formats, "automatic decimals" is used for the automatic
1663  // currency format with (fixed) decimals from the locale settings
1664 
1666  nPrec = rLoc.getCurrDigits();
1667  }
1668  else
1669  {
1670  // for other types, "automatic decimals" means dynamic determination of
1671  // decimals, as achieved with the "general" keyword
1672 
1673  aFormatCode.append( pFormatter->GetStandardName( nFormatLang ) );
1674  return;
1675  }
1676  }
1677  if ( bAutoInt )
1678  {
1680  }
1681 
1682  sal_uInt16 nGenPrec = nPrec;
1683  if ( rInfo.nMinDecimalDigits >= 0 )
1684  nGenPrec = rInfo.nMinDecimalDigits;
1685  if ( rInfo.bDecReplace )
1686  nGenPrec = 0; // generate format without decimals...
1687 
1688  bool bGrouping = rInfo.bGrouping;
1689  size_t const nEmbeddedCount = rInfo.m_EmbeddedElements.size();
1690  if ( nEmbeddedCount )
1691  bGrouping = false; // grouping and embedded characters can't be used together
1692 
1693  sal_uInt32 nStdIndex = pFormatter->GetStandardIndex( nFormatLang );
1694  OUStringBuffer aNumStr = pFormatter->GenerateFormat( nStdIndex, nFormatLang,
1695  bGrouping, false, nGenPrec, nLeading );
1696 
1697  if ( rInfo.nExpDigits >= 0 && nLeading == 0 && !bGrouping && nEmbeddedCount == 0 )
1698  {
1699  // #i43959# For scientific numbers, "#" in the integer part forces a digit,
1700  // so it has to be removed if nLeading is 0 (".00E+0", not "#.00E+0").
1701 
1702  aNumStr.stripStart('#');
1703  }
1704 
1705  if ( bGrouping && rInfo.nExpInterval > rInfo.nInteger )
1706  {
1707  sal_Int32 nIndex = 0;
1708  sal_Int32 nDigits = rInfo.nInteger;
1709  sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() );
1710  if ( nIntegerEnd < 0 )
1711  nIntegerEnd = aNumStr.getLength();
1712  while ( nIndex >= 0 && nIndex < nIntegerEnd )
1713  {
1714  if ( ( nIndex = aNumStr.indexOf( '#', nIndex ) ) >= 0 )
1715  {
1716  nDigits ++;
1717  nIndex ++;
1718  }
1719  else
1720  nIndex = -1;
1721  }
1722  while ( rInfo.nExpInterval > nDigits )
1723  {
1724  nDigits++;
1725  aNumStr.insert( 0, '#' );
1726  }
1727  }
1728 
1729  if ( nEmbeddedCount )
1730  {
1731  // insert embedded strings into number string
1732  // only the integer part is supported
1733  // nZeroPos is the string position where format position 0 is inserted
1734 
1735  sal_Int32 nZeroPos = aNumStr.indexOf( pData->GetLocaleData( nFormatLang ).getNumDecimalSep() );
1736  if ( nZeroPos < 0 )
1737  {
1738  nZeroPos = aNumStr.getLength();
1739  }
1740 
1741  // m_EmbeddedElements is sorted - last entry has the largest position (leftmost)
1742  sal_Int32 const nLastFormatPos = rInfo.m_EmbeddedElements.rbegin()->first;
1743  if ( nLastFormatPos >= nZeroPos )
1744  {
1745  // add '#' characters so all embedded texts are really embedded in digits
1746  // (there always has to be a digit before the leftmost embedded text)
1747 
1748  sal_Int32 nAddCount = nLastFormatPos + 1 - nZeroPos;
1749  for(sal_Int32 index = 0; index < nAddCount; ++index)
1750  {
1751  aNumStr.insert(0, '#');
1752  }
1753  nZeroPos = nZeroPos + nAddCount;
1754  }
1755 
1756  // m_EmbeddedElements is sorted with ascending positions - loop is from right to left
1757  for (auto const& it : rInfo.m_EmbeddedElements)
1758  {
1759  sal_Int32 const nFormatPos = it.first;
1760  sal_Int32 nInsertPos = nZeroPos - nFormatPos;
1761  if ( nFormatPos >= 0 && nInsertPos >= 0 )
1762  {
1763  // #107805# always quote embedded strings - even space would otherwise
1764  // be recognized as thousands separator in French.
1765 
1766  aNumStr.insert(nInsertPos, '"');
1767  aNumStr.insert(nInsertPos, it.second);
1768  aNumStr.insert(nInsertPos, '"');
1769  }
1770  }
1771  }
1772 
1773  aFormatCode.append( aNumStr.makeStringAndClear() );
1774 
1775  if ( ( rInfo.bDecReplace || rInfo.nMinDecimalDigits < rInfo.nDecimals ) && nPrec ) // add decimal replacement (dashes)
1776  {
1777  // add dashes for explicit decimal replacement, # or ? for variable decimals
1778  sal_Unicode cAdd = rInfo.bDecReplace ? '-' : ( rInfo.bDecAlign ? '?': '#' );
1779 
1780  if ( rInfo.nMinDecimalDigits == 0 )
1782  for ( sal_uInt16 i=rInfo.nMinDecimalDigits; i<nPrec; i++)
1783  aFormatCode.append( cAdd );
1784  }
1785 
1786  // add extra thousands separators for display factor
1787 
1788  if (rInfo.fDisplayFactor == 1.0 || rInfo.fDisplayFactor <= 0.0)
1789  return;
1790 
1791  // test for 1.0 is just for optimization - nSepCount would be 0
1792 
1793  // one separator for each factor of 1000
1794  sal_Int32 nSepCount = static_cast<sal_Int32>(::rtl::math::round( log10(rInfo.fDisplayFactor) / 3.0 ));
1795  if ( nSepCount > 0 )
1796  {
1797  OUString aSep = pData->GetLocaleData( nFormatLang ).getNumThousandSep();
1798  for ( sal_Int32 i=0; i<nSepCount; i++ )
1799  aFormatCode.append( aSep );
1800  }
1801 }
1802 
1803 void SvXMLNumFormatContext::AddCurrency( const OUString& rContent, LanguageType nLang )
1804 {
1805  bool bAutomatic = false;
1806  OUString aSymbol = rContent;
1807  if ( aSymbol.isEmpty())
1808  {
1809  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1810  if ( pFormatter )
1811  {
1812  pFormatter->ChangeIntl( nFormatLang );
1813  OUString sCurString, sDummy;
1814  pFormatter->GetCompatibilityCurrency( sCurString, sDummy );
1815  aSymbol = sCurString;
1816 
1817  bAutomatic = true;
1818  }
1819  }
1820  else if ( nLang == LANGUAGE_SYSTEM && aSymbol == "CCC" )
1821  {
1822  // "CCC" is used for automatic long symbol
1823  bAutomatic = true;
1824  }
1825 
1826  if ( bAutomatic )
1827  {
1828  // remove unnecessary quotes before automatic symbol (formats like "-(0DM)")
1829  // otherwise the currency symbol isn't recognized (#94048#)
1830 
1831  sal_Int32 nLength = aFormatCode.getLength();
1832  if ( nLength > 1 && aFormatCode[nLength - 1] == '"' )
1833  {
1834  // find start of quoted string
1835  // When SvXMLNumFmtElementContext::EndElement creates escaped quotes,
1836  // they must be handled here, too.
1837 
1838  sal_Int32 nFirst = nLength - 2;
1839  while ( nFirst >= 0 && aFormatCode[nFirst] != '"' )
1840  --nFirst;
1841  if ( nFirst >= 0 )
1842  {
1843  // remove both quotes from aFormatCode
1844  OUString aOld = aFormatCode.makeStringAndClear();
1845  if ( nFirst > 0 )
1846  aFormatCode.append( aOld.copy( 0, nFirst ) );
1847  if ( nLength > nFirst + 2 )
1848  aFormatCode.append( aOld.copy( nFirst + 1, nLength - nFirst - 2 ) );
1849  }
1850  }
1851  }
1852 
1853  if (!bAutomatic)
1854  aFormatCode.append( "[$" ); // intro for "new" currency symbols
1855 
1856  aFormatCode.append( aSymbol );
1857 
1858  if (!bAutomatic)
1859  {
1860  if ( nLang != LANGUAGE_SYSTEM )
1861  {
1862  // '-' sign and language code in hex:
1863  aFormatCode.append("-").append(OUString(OUString::number(sal_uInt16(nLang), 16)).toAsciiUpperCase());
1864  }
1865 
1866  aFormatCode.append( ']' ); // end of "new" currency symbol
1867  }
1868 }
1869 
1870 void SvXMLNumFormatContext::AddNfKeyword( sal_uInt16 nIndex )
1871 {
1872  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1873  if (!pFormatter)
1874  return;
1875 
1876  if ( nIndex == NF_KEY_G || nIndex == NF_KEY_GG || nIndex == NF_KEY_GGG )
1877  bHasEra = true;
1878 
1879  if ( nIndex == NF_KEY_NNNN )
1880  {
1881  nIndex = NF_KEY_NNN;
1882  bHasLongDoW = true; // to remove string constant with separator
1883  }
1884 
1885  OUString sKeyword = pFormatter->GetKeyword( nFormatLang, nIndex );
1886 
1887  if ( nIndex == NF_KEY_H || nIndex == NF_KEY_HH ||
1888  nIndex == NF_KEY_MI || nIndex == NF_KEY_MMI ||
1889  nIndex == NF_KEY_S || nIndex == NF_KEY_SS )
1890  {
1891  if ( !bTruncate && !bHasDateTime )
1892  {
1893  // with truncate-on-overflow = false, add "[]" to first time part
1894  aFormatCode.append("[").append(sKeyword).append("]");
1895  }
1896  else
1897  {
1898  aFormatCode.append( sKeyword );
1899  }
1900  bHasDateTime = true;
1901  }
1902  else
1903  {
1904  aFormatCode.append( sKeyword );
1905  }
1906  // collect the date elements that the format contains, to recognize default date formats
1907  switch ( nIndex )
1908  {
1909  case NF_KEY_NN: eDateDOW = XML_DEA_SHORT; break;
1910  case NF_KEY_NNN:
1911  case NF_KEY_NNNN: eDateDOW = XML_DEA_LONG; break;
1912  case NF_KEY_D: eDateDay = XML_DEA_SHORT; break;
1913  case NF_KEY_DD: eDateDay = XML_DEA_LONG; break;
1914  case NF_KEY_M: eDateMonth = XML_DEA_SHORT; break;
1915  case NF_KEY_MM: eDateMonth = XML_DEA_LONG; break;
1916  case NF_KEY_MMM: eDateMonth = XML_DEA_TEXTSHORT; break;
1917  case NF_KEY_MMMM: eDateMonth = XML_DEA_TEXTLONG; break;
1918  case NF_KEY_YY: eDateYear = XML_DEA_SHORT; break;
1919  case NF_KEY_YYYY: eDateYear = XML_DEA_LONG; break;
1920  case NF_KEY_H: eDateHours = XML_DEA_SHORT; break;
1921  case NF_KEY_HH: eDateHours = XML_DEA_LONG; break;
1922  case NF_KEY_MI: eDateMins = XML_DEA_SHORT; break;
1923  case NF_KEY_MMI: eDateMins = XML_DEA_LONG; break;
1924  case NF_KEY_S: eDateSecs = XML_DEA_SHORT; break;
1925  case NF_KEY_SS: eDateSecs = XML_DEA_LONG; break;
1926  case NF_KEY_AP:
1927  case NF_KEY_AMPM: break; // AM/PM may or may not be in date/time formats -> ignore by itself
1928  default:
1929  bDateNoDefault = true; // any other element -> no default format
1930  }
1931 }
1932 
1933 static bool lcl_IsAtEnd( OUStringBuffer& rBuffer, const OUString& rToken )
1934 {
1935  sal_Int32 nBufLen = rBuffer.getLength();
1936  sal_Int32 nTokLen = rToken.getLength();
1937 
1938  if ( nTokLen > nBufLen )
1939  return false;
1940 
1941  sal_Int32 nStartPos = nBufLen - nTokLen;
1942  for ( sal_Int32 nTokPos = 0; nTokPos < nTokLen; nTokPos++ )
1943  if ( rToken[ nTokPos ] != rBuffer[nStartPos + nTokPos] )
1944  return false;
1945 
1946  return true;
1947 }
1948 
1949 bool SvXMLNumFormatContext::ReplaceNfKeyword( sal_uInt16 nOld, sal_uInt16 nNew )
1950 {
1951  // replaces one keyword with another if it is found at the end of the code
1952 
1953  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1954  if (!pFormatter)
1955  return false;
1956 
1957  OUString sOldStr = pFormatter->GetKeyword( nFormatLang, nOld );
1958  if ( lcl_IsAtEnd( aFormatCode, sOldStr ) )
1959  {
1960  // remove old keyword
1961  aFormatCode.setLength( aFormatCode.getLength() - sOldStr.getLength() );
1962 
1963  // add new keyword
1964  OUString sNewStr = pFormatter->GetKeyword( nFormatLang, nNew );
1965  aFormatCode.append( sNewStr );
1966 
1967  return true; // changed
1968  }
1969  return false; // not found
1970 }
1971 
1972 void SvXMLNumFormatContext::AddCondition( const sal_Int32 nIndex )
1973 {
1974  OUString rApplyName = aMyConditions[nIndex].sMapName;
1975  OUString rCondition = aMyConditions[nIndex].sCondition;
1976  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
1977  sal_uInt32 l_nKey = pData->GetKeyForName( rApplyName );
1978 
1979  OUString sRealCond;
1980  if ( !(pFormatter && l_nKey != NUMBERFORMAT_ENTRY_NOT_FOUND &&
1981  rCondition.startsWith("value()", &sRealCond)) )
1982  return;
1983 
1986 
1987  bool bDefaultCond = false;
1988 
1991  if ( aConditions.isEmpty() && aMyConditions.size() == 1 && sRealCond == ">=0" )
1992  bDefaultCond = true;
1993 
1994  if ( nType == SvXMLStylesTokens::TEXT_STYLE && static_cast<size_t>(nIndex) == aMyConditions.size() - 1 )
1995  {
1996  // The last condition in a number format with a text part can only
1997  // be "all other numbers", the condition string must be empty.
1998  bDefaultCond = true;
1999  }
2000 
2001  if (!bDefaultCond)
2002  {
2003  // Convert != to <>
2004  sal_Int32 nPos = sRealCond.indexOf( "!=" );
2005  if ( nPos >= 0 )
2006  {
2007  sRealCond = sRealCond.replaceAt( nPos, 2, "<>" );
2008  }
2009 
2010  nPos = sRealCond.indexOf( '.' );
2011  if ( nPos >= 0 )
2012  {
2013  // #i8026# #103991# localize decimal separator
2014  const OUString& rDecSep = GetLocaleData().getNumDecimalSep();
2015  if ( rDecSep.getLength() > 1 || rDecSep[0] != '.' )
2016  {
2017  sRealCond = sRealCond.replaceAt( nPos, 1, rDecSep );
2018  }
2019  }
2020  aConditions.append("[").append(sRealCond).append("]");
2021  }
2022 
2023  const SvNumberformat* pFormat = pFormatter->GetEntry(l_nKey);
2024  if ( pFormat )
2025  aConditions.append( pFormat->GetFormatstring() );
2026 
2027  aConditions.append( ';' );
2028 }
2029 
2030 void SvXMLNumFormatContext::AddCondition( const OUString& rCondition, const OUString& rApplyName )
2031 {
2032  MyCondition aCondition;
2033  aCondition.sCondition = rCondition;
2034  aCondition.sMapName = rApplyName;
2035  aMyConditions.push_back(aCondition);
2036 }
2037 
2039 {
2040  SvNumberFormatter* pFormatter = pData->GetNumberFormatter();
2041  if (!pFormatter)
2042  return;
2043 
2044  OUStringBuffer aColName;
2045  for ( sal_uInt16 i=0; i<XML_NUMF_COLORCOUNT; i++ )
2046  if (nColor == aNumFmtStdColors[i])
2047  {
2048  aColName = pFormatter->GetKeyword( nFormatLang, sal::static_int_cast< sal_uInt16 >(NF_KEY_FIRSTCOLOR + i) );
2049  break;
2050  }
2051 
2052  if ( !aColName.isEmpty() )
2053  {
2054  aColName.insert( 0, '[' );
2055  aColName.append( ']' );
2056  aFormatCode.insert( 0, aColName.makeStringAndClear() );
2057  }
2058 }
2059 
2060 void SvXMLNumFormatContext::UpdateCalendar( const OUString& rNewCalendar, bool bImplicitSecondaryCalendarEC )
2061 {
2062  if ( rNewCalendar != sCalendar )
2063  {
2064  sCalendar = rNewCalendar;
2065  if ( !sCalendar.isEmpty() && !bImplicitSecondaryCalendarEC )
2066  {
2067  aFormatCode.append( "[~" ); // intro for calendar code
2068  aFormatCode.append( sCalendar );
2069  aFormatCode.append( ']' ); // end of calendar code
2070  }
2071  }
2072 }
2073 
2075 {
2076  return nFormatLang == LANGUAGE_SYSTEM;
2077 }
2078 
2079 
2080 // SvXMLNumFmtHelper
2081 
2082 
2084  const uno::Reference<util::XNumberFormatsSupplier>& rSupp,
2085  const uno::Reference<uno::XComponentContext>& rxContext )
2086 {
2087  SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" );
2088 
2089  SvNumberFormatter* pFormatter = nullptr;
2091  comphelper::getUnoTunnelImplementation<SvNumberFormatsSupplierObj>( rSupp );
2092  if (pObj)
2093  pFormatter = pObj->GetNumberFormatter();
2094 
2095  pData = std::make_unique<SvXMLNumImpData>( pFormatter, rxContext );
2096 }
2097 
2099  SvNumberFormatter* pNumberFormatter,
2100  const uno::Reference<uno::XComponentContext>& rxContext )
2101 {
2102  SAL_WARN_IF( !rxContext.is(), "xmloff", "got no service manager" );
2103 
2104  pData = std::make_unique<SvXMLNumImpData>( pNumberFormatter, rxContext );
2105 }
2106 
2108 {
2109  // remove temporary (volatile) formats from NumberFormatter
2110  pData->RemoveVolatileFormats();
2111 }
2112 
2113 
2115  sal_Int32 nElement,
2116  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList,
2117  SvXMLStylesContext& rStyles )
2118 {
2119  SvXMLStylesTokens nStyleToken;
2120  switch (nElement)
2121  {
2123  nStyleToken = SvXMLStylesTokens::NUMBER_STYLE;
2124  break;
2126  nStyleToken = SvXMLStylesTokens::CURRENCY_STYLE;
2127  break;
2130  break;
2132  nStyleToken = SvXMLStylesTokens::DATE_STYLE;
2133  break;
2135  nStyleToken = SvXMLStylesTokens::TIME_STYLE;
2136  break;
2138  nStyleToken = SvXMLStylesTokens::BOOLEAN_STYLE;
2139  break;
2141  nStyleToken = SvXMLStylesTokens::TEXT_STYLE;
2142  break;
2143  default:
2144  // return NULL if not a data style, caller must handle other elements
2145  return nullptr;
2146  }
2147  return new SvXMLNumFormatContext( rImport, nElement,
2148  pData.get(), nStyleToken, xAttrList, rStyles );
2149 }
2150 
2152 {
2153  if (pData->GetNumberFormatter())
2154  {
2155  const SvNumberformat* pEntry = pData->GetNumberFormatter()->GetEntry(nKey);
2156  if (pEntry)
2157  return pEntry->GetLanguage();
2158  }
2159 
2160  return LANGUAGE_SYSTEM;
2161 }
2162 
2163 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
NF_KEY_AMPM
const Color aNumFmtStdColors[XML_NUMF_COLORCOUNT]
Definition: xmlnumfi.cxx:218
void AddNumber(const SvXMLNumberInfo &rInfo)
Definition: xmlnumfi.cxx:1641
sal_Int32 nIndex
const OUString & GetNumDecimalSep() const
NF_INDEX_TABLE_RESERVED_START
NF_KEY_YY
sal_Int32 nMinDecimalDigits
Definition: xmlnumfi.cxx:97
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTMAGENTA
SvXMLStylesTokens nType
Definition: xmlnumfi.hxx:121
LanguageType nFormatLang
Definition: xmlnumfi.hxx:127
NF_KEY_NNNN
sal_Int32 nExpDigits
Definition: xmlnumfi.cxx:90
std::unique_ptr< ContentProperties > pData
the SvXMLTypeConverter converts values of various types from their internal representation to the tex...
Definition: xmluconv.hxx:77
NF_INDEX_TABLE_ENTRIES
NF_DATE_SYS_NNDMMMMYYYY
sal_uInt32 GetFormatIndex(NfIndexTableOffset, LanguageType eLnge=LANGUAGE_DONTKNOW)
OUString sCondition
Definition: xmlnumfi.hxx:112
sal_uInt16 getCurrDigits() const
LanguageType getLanguageType(bool bResolveSystem=true) const
NF_DATETIME_SYS_DDMMYYYY_HHMMSS
virtual void SAL_CALL startFastElement(sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > &Attribs) override
Definition: xmlictxt.cxx:71
void GetCompatibilityCurrency(OUString &rSymbol, OUString &rAbbrev) const
SvXMLDateElementAttributes eDateSecs
Definition: xmlnumfi.hxx:148
constexpr size_t NF_MAX_FORMAT_SYMBOLS
virtual ~SvXMLNumFormatContext() override
Definition: xmlnumfi.cxx:1290
sal_Int32 nZerosDenomDigits
Definition: xmlnumfi.cxx:99
SvXMLNumFormatContext(SvXMLImport &rImport, sal_Int32 nElement, SvXMLNumImpData *pNewData, SvXMLStylesTokens nNewType, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, SvXMLStylesContext &rStyles)
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:62
SvXMLDateElementAttributes eDateDay
Definition: xmlnumfi.hxx:143
OUString aIntegerFractionDelimiter
Definition: xmlnumfi.cxx:105
NfIndexTableOffset GetIndexTableOffset(sal_uInt32 nFormat) const
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
LanguageTag getLanguageTag() const
Best call this only once per instance, it recreates a LanguageTag instance on every call...
SvNumberFormatter * pFormatter
Definition: xmlnumfi.cxx:67
SvXMLStyleContext * CreateChildContext(SvXMLImport &rImport, sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList, SvXMLStylesContext &rStyles)
Definition: xmlnumfi.cxx:2114
sal_Int32 nMinNumerDigits
Definition: xmlnumfi.cxx:92
const LocaleDataWrapper & GetLocaleData(LanguageType nLang)
Definition: xmlnumfi.cxx:373
void SetComment(const OUString &rStr)
NF_KEY_NNN
sal_Int32 nExpInterval
Definition: xmlnumfi.cxx:91
NF_KEY_DD
const OUString & GetFormatstring() const
NF_DATE_SYS_DDMMM
NF_DATE_SYS_DDMMYY
sal_Int32 nMaxNumerDigits
Definition: xmlnumfi.cxx:94
XmlStyleFamily
Definition: families.hxx:47
sal_uInt16 sal_Unicode
#define min(a, b)
sal_Int32 nZerosNumerDigits
Definition: xmlnumfi.cxx:98
NF_KEY_MMMM
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
SvXMLNumImpData * pData
Definition: xmlnumfi.hxx:118
constexpr sal_uInt32 NUMBERFORMAT_ENTRY_NOT_FOUND
sal_uInt32 GetStandardIndex(LanguageType eLnge=LANGUAGE_DONTKNOW)
void RemoveVolatileFormats()
Definition: xmlnumfi.cxx:353
sal_uInt32 GetKeyForName(const OUString &rName)
Definition: xmlnumfi.cxx:303
std::vector< MyCondition > aMyConditions
Definition: xmlnumfi.hxx:120
NfIndexTableOffset
static void convertNumber(OUStringBuffer &b, sal_Int32 n)
OUString GetStandardName(LanguageType eLnge)
static OUString getPrefixAndNameFromToken(sal_Int32 nToken)
Definition: xmlimp.cxx:2000
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTRED
const char * sName
bool PutEntry(OUString &rString, sal_Int32 &nCheckPos, SvNumFormatType &nType, sal_uInt32 &nKey, LanguageType eLnge=LANGUAGE_DONTKNOW)
SvXMLStylesContext * pStyles
Definition: xmlnumfi.hxx:119
LanguageType GetLanguageForKey(sal_Int32 nKey)
Definition: xmlnumfi.cxx:2151
OUString sMapName
Definition: xmlnumfi.hxx:113
const OUString & getNumDecimalSep() const
NF_BOOLEAN
SvNumFormatType GetType() const
void SetUsed(sal_uInt32 nKey)
Definition: xmlnumfi.cxx:338
SvXMLDateElementAttributes eDateMonth
Definition: xmlnumfi.hxx:144
NF_DATE_SYS_DMMMYYYY
int i
NF_KEY_MM
#define XML_NUMF_COLORCOUNT
Definition: xmlnumfi.cxx:216
NF_KEY_SS
sal_Int32 nDecimals
Definition: xmlnumfi.cxx:88
bool isEmpty() const
void AddCurrency(const OUString &rContent, LanguageType nLang)
Definition: xmlnumfi.cxx:1803
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
Definition: xmlnumfi.cxx:1294
SvXMLDateElementAttributes
Definition: xmlnumfi.hxx:49
#define LANGUAGE_SYSTEM
std::map< sal_Int32, OUString > m_EmbeddedElements
Definition: xmlnumfi.cxx:106
sal_Int32 nMaxDenomDigits
Definition: xmlnumfi.cxx:95
NF_KEY_GG
NF_KEY_FIRSTCOLOR
NUMBER
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_GRAY
SvXMLDateElementAttributes eDateDOW
Definition: xmlnumfi.hxx:142
NF_DATETIME_SYS_DDMMYYYY_HHMM
bool ReplaceNfKeyword(sal_uInt16 nOld, sal_uInt16 nNew)
Definition: xmlnumfi.cxx:1949
sal_Int32 nMinDenomDigits
Definition: xmlnumfi.cxx:93
OUStringBuffer aConditions
Definition: xmlnumfi.hxx:135
SvNumFormatType
NF_DATE_SYS_DDMMYYYY
SvXMLStylesTokens
Definition: xmlnumfi.hxx:38
OUStringBuffer aFormatCode
Definition: xmlnumfi.hxx:134
tuple index
std::vector< SvXMLNumFmtEntry > m_NameEntries
Definition: xmlnumfi.cxx:69
void DeleteEntry(sal_uInt32 nKey)
const uno::Reference< uno::XComponentContext > m_xContext
SvXMLDateElementAttributes eDateHours
Definition: xmlnumfi.hxx:146
void AddColor(Color nColor)
Definition: xmlnumfi.cxx:2038
NF_KEY_MMI
SvXMLImportContext(SvXMLImport &rImport, sal_uInt16 nPrfx, const OUString &rLName)
A contexts constructor does anything that is required if an element starts.
Definition: xmlictxt.cxx:29
SvXMLNumFmtHelper(const css::uno::Reference< css::util::XNumberFormatsSupplier > &rSupp, const css::uno::Reference< css::uno::XComponentContext > &rxContext)
const css::uno::Reference< css::uno::XComponentContext > & GetComponentContext() const
NF_NUMBER_SYSTEM
NF_DATE_DIN_DMMMMYYYY
NF_KEY_GGG
SvXMLStyleTokens
Definition: xmlnumfi.cxx:188
const SvXMLDefaultDateFormat aDefaultDateFormats[]
Definition: xmlnumfi.cxx:269
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:44
const SvXMLEnumMapEntry< bool > aStyleValueMap[]
Definition: xmlnumfi.cxx:238
OUString GenerateFormat(sal_uInt32 nIndex, LanguageType eLnge=LANGUAGE_DONTKNOW, bool bThousand=false, bool IsRed=false, sal_uInt16 nPrecision=0, sal_uInt16 nLeadingCnt=1)
Map an XMLTokenEnum to an enum value.
Definition: ximpshap.hxx:40
void AddCondition(const sal_Int32 nIndex)
Definition: xmlnumfi.cxx:1972
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTCYAN
const NativeNumberWrapper * GetNatNum() const
const SvXMLEnumMapEntry< bool > aFormatSourceMap[]
Definition: xmlnumfi.cxx:245
NF_KEY_YYYY
virtual void SAL_CALL endFastElement(sal_Int32 Element) override
Definition: xmlictxt.cxx:114
void ChangeIntl(LanguageType eLnge)
NF_DATE_SYSTEM_LONG
#define SAL_WARN_IF(condition, area, stream)
const OUString & GetName() const
Definition: xmlstyle.hxx:98
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3378
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
SvXMLNumImpData(SvNumberFormatter *pFmt, const uno::Reference< uno::XComponentContext > &rxContext)
Definition: xmlnumfi.cxx:294
NF_DATE_SYS_NNNNDMMMMYYYY
std::unique_ptr< SvXMLNumImpData > pData
Definition: xmlnumfi.hxx:72
sal_Int32 nInteger
Definition: xmlnumfi.cxx:89
Handling of tokens in XML:
void AddKey(sal_uInt32 nKey, const OUString &rName, bool bRemoveAfterUse)
Definition: xmlnumfi.cxx:313
void AddNumberStyle(sal_Int32 nKey, const OUString &sName)
Definition: xmlimp.cxx:1543
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_WHITE
#define SAL_INFO(area, stream)
OUString aName
std::unique_ptr< LocaleDataWrapper > pLocaleData
Definition: xmlnumfi.cxx:68
virtual css::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 Element, const css::uno::Reference< css::xml::sax::XFastAttributeList > &Attribs) override
Definition: xmlictxt.cxx:128
sal_Int32 nFracDenominator
Definition: xmlnumfi.cxx:96
NF_DATE_SYS_DMMMYY
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BROWN
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTGREEN
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:1092
NF_DATE_SYS_MMYY
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:94
SvNumberFormatter * GetNumberFormatter() const
NF_DATE_DIN_DMMMYYYY
QPRO_FUNC_TYPE nType
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_YELLOW
SvXMLStylesTokens GetType() const
Definition: xmlnumfi.hxx:175
void UpdateCalendar(const OUString &rNewCalendar, bool bImplicitSecondaryCalendarEC=false)
Definition: xmlnumfi.cxx:2060
static void lcl_EnquoteIfNecessary(OUStringBuffer &rContent, const SvXMLNumFormatContext &rParent)
Definition: xmlnumfi.cxx:538
SAL_DLLPRIVATE sal_Int32 PrivateGetKey()
Definition: xmlnumfi.cxx:1430
NF_DATE_SYS_NNDMMMYY
sal_uInt32 GetEntryKey(const OUString &sStr, LanguageType eLnge=LANGUAGE_DONTKNOW)
const OUString & getNumThousandSep() const
const SvXMLStyleContext * FindStyleChildContext(XmlStyleFamily nFamily, const OUString &rName, bool bCreateIndex=false) const
Definition: xmlstyle.cxx:808
SvXMLDateElementAttributes eDateMins
Definition: xmlnumfi.hxx:147
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_LIGHTBLUE
static bool lcl_ValidChar(sal_Unicode cChar, const SvXMLNumFormatContext &rParent)
Definition: xmlnumfi.cxx:488
NF_DATETIME_SYSTEM_SHORT_HHMM
#define SAL_WARN(area, stream)
SvXMLDateElementAttributes eDateYear
Definition: xmlnumfi.hxx:145
SvNumberFormatter * GetNumberFormatter() const
Definition: xmlnumfi.cxx:78
NF_KEY_AP
sal_Int32 nLength
Definition: xmltoken.cxx:36
if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
OUString GetKeyword(LanguageType eLnge, sal_uInt16 nIndex)
uno::Reference< uno::XComponentContext > m_xContext
Definition: xmlnumfi.cxx:71
virtual void CreateAndInsert(bool bOverwrite) override
Definition: xmlnumfi.cxx:1462
const LocaleDataWrapper & GetLocaleData() const
Definition: xmlnumfi.cxx:1624
sal_Int32 nNatNum
NF_KEY_HH
Helper to gather the single language tag relevant attributes during reading ODF and form a resulting ...
virtual void SAL_CALL characters(const OUString &aChars) override
Definition: xmlictxt.cxx:142
bool IsSystemLanguage() const
determine whether number format uses the system language
Definition: xmlnumfi.cxx:2074
constexpr sal_uInt16 XML_NAMESPACE_STYLE
LanguageType GetLanguage() const
void AddToCode(const OUString &rString)
Definition: xmlnumfi.cxx:1635
void AddNfKeyword(sal_uInt16 nIndex)
Definition: xmlnumfi.cxx:1870
sal_uInt16 nPos
double fDisplayFactor
Definition: xmlnumfi.cxx:104
NF_DATE_SYS_DMMMMYYYY
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
static bool lcl_IsAtEnd(OUStringBuffer &rBuffer, const OUString &rToken)
Definition: xmlnumfi.cxx:1933