Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basic/source/sbx/sbxvalue.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 <config_features.h>
21
22
#include <math.h>
23
#include <string_view>
24
25
#include <osl/diagnose.h>
26
#include <o3tl/safeint.hxx>
27
#include <tools/debug.hxx>
28
#include <tools/stream.hxx>
29
#include <sal/log.hxx>
30
31
#include <basic/sbx.hxx>
32
#include <sbunoobj.hxx>
33
#include "sbxconv.hxx"
34
#include <runtime.hxx>
35
#include <filefmt.hxx>
36
37
38
///////////////////////////// constructors
39
40
SbxValue::SbxValue()
41
4.91k
{
42
4.91k
    aData.eType = SbxEMPTY;
43
4.91k
}
SbxValue::SbxValue()
Line
Count
Source
41
4.91k
{
42
4.91k
    aData.eType = SbxEMPTY;
43
4.91k
}
Unexecuted instantiation: SbxValue::SbxValue()
44
45
SbxValue::SbxValue( SbxDataType t )
46
0
{
47
0
    int n = t & 0x0FFF;
48
49
0
    if( n == SbxVARIANT )
50
0
        n = SbxEMPTY;
51
0
    else
52
0
        SetFlag( SbxFlagBits::Fixed );
53
0
    aData.clear(SbxDataType( n ));
54
0
}
Unexecuted instantiation: SbxValue::SbxValue(SbxDataType)
Unexecuted instantiation: SbxValue::SbxValue(SbxDataType)
55
56
SbxValue::SbxValue( const SbxValue& r )
57
51.2k
    : SvRefBase( r ), SbxBase( r )
58
51.2k
{
59
51.2k
    if( !r.CanRead() )
60
0
    {
61
0
        SetError( ERRCODE_BASIC_PROP_WRITEONLY );
62
0
        if( !IsFixed() )
63
0
            aData.eType = SbxNULL;
64
0
    }
65
51.2k
    else
66
51.2k
    {
67
51.2k
        const_cast<SbxValue*>(&r)->Broadcast( SfxHintId::BasicDataWanted );
68
51.2k
        aData = r.aData;
69
        // Copy pointer, increment references
70
51.2k
        switch( aData.eType )
71
51.2k
        {
72
1.91k
            case SbxSTRING:
73
1.91k
                if( aData.pOUString )
74
0
                    aData.pOUString = new OUString( *aData.pOUString );
75
1.91k
                break;
76
0
            case SbxOBJECT:
77
0
                if( aData.pObj )
78
0
                    aData.pObj->AddFirstRef();
79
0
                break;
80
0
            case SbxDECIMAL:
81
0
                if( aData.pDecimal )
82
0
                    aData.pDecimal->addRef();
83
0
                break;
84
49.3k
            default: break;
85
51.2k
        }
86
51.2k
    }
87
51.2k
}
SbxValue::SbxValue(SbxValue const&)
Line
Count
Source
57
51.2k
    : SvRefBase( r ), SbxBase( r )
58
51.2k
{
59
51.2k
    if( !r.CanRead() )
60
0
    {
61
0
        SetError( ERRCODE_BASIC_PROP_WRITEONLY );
62
0
        if( !IsFixed() )
63
0
            aData.eType = SbxNULL;
64
0
    }
65
51.2k
    else
66
51.2k
    {
67
51.2k
        const_cast<SbxValue*>(&r)->Broadcast( SfxHintId::BasicDataWanted );
68
51.2k
        aData = r.aData;
69
        // Copy pointer, increment references
70
51.2k
        switch( aData.eType )
71
51.2k
        {
72
1.91k
            case SbxSTRING:
73
1.91k
                if( aData.pOUString )
74
0
                    aData.pOUString = new OUString( *aData.pOUString );
75
1.91k
                break;
76
0
            case SbxOBJECT:
77
0
                if( aData.pObj )
78
0
                    aData.pObj->AddFirstRef();
79
0
                break;
80
0
            case SbxDECIMAL:
81
0
                if( aData.pDecimal )
82
0
                    aData.pDecimal->addRef();
83
0
                break;
84
49.3k
            default: break;
85
51.2k
        }
86
51.2k
    }
87
51.2k
}
Unexecuted instantiation: SbxValue::SbxValue(SbxValue const&)
88
89
SbxValue& SbxValue::operator=( const SbxValue& r )
90
7.30k
{
91
7.30k
    if( &r != this )
92
7.30k
    {
93
7.30k
        if( !CanWrite() )
94
0
            SetError( ERRCODE_BASIC_PROP_READONLY );
95
7.30k
        else
96
7.30k
        {
97
            // string -> byte array
98
7.30k
            if( IsFixed() && (aData.eType == SbxOBJECT)
99
0
                && aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
100
0
                && (r.aData.eType == SbxSTRING) )
101
0
            {
102
0
                OUString aStr = r.GetOUString();
103
0
                SbxArray* pArr = StringToByteArray(aStr);
104
0
                PutObject(pArr);
105
0
                return *this;
106
0
            }
107
            // byte array -> string
108
7.30k
            if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
109
0
                && r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
110
0
                && (aData.eType == SbxSTRING) )
111
0
            {
112
0
                SbxBase* pObj = r.GetObject();
113
0
                SbxArray* pArr = dynamic_cast<SbxArray*>( pObj );
114
0
                if( pArr )
115
0
                {
116
0
                    OUString aStr = ByteArrayToString( pArr );
117
0
                    PutString(aStr);
118
0
                    return *this;
119
0
                }
120
0
            }
121
            // Readout the content of the variables
122
7.30k
            SbxValues aNew;
123
7.30k
            if( IsFixed() )
124
                // then the type has to match
125
0
                aNew.eType = aData.eType;
126
7.30k
            else if( r.IsFixed() )
127
                // Source fixed: copy the type
128
0
                aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
129
7.30k
            else
130
                // both variant: then don't care
131
7.30k
                aNew.eType = SbxVARIANT;
132
7.30k
            if( r.Get( aNew ) )
133
7.30k
                Put( aNew );
134
7.30k
        }
135
7.30k
    }
136
7.30k
    return *this;
