Line data Source code
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 <tools/debug.hxx>
24 : #include <i18nlangtag/mslangid.hxx>
25 : #include <unotools/charclass.hxx>
26 : #include <unotools/localedatawrapper.hxx>
27 : #include <unotools/numberformatcodewrapper.hxx>
28 : #include <rtl/instance.hxx>
29 :
30 : #include <svl/zforlist.hxx>
31 : #include <svl/zformat.hxx>
32 : #include <unotools/digitgroupingiterator.hxx>
33 :
34 : #include "zforscan.hxx"
35 :
36 : #include <svl/nfsymbol.hxx>
37 : using namespace svt;
38 :
39 : const sal_Unicode cNoBreakSpace = 0xA0;
40 : const sal_Unicode cNarrowNoBreakSpace = 0x202F;
41 :
42 : namespace
43 : {
44 : struct ImplEnglishColors
45 : {
46 0 : const OUString* operator()()
47 : {
48 : static const OUString aEnglishColors[NF_MAX_DEFAULT_COLORS] =
49 : {
50 : OUString( "BLACK" ),
51 : OUString( "BLUE" ),
52 : OUString( "GREEN" ),
53 : OUString( "CYAN" ),
54 : OUString( "RED" ),
55 : OUString( "MAGENTA" ),
56 : OUString( "BROWN" ),
57 : OUString( "GREY" ),
58 : OUString( "YELLOW" ),
59 : OUString( "WHITE" )
60 0 : };
61 0 : return &aEnglishColors[0];
62 : }
63 : };
64 :
65 : struct theEnglishColors
66 : : public rtl::StaticAggregate< const OUString, ImplEnglishColors> {};
67 :
68 : }
69 :
70 0 : ImpSvNumberformatScan::ImpSvNumberformatScan( SvNumberFormatter* pFormatterP )
71 : : eNewLnge(LANGUAGE_DONTKNOW)
72 : , eTmpLnge(LANGUAGE_DONTKNOW)
73 0 : , nCurrPos(-1)
74 : {
75 0 : pFormatter = pFormatterP;
76 0 : bConvertMode = false;
77 0 : bConvertSystemToSystem = false;
78 : //! All keywords MUST be UPPERCASE!
79 0 : sKeyword[NF_KEY_E] = "E"; // Exponent
80 0 : sKeyword[NF_KEY_AMPM] = "AM/PM"; // AM/PM
81 0 : sKeyword[NF_KEY_AP] = "A/P"; // AM/PM short
82 0 : sKeyword[NF_KEY_MI] = "M"; // Minute
83 0 : sKeyword[NF_KEY_MMI] = "MM"; // Minute 02
84 0 : sKeyword[NF_KEY_S] = "S"; // Second
85 0 : sKeyword[NF_KEY_SS] = "SS"; // Second 02
86 0 : sKeyword[NF_KEY_Q] = "Q"; // Quarter short 'Q'
87 0 : sKeyword[NF_KEY_QQ] = "QQ"; // Quarter long
88 0 : sKeyword[NF_KEY_NN] = "NN"; // Day of week short
89 0 : sKeyword[NF_KEY_NNN] = "NNN"; // Day of week long
90 0 : sKeyword[NF_KEY_NNNN] = "NNNN"; // Day of week long incl. separator
91 0 : sKeyword[NF_KEY_WW] = "WW"; // Week of year
92 0 : sKeyword[NF_KEY_CCC] = "CCC"; // Currency abbreviation
93 0 : bKeywordsNeedInit = true; // locale dependent keywords
94 0 : bCompatCurNeedInit = true; // locale dependent compatibility currency strings
95 :
96 0 : StandardColor[0] = Color(COL_BLACK);
97 0 : StandardColor[1] = Color(COL_LIGHTBLUE);
98 0 : StandardColor[2] = Color(COL_LIGHTGREEN);
99 0 : StandardColor[3] = Color(COL_LIGHTCYAN);
100 0 : StandardColor[4] = Color(COL_LIGHTRED);
101 0 : StandardColor[5] = Color(COL_LIGHTMAGENTA);
102 0 : StandardColor[6] = Color(COL_BROWN);
103 0 : StandardColor[7] = Color(COL_GRAY);
104 0 : StandardColor[8] = Color(COL_YELLOW);
105 0 : StandardColor[9] = Color(COL_WHITE);
106 :
107 0 : pNullDate = new Date(30,12,1899);
108 0 : nStandardPrec = 2;
109 :
110 0 : sErrStr = "###";
111 0 : Reset();
112 0 : }
113 :
114 0 : ImpSvNumberformatScan::~ImpSvNumberformatScan()
115 : {
116 0 : delete pNullDate;
117 0 : Reset();
118 0 : }
119 :
120 0 : void ImpSvNumberformatScan::ChangeIntl()
121 : {
122 0 : bKeywordsNeedInit = true;
123 0 : bCompatCurNeedInit = true;
124 : // may be initialized by InitSpecialKeyword()
125 0 : sKeyword[NF_KEY_TRUE] = "";
126 0 : sKeyword[NF_KEY_FALSE] = "";
127 0 : }
128 :
129 0 : void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const
130 : {
131 0 : switch ( eIdx )
132 : {
133 : case NF_KEY_TRUE :
134 0 : ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE] =
135 0 : pFormatter->GetCharClass()->uppercase( pFormatter->GetLocaleData()->getTrueWord() );
136 0 : if ( sKeyword[NF_KEY_TRUE].isEmpty() )
137 : {
138 : SAL_WARN( "svl.numbers", "InitSpecialKeyword: TRUE_WORD?" );
139 0 : ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_TRUE] = "TRUE";
140 : }
141 0 : break;
142 : case NF_KEY_FALSE :
143 0 : ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE] =
144 0 : pFormatter->GetCharClass()->uppercase( pFormatter->GetLocaleData()->getFalseWord() );
145 0 : if ( sKeyword[NF_KEY_FALSE].isEmpty() )
146 : {
147 : SAL_WARN( "svl.numbers", "InitSpecialKeyword: FALSE_WORD?" );
148 0 : ((ImpSvNumberformatScan*)this)->sKeyword[NF_KEY_FALSE] = "FALSE";
149 : }
150 0 : break;
151 : default:
152 : SAL_WARN( "svl.numbers", "InitSpecialKeyword: unknown request" );
153 : }
154 0 : }
155 :
156 0 : void ImpSvNumberformatScan::InitCompatCur() const
157 : {
158 0 : ImpSvNumberformatScan* pThis = (ImpSvNumberformatScan*)this;
159 : // currency symbol for old style ("automatic") compatibility format codes
160 0 : pFormatter->GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev );
161 : // currency symbol upper case
162 0 : pThis->sCurString = pFormatter->GetCharClass()->uppercase( sCurSymbol );
163 0 : bCompatCurNeedInit = false;
164 0 : }
165 :
166 0 : void ImpSvNumberformatScan::InitKeywords() const
167 : {
168 0 : if ( !bKeywordsNeedInit )
169 0 : return ;
170 0 : ((ImpSvNumberformatScan*)this)->SetDependentKeywords();
171 0 : bKeywordsNeedInit = false;
172 : }
173 :
174 : /** Extract the name of General, Standard, Whatever, ignoring leading modifiers
175 : such as [NatNum1]. */
176 0 : static OUString lcl_extractStandardGeneralName( const OUString & rCode )
177 : {
178 0 : OUString aStr;
179 0 : const sal_Unicode* p = rCode.getStr();
180 0 : const sal_Unicode* const pStop = p + rCode.getLength();
181 0 : const sal_Unicode* pBeg = p; // name begins here
182 0 : bool bMod = false;
183 0 : bool bDone = false;
184 0 : while (p < pStop && !bDone)
185 : {
186 0 : switch (*p)
187 : {
188 : case '[':
189 0 : bMod = true;
190 0 : break;
191 : case ']':
192 0 : if (bMod)
193 : {
194 0 : bMod = false;
195 0 : pBeg = p+1;
196 : }
197 : // else: would be a locale data error, easily to be spotted in
198 : // UI dialog
199 0 : break;
200 : case ';':
201 0 : if (!bMod)
202 : {
203 0 : bDone = true;
204 0 : --p; // put back, increment by one follows
205 : }
206 0 : break;
207 : }
208 0 : ++p;
209 0 : if (bMod)
210 : {
211 0 : pBeg = p;
212 : }
213 : }
214 0 : if (pBeg < p)
215 : {
216 0 : aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg);
217 : }
218 0 : return aStr;
219 : }
220 :
221 0 : void ImpSvNumberformatScan::SetDependentKeywords()
222 : {
223 : using namespace ::com::sun::star;
224 : using namespace ::com::sun::star::uno;
225 :
226 0 : const CharClass* pCharClass = pFormatter->GetCharClass();
227 0 : const LocaleDataWrapper* pLocaleData = pFormatter->GetLocaleData();
228 : // #80023# be sure to generate keywords for the loaded Locale, not for the
229 : // requested Locale, otherwise number format codes might not match
230 0 : const LanguageTag& rLoadedLocale = pLocaleData->getLoadedLanguageTag();
231 0 : LanguageType eLang = rLoadedLocale.getLanguageType( false);
232 : NumberFormatCodeWrapper aNumberFormatCode( pFormatter->GetComponentContext(),
233 0 : rLoadedLocale.getLocale() );
234 :
235 0 : i18n::NumberFormatCode aFormat = aNumberFormatCode.getFormatCode( NF_NUMBER_STANDARD );
236 0 : sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code);
237 0 : sKeyword[NF_KEY_GENERAL] = pCharClass->uppercase( sNameStandardFormat );
238 :
239 : // preset new calendar keywords
240 0 : sKeyword[NF_KEY_AAA] = "AAA";
241 0 : sKeyword[NF_KEY_AAAA] = "AAAA";
242 0 : sKeyword[NF_KEY_EC] = "E";
243 0 : sKeyword[NF_KEY_EEC] = "EE";
244 0 : sKeyword[NF_KEY_G] = "G";
245 0 : sKeyword[NF_KEY_GG] = "GG";
246 0 : sKeyword[NF_KEY_GGG] = "GGG";
247 0 : sKeyword[NF_KEY_R] = "R";
248 0 : sKeyword[NF_KEY_RR] = "RR";
249 :
250 : // Thai T NatNum special. Other locale's small letter 't' results in upper
251 : // case comparison not matching but length does in conversion mode. Ugly.
252 0 : if (eLang == LANGUAGE_THAI)
253 : {
254 0 : sKeyword[NF_KEY_THAI_T] = "T";
255 : }
256 : else
257 : {
258 0 : sKeyword[NF_KEY_THAI_T] = "t";
259 : }
260 0 : switch ( eLang )
261 : {
262 : case LANGUAGE_GERMAN:
263 : case LANGUAGE_GERMAN_SWISS:
264 : case LANGUAGE_GERMAN_AUSTRIAN:
265 : case LANGUAGE_GERMAN_LUXEMBOURG:
266 : case LANGUAGE_GERMAN_LIECHTENSTEIN:
267 : //! all capital letters
268 0 : sKeyword[NF_KEY_M] = "M"; // month 1
269 0 : sKeyword[NF_KEY_MM] = "MM"; // month 01
270 0 : sKeyword[NF_KEY_MMM] = "MMM"; // month Jan
271 0 : sKeyword[NF_KEY_MMMM] = "MMMM"; // month Januar
272 0 : sKeyword[NF_KEY_MMMMM] = "MMMMM"; // month J
273 0 : sKeyword[NF_KEY_H] = "H"; // hour 2
274 0 : sKeyword[NF_KEY_HH] = "HH"; // hour 02
275 0 : sKeyword[NF_KEY_D] = "T";
276 0 : sKeyword[NF_KEY_DD] = "TT";
277 0 : sKeyword[NF_KEY_DDD] = "TTT";
278 0 : sKeyword[NF_KEY_DDDD] = "TTTT";
279 0 : sKeyword[NF_KEY_YY] = "JJ";
280 0 : sKeyword[NF_KEY_YYYY] = "JJJJ";
281 0 : sKeyword[NF_KEY_BOOLEAN] = "LOGISCH";
282 0 : sKeyword[NF_KEY_COLOR] = "FARBE";
283 0 : sKeyword[NF_KEY_BLACK] = "SCHWARZ";
284 0 : sKeyword[NF_KEY_BLUE] = "BLAU";
285 0 : sKeyword[NF_KEY_GREEN] = OUString( "GR" "\xDC" "N", 4, RTL_TEXTENCODING_ISO_8859_1 );
286 0 : sKeyword[NF_KEY_CYAN] = "CYAN";
287 0 : sKeyword[NF_KEY_RED] = "ROT";
288 0 : sKeyword[NF_KEY_MAGENTA] = "MAGENTA";
289 0 : sKeyword[NF_KEY_BROWN] = "BRAUN";
290 0 : sKeyword[NF_KEY_GREY] = "GRAU";
291 0 : sKeyword[NF_KEY_YELLOW] = "GELB";
292 0 : sKeyword[NF_KEY_WHITE] = "WEISS";
293 0 : break;
294 : default:
295 : // day
296 0 : switch ( eLang )
297 : {
298 : case LANGUAGE_ITALIAN:
299 : case LANGUAGE_ITALIAN_SWISS:
300 0 : sKeyword[NF_KEY_D] = "G";
301 0 : sKeyword[NF_KEY_DD] = "GG";
302 0 : sKeyword[NF_KEY_DDD] = "GGG";
303 0 : sKeyword[NF_KEY_DDDD] = "GGGG";
304 : // must exchange the era code, same as Xcl
305 0 : sKeyword[NF_KEY_G] = "X";
306 0 : sKeyword[NF_KEY_GG] = "XX";
307 0 : sKeyword[NF_KEY_GGG] = "XXX";
308 0 : break;
309 : case LANGUAGE_FRENCH:
310 : case LANGUAGE_FRENCH_BELGIAN:
311 : case LANGUAGE_FRENCH_CANADIAN:
312 : case LANGUAGE_FRENCH_SWISS:
313 : case LANGUAGE_FRENCH_LUXEMBOURG:
314 : case LANGUAGE_FRENCH_MONACO:
315 0 : sKeyword[NF_KEY_D] = "J";
316 0 : sKeyword[NF_KEY_DD] = "JJ";
317 0 : sKeyword[NF_KEY_DDD] = "JJJ";
318 0 : sKeyword[NF_KEY_DDDD] = "JJJJ";
319 0 : break;
320 : case LANGUAGE_FINNISH:
321 0 : sKeyword[NF_KEY_D] = "P";
322 0 : sKeyword[NF_KEY_DD] = "PP";
323 0 : sKeyword[NF_KEY_DDD] = "PPP";
324 0 : sKeyword[NF_KEY_DDDD] = "PPPP";
325 0 : break;
326 : default:
327 0 : sKeyword[NF_KEY_D] = "D";
328 0 : sKeyword[NF_KEY_DD] = "DD";
329 0 : sKeyword[NF_KEY_DDD] = "DDD";
330 0 : sKeyword[NF_KEY_DDDD] = "DDDD";
331 : }
332 : // month
333 0 : switch ( eLang )
334 : {
335 : case LANGUAGE_FINNISH:
336 0 : sKeyword[NF_KEY_M] = "K";
337 0 : sKeyword[NF_KEY_MM] = "KK";
338 0 : sKeyword[NF_KEY_MMM] = "KKK";
339 0 : sKeyword[NF_KEY_MMMM] = "KKKK";
340 0 : sKeyword[NF_KEY_MMMMM] = "KKKKK";
341 0 : break;
342 : default:
343 0 : sKeyword[NF_KEY_M] = "M";
344 0 : sKeyword[NF_KEY_MM] = "MM";
345 0 : sKeyword[NF_KEY_MMM] = "MMM";
346 0 : sKeyword[NF_KEY_MMMM] = "MMMM";
347 0 : sKeyword[NF_KEY_MMMMM] = "MMMMM";
348 : }
349 : // year
350 0 : switch ( eLang )
351 : {
352 : case LANGUAGE_ITALIAN:
353 : case LANGUAGE_ITALIAN_SWISS:
354 : case LANGUAGE_FRENCH:
355 : case LANGUAGE_FRENCH_BELGIAN:
356 : case LANGUAGE_FRENCH_CANADIAN:
357 : case LANGUAGE_FRENCH_SWISS:
358 : case LANGUAGE_FRENCH_LUXEMBOURG:
359 : case LANGUAGE_FRENCH_MONACO:
360 : case LANGUAGE_PORTUGUESE:
361 : case LANGUAGE_PORTUGUESE_BRAZILIAN:
362 : case LANGUAGE_SPANISH_MODERN:
363 : case LANGUAGE_SPANISH_DATED:
364 : case LANGUAGE_SPANISH_MEXICAN:
365 : case LANGUAGE_SPANISH_GUATEMALA:
366 : case LANGUAGE_SPANISH_COSTARICA:
367 : case LANGUAGE_SPANISH_PANAMA:
368 : case LANGUAGE_SPANISH_DOMINICAN_REPUBLIC:
369 : case LANGUAGE_SPANISH_VENEZUELA:
370 : case LANGUAGE_SPANISH_COLOMBIA:
371 : case LANGUAGE_SPANISH_PERU:
372 : case LANGUAGE_SPANISH_ARGENTINA:
373 : case LANGUAGE_SPANISH_ECUADOR:
374 : case LANGUAGE_SPANISH_CHILE:
375 : case LANGUAGE_SPANISH_URUGUAY:
376 : case LANGUAGE_SPANISH_PARAGUAY:
377 : case LANGUAGE_SPANISH_BOLIVIA:
378 : case LANGUAGE_SPANISH_EL_SALVADOR:
379 : case LANGUAGE_SPANISH_HONDURAS:
380 : case LANGUAGE_SPANISH_NICARAGUA:
381 : case LANGUAGE_SPANISH_PUERTO_RICO:
382 0 : sKeyword[NF_KEY_YY] = "AA";
383 0 : sKeyword[NF_KEY_YYYY] = "AAAA";
384 : // must exchange the day of week name code, same as Xcl
385 0 : sKeyword[NF_KEY_AAA] = "OOO";
386 0 : sKeyword[NF_KEY_AAAA] = "OOOO";
387 0 : break;
388 : case LANGUAGE_DUTCH:
389 : case LANGUAGE_DUTCH_BELGIAN:
390 0 : sKeyword[NF_KEY_YY] = "JJ";
391 0 : sKeyword[NF_KEY_YYYY] = "JJJJ";
392 0 : break;
393 : case LANGUAGE_FINNISH:
394 0 : sKeyword[NF_KEY_YY] = "VV";
395 0 : sKeyword[NF_KEY_YYYY] = "VVVV";
396 0 : break;
397 : default:
398 0 : sKeyword[NF_KEY_YY] = "YY";
399 0 : sKeyword[NF_KEY_YYYY] = "YYYY";
400 : }
401 : // hour
402 0 : switch ( eLang )
403 : {
404 : case LANGUAGE_DUTCH:
405 : case LANGUAGE_DUTCH_BELGIAN:
406 0 : sKeyword[NF_KEY_H] = "U";
407 0 : sKeyword[NF_KEY_HH] = "UU";
408 0 : break;
409 : case LANGUAGE_FINNISH:
410 : case LANGUAGE_SWEDISH:
411 : case LANGUAGE_SWEDISH_FINLAND:
412 : case LANGUAGE_DANISH:
413 : case LANGUAGE_NORWEGIAN:
414 : case LANGUAGE_NORWEGIAN_BOKMAL:
415 : case LANGUAGE_NORWEGIAN_NYNORSK:
416 0 : sKeyword[NF_KEY_H] = "T";
417 0 : sKeyword[NF_KEY_HH] = "TT";
418 0 : break;
419 : default:
420 0 : sKeyword[NF_KEY_H] = "H";
421 0 : sKeyword[NF_KEY_HH] = "HH";
422 : }
423 : // boolean
424 0 : sKeyword[NF_KEY_BOOLEAN] = "BOOLEAN";
425 : // colours
426 0 : sKeyword[NF_KEY_COLOR] = "COLOR";
427 0 : sKeyword[NF_KEY_BLACK] = "BLACK";
428 0 : sKeyword[NF_KEY_BLUE] = "BLUE";
429 0 : sKeyword[NF_KEY_GREEN] = "GREEN";
430 0 : sKeyword[NF_KEY_CYAN] = "CYAN";
431 0 : sKeyword[NF_KEY_RED] = "RED";
432 0 : sKeyword[NF_KEY_MAGENTA] = "MAGENTA";
433 0 : sKeyword[NF_KEY_BROWN] = "BROWN";
434 0 : sKeyword[NF_KEY_GREY] = "GREY";
435 0 : sKeyword[NF_KEY_YELLOW] = "YELLOW";
436 0 : sKeyword[NF_KEY_WHITE] = "WHITE";
437 0 : break;
438 : }
439 :
440 : // boolean keyords
441 0 : InitSpecialKeyword( NF_KEY_TRUE );
442 0 : InitSpecialKeyword( NF_KEY_FALSE );
443 :
444 : // compatibility currency strings
445 0 : InitCompatCur();
446 0 : }
447 :
448 0 : void ImpSvNumberformatScan::ChangeNullDate(sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear)
449 : {
450 0 : if ( pNullDate )
451 0 : *pNullDate = Date(nDay, nMonth, nYear);
452 : else
453 0 : pNullDate = new Date(nDay, nMonth, nYear);
454 0 : }
455 :
456 0 : void ImpSvNumberformatScan::ChangeStandardPrec(sal_uInt16 nPrec)
457 : {
458 0 : nStandardPrec = nPrec;
459 0 : }
460 :
461 0 : Color* ImpSvNumberformatScan::GetColor(OUString& sStr)
462 : {
463 0 : OUString sString = pFormatter->GetCharClass()->uppercase(sStr);
464 0 : const NfKeywordTable & rKeyword = GetKeywords();
465 0 : size_t i = 0;
466 0 : while (i < NF_MAX_DEFAULT_COLORS && sString != rKeyword[NF_KEY_FIRSTCOLOR+i] )
467 : {
468 0 : i++;
469 : }
470 0 : if ( i >= NF_MAX_DEFAULT_COLORS )
471 : {
472 0 : const OUString* pEnglishColors = theEnglishColors::get();
473 0 : size_t j = 0;
474 0 : while ( j < NF_MAX_DEFAULT_COLORS && sString != pEnglishColors[j] )
475 : {
476 0 : ++j;
477 : }
478 0 : if ( j < NF_MAX_DEFAULT_COLORS )
479 : {
480 0 : i = j;
481 : }
482 : }
483 :
484 0 : Color* pResult = NULL;
485 0 : if (i >= NF_MAX_DEFAULT_COLORS)
486 : {
487 0 : const OUString& rColorWord = rKeyword[NF_KEY_COLOR];
488 0 : if (sString.startsWith(rColorWord))
489 : {
490 0 : sal_Int32 nPos = rColorWord.getLength();
491 0 : sStr = sStr.copy(nPos);
492 0 : sStr = comphelper::string::strip(sStr, ' ');
493 0 : if (bConvertMode)
494 : {
495 0 : pFormatter->ChangeIntl(eNewLnge);
496 0 : sStr = GetKeywords()[NF_KEY_COLOR] + sStr; // Color -> FARBE
497 0 : pFormatter->ChangeIntl(eTmpLnge);
498 : }
499 : else
500 : {
501 0 : sStr = rColorWord + sStr;
502 : }
503 0 : sString = sString.copy(nPos);
504 0 : sString = comphelper::string::strip(sString, ' ');
505 :
506 0 : if ( CharClass::isAsciiNumeric( sString ) )
507 : {
508 0 : long nIndex = sString.toInt32();
509 0 : if (nIndex > 0 && nIndex <= 64)
510 : {
511 0 : pResult = pFormatter->GetUserDefColor((sal_uInt16)nIndex-1);
512 : }
513 : }
514 : }
515 : }
516 : else
517 : {
518 0 : sStr = "";
519 0 : if (bConvertMode)
520 : {
521 0 : pFormatter->ChangeIntl(eNewLnge);
522 0 : sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i]; // red -> rot
523 0 : pFormatter->ChangeIntl(eTmpLnge);
524 : }
525 : else
526 : {
527 0 : sStr = rKeyword[NF_KEY_FIRSTCOLOR+i];
528 : }
529 0 : pResult = &(StandardColor[i]);
530 : }
531 0 : return pResult;
532 : }
533 :
534 0 : short ImpSvNumberformatScan::GetKeyWord( const OUString& sSymbol, sal_Int32 nPos )
535 : {
536 0 : OUString sString = pFormatter->GetCharClass()->uppercase( sSymbol, nPos, sSymbol.getLength() - nPos );
537 0 : const NfKeywordTable & rKeyword = GetKeywords();
538 : // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere
539 0 : if ( sString.startsWith( rKeyword[NF_KEY_GENERAL] ))
540 : {
541 0 : return NF_KEY_GENERAL;
542 : }
543 : //! MUST be a reverse search to find longer strings first
544 0 : short i = NF_KEYWORD_ENTRIES_COUNT-1;
545 0 : bool bFound = false;
546 0 : for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i )
547 : {
548 0 : bFound = sString.startsWith(rKeyword[i]);
549 0 : if ( bFound )
550 : {
551 0 : break;
552 : }
553 : }
554 : // new keywords take precedence over old keywords
555 0 : if ( !bFound )
556 : {
557 : // skip the gap of colors et al between new and old keywords and search on
558 0 : i = NF_KEY_LASTKEYWORD;
559 0 : while ( i > 0 && sString.indexOf(rKeyword[i]) != 0 )
560 : {
561 0 : i--;
562 : }
563 0 : if ( i > NF_KEY_LASTOLDKEYWORD && sString != rKeyword[i] )
564 : {
565 : // found something, but maybe it's something else?
566 : // e.g. new NNN is found in NNNN, for NNNN we must search on
567 0 : short j = i - 1;
568 0 : while ( j > 0 && sString.indexOf(rKeyword[j]) != 0 )
569 : {
570 0 : j--;
571 : }
572 0 : if ( j && rKeyword[j].getLength() > rKeyword[i].getLength() )
573 : {
574 0 : return j;
575 : }
576 : }
577 : }
578 : // The Thai T NatNum modifier during Xcl import.
579 0 : if (i == 0 && bConvertMode &&
580 0 : sString[0] == 'T' &&
581 0 : eTmpLnge == LANGUAGE_ENGLISH_US &&
582 0 : MsLangId::getRealLanguage( eNewLnge) == LANGUAGE_THAI)
583 : {
584 0 : i = NF_KEY_THAI_T;
585 : }
586 0 : return i; // 0 => not found
587 : }
588 :
589 : /**
590 : * Next_Symbol
591 : *
592 : * Splits up the input for further processing (by the Turing machine).
593 : *
594 : * Starting state = SsStar
595 : *
596 : * ---------------+-------------------+---------------------------+---------------
597 : * Old state | Character read | Event | New state
598 : * ---------------+-------------------+---------------------------+---------------
599 : * SsStart | Character | Symbol = Character | SsGetWord
600 : * | " | Type = String | SsGetString
601 : * | \ | Type = String | SsGetChar
602 : * | * | Type = Star | SsGetStar
603 : * | _ | Type = Blank | SsGetBlank
604 : * | @ # 0 ? / . , % [ | Symbol = Character; |
605 : * | ] ' Blank | Type = Control character | SsStop
606 : * | $ - + ( ) : | Type = String; |
607 : * | Else | Symbol = Character | SsStop
608 : * ---------------|-------------------+---------------------------+---------------
609 : * SsGetChar | Else | Symbol = Character | SsStop
610 : * ---------------+-------------------+---------------------------+---------------
611 : * GetString | " | | SsStop
612 : * | Else | Symbol += Character | GetString
613 : * ---------------+-------------------+---------------------------+---------------
614 : * SsGetWord | Character | Symbol += Character |
615 : * | + - (E+ E-)| Symbol += Character | SsStop
616 : * | / (AM/PM)| Symbol += Character |
617 : * | Else | Pos--, if Key Type = Word | SsStop
618 : * ---------------+-------------------+---------------------------+---------------
619 : * SsGetStar | Else | Symbol += Character | SsStop
620 : * | | Mark special case * |
621 : * ---------------+-------------------+---------------------------+---------------
622 : * SsGetBlank | Else | Symbol + =Character | SsStop
623 : * | | Mark special case _ |
624 : * ---------------------------------------------------------------+--------------
625 : *
626 : * If we recognize a keyword in the state SsGetWord (even as the symbol's start text)
627 : * we write back the rest of the characters!
628 : */
629 :
630 : enum ScanState
631 : {
632 : SsStop = 0,
633 : SsStart = 1,
634 : SsGetChar = 2,
635 : SsGetString = 3,
636 : SsGetWord = 4,
637 : SsGetStar = 5,
638 : SsGetBlank = 6
639 : };
640 :
641 0 : short ImpSvNumberformatScan::Next_Symbol( const OUString& rStr,
642 : sal_Int32& nPos,
643 : OUString& sSymbol )
644 : {
645 0 : if ( bKeywordsNeedInit )
646 : {
647 0 : InitKeywords();
648 : }
649 0 : const CharClass* pChrCls = pFormatter->GetCharClass();
650 0 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
651 0 : const sal_Int32 nStart = nPos;
652 0 : short eType = 0;
653 0 : ScanState eState = SsStart;
654 0 : sSymbol = "";
655 0 : while ( nPos < rStr.getLength() && eState != SsStop )
656 : {
657 0 : sal_Unicode cToken = rStr[nPos++];
658 0 : switch (eState)
659 : {
660 : case SsStart:
661 : // Fetch any currency longer than one character and don't get
662 : // confused later on by "E/" or other combinations of letters
663 : // and meaningful symbols. Necessary for old automatic currency.
664 : // #96158# But don't do it if we're starting a "[...]" section,
665 : // for example a "[$...]" new currency symbol to not parse away
666 : // "$U" (symbol) of "[$UYU]" (abbreviation).
667 0 : if ( nCurrPos >= 0 && sCurString.getLength() > 1 &&
668 0 : nPos-1 + sCurString.getLength() <= rStr.getLength() &&
669 0 : !(nPos > 1 && rStr[nPos-2] == '[') )
670 : {
671 0 : OUString aTest = pChrCls->uppercase( rStr.copy( nPos-1, sCurString.getLength() ) );
672 0 : if ( aTest == sCurString )
673 : {
674 0 : sSymbol = rStr.copy( --nPos, sCurString.getLength() );
675 0 : nPos = nPos + sSymbol.getLength();
676 0 : eState = SsStop;
677 0 : eType = NF_SYMBOLTYPE_STRING;
678 0 : return eType;
679 0 : }
680 : }
681 0 : switch (cToken)
682 : {
683 : case '#':
684 : case '0':
685 : case '?':
686 : case '%':
687 : case '@':
688 : case '[':
689 : case ']':
690 : case ',':
691 : case '.':
692 : case '/':
693 : case '\'':
694 : case ' ':
695 : case ':':
696 : case '-':
697 0 : eType = NF_SYMBOLTYPE_DEL;
698 0 : sSymbol += OUString(cToken);
699 0 : eState = SsStop;
700 0 : break;
701 : case '*':
702 0 : eType = NF_SYMBOLTYPE_STAR;
703 0 : sSymbol += OUString(cToken);
704 0 : eState = SsGetStar;
705 0 : break;
706 : case '_':
707 0 : eType = NF_SYMBOLTYPE_BLANK;
708 0 : sSymbol += OUString(cToken);
709 0 : eState = SsGetBlank;
710 0 : break;
711 : case '"':
712 0 : eType = NF_SYMBOLTYPE_STRING;
713 0 : eState = SsGetString;
714 0 : sSymbol += OUString(cToken);
715 0 : break;
716 : case '\\':
717 0 : eType = NF_SYMBOLTYPE_STRING;
718 0 : eState = SsGetChar;
719 0 : sSymbol += OUString(cToken);
720 0 : break;
721 : case '$':
722 : case '+':
723 : case '(':
724 : case ')':
725 0 : eType = NF_SYMBOLTYPE_STRING;
726 0 : eState = SsStop;
727 0 : sSymbol += OUString(cToken);
728 0 : break;
729 : default :
730 0 : if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) ||
731 0 : StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) ||
732 0 : StringEqualsChar( pFormatter->GetDateSep(), cToken) ||
733 0 : StringEqualsChar( pLoc->getTimeSep(), cToken) ||
734 0 : StringEqualsChar( pLoc->getTime100SecSep(), cToken))
735 : {
736 : // Another separator than pre-known ASCII
737 0 : eType = NF_SYMBOLTYPE_DEL;
738 0 : sSymbol += OUString(cToken);
739 0 : eState = SsStop;
740 : }
741 0 : else if ( pChrCls->isLetter( rStr, nPos-1 ) )
742 : {
743 0 : short nTmpType = GetKeyWord( rStr, nPos-1 );
744 0 : if ( nTmpType )
745 : {
746 0 : bool bCurrency = false;
747 : // "Automatic" currency may start with keyword,
748 : // like "R" (Rand) and 'R' (era)
749 0 : if ( nCurrPos >= 0 &&
750 0 : nPos-1 + sCurString.getLength() <= rStr.getLength() &&
751 0 : sCurString.startsWith( sKeyword[nTmpType] ) )
752 : {
753 0 : OUString aTest = pChrCls->uppercase( rStr.copy( nPos-1, sCurString.getLength() ) );
754 0 : if ( aTest == sCurString )
755 : {
756 0 : bCurrency = true;
757 0 : }
758 : }
759 0 : if ( bCurrency )
760 : {
761 0 : eState = SsGetWord;
762 0 : sSymbol += OUString(cToken);
763 : }
764 : else
765 : {
766 0 : eType = nTmpType;
767 0 : sal_Int32 nLen = sKeyword[eType].getLength();
768 0 : sSymbol = rStr.copy( nPos-1, nLen );
769 0 : if ((eType == NF_KEY_E || IsAmbiguousE(eType)) && nPos < rStr.getLength())
770 : {
771 0 : sal_Unicode cNext = rStr[nPos];
772 0 : switch ( cNext )
773 : {
774 : case '+' :
775 : case '-' : // E+ E- combine to one symbol
776 0 : sSymbol += OUString(cNext);
777 0 : eType = NF_KEY_E;
778 0 : nPos++;
779 0 : break;
780 : case '0' :
781 : case '#' : // scientific E without sign
782 0 : eType = NF_KEY_E;
783 0 : break;
784 : }
785 : }
786 0 : nPos--;
787 0 : nPos = nPos + nLen;
788 0 : eState = SsStop;
789 : }
790 : }
791 : else
792 : {
793 0 : eState = SsGetWord;
794 0 : sSymbol += OUString(cToken);
795 : }
796 : }
797 : else
798 : {
799 0 : eType = NF_SYMBOLTYPE_STRING;
800 0 : eState = SsStop;
801 0 : sSymbol += OUString(cToken);
802 : }
803 0 : break;
804 : }
805 0 : break;
806 : case SsGetChar:
807 0 : sSymbol += OUString(cToken);
808 0 : eState = SsStop;
809 0 : break;
810 : case SsGetString:
811 0 : if (cToken == '"')
812 : {
813 0 : eState = SsStop;
814 : }
815 0 : sSymbol += OUString(cToken);
816 0 : break;
817 : case SsGetWord:
818 0 : if ( pChrCls->isLetter( rStr, nPos-1 ) )
819 : {
820 0 : short nTmpType = GetKeyWord( rStr, nPos-1 );
821 0 : if ( nTmpType )
822 : {
823 : // beginning of keyword, stop scan and put back
824 0 : eType = NF_SYMBOLTYPE_STRING;
825 0 : eState = SsStop;
826 0 : nPos--;
827 : }
828 : else
829 : {
830 0 : sSymbol += OUString(cToken);
831 : }
832 : }
833 : else
834 : {
835 0 : bool bDontStop = false;
836 : sal_Unicode cNext;
837 0 : switch (cToken)
838 : {
839 : case '/': // AM/PM, A/P
840 0 : cNext = rStr[nPos];
841 0 : if ( cNext == 'P' || cNext == 'p' )
842 : {
843 0 : sal_Int32 nLen = sSymbol.getLength();
844 0 : if ( 1 <= nLen &&
845 0 : (sSymbol[0] == 'A' || sSymbol[0] == 'a') &&
846 0 : (nLen == 1 ||
847 0 : (nLen == 2 && (sSymbol[1] == 'M' || sSymbol[1] == 'm')
848 0 : && (rStr[nPos + 1] == 'M' || rStr[nPos + 1] == 'm'))))
849 : {
850 0 : sSymbol += OUString(cToken);
851 0 : bDontStop = true;
852 : }
853 : }
854 0 : break;
855 : }
856 : // anything not recognized will stop the scan
857 0 : if ( eState != SsStop && !bDontStop )
858 : {
859 0 : eState = SsStop;
860 0 : nPos--;
861 0 : eType = NF_SYMBOLTYPE_STRING;
862 : }
863 : }
864 0 : break;
865 : case SsGetStar:
866 0 : eState = SsStop;
867 0 : sSymbol += OUString(cToken);
868 0 : nRepPos = (nPos - nStart) - 1; // everytime > 0!!
869 0 : break;
870 : case SsGetBlank:
871 0 : eState = SsStop;
872 0 : sSymbol += OUString(cToken);
873 0 : break;
874 : default:
875 0 : break;
876 : } // of switch
877 : } // of while
878 0 : if (eState == SsGetWord)
879 : {
880 0 : eType = NF_SYMBOLTYPE_STRING;
881 : }
882 0 : return eType;
883 : }
884 :
885 0 : sal_Int32 ImpSvNumberformatScan::Symbol_Division(const OUString& rString)
886 : {
887 0 : nCurrPos = -1;
888 : // Do we have some sort of currency?
889 0 : OUString sString = pFormatter->GetCharClass()->uppercase(rString);
890 0 : sal_Int32 nCPos = 0;
891 0 : while (nCPos >= 0)
892 : {
893 0 : nCPos = sString.indexOf(GetCurString(),nCPos);
894 0 : if (nCPos >= 0)
895 : {
896 : // In Quotes?
897 0 : sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sString, nCPos );
898 0 : if ( nQ < 0 )
899 : {
900 : sal_Unicode c;
901 0 : if ( nCPos == 0 ||
902 0 : ((c = sString[nCPos-1]) != '"'
903 0 : && c != '\\') ) // dm can be protected by "dm \d
904 : {
905 0 : nCurrPos = nCPos;
906 0 : nCPos = -1;
907 : }
908 : else
909 : {
910 0 : nCPos++; // Continue search
911 : }
912 : }
913 : else
914 : {
915 0 : nCPos = nQ + 1; // Continue search
916 : }
917 : }
918 : }
919 0 : nAnzStrings = 0;
920 0 : bool bStar = false; // Is set on detecting '*'
921 0 : Reset();
922 :
923 0 : sal_Int32 nPos = 0;
924 0 : const sal_Int32 nLen = rString.getLength();
925 0 : while (nPos < nLen && nAnzStrings < NF_MAX_FORMAT_SYMBOLS)
926 : {
927 0 : nTypeArray[nAnzStrings] = Next_Symbol(rString, nPos, sStrArray[nAnzStrings]);
928 0 : if (nTypeArray[nAnzStrings] == NF_SYMBOLTYPE_STAR)
929 : { // Monitoring the '*'
930 0 : if (bStar)
931 : {
932 0 : return nPos; // Error: double '*'
933 : }
934 : else
935 : {
936 0 : bStar = true;
937 : }
938 : }
939 0 : nAnzStrings++;
940 : }
941 :
942 0 : return 0; // 0 => ok
943 : }
944 :
945 0 : void ImpSvNumberformatScan::SkipStrings(sal_uInt16& i, sal_Int32& nPos)
946 : {
947 0 : while (i < nAnzStrings && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING
948 0 : || nTypeArray[i] == NF_SYMBOLTYPE_BLANK
949 0 : || nTypeArray[i] == NF_SYMBOLTYPE_STAR) )
950 : {
951 0 : nPos = nPos + sStrArray[i].getLength();
952 0 : i++;
953 : }
954 0 : }
955 :
956 0 : sal_uInt16 ImpSvNumberformatScan::PreviousKeyword(sal_uInt16 i)
957 : {
958 0 : short res = 0;
959 0 : if (i > 0 && i < nAnzStrings)
960 : {
961 0 : i--;
962 0 : while (i > 0 && nTypeArray[i] <= 0)
963 : {
964 0 : i--;
965 : }
966 0 : if (nTypeArray[i] > 0)
967 : {
968 0 : res = nTypeArray[i];
969 : }
970 : }
971 0 : return res;
972 : }
973 :
974 0 : sal_uInt16 ImpSvNumberformatScan::NextKeyword(sal_uInt16 i)
975 : {
976 0 : short res = 0;
977 0 : if (i < nAnzStrings-1)
978 : {
979 0 : i++;
980 0 : while (i < nAnzStrings-1 && nTypeArray[i] <= 0)
981 : {
982 0 : i++;
983 : }
984 0 : if (nTypeArray[i] > 0)
985 : {
986 0 : res = nTypeArray[i];
987 : }
988 : }
989 0 : return res;
990 : }
991 :
992 0 : short ImpSvNumberformatScan::PreviousType( sal_uInt16 i )
993 : {
994 0 : if ( i > 0 && i < nAnzStrings )
995 : {
996 0 : do
997 : {
998 0 : i--;
999 : }
1000 0 : while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY );
1001 0 : return nTypeArray[i];
1002 : }
1003 0 : return 0;
1004 : }
1005 :
1006 0 : sal_Unicode ImpSvNumberformatScan::PreviousChar(sal_uInt16 i)
1007 : {
1008 0 : sal_Unicode res = ' ';
1009 0 : if (i > 0 && i < nAnzStrings)
1010 : {
1011 0 : i--;
1012 0 : while (i > 0 &&
1013 0 : ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY ||
1014 0 : nTypeArray[i] == NF_SYMBOLTYPE_STRING ||
1015 0 : nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
1016 0 : nTypeArray[i] == NF_SYMBOLTYPE_BLANK ))
1017 : {
1018 0 : i--;
1019 : }
1020 0 : if (sStrArray[i].getLength() > 0)
1021 : {
1022 0 : res = sStrArray[i][sStrArray[i].getLength()-1];
1023 : }
1024 : }
1025 0 : return res;
1026 : }
1027 :
1028 0 : sal_Unicode ImpSvNumberformatScan::NextChar(sal_uInt16 i)
1029 : {
1030 0 : sal_Unicode res = ' ';
1031 0 : if (i < nAnzStrings-1)
1032 : {
1033 0 : i++;
1034 0 : while (i < nAnzStrings-1 &&
1035 0 : ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY ||
1036 0 : nTypeArray[i] == NF_SYMBOLTYPE_STRING ||
1037 0 : nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
1038 0 : nTypeArray[i] == NF_SYMBOLTYPE_BLANK))
1039 : {
1040 0 : i++;
1041 : }
1042 0 : if (sStrArray[i].getLength() > 0)
1043 : {
1044 0 : res = sStrArray[i][0];
1045 : }
1046 : }
1047 0 : return res;
1048 : }
1049 :
1050 0 : bool ImpSvNumberformatScan::IsLastBlankBeforeFrac(sal_uInt16 i)
1051 : {
1052 0 : bool res = true;
1053 0 : if (i < nAnzStrings-1)
1054 : {
1055 0 : bool bStop = false;
1056 0 : i++;
1057 0 : while (i < nAnzStrings-1 && !bStop)
1058 : {
1059 0 : i++;
1060 0 : if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1061 0 : sStrArray[i][0] == '/')
1062 : {
1063 0 : bStop = true;
1064 : }
1065 0 : else if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL &&
1066 0 : sStrArray[i][0] == ' ')
1067 : {
1068 0 : res = false;
1069 : }
1070 : }
1071 0 : if (!bStop) // no '/'{
1072 : {
1073 0 : res = false;
1074 : }
1075 : }
1076 : else
1077 : {
1078 0 : res = false; // no '/' any more
1079 : }
1080 0 : return res;
1081 : }
1082 :
1083 0 : void ImpSvNumberformatScan::Reset()
1084 : {
1085 0 : nAnzStrings = 0;
1086 0 : nAnzResStrings = 0;
1087 0 : eScannedType = NUMBERFORMAT_UNDEFINED;
1088 0 : nRepPos = 0;
1089 0 : bExp = false;
1090 0 : bThousand = false;
1091 0 : nThousand = 0;
1092 0 : bDecSep = false;
1093 0 : nDecPos = (sal_uInt16)-1;
1094 0 : nExpPos = (sal_uInt16)-1;
1095 0 : nBlankPos = (sal_uInt16)-1;
1096 0 : nCntPre = 0;
1097 0 : nCntPost = 0;
1098 0 : nCntExp = 0;
1099 0 : bFrac = false;
1100 0 : bBlank = false;
1101 0 : nNatNumModifier = 0;
1102 0 : }
1103 :
1104 0 : bool ImpSvNumberformatScan::Is100SecZero( sal_uInt16 i, bool bHadDecSep )
1105 : {
1106 0 : sal_uInt16 nIndexPre = PreviousKeyword( i );
1107 0 : return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS) &&
1108 0 : (bHadDecSep ||
1109 0 : ( i > 0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING));
1110 : // SS"any"00 take "any" as a valid decimal separator
1111 : }
1112 :
1113 0 : sal_Int32 ImpSvNumberformatScan::ScanType()
1114 : {
1115 0 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1116 :
1117 0 : sal_Int32 nPos = 0;
1118 0 : sal_uInt16 i = 0;
1119 : short eNewType;
1120 0 : bool bMatchBracket = false;
1121 0 : bool bHaveGeneral = false; // if General/Standard encountered
1122 :
1123 0 : SkipStrings(i, nPos);
1124 0 : while (i < nAnzStrings)
1125 : {
1126 0 : if (nTypeArray[i] > 0)
1127 : { // keyword
1128 : sal_uInt16 nIndexPre;
1129 : sal_uInt16 nIndexNex;
1130 : sal_Unicode cChar;
1131 :
1132 0 : switch (nTypeArray[i])
1133 : {
1134 : case NF_KEY_E: // E
1135 0 : eNewType = NUMBERFORMAT_SCIENTIFIC;
1136 0 : break;
1137 : case NF_KEY_AMPM: // AM,A,PM,P
1138 : case NF_KEY_AP:
1139 : case NF_KEY_H: // H
1140 : case NF_KEY_HH: // HH
1141 : case NF_KEY_S: // S
1142 : case NF_KEY_SS: // SS
1143 0 : eNewType = NUMBERFORMAT_TIME;
1144 0 : break;
1145 : case NF_KEY_M: // M
1146 : case NF_KEY_MM: // MM
1147 : // minute or month
1148 0 : nIndexPre = PreviousKeyword(i);
1149 0 : nIndexNex = NextKeyword(i);
1150 0 : cChar = PreviousChar(i);
1151 0 : if (nIndexPre == NF_KEY_H || // H
1152 0 : nIndexPre == NF_KEY_HH || // HH
1153 0 : nIndexNex == NF_KEY_S || // S
1154 0 : nIndexNex == NF_KEY_SS || // SS
1155 : cChar == '[' ) // [M
1156 : {
1157 0 : eNewType = NUMBERFORMAT_TIME;
1158 0 : nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5
1159 : }
1160 : else
1161 : {
1162 0 : eNewType = NUMBERFORMAT_DATE;
1163 : }
1164 0 : break;
1165 : case NF_KEY_MMM: // MMM
1166 : case NF_KEY_MMMM: // MMMM
1167 : case NF_KEY_MMMMM: // MMMMM
1168 : case NF_KEY_Q: // Q
1169 : case NF_KEY_QQ: // QQ
1170 : case NF_KEY_D: // D
1171 : case NF_KEY_DD: // DD
1172 : case NF_KEY_DDD: // DDD
1173 : case NF_KEY_DDDD: // DDDD
1174 : case NF_KEY_YY: // YY
1175 : case NF_KEY_YYYY: // YYYY
1176 : case NF_KEY_NN: // NN
1177 : case NF_KEY_NNN: // NNN
1178 : case NF_KEY_NNNN: // NNNN
1179 : case NF_KEY_WW : // WW
1180 : case NF_KEY_AAA : // AAA
1181 : case NF_KEY_AAAA : // AAAA
1182 : case NF_KEY_EC : // E
1183 : case NF_KEY_EEC : // EE
1184 : case NF_KEY_G : // G
1185 : case NF_KEY_GG : // GG
1186 : case NF_KEY_GGG : // GGG
1187 : case NF_KEY_R : // R
1188 : case NF_KEY_RR : // RR
1189 0 : eNewType = NUMBERFORMAT_DATE;
1190 0 : break;
1191 : case NF_KEY_CCC: // CCC
1192 0 : eNewType = NUMBERFORMAT_CURRENCY;
1193 0 : break;
1194 : case NF_KEY_GENERAL: // Standard
1195 0 : eNewType = NUMBERFORMAT_NUMBER;
1196 0 : bHaveGeneral = true;
1197 0 : break;
1198 : default:
1199 0 : eNewType = NUMBERFORMAT_UNDEFINED;
1200 0 : break;
1201 : }
1202 : }
1203 : else
1204 : { // control character
1205 0 : switch ( sStrArray[i][0] )
1206 : {
1207 : case '#':
1208 : case '?':
1209 0 : eNewType = NUMBERFORMAT_NUMBER;
1210 0 : break;
1211 : case '0':
1212 0 : if ( (eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME )
1213 : {
1214 0 : if ( Is100SecZero( i, bDecSep ) )
1215 : {
1216 0 : bDecSep = true; // subsequent 0's
1217 0 : eNewType = NUMBERFORMAT_TIME;
1218 : }
1219 : else
1220 : {
1221 0 : return nPos; // Error
1222 : }
1223 : }
1224 : else
1225 : {
1226 0 : eNewType = NUMBERFORMAT_NUMBER;
1227 : }
1228 0 : break;
1229 : case '%':
1230 0 : eNewType = NUMBERFORMAT_PERCENT;
1231 0 : break;
1232 : case '/':
1233 0 : eNewType = NUMBERFORMAT_FRACTION;
1234 0 : break;
1235 : case '[':
1236 0 : if ( i < nAnzStrings-1 &&
1237 0 : nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1238 0 : sStrArray[i+1][0] == '$' )
1239 : { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR
1240 0 : eNewType = NUMBERFORMAT_CURRENCY;
1241 0 : bMatchBracket = true;
1242 : }
1243 0 : else if ( i < nAnzStrings-1 &&
1244 0 : nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1245 0 : sStrArray[i+1][0] == '~' )
1246 : { // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1247 0 : eNewType = NUMBERFORMAT_DATE;
1248 0 : bMatchBracket = true;
1249 : }
1250 : else
1251 : {
1252 0 : sal_uInt16 nIndexNex = NextKeyword(i);
1253 0 : if (nIndexNex == NF_KEY_H || // H
1254 0 : nIndexNex == NF_KEY_HH || // HH
1255 0 : nIndexNex == NF_KEY_M || // M
1256 0 : nIndexNex == NF_KEY_MM || // MM
1257 0 : nIndexNex == NF_KEY_S || // S
1258 : nIndexNex == NF_KEY_SS ) // SS
1259 0 : eNewType = NUMBERFORMAT_TIME;
1260 : else
1261 : {
1262 0 : return nPos; // Error
1263 : }
1264 : }
1265 0 : break;
1266 : case '@':
1267 0 : eNewType = NUMBERFORMAT_TEXT;
1268 0 : break;
1269 : default:
1270 0 : if (pLoc->getTime100SecSep().equals(sStrArray[i]))
1271 : {
1272 0 : bDecSep = true; // for SS,0
1273 : }
1274 0 : eNewType = NUMBERFORMAT_UNDEFINED;
1275 0 : break;
1276 : }
1277 : }
1278 0 : if (eScannedType == NUMBERFORMAT_UNDEFINED)
1279 : {
1280 0 : eScannedType = eNewType;
1281 : }
1282 0 : else if (eScannedType == NUMBERFORMAT_TEXT || eNewType == NUMBERFORMAT_TEXT)
1283 : {
1284 0 : eScannedType = NUMBERFORMAT_TEXT; // Text always remains text
1285 : }
1286 0 : else if (eNewType == NUMBERFORMAT_UNDEFINED)
1287 : { // Remains as is
1288 : }
1289 0 : else if (eScannedType != eNewType)
1290 : {
1291 0 : switch (eScannedType)
1292 : {
1293 : case NUMBERFORMAT_DATE:
1294 0 : switch (eNewType)
1295 : {
1296 : case NUMBERFORMAT_TIME:
1297 0 : eScannedType = NUMBERFORMAT_DATETIME;
1298 0 : break;
1299 : case NUMBERFORMAT_FRACTION: // DD/MM
1300 0 : break;
1301 : default:
1302 0 : if (nCurrPos >= 0)
1303 : {
1304 0 : eScannedType = NUMBERFORMAT_UNDEFINED;
1305 : }
1306 0 : else if ( sStrArray[i] != OUString(pFormatter->GetDateSep()) )
1307 : {
1308 0 : return nPos;
1309 : }
1310 : }
1311 0 : break;
1312 : case NUMBERFORMAT_TIME:
1313 0 : switch (eNewType)
1314 : {
1315 : case NUMBERFORMAT_DATE:
1316 0 : eScannedType = NUMBERFORMAT_DATETIME;
1317 0 : break;
1318 : case NUMBERFORMAT_FRACTION: // MM/SS
1319 0 : break;
1320 : default:
1321 0 : if (nCurrPos >= 0)
1322 : {
1323 0 : eScannedType = NUMBERFORMAT_UNDEFINED;
1324 : }
1325 0 : else if (!pLoc->getTimeSep().equals(sStrArray[i]))
1326 : {
1327 0 : return nPos;
1328 : }
1329 0 : break;
1330 : }
1331 0 : break;
1332 : case NUMBERFORMAT_DATETIME:
1333 0 : switch (eNewType)
1334 : {
1335 : case NUMBERFORMAT_TIME:
1336 : case NUMBERFORMAT_DATE:
1337 0 : break;
1338 : case NUMBERFORMAT_FRACTION: // DD/MM
1339 0 : break;
1340 : default:
1341 0 : if (nCurrPos >= 0)
1342 : {
1343 0 : eScannedType = NUMBERFORMAT_UNDEFINED;
1344 : }
1345 0 : else if ( OUString(pFormatter->GetDateSep()) != sStrArray[i] &&
1346 0 : !pLoc->getTimeSep().equals(sStrArray[i]) )
1347 : {
1348 0 : return nPos;
1349 : }
1350 : }
1351 0 : break;
1352 : case NUMBERFORMAT_PERCENT:
1353 0 : switch (eNewType)
1354 : {
1355 : case NUMBERFORMAT_NUMBER: // Only number to percent
1356 0 : break;
1357 : default:
1358 0 : return nPos;
1359 : }
1360 0 : break;
1361 : case NUMBERFORMAT_SCIENTIFIC:
1362 0 : switch (eNewType)
1363 : {
1364 : case NUMBERFORMAT_NUMBER: // Only number to E
1365 0 : break;
1366 : default:
1367 0 : return nPos;
1368 : }
1369 0 : break;
1370 : case NUMBERFORMAT_NUMBER:
1371 0 : switch (eNewType)
1372 : {
1373 : case NUMBERFORMAT_SCIENTIFIC:
1374 : case NUMBERFORMAT_PERCENT:
1375 : case NUMBERFORMAT_FRACTION:
1376 : case NUMBERFORMAT_CURRENCY:
1377 0 : eScannedType = eNewType;
1378 0 : break;
1379 : default:
1380 0 : if (nCurrPos >= 0)
1381 : {
1382 0 : eScannedType = NUMBERFORMAT_UNDEFINED;
1383 : }
1384 : else
1385 : {
1386 0 : return nPos;
1387 : }
1388 : }
1389 0 : break;
1390 : case NUMBERFORMAT_FRACTION:
1391 0 : switch (eNewType)
1392 : {
1393 : case NUMBERFORMAT_NUMBER: // Only number to fraction
1394 0 : break;
1395 : default:
1396 0 : return nPos;
1397 : }
1398 0 : break;
1399 : default:
1400 0 : break;
1401 : }
1402 : }
1403 0 : nPos = nPos + sStrArray[i].getLength(); // Position of correction
1404 0 : i++;
1405 0 : if ( bMatchBracket )
1406 : { // no type detection inside of matching brackets if [$...], [~...]
1407 0 : while ( bMatchBracket && i < nAnzStrings )
1408 : {
1409 0 : if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL
1410 0 : && sStrArray[i][0] == ']' )
1411 : {
1412 0 : bMatchBracket = false;
1413 : }
1414 : else
1415 : {
1416 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1417 : }
1418 0 : nPos = nPos + sStrArray[i].getLength();
1419 0 : i++;
1420 : }
1421 0 : if ( bMatchBracket )
1422 : {
1423 0 : return nPos; // missing closing bracket at end of code
1424 : }
1425 : }
1426 0 : SkipStrings(i, nPos);
1427 : }
1428 :
1429 0 : if ((eScannedType == NUMBERFORMAT_NUMBER ||
1430 0 : eScannedType == NUMBERFORMAT_UNDEFINED) &&
1431 0 : nCurrPos >= 0 && !bHaveGeneral)
1432 : {
1433 0 : eScannedType = NUMBERFORMAT_CURRENCY; // old "automatic" currency
1434 : }
1435 0 : if (eScannedType == NUMBERFORMAT_UNDEFINED)
1436 : {
1437 0 : eScannedType = NUMBERFORMAT_DEFINED;
1438 : }
1439 0 : return 0; // All is fine
1440 : }
1441 :
1442 0 : bool ImpSvNumberformatScan::InsertSymbol( sal_uInt16 & nPos, svt::NfSymbolType eType, const OUString& rStr )
1443 : {
1444 0 : if (nAnzStrings >= NF_MAX_FORMAT_SYMBOLS || nPos > nAnzStrings)
1445 : {
1446 0 : return false;
1447 : }
1448 0 : if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY)
1449 : {
1450 0 : --nPos; // reuse position
1451 : }
1452 : else
1453 : {
1454 0 : if ((size_t) (nAnzStrings + 1) >= NF_MAX_FORMAT_SYMBOLS)
1455 : {
1456 0 : return false;
1457 : }
1458 0 : ++nAnzStrings;
1459 0 : for (size_t i = nAnzStrings; i > nPos; --i)
1460 : {
1461 0 : nTypeArray[i] = nTypeArray[i-1];
1462 0 : sStrArray[i] = sStrArray[i-1];
1463 : }
1464 : }
1465 0 : ++nAnzResStrings;
1466 0 : nTypeArray[nPos] = static_cast<short>(eType);
1467 0 : sStrArray[nPos] = rStr;
1468 0 : return true;
1469 : }
1470 :
1471 0 : int ImpSvNumberformatScan::FinalScanGetCalendar( sal_Int32& nPos, sal_uInt16& i,
1472 : sal_uInt16& rAnzResStrings )
1473 : {
1474 0 : if ( i < nAnzStrings-1 &&
1475 0 : sStrArray[i][0] == '[' &&
1476 0 : nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
1477 0 : sStrArray[i+1][0] == '~' )
1478 : {
1479 : // [~calendarID]
1480 : // as of SV_NUMBERFORMATTER_VERSION_CALENDAR
1481 0 : nPos = nPos + sStrArray[i].getLength(); // [
1482 0 : nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1483 0 : nPos = nPos + sStrArray[++i].getLength(); // ~
1484 0 : sStrArray[i-1] += sStrArray[i]; // [~
1485 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1486 0 : rAnzResStrings--;
1487 0 : if ( ++i >= nAnzStrings )
1488 : {
1489 0 : return -1; // error
1490 : }
1491 0 : nPos = nPos + sStrArray[i].getLength(); // calendarID
1492 0 : OUString& rStr = sStrArray[i];
1493 0 : nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert
1494 0 : i++;
1495 0 : while ( i < nAnzStrings && sStrArray[i][0] != ']' )
1496 : {
1497 0 : nPos = nPos + sStrArray[i].getLength();
1498 0 : rStr += sStrArray[i];
1499 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1500 0 : rAnzResStrings--;
1501 0 : i++;
1502 : }
1503 0 : if ( rStr.getLength() && i < nAnzStrings &&
1504 0 : sStrArray[i][0] == ']' )
1505 : {
1506 0 : nTypeArray[i] = NF_SYMBOLTYPE_CALDEL;
1507 0 : nPos = nPos + sStrArray[i].getLength();
1508 0 : i++;
1509 : }
1510 : else
1511 : {
1512 0 : return -1; // error
1513 : }
1514 0 : return 1;
1515 : }
1516 0 : return 0;
1517 : }
1518 :
1519 0 : sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString )
1520 : {
1521 0 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1522 :
1523 : // save values for convert mode
1524 0 : OUString sOldDecSep = pFormatter->GetNumDecimalSep();
1525 0 : OUString sOldThousandSep = pFormatter->GetNumThousandSep();
1526 0 : OUString sOldDateSep = pFormatter->GetDateSep();
1527 0 : OUString sOldTimeSep = pLoc->getTimeSep();
1528 0 : OUString sOldTime100SecSep= pLoc->getTime100SecSep();
1529 0 : OUString sOldCurSymbol = GetCurSymbol();
1530 0 : OUString sOldCurString = GetCurString();
1531 0 : sal_Unicode cOldKeyH = sKeyword[NF_KEY_H][0];
1532 0 : sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI][0];
1533 0 : sal_Unicode cOldKeyS = sKeyword[NF_KEY_S][0];
1534 :
1535 : // If the group separator is a No-Break Space (French) continue with a
1536 : // normal space instead so queries on space work correctly.
1537 : // The same for Narrow No-Break Space just in case some locale uses it.
1538 : // The format string is adjusted to allow both.
1539 : // For output of the format code string the LocaleData characters are used.
1540 0 : if ( (sOldThousandSep[0] == cNoBreakSpace || sOldThousandSep[0] == cNarrowNoBreakSpace) &&
1541 0 : sOldThousandSep.getLength() == 1 )
1542 : {
1543 0 : sOldThousandSep = " ";
1544 : }
1545 : // change locale data et al
1546 0 : if (bConvertMode)
1547 : {
1548 0 : pFormatter->ChangeIntl(eNewLnge);
1549 : //! pointer may have changed
1550 0 : pLoc = pFormatter->GetLocaleData();
1551 : //! init new keywords
1552 0 : InitKeywords();
1553 : }
1554 0 : const CharClass* pChrCls = pFormatter->GetCharClass();
1555 :
1556 0 : sal_Int32 nPos = 0; // error correction position
1557 0 : sal_uInt16 i = 0; // symbol loop counter
1558 0 : sal_uInt16 nCounter = 0; // counts digits
1559 0 : nAnzResStrings = nAnzStrings; // counts remaining symbols
1560 0 : bDecSep = false; // reset in case already used in TypeCheck
1561 0 : bool bThaiT = false; // Thai T NatNum modifier present
1562 0 : bool bTimePart = false;
1563 :
1564 0 : switch (eScannedType)
1565 : {
1566 : case NUMBERFORMAT_TEXT:
1567 : case NUMBERFORMAT_DEFINED:
1568 0 : while (i < nAnzStrings)
1569 : {
1570 0 : switch (nTypeArray[i])
1571 : {
1572 : case NF_SYMBOLTYPE_BLANK:
1573 : case NF_SYMBOLTYPE_STAR:
1574 0 : break;
1575 : case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
1576 0 : break;
1577 : default:
1578 0 : if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL ||
1579 0 : sStrArray[i][0] != '@' )
1580 : {
1581 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1582 : }
1583 0 : break;
1584 : }
1585 0 : nPos = nPos + sStrArray[i].getLength();
1586 0 : i++;
1587 : } // of while
1588 0 : break;
1589 :
1590 : case NUMBERFORMAT_NUMBER:
1591 : case NUMBERFORMAT_PERCENT:
1592 : case NUMBERFORMAT_CURRENCY:
1593 : case NUMBERFORMAT_SCIENTIFIC:
1594 : case NUMBERFORMAT_FRACTION:
1595 0 : while (i < nAnzStrings)
1596 : {
1597 : // TODO: rechecking eScannedType is unnecessary.
1598 : // This switch-case is for eScannedType == NUMBERFORMAT_FRACTION anyway
1599 0 : if (eScannedType == NUMBERFORMAT_FRACTION && // special case
1600 0 : nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/#
1601 0 : StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden
1602 0 : StringEqualsChar( sStrArray[i], ' ' ) &&
1603 0 : !bFrac &&
1604 0 : IsLastBlankBeforeFrac(i) )
1605 : {
1606 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string
1607 : } // No thousands marker
1608 :
1609 0 : if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK ||
1610 0 : nTypeArray[i] == NF_SYMBOLTYPE_STAR ||
1611 0 : nTypeArray[i] == NF_KEY_CCC || // CCC
1612 0 : nTypeArray[i] == NF_KEY_GENERAL ) // Standard
1613 : {
1614 0 : if (nTypeArray[i] == NF_KEY_GENERAL)
1615 : {
1616 0 : nThousand = FLAG_STANDARD_IN_FORMAT;
1617 0 : if ( bConvertMode )
1618 : {
1619 0 : sStrArray[i] = sNameStandardFormat;
1620 : }
1621 : }
1622 0 : nPos = nPos + sStrArray[i].getLength();
1623 0 : i++;
1624 : }
1625 0 : else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // No Strings or
1626 0 : nTypeArray[i] > 0) // Keywords
1627 : {
1628 0 : if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
1629 0 : nTypeArray[i] == NF_KEY_E) // E+
1630 : {
1631 0 : if (bExp) // Double
1632 : {
1633 0 : return nPos;
1634 : }
1635 0 : bExp = true;
1636 0 : nExpPos = i;
1637 0 : if (bDecSep)
1638 : {
1639 0 : nCntPost = nCounter;
1640 : }
1641 : else
1642 : {
1643 0 : nCntPre = nCounter;
1644 : }
1645 0 : nCounter = 0;
1646 0 : nTypeArray[i] = NF_SYMBOLTYPE_EXP;
1647 : }
1648 0 : else if (eScannedType == NUMBERFORMAT_FRACTION &&
1649 0 : sStrArray[i][0] == ' ')
1650 : {
1651 0 : if (!bBlank && !bFrac) // Not double or after a /
1652 : {
1653 0 : if (bDecSep && nCounter > 0) // Decimal places
1654 : {
1655 0 : return nPos; // Error
1656 : }
1657 0 : bBlank = true;
1658 0 : nBlankPos = i;
1659 0 : nCntPre = nCounter;
1660 0 : nCounter = 0;
1661 : }
1662 0 : nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK;
1663 : }
1664 0 : else if (nTypeArray[i] == NF_KEY_THAI_T)
1665 : {
1666 0 : bThaiT = true;
1667 0 : sStrArray[i] = sKeyword[nTypeArray[i]];
1668 : }
1669 0 : else if (sStrArray[i][0] >= '0' &&
1670 0 : sStrArray[i][0] <= '9')
1671 : {
1672 0 : OUString sDiv;
1673 0 : sal_uInt16 j = i;
1674 0 : while(j < nAnzStrings)
1675 : {
1676 0 : sDiv += sStrArray[j++];
1677 : }
1678 0 : if (OUString::number(sDiv.toInt32()) == sDiv)
1679 : {
1680 : // Found a Divisor
1681 0 : while (i < j)
1682 : {
1683 0 : nTypeArray[i++] = NF_SYMBOLTYPE_FRAC_FDIV;
1684 : }
1685 0 : i = j - 1; // Stop the loop
1686 0 : if (nCntPost)
1687 : {
1688 0 : nCounter = nCntPost;
1689 : }
1690 0 : else if (nCntPre)
1691 : {
1692 0 : nCounter = nCntPre;
1693 : }
1694 : // don't artificially increment nCntPre for forced denominator
1695 0 : if ( ( eScannedType != NUMBERFORMAT_FRACTION ) && (!nCntPre) )
1696 : {
1697 0 : nCntPre++;
1698 : }
1699 0 : }
1700 : }
1701 : else
1702 : {
1703 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1704 : }
1705 0 : nPos = nPos + sStrArray[i].getLength();
1706 0 : i++;
1707 : }
1708 0 : else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL)
1709 : {
1710 0 : sal_Unicode cHere = sStrArray[i][0];
1711 0 : sal_Unicode cSaved = cHere;
1712 : // Handle not pre-known separators in switch.
1713 : sal_Unicode cSimplified;
1714 0 : if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere))
1715 : {
1716 0 : cSimplified = ',';
1717 : }
1718 0 : else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere))
1719 : {
1720 0 : cSimplified = '.';
1721 : }
1722 : else
1723 : {
1724 0 : cSimplified = cHere;
1725 : }
1726 :
1727 0 : OUString& rStr = sStrArray[i];
1728 :
1729 0 : switch ( cSimplified )
1730 : {
1731 : case '#':
1732 : case '0':
1733 : case '?':
1734 0 : if (nThousand > 0) // #... #
1735 : {
1736 0 : return nPos; // Error
1737 : }
1738 0 : else if (bFrac && cHere == '0')
1739 : {
1740 0 : return nPos; // Denominator is 0
1741 : }
1742 0 : nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1743 0 : nPos = nPos + rStr.getLength();
1744 0 : i++;
1745 0 : nCounter++;
1746 0 : while (i < nAnzStrings &&
1747 0 : (sStrArray[i][0] == '#' ||
1748 0 : sStrArray[i][0] == '0' ||
1749 0 : sStrArray[i][0] == '?'))
1750 : {
1751 0 : nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1752 0 : nPos = nPos + sStrArray[i].getLength();
1753 0 : nCounter++;
1754 0 : i++;
1755 : }
1756 0 : break;
1757 : case '-':
1758 0 : if ( bDecSep && nDecPos+1 == i &&
1759 0 : nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP )
1760 : {
1761 : // "0.--"
1762 0 : nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
1763 0 : nPos = nPos + rStr.getLength();
1764 0 : i++;
1765 0 : nCounter++;
1766 0 : while (i < nAnzStrings &&
1767 0 : (sStrArray[i][0] == '-') )
1768 : {
1769 : // If more than two dashes are present in
1770 : // currency formats the last dash will be
1771 : // interpreted literally as a minus sign.
1772 : // Has to be this ugly. Period.
1773 0 : if ( eScannedType == NUMBERFORMAT_CURRENCY
1774 0 : && rStr.getLength() >= 2 &&
1775 0 : (i == nAnzStrings-1 ||
1776 0 : sStrArray[i+1][0] != '-') )
1777 : {
1778 0 : break;
1779 : }
1780 0 : rStr += sStrArray[i];
1781 0 : nPos = nPos + sStrArray[i].getLength();
1782 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1783 0 : nAnzResStrings--;
1784 0 : nCounter++;
1785 0 : i++;
1786 : }
1787 : }
1788 : else
1789 : {
1790 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1791 0 : nPos = nPos + sStrArray[i].getLength();
1792 0 : i++;
1793 : }
1794 0 : break;
1795 : case '.':
1796 : case ',':
1797 : case '\'':
1798 : case ' ':
1799 0 : if ( StringEqualsChar( sOldThousandSep, cSaved ) )
1800 : {
1801 : // previous char with skip empty
1802 0 : sal_Unicode cPre = PreviousChar(i);
1803 : sal_Unicode cNext;
1804 0 : if (bExp || bBlank || bFrac)
1805 : {
1806 : // after E, / or ' '
1807 0 : if ( !StringEqualsChar( sOldThousandSep, ' ' ) )
1808 : {
1809 0 : nPos = nPos + sStrArray[i].getLength();
1810 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1811 0 : nAnzResStrings--;
1812 0 : i++; // eat it
1813 : }
1814 : else
1815 : {
1816 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1817 : }
1818 : }
1819 0 : else if (i > 0 && i < nAnzStrings-1 &&
1820 0 : (cPre == '#' || cPre == '0') &&
1821 0 : ((cNext = NextChar(i)) == '#' || cNext == '0')) // #,#
1822 : {
1823 0 : nPos = nPos + sStrArray[i].getLength();
1824 0 : if (!bThousand) // only once
1825 : {
1826 0 : bThousand = true;
1827 : }
1828 : // Eat it, will be reinserted at proper grouping positions further down.
1829 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1830 0 : nAnzResStrings--;
1831 0 : i++;
1832 : }
1833 0 : else if (i > 0 && (cPre == '#' || cPre == '0')
1834 0 : && PreviousType(i) == NF_SYMBOLTYPE_DIGIT
1835 0 : && nThousand < FLAG_STANDARD_IN_FORMAT )
1836 : { // #,,,,
1837 0 : if ( StringEqualsChar( sOldThousandSep, ' ' ) )
1838 : {
1839 : // strange, those French..
1840 0 : bool bFirst = true;
1841 : // set a hard No-Break Space or ConvertMode
1842 0 : const OUString& rSepF = pFormatter->GetNumThousandSep();
1843 0 : while ( i < nAnzStrings &&
1844 0 : sStrArray[i] == sOldThousandSep &&
1845 0 : StringEqualsChar( sOldThousandSep, NextChar(i) ) )
1846 : { // last was a space or another space
1847 : // is following => separator
1848 0 : nPos = nPos + sStrArray[i].getLength();
1849 0 : if ( bFirst )
1850 : {
1851 0 : bFirst = false;
1852 0 : rStr = rSepF;
1853 0 : nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1854 : }
1855 : else
1856 : {
1857 0 : rStr += rSepF;
1858 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1859 0 : nAnzResStrings--;
1860 : }
1861 0 : nThousand++;
1862 0 : i++;
1863 : }
1864 0 : if ( i < nAnzStrings-1 &&
1865 0 : sStrArray[i] == sOldThousandSep )
1866 : {
1867 : // something following last space
1868 : // => space if currency contained,
1869 : // else separator
1870 0 : nPos = nPos + sStrArray[i].getLength();
1871 0 : if ( (nPos <= nCurrPos &&
1872 0 : nCurrPos < nPos + sStrArray[i+1].getLength()) ||
1873 0 : nTypeArray[i+1] == NF_KEY_CCC ||
1874 0 : (i < nAnzStrings-2 &&
1875 0 : sStrArray[i+1][0] == '[' &&
1876 0 : sStrArray[i+2][0] == '$') )
1877 : {
1878 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1879 : }
1880 : else
1881 : {
1882 0 : if ( bFirst )
1883 : {
1884 0 : bFirst = false;
1885 0 : rStr = rSepF;
1886 0 : nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1887 : }
1888 : else
1889 : {
1890 0 : rStr += rSepF;
1891 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1892 0 : nAnzResStrings--;
1893 : }
1894 0 : nThousand++;
1895 : }
1896 0 : i++;
1897 : }
1898 : }
1899 : else
1900 : {
1901 0 : do
1902 : {
1903 0 : nThousand++;
1904 0 : nTypeArray[i] = NF_SYMBOLTYPE_THSEP;
1905 0 : nPos = nPos + sStrArray[i].getLength();
1906 0 : sStrArray[i] = pFormatter->GetNumThousandSep();
1907 0 : i++;
1908 : }
1909 0 : while (i < nAnzStrings && sStrArray[i] == sOldThousandSep);
1910 : }
1911 : }
1912 : else // any grsep
1913 : {
1914 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1915 0 : nPos = nPos + rStr.getLength();
1916 0 : i++;
1917 0 : while ( i < nAnzStrings && sStrArray[i] == sOldThousandSep )
1918 : {
1919 0 : rStr += sStrArray[i];
1920 0 : nPos = nPos + sStrArray[i].getLength();
1921 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1922 0 : nAnzResStrings--;
1923 0 : i++;
1924 : }
1925 : }
1926 : }
1927 0 : else if ( StringEqualsChar( sOldDecSep, cSaved ) )
1928 : {
1929 0 : if (bBlank || bFrac) // . behind / or ' '
1930 : {
1931 0 : return nPos; // error
1932 : }
1933 0 : else if (bExp) // behind E
1934 : {
1935 0 : nPos = nPos + sStrArray[i].getLength();
1936 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1937 0 : nAnzResStrings--;
1938 0 : i++; // eat it
1939 : }
1940 0 : else if (bDecSep) // any .
1941 : {
1942 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1943 0 : nPos = nPos + rStr.getLength();
1944 0 : i++;
1945 0 : while ( i < nAnzStrings && sStrArray[i] == sOldDecSep )
1946 : {
1947 0 : rStr += sStrArray[i];
1948 0 : nPos = nPos + sStrArray[i].getLength();
1949 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1950 0 : nAnzResStrings--;
1951 0 : i++;
1952 : }
1953 : }
1954 : else
1955 : {
1956 0 : nPos = nPos + sStrArray[i].getLength();
1957 0 : nTypeArray[i] = NF_SYMBOLTYPE_DECSEP;
1958 0 : sStrArray[i] = pFormatter->GetNumDecimalSep();
1959 0 : bDecSep = true;
1960 0 : nDecPos = i;
1961 0 : nCntPre = nCounter;
1962 0 : nCounter = 0;
1963 :
1964 0 : i++;
1965 : }
1966 : } // of else = DecSep
1967 : else // . without meaning
1968 : {
1969 0 : if (cSaved == ' ' &&
1970 0 : eScannedType == NUMBERFORMAT_FRACTION &&
1971 0 : StringEqualsChar( sStrArray[i], ' ' ) )
1972 : {
1973 0 : if (!bBlank && !bFrac) // no dups
1974 : { // or behind /
1975 0 : if (bDecSep && nCounter > 0) // dec.
1976 : {
1977 0 : return nPos; // error
1978 : }
1979 0 : bBlank = true;
1980 0 : nBlankPos = i;
1981 0 : nCntPre = nCounter;
1982 0 : nCounter = 0;
1983 : }
1984 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1985 0 : nPos = nPos + sStrArray[i].getLength();
1986 : }
1987 : else
1988 : {
1989 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
1990 0 : nPos = nPos + rStr.getLength();
1991 0 : i++;
1992 0 : while (i < nAnzStrings && StringEqualsChar( sStrArray[i], cSaved ) )
1993 : {
1994 0 : rStr += sStrArray[i];
1995 0 : nPos = nPos + sStrArray[i].getLength();
1996 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
1997 0 : nAnzResStrings--;
1998 0 : i++;
1999 : }
2000 : }
2001 : }
2002 0 : break;
2003 : case '/':
2004 0 : if (eScannedType == NUMBERFORMAT_FRACTION)
2005 : {
2006 0 : if ( i == 0 ||
2007 0 : (nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT &&
2008 0 : nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) )
2009 : {
2010 0 : return nPos ? nPos : 1; // /? not allowed
2011 : }
2012 0 : else if (!bFrac || (bDecSep && nCounter > 0))
2013 : {
2014 0 : bFrac = true;
2015 0 : nCntPost = nCounter;
2016 0 : nCounter = 0;
2017 0 : nTypeArray[i] = NF_SYMBOLTYPE_FRAC;
2018 0 : nPos = nPos + sStrArray[i].getLength();
2019 0 : i++;
2020 : }
2021 : else // / double or in , in the denominator
2022 : {
2023 0 : return nPos; // Error
2024 : }
2025 : }
2026 : else
2027 : {
2028 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2029 0 : nPos = nPos + sStrArray[i].getLength();
2030 0 : i++;
2031 : }
2032 0 : break;
2033 : case '[' :
2034 0 : if ( eScannedType == NUMBERFORMAT_CURRENCY &&
2035 0 : i < nAnzStrings-1 &&
2036 0 : nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
2037 0 : sStrArray[i+1][0] == '$' )
2038 : {
2039 : // [$DM-xxx]
2040 : // As of SV_NUMBERFORMATTER_VERSION_NEW_CURR
2041 0 : nPos = nPos + sStrArray[i].getLength(); // [
2042 0 : nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
2043 0 : nPos = nPos + sStrArray[++i].getLength(); // $
2044 0 : sStrArray[i-1] += sStrArray[i]; // [$
2045 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2046 0 : nAnzResStrings--;
2047 0 : if ( ++i >= nAnzStrings )
2048 : {
2049 0 : return nPos; // Error
2050 : }
2051 0 : nPos = nPos + sStrArray[i].getLength(); // DM
2052 0 : OUString* pStr = &sStrArray[i];
2053 0 : nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // convert
2054 0 : bool bHadDash = false;
2055 0 : i++;
2056 0 : while ( i < nAnzStrings && sStrArray[i][0] != ']' )
2057 : {
2058 0 : nPos = nPos + sStrArray[i].getLength();
2059 0 : if ( bHadDash )
2060 : {
2061 0 : *pStr += sStrArray[i];
2062 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2063 0 : nAnzResStrings--;
2064 : }
2065 : else
2066 : {
2067 0 : if ( sStrArray[i][0] == '-' )
2068 : {
2069 0 : bHadDash = true;
2070 0 : pStr = &sStrArray[i];
2071 0 : nTypeArray[i] = NF_SYMBOLTYPE_CURREXT;
2072 : }
2073 : else
2074 : {
2075 0 : *pStr += sStrArray[i];
2076 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2077 0 : nAnzResStrings--;
2078 : }
2079 : }
2080 0 : i++;
2081 : }
2082 0 : if ( rStr.getLength() && i < nAnzStrings && sStrArray[i][0] == ']' )
2083 : {
2084 0 : nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL;
2085 0 : nPos = nPos + sStrArray[i].getLength();
2086 0 : i++;
2087 : }
2088 : else
2089 : {
2090 0 : return nPos; // Error
2091 : }
2092 : }
2093 : else
2094 : {
2095 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2096 0 : nPos = nPos + sStrArray[i].getLength();
2097 0 : i++;
2098 : }
2099 0 : break;
2100 : default: // Other Dels
2101 0 : if (eScannedType == NUMBERFORMAT_PERCENT && cHere == '%')
2102 : {
2103 0 : nTypeArray[i] = NF_SYMBOLTYPE_PERCENT;
2104 : }
2105 : else
2106 : {
2107 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2108 : }
2109 0 : nPos = nPos + sStrArray[i].getLength();
2110 0 : i++;
2111 0 : break;
2112 : } // of switch (Del)
2113 : } // of else Del
2114 : else
2115 : {
2116 : SAL_WARN( "svl.numbers", "unknown NF_SYMBOLTYPE_..." );
2117 0 : nPos = nPos + sStrArray[i].getLength();
2118 0 : i++;
2119 : }
2120 : } // of while
2121 0 : if (eScannedType == NUMBERFORMAT_FRACTION)
2122 : {
2123 0 : if (bFrac)
2124 : {
2125 0 : nCntExp = nCounter;
2126 : }
2127 0 : else if (bBlank)
2128 : {
2129 0 : nCntPost = nCounter;
2130 : }
2131 : else
2132 : {
2133 0 : nCntPre = nCounter;
2134 : }
2135 : }
2136 : else
2137 : {
2138 0 : if (bExp)
2139 : {
2140 0 : nCntExp = nCounter;
2141 : }
2142 0 : else if (bDecSep)
2143 : {
2144 0 : nCntPost = nCounter;
2145 : }
2146 : else
2147 : {
2148 0 : nCntPre = nCounter;
2149 : }
2150 : }
2151 0 : if (bThousand) // Expansion of grouping separators
2152 : {
2153 : sal_uInt16 nMaxPos;
2154 0 : if (bFrac)
2155 : {
2156 0 : if (bBlank)
2157 : {
2158 0 : nMaxPos = nBlankPos;
2159 : }
2160 : else
2161 : {
2162 0 : nMaxPos = 0; // no grouping
2163 : }
2164 : }
2165 0 : else if (bDecSep) // decimal separator present
2166 : {
2167 0 : nMaxPos = nDecPos;
2168 : }
2169 0 : else if (bExp) // 'E' exponent present
2170 : {
2171 0 : nMaxPos = nExpPos;
2172 : }
2173 : else // up to end
2174 : {
2175 0 : nMaxPos = i;
2176 : }
2177 : // Insert separators at proper positions.
2178 0 : sal_Int32 nCount = 0;
2179 0 : utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping());
2180 0 : size_t nFirstDigitSymbol = nMaxPos;
2181 0 : size_t nFirstGroupingSymbol = nMaxPos;
2182 0 : i = nMaxPos;
2183 0 : while (i-- > 0)
2184 : {
2185 0 : if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2186 : {
2187 0 : nFirstDigitSymbol = i;
2188 0 : nCount = nCount + sStrArray[i].getLength(); // MSC converts += to int and then warns, so ...
2189 : // Insert separator only if not leftmost symbol.
2190 0 : if (i > 0 && nCount >= aGrouping.getPos())
2191 : {
2192 : DBG_ASSERT( sStrArray[i].getLength() == 1,
2193 : "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion");
2194 0 : if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP, pFormatter->GetNumThousandSep()))
2195 : {
2196 : // nPos isn't correct here, but signals error
2197 0 : return nPos;
2198 : }
2199 : // i may have been decremented by 1
2200 0 : nFirstDigitSymbol = i + 1;
2201 0 : nFirstGroupingSymbol = i;
2202 0 : aGrouping.advance();
2203 : }
2204 : }
2205 : }
2206 : // Generated something like "string",000; remove separator again.
2207 0 : if (nFirstGroupingSymbol < nFirstDigitSymbol)
2208 : {
2209 0 : nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY;
2210 0 : nAnzResStrings--;
2211 0 : }
2212 : }
2213 : // Combine digits into groups to save memory (Info will be copied
2214 : // later, taking only non-empty symbols).
2215 0 : for (i = 0; i < nAnzStrings; ++i)
2216 : {
2217 0 : if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2218 : {
2219 0 : OUString& rStr = sStrArray[i];
2220 0 : while (++i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_DIGIT)
2221 : {
2222 0 : rStr += sStrArray[i];
2223 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2224 0 : nAnzResStrings--;
2225 : }
2226 : }
2227 : }
2228 0 : break; // of NUMBERFORMAT_NUMBER
2229 : case NUMBERFORMAT_DATE:
2230 0 : while (i < nAnzStrings)
2231 : {
2232 : int nCalRet;
2233 0 : switch (nTypeArray[i])
2234 : {
2235 : case NF_SYMBOLTYPE_BLANK:
2236 : case NF_SYMBOLTYPE_STAR:
2237 : case NF_SYMBOLTYPE_STRING:
2238 0 : nPos = nPos + sStrArray[i].getLength();
2239 0 : i++;
2240 0 : break;
2241 : case NF_SYMBOLTYPE_DEL:
2242 0 : if (sStrArray[i] == sOldDateSep)
2243 : {
2244 0 : nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2245 0 : nPos = nPos + sStrArray[i].getLength();
2246 0 : if (bConvertMode)
2247 : {
2248 0 : sStrArray[i] = pFormatter->GetDateSep();
2249 : }
2250 0 : i++;
2251 : }
2252 0 : else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2253 : {
2254 0 : if ( nCalRet < 0 )
2255 : {
2256 0 : return nPos; // error
2257 : }
2258 : }
2259 : else
2260 : {
2261 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2262 0 : nPos = nPos + sStrArray[i].getLength();
2263 0 : i++;
2264 : }
2265 0 : break;
2266 : case NF_KEY_THAI_T :
2267 0 : bThaiT = true;
2268 : // fall thru
2269 : case NF_KEY_M: // M
2270 : case NF_KEY_MM: // MM
2271 : case NF_KEY_MMM: // MMM
2272 : case NF_KEY_MMMM: // MMMM
2273 : case NF_KEY_MMMMM: // MMMMM
2274 : case NF_KEY_Q: // Q
2275 : case NF_KEY_QQ: // QQ
2276 : case NF_KEY_D: // D
2277 : case NF_KEY_DD: // DD
2278 : case NF_KEY_DDD: // DDD
2279 : case NF_KEY_DDDD: // DDDD
2280 : case NF_KEY_YY: // YY
2281 : case NF_KEY_YYYY: // YYYY
2282 : case NF_KEY_NN: // NN
2283 : case NF_KEY_NNN: // NNN
2284 : case NF_KEY_NNNN: // NNNN
2285 : case NF_KEY_WW : // WW
2286 : case NF_KEY_AAA : // AAA
2287 : case NF_KEY_AAAA : // AAAA
2288 : case NF_KEY_EC : // E
2289 : case NF_KEY_EEC : // EE
2290 : case NF_KEY_G : // G
2291 : case NF_KEY_GG : // GG
2292 : case NF_KEY_GGG : // GGG
2293 : case NF_KEY_R : // R
2294 : case NF_KEY_RR : // RR
2295 0 : sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2296 0 : nPos = nPos + sStrArray[i].getLength();
2297 0 : i++;
2298 0 : break;
2299 : default: // Other keywords
2300 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2301 0 : nPos = nPos + sStrArray[i].getLength();
2302 0 : i++;
2303 0 : break;
2304 : }
2305 : } // of while
2306 0 : break; // of NUMBERFORMAT_DATE
2307 : case NUMBERFORMAT_TIME:
2308 0 : while (i < nAnzStrings)
2309 : {
2310 : sal_Unicode cChar;
2311 :
2312 0 : switch (nTypeArray[i])
2313 : {
2314 : case NF_SYMBOLTYPE_BLANK:
2315 : case NF_SYMBOLTYPE_STAR:
2316 0 : nPos = nPos + sStrArray[i].getLength();
2317 0 : i++;
2318 0 : break;
2319 : case NF_SYMBOLTYPE_DEL:
2320 0 : switch( sStrArray[i][0] )
2321 : {
2322 : case '0':
2323 0 : if ( Is100SecZero( i, bDecSep ) )
2324 : {
2325 0 : bDecSep = true;
2326 0 : nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2327 0 : OUString& rStr = sStrArray[i];
2328 0 : i++;
2329 0 : nPos = nPos + sStrArray[i].getLength();
2330 0 : nCounter++;
2331 0 : while (i < nAnzStrings &&
2332 0 : sStrArray[i][0] == '0')
2333 : {
2334 0 : rStr += sStrArray[i];
2335 0 : nPos = nPos + sStrArray[i].getLength();
2336 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2337 0 : nAnzResStrings--;
2338 0 : nCounter++;
2339 0 : i++;
2340 : }
2341 : }
2342 : else
2343 : {
2344 0 : return nPos;
2345 : }
2346 0 : break;
2347 : case '#':
2348 : case '?':
2349 0 : return nPos;
2350 : case '[':
2351 0 : if (bThousand) // Double
2352 : {
2353 0 : return nPos;
2354 : }
2355 0 : bThousand = true; // Empty for Time
2356 0 : cChar = pChrCls->uppercase(OUString(NextChar(i)))[0];
2357 0 : if ( cChar == cOldKeyH )
2358 : {
2359 0 : nThousand = 1; // H
2360 : }
2361 0 : else if ( cChar == cOldKeyMI )
2362 : {
2363 0 : nThousand = 2; // M
2364 : }
2365 0 : else if ( cChar == cOldKeyS )
2366 : {
2367 0 : nThousand = 3; // S
2368 : }
2369 : else
2370 : {
2371 0 : return nPos;
2372 : }
2373 0 : nPos = nPos + sStrArray[i].getLength();
2374 0 : i++;
2375 0 : break;
2376 : case ']':
2377 0 : if (!bThousand) // No preceding [
2378 : {
2379 0 : return nPos;
2380 : }
2381 0 : nPos = nPos + sStrArray[i].getLength();
2382 0 : i++;
2383 0 : break;
2384 : default:
2385 0 : nPos = nPos + sStrArray[i].getLength();
2386 0 : if ( sStrArray[i] == sOldTimeSep )
2387 : {
2388 0 : nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2389 0 : if ( bConvertMode )
2390 : {
2391 0 : sStrArray[i] = pLoc->getTimeSep();
2392 : }
2393 : }
2394 0 : else if ( sStrArray[i] == sOldTime100SecSep )
2395 : {
2396 0 : bDecSep = true;
2397 0 : nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2398 0 : if ( bConvertMode )
2399 : {
2400 0 : sStrArray[i] = pLoc->getTime100SecSep();
2401 : }
2402 : }
2403 : else
2404 : {
2405 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2406 : }
2407 0 : i++;
2408 0 : break;
2409 : }
2410 0 : break;
2411 : case NF_SYMBOLTYPE_STRING:
2412 0 : nPos = nPos + sStrArray[i].getLength();
2413 0 : i++;
2414 0 : break;
2415 : case NF_KEY_AMPM: // AM/PM
2416 : case NF_KEY_AP: // A/P
2417 0 : bExp = true; // Abuse for A/P
2418 0 : sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2419 0 : nPos = nPos + sStrArray[i].getLength();
2420 0 : i++;
2421 0 : break;
2422 : case NF_KEY_THAI_T :
2423 0 : bThaiT = true;
2424 : // fall thru
2425 : case NF_KEY_MI: // M
2426 : case NF_KEY_MMI: // MM
2427 : case NF_KEY_H: // H
2428 : case NF_KEY_HH: // HH
2429 : case NF_KEY_S: // S
2430 : case NF_KEY_SS: // SS
2431 0 : sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2432 0 : nPos = nPos + sStrArray[i].getLength();
2433 0 : i++;
2434 0 : break;
2435 : default: // Other keywords
2436 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2437 0 : nPos = nPos + sStrArray[i].getLength();
2438 0 : i++;
2439 0 : break;
2440 : }
2441 : } // of while
2442 0 : nCntPost = nCounter; // Zero counter
2443 0 : if (bExp)
2444 : {
2445 0 : nCntExp = 1; // Remembers AM/PM
2446 : }
2447 0 : break; // of NUMBERFORMAT_TIME
2448 : case NUMBERFORMAT_DATETIME:
2449 0 : while (i < nAnzStrings)
2450 : {
2451 : int nCalRet;
2452 0 : switch (nTypeArray[i])
2453 : {
2454 : case NF_SYMBOLTYPE_BLANK:
2455 : case NF_SYMBOLTYPE_STAR:
2456 : case NF_SYMBOLTYPE_STRING:
2457 0 : nPos = nPos + sStrArray[i].getLength();
2458 0 : i++;
2459 0 : break;
2460 : case NF_SYMBOLTYPE_DEL:
2461 0 : if ( (nCalRet = FinalScanGetCalendar( nPos, i, nAnzResStrings )) != 0 )
2462 : {
2463 0 : if ( nCalRet < 0 )
2464 : {
2465 0 : return nPos; // Error
2466 : }
2467 : }
2468 : else
2469 : {
2470 0 : switch( sStrArray[i][0] )
2471 : {
2472 : case '0':
2473 0 : if ( bTimePart && Is100SecZero( i, bDecSep ) )
2474 : {
2475 0 : bDecSep = true;
2476 0 : nTypeArray[i] = NF_SYMBOLTYPE_DIGIT;
2477 0 : OUString& rStr = sStrArray[i];
2478 0 : i++;
2479 0 : nPos = nPos + sStrArray[i].getLength();
2480 0 : nCounter++;
2481 0 : while (i < nAnzStrings &&
2482 0 : sStrArray[i][0] == '0')
2483 : {
2484 0 : rStr += sStrArray[i];
2485 0 : nPos = nPos + sStrArray[i].getLength();
2486 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2487 0 : nAnzResStrings--;
2488 0 : nCounter++;
2489 0 : i++;
2490 : }
2491 : }
2492 : else
2493 : {
2494 0 : return nPos;
2495 : }
2496 0 : break;
2497 : case '#':
2498 : case '?':
2499 0 : return nPos;
2500 : default:
2501 0 : nPos = nPos + sStrArray[i].getLength();
2502 0 : if (bTimePart)
2503 : {
2504 0 : if ( sStrArray[i] == sOldTimeSep )
2505 : {
2506 0 : nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP;
2507 0 : if ( bConvertMode )
2508 : {
2509 0 : sStrArray[i] = pLoc->getTimeSep();
2510 : }
2511 : }
2512 0 : else if ( sStrArray[i] == sOldTime100SecSep )
2513 : {
2514 0 : bDecSep = true;
2515 0 : nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP;
2516 0 : if ( bConvertMode )
2517 : {
2518 0 : sStrArray[i] = pLoc->getTime100SecSep();
2519 : }
2520 : }
2521 : else
2522 : {
2523 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2524 : }
2525 : }
2526 : else
2527 : {
2528 0 : if ( sStrArray[i] == sOldDateSep )
2529 : {
2530 0 : nTypeArray[i] = NF_SYMBOLTYPE_DATESEP;
2531 0 : if (bConvertMode)
2532 0 : sStrArray[i] = pFormatter->GetDateSep();
2533 : }
2534 : else
2535 : {
2536 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2537 : }
2538 : }
2539 0 : i++;
2540 0 : break;
2541 : }
2542 : }
2543 0 : break;
2544 : case NF_KEY_AMPM: // AM/PM
2545 : case NF_KEY_AP: // A/P
2546 0 : bTimePart = true;
2547 0 : bExp = true; // Abuse for A/P
2548 0 : sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2549 0 : nPos = nPos + sStrArray[i].getLength();
2550 0 : i++;
2551 0 : break;
2552 : case NF_KEY_MI: // M
2553 : case NF_KEY_MMI: // MM
2554 : case NF_KEY_H: // H
2555 : case NF_KEY_HH: // HH
2556 : case NF_KEY_S: // S
2557 : case NF_KEY_SS: // SS
2558 0 : bTimePart = true;
2559 0 : sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2560 0 : nPos = nPos + sStrArray[i].getLength();
2561 0 : i++;
2562 0 : break;
2563 : case NF_KEY_M: // M
2564 : case NF_KEY_MM: // MM
2565 : case NF_KEY_MMM: // MMM
2566 : case NF_KEY_MMMM: // MMMM
2567 : case NF_KEY_MMMMM: // MMMMM
2568 : case NF_KEY_Q: // Q
2569 : case NF_KEY_QQ: // QQ
2570 : case NF_KEY_D: // D
2571 : case NF_KEY_DD: // DD
2572 : case NF_KEY_DDD: // DDD
2573 : case NF_KEY_DDDD: // DDDD
2574 : case NF_KEY_YY: // YY
2575 : case NF_KEY_YYYY: // YYYY
2576 : case NF_KEY_NN: // NN
2577 : case NF_KEY_NNN: // NNN
2578 : case NF_KEY_NNNN: // NNNN
2579 : case NF_KEY_WW : // WW
2580 : case NF_KEY_AAA : // AAA
2581 : case NF_KEY_AAAA : // AAAA
2582 : case NF_KEY_EC : // E
2583 : case NF_KEY_EEC : // EE
2584 : case NF_KEY_G : // G
2585 : case NF_KEY_GG : // GG
2586 : case NF_KEY_GGG : // GGG
2587 : case NF_KEY_R : // R
2588 : case NF_KEY_RR : // RR
2589 0 : bTimePart = false;
2590 0 : sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT
2591 0 : nPos = nPos + sStrArray[i].getLength();
2592 0 : i++;
2593 0 : break;
2594 : case NF_KEY_THAI_T :
2595 0 : bThaiT = true;
2596 0 : sStrArray[i] = sKeyword[nTypeArray[i]];
2597 0 : nPos = nPos + sStrArray[i].getLength();
2598 0 : i++;
2599 0 : break;
2600 : default: // Other keywords
2601 0 : nTypeArray[i] = NF_SYMBOLTYPE_STRING;
2602 0 : nPos = nPos + sStrArray[i].getLength();
2603 0 : i++;
2604 0 : break;
2605 : }
2606 : } // of while
2607 0 : nCntPost = nCounter; // decimals (100th seconds)
2608 0 : if (bExp)
2609 : {
2610 0 : nCntExp = 1; // Remembers AM/PM
2611 : }
2612 0 : break; // of NUMBERFORMAT_DATETIME
2613 : default:
2614 0 : break;
2615 : }
2616 0 : if (eScannedType == NUMBERFORMAT_SCIENTIFIC &&
2617 0 : (nCntPre + nCntPost == 0 || nCntExp == 0))
2618 : {
2619 0 : return nPos;
2620 : }
2621 0 : else if (eScannedType == NUMBERFORMAT_FRACTION && (nCntExp > 8 || nCntExp == 0))
2622 : {
2623 0 : return nPos;
2624 : }
2625 0 : if (bThaiT && !GetNatNumModifier())
2626 : {
2627 0 : SetNatNumModifier(1);
2628 : }
2629 0 : if ( bConvertMode )
2630 : {
2631 : // strings containing keywords of the target locale must be quoted, so
2632 : // the user sees the difference and is able to edit the format string
2633 0 : for ( i=0; i < nAnzStrings; i++ )
2634 : {
2635 0 : if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING &&
2636 0 : sStrArray[i][0] != '\"' )
2637 : {
2638 0 : if ( bConvertSystemToSystem && eScannedType == NUMBERFORMAT_CURRENCY )
2639 : {
2640 : // don't stringize automatic currency, will be converted
2641 0 : if ( sStrArray[i] == sOldCurSymbol )
2642 : {
2643 0 : continue; // for
2644 : }
2645 : // DM might be splitted into D and M
2646 0 : if ( sStrArray[i].getLength() < sOldCurSymbol.getLength() &&
2647 0 : pChrCls->uppercase( sStrArray[i], 0, 1 )[0] ==
2648 0 : sOldCurString[0] )
2649 : {
2650 0 : OUString aTmp( sStrArray[i] );
2651 0 : sal_uInt16 j = i + 1;
2652 0 : while ( aTmp.getLength() < sOldCurSymbol.getLength() &&
2653 0 : j < nAnzStrings &&
2654 0 : nTypeArray[j] == NF_SYMBOLTYPE_STRING )
2655 : {
2656 0 : aTmp += sStrArray[j++];
2657 : }
2658 0 : if ( pChrCls->uppercase( aTmp ) == sOldCurString )
2659 : {
2660 0 : sStrArray[i++] = aTmp;
2661 0 : for ( ; i<j; i++ )
2662 : {
2663 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2664 0 : nAnzResStrings--;
2665 : }
2666 0 : i = j - 1;
2667 0 : continue; // for
2668 0 : }
2669 : }
2670 : }
2671 0 : OUString& rStr = sStrArray[i];
2672 0 : sal_Int32 nLen = rStr.getLength();
2673 0 : for ( sal_Int32 j = 0; j < nLen; j++ )
2674 : {
2675 0 : if ( (j == 0 || rStr[j - 1] != '\\') && GetKeyWord( rStr, j ) )
2676 : {
2677 0 : rStr = "\"" + rStr + "\"";
2678 0 : break; // for
2679 : }
2680 : }
2681 : }
2682 : }
2683 : }
2684 : // Concatenate strings, remove quotes for output, and rebuild the format string
2685 0 : rString = "";
2686 0 : i = 0;
2687 0 : while (i < nAnzStrings)
2688 : {
2689 : sal_Int32 nStringPos;
2690 0 : sal_Int32 nArrPos = 0;
2691 0 : sal_uInt16 iPos = i;
2692 0 : switch ( nTypeArray[i] )
2693 : {
2694 : case NF_SYMBOLTYPE_STRING :
2695 0 : nStringPos = rString.getLength();
2696 0 : do
2697 : {
2698 0 : if (sStrArray[i].getLength() == 2 &&
2699 0 : sStrArray[i][0] == '\\')
2700 : {
2701 : // Unescape some simple forms of symbols even in the UI
2702 : // visible string to prevent duplicates that differ
2703 : // only in notation, originating from import.
2704 : // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical,
2705 : // but 0\ 000 0 and 0 000 0 in a French locale are not.
2706 :
2707 0 : sal_Unicode c = sStrArray[i][1];
2708 :
2709 0 : switch (c)
2710 : {
2711 : case '+':
2712 : case '-':
2713 0 : rString += OUString(c);
2714 0 : break;
2715 : case ' ':
2716 : case '.':
2717 : case '/':
2718 0 : if (((eScannedType & NUMBERFORMAT_DATE) == 0) &&
2719 0 : (StringEqualsChar( pFormatter->GetNumThousandSep(), c) ||
2720 0 : StringEqualsChar( pFormatter->GetNumDecimalSep(), c) ||
2721 0 : (c == ' ' &&
2722 0 : (StringEqualsChar( pFormatter->GetNumThousandSep(), cNoBreakSpace) ||
2723 0 : StringEqualsChar( pFormatter->GetNumThousandSep(), cNarrowNoBreakSpace)))))
2724 : {
2725 0 : rString += sStrArray[i];
2726 : }
2727 0 : else if ((eScannedType & NUMBERFORMAT_DATE) &&
2728 0 : StringEqualsChar( pFormatter->GetDateSep(), c))
2729 : {
2730 0 : rString += sStrArray[i];
2731 : }
2732 0 : else if ((eScannedType & NUMBERFORMAT_TIME) &&
2733 0 : (StringEqualsChar( pLoc->getTimeSep(), c) ||
2734 0 : StringEqualsChar( pLoc->getTime100SecSep(), c)))
2735 : {
2736 0 : rString += sStrArray[i];
2737 : }
2738 0 : else if (eScannedType & NUMBERFORMAT_FRACTION)
2739 : {
2740 0 : rString += sStrArray[i];
2741 : }
2742 : else
2743 : {
2744 0 : rString += OUString(c);
2745 : }
2746 0 : break;
2747 : default:
2748 0 : rString += sStrArray[i];
2749 : }
2750 : }
2751 : else
2752 : {
2753 0 : rString += sStrArray[i];
2754 : }
2755 0 : if ( RemoveQuotes( sStrArray[i] ) > 0 )
2756 : {
2757 : // update currency up to quoted string
2758 0 : if ( eScannedType == NUMBERFORMAT_CURRENCY )
2759 : {
2760 : // dM -> DM or DM -> $ in old automatic
2761 : // currency formats, oh my ..., why did we ever introduce them?
2762 0 : OUString aTmp( pChrCls->uppercase( sStrArray[iPos], nArrPos,
2763 0 : sStrArray[iPos].getLength()-nArrPos ) );
2764 0 : sal_Int32 nCPos = aTmp.indexOf( sOldCurString );
2765 0 : if ( nCPos >= 0 )
2766 : {
2767 0 : const OUString& rCur = bConvertMode && bConvertSystemToSystem ?
2768 0 : GetCurSymbol() : sOldCurSymbol;
2769 0 : sStrArray[iPos] = sStrArray[iPos].replaceAt( nArrPos + nCPos,
2770 : sOldCurString.getLength(),
2771 0 : rCur );
2772 0 : rString = rString.replaceAt( nStringPos + nCPos,
2773 : sOldCurString.getLength(),
2774 0 : rCur );
2775 : }
2776 0 : nStringPos = rString.getLength();
2777 0 : if ( iPos == i )
2778 : {
2779 0 : nArrPos = sStrArray[iPos].getLength();
2780 : }
2781 : else
2782 : {
2783 0 : nArrPos = sStrArray[iPos].getLength() + sStrArray[i].getLength();
2784 0 : }
2785 : }
2786 : }
2787 0 : if ( iPos != i )
2788 : {
2789 0 : sStrArray[iPos] += sStrArray[i];
2790 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2791 0 : nAnzResStrings--;
2792 : }
2793 0 : i++;
2794 : }
2795 0 : while ( i < nAnzStrings && nTypeArray[i] == NF_SYMBOLTYPE_STRING );
2796 :
2797 0 : if ( i < nAnzStrings )
2798 : {
2799 0 : i--; // enter switch on next symbol again
2800 : }
2801 0 : if ( eScannedType == NUMBERFORMAT_CURRENCY && nStringPos < rString.getLength() )
2802 : {
2803 : // same as above, since last RemoveQuotes
2804 0 : OUString aTmp( pChrCls->uppercase( sStrArray[iPos], nArrPos,
2805 0 : sStrArray[iPos].getLength()-nArrPos ) );
2806 0 : sal_Int32 nCPos = aTmp.indexOf( sOldCurString );
2807 0 : if ( nCPos >= 0 )
2808 : {
2809 0 : const OUString& rCur = bConvertMode && bConvertSystemToSystem ?
2810 0 : GetCurSymbol() : sOldCurSymbol;
2811 0 : sStrArray[iPos] = sStrArray[iPos].replaceAt( nArrPos + nCPos,
2812 : sOldCurString.getLength(),
2813 0 : rCur );
2814 0 : rString = rString.replaceAt( nStringPos + nCPos,
2815 0 : sOldCurString.getLength(), rCur );
2816 0 : }
2817 : }
2818 0 : break;
2819 : case NF_SYMBOLTYPE_CURRENCY :
2820 0 : rString += sStrArray[i];
2821 0 : RemoveQuotes( sStrArray[i] );
2822 0 : break;
2823 : case NF_KEY_THAI_T:
2824 0 : if (bThaiT && GetNatNumModifier() == 1)
2825 : {
2826 : // Remove T from format code, will be replaced with a [NatNum1] prefix.
2827 0 : nTypeArray[i] = NF_SYMBOLTYPE_EMPTY;
2828 0 : nAnzResStrings--;
2829 : }
2830 : else
2831 : {
2832 0 : rString += sStrArray[i];
2833 : }
2834 0 : break;
2835 : case NF_SYMBOLTYPE_EMPTY :
2836 : // nothing
2837 0 : break;
2838 : default:
2839 0 : rString += sStrArray[i];
2840 : }
2841 0 : i++;
2842 : }
2843 0 : return 0;
2844 : }
2845 :
2846 0 : sal_Int32 ImpSvNumberformatScan::RemoveQuotes( OUString& rStr )
2847 : {
2848 0 : if ( rStr.getLength() > 1 )
2849 : {
2850 0 : sal_Unicode c = rStr[0];
2851 0 : sal_Int32 n = rStr.getLength() - 1;
2852 0 : if ( c == '"' && rStr[n] == '"' )
2853 : {
2854 0 : rStr = rStr.copy( 1, n-1);
2855 0 : return 2;
2856 : }
2857 0 : else if ( c == '\\' )
2858 : {
2859 0 : rStr = rStr.copy(1);
2860 0 : return 1;
2861 : }
2862 : }
2863 0 : return 0;
2864 : }
2865 :
2866 0 : sal_Int32 ImpSvNumberformatScan::ScanFormat( OUString& rString )
2867 : {
2868 0 : sal_Int32 res = Symbol_Division(rString); // Lexical analysis
2869 0 : if (!res)
2870 : {
2871 0 : res = ScanType(); // Recognizing the Format type
2872 : }
2873 0 : if (!res)
2874 : {
2875 0 : res = FinalScan( rString ); // Type dependent final analysis
2876 : }
2877 0 : return res; // res = control position; res = 0 => Format ok
2878 : }
2879 :
2880 0 : void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, sal_uInt16 nAnz)
2881 : {
2882 : size_t i,j;
2883 0 : j = 0;
2884 0 : i = 0;
2885 0 : while (i < nAnz && j < NF_MAX_FORMAT_SYMBOLS)
2886 : {
2887 0 : if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY)
2888 : {
2889 0 : pInfo->sStrArray[i] = sStrArray[j];
2890 0 : pInfo->nTypeArray[i] = nTypeArray[j];
2891 0 : i++;
2892 : }
2893 0 : j++;
2894 : }
2895 0 : pInfo->eScannedType = eScannedType;
2896 0 : pInfo->bThousand = bThousand;
2897 0 : pInfo->nThousand = nThousand;
2898 0 : pInfo->nCntPre = nCntPre;
2899 0 : pInfo->nCntPost = nCntPost;
2900 0 : pInfo->nCntExp = nCntExp;
2901 0 : }
2902 :
2903 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|