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