137
7.30k
}
138
139
SbxValue::~SbxValue()
140
56.1k
{
141
56.1k
    SetFlag( SbxFlagBits::Write );
142
    // cid#1486004 silence Uncaught exception
143
56.1k
    suppress_fun_call_w_exception(SbxValue::Clear());
144
56.1k
}
145
146
void SbxValue::Clear()
147
56.1k
{
148
56.1k
    switch( aData.eType )
149
56.1k
    {
150
0
        case SbxNULL:
151
0
        case SbxEMPTY:
152
0
        case SbxVOID:
153
0
            break;
154
9.11k
        case SbxSTRING:
155
9.11k
            delete aData.pOUString; aData.pOUString = nullptr;
156
9.11k
            break;
157
0
        case SbxOBJECT:
158
0
            if( aData.pObj )
159
0
            {
160
0
                if( aData.pObj != this )
161
0
                {
162
0
                    SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
163
0
                    SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
164
0
                    bool bParentProp = pThisVar && (pThisVar->GetUserData() & 0xFFFF) == 5345;
165
0
                    if ( !bParentProp )
166
0
                        aData.pObj->ReleaseRef();
167
0
                }
168
0
                aData.pObj = nullptr;
169
0
            }
170
0
            break;
171
0
        case SbxDECIMAL:
172
0
            releaseDecimalPtr( aData.pDecimal );
173
0
            break;
174
0
        case SbxDATAOBJECT:
175
0
            aData.pData = nullptr; break;
176
47.0k
        default:
177
47.0k
        {
178
47.0k
            SbxValues aEmpty;
179
47.0k
            aEmpty.clear(GetType());
180
47.0k
            Put( aEmpty );
181
47.0k
        }
182
56.1k
    }
183
56.1k
}
184
185
// Dummy
186
187
void SbxValue::Broadcast( SfxHintId )
188
132k
{}
189
190
//////////////////////////// Readout data
191
192
// Detect the "right" variables. If it is an object, will be addressed either
193
// the object itself or its default property.
194
// If the variable contain a variable or an object, this will be
195
// addressed.
196
197
SbxValue* SbxValue::TheRealValue( bool bObjInObjError ) const
198
74.1k
{
199
74.1k
    SbxValue* p = const_cast<SbxValue*>(this);
200
74.1k
    for( ;; )
201
74.1k
    {
202
74.1k
        SbxDataType t = SbxDataType( p->aData.eType & 0x0FFF );
203
74.1k
        if( t == SbxOBJECT )
204
0
        {
205
            // The block contains an object or a variable
206
0
            SbxObject* pObj = dynamic_cast<SbxObject*>( p->aData.pObj );
207
0
            if( pObj )
208
0
            {
209
                // Has the object a default property?
210
0
                SbxVariable* pDflt = pObj->GetDfltProperty();
211
212
                // If this is an object and contains itself,
213
                // we cannot access on it
214
                // The old condition to set an error is not correct,
215
                // because e.g. a regular variant variable with an object
216
                // could be affected if another value should be assigned.
217
                // Therefore with flag.
218
0
                if( bObjInObjError && !pDflt &&
219
0
                    static_cast<SbxValue*>(pObj)->aData.eType == SbxOBJECT &&
220
0
                    static_cast<SbxValue*>(pObj)->aData.pObj == pObj )
221
0
                {
222
0
#if !HAVE_FEATURE_SCRIPTING
223
0
                    const bool bSuccess = false;
224
#else
225
                    bool bSuccess = handleToStringForCOMObjects( pObj, p );
226
#endif
227
0
                    if( !bSuccess )
228
0
                    {
229
0
                        SetError( ERRCODE_BASIC_BAD_PROP_VALUE );
230
0
                        p = nullptr;
231
0
                    }
232
0
                }
233
0
                else if( pDflt )
234
0
                    p = pDflt;
235
0
                break;
236
0
            }
237
            // Did we have an array?
238
0
            SbxArray* pArray = dynamic_cast<SbxArray*>( p->aData.pObj );
239
0
            if( pArray )
240
0
            {
241
                // When indicated get the parameter
242
0
                SbxArray* pPar = nullptr;
243
0
                SbxVariable* pVar = dynamic_cast<SbxVariable*>( p );
244
0
                if( pVar )
245
0
                    pPar = pVar->GetParameters();
246
0
                if( pPar )
247
0
                {
248
                    // Did we have a dimensioned array?
249
0
                    SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( p->aData.pObj );
250
0
                    if( pDimArray )
251
0
                        p = pDimArray->Get( pPar );
252
0
                    else
253
0
                        p = pArray->Get(pPar->Get(1)->GetInteger());
254
0
                    break;
255
0
                }
256
0
            }
257
            // Otherwise guess a SbxValue
258
0
            SbxValue* pVal = dynamic_cast<SbxValue*>( p->aData.pObj );
259
0
            if( pVal )
260
0
                p = pVal;
261
0
            else
262
0
                break;
263
0
        }
264
74.1k
        else
265
74.1k
            break;
266
74.1k
    }
267
74.1k
    return p;
268
74.1k
}
269
270
bool SbxValue::Get( SbxValues& rRes ) const
271
8.79k
{
272
8.79k
    bool bRes = false;
273
8.79k
    ErrCode eOld = GetError();
274
8.79k
    if( eOld != ERRCODE_NONE )
275
0
        ResetError();
276
8.79k
    if( !CanRead() )
277
0
    {
278
0
        SetError( ERRCODE_BASIC_PROP_WRITEONLY );
279
0
        rRes.pObj = nullptr;
280
0
    }
281
8.79k
    else
282
8.79k
    {
283
        // If an object or a VARIANT is requested, don't search the real values
284
8.79k
        SbxValue* p = const_cast<SbxValue*>(this);
285
8.79k
        if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
286
1.49k
            p = TheRealValue( true );
287
8.79k
        if( p )
288
8.79k
        {
289
8.79k
            p->Broadcast( SfxHintId::BasicDataWanted );
290
8.79k
            switch( rRes.eType )
291
8.79k
            {
292
0
                case SbxEMPTY:
293
0
                case SbxVOID:
294
0
                case SbxNULL:    break;
295
7.30k
                case SbxVARIANT: rRes = p->aData; break;
296
0
                case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
297
0
                case SbxLONG:    rRes.nLong = ImpGetLong( &p->aData ); break;
298
0
                case SbxSALINT64:   rRes.nInt64 = ImpGetInt64( &p->aData ); break;
299
0
                case SbxSALUINT64:  rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
300
0
                case SbxSINGLE:  rRes.nSingle = ImpGetSingle( &p->aData ); break;
301
1.49k
                case SbxDOUBLE:  rRes.nDouble = ImpGetDouble( &p->aData ); break;
302
0
                case SbxCURRENCY:rRes.nInt64 = ImpGetCurrency( &p->aData ); break;
303
0
                case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
304
0
                case SbxDATE:    rRes.nDouble = ImpGetDate( &p->aData ); break;
305
0
                case SbxBOOL:
306
0
                    rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
307
0
                        ImpGetBool( &p->aData ) );
308
0
                    break;
309
0
                case SbxCHAR:    rRes.nChar = ImpGetChar( &p->aData ); break;
310
0
                case SbxBYTE:    rRes.nByte = ImpGetByte( &p->aData ); break;
311
0
                case SbxUSHORT:  rRes.nUShort = ImpGetUShort( &p->aData ); break;
312
0
                case SbxULONG:   rRes.nULong = ImpGetULong( &p->aData ); break;
313
0
                case SbxLPSTR:
314
0
                case SbxSTRING:  p->aPic = ImpGetString( &p->aData );
315
0
                                 rRes.pOUString = &p->aPic; break;
316
0
                case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
317
0
                                    rRes.pOUString = &p->aPic; break;
318
0
                case SbxINT:
319
0
                    rRes.nInt = static_cast<int>(ImpGetLong( &p->aData ));
320
0
                    break;
321
0
                case SbxUINT:
322
0
                    rRes.nUInt = static_cast<int>(ImpGetULong( &p->aData ));
323
0
                    break;
324
0
                case SbxOBJECT:
325
0
                    if( p->aData.eType == SbxOBJECT )
326
0
                        rRes.pObj = p->aData.pObj;
327
0
                    else
328
0
                    {
329
0
                        SetError( ERRCODE_BASIC_NO_OBJECT );
330
0
                        rRes.pObj = nullptr;
331
0
                    }
332
0
                    break;
333
0
                default:
334
0
                    if( p->aData.eType == rRes.eType )
335
0
                        rRes = p->aData;
336
0
                    else
337
0
                    {
338
0
                        SetError( ERRCODE_BASIC_CONVERSION );
339
0
                        rRes.pObj = nullptr;
340
0
                    }
341
8.79k
            }
342
8.79k
        }
343
0
        else
344
0
        {
345
            // Object contained itself
346
0
            SbxDataType eTemp = rRes.eType;
347
0
            rRes.clear(eTemp);
348
0
        }
349
8.79k
    }
350
8.79k
    if( !IsError() )
351
8.79k
    {
352
8.79k
        bRes = true;
353
8.79k
        if( eOld != ERRCODE_NONE )
354
0
            SetError( eOld );
355
8.79k
    }
356
8.79k
    return bRes;
