/src/libreoffice/svl/source/numbers/zforscan.cxx
Line | Count | Source |
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 | | |
21 | | #include <stdlib.h> |
22 | | #include <comphelper/string.hxx> |
23 | | #include <o3tl/untaint.hxx> |
24 | | #include <o3tl/string_view.hxx> |
25 | | #include <sal/log.hxx> |
26 | | #include <tools/debug.hxx> |
27 | | #include <i18nlangtag/mslangid.hxx> |
28 | | #include <unotools/charclass.hxx> |
29 | | #include <unotools/localedatawrapper.hxx> |
30 | | #include <com/sun/star/i18n/NumberFormatCode.hpp> |
31 | | #include <com/sun/star/i18n/NumberFormatMapper.hpp> |
32 | | |
33 | | #include <svl/zforlist.hxx> |
34 | | #include <svl/zformat.hxx> |
35 | | #include <unotools/digitgroupingiterator.hxx> |
36 | | |
37 | | #include "zforscan.hxx" |
38 | | |
39 | | #include <svl/nfsymbol.hxx> |
40 | | using namespace svt; |
41 | | |
42 | | const sal_Unicode cNoBreakSpace = 0xA0; |
43 | | const sal_Unicode cNarrowNoBreakSpace = 0x202F; |
44 | | |
45 | | const int MaxCntPost = 20; //max dec places allow by rtl_math_round |
46 | | |
47 | | const NfKeywordTable ImpSvNumberformatScan::sEnglishKeyword = |
48 | | { // Syntax keywords in English (USA) |
49 | | //! All keywords MUST be UPPERCASE! In same order as NfKeywordIndex |
50 | | u""_ustr, // NF_KEY_NONE 0 |
51 | | u"E"_ustr, // NF_KEY_E Exponent |
52 | | u"AM/PM"_ustr, // NF_KEY_AMPM AM/PM |
53 | | u"A/P"_ustr, // NF_KEY_AP AM/PM short |
54 | | u"M"_ustr, // NF_KEY_MI Minute |
55 | | u"MM"_ustr, // NF_KEY_MMI Minute 02 |
56 | | u"M"_ustr, // NF_KEY_M month (!) |
57 | | u"MM"_ustr, // NF_KEY_MM month 02 (!) |
58 | | u"MMM"_ustr, // NF_KEY_MMM month short name |
59 | | u"MMMM"_ustr, // NF_KEY_MMMM month long name |
60 | | u"MMMMM"_ustr, // NF_KEY_MMMMM first letter of month name |
61 | | u"H"_ustr, // NF_KEY_H hour |
62 | | u"HH"_ustr, // NF_KEY_HH hour 02 |
63 | | u"S"_ustr, // NF_KEY_S Second |
64 | | u"SS"_ustr, // NF_KEY_SS Second 02 |
65 | | u"Q"_ustr, // NF_KEY_Q Quarter short 'Q' |
66 | | u"QQ"_ustr, // NF_KEY_QQ Quarter long |
67 | | u"D"_ustr, // NF_KEY_D day of month |
68 | | u"DD"_ustr, // NF_KEY_DD day of month 02 |
69 | | u"DDD"_ustr, // NF_KEY_DDD day of week short |
70 | | u"DDDD"_ustr, // NF_KEY_DDDD day of week long |
71 | | u"YY"_ustr, // NF_KEY_YY year two digits |
72 | | u"YYYY"_ustr, // NF_KEY_YYYY year four digits |
73 | | u"NN"_ustr, // NF_KEY_NN Day of week short |
74 | | u"NNN"_ustr, // NF_KEY_NNN Day of week long |
75 | | u"NNNN"_ustr, // NF_KEY_NNNN Day of week long incl. separator |
76 | | u"AAA"_ustr, // NF_KEY_AAA |
77 | | u"AAAA"_ustr, // NF_KEY_AAAA |
78 | | u"E"_ustr, // NF_KEY_EC |
79 | | u"EE"_ustr, // NF_KEY_EEC |
80 | | u"G"_ustr, // NF_KEY_G |
81 | | u"GG"_ustr, // NF_KEY_GG |
82 | | u"GGG"_ustr, // NF_KEY_GGG |
83 | | u"R"_ustr, // NF_KEY_R |
84 | | u"RR"_ustr, // NF_KEY_RR |
85 | | u"WW"_ustr, // NF_KEY_WW Week of year |
86 | | u"t"_ustr, // NF_KEY_THAI_T Thai T modifier, speciality of Thai Excel, only |
87 | | // used with Thai locale and converted to [NatNum1], only |
88 | | // exception as lowercase |
89 | | u"CCC"_ustr, // NF_KEY_CCC Currency abbreviation |
90 | | u"BOOLEAN"_ustr, // NF_KEY_BOOLEAN boolean |
91 | | u"GENERAL"_ustr, // NF_KEY_GENERAL General / Standard |
92 | | |
93 | | // Reserved words translated and color names follow: |
94 | | u"TRUE"_ustr, // NF_KEY_TRUE boolean true |
95 | | u"FALSE"_ustr, // NF_KEY_FALSE boolean false |
96 | | u"COLOR"_ustr, // NF_KEY_COLOR color |
97 | | // colours |
98 | | u"BLACK"_ustr, // NF_KEY_BLACK |
99 | | u"BLUE"_ustr, // NF_KEY_BLUE |
100 | | u"GREEN"_ustr, // NF_KEY_GREEN |
101 | | u"CYAN"_ustr, // NF_KEY_CYAN |
102 | | u"RED"_ustr, // NF_KEY_RED |
103 | | u"MAGENTA"_ustr, // NF_KEY_MAGENTA |
104 | | u"BROWN"_ustr, // NF_KEY_BROWN |
105 | | u"GREY"_ustr, // NF_KEY_GREY |
106 | | u"YELLOW"_ustr, // NF_KEY_YELLOW |
107 | | u"WHITE"_ustr // NF_KEY_WHITE |
108 | | }; |
109 | | |
110 | | const ::std::vector<Color> ImpSvNumberformatScan::StandardColor{ |
111 | | COL_BLACK, COL_LIGHTBLUE, COL_LIGHTGREEN, COL_LIGHTCYAN, COL_LIGHTRED, |
112 | | COL_LIGHTMAGENTA, COL_BROWN, COL_GRAY, COL_YELLOW, COL_WHITE |
113 | | }; |
114 | | |
115 | | // This vector will hold *only* the color names in German language. |
116 | | static const std::u16string_view& GermanColorName(size_t i) |
117 | 0 | { |
118 | 0 | static const std::u16string_view sGermanColorNames[]{ u"FARBE", u"SCHWARZ", u"BLAU", |
119 | 0 | u"GRÜN", u"CYAN", u"ROT", |
120 | 0 | u"MAGENTA", u"BRAUN", u"GRAU", |
121 | 0 | u"GELB", u"WEISS" }; |
122 | 0 | assert(i < std::size(sGermanColorNames)); |
123 | 0 | return sGermanColorNames[i]; |
124 | 0 | } |
125 | | |
126 | | ImpSvNumberformatScan::ImpSvNumberformatScan(SvNFLanguageData& rCurrentLanguageData, |
127 | | const SvNumberFormatter& rColorCallback, |
128 | | const Date& aNullDate) |
129 | 221k | : maNullDate(aNullDate) |
130 | 221k | , mrCurrentLanguageData(rCurrentLanguageData) |
131 | 221k | , mrColorCallback(rColorCallback) |
132 | 221k | , eNewLnge(LANGUAGE_DONTKNOW) |
133 | 221k | , eTmpLnge(LANGUAGE_DONTKNOW) |
134 | 221k | , nCurrPos(-1) |
135 | 221k | , meKeywordLocalization(KeywordLocalization::AllowEnglish) |
136 | 221k | { |
137 | 221k | xNFC = css::i18n::NumberFormatMapper::create(rCurrentLanguageData.GetComponentContext()); |
138 | 221k | bConvertMode = false; |
139 | 221k | mbConvertDateOrder = false; |
140 | 221k | bConvertSystemToSystem = false; |
141 | 221k | bKeywordsNeedInit = true; // locale dependent and not locale dependent keywords |
142 | 221k | bCompatCurNeedInit = true; // locale dependent compatibility currency strings |
143 | | |
144 | 221k | static_assert( NF_KEY_BLACK - NF_KEY_COLOR == 1, "bad FARBE(COLOR), SCHWARZ(BLACK) sequence"); |
145 | 221k | static_assert( NF_KEY_FIRSTCOLOR - NF_KEY_COLOR == 1, "bad color sequence"); |
146 | 221k | static_assert( NF_MAX_DEFAULT_COLORS + 1 == 11, "bad color count"); |
147 | 221k | static_assert( NF_KEY_WHITE - NF_KEY_COLOR + 1 == 11, "bad color sequence count"); |
148 | | |
149 | 221k | nStandardPrec = 2; |
150 | | |
151 | 221k | Reset(); |
152 | 221k | } |
153 | | |
154 | | ImpSvNumberformatScan::~ImpSvNumberformatScan() |
155 | 221k | { |
156 | 221k | Reset(); |
157 | 221k | } |
158 | | |
159 | | void ImpSvNumberformatScan::ChangeIntl( KeywordLocalization eKeywordLocalization ) |
160 | 1.68M | { |
161 | 1.68M | meKeywordLocalization = eKeywordLocalization; |
162 | 1.68M | bKeywordsNeedInit = true; |
163 | 1.68M | bCompatCurNeedInit = true; |
164 | | // may be initialized by InitSpecialKeyword() |
165 | 1.68M | sKeyword[NF_KEY_TRUE].clear(); |
166 | 1.68M | sKeyword[NF_KEY_FALSE].clear(); |
167 | 1.68M | } |
168 | | |
169 | | void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const |
170 | 3.22M | { |
171 | 3.22M | switch ( eIdx ) |
172 | 3.22M | { |
173 | 1.61M | case NF_KEY_TRUE : |
174 | 1.61M | const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_TRUE] = |
175 | 1.61M | mrCurrentLanguageData.GetCharClass()->uppercase( mrCurrentLanguageData.GetLocaleData()->getTrueWord() ); |
176 | 1.61M | if ( sKeyword[NF_KEY_TRUE].isEmpty() ) |
177 | 0 | { |
178 | 0 | SAL_WARN( "svl.numbers", "InitSpecialKeyword: TRUE_WORD?" ); |
179 | 0 | const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_TRUE] = sEnglishKeyword[NF_KEY_TRUE]; |
180 | 0 | } |
181 | 1.61M | break; |
182 | 1.61M | case NF_KEY_FALSE : |
183 | 1.61M | const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_FALSE] = |
184 | 1.61M | mrCurrentLanguageData.GetCharClass()->uppercase( mrCurrentLanguageData.GetLocaleData()->getFalseWord() ); |
185 | 1.61M | if ( sKeyword[NF_KEY_FALSE].isEmpty() ) |
186 | 0 | { |
187 | 0 | SAL_WARN( "svl.numbers", "InitSpecialKeyword: FALSE_WORD?" ); |
188 | 0 | const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_FALSE] = sEnglishKeyword[NF_KEY_FALSE]; |
189 | 0 | } |
190 | 1.61M | break; |
191 | 1.61M | default: |
192 | 0 | SAL_WARN( "svl.numbers", "InitSpecialKeyword: unknown request" ); |
193 | 3.22M | } |
194 | 3.22M | } |
195 | | |
196 | | void ImpSvNumberformatScan::InitCompatCur() const |
197 | 1.59M | { |
198 | 1.59M | ImpSvNumberformatScan* pThis = const_cast<ImpSvNumberformatScan*>(this); |
199 | | // currency symbol for old style ("automatic") compatibility format codes |
200 | 1.59M | mrCurrentLanguageData.GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev ); |
201 | | // currency symbol upper case |
202 | 1.59M | pThis->sCurString = mrCurrentLanguageData.GetCharClass()->uppercase( sCurSymbol ); |
203 | 1.59M | bCompatCurNeedInit = false; |
204 | 1.59M | } |
205 | | |
206 | | void ImpSvNumberformatScan::InitKeywords() const |
207 | 233M | { |
208 | 233M | if ( !bKeywordsNeedInit ) |
209 | 232M | return ; |
210 | 1.59M | const_cast<ImpSvNumberformatScan*>(this)->SetDependentKeywords(); |
211 | 1.59M | bKeywordsNeedInit = false; |
212 | 1.59M | } |
213 | | |
214 | | /** Extract the name of General, Standard, Whatever, ignoring leading modifiers |
215 | | such as [NatNum1]. */ |
216 | | static OUString lcl_extractStandardGeneralName( const OUString & rCode ) |
217 | 1.59M | { |
218 | 1.59M | OUString aStr; |
219 | 1.59M | const sal_Unicode* p = rCode.getStr(); |
220 | 1.59M | const sal_Unicode* const pStop = p + rCode.getLength(); |
221 | 1.59M | const sal_Unicode* pBeg = p; // name begins here |
222 | 1.59M | bool bMod = false; |
223 | 1.59M | bool bDone = false; |
224 | 12.7M | while (p < pStop && !bDone) |
225 | 11.1M | { |
226 | 11.1M | switch (*p) |
227 | 11.1M | { |
228 | 0 | case '[': |
229 | 0 | bMod = true; |
230 | 0 | break; |
231 | 0 | case ']': |
232 | 0 | if (bMod) |
233 | 0 | { |
234 | 0 | bMod = false; |
235 | 0 | pBeg = p+1; |
236 | 0 | } |
237 | | // else: would be a locale data error, easily to be spotted in |
238 | | // UI dialog |
239 | 0 | break; |
240 | 0 | case ';': |
241 | 0 | if (!bMod) |
242 | 0 | { |
243 | 0 | bDone = true; |
244 | 0 | --p; // put back, increment by one follows |
245 | 0 | } |
246 | 0 | break; |
247 | 11.1M | } |
248 | 11.1M | ++p; |
249 | 11.1M | if (bMod) |
250 | 0 | { |
251 | 0 | pBeg = p; |
252 | 0 | } |
253 | 11.1M | } |
254 | 1.59M | if (pBeg < p) |
255 | 1.59M | { |
256 | 1.59M | aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg); |
257 | 1.59M | } |
258 | 1.59M | return aStr; |
259 | 1.59M | } |
260 | | |
261 | | void ImpSvNumberformatScan::SetDependentKeywords() |
262 | 1.59M | { |
263 | 1.59M | using namespace ::com::sun::star; |
264 | 1.59M | using namespace ::com::sun::star::uno; |
265 | | |
266 | 1.59M | const CharClass* pCharClass = mrCurrentLanguageData.GetCharClass(); |
267 | 1.59M | const LocaleDataWrapper* pLocaleData = mrCurrentLanguageData.GetLocaleData(); |
268 | | // #80023# be sure to generate keywords for the loaded Locale, not for the |
269 | | // requested Locale, otherwise number format codes might not match |
270 | 1.59M | const LanguageTag aLoadedLocale = pLocaleData->getLoadedLanguageTag(); |
271 | 1.59M | LanguageType eLang = aLoadedLocale.getLanguageType( false); |
272 | | |
273 | 1.59M | bool bL10n = (meKeywordLocalization != KeywordLocalization::EnglishOnly); |
274 | 1.59M | if (bL10n) |
275 | 1.59M | { |
276 | | // Check if this actually is a locale that uses any localized keywords, |
277 | | // if not then disable localized keywords completely. |
278 | 1.59M | if ( !eLang.anyOf( LANGUAGE_GERMAN, |
279 | 1.59M | LANGUAGE_GERMAN_SWISS, |
280 | 1.59M | LANGUAGE_GERMAN_AUSTRIAN, |
281 | 1.59M | LANGUAGE_GERMAN_LUXEMBOURG, |
282 | 1.59M | LANGUAGE_GERMAN_LIECHTENSTEIN, |
283 | 1.59M | LANGUAGE_DUTCH, |
284 | 1.59M | LANGUAGE_DUTCH_BELGIAN, |
285 | 1.59M | LANGUAGE_FRENCH, |
286 | 1.59M | LANGUAGE_FRENCH_BELGIAN, |
287 | 1.59M | LANGUAGE_FRENCH_CANADIAN, |
288 | 1.59M | LANGUAGE_FRENCH_SWISS, |
289 | 1.59M | LANGUAGE_FRENCH_LUXEMBOURG, |
290 | 1.59M | LANGUAGE_FRENCH_MONACO, |
291 | 1.59M | LANGUAGE_FINNISH, |
292 | 1.59M | LANGUAGE_ITALIAN, |
293 | 1.59M | LANGUAGE_ITALIAN_SWISS, |
294 | 1.59M | LANGUAGE_DANISH, |
295 | 1.59M | LANGUAGE_NORWEGIAN, |
296 | 1.59M | LANGUAGE_NORWEGIAN_BOKMAL, |
297 | 1.59M | LANGUAGE_NORWEGIAN_NYNORSK, |
298 | 1.59M | LANGUAGE_SWEDISH, |
299 | 1.59M | LANGUAGE_SWEDISH_FINLAND, |
300 | 1.59M | LANGUAGE_PORTUGUESE, |
301 | 1.59M | LANGUAGE_PORTUGUESE_BRAZILIAN, |
302 | 1.59M | LANGUAGE_SPANISH_MODERN, |
303 | 1.59M | LANGUAGE_SPANISH_DATED, |
304 | 1.59M | LANGUAGE_SPANISH_MEXICAN, |
305 | 1.59M | LANGUAGE_SPANISH_GUATEMALA, |
306 | 1.59M | LANGUAGE_SPANISH_COSTARICA, |
307 | 1.59M | LANGUAGE_SPANISH_PANAMA, |
308 | 1.59M | LANGUAGE_SPANISH_DOMINICAN_REPUBLIC, |
309 | 1.59M | LANGUAGE_SPANISH_VENEZUELA, |
310 | 1.59M | LANGUAGE_SPANISH_COLOMBIA, |
311 | 1.59M | LANGUAGE_SPANISH_PERU, |
312 | 1.59M | LANGUAGE_SPANISH_ARGENTINA, |
313 | 1.59M | LANGUAGE_SPANISH_ECUADOR, |
314 | 1.59M | LANGUAGE_SPANISH_CHILE, |
315 | 1.59M | LANGUAGE_SPANISH_URUGUAY, |
316 | 1.59M | LANGUAGE_SPANISH_PARAGUAY, |
317 | 1.59M | LANGUAGE_SPANISH_BOLIVIA, |
318 | 1.59M | LANGUAGE_SPANISH_EL_SALVADOR, |
319 | 1.59M | LANGUAGE_SPANISH_HONDURAS, |
320 | 1.59M | LANGUAGE_SPANISH_NICARAGUA, |
321 | 1.59M | LANGUAGE_SPANISH_PUERTO_RICO )) |
322 | 1.59M | { |
323 | 1.59M | bL10n = false; |
324 | 1.59M | meKeywordLocalization = KeywordLocalization::EnglishOnly; |
325 | 1.59M | } |
326 | 1.59M | } |
327 | | |
328 | | // Init the current NfKeywordTable with English keywords. |
329 | 1.59M | sKeyword = sEnglishKeyword; |
330 | | |
331 | | // Set the uppercase localized General name, e.g. Standard -> STANDARD |
332 | 1.59M | i18n::NumberFormatCode aFormat = xNFC->getFormatCode( NF_NUMBER_STANDARD, aLoadedLocale.getLocale() ); |
333 | 1.59M | sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code ); |
334 | 1.59M | sKeyword[NF_KEY_GENERAL] = pCharClass->uppercase( sNameStandardFormat ); |
335 | | |
336 | | // Thai T NatNum special. Other locale's small letter 't' results in upper |
337 | | // case comparison not matching but length does in conversion mode. Ugly. |
338 | 1.59M | if (eLang == LANGUAGE_THAI) |
339 | 0 | { |
340 | 0 | sKeyword[NF_KEY_THAI_T] = "T"; |
341 | 0 | } |
342 | 1.59M | else |
343 | 1.59M | { |
344 | 1.59M | sKeyword[NF_KEY_THAI_T] = sEnglishKeyword[NF_KEY_THAI_T]; |
345 | 1.59M | } |
346 | | |
347 | | // boolean keywords |
348 | 1.59M | InitSpecialKeyword( NF_KEY_TRUE ); |
349 | 1.59M | InitSpecialKeyword( NF_KEY_FALSE ); |
350 | | |
351 | | // Boolean equivalent format codes that are written to Excel files, may |
352 | | // have been written to ODF as well, specifically if such loaded Excel file |
353 | | // was saved as ODF, and shall result in proper Boolean again. |
354 | | // "TRUE";"TRUE";"FALSE" |
355 | 1.59M | sBooleanEquivalent1 = "\"" + sKeyword[NF_KEY_TRUE] + "\";\"" + |
356 | 1.59M | sKeyword[NF_KEY_TRUE] + "\";\"" + sKeyword[NF_KEY_FALSE] + "\""; |
357 | | // [>0]"TRUE";[<0]"TRUE";"FALSE" |
358 | 1.59M | sBooleanEquivalent2 = "[>0]\"" + sKeyword[NF_KEY_TRUE] + "\";[<0]\"" + |
359 | 1.59M | sKeyword[NF_KEY_TRUE] + "\";\"" + sKeyword[NF_KEY_FALSE] + "\""; |
360 | | |
361 | | // compatibility currency strings |
362 | 1.59M | InitCompatCur(); |
363 | | |
364 | 1.59M | if (!bL10n) |
365 | 1.59M | return; |
366 | | |
367 | | // All locale dependent keywords overrides follow. |
368 | | |
369 | 0 | if ( eLang.anyOf( |
370 | 0 | LANGUAGE_GERMAN, |
371 | 0 | LANGUAGE_GERMAN_SWISS, |
372 | 0 | LANGUAGE_GERMAN_AUSTRIAN, |
373 | 0 | LANGUAGE_GERMAN_LUXEMBOURG, |
374 | 0 | LANGUAGE_GERMAN_LIECHTENSTEIN)) |
375 | 0 | { |
376 | | //! all capital letters |
377 | 0 | sKeyword[NF_KEY_M] = "M"; // month 1 |
378 | 0 | sKeyword[NF_KEY_MM] = "MM"; // month 01 |
379 | 0 | sKeyword[NF_KEY_MMM] = "MMM"; // month Jan |
380 | 0 | sKeyword[NF_KEY_MMMM] = "MMMM"; // month Januar |
381 | 0 | sKeyword[NF_KEY_MMMMM] = "MMMMM"; // month J |
382 | 0 | sKeyword[NF_KEY_H] = "H"; // hour 2 |
383 | 0 | sKeyword[NF_KEY_HH] = "HH"; // hour 02 |
384 | 0 | sKeyword[NF_KEY_D] = "T"; |
385 | 0 | sKeyword[NF_KEY_DD] = "TT"; |
386 | 0 | sKeyword[NF_KEY_DDD] = "TTT"; |
387 | 0 | sKeyword[NF_KEY_DDDD] = "TTTT"; |
388 | 0 | sKeyword[NF_KEY_YY] = "JJ"; |
389 | 0 | sKeyword[NF_KEY_YYYY] = "JJJJ"; |
390 | 0 | sKeyword[NF_KEY_BOOLEAN] = "LOGISCH"; |
391 | 0 | sKeyword[NF_KEY_COLOR] = GermanColorName(NF_KEY_COLOR - NF_KEY_COLOR); |
392 | 0 | sKeyword[NF_KEY_BLACK] = GermanColorName(NF_KEY_BLACK - NF_KEY_COLOR); |
393 | 0 | sKeyword[NF_KEY_BLUE] = GermanColorName(NF_KEY_BLUE - NF_KEY_COLOR); |
394 | 0 | sKeyword[NF_KEY_GREEN] = GermanColorName(NF_KEY_GREEN - NF_KEY_COLOR); |
395 | 0 | sKeyword[NF_KEY_CYAN] = GermanColorName(NF_KEY_CYAN - NF_KEY_COLOR); |
396 | 0 | sKeyword[NF_KEY_RED] = GermanColorName(NF_KEY_RED - NF_KEY_COLOR); |
397 | 0 | sKeyword[NF_KEY_MAGENTA] = GermanColorName(NF_KEY_MAGENTA - NF_KEY_COLOR); |
398 | 0 | sKeyword[NF_KEY_BROWN] = GermanColorName(NF_KEY_BROWN - NF_KEY_COLOR); |
399 | 0 | sKeyword[NF_KEY_GREY] = GermanColorName(NF_KEY_GREY - NF_KEY_COLOR); |
400 | 0 | sKeyword[NF_KEY_YELLOW] = GermanColorName(NF_KEY_YELLOW - NF_KEY_COLOR); |
401 | 0 | sKeyword[NF_KEY_WHITE] = GermanColorName(NF_KEY_WHITE - NF_KEY_COLOR); |
402 | 0 | } |
403 | 0 | else |
404 | 0 | { |
405 | | // day |
406 | 0 | if ( eLang.anyOf( |
407 | 0 | LANGUAGE_ITALIAN, |
408 | 0 | LANGUAGE_ITALIAN_SWISS)) |
409 | 0 | { |
410 | 0 | sKeyword[NF_KEY_D] = "G"; |
411 | 0 | sKeyword[NF_KEY_DD] = "GG"; |
412 | 0 | sKeyword[NF_KEY_DDD] = "GGG"; |
413 | 0 | sKeyword[NF_KEY_DDDD] = "GGGG"; |
414 | | // must exchange the era code, same as Xcl |
415 | 0 | sKeyword[NF_KEY_G] = "X"; |
416 | 0 | sKeyword[NF_KEY_GG] = "XX"; |
417 | 0 | sKeyword[NF_KEY_GGG] = "XXX"; |
418 | 0 | } |
419 | 0 | else if ( eLang.anyOf( |
420 | 0 | LANGUAGE_FRENCH, |
421 | 0 | LANGUAGE_FRENCH_BELGIAN, |
422 | 0 | LANGUAGE_FRENCH_CANADIAN, |
423 | 0 | LANGUAGE_FRENCH_SWISS, |
424 | 0 | LANGUAGE_FRENCH_LUXEMBOURG, |
425 | 0 | LANGUAGE_FRENCH_MONACO)) |
426 | 0 | { |
427 | 0 | sKeyword[NF_KEY_D] = "J"; |
428 | 0 | sKeyword[NF_KEY_DD] = "JJ"; |
429 | 0 | sKeyword[NF_KEY_DDD] = "JJJ"; |
430 | 0 | sKeyword[NF_KEY_DDDD] = "JJJJ"; |
431 | 0 | } |
432 | 0 | else if ( eLang == LANGUAGE_FINNISH ) |
433 | 0 | { |
434 | 0 | sKeyword[NF_KEY_D] = "P"; |
435 | 0 | sKeyword[NF_KEY_DD] = "PP"; |
436 | 0 | sKeyword[NF_KEY_DDD] = "PPP"; |
437 | 0 | sKeyword[NF_KEY_DDDD] = "PPPP"; |
438 | 0 | } |
439 | | |
440 | | // month |
441 | 0 | if ( eLang == LANGUAGE_FINNISH ) |
442 | 0 | { |
443 | 0 | sKeyword[NF_KEY_M] = "K"; |
444 | 0 | sKeyword[NF_KEY_MM] = "KK"; |
445 | 0 | sKeyword[NF_KEY_MMM] = "KKK"; |
446 | 0 | sKeyword[NF_KEY_MMMM] = "KKKK"; |
447 | 0 | sKeyword[NF_KEY_MMMMM] = "KKKKK"; |
448 | 0 | } |
449 | | |
450 | | // year |
451 | 0 | if ( eLang.anyOf( |
452 | 0 | LANGUAGE_ITALIAN, |
453 | 0 | LANGUAGE_ITALIAN_SWISS, |
454 | 0 | LANGUAGE_FRENCH, |
455 | 0 | LANGUAGE_FRENCH_BELGIAN, |
456 | 0 | LANGUAGE_FRENCH_CANADIAN, |
457 | 0 | LANGUAGE_FRENCH_SWISS, |
458 | 0 | LANGUAGE_FRENCH_LUXEMBOURG, |
459 | 0 | LANGUAGE_FRENCH_MONACO, |
460 | 0 | LANGUAGE_PORTUGUESE, |
461 | 0 | LANGUAGE_PORTUGUESE_BRAZILIAN, |
462 | 0 | LANGUAGE_SPANISH_MODERN, |
463 | 0 | LANGUAGE_SPANISH_DATED, |
464 | 0 | LANGUAGE_SPANISH_MEXICAN, |
465 | 0 | LANGUAGE_SPANISH_GUATEMALA, |
466 | 0 | LANGUAGE_SPANISH_COSTARICA, |
467 | 0 | LANGUAGE_SPANISH_PANAMA, |
468 | 0 | LANGUAGE_SPANISH_DOMINICAN_REPUBLIC, |
469 | 0 | LANGUAGE_SPANISH_VENEZUELA, |
470 | 0 | LANGUAGE_SPANISH_COLOMBIA, |
471 | 0 | LANGUAGE_SPANISH_PERU, |
472 | 0 | LANGUAGE_SPANISH_ARGENTINA, |
473 | 0 | LANGUAGE_SPANISH_ECUADOR, |
474 | 0 | LANGUAGE_SPANISH_CHILE, |
475 | 0 | LANGUAGE_SPANISH_URUGUAY, |
476 | 0 | LANGUAGE_SPANISH_PARAGUAY, |
477 | 0 | LANGUAGE_SPANISH_BOLIVIA, |
478 | 0 | LANGUAGE_SPANISH_EL_SALVADOR, |
479 | 0 | LANGUAGE_SPANISH_HONDURAS, |
480 | 0 | LANGUAGE_SPANISH_NICARAGUA, |
481 | 0 | LANGUAGE_SPANISH_PUERTO_RICO)) |
482 | 0 | { |
483 | 0 | sKeyword[NF_KEY_YY] = "AA"; |
484 | 0 | sKeyword[NF_KEY_YYYY] = "AAAA"; |
485 | | // must exchange the day of week name code, same as Xcl |
486 | 0 | sKeyword[NF_KEY_AAA] = "OOO"; |
487 | 0 | sKeyword[NF_KEY_AAAA] = "OOOO"; |
488 | 0 | } |
489 | 0 | else if ( eLang.anyOf( |
490 | 0 | LANGUAGE_DUTCH, |
491 | 0 | LANGUAGE_DUTCH_BELGIAN)) |
492 | 0 | { |
493 | 0 | sKeyword[NF_KEY_YY] = "JJ"; |
494 | 0 | sKeyword[NF_KEY_YYYY] = "JJJJ"; |
495 | 0 | } |
496 | 0 | else if ( eLang == LANGUAGE_FINNISH ) |
497 | 0 | { |
498 | 0 | sKeyword[NF_KEY_YY] = "VV"; |
499 | 0 | sKeyword[NF_KEY_YYYY] = "VVVV"; |
500 | 0 | } |
501 | | |
502 | | // hour |
503 | 0 | if ( eLang.anyOf( |
504 | 0 | LANGUAGE_DUTCH, |
505 | 0 | LANGUAGE_DUTCH_BELGIAN)) |
506 | 0 | { |
507 | 0 | sKeyword[NF_KEY_H] = "U"; |
508 | 0 | sKeyword[NF_KEY_HH] = "UU"; |
509 | 0 | } |
510 | 0 | else if ( eLang.anyOf( |
511 | 0 | LANGUAGE_FINNISH, |
512 | 0 | LANGUAGE_SWEDISH, |
513 | 0 | LANGUAGE_SWEDISH_FINLAND, |
514 | 0 | LANGUAGE_DANISH, |
515 | 0 | LANGUAGE_NORWEGIAN, |
516 | 0 | LANGUAGE_NORWEGIAN_BOKMAL, |
517 | 0 | LANGUAGE_NORWEGIAN_NYNORSK)) |
518 | 0 | { |
519 | 0 | sKeyword[NF_KEY_H] = "T"; |
520 | 0 | sKeyword[NF_KEY_HH] = "TT"; |
521 | 0 | } |
522 | 0 | } |
523 | 0 | } |
524 | | |
525 | | void ImpSvNumberformatScan::ChangeNullDate(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear) |
526 | 207k | { |
527 | 207k | Date aDate(nDay, nMonth, nYear); |
528 | 207k | if (!aDate.IsValidDate()) |
529 | 0 | { |
530 | 0 | aDate.Normalize(); |
531 | 0 | SAL_WARN("svl.numbers","ImpSvNumberformatScan::ChangeNullDate - not valid" |
532 | 0 | " d: " << nDay << " m: " << nMonth << " y: " << nYear << " normalized to" |
533 | 0 | " d: " << aDate.GetDay() << " m: " << aDate.GetMonth() << " y: " << aDate.GetYear()); |
534 | | // Slap the caller if really bad, like year 0. |
535 | 0 | assert(aDate.IsValidDate()); |
536 | 0 | } |
537 | 207k | if (aDate.IsValidDate()) |
538 | 207k | maNullDate = aDate; |
539 | 207k | } |
540 | | |
541 | | void ImpSvNumberformatScan::ChangeStandardPrec(sal_uInt16 nPrec) |
542 | 265k | { |
543 | 265k | nStandardPrec = nPrec; |
544 | 265k | } |
545 | | |
546 | | const Color* ImpSvNumberformatScan::GetColor(OUString& sStr) const |
547 | 1.53M | { |
548 | 1.53M | OUString sString = mrCurrentLanguageData.GetCharClass()->uppercase(sStr); |
549 | 1.53M | const NfKeywordTable & rKeyword = GetKeywords(); |
550 | 1.53M | size_t i = 0; |
551 | 7.73M | while (i < NF_MAX_DEFAULT_COLORS && sString != rKeyword[NF_KEY_FIRSTCOLOR+i] ) |
552 | 6.20M | { |
553 | 6.20M | i++; |
554 | 6.20M | } |
555 | 1.53M | if (i >= NF_MAX_DEFAULT_COLORS && meKeywordLocalization == KeywordLocalization::AllowEnglish) |
556 | 0 | { |
557 | 0 | LanguageType eLang = mrCurrentLanguageData.GetLocaleData()->getLoadedLanguageTag().getLanguageType( false); |
558 | 0 | if ( eLang.anyOf( |
559 | 0 | LANGUAGE_GERMAN, |
560 | 0 | LANGUAGE_GERMAN_SWISS, |
561 | 0 | LANGUAGE_GERMAN_AUSTRIAN, |
562 | 0 | LANGUAGE_GERMAN_LUXEMBOURG, |
563 | 0 | LANGUAGE_GERMAN_LIECHTENSTEIN )) // only German uses localized color names |
564 | 0 | { |
565 | 0 | size_t j = 0; |
566 | 0 | while ( j < NF_MAX_DEFAULT_COLORS && sString != sEnglishKeyword[NF_KEY_FIRSTCOLOR + j] ) |
567 | 0 | { |
568 | 0 | ++j; |
569 | 0 | } |
570 | 0 | if ( j < NF_MAX_DEFAULT_COLORS ) |
571 | 0 | { |
572 | 0 | i = j; |
573 | 0 | } |
574 | 0 | } |
575 | 0 | } |
576 | | |
577 | 1.53M | enum ColorKeywordConversion |
578 | 1.53M | { |
579 | 1.53M | None, |
580 | 1.53M | GermanToEnglish, |
581 | 1.53M | EnglishToGerman |
582 | 1.53M | } eColorKeywordConversion(None); |
583 | | |
584 | 1.53M | if (bConvertMode) |
585 | 35.0k | { |
586 | 35.0k | const bool bFromGerman = eTmpLnge.anyOf( |
587 | 35.0k | LANGUAGE_GERMAN, |
588 | 35.0k | LANGUAGE_GERMAN_SWISS, |
589 | 35.0k | LANGUAGE_GERMAN_AUSTRIAN, |
590 | 35.0k | LANGUAGE_GERMAN_LUXEMBOURG, |
591 | 35.0k | LANGUAGE_GERMAN_LIECHTENSTEIN); |
592 | 35.0k | const bool bToGerman = eNewLnge.anyOf( |
593 | 35.0k | LANGUAGE_GERMAN, |
594 | 35.0k | LANGUAGE_GERMAN_SWISS, |
595 | 35.0k | LANGUAGE_GERMAN_AUSTRIAN, |
596 | 35.0k | LANGUAGE_GERMAN_LUXEMBOURG, |
597 | 35.0k | LANGUAGE_GERMAN_LIECHTENSTEIN); |
598 | 35.0k | if (bFromGerman && !bToGerman) |
599 | 737 | eColorKeywordConversion = ColorKeywordConversion::GermanToEnglish; |
600 | 34.2k | else if (!bFromGerman && bToGerman) |
601 | 0 | eColorKeywordConversion = ColorKeywordConversion::EnglishToGerman; |
602 | 35.0k | } |
603 | | |
604 | 1.53M | const Color* pResult = nullptr; |
605 | 1.53M | if (i >= NF_MAX_DEFAULT_COLORS) |
606 | 10.8k | { |
607 | 10.8k | const OUString& rColorWord = rKeyword[NF_KEY_COLOR]; |
608 | 10.8k | bool bL10n = true; |
609 | 10.8k | if ((bL10n = sString.startsWith(rColorWord)) || |
610 | 9.67k | ((meKeywordLocalization == KeywordLocalization::AllowEnglish) && |
611 | 0 | sString.startsWith(sEnglishKeyword[NF_KEY_COLOR]))) |
612 | 1.18k | { |
613 | 1.18k | sal_Int32 nPos = (bL10n ? rColorWord.getLength() : sEnglishKeyword[NF_KEY_COLOR].getLength()); |
614 | 1.18k | sStr = sStr.copy(nPos); |
615 | 1.18k | sStr = comphelper::string::strip(sStr, ' '); |
616 | 1.18k | switch (eColorKeywordConversion) |
617 | 1.18k | { |
618 | 1.04k | case ColorKeywordConversion::None: |
619 | 1.04k | sStr = rColorWord + sStr; |
620 | 1.04k | break; |
621 | 146 | case ColorKeywordConversion::GermanToEnglish: |
622 | 146 | sStr = sEnglishKeyword[NF_KEY_COLOR] + sStr; // Farbe -> COLOR |
623 | 146 | break; |
624 | 0 | case ColorKeywordConversion::EnglishToGerman: |
625 | 0 | sStr = GermanColorName(NF_KEY_COLOR - NF_KEY_COLOR) + sStr; // Color -> FARBE |
626 | 0 | break; |
627 | 1.18k | } |
628 | 1.18k | sString = sString.copy(nPos); |
629 | 1.18k | sString = comphelper::string::strip(sString, ' '); |
630 | | |
631 | 1.18k | if ( CharClass::isAsciiNumeric( sString ) ) |
632 | 314 | { |
633 | 314 | sal_Int32 nIndex = sString.toInt32(); |
634 | 314 | if (nIndex > 0 && nIndex <= 64) |
635 | 256 | { |
636 | 256 | pResult = GetUserDefColor(static_cast<sal_uInt16>(nIndex)-1); |
637 | 256 | } |
638 | 314 | } |
639 | 1.18k | } |
640 | 10.8k | } |
641 | 1.52M | else |
642 | 1.52M | { |
643 | 1.52M | sStr.clear(); |
644 | 1.52M | switch (eColorKeywordConversion) |
645 | 1.52M | { |
646 | 1.52M | case ColorKeywordConversion::None: |
647 | 1.52M | sStr = rKeyword[NF_KEY_FIRSTCOLOR+i]; |
648 | 1.52M | break; |
649 | 89 | case ColorKeywordConversion::GermanToEnglish: |
650 | 89 | sStr = sEnglishKeyword[NF_KEY_FIRSTCOLOR + i]; // Rot -> RED |
651 | 89 | break; |
652 | 0 | case ColorKeywordConversion::EnglishToGerman: |
653 | 0 | sStr = GermanColorName(NF_KEY_FIRSTCOLOR - NF_KEY_COLOR + i); // Red -> ROT |
654 | 0 | break; |
655 | 1.52M | } |
656 | 1.52M | pResult = &(StandardColor[i]); |
657 | 1.52M | } |
658 | 1.53M | return pResult; |
659 | 1.53M | } |
660 | | |
661 | | short ImpSvNumberformatScan::GetKeyWord( const OUString& sSymbol, sal_Int32 nPos, bool& rbFoundEnglish ) const |
662 | 61.2M | { |
663 | 61.2M | OUString sString = mrCurrentLanguageData.GetCharClass()->uppercase( sSymbol, nPos, sSymbol.getLength() - nPos ); |
664 | 61.2M | const NfKeywordTable & rKeyword = GetKeywords(); |
665 | | // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere |
666 | 61.2M | if (sString.startsWith( rKeyword[NF_KEY_GENERAL] )) |
667 | 246k | { |
668 | 246k | return NF_KEY_GENERAL; |
669 | 246k | } |
670 | 61.0M | if ((meKeywordLocalization == KeywordLocalization::AllowEnglish) && |
671 | 0 | sString.startsWith( sEnglishKeyword[NF_KEY_GENERAL])) |
672 | 0 | { |
673 | 0 | rbFoundEnglish = true; |
674 | 0 | return NF_KEY_GENERAL; |
675 | 0 | } |
676 | | |
677 | | // MUST be a reverse search to find longer strings first, |
678 | | // new keywords take precedence over old keywords, |
679 | | // skip colors et al after keywords. |
680 | 61.0M | short i = NF_KEY_LASTKEYWORD; |
681 | 1.62G | while (i > 0 && !sString.startsWith( rKeyword[i])) |
682 | 1.56G | { |
683 | 1.56G | i--; |
684 | 1.56G | } |
685 | 61.0M | if (i == 0 && meKeywordLocalization == KeywordLocalization::AllowEnglish) |
686 | 0 | { |
687 | | // No localized (if so) keyword, try English keywords if keywords |
688 | | // are localized. That was already checked in SetDependentKeywords(). |
689 | 0 | i = NF_KEY_LASTKEYWORD; |
690 | 0 | while (i > 0 && !sString.startsWith( sEnglishKeyword[i])) |
691 | 0 | { |
692 | 0 | i--; |
693 | 0 | } |
694 | 0 | } |
695 | | |
696 | | // The Thai T NatNum modifier during Xcl import. |
697 | 61.0M | if (i == 0 && bConvertMode && |
698 | 2.49M | sString[0] == 'T' && |
699 | 83.6k | eTmpLnge == LANGUAGE_ENGLISH_US && |
700 | 46.2k | MsLangId::getRealLanguage( eNewLnge) == LANGUAGE_THAI) |
701 | 0 | { |
702 | 0 | i = NF_KEY_THAI_T; |
703 | 0 | } |
704 | 61.0M | return i; // 0 => not found |
705 | 61.0M | } |
706 | | |
707 | | /** |
708 | | * Next_Symbol |
709 | | * |
710 | | * Splits up the input for further processing (by the Turing machine). |
711 | | * |
712 | | * Starting state = SsStar |
713 | | * |
714 | | * ---------------+-------------------+---------------------------+--------------- |
715 | | * Old state | Character read | Event | New state |
716 | | * ---------------+-------------------+---------------------------+--------------- |
717 | | * SsStart | Character | Symbol = Character | SsGetWord |
718 | | * | " | Type = String | SsGetString |
719 | | * | \ | Type = String | SsGetChar |
720 | | * | * | Type = Star | SsGetStar |
721 | | * | _ | Type = Blank | SsGetBlank |
722 | | * | @ # 0 ? / . , % [ | Symbol = Character; | |
723 | | * | ] ' Blank | Type = Control character | SsStop |
724 | | * | $ - + ( ) : | Type = String; | |
725 | | * | Else | Symbol = Character | SsStop |
726 | | * ---------------|-------------------+---------------------------+--------------- |
727 | | * SsGetChar | Else | Symbol = Character | SsStop |
728 | | * ---------------+-------------------+---------------------------+--------------- |
729 | | * GetString | " | | SsStop |
730 | | * | Else | Symbol += Character | GetString |
731 | | * ---------------+-------------------+---------------------------+--------------- |
732 | | * SsGetWord | Character | Symbol += Character | |
733 | | * | + - (E+ E-)| Symbol += Character | SsStop |
734 | | * | / (AM/PM)| Symbol += Character | |
735 | | * | Else | Pos--, if Key Type = Word | SsStop |
736 | | * ---------------+-------------------+---------------------------+--------------- |
737 | | * SsGetStar | Else | Symbol += Character | SsStop |
738 | | * | | Mark special case * | |
739 | | * ---------------+-------------------+---------------------------+--------------- |
740 | | * SsGetBlank | Else | Symbol + =Character | SsStop |
741 | | * | | Mark special case _ | |
742 | | * ---------------------------------------------------------------+-------------- |
743 | | * |
744 | | * If we recognize a keyword in the state SsGetWord (even as the symbol's start text) |
745 | | * we write back the rest of the characters! |
746 | | */ |
747 | | |
748 | | namespace { |
749 | | |
750 | | enum ScanState |
751 | | { |
752 | | SsStop = 0, |
753 | | SsStart = 1, |
754 | | SsGetChar = 2, |
755 | | SsGetString = 3, |
756 | | SsGetWord = 4, |
757 | | SsGetStar = 5, |
758 | | SsGetBlank = 6 |
759 | | }; |
760 | | |
761 | | } |
762 | | |
763 | | short ImpSvNumberformatScan::Next_Symbol( const OUString& rStr, |
764 | | sal_Int32& nPos, |
765 | | OUString& sSymbol ) const |
766 | 210M | { |
767 | 210M | InitKeywords(); |
768 | 210M | const CharClass* pChrCls = mrCurrentLanguageData.GetCharClass(); |
769 | 210M | const LocaleDataWrapper* pLoc = mrCurrentLanguageData.GetLocaleData(); |
770 | 210M | short eType = 0; |
771 | 210M | ScanState eState = SsStart; |
772 | 210M | OUStringBuffer sSymbolBuffer; |
773 | 432M | while ( nPos < rStr.getLength() && eState != SsStop ) |
774 | 221M | { |
775 | 221M | sal_Unicode cToken = rStr[nPos++]; |
776 | 221M | switch (eState) |
777 | 221M | { |
778 | 210M | case SsStart: |
779 | | // Fetch any currency longer than one character and don't get |
780 | | // confused later on by "E/" or other combinations of letters |
781 | | // and meaningful symbols. Necessary for old automatic currency. |
782 | | // #96158# But don't do it if we're starting a "[...]" section, |
783 | | // for example a "[$...]" new currency symbol to not parse away |
784 | | // "$U" (symbol) of "[$UYU]" (abbreviation). |
785 | 210M | if ( nCurrPos >= 0 && sCurString.getLength() > 1 && |
786 | 1.43M | nPos-1 + sCurString.getLength() <= rStr.getLength() && |
787 | 1.27M | (nPos <= 1 || rStr[nPos-2] != '[') ) |
788 | 1.21M | { |
789 | 1.21M | OUString aTest = pChrCls->uppercase( rStr.copy( nPos-1, sCurString.getLength() ) ); |
790 | 1.21M | if ( aTest == sCurString ) |
791 | 109k | { |
792 | 109k | sSymbol = rStr.copy( --nPos, sCurString.getLength() ); |
793 | 109k | nPos = nPos + sSymbol.getLength(); |
794 | 109k | eType = NF_SYMBOLTYPE_STRING; |
795 | 109k | return eType; |
796 | 109k | } |
797 | 1.21M | } |
798 | 210M | switch (cToken) |
799 | 210M | { |
800 | 26.6M | case '#': |
801 | 59.5M | case '0': |
802 | 64.6M | case '?': |
803 | 65.1M | case '%': |
804 | 65.4M | case '@': |
805 | 71.8M | case '[': |
806 | 78.2M | case ']': |
807 | 88.2M | case ',': |
808 | 96.5M | case '.': |
809 | 102M | case '/': |
810 | 102M | case '\'': |
811 | 116M | case ' ': |
812 | 122M | case ':': |
813 | 134M | case '-': |
814 | 134M | eType = NF_SYMBOLTYPE_DEL; |
815 | 134M | sSymbolBuffer.append(OUStringChar(cToken)); |
816 | 134M | eState = SsStop; |
817 | 134M | break; |
818 | 1.00M | case '*': |
819 | 1.00M | eType = NF_SYMBOLTYPE_STAR; |
820 | 1.00M | sSymbolBuffer.append(OUStringChar(cToken)); |
821 | 1.00M | eState = SsGetStar; |
822 | 1.00M | break; |
823 | 624k | case '_': |
824 | 624k | eType = NF_SYMBOLTYPE_BLANK; |
825 | 624k | sSymbolBuffer.append(OUStringChar(cToken)); |
826 | 624k | eState = SsGetBlank; |
827 | 624k | break; |
828 | 537k | case '"': |
829 | 537k | eType = NF_SYMBOLTYPE_STRING; |
830 | 537k | eState = SsGetString; |
831 | 537k | sSymbolBuffer.append(OUStringChar(cToken)); |
832 | 537k | break; |
833 | 148k | case '\\': |
834 | 148k | eType = NF_SYMBOLTYPE_STRING; |
835 | 148k | eState = SsGetChar; |
836 | 148k | sSymbolBuffer.append(OUStringChar(cToken)); |
837 | 148k | break; |
838 | 9.21M | case '$': |
839 | 9.23M | case '+': |
840 | 9.75M | case '(': |
841 | 10.2M | case ')': |
842 | 10.2M | eType = NF_SYMBOLTYPE_STRING; |
843 | 10.2M | eState = SsStop; |
844 | 10.2M | sSymbolBuffer.append(OUStringChar(cToken)); |
845 | 10.2M | break; |
846 | 63.6M | default : |
847 | 63.6M | if (StringEqualsChar( mrCurrentLanguageData.GetNumDecimalSep(), cToken) || |
848 | 63.6M | StringEqualsChar( mrCurrentLanguageData.GetNumThousandSep(), cToken) || |
849 | 63.6M | StringEqualsChar( mrCurrentLanguageData.GetDateSep(), cToken) || |
850 | 63.6M | StringEqualsChar( pLoc->getTimeSep(), cToken) || |
851 | 63.6M | StringEqualsChar( pLoc->getTime100SecSep(), cToken)) |
852 | 0 | { |
853 | | // Another separator than pre-known ASCII |
854 | 0 | eType = NF_SYMBOLTYPE_DEL; |
855 | 0 | sSymbolBuffer.append(OUStringChar(cToken)); |
856 | 0 | eState = SsStop; |
857 | 0 | } |
858 | 63.6M | else if ( pChrCls->isLetter( rStr, nPos-1 ) ) |
859 | 51.7M | { |
860 | 51.7M | bool bFoundEnglish = false; |
861 | 51.7M | short nTmpType = GetKeyWord( rStr, nPos-1, bFoundEnglish); |
862 | 51.7M | if ( nTmpType ) |
863 | 46.1M | { |
864 | 46.1M | bool bCurrency = false; |
865 | | // "Automatic" currency may start with keyword, |
866 | | // like "R" (Rand) and 'R' (era) |
867 | 46.1M | if ( nCurrPos >= 0 && |
868 | 146k | nPos-1 + sCurString.getLength() <= rStr.getLength() && |
869 | 146k | sCurString.startsWith( bFoundEnglish ? sEnglishKeyword[nTmpType] : sKeyword[nTmpType])) |
870 | 31.8k | { |
871 | 31.8k | OUString aTest = pChrCls->uppercase( rStr.copy( nPos-1, sCurString.getLength() ) ); |
872 | 31.8k | if ( aTest == sCurString ) |
873 | 31.7k | { |
874 | 31.7k | bCurrency = true; |
875 | 31.7k | } |
876 | 31.8k | } |
877 | 46.1M | if ( bCurrency ) |
878 | 31.7k | { |
879 | 31.7k | eState = SsGetWord; |
880 | 31.7k | sSymbolBuffer.append(OUStringChar(cToken)); |
881 | 31.7k | } |
882 | 46.1M | else |
883 | 46.1M | { |
884 | 46.1M | eType = nTmpType; |
885 | | // The code to be advanced is the detected keyword, |
886 | | // not necessarily the locale's keyword, but the |
887 | | // symbol is to be the locale's keyword. |
888 | 46.1M | sal_Int32 nLen; |
889 | 46.1M | if (bFoundEnglish) |
890 | 0 | { |
891 | 0 | nLen = sEnglishKeyword[eType].getLength(); |
892 | | // Use the locale's General keyword name, not uppercase. |
893 | 0 | sSymbolBuffer = (eType == NF_KEY_GENERAL ? sNameStandardFormat : sKeyword[eType]); |
894 | 0 | } |
895 | 46.1M | else |
896 | 46.1M | { |
897 | 46.1M | nLen = sKeyword[eType].getLength(); |
898 | | // Preserve a locale's keyword's case as entered. |
899 | 46.1M | sSymbolBuffer = rStr.subView( nPos-1, nLen); |
900 | 46.1M | } |
901 | 46.1M | if ((eType == NF_KEY_E || IsAmbiguousE(eType)) && nPos < rStr.getLength()) |
902 | 3.21M | { |
903 | 3.21M | sal_Unicode cNext = rStr[nPos]; |
904 | 3.21M | switch ( cNext ) |
905 | 3.21M | { |
906 | 730k | case '+' : |
907 | 737k | case '-' : // E+ E- combine to one symbol |
908 | 737k | sSymbolBuffer.append(OUStringChar(cNext)); |
909 | 737k | eType = NF_KEY_E; |
910 | 737k | nPos++; |
911 | 737k | break; |
912 | 8.42k | case '0' : |
913 | 10.0k | case '#' : // scientific E without sign |
914 | 10.0k | eType = NF_KEY_E; |
915 | 10.0k | break; |
916 | 3.21M | } |
917 | 3.21M | } |
918 | 46.1M | nPos--; |
919 | 46.1M | nPos = nPos + nLen; |
920 | 46.1M | eState = SsStop; |
921 | 46.1M | } |
922 | 46.1M | } |
923 | 5.55M | else |
924 | 5.55M | { |
925 | 5.55M | eState = SsGetWord; |
926 | 5.55M | sSymbolBuffer.append(OUStringChar(cToken)); |
927 | 5.55M | } |
928 | 51.7M | } |
929 | 11.9M | else |
930 | 11.9M | { |
931 | 11.9M | eType = NF_SYMBOLTYPE_STRING; |
932 | 11.9M | eState = SsStop; |
933 | 11.9M | sSymbolBuffer.append(OUStringChar(cToken)); |
934 | 11.9M | } |
935 | 63.6M | break; |
936 | 210M | } |
937 | 210M | break; |
938 | 210M | case SsGetChar: |
939 | 147k | sSymbolBuffer.append(OUStringChar(cToken)); |
940 | 147k | eState = SsStop; |
941 | 147k | break; |
942 | 1.18M | case SsGetString: |
943 | 1.18M | if (cToken == '"') |
944 | 526k | { |
945 | 526k | eState = SsStop; |
946 | 526k | } |
947 | 1.18M | sSymbolBuffer.append(OUStringChar(cToken)); |
948 | 1.18M | break; |
949 | 8.37M | case SsGetWord: |
950 | 8.37M | if ( pChrCls->isLetter( rStr, nPos-1 ) ) |
951 | 7.91M | { |
952 | 7.91M | bool bFoundEnglish = false; |
953 | 7.91M | short nTmpType = GetKeyWord( rStr, nPos-1, bFoundEnglish); |
954 | 7.91M | if ( nTmpType ) |
955 | 5.02M | { |
956 | | // beginning of keyword, stop scan and put back |
957 | 5.02M | eType = NF_SYMBOLTYPE_STRING; |
958 | 5.02M | eState = SsStop; |
959 | 5.02M | nPos--; |
960 | 5.02M | } |
961 | 2.89M | else |
962 | 2.89M | { |
963 | 2.89M | sSymbolBuffer.append(OUStringChar(cToken)); |
964 | 2.89M | } |
965 | 7.91M | } |
966 | 460k | else |
967 | 460k | { |
968 | 460k | bool bDontStop = false; |
969 | 460k | sal_Unicode cNext; |
970 | 460k | switch (cToken) |
971 | 460k | { |
972 | 17.9k | case '/': // AM/PM, A/P |
973 | 17.9k | if (nPos < rStr.getLength()) |
974 | 17.4k | { |
975 | 17.4k | cNext = rStr[nPos]; |
976 | 17.4k | if ( cNext == 'P' || cNext == 'p' ) |
977 | 2.32k | { |
978 | 2.32k | sal_Int32 nLen = sSymbolBuffer.getLength(); |
979 | 2.32k | if ( 1 <= nLen && |
980 | 2.32k | (sSymbolBuffer[0] == 'A' || sSymbolBuffer[0] == 'a') && |
981 | 790 | (nLen == 1 || |
982 | 790 | (nLen == 2 && (sSymbolBuffer[1] == 'M' || sSymbolBuffer[1] == 'm') |
983 | 0 | && (rStr[nPos + 1] == 'M' || rStr[nPos + 1] == 'm')))) |
984 | 0 | { |
985 | 0 | sSymbolBuffer.append(OUStringChar(cToken)); |
986 | 0 | bDontStop = true; |
987 | 0 | } |
988 | 2.32k | } |
989 | 17.4k | } |
990 | 17.9k | break; |
991 | 460k | } |
992 | | // anything not recognized will stop the scan |
993 | 460k | if (!bDontStop) |
994 | 460k | { |
995 | 460k | eState = SsStop; |
996 | 460k | nPos--; |
997 | 460k | eType = NF_SYMBOLTYPE_STRING; |
998 | 460k | } |
999 | 460k | } |
1000 | 8.37M | break; |
1001 | 8.37M | case SsGetStar: |
1002 | 1.62M | case SsGetBlank: |
1003 | 1.62M | eState = SsStop; |
1004 | 1.62M | sSymbolBuffer.append(OUStringChar(cToken)); |
1005 | 1.62M | break; |
1006 | 0 | default: |
1007 | 0 | break; |
1008 | 221M | } // of switch |
1009 | 221M | } // of while |
1010 | 210M | if (eState == SsGetWord) |
1011 | 104k | { |
1012 | 104k | eType = NF_SYMBOLTYPE_STRING; |
1013 | 104k | } |
1014 | 210M | sSymbol = sSymbolBuffer.makeStringAndClear(); |
1015 | 210M | return eType; |
1016 | 210M | } |
1017 | | |
1018 | | sal_Int32 ImpSvNumberformatScan::Symbol_Division(const OUString& rString) |
1019 | 25.9M | { |
1020 | 25.9M | nCurrPos = -1; |
1021 | | // Do we have some sort of currency? |
1022 | 25.9M | OUString sString = mrCurrentLanguageData.GetCharClass()->uppercase(rString); |
1023 | 25.9M | sal_Int32 nCPos = 0; |
1024 | 51.8M | while (nCPos >= 0 && nCPos < sString.getLength()) |
1025 | 25.9M | { |
1026 | 25.9M | nCPos = sString.indexOf(GetCurString(),nCPos); |
1027 | 25.9M | if (nCPos >= 0) |
1028 | 5.97M | { |
1029 | | // In Quotes? |
1030 | 5.97M | sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sString, nCPos ); |
1031 | 5.97M | if ( nQ < 0 ) |
1032 | 5.96M | { |
1033 | 5.96M | sal_Unicode c; |
1034 | 5.96M | if ( nCPos == 0 || |
1035 | 4.70M | ((c = sString[nCPos-1]) != '"' |
1036 | 4.70M | && c != '\\') ) // dm can be protected by "dm \d |
1037 | 5.95M | { |
1038 | 5.95M | nCurrPos = nCPos; |
1039 | 5.95M | nCPos = -1; |
1040 | 5.95M | } |
1041 | 2.57k | else |
1042 | 2.57k | { |
1043 | 2.57k | nCPos++; // Continue search |
1044 | 2.57k | } |
1045 | 5.96M | } |
1046 | 9.48k | else |
1047 | 9.48k | { |
1048 | 9.48k | nCPos = nQ + 1; // Continue search |
1049 | 9.48k | } |
1050 | 5.97M | } |
1051 | 25.9M | } |
1052 | 25.9M | nStringsCnt = 0; |
1053 | 25.9M | bool bStar = false; // Is set on detecting '*' |
1054 | 25.9M | Reset(); |
1055 | | |
1056 | 25.9M | sal_Int32 nPos = 0; |
1057 | 25.9M | const sal_Int32 nLen = rString.getLength(); |
1058 | 236M | while (nPos < nLen && nStringsCnt < NF_MAX_FORMAT_SYMBOLS) |
1059 | 210M | { |
1060 | 210M | nTypeArray[nStringsCnt] = Next_Symbol(rString, nPos, sStrArray[nStringsCnt]); |
1061 | 210M | if (nTypeArray[nStringsCnt] == NF_SYMBOLTYPE_STAR) |
1062 | 1.00M | { // Monitoring the '*' |
1063 | 1.00M | if (bStar) |
1064 | 1.15k | { |
1065 | 1.15k | return nPos; // Error: double '*' |
1066 | 1.15k | } |
1067 | 1.00M | else |
1068 | 1.00M | { |
1069 | | // Valid only if there is a character following, else we are |
1070 | | // at the end of a code that does not have a fill character |
1071 | | // (yet?). |
1072 | 1.00M | if (sStrArray[nStringsCnt].getLength() < 2) |
1073 | 503 | return nPos; |
1074 | 1.00M | bStar = true; |
1075 | 1.00M | } |
1076 | 1.00M | } |
1077 | 210M | nStringsCnt++; |
1078 | 210M | } |
1079 | | |
1080 | 25.9M | return 0; // 0 => ok |
1081 | 25.9M | } |
1082 | | |
1083 | | void ImpSvNumberformatScan::SkipStrings(sal_uInt16& i, sal_Int32& nPos) const |
1084 | 185M | { |
1085 | 194M | while (i < nStringsCnt && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING |
1086 | 161M | || nTypeArray[i] == NF_SYMBOLTYPE_BLANK |
1087 | 160M | || nTypeArray[i] == NF_SYMBOLTYPE_STAR) ) |
1088 | 8.92M | { |
1089 | 8.92M | nPos = nPos + sStrArray[i].getLength(); |
1090 | 8.92M | i++; |
1091 | 8.92M | } |
1092 | 185M | } |
1093 | | |
1094 | | sal_uInt16 ImpSvNumberformatScan::PreviousKeyword(sal_uInt16 i) const |
1095 | 10.4M | { |
1096 | 10.4M | short res = 0; |
1097 | 10.4M | if (i > 0 && i < nStringsCnt) |
1098 | 8.32M | { |
1099 | 8.32M | i--; |
1100 | 20.1M | while (i > 0 && nTypeArray[i] <= 0) |
1101 | 11.7M | { |
1102 | 11.7M | i--; |
1103 | 11.7M | } |
1104 | 8.32M | if (nTypeArray[i] > 0) |
1105 | 8.22M | { |
1106 | 8.22M | res = nTypeArray[i]; |
1107 | 8.22M | } |
1108 | 8.32M | } |
1109 | 10.4M | return res; |
1110 | 10.4M | } |
1111 | | |
1112 | | sal_uInt16 ImpSvNumberformatScan::NextKeyword(sal_uInt16 i) const |
1113 | 7.56M | { |
1114 | 7.56M | short res = 0; |
1115 | 7.56M | if (i < nStringsCnt-1) |
1116 | 7.27M | { |
1117 | 7.27M | i++; |
1118 | 14.4M | while (i < nStringsCnt-1 && nTypeArray[i] <= 0) |
1119 | 7.19M | { |
1120 | 7.19M | i++; |
1121 | 7.19M | } |
1122 | 7.27M | if (nTypeArray[i] > 0) |
1123 | 7.25M | { |
1124 | 7.25M | res = nTypeArray[i]; |
1125 | 7.25M | } |
1126 | 7.27M | } |
1127 | 7.56M | return res; |
1128 | 7.56M | } |
1129 | | |
1130 | | short ImpSvNumberformatScan::PreviousType( sal_uInt16 i ) const |
1131 | 15.7k | { |
1132 | 15.7k | if ( i > 0 && i < nStringsCnt ) |
1133 | 15.7k | { |
1134 | 15.7k | do |
1135 | 16.2k | { |
1136 | 16.2k | i--; |
1137 | 16.2k | } |
1138 | 16.2k | while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY ); |
1139 | 15.7k | return nTypeArray[i]; |
1140 | 15.7k | } |
1141 | 0 | return 0; |
1142 | 15.7k | } |
1143 | | |
1144 | | sal_Unicode ImpSvNumberformatScan::PreviousChar(sal_uInt16 i) const |
1145 | 11.5M | { |
1146 | 11.5M | sal_Unicode res = ' '; |
1147 | 11.5M | if (i > 0 && i < nStringsCnt) |
1148 | 9.60M | { |
1149 | 9.60M | i--; |
1150 | 9.72M | while (i > 0 && |
1151 | 8.22M | ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY || |
1152 | 8.20M | nTypeArray[i] == NF_SYMBOLTYPE_STRING || |
1153 | 8.10M | nTypeArray[i] == NF_SYMBOLTYPE_STAR || |
1154 | 8.10M | nTypeArray[i] == NF_SYMBOLTYPE_BLANK )) |
1155 | 126k | { |
1156 | 126k | i--; |
1157 | 126k | } |
1158 | 9.60M | if (sStrArray[i].getLength() > 0) |
1159 | 9.60M | { |
1160 | 9.60M | res = sStrArray[i][sStrArray[i].getLength()-1]; |
1161 | 9.60M | } |
1162 | 9.60M | } |
1163 | 11.5M | return res; |
1164 | 11.5M | } |
1165 | | |
1166 | | sal_Unicode ImpSvNumberformatScan::NextChar(sal_uInt16 i) const |
1167 | 8.41M | { |
1168 | 8.41M | sal_Unicode res = ' '; |
1169 | 8.41M | if (i < nStringsCnt-1) |
1170 | 8.41M | { |
1171 | 8.41M | i++; |
1172 | 8.42M | while (i < nStringsCnt-1 && |
1173 | 8.41M | ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY || |
1174 | 8.41M | nTypeArray[i] == NF_SYMBOLTYPE_STRING || |
1175 | 8.40M | nTypeArray[i] == NF_SYMBOLTYPE_STAR || |
1176 | 8.40M | nTypeArray[i] == NF_SYMBOLTYPE_BLANK)) |
1177 | 13.0k | { |
1178 | 13.0k | i++; |
1179 | 13.0k | } |
1180 | 8.41M | if (sStrArray[i].getLength() > 0) |
1181 | 8.41M | { |
1182 | 8.41M | res = sStrArray[i][0]; |
1183 | 8.41M | } |
1184 | 8.41M | } |
1185 | 8.41M | return res; |
1186 | 8.41M | } |
1187 | | |
1188 | | bool ImpSvNumberformatScan::IsLastBlankBeforeFrac(sal_uInt16 i) const |
1189 | 0 | { |
1190 | 0 | bool res = true; |
1191 | 0 | if (i < nStringsCnt-1) |
1192 | 0 | { |
1193 | 0 | bool bStop = false; |
1194 | 0 | i++; |
1195 | 0 | while (i < nStringsCnt-1 && !bStop) |
1196 | 0 | { |
1197 | 0 | i++; |
1198 | 0 | if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL && |
1199 | 0 | sStrArray[i][0] == '/') |
1200 | 0 | { |
1201 | 0 | bStop = true; |
1202 | 0 | } |
1203 | 0 | else if ( ( nTypeArray[i] == NF_SYMBOLTYPE_DEL && |
1204 | 0 | sStrArray[i][0] == ' ') || |
1205 | 0 | nTypeArray[i] == NF_SYMBOLTYPE_STRING ) // integer/fraction delimiter can also be a string |
1206 | 0 | { |
1207 | 0 | res = false; |
1208 | 0 | } |
1209 | 0 | } |
1210 | 0 | if (!bStop) // no '/'{ |
1211 | 0 | { |
1212 | 0 | res = false; |
1213 | 0 | } |
1214 | 0 | } |
1215 | 0 | else |
1216 | 0 | { |
1217 | 0 | res = false; // no '/' any more |
1218 | 0 | } |
1219 | 0 | return res; |
1220 | 0 | } |
1221 | | |
1222 | | void ImpSvNumberformatScan::Reset() |
1223 | 26.3M | { |
1224 | 26.3M | nStringsCnt = 0; |
1225 | 26.3M | nResultStringsCnt = 0; |
1226 | 26.3M | eScannedType = SvNumFormatType::UNDEFINED; |
1227 | 26.3M | bExp = false; |
1228 | 26.3M | bThousand = false; |
1229 | 26.3M | nThousand = 0; |
1230 | 26.3M | bDecSep = false; |
1231 | 26.3M | nDecPos = sal_uInt16(-1); |
1232 | 26.3M | nExpPos = sal_uInt16(-1); |
1233 | 26.3M | nBlankPos = sal_uInt16(-1); |
1234 | 26.3M | nCntPre = 0; |
1235 | 26.3M | nCntPost = 0; |
1236 | 26.3M | nCntExp = 0; |
1237 | 26.3M | bFrac = false; |
1238 | 26.3M | bBlank = false; |
1239 | 26.3M | nNatNumModifier = 0; |
1240 | 26.3M | } |
1241 | | |
1242 | | bool ImpSvNumberformatScan::Is100SecZero( sal_uInt16 i, bool bHadDecSep ) const |
1243 | 3.45M | { |
1244 | 3.45M | sal_uInt16 nIndexPre = PreviousKeyword( i ); |
1245 | 3.45M | return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS) && |
1246 | 3.45M | (bHadDecSep || |
1247 | 23.1k | ( i > 0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING)); |
1248 | | // SS"any"00 take "any" as a valid decimal separator |
1249 | 3.45M | } |
1250 | | |
1251 | | sal_Int32 ImpSvNumberformatScan::ScanType() |
1252 | 25.9M | { |
1253 | 25.9M | const LocaleDataWrapper* pLoc = mrCurrentLanguageData.GetLocaleData(); |
1254 | | |
1255 | 25.9M | sal_Int32 nPos = 0; |
1256 | 25.9M | sal_uInt16 i = 0; |
1257 | 25.9M | SvNumFormatType eNewType; |
1258 | 25.9M | bool bMatchBracket = false; |
1259 | 25.9M | bool bHaveGeneral = false; // if General/Standard encountered |
1260 | 25.9M | bool bIsTimeDetected =false; // hour or second found in format |
1261 | 25.9M | bool bHaveMinute = false; |
1262 | | |
1263 | 25.9M | SkipStrings(i, nPos); |
1264 | 185M | while (i < nStringsCnt) |
1265 | 159M | { |
1266 | 159M | if (nTypeArray[i] > 0) |
1267 | 38.8M | { // keyword |
1268 | 38.8M | sal_uInt16 nIndexPre; |
1269 | 38.8M | sal_uInt16 nIndexNex; |
1270 | | |
1271 | 38.8M | switch (nTypeArray[i]) |
1272 | 38.8M | { |
1273 | 747k | case NF_KEY_E: // E |
1274 | 747k | eNewType = SvNumFormatType::SCIENTIFIC; |
1275 | 747k | break; |
1276 | 79.8k | case NF_KEY_H: // H |
1277 | 3.21M | case NF_KEY_HH: // HH |
1278 | 3.21M | bIsTimeDetected = true; |
1279 | 3.21M | [[fallthrough]]; |
1280 | 3.30M | case NF_KEY_S: // S |
1281 | 5.76M | case NF_KEY_SS: // SS |
1282 | 5.76M | if ( !bHaveMinute ) |
1283 | 3.28M | bIsTimeDetected = true; |
1284 | 5.76M | [[fallthrough]]; |
1285 | 6.70M | case NF_KEY_AMPM: // AM,A,PM,P |
1286 | 6.70M | case NF_KEY_AP: |
1287 | 6.70M | eNewType = SvNumFormatType::TIME; |
1288 | 6.70M | break; |
1289 | 364k | case NF_KEY_M: // M |
1290 | 7.02M | case NF_KEY_MM: // MM |
1291 | 7.02M | case NF_KEY_MI: // M minute detected in Finnish |
1292 | 7.02M | case NF_KEY_MMI: // MM |
1293 | | /* Minute or month. |
1294 | | Minute if one of: |
1295 | | * preceded by time keyword H (ignoring separators) |
1296 | | * followed by time keyword S (ignoring separators) |
1297 | | * H or S was detected and this is the first M following |
1298 | | * preceded by '[' amount bracket |
1299 | | Else month. |
1300 | | That are the Excel rules. BUT, we break it because certainly |
1301 | | in something like {HH YYYY-MM-DD} the MM is NOT meant to be |
1302 | | minute, so not if MM is between YY and DD or DD and YY. |
1303 | | Actually not if any date specific keyword followed a time |
1304 | | setting keyword. |
1305 | | */ |
1306 | 7.02M | nIndexPre = PreviousKeyword(i); |
1307 | 7.02M | nIndexNex = NextKeyword(i); |
1308 | 7.02M | if (nIndexPre == NF_KEY_H || // H |
1309 | 6.98M | nIndexPre == NF_KEY_HH || // HH |
1310 | 3.84M | nIndexNex == NF_KEY_S || // S |
1311 | 3.84M | nIndexNex == NF_KEY_SS || // SS |
1312 | 3.57M | bIsTimeDetected || // tdf#101147 |
1313 | 3.56M | PreviousChar(i) == '[' ) // [M |
1314 | 3.46M | { |
1315 | 3.46M | eNewType = SvNumFormatType::TIME; |
1316 | 3.46M | if ( nTypeArray[i] == NF_KEY_M || nTypeArray[i] == NF_KEY_MM ) |
1317 | 3.46M | { |
1318 | 3.46M | nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5 |
1319 | 3.46M | } |
1320 | 3.46M | bIsTimeDetected = false; // next M should be month |
1321 | 3.46M | bHaveMinute = true; |
1322 | 3.46M | } |
1323 | 3.55M | else |
1324 | 3.55M | { |
1325 | 3.55M | eNewType = SvNumFormatType::DATE; |
1326 | 3.55M | if ( nTypeArray[i] == NF_KEY_MI || nTypeArray[i] == NF_KEY_MMI ) |
1327 | 0 | { // follow resolution of tdf#33689 for Finnish |
1328 | 0 | nTypeArray[i] += 2; // 4 -> 6, 5 -> 7 |
1329 | 0 | } |
1330 | 3.55M | } |
1331 | 7.02M | break; |
1332 | 1.45M | case NF_KEY_MMM: // MMM |
1333 | 5.29M | case NF_KEY_MMMM: // MMMM |
1334 | 5.30M | case NF_KEY_MMMMM: // MMMMM |
1335 | 5.32M | case NF_KEY_Q: // Q |
1336 | 5.56M | case NF_KEY_QQ: // QQ |
1337 | 9.99M | case NF_KEY_D: // D |
1338 | 13.3M | case NF_KEY_DD: // DD |
1339 | 13.3M | case NF_KEY_DDD: // DDD |
1340 | 13.3M | case NF_KEY_DDDD: // DDDD |
1341 | 15.5M | case NF_KEY_YY: // YY |
1342 | 20.9M | case NF_KEY_YYYY: // YYYY |
1343 | 22.1M | case NF_KEY_NN: // NN |
1344 | 22.1M | case NF_KEY_NNN: // NNN |
1345 | 23.0M | case NF_KEY_NNNN: // NNNN |
1346 | 23.3M | case NF_KEY_WW : // WW |
1347 | 23.3M | case NF_KEY_AAA : // AAA |
1348 | 23.4M | case NF_KEY_AAAA : // AAAA |
1349 | 23.4M | case NF_KEY_EC : // E |
1350 | 23.4M | case NF_KEY_EEC : // EE |
1351 | 23.5M | case NF_KEY_G : // G |
1352 | 23.5M | case NF_KEY_GG : // GG |
1353 | 23.5M | case NF_KEY_GGG : // GGG |
1354 | 23.5M | case NF_KEY_R : // R |
1355 | 23.6M | case NF_KEY_RR : // RR |
1356 | 23.6M | eNewType = SvNumFormatType::DATE; |
1357 | 23.6M | bIsTimeDetected = false; |
1358 | 23.6M | break; |
1359 | 240k | case NF_KEY_CCC: // CCC |
1360 | 240k | eNewType = SvNumFormatType::CURRENCY; |
1361 | 240k | break; |
1362 | 239k | case NF_KEY_BOOLEAN: // BOOLEAN |
1363 | 239k | eNewType = SvNumFormatType::LOGICAL; |
1364 | 239k | break; |
1365 | 246k | case NF_KEY_GENERAL: // General |
1366 | 246k | eNewType = SvNumFormatType::NUMBER; |
1367 | 246k | bHaveGeneral = true; |
1368 | 246k | break; |
1369 | 0 | default: |
1370 | 0 | eNewType = SvNumFormatType::UNDEFINED; |
1371 | 0 | break; |
1372 | 38.8M | } |
1373 | 38.8M | } |
1374 | 121M | else |
1375 | 121M | { // control character |
1376 | 121M | switch ( sStrArray[i][0] ) |
1377 | 121M | { |
1378 | 26.6M | case '#': |
1379 | 31.7M | case '?': |
1380 | 31.7M | eNewType = SvNumFormatType::NUMBER; |
1381 | 31.7M | break; |
1382 | 29.3M | case '0': |
1383 | 29.3M | if ( eScannedType & SvNumFormatType::TIME ) |
1384 | 2.46M | { |
1385 | 2.46M | if ( Is100SecZero( i, bDecSep ) ) |
1386 | 2.46M | { |
1387 | 2.46M | bDecSep = true; // subsequent 0's |
1388 | 2.46M | eNewType = SvNumFormatType::TIME; |
1389 | 2.46M | } |
1390 | 1.98k | else |
1391 | 1.98k | { |
1392 | 1.98k | return nPos; // Error |
1393 | 1.98k | } |
1394 | 2.46M | } |
1395 | 26.8M | else |
1396 | 26.8M | { |
1397 | 26.8M | eNewType = SvNumFormatType::NUMBER; |
1398 | 26.8M | } |
1399 | 29.3M | break; |
1400 | 29.3M | case '%': |
1401 | 498k | eNewType = SvNumFormatType::PERCENT; |
1402 | 498k | break; |
1403 | 5.66M | case '/': |
1404 | 5.66M | eNewType = SvNumFormatType::FRACTION; |
1405 | 5.66M | break; |
1406 | 6.42M | case '[': |
1407 | 6.42M | if ( i < nStringsCnt-1 && |
1408 | 6.42M | nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && |
1409 | 5.89M | sStrArray[i+1][0] == '$' ) |
1410 | 3.47M | { |
1411 | 3.47M | eNewType = SvNumFormatType::CURRENCY; |
1412 | 3.47M | bMatchBracket = true; |
1413 | 3.47M | } |
1414 | 2.95M | else if ( i < nStringsCnt-1 && |
1415 | 2.95M | nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && |
1416 | 2.42M | sStrArray[i+1][0] == '~' ) |
1417 | 2.41M | { |
1418 | 2.41M | eNewType = SvNumFormatType::DATE; |
1419 | 2.41M | bMatchBracket = true; |
1420 | 2.41M | } |
1421 | 539k | else |
1422 | 539k | { |
1423 | 539k | sal_uInt16 nIndexNex = NextKeyword(i); |
1424 | 539k | if (nIndexNex == NF_KEY_H || // H |
1425 | 527k | nIndexNex == NF_KEY_HH || // HH |
1426 | 48.3k | nIndexNex == NF_KEY_M || // M |
1427 | 35.4k | nIndexNex == NF_KEY_MM || // MM |
1428 | 13.5k | nIndexNex == NF_KEY_S || // S |
1429 | 7.51k | nIndexNex == NF_KEY_SS ) // SS |
1430 | 534k | eNewType = SvNumFormatType::TIME; |
1431 | 5.43k | else |
1432 | 5.43k | { |
1433 | 5.43k | return nPos; // Error |
1434 | 5.43k | } |
1435 | 539k | } |
1436 | 6.42M | break; |
1437 | 6.42M | case '@': |
1438 | 264k | eNewType = SvNumFormatType::TEXT; |
1439 | 264k | break; |
1440 | 47.1M | default: |
1441 | | // Separator for SS,0 |
1442 | 47.1M | if ((eScannedType & SvNumFormatType::TIME) |
1443 | 8.12M | && 0 < i && (nTypeArray[i-1] == NF_KEY_S || nTypeArray[i-1] == NF_KEY_SS)) |
1444 | 1.23M | { |
1445 | | // For ISO 8601 only YYYY-MM-DD"T"HH:MM:SS,0 accept both |
1446 | | // ',' and '.' regardless of locale's separator, and only |
1447 | | // those. |
1448 | | // XXX NOTE: this catches only known separators of |
1449 | | // NF_SYMBOLTYPE_DEL as all NF_SYMBOLTYPE_STRING are |
1450 | | // skipped during the loop. Meant to error out if the |
1451 | | // Time100SecSep or decimal separator differ and were used. |
1452 | 1.23M | if ((eScannedType & SvNumFormatType::DATE) |
1453 | 491k | && 11 <= i && i < nStringsCnt-1 |
1454 | 487k | && (nTypeArray[i-6] == NF_SYMBOLTYPE_STRING |
1455 | 246k | && (sStrArray[i-6] == "\"T\"" || sStrArray[i-6] == "\\T" |
1456 | 7.28k | || sStrArray[i-6] == "T")) |
1457 | 244k | && (nTypeArray[i-11] == NF_KEY_YYYY) |
1458 | 244k | && (nTypeArray[i-9] == NF_KEY_M || nTypeArray[i-9] == NF_KEY_MM) |
1459 | 244k | && (nTypeArray[i-7] == NF_KEY_D || nTypeArray[i-7] == NF_KEY_DD) |
1460 | 243k | && (nTypeArray[i-5] == NF_KEY_H || nTypeArray[i-5] == NF_KEY_HH) |
1461 | 243k | && (nTypeArray[i-3] == NF_KEY_MI || nTypeArray[i-3] == NF_KEY_MMI) |
1462 | 240k | && (nTypeArray[i+1] == NF_SYMBOLTYPE_DEL && sStrArray[i+1][0] == '0')) |
1463 | | |
1464 | 240k | { |
1465 | 240k | if (sStrArray[i].getLength() == 1 && (sStrArray[i][0] == ',' || sStrArray[i][0] == '.')) |
1466 | 240k | bDecSep = true; |
1467 | 208 | else |
1468 | 208 | return nPos; // Error |
1469 | 240k | } |
1470 | 991k | else if (pLoc->getTime100SecSep() == sStrArray[i]) |
1471 | 732k | bDecSep = true; |
1472 | 258k | else if ( sStrArray[i][0] == ']' && i < nStringsCnt - 1 && pLoc->getTime100SecSep() == sStrArray[i+1] ) |
1473 | 623 | { |
1474 | 623 | bDecSep = true; |
1475 | 623 | i++; |
1476 | 623 | } |
1477 | 1.23M | } |
1478 | 47.1M | eNewType = SvNumFormatType::UNDEFINED; |
1479 | 47.1M | break; |
1480 | 121M | } |
1481 | 121M | } |
1482 | 159M | if (eScannedType == SvNumFormatType::UNDEFINED) |
1483 | 28.9M | { |
1484 | 28.9M | eScannedType = eNewType; |
1485 | 28.9M | } |
1486 | 130M | else if (eScannedType == SvNumFormatType::TEXT || eNewType == SvNumFormatType::TEXT) |
1487 | 16.0k | { |
1488 | 16.0k | eScannedType = SvNumFormatType::TEXT; // Text always remains text |
1489 | 16.0k | } |
1490 | 130M | else if (eNewType == SvNumFormatType::UNDEFINED) |
1491 | 44.0M | { // Remains as is |
1492 | 44.0M | } |
1493 | 86.9M | else if (eScannedType != eNewType) |
1494 | 34.7M | { |
1495 | 34.7M | switch (eScannedType) |
1496 | 34.7M | { |
1497 | 5.18M | case SvNumFormatType::DATE: |
1498 | 5.18M | switch (eNewType) |
1499 | 5.18M | { |
1500 | 1.71M | case SvNumFormatType::TIME: |
1501 | 1.71M | eScannedType = SvNumFormatType::DATETIME; |
1502 | 1.71M | break; |
1503 | 3.46M | case SvNumFormatType::FRACTION: // DD/MM |
1504 | 3.46M | break; |
1505 | 8.89k | default: |
1506 | 8.89k | if (nCurrPos >= 0) |
1507 | 5.11k | { |
1508 | 5.11k | eScannedType = SvNumFormatType::UNDEFINED; |
1509 | 5.11k | } |
1510 | 3.78k | else if ( sStrArray[i] != mrCurrentLanguageData.GetDateSep() ) |
1511 | 3.78k | { |
1512 | 3.78k | return nPos; |
1513 | 3.78k | } |
1514 | 5.18M | } |
1515 | 5.18M | break; |
1516 | 5.18M | case SvNumFormatType::TIME: |
1517 | 34.2k | switch (eNewType) |
1518 | 34.2k | { |
1519 | 27.6k | case SvNumFormatType::DATE: |
1520 | 27.6k | eScannedType = SvNumFormatType::DATETIME; |
1521 | 27.6k | break; |
1522 | 4.09k | case SvNumFormatType::FRACTION: // MM/SS |
1523 | 4.09k | break; |
1524 | 2.52k | default: |
1525 | 2.52k | if (nCurrPos >= 0) |
1526 | 1.91k | { |
1527 | 1.91k | eScannedType = SvNumFormatType::UNDEFINED; |
1528 | 1.91k | } |
1529 | 610 | else if (pLoc->getTimeSep() != sStrArray[i]) |
1530 | 610 | { |
1531 | 610 | return nPos; |
1532 | 610 | } |
1533 | 1.91k | break; |
1534 | 34.2k | } |
1535 | 33.6k | break; |
1536 | 4.97M | case SvNumFormatType::DATETIME: |
1537 | 4.97M | switch (eNewType) |
1538 | 4.97M | { |
1539 | 4.87M | case SvNumFormatType::TIME: |
1540 | 4.96M | case SvNumFormatType::DATE: |
1541 | 4.96M | break; |
1542 | 8.29k | case SvNumFormatType::FRACTION: // DD/MM |
1543 | 8.29k | break; |
1544 | 3.13k | default: |
1545 | 3.13k | if (nCurrPos >= 0) |
1546 | 2.05k | { |
1547 | 2.05k | eScannedType = SvNumFormatType::UNDEFINED; |
1548 | 2.05k | } |
1549 | 1.07k | else if ( mrCurrentLanguageData.GetDateSep() != sStrArray[i] && |
1550 | 1.07k | pLoc->getTimeSep() != sStrArray[i] ) |
1551 | 1.07k | { |
1552 | 1.07k | return nPos; |
1553 | 1.07k | } |
1554 | 4.97M | } |
1555 | 4.97M | break; |
1556 | 4.97M | case SvNumFormatType::PERCENT: |
1557 | 1.72M | case SvNumFormatType::SCIENTIFIC: |
1558 | 3.91M | case SvNumFormatType::FRACTION: |
1559 | 3.91M | switch (eNewType) |
1560 | 3.91M | { |
1561 | 3.90M | case SvNumFormatType::NUMBER: |
1562 | 3.90M | break; |
1563 | 12.5k | default: |
1564 | 12.5k | return nPos; |
1565 | 3.91M | } |
1566 | 3.90M | break; |
1567 | 3.90M | case SvNumFormatType::NUMBER: |
1568 | 3.65M | switch (eNewType) |
1569 | 3.65M | { |
1570 | 734k | case SvNumFormatType::SCIENTIFIC: |
1571 | 1.22M | case SvNumFormatType::PERCENT: |
1572 | 3.39M | case SvNumFormatType::FRACTION: |
1573 | 3.63M | case SvNumFormatType::CURRENCY: |
1574 | 3.63M | eScannedType = eNewType; |
1575 | 3.63M | break; |
1576 | 19.5k | default: |
1577 | 19.5k | if (nCurrPos >= 0) |
1578 | 10.8k | { |
1579 | 10.8k | eScannedType = SvNumFormatType::UNDEFINED; |
1580 | 10.8k | } |
1581 | 8.68k | else |
1582 | 8.68k | { |
1583 | 8.68k | return nPos; |
1584 | 8.68k | } |
1585 | 3.65M | } |
1586 | 3.65M | break; |
1587 | 16.9M | default: |
1588 | 16.9M | break; |
1589 | 34.7M | } |
1590 | 34.7M | } |
1591 | 159M | nPos = nPos + sStrArray[i].getLength(); // Position of correction |
1592 | 159M | i++; |
1593 | 159M | if ( bMatchBracket ) |
1594 | 5.88M | { // no type detection inside of matching brackets if [$...], [~...] |
1595 | 47.2M | while ( bMatchBracket && i < nStringsCnt ) |
1596 | 41.3M | { |
1597 | 41.3M | if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL |
1598 | 12.8M | && sStrArray[i][0] == ']' ) |
1599 | 5.88M | { |
1600 | 5.88M | bMatchBracket = false; |
1601 | 5.88M | } |
1602 | 35.4M | else |
1603 | 35.4M | { |
1604 | 35.4M | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
1605 | 35.4M | } |
1606 | 41.3M | nPos = nPos + sStrArray[i].getLength(); |
1607 | 41.3M | i++; |
1608 | 41.3M | } |
1609 | 5.88M | if ( bMatchBracket ) |
1610 | 4.66k | { |
1611 | 4.66k | return nPos; // missing closing bracket at end of code |
1612 | 4.66k | } |
1613 | 5.88M | } |
1614 | 159M | SkipStrings(i, nPos); |
1615 | 159M | } |
1616 | | |
1617 | 25.8M | if ((eScannedType == SvNumFormatType::NUMBER || |
1618 | 18.8M | eScannedType == SvNumFormatType::UNDEFINED) && |
1619 | 7.13M | nCurrPos >= 0 && !bHaveGeneral) |
1620 | 2.46M | { |
1621 | 2.46M | eScannedType = SvNumFormatType::CURRENCY; // old "automatic" currency |
1622 | 2.46M | } |
1623 | 25.8M | if (eScannedType == SvNumFormatType::UNDEFINED) |
1624 | 94.3k | { |
1625 | 94.3k | eScannedType = SvNumFormatType::DEFINED; |
1626 | 94.3k | } |
1627 | 25.8M | return 0; // All is fine |
1628 | 25.9M | } |
1629 | | |
1630 | | bool ImpSvNumberformatScan::InsertSymbol( sal_uInt16 & nPos, svt::NfSymbolType eType, const OUString& rStr ) |
1631 | 7.89M | { |
1632 | 7.89M | if (nStringsCnt >= NF_MAX_FORMAT_SYMBOLS || nPos > nStringsCnt) |
1633 | 189 | { |
1634 | 189 | return false; |
1635 | 189 | } |
1636 | 7.89M | if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY) |
1637 | 7.89M | { |
1638 | 7.89M | --nPos; // reuse position |
1639 | 7.89M | } |
1640 | 7.31k | else |
1641 | 7.31k | { |
1642 | 7.31k | if (nStringsCnt >= NF_MAX_FORMAT_SYMBOLS - 1) |
1643 | 289 | { |
1644 | 289 | return false; |
1645 | 289 | } |
1646 | 7.02k | ++nStringsCnt; |
1647 | 7.02k | sal_uInt16 i = nStringsCnt; |
1648 | 128k | while (i > nPos) |
1649 | 121k | { |
1650 | 121k | sal_uInt16 nexti = o3tl::sanitizing_dec(i); |
1651 | 121k | nTypeArray[i] = nTypeArray[nexti]; |
1652 | 121k | sStrArray[i] = sStrArray[nexti]; |
1653 | 121k | i = nexti; |
1654 | 121k | } |
1655 | 7.02k | } |
1656 | 7.89M | ++nResultStringsCnt; |
1657 | 7.89M | nTypeArray[nPos] = static_cast<short>(eType); |
1658 | 7.89M | sStrArray[nPos] = rStr; |
1659 | 7.89M | return true; |
1660 | 7.89M | } |
1661 | | |
1662 | | int ImpSvNumberformatScan::FinalScanGetCalendar( sal_Int32& nPos, sal_uInt16& i, |
1663 | | sal_uInt16& rResultStringsCnt ) |
1664 | 25.4M | { |
1665 | 25.4M | if ( i < nStringsCnt-1 && |
1666 | 25.4M | sStrArray[i][0] == '[' && |
1667 | 2.43M | nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && |
1668 | 2.41M | sStrArray[i+1][0] == '~' ) |
1669 | 2.41M | { |
1670 | | // [~calendarID] |
1671 | 2.41M | nPos = nPos + sStrArray[i].getLength(); // [ |
1672 | 2.41M | nTypeArray[i] = NF_SYMBOLTYPE_CALDEL; |
1673 | 2.41M | nPos = nPos + sStrArray[++i].getLength(); // ~ |
1674 | 2.41M | sStrArray[i-1] += sStrArray[i]; // [~ |
1675 | 2.41M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
1676 | 2.41M | rResultStringsCnt--; |
1677 | 2.41M | if ( ++i >= nStringsCnt ) |
1678 | 0 | { |
1679 | 0 | return -1; // error |
1680 | 0 | } |
1681 | 2.41M | nPos = nPos + sStrArray[i].getLength(); // calendarID |
1682 | 2.41M | OUString& rStr = sStrArray[i]; |
1683 | 2.41M | nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert |
1684 | 2.41M | i++; |
1685 | 12.0M | while ( i < nStringsCnt && sStrArray[i][0] != ']' ) |
1686 | 9.64M | { |
1687 | 9.64M | nPos = nPos + sStrArray[i].getLength(); |
1688 | 9.64M | rStr += sStrArray[i]; |
1689 | 9.64M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
1690 | 9.64M | rResultStringsCnt--; |
1691 | 9.64M | i++; |
1692 | 9.64M | } |
1693 | 2.41M | if ( rStr.getLength() && i < nStringsCnt && |
1694 | 2.41M | sStrArray[i][0] == ']' ) |
1695 | 2.41M | { |
1696 | 2.41M | nTypeArray[i] = NF_SYMBOLTYPE_CALDEL; |
1697 | 2.41M | nPos = nPos + sStrArray[i].getLength(); |
1698 | 2.41M | i++; |
1699 | 2.41M | } |
1700 | 931 | else |
1701 | 931 | { |
1702 | 931 | return -1; // error |
1703 | 931 | } |
1704 | 2.41M | return 1; |
1705 | 2.41M | } |
1706 | 23.0M | return 0; |
1707 | 25.4M | } |
1708 | | |
1709 | | bool ImpSvNumberformatScan::IsDateFragment( size_t nPos1, size_t nPos2 ) const |
1710 | 14.9k | { |
1711 | 14.9k | return nPos2 - nPos1 == 2 && nTypeArray[nPos1+1] == NF_SYMBOLTYPE_DATESEP; |
1712 | 14.9k | } |
1713 | | |
1714 | | void ImpSvNumberformatScan::SwapArrayElements( size_t nPos1, size_t nPos2 ) |
1715 | 148 | { |
1716 | 148 | std::swap( nTypeArray[nPos1], nTypeArray[nPos2]); |
1717 | 148 | std::swap( sStrArray[nPos1], sStrArray[nPos2]); |
1718 | 148 | } |
1719 | | |
1720 | | sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString ) |
1721 | 25.8M | { |
1722 | 25.8M | const LocaleDataWrapper* pLoc = mrCurrentLanguageData.GetLocaleData(); |
1723 | | |
1724 | | // save values for convert mode |
1725 | 25.8M | OUString sOldDecSep = mrCurrentLanguageData.GetNumDecimalSep(); |
1726 | 25.8M | OUString sOldThousandSep = mrCurrentLanguageData.GetNumThousandSep(); |
1727 | 25.8M | OUString sOldDateSep = mrCurrentLanguageData.GetDateSep(); |
1728 | 25.8M | OUString sOldTimeSep = pLoc->getTimeSep(); |
1729 | 25.8M | OUString sOldTime100SecSep= pLoc->getTime100SecSep(); |
1730 | 25.8M | OUString sOldCurSymbol = GetCurSymbol(); |
1731 | 25.8M | OUString sOldCurString = GetCurString(); |
1732 | 25.8M | sal_Unicode cOldKeyH = sKeyword[NF_KEY_H][0]; |
1733 | 25.8M | sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI][0]; |
1734 | 25.8M | sal_Unicode cOldKeyS = sKeyword[NF_KEY_S][0]; |
1735 | 25.8M | DateOrder eOldDateOrder = pLoc->getDateOrder(); |
1736 | 25.8M | sal_uInt16 nDayPos, nMonthPos, nYearPos; |
1737 | 25.8M | nDayPos = nMonthPos = nYearPos = SAL_MAX_UINT16; |
1738 | | |
1739 | | // If the group separator is a No-Break Space (French) continue with a |
1740 | | // normal space instead so queries on space work correctly. |
1741 | | // The same for Narrow No-Break Space just in case some locale uses it. |
1742 | | // The format string is adjusted to allow both. |
1743 | | // For output of the format code string the LocaleData characters are used. |
1744 | 25.8M | if ( (sOldThousandSep[0] == cNoBreakSpace || sOldThousandSep[0] == cNarrowNoBreakSpace) && |
1745 | 0 | sOldThousandSep.getLength() == 1 ) |
1746 | 0 | { |
1747 | 0 | sOldThousandSep = " "; |
1748 | 0 | } |
1749 | 25.8M | bool bNewDateOrder = false; |
1750 | | // change locale data et al |
1751 | 25.8M | if (bConvertMode) |
1752 | 725k | { |
1753 | 725k | mrCurrentLanguageData.ChangeIntl(eNewLnge); |
1754 | | //! pointer may have changed |
1755 | 725k | pLoc = mrCurrentLanguageData.GetLocaleData(); |
1756 | | //! init new keywords |
1757 | 725k | InitKeywords(); |
1758 | | // Adapt date order to target locale, but Excel does not handle date |
1759 | | // particle re-ordering for the target locale when loading documents, |
1760 | | // though it does exchange separators, tdf#113889 |
1761 | 725k | bNewDateOrder = (mbConvertDateOrder && eOldDateOrder != pLoc->getDateOrder()); |
1762 | 725k | } |
1763 | 25.8M | const CharClass* pChrCls = mrCurrentLanguageData.GetCharClass(); |
1764 | | |
1765 | 25.8M | sal_Int32 nPos = 0; // error correction position |
1766 | 25.8M | sal_uInt16 i = 0; // symbol loop counter |
1767 | 25.8M | sal_uInt16 nCounter = 0; // counts digits |
1768 | 25.8M | nResultStringsCnt = nStringsCnt; // counts remaining symbols |
1769 | 25.8M | bDecSep = false; // reset in case already used in TypeCheck |
1770 | 25.8M | bool bThaiT = false; // Thai T NatNum modifier present |
1771 | 25.8M | bool bTimePart = false; |
1772 | 25.8M | bool bDenomin = false; // Set when reading end of denominator |
1773 | | |
1774 | 25.8M | switch (eScannedType) |
1775 | 25.8M | { |
1776 | 260k | case SvNumFormatType::TEXT: |
1777 | 355k | case SvNumFormatType::DEFINED: |
1778 | 914k | while (i < nStringsCnt) |
1779 | 559k | { |
1780 | 559k | switch (nTypeArray[i]) |
1781 | 559k | { |
1782 | 41.4k | case NF_SYMBOLTYPE_BLANK: |
1783 | 50.9k | case NF_SYMBOLTYPE_STAR: |
1784 | 50.9k | break; |
1785 | 399 | case NF_KEY_GENERAL : // #77026# "General" is the same as "@" |
1786 | 399 | break; |
1787 | 508k | default: |
1788 | 508k | if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL || |
1789 | 290k | sStrArray[i][0] != '@' ) |
1790 | 244k | { |
1791 | 244k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
1792 | 244k | } |
1793 | 508k | break; |
1794 | 559k | } |
1795 | 559k | nPos = nPos + sStrArray[i].getLength(); |
1796 | 559k | i++; |
1797 | 559k | } // of while |
1798 | 355k | break; |
1799 | | |
1800 | 4.56M | case SvNumFormatType::NUMBER: |
1801 | 5.06M | case SvNumFormatType::PERCENT: |
1802 | 11.2M | case SvNumFormatType::CURRENCY: |
1803 | 11.9M | case SvNumFormatType::SCIENTIFIC: |
1804 | 14.1M | case SvNumFormatType::FRACTION: |
1805 | 82.3M | while (i < nStringsCnt) |
1806 | 68.2M | { |
1807 | | // TODO: rechecking eScannedType is unnecessary. |
1808 | | // This switch-case is for eScannedType == SvNumFormatType::FRACTION anyway |
1809 | 68.2M | if (eScannedType == SvNumFormatType::FRACTION && // special case |
1810 | 13.1M | nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/# |
1811 | 9.44M | StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden |
1812 | 0 | StringEqualsChar( sStrArray[i], ' ' ) && |
1813 | 0 | !bFrac && |
1814 | 0 | IsLastBlankBeforeFrac(i) ) |
1815 | 0 | { |
1816 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string |
1817 | 0 | } // No thousands marker |
1818 | | |
1819 | 68.2M | if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK || |
1820 | 67.6M | nTypeArray[i] == NF_SYMBOLTYPE_STAR || |
1821 | 66.6M | nTypeArray[i] == NF_KEY_CCC || // CCC |
1822 | 66.4M | nTypeArray[i] == NF_KEY_GENERAL ) // Standard |
1823 | 2.02M | { |
1824 | 2.02M | if (nTypeArray[i] == NF_KEY_GENERAL) |
1825 | 245k | { |
1826 | 245k | nThousand = FLAG_STANDARD_IN_FORMAT; |
1827 | 245k | if ( bConvertMode ) |
1828 | 6.15k | { |
1829 | 6.15k | sStrArray[i] = sNameStandardFormat; |
1830 | 6.15k | } |
1831 | 245k | } |
1832 | 2.02M | nPos = nPos + sStrArray[i].getLength(); |
1833 | 2.02M | i++; |
1834 | 2.02M | } |
1835 | 66.2M | else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // No Strings or |
1836 | 58.6M | nTypeArray[i] > 0) // Keywords |
1837 | 8.29M | { |
1838 | 8.29M | if (eScannedType == SvNumFormatType::SCIENTIFIC && |
1839 | 782k | nTypeArray[i] == NF_KEY_E) // E+ |
1840 | 743k | { |
1841 | 743k | if (bExp) // Double |
1842 | 895 | { |
1843 | 895 | return nPos; |
1844 | 895 | } |
1845 | 742k | bExp = true; |
1846 | 742k | nExpPos = i; |
1847 | 742k | if (bDecSep) |
1848 | 731k | { |
1849 | 731k | nCntPost = nCounter; |
1850 | 731k | } |
1851 | 10.5k | else |
1852 | 10.5k | { |
1853 | 10.5k | nCntPre = nCounter; |
1854 | 10.5k | } |
1855 | 742k | nCounter = 0; |
1856 | 742k | nTypeArray[i] = NF_SYMBOLTYPE_EXP; |
1857 | 742k | } |
1858 | 7.55M | else if (eScannedType == SvNumFormatType::FRACTION && |
1859 | 3.67M | (sStrArray[i][0] == ' ' || ( nTypeArray[i] == NF_SYMBOLTYPE_STRING && (sStrArray[i][0] < '0' || sStrArray[i][0] > '9') ) ) ) |
1860 | 2.20M | { |
1861 | 2.20M | if (!bBlank && !bFrac) // Not double or after a / |
1862 | 14.2k | { |
1863 | 14.2k | if (bDecSep && nCounter > 0) // Decimal places |
1864 | 344 | { |
1865 | 344 | return nPos; // Error |
1866 | 344 | } |
1867 | 13.8k | if (sStrArray[i][0] == ' ' || nCounter > 0 ) // treat string as integer/fraction delimiter only if there is integer |
1868 | 7.21k | { |
1869 | 7.21k | bBlank = true; |
1870 | 7.21k | nBlankPos = i; |
1871 | 7.21k | nCntPre = nCounter; |
1872 | 7.21k | nCounter = 0; |
1873 | 7.21k | nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK; |
1874 | 7.21k | } |
1875 | 13.8k | } |
1876 | 2.19M | else if ( sStrArray[i][0] == ' ' ) |
1877 | 2.16M | nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK; |
1878 | 25.9k | else if ( bFrac && ( nCounter > 0 ) ) |
1879 | 14.8k | bDenomin = true; // following elements are no more part of denominator |
1880 | 2.20M | } |
1881 | 5.34M | else if (nTypeArray[i] == NF_KEY_THAI_T) |
1882 | 0 | { |
1883 | 0 | bThaiT = true; |
1884 | 0 | sStrArray[i] = sKeyword[nTypeArray[i]]; |
1885 | 0 | } |
1886 | 5.34M | else if (sStrArray[i][0] >= '0' && |
1887 | 1.89M | sStrArray[i][0] <= '9' && !bDenomin) // denominator was not yet found |
1888 | 1.56M | { |
1889 | 1.56M | OUStringBuffer sDiv; |
1890 | 1.56M | sal_uInt16 j = i; |
1891 | 5.42M | while(j < nStringsCnt && sStrArray[j][0] >= '0' && sStrArray[j][0] <= '9') |
1892 | 3.86M | { |
1893 | 3.86M | sDiv.append(sStrArray[j++]); |
1894 | 3.86M | } |
1895 | 1.56M | assert(j > 0 && "if i is 0, first iteration through loop is guaranteed by surrounding if condition"); |
1896 | 1.56M | if (std::u16string_view(OUString::number(o3tl::toInt32(sDiv))) == sDiv) |
1897 | 1.49M | { |
1898 | | // Found a Divisor |
1899 | 4.07M | while (i < j) |
1900 | 2.57M | { |
1901 | 2.57M | nTypeArray[i++] = NF_SYMBOLTYPE_FRAC_FDIV; |
1902 | 2.57M | } |
1903 | 1.49M | i = j - 1; // Stop the loop |
1904 | 1.49M | if (nCntPost) |
1905 | 1.43M | { |
1906 | 1.43M | nCounter = nCntPost; |
1907 | 1.43M | } |
1908 | 60.0k | else if (nCntPre) |
1909 | 18.2k | { |
1910 | 18.2k | nCounter = nCntPre; |
1911 | 18.2k | } |
1912 | | // don't artificially increment nCntPre for forced denominator |
1913 | 1.49M | if ( ( eScannedType != SvNumFormatType::FRACTION ) && (!nCntPre) ) |
1914 | 37.6k | { |
1915 | 37.6k | nCntPre++; |
1916 | 37.6k | } |
1917 | 1.49M | if ( bFrac ) |
1918 | 1.43M | bDenomin = true; // next content should be treated as outside denominator |
1919 | 1.49M | } |
1920 | 1.56M | } |
1921 | 3.78M | else |
1922 | 3.78M | { |
1923 | 3.78M | if ( bFrac && ( nCounter > 0 ) ) |
1924 | 10.9k | bDenomin = true; // next content should be treated as outside denominator |
1925 | 3.78M | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
1926 | 3.78M | } |
1927 | 8.29M | nPos = nPos + sStrArray[i].getLength(); |
1928 | 8.29M | i++; |
1929 | 8.29M | } |
1930 | 57.9M | else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL) |
1931 | 57.9M | { |
1932 | 57.9M | sal_Unicode cHere = sStrArray[i][0]; |
1933 | 57.9M | sal_Unicode cSaved = cHere; |
1934 | | // Handle not pre-known separators in switch. |
1935 | 57.9M | sal_Unicode cSimplified; |
1936 | 57.9M | if (StringEqualsChar( mrCurrentLanguageData.GetNumThousandSep(), cHere)) |
1937 | 7.94M | { |
1938 | 7.94M | cSimplified = ','; |
1939 | 7.94M | } |
1940 | 49.9M | else if (StringEqualsChar( mrCurrentLanguageData.GetNumDecimalSep(), cHere)) |
1941 | 6.48M | { |
1942 | 6.48M | cSimplified = '.'; |
1943 | 6.48M | } |
1944 | 43.4M | else |
1945 | 43.4M | { |
1946 | 43.4M | cSimplified = cHere; |
1947 | 43.4M | } |
1948 | | |
1949 | 57.9M | OUString& rStr = sStrArray[i]; |
1950 | | |
1951 | 57.9M | switch ( cSimplified ) |
1952 | 57.9M | { |
1953 | 18.2M | case '#': |
1954 | 28.0M | case '0': |
1955 | 30.9M | case '?': |
1956 | 30.9M | if (nThousand > 0) // #... # |
1957 | 626 | { |
1958 | 626 | return nPos; // Error |
1959 | 626 | } |
1960 | 30.9M | if ( !bDenomin ) |
1961 | 30.9M | { |
1962 | 30.9M | nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; |
1963 | 30.9M | nPos = nPos + rStr.getLength(); |
1964 | 30.9M | i++; |
1965 | 30.9M | nCounter++; |
1966 | 57.8M | while (i < nStringsCnt && |
1967 | 48.2M | (sStrArray[i][0] == '#' || |
1968 | 39.8M | sStrArray[i][0] == '0' || |
1969 | 23.4M | sStrArray[i][0] == '?')) |
1970 | 26.9M | { |
1971 | 26.9M | nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; |
1972 | 26.9M | nPos = nPos + sStrArray[i].getLength(); |
1973 | 26.9M | nCounter++; |
1974 | 26.9M | i++; |
1975 | 26.9M | } |
1976 | 30.9M | } |
1977 | 8.18k | else // after denominator, treat any character as text |
1978 | 8.18k | { |
1979 | 8.18k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
1980 | 8.18k | nPos = nPos + sStrArray[i].getLength(); |
1981 | 8.18k | } |
1982 | 30.9M | break; |
1983 | 3.93M | case '-': |
1984 | 3.93M | if ( bDecSep && nDecPos+1 == i && |
1985 | 956k | nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP ) |
1986 | 956k | { |
1987 | | // "0.--" |
1988 | 956k | nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; |
1989 | 956k | nPos = nPos + rStr.getLength(); |
1990 | 956k | i++; |
1991 | 956k | nCounter++; |
1992 | 1.91M | while (i < nStringsCnt && |
1993 | 962k | (sStrArray[i][0] == '-') ) |
1994 | 962k | { |
1995 | | // If more than two dashes are present in |
1996 | | // currency formats the last dash will be |
1997 | | // interpreted literally as a minus sign. |
1998 | | // Has to be this ugly. Period. |
1999 | 962k | if ( eScannedType == SvNumFormatType::CURRENCY |
2000 | 961k | && rStr.getLength() >= 2 && |
2001 | 5.57k | (i == nStringsCnt-1 || |
2002 | 4.35k | sStrArray[i+1][0] != '-') ) |
2003 | 1.77k | { |
2004 | 1.77k | break; |
2005 | 1.77k | } |
2006 | 960k | rStr += sStrArray[i]; |
2007 | 960k | nPos = nPos + sStrArray[i].getLength(); |
2008 | 960k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2009 | 960k | nResultStringsCnt--; |
2010 | 960k | nCounter++; |
2011 | 960k | i++; |
2012 | 960k | } |
2013 | 956k | } |
2014 | 2.97M | else |
2015 | 2.97M | { |
2016 | 2.97M | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2017 | 2.97M | nPos = nPos + sStrArray[i].getLength(); |
2018 | 2.97M | i++; |
2019 | 2.97M | } |
2020 | 3.93M | break; |
2021 | 6.48M | case '.': |
2022 | 14.4M | case ',': |
2023 | 14.4M | case '\'': |
2024 | 16.8M | case ' ': |
2025 | 16.8M | if ( StringEqualsChar( sOldThousandSep, cSaved ) ) |
2026 | 7.94M | { |
2027 | | // previous char with skip empty |
2028 | 7.94M | sal_Unicode cPre = PreviousChar(i); |
2029 | 7.94M | sal_Unicode cNext; |
2030 | 7.94M | if (bExp || bBlank || bFrac) |
2031 | 9.15k | { |
2032 | | // after E, / or ' ' |
2033 | 9.15k | if ( !StringEqualsChar( sOldThousandSep, ' ' ) ) |
2034 | 9.15k | { |
2035 | 9.15k | nPos = nPos + sStrArray[i].getLength(); |
2036 | 9.15k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2037 | 9.15k | nResultStringsCnt--; |
2038 | 9.15k | i++; // eat it |
2039 | 9.15k | } |
2040 | 0 | else |
2041 | 0 | { |
2042 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2043 | 0 | if ( bFrac && (nCounter > 0) ) |
2044 | 0 | bDenomin = true; // end of denominator |
2045 | 0 | } |
2046 | 9.15k | } |
2047 | 7.93M | else if (i > 0 && i < nStringsCnt-1 && |
2048 | 7.92M | (cPre == '#' || cPre == '0' || cPre == '?') && |
2049 | 7.91M | ((cNext = NextChar(i)) == '#' || cNext == '0' || cNext == '?')) // #,# |
2050 | 7.90M | { |
2051 | 7.90M | nPos = nPos + sStrArray[i].getLength(); |
2052 | 7.90M | if (!bThousand) // only once |
2053 | 7.90M | { |
2054 | 7.90M | bThousand = true; |
2055 | 7.90M | } |
2056 | | // Eat it, will be reinserted at proper grouping positions further down. |
2057 | 7.90M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2058 | 7.90M | nResultStringsCnt--; |
2059 | 7.90M | i++; |
2060 | 7.90M | } |
2061 | 31.9k | else if (i > 0 && (cPre == '#' || cPre == '0' || cPre == '?') |
2062 | 15.7k | && PreviousType(i) == NF_SYMBOLTYPE_DIGIT |
2063 | 12.0k | && nThousand < FLAG_STANDARD_IN_FORMAT ) |
2064 | 12.0k | { // #,,,, |
2065 | 12.0k | if ( StringEqualsChar( sOldThousandSep, ' ' ) ) |
2066 | 0 | { |
2067 | | // strange, those French... |
2068 | 0 | bool bFirst = true; |
2069 | | // set a hard No-Break Space or ConvertMode |
2070 | 0 | const OUString& rSepF = mrCurrentLanguageData.GetNumThousandSep(); |
2071 | 0 | while ( i < nStringsCnt && |
2072 | 0 | sStrArray[i] == sOldThousandSep && |
2073 | 0 | StringEqualsChar( sOldThousandSep, NextChar(i) ) ) |
2074 | 0 | { // last was a space or another space |
2075 | | // is following => separator |
2076 | 0 | nPos = nPos + sStrArray[i].getLength(); |
2077 | 0 | if ( bFirst ) |
2078 | 0 | { |
2079 | 0 | bFirst = false; |
2080 | 0 | rStr = rSepF; |
2081 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_THSEP; |
2082 | 0 | } |
2083 | 0 | else |
2084 | 0 | { |
2085 | 0 | rStr += rSepF; |
2086 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2087 | 0 | nResultStringsCnt--; |
2088 | 0 | } |
2089 | 0 | nThousand++; |
2090 | 0 | i++; |
2091 | 0 | } |
2092 | 0 | if ( i < nStringsCnt-1 && |
2093 | 0 | sStrArray[i] == sOldThousandSep ) |
2094 | 0 | { |
2095 | | // something following last space |
2096 | | // => space if currency contained, |
2097 | | // else separator |
2098 | 0 | nPos = nPos + sStrArray[i].getLength(); |
2099 | 0 | if ( (nPos <= nCurrPos && |
2100 | 0 | nCurrPos < nPos + sStrArray[i+1].getLength()) || |
2101 | 0 | nTypeArray[i+1] == NF_KEY_CCC || |
2102 | 0 | (i < nStringsCnt-2 && |
2103 | 0 | sStrArray[i+1][0] == '[' && |
2104 | 0 | sStrArray[i+2][0] == '$') ) |
2105 | 0 | { |
2106 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2107 | 0 | } |
2108 | 0 | else |
2109 | 0 | { |
2110 | 0 | if ( bFirst ) |
2111 | 0 | { |
2112 | 0 | rStr = rSepF; |
2113 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_THSEP; |
2114 | 0 | } |
2115 | 0 | else |
2116 | 0 | { |
2117 | 0 | rStr += rSepF; |
2118 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2119 | 0 | nResultStringsCnt--; |
2120 | 0 | } |
2121 | 0 | nThousand++; |
2122 | 0 | } |
2123 | 0 | i++; |
2124 | 0 | } |
2125 | 0 | } |
2126 | 12.0k | else |
2127 | 12.0k | { |
2128 | 12.0k | do |
2129 | 13.9k | { |
2130 | 13.9k | nThousand++; |
2131 | 13.9k | nTypeArray[i] = NF_SYMBOLTYPE_THSEP; |
2132 | 13.9k | nPos = nPos + sStrArray[i].getLength(); |
2133 | 13.9k | sStrArray[i] = mrCurrentLanguageData.GetNumThousandSep(); |
2134 | 13.9k | i++; |
2135 | 13.9k | } |
2136 | 13.9k | while (i < nStringsCnt && sStrArray[i] == sOldThousandSep); |
2137 | 12.0k | } |
2138 | 12.0k | } |
2139 | 19.9k | else // any grsep |
2140 | 19.9k | { |
2141 | 19.9k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2142 | 19.9k | nPos = nPos + rStr.getLength(); |
2143 | 19.9k | i++; |
2144 | 28.5k | while ( i < nStringsCnt && sStrArray[i] == sOldThousandSep ) |
2145 | 8.56k | { |
2146 | 8.56k | rStr += sStrArray[i]; |
2147 | 8.56k | nPos = nPos + sStrArray[i].getLength(); |
2148 | 8.56k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2149 | 8.56k | nResultStringsCnt--; |
2150 | 8.56k | i++; |
2151 | 8.56k | } |
2152 | 19.9k | } |
2153 | 7.94M | } |
2154 | 8.93M | else if ( StringEqualsChar( sOldDecSep, cSaved ) ) |
2155 | 6.48M | { |
2156 | 6.48M | if (bBlank || bFrac) // . behind / or ' ' |
2157 | 427 | { |
2158 | 427 | return nPos; // error |
2159 | 427 | } |
2160 | 6.48M | else if (bExp) // behind E |
2161 | 1.96k | { |
2162 | 1.96k | nPos = nPos + sStrArray[i].getLength(); |
2163 | 1.96k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2164 | 1.96k | nResultStringsCnt--; |
2165 | 1.96k | i++; // eat it |
2166 | 1.96k | } |
2167 | 6.48M | else if (bDecSep) // any . |
2168 | 4.49k | { |
2169 | 4.49k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2170 | 4.49k | nPos = nPos + rStr.getLength(); |
2171 | 4.49k | i++; |
2172 | 14.6k | while ( i < nStringsCnt && sStrArray[i] == sOldDecSep ) |
2173 | 10.1k | { |
2174 | 10.1k | rStr += sStrArray[i]; |
2175 | 10.1k | nPos = nPos + sStrArray[i].getLength(); |
2176 | 10.1k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2177 | 10.1k | nResultStringsCnt--; |
2178 | 10.1k | i++; |
2179 | 10.1k | } |
2180 | 4.49k | } |
2181 | 6.47M | else |
2182 | 6.47M | { |
2183 | 6.47M | nPos = nPos + sStrArray[i].getLength(); |
2184 | 6.47M | nTypeArray[i] = NF_SYMBOLTYPE_DECSEP; |
2185 | 6.47M | sStrArray[i] = mrCurrentLanguageData.GetNumDecimalSep(); |
2186 | 6.47M | bDecSep = true; |
2187 | 6.47M | nDecPos = i; |
2188 | 6.47M | nCntPre = nCounter; |
2189 | 6.47M | nCounter = 0; |
2190 | | |
2191 | 6.47M | i++; |
2192 | 6.47M | } |
2193 | 6.48M | } // of else = DecSep |
2194 | 2.45M | else // . without meaning |
2195 | 2.45M | { |
2196 | 2.45M | if (cSaved == ' ' && |
2197 | 2.44M | eScannedType == SvNumFormatType::FRACTION && |
2198 | 2.16M | StringEqualsChar( sStrArray[i], ' ' ) ) |
2199 | 2.16M | { |
2200 | 2.16M | if (!bBlank && !bFrac) // no dups |
2201 | 2.15M | { // or behind / |
2202 | 2.15M | if (bDecSep && nCounter > 0) // dec. |
2203 | 303 | { |
2204 | 303 | return nPos; // error |
2205 | 303 | } |
2206 | 2.15M | bBlank = true; |
2207 | 2.15M | nBlankPos = i; |
2208 | 2.15M | nCntPre = nCounter; |
2209 | 2.15M | nCounter = 0; |
2210 | 2.15M | } |
2211 | 2.16M | if ( bFrac && (nCounter > 0) ) |
2212 | 3.82k | bDenomin = true; // next content is not part of denominator |
2213 | 2.16M | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2214 | 2.16M | nPos = nPos + sStrArray[i].getLength(); |
2215 | 2.16M | } |
2216 | 286k | else |
2217 | 286k | { |
2218 | 286k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2219 | 286k | if ( bFrac && (nCounter > 0) ) |
2220 | 376 | bDenomin = true; // next content is not part of denominator |
2221 | 286k | nPos = nPos + rStr.getLength(); |
2222 | 286k | i++; |
2223 | 291k | while (i < nStringsCnt && StringEqualsChar( sStrArray[i], cSaved ) ) |
2224 | 5.23k | { |
2225 | 5.23k | rStr += sStrArray[i]; |
2226 | 5.23k | nPos = nPos + sStrArray[i].getLength(); |
2227 | 5.23k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2228 | 5.23k | nResultStringsCnt--; |
2229 | 5.23k | i++; |
2230 | 5.23k | } |
2231 | 286k | } |
2232 | 2.45M | } |
2233 | 16.8M | break; |
2234 | 16.8M | case '/': |
2235 | 2.17M | if (eScannedType == SvNumFormatType::FRACTION) |
2236 | 2.17M | { |
2237 | 2.17M | if ( i == 0 || |
2238 | 2.17M | (nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT && |
2239 | 6.12k | nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) ) |
2240 | 2.92k | { |
2241 | 2.92k | return nPos ? nPos : 1; // /? not allowed |
2242 | 2.92k | } |
2243 | 2.17M | else if (!bFrac || (bDecSep && nCounter > 0)) |
2244 | 2.17M | { |
2245 | 2.17M | bFrac = true; |
2246 | 2.17M | nCntPost = nCounter; |
2247 | 2.17M | nCounter = 0; |
2248 | 2.17M | nTypeArray[i] = NF_SYMBOLTYPE_FRAC; |
2249 | 2.17M | nPos = nPos + sStrArray[i].getLength(); |
2250 | 2.17M | i++; |
2251 | 2.17M | } |
2252 | 1.54k | else // / double or in , in the denominator |
2253 | 1.54k | { |
2254 | 1.54k | return nPos; // Error |
2255 | 1.54k | } |
2256 | 2.17M | } |
2257 | 727 | else |
2258 | 727 | { |
2259 | 727 | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2260 | 727 | nPos = nPos + sStrArray[i].getLength(); |
2261 | 727 | i++; |
2262 | 727 | } |
2263 | 2.17M | break; |
2264 | 3.47M | case '[' : |
2265 | 3.47M | if ( eScannedType == SvNumFormatType::CURRENCY && |
2266 | 3.47M | i < nStringsCnt-1 && |
2267 | 3.47M | nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && |
2268 | 3.46M | sStrArray[i+1][0] == '$' ) |
2269 | 3.46M | { |
2270 | | // [$DM-xxx] |
2271 | 3.46M | nPos = nPos + sStrArray[i].getLength(); // [ |
2272 | 3.46M | nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL; |
2273 | 3.46M | nPos = nPos + sStrArray[++i].getLength(); // $ |
2274 | 3.46M | sStrArray[i-1] += sStrArray[i]; // [$ |
2275 | 3.46M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2276 | 3.46M | nResultStringsCnt--; |
2277 | 3.46M | if ( ++i >= nStringsCnt ) |
2278 | 0 | { |
2279 | 0 | return nPos; // Error |
2280 | 0 | } |
2281 | 3.46M | nPos = nPos + sStrArray[i].getLength(); // DM |
2282 | 3.46M | OUString* pStr = &sStrArray[i]; |
2283 | 3.46M | nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // convert |
2284 | 3.46M | bool bHadDash = false; |
2285 | 3.46M | i++; |
2286 | 17.4M | while ( i < nStringsCnt && sStrArray[i][0] != ']' ) |
2287 | 14.0M | { |
2288 | 14.0M | nPos = nPos + sStrArray[i].getLength(); |
2289 | 14.0M | if ( bHadDash ) |
2290 | 10.4M | { |
2291 | 10.4M | *pStr += sStrArray[i]; |
2292 | 10.4M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2293 | 10.4M | nResultStringsCnt--; |
2294 | 10.4M | } |
2295 | 3.50M | else |
2296 | 3.50M | { |
2297 | 3.50M | if ( sStrArray[i][0] == '-' ) |
2298 | 3.45M | { |
2299 | 3.45M | bHadDash = true; |
2300 | 3.45M | pStr = &sStrArray[i]; |
2301 | 3.45M | nTypeArray[i] = NF_SYMBOLTYPE_CURREXT; |
2302 | 3.45M | } |
2303 | 43.6k | else |
2304 | 43.6k | { |
2305 | 43.6k | *pStr += sStrArray[i]; |
2306 | 43.6k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2307 | 43.6k | nResultStringsCnt--; |
2308 | 43.6k | } |
2309 | 3.50M | } |
2310 | 14.0M | i++; |
2311 | 14.0M | } |
2312 | 3.46M | if ( rStr.getLength() && i < nStringsCnt && sStrArray[i][0] == ']' ) |
2313 | 3.46M | { |
2314 | 3.46M | nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL; |
2315 | 3.46M | nPos = nPos + sStrArray[i].getLength(); |
2316 | 3.46M | i++; |
2317 | 3.46M | } |
2318 | 713 | else |
2319 | 713 | { |
2320 | 713 | return nPos; // Error |
2321 | 713 | } |
2322 | 3.46M | } |
2323 | 4.83k | else |
2324 | 4.83k | { |
2325 | 4.83k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2326 | 4.83k | nPos = nPos + sStrArray[i].getLength(); |
2327 | 4.83k | i++; |
2328 | 4.83k | } |
2329 | 3.47M | break; |
2330 | 3.47M | default: // Other Dels |
2331 | 516k | if (eScannedType == SvNumFormatType::PERCENT && cHere == '%') |
2332 | 497k | { |
2333 | 497k | nTypeArray[i] = NF_SYMBOLTYPE_PERCENT; |
2334 | 497k | } |
2335 | 19.5k | else |
2336 | 19.5k | { |
2337 | 19.5k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2338 | 19.5k | } |
2339 | 516k | nPos = nPos + sStrArray[i].getLength(); |
2340 | 516k | i++; |
2341 | 516k | break; |
2342 | 57.9M | } // of switch (Del) |
2343 | 57.9M | } // of else Del |
2344 | 0 | else |
2345 | 0 | { |
2346 | 0 | SAL_WARN( "svl.numbers", "unknown NF_SYMBOLTYPE_..." ); |
2347 | 0 | nPos = nPos + sStrArray[i].getLength(); |
2348 | 0 | i++; |
2349 | 0 | } |
2350 | 68.2M | } // of while |
2351 | 14.1M | if (eScannedType == SvNumFormatType::FRACTION) |
2352 | 2.16M | { |
2353 | 2.16M | if (bFrac) |
2354 | 2.16M | { |
2355 | 2.16M | nCntExp = nCounter; |
2356 | 2.16M | } |
2357 | 0 | else if (bBlank) |
2358 | 0 | { |
2359 | 0 | nCntPost = nCounter; |
2360 | 0 | } |
2361 | 0 | else |
2362 | 0 | { |
2363 | 0 | nCntPre = nCounter; |
2364 | 0 | } |
2365 | 2.16M | } |
2366 | 11.9M | else |
2367 | 11.9M | { |
2368 | 11.9M | if (bExp) |
2369 | 741k | { |
2370 | 741k | nCntExp = nCounter; |
2371 | 741k | } |
2372 | 11.2M | else if (bDecSep) |
2373 | 5.74M | { |
2374 | 5.74M | nCntPost = nCounter; |
2375 | 5.74M | } |
2376 | 5.49M | else |
2377 | 5.49M | { |
2378 | 5.49M | nCntPre = nCounter; |
2379 | 5.49M | } |
2380 | 11.9M | } |
2381 | 14.1M | if (bThousand) // Expansion of grouping separators |
2382 | 7.90M | { |
2383 | 7.90M | sal_uInt16 nMaxPos; |
2384 | 7.90M | if (bFrac) |
2385 | 3.05k | { |
2386 | 3.05k | if (bBlank) |
2387 | 1.25k | { |
2388 | 1.25k | nMaxPos = nBlankPos; |
2389 | 1.25k | } |
2390 | 1.80k | else |
2391 | 1.80k | { |
2392 | 1.80k | nMaxPos = 0; // no grouping |
2393 | 1.80k | } |
2394 | 3.05k | } |
2395 | 7.89M | else if (bDecSep) // decimal separator present |
2396 | 4.72M | { |
2397 | 4.72M | nMaxPos = nDecPos; |
2398 | 4.72M | } |
2399 | 3.17M | else if (bExp) // 'E' exponent present |
2400 | 1.80k | { |
2401 | 1.80k | nMaxPos = nExpPos; |
2402 | 1.80k | } |
2403 | 3.17M | else // up to end |
2404 | 3.17M | { |
2405 | 3.17M | nMaxPos = i; |
2406 | 3.17M | } |
2407 | | // Insert separators at proper positions. |
2408 | 7.90M | sal_Int32 nCount = 0; |
2409 | 7.90M | utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping()); |
2410 | 7.90M | size_t nFirstDigitSymbol = nMaxPos; |
2411 | 7.90M | size_t nFirstGroupingSymbol = nMaxPos; |
2412 | 7.90M | i = nMaxPos; |
2413 | 74.7M | while (i-- > 0) |
2414 | 66.8M | { |
2415 | 66.8M | if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT) |
2416 | 31.5M | { |
2417 | 31.5M | nFirstDigitSymbol = i; |
2418 | 31.5M | nCount = nCount + sStrArray[i].getLength(); // MSC converts += to int and then warns, so ... |
2419 | | // Insert separator only if not leftmost symbol. |
2420 | 31.5M | if (i > 0 && nCount >= aGrouping.getPos()) |
2421 | 7.89M | { |
2422 | 7.89M | DBG_ASSERT( sStrArray[i].getLength() == 1, |
2423 | 7.89M | "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion"); |
2424 | 7.89M | if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP, mrCurrentLanguageData.GetNumThousandSep())) |
2425 | 478 | { |
2426 | | // nPos isn't correct here, but signals error |
2427 | 478 | return nPos; |
2428 | 478 | } |
2429 | | // i may have been decremented by 1 |
2430 | 7.89M | nFirstDigitSymbol = i + 1; |
2431 | 7.89M | nFirstGroupingSymbol = i; |
2432 | 7.89M | aGrouping.advance(); |
2433 | 7.89M | } |
2434 | 31.5M | } |
2435 | 66.8M | } |
2436 | | // Generated something like "string",000; remove separator again. |
2437 | 7.90M | if (nFirstGroupingSymbol < nFirstDigitSymbol) |
2438 | 2.30k | { |
2439 | 2.30k | nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY; |
2440 | 2.30k | nResultStringsCnt--; |
2441 | 2.30k | } |
2442 | 7.90M | } |
2443 | | // Combine digits into groups to save memory (Info will be copied |
2444 | | // later, taking only non-empty symbols). |
2445 | 84.3M | for (i = 0; i < nStringsCnt; ++i) |
2446 | 70.1M | { |
2447 | 70.1M | if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT) |
2448 | 31.8M | { |
2449 | 31.8M | OUString& rStr = sStrArray[i]; |
2450 | 58.8M | while (++i < nStringsCnt && nTypeArray[i] == NF_SYMBOLTYPE_DIGIT) |
2451 | 26.9M | { |
2452 | 26.9M | rStr += sStrArray[i]; |
2453 | 26.9M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2454 | 26.9M | nResultStringsCnt--; |
2455 | 26.9M | } |
2456 | 31.8M | } |
2457 | 70.1M | } |
2458 | 14.1M | break; // of SvNumFormatType::NUMBER |
2459 | 7.64M | case SvNumFormatType::DATE: |
2460 | 48.2M | while (i < nStringsCnt) |
2461 | 40.6M | { |
2462 | 40.6M | switch (nTypeArray[i]) |
2463 | 40.6M | { |
2464 | 5.08k | case NF_SYMBOLTYPE_BLANK: |
2465 | 7.85k | case NF_SYMBOLTYPE_STAR: |
2466 | 327k | case NF_SYMBOLTYPE_STRING: |
2467 | 327k | nPos = nPos + sStrArray[i].getLength(); |
2468 | 327k | i++; |
2469 | 327k | break; |
2470 | 18.4M | case NF_SYMBOLTYPE_DEL: |
2471 | 18.4M | int nCalRet; |
2472 | 18.4M | if (sStrArray[i] == sOldDateSep) |
2473 | 2.01M | { |
2474 | 2.01M | nTypeArray[i] = NF_SYMBOLTYPE_DATESEP; |
2475 | 2.01M | nPos = nPos + sStrArray[i].getLength(); |
2476 | 2.01M | if (bConvertMode) |
2477 | 91.9k | { |
2478 | 91.9k | sStrArray[i] = mrCurrentLanguageData.GetDateSep(); |
2479 | 91.9k | } |
2480 | 2.01M | i++; |
2481 | 2.01M | } |
2482 | 16.4M | else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nResultStringsCnt )) != 0 ) |
2483 | 2.41M | { |
2484 | 2.41M | if ( nCalRet < 0 ) |
2485 | 535 | { |
2486 | 535 | return nPos; // error |
2487 | 535 | } |
2488 | 2.41M | } |
2489 | 14.0M | else |
2490 | 14.0M | { |
2491 | 14.0M | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2492 | 14.0M | nPos = nPos + sStrArray[i].getLength(); |
2493 | 14.0M | i++; |
2494 | 14.0M | } |
2495 | 18.4M | break; |
2496 | 18.4M | case NF_KEY_THAI_T : |
2497 | 0 | bThaiT = true; |
2498 | 0 | [[fallthrough]]; |
2499 | 307k | case NF_KEY_M: // M |
2500 | 1.84M | case NF_KEY_MM: // MM |
2501 | 3.30M | case NF_KEY_MMM: // MMM |
2502 | 7.13M | case NF_KEY_MMMM: // MMMM |
2503 | 7.13M | case NF_KEY_MMMMM: // MMMMM |
2504 | 7.13M | case NF_KEY_Q: // Q |
2505 | 7.38M | case NF_KEY_QQ: // QQ |
2506 | 11.7M | case NF_KEY_D: // D |
2507 | 13.4M | case NF_KEY_DD: // DD |
2508 | 13.4M | case NF_KEY_DDD: // DDD |
2509 | 13.4M | case NF_KEY_DDDD: // DDDD |
2510 | 15.4M | case NF_KEY_YY: // YY |
2511 | 19.2M | case NF_KEY_YYYY: // YYYY |
2512 | 20.4M | case NF_KEY_NN: // NN |
2513 | 20.4M | case NF_KEY_NNN: // NNN |
2514 | 21.4M | case NF_KEY_NNNN: // NNNN |
2515 | 21.6M | case NF_KEY_WW : // WW |
2516 | 21.6M | case NF_KEY_AAA : // AAA |
2517 | 21.7M | case NF_KEY_AAAA : // AAAA |
2518 | 21.7M | case NF_KEY_EC : // E |
2519 | 21.7M | case NF_KEY_EEC : // EE |
2520 | 21.8M | case NF_KEY_G : // G |
2521 | 21.8M | case NF_KEY_GG : // GG |
2522 | 21.8M | case NF_KEY_GGG : // GGG |
2523 | 21.8M | case NF_KEY_R : // R |
2524 | 21.8M | case NF_KEY_RR : // RR |
2525 | 21.8M | sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT |
2526 | 21.8M | nPos = nPos + sStrArray[i].getLength(); |
2527 | 21.8M | if (bNewDateOrder) |
2528 | 12.2k | { |
2529 | | // For simple numeric date formats record date order and |
2530 | | // later rearrange. |
2531 | 12.2k | switch (nTypeArray[i]) |
2532 | 12.2k | { |
2533 | 2.01k | case NF_KEY_M: |
2534 | 2.19k | case NF_KEY_MM: |
2535 | 2.19k | if (nMonthPos == SAL_MAX_UINT16) |
2536 | 1.88k | nMonthPos = i; |
2537 | 307 | else |
2538 | 307 | bNewDateOrder = false; |
2539 | 2.19k | break; |
2540 | 1.95k | case NF_KEY_D: |
2541 | 3.37k | case NF_KEY_DD: |
2542 | 3.37k | if (nDayPos == SAL_MAX_UINT16) |
2543 | 3.01k | nDayPos = i; |
2544 | 364 | else |
2545 | 364 | bNewDateOrder = false; |
2546 | 3.37k | break; |
2547 | 1.02k | case NF_KEY_YY: |
2548 | 1.72k | case NF_KEY_YYYY: |
2549 | 1.72k | if (nYearPos == SAL_MAX_UINT16) |
2550 | 1.00k | nYearPos = i; |
2551 | 716 | else |
2552 | 716 | bNewDateOrder = false; |
2553 | 1.72k | break; |
2554 | 4.97k | default: |
2555 | 4.97k | ; // nothing |
2556 | 12.2k | } |
2557 | 12.2k | } |
2558 | 21.8M | i++; |
2559 | 21.8M | break; |
2560 | 1.36k | default: // Other keywords |
2561 | 1.36k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2562 | 1.36k | nPos = nPos + sStrArray[i].getLength(); |
2563 | 1.36k | i++; |
2564 | 1.36k | break; |
2565 | 40.6M | } |
2566 | 40.6M | } // of while |
2567 | 7.64M | break; // of SvNumFormatType::DATE |
2568 | 7.64M | case SvNumFormatType::TIME: |
2569 | 12.0M | while (i < nStringsCnt) |
2570 | 10.2M | { |
2571 | 10.2M | sal_Unicode cChar; |
2572 | | |
2573 | 10.2M | switch (nTypeArray[i]) |
2574 | 10.2M | { |
2575 | 1.20k | case NF_SYMBOLTYPE_BLANK: |
2576 | 2.83k | case NF_SYMBOLTYPE_STAR: |
2577 | 79.9k | case NF_SYMBOLTYPE_STRING: |
2578 | 79.9k | nPos = nPos + sStrArray[i].getLength(); |
2579 | 79.9k | i++; |
2580 | 79.9k | break; |
2581 | 5.21M | case NF_SYMBOLTYPE_DEL: |
2582 | 5.21M | switch( sStrArray[i][0] ) |
2583 | 5.21M | { |
2584 | 495k | case '0': |
2585 | 495k | if ( Is100SecZero( i, bDecSep ) ) |
2586 | 494k | { |
2587 | 494k | bDecSep = true; |
2588 | 494k | nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; |
2589 | 494k | OUString& rStr = sStrArray[i]; |
2590 | | |
2591 | 494k | nCounter++; |
2592 | 494k | i++; |
2593 | 978k | while (i < nStringsCnt && |
2594 | 485k | sStrArray[i][0] == '0') |
2595 | 483k | { |
2596 | 483k | rStr += sStrArray[i]; |
2597 | 483k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2598 | 483k | nResultStringsCnt--; |
2599 | 483k | nCounter++; |
2600 | 483k | i++; |
2601 | 483k | } |
2602 | 494k | nPos += rStr.getLength(); |
2603 | 494k | } |
2604 | 636 | else |
2605 | 636 | { |
2606 | 636 | return nPos; |
2607 | 636 | } |
2608 | 494k | break; |
2609 | 494k | case '#': |
2610 | 605 | case '?': |
2611 | 605 | return nPos; |
2612 | 498k | case '[': |
2613 | 498k | if (bThousand) // Double |
2614 | 1.07k | { |
2615 | 1.07k | return nPos; |
2616 | 1.07k | } |
2617 | 497k | bThousand = true; // Empty for Time |
2618 | 497k | cChar = pChrCls->uppercase(OUString(NextChar(i)))[0]; |
2619 | 497k | if ( cChar == cOldKeyH ) |
2620 | 489k | { |
2621 | 489k | nThousand = 1; // H |
2622 | 489k | } |
2623 | 7.93k | else if ( cChar == cOldKeyMI ) |
2624 | 4.29k | { |
2625 | 4.29k | nThousand = 2; // M |
2626 | 4.29k | } |
2627 | 3.64k | else if ( cChar == cOldKeyS ) |
2628 | 2.63k | { |
2629 | 2.63k | nThousand = 3; // S |
2630 | 2.63k | } |
2631 | 1.01k | else |
2632 | 1.01k | { |
2633 | 1.01k | return nPos; |
2634 | 1.01k | } |
2635 | 496k | nPos = nPos + sStrArray[i].getLength(); |
2636 | 496k | i++; |
2637 | 496k | break; |
2638 | 493k | case ']': |
2639 | 493k | if (!bThousand) // No preceding [ |
2640 | 879 | { |
2641 | 879 | return nPos; |
2642 | 879 | } |
2643 | 492k | nPos = nPos + sStrArray[i].getLength(); |
2644 | 492k | i++; |
2645 | 492k | break; |
2646 | 3.72M | default: |
2647 | 3.72M | nPos = nPos + sStrArray[i].getLength(); |
2648 | 3.72M | if ( sStrArray[i] == sOldTimeSep ) |
2649 | 2.74M | { |
2650 | 2.74M | nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP; |
2651 | 2.74M | if ( bConvertMode ) |
2652 | 107k | { |
2653 | 107k | sStrArray[i] = pLoc->getTimeSep(); |
2654 | 107k | } |
2655 | 2.74M | } |
2656 | 982k | else if ( sStrArray[i] == sOldTime100SecSep ) |
2657 | 494k | { |
2658 | 494k | bDecSep = true; |
2659 | 494k | nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP; |
2660 | 494k | if ( bConvertMode ) |
2661 | 15.3k | { |
2662 | 15.3k | sStrArray[i] = pLoc->getTime100SecSep(); |
2663 | 15.3k | } |
2664 | 494k | } |
2665 | 488k | else |
2666 | 488k | { |
2667 | 488k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2668 | 488k | } |
2669 | 3.72M | i++; |
2670 | 3.72M | break; |
2671 | 5.21M | } |
2672 | 5.20M | break; |
2673 | 5.20M | case NF_KEY_AMPM: // AM/PM |
2674 | 486k | case NF_KEY_AP: // A/P |
2675 | 486k | bExp = true; // Abuse for A/P |
2676 | 486k | sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT |
2677 | 486k | nPos = nPos + sStrArray[i].getLength(); |
2678 | 486k | i++; |
2679 | 486k | break; |
2680 | 0 | case NF_KEY_THAI_T : |
2681 | 0 | bThaiT = true; |
2682 | 0 | [[fallthrough]]; |
2683 | 6.68k | case NF_KEY_MI: // M |
2684 | 1.74M | case NF_KEY_MMI: // MM |
2685 | 1.79M | case NF_KEY_H: // H |
2686 | 3.23M | case NF_KEY_HH: // HH |
2687 | 3.24M | case NF_KEY_S: // S |
2688 | 4.49M | case NF_KEY_SS: // SS |
2689 | 4.49M | sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT |
2690 | 4.49M | nPos = nPos + sStrArray[i].getLength(); |
2691 | 4.49M | i++; |
2692 | 4.49M | break; |
2693 | 1.19k | default: // Other keywords |
2694 | 1.19k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2695 | 1.19k | nPos = nPos + sStrArray[i].getLength(); |
2696 | 1.19k | i++; |
2697 | 1.19k | break; |
2698 | 10.2M | } |
2699 | 10.2M | } // of while |
2700 | 1.75M | nCntPost = nCounter; // Zero counter |
2701 | 1.75M | if (bExp) |
2702 | 486k | { |
2703 | 486k | nCntExp = 1; // Remembers AM/PM |
2704 | 486k | } |
2705 | 1.75M | break; // of SvNumFormatType::TIME |
2706 | 1.74M | case SvNumFormatType::DATETIME: |
2707 | 22.0M | while (i < nStringsCnt) |
2708 | 20.2M | { |
2709 | 20.2M | int nCalRet; |
2710 | 20.2M | switch (nTypeArray[i]) |
2711 | 20.2M | { |
2712 | 10.4k | case NF_SYMBOLTYPE_BLANK: |
2713 | 18.4k | case NF_SYMBOLTYPE_STAR: |
2714 | 859k | case NF_SYMBOLTYPE_STRING: |
2715 | 859k | nPos = nPos + sStrArray[i].getLength(); |
2716 | 859k | i++; |
2717 | 859k | break; |
2718 | 9.02M | case NF_SYMBOLTYPE_DEL: |
2719 | 9.02M | if ( (nCalRet = FinalScanGetCalendar( nPos, i, nResultStringsCnt )) != 0 ) |
2720 | 1.54k | { |
2721 | 1.54k | if ( nCalRet < 0 ) |
2722 | 396 | { |
2723 | 396 | return nPos; // Error |
2724 | 396 | } |
2725 | 1.54k | } |
2726 | 9.02M | else |
2727 | 9.02M | { |
2728 | 9.02M | switch( sStrArray[i][0] ) |
2729 | 9.02M | { |
2730 | 496k | case '0': |
2731 | 496k | if (bTimePart && Is100SecZero(i, bDecSep) && nCounter < MaxCntPost) |
2732 | 494k | { |
2733 | 494k | bDecSep = true; |
2734 | 494k | nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; |
2735 | 494k | OUString& rStr = sStrArray[i]; |
2736 | 494k | nCounter++; |
2737 | 494k | i++; |
2738 | 1.47M | while (i < nStringsCnt && |
2739 | 995k | sStrArray[i][0] == '0' && nCounter < MaxCntPost) |
2740 | 981k | { |
2741 | 981k | rStr += sStrArray[i]; |
2742 | 981k | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
2743 | 981k | nResultStringsCnt--; |
2744 | 981k | nCounter++; |
2745 | 981k | i++; |
2746 | 981k | } |
2747 | 494k | nPos += rStr.getLength(); |
2748 | 494k | } |
2749 | 1.94k | else |
2750 | 1.94k | { |
2751 | 1.94k | return nPos; |
2752 | 1.94k | } |
2753 | 494k | break; |
2754 | 494k | case '#': |
2755 | 655 | case '?': |
2756 | 655 | return nPos; |
2757 | 8.53M | default: |
2758 | 8.53M | nPos = nPos + sStrArray[i].getLength(); |
2759 | 8.53M | if (bTimePart) |
2760 | 3.89M | { |
2761 | 3.89M | if ( sStrArray[i] == sOldTimeSep ) |
2762 | 2.92M | { |
2763 | 2.92M | nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP; |
2764 | 2.92M | if ( bConvertMode ) |
2765 | 43.5k | { |
2766 | 43.5k | sStrArray[i] = pLoc->getTimeSep(); |
2767 | 43.5k | } |
2768 | 2.92M | } |
2769 | 971k | else if ( sStrArray[i] == sOldTime100SecSep ) |
2770 | 483k | { |
2771 | 483k | bDecSep = true; |
2772 | 483k | nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP; |
2773 | 483k | if ( bConvertMode ) |
2774 | 2.73k | { |
2775 | 2.73k | sStrArray[i] = pLoc->getTime100SecSep(); |
2776 | 2.73k | } |
2777 | 483k | } |
2778 | 487k | else |
2779 | 487k | { |
2780 | 487k | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2781 | 487k | } |
2782 | 3.89M | } |
2783 | 4.63M | else |
2784 | 4.63M | { |
2785 | 4.63M | if ( sStrArray[i] == sOldDateSep ) |
2786 | 1.45M | { |
2787 | 1.45M | nTypeArray[i] = NF_SYMBOLTYPE_DATESEP; |
2788 | 1.45M | if (bConvertMode) |
2789 | 14.8k | sStrArray[i] = mrCurrentLanguageData.GetDateSep(); |
2790 | 1.45M | } |
2791 | 3.18M | else |
2792 | 3.18M | { |
2793 | 3.18M | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2794 | 3.18M | } |
2795 | 4.63M | } |
2796 | 8.53M | i++; |
2797 | 8.53M | break; |
2798 | 9.02M | } |
2799 | 9.02M | } |
2800 | 9.02M | break; |
2801 | 9.02M | case NF_KEY_AMPM: // AM/PM |
2802 | 459k | case NF_KEY_AP: // A/P |
2803 | 459k | bTimePart = true; |
2804 | 459k | bExp = true; // Abuse for A/P |
2805 | 459k | sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT |
2806 | 459k | nPos = nPos + sStrArray[i].getLength(); |
2807 | 459k | i++; |
2808 | 459k | break; |
2809 | 7.45k | case NF_KEY_MI: // M |
2810 | 1.71M | case NF_KEY_MMI: // MM |
2811 | 1.73M | case NF_KEY_H: // H |
2812 | 3.42M | case NF_KEY_HH: // HH |
2813 | 3.49M | case NF_KEY_S: // S |
2814 | 4.69M | case NF_KEY_SS: // SS |
2815 | 4.69M | bTimePart = true; |
2816 | 4.69M | sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT |
2817 | 4.69M | nPos = nPos + sStrArray[i].getLength(); |
2818 | 4.69M | i++; |
2819 | 4.69M | break; |
2820 | 27.2k | case NF_KEY_M: // M |
2821 | 1.70M | case NF_KEY_MM: // MM |
2822 | 1.70M | case NF_KEY_MMM: // MMM |
2823 | 1.71M | case NF_KEY_MMMM: // MMMM |
2824 | 1.71M | case NF_KEY_MMMMM: // MMMMM |
2825 | 1.73M | case NF_KEY_Q: // Q |
2826 | 1.73M | case NF_KEY_QQ: // QQ |
2827 | 1.76M | case NF_KEY_D: // D |
2828 | 3.44M | case NF_KEY_DD: // DD |
2829 | 3.45M | case NF_KEY_DDD: // DDD |
2830 | 3.45M | case NF_KEY_DDDD: // DDDD |
2831 | 3.70M | case NF_KEY_YY: // YY |
2832 | 5.15M | case NF_KEY_YYYY: // YYYY |
2833 | 5.15M | case NF_KEY_NN: // NN |
2834 | 5.15M | case NF_KEY_NNN: // NNN |
2835 | 5.16M | case NF_KEY_NNNN: // NNNN |
2836 | 5.16M | case NF_KEY_WW : // WW |
2837 | 5.16M | case NF_KEY_AAA : // AAA |
2838 | 5.16M | case NF_KEY_AAAA : // AAAA |
2839 | 5.19M | case NF_KEY_EC : // E |
2840 | 5.19M | case NF_KEY_EEC : // EE |
2841 | 5.20M | case NF_KEY_G : // G |
2842 | 5.21M | case NF_KEY_GG : // GG |
2843 | 5.21M | case NF_KEY_GGG : // GGG |
2844 | 5.24M | case NF_KEY_R : // R |
2845 | 5.25M | case NF_KEY_RR : // RR |
2846 | 5.25M | bTimePart = false; |
2847 | 5.25M | sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT |
2848 | 5.25M | nPos = nPos + sStrArray[i].getLength(); |
2849 | 5.25M | if (bNewDateOrder) |
2850 | 11.5k | { |
2851 | | // For simple numeric date formats record date order and |
2852 | | // later rearrange. |
2853 | 11.5k | switch (nTypeArray[i]) |
2854 | 11.5k | { |
2855 | 1.73k | case NF_KEY_M: |
2856 | 1.91k | case NF_KEY_MM: |
2857 | 1.91k | if (nMonthPos == SAL_MAX_UINT16) |
2858 | 1.61k | nMonthPos = i; |
2859 | 297 | else |
2860 | 297 | bNewDateOrder = false; |
2861 | 1.91k | break; |
2862 | 2.36k | case NF_KEY_D: |
2863 | 2.75k | case NF_KEY_DD: |
2864 | 2.75k | if (nDayPos == SAL_MAX_UINT16) |
2865 | 2.21k | nDayPos = i; |
2866 | 544 | else |
2867 | 544 | bNewDateOrder = false; |
2868 | 2.75k | break; |
2869 | 803 | case NF_KEY_YY: |
2870 | 1.23k | case NF_KEY_YYYY: |
2871 | 1.23k | if (nYearPos == SAL_MAX_UINT16) |
2872 | 1.13k | nYearPos = i; |
2873 | 94 | else |
2874 | 94 | bNewDateOrder = false; |
2875 | 1.23k | break; |
2876 | 5.66k | default: |
2877 | 5.66k | ; // nothing |
2878 | 11.5k | } |
2879 | 11.5k | } |
2880 | 5.25M | i++; |
2881 | 5.25M | break; |
2882 | 0 | case NF_KEY_THAI_T : |
2883 | 0 | bThaiT = true; |
2884 | 0 | sStrArray[i] = sKeyword[nTypeArray[i]]; |
2885 | 0 | nPos = nPos + sStrArray[i].getLength(); |
2886 | 0 | i++; |
2887 | 0 | break; |
2888 | 947 | default: // Other keywords |
2889 | 947 | nTypeArray[i] = NF_SYMBOLTYPE_STRING; |
2890 | 947 | nPos = nPos + sStrArray[i].getLength(); |
2891 | 947 | i++; |
2892 | 947 | break; |
2893 | 20.2M | } |
2894 | 20.2M | } // of while |
2895 | 1.73M | nCntPost = nCounter; // decimals (100th seconds) |
2896 | 1.73M | if (bExp) |
2897 | 459k | { |
2898 | 459k | nCntExp = 1; // Remembers AM/PM |
2899 | 459k | } |
2900 | 1.73M | break; // of SvNumFormatType::DATETIME |
2901 | 240k | default: |
2902 | 240k | break; |
2903 | 25.8M | } |
2904 | 25.8M | if (eScannedType == SvNumFormatType::SCIENTIFIC && |
2905 | 741k | (nCntPre + nCntPost == 0 || nCntExp == 0)) |
2906 | 5.81k | { |
2907 | 5.81k | return nPos; |
2908 | 5.81k | } |
2909 | 25.8M | else if (eScannedType == SvNumFormatType::FRACTION && (nCntExp > 8 || nCntExp == 0)) |
2910 | 3.64k | { |
2911 | 3.64k | return nPos; |
2912 | 3.64k | } |
2913 | 25.8M | if (bThaiT && !GetNatNumModifier()) |
2914 | 0 | { |
2915 | 0 | SetNatNumModifier(1); |
2916 | 0 | } |
2917 | 25.8M | if ( bConvertMode ) |
2918 | 704k | { |
2919 | 704k | if (bNewDateOrder && sOldDateSep == "-") |
2920 | 2.06k | { |
2921 | | // Keep ISO formats Y-M-D, Y-M and M-D |
2922 | 2.06k | if (IsDateFragment( nYearPos, nMonthPos)) |
2923 | 0 | { |
2924 | 0 | nTypeArray[nYearPos+1] = NF_SYMBOLTYPE_STRING; |
2925 | 0 | sStrArray[nYearPos+1] = sOldDateSep; |
2926 | 0 | bNewDateOrder = false; |
2927 | 0 | } |
2928 | 2.06k | if (IsDateFragment( nMonthPos, nDayPos)) |
2929 | 59 | { |
2930 | 59 | nTypeArray[nMonthPos+1] = NF_SYMBOLTYPE_STRING; |
2931 | 59 | sStrArray[nMonthPos+1] = sOldDateSep; |
2932 | 59 | bNewDateOrder = false; |
2933 | 59 | } |
2934 | 2.06k | } |
2935 | 704k | if (bNewDateOrder) |
2936 | 12.9k | { |
2937 | | // Rearrange date order to the target locale if the original order |
2938 | | // includes date separators and is adjacent. |
2939 | | /* TODO: for incomplete dates trailing separators need to be |
2940 | | * handled according to the locale's usage, e.g. en-US M/D should |
2941 | | * be converted to de-DE D.M. and vice versa. As is, it's |
2942 | | * M/D -> D.M and D.M. -> M/D/ where specifically the latter looks |
2943 | | * odd. Check accepted date patterns and append/remove? */ |
2944 | 12.9k | switch (eOldDateOrder) |
2945 | 12.9k | { |
2946 | 10.6k | case DateOrder::DMY: |
2947 | 10.6k | switch (pLoc->getDateOrder()) |
2948 | 10.6k | { |
2949 | 10.6k | case DateOrder::MDY: |
2950 | | // Convert only if the actual format is not of YDM |
2951 | | // order (which would be a completely unusual order |
2952 | | // anyway, but..), e.g. YYYY.DD.MM not to |
2953 | | // YYYY/MM/DD |
2954 | 10.6k | if (IsDateFragment( nDayPos, nMonthPos) && !IsDateFragment( nYearPos, nDayPos)) |
2955 | 148 | SwapArrayElements( nDayPos, nMonthPos); |
2956 | 10.6k | break; |
2957 | 0 | case DateOrder::YMD: |
2958 | 0 | if (nYearPos != SAL_MAX_UINT16) |
2959 | 0 | { |
2960 | 0 | if (IsDateFragment( nDayPos, nMonthPos) && IsDateFragment( nMonthPos, nYearPos)) |
2961 | 0 | SwapArrayElements( nDayPos, nYearPos); |
2962 | 0 | } |
2963 | 0 | else |
2964 | 0 | { |
2965 | 0 | if (IsDateFragment( nDayPos, nMonthPos)) |
2966 | 0 | SwapArrayElements( nDayPos, nMonthPos); |
2967 | 0 | } |
2968 | 0 | break; |
2969 | 0 | default: |
2970 | 0 | ; // nothing |
2971 | 10.6k | } |
2972 | 10.6k | break; |
2973 | 10.6k | case DateOrder::MDY: |
2974 | 0 | switch (pLoc->getDateOrder()) |
2975 | 0 | { |
2976 | 0 | case DateOrder::DMY: |
2977 | | // Convert only if the actual format is not of YMD |
2978 | | // order, e.g. YYYY/MM/DD not to YYYY.DD.MM |
2979 | | /* TODO: convert such to DD.MM.YYYY instead? */ |
2980 | 0 | if (IsDateFragment( nMonthPos, nDayPos) && !IsDateFragment( nYearPos, nMonthPos)) |
2981 | 0 | SwapArrayElements( nMonthPos, nDayPos); |
2982 | 0 | break; |
2983 | 0 | case DateOrder::YMD: |
2984 | 0 | if (nYearPos != SAL_MAX_UINT16) |
2985 | 0 | { |
2986 | 0 | if (IsDateFragment( nMonthPos, nDayPos) && IsDateFragment( nDayPos, nYearPos)) |
2987 | 0 | { |
2988 | 0 | SwapArrayElements( nYearPos, nMonthPos); // YDM |
2989 | 0 | SwapArrayElements( nYearPos, nDayPos); // YMD |
2990 | 0 | } |
2991 | 0 | } |
2992 | 0 | break; |
2993 | 0 | default: |
2994 | 0 | ; // nothing |
2995 | 0 | } |
2996 | 0 | break; |
2997 | 2.31k | case DateOrder::YMD: |
2998 | 2.31k | switch (pLoc->getDateOrder()) |
2999 | 2.31k | { |
3000 | 0 | case DateOrder::DMY: |
3001 | 0 | if (nYearPos != SAL_MAX_UINT16) |
3002 | 0 | { |
3003 | 0 | if (IsDateFragment( nYearPos, nMonthPos) && IsDateFragment( nMonthPos, nDayPos)) |
3004 | 0 | SwapArrayElements( nYearPos, nDayPos); |
3005 | 0 | } |
3006 | 0 | else |
3007 | 0 | { |
3008 | 0 | if (IsDateFragment( nMonthPos, nDayPos)) |
3009 | 0 | SwapArrayElements( nMonthPos, nDayPos); |
3010 | 0 | } |
3011 | 0 | break; |
3012 | 2.31k | case DateOrder::MDY: |
3013 | 2.31k | if (nYearPos != SAL_MAX_UINT16) |
3014 | 94 | { |
3015 | 94 | if (IsDateFragment( nYearPos, nMonthPos) && IsDateFragment( nMonthPos, nDayPos)) |
3016 | 0 | { |
3017 | 0 | SwapArrayElements( nYearPos, nDayPos); // DMY |
3018 | 0 | SwapArrayElements( nYearPos, nMonthPos); // MDY |
3019 | 0 | } |
3020 | 94 | } |
3021 | 2.31k | break; |
3022 | 0 | default: |
3023 | 0 | ; // nothing |
3024 | 2.31k | } |
3025 | 2.31k | break; |
3026 | 2.31k | default: |
3027 | 0 | ; // nothing |
3028 | 12.9k | } |
3029 | 12.9k | } |
3030 | | // strings containing keywords of the target locale must be quoted, so |
3031 | | // the user sees the difference and is able to edit the format string |
3032 | 5.14M | for ( i=0; i < nStringsCnt; i++ ) |
3033 | 4.44M | { |
3034 | 4.44M | if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING && |
3035 | 1.41M | sStrArray[i][0] != '\"' ) |
3036 | 1.37M | { |
3037 | 1.37M | if ( bConvertSystemToSystem && eScannedType == SvNumFormatType::CURRENCY ) |
3038 | 0 | { |
3039 | | // don't stringize automatic currency, will be converted |
3040 | 0 | if ( sStrArray[i] == sOldCurSymbol ) |
3041 | 0 | { |
3042 | 0 | continue; // for |
3043 | 0 | } |
3044 | | // DM might be split into D and M |
3045 | 0 | if ( sStrArray[i].getLength() < sOldCurSymbol.getLength() && |
3046 | 0 | pChrCls->uppercase( sStrArray[i], 0, 1 )[0] == |
3047 | 0 | sOldCurString[0] ) |
3048 | 0 | { |
3049 | 0 | OUString aTmp( sStrArray[i] ); |
3050 | 0 | sal_uInt16 j = i + 1; |
3051 | 0 | while ( aTmp.getLength() < sOldCurSymbol.getLength() && |
3052 | 0 | j < nStringsCnt && |
3053 | 0 | nTypeArray[j] == NF_SYMBOLTYPE_STRING ) |
3054 | 0 | { |
3055 | 0 | aTmp += sStrArray[j++]; |
3056 | 0 | } |
3057 | 0 | if ( pChrCls->uppercase( aTmp ) == sOldCurString ) |
3058 | 0 | { |
3059 | 0 | sStrArray[i++] = aTmp; |
3060 | 0 | for ( ; i<j; i++ ) |
3061 | 0 | { |
3062 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
3063 | 0 | nResultStringsCnt--; |
3064 | 0 | } |
3065 | 0 | i = j - 1; |
3066 | 0 | continue; // for |
3067 | 0 | } |
3068 | 0 | } |
3069 | 0 | } |
3070 | 1.37M | OUString& rStr = sStrArray[i]; |
3071 | 1.37M | sal_Int32 nLen = rStr.getLength(); |
3072 | 3.11M | for ( sal_Int32 j = 0; j < nLen; j++ ) |
3073 | 1.77M | { |
3074 | 1.77M | bool bFoundEnglish = false; |
3075 | 1.77M | if ( (j == 0 || rStr[j - 1] != '\\') && GetKeyWord( rStr, j, bFoundEnglish) ) |
3076 | 35.1k | { |
3077 | 35.1k | rStr = "\"" + rStr + "\""; |
3078 | 35.1k | break; // for |
3079 | 35.1k | } |
3080 | 1.77M | } |
3081 | 1.37M | } |
3082 | 4.44M | } |
3083 | 704k | } |
3084 | | // Concatenate strings, remove quotes for output, and rebuild the format string |
3085 | 25.8M | rString.clear(); |
3086 | 25.8M | i = 0; |
3087 | 230M | while (i < nStringsCnt) |
3088 | 204M | { |
3089 | 204M | sal_Int32 nStringPos; |
3090 | 204M | sal_Int32 nArrPos = 0; |
3091 | 204M | sal_uInt16 iPos = i; |
3092 | 204M | switch ( nTypeArray[i] ) |
3093 | 204M | { |
3094 | 21.8M | case NF_SYMBOLTYPE_STRING : |
3095 | 24.0M | case NF_SYMBOLTYPE_FRACBLANK : |
3096 | 24.0M | nStringPos = rString.getLength(); |
3097 | 24.0M | do |
3098 | 28.9M | { |
3099 | 28.9M | if (sStrArray[i].getLength() == 2 && |
3100 | 324k | sStrArray[i][0] == '\\') |
3101 | 133k | { |
3102 | | // Unescape some simple forms of symbols even in the UI |
3103 | | // visible string to prevent duplicates that differ |
3104 | | // only in notation, originating from import. |
3105 | | // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical, |
3106 | | // but 0\ 000 0 and 0 000 0 in a French locale are not. |
3107 | | |
3108 | 133k | sal_Unicode c = sStrArray[i][1]; |
3109 | | |
3110 | 133k | switch (c) |
3111 | 133k | { |
3112 | 1.53k | case '+': |
3113 | 31.0k | case '-': |
3114 | 31.0k | rString += OUStringChar(c); |
3115 | 31.0k | break; |
3116 | 43.5k | case ' ': |
3117 | 46.4k | case '.': |
3118 | 48.7k | case '/': |
3119 | 48.7k | if (!(eScannedType & SvNumFormatType::DATE) && |
3120 | 41.5k | (StringEqualsChar( mrCurrentLanguageData.GetNumThousandSep(), c) || |
3121 | 41.1k | StringEqualsChar( mrCurrentLanguageData.GetNumDecimalSep(), c) || |
3122 | 40.5k | (c == ' ' && |
3123 | 40.1k | (StringEqualsChar( mrCurrentLanguageData.GetNumThousandSep(), cNoBreakSpace) || |
3124 | 40.1k | StringEqualsChar( mrCurrentLanguageData.GetNumThousandSep(), cNarrowNoBreakSpace))))) |
3125 | 1.04k | { |
3126 | 1.04k | rString += sStrArray[i]; |
3127 | 1.04k | } |
3128 | 47.7k | else if ((eScannedType & SvNumFormatType::DATE) && |
3129 | 7.23k | StringEqualsChar( mrCurrentLanguageData.GetDateSep(), c)) |
3130 | 1.91k | { |
3131 | 1.91k | rString += sStrArray[i]; |
3132 | 1.91k | } |
3133 | 45.8k | else if ((eScannedType & SvNumFormatType::TIME) && |
3134 | 5.58k | (StringEqualsChar( pLoc->getTimeSep(), c) || |
3135 | 5.58k | StringEqualsChar( pLoc->getTime100SecSep(), c))) |
3136 | 648 | { |
3137 | 648 | rString += sStrArray[i]; |
3138 | 648 | } |
3139 | 45.1k | else if (eScannedType & SvNumFormatType::FRACTION) |
3140 | 5.21k | { |
3141 | 5.21k | rString += sStrArray[i]; |
3142 | 5.21k | } |
3143 | 39.9k | else |
3144 | 39.9k | { |
3145 | 39.9k | rString += OUStringChar(c); |
3146 | 39.9k | } |
3147 | 48.7k | break; |
3148 | 53.6k | default: |
3149 | 53.6k | rString += sStrArray[i]; |
3150 | 133k | } |
3151 | 133k | } |
3152 | 28.8M | else |
3153 | 28.8M | { |
3154 | 28.8M | rString += sStrArray[i]; |
3155 | 28.8M | } |
3156 | 28.9M | if ( RemoveQuotes( sStrArray[i] ) > 0 ) |
3157 | 690k | { |
3158 | | // update currency up to quoted string |
3159 | 690k | if ( eScannedType == SvNumFormatType::CURRENCY ) |
3160 | 79.5k | { |
3161 | | // dM -> DM or DM -> $ in old automatic |
3162 | | // currency formats, oh my ..., why did we ever introduce them? |
3163 | 79.5k | OUString aTmp( pChrCls->uppercase( sStrArray[iPos], nArrPos, |
3164 | 79.5k | sStrArray[iPos].getLength()-nArrPos ) ); |
3165 | 79.5k | sal_Int32 nCPos = aTmp.indexOf( sOldCurString ); |
3166 | 79.5k | if ( nCPos >= 0 ) |
3167 | 3.18k | { |
3168 | 3.18k | const OUString& rCur = bConvertMode && bConvertSystemToSystem ? |
3169 | 3.18k | GetCurSymbol() : sOldCurSymbol; |
3170 | 3.18k | sStrArray[iPos] = sStrArray[iPos].replaceAt( nArrPos + nCPos, |
3171 | 3.18k | sOldCurString.getLength(), |
3172 | 3.18k | rCur ); |
3173 | 3.18k | rString = rString.replaceAt( nStringPos + nCPos, |
3174 | 3.18k | sOldCurString.getLength(), |
3175 | 3.18k | rCur ); |
3176 | 3.18k | } |
3177 | 79.5k | nStringPos = rString.getLength(); |
3178 | 79.5k | if ( iPos == i ) |
3179 | 56.0k | { |
3180 | 56.0k | nArrPos = sStrArray[iPos].getLength(); |
3181 | 56.0k | } |
3182 | 23.4k | else |
3183 | 23.4k | { |
3184 | 23.4k | nArrPos = sStrArray[iPos].getLength() + sStrArray[i].getLength(); |
3185 | 23.4k | } |
3186 | 79.5k | } |
3187 | 690k | } |
3188 | 28.9M | if ( iPos != i ) |
3189 | 4.90M | { |
3190 | 4.90M | sStrArray[iPos] += sStrArray[i]; |
3191 | 4.90M | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
3192 | 4.90M | nResultStringsCnt--; |
3193 | 4.90M | } |
3194 | 28.9M | i++; |
3195 | 28.9M | } |
3196 | 28.9M | while ( i < nStringsCnt && nTypeArray[i] == NF_SYMBOLTYPE_STRING ); |
3197 | | |
3198 | 24.0M | if ( i < nStringsCnt ) |
3199 | 23.2M | { |
3200 | 23.2M | i--; // enter switch on next symbol again |
3201 | 23.2M | } |
3202 | 24.0M | if ( eScannedType == SvNumFormatType::CURRENCY && nStringPos < rString.getLength() ) |
3203 | 4.50M | { |
3204 | | // same as above, since last RemoveQuotes |
3205 | 4.50M | OUString aTmp( pChrCls->uppercase( sStrArray[iPos], nArrPos, |
3206 | 4.50M | sStrArray[iPos].getLength()-nArrPos ) ); |
3207 | 4.50M | sal_Int32 nCPos = aTmp.indexOf( sOldCurString ); |
3208 | 4.50M | if ( nCPos >= 0 ) |
3209 | 2.46M | { |
3210 | 2.46M | const OUString& rCur = bConvertMode && bConvertSystemToSystem ? |
3211 | 2.46M | GetCurSymbol() : sOldCurSymbol; |
3212 | 2.46M | sStrArray[iPos] = sStrArray[iPos].replaceAt( nArrPos + nCPos, |
3213 | 2.46M | sOldCurString.getLength(), |
3214 | 2.46M | rCur ); |
3215 | 2.46M | rString = rString.replaceAt( nStringPos + nCPos, |
3216 | 2.46M | sOldCurString.getLength(), rCur ); |
3217 | 2.46M | } |
3218 | 4.50M | } |
3219 | 24.0M | break; |
3220 | 3.46M | case NF_SYMBOLTYPE_CURRENCY : |
3221 | 3.46M | rString += sStrArray[i]; |
3222 | 3.46M | RemoveQuotes( sStrArray[i] ); |
3223 | 3.46M | break; |
3224 | 0 | case NF_KEY_THAI_T: |
3225 | 0 | if (bThaiT && GetNatNumModifier() == 1) |
3226 | 0 | { |
3227 | | // Remove T from format code, will be replaced with a [NatNum1] prefix. |
3228 | 0 | nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; |
3229 | 0 | nResultStringsCnt--; |
3230 | 0 | } |
3231 | 0 | else |
3232 | 0 | { |
3233 | 0 | rString += sStrArray[i]; |
3234 | 0 | } |
3235 | 0 | break; |
3236 | 55.4M | case NF_SYMBOLTYPE_EMPTY : |
3237 | | // nothing |
3238 | 55.4M | break; |
3239 | 121M | default: |
3240 | 121M | rString += sStrArray[i]; |
3241 | 204M | } |
3242 | 204M | i++; |
3243 | 204M | } |
3244 | 25.8M | return 0; |
3245 | 25.8M | } |
3246 | | |
3247 | | sal_Int32 ImpSvNumberformatScan::RemoveQuotes( OUString& rStr ) |
3248 | 32.4M | { |
3249 | 32.4M | if ( rStr.getLength() > 1 ) |
3250 | 1.02M | { |
3251 | 1.02M | sal_Unicode c = rStr[0]; |
3252 | 1.02M | sal_Int32 n = rStr.getLength() - 1; |
3253 | 1.02M | if ( c == '"' && rStr[n] == '"' ) |
3254 | 557k | { |
3255 | 557k | rStr = rStr.copy( 1, n-1); |
3256 | 557k | return 2; |
3257 | 557k | } |
3258 | 470k | else if ( c == '\\' ) |
3259 | 133k | { |
3260 | 133k | rStr = rStr.copy(1); |
3261 | 133k | return 1; |
3262 | 133k | } |
3263 | 1.02M | } |
3264 | 31.7M | return 0; |
3265 | 32.4M | } |
3266 | | |
3267 | | sal_Int32 ImpSvNumberformatScan::ScanFormat( OUString& rString ) |
3268 | 25.9M | { |
3269 | 25.9M | sal_Int32 res = Symbol_Division(rString); // Lexical analysis |
3270 | 25.9M | if (!res) |
3271 | 25.9M | { |
3272 | 25.9M | res = ScanType(); // Recognizing the Format type |
3273 | 25.9M | } |
3274 | 25.9M | if (!res) |
3275 | 25.8M | { |
3276 | 25.8M | res = FinalScan( rString ); // Type dependent final analysis |
3277 | 25.8M | } |
3278 | 25.9M | return res; // res = control position; res = 0 => Format ok |
3279 | 25.9M | } |
3280 | | |
3281 | | void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, sal_uInt16 nCnt) |
3282 | 25.8M | { |
3283 | 25.8M | size_t i,j; |
3284 | 25.8M | j = 0; |
3285 | 25.8M | i = 0; |
3286 | 220M | while (i < nCnt && j < NF_MAX_FORMAT_SYMBOLS) |
3287 | 194M | { |
3288 | 194M | if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY) |
3289 | 149M | { |
3290 | 149M | pInfo->sStrArray[i] = sStrArray[j]; |
3291 | 149M | pInfo->nTypeArray[i] = nTypeArray[j]; |
3292 | 149M | i++; |
3293 | 149M | } |
3294 | 194M | j++; |
3295 | 194M | } |
3296 | 25.8M | pInfo->eScannedType = eScannedType; |
3297 | 25.8M | pInfo->bThousand = bThousand; |
3298 | 25.8M | pInfo->nThousand = nThousand; |
3299 | 25.8M | pInfo->nCntPre = nCntPre; |
3300 | 25.8M | pInfo->nCntPost = nCntPost; |
3301 | 25.8M | pInfo->nCntExp = nCntExp; |
3302 | 25.8M | } |
3303 | | |
3304 | | bool ImpSvNumberformatScan::ReplaceBooleanEquivalent( OUString& rString ) |
3305 | 22.4M | { |
3306 | 22.4M | InitKeywords(); |
3307 | | /* TODO: compare case insensitive? Or rather leave as is and case not |
3308 | | * matching indicates user supplied on purpose? Written to file / generated |
3309 | | * was always uppercase. */ |
3310 | 22.4M | if (rString == sBooleanEquivalent1 || rString == sBooleanEquivalent2) |
3311 | 6 | { |
3312 | 6 | rString = GetKeywords()[NF_KEY_BOOLEAN]; |
3313 | 6 | return true; |
3314 | 6 | } |
3315 | 22.4M | return false; |
3316 | 22.4M | } |
3317 | | |
3318 | | Color* ImpSvNumberformatScan::GetUserDefColor(sal_uInt16 nIndex) const |
3319 | 256 | { |
3320 | 256 | return mrColorCallback.GetUserDefColor(nIndex); |
3321 | 256 | } |
3322 | | |
3323 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |