Coverage Report

Created: 2026-02-14 09:37

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