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