Coverage Report

Created: 2026-06-30 11:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basic/source/sbx/sbxcurr.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 <rtl/ustrbuf.hxx>
21
22
#include <basic/sberrors.hxx>
23
#include <basic/sbxvar.hxx>
24
#include <svl/numformat.hxx>
25
#include <vcl/svapp.hxx>
26
#include <vcl/settings.hxx>
27
#include <sbintern.hxx>
28
#include <runtime.hxx>
29
#include "sbxconv.hxx"
30
31
32
static OUString ImpCurrencyToString( sal_Int64 rVal )
33
0
{
34
0
    sal_Unicode cDecimalSep, cThousandSepDummy, cDecimalSepAltDummy;
35
0
    ImpGetIntntlSep(cDecimalSep, cThousandSepDummy, cDecimalSepAltDummy);
36
37
0
    auto strNum = OUString::number(rVal);
38
0
    std::u16string_view aAbsStr(strNum);
39
0
    OUStringBuffer aBuf(22);
40
0
    if (rVal < 0)
41
0
    {
42
0
        aBuf.append('-');
43
0
        assert(aAbsStr[0] == '-');
44
0
        aAbsStr = aAbsStr.substr(1); // skip the minus
45
0
    }
46
0
    size_t hasFractDigits = std::min(aAbsStr.length(), size_t(4));
47
0
    size_t hasWholeDigits = aAbsStr.length() - hasFractDigits;
48
49
0
    if (hasWholeDigits > 0)
50
0
        aBuf.append(aAbsStr.substr(0, hasWholeDigits));
51
0
    else
52
0
        aBuf.append('0');
53
0
    aBuf.append(cDecimalSep);
54
    // Handle leading 0's to right of decimal separator
55
    // Note: in VBA the stringification is a little more complex
56
    // but more natural as only the necessary digits
57
    // to the right of the decimal places are displayed
58
    // It would be great to conditionally be able to display like that too
59
60
    // Val   OOo (Cur)  VBA (Cur)
61
    // ---   ---------  ---------
62
    // 0     0.0000     0
63
    // 0.1   0.1000     0.1
64
0
    for (size_t i = 4; i > hasFractDigits; --i)
65
0
        aBuf.append('0');
66
0
    aBuf.append(aAbsStr.substr(aAbsStr.length() - hasFractDigits, hasFractDigits));
67
68
0
    return aBuf.makeStringAndClear();
69
0
}
70
71
static sal_Int64 ImpStringToCurrency(const rtl::OUString& rStr)
72
0
{
73
0
    LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
74
0
    std::shared_ptr<SvNumberFormatter> pFormatter;
75
0
    if (GetSbData()->pInst)
76
0
    {
77
0
        pFormatter = GetSbData()->pInst->GetNumberFormatter();
78
0
    }
79
0
    else
80
0
    {
81
0
        sal_uInt32 n; // Dummy
82
0
        pFormatter = SbiInstance::PrepareNumberFormatter(/*date index*/ n, /*time index*/ n,
83
0
                                                         /*date time index*/ n);
84
0
    }
85
86
    // Passing a locale index switches IsNumberFormat() to use that locale,
87
    // in case the formatter wasn't default-created with it.
88
0
    sal_uInt32 nIndex = pFormatter->GetStandardIndex(eLangType);
89
90
0
    double fResult = 0.0;
91
0
    bool bSuccess = pFormatter->IsNumberFormat(rStr, nIndex, fResult);
92
0
    if (bSuccess)
93
0
    {
94
0
        SvNumFormatType nType = pFormatter->GetType(nIndex);
95
0
        if (!(nType & (SvNumFormatType::CURRENCY | SvNumFormatType::NUMBER)))
96
0
        {
97
0
            bSuccess = false;
98
0
        }
99
0
    }
100
101
0
    if (!bSuccess)
102
0
    {
103
0
        SbxBase::SetError(ERRCODE_BASIC_CONVERSION);
104
0
    }
105
106
0
    return CurFrom(fResult);
107
0
}
108
109
sal_Int64 ImpGetCurrency( const SbxValues* p )
110
0
{
111
0
    switch( +p->eType )
112
0
    {
113
0
        case SbxERROR:
114
0
        case SbxNULL:
115
0
            SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
116
0
            return 0;
117
0
        case SbxEMPTY:
118
0
            return 0;
119
0
        case SbxCURRENCY:
120
0
            return p->nInt64;
121
0
        case SbxBYTE:
122
0
            return CurFrom(p->nByte);
123
0
        case SbxCHAR:
124
0
            return CurFrom(p->nChar);
125
0
        case SbxBOOL:
126
0
        case SbxINTEGER:
127
0
            return CurFrom(p->nInteger);
128
0
        case SbxUSHORT:
129
0
            return CurFrom(p->nUShort);
130
0
        case SbxLONG:
131
0
            return CurFrom(p->nLong);
132
0
        case SbxULONG:
133
0
            return CurFrom(p->nULong);
134
0
        case SbxSALINT64:
135
0
            return CurFrom(p->nInt64);
136
0
        case SbxSALUINT64:
137
0
            return CurFrom(p->uInt64);
138
0
        case SbxSINGLE:
139
0
            return CurFrom(p->nSingle);
140
141
0
        case SbxDATE:
142
0
        case SbxDOUBLE:
143
0
            return CurFrom(p->nDouble);
144
145
0
        case SbxDECIMAL:
146
0
        case SbxBYREF | SbxDECIMAL:
147
0
            if( p->pDecimal )
148
0
            {
149
0
                double d = 0.0;
150
0
                p->pDecimal->getDouble( d );
151
0
                return CurFrom(d);
152
0
            }
153
0
            return 0;
154
155
0
        case SbxBYREF | SbxSTRING:
156
0
        case SbxSTRING:
157
0
        case SbxLPSTR:
158
0
            if (p->pOUString)
159
0
                return ImpStringToCurrency( *p->pOUString );
160
0
            return 0;
161
0
        case SbxOBJECT:
162
0
            if (SbxValue* pVal = dynamic_cast<SbxValue*>(p->pObj))
163
0
                return pVal->GetCurrency();
164
0
            SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
165
0
            return 0;
166
167
0
        case SbxBYREF | SbxCHAR:
168
0
            return CurFrom(*p->pChar);
169
0
        case SbxBYREF | SbxBYTE:
170
0
            return CurFrom(*p->pByte);
171
0
        case SbxBYREF | SbxBOOL:
172
0
        case SbxBYREF | SbxINTEGER:
173
0
            return CurFrom(*p->pInteger);
174
0
        case SbxBYREF | SbxERROR:
175
0
        case SbxBYREF | SbxUSHORT:
176
0
            return CurFrom(*p->pUShort);
177
178
0
        case SbxBYREF | SbxLONG:
179
0
            return CurFrom(*p->pLong);
180
0
        case SbxBYREF | SbxULONG:
181
0
            return CurFrom(*p->pULong);
182
0
        case SbxBYREF | SbxSINGLE:
183
0
            return CurFrom(*p->pSingle);
184
0
        case SbxBYREF | SbxDATE:
185
0
        case SbxBYREF | SbxDOUBLE:
186
0
            return CurFrom(*p->pDouble);
187
0
        case SbxBYREF | SbxCURRENCY:
188
0
            return *p->pnInt64;
189
0
        case SbxBYREF | SbxSALINT64:
190
0
            return CurFrom(*p->pnInt64);
191
0
        case SbxBYREF | SbxSALUINT64:
192
0
            return CurFrom(*p->puInt64);
193
194
0
        default:
195
0
            SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
196
0
            return 0;
197
0
    }
198
0
}
199
200
void ImpPutCurrency( SbxValues* p, const sal_Int64 r )
201
0
{
202
0
    switch( +p->eType )
203
0
    {
204
0
        case SbxDATE:
205
0
        case SbxDOUBLE:
206
0
            p->nDouble =  CurTo<double>( r ); break;
207
0
        case SbxSALUINT64:
208
0
            p->uInt64 = CurTo<sal_uInt64>(r); break;
209
0
        case SbxSALINT64:
210
0
            p->nInt64 = CurTo<sal_Int64>(r); break;
211
212
0
        case SbxCURRENCY:
213
0
            p->nInt64 = r; break;
214
215
0
        case SbxDECIMAL:
216
0
        case SbxBYREF | SbxDECIMAL:
217
0
            if (!ImpCreateDecimal(p)->setDouble(CurTo<double>(r)))
218
0
                SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
219
0
            break;
220
0
        case SbxBYREF | SbxSTRING:
221
0
        case SbxSTRING:
222
0
        case SbxLPSTR:
223
0
            if( !p->pOUString )
224
0
                p->pOUString = new OUString;
225
226
0
            *p->pOUString = ImpCurrencyToString( r );
227
0
            break;
228
0
        case SbxOBJECT:
229
0
            if (SbxValue* pVal = dynamic_cast<SbxValue*>(p->pObj))
230
0
                pVal->PutCurrency( r );
231
0
            else
232
0
                SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
233
0
            break;
234
0
        case SbxCHAR:
235
0
            p->nChar = CurTo<sal_Unicode>(r); break;
236
0
        case SbxBYREF | SbxCHAR:
237
0
            *p->pChar = CurTo<sal_Unicode>(r); break;
238
0
        case SbxBYTE:
239
0
            p->nByte = CurTo<sal_uInt8>(r); break;
240
0
        case SbxBYREF | SbxBYTE:
241
0
            *p->pByte = CurTo<sal_uInt8>(r); break;
242
0
        case SbxINTEGER:
243
0
        case SbxBOOL:
244
0
            p->nInteger = CurTo<sal_Int16>(r); break;
245
0
        case SbxBYREF | SbxINTEGER:
246
0
        case SbxBYREF | SbxBOOL:
247
0
            *p->pInteger = CurTo<sal_Int16>(r); break;
248
0
        case SbxERROR:
249
0
        case SbxUSHORT:
250
0
            p->nUShort = CurTo<sal_uInt16>(r); break;
251
0
        case SbxBYREF | SbxERROR:
252
0
        case SbxBYREF | SbxUSHORT:
253
0
            *p->pUShort = CurTo<sal_uInt16>(r); break;
254
0
        case SbxLONG:
255
0
            p->nLong = CurTo<sal_Int32>(r); break;
256
0
        case SbxBYREF | SbxLONG:
257
0
            *p->pLong = CurTo<sal_Int32>(r); break;
258
0
        case SbxULONG:
259
0
            p->nULong = CurTo<sal_uInt32>(r); break;
260
0
        case SbxBYREF | SbxULONG:
261
0
            *p->pULong = CurTo<sal_uInt32>(r); break;
262
0
        case SbxBYREF | SbxCURRENCY:
263
0
            *p->pnInt64 = r; break;
264
0
        case SbxBYREF | SbxSALINT64:
265
0
            *p->pnInt64 = CurTo<sal_Int64>(r); break;
266
0
        case SbxBYREF | SbxSALUINT64:
267
0
            *p->puInt64 = CurTo<sal_uInt64>(r); break;
268
0
        case SbxSINGLE:
269
0
            p->nSingle = CurTo<float>( r ); break;
270
0
        case SbxBYREF | SbxSINGLE:
271
0
            *p->pSingle = CurTo<float>( r ); break;
272
0
        case SbxBYREF | SbxDATE:
273
0
        case SbxBYREF | SbxDOUBLE:
274
0
            *p->pDouble = CurTo<double>( r ); break;
275
0
        default:
276
0
            SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
277
0
    }
278
0
}
279
280
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */