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