357
8.79k
}
358
359
SbxValues SbxValue::Get(SbxDataType t) const
360
604
{
361
604
    SbxValues aRes(t);
362
604
    Get(aRes);
363
604
    return aRes;
364
604
}
365
366
const OUString& SbxValue::GetCoreString() const
367
0
{
368
0
    SbxValues aRes(SbxCoreSTRING);
369
0
    if( Get( aRes ) )
370
0
    {
371
0
        const_cast<SbxValue*>(this)->aToolString = *aRes.pOUString;
372
0
    }
373
0
    else
374
0
    {
375
0
        const_cast<SbxValue*>(this)->aToolString.clear();
376
0
    }
377
0
    return aToolString;
378
0
}
379
380
OUString SbxValue::GetOUString() const
381
0
{
382
0
    OUString aResult;
383
0
    SbxValues aRes(SbxSTRING);
384
0
    if( Get( aRes ) )
385
0
    {
386
0
        aResult = *aRes.pOUString;
387
0
    }
388
0
    return aResult;
389
0
}
390
391
//////////////////////////// Write data
392
393
bool SbxValue::Put( const SbxValues& rVal )
394
72.6k
{
395
72.6k
    bool bRes = false;
396
72.6k
    ErrCode eOld = GetError();
397
72.6k
    if( eOld != ERRCODE_NONE )
398
0
        ResetError();
399
72.6k
    if( !CanWrite() )
400
0
        SetError( ERRCODE_BASIC_PROP_READONLY );
401
72.6k
    else if( rVal.eType & 0xF000 )
402
0
        SetError( ERRCODE_BASIC_BAD_ARGUMENT );
403
72.6k
    else
404
72.6k
    {
405
        // If an object is requested, don't search the real values
406
72.6k
        SbxValue* p = this;
407
72.6k
        if( rVal.eType != SbxOBJECT )
408
72.6k
            p = TheRealValue( false );  // Don't allow an error here
409
72.6k
        if( p )
410
72.6k
        {
411
72.6k
            if( !p->CanWrite() )
412
0
                SetError( ERRCODE_BASIC_PROP_READONLY );
413
72.6k
            else if( p->IsFixed() || p->SetType( static_cast<SbxDataType>( rVal.eType & 0x0FFF ) ) )
414
72.6k
              switch( rVal.eType & 0x0FFF )
415
72.6k
            {
416
0
                case SbxEMPTY:
417
0
                case SbxVOID:
418
0
                case SbxNULL:       break;
419
0
                case SbxINTEGER:    ImpPutInteger( &p->aData, rVal.nInteger ); break;
420
54.5k
                case SbxLONG:       ImpPutLong( &p->aData, rVal.nLong ); break;
421
0
                case SbxSALINT64:   ImpPutInt64( &p->aData, rVal.nInt64 ); break;
422
0
                case SbxSALUINT64:  ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
423
0
                case SbxSINGLE:     ImpPutSingle( &p->aData, rVal.nSingle ); break;
424
8.97k
                case SbxDOUBLE:     ImpPutDouble( &p->aData, rVal.nDouble ); break;
425
0
                case SbxCURRENCY:   ImpPutCurrency( &p->aData, rVal.nInt64 ); break;
426
0
                case SbxDECIMAL:    ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
427
0
                case SbxDATE:       ImpPutDate( &p->aData, rVal.nDouble ); break;
428
1.91k
                case SbxBOOL:       ImpPutBool( &p->aData, rVal.nInteger ); break;
429
0
                case SbxCHAR:       ImpPutChar( &p->aData, rVal.nChar ); break;
430
0
                case SbxBYTE:       ImpPutByte( &p->aData, rVal.nByte ); break;
431
0
                case SbxUSHORT:     ImpPutUShort( &p->aData, rVal.nUShort ); break;
432
0
                case SbxULONG:      ImpPutULong( &p->aData, rVal.nULong ); break;
433
0
                case SbxLPSTR:
434
7.19k
                case SbxSTRING:     ImpPutString( &p->aData, rVal.pOUString ); break;
435
0
                case SbxINT:
436
0
                    ImpPutLong( &p->aData, static_cast<sal_Int32>(rVal.nInt) );
437
0
                    break;
438
0
                case SbxUINT:
439
0
                    ImpPutULong( &p->aData, static_cast<sal_uInt32>(rVal.nUInt) );
440
0
                    break;
441
0
                case SbxOBJECT:
442
0
                    if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
443
0
                    {
444
                        // is already inside
445
0
                        if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
446
0
                            break;
447
448
                        // Delete only the value part!
449
0
                        p->SbxValue::Clear();
450
451
                        // real assignment
452
0
                        p->aData.pObj = rVal.pObj;
453
454
                        // if necessary increment Ref-Count
455
0
                        if( p->aData.pObj && p->aData.pObj != p )
456
0
                        {
457
0
                            if ( p != this )
458
0
                            {
459
0
                                OSL_FAIL( "TheRealValue" );
460
0
                            }
461
0
                            SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
462
0
                            SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
463
0
                            bool bParentProp = pThisVar && (pThisVar->GetUserData() & 0xFFFF) == 5345;
464
0
                            if ( !bParentProp )
465
0
                                p->aData.pObj->AddFirstRef();
466
0
                        }
467
0
                    }
468
0
                    else
469
0
                        SetError( ERRCODE_BASIC_CONVERSION );
470
0
                    break;
471
0
                default:
472
0
                    if( p->aData.eType == rVal.eType )
473
0
                        p->aData = rVal;
474
0
                    else
475
0
                    {
476
0
                        SetError( ERRCODE_BASIC_CONVERSION );
477
0
                        if( !p->IsFixed() )
478
0
                            p->aData.eType = SbxNULL;
479
0
                    }
480
72.6k
            }
481
72.6k
            if( !IsError() )
482
72.6k
            {
483
72.6k
                p->SetModified( true );
484
72.6k
                p->Broadcast( SfxHintId::BasicDataChanged );
485
72.6k
                if( eOld != ERRCODE_NONE )
486
0
                    SetError( eOld );
487
72.6k
                bRes = true;
488
72.6k
            }
489
72.6k
        }
490
72.6k
    }
491
72.6k
    return bRes;
492
72.6k
}
493
494
// with advanced evaluation (International, "TRUE"/"FALSE")
495
static OUString ImpConvStringExt(const OUString& rSrc, SbxDataType eTargetType)
496
0
{
497
    // only special cases are handled, nothing on default
498
0
    switch (eTargetType)
499
0
    {
500
        // Consider international for floating point. Following default conversion (SbxValue::Put)
501
        // assumes internationalized strings, but the input may use standard decimal dot.
502
0
        case SbxSINGLE:
503
0
        case SbxDOUBLE:
504
0
        case SbxCURRENCY:
505
0
        {
506
0
            sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt;
507
0
            ImpGetIntntlSep(cDecimalSep, cThousandSep, cDecimalSepAlt);
508
509
            // 1. If any of the returned decimal separators is dot, do nothing
510
0
            if (cDecimalSep == '.' || cDecimalSepAlt == '.')
511
0
                break;
512
513
            // 2. If there are internationalized separators already, do nothing
514
0
            if (rSrc.indexOf(cDecimalSep) >= 0 || rSrc.indexOf(cDecimalSepAlt) >= 0)
515
0
                break;
516
517
            // 3. Replace all dots with the primary separator. This resolves possible ambiguity with
518
            // dot as thousand separator, in favor of decimal dot; unlike "only change one dot"
519
            // approach, this prevents inconsistency like converting "234.567" to a number with
520
            // floating point 234.567, while "1.234.567" to a whole number 1234567. The latter will
521
            // be rejected now.
522
0
            return rSrc.replaceAll(".", OUStringChar(cDecimalSep));
523
0
        }
524
525
        // check as string in case of sal_Bool sal_True and sal_False
526
0
        case SbxBOOL:
527
0
            if (rSrc.equalsIgnoreAsciiCase("true"))
528
0
                return OUString::number(SbxTRUE);
529
0
            if (rSrc.equalsIgnoreAsciiCase("false"))
530
0
                return OUString::number(SbxFALSE);
531
0
            break;
532
533
0
        default:
534
0
            break;
535
0
    }
536
537
0
    return rSrc;
538
0
}
539
540
// From 1996-03-28:
541
// Method to execute a pretreatment of the strings at special types.
542
// In particular necessary for BASIC-IDE, so that
543
// the output in the Watch-Window can be written back with PutStringExt,
544
// if Float were declared with either '.' or locale-specific decimal
545
// separator, or BOOl explicit with "TRUE" or "FALSE".
546
// Implementation in ImpConvStringExt
547
void SbxValue::PutStringExt( const OUString& r )
548
0
{
549
    // Identify the own type (not as in Put() with TheRealValue(),
550
    // Objects are not handled anyway)
551
0
    SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
552
0
    OUString aStr(ImpConvStringExt(r, eTargetType));
553
554
    // tinker a Source-Value
555
0
    SbxValues aRes(SbxSTRING);
556
0
    aRes.pOUString = &aStr;
557
558
    // #34939: For Strings which contain a number, and if this has a Num-Type,
559
    // set a Fixed flag so that the type will not be changed
560
0
    SbxFlagBits nFlags_ = GetFlags();
561
0
    if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
562
0
        ( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
563
0
        eTargetType == SbxBOOL )
564
0
    {
565
0
        SbxValue aVal;
566
0
        aVal.Put( aRes );
567
0
        if( aVal.IsNumeric() )
568
0
            SetFlag( SbxFlagBits::Fixed );
569
0
    }
570
571
0
    const bool bRet = Put(aRes);
572
573
    // If FIXED resulted in an error, set it back
574
    // (UI-Action should not result in an error, but simply fail)
575
0
    if( !bRet )
576
0
        ResetError();
577
578
0
    SetFlags( nFlags_ );
579
0
}
580
581
bool SbxValue::PutBool( bool b )
582
958
{
583
958
    SbxValues aRes(SbxBOOL);
584
958
    aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
585
958
    return Put(aRes);
586
958
}
587
588
bool SbxValue::PutEmpty()
589
0
{
590
0
    bool bRet = SetType( SbxEMPTY );
591
0
    SetModified( true );
592
0
    return bRet;
593
0
}
594
595
void SbxValue::PutNull()
596
0
{
597
0
    bool bRet = SetType( SbxNULL );
598
0
    if( bRet )
599
0
        SetModified( true );
600
0
}
601
602
603
// Special decimal methods
604
void SbxValue::PutDecimal( css::bridge::oleautomation::Decimal const & rAutomationDec )
605
0
{
606
0
    SbxValue::Clear();
607
0
    aData.pDecimal = new SbxDecimal( rAutomationDec );
608
0
    aData.pDecimal->addRef();
609
0
    aData.eType = SbxDECIMAL;
610
0
}
611
612
void SbxValue::fillAutomationDecimal
613
    ( css::bridge::oleautomation::Decimal& rAutomationDec ) const
