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