xref: /AOO41X/main/scaddins/source/analysis/analysishelper.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #include <com/sun/star/util/XNumberFormatTypes.hpp>
25 
26 #include <string.h>
27 #include <stdio.h>
28 #include <tools/resary.hxx>
29 #include <rtl/math.hxx>
30 #include "analysishelper.hxx"
31 #include "analysis.hrc"
32 
33 using namespace                 ::rtl;
34 using namespace                 ::com::sun::star;
35 
36 
37 
38 #define UNIQUE              sal_False   // function name does not exist in Calc
39 #define DOUBLE              sal_True    // function name exists in Calc
40 
41 #define STDPAR              sal_False   // all parameters are described
42 #define INTPAR              sal_True    // first parameter is internal
43 
44 #define FUNCDATA( FUNCNAME, DBL, OPT, NUMOFPAR, CAT ) \
45     { "get" #FUNCNAME, ANALYSIS_FUNCNAME_##FUNCNAME, ANALYSIS_##FUNCNAME, DBL, OPT, ANALYSIS_DEFFUNCNAME_##FUNCNAME, NUMOFPAR, CAT }
46 
47 const FuncDataBase pFuncDatas[] =
48 {
49     //                          UNIQUE or   INTPAR or
50     //         function name     DOUBLE      STDPAR     # of param  category
51     FUNCDATA( Workday,          UNIQUE,     INTPAR,     3,          FDCat_DateTime ),
52     FUNCDATA( Yearfrac,         UNIQUE,     INTPAR,     3,          FDCat_DateTime ),
53     FUNCDATA( Edate,            UNIQUE,     INTPAR,     2,          FDCat_DateTime ),
54     FUNCDATA( Weeknum,          DOUBLE,     INTPAR,     2,          FDCat_DateTime ),
55     FUNCDATA( Eomonth,          UNIQUE,     INTPAR,     2,          FDCat_DateTime ),
56     FUNCDATA( Networkdays,      UNIQUE,     INTPAR,     3,          FDCat_DateTime ),
57     FUNCDATA( Iseven,           DOUBLE,     STDPAR,     1,          FDCat_Inf ),
58     FUNCDATA( Isodd,            DOUBLE,     STDPAR,     1,          FDCat_Inf ),
59     FUNCDATA( Multinomial,      UNIQUE,     STDPAR,     1,          FDCat_Math ),
60     FUNCDATA( Seriessum,        UNIQUE,     STDPAR,     4,          FDCat_Math ),
61     FUNCDATA( Quotient,         UNIQUE,     STDPAR,     2,          FDCat_Math ),
62     FUNCDATA( Mround,           UNIQUE,     STDPAR,     2,          FDCat_Math ),
63     FUNCDATA( Sqrtpi,           UNIQUE,     STDPAR,     1,          FDCat_Math ),
64     FUNCDATA( Randbetween,      UNIQUE,     STDPAR,     2,          FDCat_Math ),
65     FUNCDATA( Gcd,              DOUBLE,     INTPAR,     1,          FDCat_Math ),
66     FUNCDATA( Lcm,              DOUBLE,     INTPAR,     1,          FDCat_Math ),
67     FUNCDATA( Besseli,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
68     FUNCDATA( Besselj,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
69     FUNCDATA( Besselk,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
70     FUNCDATA( Bessely,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
71     FUNCDATA( Bin2Oct,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
72     FUNCDATA( Bin2Dec,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
73     FUNCDATA( Bin2Hex,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
74     FUNCDATA( Oct2Bin,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
75     FUNCDATA( Oct2Dec,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
76     FUNCDATA( Oct2Hex,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
77     FUNCDATA( Dec2Bin,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
78     FUNCDATA( Dec2Hex,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
79     FUNCDATA( Dec2Oct,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
80     FUNCDATA( Hex2Bin,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
81     FUNCDATA( Hex2Dec,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
82     FUNCDATA( Hex2Oct,          UNIQUE,     INTPAR,     2,          FDCat_Tech ),
83     FUNCDATA( Delta,            UNIQUE,     INTPAR,     2,          FDCat_Tech ),
84     FUNCDATA( Erf,              UNIQUE,     INTPAR,     2,          FDCat_Tech ),
85     FUNCDATA( Erfc,             UNIQUE,     STDPAR,     1,          FDCat_Tech ),
86     FUNCDATA( Gestep,           UNIQUE,     INTPAR,     2,          FDCat_Tech ),
87     FUNCDATA( Factdouble,       UNIQUE,     STDPAR,     1,          FDCat_Tech ),
88     FUNCDATA( Imabs,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
89     FUNCDATA( Imaginary,        UNIQUE,     STDPAR,     1,          FDCat_Tech ),
90     FUNCDATA( Impower,          UNIQUE,     STDPAR,     2,          FDCat_Tech ),
91     FUNCDATA( Imargument,       UNIQUE,     STDPAR,     1,          FDCat_Tech ),
92     FUNCDATA( Imcos,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
93     FUNCDATA( Imdiv,            UNIQUE,     STDPAR,     2,          FDCat_Tech ),
94     FUNCDATA( Imexp,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
95     FUNCDATA( Imconjugate,      UNIQUE,     STDPAR,     1,          FDCat_Tech ),
96     FUNCDATA( Imln,             UNIQUE,     STDPAR,     1,          FDCat_Tech ),
97     FUNCDATA( Imlog10,          UNIQUE,     STDPAR,     1,          FDCat_Tech ),
98     FUNCDATA( Imlog2,           UNIQUE,     STDPAR,     1,          FDCat_Tech ),
99     FUNCDATA( Improduct,        UNIQUE,     INTPAR,     2,          FDCat_Tech ),
100     FUNCDATA( Imreal,           UNIQUE,     STDPAR,     1,          FDCat_Tech ),
101     FUNCDATA( Imsin,            UNIQUE,     STDPAR,     1,          FDCat_Tech ),
102     FUNCDATA( Imsub,            UNIQUE,     STDPAR,     2,          FDCat_Tech ),
103     FUNCDATA( Imsqrt,           UNIQUE,     STDPAR,     1,          FDCat_Tech ),
104     FUNCDATA( Imsum,            UNIQUE,     INTPAR,     1,          FDCat_Tech ),
105     FUNCDATA( Complex,          UNIQUE,     STDPAR,     3,          FDCat_Tech ),
106     FUNCDATA( Convert,          DOUBLE,     STDPAR,     3,          FDCat_Tech ),
107     FUNCDATA( Amordegrc,        UNIQUE,     INTPAR,     7,          FDCat_Finance ),
108     FUNCDATA( Amorlinc,         UNIQUE,     INTPAR,     7,          FDCat_Finance ),
109     FUNCDATA( Accrint,          UNIQUE,     INTPAR,     7,          FDCat_Finance ),
110     FUNCDATA( Accrintm,         UNIQUE,     INTPAR,     5,          FDCat_Finance ),
111     FUNCDATA( Received,         UNIQUE,     INTPAR,     5,          FDCat_Finance ),
112     FUNCDATA( Disc,             UNIQUE,     INTPAR,     5,          FDCat_Finance ),
113     FUNCDATA( Duration,         DOUBLE,     INTPAR,     6,          FDCat_Finance ),
114     FUNCDATA( Effect,           DOUBLE,     STDPAR,     2,          FDCat_Finance ),
115     FUNCDATA( Cumprinc,         DOUBLE,     STDPAR,     6,          FDCat_Finance ),
116     FUNCDATA( Cumipmt,          DOUBLE,     STDPAR,     6,          FDCat_Finance ),
117     FUNCDATA( Price,            UNIQUE,     INTPAR,     7,          FDCat_Finance ),
118     FUNCDATA( Pricedisc,        UNIQUE,     INTPAR,     5,          FDCat_Finance ),
119     FUNCDATA( Pricemat,         UNIQUE,     INTPAR,     6,          FDCat_Finance ),
120     FUNCDATA( Mduration,        UNIQUE,     INTPAR,     6,          FDCat_Finance ),
121     FUNCDATA( Nominal,          DOUBLE,     STDPAR,     2,          FDCat_Finance ),
122     FUNCDATA( Dollarfr,         UNIQUE,     STDPAR,     2,          FDCat_Finance ),
123     FUNCDATA( Dollarde,         UNIQUE,     STDPAR,     2,          FDCat_Finance ),
124     FUNCDATA( Yield,            UNIQUE,     INTPAR,     7,          FDCat_Finance ),
125     FUNCDATA( Yielddisc,        UNIQUE,     INTPAR,     5,          FDCat_Finance ),
126     FUNCDATA( Yieldmat,         UNIQUE,     INTPAR,     6,          FDCat_Finance ),
127     FUNCDATA( Tbilleq,          UNIQUE,     INTPAR,     3,          FDCat_Finance ),
128     FUNCDATA( Tbillprice,       UNIQUE,     INTPAR,     3,          FDCat_Finance ),
129     FUNCDATA( Tbillyield,       UNIQUE,     INTPAR,     3,          FDCat_Finance ),
130     FUNCDATA( Oddfprice,        UNIQUE,     INTPAR,     9,          FDCat_Finance ),
131     FUNCDATA( Oddfyield,        UNIQUE,     INTPAR,     9,          FDCat_Finance ),
132     FUNCDATA( Oddlprice,        UNIQUE,     INTPAR,     8,          FDCat_Finance ),
133     FUNCDATA( Oddlyield,        UNIQUE,     INTPAR,     8,          FDCat_Finance ),
134     FUNCDATA( Xirr,             UNIQUE,     INTPAR,     3,          FDCat_Finance ),
135     FUNCDATA( Xnpv,             UNIQUE,     STDPAR,     3,          FDCat_Finance ),
136     FUNCDATA( Intrate,          UNIQUE,     INTPAR,     5,          FDCat_Finance ),
137     FUNCDATA( Coupncd,          UNIQUE,     INTPAR,     4,          FDCat_Finance ),
138     FUNCDATA( Coupdays,         UNIQUE,     INTPAR,     4,          FDCat_Finance ),
139     FUNCDATA( Coupdaysnc,       UNIQUE,     INTPAR,     4,          FDCat_Finance ),
140     FUNCDATA( Coupdaybs,        UNIQUE,     INTPAR,     4,          FDCat_Finance ),
141     FUNCDATA( Couppcd,          UNIQUE,     INTPAR,     4,          FDCat_Finance ),
142     FUNCDATA( Coupnum,          UNIQUE,     INTPAR,     4,          FDCat_Finance ),
143     FUNCDATA( Fvschedule,       UNIQUE,     STDPAR,     2,          FDCat_Finance )
144 };
145 #undef FUNCDATA
146 
147 
148 sal_uInt16 DaysInMonth( sal_uInt16 nMonth, sal_uInt16 nYear )
149 {
150     if( (nMonth == 2) && IsLeapYear( nYear ) )
151         return 29;
152     static const sal_uInt16 aDaysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
153     return aDaysInMonth[ nMonth ];
154 }
155 
156 
157 /**
158  * Convert a date to a count of days starting from 01/01/0001
159  *
160  * The internal representation of a Date used in this Addin
161  * is the number of days between 01/01/0001 and the date
162  * this function converts a Day , Month, Year representation
163  * to this internal Date value.
164  *
165  */
166 
167 sal_Int32 DateToDays( sal_uInt16 nDay, sal_uInt16 nMonth, sal_uInt16 nYear )
168 {
169     sal_Int32 nDays = ((sal_Int32)nYear-1) * 365;
170     nDays += ((nYear-1) / 4) - ((nYear-1) / 100) + ((nYear-1) / 400);
171 
172     for( sal_uInt16 i = 1; i < nMonth; i++ )
173         nDays += DaysInMonth(i,nYear);
174     nDays += nDay;
175 
176     return nDays;
177 }
178 
179 
180 /**
181  * Convert a count of days starting from 01/01/0001 to a date
182  *
183  * The internal representation of a Date used in this Addin
184  * is the number of days between 01/01/0001 and the date
185  * this function converts this internal Date value
186  * to a Day , Month, Year representation of a Date.
187  *
188  */
189 
190 void DaysToDate( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear )
191     throw( lang::IllegalArgumentException )
192 {
193     if( nDays < 0 )
194         throw lang::IllegalArgumentException();
195 
196     sal_Int32   nTempDays;
197     sal_Int32   i = 0;
198     sal_Bool    bCalc;
199 
200     do
201     {
202         nTempDays = nDays;
203         rYear = (sal_uInt16)((nTempDays / 365) - i);
204         nTempDays -= ((sal_Int32) rYear -1) * 365;
205         nTempDays -= (( rYear -1) / 4) - (( rYear -1) / 100) + ((rYear -1) / 400);
206         bCalc = sal_False;
207         if ( nTempDays < 1 )
208         {
209             i++;
210             bCalc = sal_True;
211         }
212         else
213         {
214             if ( nTempDays > 365 )
215             {
216                 if ( (nTempDays != 366) || !IsLeapYear( rYear ) )
217                 {
218                     i--;
219                     bCalc = sal_True;
220                 }
221             }
222         }
223     }
224     while ( bCalc );
225 
226     rMonth = 1;
227     while ( (sal_Int32)nTempDays > DaysInMonth( rMonth, rYear ) )
228     {
229         nTempDays -= DaysInMonth( rMonth, rYear );
230         rMonth++;
231     }
232     rDay = (sal_uInt16)nTempDays;
233 }
234 
235 
236 /**
237  * Get the null date used by the spreadsheet document
238  *
239  * The internal representation of a Date used in this Addin
240  * is the number of days between 01/01/0001 and the date
241  * this function returns this internal Date value for the document null date
242  *
243  */
244 
245 sal_Int32 GetNullDate( constREFXPS& xOpt ) THROWDEF_RTE
246 {
247     if( xOpt.is() )
248     {
249         try
250         {
251             ANY aAny = xOpt->getPropertyValue( STRFROMASCII( "NullDate" ) );
252             util::Date  aDate;
253             if( aAny >>= aDate )
254                 return DateToDays( aDate.Day, aDate.Month, aDate.Year );
255         }
256         catch( uno::Exception& )
257         {
258         }
259     }
260 
261     // no null date available -> no calculations possible
262     throw uno::RuntimeException();
263 }
264 
265 
266 sal_Int32 GetDiffDate360(
267                 sal_uInt16 nDay1, sal_uInt16 nMonth1, sal_uInt16 nYear1, sal_Bool bLeapYear1,
268                 sal_uInt16 nDay2, sal_uInt16 nMonth2, sal_uInt16 nYear2,
269                 sal_Bool bUSAMethod )
270 {
271     if( nDay1 == 31 )
272         nDay1--;
273     else if( bUSAMethod && ( nMonth1 == 2 && ( nDay1 == 29 || ( nDay1 == 28 && !bLeapYear1 ) ) ) )
274             nDay1 = 30;
275 
276     if( nDay2 == 31 )
277     {
278         if( bUSAMethod && nDay1 != 30 )
279         {
280             //aDate2 += 1;      -> 1.xx.yyyy
281             nDay2 = 1;
282             if( nMonth2 == 12 )
283             {
284                 nYear2++;
285                 nMonth2 = 1;
286             }
287             else
288                 nMonth2++;
289         }
290         else
291             nDay2 = 30;
292     }
293 
294     return nDay2 + nMonth2 * 30 + nYear2 * 360 - nDay1 - nMonth1 * 30 - nYear1 * 360;
295 }
296 
297 
298 sal_Int32 GetDiffDate360( sal_Int32 nNullDate, sal_Int32 nDate1, sal_Int32 nDate2, sal_Bool bUSAMethod )
299 {
300     nDate1 += nNullDate;
301     nDate2 += nNullDate;
302 
303     sal_uInt16 nDay1, nMonth1, nYear1, nDay2, nMonth2, nYear2;
304 
305     DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
306     DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
307 
308     return GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ), nDay2, nMonth2, nYear2, bUSAMethod );
309 }
310 
311 
312 sal_Int32 GetDaysInYears( sal_uInt16 nYear1, sal_uInt16 nYear2 )
313 {
314     sal_uInt16  nLeaps = 0;
315     for( sal_uInt16 n = nYear1 ; n <= nYear2 ; n++ )
316     {
317         if( IsLeapYear( n ) )
318             nLeaps++;
319     }
320 
321     sal_uInt32  nSum = 1;
322     nSum += nYear2;
323     nSum -= nYear1;
324     nSum *= 365;
325     nSum += nLeaps;
326 
327     return nSum;
328 }
329 
330 
331 void GetDiffParam( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
332     sal_uInt16& rYears, sal_Int32& rDayDiffPart, sal_Int32& rDaysInYear ) THROWDEF_RTE_IAE
333 {
334     if( nStartDate > nEndDate )
335     {
336         sal_Int32   n = nEndDate;
337         nEndDate = nStartDate;
338         nStartDate = n;
339     }
340 
341     sal_Int32   nDate1 = nStartDate + nNullDate;
342     sal_Int32   nDate2 = nEndDate + nNullDate;
343 
344     sal_uInt16  nDay1, nDay2;
345     sal_uInt16  nMonth1, nMonth2;
346     sal_uInt16  nYear1, nYear2;
347 
348     DaysToDate( nDate1, nDay1, nMonth1, nYear1 );
349     DaysToDate( nDate2, nDay2, nMonth2, nYear2 );
350 
351     sal_uInt16  nYears;
352 
353     sal_Int32   nDayDiff, nDaysInYear;
354 
355     switch( nMode )
356     {
357         case 0:         // 0=USA (NASD) 30/360
358         case 4:         // 4=Europe 30/360
359             nDaysInYear = 360;
360             nYears = nYear2 - nYear1;
361             nDayDiff = GetDiffDate360( nDay1, nMonth1, nYear1, IsLeapYear( nYear1 ),
362                                         nDay2, nMonth2, nYear2, nMode == 0 ) - nYears * nDaysInYear;
363             break;
364         case 1:         // 1=exact/exact
365             nYears = nYear2 - nYear1;
366 
367             nDaysInYear = IsLeapYear( nYear1 )? 366 : 365;
368 
369             if( nYears && ( nMonth1 > nMonth2 || ( nMonth1 == nMonth2 && nDay1 > nDay2 ) ) )
370                 nYears--;
371 
372             if( nYears )
373                 nDayDiff = nDate2 - DateToDays( nDay1, nMonth1, nYear2 );
374             else
375                 nDayDiff = nDate2 - nDate1;
376 
377             if( nDayDiff < 0 )
378                 nDayDiff += nDaysInYear;
379 
380             break;
381         case 2:         // 2=exact/360
382             nDaysInYear = 360;
383             nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
384             nDayDiff = nDate2 - nDate1;
385             nDayDiff %= nDaysInYear;
386             break;
387         case 3:         //3=exact/365
388             nDaysInYear = 365;
389             nYears = sal_uInt16( ( nDate2 - nDate1 ) / nDaysInYear );
390             nDayDiff = nDate2 - nDate1;
391             nDayDiff %= nDaysInYear;
392             break;
393         default:
394             THROW_IAE;
395     }
396 
397     rYears = nYears;
398     rDayDiffPart = nDayDiff;
399     rDaysInYear = nDaysInYear;
400 }
401 
402 
403 sal_Int32 GetDiffDate( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode,
404     sal_Int32* pOptDaysIn1stYear ) THROWDEF_RTE_IAE
405 {
406     sal_Bool    bNeg = nStartDate > nEndDate;
407 
408     if( bNeg )
409     {
410         sal_Int32   n = nEndDate;
411         nEndDate = nStartDate;
412         nStartDate = n;
413     }
414 
415     sal_Int32       nRet;
416 
417     switch( nMode )
418     {
419         case 0:         // 0=USA (NASD) 30/360
420         case 4:         // 4=Europe 30/360
421             {
422             sal_uInt16      nD1, nM1, nY1, nD2, nM2, nY2;
423 
424             nStartDate += nNullDate;
425             nEndDate += nNullDate;
426 
427             DaysToDate( nStartDate, nD1, nM1, nY1 );
428             DaysToDate( nEndDate, nD2, nM2, nY2 );
429 
430             sal_Bool        bLeap = IsLeapYear( nY1 );
431             sal_Int32       nDays, nMonths/*, nYears*/;
432 
433             nMonths = nM2 - nM1;
434             nDays = nD2 - nD1;
435 
436             nMonths += ( nY2 - nY1 ) * 12;
437 
438             nRet = nMonths * 30 + nDays;
439             if( nMode == 0 && nM1 == 2 && nM2 != 2 && nY1 == nY2 )
440                 nRet -= bLeap? 1 : 2;
441 
442             if( pOptDaysIn1stYear )
443                 *pOptDaysIn1stYear = 360;
444             }
445             break;
446         case 1:         // 1=exact/exact
447             if( pOptDaysIn1stYear )
448             {
449                 sal_uInt16      nD, nM, nY;
450 
451                 DaysToDate( nStartDate + nNullDate, nD, nM, nY );
452 
453                 *pOptDaysIn1stYear = IsLeapYear( nY )? 366 : 365;
454             }
455             nRet = nEndDate - nStartDate;
456             break;
457         case 2:         // 2=exact/360
458             nRet = nEndDate - nStartDate;
459             if( pOptDaysIn1stYear )
460                 *pOptDaysIn1stYear = 360;
461             break;
462         case 3:         //3=exact/365
463             nRet = nEndDate - nStartDate;
464             if( pOptDaysIn1stYear )
465                 *pOptDaysIn1stYear = 365;
466             break;
467         default:
468             THROW_IAE;
469     }
470 
471     return bNeg? -nRet : nRet;
472 }
473 
474 
475 double GetYearDiff( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
476 {
477     sal_Int32   nDays1stYear;
478     sal_Int32   nTotalDays = GetDiffDate( nNullDate, nStartDate, nEndDate, nMode, &nDays1stYear );
479 
480     return double( nTotalDays ) / double( nDays1stYear );
481 }
482 
483 
484 sal_Int32 GetDaysInYear( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
485 {
486     switch( nMode )
487     {
488         case 0:         // 0=USA (NASD) 30/360
489         case 2:         // 2=exact/360
490         case 4:         // 4=Europe 30/360
491             return 360;
492         case 1:         // 1=exact/exact
493             {
494             sal_uInt16  nD, nM, nY;
495             nDate += nNullDate;
496             DaysToDate( nDate, nD, nM, nY );
497             return IsLeapYear( nY )? 366 : 365;
498             }
499         case 3:         //3=exact/365
500             return 365;
501         default:
502             THROW_IAE;
503     }
504 }
505 
506 
507 double GetYearFrac( sal_Int32 nNullDate, sal_Int32 nStartDate, sal_Int32 nEndDate, sal_Int32 nMode ) THROWDEF_RTE_IAE
508 {
509     if( nStartDate == nEndDate )
510         return 0.0;     // nothing to do...
511 
512     sal_uInt16  nYears;
513     sal_Int32   nDayDiff, nDaysInYear;
514 
515     GetDiffParam( nNullDate, nStartDate, nEndDate, nMode, nYears, nDayDiff, nDaysInYear );
516 
517     return double( nYears ) + double( nDayDiff ) / double( nDaysInYear );
518 }
519 
520 
521 double Fak( sal_Int32 n )
522 {
523     if( n > 0 )
524     {
525         double  fRet = n;
526         double  f = n - 1;
527 
528         while( f >= 2.0 )
529         {
530             fRet *= f;
531             f--;
532         }
533 
534         return fRet;
535     }
536     else if( !n )
537         return 1.0;
538     else
539         return 0.0;
540 }
541 
542 
543 double GetGcd( double f1, double f2 )
544 {
545     double  f = fmod( f1, f2 );
546     while( f > 0.0 )
547     {
548         f1 = f2;
549         f2 = f;
550         f = fmod( f1, f2 );
551     }
552 
553     return f2;
554 }
555 
556 
557 double ConvertToDec( const STRING& aStr, sal_uInt16 nBase, sal_uInt16 nCharLim ) THROWDEF_RTE_IAE
558 {
559     if ( nBase < 2 || nBase > 36 )
560         THROW_IAE;
561 
562     sal_uInt32      nStrLen = aStr.getLength();
563     if( nStrLen > nCharLim )
564         THROW_IAE;
565     else if( !nStrLen )
566         return 0.0;
567 
568     double          fVal = 0.0;
569 
570     register const sal_Unicode* p = aStr.getStr();
571 
572     sal_uInt16          nFirstDig = 0;
573     sal_Bool            bFirstDig = sal_True;
574     double              fBase = nBase;
575 
576     while ( *p )
577     {
578         sal_uInt16      n;
579 
580         if( '0' <= *p && *p <= '9' )
581             n = *p - '0';
582         else if( 'A' <= *p && *p <= 'Z' )
583             n = 10 + ( *p - 'A' );
584         else if ( 'a' <= *p && *p <= 'z' )
585             n = 10 + ( *p - 'a' );
586         else
587             n = nBase;
588 
589         if( n < nBase )
590         {
591             if( bFirstDig )
592             {
593                 bFirstDig = sal_False;
594                 nFirstDig = n;
595             }
596             fVal = fVal * fBase + double( n );
597         }
598         else
599             // illegal char!
600             THROW_IAE;
601 
602         p++;
603 
604     }
605 
606     if( nStrLen == nCharLim && !bFirstDig && (nFirstDig >= nBase / 2) )
607     {   // handling negativ values
608         fVal = ( pow( double( nBase ), double( nCharLim ) ) - fVal );   // complement
609         fVal *= -1.0;
610     }
611 
612     return fVal;
613 }
614 
615 
616 static inline sal_Char GetMaxChar( sal_uInt16 nBase )
617 {
618     const sal_Char* c = "--123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
619     return c[ nBase ];
620 }
621 
622 
623 STRING ConvertFromDec( double fNum, double fMin, double fMax, sal_uInt16 nBase,
624     sal_Int32 nPlaces, sal_Int32 nMaxPlaces, sal_Bool bUsePlaces ) THROWDEF_RTE_IAE
625 {
626     fNum = ::rtl::math::approxFloor( fNum );
627     fMin = ::rtl::math::approxFloor( fMin );
628     fMax = ::rtl::math::approxFloor( fMax );
629 
630     if( fNum < fMin || fNum > fMax || ( bUsePlaces && ( nPlaces <= 0 || nPlaces > nMaxPlaces ) ) )
631         THROW_IAE;
632 
633     sal_Int64 nNum = static_cast< sal_Int64 >( fNum );
634     sal_Bool        bNeg = nNum < 0;
635     if( bNeg )
636         nNum = sal_Int64( pow( double( nBase ), double( nMaxPlaces ) ) ) + nNum;
637 
638     STRING          aRet( STRING::valueOf( nNum, nBase ).toAsciiUpperCase() );
639 
640 
641     if( bUsePlaces )
642     {
643         sal_Int32 nLen = aRet.getLength();
644         if( !bNeg && nLen > nPlaces )
645         {
646             THROW_IAE;
647         }
648         else if( ( bNeg && nLen < nMaxPlaces ) || ( !bNeg && nLen < nPlaces ) )
649         {
650             sal_Int32   nLeft = nPlaces - nLen;
651             sal_Char*   p = new sal_Char[ nLeft + 1 ];
652             memset( p, bNeg? GetMaxChar( nBase ) : '0', nLeft );
653             p[ nLeft ] = 0x00;
654             STRING  aTmp( p, nLeft, RTL_TEXTENCODING_MS_1252 );
655             aTmp += aRet;
656             aRet = aTmp;
657 
658             delete[] p;
659         }
660     }
661 
662     return aRet;
663 }
664 
665 // implementation moved to module sal, see #i97091#
666 double Erf( double x )
667 {
668     return ::rtl::math::erf(x);
669 }
670 
671 // implementation moved to module sal, see #i97091#
672 double Erfc( double x )
673 {
674     return ::rtl::math::erfc(x);
675 }
676 
677 inline sal_Bool IsNum( sal_Unicode c )
678 {
679     return c >= '0' && c <= '9';
680 }
681 
682 
683 inline sal_Bool IsComma( sal_Unicode c )
684 {
685     return c == '.' || c == ',';
686 }
687 
688 
689 inline sal_Bool IsExpStart( sal_Unicode c )
690 {
691     return c == 'e' || c == 'E';
692 }
693 
694 
695 inline sal_Bool IsImagUnit( sal_Unicode c )
696 {
697     return c == 'i' || c == 'j';
698 }
699 
700 
701 inline sal_uInt16 GetVal( sal_Unicode c )
702 {
703     return sal_uInt16( c - '0' );
704 }
705 
706 
707 sal_Bool ParseDouble( const sal_Unicode*& rp, double& rRet )
708 {
709     double              fInt = 0.0;
710     double              fFrac = 0.0;
711     double              fMult = 0.1;    // multiplier to multiply digits with, when adding fractional ones
712     sal_Int32           nExp = 0;
713     sal_Int32           nMaxExp = 307;
714     sal_uInt16          nDigCnt = 18;   // max. number of digits to read in, rest doesn't matter
715 
716     enum State  { S_End = 0, S_Sign, S_IntStart, S_Int, S_IgnoreIntDigs, S_Frac, S_IgnoreFracDigs, S_ExpSign, S_Exp };
717 
718     State           eS = S_Sign;
719 
720     sal_Bool            bNegNum = sal_False;
721     sal_Bool            bNegExp = sal_False;
722 
723     const sal_Unicode*  p = rp;
724     sal_Unicode         c;
725 
726     while( eS )
727     {
728         c = *p;
729         switch( eS )
730         {
731             case S_Sign:
732                 if( IsNum( c ) )
733                 {
734                     fInt = GetVal( c );
735                     nDigCnt--;
736                     eS = S_Int;
737                 }
738                 else if( c == '-' )
739                 {
740                     bNegNum = sal_True;
741                     eS = S_IntStart;
742                 }
743                 else if( c == '+' )
744                     eS = S_IntStart;
745                 else if( IsComma( c ) )
746                     eS = S_Frac;
747                 else
748                     return sal_False;
749                 break;
750             case S_IntStart:
751                 if( IsNum( c ) )
752                 {
753                     fInt = GetVal( c );
754                     nDigCnt--;
755                     eS = S_Int;
756                 }
757                 else if( IsComma( c ) )
758                     eS = S_Frac;
759                 else if( IsImagUnit( c ) )
760                 {
761                     rRet = 0.0;
762                     return sal_True;
763                 }
764                 else
765                     return sal_False;
766                 break;
767             case S_Int:
768                 if( IsNum( c ) )
769                 {
770                     fInt *= 10.0;
771                     fInt += double( GetVal( c ) );
772                     nDigCnt--;
773                     if( !nDigCnt )
774                         eS = S_IgnoreIntDigs;
775                 }
776                 else if( IsComma( c ) )
777                     eS = S_Frac;
778                 else if( IsExpStart( c ) )
779                     eS = S_ExpSign;
780                 else
781                     eS = S_End;
782                 break;
783             case S_IgnoreIntDigs:
784                 if( IsNum( c ) )
785                     nExp++;         // just multiply num with 10... ;-)
786                 else if( IsComma( c ) )
787                     eS = S_Frac;
788                 else if( IsExpStart( c ) )
789                     eS = S_ExpSign;
790                 else
791                     eS = S_End;
792                 break;
793             case S_Frac:
794                 if( IsNum( c ) )
795                 {
796                     fFrac += double( GetVal( c ) ) * fMult;
797                     nDigCnt--;
798                     if( nDigCnt )
799                         fMult *= 0.1;
800                     else
801                         eS = S_IgnoreFracDigs;
802                 }
803                 else if( IsExpStart( c ) )
804                     eS = S_ExpSign;
805                 else
806                     eS = S_End;
807                 break;
808             case S_IgnoreFracDigs:
809                 if( IsExpStart( c ) )
810                     eS = S_ExpSign;
811                 else if( !IsNum( c ) )
812                     eS = S_End;
813                 break;
814             case S_ExpSign:
815                 if( IsNum( c ) )
816                 {
817                     nExp = GetVal( c );
818                     eS = S_Exp;
819                 }
820                 else if( c == '-' )
821                 {
822                     bNegExp = sal_True;
823                     eS = S_Exp;
824                 }
825                 else if( c != '+' )
826                     eS = S_End;
827                 break;
828             case S_Exp:
829                 if( IsNum( c ) )
830                 {
831                     nExp *= 10;
832                     nExp += GetVal( c );
833                     if( nExp > nMaxExp )
834                         return sal_False;
835                 }
836                 else
837                     eS = S_End;
838                 break;
839             case S_End:     // to avoid compiler warning
840                 break;      // loop exits anyway
841         }
842 
843         p++;
844     }
845 
846     p--;        // set pointer back to last
847     rp = p;
848 
849     fInt += fFrac;
850     sal_Int32   nLog10 = sal_Int32( log10( fInt ) );
851 
852     if( bNegExp )
853         nExp = -nExp;
854 
855     if( nLog10 + nExp > nMaxExp )
856         return sal_False;
857 
858     fInt = ::rtl::math::pow10Exp( fInt, nExp );
859 
860     if( bNegNum )
861         fInt = -fInt;
862 
863     rRet = fInt;
864 
865     return sal_True;
866 }
867 
868 
869 STRING GetString( double f, sal_Bool bLeadingSign, sal_uInt16 nMaxDig )
870 {
871     const int       nBuff = 256;
872     sal_Char        aBuff[ nBuff + 1 ];
873     const char*     pFormStr = bLeadingSign? "%+.*g" : "%.*g";
874     int             nLen = snprintf( aBuff, nBuff, pFormStr, int( nMaxDig ), f );
875                     // you never know which underlying implementation you get ...
876                     aBuff[nBuff] = 0;
877                     if ( nLen < 0 || nLen > nBuff )
878                         nLen = strlen( aBuff );
879 
880     STRING          aRet( aBuff, nLen, RTL_TEXTENCODING_MS_1252 );
881 
882     return aRet;
883 }
884 
885 
886 double GetAmordegrc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
887     double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
888 {
889     if( nBase == 2 )
890         THROW_IAE;
891 
892     sal_uInt32  nPer = sal_uInt32( fPer );
893     double      fUsePer = 1.0 / fRate;
894     double      fAmorCoeff;
895 
896     if( fUsePer < 3.0 )
897         fAmorCoeff = 1.0;
898     else if( fUsePer < 5.0 )
899         fAmorCoeff = 1.5;
900     else if( fUsePer <= 6.0 )
901         fAmorCoeff = 2.0;
902     else
903         fAmorCoeff = 2.5;
904 
905     fRate *= fAmorCoeff;
906     double      fNRate = ::rtl::math::round( GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost, 0 );
907     fCost -= fNRate;
908     double      fRest = fCost - fRestVal;   // Anschaffungskosten - Restwert - Summe aller Abschreibungen
909 
910     for( sal_uInt32 n = 0 ; n < nPer ; n++ )
911     {
912         fNRate = ::rtl::math::round( fRate * fCost, 0 );
913         fRest -= fNRate;
914 
915         if( fRest < 0.0 )
916         {
917             switch( nPer - n )
918             {
919                 case 0:
920                 case 1:
921                     return ::rtl::math::round( fCost * 0.5, 0 );
922                 default:
923                     return 0.0;
924             }
925         }
926 
927         fCost -= fNRate;
928     }
929 
930     return fNRate;
931 }
932 
933 
934 double GetAmorlinc( sal_Int32 nNullDate, double fCost, sal_Int32 nDate, sal_Int32 nFirstPer,
935     double fRestVal, double fPer, double fRate, sal_Int32 nBase ) THROWDEF_RTE_IAE
936 {
937     if( nBase == 2 )
938         THROW_IAE;
939 
940     sal_uInt32  nPer = sal_uInt32( fPer );
941     double      fOneRate = fCost * fRate;
942     double      fCostDelta = fCost - fRestVal;
943     double      f0Rate = GetYearFrac( nNullDate, nDate, nFirstPer, nBase ) * fRate * fCost;
944     sal_uInt32  nNumOfFullPeriods = sal_uInt32( ( fCost - fRestVal - f0Rate) / fOneRate );
945 
946     if( nPer == 0 )
947         return f0Rate;
948     else if( nPer <= nNumOfFullPeriods )
949         return fOneRate;
950     else if( nPer == nNumOfFullPeriods + 1 )
951         return fCostDelta - fOneRate * nNumOfFullPeriods - f0Rate;
952     else
953         return 0.0;
954 }
955 
956 
957 double GetDuration( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup,
958     double fYield, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
959 {
960     double          fYearfrac = GetYearFrac( nNullDate, nSettle, nMat, nBase );
961     double          fNumOfCoups = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
962     double          fDur = 0.0;
963     const double    f100 = 100.0;
964     fCoup *= f100 / double( nFreq );    // fCoup is used as cash flow
965     fYield /= nFreq;
966     fYield += 1.0;
967 
968     double nDiff = fYearfrac * nFreq - fNumOfCoups;
969 
970     double          t;
971 
972     for( t = 1.0 ; t < fNumOfCoups ; t++ )
973         fDur += ( t + nDiff ) * ( fCoup ) / pow( fYield, t + nDiff );
974 
975     fDur += ( fNumOfCoups + nDiff ) * ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
976 
977     double          p = 0.0;
978     for( t = 1.0 ; t < fNumOfCoups ; t++ )
979         p += fCoup / pow( fYield, t + nDiff );
980 
981     p += ( fCoup + f100 ) / pow( fYield, fNumOfCoups + nDiff );
982 
983     fDur /= p;
984     fDur /= double( nFreq );
985 
986     return fDur;
987 }
988 
989 
990 double GetYieldmat( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
991     double fRate, double fPrice, sal_Int32 nBase ) THROWDEF_RTE_IAE
992 {
993     double      fIssMat = GetYearFrac( nNullDate, nIssue, nMat, nBase );
994     double      fIssSet = GetYearFrac( nNullDate, nIssue, nSettle, nBase );
995     double      fSetMat = GetYearFrac( nNullDate, nSettle, nMat, nBase );
996 
997     double      y = 1.0 + fIssMat * fRate;
998     y /= fPrice / 100.0 + fIssSet * fRate;
999     y--;
1000     y /= fSetMat;
1001 
1002     return y;
1003 }
1004 
1005 
1006 double GetOddfprice( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1007     sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fYield*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1008     sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1009 {
1010     THROW_RTE;  // #87380#
1011 /*
1012     double      fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase ) - 1.0;
1013     double      fNq = GetCoupnum( nNullDate, nSettle, nFirstCoup, nFreq, nBase ) - 1.0;
1014     double      fDSC = GetCoupdaysnc( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1015     double      fDSC_E = fDSC / GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1016     double      fNC = GetCoupnum( nNullDate, nIssue, nFirstCoup, nFreq, nBase );
1017     sal_uInt32  nNC = sal_uInt32( fNC );
1018     sal_uInt16  nMonthDelta = 12 / sal_uInt16( nFreq );
1019 
1020     sal_uInt32  i;
1021     double      f1YieldFreq = 1.0 + fYield / double( nFreq );
1022     double      f100RateFreq = 100.0 * fRate / double( nFreq );
1023 
1024     double*     pDC = new double[ nNC + 1 ];
1025     double*     pNL = new double[ nNC + 1 ];
1026     double*     pA = new double[ nNC + 1 ];
1027 
1028     pDC[ 0 ] = pNL[ 0 ] = pA[ 0 ] = 1.0;
1029 
1030     ScaDate aStartDate( nNullDate, nSettle, nBase );
1031     ScaDate aNextCoup( nNullDate, nFirstCoup, nBase );
1032     if( nNC )
1033     {
1034         pDC[ 1 ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1035         pNL[ 1 ] = GetCoupdays( nNullDate, nSettle, nFirstCoup, nFreq, nBase );
1036         pA[ 1 ] = pDC[ 1 ];
1037         ScaDate aPre;
1038         for( i = 1 ; i <= nNC ; i++ )
1039         {
1040             aPre = aStartDate;
1041             aStartDate.addMonths( nMonthDelta );
1042             aNextCoup.addMonths( nMonthDelta );
1043             pDC[ i ] = ScaDate::GetDiff( aPre, aStartDate );
1044             pNL[ i ] = GetCoupdays( nNullDate, aStartDate.GetDate( nNullDate ), aNextCoup.GetDate( nNullDate ),
1045                                         nFreq, nBase );
1046             pA[ i ] = ScaDate::GetDiff( aStartDate, aNextCoup );
1047         }
1048     }
1049 
1050     double      fT1 = fRedemp / pow( f1YieldFreq, fN + fNq + fDSC_E );
1051 
1052     double      fT2 = 0.0;
1053     for( i = 1 ; i <= nNC ; i++ )
1054         fT2 += pDC[ i ] / pNL[ i ];
1055     fT2 *= f100RateFreq / pow( f1YieldFreq, fNq + fDSC_E );
1056 
1057     double      fT3 = 0.0;
1058     for( double k = 2.0 ; k <= fN ; k++ )
1059         fT3 += 1.0 / pow( f1YieldFreq, k - fNq + fDSC_E );
1060     fT3 *= f100RateFreq;
1061 
1062     double      fT4 = 0.0;
1063     for( i = 1 ; i <= nNC ; i++ )
1064         fT4 += pA[ i ] / pNL[ i ];
1065     fT4 *= f100RateFreq;
1066 
1067     if( nNC )
1068     {
1069         delete pDC;
1070         delete pNL;
1071         delete pA;
1072     }
1073 
1074     return fT1 + fT2 + fT3 - fT4;
1075 */
1076 }
1077 
1078 
1079 double getYield_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fCoup, double fPrice,
1080                     double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1081 {
1082     double      fRate = fCoup;
1083     double      fPriceN = 0.0;
1084     double      fYield1 = 0.0;
1085     double      fYield2 = 1.0;
1086     double      fPrice1 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield1, fRedemp, nFreq, nBase );
1087     double      fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1088     double      fYieldN = ( fYield2 - fYield1 ) * 0.5;
1089 
1090     for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1091     {
1092         fPriceN = getPrice_( nNullDate, nSettle, nMat, fRate, fYieldN, fRedemp, nFreq, nBase );
1093 
1094         if( fPrice == fPrice1 )
1095             return fYield1;
1096         else if( fPrice == fPrice2 )
1097             return fYield2;
1098         else if( fPrice == fPriceN )
1099             return fYieldN;
1100         else if( fPrice < fPrice2 )
1101         {
1102             fYield2 *= 2.0;
1103             fPrice2 = getPrice_( nNullDate, nSettle, nMat, fRate, fYield2, fRedemp, nFreq, nBase );
1104 
1105             fYieldN = ( fYield2 - fYield1 ) * 0.5;
1106         }
1107         else
1108         {
1109             if( fPrice < fPriceN )
1110             {
1111                 fYield1 = fYieldN;
1112                 fPrice1 = fPriceN;
1113             }
1114             else
1115             {
1116                 fYield2 = fYieldN;
1117                 fPrice2 = fPriceN;
1118             }
1119 
1120             fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1121         }
1122     }
1123 
1124     if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1125         THROW_IAE;      // result not precise enough
1126 
1127     return fYieldN;
1128 }
1129 
1130 
1131 double getPrice_( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, double fRate, double fYield,
1132                     double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1133 {
1134     double      fFreq = nFreq;
1135 
1136     double      fE = GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase );
1137     double      fDSC_E = GetCoupdaysnc( nNullDate, nSettle, nMat, nFreq, nBase ) / fE;
1138     double      fN = GetCoupnum( nNullDate, nSettle, nMat, nFreq, nBase );
1139     double      fA = GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1140 
1141     double      fRet = fRedemp / ( pow( 1.0 + fYield / fFreq, fN - 1.0 + fDSC_E ) );
1142     fRet -= 100.0 * fRate / fFreq * fA / fE;
1143 
1144     double      fT1 = 100.0 * fRate / fFreq;
1145     double      fT2 = 1.0 + fYield / fFreq;
1146 
1147     for( double fK = 0.0 ; fK < fN ; fK++ )
1148         fRet += fT1 / pow( fT2, fK + fDSC_E );
1149 
1150     return fRet;
1151 }
1152 
1153 
1154 double GetOddfyield( sal_Int32 /*nNullDate*/, sal_Int32 /*nSettle*/, sal_Int32 /*nMat*/, sal_Int32 /*nIssue*/,
1155     sal_Int32 /*nFirstCoup*/, double /*fRate*/, double /*fPrice*/, double /*fRedemp*/, sal_Int32 /*nFreq*/,
1156     sal_Int32 /*nBase*/ ) THROWDEF_RTE_IAE
1157 {
1158     THROW_RTE;  // #87380#
1159 /*
1160     //GetOddfprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nIssue,
1161     //sal_Int32 nFirstCoup, double fRate, double fYield, double fRedemp, sal_Int32 nFreq,
1162     //sal_Int32 nBase )
1163     double      fPriceN = 0.0;
1164     double      fYield1 = 0.0;
1165     double      fYield2 = 1.0;
1166     double      fPrice1 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield1, fRedemp, nFreq, nBase );
1167     double      fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1168     double      fYieldN = ( fYield2 - fYield1 ) * 0.5;
1169 
1170     for( sal_uInt32 nIter = 0 ; nIter < 100 && fPriceN != fPrice ; nIter++ )
1171     {
1172         fPriceN = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYieldN, fRedemp, nFreq, nBase );
1173 
1174         if( fPrice == fPrice1 )
1175             return fYield1;
1176         else if( fPrice == fPrice2 )
1177             return fYield2;
1178         else if( fPrice == fPriceN )
1179             return fYieldN;
1180         else if( fPrice < fPrice2 )
1181         {
1182             fYield2 *= 2.0;
1183             fPrice2 = GetOddfprice( nNullDate, nSettle, nMat, nIssue, nFirstCoup, fRate, fYield2, fRedemp, nFreq, nBase );
1184 
1185             fYieldN = ( fYield2 - fYield1 ) * 0.5;
1186         }
1187         else
1188         {
1189             if( fPrice < fPriceN )
1190             {
1191                 fYield1 = fYieldN;
1192                 fPrice1 = fPriceN;
1193             }
1194             else
1195             {
1196                 fYield2 = fYieldN;
1197                 fPrice2 = fPriceN;
1198             }
1199 
1200             fYieldN = fYield2 - ( fYield2 - fYield1 ) * ( ( fPrice - fPrice2 ) / ( fPrice1 - fPrice2 ) );
1201         }
1202     }
1203 
1204     if( fabs( fPrice - fPriceN ) > fPrice / 100.0 )
1205         THROW_IAE;      // result not precise enough
1206 
1207     return fYieldN;
1208 */
1209 }
1210 
1211 
1212 double GetOddlprice( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1213     double fRate, double fYield, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1214 {
1215     double      fFreq = double( nFreq );
1216     double      fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1217     double      fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1218     double      fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1219 
1220     double      p = fRedemp + fDCi * 100.0 * fRate / fFreq;
1221     p /= fDSCi * fYield / fFreq + 1.0;
1222     p -= fAi * 100.0 * fRate / fFreq;
1223 
1224     return p;
1225 }
1226 
1227 
1228 double GetOddlyield( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nLastCoup,
1229     double fRate, double fPrice, double fRedemp, sal_Int32 nFreq, sal_Int32 nBase ) THROWDEF_RTE_IAE
1230 {
1231     double      fFreq = double( nFreq );
1232     double      fDCi = GetYearFrac( nNullDate, nLastCoup, nMat, nBase ) * fFreq;
1233     double      fDSCi = GetYearFrac( nNullDate, nSettle, nMat, nBase ) * fFreq;
1234     double      fAi = GetYearFrac( nNullDate, nLastCoup, nSettle, nBase ) * fFreq;
1235 
1236     double      y = fRedemp + fDCi * 100.0 * fRate / fFreq;
1237     y /= fPrice + fAi * 100.0 * fRate / fFreq;
1238     y--;
1239     y *= fFreq / fDSCi;
1240 
1241     return y;
1242 }
1243 
1244 
1245 double GetRmz( double fZins, double fZzr, double fBw, double fZw, sal_Int32 nF )
1246 {
1247     double      fRmz;
1248     if( fZins == 0.0 )
1249         fRmz = ( fBw + fZw ) / fZzr;
1250     else
1251     {
1252         double  fTerm = pow( 1.0 + fZins, fZzr );
1253         if( nF > 0 )
1254             fRmz = ( fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm ) ) / ( 1.0 + fZins );
1255         else
1256             fRmz = fZw * fZins / ( fTerm - 1.0 ) + fBw * fZins / ( 1.0 - 1.0 / fTerm );
1257     }
1258 
1259     return -fRmz;
1260 }
1261 
1262 
1263 double GetZw( double fZins, double fZzr, double fRmz, double fBw, sal_Int32 nF )
1264 {
1265     double      fZw;
1266     if( fZins == 0.0 )
1267         fZw = fBw + fRmz * fZzr;
1268     else
1269     {
1270         double  fTerm = pow( 1.0 + fZins, fZzr );
1271         if( nF > 0 )
1272             fZw = fBw * fTerm + fRmz * ( 1.0 + fZins ) * ( fTerm - 1.0 ) / fZins;
1273         else
1274             fZw = fBw * fTerm + fRmz * ( fTerm - 1.0 ) / fZins;
1275     }
1276 
1277     return -fZw;
1278 }
1279 
1280 
1281 /*double TBillYield( constREFXPS& xOpt, sal_Int32 nSettle, sal_Int32 nMat, double fPrice ) THROWDEF_RTE_IAE
1282 {
1283     sal_Int32   nDiff = GetDiffDate360( xOpt, nSettle, nMat, sal_True );
1284 
1285     if( fPrice <= 0.0 || nSettle >= nMat || nDiff > 360 )
1286         THROW_IAE;
1287 
1288     double      fRet = 100.0;
1289     fRet /= fPrice;
1290     fRet--;
1291     fRet *= double( nDiff );
1292     fRet /= 360.0;
1293 
1294     return fRet;
1295 }*/
1296 
1297 
1298 //-----------------------------------------------------------------------------
1299 // financial functions COUP***
1300 
1301 
1302 //-------
1303 // COUPPCD: find last coupon date before settlement (can be equal to settlement)
1304 void lcl_GetCouppcd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1305     throw( lang::IllegalArgumentException )
1306 {
1307     rDate = rMat;
1308     rDate.setYear( rSettle.getYear() );
1309     if( rDate < rSettle )
1310         rDate.addYears( 1 );
1311     while( rDate > rSettle )
1312         rDate.addMonths( -12 / nFreq );
1313 }
1314 
1315 double GetCouppcd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1316     THROWDEF_RTE_IAE
1317 {
1318     if( nSettle >= nMat || CHK_Freq )
1319         THROW_IAE;
1320 
1321     ScaDate aDate;
1322     lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1323     return aDate.getDate( nNullDate );
1324 }
1325 
1326 
1327 //-------
1328 // COUPNCD: find first coupon date after settlement (is never equal to settlement)
1329 void lcl_GetCoupncd( ScaDate& rDate, const ScaDate& rSettle, const ScaDate& rMat, sal_Int32 nFreq )
1330     throw( lang::IllegalArgumentException )
1331 {
1332     rDate = rMat;
1333     rDate.setYear( rSettle.getYear() );
1334     if( rDate > rSettle )
1335         rDate.addYears( -1 );
1336     while( rDate <= rSettle )
1337         rDate.addMonths( 12 / nFreq );
1338 }
1339 
1340 double GetCoupncd( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1341     THROWDEF_RTE_IAE
1342 {
1343     if( nSettle >= nMat || CHK_Freq )
1344         THROW_IAE;
1345 
1346     ScaDate aDate;
1347     lcl_GetCoupncd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1348     return aDate.getDate( nNullDate );
1349 }
1350 
1351 
1352 //-------
1353 // COUPDAYBS: get day count: coupon date before settlement <-> settlement
1354 double GetCoupdaybs( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1355     THROWDEF_RTE_IAE
1356 {
1357     if( nSettle >= nMat || CHK_Freq )
1358         THROW_IAE;
1359 
1360     ScaDate aSettle( nNullDate, nSettle, nBase );
1361     ScaDate aDate;
1362     lcl_GetCouppcd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1363     return ScaDate::getDiff( aDate, aSettle );
1364 }
1365 
1366 
1367 //-------
1368 // COUPDAYSNC: get day count: settlement <-> coupon date after settlement
1369 double GetCoupdaysnc( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1370     THROWDEF_RTE_IAE
1371 {
1372     if( nSettle >= nMat || CHK_Freq )
1373         THROW_IAE;
1374 
1375     if( (nBase != 0) && (nBase != 4) )
1376     {
1377         ScaDate aSettle( nNullDate, nSettle, nBase );
1378         ScaDate aDate;
1379         lcl_GetCoupncd( aDate, aSettle, ScaDate( nNullDate, nMat, nBase ), nFreq );
1380         return ScaDate::getDiff( aSettle, aDate );
1381     }
1382     return GetCoupdays( nNullDate, nSettle, nMat, nFreq, nBase ) - GetCoupdaybs( nNullDate, nSettle, nMat, nFreq, nBase );
1383 }
1384 
1385 
1386 //-------
1387 // COUPDAYS: get day count: coupon date before settlement <-> coupon date after settlement
1388 double GetCoupdays( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1389     THROWDEF_RTE_IAE
1390 {
1391     if( nSettle >= nMat || CHK_Freq )
1392         THROW_IAE;
1393 
1394     if( nBase == 1 )
1395     {
1396         ScaDate aDate;
1397         lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), ScaDate( nNullDate, nMat, nBase ), nFreq );
1398         ScaDate aNextDate( aDate );
1399         aNextDate.addMonths( 12 / nFreq );
1400         return ScaDate::getDiff( aDate, aNextDate );
1401     }
1402     return static_cast< double >( GetDaysInYear( 0, 0, nBase ) ) / nFreq;
1403 }
1404 
1405 
1406 //-------
1407 // COUPNUM: get count of coupon dates
1408 double GetCoupnum( sal_Int32 nNullDate, sal_Int32 nSettle, sal_Int32 nMat, sal_Int32 nFreq, sal_Int32 nBase )
1409     THROWDEF_RTE_IAE
1410 {
1411     if( nSettle >= nMat || CHK_Freq )
1412         THROW_IAE;
1413 
1414     ScaDate aMat( nNullDate, nMat, nBase );
1415     ScaDate aDate;
1416     lcl_GetCouppcd( aDate, ScaDate( nNullDate, nSettle, nBase ), aMat, nFreq );
1417     sal_uInt16 nMonths = (aMat.getYear() - aDate.getYear()) * 12 + aMat.getMonth() - aDate.getMonth();
1418     return static_cast< double >( nMonths * nFreq / 12 );
1419 }
1420 
1421 
1422 
1423 
1424 
1425 
1426 
1427 const sal_uInt32 MyList::nStartSize = 16;
1428 const sal_uInt32 MyList::nIncrSize = 16;
1429 
1430 
1431 void MyList::_Grow( void )
1432 {
1433     nSize += nIncrSize;
1434 
1435     void**          pNewData = new void*[ nSize ];
1436     memcpy( pNewData, pData, nNew * sizeof( void* ) );
1437 
1438     delete[] pData;
1439     pData = pNewData;
1440 }
1441 
1442 
1443 MyList::MyList( void )
1444 {
1445     nSize = nStartSize;
1446     pData = new void*[ nSize ];
1447     nNew = nAct = 0;
1448 }
1449 
1450 
1451 MyList::~MyList()
1452 {
1453     delete[] pData;
1454 }
1455 
1456 
1457 void MyList::Insert( void* p, sal_uInt32 n )
1458 {
1459     if( n >= nNew )
1460         Append( p );
1461     else
1462     {
1463         Grow();
1464 
1465         void**      pIns = pData + n;
1466         memmove( pIns + 1, pIns, ( nNew - n ) * sizeof( void* ) );
1467 
1468         *pIns = p;
1469 
1470         nNew++;
1471     }
1472 }
1473 
1474 
1475 
1476 
1477 StringList::~StringList()
1478 {
1479     for( STRING* p = ( STRING* ) First() ; p ; p = ( STRING* ) Next() )
1480         delete p;
1481 }
1482 
1483 
1484 class AnalysisRscStrArrLoader : public Resource
1485 {
1486 private:
1487     ResStringArray          aStrArray;
1488 public:
1489                             AnalysisRscStrArrLoader( sal_uInt16 nRsc, sal_uInt16 nArrayId, ResMgr& rResMgr ) :
1490                                 Resource( AnalysisResId( nRsc, rResMgr ) ),
1491                                 aStrArray( AnalysisResId( nArrayId, rResMgr ) )
1492                             {
1493                                 FreeResource();
1494                             }
1495 
1496     const ResStringArray&   GetStringArray() const { return aStrArray; }
1497 };
1498 
1499 
1500 
1501 
1502 FuncData::FuncData( const FuncDataBase& r, ResMgr& rResMgr ) :
1503     aIntName( OUString::createFromAscii( r.pIntName ) ),
1504     nUINameID( r.nUINameID ),
1505     nDescrID( r.nDescrID ),
1506     bDouble( r.bDouble ),
1507     bWithOpt( r.bWithOpt ),
1508     nParam( r.nNumOfParams ),
1509     nCompID( r.nCompListID ),
1510     eCat( r.eCat )
1511 {
1512     AnalysisRscStrArrLoader aArrLoader( RID_ANALYSIS_DEFFUNCTION_NAMES, nCompID, rResMgr );
1513 //  ResStringArray      aDefFuncNameArray( AnalysisResId( nCompID, rResMgr ) );
1514     const ResStringArray&   rArr = aArrLoader.GetStringArray();
1515 
1516     sal_uInt16              nCount = sal::static_int_cast<sal_uInt16>( rArr.Count() );
1517     sal_uInt16              n;
1518 
1519     for( n = 0 ; n < nCount ; n++ )
1520         aCompList.Append( rArr.GetString( n ) );
1521 }
1522 
1523 
1524 FuncData::~FuncData()
1525 {
1526 }
1527 
1528 
1529 sal_uInt16 FuncData::GetStrIndex( sal_uInt16 nParamNum ) const
1530 {
1531     if( !bWithOpt )
1532         nParamNum++;
1533 
1534     if( nParamNum > nParam )
1535         return nParam * 2;
1536     else
1537         return nParamNum * 2;
1538 }
1539 
1540 
1541 
1542 
1543 FuncDataList::FuncDataList( ResMgr& rResMgr )
1544 {
1545     const sal_uInt32    nNum = sizeof( pFuncDatas ) / sizeof( FuncDataBase );
1546 
1547     for( sal_uInt16 n = 0 ; n < nNum ; n++ )
1548         Append( new FuncData( pFuncDatas[ n ], rResMgr ) );
1549 }
1550 
1551 
1552 FuncDataList::~FuncDataList()
1553 {
1554     for( FuncData* p = ( FuncData* ) First() ; p ; p = ( FuncData* ) Next() )
1555         delete p;
1556 }
1557 
1558 
1559 const FuncData* FuncDataList::Get(  const OUString& aProgrammaticName ) const
1560 {
1561     if( aLastName == aProgrammaticName )
1562         return Get( nLast );
1563 
1564     ( ( FuncDataList* ) this )->aLastName = aProgrammaticName;
1565 
1566     sal_uInt32  nE = Count();
1567     for( sal_uInt32 n = 0 ; n < nE ; n++ )
1568     {
1569         const FuncData* p = Get( n );
1570         if( p->Is( aProgrammaticName ) )
1571         {
1572             ( ( FuncDataList* ) this )->nLast = n;
1573             return p;
1574         }
1575     }
1576 
1577     ( ( FuncDataList* ) this )->nLast = 0xFFFFFFFF;
1578     return NULL;
1579 }
1580 
1581 
1582 AnalysisResId::AnalysisResId( sal_uInt16 nId, ResMgr& rResMgr ) : ResId( nId, rResMgr )
1583 {
1584 }
1585 
1586 
1587 
1588 
1589 SortedIndividualInt32List::SortedIndividualInt32List()
1590 {
1591 }
1592 
1593 
1594 SortedIndividualInt32List::~SortedIndividualInt32List()
1595 {
1596 }
1597 
1598 
1599 void SortedIndividualInt32List::Insert( sal_Int32 nDay )
1600 {
1601     sal_uInt32 nIndex = Count();
1602     while( nIndex )
1603     {
1604         nIndex--;
1605         sal_Int32 nRef = Get( nIndex );
1606         if( nDay == nRef )
1607             return;
1608         else if( nDay > nRef )
1609         {
1610             MyList::Insert( (void*) nDay, nIndex + 1 );
1611             return;
1612         }
1613     }
1614     MyList::Insert( (void*) nDay, 0UL );
1615 }
1616 
1617 
1618 void SortedIndividualInt32List::Insert( sal_Int32 nDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend )
1619 {
1620     if( !nDay )
1621         return;
1622 
1623     nDay += nNullDate;
1624     if( bInsertOnWeekend || (GetDayOfWeek( nDay ) < 5) )
1625         Insert( nDay );
1626 }
1627 
1628 
1629 void SortedIndividualInt32List::Insert(
1630         double fDay, sal_Int32 nNullDate, sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1631 {
1632     if( (fDay < -2147483648.0) || (fDay > 2147483649.0) )
1633         throw lang::IllegalArgumentException();
1634     Insert( static_cast< sal_Int32 >( fDay ), nNullDate, bInsertOnWeekend );
1635 }
1636 
1637 
1638 sal_Bool SortedIndividualInt32List::Find( sal_Int32 nVal ) const
1639 {
1640     sal_uInt32  nE = Count();
1641 
1642     if( !nE || nVal < Get( 0 ) || nVal > Get( nE - 1 ) )
1643         return sal_False;
1644 
1645     // linear search
1646 
1647     for( sal_uInt32 n = 0 ; n < nE ; n++ )
1648     {
1649         sal_Int32   nRef = Get( n );
1650 
1651         if( nRef == nVal )
1652             return sal_True;
1653         else if( nRef > nVal )
1654             return sal_False;
1655     }
1656     return sal_False;
1657 }
1658 
1659 
1660 void SortedIndividualInt32List::InsertHolidayList(
1661         const ScaAnyConverter& rAnyConv,
1662         const uno::Any& rHolAny,
1663         sal_Int32 nNullDate,
1664         sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1665 {
1666     double fDay;
1667     if( rAnyConv.getDouble( fDay, rHolAny ) )
1668         Insert( fDay, nNullDate, bInsertOnWeekend );
1669 }
1670 
1671 
1672 void SortedIndividualInt32List::InsertHolidayList(
1673         ScaAnyConverter& rAnyConv,
1674         const uno::Reference< beans::XPropertySet >& xOptions,
1675         const uno::Any& rHolAny,
1676         sal_Int32 nNullDate,
1677         sal_Bool bInsertOnWeekend ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1678 {
1679     rAnyConv.init( xOptions );
1680     if( rHolAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1681     {
1682         uno::Sequence< uno::Sequence< uno::Any > > aAnySeq;
1683         if( rHolAny >>= aAnySeq )
1684         {
1685             const uno::Sequence< uno::Any >* pSeqArray = aAnySeq.getConstArray();
1686             for( sal_Int32 nIndex1 = 0; nIndex1 < aAnySeq.getLength(); nIndex1++ )
1687             {
1688                 const uno::Sequence< uno::Any >& rSubSeq = pSeqArray[ nIndex1 ];
1689                 const uno::Any* pAnyArray = rSubSeq.getConstArray();
1690 
1691                 for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1692                     InsertHolidayList( rAnyConv, pAnyArray[ nIndex2 ], nNullDate, bInsertOnWeekend );
1693             }
1694         }
1695         else
1696             throw lang::IllegalArgumentException();
1697     }
1698     else
1699         InsertHolidayList( rAnyConv, rHolAny, nNullDate, bInsertOnWeekend );
1700 }
1701 
1702 
1703 
1704 //-----------------------------------------------------------------------------
1705 
1706 ScaDoubleList::~ScaDoubleList()
1707 {
1708     for( double* pDbl = const_cast< double* >( First() ); pDbl; pDbl = const_cast< double* >( Next() ) )
1709         delete pDbl;
1710 }
1711 
1712 
1713 void ScaDoubleList::Append(
1714         const uno::Sequence< uno::Sequence< double > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1715 {
1716     const uno::Sequence< double >* pSeqArray = rValueSeq.getConstArray();
1717     for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1718     {
1719         const uno::Sequence< double >& rSubSeq = pSeqArray[ nIndex1 ];
1720         const double* pArray = rSubSeq.getConstArray();
1721         for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1722             Append( pArray[ nIndex2 ] );
1723     }
1724 }
1725 
1726 
1727 void ScaDoubleList::Append(
1728         const uno::Sequence< uno::Sequence< sal_Int32 > >& rValueSeq ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1729 {
1730     const uno::Sequence< sal_Int32 >* pSeqArray = rValueSeq.getConstArray();
1731     for( sal_Int32 nIndex1 = 0; nIndex1 < rValueSeq.getLength(); nIndex1++ )
1732     {
1733         const uno::Sequence< sal_Int32 >& rSubSeq = pSeqArray[ nIndex1 ];
1734         const sal_Int32* pArray = rSubSeq.getConstArray();
1735         for( sal_Int32 nIndex2 = 0; nIndex2 < rSubSeq.getLength(); nIndex2++ )
1736             Append( pArray[ nIndex2 ] );
1737     }
1738 }
1739 
1740 
1741 
1742 void ScaDoubleList::Append(
1743         const ScaAnyConverter& rAnyConv,
1744         const uno::Any& rAny,
1745         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1746 {
1747     if( rAny.getValueTypeClass() == uno::TypeClass_SEQUENCE )
1748         Append( rAnyConv, *static_cast< const uno::Sequence< uno::Sequence< uno::Any > >* >( rAny.getValue() ), bIgnoreEmpty );
1749     else
1750     {
1751         double fValue;
1752         if( rAnyConv.getDouble( fValue, rAny ) )
1753             Append( fValue );
1754         else if( !bIgnoreEmpty )
1755             Append( 0.0 );
1756     }
1757 }
1758 
1759 
1760 void ScaDoubleList::Append(
1761         const ScaAnyConverter& rAnyConv,
1762         const uno::Sequence< uno::Any >& rAnySeq,
1763         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1764 {
1765     const uno::Any* pArray = rAnySeq.getConstArray();
1766     for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1767         Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1768 }
1769 
1770 
1771 void ScaDoubleList::Append(
1772         const ScaAnyConverter& rAnyConv,
1773         const uno::Sequence< uno::Sequence< uno::Any > >& rAnySeq,
1774         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1775 {
1776     const uno::Sequence< uno::Any >* pArray = rAnySeq.getConstArray();
1777     for( sal_Int32 nIndex = 0; nIndex < rAnySeq.getLength(); nIndex++ )
1778         Append( rAnyConv, pArray[ nIndex ], bIgnoreEmpty );
1779 }
1780 
1781 
1782 
1783 void ScaDoubleList::Append(
1784         ScaAnyConverter& rAnyConv,
1785         const uno::Reference< beans::XPropertySet >& xOpt,
1786         const uno::Sequence< uno::Any >& rAnySeq,
1787         sal_Bool bIgnoreEmpty ) throw( uno::RuntimeException, lang::IllegalArgumentException )
1788 {
1789     rAnyConv.init( xOpt );
1790     Append( rAnyConv, rAnySeq, bIgnoreEmpty );
1791 }
1792 
1793 
1794 sal_Bool ScaDoubleList::CheckInsert( double ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1795 {
1796     return sal_True;
1797 }
1798 
1799 
1800 
1801 //-----------------------------------------------------------------------------
1802 
1803 sal_Bool ScaDoubleListGT0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1804 {
1805     if( fValue < 0.0 )
1806         throw lang::IllegalArgumentException();
1807     return fValue > 0.0;
1808 }
1809 
1810 
1811 
1812 //-----------------------------------------------------------------------------
1813 
1814 sal_Bool ScaDoubleListGE0::CheckInsert( double fValue ) const throw( uno::RuntimeException, lang::IllegalArgumentException )
1815 {
1816     if( fValue < 0.0 )
1817         throw lang::IllegalArgumentException();
1818     return sal_True;
1819 }
1820 
1821 
1822 
1823 //-----------------------------------------------------------------------------
1824 
1825 Complex::Complex( const STRING& rStr ) THROWDEF_RTE_IAE
1826 {
1827     if( !ParseString( rStr, *this ) )
1828         THROW_IAE;
1829 }
1830 
1831 
1832 inline sal_Bool Complex::IsImagUnit( sal_Unicode c )
1833 {
1834     return c == 'i' || c == 'j';
1835 }
1836 
1837 sal_Bool Complex::ParseString( const STRING& rStr, Complex& rCompl )
1838 {
1839     rCompl.c = '\0';    // do not force a symbol, if only real part present
1840 
1841     const sal_Unicode*      pStr = ( const sal_Unicode * ) rStr;
1842 
1843     if( IsImagUnit( *pStr ) && rStr.getLength() == 1)
1844     {
1845         rCompl.r = 0.0;
1846         rCompl.i = 1.0;
1847         rCompl.c = *pStr;
1848         return sal_True;
1849     }
1850 
1851     double                  f;
1852 
1853     if( !ParseDouble( pStr, f ) )
1854         return sal_False;
1855 
1856     switch( *pStr )
1857     {
1858         case '-':   // imag part follows
1859         case '+':
1860             {
1861             double      r = f;
1862             if( IsImagUnit( pStr[ 1 ] ) )
1863             {
1864                 rCompl.c = pStr[ 1 ];
1865                 if( pStr[ 2 ] == 0 )
1866                 {
1867                     rCompl.r = f;
1868                     rCompl.i = ( *pStr == '+' )? 1.0 : -1.0;
1869                     return sal_True;
1870                 }
1871             }
1872             else if( ParseDouble( pStr, f ) && IsImagUnit( *pStr ) )
1873             {
1874                 rCompl.c = *pStr;
1875                 pStr++;
1876                 if( *pStr == 0 )
1877                 {
1878                     rCompl.r = r;
1879                     rCompl.i = f;
1880                     return sal_True;
1881                 }
1882             }
1883             }
1884             break;
1885         case 'j':
1886         case 'i':
1887             rCompl.c = *pStr;
1888             pStr++;
1889             if( *pStr == 0 )
1890             {
1891                 rCompl.i = f;
1892                 rCompl.r = 0.0;
1893                 return sal_True;
1894             }
1895             break;
1896         case 0:     // only real-part
1897             rCompl.r = f;
1898             rCompl.i = 0.0;
1899             return sal_True;
1900     }
1901 
1902     return sal_False;
1903 }
1904 
1905 
1906 STRING Complex::GetString() const THROWDEF_RTE_IAE
1907 {
1908     static const String aI( 'i' );
1909     static const String aJ( 'j' );
1910     static const String aPlus( '+' );
1911     static const String aMinus( '-' );
1912 
1913     CHK_FINITE(r);
1914     CHK_FINITE(i);
1915     STRING aRet;
1916 
1917     bool bHasImag = i != 0.0;
1918     bool bHasReal = !bHasImag || (r != 0.0);
1919 
1920     if( bHasReal )
1921         aRet = ::GetString( r );
1922     if( bHasImag )
1923     {
1924         if( i == 1.0 )
1925         {
1926             if( bHasReal )
1927                 aRet += aPlus;
1928         }
1929         else if( i == -1.0 )
1930             aRet += aMinus;
1931         else
1932             aRet += ::GetString( i, bHasReal );
1933         aRet += (c != 'j') ? aI : aJ;
1934     }
1935 
1936     return aRet;
1937 }
1938 
1939 
1940 double Complex::Arg( void ) const THROWDEF_RTE_IAE
1941 {
1942     if( r == 0.0 && i == 0.0 )
1943         THROW_IAE;
1944 
1945     double  phi = acos( r / Abs() );
1946 
1947     if( i < 0.0 )
1948         phi = -phi;
1949 
1950     return phi;
1951 }
1952 
1953 
1954 void Complex::Power( double fPower ) THROWDEF_RTE_IAE
1955 {
1956     if( r == 0.0 && i == 0.0 )
1957     {
1958         if( fPower > 0 )
1959         {
1960             r = i = 0.0;
1961             return;
1962         }
1963         else
1964             THROW_IAE;
1965     }
1966 
1967     double      p, phi;
1968 
1969     p = Abs();
1970 
1971     phi = acos( r / p );
1972     if( i < 0.0 )
1973         phi = -phi;
1974 
1975     p = pow( p, fPower );
1976     phi *= fPower;
1977 
1978     r = cos( phi ) * p;
1979     i = sin( phi ) * p;
1980 }
1981 
1982 
1983 void Complex::Sqrt( void )
1984 {
1985     static const double fMultConst = 0.7071067811865475;    // ...2440084436210485 = 1/sqrt(2)
1986     double  p = Abs();
1987     double  i_ = sqrt( p - r ) * fMultConst;
1988 
1989     r = sqrt( p + r ) * fMultConst;
1990     i = ( i < 0.0 )? -i_ : i_;
1991 }
1992 
1993 
1994 inline sal_Bool SinOverflow( double f )
1995 {
1996     return fabs( f ) >= 134217728;
1997 }
1998 
1999 
2000 void Complex::Sin( void ) THROWDEF_RTE_IAE
2001 {
2002     if( SinOverflow( r ) )
2003         THROW_IAE;
2004 
2005     if( i )
2006     {
2007         double  r_;
2008 
2009         r_ = sin( r ) * cosh( i );
2010         i = cos( r ) * sinh( i );
2011         r = r_;
2012     }
2013     else
2014         r = sin( r );
2015 }
2016 
2017 
2018 void Complex::Cos( void ) THROWDEF_RTE_IAE
2019 {
2020     if( SinOverflow( r ) )
2021         THROW_IAE;
2022 
2023     if( i )
2024     {
2025         double      r_;
2026 
2027         r_ = cos( r ) * cosh( i );
2028         i = -( sin( r ) * sinh( i ) );
2029         r = r_;
2030     }
2031     else
2032         r = cos( r );
2033 }
2034 
2035 
2036 void Complex::Div( const Complex& z ) THROWDEF_RTE_IAE
2037 {
2038     if( z.r == 0 && z.i == 0 )
2039         THROW_IAE;
2040 
2041     double  a1 = r;
2042     double  a2 = z.r;
2043     double  b1 = i;
2044     double  b2 = z.i;
2045 
2046     double  f = 1.0 / ( a2 * a2 + b2 * b2 );
2047 
2048     r = ( a1 * a2 + b1 * b2 ) * f;
2049     i = ( a2 * b1 - a1 * b2 ) * f;
2050 
2051     if( !c ) c = z.c;
2052 }
2053 
2054 
2055 void Complex::Exp( void )
2056 {
2057     double  fE = exp( r );
2058     r = fE * cos( i );
2059     i = fE * sin( i );
2060 }
2061 
2062 
2063 void Complex::Ln( void ) THROWDEF_RTE_IAE
2064 {
2065     if( r == 0.0 && i == 0.0 )
2066         THROW_IAE;
2067 
2068     double      fAbs = Abs();
2069     sal_Bool    bNegi = i < 0.0;
2070 
2071     i = acos( r / fAbs );
2072 
2073     if( bNegi )
2074         i = -i;
2075 
2076     r = log( fAbs );
2077 }
2078 
2079 
2080 void Complex::Log10( void ) THROWDEF_RTE_IAE
2081 {
2082     Ln();
2083     Mult( 0.434294481903251828 );   // * log10( e )
2084 }
2085 
2086 
2087 void Complex::Log2( void ) THROWDEF_RTE_IAE
2088 {
2089     Ln();
2090     Mult( 1.442695040888963407 );   // * log2( e )
2091 }
2092 
2093 
2094 
2095 
2096 ComplexList::~ComplexList()
2097 {
2098     for( Complex* p = ( Complex* ) First() ; p ; p = ( Complex* ) Next() )
2099         delete p;
2100 }
2101 
2102 
2103 void ComplexList::Append( const SEQSEQ( STRING )& r, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2104 {
2105     sal_Int32   n1, n2;
2106     sal_Int32   nE1 = r.getLength();
2107     sal_Int32   nE2;
2108     sal_Bool    bEmpty0 = eAH == AH_EmpyAs0;
2109     sal_Bool    bErrOnEmpty = eAH == AH_EmptyAsErr;
2110 
2111     for( n1 = 0 ; n1 < nE1 ; n1++ )
2112     {
2113         const SEQ( STRING )&    rList = r[ n1 ];
2114         nE2 = rList.getLength();
2115 
2116         for( n2 = 0 ; n2 < nE2 ; n2++ )
2117         {
2118             const STRING&   rStr = rList[ n2 ];
2119 
2120             if( rStr.getLength() )
2121                 Append( new Complex( rStr ) );
2122             else if( bEmpty0 )
2123                 Append( new Complex( 0.0 ) );
2124             else if( bErrOnEmpty )
2125                 THROW_IAE;
2126         }
2127     }
2128 }
2129 
2130 
2131 void ComplexList::Append( const SEQ( ANY )& aMultPars, ComplListAppendHandl eAH ) THROWDEF_RTE_IAE
2132 {
2133     sal_Int32       nEle = aMultPars.getLength();
2134     sal_Bool        bEmpty0 = eAH == AH_EmpyAs0;
2135     sal_Bool        bErrOnEmpty = eAH == AH_EmptyAsErr;
2136 
2137     for( sal_Int32 i = 0 ; i < nEle ; i++ )
2138     {
2139         const ANY&  r = aMultPars[ i ];
2140         switch( r.getValueTypeClass() )
2141         {
2142             case uno::TypeClass_VOID:       break;
2143             case uno::TypeClass_STRING:
2144                 {
2145                 const STRING*       pStr = ( const STRING* ) r.getValue();
2146 
2147                 if( pStr->getLength() )
2148                     Append( new Complex( *( STRING* ) r.getValue() ) );
2149                 else if( bEmpty0 )
2150                     Append( new Complex( 0.0 ) );
2151                 else if( bErrOnEmpty )
2152                     THROW_IAE;
2153                 }
2154                 break;
2155             case uno::TypeClass_DOUBLE:
2156                 Append( new Complex( *( double* ) r.getValue(), 0.0 ) );
2157                 break;
2158             case uno::TypeClass_SEQUENCE:
2159                 {
2160                 SEQSEQ( ANY )           aValArr;
2161                 if( r >>= aValArr )
2162                 {
2163                     sal_Int32           nE = aValArr.getLength();
2164                     const SEQ( ANY )*   pArr = aValArr.getConstArray();
2165                     for( sal_Int32 n = 0 ; n < nE ; n++ )
2166                         Append( pArr[ n ], eAH );
2167                 }
2168                 else
2169                     THROW_IAE;
2170                 }
2171                 break;
2172             default:
2173                 THROW_IAE;
2174         }
2175     }
2176 }
2177 
2178 
2179 
2180 
2181 ConvertData::ConvertData( const sal_Char p[], double fC, ConvertDataClass e, sal_Bool bPrefSupport ) : aName( p, strlen( p ), RTL_TEXTENCODING_MS_1252 )
2182 {
2183     fConst = fC;
2184     eClass = e;
2185     bPrefixSupport = bPrefSupport;
2186 }
2187 
2188 ConvertData::~ConvertData()
2189 {
2190 }
2191 
2192 
2193 sal_Int16 ConvertData::GetMatchingLevel( const STRING& rRef ) const
2194 {
2195     STRING aStr = rRef;
2196     sal_Int32 nLen = rRef.getLength();
2197     sal_Int32 nIndex = rRef.lastIndexOf( '^' );
2198     if( nIndex > 0 && nIndex  == ( nLen - 2 ) )
2199     {
2200         const sal_Unicode*  p = aStr.getStr();
2201         aStr = STRING( p, nLen - 2 );
2202         aStr += STRING( p[ nLen - 1 ] );
2203     }
2204     if( aName.equals( aStr ) )
2205         return 0;
2206     else
2207     {
2208         const sal_Unicode*  p = aStr.getStr();
2209 
2210         nLen = aStr.getLength();
2211         bool bPref = IsPrefixSupport();
2212         bool bOneChar = (bPref && nLen > 1 && (aName == p + 1));
2213         if (bOneChar || (bPref && nLen > 2 && (aName == p + 2) &&
2214                     *p == 'd' && *(p+1) == 'a'))
2215         {
2216             sal_Int16       n;
2217             switch( *p )
2218             {
2219                 case 'y':   n = -24;    break;      // yocto
2220                 case 'z':   n = -21;    break;      // zepto
2221                 case 'a':   n = -18;    break;
2222                 case 'f':   n = -15;    break;
2223                 case 'p':   n = -12;    break;
2224                 case 'n':   n = -9;     break;
2225                 case 'u':   n = -6;     break;
2226                 case 'm':   n = -3;     break;
2227                 case 'c':   n = -2;     break;
2228                 case 'd':
2229                     {
2230                         if ( bOneChar )
2231                             n = -1;                 // deci
2232                         else
2233                             n = 1;                  // deca
2234                     }
2235                     break;
2236                 case 'e':   n = 1;      break;
2237                 case 'h':   n = 2;      break;
2238                 case 'k':   n = 3;      break;
2239                 case 'M':   n = 6;      break;
2240                 case 'G':   n = 9;      break;
2241                 case 'T':   n = 12;     break;
2242                 case 'P':   n = 15;     break;
2243                 case 'E':   n = 18;     break;
2244                 case 'Z':   n = 21;     break;      // zetta
2245                 case 'Y':   n = 24;     break;      // yotta
2246                 default:
2247                             n = INV_MATCHLEV;
2248             }
2249 
2250 // We could weed some nonsense out, ODFF doesn't say so though.
2251 #if 0
2252             if (n < 0 && Class() == CDC_Information)
2253                 n = INV_MATCHLEV;   // milli-bits doesn't make sense
2254 #endif
2255 
2256 //! <HACK> #100616# "cm3" is not 10^-2 m^3 but 10^-6 m^3 !!! ------------------
2257             if( n != INV_MATCHLEV )
2258             {
2259                 sal_Unicode cLast = p[ aStr.getLength() - 1 ];
2260                 if( cLast == '2' )
2261                     n *= 2;
2262                 else if( cLast == '3' )
2263                     n *= 3;
2264             }
2265 //! </HACK> -------------------------------------------------------------------
2266 
2267             return n;
2268         }
2269         else if ( nLen > 2 && ( aName == p + 2 ) && ( Class() == CDC_Information ) )
2270         {
2271             const sal_Unicode*  pStr = aStr.getStr();
2272             if ( *(pStr + 1) != 'i')
2273                 return INV_MATCHLEV;
2274             sal_Int16 n;
2275             switch( *pStr )
2276             {
2277                 case 'k':   n = 10;      break;
2278                 case 'M':   n = 20;      break;
2279                 case 'G':   n = 30;      break;
2280                 case 'T':   n = 40;      break;
2281                 case 'P':   n = 50;      break;
2282                 case 'E':   n = 60;      break;
2283                 case 'Z':   n = 70;      break;
2284                 case 'Y':   n = 80;      break;
2285                 default:
2286                             n = INV_MATCHLEV;
2287             }
2288             return n;
2289         }
2290         else
2291             return INV_MATCHLEV;
2292     }
2293 }
2294 
2295 
2296 double ConvertData::Convert(
2297     double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2298 {
2299     if( Class() != r.Class() )
2300         THROW_IAE;
2301 
2302     sal_Bool bBinFromLev = ( nLevFrom > 0 && ( nLevFrom % 10 ) == 0 );
2303     sal_Bool bBinToLev   = ( nLevTo > 0 && ( nLevTo % 10 ) == 0 );
2304 
2305     if ( Class() == CDC_Information && ( bBinFromLev || bBinToLev ) )
2306     {
2307         if ( bBinFromLev && bBinToLev )
2308         {
2309             nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );
2310             f *= r.fConst / fConst;
2311             if( nLevFrom )
2312                 f *= pow( 2.0, nLevFrom );
2313         }
2314         else if ( bBinFromLev )
2315             f *= ( r.fConst / fConst ) * ( pow( 2.0, nLevFrom ) / pow( 10.0, nLevTo ) );
2316         else
2317             f *= ( r.fConst / fConst ) * ( pow( 10.0, nLevFrom ) / pow( 2.0, nLevTo ) );
2318         return f;
2319     }
2320 
2321     nLevFrom = sal::static_int_cast<sal_Int16>( nLevFrom - nLevTo );    // effective level
2322 
2323     f *= r.fConst / fConst;
2324 
2325     if( nLevFrom )
2326         f = ::rtl::math::pow10Exp( f, nLevFrom );
2327 
2328     return f;
2329 }
2330 
2331 
2332 double ConvertData::ConvertToBase( double f, sal_Int16 n ) const
2333 {
2334     return ::rtl::math::pow10Exp( f / fConst, n );
2335 }
2336 
2337 
2338 double ConvertData::ConvertFromBase( double f, sal_Int16 n ) const
2339 {
2340     return ::rtl::math::pow10Exp( f * fConst, -n );
2341 }
2342 
2343 
2344 
2345 ConvertDataLinear::~ConvertDataLinear()
2346 {
2347 }
2348 
2349 double ConvertDataLinear::Convert(
2350     double f, const ConvertData& r, sal_Int16 nLevFrom, sal_Int16 nLevTo ) const THROWDEF_RTE_IAE
2351 {
2352     if( Class() != r.Class() )
2353         THROW_IAE;
2354 
2355 //  return ::rtl::math::round( r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo ), 13 );
2356     return r.ConvertFromBase( ConvertToBase( f, nLevFrom ), nLevTo );
2357 }
2358 
2359 
2360 double ConvertDataLinear::ConvertToBase( double f, sal_Int16 n ) const
2361 {
2362     if( n )
2363         f = ::rtl::math::pow10Exp( f, n );
2364 
2365     f /= fConst;
2366     f -= fOffs;
2367 
2368     return f;
2369 }
2370 
2371 
2372 double ConvertDataLinear::ConvertFromBase( double f, sal_Int16 n ) const
2373 {
2374     f += fOffs;
2375     f *= fConst;
2376 
2377     if( n )
2378         f = ::rtl::math::pow10Exp( f, -n );
2379 
2380     return f;
2381 }
2382 
2383 
2384 
2385 
2386 ConvertDataList::ConvertDataList( void )
2387 {
2388 #define NEWD(str,unit,cl)   Append(new ConvertData(str,unit,cl))
2389 #define NEWDP(str,unit,cl)  Append(new ConvertData(str,unit,cl,sal_True))
2390 #define NEWL(str,unit,offs,cl)  Append(new ConvertDataLinear(str,unit,offs,cl))
2391 #define NEWLP(str,unit,offs,cl) Append(new ConvertDataLinear(str,unit,offs,cl,sal_True))
2392 
2393     // *** are extra and not standard Excel Analysis Addin!
2394 
2395     // MASS: 1 Gram is...
2396     NEWDP( "g",         1.0000000000000000E00,  CDC_Mass ); // Gram
2397     NEWD( "sg",         6.8522050005347800E-05, CDC_Mass ); // Pieces
2398     NEWD( "lbm",        2.2046229146913400E-03, CDC_Mass ); // Pound (commercial weight)
2399     NEWDP( "u",         6.0221370000000000E23,  CDC_Mass ); // U (atomic mass)
2400     NEWD( "ozm",        3.5273971800362700E-02, CDC_Mass ); // Ounce (commercial weight)
2401     NEWD( "stone",      1.574730e-04,           CDC_Mass ); // *** Stone
2402     NEWD( "ton",        1.102311e-06,           CDC_Mass ); // *** Ton
2403     NEWD( "grain",      1.543236E01,            CDC_Mass ); // *** Grain
2404     NEWD( "pweight",    7.054792E-01,           CDC_Mass ); // *** Pennyweight
2405     NEWD( "hweight",    1.968413E-05,           CDC_Mass ); // *** Hundredweight
2406     NEWD( "shweight",   2.204623E-05,           CDC_Mass ); // *** Shorthundredweight
2407     NEWD( "brton",      9.842065E-07,           CDC_Mass ); // *** Gross Registered Ton
2408     NEWD( "cwt",        2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight
2409     NEWD( "shweight",   2.2046226218487758E-05, CDC_Mass ); // U.S. (short) hundredweight also
2410     NEWD( "uk_cwt",     1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight
2411     NEWD( "lcwt",       1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2412     NEWD( "hweight",    1.9684130552221213E-05, CDC_Mass ); // Imperial hundredweight also
2413     NEWD( "uk_ton",     9.8420652761106063E-07, CDC_Mass ); // Imperial ton
2414     NEWD( "LTON",       9.8420652761106063E-07, CDC_Mass ); // Imperial ton also
2415 
2416     // LENGTH: 1 Meter is...
2417     NEWDP( "m",         1.0000000000000000E00,  CDC_Length ); // Meter
2418     NEWD( "mi",         6.2137119223733397E-04, CDC_Length ); // Britsh Mile        6,21371192237333969617434184363e-4
2419     NEWD( "Nmi",        5.3995680345572354E-04, CDC_Length ); // Nautical Mile      5,39956803455723542116630669546e-4
2420     NEWD( "in",         3.9370078740157480E01,  CDC_Length ); // Inch               39,37007874015748031496062992126
2421     NEWD( "ft",         3.2808398950131234E00,  CDC_Length ); // Foot               3,2808398950131233595800524934383
2422     NEWD( "yd",         1.0936132983377078E00,  CDC_Length ); // Yard               1,0936132983377077865266841644794
2423     NEWDP( "ang",       1.0000000000000000E10,  CDC_Length ); // Angstroem
2424     NEWD( "Pica",       2.8346456692913386E03,  CDC_Length ); // Pica (1/72 Inch)   2834,6456692913385826771653543307
2425     NEWD( "ell",        8.748906E-01,           CDC_Length ); // *** Ell
2426     NEWDP( "parsec",    3.240779E-17,           CDC_Length ); // *** Parsec
2427     NEWDP( "pc",        3.240779E-17,           CDC_Length ); // *** Parsec also
2428     NEWDP( "lightyear", 1.0570234557732930E-16, CDC_Length ); // *** Light Year
2429     NEWDP( "ly",        1.0570234557732930E-16, CDC_Length ); // *** Light Year also
2430     NEWD( "survey_mi",  6.2136994949494949E-04, CDC_Length ); // U.S. survey mile
2431 
2432     // TIME: 1 Second is...
2433     NEWD( "yr",     3.1688087814028950E-08, CDC_Time ); // Year
2434     NEWD( "day",    1.1574074074074074E-05, CDC_Time ); // Day
2435     NEWD( "d",      1.1574074074074074E-05, CDC_Time ); // Day also
2436     NEWD( "hr",     2.7777777777777778E-04, CDC_Time ); // Hour
2437     NEWD( "mn",     1.6666666666666667E-02, CDC_Time ); // Minute
2438     NEWD( "min",    1.6666666666666667E-02, CDC_Time ); // Minute also
2439     NEWDP( "sec",   1.0000000000000000E00,  CDC_Time ); // Second
2440     NEWDP( "s",     1.0000000000000000E00,  CDC_Time ); // Second also
2441 
2442     // PRESSURE: 1 Pascal is...
2443     NEWDP( "Pa",    1.0000000000000000E00,  CDC_Pressure ); // Pascal
2444     NEWDP( "atm",   9.8692329999819300E-06, CDC_Pressure ); // Atmosphere
2445     NEWDP( "at",    9.8692329999819300E-06, CDC_Pressure ); // Atmosphere also
2446     NEWDP( "mmHg",  7.5006170799862700E-03, CDC_Pressure ); // mm Hg (Mercury)
2447     NEWD( "Torr",   7.5006380000000000E-03, CDC_Pressure ); // *** Torr
2448     NEWD( "psi",    1.4503770000000000E-04, CDC_Pressure ); // *** Psi
2449 
2450     // FORCE: 1 Newton is...
2451     NEWDP( "N",     1.0000000000000000E00,  CDC_Force ); // Newton
2452     NEWDP( "dyn",   1.0000000000000000E05,  CDC_Force ); // Dyn
2453     NEWDP( "dy",    1.0000000000000000E05,  CDC_Force ); // Dyn also
2454     NEWD( "lbf",    2.24808923655339E-01,   CDC_Force ); // Pound-Force
2455     NEWDP( "pond",  1.019716E02,            CDC_Force ); // *** Pond
2456 
2457     // ENERGY: 1 Joule is...
2458     NEWDP( "J",     1.0000000000000000E00,  CDC_Energy ); // Joule
2459     NEWDP( "e",     1.0000000000000000E07,  CDC_Energy ); // Erg  -> http://www.chemie.fu-berlin.de/chemistry/general/si.html
2460 //  NEWD( "e",      9.99999519343231E06,    CDC_Energy ); // Erg
2461     NEWDP( "c",     2.3900624947346700E-01, CDC_Energy ); // Thermodynamical Calorie
2462     NEWDP( "cal",   2.3884619064201700E-01, CDC_Energy ); // Calorie
2463     NEWDP( "eV",    6.2414570000000000E18,  CDC_Energy ); // Electronvolt
2464     NEWDP( "ev",    6.2414570000000000E18,  CDC_Energy ); // Electronvolt also
2465     NEWD( "HPh",    3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours
2466     NEWD( "hh",     3.7250611111111111E-07, CDC_Energy ); // Horsepower Hours also
2467 //  NEWD( "HPh",    3.72506430801000E-07,   CDC_Energy ); // Horsepower Hours
2468     NEWDP( "Wh",    2.7777777777777778E-04, CDC_Energy ); // Watt Hours
2469     NEWDP( "wh",    2.7777777777777778E-04, CDC_Energy ); // Watt Hours also
2470     NEWD( "flb",    2.37304222192651E01,    CDC_Energy ); // Foot Pound
2471     NEWD( "BTU",    9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit
2472     NEWD( "btu",    9.4781506734901500E-04, CDC_Energy ); // British Thermal Unit also
2473 
2474     // POWER: 1 Watt is...
2475     NEWDP( "W",     1.0000000000000000E00,  CDC_Power ); // Watt
2476     NEWDP( "w",     1.0000000000000000E00,  CDC_Power ); // Watt also
2477     NEWD( "HP",     1.341022E-03,           CDC_Power ); // Horsepower
2478     NEWD( "h",      1.341022E-03,           CDC_Power ); // Horsepower also
2479     NEWD( "PS",     1.359622E-03,           CDC_Power ); // *** German Pferdestaerke
2480 //  NEWD( "HP",     1.4102006031908E-03,    CDC_Power ); // Excel seams to be a little bit wrong... either this doesn't fit to J -> HPh
2481 
2482     // MAGNETISM: 1 Tesla is...
2483     NEWDP( "T",     1.0000000000000000E00,  CDC_Magnetism ); // Tesla
2484     NEWDP( "ga",    1.0000000000000000E04,  CDC_Magnetism ); // Gauss
2485 
2486     // TEMERATURE: 1 Kelvin is...
2487     NEWL( "C",      1.0000000000000000E00,  -2.7315000000000000E02, CDC_Temperature ); // Celsius
2488     NEWL( "cel",    1.0000000000000000E00,  -2.7315000000000000E02, CDC_Temperature ); // Celsius also
2489     NEWL( "F",      1.8000000000000000E00,  -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit
2490     NEWL( "fah",    1.8000000000000000E00,  -2.5537222222222222E02, CDC_Temperature ); // Fahrenheit also
2491     NEWLP( "K",     1.0000000000000000E00,  +0.0000000000000000E00, CDC_Temperature ); // Kelvin
2492     NEWLP( "kel",   1.0000000000000000E00,  +0.0000000000000000E00, CDC_Temperature ); // Kelvin also
2493     NEWL( "Reau",   8.0000000000000000E-01, -2.7315000000000000E02, CDC_Temperature ); // *** Reaumur
2494     NEWL( "Rank",   1.8000000000000000E00,  +0.0000000000000000E00, CDC_Temperature ); // *** Rankine
2495 
2496     // VOLUMNE: 1 Liter is...
2497     NEWD( "tsp",        2.0284000000000000E02,  CDC_Volume ); // Teaspoon
2498     NEWD( "tbs",        6.7613333333333333E01,  CDC_Volume ); // Tablespoon
2499     NEWD( "oz",         3.3806666666666667E01,  CDC_Volume ); // Ounce Liquid
2500     NEWD( "cup",        4.2258333333333333E00,  CDC_Volume ); // Cup
2501     NEWD( "pt",         2.1129166666666667E00,  CDC_Volume ); // US Pint
2502     NEWD( "us_pt",      2.1129166666666667E00,  CDC_Volume ); // US Pint also
2503     NEWD( "uk_pt",      1.75975569552166E00,    CDC_Volume ); // UK Pint
2504     NEWD( "qt",         1.0564583333333333E00,  CDC_Volume ); // Quart
2505     NEWD( "gal",        2.6411458333333333E-01, CDC_Volume ); // Gallone
2506     NEWDP( "l",         1.0000000000000000E00,  CDC_Volume ); // Liter
2507     NEWDP( "L",         1.0000000000000000E00,  CDC_Volume ); // Liter also
2508     NEWDP( "lt",        1.0000000000000000E00,  CDC_Volume ); // Liter also
2509     NEWDP( "m3",        1.0000000000000000E-03, CDC_Volume ); // *** Cubic Meter
2510     NEWD( "mi3",        2.3991275857892772E-13, CDC_Volume ); // *** Cubic Britsh Mile
2511     NEWD( "Nmi3",       1.5742621468581148E-13, CDC_Volume ); // *** Cubic Nautical Mile
2512     NEWD( "in3",        6.1023744094732284E01,  CDC_Volume ); // *** Cubic Inch
2513     NEWD( "ft3",        3.5314666721488590E-02, CDC_Volume ); // *** Cubic Foot
2514     NEWD( "yd3",        1.3079506193143922E-03, CDC_Volume ); // *** Cubic Yard
2515     NEWDP( "ang3",      1.0000000000000000E27,  CDC_Volume ); // *** Cubic Angstroem
2516     NEWD( "Pica3",      2.2776990435870636E07,  CDC_Volume ); // *** Cubic Pica
2517     NEWD( "barrel",     6.289811E-03,           CDC_Volume ); // *** Barrel (=42gal?)
2518     NEWD( "bushel",     2.837759E-02,           CDC_Volume ); // *** Bushel
2519     NEWD( "regton",     3.531467E-04,           CDC_Volume ); // *** Register ton
2520     NEWD( "GRT",        3.531467E-04,           CDC_Volume ); // *** Register ton also
2521     NEWD( "Schooner",   2.3529411764705882E00,  CDC_Volume ); // *** austr. Schooner
2522     NEWD( "Middy",      3.5087719298245614E00,  CDC_Volume ); // *** austr. Middy
2523     NEWD( "Glass",      5.0000000000000000E00,  CDC_Volume ); // *** austr. Glass
2524     NEWD( "Sixpack",    0.5,                    CDC_Volume ); // ***
2525     NEWD( "Humpen",     2.0,                    CDC_Volume ); // ***
2526     NEWD( "ly3",        1.1810108125623799E-51, CDC_Volume ); // *** Cubic light-year
2527     NEWD( "MTON",       1.4125866688595436E00,  CDC_Volume ); // *** Measurement ton
2528     NEWD( "tspm",       5.0000000000000000E02,  CDC_Volume ); // *** Modern teaspoon
2529     NEWD( "uk_gal",     2.199694619402070E-01,  CDC_Volume ); // U.K. / Imperial gallon
2530     NEWD( "uk_qt",      8.798778477608300E-01,  CDC_Volume ); // U.K. / Imperial quart
2531 
2532     // 1 Square Meter is...
2533     NEWDP( "m2",        1.0000000000000000E00,  CDC_Area ); // *** Square Meter
2534     NEWD( "mi2",        3.8610215854244585E-07, CDC_Area ); // *** Square Britsh Mile
2535     NEWD( "Nmi2",       2.9155334959812286E-07, CDC_Area ); // *** Square Nautical Mile
2536     NEWD( "in2",        1.5500031000062000E03,  CDC_Area ); // *** Square Inch
2537     NEWD( "ft2",        1.0763910416709722E01,  CDC_Area ); // *** Square Foot
2538     NEWD( "yd2",        1.1959900463010803E00,  CDC_Area ); // *** Square Yard
2539     NEWDP( "ang2",      1.0000000000000000E20,  CDC_Area ); // *** Square Angstroem
2540     NEWD( "Pica2",      8.0352160704321409E06,  CDC_Area ); // *** Square Pica
2541     NEWD( "Morgen",     4.0000000000000000E-04, CDC_Area ); // *** Morgen
2542     NEWDP( "ar",        1.000000E-02,           CDC_Area ); // *** Ar
2543     NEWD( "acre",       2.471053815E-04,        CDC_Area ); // *** Acre
2544     NEWD( "uk_acre",    2.4710538146716534E-04, CDC_Area ); // *** International acre
2545     NEWD( "us_acre",    2.4710439304662790E-04, CDC_Area ); // *** U.S. survey/statute acre
2546     NEWD( "ly2",        1.1172985860549147E-32, CDC_Area ); // *** Square Light-year
2547     NEWD( "ha",         1.000000E-04,           CDC_Area ); // *** Hectare
2548     NEWD( "Quadratlatschen",5.6689342403628117914,CDC_Area ); // ***
2549 
2550     // SPEED: 1 Meter per Second is...
2551     NEWDP( "m/s",   1.0000000000000000E00,  CDC_Speed ); // *** Meters per Second
2552     NEWDP( "m/sec", 1.0000000000000000E00,  CDC_Speed ); // *** Meters per Second also
2553     NEWDP( "m/h",   3.6000000000000000E03,  CDC_Speed ); // *** Meters per Hour
2554     NEWDP( "m/hr",  3.6000000000000000E03,  CDC_Speed ); // *** Meters per Hour also
2555     NEWD( "mph",    2.2369362920544023E00,  CDC_Speed ); // *** Britsh Miles per Hour
2556     NEWD( "kn",     1.9438444924406048E00,  CDC_Speed ); // *** Knot = Nautical Miles per Hour
2557     NEWD( "admkn",  1.9438446603753486E00,  CDC_Speed ); // *** Admiralty Knot
2558     NEWD( "wahnsinnige Geschwindigkeit", 2.0494886343432328E-14, CDC_Speed ); // ***
2559     NEWD( "ludicrous speed", 2.0494886343432328E-14, CDC_Speed ); // ***
2560     NEWD( "laecherliche Geschwindigkeit", 4.0156958471424288E-06, CDC_Speed); // ***
2561     NEWD( "ridiculous speed", 4.0156958471424288E-06, CDC_Speed); // ***
2562 
2563     // INFORMATION: 1 Bit is...
2564     NEWDP( "bit",   1.00E00,  CDC_Information); // *** Bit
2565     NEWDP( "byte",  1.25E-01, CDC_Information); // *** Byte
2566 }
2567 
2568 
2569 ConvertDataList::~ConvertDataList()
2570 {
2571     for( ConvertData* p = First() ; p ; p = Next() )
2572         delete p;
2573 }
2574 
2575 
2576 double ConvertDataList::Convert( double fVal, const STRING& rFrom, const STRING& rTo ) THROWDEF_RTE_IAE
2577 {
2578 // This will not catch illegal units
2579 //   if( rFrom == rTo )
2580 //       return fVal;
2581 
2582     ConvertData*    pFrom = NULL;
2583     ConvertData*    pTo = NULL;
2584     sal_Bool        bSearchFrom = sal_True;
2585     sal_Bool        bSearchTo = sal_True;
2586     sal_Int16       nLevelFrom = 0;
2587     sal_Int16       nLevelTo = 0;
2588 
2589     ConvertData*    p = First();
2590     while( p && ( bSearchFrom || bSearchTo ) )
2591     {
2592         if( bSearchFrom )
2593         {
2594             sal_Int16   n = p->GetMatchingLevel( rFrom );
2595             if( n != INV_MATCHLEV )
2596             {
2597                 if( n )
2598                 {   // only first match for partial equality rulz a little bit more
2599                     pFrom = p;
2600                     nLevelFrom = n;
2601                 }
2602                 else
2603                 {   // ... but exact match rulz most
2604                     pFrom = p;
2605                     bSearchFrom = sal_False;
2606                     nLevelFrom = n;
2607                 }
2608             }
2609         }
2610 
2611         if( bSearchTo )
2612         {
2613             sal_Int16   n = p->GetMatchingLevel( rTo );
2614             if( n != INV_MATCHLEV )
2615             {
2616                 if( n )
2617                 {   // only first match for partial equality rulz a little bit more
2618                     pTo = p;
2619                     nLevelTo = n;
2620                 }
2621                 else
2622                 {   // ... but exact match rulz most
2623                     pTo = p;
2624                     bSearchTo = sal_False;
2625                     nLevelTo = n;
2626                 }
2627             }
2628         }
2629 
2630         p = Next();
2631     }
2632 
2633     if( pFrom && pTo )
2634         return pFrom->Convert( fVal, *pTo, nLevelFrom, nLevelTo );
2635     else
2636         THROW_IAE;
2637 }
2638 
2639 
2640 
2641 //-----------------------------------------------------------------------------
2642 
2643 ScaDate::ScaDate() :
2644     nOrigDay( 1 ),
2645     nDay( 1 ),
2646     nMonth( 1 ),
2647     nYear( 1900 ),
2648     bLastDayMode( sal_True ),
2649     bLastDay( sal_False ),
2650     b30Days( sal_False ),
2651     bUSMode( sal_False )
2652 {
2653 }
2654 
2655 ScaDate::ScaDate( sal_Int32 nNullDate, sal_Int32 nDate, sal_Int32 nBase )
2656 {
2657     DaysToDate( nNullDate + nDate, nOrigDay, nMonth, nYear );
2658     bLastDayMode = (nBase != 5);
2659     bLastDay = (nOrigDay >= ::DaysInMonth( nMonth, nYear ));
2660     b30Days = (nBase == 0) || (nBase == 4);
2661     bUSMode = (nBase == 0);
2662     setDay();
2663 }
2664 
2665 ScaDate::ScaDate( const ScaDate& rCopy ) :
2666     nOrigDay( rCopy.nOrigDay ),
2667     nDay( rCopy.nDay ),
2668     nMonth( rCopy.nMonth ),
2669     nYear( rCopy.nYear ),
2670     bLastDayMode( rCopy.bLastDayMode ),
2671     bLastDay( rCopy.bLastDay ),
2672     b30Days( rCopy.b30Days ),
2673     bUSMode( rCopy.bUSMode )
2674 {
2675 }
2676 
2677 ScaDate& ScaDate::operator=( const ScaDate& rCopy )
2678 {
2679     if( this != &rCopy )
2680     {
2681         nOrigDay = rCopy.nOrigDay;
2682         nDay = rCopy.nDay;
2683         nMonth = rCopy.nMonth;
2684         nYear = rCopy.nYear;
2685         bLastDayMode = rCopy.bLastDayMode;
2686         bLastDay = rCopy.bLastDay;
2687         b30Days = rCopy.b30Days;
2688         bUSMode = rCopy.bUSMode;
2689     }
2690     return *this;
2691 }
2692 
2693 void ScaDate::setDay()
2694 {
2695     if( b30Days )
2696     {
2697         // 30-days-mode: set nDay to 30 if original was last day in month
2698         nDay = Min( nOrigDay, static_cast< sal_uInt16 >( 30 ) );
2699         if( bLastDay || (nDay >= ::DaysInMonth( nMonth, nYear )) )
2700             nDay = 30;
2701     }
2702     else
2703     {
2704         // set nDay to last day in this month if original was last day
2705         sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2706         nDay = bLastDay ? nLastDay : Min( nOrigDay, nLastDay );
2707     }
2708 }
2709 
2710 sal_Int32 ScaDate::getDaysInMonthRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2711 {
2712     if( nFrom > nTo )
2713         return 0;
2714 
2715     sal_Int32 nRet = 0;
2716     if( b30Days )
2717         nRet = (nTo - nFrom + 1) * 30;
2718     else
2719     {
2720         for( sal_uInt16 nMonthIx = nFrom; nMonthIx <= nTo; ++nMonthIx )
2721             nRet += getDaysInMonth( nMonthIx );
2722     }
2723     return nRet;
2724 }
2725 
2726 sal_Int32 ScaDate::getDaysInYearRange( sal_uInt16 nFrom, sal_uInt16 nTo ) const
2727 {
2728     if( nFrom > nTo )
2729         return 0;
2730 
2731     return b30Days ? ((nTo - nFrom + 1) * 360) : ::GetDaysInYears( nFrom, nTo );
2732 }
2733 
2734 void ScaDate::doAddYears( sal_Int32 nYearCount ) throw( lang::IllegalArgumentException )
2735 {
2736     sal_Int32 nNewYear = nYearCount + nYear;
2737     if( (nNewYear < 0) || (nNewYear > 0x7FFF) )
2738         throw lang::IllegalArgumentException();
2739     nYear = static_cast< sal_uInt16 >( nNewYear );
2740 }
2741 
2742 void ScaDate::addMonths( sal_Int32 nMonthCount ) throw( lang::IllegalArgumentException )
2743 {
2744     sal_Int32 nNewMonth = nMonthCount + nMonth;
2745     if( nNewMonth > 12 )
2746     {
2747         --nNewMonth;
2748         doAddYears( nNewMonth / 12 );
2749         nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 ) + 1;
2750     }
2751     else if( nNewMonth < 1 )
2752     {
2753         doAddYears( nNewMonth / 12 - 1 );
2754         nMonth = static_cast< sal_uInt16 >( nNewMonth % 12 + 12 );
2755     }
2756     else
2757         nMonth = static_cast< sal_uInt16 >( nNewMonth );
2758     setDay();
2759 }
2760 
2761 sal_Int32 ScaDate::getDate( sal_Int32 nNullDate ) const
2762 {
2763     sal_uInt16 nLastDay = ::DaysInMonth( nMonth, nYear );
2764     sal_uInt16 nRealDay = (bLastDayMode && bLastDay) ? nLastDay : Min( nLastDay, nOrigDay );
2765     return ::DateToDays( nRealDay, nMonth, nYear ) - nNullDate;
2766 }
2767 
2768 sal_Int32 ScaDate::getDiff( const ScaDate& rFrom, const ScaDate& rTo ) throw( lang::IllegalArgumentException )
2769 {
2770     if( rFrom > rTo )
2771         return getDiff( rTo, rFrom );
2772 
2773     sal_Int32 nDiff = 0;
2774     ScaDate aFrom( rFrom );
2775     ScaDate aTo( rTo );
2776 
2777     if( rTo.b30Days )
2778     {
2779         // corrections for base 0 (US NASD)
2780         if( rTo.bUSMode )
2781         {
2782             if( ((rFrom.nMonth == 2) || (rFrom.nDay < 30)) && (aTo.nOrigDay == 31) )
2783                 aTo.nDay = 31;
2784             else if( (aTo.nMonth == 2) && aTo.bLastDay )
2785                 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2786         }
2787         // corrections for base 4 (Europe)
2788         else
2789         {
2790             if( (aFrom.nMonth == 2) && (aFrom.nDay == 30) )
2791                 aFrom.nDay = ::DaysInMonth( 2, aFrom.nYear );
2792             if( (aTo.nMonth == 2) && (aTo.nDay == 30) )
2793                 aTo.nDay = ::DaysInMonth( 2, aTo.nYear );
2794         }
2795     }
2796 
2797     if( (aFrom.nYear < aTo.nYear) || ((aFrom.nYear == aTo.nYear) && (aFrom.nMonth < aTo.nMonth)) )
2798     {
2799         // move aFrom to 1st day of next month
2800         nDiff = aFrom.getDaysInMonth() - aFrom.nDay + 1;
2801         aFrom.nOrigDay = aFrom.nDay = 1;
2802         aFrom.bLastDay = sal_False;
2803         aFrom.addMonths( 1 );
2804 
2805         if( aFrom.nYear < aTo.nYear )
2806         {
2807             // move aFrom to 1st day of next year
2808             nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, 12 );
2809             aFrom.addMonths( 13 - aFrom.nMonth );
2810 
2811             // move aFrom to 1st day of this year
2812             nDiff += aFrom.getDaysInYearRange( aFrom.nYear, aTo.nYear - 1 );
2813             aFrom.addYears( aTo.nYear - aFrom.nYear );
2814         }
2815 
2816         // move aFrom to 1st day of this month
2817         nDiff += aFrom.getDaysInMonthRange( aFrom.nMonth, aTo.nMonth - 1 );
2818         aFrom.addMonths( aTo.nMonth - aFrom.nMonth );
2819     }
2820     // finally add remaining days in this month
2821     nDiff += aTo.nDay - aFrom.nDay;
2822     return nDiff > 0 ? nDiff : 0;
2823 }
2824 
2825 sal_Bool ScaDate::operator<( const ScaDate& rCmp ) const
2826 {
2827     if( nYear != rCmp.nYear )
2828         return nYear < rCmp.nYear;
2829     if( nMonth != rCmp.nMonth )
2830         return nMonth < rCmp.nMonth;
2831     if( nDay != rCmp.nDay )
2832         return nDay < rCmp.nDay;
2833     if( bLastDay || rCmp.bLastDay )
2834         return !bLastDay && rCmp.bLastDay;
2835     return nOrigDay < rCmp.nOrigDay;
2836 }
2837 
2838 
2839 
2840 //-----------------------------------------------------------------------------
2841 
2842 ScaAnyConverter::ScaAnyConverter( const uno::Reference< lang::XMultiServiceFactory >& xServiceFact ) :
2843     bHasValidFormat( sal_False )
2844 {
2845     if( xServiceFact.is() )
2846     {
2847         uno::Reference< uno::XInterface > xInstance = xServiceFact->createInstance(
2848             OUString::createFromAscii( "com.sun.star.util.NumberFormatter" ) );
2849         xFormatter = uno::Reference< util::XNumberFormatter >( xInstance, uno::UNO_QUERY );
2850     }
2851 }
2852 
2853 ScaAnyConverter::~ScaAnyConverter()
2854 {
2855 }
2856 
2857 void ScaAnyConverter::init( const uno::Reference< beans::XPropertySet >& xPropSet ) throw( uno::RuntimeException )
2858 {
2859     // try to get default number format
2860     bHasValidFormat = sal_False;
2861     if( xFormatter.is() )
2862     {
2863         // get XFormatsSupplier from outer XPropertySet
2864         uno::Reference< util::XNumberFormatsSupplier > xFormatsSupp( xPropSet, uno::UNO_QUERY );
2865         if( xFormatsSupp.is() )
2866         {
2867             // get XNumberFormatTypes from XNumberFormatsSupplier to get standard index
2868             uno::Reference< util::XNumberFormats > xFormats( xFormatsSupp->getNumberFormats() );
2869             uno::Reference< util::XNumberFormatTypes > xFormatTypes( xFormats, uno::UNO_QUERY );
2870             if( xFormatTypes.is() )
2871             {
2872                 lang::Locale eLocale;
2873                 nDefaultFormat = xFormatTypes->getStandardIndex( eLocale );
2874                 xFormatter->attachNumberFormatsSupplier( xFormatsSupp );
2875                 bHasValidFormat = sal_True;
2876             }
2877         }
2878     }
2879 }
2880 
2881 double ScaAnyConverter::convertToDouble( const OUString& rString ) const throw( lang::IllegalArgumentException )
2882 {
2883     double fValue = 0.0;
2884     if( bHasValidFormat )
2885     {
2886         try
2887         {
2888             fValue = xFormatter->convertStringToNumber( nDefaultFormat, rString );
2889         }
2890         catch( uno::Exception& )
2891         {
2892             throw lang::IllegalArgumentException();
2893         }
2894     }
2895     else
2896     {
2897         rtl_math_ConversionStatus eStatus;
2898         sal_Int32 nEnd;
2899         fValue = ::rtl::math::stringToDouble( rString, '.', ',', &eStatus, &nEnd );
2900         if( (eStatus != rtl_math_ConversionStatus_Ok) || (nEnd < rString.getLength()) )
2901             throw lang::IllegalArgumentException();
2902     }
2903     return fValue;
2904 }
2905 
2906 sal_Bool ScaAnyConverter::getDouble(
2907         double& rfResult,
2908         const uno::Any& rAny ) const throw( lang::IllegalArgumentException )
2909 {
2910     rfResult = 0.0;
2911     sal_Bool bContainsVal = sal_True;
2912     switch( rAny.getValueTypeClass() )
2913     {
2914         case uno::TypeClass_VOID:
2915             bContainsVal = sal_False;
2916         break;
2917         case uno::TypeClass_DOUBLE:
2918             rAny >>= rfResult;
2919         break;
2920         case uno::TypeClass_STRING:
2921         {
2922             const OUString* pString = static_cast< const OUString* >( rAny.getValue() );
2923             if( pString->getLength() )
2924                 rfResult = convertToDouble( *pString );
2925             else
2926                 bContainsVal = sal_False;
2927         }
2928         break;
2929         default:
2930             throw lang::IllegalArgumentException();
2931     }
2932     return bContainsVal;
2933 }
2934 
2935 sal_Bool ScaAnyConverter::getDouble(
2936         double& rfResult,
2937         const uno::Reference< beans::XPropertySet >& xPropSet,
2938         const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2939 {
2940     init( xPropSet );
2941     return getDouble( rfResult, rAny );
2942 }
2943 
2944 double ScaAnyConverter::getDouble(
2945         const uno::Reference< beans::XPropertySet >& xPropSet,
2946         const uno::Any& rAny,
2947         double fDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2948 {
2949     double fResult;
2950     if( !getDouble( fResult, xPropSet, rAny ) )
2951         fResult = fDefault;
2952     return fResult;
2953 }
2954 
2955 sal_Bool ScaAnyConverter::getInt32(
2956         sal_Int32& rnResult,
2957         const uno::Reference< beans::XPropertySet >& xPropSet,
2958         const uno::Any& rAny ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2959 {
2960     double fResult;
2961     sal_Bool bContainsVal = getDouble( fResult, xPropSet, rAny );
2962     if( (fResult <= -2147483649.0) || (fResult >= 2147483648.0) )
2963         throw lang::IllegalArgumentException();
2964 
2965     rnResult = static_cast< sal_Int32 >( fResult );
2966     return bContainsVal;
2967 }
2968 
2969 sal_Int32 ScaAnyConverter::getInt32(
2970         const uno::Reference< beans::XPropertySet >& xPropSet,
2971         const uno::Any& rAny,
2972         sal_Int32 nDefault ) throw( uno::RuntimeException, lang::IllegalArgumentException )
2973 {
2974     sal_Int32 nResult;
2975     if( !getInt32( nResult, xPropSet, rAny ) )
2976         nResult = nDefault;
2977     return nResult;
2978 }
2979 
2980 
2981 
2982 //-----------------------------------------------------------------------------
2983 
2984 
2985