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