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