614
0
{
615
0
    SbxDecimal* pDecimal = GetDecimal();
616
0
    if( pDecimal != nullptr )
617
0
    {
618
0
        pDecimal->fillAutomationDecimal( rAutomationDec );
619
0
    }
620
0
}
621
622
623
bool SbxValue::PutString( const OUString& r )
624
7.19k
{
625
7.19k
    SbxValues aRes(SbxSTRING);
626
7.19k
    aRes.pOUString = const_cast<OUString*>(&r);
627
7.19k
    return Put(aRes);
628
7.19k
}
629
630
631
#define PUT( p, e, t, m ) \
632
9.69k
bool SbxValue::p( t n ) \
633
9.69k
{ SbxValues aRes(e); aRes.m = n; return Put(aRes); }
Unexecuted instantiation: SbxValue::PutByte(unsigned char)
Unexecuted instantiation: SbxValue::PutChar(char16_t)
Unexecuted instantiation: SbxValue::PutCurrency(long)
SbxValue::PutDouble(double)
Line
Count
Source
632
1.42k
bool SbxValue::p( t n ) \
633
1.42k
{ SbxValues aRes(e); aRes.m = n; return Put(aRes); }
Unexecuted instantiation: SbxValue::PutInteger(short)
SbxValue::PutLong(int)
Line
Count
Source
632
8.27k
bool SbxValue::p( t n ) \
633
8.27k
{ SbxValues aRes(e); aRes.m = n; return Put(aRes); }
Unexecuted instantiation: SbxValue::PutObject(SbxBase*)
Unexecuted instantiation: SbxValue::PutSingle(float)
Unexecuted instantiation: SbxValue::PutULong(unsigned int)
Unexecuted instantiation: SbxValue::PutUShort(unsigned short)
Unexecuted instantiation: SbxValue::PutInt64(long)
Unexecuted instantiation: SbxValue::PutUInt64(unsigned long)
Unexecuted instantiation: SbxValue::PutDecimal(SbxDecimal*)
634
635
void SbxValue::PutDate( double n )
636
0
{ SbxValues aRes(SbxDATE); aRes.nDouble = n; Put( aRes ); }
637
void SbxValue::PutErr( sal_uInt16 n )
638
0
{ SbxValues aRes(SbxERROR); aRes.nUShort = n; Put( aRes ); }
639
640
PUT( PutByte,     SbxBYTE,       sal_uInt8,        nByte )
641
PUT( PutChar,     SbxCHAR,       sal_Unicode,      nChar )
642
PUT( PutCurrency, SbxCURRENCY,   sal_Int64,        nInt64 )
643
PUT( PutDouble,   SbxDOUBLE,     double,           nDouble )
644
PUT( PutInteger,  SbxINTEGER,    sal_Int16,        nInteger )
645
PUT( PutLong,     SbxLONG,       sal_Int32,        nLong )
646
PUT( PutObject,   SbxOBJECT,     SbxBase*,         pObj )
647
PUT( PutSingle,   SbxSINGLE,     float,            nSingle )
648
PUT( PutULong,    SbxULONG,      sal_uInt32,       nULong )
649
PUT( PutUShort,   SbxUSHORT,     sal_uInt16,       nUShort )
650
PUT( PutInt64,    SbxSALINT64,   sal_Int64,        nInt64 )
651
PUT( PutUInt64,   SbxSALUINT64,  sal_uInt64,       uInt64 )
652
PUT( PutDecimal,  SbxDECIMAL,    SbxDecimal*,      pDecimal )
653
654
////////////////////////// Setting of the data type
655
656
bool SbxValue::IsFixed() const
657
118k
{
658
118k
    return (GetFlags() & SbxFlagBits::Fixed) || ((aData.eType & SbxBYREF) != 0);
659
118k
}
660
661
// A variable is numeric, if it is EMPTY or really numeric
662
// or if it contains a complete convertible String
663
664
// #41692, implement it for RTL and Basic-Core separately
665
bool SbxValue::IsNumeric() const
666
0
{
667
0
    return ImpIsNumeric( /*bOnlyIntntl*/false );
668
0
}
669
670
bool SbxValue::IsNumericRTL() const
671
0
{
672
0
    return ImpIsNumeric( /*bOnlyIntntl*/true );
673
0
}
674
675
bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const
676
0
{
677
678
0
    if( !CanRead() )
679
0
    {
680
0
        SetError( ERRCODE_BASIC_PROP_WRITEONLY );
681
0
        return false;
682
0
    }
683
    // Test downcast!!!
684
0
    if( auto pSbxVar = dynamic_cast<const SbxVariable*>( this) )
685
0
        const_cast<SbxVariable*>(pSbxVar)->Broadcast( SfxHintId::BasicDataWanted );
686
0
    SbxDataType t = GetType();
687
0
    if( t == SbxSTRING )
688
0
    {
689
0
        if( aData.pOUString )
690
0
        {
691
0
            OUString s( *aData.pOUString );
692
0
            double n;
693
0
            SbxDataType t2;
694
0
            sal_Int32 nLen = 0;
695
0
            bool bHasNumber = false;
696
0
            if( ImpScan( s, n, t2, &nLen, &bHasNumber, bOnlyIntntl ) == ERRCODE_NONE )
697
0
                return nLen == s.getLength() && bHasNumber;
698
0
        }
699
0
        return false;
700
0
    }
701
#if HAVE_FEATURE_SCRIPTING
702
    else if (t == SbxBOOL && bOnlyIntntl && SbiRuntime::isVBAEnabled())
703
        return true;
704
#endif
705
0
    else
706
0
        return t == SbxEMPTY
707
0
            || ( t >= SbxINTEGER && t <= SbxCURRENCY )
708
0
            || ( t >= SbxCHAR && t <= SbxUINT );
709
0
}
710
711
SbxDataType SbxValue::GetType() const
712
53.6k
{
713
53.6k
    return SbxDataType( aData.eType & 0x0FFF );
714
53.6k
}
715
716
717
bool SbxValue::SetType( SbxDataType t )
718
72.6k
{
719
72.6k
    DBG_ASSERT( !( t & 0xF000 ), "SetType of BYREF|ARRAY is forbidden!" );
720
72.6k
    if( ( t == SbxEMPTY && aData.eType == SbxVOID )
721
72.6k
     || ( aData.eType == SbxEMPTY && t == SbxVOID ) )
722
0
        return true;
723
72.6k
    if( ( t & 0x0FFF ) == SbxVARIANT )
724
0
    {
725
        // Try to set the data type to Variant
726
0
        ResetFlag( SbxFlagBits::Fixed );
727
0
        if( IsFixed() )
728
0
        {
729
0
            SetError( ERRCODE_BASIC_CONVERSION );
730
0
            return false;
731
0
        }
732
0
        t = SbxEMPTY;
733
0
    }
734
72.6k
    if( ( t & 0x0FFF ) == ( aData.eType & 0x0FFF ) )
735
56.1k
        return true;
736
737
16.5k
    if( !CanWrite() || IsFixed() )
738
0
    {
739
0
        SetError( ERRCODE_BASIC_CONVERSION );
740
0
        return false;
741
0
    }
742
16.5k
    else
743
16.5k
    {
744
        // De-allocate potential objects
745
16.5k
        switch( aData.eType )
746
16.5k
        {
747
0
            case SbxSTRING:
748
0
                delete aData.pOUString;
749
0
                break;
750
0
            case SbxOBJECT:
751
0
                if( aData.pObj && aData.pObj != this )
752
0
                {
753
0
                    SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
754
0
                    SbxVariable *pThisVar = dynamic_cast<SbxVariable*>( this );
755
0
                    sal_uInt32 nSlotId = pThisVar
756
0
                                ? pThisVar->GetUserData() & 0xFFFF
757
0
                                : 0;
758
0
                    DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName() == "Parent",
759
0
                                "SID_PARENTOBJECT is not named 'Parent'" );
760
0
                    bool bParentProp = nSlotId == 5345;
761
0
                    if ( !bParentProp )
762
0
                        aData.pObj->ReleaseRef();
763
0
                }
764
0
                break;
765
16.5k
            default: break;
766
16.5k
        }
767
16.5k
        aData.clear(t);
768
16.5k
    }
