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