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