769
16.5k
    return true;
770
16.5k
}
771
772
bool SbxValue::Convert( SbxDataType eTo )
773
0
{
774
0
    eTo = SbxDataType( eTo & 0x0FFF );
775
0
    if( ( aData.eType & 0x0FFF ) == eTo )
776
0
        return true;
777
0
    if( !CanWrite() )
778
0
        return false;
779
0
    if( eTo == SbxVARIANT )
780
0
    {
781
        // Trial to set the data type to Variant
782
0
        ResetFlag( SbxFlagBits::Fixed );
783
0
        if( IsFixed() )
784
0
        {
785
0
            SetError( ERRCODE_BASIC_CONVERSION );
786
0
            return false;
787
0
        }
788
0
        else
789
0
            return true;
790
0
    }
791
    // Converting from null doesn't work. Once null, always null!
792
0
    if( aData.eType == SbxNULL )
793
0
    {
794
0
        SetError( ERRCODE_BASIC_CONVERSION );
795
0
        return false;
796
0
    }
797
798
    // Conversion of the data:
799
0
    SbxValues aNew(eTo);
800
0
    if( Get( aNew ) )
801
0
    {
802
        // The data type could be converted. It ends here with fixed elements,
803
        // because the data had not to be taken over
804
0
        if( !IsFixed() )
805
0
        {
806
0
            SetType( eTo );
807
0
            Put( aNew );
808
0
            SetModified( true );
809
0
        }
810
0
        return true;
811
0
    }
812
0
    else
813
0
        return false;
814
0
}
815
////////////////////////////////// Calculating
816
817
static sal_Int64 MulAndDiv(sal_Int64 n, sal_Int64 mul, sal_Int64 div)
818
0
{
819
0
    if (div == 0)
820
0
    {
821
0
        SbxBase::SetError(ERRCODE_BASIC_ZERODIV);
822
0
        return n;
823
0
    }
824
0
    auto errorValue = [](sal_Int64 x, sal_Int64 y, sal_Int64 z)
825
0
    {
826
0
        const int i = (x < 0 ? -1 : 1) * (y < 0 ? -1 : 1) * (z < 0 ? -1 : 1);
827
0
        return i == 1 ? SAL_MAX_INT64 : SAL_MIN_INT64;
828
0
    };
829
0
    sal_Int64 result;
830
    // If x * integral part of (mul/div) overflows -> product does not fit
831
0
    if (o3tl::checked_multiply(n, mul / div, result))
832
0
    {
833
0
        SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW);
834
0
        return errorValue(n, mul, div);
835
0
    }
836
0
    if (sal_Int64 mul_frac = mul % div)
837
0
    {
838
        // can't overflow: mul_frac < div
839
0
        sal_Int64 result_frac = n / div * mul_frac;
840
0
        if (sal_Int64 x_frac = n % div)
841
0
            result_frac += x_frac * mul_frac / div;
842
0
        if (o3tl::checked_add(result, result_frac, result))
843
0
        {
844
0
            SbxBase::SetError(ERRCODE_BASIC_MATH_OVERFLOW);
845
0
            return errorValue(n, mul, div);
846
0
        }
847
0
    }
848
0
    return result;
849
0
}
850
851
bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
852
445
{
853
445
#if !HAVE_FEATURE_SCRIPTING
854
445
    const bool bVBAInterop = false;
855
#else
856
    bool bVBAInterop =  SbiRuntime::isVBAEnabled();
857
#endif
858
445
    SbxDataType eThisType = GetType();
859
445
    SbxDataType eOpType = rOp.GetType();
860
445
    ErrCode eOld = GetError();
861
445
    if( eOld != ERRCODE_NONE )
862
0
        ResetError();
863
445
    if( !CanWrite() )
864
0
        SetError( ERRCODE_BASIC_PROP_READONLY );
865
445
    else if( !rOp.CanRead() )
866
0
        SetError( ERRCODE_BASIC_PROP_WRITEONLY );
867
    // Special rule 1: If one operand is null, the result is null
868
445
    else if( eThisType == SbxNULL || eOpType == SbxNULL )
869
0
        SetType( SbxNULL );
870
445
    else
871
445
    {
872
445
        SbxValues aL, aR;
873
445
        bool bDecimal = false;
874
445
        if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING && eOpType != SbxEMPTY ) ||
875
0
             ( eThisType != SbxSTRING && eThisType != SbxEMPTY && eOpType == SbxSTRING ) ) &&
876
0
             ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
877
0
        {
878
0
            goto Lbl_OpIsDouble;
879
0
        }
880
445
        else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && (  eOp == SbxPLUS ) ) )
881
0
        {
882
0
            if( eOp == SbxCAT || eOp == SbxPLUS )
883
0
            {
884
                // From 1999-11-5, keep OUString in mind
885
0
                aL.eType = aR.eType = SbxSTRING;
886
0
                rOp.Get( aR );
887
                // From 1999-12-8, #70399: Here call GetType() again, Get() can change the type!
888
0
                if( rOp.GetType() == SbxEMPTY )
889
0
                    goto Lbl_OpIsEmpty;     // concatenate empty, *this stays lhs as result
890
0
                Get( aL );
891
892
                // #30576: To begin with test, if the conversion worked
893
0
                if( aL.pOUString != nullptr && aR.pOUString != nullptr )
894
0
                {
895
                    // tdf#108039: catch possible bad_alloc
896
0
                    try {
897
0
                        *aL.pOUString += *aR.pOUString;
898
0
                    }
899
0
                    catch (const std::bad_alloc&) {
900
0
                        SetError(ERRCODE_BASIC_MATH_OVERFLOW);
901
0
                    }
902
0
                }
903
                // Not even Left OK?
904
0
                else if( aL.pOUString == nullptr )
905
0
                {
906
0
                    aL.pOUString = new OUString();
907
0
                }
908
0
            }
909
0
            else
910
0
                SetError( ERRCODE_BASIC_CONVERSION );
911
0
        }
912
445
        else if( eOpType == SbxSTRING && rOp.IsFixed() )
913
0
        {   // Numeric: there is no String allowed on the right side
914
0
            SetError( ERRCODE_BASIC_CONVERSION );
915
            // falls all the way out
916
0
        }
917
445
        else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
