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 : #include <stdio.h>
21 : #include <ctype.h>
22 : #include <float.h>
23 : #include <errno.h>
24 : #include <stdlib.h>
25 : #include <comphelper/string.hxx>
26 : #include <sal/log.hxx>
27 : #include <tools/debug.hxx>
28 : #include <osl/diagnose.h>
29 : #include <i18nlangtag/mslangid.hxx>
30 : #include <rtl/math.hxx>
31 : #include <unotools/charclass.hxx>
32 : #include <unotools/calendarwrapper.hxx>
33 : #include <unotools/nativenumberwrapper.hxx>
34 : #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
35 : #include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
36 : #include <com/sun/star/i18n/CalendarDisplayCode.hpp>
37 : #include <com/sun/star/i18n/AmPmValue.hpp>
38 :
39 : #include <svl/zformat.hxx>
40 : #include "zforscan.hxx"
41 :
42 : #include "zforfind.hxx"
43 : #include <svl/zforlist.hxx>
44 : #include <unotools/digitgroupingiterator.hxx>
45 : #include <svl/nfsymbol.hxx>
46 :
47 : #include <cmath>
48 : #include <boost/scoped_ptr.hpp>
49 :
50 : using namespace svt;
51 :
52 : namespace {
53 :
54 : char const GREGORIAN[] = "gregorian";
55 :
56 : const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary...
57 : const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value.
58 :
59 : } // namespace
60 :
61 : const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0
62 : const sal_uInt16 _MAX_FRACTION_PREC = 3;
63 : const double D_EPS = 1.0E-2;
64 :
65 : const double _D_MAX_D_BY_100 = 1.7E306;
66 : const double _D_MIN_M_BY_1000 = 2.3E-305;
67 :
68 : static const sal_uInt8 cCharWidths[ 128-32 ] = {
69 : 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1,
70 : 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2,
71 : 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3,
72 : 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2,
73 : 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2,
74 : 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1
75 : };
76 :
77 : // static
78 123 : sal_Int32 SvNumberformat::InsertBlanks( OUStringBuffer& r, sal_Int32 nPos, sal_Unicode c )
79 : {
80 123 : if( c >= 32 )
81 : {
82 123 : int n = 2; // Default for chars > 128 (HACK!)
83 123 : if( c <= 127 )
84 : {
85 123 : n = (int)cCharWidths[ c - 32 ];
86 : }
87 369 : while( n-- )
88 : {
89 123 : r.insert( nPos++, ' ');
90 : }
91 : }
92 123 : return nPos;
93 : }
94 :
95 4173 : static long GetPrecExp( double fAbsVal )
96 : {
97 : DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" );
98 4173 : if ( fAbsVal < 1e-7 || fAbsVal > 1e7 )
99 : {
100 : // Shear: whether it's faster or not, falls in between 1e6 and 1e7
101 4 : return (long) floor( log10( fAbsVal ) ) + 1;
102 : }
103 : else
104 : {
105 4169 : long nPrecExp = 1;
106 8616 : while( fAbsVal < 1 )
107 : {
108 278 : fAbsVal *= 10;
109 278 : nPrecExp--;
110 : }
111 13709 : while( fAbsVal >= 10 )
112 : {
113 5371 : fAbsVal /= 10;
114 5371 : nPrecExp++;
115 : }
116 4169 : return nPrecExp;
117 : }
118 : }
119 :
120 : /**
121 : * SvNumberformatInfo
122 : * */
123 :
124 19512 : void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz )
125 : {
126 77490 : for (sal_uInt16 i = 0; i < nAnz; ++i)
127 : {
128 57978 : sStrArray[i] = rNumFor.sStrArray[i];
129 57978 : nTypeArray[i] = rNumFor.nTypeArray[i];
130 : }
131 19512 : eScannedType = rNumFor.eScannedType;
132 19512 : bThousand = rNumFor.bThousand;
133 19512 : nThousand = rNumFor.nThousand;
134 19512 : nCntPre = rNumFor.nCntPre;
135 19512 : nCntPost = rNumFor.nCntPost;
136 19512 : nCntExp = rNumFor.nCntExp;
137 19512 : }
138 :
139 : // static
140 0 : sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, bool bDate )
141 : {
142 0 : sal_uInt8 nNatNum = 0;
143 0 : eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
144 0 : eLang &= 0x03FF; // 10 bit primary language
145 0 : if ( bDate )
146 : {
147 0 : if ( nDBNum == 4 && eLang == (LANGUAGE_KOREAN & 0x03FF) )
148 : {
149 0 : nNatNum = 9;
150 : }
151 0 : else if ( nDBNum <= 3 )
152 : {
153 0 : nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3
154 : }
155 : }
156 : else
157 : {
158 0 : switch ( nDBNum )
159 : {
160 : case 1:
161 0 : switch ( eLang )
162 : {
163 : case (LANGUAGE_CHINESE & 0x03FF):
164 0 : nNatNum = 4;
165 0 : break;
166 : case (LANGUAGE_JAPANESE & 0x03FF):
167 0 : nNatNum = 1;
168 0 : break;
169 : case (LANGUAGE_KOREAN & 0x03FF):
170 0 : nNatNum = 1;
171 0 : break;
172 : }
173 0 : break;
174 : case 2:
175 0 : switch ( eLang )
176 : {
177 : case (LANGUAGE_CHINESE & 0x03FF):
178 0 : nNatNum = 5;
179 0 : break;
180 : case (LANGUAGE_JAPANESE & 0x03FF):
181 0 : nNatNum = 4;
182 0 : break;
183 : case (LANGUAGE_KOREAN & 0x03FF):
184 0 : nNatNum = 2;
185 0 : break;
186 : }
187 0 : break;
188 : case 3:
189 0 : switch ( eLang )
190 : {
191 : case (LANGUAGE_CHINESE & 0x03FF):
192 0 : nNatNum = 6;
193 0 : break;
194 : case (LANGUAGE_JAPANESE & 0x03FF):
195 0 : nNatNum = 5;
196 0 : break;
197 : case (LANGUAGE_KOREAN & 0x03FF):
198 0 : nNatNum = 3;
199 0 : break;
200 : }
201 0 : break;
202 : case 4:
203 0 : switch ( eLang )
204 : {
205 : case (LANGUAGE_JAPANESE & 0x03FF):
206 0 : nNatNum = 7;
207 0 : break;
208 : case (LANGUAGE_KOREAN & 0x03FF):
209 0 : nNatNum = 9;
210 0 : break;
211 : }
212 0 : break;
213 : }
214 : }
215 0 : return nNatNum;
216 : }
217 :
218 : #ifdef THE_FUTURE
219 : /* XXX NOTE: even though the MapNatNumToDBNum method is currently unused please
220 : * don't remove it in case we'd have to use it for some obscure exports to
221 : * Excel. */
222 :
223 : // static
224 : sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, bool bDate )
225 : {
226 : sal_uInt8 nDBNum = 0;
227 : eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc.
228 : eLang &= 0x03FF; // 10 bit primary language
229 : if ( bDate )
230 : {
231 : if ( nNatNum == 9 && eLang == (LANGUAGE_KOREAN & 0x03FF) )
232 : {
233 : nDBNum = 4;
234 : }
235 : else if ( nNatNum <= 3 )
236 : {
237 : nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3
238 : }
239 : }
240 : else
241 : {
242 : switch ( nNatNum )
243 : {
244 : case 1:
245 : switch ( eLang )
246 : {
247 : case (LANGUAGE_JAPANESE & 0x03FF):
248 : nDBNum = 1;
249 : break;
250 : case (LANGUAGE_KOREAN & 0x03FF):
251 : nDBNum = 1;
252 : break;
253 : }
254 : break;
255 : case 2:
256 : switch ( eLang )
257 : {
258 : case (LANGUAGE_KOREAN & 0x03FF):
259 : nDBNum = 2;
260 : break;
261 : }
262 : break;
263 : case 3:
264 : switch ( eLang )
265 : {
266 : case (LANGUAGE_KOREAN & 0x03FF):
267 : nDBNum = 3;
268 : break;
269 : }
270 : break;
271 : case 4:
272 : switch ( eLang )
273 : {
274 : case (LANGUAGE_CHINESE & 0x03FF):
275 : nDBNum = 1;
276 : break;
277 : case (LANGUAGE_JAPANESE & 0x03FF):
278 : nDBNum = 2;
279 : break;
280 : }
281 : break;
282 : case 5:
283 : switch ( eLang )
284 : {
285 : case (LANGUAGE_CHINESE & 0x03FF):
286 : nDBNum = 2;
287 : break;
288 : case (LANGUAGE_JAPANESE & 0x03FF):
289 : nDBNum = 3;
290 : break;
291 : }
292 : break;
293 : case 6:
294 : switch ( eLang )
295 : {
296 : case (LANGUAGE_CHINESE & 0x03FF):
297 : nDBNum = 3;
298 : break;
299 : }
300 : break;
301 : case 7:
302 : switch ( eLang )
303 : {
304 : case (LANGUAGE_JAPANESE & 0x03FF):
305 : nDBNum = 4;
306 : break;
307 : }
308 : break;
309 : case 8:
310 : break;
311 : case 9:
312 : switch ( eLang )
313 : {
314 : case (LANGUAGE_KOREAN & 0x03FF):
315 : nDBNum = 4;
316 : break;
317 : }
318 : break;
319 : case 10:
320 : break;
321 : case 11:
322 : break;
323 : }
324 : }
325 : return nDBNum;
326 : }
327 : #endif
328 :
329 : /**
330 : * SvNumFor
331 : */
332 :
333 1465676 : ImpSvNumFor::ImpSvNumFor()
334 : {
335 1465676 : nAnzStrings = 0;
336 1465676 : aI.nTypeArray = NULL;
337 1465676 : aI.sStrArray = NULL;
338 1465676 : aI.eScannedType = css::util::NumberFormat::UNDEFINED;
339 1465676 : aI.bThousand = false;
340 1465676 : aI.nThousand = 0;
341 1465676 : aI.nCntPre = 0;
342 1465676 : aI.nCntPost = 0;
343 1465676 : aI.nCntExp = 0;
344 1465676 : pColor = NULL;
345 1465676 : }
346 :
347 2893688 : ImpSvNumFor::~ImpSvNumFor()
348 : {
349 1446844 : delete [] aI.sStrArray;
350 1446844 : delete [] aI.nTypeArray;
351 1446844 : }
352 :
353 454583 : void ImpSvNumFor::Enlarge(sal_uInt16 nAnz)
354 : {
355 454583 : if ( nAnzStrings != nAnz )
356 : {
357 442328 : delete [] aI.nTypeArray;
358 442328 : delete [] aI.sStrArray;
359 442328 : nAnzStrings = nAnz;
360 442328 : if ( nAnz )
361 : {
362 442328 : aI.nTypeArray = new short[nAnz];
363 442328 : aI.sStrArray = new OUString[nAnz];
364 : }
365 : else
366 : {
367 0 : aI.nTypeArray = NULL;
368 0 : aI.sStrArray = NULL;
369 : }
370 : }
371 454583 : }
372 :
373 19512 : void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc )
374 : {
375 19512 : Enlarge( rNumFor.nAnzStrings );
376 19512 : aI.Copy( rNumFor.aI, nAnzStrings );
377 19512 : sColorName = rNumFor.sColorName;
378 19512 : if ( pSc )
379 : {
380 19512 : pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents
381 : }
382 : else
383 : {
384 0 : pColor = rNumFor.pColor;
385 : }
386 19512 : aNatNum = rNumFor.aNatNum;
387 19512 : }
388 :
389 0 : bool ImpSvNumFor::HasNewCurrency() const
390 : {
391 0 : for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
392 : {
393 0 : if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
394 : {
395 0 : return true;
396 : }
397 : }
398 0 : return false;
399 : }
400 :
401 8260 : bool ImpSvNumFor::GetNewCurrencySymbol( OUString& rSymbol,
402 : OUString& rExtension ) const
403 : {
404 10512 : for ( sal_uInt16 j=0; j<nAnzStrings; j++ )
405 : {
406 2344 : if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY )
407 : {
408 92 : rSymbol = aI.sStrArray[j];
409 92 : if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT )
410 : {
411 52 : rExtension = aI.sStrArray[j+1];
412 : }
413 : else
414 : {
415 40 : rExtension.clear();
416 : }
417 92 : return true;
418 : }
419 : }
420 : //! No Erase at rSymbol, rExtension
421 8168 : return false;
422 : }
423 :
424 : /**
425 : * SvNumberformat
426 : */
427 :
428 : enum BracketFormatSymbolType
429 : {
430 : BRACKET_SYMBOLTYPE_FORMAT = -1, // subformat string
431 : BRACKET_SYMBOLTYPE_COLOR = -2, // color
432 : BRACKET_SYMBOLTYPE_ERROR = -3, // error
433 : BRACKET_SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers
434 : BRACKET_SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible
435 : BRACKET_SYMBOLTYPE_DBNUM3 = -6,
436 : BRACKET_SYMBOLTYPE_DBNUM4 = -7,
437 : BRACKET_SYMBOLTYPE_DBNUM5 = -8,
438 : BRACKET_SYMBOLTYPE_DBNUM6 = -9,
439 : BRACKET_SYMBOLTYPE_DBNUM7 = -10,
440 : BRACKET_SYMBOLTYPE_DBNUM8 = -11,
441 : BRACKET_SYMBOLTYPE_DBNUM9 = -12,
442 : BRACKET_SYMBOLTYPE_LOCALE = -13,
443 : BRACKET_SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII
444 : BRACKET_SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent
445 : BRACKET_SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ...
446 : BRACKET_SYMBOLTYPE_NATNUM3 = -17,
447 : BRACKET_SYMBOLTYPE_NATNUM4 = -18,
448 : BRACKET_SYMBOLTYPE_NATNUM5 = -19,
449 : BRACKET_SYMBOLTYPE_NATNUM6 = -20,
450 : BRACKET_SYMBOLTYPE_NATNUM7 = -21,
451 : BRACKET_SYMBOLTYPE_NATNUM8 = -22,
452 : BRACKET_SYMBOLTYPE_NATNUM9 = -23,
453 : BRACKET_SYMBOLTYPE_NATNUM10 = -24,
454 : BRACKET_SYMBOLTYPE_NATNUM11 = -25,
455 : BRACKET_SYMBOLTYPE_NATNUM12 = -26,
456 : BRACKET_SYMBOLTYPE_NATNUM13 = -27,
457 : BRACKET_SYMBOLTYPE_NATNUM14 = -28,
458 : BRACKET_SYMBOLTYPE_NATNUM15 = -29,
459 : BRACKET_SYMBOLTYPE_NATNUM16 = -30,
460 : BRACKET_SYMBOLTYPE_NATNUM17 = -31,
461 : BRACKET_SYMBOLTYPE_NATNUM18 = -32,
462 : BRACKET_SYMBOLTYPE_NATNUM19 = -33
463 : };
464 :
465 4878 : void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat )
466 : {
467 4878 : sFormatstring = rFormat.sFormatstring;
468 4878 : eType = rFormat.eType;
469 4878 : maLocale = rFormat.maLocale;
470 4878 : fLimit1 = rFormat.fLimit1;
471 4878 : fLimit2 = rFormat.fLimit2;
472 4878 : eOp1 = rFormat.eOp1;
473 4878 : eOp2 = rFormat.eOp2;
474 4878 : bStandard = rFormat.bStandard;
475 4878 : bIsUsed = rFormat.bIsUsed;
476 4878 : sComment = rFormat.sComment;
477 4878 : bAdditionalBuiltin = rFormat.bAdditionalBuiltin;
478 :
479 : // #121103# when copying between documents, get color pointers from own scanner
480 4878 : ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL;
481 :
482 24390 : for (sal_uInt16 i = 0; i < 4; i++)
483 : {
484 19512 : NumFor[i].Copy(rFormat.NumFor[i], pColorSc);
485 : }
486 4878 : }
487 :
488 0 : SvNumberformat::SvNumberformat( SvNumberformat& rFormat )
489 0 : : rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag )
490 : {
491 0 : ImpCopyNumberformat( rFormat );
492 0 : }
493 :
494 4878 : SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc )
495 : : rScan(rSc)
496 4878 : , bStarFlag( rFormat.bStarFlag )
497 : {
498 4878 : ImpCopyNumberformat( rFormat );
499 4878 : }
500 :
501 931915 : static bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType )
502 : {
503 931915 : if ( nSymbolType > 0 )
504 : {
505 192 : return true; // conditions
506 : }
507 931723 : switch ( nSymbolType )
508 : {
509 : case BRACKET_SYMBOLTYPE_COLOR :
510 : case BRACKET_SYMBOLTYPE_DBNUM1 :
511 : case BRACKET_SYMBOLTYPE_DBNUM2 :
512 : case BRACKET_SYMBOLTYPE_DBNUM3 :
513 : case BRACKET_SYMBOLTYPE_DBNUM4 :
514 : case BRACKET_SYMBOLTYPE_DBNUM5 :
515 : case BRACKET_SYMBOLTYPE_DBNUM6 :
516 : case BRACKET_SYMBOLTYPE_DBNUM7 :
517 : case BRACKET_SYMBOLTYPE_DBNUM8 :
518 : case BRACKET_SYMBOLTYPE_DBNUM9 :
519 : case BRACKET_SYMBOLTYPE_LOCALE :
520 : case BRACKET_SYMBOLTYPE_NATNUM0 :
521 : case BRACKET_SYMBOLTYPE_NATNUM1 :
522 : case BRACKET_SYMBOLTYPE_NATNUM2 :
523 : case BRACKET_SYMBOLTYPE_NATNUM3 :
524 : case BRACKET_SYMBOLTYPE_NATNUM4 :
525 : case BRACKET_SYMBOLTYPE_NATNUM5 :
526 : case BRACKET_SYMBOLTYPE_NATNUM6 :
527 : case BRACKET_SYMBOLTYPE_NATNUM7 :
528 : case BRACKET_SYMBOLTYPE_NATNUM8 :
529 : case BRACKET_SYMBOLTYPE_NATNUM9 :
530 : case BRACKET_SYMBOLTYPE_NATNUM10 :
531 : case BRACKET_SYMBOLTYPE_NATNUM11 :
532 : case BRACKET_SYMBOLTYPE_NATNUM12 :
533 : case BRACKET_SYMBOLTYPE_NATNUM13 :
534 : case BRACKET_SYMBOLTYPE_NATNUM14 :
535 : case BRACKET_SYMBOLTYPE_NATNUM15 :
536 : case BRACKET_SYMBOLTYPE_NATNUM16 :
537 : case BRACKET_SYMBOLTYPE_NATNUM17 :
538 : case BRACKET_SYMBOLTYPE_NATNUM18 :
539 : case BRACKET_SYMBOLTYPE_NATNUM19 :
540 61571 : return true;
541 : }
542 870152 : return false;
543 : }
544 :
545 :
546 2 : OUString SvNumberformat::ImpObtainCalendarAndNumerals( OUStringBuffer & rString, sal_Int32 & nPos,
547 : LanguageType & nLang, const LocaleType & aTmpLocale )
548 : {
549 2 : OUString sCalendar;
550 : /* TODO: this could be enhanced to allow other possible locale dependent
551 : * calendars and numerals. BUT only if our locale data allows it! For LCID
552 : * numerals and calendars see
553 : * http://office.microsoft.com/en-us/excel/HA010346351033.aspx */
554 2 : if (MsLangId::getRealLanguage( aTmpLocale.meLanguage) == LANGUAGE_THAI)
555 : {
556 : // Numeral shape code "D" = Thai digits.
557 1 : if (aTmpLocale.mnNumeralShape == 0xD)
558 : {
559 0 : rString.insert( nPos, "[NatNum1]");
560 : }
561 : // Calendar type code "07" = Thai Buddhist calendar, insert this after
562 : // all prefixes have been consumed as it is actually a format modifier
563 : // and not a prefix.
564 1 : if (aTmpLocale.mnCalendarType == 0x07)
565 : {
566 : // Currently calendars are tied to the locale of the entire number
567 : // format, e.g. [~buddhist] in en_US doesn't work.
568 : // => Having different locales in sub formats does not work!
569 : /* TODO: calendars could be tied to a sub format's NatNum info
570 : * instead, or even better be available for any locale. Needs a
571 : * different implementation of GetCal() and locale data calendars.
572 : * */
573 : // If this is not Thai yet, make it so.
574 1 : if (MsLangId::getRealLanguage( maLocale.meLanguage) != LANGUAGE_THAI)
575 : {
576 0 : maLocale = aTmpLocale;
577 0 : nLang = maLocale.meLanguage = LANGUAGE_THAI;
578 : }
579 1 : sCalendar="[~buddhist]";
580 : }
581 : }
582 2 : return sCalendar;
583 : }
584 :
585 :
586 361541 : SvNumberformat::SvNumberformat(OUString& rString,
587 : ImpSvNumberformatScan* pSc,
588 : ImpSvNumberInputScan* pISc,
589 : sal_Int32& nCheckPos,
590 : LanguageType& eLan,
591 : bool bStan)
592 : : rScan(*pSc)
593 : , bAdditionalBuiltin( false )
594 361541 : , bStarFlag( false )
595 : {
596 361541 : OUStringBuffer sBuff(rString);
597 :
598 : // If the group (AKA thousand) separator is a No-Break Space (French)
599 : // replace all occurrences by a simple space.
600 : // The same for Narrow No-Break Space just in case some locale uses it.
601 : // The tokens will be changed to the LocaleData separator again later on.
602 361541 : const OUString& rThSep = GetFormatter().GetNumThousandSep();
603 361541 : if ( rThSep.getLength() == 1)
604 : {
605 361541 : const sal_Unicode cNBSp = 0xA0;
606 361541 : const sal_Unicode cNNBSp = 0x202F;
607 361541 : if (rThSep[0] == cNBSp )
608 3483 : sBuff.replace( cNBSp, ' ');
609 358058 : else if (rThSep[0] == cNNBSp )
610 0 : sBuff.replace( cNNBSp, ' ');
611 : }
612 :
613 361541 : if (rScan.GetConvertMode())
614 : {
615 14703 : maLocale.meLanguage = rScan.GetNewLnge();
616 14703 : eLan = maLocale.meLanguage; // Make sure to return switch
617 : }
618 : else
619 : {
620 346838 : maLocale.meLanguage = eLan;
621 : }
622 361541 : bStandard = bStan;
623 361541 : bIsUsed = false;
624 361541 : fLimit1 = 0.0;
625 361541 : fLimit2 = 0.0;
626 361541 : eOp1 = NUMBERFORMAT_OP_NO;
627 361541 : eOp2 = NUMBERFORMAT_OP_NO;
628 361541 : eType = css::util::NumberFormat::DEFINED;
629 :
630 361541 : bool bCancel = false;
631 361541 : bool bCondition = false;
632 : short eSymbolType;
633 361541 : sal_Int32 nPos = 0;
634 : sal_Int32 nPosOld;
635 361541 : nCheckPos = 0;
636 :
637 : // Split into 4 sub formats
638 : sal_uInt16 nIndex;
639 796618 : for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ )
640 : {
641 : // Original language/country may have to be reestablished
642 435077 : if (rScan.GetConvertMode())
643 : {
644 20426 : (rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge());
645 : }
646 435077 : OUString sInsertCalendar; // a calendar resulting from parsing LCID
647 870154 : OUString sStr;
648 435077 : nPosOld = nPos; // Start position of substring
649 : // first get bracketed prefixes; e.g. conditions, color
650 466054 : do
651 : {
652 466054 : eSymbolType = ImpNextSymbol(sBuff, nPos, sStr);
653 466054 : if (eSymbolType > 0) // condition
654 : {
655 192 : if ( nIndex == 0 && !bCondition )
656 : {
657 99 : bCondition = true;
658 99 : eOp1 = (SvNumberformatLimitOps) eSymbolType;
659 : }
660 93 : else if ( nIndex == 1 && bCondition )
661 : {
662 93 : eOp2 = (SvNumberformatLimitOps) eSymbolType;
663 : }
664 : else // error
665 : {
666 0 : bCancel = true; // break for
667 0 : nCheckPos = nPosOld;
668 : }
669 192 : if (!bCancel)
670 : {
671 : double fNumber;
672 192 : sal_Int32 nAnzChars = ImpGetNumber(sBuff, nPos, sStr);
673 192 : if (nAnzChars > 0)
674 : {
675 192 : short F_Type = css::util::NumberFormat::UNDEFINED;
676 384 : if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) ||
677 192 : ( F_Type != css::util::NumberFormat::NUMBER &&
678 0 : F_Type != css::util::NumberFormat::SCIENTIFIC) )
679 : {
680 0 : fNumber = 0.0;
681 0 : nPos = nPos - nAnzChars;
682 0 : sBuff.remove(nPos, nAnzChars);
683 0 : sBuff.insert(nPos, '0');
684 0 : nPos++;
685 : }
686 : }
687 : else
688 : {
689 0 : fNumber = 0.0;
690 0 : sBuff.insert(nPos++, '0');
691 : }
692 192 : if (nIndex == 0)
693 : {
694 99 : fLimit1 = fNumber;
695 : }
696 : else
697 : {
698 93 : fLimit2 = fNumber;
699 : }
700 192 : if ( sBuff[nPos] == ']' )
701 : {
702 192 : nPos++;
703 : }
704 : else
705 : {
706 0 : bCancel = true; // break for
707 0 : nCheckPos = nPos;
708 : }
709 : }
710 192 : nPosOld = nPos; // position before string
711 : }
712 465862 : else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
713 : {
714 30786 : OUString sSymbol( sStr);
715 30786 : switch ( eSymbolType )
716 : {
717 : case BRACKET_SYMBOLTYPE_COLOR :
718 30667 : if ( NumFor[nIndex].GetColor() != NULL )
719 : { // error, more than one color
720 0 : bCancel = true; // break for
721 0 : nCheckPos = nPosOld;
722 : }
723 : else
724 : {
725 30667 : Color* pColor = pSc->GetColor( sStr);
726 30667 : NumFor[nIndex].SetColor( pColor, sStr);
727 30667 : if (pColor == NULL)
728 : { // error
729 1 : bCancel = true; // break for
730 1 : nCheckPos = nPosOld;
731 : }
732 : }
733 30667 : break;
734 : case BRACKET_SYMBOLTYPE_NATNUM0 :
735 : case BRACKET_SYMBOLTYPE_NATNUM1 :
736 : case BRACKET_SYMBOLTYPE_NATNUM2 :
737 : case BRACKET_SYMBOLTYPE_NATNUM3 :
738 : case BRACKET_SYMBOLTYPE_NATNUM4 :
739 : case BRACKET_SYMBOLTYPE_NATNUM5 :
740 : case BRACKET_SYMBOLTYPE_NATNUM6 :
741 : case BRACKET_SYMBOLTYPE_NATNUM7 :
742 : case BRACKET_SYMBOLTYPE_NATNUM8 :
743 : case BRACKET_SYMBOLTYPE_NATNUM9 :
744 : case BRACKET_SYMBOLTYPE_NATNUM10 :
745 : case BRACKET_SYMBOLTYPE_NATNUM11 :
746 : case BRACKET_SYMBOLTYPE_NATNUM12 :
747 : case BRACKET_SYMBOLTYPE_NATNUM13 :
748 : case BRACKET_SYMBOLTYPE_NATNUM14 :
749 : case BRACKET_SYMBOLTYPE_NATNUM15 :
750 : case BRACKET_SYMBOLTYPE_NATNUM16 :
751 : case BRACKET_SYMBOLTYPE_NATNUM17 :
752 : case BRACKET_SYMBOLTYPE_NATNUM18 :
753 : case BRACKET_SYMBOLTYPE_NATNUM19 :
754 105 : if ( NumFor[nIndex].GetNatNum().IsSet() )
755 : {
756 0 : bCancel = true; // break for
757 0 : nCheckPos = nPosOld;
758 : }
759 : else
760 : {
761 105 : sStr = "NatNum";
762 : //! eSymbolType is negative
763 105 : sal_uInt8 nNum = (sal_uInt8)(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0));
764 105 : sStr += OUString::number( nNum );
765 105 : NumFor[nIndex].SetNatNumNum( nNum, false );
766 : }
767 105 : break;
768 : case BRACKET_SYMBOLTYPE_DBNUM1 :
769 : case BRACKET_SYMBOLTYPE_DBNUM2 :
770 : case BRACKET_SYMBOLTYPE_DBNUM3 :
771 : case BRACKET_SYMBOLTYPE_DBNUM4 :
772 : case BRACKET_SYMBOLTYPE_DBNUM5 :
773 : case BRACKET_SYMBOLTYPE_DBNUM6 :
774 : case BRACKET_SYMBOLTYPE_DBNUM7 :
775 : case BRACKET_SYMBOLTYPE_DBNUM8 :
776 : case BRACKET_SYMBOLTYPE_DBNUM9 :
777 0 : if ( NumFor[nIndex].GetNatNum().IsSet() )
778 : {
779 0 : bCancel = true; // break for
780 0 : nCheckPos = nPosOld;
781 : }
782 : else
783 : {
784 0 : sStr = "DBNum";
785 : //! eSymbolType is negative
786 0 : sal_uInt8 nNum = (sal_uInt8)(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1));
787 0 : sStr += OUString((sal_Unicode)('0' + nNum));
788 0 : NumFor[nIndex].SetNatNumNum( nNum, true );
789 : }
790 0 : break;
791 : case BRACKET_SYMBOLTYPE_LOCALE :
792 28 : if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW ||
793 14 : sBuff[nPos-1] != ']' )
794 : // Check also for ']' to avoid pulling in
795 : // locale data for the preview string for not
796 : // yet completed LCIDs in the dialog.
797 : {
798 0 : bCancel = true; // break for
799 0 : nCheckPos = nPosOld;
800 : }
801 : else
802 : {
803 14 : sal_Int32 nTmp = 2;
804 14 : LocaleType aTmpLocale( ImpGetLocaleType( sStr, nTmp));
805 14 : if (aTmpLocale.meLanguage == LANGUAGE_DONTKNOW)
806 : {
807 0 : bCancel = true; // break for
808 0 : nCheckPos = nPosOld;
809 : }
810 : else
811 : {
812 : // Only the first sub format's locale will be
813 : // used as the format's overall locale.
814 : // Sorts this also under the corresponding
815 : // locale for the dialog.
816 : // If we don't support the locale this would
817 : // result in an unknown (empty) language
818 : // listbox entry and the user would never see
819 : // this format.
820 27 : if (nIndex == 0 && (aTmpLocale.meLanguage == 0 ||
821 13 : SvNumberFormatter::IsLocaleInstalled( aTmpLocale.meLanguage)))
822 : {
823 10 : maLocale = aTmpLocale;
824 10 : eLan = aTmpLocale.meLanguage; // return to caller
825 : /* TODO: fiddle with scanner to make this
826 : * known? A change in the locale may affect
827 : * separators and keywords. On the other
828 : * hand they may have been entered as used
829 : * in the originating locale, there's no
830 : * way to predict other than analyzing the
831 : * format code, we assume here the current
832 : * context is used, which is most likely
833 : * the case.
834 : * */
835 : }
836 14 : sStr = "$-" + aTmpLocale.generateCode();
837 14 : NumFor[nIndex].SetNatNumLang( MsLangId::getRealLanguage( aTmpLocale.meLanguage));
838 :
839 : // "$-NNCCLLLL" Numerals and Calendar
840 14 : if (sSymbol.getLength() > 6)
841 : {
842 2 : sInsertCalendar = ImpObtainCalendarAndNumerals( sBuff, nPos, eLan, aTmpLocale);
843 : }
844 : /* NOTE: there can be only one calendar
845 : * inserted so the last one wins, though
846 : * our own calendar modifiers support
847 : * multiple calendars within one sub format
848 : * code if at different positions. */
849 : }
850 : }
851 14 : break;
852 : }
853 30786 : if ( !bCancel )
854 : {
855 30785 : if (sStr == sSymbol)
856 : {
857 30566 : nPosOld = nPos;
858 : }
859 : else
860 : {
861 219 : sBuff.remove(nPosOld, nPos - nPosOld);
862 219 : if (!sStr.isEmpty())
863 : {
864 219 : sBuff.insert(nPosOld, sStr);
865 219 : nPos = nPosOld + sStr.getLength();
866 219 : sBuff.insert(nPos, "]");
867 219 : sBuff.insert(nPosOld, "[");
868 219 : nPos += 2;
869 219 : nPosOld = nPos; // position before string
870 : }
871 : else
872 : {
873 0 : nPos = nPosOld; // prefix removed for whatever reason
874 : }
875 : }
876 30786 : }
877 : }
878 : }
879 466054 : while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) );
880 :
881 : // The remaining format code string
882 435077 : if ( !bCancel )
883 : {
884 435076 : if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT)
885 : {
886 435076 : if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO)
887 : {
888 71370 : eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0
889 : }
890 363706 : else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO)
891 : {
892 967 : eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0
893 : }
894 435076 : if (sStr.isEmpty())
895 : {
896 : // empty sub format
897 : }
898 : else
899 : {
900 435073 : if (!sInsertCalendar.isEmpty())
901 : {
902 1 : sStr = sInsertCalendar + sStr;
903 : }
904 435073 : sal_Int32 nStrPos = pSc->ScanFormat( sStr);
905 435073 : sal_uInt16 nAnz = pSc->GetAnzResStrings();
906 435073 : if (nAnz == 0) // error
907 : {
908 0 : nStrPos = 1;
909 : }
910 435073 : if (nStrPos == 0) // ok
911 : {
912 : // e.g. Thai T speciality
913 435071 : if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet())
914 : {
915 0 : sStr = "[NatNum" + OUString::number( pSc->GetNatNumModifier()) + "]" + sStr;
916 0 : NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), false );
917 : }
918 : // #i53826# #i42727# For the Thai T speciality we need
919 : // to freeze the locale and immunize it against
920 : // conversions during exports, just in case we want to
921 : // save to Xcl. This disables the feature of being able
922 : // to convert a NatNum to another locale. You can't
923 : // have both.
924 : // FIXME: implement a specialized export conversion
925 : // that works on tokens (have to tokenize all first)
926 : // and doesn't use the format string and
927 : // PutandConvertEntry() to LANGUAGE_ENGLISH_US in
928 : // sc/source/filter/excel/xestyle.cxx
929 : // XclExpNumFmtBuffer::WriteFormatRecord().
930 : LanguageType eLanguage;
931 870247 : if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 &&
932 435164 : ((eLanguage = MsLangId::getRealLanguage( eLan)) == LANGUAGE_THAI) &&
933 93 : NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW)
934 : {
935 91 : sStr = "[$-" + OUString::number( eLanguage, 16 ).toAsciiUpperCase() + "]" + sStr;
936 91 : NumFor[nIndex].SetNatNumLang( eLanguage);
937 : }
938 435071 : sBuff.remove(nPosOld, nPos - nPosOld);
939 435071 : sBuff.insert(nPosOld, sStr);
940 435071 : nPos = nPosOld + sStr.getLength();
941 435071 : if (nPos < sBuff.getLength())
942 : {
943 73533 : sBuff.insert(nPos, ";");
944 73533 : nPos++;
945 : }
946 435071 : NumFor[nIndex].Enlarge(nAnz);
947 435071 : pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz);
948 : // type check
949 435071 : if (nIndex == 0)
950 : {
951 361537 : eType = (short) NumFor[nIndex].Info().eScannedType;
952 : }
953 73534 : else if (nIndex == 3)
954 : { // #77026# Everything recognized IS text
955 1007 : NumFor[nIndex].Info().eScannedType = css::util::NumberFormat::TEXT;
956 : }
957 72527 : else if ( (short) NumFor[nIndex].Info().eScannedType != eType)
958 : {
959 378 : eType = css::util::NumberFormat::DEFINED;
960 : }
961 : }
962 : else
963 : {
964 2 : nCheckPos = nPosOld + nStrPos; // error in string
965 2 : bCancel = true; // break for
966 : }
967 : }
968 : }
969 0 : else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error
970 : {
971 0 : nCheckPos = nPosOld;
972 0 : bCancel = true;
973 : }
974 0 : else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) )
975 : {
976 0 : nCheckPos = nPosOld + 1; // error, prefix in string
977 0 : bCancel = true; // break for
978 : }
979 : }
980 435077 : if ( bCancel && !nCheckPos )
981 : {
982 1 : nCheckPos = 1; // nCheckPos is used as an error condition
983 : }
984 435077 : if ( !bCancel )
985 : {
986 435179 : if ( NumFor[nIndex].GetNatNum().IsSet() &&
987 105 : NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW )
988 : {
989 12 : NumFor[nIndex].SetNatNumLang( eLan );
990 : }
991 : }
992 435077 : if (sBuff.getLength() == nPos)
993 : {
994 361593 : if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT &&
995 53 : sBuff[nPos - 1] == ';' )
996 : {
997 : // #83510# A 4th subformat explicitly specified to be empty
998 : // hides any text. Need the type here for HasTextFormat()
999 0 : NumFor[3].Info().eScannedType = css::util::NumberFormat::TEXT;
1000 : }
1001 361540 : bCancel = true;
1002 : }
1003 435077 : if ( NumFor[nIndex].GetNatNum().IsSet() )
1004 : {
1005 105 : NumFor[nIndex].SetNatNumDate( (NumFor[nIndex].Info().eScannedType & css::util::NumberFormat::DATE) != 0 );
1006 : }
1007 435077 : }
1008 :
1009 361541 : if ( bCondition && !nCheckPos )
1010 : {
1011 99 : if ( nIndex == 1 && NumFor[0].GetCount() == 0 &&
1012 0 : sBuff[sBuff.getLength() - 1] != ';' )
1013 : {
1014 : // No format code => GENERAL but not if specified empty
1015 0 : OUString aAdd( pSc->GetStandardName() );
1016 0 : if ( !pSc->ScanFormat( aAdd ) )
1017 : {
1018 0 : sal_uInt16 nAnz = pSc->GetAnzResStrings();
1019 0 : if ( nAnz )
1020 : {
1021 0 : NumFor[0].Enlarge(nAnz);
1022 0 : pSc->CopyInfo( &(NumFor[0].Info()), nAnz );
1023 0 : sBuff.append(aAdd);
1024 : }
1025 0 : }
1026 : }
1027 99 : else if ( nIndex == 1 && NumFor[nIndex].GetCount() == 0 &&
1028 99 : sBuff[sBuff.getLength() - 1] != ';' &&
1029 0 : (NumFor[0].GetCount() > 1 ||
1030 0 : (NumFor[0].GetCount() == 1 &&
1031 0 : NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) )
1032 : {
1033 : // No trailing second subformat => GENERAL but not if specified empty
1034 : // and not if first subformat is GENERAL
1035 0 : OUString aAdd( pSc->GetStandardName() );
1036 0 : if ( !pSc->ScanFormat( aAdd ) )
1037 : {
1038 0 : sal_uInt16 nAnz = pSc->GetAnzResStrings();
1039 0 : if ( nAnz )
1040 : {
1041 0 : NumFor[nIndex].Enlarge(nAnz);
1042 0 : pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
1043 0 : sBuff.append(";");
1044 0 : sBuff.append(aAdd);
1045 : }
1046 0 : }
1047 : }
1048 111 : else if ( nIndex == 2 && NumFor[nIndex].GetCount() == 0 &&
1049 111 : sBuff[sBuff.getLength() - 1] != ';' &&
1050 6 : eOp2 != NUMBERFORMAT_OP_NO )
1051 : {
1052 : // No trailing third subformat => GENERAL but not if specified empty
1053 0 : OUString aAdd( pSc->GetStandardName() );
1054 0 : if ( !pSc->ScanFormat( aAdd ) )
1055 : {
1056 0 : sal_uInt16 nAnz = pSc->GetAnzResStrings();
1057 0 : if ( nAnz )
1058 : {
1059 0 : NumFor[nIndex].Enlarge(nAnz);
1060 0 : pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz );
1061 0 : sBuff.append(";");
1062 0 : sBuff.append(aAdd);
1063 : }
1064 0 : }
1065 : }
1066 : }
1067 361541 : rString = sBuff.makeStringAndClear();
1068 361541 : sFormatstring = rString;
1069 :
1070 1083564 : if (NumFor[2].GetCount() == 0 && // No third partial string
1071 501289 : eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO &&
1072 502347 : fLimit1 == 0.0 && fLimit2 == 0.0)
1073 : {
1074 70403 : eOp1 = NUMBERFORMAT_OP_GE; // Add 0 to the first format
1075 361541 : }
1076 :
1077 361541 : }
1078 :
1079 1808555 : SvNumberformat::~SvNumberformat()
1080 : {
1081 1808555 : }
1082 :
1083 : /**
1084 : * Next_Symbol
1085 : *
1086 : * Splits up the symbols for further processing (by the Turing machine)
1087 : *
1088 : * Start state = SsStart, * = Special state
1089 : * ---------------+-------------------+----------------------------+---------------
1090 : * Old State | Symbol read | Event | New state
1091 : * ---------------+-------------------+----------------------------+---------------
1092 : * SsStart | ; | Pos-- | SsGetString
1093 : * | [ | Symbol += Character | SsGetBracketed
1094 : * | ] | Error | SsStop
1095 : * | BLANK | |
1096 : * | Else | Symbol += Character | SsGetString
1097 : * ---------------+-------------------+----------------------------+---------------
1098 : * SsGetString | ; | | SsStop
1099 : * | Else | Symbol += Character |
1100 : * ---------------+-------------------+----------------------------+---------------
1101 : * SsGetBracketed | <, > = | del [ |
1102 : * | | Symbol += Character | SsGetCon
1103 : * | BLANK | |
1104 : * | h, H, m, M, s, S | Symbol += Character | SsGetTime
1105 : * | Else | del [ |
1106 : * | | Symbol += Character | SsGetPrefix
1107 : * ---------------+-------------------+----------------------------+---------------
1108 : * SsGetTime | ] | Symbol += Character | SsGetString
1109 : * | h, H, m, M, s, S | Symbol += Character, * | SsGetString
1110 : * | Else | del [; Symbol += Character | SsGetPrefix
1111 : * ---------------+-------------------+----------------------------+---------------
1112 : * SsGetPrefix | ] | | SsStop
1113 : * | Else | Symbol += Character |
1114 : * ---------------+-------------------+----------------------------+---------------
1115 : * SsGetCon | >, = | Symbol += Character |
1116 : * | ] | | SsStop
1117 : * | Else | Error | SsStop
1118 : * ---------------+-------------------+----------------------------+---------------
1119 : */
1120 :
1121 : enum ScanState
1122 : {
1123 : SsStop,
1124 : SsStart,
1125 : SsGetCon, // condition
1126 : SsGetString, // format string
1127 : SsGetPrefix, // color or NatNumN
1128 : SsGetTime, // [HH] for time
1129 : SsGetBracketed // any [...] not decided yet
1130 : };
1131 :
1132 : // read a string until ']' and delete spaces in input
1133 : // static
1134 192 : sal_Int32 SvNumberformat::ImpGetNumber(OUStringBuffer& rString,
1135 : sal_Int32& nPos,
1136 : OUString& sSymbol)
1137 : {
1138 192 : sal_Int32 nStartPos = nPos;
1139 : sal_Unicode cToken;
1140 192 : sal_Int32 nLen = rString.getLength();
1141 192 : OUStringBuffer sBuffSymbol;
1142 576 : while ( nPos < nLen && ((cToken = rString[nPos]) != ']') )
1143 : {
1144 192 : if (cToken == ' ')
1145 : { // delete spaces
1146 0 : rString.remove(nPos,1);
1147 0 : nLen--;
1148 : }
1149 : else
1150 : {
1151 192 : nPos++;
1152 192 : sBuffSymbol.append(cToken);
1153 : }
1154 : }
1155 192 : sSymbol = sBuffSymbol.makeStringAndClear();
1156 192 : return nPos - nStartPos;
1157 : }
1158 :
1159 : namespace {
1160 :
1161 44 : sal_Unicode toUniChar(sal_uInt8 n)
1162 : {
1163 : sal_Char c;
1164 44 : if (n < 10)
1165 : {
1166 37 : c = '0' + n;
1167 : }
1168 : else
1169 : {
1170 7 : c = 'A' + n - 10;
1171 : }
1172 44 : return sal_Unicode(c);
1173 : }
1174 :
1175 73535 : bool IsCombiningSymbol( OUStringBuffer& rStringBuffer, sal_Int32 nPos )
1176 : {
1177 73535 : bool bRet = false;
1178 147070 : while (nPos >= 0)
1179 : {
1180 73535 : switch (rStringBuffer[nPos])
1181 : {
1182 : case '*':
1183 : case '\\':
1184 : case '_':
1185 0 : bRet = !bRet;
1186 0 : --nPos;
1187 0 : break;
1188 : default:
1189 73535 : return bRet;
1190 : }
1191 : }
1192 0 : return bRet;
1193 : }
1194 :
1195 : } // namespace
1196 :
1197 14 : OUString SvNumberformat::LocaleType::generateCode() const
1198 : {
1199 14 : OUStringBuffer aBuf;
1200 : #if 0
1201 : // TODO: We may re-enable this later. Don't remove it! --Kohei
1202 : if (mnNumeralShape)
1203 : {
1204 : sal_uInt8 nVal = mnNumeralShape;
1205 : for (sal_uInt8 i = 0; i < 2; ++i)
1206 : {
1207 : sal_uInt8 n = (nVal & 0xF0) >> 4;
1208 : if (n || aBuf.getLength())
1209 : {
1210 : aBuf.append(toUniChar(n));
1211 : }
1212 : nVal = nVal << 4;
1213 : }
1214 : }
1215 :
1216 : if (mnNumeralShape || mnCalendarType)
1217 : {
1218 : sal_uInt8 nVal = mnCalendarType;
1219 : for (sal_uInt8 i = 0; i < 2; ++i)
1220 : {
1221 : sal_uInt8 n = (nVal & 0xF0) >> 4;
1222 : if (n || aBuf.getLength())
1223 : {
1224 : aBuf.append(toUniChar(n));
1225 : }
1226 : nVal = nVal << 4;
1227 : }
1228 : }
1229 : #endif
1230 :
1231 14 : sal_uInt16 n16 = static_cast<sal_uInt16>(meLanguage);
1232 70 : for (sal_uInt8 i = 0; i < 4; ++i)
1233 : {
1234 56 : sal_uInt8 n = static_cast<sal_uInt8>((n16 & 0xF000) >> 12);
1235 : // Omit leading zeros for consistency.
1236 56 : if (n || !aBuf.isEmpty() || i == 3)
1237 : {
1238 44 : aBuf.append(toUniChar(n));
1239 : }
1240 56 : n16 = n16 << 4;
1241 : }
1242 :
1243 14 : return aBuf.makeStringAndClear();
1244 : }
1245 :
1246 366419 : SvNumberformat::LocaleType::LocaleType()
1247 : : mnNumeralShape(0)
1248 : , mnCalendarType(0)
1249 366419 : , meLanguage(LANGUAGE_DONTKNOW)
1250 : {
1251 366419 : }
1252 :
1253 14 : SvNumberformat::LocaleType::LocaleType(sal_uInt32 nRawNum)
1254 : : mnNumeralShape(0)
1255 : , mnCalendarType(0)
1256 14 : , meLanguage(LANGUAGE_DONTKNOW)
1257 : {
1258 14 : meLanguage = static_cast<LanguageType>(nRawNum & 0x0000FFFF);
1259 14 : nRawNum = (nRawNum >> 16);
1260 14 : mnCalendarType = static_cast<sal_uInt8>(nRawNum & 0xFF);
1261 14 : nRawNum = (nRawNum >> 8);
1262 14 : mnNumeralShape = static_cast<sal_uInt8>(nRawNum & 0xFF);
1263 14 : }
1264 :
1265 : // static
1266 14 : SvNumberformat::LocaleType SvNumberformat::ImpGetLocaleType(const OUString& rString, sal_Int32& nPos )
1267 : {
1268 14 : sal_uInt32 nNum = 0;
1269 14 : sal_Unicode cToken = 0;
1270 14 : sal_Int32 nStart = nPos;
1271 14 : sal_Int32 nLen = rString.getLength();
1272 82 : while ( nPos < nLen && (nPos - nStart < 8) && ((cToken = rString[nPos]) != ']') )
1273 : {
1274 54 : if ( '0' <= cToken && cToken <= '9' )
1275 : {
1276 47 : nNum *= 16;
1277 47 : nNum += cToken - '0';
1278 : }
1279 7 : else if ( 'a' <= cToken && cToken <= 'f' )
1280 : {
1281 0 : nNum *= 16;
1282 0 : nNum += cToken - 'a' + 10;
1283 : }
1284 7 : else if ( 'A' <= cToken && cToken <= 'F' )
1285 : {
1286 7 : nNum *= 16;
1287 7 : nNum += cToken - 'A' + 10;
1288 : }
1289 : else
1290 : {
1291 0 : return LANGUAGE_DONTKNOW;
1292 : }
1293 54 : ++nPos;
1294 : }
1295 :
1296 14 : return (cToken == ']' || nPos == nLen) ? LocaleType(nNum) : LocaleType();
1297 : }
1298 :
1299 81635 : static bool lcl_matchKeywordAndGetNumber( const OUString & rString, const sal_Int32 nPos,
1300 : const OUString & rKeyword, sal_Int32 & nNumber )
1301 : {
1302 81635 : if (0 <= nPos && nPos + rKeyword.getLength() < rString.getLength() && rString.matchIgnoreAsciiCase( rKeyword, nPos))
1303 : {
1304 106 : nNumber = rString.copy( nPos + rKeyword.getLength()).toInt32();
1305 106 : return true;
1306 : }
1307 : else
1308 : {
1309 81529 : nNumber = 0;
1310 81529 : return false;
1311 : }
1312 : }
1313 :
1314 466054 : short SvNumberformat::ImpNextSymbol(OUStringBuffer& rString,
1315 : sal_Int32& nPos,
1316 : OUString& sSymbol)
1317 : {
1318 466054 : short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1319 : sal_Unicode cToken;
1320 466054 : sal_Unicode cLetter = ' '; // Preliminary result
1321 466054 : sal_Int32 nLen = rString.getLength();
1322 466054 : ScanState eState = SsStart;
1323 466054 : OUStringBuffer sBuffSymbol;
1324 :
1325 466054 : const NfKeywordTable & rKeywords = rScan.GetKeywords();
1326 5922139 : while (nPos < nLen && eState != SsStop)
1327 : {
1328 4990031 : cToken = rString[nPos];
1329 4990031 : nPos++;
1330 4990031 : switch (eState)
1331 : {
1332 : case SsStart:
1333 466106 : if (cToken == '[')
1334 : {
1335 121645 : eState = SsGetBracketed;
1336 121645 : sBuffSymbol.append(cToken);
1337 : }
1338 344461 : else if (cToken == ';')
1339 : {
1340 3 : eState = SsGetString;
1341 3 : nPos--;
1342 3 : eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1343 : }
1344 344458 : else if (cToken == ']')
1345 : {
1346 0 : eState = SsStop;
1347 0 : eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1348 : }
1349 344458 : else if (cToken == ' ') // Skip Blanks
1350 : {
1351 52 : nPos--;
1352 52 : rString.remove(nPos, 1);
1353 52 : nLen--;
1354 : }
1355 : else
1356 : {
1357 344406 : sBuffSymbol.append(cToken);
1358 344406 : eState = SsGetString;
1359 344406 : eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1360 : }
1361 466106 : break;
1362 : case SsGetBracketed:
1363 121645 : switch (cToken)
1364 : {
1365 : case '<':
1366 : case '>':
1367 : case '=':
1368 192 : sBuffSymbol.stripStart('[');
1369 192 : sBuffSymbol.append(cToken);
1370 192 : cLetter = cToken;
1371 192 : eState = SsGetCon;
1372 192 : switch (cToken)
1373 : {
1374 : case '<':
1375 99 : eSymbolType = NUMBERFORMAT_OP_LT;
1376 99 : break;
1377 : case '>':
1378 93 : eSymbolType = NUMBERFORMAT_OP_GT;
1379 93 : break;
1380 : case '=':
1381 0 : eSymbolType = NUMBERFORMAT_OP_EQ;
1382 0 : break;
1383 : }
1384 192 : break;
1385 : case ' ':
1386 0 : nPos--;
1387 0 : rString.remove(nPos, 1);
1388 0 : nLen--;
1389 0 : break;
1390 : case '$' :
1391 33635 : if ( rString[nPos] == '-' )
1392 : {
1393 : // [$-xxx] locale
1394 14 : sBuffSymbol.stripStart('[');
1395 14 : eSymbolType = BRACKET_SYMBOLTYPE_LOCALE;
1396 14 : eState = SsGetPrefix;
1397 : }
1398 : else
1399 : { // currency
1400 33621 : eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1401 33621 : eState = SsGetString;
1402 : }
1403 33635 : sBuffSymbol.append(cToken);
1404 33635 : break;
1405 : case '~' :
1406 : // calendarID
1407 46948 : eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1408 46948 : sBuffSymbol.append(cToken);
1409 46948 : eState = SsGetString;
1410 46948 : break;
1411 : default:
1412 : {
1413 40870 : const OUString aNatNum("NATNUM");
1414 81740 : const OUString aDBNum("DBNUM");
1415 81740 : const OUString aBufStr( rString.toString());
1416 : sal_Int32 nNatNumNum;
1417 : sal_Int32 nDBNum;
1418 81845 : if ( lcl_matchKeywordAndGetNumber( aBufStr, nPos-1, aNatNum, nNatNumNum) &&
1419 40975 : 0 <= nNatNumNum && nNatNumNum <= 19 )
1420 : {
1421 105 : sBuffSymbol.stripStart('[');
1422 105 : sBuffSymbol.append( aBufStr.copy( --nPos, aNatNum.getLength()+1 ));
1423 105 : nPos += aNatNum.getLength()+1;
1424 : //! SymbolType is negative
1425 105 : eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum);
1426 105 : eState = SsGetPrefix;
1427 : }
1428 81531 : else if ( lcl_matchKeywordAndGetNumber( aBufStr, nPos-1, aDBNum, nDBNum) &&
1429 40765 : '1' <= nDBNum && nDBNum <= '9' )
1430 : {
1431 0 : sBuffSymbol.stripStart('[');
1432 0 : sBuffSymbol.append( aBufStr.copy( --nPos, aDBNum.getLength()+1 ));
1433 0 : nPos += aDBNum.getLength()+1;
1434 : //! SymbolType is negative
1435 0 : eSymbolType = sal::static_int_cast< short >( BRACKET_SYMBOLTYPE_DBNUM1 - (nDBNum - '1'));
1436 0 : eState = SsGetPrefix;
1437 : }
1438 : else
1439 : {
1440 40765 : sal_Unicode cUpper = rChrCls().uppercase( aBufStr, nPos-1, 1)[0];
1441 112197 : if ( cUpper == rKeywords[NF_KEY_H][0] || // H
1442 71432 : cUpper == rKeywords[NF_KEY_MI][0] || // M
1443 30667 : cUpper == rKeywords[NF_KEY_S][0] ) // S
1444 : {
1445 10098 : sBuffSymbol.append(cToken);
1446 10098 : eState = SsGetTime;
1447 10098 : cLetter = cToken;
1448 : }
1449 : else
1450 : {
1451 30667 : sBuffSymbol.stripStart('[');
1452 30667 : sBuffSymbol.append(cToken);
1453 30667 : eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1454 30667 : eState = SsGetPrefix;
1455 : }
1456 40870 : }
1457 : }
1458 : }
1459 121645 : break;
1460 : case SsGetString:
1461 4290142 : if (cToken == ';' && (nPos < 2 || !IsCombiningSymbol( rString, nPos-2)))
1462 : {
1463 73536 : eState = SsStop;
1464 : }
1465 : else
1466 : {
1467 4216606 : sBuffSymbol.append(cToken);
1468 : }
1469 4290142 : break;
1470 : case SsGetTime:
1471 19727 : if (cToken == ']')
1472 : {
1473 10098 : sBuffSymbol.append(cToken);
1474 10098 : eState = SsGetString;
1475 10098 : eSymbolType = BRACKET_SYMBOLTYPE_FORMAT;
1476 : }
1477 : else
1478 : {
1479 9629 : sal_Unicode cUpper = rChrCls().uppercase(rString.toString(), nPos-1, 1)[0];
1480 19258 : if (cUpper == rKeywords[NF_KEY_H][0] || // H
1481 9629 : cUpper == rKeywords[NF_KEY_MI][0] || // M
1482 0 : cUpper == rKeywords[NF_KEY_S][0] ) // S
1483 : {
1484 9629 : if (cLetter == cToken)
1485 : {
1486 9629 : sBuffSymbol.append(cToken);
1487 9629 : cLetter = ' ';
1488 : }
1489 : else
1490 : {
1491 0 : sBuffSymbol.stripStart('[');
1492 0 : sBuffSymbol.append(cToken);
1493 0 : eState = SsGetPrefix;
1494 : }
1495 : }
1496 : else
1497 : {
1498 0 : sBuffSymbol.stripStart('[');
1499 0 : sBuffSymbol.append(cToken);
1500 0 : eSymbolType = BRACKET_SYMBOLTYPE_COLOR;
1501 0 : eState = SsGetPrefix;
1502 : }
1503 : }
1504 19727 : break;
1505 : case SsGetCon:
1506 192 : switch (cToken)
1507 : {
1508 : case '<':
1509 0 : eState = SsStop;
1510 0 : eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1511 0 : break;
1512 : case '>':
1513 6 : if (cLetter == '<')
1514 : {
1515 6 : sBuffSymbol.append(cToken);
1516 6 : cLetter = ' ';
1517 6 : eState = SsStop;
1518 6 : eSymbolType = NUMBERFORMAT_OP_NE;
1519 : }
1520 : else
1521 : {
1522 0 : eState = SsStop;
1523 0 : eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1524 : }
1525 6 : break;
1526 : case '=':
1527 0 : if (cLetter == '<')
1528 : {
1529 0 : sBuffSymbol.append(cToken);
1530 0 : cLetter = ' ';
1531 0 : eSymbolType = NUMBERFORMAT_OP_LE;
1532 : }
1533 0 : else if (cLetter == '>')
1534 : {
1535 0 : sBuffSymbol.append(cToken);
1536 0 : cLetter = ' ';
1537 0 : eSymbolType = NUMBERFORMAT_OP_GE;
1538 : }
1539 : else
1540 : {
1541 0 : eState = SsStop;
1542 0 : eSymbolType = BRACKET_SYMBOLTYPE_ERROR;
1543 : }
1544 0 : break;
1545 : case ' ':
1546 0 : nPos--;
1547 0 : rString.remove(nPos,1);
1548 0 : nLen--;
1549 0 : break;
1550 : default:
1551 186 : eState = SsStop;
1552 186 : nPos--;
1553 186 : break;
1554 : }
1555 192 : break;
1556 : case SsGetPrefix:
1557 92219 : if (cToken == ']')
1558 : {
1559 30786 : eState = SsStop;
1560 : }
1561 : else
1562 : {
1563 61433 : sBuffSymbol.append(cToken);
1564 : }
1565 92219 : break;
1566 : default:
1567 0 : break;
1568 : } // of switch
1569 : } // of while
1570 466054 : sSymbol = sBuffSymbol.makeStringAndClear();
1571 466054 : return eSymbolType;
1572 : }
1573 :
1574 0 : void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter,
1575 : LanguageType eConvertFrom,
1576 : LanguageType eConvertTo, bool bSystem )
1577 : {
1578 : sal_Int32 nCheckPos;
1579 : sal_uInt32 nKey;
1580 0 : short nType = eType;
1581 0 : OUString aFormatString( sFormatstring );
1582 0 : if ( bSystem )
1583 : {
1584 : rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType,
1585 0 : nKey, eConvertFrom, eConvertTo );
1586 : }
1587 : else
1588 : {
1589 : rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType,
1590 0 : nKey, eConvertFrom, eConvertTo );
1591 : }
1592 0 : const SvNumberformat* pFormat = rConverter.GetEntry( nKey );
1593 : DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" );
1594 0 : if ( pFormat )
1595 : {
1596 0 : ImpCopyNumberformat( *pFormat );
1597 : // Reset values taken over from Formatter/Scanner
1598 0 : if ( bSystem )
1599 : {
1600 0 : maLocale.meLanguage = LANGUAGE_SYSTEM;
1601 : }
1602 : // pColor still points to table in temporary Formatter/Scanner
1603 0 : for ( sal_uInt16 i = 0; i < 4; i++ )
1604 : {
1605 0 : OUString aColorName = NumFor[i].GetColorName();
1606 0 : Color* pColor = rScan.GetColor( aColorName );
1607 0 : NumFor[i].SetColor( pColor, aColorName );
1608 0 : }
1609 0 : }
1610 0 : }
1611 :
1612 0 : bool SvNumberformat::HasNewCurrency() const
1613 : {
1614 0 : for ( sal_uInt16 j=0; j<4; j++ )
1615 : {
1616 0 : if ( NumFor[j].HasNewCurrency() )
1617 : {
1618 0 : return true;
1619 : }
1620 : }
1621 0 : return false;
1622 : }
1623 :
1624 2134 : bool SvNumberformat::GetNewCurrencySymbol( OUString& rSymbol,
1625 : OUString& rExtension ) const
1626 : {
1627 10302 : for ( sal_uInt16 j=0; j<4; j++ )
1628 : {
1629 8260 : if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) )
1630 : {
1631 92 : return true;
1632 : }
1633 : }
1634 2042 : rSymbol.clear();
1635 2042 : rExtension.clear();
1636 2042 : return false;
1637 : }
1638 :
1639 : // static
1640 24065 : OUString SvNumberformat::StripNewCurrencyDelimiters( const OUString& rStr,
1641 : bool bQuoteSymbol )
1642 : {
1643 24065 : OUString aTmp;
1644 48130 : OUString aSource(rStr);
1645 : sal_Int32 nStartPos, nPos, nLen;
1646 24065 : nLen = aSource.getLength();
1647 24065 : nStartPos = 0;
1648 96260 : while ( (nPos = aSource.indexOf( "[$", nStartPos )) >= 0 )
1649 : {
1650 : sal_Int32 nEnd;
1651 48130 : if ( (nEnd = GetQuoteEnd( aSource, nPos )) >= 0 )
1652 : {
1653 0 : aTmp += aSource.copy( nStartPos, ++nEnd - nStartPos );
1654 0 : nStartPos = nEnd;
1655 : }
1656 : else
1657 : {
1658 48130 : aTmp += aSource.copy( nStartPos, nPos - nStartPos );
1659 48130 : nStartPos = nPos + 2;
1660 : sal_Int32 nDash;
1661 48130 : nEnd = nStartPos - 1;
1662 48130 : do
1663 : {
1664 48130 : nDash = aSource.indexOf( '-', ++nEnd );
1665 : }
1666 : while ( (nEnd = GetQuoteEnd( aSource, nDash )) >= 0 );
1667 : sal_Int32 nClose;
1668 48130 : nEnd = nStartPos - 1;
1669 48130 : do
1670 : {
1671 48130 : nClose = aSource.indexOf( ']', ++nEnd );
1672 : }
1673 : while ( (nEnd = GetQuoteEnd( aSource, nClose )) >= 0 );
1674 :
1675 48130 : if(nClose < 0)
1676 : {
1677 : /* there should always be a closing ]
1678 : * but the old String class would have hidden
1679 : * that. so be conservative too
1680 : */
1681 0 : nClose = nLen;
1682 : }
1683 :
1684 48130 : nPos = nClose;
1685 48130 : if(nDash >= 0 && nDash < nClose)
1686 : {
1687 48130 : nPos = nDash;
1688 : }
1689 48130 : if ( !bQuoteSymbol || aSource[ nStartPos ] == '"' )
1690 : {
1691 48130 : aTmp += aSource.copy( nStartPos, nPos - nStartPos );
1692 : }
1693 : else
1694 : {
1695 0 : aTmp += "\"";
1696 0 : aTmp += aSource.copy( nStartPos, nPos - nStartPos );
1697 0 : aTmp += "\"";
1698 : }
1699 48130 : nStartPos = nClose + 1;
1700 : }
1701 : }
1702 24065 : if ( nLen > nStartPos )
1703 : {
1704 23640 : aTmp += aSource.copy( nStartPos, nLen - nStartPos );
1705 : }
1706 48130 : return aTmp;
1707 : }
1708 :
1709 6924 : void SvNumberformat::ImpGetOutputStandard(double& fNumber, OUStringBuffer& rOutString)
1710 : {
1711 6924 : OUString sTemp;
1712 6924 : ImpGetOutputStandard(fNumber, sTemp);
1713 6924 : rOutString = sTemp;
1714 6924 : }
1715 :
1716 6924 : void SvNumberformat::ImpGetOutputStandard(double& fNumber, OUString& rOutString)
1717 : {
1718 6924 : sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
1719 :
1720 6924 : if ( fabs(fNumber) > 1.0E15 ) // #58531# was E16
1721 : {
1722 0 : nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
1723 0 : rOutString = ::rtl::math::doubleToUString( fNumber,
1724 : rtl_math_StringFormat_E2, nStandardPrec /*2*/,
1725 0 : GetFormatter().GetNumDecimalSep()[0]);
1726 : }
1727 : else
1728 : {
1729 6924 : ImpGetOutputStdToPrecision(fNumber, rOutString, nStandardPrec);
1730 : }
1731 6924 : }
1732 :
1733 58233 : void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, OUString& rOutString, sal_uInt16 nPrecision) const
1734 : {
1735 : // Make sure the precision doesn't go over the maximum allowable precision.
1736 58233 : nPrecision = ::std::min(UPPER_PRECISION, nPrecision);
1737 :
1738 : #if 0
1739 : {
1740 : // debugger test case for ANSI standard correctness
1741 : OUString aTest;
1742 : // expect 0.00123 OK
1743 : aTest = ::rtl::math::doubleToUString( 0.001234567,
1744 : rtl_math_StringFormat_G, 3, '.', true );
1745 : // expect 123 OK
1746 : aTest = ::rtl::math::doubleToUString( 123.4567,
1747 : rtl_math_StringFormat_G, 3, '.', true );
1748 : // expect 123.5 OK
1749 : aTest = ::rtl::math::doubleToUString( 123.4567,
1750 : rtl_math_StringFormat_G, 4, '.', true );
1751 : // expect 1e+03 (as 999.6 rounded to 3 significant digits results in
1752 : // 1000 with an exponent equal to significant digits)
1753 : // Currently (24-Jan-2003) we do fail in this case and output 1000
1754 : // instead, negligible.
1755 : aTest = ::rtl::math::doubleToUString( 999.6,
1756 : rtl_math_StringFormat_G, 3, '.', true );
1757 : // expect what? result is 1.2e+004
1758 : aTest = ::rtl::math::doubleToUString( 12345.6789,
1759 : rtl_math_StringFormat_G, -3, '.', true );
1760 : }
1761 : #endif
1762 :
1763 : // We decided to strip trailing zeros unconditionally, since binary
1764 : // double-precision rounding error makes it impossible to determine e.g.
1765 : // whether 844.10000000000002273737 is what the user has typed, or the
1766 : // user has typed 844.1 but IEEE 754 represents it that way internally.
1767 :
1768 116466 : rOutString = ::rtl::math::doubleToUString( rNumber,
1769 : rtl_math_StringFormat_F, nPrecision /*2*/,
1770 116466 : GetFormatter().GetNumDecimalSep()[0], true );
1771 58549 : if (rOutString[0] == '-' &&
1772 316 : comphelper::string::getTokenCount(rOutString, '0') == rOutString.getLength())
1773 : {
1774 0 : rOutString = comphelper::string::stripStart(rOutString, '-'); // not -0
1775 : }
1776 58233 : rOutString = impTransliterate(rOutString, NumFor[0].GetNatNum());
1777 58233 : }
1778 :
1779 864 : void SvNumberformat::ImpGetOutputInputLine(double fNumber, OUString& OutString)
1780 : {
1781 864 : bool bModified = false;
1782 864 : if ( (eType & css::util::NumberFormat::PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100))
1783 : {
1784 0 : if (fNumber == 0.0)
1785 : {
1786 0 : OutString = "0%";
1787 0 : return;
1788 : }
1789 0 : fNumber *= 100;
1790 0 : bModified = true;
1791 : }
1792 :
1793 864 : if (fNumber == 0.0)
1794 : {
1795 166 : OutString = "0";
1796 166 : return;
1797 : }
1798 :
1799 1396 : OutString = ::rtl::math::doubleToUString( fNumber,
1800 : rtl_math_StringFormat_Automatic,
1801 : rtl_math_DecimalPlaces_Max,
1802 1396 : GetFormatter().GetNumDecimalSep()[0], true );
1803 :
1804 698 : if ( eType & css::util::NumberFormat::PERCENT && bModified)
1805 : {
1806 0 : OutString += "%";
1807 : }
1808 698 : return;
1809 : }
1810 :
1811 6552 : short SvNumberformat::ImpCheckCondition(double& fNumber,
1812 : double& fLimit,
1813 : SvNumberformatLimitOps eOp)
1814 : {
1815 6552 : switch(eOp)
1816 : {
1817 : case NUMBERFORMAT_OP_NO:
1818 6247 : return -1;
1819 : case NUMBERFORMAT_OP_EQ:
1820 0 : return (short) (fNumber == fLimit);
1821 : case NUMBERFORMAT_OP_NE:
1822 100 : return (short) (fNumber != fLimit);
1823 : case NUMBERFORMAT_OP_LT:
1824 0 : return (short) (fNumber < fLimit);
1825 : case NUMBERFORMAT_OP_LE:
1826 0 : return (short) (fNumber <= fLimit);
1827 : case NUMBERFORMAT_OP_GT:
1828 13 : return (short) (fNumber > fLimit);
1829 : case NUMBERFORMAT_OP_GE:
1830 192 : return (short) (fNumber >= fLimit);
1831 : default:
1832 0 : return -1;
1833 : }
1834 : }
1835 :
1836 0 : static bool lcl_appendStarFillChar( OUStringBuffer& rBuf, const OUString& rStr )
1837 : {
1838 : // Right during user input the star symbol is the very
1839 : // last character before the user enters another one.
1840 0 : if (rStr.getLength() > 1)
1841 : {
1842 0 : rBuf.append((sal_Unicode) 0x1B);
1843 0 : rBuf.append(rStr[1]);
1844 0 : return true;
1845 : }
1846 0 : return false;
1847 : }
1848 :
1849 0 : static bool lcl_insertStarFillChar( OUStringBuffer& rBuf, sal_Int32 nPos, const OUString& rStr )
1850 : {
1851 0 : if (rStr.getLength() > 1)
1852 : {
1853 0 : rBuf.insert( nPos, rStr[1]);
1854 0 : rBuf.insert( nPos, (sal_Unicode) 0x1B);
1855 0 : return true;
1856 : }
1857 0 : return false;
1858 : }
1859 :
1860 456 : bool SvNumberformat::GetOutputString(const OUString& sString,
1861 : OUString& OutString,
1862 : Color** ppColor)
1863 : {
1864 456 : OUStringBuffer sOutBuff;
1865 : sal_uInt16 nIx;
1866 456 : if (eType & css::util::NumberFormat::TEXT)
1867 : {
1868 456 : nIx = 0;
1869 : }
1870 0 : else if (NumFor[3].GetCount() > 0)
1871 : {
1872 0 : nIx = 3;
1873 : }
1874 : else
1875 : {
1876 0 : *ppColor = NULL; // no change of color
1877 0 : return false;
1878 : }
1879 456 : *ppColor = NumFor[nIx].GetColor();
1880 456 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
1881 456 : bool bRes = false;
1882 456 : if (rInfo.eScannedType == css::util::NumberFormat::TEXT)
1883 : {
1884 456 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
1885 916 : for (sal_uInt16 i = 0; i < nAnz; i++)
1886 : {
1887 460 : switch (rInfo.nTypeArray[i])
1888 : {
1889 : case NF_SYMBOLTYPE_STAR:
1890 0 : if( bStarFlag )
1891 : {
1892 0 : bRes = lcl_appendStarFillChar( sOutBuff, rInfo.sStrArray[i]);
1893 : }
1894 0 : break;
1895 : case NF_SYMBOLTYPE_BLANK:
1896 : InsertBlanks( sOutBuff, sOutBuff.getLength(),
1897 0 : rInfo.sStrArray[i][1] );
1898 0 : break;
1899 : case NF_KEY_GENERAL : // #77026# "General" is the same as "@"
1900 : case NF_SYMBOLTYPE_DEL :
1901 456 : sOutBuff.append(sString);
1902 456 : break;
1903 : default:
1904 4 : sOutBuff.append(rInfo.sStrArray[i]);
1905 : }
1906 : }
1907 : }
1908 456 : OutString = sOutBuff.makeStringAndClear();
1909 456 : return bRes;
1910 : }
1911 :
1912 13 : sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y)
1913 : {
1914 13 : if (y == 0)
1915 : {
1916 0 : return x;
1917 : }
1918 : else
1919 : {
1920 13 : sal_uLong z = x%y;
1921 73 : while (z)
1922 : {
1923 47 : x = y;
1924 47 : y = z;
1925 47 : z = x%y;
1926 : }
1927 13 : return y;
1928 : }
1929 : }
1930 :
1931 0 : sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y)
1932 : {
1933 0 : if (y == 0)
1934 : {
1935 0 : return x;
1936 : }
1937 : else
1938 : {
1939 0 : sal_uLong z = x%y;
1940 0 : while ((double)z/(double)y > D_EPS)
1941 : {
1942 0 : x = y;
1943 0 : y = z;
1944 0 : z = x%y;
1945 : }
1946 0 : return y;
1947 : }
1948 : }
1949 :
1950 : namespace {
1951 :
1952 80 : void lcl_GetOutputStringScientific(double fNumber, sal_uInt16 nCharCount,
1953 : const SvNumberFormatter& rFormatter, OUString& rOutString)
1954 : {
1955 80 : bool bSign = ::rtl::math::isSignBitSet(fNumber);
1956 :
1957 : // 1.000E+015 (one digit and the decimal point, and the two chars +
1958 : // nExpDigit for the exponential part, totalling 6 or 7).
1959 80 : double fExp = log10( fabs(fNumber) );
1960 80 : if( fExp < 0.0 )
1961 0 : fExp = 1.0 - fExp;
1962 80 : sal_uInt16 nCharFormat = 6 + (fExp >= 100.0 ? 1 : 0);
1963 80 : sal_uInt16 nPrec = nCharCount > nCharFormat ? nCharCount - nCharFormat : 0;
1964 80 : if (nPrec && bSign)
1965 : {
1966 : // Make room for the negative sign.
1967 4 : --nPrec;
1968 : }
1969 80 : nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals.
1970 :
1971 160 : rOutString = ::rtl::math::doubleToUString(fNumber, rtl_math_StringFormat_E2,
1972 160 : nPrec, rFormatter.GetNumDecimalSep()[0]);
1973 80 : }
1974 :
1975 10 : sal_Int32 lcl_GetForcedDenominator(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nAnz)
1976 : {
1977 : sal_uInt16 i;
1978 10 : OUString aDiv;
1979 60 : for( i = 0; i < nAnz; i++ )
1980 : {
1981 50 : if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC_FDIV )
1982 : {
1983 0 : aDiv += rInfo.sStrArray[i];
1984 : }
1985 : }
1986 10 : return aDiv.toInt32();
1987 : }
1988 :
1989 : // TODO: More optimizations?
1990 0 : void lcl_ForcedDenominator(sal_uLong &nFrac, sal_uLong &nDiv, sal_uLong nForcedDiv)
1991 : {
1992 0 : double fFrac = (double)nFrac / (double)nDiv;
1993 0 : double fMultiplier = (double)nForcedDiv / (double)nDiv;
1994 0 : nFrac = (sal_uLong)( (double)nFrac * fMultiplier );
1995 :
1996 0 : double fFracNew = (double)nFrac / (double)nForcedDiv;
1997 0 : double fFracNew1 = (double)(nFrac + 1) / (double)nForcedDiv;
1998 0 : double fDiff = fFrac - fFracNew;
1999 0 : if( fDiff > ( fFracNew1 - fFrac ) )
2000 : {
2001 0 : nFrac++;
2002 : }
2003 0 : nDiv = nForcedDiv;
2004 0 : }
2005 :
2006 : }
2007 :
2008 2 : sal_Int32 SvNumberformat::GetForcedDenominatorForType( sal_uInt16 nNumFor ) const
2009 : {
2010 2 : const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
2011 2 : sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
2012 2 : return lcl_GetForcedDenominator( rInfo, nAnz );
2013 : }
2014 :
2015 954 : bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, OUString& rOutString) const
2016 : {
2017 : using namespace std;
2018 :
2019 954 : if (eType != css::util::NumberFormat::NUMBER)
2020 : {
2021 0 : return false;
2022 : }
2023 954 : double fTestNum = fNumber;
2024 954 : bool bSign = ::rtl::math::isSignBitSet(fTestNum);
2025 954 : if (bSign)
2026 : {
2027 314 : fTestNum = -fTestNum;
2028 : }
2029 954 : if (fTestNum < EXP_LOWER_BOUND)
2030 : {
2031 0 : lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2032 0 : return true;
2033 : }
2034 :
2035 954 : double fExp = log10(fTestNum);
2036 : // Values < 1.0 always have one digit before the decimal point.
2037 954 : sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1;
2038 :
2039 954 : if (nDigitPre > 15)
2040 : {
2041 8 : lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2042 8 : return true;
2043 : }
2044 :
2045 946 : sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0;
2046 946 : if (nPrec && bSign)
2047 : {
2048 : // Subtract the negative sign.
2049 310 : --nPrec;
2050 : }
2051 946 : if (nPrec)
2052 : {
2053 : // Subtract the decimal point.
2054 874 : --nPrec;
2055 : }
2056 946 : ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec);
2057 946 : if (rOutString.getLength() > nCharCount)
2058 : {
2059 : // String still wider than desired. Switch to scientific notation.
2060 72 : lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString);
2061 : }
2062 946 : return true;
2063 : }
2064 :
2065 65582 : bool SvNumberformat::GetOutputString(double fNumber,
2066 : OUString& OutString,
2067 : Color** ppColor)
2068 : {
2069 65582 : bool bRes = false;
2070 65582 : OUStringBuffer sBuff;
2071 65582 : OutString.clear();
2072 65582 : *ppColor = NULL; // No color change
2073 65582 : if (eType & css::util::NumberFormat::LOGICAL)
2074 : {
2075 674 : if (fNumber)
2076 : {
2077 311 : OutString = rScan.GetTrueString();
2078 : }
2079 : else
2080 : {
2081 363 : OutString = rScan.GetFalseString();
2082 : }
2083 674 : return false;
2084 : }
2085 64908 : if (eType & css::util::NumberFormat::TEXT)
2086 : {
2087 0 : ImpGetOutputStandard(fNumber, sBuff);
2088 0 : OutString = sBuff.makeStringAndClear();
2089 0 : return false;
2090 : }
2091 64908 : bool bHadStandard = false;
2092 64908 : if (bStandard) // Individual standard formats
2093 : {
2094 58408 : if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // All number format InputLine
2095 : {
2096 864 : ImpGetOutputInputLine(fNumber, OutString);
2097 864 : return false;
2098 : }
2099 57544 : switch (eType)
2100 : {
2101 : case css::util::NumberFormat::NUMBER: // Standard number format
2102 57207 : if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION)
2103 : {
2104 50363 : bool bSign = ::rtl::math::isSignBitSet(fNumber);
2105 50363 : if (bSign)
2106 : {
2107 1937 : if (!(fNumber < 0.0))
2108 : {
2109 0 : bSign = false;
2110 : }
2111 1937 : fNumber = -fNumber;
2112 : }
2113 : {
2114 50363 : OUString sTemp;
2115 50363 : ImpGetOutputStdToPrecision(fNumber, sTemp, 10); // Use 10 decimals for general 'unlimited' format.
2116 50363 : sBuff.append(sTemp);
2117 : }
2118 50363 : if (fNumber < EXP_LOWER_BOUND)
2119 : {
2120 1665 : sal_Int32 nLen = sBuff.getLength();
2121 1665 : if (!nLen)
2122 : {
2123 0 : return false;
2124 : }
2125 : // #i112250# With the 10-decimal limit, small numbers are formatted as "0".
2126 : // Switch to scientific in that case, too:
2127 1665 : if (nLen > 11 || ((nLen == 1 && sBuff[0] == '0') && fNumber != 0.0))
2128 : {
2129 0 : sal_uInt16 nStandardPrec = rScan.GetStandardPrec();
2130 0 : nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals
2131 0 : sBuff = ::rtl::math::doubleToUString( fNumber,
2132 : rtl_math_StringFormat_E2, nStandardPrec /*2*/,
2133 0 : GetFormatter().GetNumDecimalSep()[0], true);
2134 : }
2135 : }
2136 50363 : if (bSign)
2137 : {
2138 1937 : sBuff.insert(0, '-');
2139 : }
2140 50363 : OutString = sBuff.makeStringAndClear();
2141 50363 : return false;
2142 : }
2143 6844 : ImpGetOutputStandard(fNumber, sBuff);
2144 6844 : bHadStandard = true;
2145 6844 : break;
2146 : case css::util::NumberFormat::DATE:
2147 160 : bRes |= ImpGetDateOutput(fNumber, 0, sBuff);
2148 160 : bHadStandard = true;
2149 160 : break;
2150 : case css::util::NumberFormat::TIME:
2151 150 : bRes |= ImpGetTimeOutput(fNumber, 0, sBuff);
2152 150 : bHadStandard = true;
2153 150 : break;
2154 : case css::util::NumberFormat::DATETIME:
2155 2 : bRes |= ImpGetDateTimeOutput(fNumber, 0, sBuff);
2156 2 : bHadStandard = true;
2157 2 : break;
2158 : }
2159 : }
2160 13681 : if ( !bHadStandard )
2161 : {
2162 : sal_uInt16 nIx; // Index of the partial format
2163 6525 : short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1);
2164 6525 : if (nCheck == -1 || nCheck == 1) // Only 1 String or True
2165 : {
2166 6498 : nIx = 0;
2167 : }
2168 : else
2169 : {
2170 27 : nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2);
2171 27 : if (nCheck == -1 || nCheck == 1)
2172 : {
2173 27 : nIx = 1;
2174 : }
2175 : else
2176 : {
2177 0 : nIx = 2;
2178 : }
2179 : }
2180 6532 : if (fNumber < 0.0 &&
2181 986 : ((nIx == 0 && IsFirstSubformatRealNegative()) || // 1st, usually positive subformat
2182 7 : (nIx == 1 && IsSecondSubformatRealNegative()))) // 2nd, usually negative subformat
2183 : {
2184 7 : fNumber = -fNumber; // eliminate sign
2185 : }
2186 6525 : *ppColor = NumFor[nIx].GetColor();
2187 6525 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2188 6525 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
2189 6525 : if (nAnz == 0 && rInfo.eScannedType == css::util::NumberFormat::UNDEFINED)
2190 : {
2191 0 : return false; // Empty => nothing
2192 : }
2193 6525 : else if (nAnz == 0) // Else Standard Format
2194 : {
2195 0 : ImpGetOutputStandard(fNumber, sBuff);
2196 0 : OutString = sBuff.makeStringAndClear();
2197 0 : return false;
2198 : }
2199 6525 : switch (rInfo.eScannedType)
2200 : {
2201 : case css::util::NumberFormat::TEXT:
2202 : case css::util::NumberFormat::DEFINED:
2203 40 : for (sal_uInt16 i = 0; i < nAnz; i++)
2204 : {
2205 20 : switch (rInfo.nTypeArray[i])
2206 : {
2207 : case NF_SYMBOLTYPE_STAR:
2208 0 : if( bStarFlag )
2209 : {
2210 0 : bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
2211 : }
2212 0 : break;
2213 : case NF_SYMBOLTYPE_BLANK:
2214 : InsertBlanks(sBuff, sBuff.getLength(),
2215 0 : rInfo.sStrArray[i][1] );
2216 0 : break;
2217 : case NF_SYMBOLTYPE_STRING:
2218 : case NF_SYMBOLTYPE_CURRENCY:
2219 20 : sBuff.append(rInfo.sStrArray[i]);
2220 20 : break;
2221 : case NF_SYMBOLTYPE_THSEP:
2222 0 : if (rInfo.nThousand == 0)
2223 : {
2224 0 : sBuff.append(rInfo.sStrArray[i]);
2225 : }
2226 0 : break;
2227 : default:
2228 0 : break;
2229 : }
2230 : }
2231 20 : break;
2232 : case css::util::NumberFormat::DATE:
2233 1528 : bRes |= ImpGetDateOutput(fNumber, nIx, sBuff);
2234 1528 : break;
2235 : case css::util::NumberFormat::TIME:
2236 208 : bRes |= ImpGetTimeOutput(fNumber, nIx, sBuff);
2237 208 : break;
2238 : case css::util::NumberFormat::DATETIME:
2239 11 : bRes |= ImpGetDateTimeOutput(fNumber, nIx, sBuff);
2240 11 : break;
2241 : case css::util::NumberFormat::NUMBER:
2242 : case css::util::NumberFormat::PERCENT:
2243 : case css::util::NumberFormat::CURRENCY:
2244 4699 : bRes |= ImpGetNumberOutput(fNumber, nIx, sBuff);
2245 4699 : break;
2246 : case css::util::NumberFormat::FRACTION:
2247 8 : bRes |= ImpGetFractionOutput(fNumber, nIx, sBuff);
2248 8 : break;
2249 : case css::util::NumberFormat::SCIENTIFIC:
2250 51 : bRes |= ImpGetScientificOutput(fNumber, nIx, sBuff);
2251 51 : break;
2252 : }
2253 : }
2254 13681 : OutString = sBuff.makeStringAndClear();
2255 13681 : return bRes;
2256 : }
2257 :
2258 51 : bool SvNumberformat::ImpGetScientificOutput(double fNumber,
2259 : sal_uInt16 nIx,
2260 : OUStringBuffer& sStr)
2261 : {
2262 51 : bool bRes = false;
2263 51 : bool bSign = false;
2264 :
2265 51 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2266 51 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
2267 :
2268 51 : if (fNumber < 0)
2269 : {
2270 3 : if (nIx == 0) // Not in the ones at the end
2271 : {
2272 3 : bSign = true; // Formats
2273 : }
2274 3 : fNumber = -fNumber;
2275 : }
2276 :
2277 102 : sStr = ::rtl::math::doubleToUString( fNumber,
2278 : rtl_math_StringFormat_E,
2279 102 : rInfo.nCntPre + rInfo.nCntPost - 1, '.' );
2280 51 : OUStringBuffer ExpStr;
2281 51 : short nExpSign = 1;
2282 51 : sal_Int32 nExPos = sStr.indexOf('E');
2283 :
2284 51 : if ( nExPos >= 0 )
2285 : {
2286 : // split into mantisse and exponent and get rid of "E+" or "E-"
2287 51 : sal_Int32 nExpStart = nExPos + 1;
2288 :
2289 51 : switch ( sStr[ nExpStart ] )
2290 : {
2291 : case '-' :
2292 7 : nExpSign = -1;
2293 : // fall through
2294 : case '+' :
2295 51 : ++nExpStart;
2296 51 : break;
2297 : }
2298 51 : ExpStr = sStr.toString().copy( nExpStart ); // part following the "E+"
2299 51 : sStr.truncate( nExPos );
2300 :
2301 51 : if ( rInfo.nCntPre != 1 ) // rescale Exp
2302 : {
2303 10 : sal_Int32 nExp = ExpStr.toString().toInt32() * nExpSign;
2304 10 : sal_Int32 nRescale = (rInfo.nCntPre != 0) ? nExp % (sal_Int32)rInfo.nCntPre : -1;
2305 10 : if( nRescale < 0 && rInfo.nCntPre != 0 )
2306 1 : nRescale += (sal_Int32)rInfo.nCntPre;
2307 10 : nExp -= nRescale;
2308 10 : if ( nExp < 0 )
2309 : {
2310 1 : nExpSign = -1;
2311 1 : nExp = -nExp;
2312 : }
2313 : else
2314 : {
2315 9 : nExpSign = 1;
2316 : }
2317 10 : ExpStr = OUString::number( nExp );
2318 : // rescale mantissa
2319 20 : sStr = ::rtl::math::doubleToUString( fNumber,
2320 : rtl_math_StringFormat_E,
2321 10 : nRescale + rInfo.nCntPost, '.' );
2322 10 : sStr.truncate( sStr.indexOf('E') );
2323 : }
2324 :
2325 : // cut any decimal delimiter
2326 51 : sal_Int32 index = 0;
2327 :
2328 152 : while((index = sStr.indexOf('.', index)) >= 0)
2329 : {
2330 50 : sStr.remove(index, 1);
2331 : }
2332 : }
2333 :
2334 51 : sal_uInt16 j = nAnz-1; // Last symbol
2335 : sal_Int32 k; // Position in ExpStr
2336 51 : sal_Int32 nZeros = 0; // Erase leading zeros
2337 :
2338 51 : bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP);
2339 :
2340 105 : while (nZeros < k && ExpStr[nZeros] == '0')
2341 : {
2342 3 : ++nZeros;
2343 : }
2344 51 : if (nZeros)
2345 : {
2346 3 : ExpStr.remove( 0, nZeros);
2347 : }
2348 :
2349 51 : bool bCont = true;
2350 :
2351 51 : if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP)
2352 : {
2353 51 : const OUString& rStr = rInfo.sStrArray[j];
2354 51 : if (nExpSign == -1)
2355 : {
2356 7 : ExpStr.insert(0, '-');
2357 : }
2358 44 : else if (rStr.getLength() > 1 && rStr[1] == '+')
2359 : {
2360 35 : ExpStr.insert(0, '+');
2361 : }
2362 51 : ExpStr.insert(0, rStr[0]);
2363 51 : if ( j )
2364 : {
2365 51 : j--;
2366 : }
2367 : else
2368 : {
2369 0 : bCont = false;
2370 : }
2371 : }
2372 : // Continure main number:
2373 51 : if ( !bCont )
2374 : {
2375 0 : sStr.truncate();
2376 : }
2377 : else
2378 : {
2379 51 : bRes |= ImpDecimalFill(sStr, fNumber, j, nIx, false);
2380 : }
2381 :
2382 51 : if (bSign)
2383 : {
2384 3 : sStr.insert(0, '-');
2385 : }
2386 51 : sStr.append(ExpStr);
2387 :
2388 51 : return bRes;
2389 : }
2390 :
2391 8 : bool SvNumberformat::ImpGetFractionOutput(double fNumber,
2392 : sal_uInt16 nIx,
2393 : OUStringBuffer& sBuff)
2394 : {
2395 8 : bool bRes = false;
2396 8 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2397 8 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
2398 16 : OUStringBuffer sStr, sFrac, sDiv; // Strings, value for
2399 : sal_uLong nFrac, nDiv; // Integral part
2400 8 : bool bSign = false; // Numerator and denominator
2401 :
2402 8 : if (fNumber < 0)
2403 : {
2404 0 : if (nIx == 0) // Not in the ones at the end
2405 0 : bSign = true; // Formats
2406 0 : fNumber = -fNumber;
2407 : }
2408 :
2409 8 : double fNum = floor(fNumber); // Integral part
2410 :
2411 8 : fNumber -= fNum; // Fractional part
2412 8 : if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9) // Too large
2413 : {
2414 0 : sBuff = rScan.GetErrorString();
2415 0 : return false;
2416 : }
2417 8 : if (rInfo.nCntExp == 0)
2418 : {
2419 : SAL_WARN( "svl.numbers", "SvNumberformat:: Fraction, nCntExp == 0");
2420 0 : sBuff.truncate();
2421 0 : return false;
2422 : }
2423 :
2424 8 : sal_uLong nBasis = ((sal_uLong)floor( pow(10.0,rInfo.nCntExp))) - 1; // 9, 99, 999 ,...
2425 : sal_uLong x0, y0, x1, y1;
2426 :
2427 8 : if (rInfo.nCntExp <= _MAX_FRACTION_PREC)
2428 : {
2429 : bool bUpperHalf;
2430 :
2431 8 : if (fNumber > 0.5)
2432 : {
2433 0 : bUpperHalf = true;
2434 0 : fNumber -= (fNumber - 0.5) * 2.0;
2435 : }
2436 : else
2437 : {
2438 8 : bUpperHalf = false;
2439 : }
2440 : // Find entry to Farey sequence:
2441 8 : x0 = (sal_uLong) floor(fNumber*nBasis); // e.g.: 2/9 <= x < 3/9
2442 8 : if (x0 == 0) // => x0 = 2
2443 : {
2444 0 : y0 = 1;
2445 0 : x1 = 1;
2446 0 : y1 = nBasis;
2447 : }
2448 8 : else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2
2449 : { // is ok (nBasis is odd)
2450 0 : y0 = nBasis;
2451 0 : x1 = 1;
2452 0 : y1 = 2;
2453 : }
2454 8 : else if (x0 == 1)
2455 : {
2456 4 : y0 = nBasis; // 1/n; 1/(n-1)
2457 4 : x1 = 1;
2458 4 : y1 = nBasis - 1;
2459 : }
2460 : else
2461 : {
2462 4 : y0 = nBasis; // e.g.: 2/9 2/8
2463 4 : x1 = x0;
2464 4 : y1 = nBasis - 1;
2465 4 : double fUg = (double) x0 / (double) y0;
2466 4 : double fOg = (double) x1 / (double) y1;
2467 4 : sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen
2468 4 : x0 /= nGgt;
2469 4 : y0 /= nGgt; // Nest:
2470 4 : sal_uLong x2 = 0;
2471 4 : sal_uLong y2 = 0;
2472 4 : bool bStop = false;
2473 17 : while (!bStop)
2474 : {
2475 : #ifdef __GNUC__
2476 : // #i21648# GCC over-optimizes something resulting
2477 : // in wrong fTest values throughout the loops.
2478 : volatile
2479 : #endif
2480 9 : double fTest = (double)x1/(double)y1;
2481 28 : while (!bStop)
2482 : {
2483 26 : while (fTest > fOg)
2484 : {
2485 6 : x1--;
2486 6 : fTest = (double)x1/(double)y1;
2487 : }
2488 28 : while (fTest < fUg && y1 > 1)
2489 : {
2490 8 : y1--;
2491 8 : fTest = (double)x1/(double)y1;
2492 : }
2493 10 : if (fTest <= fOg)
2494 : {
2495 9 : fOg = fTest;
2496 9 : bStop = true;
2497 : }
2498 1 : else if (y1 == 1)
2499 : {
2500 0 : bStop = true;
2501 : }
2502 : } // of while
2503 9 : nGgt = ImpGGT(y1, x1); // Shorten x1/y1
2504 9 : x2 = x1 / nGgt;
2505 9 : y2 = y1 / nGgt;
2506 9 : if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test for x2/y2
2507 4 : bStop = true; // Next Farey number
2508 : else
2509 : {
2510 5 : y1--;
2511 5 : bStop = false;
2512 : }
2513 : } // of while
2514 4 : x1 = x2;
2515 4 : y1 = y2;
2516 : } // of else
2517 :
2518 : double fup, flow;
2519 :
2520 8 : flow = (double)x0/(double)y0;
2521 8 : fup = (double)x1/(double)y1;
2522 70 : while (fNumber > fup)
2523 : {
2524 54 : sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // Next Farey number
2525 54 : sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0;
2526 :
2527 54 : x0 = x1;
2528 54 : y0 = y1;
2529 54 : x1 = x2;
2530 54 : y1 = y2;
2531 54 : flow = fup;
2532 54 : fup = (double)x1/(double)y1;
2533 : }
2534 8 : if (fNumber - flow < fup - fNumber)
2535 : {
2536 3 : nFrac = x0;
2537 3 : nDiv = y0;
2538 : }
2539 : else
2540 : {
2541 5 : nFrac = x1;
2542 5 : nDiv = y1;
2543 : }
2544 8 : if (bUpperHalf) // Recover original
2545 : {
2546 0 : if (nFrac == 0 && nDiv == 1) // 1/1
2547 : {
2548 0 : fNum += 1.0;
2549 : }
2550 : else
2551 : {
2552 0 : nFrac = nDiv - nFrac;
2553 : }
2554 : }
2555 : }
2556 : else // Large denominator
2557 : { // 0,1234->123/1000
2558 : sal_uLong nGgt;
2559 :
2560 0 : nDiv = 10000000;
2561 0 : nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0));
2562 0 : nGgt = ImpGGT(nDiv, nFrac);
2563 0 : if (nGgt > 1)
2564 : {
2565 0 : nDiv /= nGgt;
2566 0 : nFrac /= nGgt;
2567 : }
2568 0 : if (nDiv > nBasis)
2569 : {
2570 0 : nGgt = ImpGGTRound(nDiv, nFrac);
2571 0 : if (nGgt > 1)
2572 : {
2573 0 : nDiv /= nGgt;
2574 0 : nFrac /= nGgt;
2575 : }
2576 : }
2577 0 : if (nDiv > nBasis)
2578 : {
2579 0 : nDiv = nBasis;
2580 0 : nFrac = ((sal_uLong)floor(0.5 + fNumber *
2581 0 : pow(10.0,rInfo.nCntExp)));
2582 0 : nGgt = ImpGGTRound(nDiv, nFrac);
2583 0 : if (nGgt > 1)
2584 : {
2585 0 : nDiv /= nGgt;
2586 0 : nFrac /= nGgt;
2587 : }
2588 : }
2589 : }
2590 :
2591 8 : if( sal_Int32 nForcedDiv = lcl_GetForcedDenominator(NumFor[nIx].Info(), nAnz) )
2592 : {
2593 0 : lcl_ForcedDenominator(nFrac, nDiv, nForcedDiv);
2594 0 : if( nFrac >= nDiv )
2595 : {
2596 0 : nFrac = nDiv = 0;
2597 0 : fNum = fNum + 1.0;
2598 : }
2599 : }
2600 :
2601 8 : if (rInfo.nCntPre == 0) // Improper fraction
2602 : {
2603 0 : double fNum1 = fNum * (double)nDiv + (double)nFrac;
2604 :
2605 0 : if (fNum1 > _D_MAX_U_LONG_)
2606 : {
2607 0 : sBuff = rScan.GetErrorString();
2608 0 : return false;
2609 : }
2610 0 : nFrac = (sal_uLong) floor(fNum1);
2611 : }
2612 8 : else if (fNum == 0.0 && nFrac != 0)
2613 : {
2614 : }
2615 : else
2616 : {
2617 : char aBuf[100];
2618 7 : sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked)
2619 7 : sStr.appendAscii( aBuf );
2620 7 : impTransliterate(sStr, NumFor[nIx].GetNatNum());
2621 : }
2622 8 : if (rInfo.nCntPre > 0 && nFrac == 0)
2623 : {
2624 0 : sDiv.truncate();
2625 : }
2626 : else
2627 : {
2628 8 : sFrac = ImpIntToString( nIx, nFrac );
2629 8 : sDiv = ImpIntToString( nIx, nDiv );
2630 : }
2631 :
2632 8 : sal_uInt16 j = nAnz-1; // Last symbol -> backwards
2633 : sal_Int32 k; // Denominator
2634 :
2635 8 : bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC);
2636 :
2637 8 : bool bCont = true;
2638 8 : if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC)
2639 : {
2640 8 : if (rInfo.nCntPre > 0 && nFrac == 0)
2641 : {
2642 0 : sDiv.insert(0, ' ');
2643 : }
2644 : else
2645 : {
2646 8 : sDiv.insert(0, rInfo.sStrArray[j][0]);
2647 : }
2648 8 : if ( j )
2649 : {
2650 8 : j--;
2651 : }
2652 : else
2653 : {
2654 0 : bCont = false;
2655 : }
2656 : }
2657 : // Further numerators:
2658 8 : if ( !bCont )
2659 : {
2660 0 : sFrac.truncate();
2661 : }
2662 : else
2663 : {
2664 8 : bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK);
2665 8 : if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK)
2666 : {
2667 8 : sFrac.insert(0, rInfo.sStrArray[j]);
2668 8 : if ( j )
2669 : {
2670 8 : j--;
2671 : }
2672 : else
2673 : {
2674 0 : bCont = false;
2675 : }
2676 : }
2677 : }
2678 : // Continue main number
2679 8 : if ( !bCont )
2680 : {
2681 0 : sStr.truncate();
2682 : }
2683 : else
2684 : {
2685 8 : k = sStr.getLength(); // After last figure
2686 : bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx,
2687 8 : rInfo.nCntPre);
2688 : }
2689 8 : if (bSign && !(nFrac == 0 && fNum == 0.0))
2690 : {
2691 0 : sBuff.insert(0, '-'); // Not -0
2692 : }
2693 8 : sBuff.append(sStr);
2694 8 : sBuff.append(sFrac);
2695 8 : sBuff.append(sDiv);
2696 16 : return bRes;
2697 : }
2698 :
2699 358 : bool SvNumberformat::ImpGetTimeOutput(double fNumber,
2700 : sal_uInt16 nIx,
2701 : OUStringBuffer& sBuff)
2702 : {
2703 : using namespace ::com::sun::star::i18n;
2704 358 : bool bCalendarSet = false;
2705 358 : double fNumberOrig = fNumber;
2706 358 : bool bRes = false;
2707 358 : bool bSign = false;
2708 358 : if (fNumber < 0.0)
2709 : {
2710 0 : fNumber = -fNumber;
2711 0 : if (nIx == 0)
2712 : {
2713 0 : bSign = true;
2714 : }
2715 : }
2716 358 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
2717 358 : if (rInfo.bThousand) // [] format
2718 : {
2719 0 : if (fNumber > 1.0E10) // Too large
2720 : {
2721 0 : sBuff = rScan.GetErrorString();
2722 0 : return false;
2723 : }
2724 : }
2725 : else
2726 : {
2727 358 : fNumber -= floor(fNumber); // Else truncate date
2728 : }
2729 : bool bInputLine;
2730 : sal_Int32 nCntPost;
2731 716 : if ( rScan.GetStandardPrec() == 300 &&
2732 358 : 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
2733 : { // round at 7 decimals (+5 of 86400 == 12 significant digits)
2734 0 : bInputLine = true;
2735 0 : nCntPost = 7;
2736 : }
2737 : else
2738 : {
2739 358 : bInputLine = false;
2740 358 : nCntPost = rInfo.nCntPost;
2741 : }
2742 358 : if (bSign && !rInfo.bThousand) // No [] format
2743 : {
2744 0 : fNumber = 1.0 - fNumber; // "Inverse"
2745 : }
2746 358 : double fTime = fNumber * 86400.0;
2747 358 : fTime = ::rtl::math::round( fTime, int(nCntPost) );
2748 358 : if (bSign && fTime == 0.0)
2749 : {
2750 0 : bSign = false; // Not -00:00:00
2751 : }
2752 358 : if( floor( fTime ) > _D_MAX_U_LONG_ )
2753 : {
2754 0 : sBuff = rScan.GetErrorString();
2755 0 : return false;
2756 : }
2757 358 : sal_uLong nSeconds = (sal_uLong)floor( fTime );
2758 :
2759 : OUStringBuffer sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
2760 358 : rtl_math_StringFormat_F, int(nCntPost), '.'));
2761 358 : sSecStr.stripStart('0');
2762 358 : sSecStr.stripStart('.');
2763 358 : if ( bInputLine )
2764 : {
2765 0 : sSecStr.stripEnd('0');
2766 0 : for(sal_Int32 index = sSecStr.getLength(); index < rInfo.nCntPost; ++index)
2767 : {
2768 0 : sSecStr.append('0');
2769 : }
2770 0 : impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
2771 0 : nCntPost = sSecStr.getLength();
2772 : }
2773 : else
2774 : {
2775 358 : impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
2776 : }
2777 :
2778 358 : sal_Int32 nSecPos = 0; // For figure by figure processing
2779 : sal_uLong nHour, nMin, nSec;
2780 358 : if (!rInfo.bThousand) // No [] format
2781 : {
2782 358 : nHour = (nSeconds/3600) % 24;
2783 358 : nMin = (nSeconds%3600) / 60;
2784 358 : nSec = nSeconds%60;
2785 : }
2786 0 : else if (rInfo.nThousand == 3) // [ss]
2787 : {
2788 0 : nHour = 0;
2789 0 : nMin = 0;
2790 0 : nSec = nSeconds;
2791 : }
2792 0 : else if (rInfo.nThousand == 2) // [mm]:ss
2793 : {
2794 0 : nHour = 0;
2795 0 : nMin = nSeconds / 60;
2796 0 : nSec = nSeconds % 60;
2797 : }
2798 0 : else if (rInfo.nThousand == 1) // [hh]:mm:ss
2799 : {
2800 0 : nHour = nSeconds / 3600;
2801 0 : nMin = (nSeconds%3600) / 60;
2802 0 : nSec = nSeconds%60;
2803 : }
2804 : else
2805 : {
2806 : // TODO What should these be set to?
2807 0 : nHour = 0;
2808 0 : nMin = 0;
2809 0 : nSec = 0;
2810 : }
2811 :
2812 358 : sal_Unicode cAmPm = ' '; // a or p
2813 358 : if (rInfo.nCntExp) // AM/PM
2814 : {
2815 150 : if (nHour == 0)
2816 : {
2817 13 : nHour = 12;
2818 13 : cAmPm = 'a';
2819 : }
2820 137 : else if (nHour < 12)
2821 : {
2822 85 : cAmPm = 'a';
2823 : }
2824 : else
2825 : {
2826 52 : cAmPm = 'p';
2827 52 : if (nHour > 12)
2828 : {
2829 42 : nHour -= 12;
2830 : }
2831 : }
2832 : }
2833 358 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
2834 2418 : for (sal_uInt16 i = 0; i < nAnz; i++)
2835 : {
2836 : sal_Int32 nLen;
2837 2060 : switch (rInfo.nTypeArray[i])
2838 : {
2839 : case NF_SYMBOLTYPE_STAR:
2840 0 : if( bStarFlag )
2841 : {
2842 0 : bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
2843 : }
2844 0 : break;
2845 : case NF_SYMBOLTYPE_BLANK:
2846 : InsertBlanks(sBuff, sBuff.getLength(),
2847 0 : rInfo.sStrArray[i][1] );
2848 0 : break;
2849 : case NF_SYMBOLTYPE_STRING:
2850 : case NF_SYMBOLTYPE_CURRENCY:
2851 : case NF_SYMBOLTYPE_DATESEP:
2852 : case NF_SYMBOLTYPE_TIMESEP:
2853 : case NF_SYMBOLTYPE_TIME100SECSEP:
2854 851 : sBuff.append(rInfo.sStrArray[i]);
2855 851 : break;
2856 : case NF_SYMBOLTYPE_DIGIT:
2857 0 : nLen = ( bInputLine && i > 0 &&
2858 0 : (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
2859 0 : rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
2860 0 : nCntPost : rInfo.sStrArray[i].getLength() );
2861 0 : for (sal_Int32 j = 0; j < nLen && nSecPos < nCntPost; j++)
2862 : {
2863 0 : sBuff.append(sSecStr[nSecPos]);
2864 0 : nSecPos++;
2865 : }
2866 0 : break;
2867 : case NF_KEY_AMPM: // AM/PM
2868 150 : if ( !bCalendarSet )
2869 : {
2870 150 : double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart();
2871 150 : fDiff += fNumberOrig;
2872 150 : GetCal().setLocalDateTime( fDiff );
2873 150 : bCalendarSet = true;
2874 : }
2875 150 : if (cAmPm == 'a')
2876 : {
2877 98 : sBuff.append(GetCal().getDisplayName(
2878 98 : CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 ));
2879 : }
2880 : else
2881 : {
2882 52 : sBuff.append(GetCal().getDisplayName(
2883 52 : CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 ));
2884 : }
2885 150 : break;
2886 : case NF_KEY_AP: // A/P
2887 0 : if (cAmPm == 'a')
2888 : {
2889 0 : sBuff.append('a');
2890 : }
2891 : else
2892 : {
2893 0 : sBuff.append('p');
2894 : }
2895 0 : break;
2896 : case NF_KEY_MI: // M
2897 0 : sBuff.append(ImpIntToString( nIx, nMin ));
2898 0 : break;
2899 : case NF_KEY_MMI: // MM
2900 358 : sBuff.append(ImpIntToString( nIx, nMin, 2 ));
2901 358 : break;
2902 : case NF_KEY_H: // H
2903 0 : sBuff.append(ImpIntToString( nIx, nHour ));
2904 0 : break;
2905 : case NF_KEY_HH: // HH
2906 358 : sBuff.append(ImpIntToString( nIx, nHour, 2 ));
2907 358 : break;
2908 : case NF_KEY_S: // S
2909 0 : sBuff.append(ImpIntToString( nIx, nSec ));
2910 0 : break;
2911 : case NF_KEY_SS: // SS
2912 343 : sBuff.append(ImpIntToString( nIx, nSec, 2 ));
2913 343 : break;
2914 : default:
2915 0 : break;
2916 : }
2917 : }
2918 358 : if (bSign && rInfo.bThousand)
2919 : {
2920 0 : sBuff.insert(0, '-');
2921 : }
2922 358 : return bRes;
2923 : }
2924 :
2925 :
2926 : /** If a day of month occurs within the format, the month name is in possessive
2927 : genitive case if the day follows the month, and partitive case if the day
2928 : precedes the month. If there is no day of month the nominative case (noun)
2929 : is returned. Also if the month is immediately preceded or followed by a
2930 : literal string other than space the nominative name is used, this prevents
2931 : duplicated casing for MMMM\t\a and such in documents imported from (e.g.
2932 : Finnish) Excel or older LibO/OOo releases.
2933 : */
2934 :
2935 : // IDEA: instead of eCodeType pass the index to nTypeArray and restrict
2936 : // inspection of month name around that one, that would enable different month
2937 : // cases in one format. Though probably the most rare use case ever..
2938 :
2939 782 : sal_Int32 SvNumberformat::ImpUseMonthCase( int & io_nState, const ImpSvNumFor& rNumFor, NfKeywordIndex eCodeType ) const
2940 : {
2941 : using namespace ::com::sun::star::i18n;
2942 782 : if (!io_nState)
2943 : {
2944 782 : bool bMonthSeen = false;
2945 782 : bool bDaySeen = false;
2946 782 : const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
2947 782 : const sal_uInt16 nCount = rNumFor.GetCount();
2948 3138 : for (sal_uInt16 i = 0; i < nCount && io_nState == 0; ++i)
2949 : {
2950 : sal_Int32 nLen;
2951 2356 : switch (rInfo.nTypeArray[i])
2952 : {
2953 : case NF_KEY_D :
2954 : case NF_KEY_DD :
2955 776 : if (bMonthSeen)
2956 : {
2957 763 : io_nState = 2;
2958 : }
2959 : else
2960 : {
2961 13 : bDaySeen = true;
2962 : }
2963 776 : break;
2964 : case NF_KEY_MMM:
2965 : case NF_KEY_MMMM:
2966 : case NF_KEY_MMMMM:
2967 2346 : if ((i < nCount-1 &&
2968 1564 : rInfo.nTypeArray[i+1] == NF_SYMBOLTYPE_STRING &&
2969 2346 : rInfo.sStrArray[i+1][0] != ' ') ||
2970 26 : (i > 0 && rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING &&
2971 26 : ((nLen = rInfo.sStrArray[i-1].getLength()) > 0) &&
2972 13 : rInfo.sStrArray[i-1][nLen-1] != ' '))
2973 : {
2974 6 : io_nState = 1;
2975 : }
2976 776 : else if (bDaySeen)
2977 : {
2978 13 : io_nState = 3;
2979 : }
2980 : else
2981 : {
2982 763 : bMonthSeen = true;
2983 : }
2984 782 : break;
2985 : }
2986 : }
2987 782 : if (io_nState == 0)
2988 : {
2989 0 : io_nState = 1; // No day of month
2990 : }
2991 : }
2992 782 : switch (io_nState)
2993 : {
2994 : case 1:
2995 : // No day of month or forced nominative
2996 6 : switch (eCodeType)
2997 : {
2998 : case NF_KEY_MMM:
2999 6 : return CalendarDisplayCode::SHORT_MONTH_NAME;
3000 : case NF_KEY_MMMM:
3001 0 : return CalendarDisplayCode::LONG_MONTH_NAME;
3002 : case NF_KEY_MMMMM:
3003 0 : return CalendarDisplayCode::NARROW_MONTH_NAME;
3004 : default:
3005 : ; // nothing
3006 : }
3007 : case 2:
3008 : // Day of month follows month (the month's 17th)
3009 763 : switch (eCodeType)
3010 : {
3011 : case NF_KEY_MMM:
3012 763 : return CalendarDisplayCode::SHORT_GENITIVE_MONTH_NAME;
3013 : case NF_KEY_MMMM:
3014 0 : return CalendarDisplayCode::LONG_GENITIVE_MONTH_NAME;
3015 : case NF_KEY_MMMMM:
3016 0 : return CalendarDisplayCode::NARROW_GENITIVE_MONTH_NAME;
3017 : default:
3018 : ; // Nothing
3019 : }
3020 : case 3:
3021 : // Day of month precedes month (17 of month)
3022 13 : switch (eCodeType)
3023 : {
3024 : case NF_KEY_MMM:
3025 0 : return CalendarDisplayCode::SHORT_PARTITIVE_MONTH_NAME;
3026 : case NF_KEY_MMMM:
3027 13 : return CalendarDisplayCode::LONG_PARTITIVE_MONTH_NAME;
3028 : case NF_KEY_MMMMM:
3029 0 : return CalendarDisplayCode::NARROW_PARTITIVE_MONTH_NAME;
3030 : default:
3031 : ; // nothing
3032 : }
3033 : }
3034 : SAL_WARN( "svl.numbers", "ImpUseMonthCase: unhandled keyword index eCodeType");
3035 0 : return CalendarDisplayCode::LONG_MONTH_NAME;
3036 : }
3037 :
3038 :
3039 1701 : bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const
3040 : {
3041 1701 : if ( GetCal().getUniqueID() != GREGORIAN )
3042 : {
3043 0 : return false;
3044 : }
3045 1701 : const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
3046 1701 : const sal_uInt16 nAnz = rNumFor.GetCount();
3047 : sal_uInt16 i;
3048 8824 : for ( i = 0; i < nAnz; i++ )
3049 : {
3050 7129 : switch ( rInfo.nTypeArray[i] )
3051 : {
3052 : case NF_SYMBOLTYPE_CALENDAR :
3053 4 : return false;
3054 : case NF_KEY_EC :
3055 : case NF_KEY_EEC :
3056 : case NF_KEY_R :
3057 : case NF_KEY_RR :
3058 : case NF_KEY_AAA :
3059 : case NF_KEY_AAAA :
3060 2 : return true;
3061 : }
3062 : }
3063 1695 : return false;
3064 : }
3065 :
3066 2 : void SvNumberformat::SwitchToOtherCalendar( OUString& rOrgCalendar,
3067 : double& fOrgDateTime ) const
3068 : {
3069 2 : CalendarWrapper& rCal = GetCal();
3070 2 : if ( rCal.getUniqueID() == GREGORIAN )
3071 : {
3072 : using namespace ::com::sun::star::i18n;
3073 : ::com::sun::star::uno::Sequence< OUString > xCals = rCal.getAllCalendars(
3074 2 : rLoc().getLanguageTag().getLocale() );
3075 2 : sal_Int32 nCnt = xCals.getLength();
3076 2 : if ( nCnt > 1 )
3077 : {
3078 4 : for ( sal_Int32 j=0; j < nCnt; j++ )
3079 : {
3080 4 : if ( xCals[j] != GREGORIAN )
3081 : {
3082 2 : if ( !rOrgCalendar.getLength() )
3083 : {
3084 2 : rOrgCalendar = rCal.getUniqueID();
3085 2 : fOrgDateTime = rCal.getDateTime();
3086 : }
3087 2 : rCal.loadCalendar( xCals[j], rLoc().getLanguageTag().getLocale() );
3088 2 : rCal.setDateTime( fOrgDateTime );
3089 2 : break; // for
3090 : }
3091 : }
3092 2 : }
3093 : }
3094 2 : }
3095 :
3096 0 : void SvNumberformat::SwitchToGregorianCalendar( const OUString& rOrgCalendar,
3097 : double fOrgDateTime ) const
3098 : {
3099 0 : CalendarWrapper& rCal = GetCal();
3100 0 : if ( rOrgCalendar.getLength() && rCal.getUniqueID() != GREGORIAN )
3101 : {
3102 0 : rCal.loadCalendar( GREGORIAN, rLoc().getLanguageTag().getLocale() );
3103 0 : rCal.setDateTime( fOrgDateTime );
3104 : }
3105 0 : }
3106 :
3107 1705 : bool SvNumberformat::ImpFallBackToGregorianCalendar( OUString& rOrgCalendar, double& fOrgDateTime )
3108 : {
3109 : using namespace ::com::sun::star::i18n;
3110 1705 : CalendarWrapper& rCal = GetCal();
3111 1705 : if ( rCal.getUniqueID() != GREGORIAN )
3112 : {
3113 6 : sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
3114 6 : if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID == "Dummy" )
3115 : {
3116 0 : if ( !rOrgCalendar.getLength() )
3117 : {
3118 0 : rOrgCalendar = rCal.getUniqueID();
3119 0 : fOrgDateTime = rCal.getDateTime();
3120 : }
3121 0 : else if ( rOrgCalendar == GREGORIAN )
3122 : {
3123 0 : rOrgCalendar.clear();
3124 : }
3125 0 : rCal.loadCalendar( GREGORIAN, rLoc().getLanguageTag().getLocale() );
3126 0 : rCal.setDateTime( fOrgDateTime );
3127 0 : return true;
3128 : }
3129 : }
3130 1705 : return false;
3131 : }
3132 :
3133 :
3134 : #ifdef THE_FUTURE
3135 : /* XXX NOTE: even if the ImpSwitchToSpecifiedCalendar method is currently
3136 : * unused please don't remove it, it would be needed by
3137 : * SwitchToSpecifiedCalendar(), see comment in
3138 : * ImpSvNumberInputScan::GetDateRef() */
3139 :
3140 : bool SvNumberformat::ImpSwitchToSpecifiedCalendar( OUString& rOrgCalendar,
3141 : double& fOrgDateTime,
3142 : const ImpSvNumFor& rNumFor ) const
3143 : {
3144 : const ImpSvNumberformatInfo& rInfo = rNumFor.Info();
3145 : const sal_uInt16 nAnz = rNumFor.GetCount();
3146 : for ( sal_uInt16 i = 0; i < nAnz; i++ )
3147 : {
3148 : if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR )
3149 : {
3150 : CalendarWrapper& rCal = GetCal();
3151 : if ( !rOrgCalendar.getLength() )
3152 : {
3153 : rOrgCalendar = rCal.getUniqueID();
3154 : fOrgDateTime = rCal.getDateTime();
3155 : }
3156 : rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() );
3157 : rCal.setDateTime( fOrgDateTime );
3158 : return true;
3159 : }
3160 : }
3161 : return false;
3162 : }
3163 : #endif
3164 :
3165 : // static
3166 0 : void SvNumberformat::ImpAppendEraG( OUStringBuffer& OutString,
3167 : const CalendarWrapper& rCal,
3168 : sal_Int16 nNatNum )
3169 : {
3170 : using namespace ::com::sun::star::i18n;
3171 0 : if ( rCal.getUniqueID() == "gengou" )
3172 : {
3173 : sal_Unicode cEra;
3174 0 : sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA );
3175 0 : switch ( nVal )
3176 : {
3177 : case 1:
3178 0 : cEra = 'M';
3179 0 : break;
3180 : case 2:
3181 0 : cEra = 'T';
3182 0 : break;
3183 : case 3:
3184 0 : cEra = 'S';
3185 0 : break;
3186 : case 4:
3187 0 : cEra = 'H';
3188 0 : break;
3189 : default:
3190 0 : cEra = '?';
3191 0 : break;
3192 : }
3193 0 : OutString.append(cEra);
3194 : }
3195 : else
3196 : {
3197 0 : OutString.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ));
3198 : }
3199 0 : }
3200 :
3201 10 : bool SvNumberformat::ImpIsIso8601( const ImpSvNumFor& rNumFor )
3202 : {
3203 10 : bool bIsIso = false;
3204 10 : if ((eType & css::util::NumberFormat::DATE) == css::util::NumberFormat::DATE)
3205 : {
3206 : enum State
3207 : {
3208 : eNone,
3209 : eAtYear,
3210 : eAtSep1,
3211 : eAtMonth,
3212 : eAtSep2,
3213 : eNotIso
3214 : };
3215 10 : State eState = eNone;
3216 10 : short const * const pType = rNumFor.Info().nTypeArray;
3217 10 : sal_uInt16 nAnz = rNumFor.GetCount();
3218 20 : for (sal_uInt16 i=0; i < nAnz && !bIsIso && eState != eNotIso; ++i)
3219 : {
3220 10 : switch ( pType[i] )
3221 : {
3222 : case NF_KEY_YY: // two digits not strictly ISO 8601
3223 : case NF_KEY_YYYY:
3224 0 : if (eState != eNone)
3225 : {
3226 0 : eState = eNotIso;
3227 : }
3228 : else
3229 : {
3230 0 : eState = eAtYear;
3231 : }
3232 0 : break;
3233 : case NF_KEY_M: // single digit not strictly ISO 8601
3234 : case NF_KEY_MM:
3235 10 : if (eState != eAtSep1)
3236 : {
3237 10 : eState = eNotIso;
3238 : }
3239 : else
3240 : {
3241 0 : eState = eAtMonth;
3242 : }
3243 10 : break;
3244 : case NF_KEY_D: // single digit not strictly ISO 8601
3245 : case NF_KEY_DD:
3246 0 : if (eState != eAtSep2)
3247 : {
3248 0 : eState = eNotIso;
3249 : }
3250 : else
3251 : {
3252 0 : bIsIso = true;
3253 : }
3254 0 : break;
3255 : case NF_SYMBOLTYPE_STRING:
3256 : case NF_SYMBOLTYPE_DATESEP:
3257 0 : if (comphelper::string::equals(rNumFor.Info().sStrArray[i], '-'))
3258 : {
3259 0 : if (eState == eAtYear)
3260 : {
3261 0 : eState = eAtSep1;
3262 : }
3263 0 : else if (eState == eAtMonth)
3264 : {
3265 0 : eState = eAtSep2;
3266 : }
3267 : else
3268 : {
3269 0 : eState = eNotIso;
3270 : }
3271 : }
3272 : else
3273 : {
3274 0 : eState = eNotIso;
3275 : }
3276 0 : break;
3277 : default:
3278 0 : eState = eNotIso;
3279 : }
3280 : }
3281 : }
3282 : else
3283 : {
3284 : SAL_WARN( "svl.numbers", "SvNumberformat::ImpIsIso8601: no date" );
3285 : }
3286 10 : return bIsIso;
3287 : }
3288 :
3289 1688 : bool SvNumberformat::ImpGetDateOutput(double fNumber,
3290 : sal_uInt16 nIx,
3291 : OUStringBuffer& sBuff)
3292 : {
3293 : using namespace ::com::sun::star::i18n;
3294 1688 : bool bRes = false;
3295 :
3296 1688 : CalendarWrapper& rCal = GetCal();
3297 1688 : double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
3298 1688 : fNumber += fDiff;
3299 1688 : rCal.setLocalDateTime( fNumber );
3300 1688 : int nUseMonthCase = 0; // Not decided yet
3301 1688 : OUString aOrgCalendar; // empty => not changed yet
3302 :
3303 1688 : double fOrgDateTime(0.0);
3304 1688 : bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
3305 1688 : if ( bOtherCalendar )
3306 : {
3307 2 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3308 : }
3309 1688 : if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
3310 : {
3311 0 : bOtherCalendar = false;
3312 : }
3313 1688 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3314 1688 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
3315 1688 : sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
3316 3376 : OUString aYear;
3317 :
3318 8686 : for (sal_uInt16 i = 0; i < nAnz; i++)
3319 : {
3320 6998 : switch (rInfo.nTypeArray[i])
3321 : {
3322 : case NF_SYMBOLTYPE_CALENDAR :
3323 4 : if ( !aOrgCalendar.getLength() )
3324 : {
3325 4 : aOrgCalendar = rCal.getUniqueID();
3326 4 : fOrgDateTime = rCal.getDateTime();
3327 : }
3328 4 : rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLanguageTag().getLocale() );
3329 4 : rCal.setDateTime( fOrgDateTime );
3330 4 : ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3331 4 : break;
3332 : case NF_SYMBOLTYPE_STAR:
3333 0 : if( bStarFlag )
3334 : {
3335 0 : bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
3336 : }
3337 0 : break;
3338 : case NF_SYMBOLTYPE_BLANK:
3339 0 : InsertBlanks( sBuff, sBuff.getLength(), rInfo.sStrArray[i][1] );
3340 0 : break;
3341 : case NF_SYMBOLTYPE_STRING:
3342 : case NF_SYMBOLTYPE_CURRENCY:
3343 : case NF_SYMBOLTYPE_DATESEP:
3344 : case NF_SYMBOLTYPE_TIMESEP:
3345 : case NF_SYMBOLTYPE_TIME100SECSEP:
3346 2649 : sBuff.append(rInfo.sStrArray[i]);
3347 2649 : break;
3348 : case NF_KEY_M: // M
3349 65 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_MONTH, nNatNum ));
3350 65 : break;
3351 : case NF_KEY_MM: // MM
3352 841 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_MONTH, nNatNum ));
3353 841 : break;
3354 : case NF_KEY_MMM: // MMM
3355 769 : sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
3356 769 : static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
3357 2307 : nNatNum));
3358 769 : break;
3359 : case NF_KEY_MMMM: // MMMM
3360 13 : sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
3361 13 : static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
3362 39 : nNatNum));
3363 13 : break;
3364 : case NF_KEY_MMMMM: // MMMMM
3365 0 : sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
3366 0 : static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
3367 0 : nNatNum));
3368 0 : break;
3369 : case NF_KEY_Q: // Q
3370 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_QUARTER, nNatNum ));
3371 0 : break;
3372 : case NF_KEY_QQ: // QQ
3373 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum ));
3374 0 : break;
3375 : case NF_KEY_D: // D
3376 113 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum ));
3377 113 : break;
3378 : case NF_KEY_DD: // DD
3379 1569 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum ));
3380 1569 : break;
3381 : case NF_KEY_DDD: // DDD
3382 11 : if ( bOtherCalendar )
3383 : {
3384 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3385 : }
3386 11 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
3387 11 : if ( bOtherCalendar )
3388 : {
3389 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3390 : }
3391 11 : break;
3392 : case NF_KEY_DDDD: // DDDD
3393 0 : if ( bOtherCalendar )
3394 : {
3395 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3396 : }
3397 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
3398 0 : if ( bOtherCalendar )
3399 : {
3400 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3401 : }
3402 0 : break;
3403 : case NF_KEY_YY: // YY
3404 243 : if ( bOtherCalendar )
3405 : {
3406 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3407 : }
3408 243 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
3409 243 : if ( bOtherCalendar )
3410 : {
3411 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3412 : }
3413 243 : break;
3414 : case NF_KEY_YYYY: // YYYY
3415 709 : if ( bOtherCalendar )
3416 : {
3417 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3418 : }
3419 709 : aYear = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum );
3420 709 : if (aYear.getLength() < 4)
3421 : {
3422 : using namespace comphelper::string;
3423 : // Ensure that year consists of at least 4 digits, so it
3424 : // can be distinguished from 2 digits display and edited
3425 : // without suddenly being hit by the 2-digit year magic.
3426 0 : OUStringBuffer aBuf;
3427 0 : padToLength(aBuf, 4 - aYear.getLength(), '0');
3428 0 : impTransliterate(aBuf, NumFor[nIx].GetNatNum());
3429 0 : aBuf.append(aYear);
3430 0 : sBuff.append(aBuf);
3431 : }
3432 : else
3433 : {
3434 709 : sBuff.append(aYear);
3435 : }
3436 709 : if ( bOtherCalendar )
3437 : {
3438 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3439 : }
3440 709 : break;
3441 : case NF_KEY_EC: // E
3442 1 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
3443 1 : break;
3444 : case NF_KEY_EEC: // EE
3445 : case NF_KEY_R: // R
3446 1 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum ));
3447 1 : break;
3448 : case NF_KEY_NN: // NN
3449 : case NF_KEY_AAA: // AAA
3450 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
3451 0 : break;
3452 : case NF_KEY_NNN: // NNN
3453 : case NF_KEY_AAAA: // AAAA
3454 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
3455 0 : break;
3456 : case NF_KEY_NNNN: // NNNN
3457 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
3458 0 : sBuff.append(rLoc().getLongDateDayOfWeekSep());
3459 0 : break;
3460 : case NF_KEY_WW : // WW
3461 : sBuff.append(ImpIntToString( nIx,
3462 0 : rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR )));
3463 0 : break;
3464 : case NF_KEY_G: // G
3465 0 : ImpAppendEraG(sBuff, rCal, nNatNum );
3466 0 : break;
3467 : case NF_KEY_GG: // GG
3468 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ));
3469 0 : break;
3470 : case NF_KEY_GGG: // GGG
3471 2 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_ERA, nNatNum ));
3472 2 : break;
3473 : case NF_KEY_RR: // RR => GGGEE
3474 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ));
3475 0 : break;
3476 : }
3477 : }
3478 1688 : if ( aOrgCalendar.getLength() )
3479 : {
3480 6 : rCal.loadCalendar( aOrgCalendar, rLoc().getLanguageTag().getLocale() ); // restore calendar
3481 : }
3482 3376 : return bRes;
3483 : }
3484 :
3485 13 : bool SvNumberformat::ImpGetDateTimeOutput(double fNumber,
3486 : sal_uInt16 nIx,
3487 : OUStringBuffer& sBuff)
3488 : {
3489 : using namespace ::com::sun::star::i18n;
3490 13 : bool bRes = false;
3491 :
3492 13 : CalendarWrapper& rCal = GetCal();
3493 13 : double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart();
3494 13 : fNumber += fDiff;
3495 :
3496 13 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3497 : bool bInputLine;
3498 : sal_Int32 nCntPost;
3499 26 : if ( rScan.GetStandardPrec() == 300 &&
3500 13 : 0 < rInfo.nCntPost && rInfo.nCntPost < 7 )
3501 : {
3502 : // round at 7 decimals (+5 of 86400 == 12 significant digits)
3503 0 : bInputLine = true;
3504 0 : nCntPost = 7;
3505 : }
3506 : else
3507 : {
3508 13 : bInputLine = false;
3509 13 : nCntPost = rInfo.nCntPost;
3510 : }
3511 13 : double fTime = (fNumber - floor( fNumber )) * 86400.0;
3512 13 : fTime = ::rtl::math::round( fTime, int(nCntPost) );
3513 13 : if (fTime >= 86400.0)
3514 : {
3515 : // result of fNumber==x.999999999... rounded up, use correct date/time
3516 0 : fTime -= 86400.0;
3517 0 : fNumber = floor( fNumber + 0.5) + fTime;
3518 : }
3519 13 : rCal.setLocalDateTime( fNumber );
3520 :
3521 13 : int nUseMonthCase = 0; // Not decided yet
3522 13 : OUString aOrgCalendar; // empty => not changed yet
3523 13 : double fOrgDateTime(0.0);
3524 13 : bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] );
3525 13 : if ( bOtherCalendar )
3526 : {
3527 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3528 : }
3529 13 : if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) )
3530 : {
3531 0 : bOtherCalendar = false;
3532 : }
3533 13 : sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum();
3534 :
3535 13 : sal_uLong nSeconds = (sal_uLong)floor( fTime );
3536 : OUStringBuffer sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds,
3537 26 : rtl_math_StringFormat_F, int(nCntPost), '.'));
3538 13 : sSecStr.stripStart('0');
3539 13 : sSecStr.stripStart('.');
3540 13 : if ( bInputLine )
3541 : {
3542 0 : sSecStr.stripEnd('0');
3543 0 : for(sal_Int32 index = sSecStr.getLength(); index < rInfo.nCntPost; ++index)
3544 : {
3545 0 : sSecStr.append('0');
3546 : }
3547 0 : impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
3548 0 : nCntPost = sSecStr.getLength();
3549 : }
3550 : else
3551 : {
3552 13 : impTransliterate(sSecStr, NumFor[nIx].GetNatNum());
3553 : }
3554 :
3555 13 : sal_Int32 nSecPos = 0; // For figure by figure processing
3556 : sal_uLong nHour, nMin, nSec;
3557 13 : if (!rInfo.bThousand) // [] format
3558 : {
3559 13 : nHour = (nSeconds/3600) % 24;
3560 13 : nMin = (nSeconds%3600) / 60;
3561 13 : nSec = nSeconds%60;
3562 : }
3563 0 : else if (rInfo.nThousand == 3) // [ss]
3564 : {
3565 0 : nHour = 0;
3566 0 : nMin = 0;
3567 0 : nSec = nSeconds;
3568 : }
3569 0 : else if (rInfo.nThousand == 2) // [mm]:ss
3570 : {
3571 0 : nHour = 0;
3572 0 : nMin = nSeconds / 60;
3573 0 : nSec = nSeconds % 60;
3574 : }
3575 0 : else if (rInfo.nThousand == 1) // [hh]:mm:ss
3576 : {
3577 0 : nHour = nSeconds / 3600;
3578 0 : nMin = (nSeconds%3600) / 60;
3579 0 : nSec = nSeconds%60;
3580 : }
3581 : else
3582 : {
3583 0 : nHour = 0; // TODO What should these values be?
3584 0 : nMin = 0;
3585 0 : nSec = 0;
3586 : }
3587 13 : sal_Unicode cAmPm = ' '; // a or p
3588 13 : if (rInfo.nCntExp) // AM/PM
3589 : {
3590 13 : if (nHour == 0)
3591 : {
3592 0 : nHour = 12;
3593 0 : cAmPm = 'a';
3594 : }
3595 13 : else if (nHour < 12)
3596 : {
3597 2 : cAmPm = 'a';
3598 : }
3599 : else
3600 : {
3601 11 : cAmPm = 'p';
3602 11 : if (nHour > 12)
3603 : {
3604 0 : nHour -= 12;
3605 : }
3606 : }
3607 : }
3608 13 : const sal_uInt16 nAnz = NumFor[nIx].GetCount();
3609 : sal_Int32 nLen;
3610 26 : OUString aYear;
3611 178 : for (sal_uInt16 i = 0; i < nAnz; i++)
3612 : {
3613 165 : switch (rInfo.nTypeArray[i])
3614 : {
3615 : case NF_SYMBOLTYPE_CALENDAR :
3616 0 : if ( !aOrgCalendar.getLength() )
3617 : {
3618 0 : aOrgCalendar = rCal.getUniqueID();
3619 0 : fOrgDateTime = rCal.getDateTime();
3620 : }
3621 0 : rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLanguageTag().getLocale() );
3622 0 : rCal.setDateTime( fOrgDateTime );
3623 0 : ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3624 0 : break;
3625 : case NF_SYMBOLTYPE_STAR:
3626 0 : if( bStarFlag )
3627 : {
3628 0 : bRes = lcl_appendStarFillChar( sBuff, rInfo.sStrArray[i]);
3629 : }
3630 0 : break;
3631 : case NF_SYMBOLTYPE_BLANK:
3632 : InsertBlanks( sBuff, sBuff.getLength(),
3633 0 : rInfo.sStrArray[i][1] );
3634 0 : break;
3635 : case NF_SYMBOLTYPE_STRING:
3636 : case NF_SYMBOLTYPE_CURRENCY:
3637 : case NF_SYMBOLTYPE_DATESEP:
3638 : case NF_SYMBOLTYPE_TIMESEP:
3639 : case NF_SYMBOLTYPE_TIME100SECSEP:
3640 76 : sBuff.append(rInfo.sStrArray[i]);
3641 76 : break;
3642 : case NF_SYMBOLTYPE_DIGIT:
3643 0 : nLen = ( bInputLine && i > 0 &&
3644 0 : (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING ||
3645 0 : rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ?
3646 0 : nCntPost : rInfo.sStrArray[i].getLength() );
3647 0 : for (sal_Int32 j = 0; j < nLen && nSecPos < nCntPost; j++)
3648 : {
3649 0 : sBuff.append(sSecStr[ nSecPos ]);
3650 0 : nSecPos++;
3651 : }
3652 0 : break;
3653 : case NF_KEY_AMPM: // AM/PM
3654 13 : if (cAmPm == 'a')
3655 : {
3656 : sBuff.append(rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3657 2 : AmPmValue::AM, 0 ));
3658 : }
3659 : else
3660 : {
3661 : sBuff.append(rCal.getDisplayName( CalendarDisplayIndex::AM_PM,
3662 11 : AmPmValue::PM, 0 ));
3663 : }
3664 13 : break;
3665 : case NF_KEY_AP: // A/P
3666 0 : if (cAmPm == 'a')
3667 : {
3668 0 : sBuff.append('a');
3669 : }
3670 : else
3671 : {
3672 0 : sBuff.append('p');
3673 : }
3674 0 : break;
3675 : case NF_KEY_MI: // M
3676 0 : sBuff.append(ImpIntToString( nIx, nMin ));
3677 0 : break;
3678 : case NF_KEY_MMI: // MM
3679 13 : sBuff.append(ImpIntToString( nIx, nMin, 2 ));
3680 13 : break;
3681 : case NF_KEY_H: // H
3682 11 : sBuff.append(ImpIntToString( nIx, nHour ));
3683 11 : break;
3684 : case NF_KEY_HH: // HH
3685 2 : sBuff.append(ImpIntToString( nIx, nHour, 2 ));
3686 2 : break;
3687 : case NF_KEY_S: // S
3688 0 : sBuff.append(ImpIntToString( nIx, nSec ));
3689 0 : break;
3690 : case NF_KEY_SS: // SS
3691 11 : sBuff.append(ImpIntToString( nIx, nSec, 2 ));
3692 11 : break;
3693 : case NF_KEY_M: // M
3694 : sBuff.append(rCal.getDisplayString(
3695 11 : CalendarDisplayCode::SHORT_MONTH, nNatNum ));
3696 11 : break;
3697 : case NF_KEY_MM: // MM
3698 : sBuff.append(rCal.getDisplayString(
3699 2 : CalendarDisplayCode::LONG_MONTH, nNatNum ));
3700 2 : break;
3701 : case NF_KEY_MMM: // MMM
3702 0 : sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
3703 0 : static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
3704 0 : nNatNum));
3705 0 : break;
3706 : case NF_KEY_MMMM: // MMMM
3707 0 : sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
3708 0 : static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
3709 0 : nNatNum));
3710 0 : break;
3711 : case NF_KEY_MMMMM: // MMMMM
3712 0 : sBuff.append(rCal.getDisplayString( ImpUseMonthCase( nUseMonthCase, NumFor[nIx],
3713 0 : static_cast<NfKeywordIndex>(rInfo.nTypeArray[i])),
3714 0 : nNatNum));
3715 0 : break;
3716 : case NF_KEY_Q: // Q
3717 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_QUARTER, nNatNum ));
3718 0 : break;
3719 : case NF_KEY_QQ: // QQ
3720 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_QUARTER, nNatNum ));
3721 0 : break;
3722 : case NF_KEY_D: // D
3723 11 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY, nNatNum ));
3724 11 : break;
3725 : case NF_KEY_DD: // DD
3726 2 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY, nNatNum ));
3727 2 : break;
3728 : case NF_KEY_DDD: // DDD
3729 0 : if ( bOtherCalendar )
3730 : {
3731 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3732 : }
3733 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
3734 0 : if ( bOtherCalendar )
3735 : {
3736 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3737 : }
3738 0 : break;
3739 : case NF_KEY_DDDD: // DDDD
3740 0 : if ( bOtherCalendar )
3741 : {
3742 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3743 : }
3744 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
3745 0 : if ( bOtherCalendar )
3746 : {
3747 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3748 : }
3749 0 : break;
3750 : case NF_KEY_YY: // YY
3751 2 : if ( bOtherCalendar )
3752 : {
3753 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3754 : }
3755 2 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
3756 2 : if ( bOtherCalendar )
3757 : {
3758 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3759 : }
3760 2 : break;
3761 : case NF_KEY_YYYY: // YYYY
3762 11 : if ( bOtherCalendar )
3763 : {
3764 0 : SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime );
3765 : }
3766 11 : aYear = rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum );
3767 11 : if (aYear.getLength() < 4)
3768 : {
3769 : using namespace comphelper::string;
3770 : // Ensure that year consists of at least 4 digits, so it
3771 : // can be distinguished from 2 digits display and edited
3772 : // without suddenly being hit by the 2-digit year magic.
3773 0 : OUStringBuffer aBuf;
3774 0 : padToLength(aBuf, 4 - aYear.getLength(), '0');
3775 0 : impTransliterate(aBuf, NumFor[nIx].GetNatNum());
3776 0 : aBuf.append(aYear);
3777 0 : sBuff.append(aBuf);
3778 : }
3779 : else
3780 : {
3781 11 : sBuff.append(aYear);
3782 : }
3783 11 : if ( bOtherCalendar )
3784 : {
3785 0 : SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
3786 : }
3787 11 : break;
3788 : case NF_KEY_EC: // E
3789 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_YEAR, nNatNum ));
3790 0 : break;
3791 : case NF_KEY_EEC: // EE
3792 : case NF_KEY_R: // R
3793 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR, nNatNum ));
3794 0 : break;
3795 : case NF_KEY_NN: // NN
3796 : case NF_KEY_AAA: // AAA
3797 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ));
3798 0 : break;
3799 : case NF_KEY_NNN: // NNN
3800 : case NF_KEY_AAAA: // AAAA
3801 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
3802 0 : break;
3803 : case NF_KEY_NNNN: // NNNN
3804 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_DAY_NAME, nNatNum ));
3805 0 : sBuff.append(rLoc().getLongDateDayOfWeekSep());
3806 0 : break;
3807 : case NF_KEY_WW : // WW
3808 0 : sBuff.append(ImpIntToString( nIx, rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR )));
3809 0 : break;
3810 : case NF_KEY_G: // G
3811 0 : ImpAppendEraG( sBuff, rCal, nNatNum );
3812 0 : break;
3813 : case NF_KEY_GG: // GG
3814 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ));
3815 0 : break;
3816 : case NF_KEY_GGG: // GGG
3817 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_ERA, nNatNum ));
3818 0 : break;
3819 : case NF_KEY_RR: // RR => GGGEE
3820 0 : sBuff.append(rCal.getDisplayString( CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ));
3821 0 : break;
3822 : }
3823 : }
3824 13 : if ( aOrgCalendar.getLength() )
3825 : {
3826 0 : rCal.loadCalendar( aOrgCalendar, rLoc().getLanguageTag().getLocale() ); // restore calendar
3827 : }
3828 26 : return bRes;
3829 : }
3830 :
3831 4699 : bool SvNumberformat::ImpGetNumberOutput(double fNumber,
3832 : sal_uInt16 nIx,
3833 : OUStringBuffer& sStr)
3834 : {
3835 4699 : bool bRes = false;
3836 : bool bSign;
3837 4699 : if (fNumber < 0.0)
3838 : {
3839 181 : if (nIx == 0) // Not in the ones at the back
3840 : {
3841 181 : bSign = true; // Formats
3842 : }
3843 : else
3844 : {
3845 0 : bSign = false;
3846 : }
3847 181 : fNumber = -fNumber;
3848 : }
3849 : else
3850 : {
3851 4518 : bSign = false;
3852 4518 : if ( ::rtl::math::isSignBitSet( fNumber ) )
3853 : {
3854 0 : fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-'
3855 : }
3856 : }
3857 4699 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3858 4699 : if (rInfo.eScannedType == css::util::NumberFormat::PERCENT)
3859 : {
3860 1319 : if (fNumber < _D_MAX_D_BY_100)
3861 : {
3862 1319 : fNumber *= 100.0;
3863 : }
3864 : else
3865 : {
3866 0 : sStr = rScan.GetErrorString();
3867 0 : return false;
3868 : }
3869 : }
3870 : sal_uInt16 i, j;
3871 4699 : bool bInteger = false;
3872 4699 : if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT )
3873 : {
3874 : // Special formatting only if no GENERAL keyword in format code
3875 4619 : const sal_uInt16 nThousand = rInfo.nThousand;
3876 : long nPrecExp;
3877 4619 : for (i = 0; i < nThousand; i++)
3878 : {
3879 0 : if (fNumber > _D_MIN_M_BY_1000)
3880 : {
3881 0 : fNumber /= 1000.0;
3882 : }
3883 : else
3884 : {
3885 0 : fNumber = 0.0;
3886 : }
3887 : }
3888 4619 : if (fNumber > 0.0)
3889 : {
3890 4173 : nPrecExp = GetPrecExp( fNumber );
3891 : }
3892 : else
3893 : {
3894 446 : nPrecExp = 0;
3895 : }
3896 4619 : if (rInfo.nCntPost) // Decimal places
3897 : {
3898 3201 : if ((rInfo.nCntPost + nPrecExp) > 15 && nPrecExp < 15)
3899 : {
3900 0 : sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, 15-nPrecExp, '.');
3901 0 : for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++)
3902 : {
3903 0 : sStr.append('0');
3904 0 : }
3905 : }
3906 : else
3907 : {
3908 3201 : sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, rInfo.nCntPost, '.' );
3909 : }
3910 3201 : sStr.stripStart('0'); // Strip leading zeros
3911 : }
3912 1418 : else if (fNumber == 0.0) // Null
3913 : {
3914 : // Nothing to be done here, keep empty string sStr,
3915 : // ImpNumberFillWithThousands does the rest
3916 : }
3917 : else // Integer
3918 : {
3919 1378 : sStr = ::rtl::math::doubleToUString( fNumber, rtl_math_StringFormat_F, 0, '.');
3920 1378 : sStr.stripStart('0'); // Strip leading zeros
3921 : }
3922 4619 : sal_Int32 nPoint = sStr.indexOf('.' );
3923 4619 : if ( nPoint >= 0)
3924 : {
3925 3201 : const sal_Unicode* p = sStr.getStr() + nPoint;
3926 3201 : while ( *++p == '0' )
3927 : ;
3928 3201 : if ( !*p )
3929 : {
3930 2446 : bInteger = true;
3931 : }
3932 3201 : sStr.remove( nPoint, 1 ); // Remove .
3933 : }
3934 14038 : if (bSign && (sStr.isEmpty() ||
3935 5162 : comphelper::string::getTokenCount(sStr.toString(), '0') == sStr.getLength()+1)) // Only 00000
3936 : {
3937 0 : bSign = false; // Not -0.00
3938 : }
3939 : } // End of != FLAG_STANDARD_IN_FORMAT
3940 :
3941 : // Edit backwards:
3942 4699 : j = NumFor[nIx].GetCount()-1; // Last symbol
3943 : // Decimal places:
3944 4699 : bRes |= ImpDecimalFill( sStr, fNumber, j, nIx, bInteger );
3945 4699 : if (bSign)
3946 : {
3947 181 : sStr.insert(0, '-');
3948 : }
3949 4699 : impTransliterate(sStr, NumFor[nIx].GetNatNum());
3950 4699 : return bRes;
3951 : }
3952 :
3953 4750 : bool SvNumberformat::ImpDecimalFill( OUStringBuffer& sStr, // number string
3954 : double& rNumber, // number
3955 : sal_uInt16 j, // symbol index within format code
3956 : sal_uInt16 nIx, // subformat index
3957 : bool bInteger) // is integer
3958 : {
3959 4750 : bool bRes = false;
3960 4750 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
3961 4750 : sal_Int32 k = sStr.getLength(); // After last figure
3962 : // Decimal places:
3963 4750 : if (rInfo.nCntPost > 0)
3964 : {
3965 3245 : bool bTrailing = true; // Trailing zeros?
3966 3245 : bool bFilled = false; // Was filled?
3967 : short nType;
3968 16461 : while (j > 0 && // Backwards
3969 6608 : (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP)
3970 : {
3971 3363 : switch ( nType )
3972 : {
3973 : case NF_SYMBOLTYPE_STAR:
3974 0 : if( bStarFlag )
3975 : {
3976 0 : bRes = lcl_insertStarFillChar( sStr, k, rInfo.sStrArray[j]);
3977 : }
3978 0 : break;
3979 : case NF_SYMBOLTYPE_BLANK:
3980 0 : if (rInfo.sStrArray[j].getLength() >= 2)
3981 0 : /*k = */ InsertBlanks(sStr, k, rInfo.sStrArray[j][1] );
3982 0 : break;
3983 : case NF_SYMBOLTYPE_STRING:
3984 : case NF_SYMBOLTYPE_CURRENCY:
3985 : case NF_SYMBOLTYPE_PERCENT:
3986 92 : sStr.insert(k, rInfo.sStrArray[j]);
3987 92 : break;
3988 : case NF_SYMBOLTYPE_THSEP:
3989 0 : if (rInfo.nThousand == 0)
3990 : {
3991 0 : sStr.insert(k, rInfo.sStrArray[j]);
3992 : }
3993 0 : break;
3994 : case NF_SYMBOLTYPE_DIGIT:
3995 : {
3996 3245 : const OUString& rStr = rInfo.sStrArray[j];
3997 3245 : const sal_Unicode* p1 = rStr.getStr();
3998 3245 : const sal_Unicode* p = p1 + rStr.getLength();
3999 13072 : while (k && p1 < p--)
4000 : {
4001 6582 : const sal_Unicode c = *p;
4002 6582 : k--;
4003 6582 : if ( sStr[k] != '0' )
4004 : {
4005 1146 : bTrailing = false;
4006 : }
4007 6582 : if (bTrailing)
4008 : {
4009 5279 : if ( c == '0' )
4010 : {
4011 5277 : bFilled = true;
4012 : }
4013 2 : else if ( c == '-' )
4014 : {
4015 0 : if ( bInteger )
4016 : {
4017 0 : sStr[ k ] = '-';
4018 : }
4019 0 : bFilled = true;
4020 : }
4021 2 : else if ( c == '?' )
4022 : {
4023 0 : sStr[ k ] = ' ';
4024 0 : bFilled = true;
4025 : }
4026 2 : else if ( !bFilled ) // #
4027 : {
4028 2 : sStr.remove(k,1);
4029 : }
4030 : }
4031 : } // of for
4032 3245 : break;
4033 : } // of case digi
4034 : case NF_KEY_CCC: // CCC currency
4035 0 : sStr.insert(k, rScan.GetCurAbbrev());
4036 0 : break;
4037 : case NF_KEY_GENERAL: // Standard in the String
4038 : {
4039 0 : OUStringBuffer sNum;
4040 0 : ImpGetOutputStandard(rNumber, sNum);
4041 0 : sNum.stripStart('-');
4042 0 : sStr.insert(k, sNum.makeStringAndClear());
4043 0 : break;
4044 : }
4045 : default:
4046 26 : break;
4047 : } // of switch
4048 3363 : j--;
4049 : } // of while
4050 : } // of decimal places
4051 :
4052 : bRes |= ImpNumberFillWithThousands(sStr, rNumber, k, j, nIx, // Fill with . if needed
4053 4750 : rInfo.nCntPre);
4054 4750 : if ( rInfo.nCntPost > 0 )
4055 : {
4056 3245 : const OUString& rDecSep = GetFormatter().GetNumDecimalSep();
4057 3245 : sal_Int32 nLen = rDecSep.getLength();
4058 3245 : if ( sStr.getLength() > nLen && ( sStr.indexOf( rDecSep, sStr.getLength() - nLen) == sStr.getLength() - nLen) )
4059 : {
4060 0 : sStr.truncate( sStr.getLength() - nLen ); // no decimals => strip DecSep
4061 : }
4062 : }
4063 :
4064 4750 : return bRes;
4065 : }
4066 :
4067 4758 : bool SvNumberformat::ImpNumberFillWithThousands( OUStringBuffer& sBuff, // number string
4068 : double& rNumber, // number
4069 : sal_Int32 k, // position within string
4070 : sal_uInt16 j, // symbol index within format code
4071 : sal_uInt16 nIx, // subformat index
4072 : sal_Int32 nDigCnt) // count of integer digits in format
4073 : {
4074 4758 : bool bRes = false;
4075 4758 : sal_Int32 nLeadingStringChars = 0; // inserted StringChars before number
4076 4758 : sal_Int32 nDigitCount = 0; // count of integer digits from the right
4077 4758 : bool bStop = false;
4078 4758 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
4079 : // no normal thousands separators if number divided by thousands
4080 4758 : bool bDoThousands = (rInfo.nThousand == 0);
4081 4758 : utl::DigitGroupingIterator aGrouping( GetFormatter().GetLocaleData()->getDigitGrouping());
4082 :
4083 25165 : while (!bStop) // backwards
4084 : {
4085 15649 : if (j == 0)
4086 : {
4087 4758 : bStop = true;
4088 : }
4089 15649 : switch (rInfo.nTypeArray[j])
4090 : {
4091 : case NF_SYMBOLTYPE_DECSEP:
4092 3245 : aGrouping.reset();
4093 : // fall through
4094 : case NF_SYMBOLTYPE_STRING:
4095 : case NF_SYMBOLTYPE_CURRENCY:
4096 : case NF_SYMBOLTYPE_PERCENT:
4097 4738 : sBuff.insert(k, rInfo.sStrArray[j]);
4098 4738 : if ( k == 0 )
4099 : {
4100 799 : nLeadingStringChars = nLeadingStringChars + rInfo.sStrArray[j].getLength();
4101 : }
4102 4738 : break;
4103 : case NF_SYMBOLTYPE_STAR:
4104 13 : if( bStarFlag )
4105 : {
4106 0 : bRes = lcl_insertStarFillChar( sBuff, k, rInfo.sStrArray[j]);
4107 : }
4108 13 : break;
4109 : case NF_SYMBOLTYPE_BLANK:
4110 26 : if (rInfo.sStrArray[j].getLength() >= 2)
4111 26 : /*k = */ InsertBlanks(sBuff, k, rInfo.sStrArray[j][1] );
4112 26 : break;
4113 : case NF_SYMBOLTYPE_THSEP:
4114 : // #i7284# #102685# Insert separator also if number is divided
4115 : // by thousands and the separator is specified somewhere in
4116 : // between and not only at the end.
4117 : // #i12596# But do not insert if it's a parenthesized negative
4118 : // format like (#,)
4119 : // In fact, do not insert if divided and regex [0#,],[^0#] and
4120 : // no other digit symbol follows (which was already detected
4121 : // during scan of format code, otherwise there would be no
4122 : // division), else do insert. Same in ImpNumberFill() below.
4123 2826 : if ( !bDoThousands && j < NumFor[nIx].GetCount()-1 )
4124 : {
4125 0 : bDoThousands = ((j == 0) ||
4126 0 : (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
4127 0 : rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
4128 0 : (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
4129 : }
4130 2826 : if ( bDoThousands )
4131 : {
4132 2826 : if (k > 0)
4133 : {
4134 264 : sBuff.insert(k, rInfo.sStrArray[j]);
4135 : }
4136 2562 : else if (nDigitCount < nDigCnt)
4137 : {
4138 : // Leading '#' displays nothing (e.g. no leading
4139 : // separator for numbers <1000 with #,##0 format).
4140 : // Leading '?' displays blank.
4141 : // Everything else, including nothing, displays the
4142 : // separator.
4143 2562 : sal_Unicode cLeader = 0;
4144 2562 : if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT)
4145 : {
4146 2562 : const OUString& rStr = rInfo.sStrArray[j-1];
4147 2562 : sal_Int32 nLen = rStr.getLength();
4148 2562 : if (nLen)
4149 : {
4150 2562 : cLeader = rStr[ nLen - 1 ];
4151 : }
4152 : }
4153 2562 : switch (cLeader)
4154 : {
4155 : case '#':
4156 : ; // nothing
4157 2562 : break;
4158 : case '?':
4159 : // erAck: 2008-04-03T16:24+0200
4160 : // Actually this currently isn't executed
4161 : // because the format scanner in the context of
4162 : // "?," doesn't generate a group separator but
4163 : // a literal ',' character instead that is
4164 : // inserted unconditionally. Should be changed
4165 : // on some occasion.
4166 0 : sBuff.insert(k, ' ');
4167 0 : break;
4168 : default:
4169 0 : sBuff.insert(k, rInfo.sStrArray[j]);
4170 : }
4171 : }
4172 2826 : aGrouping.advance();
4173 : }
4174 2826 : break;
4175 : case NF_SYMBOLTYPE_DIGIT:
4176 : {
4177 7504 : const OUString& rStr = rInfo.sStrArray[j];
4178 7504 : const sal_Unicode* p1 = rStr.getStr();
4179 7504 : const sal_Unicode* p = p1 + rStr.getLength();
4180 28203 : while ( p1 < p-- )
4181 : {
4182 13195 : nDigitCount++;
4183 13195 : if (k > 0)
4184 : {
4185 6316 : k--;
4186 : }
4187 : else
4188 : {
4189 6879 : switch (*p)
4190 : {
4191 : case '0':
4192 576 : sBuff.insert(0, '0');
4193 576 : break;
4194 : case '?':
4195 0 : sBuff.insert(0, ' ');
4196 0 : break;
4197 : }
4198 : }
4199 13195 : if (nDigitCount == nDigCnt && k > 0)
4200 : {
4201 : // more digits than specified
4202 1568 : ImpDigitFill(sBuff, 0, k, nIx, nDigitCount, aGrouping);
4203 : }
4204 : }
4205 7504 : break;
4206 : }
4207 : case NF_KEY_CCC: // CCC currency
4208 0 : sBuff.insert(k, rScan.GetCurAbbrev());
4209 0 : break;
4210 : case NF_KEY_GENERAL: // "General" in string
4211 : {
4212 80 : OUStringBuffer sNum;
4213 80 : ImpGetOutputStandard(rNumber, sNum);
4214 80 : sNum.stripStart('-');
4215 80 : sBuff.insert(k, sNum.makeStringAndClear());
4216 80 : break;
4217 : }
4218 : default:
4219 462 : break;
4220 : } // switch
4221 15649 : j--; // next format code string
4222 : } // while
4223 :
4224 4758 : k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ...
4225 4758 : if (k > nLeadingStringChars)
4226 : {
4227 0 : ImpDigitFill(sBuff, nLeadingStringChars, k, nIx, nDigitCount, aGrouping);
4228 : }
4229 4758 : return bRes;
4230 : }
4231 :
4232 1568 : void SvNumberformat::ImpDigitFill(OUStringBuffer& sStr, // number string
4233 : sal_Int32 nStart, // start of digits
4234 : sal_Int32 & k, // position within string
4235 : sal_uInt16 nIx, // subformat index
4236 : sal_Int32 & nDigitCount, // count of integer digits from the right so far
4237 : utl::DigitGroupingIterator & rGrouping ) // current grouping
4238 : {
4239 1568 : if (NumFor[nIx].Info().bThousand) // Only if grouping fill in separators
4240 : {
4241 62 : const OUString& rThousandSep = GetFormatter().GetNumThousandSep();
4242 207 : while (k > nStart)
4243 : {
4244 83 : if (nDigitCount == rGrouping.getPos())
4245 : {
4246 5 : sStr.insert( k, rThousandSep );
4247 5 : rGrouping.advance();
4248 : }
4249 83 : nDigitCount++;
4250 83 : k--;
4251 : }
4252 : }
4253 : else // simply skip
4254 : {
4255 1506 : k = nStart;
4256 : }
4257 1568 : }
4258 :
4259 67 : bool SvNumberformat::ImpNumberFill( OUStringBuffer& sBuff, // number string
4260 : double& rNumber, // number for "General" format
4261 : sal_Int32& k, // position within string
4262 : sal_uInt16& j, // symbol index within format code
4263 : sal_uInt16 nIx, // subformat index
4264 : short eSymbolType ) // type of stop condition
4265 : {
4266 67 : bool bRes = false;
4267 67 : const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info();
4268 : // no normal thousands separators if number divided by thousands
4269 67 : bool bDoThousands = (rInfo.nThousand == 0);
4270 : short nType;
4271 :
4272 67 : k = sBuff.getLength(); // behind last digit
4273 :
4274 201 : while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType ) // Backwards
4275 : {
4276 67 : switch ( nType )
4277 : {
4278 : case NF_SYMBOLTYPE_STAR:
4279 0 : if( bStarFlag )
4280 : {
4281 0 : bRes = lcl_insertStarFillChar( sBuff, k, rInfo.sStrArray[j]);
4282 : }
4283 0 : break;
4284 : case NF_SYMBOLTYPE_BLANK:
4285 0 : k = InsertBlanks(sBuff, k, rInfo.sStrArray[j][1] );
4286 0 : break;
4287 : case NF_SYMBOLTYPE_THSEP:
4288 : // Same as in ImpNumberFillWithThousands() above, do not insert
4289 : // if divided and regex [0#,],[^0#] and no other digit symbol
4290 : // follows (which was already detected during scan of format
4291 : // code, otherwise there would be no division), else do insert.
4292 0 : if ( !bDoThousands && j < NumFor[nIx].GetCount()-1 )
4293 : {
4294 0 : bDoThousands = ((j == 0) ||
4295 0 : (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT &&
4296 0 : rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) ||
4297 0 : (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT));
4298 : }
4299 0 : if ( bDoThousands && k > 0 )
4300 : {
4301 0 : sBuff.insert(k, rInfo.sStrArray[j]);
4302 : }
4303 0 : break;
4304 : case NF_SYMBOLTYPE_DIGIT:
4305 : {
4306 67 : const OUString& rStr = rInfo.sStrArray[j];
4307 67 : const sal_Unicode* p1 = rStr.getStr();
4308 67 : const sal_Unicode* p = p1 + rStr.getLength();
4309 288 : while ( p1 < p-- )
4310 : {
4311 154 : if (k > 0)
4312 : {
4313 153 : k--;
4314 : }
4315 : else
4316 : {
4317 1 : switch (*p)
4318 : {
4319 : case '0':
4320 0 : sBuff.insert(0, '0');
4321 0 : break;
4322 : case '?':
4323 1 : sBuff.insert(0, ' ');
4324 1 : break;
4325 : }
4326 : }
4327 : }
4328 : }
4329 67 : break;
4330 : case NF_KEY_CCC: // CCC currency
4331 0 : sBuff.insert(k, rScan.GetCurAbbrev());
4332 0 : break;
4333 : case NF_KEY_GENERAL: // Standard in the String
4334 : {
4335 0 : OUStringBuffer sNum;
4336 0 : ImpGetOutputStandard(rNumber, sNum);
4337 0 : sNum.stripStart('-');
4338 0 : sBuff.insert(k, sNum.makeStringAndClear());
4339 : }
4340 0 : break;
4341 : case NF_SYMBOLTYPE_FRAC_FDIV: // Do Nothing
4342 0 : break;
4343 :
4344 : default:
4345 0 : sBuff.insert(k, rInfo.sStrArray[j]);
4346 0 : break;
4347 : } // of switch
4348 67 : j--; // Next String
4349 : } // of while
4350 67 : return bRes;
4351 : }
4352 :
4353 367 : void SvNumberformat::GetFormatSpecialInfo(bool& bThousand,
4354 : bool& IsRed,
4355 : sal_uInt16& nPrecision,
4356 : sal_uInt16& nAnzLeading) const
4357 : {
4358 : // as before: take info from nNumFor=0 for whole format (for dialog etc.)
4359 :
4360 : short nDummyType;
4361 367 : GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading );
4362 :
4363 : // "negative in red" is only useful for the whole format
4364 :
4365 367 : const Color* pColor = NumFor[1].GetColor();
4366 1101 : if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor
4367 369 : && (*pColor == rScan.GetRedColor()))
4368 : {
4369 2 : IsRed = true;
4370 : }
4371 : else
4372 : {
4373 365 : IsRed = false;
4374 : }
4375 367 : }
4376 :
4377 1167 : void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType,
4378 : bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const
4379 : {
4380 : // take info from a specified sub-format (for XML export)
4381 :
4382 1167 : if ( nNumFor > 3 )
4383 : {
4384 1167 : return; // invalid
4385 : }
4386 :
4387 1167 : const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info();
4388 1167 : rScannedType = rInfo.eScannedType;
4389 1167 : bThousand = rInfo.bThousand;
4390 1167 : nPrecision = rInfo.nCntPost;
4391 1167 : if (bStandard && rInfo.eScannedType == css::util::NumberFormat::NUMBER)
4392 : {
4393 : // StandardFormat
4394 381 : nAnzLeading = 1;
4395 : }
4396 : else
4397 : {
4398 786 : nAnzLeading = 0;
4399 786 : bool bStop = false;
4400 786 : sal_uInt16 i = 0;
4401 786 : const sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
4402 5161 : while (!bStop && i < nAnz)
4403 : {
4404 3589 : short nType = rInfo.nTypeArray[i];
4405 3589 : if ( nType == NF_SYMBOLTYPE_DIGIT)
4406 : {
4407 737 : const sal_Unicode* p = rInfo.sStrArray[i].getStr();
4408 2142 : while ( *p == '#' )
4409 : {
4410 668 : p++;
4411 : }
4412 1978 : while ( *p++ == '0' )
4413 : {
4414 504 : nAnzLeading++;
4415 : }
4416 : }
4417 2852 : else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP)
4418 : {
4419 337 : bStop = true;
4420 : }
4421 3589 : i++;
4422 : }
4423 : }
4424 : }
4425 :
4426 26341 : const OUString* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos,
4427 : bool bString /* = false */ ) const
4428 : {
4429 26341 : if ( nNumFor > 3 )
4430 : {
4431 0 : return NULL;
4432 : }
4433 26341 : sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
4434 26341 : if ( !nAnz )
4435 : {
4436 12146 : return NULL;
4437 : }
4438 14195 : if ( nPos == 0xFFFF )
4439 : {
4440 903 : nPos = nAnz - 1;
4441 903 : if ( bString )
4442 : { // Backwards
4443 903 : short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4444 1806 : while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
4445 0 : (*pType != NF_SYMBOLTYPE_CURRENCY) )
4446 : {
4447 0 : pType--;
4448 0 : nPos--;
4449 : }
4450 903 : if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
4451 : {
4452 903 : return NULL;
4453 : }
4454 : }
4455 : }
4456 13292 : else if ( nPos > nAnz - 1 )
4457 : {
4458 2954 : return NULL;
4459 : }
4460 10338 : else if ( bString )
4461 : {
4462 : // vorwaerts
4463 3509 : short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4464 14114 : while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
4465 3558 : (*pType != NF_SYMBOLTYPE_CURRENCY) )
4466 : {
4467 3538 : pType++;
4468 3538 : nPos++;
4469 : }
4470 3529 : if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) &&
4471 20 : (*pType != NF_SYMBOLTYPE_CURRENCY)) )
4472 : {
4473 3480 : return NULL;
4474 : }
4475 : }
4476 6858 : return &NumFor[nNumFor].Info().sStrArray[nPos];
4477 : }
4478 :
4479 11284 : short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos,
4480 : bool bString /* = false */ ) const
4481 : {
4482 11284 : if ( nNumFor > 3 )
4483 : {
4484 0 : return 0;
4485 : }
4486 11284 : sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
4487 11284 : if ( !nAnz )
4488 : {
4489 1252 : return 0;
4490 : }
4491 10032 : if ( nPos == 0xFFFF )
4492 : {
4493 0 : nPos = nAnz - 1;
4494 0 : if ( bString )
4495 : {
4496 : // Backwards
4497 0 : short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4498 0 : while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) &&
4499 0 : (*pType != NF_SYMBOLTYPE_CURRENCY) )
4500 : {
4501 0 : pType--;
4502 0 : nPos--;
4503 : }
4504 0 : if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
4505 : {
4506 0 : return 0;
4507 : }
4508 : }
4509 : }
4510 10032 : else if ( nPos > nAnz - 1 )
4511 : {
4512 1463 : return 0;
4513 : }
4514 8569 : else if ( bString )
4515 : {
4516 : // Forwards
4517 0 : short* pType = NumFor[nNumFor].Info().nTypeArray + nPos;
4518 0 : while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) &&
4519 0 : (*pType != NF_SYMBOLTYPE_CURRENCY) )
4520 : {
4521 0 : pType++;
4522 0 : nPos++;
4523 : }
4524 0 : if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) )
4525 : {
4526 0 : return 0;
4527 : }
4528 : }
4529 8569 : return NumFor[nNumFor].Info().nTypeArray[nPos];
4530 : }
4531 :
4532 0 : bool SvNumberformat::IsNegativeWithoutSign() const
4533 : {
4534 0 : if ( IsSecondSubformatRealNegative() )
4535 : {
4536 0 : const OUString* pStr = GetNumForString( 1, 0, true );
4537 0 : if ( pStr )
4538 : {
4539 0 : return !HasStringNegativeSign( *pStr );
4540 : }
4541 : }
4542 0 : return false;
4543 : }
4544 :
4545 1335 : bool SvNumberformat::IsNegativeInBracket() const
4546 : {
4547 1335 : sal_uInt16 nAnz = NumFor[1].GetCount();
4548 1335 : if (!nAnz)
4549 : {
4550 1335 : return false;
4551 : }
4552 0 : OUString *tmpStr = NumFor[1].Info().sStrArray;
4553 : using comphelper::string::equals;
4554 0 : return (equals(tmpStr[0], '(') && equals(tmpStr[nAnz-1], ')'));
4555 : }
4556 :
4557 0 : bool SvNumberformat::HasPositiveBracketPlaceholder() const
4558 : {
4559 0 : sal_uInt16 nAnz = NumFor[0].GetCount();
4560 0 : OUString *tmpStr = NumFor[0].Info().sStrArray;
4561 0 : return tmpStr[nAnz-1] == "_)";
4562 : }
4563 :
4564 6 : DateFormat SvNumberformat::GetDateOrder() const
4565 : {
4566 6 : if ( (eType & css::util::NumberFormat::DATE) == css::util::NumberFormat::DATE )
4567 : {
4568 6 : short const * const pType = NumFor[0].Info().nTypeArray;
4569 6 : sal_uInt16 nAnz = NumFor[0].GetCount();
4570 6 : for ( sal_uInt16 j=0; j<nAnz; j++ )
4571 : {
4572 6 : switch ( pType[j] )
4573 : {
4574 : case NF_KEY_D :
4575 : case NF_KEY_DD :
4576 0 : return DMY;
4577 : case NF_KEY_M :
4578 : case NF_KEY_MM :
4579 : case NF_KEY_MMM :
4580 : case NF_KEY_MMMM :
4581 : case NF_KEY_MMMMM :
4582 6 : return MDY;
4583 : case NF_KEY_YY :
4584 : case NF_KEY_YYYY :
4585 : case NF_KEY_EC :
4586 : case NF_KEY_EEC :
4587 : case NF_KEY_R :
4588 : case NF_KEY_RR :
4589 0 : return YMD;
4590 : }
4591 : }
4592 : }
4593 : else
4594 : {
4595 : SAL_WARN( "svl.numbers", "SvNumberformat::GetDateOrder: no date" );
4596 : }
4597 0 : return rLoc().getDateFormat();
4598 : }
4599 :
4600 3 : sal_uInt32 SvNumberformat::GetExactDateOrder() const
4601 : {
4602 3 : sal_uInt32 nRet = 0;
4603 3 : if ( (eType & css::util::NumberFormat::DATE) != css::util::NumberFormat::DATE )
4604 : {
4605 : SAL_WARN( "svl.numbers", "SvNumberformat::GetExactDateOrder: no date" );
4606 0 : return nRet;
4607 : }
4608 3 : short const * const pType = NumFor[0].Info().nTypeArray;
4609 3 : sal_uInt16 nAnz = NumFor[0].GetCount();
4610 3 : int nShift = 0;
4611 18 : for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ )
4612 : {
4613 15 : switch ( pType[j] )
4614 : {
4615 : case NF_KEY_D :
4616 : case NF_KEY_DD :
4617 3 : nRet = (nRet << 8) | 'D';
4618 3 : ++nShift;
4619 3 : break;
4620 : case NF_KEY_M :
4621 : case NF_KEY_MM :
4622 : case NF_KEY_MMM :
4623 : case NF_KEY_MMMM :
4624 : case NF_KEY_MMMMM :
4625 3 : nRet = (nRet << 8) | 'M';
4626 3 : ++nShift;
4627 3 : break;
4628 : case NF_KEY_YY :
4629 : case NF_KEY_YYYY :
4630 : case NF_KEY_EC :
4631 : case NF_KEY_EEC :
4632 : case NF_KEY_R :
4633 : case NF_KEY_RR :
4634 3 : nRet = (nRet << 8) | 'Y';
4635 3 : ++nShift;
4636 3 : break;
4637 : }
4638 : }
4639 3 : return nRet;
4640 : }
4641 :
4642 1358 : void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1,
4643 : SvNumberformatLimitOps& rOper2, double& rVal2 ) const
4644 : {
4645 1358 : rOper1 = eOp1;
4646 1358 : rOper2 = eOp2;
4647 1358 : rVal1 = fLimit1;
4648 1358 : rVal2 = fLimit2;
4649 1358 : }
4650 :
4651 815 : Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const
4652 : {
4653 815 : if ( nNumFor > 3 )
4654 : {
4655 0 : return NULL;
4656 : }
4657 815 : return NumFor[nNumFor].GetColor();
4658 : }
4659 :
4660 0 : static void lcl_SvNumberformat_AddLimitStringImpl( OUString& rStr,
4661 : SvNumberformatLimitOps eOp,
4662 : double fLimit, const OUString& rDecSep )
4663 : {
4664 0 : if ( eOp != NUMBERFORMAT_OP_NO )
4665 : {
4666 0 : switch ( eOp )
4667 : {
4668 : case NUMBERFORMAT_OP_EQ :
4669 0 : rStr = "[=";
4670 0 : break;
4671 : case NUMBERFORMAT_OP_NE :
4672 0 : rStr = "[<>";
4673 0 : break;
4674 : case NUMBERFORMAT_OP_LT :
4675 0 : rStr = "[<";
4676 0 : break;
4677 : case NUMBERFORMAT_OP_LE :
4678 0 : rStr = "[<=";
4679 0 : break;
4680 : case NUMBERFORMAT_OP_GT :
4681 0 : rStr = "[>";
4682 0 : break;
4683 : case NUMBERFORMAT_OP_GE :
4684 0 : rStr = "[>=";
4685 0 : break;
4686 : default:
4687 : SAL_WARN( "svl.numbers", "unsupported number format" );
4688 0 : break;
4689 : }
4690 0 : rStr += ::rtl::math::doubleToUString( fLimit,
4691 : rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
4692 0 : rDecSep[0], true);
4693 0 : rStr += "]";
4694 : }
4695 0 : }
4696 :
4697 126 : OUString SvNumberformat::GetMappedFormatstring( const NfKeywordTable& rKeywords,
4698 : const LocaleDataWrapper& rLocWrp,
4699 : bool bDontQuote ) const
4700 : {
4701 126 : OUStringBuffer aStr;
4702 : bool bDefault[4];
4703 : // 1 subformat matches all if no condition specified,
4704 126 : bDefault[0] = ( NumFor[1].GetCount() == 0 && eOp1 == NUMBERFORMAT_OP_NO );
4705 : // with 2 subformats [>=0];[<0] is implied if no condition specified
4706 131 : bDefault[1] = ( !bDefault[0] && NumFor[2].GetCount() == 0 &&
4707 3 : eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 &&
4708 128 : eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 );
4709 : // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified,
4710 : // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked.
4711 133 : bDefault[2] = ( !bDefault[0] && !bDefault[1] &&
4712 9 : eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 &&
4713 132 : eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 );
4714 126 : bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2];
4715 : // from now on bDefault[] values are used to append empty subformats at the end
4716 126 : bDefault[3] = false;
4717 126 : if ( !bDefaults )
4718 : {
4719 : // conditions specified
4720 0 : if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO )
4721 : {
4722 0 : bDefault[0] = bDefault[1] = true; // [];x
4723 : }
4724 0 : else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO &&
4725 0 : NumFor[2].GetCount() == 0 )
4726 : {
4727 0 : bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = true; // [];[];;
4728 : }
4729 : // nothing to do if conditions specified for every subformat
4730 : }
4731 126 : else if ( bDefault[0] )
4732 : {
4733 122 : bDefault[0] = false; // a single unconditional subformat is never delimited
4734 : }
4735 : else
4736 : {
4737 4 : if ( bDefault[2] && NumFor[2].GetCount() == 0 && NumFor[1].GetCount() > 0 )
4738 : {
4739 0 : bDefault[3] = true; // special cases x;x;; and ;x;;
4740 : }
4741 11 : for ( int i=0; i<3 && !bDefault[i]; ++i )
4742 : {
4743 7 : bDefault[i] = true;
4744 : }
4745 : }
4746 126 : int nSem = 0; // needed ';' delimiters
4747 126 : int nSub = 0; // subformats delimited so far
4748 630 : for ( int n=0; n<4; n++ )
4749 : {
4750 504 : if ( n > 0 )
4751 : {
4752 378 : nSem++;
4753 : }
4754 504 : OUString aPrefix;
4755 504 : bool LCIDInserted = false;
4756 :
4757 504 : if ( !bDefaults )
4758 : {
4759 0 : switch ( n )
4760 : {
4761 : case 0 :
4762 : lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1,
4763 0 : fLimit1, rLocWrp.getNumDecimalSep() );
4764 0 : break;
4765 : case 1 :
4766 : lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2,
4767 0 : fLimit2, rLocWrp.getNumDecimalSep() );
4768 0 : break;
4769 : }
4770 : }
4771 :
4772 504 : const OUString& rColorName = NumFor[n].GetColorName();
4773 504 : if ( !rColorName.isEmpty() )
4774 : {
4775 0 : const NfKeywordTable & rKey = rScan.GetKeywords();
4776 0 : for ( int j = NF_KEY_FIRSTCOLOR; j <= NF_KEY_LASTCOLOR; j++ )
4777 : {
4778 0 : if ( rKey[j] == rColorName )
4779 : {
4780 0 : aPrefix += "[";
4781 0 : aPrefix += rKeywords[j];
4782 0 : aPrefix += "]";
4783 0 : break; // for
4784 : }
4785 : }
4786 : }
4787 :
4788 504 : const SvNumberNatNum& rNum = NumFor[n].GetNatNum();
4789 :
4790 504 : sal_uInt16 nAnz = NumFor[n].GetCount();
4791 504 : if ( nSem && (nAnz || !aPrefix.isEmpty()) )
4792 : {
4793 14 : for ( ; nSem; --nSem )
4794 : {
4795 7 : aStr.append( ';' );
4796 : }
4797 18 : for ( ; nSub <= n; ++nSub )
4798 : {
4799 11 : bDefault[nSub] = false;
4800 : }
4801 : }
4802 :
4803 504 : if ( !aPrefix.isEmpty() )
4804 : {
4805 0 : aStr.append( aPrefix );
4806 : }
4807 504 : if ( nAnz )
4808 : {
4809 133 : const short* pType = NumFor[n].Info().nTypeArray;
4810 133 : const OUString* pStr = NumFor[n].Info().sStrArray;
4811 371 : for ( sal_uInt16 j=0; j<nAnz; j++ )
4812 : {
4813 238 : if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT )
4814 : {
4815 129 : aStr.append( rKeywords[pType[j]] );
4816 258 : if( NF_KEY_NNNN == pType[j] )
4817 : {
4818 0 : aStr.append( rLocWrp.getLongDateDayOfWeekSep() );
4819 : }
4820 : }
4821 : else
4822 : {
4823 109 : switch ( pType[j] )
4824 : {
4825 : case NF_SYMBOLTYPE_DECSEP :
4826 19 : aStr.append( rLocWrp.getNumDecimalSep() );
4827 19 : break;
4828 : case NF_SYMBOLTYPE_THSEP :
4829 2 : aStr.append( rLocWrp.getNumThousandSep() );
4830 2 : break;
4831 : case NF_SYMBOLTYPE_DATESEP :
4832 12 : aStr.append( rLocWrp.getDateSep() );
4833 12 : break;
4834 : case NF_SYMBOLTYPE_TIMESEP :
4835 0 : aStr.append( rLocWrp.getTimeSep() );
4836 0 : break;
4837 : case NF_SYMBOLTYPE_TIME100SECSEP :
4838 0 : aStr.append( rLocWrp.getTime100SecSep() );
4839 0 : break;
4840 : case NF_SYMBOLTYPE_STRING :
4841 24 : if( bDontQuote )
4842 : {
4843 0 : aStr.append( pStr[j] );
4844 : }
4845 24 : else if ( pStr[j].getLength() == 1 )
4846 : {
4847 10 : aStr.append( '\\' );
4848 10 : aStr.append( pStr[j] );
4849 : }
4850 : else
4851 : {
4852 14 : aStr.append( '"' );
4853 14 : aStr.append( pStr[j] );
4854 14 : aStr.append( '"' );
4855 : }
4856 24 : break;
4857 : case NF_SYMBOLTYPE_CALDEL :
4858 0 : if ( pStr[j+1] == "buddhist" )
4859 : {
4860 0 : aStr.insert( 0, "[$-" );
4861 0 : if ( rNum.IsSet() && rNum.GetNatNum() == 1 &&
4862 0 : MsLangId::getRealLanguage( rNum.GetLang() ) ==
4863 : LANGUAGE_THAI )
4864 : {
4865 0 : aStr.insert( 3, "D07041E]" ); // date in Thai digit, Buddhist era
4866 : }
4867 : else
4868 : {
4869 0 : aStr.insert( 3, "107041E]" ); // date in Arabic digit, Buddhist era
4870 : }
4871 0 : j = j+2;
4872 : }
4873 0 : LCIDInserted = true;
4874 0 : break;
4875 : default:
4876 52 : aStr.append( pStr[j] );
4877 : }
4878 : }
4879 : }
4880 : }
4881 : // The Thai T NatNum modifier during Xcl export.
4882 1008 : if (rNum.IsSet() && rNum.GetNatNum() == 1 &&
4883 0 : rKeywords[NF_KEY_THAI_T] == "T" &&
4884 0 : MsLangId::getRealLanguage( rNum.GetLang()) ==
4885 504 : LANGUAGE_THAI && !LCIDInserted )
4886 : {
4887 :
4888 0 : aStr.insert( 0, "[$-D00041E]" ); // number in Thai digit
4889 : }
4890 504 : }
4891 126 : for ( ; nSub<4 && bDefault[nSub]; ++nSub )
4892 : { // append empty subformats
4893 0 : aStr.append( ';' );
4894 : }
4895 126 : return aStr.makeStringAndClear();
4896 : }
4897 :
4898 1085 : OUString SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum,
4899 : sal_Int32 nVal, sal_uInt16 nMinDigits ) const
4900 : {
4901 1085 : OUString aStr;
4902 1085 : if ( nMinDigits )
4903 : {
4904 1085 : if ( nMinDigits == 2 )
4905 : {
4906 : // speed up the most common case
4907 1085 : if ( 0 <= nVal && nVal < 10 )
4908 : {
4909 : sal_Unicode aBuf[2];
4910 832 : aBuf[0] = '0';
4911 832 : aBuf[1] = '0' + nVal;
4912 832 : aStr = OUString(aBuf, SAL_N_ELEMENTS(aBuf));
4913 : }
4914 : else
4915 : {
4916 253 : aStr = OUString::number( nVal );
4917 : }
4918 : }
4919 : else
4920 : {
4921 0 : OUString aValStr( OUString::number( nVal ) );
4922 0 : if ( aValStr.getLength() >= nMinDigits )
4923 : {
4924 0 : aStr = aValStr;
4925 : }
4926 : else
4927 : {
4928 0 : OUStringBuffer aBuf;
4929 0 : for(sal_Int32 index = 0; index < nMinDigits - aValStr.getLength(); ++index)
4930 : {
4931 0 : aBuf.append('0');
4932 : }
4933 0 : aBuf.append(aValStr);
4934 0 : aStr = aBuf.makeStringAndClear();
4935 0 : }
4936 : }
4937 : }
4938 : else
4939 : {
4940 0 : aStr = OUString::number( nVal );
4941 : }
4942 1085 : return impTransliterate(aStr, rNum);
4943 : }
4944 :
4945 0 : OUString SvNumberformat::impTransliterateImpl(const OUString& rStr,
4946 : const SvNumberNatNum& rNum ) const
4947 : {
4948 0 : com::sun::star::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() );
4949 0 : return GetFormatter().GetNatNum()->getNativeNumberString( rStr,
4950 0 : aLocale, rNum.GetNatNum() );
4951 : }
4952 :
4953 1 : void SvNumberformat::impTransliterateImpl(OUStringBuffer& rStr,
4954 : const SvNumberNatNum& rNum ) const
4955 : {
4956 1 : com::sun::star::lang::Locale aLocale( LanguageTag( rNum.GetLang() ).getLocale() );
4957 :
4958 2 : OUString sTemp(rStr.makeStringAndClear());
4959 1 : sTemp = GetFormatter().GetNatNum()->getNativeNumberString( sTemp, aLocale, rNum.GetNatNum() );
4960 2 : rStr.append(sTemp);
4961 1 : }
4962 :
4963 800 : void SvNumberformat::GetNatNumXml( com::sun::star::i18n::NativeNumberXmlAttributes& rAttr,
4964 : sal_uInt16 nNumFor ) const
4965 : {
4966 800 : if ( nNumFor <= 3 )
4967 : {
4968 800 : const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum();
4969 800 : if ( rNum.IsSet() )
4970 : {
4971 : com::sun::star::lang::Locale aLocale(
4972 0 : LanguageTag( rNum.GetLang() ).getLocale() );
4973 0 : rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes(
4974 0 : aLocale, rNum.GetNatNum() );
4975 : }
4976 : else
4977 : {
4978 800 : rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4979 : }
4980 : }
4981 : else
4982 : {
4983 0 : rAttr = com::sun::star::i18n::NativeNumberXmlAttributes();
4984 : }
4985 800 : }
4986 :
4987 : // static
4988 0 : bool SvNumberformat::HasStringNegativeSign( const OUString& rStr )
4989 : {
4990 : // For Sign '-' needs to be at the start or at the end of the string (blanks ignored)
4991 0 : sal_Int32 nLen = rStr.getLength();
4992 0 : if ( !nLen )
4993 : {
4994 0 : return false;
4995 : }
4996 0 : const sal_Unicode* const pBeg = rStr.getStr();
4997 0 : const sal_Unicode* const pEnd = pBeg + nLen;
4998 0 : const sal_Unicode* p = pBeg;
4999 0 : do
5000 : { // Start
5001 0 : if ( *p == '-' )
5002 : {
5003 0 : return true;
5004 : }
5005 : }
5006 0 : while ( *p == ' ' && ++p < pEnd );
5007 :
5008 0 : p = pEnd - 1;
5009 :
5010 0 : do
5011 : { // End
5012 0 : if ( *p == '-' )
5013 : {
5014 0 : return true;
5015 : }
5016 : }
5017 0 : while ( *p == ' ' && pBeg < --p );
5018 0 : return false;
5019 : }
5020 :
5021 : // static
5022 265266 : bool SvNumberformat::IsInQuote( const OUString& rStr, sal_Int32 nPos,
5023 : sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut )
5024 : {
5025 265266 : sal_Int32 nLen = rStr.getLength();
5026 265266 : if ( nPos >= nLen )
5027 : {
5028 0 : return false;
5029 : }
5030 265266 : const sal_Unicode* p0 = rStr.getStr();
5031 265266 : const sal_Unicode* p = p0;
5032 265266 : const sal_Unicode* p1 = p0 + nPos;
5033 265266 : bool bQuoted = false;
5034 2878961 : while ( p <= p1 )
5035 : {
5036 2348429 : if ( *p == cQuote )
5037 : {
5038 526 : if ( p == p0 )
5039 : {
5040 200 : bQuoted = true;
5041 : }
5042 326 : else if ( bQuoted )
5043 : {
5044 4 : if ( *(p-1) != cEscIn )
5045 : {
5046 4 : bQuoted = false;
5047 : }
5048 : }
5049 : else
5050 : {
5051 322 : if ( *(p-1) != cEscOut )
5052 : {
5053 319 : bQuoted = true;
5054 : }
5055 : }
5056 : }
5057 2348429 : p++;
5058 : }
5059 265266 : return bQuoted;
5060 : }
5061 :
5062 : // static
5063 265266 : sal_Int32 SvNumberformat::GetQuoteEnd( const OUString& rStr, sal_Int32 nPos,
5064 : sal_Unicode cQuote, sal_Unicode cEscIn,
5065 : sal_Unicode cEscOut )
5066 : {
5067 265266 : if ( nPos < 0 )
5068 : {
5069 0 : return -1;
5070 : }
5071 265266 : sal_Int32 nLen = rStr.getLength();
5072 265266 : if ( nPos >= nLen )
5073 : {
5074 0 : return -1;
5075 : }
5076 265266 : if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) )
5077 : {
5078 264751 : if ( rStr[ nPos ] == cQuote )
5079 : {
5080 0 : return nPos; // Closing cQuote
5081 : }
5082 264751 : return -1;
5083 : }
5084 515 : const sal_Unicode* p0 = rStr.getStr();
5085 515 : const sal_Unicode* p = p0 + nPos;
5086 515 : const sal_Unicode* p1 = p0 + nLen;
5087 1605 : while ( p < p1 )
5088 : {
5089 1090 : if ( *p == cQuote && p > p0 && *(p-1) != cEscIn )
5090 : {
5091 515 : return sal::static_int_cast< sal_Int32 >(p - p0);
5092 : }
5093 575 : p++;
5094 : }
5095 0 : return nLen; // End of String
5096 : }
5097 :
5098 0 : sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const
5099 : {
5100 0 : sal_uInt16 nCnt = 0;
5101 0 : sal_uInt16 nAnz = NumFor[nNumFor].GetCount();
5102 0 : short const * const pType = NumFor[nNumFor].Info().nTypeArray;
5103 0 : for ( sal_uInt16 j=0; j<nAnz; ++j )
5104 : {
5105 0 : switch ( pType[j] )
5106 : {
5107 : case NF_SYMBOLTYPE_STRING:
5108 : case NF_SYMBOLTYPE_CURRENCY:
5109 : case NF_SYMBOLTYPE_DATESEP:
5110 : case NF_SYMBOLTYPE_TIMESEP:
5111 : case NF_SYMBOLTYPE_TIME100SECSEP:
5112 : case NF_SYMBOLTYPE_PERCENT:
5113 0 : ++nCnt;
5114 0 : break;
5115 : }
5116 : }
5117 0 : return nCnt;
5118 : }
5119 :
5120 50394 : const CharClass& SvNumberformat::rChrCls() const
5121 : {
5122 50394 : return rScan.GetChrCls();
5123 : }
5124 :
5125 14 : const LocaleDataWrapper& SvNumberformat::rLoc() const
5126 : {
5127 14 : return rScan.GetLoc();
5128 : }
5129 :
5130 5559 : CalendarWrapper& SvNumberformat::GetCal() const
5131 : {
5132 5559 : return rScan.GetCal();
5133 : }
5134 :
5135 428618 : const SvNumberFormatter& SvNumberformat::GetFormatter() const
5136 : {
5137 428618 : return *rScan.GetNumberformatter();
5138 : }
5139 :
5140 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|