Coverage Report

Created: 2026-07-10 11:04

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