918
0
        {
919
0
            if( GetType() == eOpType )
920
0
            {
921
0
                if (GetType() == SbxSALUINT64 || GetType() == SbxSALINT64 || GetType() == SbxULONG)
922
0
                    aL.eType = aR.eType = GetType();
923
0
                else if (GetType() == SbxCURRENCY)
924
0
                    aL.eType = aR.eType = SbxSALINT64; // Convert to integer value before operation
925
                // tdf#145960 - return type of boolean operators should be of type boolean
926
0
                else if ( eOpType == SbxBOOL && eOp != SbxMOD && eOp != SbxIDIV )
927
0
                    aL.eType = aR.eType = SbxBOOL;
928
0
                else
929
0
                    aL.eType = aR.eType = SbxLONG;
930
0
            }
931
0
            else
932
0
                aL.eType = aR.eType = SbxLONG;
933
934
0
            if (rOp.Get(aR) && Get(aL)) // re-do Get after type assigns above
935
0
            {
936
0
                switch( eOp )
937
0
                {
938
                    /* TODO: For SbxEMPTY operands with boolean operators use
939
                     * the VBA Nothing definition of Comparing Nullable Types?
940
                     * https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/data-types/nullable-value-types
941
                     */
942
                    /* TODO: it is unclear yet whether this also should be done
943
                     * for the non-bVBAInterop case or not, or at all, consider
944
                     * user defined spreadsheet functions where an empty cell
945
                     * is SbxEMPTY and usually is treated as 0 zero or "" empty
946
                     * string.
947
                     */
948
0
                    case SbxIDIV:
949
0
                        if( aL.eType == SbxSALUINT64 )
950
0
                            if( !aR.uInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
951
0
                            else aL.uInt64 /= aR.uInt64;
952
0
                        else if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
953
0
                            if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
954
0
                            else aL.nInt64 /= aR.nInt64;
955
0
                        else if( aL.eType == SbxLONG )
956
0
                            if( !aR.nLong ) SetError( ERRCODE_BASIC_ZERODIV );
957
0
                            else aL.nLong /= aR.nLong;
958
0
                        else
959
0
                            if( !aR.nULong ) SetError( ERRCODE_BASIC_ZERODIV );
960
0
                            else aL.nULong /= aR.nULong;
961
0
                        break;
962
0
                    case SbxMOD:
963
0
                        if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
964
0
                            if( !aR.nInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
965
0
                            else aL.nInt64 %= aR.nInt64;
966
0
                        else if( aL.eType == SbxSALUINT64 )
967
0
                            if( !aR.uInt64 ) SetError( ERRCODE_BASIC_ZERODIV );
968
0
                            else aL.uInt64 %= aR.uInt64;
969
0
                        else if( aL.eType == SbxLONG )
970
0
                            if( !aR.nLong ) SetError( ERRCODE_BASIC_ZERODIV );
971
0
                            else aL.nLong %= aR.nLong;
972
0
                        else
973
0
                            if( !aR.nULong ) SetError( ERRCODE_BASIC_ZERODIV );
974
0
                            else aL.nULong %= aR.nULong;
975
0
                        break;
976
0
                    case SbxAND:
977
0
                        if( aL.eType != SbxLONG && aL.eType != SbxULONG )
978
0
                            aL.nInt64 &= aR.nInt64;
979
0
                        else
980
0
                            aL.nLong &= aR.nLong;
981
0
                        break;
982
0
                    case SbxOR:
983
0
                        if( aL.eType != SbxLONG && aL.eType != SbxULONG )
984
0
                            aL.nInt64 |= aR.nInt64;
985
0
                        else
986
0
                            aL.nLong |= aR.nLong;
987
0
                        break;
988
0
                    case SbxXOR:
989
0
                        if( aL.eType != SbxLONG && aL.eType != SbxULONG )
990
0
                            aL.nInt64 ^= aR.nInt64;
991
0
                        else
992
0
                            aL.nLong ^= aR.nLong;
993
0
                        break;
994
0
                    case SbxEQV:
995
0
                        if( aL.eType != SbxLONG && aL.eType != SbxULONG )
996
0
                            aL.nInt64 = (aL.nInt64 & aR.nInt64) | (~aL.nInt64 & ~aR.nInt64);
997
0
                        else
998
0
                            aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
999
0
                        break;
1000
0
                    case SbxIMP:
1001
0
                        if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1002
0
                            aL.nInt64 = ~aL.nInt64 | aR.nInt64;
1003
0
                        else
1004
0
                            aL.nLong = ~aL.nLong | aR.nLong;
1005
0
                        break;
1006
0
                    case SbxNOT:
1007
0
                        if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1008
0
                        {
1009
0
                            if ( aL.eType != SbxBOOL )
1010
0
                                aL.nInt64 = ~aL.nInt64;
1011
0
                            else
1012
0
                                aL.nLong = ~aL.nLong;
1013
0
                        }
1014
0
                        else
1015
0
                            aL.nLong = ~aL.nLong;
1016
0
                        break;
1017
0
                    default: break;
1018
0
                }
1019
0
            }
1020
0
        }
1021
445
        else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL )
1022
0
              && ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
1023
0
        {
1024
0
            aL.eType = aR.eType = SbxDECIMAL;
1025
0
            bDecimal = true;
1026
0
            if( rOp.Get( aR ) && Get( aL ) )
1027
0
            {
1028
0
                if( aL.pDecimal && aR.pDecimal )
1029
0
                {
1030
0
                    bool bOk = true;
1031
0
                    switch( eOp )
1032
0
                    {
1033
0
                        case SbxMUL:
1034
0
                            bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
1035
0
                            break;
1036
0
                        case SbxDIV:
1037
0
                            if( aR.pDecimal->isZero() )
1038
0
                                SetError( ERRCODE_BASIC_ZERODIV );
1039
0
                            else
1040
0
                                bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
1041
0
                            break;
1042
0
                        case SbxPLUS:
1043
0
                            bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
1044
0
                            break;
1045
0
                        case SbxMINUS:
1046
0
                            bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
1047
0
                            break;
1048
0
                        case SbxNEG:
1049
0
                            bOk = ( aL.pDecimal->neg() );
1050
0
                            break;
1051
0
                        default:
1052
0
                            SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1053
0
                    }
1054
0
                    if( !bOk )
1055
0
                        SetError( ERRCODE_BASIC_MATH_OVERFLOW );
1056
0
                }
1057
0
                else
1058
0
                {
1059
0
                    SetError( ERRCODE_BASIC_CONVERSION );
1060
0
                }
1061
0
            }
1062
0
        }
1063
445
        else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
1064
0
        {
1065
0
            aL.eType = aR.eType = SbxCURRENCY;
1066
1067
0
            if (rOp.Get(aR) && Get(aL))
1068
0
            {
1069
0
                switch (eOp)
1070
0
                {
1071
0
                    case SbxMUL:
1072
0
                        aL.nInt64 = MulAndDiv(aL.nInt64, aR.nInt64, CURRENCY_FACTOR);
1073
0
                        break;
1074
1075
0
                    case SbxDIV:
1076
0
                        aL.nInt64 = MulAndDiv(aL.nInt64, CURRENCY_FACTOR, aR.nInt64);
1077
0
                        break;
1078
1079
0
                    case SbxPLUS:
1080
0
                        if (o3tl::checked_add(aL.nInt64, aR.nInt64, aL.nInt64))
1081
0
                            SetError(ERRCODE_BASIC_MATH_OVERFLOW);
1082
0
                        break;
1083
1084
0
                    case SbxNEG:
1085
                        // Use subtraction; allows to detect negation of SAL_MIN_INT64
1086
0
                        aR.nInt64 = std::exchange(aL.nInt64, 0);
1087
0
                        [[fallthrough]];
1088
0
                    case SbxMINUS:
1089
0
                        if (o3tl::checked_sub(aL.nInt64, aR.nInt64, aL.nInt64))
1090
0
                            SetError(ERRCODE_BASIC_MATH_OVERFLOW);
1091
0
                        break;
1092
1093
0
                    default:
1094
0
                        SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1095
0
                }
1096
0
            }
1097
0
        }
1098
445
        else
1099
890
Lbl_OpIsDouble:
1100
890
        {   // other types and operators including Date, Double and Single
1101
890
            aL.eType = aR.eType = SbxDOUBLE;
1102
890
            if( rOp.Get( aR ) )
1103
445
            {
1104
445
                if( Get( aL ) )
1105
445
                {
1106
445
                    switch( eOp )
1107
445
                    {
1108
0
                        case SbxEXP:
1109
0
                            aL.nDouble = pow( aL.nDouble, aR.nDouble );
1110
0
                            break;
1111
0
                        case SbxMUL:
1112
0
                            aL.nDouble *= aR.nDouble; break;
1113
0
                        case SbxDIV:
1114
0
                            if( !aR.nDouble ) SetError( ERRCODE_BASIC_ZERODIV );
1115
0
                            else aL.nDouble /= aR.nDouble;
1116
0
                            break;
1117
439
                        case SbxPLUS:
1118
439
                            aL.nDouble += aR.nDouble; break;
1119
6
                        case SbxMINUS:
1120
6
                            aL.nDouble -= aR.nDouble; break;
1121
0
                        case SbxNEG:
1122
0
                            aL.nDouble = -aL.nDouble; break;
1123
0
                        default:
1124
0
                            SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1125
445
                    }
1126
                    // Date with "+" or "-" needs special handling that
1127
                    // forces the Date type. If the operation is '+' the
1128
                    // result is always a Date, if '-' the result is only
1129
                    // a Date if one of lhs or rhs ( but not both ) is already
1130
                    // a Date
1131
445
                    if( GetType() == SbxDATE || rOp.GetType() == SbxDATE )
1132
0
                    {
1133
0
                        if( eOp == SbxPLUS  || ( ( eOp == SbxMINUS ) &&  ( GetType() != rOp.GetType() ) ) )
1134
0
                            aL.eType = SbxDATE;
1135
0
                    }
1136
1137
445
                }
1138
445
            }
1139
1140
890
        }
1141
445
        if( !IsError() )
1142
445
            Put( aL );
1143
445
        if( bDecimal )
1144
0
        {
1145
0
            releaseDecimalPtr( aL.pDecimal );
1146
0
            releaseDecimalPtr( aR.pDecimal );
1147
0
        }
1148
445
    }
1149
445
Lbl_OpIsEmpty:
1150
1151
445
    bool bRes = !IsError();
1152
445
    if( bRes && eOld != ERRCODE_NONE )
1153
0
        SetError( eOld );
1154
445
    return bRes;
