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