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