1155
445
}
1156
1157
// The comparison routine deliver TRUE or FALSE.
1158
1159
template <typename T> static bool CompareNormal(const T& l, const T& r, SbxOperator eOp)
1160
0
{
1161
0
    switch (eOp)
1162
0
    {
1163
0
        case SbxEQ:
1164
0
            return l == r;
1165
0
        case SbxNE:
1166
0
            return l != r;
1167
0
        case SbxLT:
1168
0
            return l < r;
1169
0
        case SbxGT:
1170
0
            return l > r;
1171
0
        case SbxLE:
1172
0
            return l <= r;
1173
0
        case SbxGE:
1174
0
            return l >= r;
1175
0
        default:
1176
0
            assert(false);
1177
0
    }
1178
0
    SbxBase::SetError(ERRCODE_BASIC_BAD_ARGUMENT);
1179
0
    return false;
1180
0
}
Unexecuted instantiation: sbxvalue.cxx:bool CompareNormal<rtl::OUString>(rtl::OUString const&, rtl::OUString const&, SbxOperator)
Unexecuted instantiation: sbxvalue.cxx:bool CompareNormal<float>(float const&, float const&, SbxOperator)
Unexecuted instantiation: sbxvalue.cxx:bool CompareNormal<long>(long const&, long const&, SbxOperator)
Unexecuted instantiation: sbxvalue.cxx:bool CompareNormal<double>(double const&, double const&, SbxOperator)
1181
1182
bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
1183
0
{
1184
0
#if !HAVE_FEATURE_SCRIPTING
1185
0
    const bool bVBAInterop = false;
1186
#else
1187
    bool bVBAInterop =  SbiRuntime::isVBAEnabled();
1188
#endif
1189
1190
0
    bool bRes = false;
1191
0
    ErrCode eOld = GetError();
1192
0
    if( eOld != ERRCODE_NONE )
1193
0
        ResetError();
1194
0
    if( !CanRead() || !rOp.CanRead() )
1195
0
        SetError( ERRCODE_BASIC_PROP_WRITEONLY );
1196
0
    else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
1197
0
    {
1198
0
        bRes = true;
1199
0
    }
1200
0
    else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
1201
0
        bRes = !bVBAInterop || ( eOp == SbxEQ );
1202
    // Special rule 1: If an operand is null, the result is FALSE
1203
0
    else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
1204
0
        bRes = false;
1205
    // Special rule 2: If both are variant and one is numeric
1206
    // and the other is a String, num is < str
1207
0
    else if( !IsFixed() && !rOp.IsFixed()
1208
0
     && ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
1209
0
    )
1210
0
        bRes = eOp == SbxLT || eOp == SbxLE || eOp == SbxNE;
1211
0
    else if( !IsFixed() && !rOp.IsFixed()
1212
0
     && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
1213
0
&& !bVBAInterop
1214
0
    )
1215
0
        bRes = eOp == SbxGT || eOp == SbxGE || eOp == SbxNE;
1216
0
    else
1217
0
    {
1218
0
        SbxValues aL, aR;
1219
        // If one of the operands is a String,
1220
        // a String comparing take place
1221
0
        if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
1222
0
        {
1223
0
            aL.eType = aR.eType = SbxSTRING;
1224
0
            if (Get(aL) && rOp.Get(aR))
1225
0
                bRes = CompareNormal(*aL.pOUString, *aR.pOUString, eOp);
1226
0
        }
1227
        // From 1995-12-19: If SbxSINGLE participate, then convert to SINGLE,
1228
        //              otherwise it shows a numeric error
1229
0
        else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
1230
0
        {
1231
0
            aL.eType = aR.eType = SbxSINGLE;
1232
0
            if( Get( aL ) && rOp.Get( aR ) )
1233
0
                bRes = CompareNormal(aL.nSingle, aR.nSingle, eOp);
1234
0
        }
1235
0
        else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
1236
0
        {
1237
0
            aL.eType = aR.eType = SbxDECIMAL;
1238
0
            Get( aL );
1239
0
            rOp.Get( aR );
1240
0
            if( aL.pDecimal && aR.pDecimal )
1241
0
            {
1242
0
                SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
1243
0
                switch( eOp )
1244
0
                {
1245
0
                    case SbxEQ:
1246
0
                        bRes = ( eRes == SbxDecimal::CmpResult::EQ ); break;
1247
0
                    case SbxNE:
1248
0
                        bRes = ( eRes != SbxDecimal::CmpResult::EQ ); break;
1249
0
                    case SbxLT:
1250
0
                        bRes = ( eRes == SbxDecimal::CmpResult::LT ); break;
1251
0
                    case SbxGT:
1252
0
                        bRes = ( eRes == SbxDecimal::CmpResult::GT ); break;
1253
0
                    case SbxLE:
1254
0
                        bRes = ( eRes != SbxDecimal::CmpResult::GT ); break;
1255
0
                    case SbxGE:
1256
0
                        bRes = ( eRes != SbxDecimal::CmpResult::LT ); break;
1257
0
                    default:
1258
0
                        SetError( ERRCODE_BASIC_BAD_ARGUMENT );
1259
0
                }
1260
0
            }
1261
0
            else
1262
0
            {
1263
0
                SetError( ERRCODE_BASIC_CONVERSION );
1264
0
            }
1265
0
            releaseDecimalPtr( aL.pDecimal );
1266
0
            releaseDecimalPtr( aR.pDecimal );
1267
0
        }
1268
0
        else if (GetType() == SbxCURRENCY && rOp.GetType() == SbxCURRENCY)
1269
0
        {
1270
0
            aL.eType = aR.eType = GetType();
1271
0
            if (Get(aL) && rOp.Get(aR))
1272
0
                bRes = CompareNormal(aL.nInt64, aR.nInt64, eOp);
1273
0
        }
1274
        // Everything else comparing on a SbxDOUBLE-Basis
1275
0
        else
1276
0
        {
1277
0
            aL.eType = aR.eType = SbxDOUBLE;
1278
0
            bool bGetL = Get( aL );
1279
0
            bool bGetR = rOp.Get( aR );
1280
0
            if( bGetL && bGetR )
1281
0
                bRes = CompareNormal(aL.nDouble, aR.nDouble, eOp);
1282
            // at least one value was got
1283
            // if this is VBA then a conversion error for one
1284
            // side will yield a false result of an equality test
1285
0
            else if ( bGetR || bGetL )
1286
0
            {
1287
0
                if ( bVBAInterop && eOp == SbxEQ && GetError() == ERRCODE_BASIC_CONVERSION )
1288
0
                {
1289
0
#ifndef IOS
1290
0
                    ResetError();
1291
0
                    bRes = false;
1292
0
#endif
1293
0
                }
1294
0
            }
1295
0
        }
1296
0
    }
1297
0
    if( eOld != ERRCODE_NONE )
1298
0
        SetError( eOld );
1299
0
    return bRes;
1300
0
}
1301
1302
///////////////////////////// Reading/Writing
1303
1304
bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
1305
0
{
1306
    // #TODO see if these types are really dumped to any stream
1307
    // more than likely this is functionality used in the binfilter alone
1308
0
    SbxValue::Clear();
1309
0
    sal_uInt16 nType;
1310
0
    r.ReadUInt16( nType );
1311
0
    aData.eType = SbxDataType( nType );
1312
0
    switch( nType )
1313
0
    {
1314
0
        case SbxBOOL:
1315
0
        case SbxINTEGER:
1316
0
            r.ReadInt16( aData.nInteger ); break;
1317
0
        case SbxLONG:
1318
0
        case SbxDATAOBJECT:
1319
0
            r.ReadInt32( aData.nLong );
1320
0
            break;
1321
0
        case SbxSINGLE:
1322
0
        {
1323
            // Floats as ASCII
1324
0
            OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1325
0
                RTL_TEXTENCODING_ASCII_US);
1326
0
            double d;
1327
0
            SbxDataType t;
1328
0
            if( ImpScan( aVal, d, t, nullptr ) != ERRCODE_NONE || t == SbxDOUBLE )
1329
0
            {
1330
0
                aData.nSingle = 0.0F;
1331
0
                return false;
1332
0
            }
1333
0
            aData.nSingle = static_cast<float>(d);
1334
0
            break;
1335
0
        }
1336
0
        case SbxDATE:
1337
0
        case SbxDOUBLE:
1338
0
        {
1339
            // Floats as ASCII
1340
0
            OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1341
0
                RTL_TEXTENCODING_ASCII_US);
1342
0
            SbxDataType t;
1343
0
            if( ImpScan( aVal, aData.nDouble, t, nullptr ) != ERRCODE_NONE )
1344
0
            {
1345
0
                aData.nDouble = 0.0;
1346
0
                return false;
1347
0
            }
1348
0
            break;
1349
0
        }
1350
0
        case SbxSALINT64:
1351
0
            r.ReadInt64(aData.nInt64);
1352
0
            break;
1353
0
        case SbxSALUINT64:
1354
0
            r.ReadUInt64( aData.uInt64 );
1355
0
            break;
1356
0
        case SbxCURRENCY:
