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