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