1357
0
        {
1358
0
            sal_uInt32 tmpHi = 0;
1359
0
            sal_uInt32 tmpLo = 0;
1360
0
            r.ReadUInt32( tmpHi ).ReadUInt32( tmpLo );
1361
0
            aData.nInt64 = (static_cast<sal_Int64>(tmpHi) << 32);
1362
0
            aData.nInt64 |= static_cast<sal_Int64>(tmpLo);
1363
0
            break;
1364
0
        }
1365
0
        case SbxSTRING:
1366
0
        {
1367
0
            OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1368
0
                RTL_TEXTENCODING_ASCII_US);
1369
0
            if( !aVal.isEmpty() )
1370
0
                aData.pOUString = new OUString( aVal );
1371
0
            else
1372
0
                aData.pOUString = nullptr; // JSM 1995-09-22
1373
0
            break;
1374
0
        }
1375
0
        case SbxERROR:
1376
0
        case SbxUSHORT:
1377
0
            r.ReadUInt16( aData.nUShort ); break;
1378
0
        case SbxOBJECT:
1379
0
        {
1380
0
            sal_uInt8 nMode;
1381
0
            r.ReadUChar( nMode );
1382
0
            switch( nMode )
1383
0
            {
1384
0
                case 0:
1385
0
                    aData.pObj = nullptr;
1386
0
                    break;
1387
0
                case 1:
1388
0
                {
1389
0
                    auto ref = SbxBase::Load( r );
1390
0
                    aData.pObj = ref.get();
1391
                    // if necessary increment Ref-Count
1392
0
                    if (aData.pObj)
1393
0
                        aData.pObj->AddFirstRef();
1394
0
                    return ( aData.pObj != nullptr );
1395
0
                }
1396
0
                case 2:
1397
0
                    aData.pObj = this;
1398
0
                    break;
1399
0
            }
1400
0
            break;
1401
0
        }
1402
0
        case SbxCHAR:
1403
0
        {
1404
0
            char c;
1405
0
            r.ReadChar( c );
1406
0
            aData.nChar = c;
1407
0
            break;
1408
0
        }
1409
0
        case SbxBYTE:
1410
0
            r.ReadUChar( aData.nByte ); break;
1411
0
        case SbxULONG:
1412
0
            r.ReadUInt32( aData.nULong ); break;
1413
0
        case SbxINT:
1414
0
        {
1415
0
            sal_uInt8 n;
1416
0
            r.ReadUChar( n );
1417
            // Match the Int on this system?
1418
0
            if( n > SAL_TYPES_SIZEOFINT )
1419
0
            {
1420
0
                r.ReadInt32( aData.nLong );
1421
0
                aData.eType = SbxLONG;
1422
0
            }
1423
0
            else {
1424
0
                sal_Int32 nInt;
1425
0
                r.ReadInt32( nInt );
1426
0
                aData.nInt = nInt;
1427
0
            }
1428
0
            break;
1429
0
        }
1430
0
        case SbxUINT:
1431
0
        {
1432
0
            sal_uInt8 n;
1433
0
            r.ReadUChar( n );
1434
            // Match the UInt on this system?
1435
0
            if( n > SAL_TYPES_SIZEOFINT )
1436
0
            {
1437
0
                r.ReadUInt32( aData.nULong );
1438
0
                aData.eType = SbxULONG;
1439
0
            }
1440
0
            else {
1441
0
                sal_uInt32 nUInt;
1442
0
                r.ReadUInt32( nUInt );
1443
0
                aData.nUInt = nUInt;
1444
0
            }
1445
0
            break;
1446
0
        }
1447
0
        case SbxEMPTY:
1448
0
        case SbxNULL:
1449
0
        case SbxVOID:
1450
0
            break;
1451
        // #78919 For backwards compatibility
1452
0
        case SbxWSTRING:
1453
0
        case SbxWCHAR:
1454
0
            break;
1455
0
        default:
1456
0
            aData.clear(SbxNULL);
1457
0
            ResetFlag(SbxFlagBits::Fixed);
1458
0
            SAL_WARN( "basic.sbx", "Loaded a non-supported data type" );
1459
1460
0
            return false;
1461
0
    }
1462
0
    return true;
1463
0
}
1464
1465
    std::pair<bool, sal_uInt32> SbxValue::StoreData( SvStream& r ) const
1466
0
    {
1467
0
        sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
1468
0
        r.WriteUInt16( nType );
1469
0
        switch( nType & 0x0FFF )
1470
0
        {
1471
0
            case SbxBOOL:
1472
0
            case SbxINTEGER:
1473
0
                r.WriteInt16( aData.nInteger ); break;
1474
0
            case SbxLONG:
1475
0
            case SbxDATAOBJECT:
1476
0
                r.WriteInt32( aData.nLong );
1477
0
                break;
1478
0
            case SbxDATE:
1479
                // #49935: Save as double, otherwise an error during the read in
1480
0
                const_cast<SbxValue*>(this)->aData.eType = static_cast<SbxDataType>( ( nType & 0xF000 ) | SbxDOUBLE );
1481
0
                write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1482
0
                const_cast<SbxValue*>(this)->aData.eType = static_cast<SbxDataType>(nType);
1483
0
                break;
1484
0
            case SbxSINGLE:
1485
0
            case SbxDOUBLE:
1486
0
                write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1487
0
                break;
1488
0
            case SbxSALUINT64:
1489
0
            case SbxSALINT64:
1490
                // see comment in SbxValue::StoreData
1491
0
                r.WriteUInt64( aData.uInt64 );
1492
0
                break;
1493
0
            case SbxCURRENCY:
1494
0
            {
1495
0
                sal_Int32 tmpHi = ( (aData.nInt64 >> 32) &  0xFFFFFFFF );
1496
0
                sal_Int32 tmpLo = static_cast<sal_Int32>(aData.nInt64);
1497
0
                r.WriteInt32( tmpHi ).WriteInt32( tmpLo );
1498
0
                break;
1499
0
            }
1500
0
            case SbxSTRING:
1501
0
                if( aData.pOUString )
1502
0
                {
1503
0
                    write_uInt16_lenPrefixed_uInt8s_FromOUString(r, *aData.pOUString, RTL_TEXTENCODING_ASCII_US);
1504
0
                }
1505
0
                else
1506
0
                {
1507
0
                    write_uInt16_lenPrefixed_uInt8s_FromOUString(r, std::u16string_view(), RTL_TEXTENCODING_ASCII_US);
1508
0
            }
1509
0
            break;
1510
0
            case SbxERROR:
1511
0
            case SbxUSHORT:
1512
0
                r.WriteUInt16( aData.nUShort ); break;
1513
0
            case SbxOBJECT:
1514
                // to save itself as Objectptr does not work!
1515
0
                if( aData.pObj )
1516
0
                {
1517
0
                    if( dynamic_cast<SbxValue*>( aData.pObj) != this  )
1518
0
                    {
1519
0
                        r.WriteUChar( 1 );
1520
0
                        return aData.pObj->Store( r );
1521
0
                    }
1522
0
                    else
1523
0
                        r.WriteUChar( 2 );
1524
0
                }
1525
0
                else
1526
0
                    r.WriteUChar( 0 );
1527
0
                break;
1528
0
            case SbxCHAR:
1529
0
            {
1530
0
                char c = sal::static_int_cast< char >(aData.nChar);
1531
0
                r.WriteChar( c );
1532
0
                break;
1533
0
            }
1534
0
            case SbxBYTE:
1535
0
                r.WriteUChar( aData.nByte ); break;
1536
0
            case SbxULONG:
1537
0
                r.WriteUInt32( aData.nULong ); break;
1538
0
            case SbxINT:
1539
0
            {
1540
0
                r.WriteUChar( SAL_TYPES_SIZEOFINT ).WriteInt32( aData.nInt );
1541
0
                break;
1542
0
            }
1543
0
            case SbxUINT:
1544
0
            {
1545
0
                r.WriteUChar( SAL_TYPES_SIZEOFINT ).WriteUInt32( aData.nUInt );
1546
0
                break;
1547
0
            }
1548
0
            case SbxEMPTY:
1549
0
            case SbxNULL:
1550
0
            case SbxVOID:
1551
0
                break;
1552
            // #78919 For backwards compatibility
1553
0
            case SbxWSTRING:
1554
0
            case SbxWCHAR:
1555
0
                break;
1556
0
            default:
1557
0
                SAL_WARN( "basic.sbx", "Saving a non-supported data type" );
1558
0
                return { false, 0 };
1559
0
        }
1560
0
        return { true, B_IMG_VERSION_12 };
1561
0
    }
1562
1563
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */