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