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