bump product version to 5.0.4.1
[LibreOffice.git] / basic / source / sbx / sbxvalue.cxx
blob4511a3fc87ffe9874f998756d0fb66d70365985e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_features.h>
22 #include <math.h>
23 #include <tools/debug.hxx>
24 #include <tools/stream.hxx>
26 #include <basic/sbx.hxx>
27 #include "sbunoobj.hxx"
28 #include "sbxconv.hxx"
29 #include "runtime.hxx"
31 TYPEINIT1(SbxValue,SbxBase)
33 ///////////////////////////// constructors
35 SbxValue::SbxValue() : SbxBase()
37 aData.eType = SbxEMPTY;
40 SbxValue::SbxValue( SbxDataType t, void* p ) : SbxBase()
42 int n = t & 0x0FFF;
43 if( p )
44 n |= SbxBYREF;
45 if( n == SbxVARIANT )
46 n = SbxEMPTY;
47 else
48 SetFlag( SBX_FIXED );
49 if( p )
51 switch( t & 0x0FFF )
53 case SbxINTEGER: n |= SbxBYREF; aData.pInteger = static_cast<sal_Int16*>(p); break;
54 case SbxSALUINT64: n |= SbxBYREF; aData.puInt64 = static_cast<sal_uInt64*>(p); break;
55 case SbxSALINT64:
56 case SbxCURRENCY: n |= SbxBYREF; aData.pnInt64 = static_cast<sal_Int64*>(p); break;
57 case SbxLONG: n |= SbxBYREF; aData.pLong = static_cast<sal_Int32*>(p); break;
58 case SbxSINGLE: n |= SbxBYREF; aData.pSingle = static_cast<float*>(p); break;
59 case SbxDATE:
60 case SbxDOUBLE: n |= SbxBYREF; aData.pDouble = static_cast<double*>(p); break;
61 case SbxSTRING: n |= SbxBYREF; aData.pOUString = static_cast<OUString*>(p); break;
62 case SbxERROR:
63 case SbxUSHORT:
64 case SbxBOOL: n |= SbxBYREF; aData.pUShort = static_cast<sal_uInt16*>(p); break;
65 case SbxULONG: n |= SbxBYREF; aData.pULong = static_cast<sal_uInt32*>(p); break;
66 case SbxCHAR: n |= SbxBYREF; aData.pChar = static_cast<sal_Unicode*>(p); break;
67 case SbxBYTE: n |= SbxBYREF; aData.pByte = static_cast<sal_uInt8*>(p); break;
68 case SbxINT: n |= SbxBYREF; aData.pInt = static_cast<int*>(p); break;
69 case SbxOBJECT:
70 aData.pObj = static_cast<SbxBase*>(p);
71 if( p )
72 aData.pObj->AddFirstRef();
73 break;
74 case SbxDECIMAL:
75 aData.pDecimal = static_cast<SbxDecimal*>(p);
76 if( p )
77 aData.pDecimal->addRef();
78 break;
79 default:
80 DBG_ASSERT( false, "Improper pointer argument" );
81 n = SbxNULL;
84 else
85 memset( &aData, 0, sizeof( SbxValues ) );
86 aData.eType = SbxDataType( n );
89 SbxValue::SbxValue( const SbxValue& r )
90 : SvRefBase( r ), SbxBase( r )
92 if( !r.CanRead() )
94 SetError( SbxERR_PROP_WRITEONLY );
95 if( !IsFixed() )
96 aData.eType = SbxNULL;
98 else
100 const_cast<SbxValue*>(&r)->Broadcast( SBX_HINT_DATAWANTED );
101 aData = r.aData;
102 // Copy pointer, increment references
103 switch( aData.eType )
105 case SbxSTRING:
106 if( aData.pOUString )
107 aData.pOUString = new OUString( *aData.pOUString );
108 break;
109 case SbxOBJECT:
110 if( aData.pObj )
111 aData.pObj->AddFirstRef();
112 break;
113 case SbxDECIMAL:
114 if( aData.pDecimal )
115 aData.pDecimal->addRef();
116 break;
117 default: break;
122 SbxValue& SbxValue::operator=( const SbxValue& r )
124 if( &r != this )
126 if( !CanWrite() )
127 SetError( SbxERR_PROP_READONLY );
128 else
130 // string -> byte array
131 if( IsFixed() && (aData.eType == SbxOBJECT)
132 && aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
133 && (r.aData.eType == SbxSTRING) )
135 OUString aStr = r.GetOUString();
136 SbxArray* pArr = StringToByteArray(aStr);
137 PutObject(pArr);
138 return *this;
140 // byte array -> string
141 if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
142 && r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
143 && (aData.eType == SbxSTRING) )
145 SbxBase* pObj = r.GetObject();
146 SbxArray* pArr = PTR_CAST(SbxArray, pObj);
147 if( pArr )
149 OUString aStr = ByteArrayToString( pArr );
150 PutString(aStr);
151 return *this;
154 // Readout the content of the variables
155 SbxValues aNew;
156 if( IsFixed() )
157 // then the type has to match
158 aNew.eType = aData.eType;
159 else if( r.IsFixed() )
160 // Source fixed: copy the type
161 aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
162 else
163 // both variant: then don't care
164 aNew.eType = SbxVARIANT;
165 if( r.Get( aNew ) )
166 Put( aNew );
169 return *this;
172 SbxValue::~SbxValue()
174 Broadcast( SBX_HINT_DYING );
175 SetFlag( SBX_WRITE );
176 SbxValue::Clear();
179 void SbxValue::Clear()
181 switch( aData.eType )
183 case SbxNULL:
184 case SbxEMPTY:
185 case SbxVOID:
186 break;
187 case SbxSTRING:
188 delete aData.pOUString; aData.pOUString = NULL;
189 break;
190 case SbxOBJECT:
191 if( aData.pObj )
193 if( aData.pObj != this )
195 SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
196 SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
197 bool bParentProp = pThisVar && 5345 ==
198 ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
199 if ( !bParentProp )
200 aData.pObj->ReleaseRef();
202 aData.pObj = NULL;
204 break;
205 case SbxDECIMAL:
206 if( aData.eType == SbxDECIMAL )
207 releaseDecimalPtr( aData.pDecimal );
208 break;
209 case SbxDATAOBJECT:
210 aData.pData = NULL; break;
211 default:
213 SbxValues aEmpty;
214 memset( &aEmpty, 0, sizeof( SbxValues ) );
215 aEmpty.eType = GetType();
216 Put( aEmpty );
221 // Dummy
223 void SbxValue::Broadcast( sal_uIntPtr )
226 //////////////////////////// Readout data
228 // Detect the "right" variables. If it is an object, will be addressed either
229 // the object itself or its default property.
230 // If the variable contain a variable or an object, this will be
231 // addressed.
233 SbxValue* SbxValue::TheRealValue() const
235 return TheRealValue( true );
238 SbxValue* SbxValue::TheRealValue( bool bObjInObjError ) const
240 SbxValue* p = const_cast<SbxValue*>(this);
241 for( ;; )
243 SbxDataType t = SbxDataType( p->aData.eType & 0x0FFF );
244 if( t == SbxOBJECT )
246 // The block contains an object or a variable
247 SbxObject* pObj = PTR_CAST(SbxObject,p->aData.pObj);
248 if( pObj )
250 // Has the object a default property?
251 SbxVariable* pDflt = pObj->GetDfltProperty();
253 // If this is an object and contains itself,
254 // we cannot access on it
255 // The old condition to set an error is not correct,
256 // because e.g. a regular variant variable with an object
257 // could be affected if another value should be assigned.
258 // Therefore with flag.
259 if( bObjInObjError && !pDflt &&
260 ((SbxValue*) pObj)->aData.eType == SbxOBJECT &&
261 ((SbxValue*) pObj)->aData.pObj == pObj )
263 #if !HAVE_FEATURE_SCRIPTING
264 const bool bSuccess = false;
265 #else
266 bool bSuccess = handleToStringForCOMObjects( pObj, p );
267 #endif
268 if( !bSuccess )
270 SetError( SbxERR_BAD_PROP_VALUE );
271 p = NULL;
274 else if( pDflt )
275 p = pDflt;
276 break;
278 // Did we have an array?
279 SbxArray* pArray = PTR_CAST(SbxArray,p->aData.pObj);
280 if( pArray )
282 // When indicated get the parameter
283 SbxArray* pPar = NULL;
284 SbxVariable* pVar = PTR_CAST(SbxVariable,p);
285 if( pVar )
286 pPar = pVar->GetParameters();
287 if( pPar )
289 // Did we have a dimensioned array?
290 SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,p->aData.pObj);
291 if( pDimArray )
292 p = pDimArray->Get( pPar );
293 else
294 p = pArray->Get( pPar->Get( 1 )->GetInteger() );
295 break;
298 // Otherwise guess a SbxValue
299 SbxValue* pVal = PTR_CAST(SbxValue,p->aData.pObj);
300 if( pVal )
301 p = pVal;
302 else
303 break;
305 else
306 break;
308 return p;
311 bool SbxValue::Get( SbxValues& rRes ) const
313 bool bRes = false;
314 SbxError eOld = GetError();
315 if( eOld != SbxERR_OK )
316 ResetError();
317 if( !CanRead() )
319 SetError( SbxERR_PROP_WRITEONLY );
320 rRes.pObj = NULL;
322 else
324 // If an object or a VARIANT is requested, don't search the real values
325 SbxValue* p = const_cast<SbxValue*>(this);
326 if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
327 p = TheRealValue();
328 if( p )
330 p->Broadcast( SBX_HINT_DATAWANTED );
331 switch( rRes.eType )
333 case SbxEMPTY:
334 case SbxVOID:
335 case SbxNULL: break;
336 case SbxVARIANT: rRes = p->aData; break;
337 case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
338 case SbxLONG: rRes.nLong = ImpGetLong( &p->aData ); break;
339 case SbxSALINT64: rRes.nInt64 = ImpGetInt64( &p->aData ); break;
340 case SbxSALUINT64: rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
341 case SbxSINGLE: rRes.nSingle = ImpGetSingle( &p->aData ); break;
342 case SbxDOUBLE: rRes.nDouble = ImpGetDouble( &p->aData ); break;
343 case SbxCURRENCY:rRes.nInt64 = ImpGetCurrency( &p->aData ); break;
344 case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
345 case SbxDATE: rRes.nDouble = ImpGetDate( &p->aData ); break;
346 case SbxBOOL:
347 rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
348 ImpGetBool( &p->aData ) );
349 break;
350 case SbxCHAR: rRes.nChar = ImpGetChar( &p->aData ); break;
351 case SbxBYTE: rRes.nByte = ImpGetByte( &p->aData ); break;
352 case SbxUSHORT: rRes.nUShort = ImpGetUShort( &p->aData ); break;
353 case SbxULONG: rRes.nULong = ImpGetULong( &p->aData ); break;
354 case SbxLPSTR:
355 case SbxSTRING: p->aPic = ImpGetString( &p->aData );
356 rRes.pOUString = &p->aPic; break;
357 case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
358 rRes.pOUString = &p->aPic; break;
359 case SbxINT:
360 #if SAL_TYPES_SIZEOFINT == 2
361 rRes.nInt = (int) ImpGetInteger( &p->aData );
362 #else
363 rRes.nInt = (int) ImpGetLong( &p->aData );
364 #endif
365 break;
366 case SbxUINT:
367 #if SAL_TYPES_SIZEOFINT == 2
368 rRes.nUInt = (int) ImpGetUShort( &p->aData );
369 #else
370 rRes.nUInt = (int) ImpGetULong( &p->aData );
371 #endif
372 break;
373 case SbxOBJECT:
374 if( p->aData.eType == SbxOBJECT )
375 rRes.pObj = p->aData.pObj;
376 else
378 SetError( SbxERR_NO_OBJECT );
379 rRes.pObj = NULL;
381 break;
382 default:
383 if( p->aData.eType == rRes.eType )
384 rRes = p->aData;
385 else
387 SetError( SbxERR_CONVERSION );
388 rRes.pObj = NULL;
392 else
394 // Object contained itself
395 SbxDataType eTemp = rRes.eType;
396 memset( &rRes, 0, sizeof( SbxValues ) );
397 rRes.eType = eTemp;
400 if( !IsError() )
402 bRes = true;
403 if( eOld != SbxERR_OK )
404 SetError( eOld );
406 return bRes;
409 const OUString& SbxValue::GetCoreString() const
411 SbxValues aRes;
412 aRes.eType = SbxCoreSTRING;
413 if( Get( aRes ) )
415 const_cast<SbxValue*>(this)->aToolString = *aRes.pOUString;
417 else
419 const_cast<SbxValue*>(this)->aToolString.clear();
421 return aToolString;
424 OUString SbxValue::GetOUString() const
426 OUString aResult;
427 SbxValues aRes;
428 aRes.eType = SbxSTRING;
429 if( Get( aRes ) )
431 aResult = *aRes.pOUString;
433 return aResult;
436 bool SbxValue::GetBool() const
438 SbxValues aRes;
439 aRes.eType = SbxBOOL;
440 Get( aRes );
441 return aRes.nUShort != 0;
444 #define GET( g, e, t, m ) \
445 t SbxValue::g() const { SbxValues aRes(e); Get( aRes ); return aRes.m; }
447 GET( GetByte, SbxBYTE, sal_uInt8, nByte )
448 GET( GetChar, SbxCHAR, sal_Unicode, nChar )
449 GET( GetCurrency, SbxCURRENCY, sal_Int64, nInt64 )
450 GET( GetDate, SbxDATE, double, nDouble )
451 GET( GetDouble, SbxDOUBLE, double, nDouble )
452 GET( GetInteger, SbxINTEGER, sal_Int16, nInteger )
453 GET( GetLong, SbxLONG, sal_Int32, nLong )
454 GET( GetObject, SbxOBJECT, SbxBase*, pObj )
455 GET( GetSingle, SbxSINGLE, float, nSingle )
456 GET( GetULong, SbxULONG, sal_uInt32, nULong )
457 GET( GetUShort, SbxUSHORT, sal_uInt16, nUShort )
458 GET( GetInt64, SbxSALINT64, sal_Int64, nInt64 )
459 GET( GetUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
460 GET( GetDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
463 //////////////////////////// Write data
465 bool SbxValue::Put( const SbxValues& rVal )
467 bool bRes = false;
468 SbxError eOld = GetError();
469 if( eOld != SbxERR_OK )
470 ResetError();
471 if( !CanWrite() )
472 SetError( SbxERR_PROP_READONLY );
473 else if( rVal.eType & 0xF000 )
474 SetError( SbxERR_NOTIMP );
475 else
477 // If an object is requested, don't search the real values
478 SbxValue* p = this;
479 if( rVal.eType != SbxOBJECT )
480 p = TheRealValue( false ); // Don't allow an error here
481 if( p )
483 if( !p->CanWrite() )
484 SetError( SbxERR_PROP_READONLY );
485 else if( p->IsFixed() || p->SetType( (SbxDataType) ( rVal.eType & 0x0FFF ) ) )
486 switch( rVal.eType & 0x0FFF )
488 case SbxEMPTY:
489 case SbxVOID:
490 case SbxNULL: break;
491 case SbxINTEGER: ImpPutInteger( &p->aData, rVal.nInteger ); break;
492 case SbxLONG: ImpPutLong( &p->aData, rVal.nLong ); break;
493 case SbxSALINT64: ImpPutInt64( &p->aData, rVal.nInt64 ); break;
494 case SbxSALUINT64: ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
495 case SbxSINGLE: ImpPutSingle( &p->aData, rVal.nSingle ); break;
496 case SbxDOUBLE: ImpPutDouble( &p->aData, rVal.nDouble ); break;
497 case SbxCURRENCY: ImpPutCurrency( &p->aData, rVal.nInt64 ); break;
498 case SbxDECIMAL: ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
499 case SbxDATE: ImpPutDate( &p->aData, rVal.nDouble ); break;
500 case SbxBOOL: ImpPutBool( &p->aData, rVal.nInteger ); break;
501 case SbxCHAR: ImpPutChar( &p->aData, rVal.nChar ); break;
502 case SbxBYTE: ImpPutByte( &p->aData, rVal.nByte ); break;
503 case SbxUSHORT: ImpPutUShort( &p->aData, rVal.nUShort ); break;
504 case SbxULONG: ImpPutULong( &p->aData, rVal.nULong ); break;
505 case SbxLPSTR:
506 case SbxSTRING: ImpPutString( &p->aData, rVal.pOUString ); break;
507 case SbxINT:
508 #if SAL_TYPES_SIZEOFINT == 2
509 ImpPutInteger( &p->aData, (sal_Int16) rVal.nInt );
510 #else
511 ImpPutLong( &p->aData, (sal_Int32) rVal.nInt );
512 #endif
513 break;
514 case SbxUINT:
515 #if SAL_TYPES_SIZEOFINT == 2
516 ImpPutUShort( &p->aData, (sal_uInt16) rVal.nUInt );
517 #else
518 ImpPutULong( &p->aData, (sal_uInt32) rVal.nUInt );
519 #endif
520 break;
521 case SbxOBJECT:
522 if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
524 // is already inside
525 if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
526 break;
528 // Delete only the value part!
529 p->SbxValue::Clear();
531 // real assignment
532 p->aData.pObj = rVal.pObj;
534 // if necessary increment Ref-Count
535 if( p->aData.pObj && p->aData.pObj != p )
537 if ( p != this )
539 OSL_FAIL( "TheRealValue" );
541 SAL_INFO("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
542 SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
543 bool bParentProp = pThisVar && 5345 ==
544 ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
545 if ( !bParentProp )
546 p->aData.pObj->AddFirstRef();
549 else
550 SetError( SbxERR_CONVERSION );
551 break;
552 default:
553 if( p->aData.eType == rVal.eType )
554 p->aData = rVal;
555 else
557 SetError( SbxERR_CONVERSION );
558 if( !p->IsFixed() )
559 p->aData.eType = SbxNULL;
562 if( !IsError() )
564 p->SetModified( true );
565 p->Broadcast( SBX_HINT_DATACHANGED );
566 if( eOld != SbxERR_OK )
567 SetError( eOld );
568 bRes = true;
572 return bRes;
575 // From 1996-03-28:
576 // Method to execute a pretreatment of the strings at special types.
577 // In particular necessary for BASIC-IDE, so that
578 // the output in the Watch-Window can be written back with PutStringExt,
579 // if Float were declared with ',' as the decimal separator or BOOl
580 // explicit with "TRUE" or "FALSE".
581 // Implementation in ImpConvStringExt (SBXSCAN.CXX)
582 bool SbxValue::PutStringExt( const OUString& r )
584 // Copy; if it is Unicode convert it immediately
585 OUString aStr( r );
587 // Identify the own type (not as in Put() with TheRealValue(),
588 // Objects are not handled anyway)
589 SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
591 // tinker a Source-Value
592 SbxValues aRes;
593 aRes.eType = SbxSTRING;
595 // Only if really something was converted, take the copy,
596 // otherwise take the original (Unicode remains)
597 bool bRet;
598 if( ImpConvStringExt( aStr, eTargetType ) )
599 aRes.pOUString = &aStr;
600 else
601 aRes.pOUString = const_cast<OUString*>(&r);
603 // #34939: For Strings which contain a number, and if this has a Num-Type,
604 // set a Fixed flag so that the type will not be changed
605 SbxFlagBits nFlags_ = GetFlags();
606 if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
607 ( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
608 eTargetType == SbxBOOL )
610 SbxValue aVal;
611 aVal.Put( aRes );
612 if( aVal.IsNumeric() )
613 SetFlag( SBX_FIXED );
616 Put( aRes );
617 bRet = bool( !IsError() );
619 // If FIXED resulted in an error, set it back
620 // (UI-Action should not result in an error, but simply fail)
621 if( !bRet )
622 ResetError();
624 SetFlags( nFlags_ );
625 return bRet;
628 bool SbxValue::PutBool( bool b )
630 SbxValues aRes;
631 aRes.eType = SbxBOOL;
632 aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
633 Put( aRes );
634 return !IsError();
637 bool SbxValue::PutEmpty()
639 bool bRet = SetType( SbxEMPTY );
640 SetModified( true );
641 return bRet;
644 bool SbxValue::PutNull()
646 bool bRet = SetType( SbxNULL );
647 if( bRet )
648 SetModified( true );
649 return bRet;
653 // Special decimal methods
654 bool SbxValue::PutDecimal( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec )
656 SbxValue::Clear();
657 aData.pDecimal = new SbxDecimal( rAutomationDec );
658 aData.pDecimal->addRef();
659 aData.eType = SbxDECIMAL;
660 return true;
663 bool SbxValue::fillAutomationDecimal
664 ( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ) const
666 SbxDecimal* pDecimal = GetDecimal();
667 if( pDecimal != NULL )
669 pDecimal->fillAutomationDecimal( rAutomationDec );
670 return true;
672 return false;
676 bool SbxValue::PutString( const OUString& r )
678 SbxValues aRes;
679 aRes.eType = SbxSTRING;
680 aRes.pOUString = const_cast<OUString*>(&r);
681 Put( aRes );
682 return !IsError();
686 #define PUT( p, e, t, m ) \
687 bool SbxValue::p( t n ) \
688 { SbxValues aRes(e); aRes.m = n; Put( aRes ); return !IsError(); }
690 PUT( PutByte, SbxBYTE, sal_uInt8, nByte )
691 PUT( PutChar, SbxCHAR, sal_Unicode, nChar )
692 PUT( PutCurrency, SbxCURRENCY, const sal_Int64&, nInt64 )
693 PUT( PutDate, SbxDATE, double, nDouble )
694 PUT( PutDouble, SbxDOUBLE, double, nDouble )
695 PUT( PutErr, SbxERROR, sal_uInt16, nUShort )
696 PUT( PutInteger, SbxINTEGER, sal_Int16, nInteger )
697 PUT( PutLong, SbxLONG, sal_Int32, nLong )
698 PUT( PutObject, SbxOBJECT, SbxBase*, pObj )
699 PUT( PutSingle, SbxSINGLE, float, nSingle )
700 PUT( PutULong, SbxULONG, sal_uInt32, nULong )
701 PUT( PutUShort, SbxUSHORT, sal_uInt16, nUShort )
702 PUT( PutInt64, SbxSALINT64, sal_Int64, nInt64 )
703 PUT( PutUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
704 PUT( PutDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
706 ////////////////////////// Setting of the data type
708 bool SbxValue::IsFixed() const
710 return ((GetFlags() & SBX_FIXED) != SBX_NONE) || ((aData.eType & SbxBYREF) != 0);
713 // A variable is numeric, if it is EMPTY or really numeric
714 // or if it contains a complete convertible String
716 // #41692, implement it for RTL and Basic-Core separately
717 bool SbxValue::IsNumeric() const
719 return ImpIsNumeric( /*bOnlyIntntl*/false );
722 bool SbxValue::IsNumericRTL() const
724 return ImpIsNumeric( /*bOnlyIntntl*/true );
727 bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const
730 if( !CanRead() )
732 SetError( SbxERR_PROP_WRITEONLY );
733 return false;
735 // Test downcast!!!
736 if( this->ISA(SbxVariable) )
737 const_cast<SbxVariable*>(static_cast<const SbxVariable*>(this))->Broadcast( SBX_HINT_DATAWANTED );
738 SbxDataType t = GetType();
739 if( t == SbxSTRING )
741 if( aData.pOUString )
743 OUString s( *aData.pOUString );
744 double n;
745 SbxDataType t2;
746 sal_uInt16 nLen = 0;
747 if( ImpScan( s, n, t2, &nLen, /*bAllowIntntl*/false, bOnlyIntntl ) == SbxERR_OK )
748 return nLen == s.getLength();
750 return false;
752 else
753 return t == SbxEMPTY
754 || ( t >= SbxINTEGER && t <= SbxCURRENCY )
755 || ( t >= SbxCHAR && t <= SbxUINT );
758 SbxClassType SbxValue::GetClass() const
760 return SbxCLASS_VALUE;
763 SbxDataType SbxValue::GetType() const
765 return SbxDataType( aData.eType & 0x0FFF );
769 bool SbxValue::SetType( SbxDataType t )
771 DBG_ASSERT( !( t & 0xF000 ), "SetType of BYREF|ARRAY is forbidden!" );
772 if( ( t == SbxEMPTY && aData.eType == SbxVOID )
773 || ( aData.eType == SbxEMPTY && t == SbxVOID ) )
774 return true;
775 if( ( t & 0x0FFF ) == SbxVARIANT )
777 // Try to set the data type to Variant
778 ResetFlag( SBX_FIXED );
779 if( IsFixed() )
781 SetError( SbxERR_CONVERSION );
782 return false;
784 t = SbxEMPTY;
786 if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) )
788 if( !CanWrite() || IsFixed() )
790 SetError( SbxERR_CONVERSION );
791 return false;
793 else
795 // De-allocate potential objects
796 switch( aData.eType )
798 case SbxSTRING:
799 delete aData.pOUString;
800 break;
801 case SbxOBJECT:
802 if( aData.pObj && aData.pObj != this )
804 SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
805 SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
806 sal_uInt16 nSlotId = pThisVar
807 ? ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) )
808 : 0;
809 DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName() == "Parent",
810 "SID_PARENTOBJECT is not named 'Parent'" );
811 bool bParentProp = 5345 == nSlotId;
812 if ( !bParentProp )
813 aData.pObj->ReleaseRef();
815 break;
816 default: break;
818 // This works always, because the Float representations are 0 as well.
819 memset( &aData, 0, sizeof( SbxValues ) );
820 aData.eType = t;
823 return true;
826 bool SbxValue::Convert( SbxDataType eTo )
828 eTo = SbxDataType( eTo & 0x0FFF );
829 if( ( aData.eType & 0x0FFF ) == eTo )
830 return true;
831 if( !CanWrite() )
832 return false;
833 if( eTo == SbxVARIANT )
835 // Trial to set the data type to Variant
836 ResetFlag( SBX_FIXED );
837 if( IsFixed() )
839 SetError( SbxERR_CONVERSION );
840 return false;
842 else
843 return true;
845 // Converting from null doesn't work. Once null, always null!
846 if( aData.eType == SbxNULL )
848 SetError( SbxERR_CONVERSION );
849 return false;
852 // Conversion of the data:
853 SbxValues aNew;
854 aNew.eType = eTo;
855 if( Get( aNew ) )
857 // The data type could be converted. It ends here with fixed elements,
858 // because the data had not to be taken over
859 if( !IsFixed() )
861 SetType( eTo );
862 Put( aNew );
863 SetModified( true );
865 Broadcast( SBX_HINT_CONVERTED );
866 return true;
868 else
869 return false;
871 ////////////////////////////////// Calculating
873 bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
875 #if !HAVE_FEATURE_SCRIPTING
876 const bool bVBAInterop = false;
877 #else
878 bool bVBAInterop = SbiRuntime::isVBAEnabled();
879 #endif
880 SbxDataType eThisType = GetType();
881 SbxDataType eOpType = rOp.GetType();
882 SbxError eOld = GetError();
883 if( eOld != SbxERR_OK )
884 ResetError();
885 if( !CanWrite() )
886 SetError( SbxERR_PROP_READONLY );
887 else if( !rOp.CanRead() )
888 SetError( SbxERR_PROP_WRITEONLY );
889 // Special rule 1: If one operand is null, the result is null
890 else if( eThisType == SbxNULL || eOpType == SbxNULL )
891 SetType( SbxNULL );
892 // Special rule 2: If the operand is Empty, the result is the 2. operand
893 else if( eThisType == SbxEMPTY
894 && !bVBAInterop
896 *this = rOp;
897 // 1996-2-13: Don't test for SbxEMPTY before Get
898 else
900 SbxValues aL, aR;
901 bool bDecimal = false;
902 if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING && eOpType != SbxEMPTY ) ||
903 ( eThisType != SbxSTRING && eThisType != SbxEMPTY && eOpType == SbxSTRING ) ) &&
904 ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
906 goto Lbl_OpIsDouble;
908 else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && ( eOp == SbxPLUS ) ) )
910 if( eOp == SbxCAT || eOp == SbxPLUS )
912 // From 1999-11-5, keep OUString in mind
913 aL.eType = aR.eType = SbxSTRING;
914 rOp.Get( aR );
915 // From 1999-12-8, #70399: Here call GetType() again, Get() can change the type!
916 if( rOp.GetType() == SbxEMPTY )
917 goto Lbl_OpIsEmpty;
918 Get( aL );
920 // #30576: To begin with test, if the conversion worked
921 if( aL.pOUString != NULL && aR.pOUString != NULL )
923 *aL.pOUString += *aR.pOUString;
925 // Not even Left OK?
926 else if( aL.pOUString == NULL )
928 aL.pOUString = new OUString();
930 Put( aL );
932 else
933 SetError( SbxERR_CONVERSION );
935 else if( eOpType == SbxSTRING && rOp.IsFixed() )
936 { // Numeric: there is no String allowed on the right side
937 SetError( SbxERR_CONVERSION );
938 // falls all the way out
940 else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
942 if( GetType() == eOpType )
944 if( GetType() == SbxSALUINT64 || GetType() == SbxSALINT64
945 || GetType() == SbxCURRENCY || GetType() == SbxULONG )
946 aL.eType = aR.eType = GetType();
947 else if ( bVBAInterop && eOpType == SbxBOOL )
948 aL.eType = aR.eType = SbxBOOL;
949 else
950 aL.eType = aR.eType = SbxLONG;
952 else
953 aL.eType = aR.eType = SbxLONG;
955 if( rOp.Get( aR ) ) // re-do Get after type assigns above
957 if( rOp.GetType() == SbxEMPTY )
959 if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNOT ) ) )
960 goto Lbl_OpIsEmpty;
962 if( Get( aL ) ) switch( eOp )
964 case SbxIDIV:
965 if( aL.eType == SbxCURRENCY )
966 if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
967 else {
968 aL.nInt64 /= aR.nInt64;
969 aL.nInt64 *= CURRENCY_FACTOR;
971 else if( aL.eType == SbxSALUINT64 )
972 if( !aR.uInt64 ) SetError( SbxERR_ZERODIV );
973 else aL.uInt64 /= aR.uInt64;
974 else if( aL.eType == SbxSALINT64 )
975 if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
976 else aL.nInt64 /= aR.nInt64;
977 else if( aL.eType == SbxLONG )
978 if( !aR.nLong ) SetError( SbxERR_ZERODIV );
979 else aL.nLong /= aR.nLong;
980 else
981 if( !aR.nULong ) SetError( SbxERR_ZERODIV );
982 else aL.nULong /= aR.nULong;
983 break;
984 case SbxMOD:
985 if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
986 if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
987 else aL.nInt64 %= aR.nInt64;
988 else if( aL.eType == SbxSALUINT64 )
989 if( !aR.uInt64 ) SetError( SbxERR_ZERODIV );
990 else aL.uInt64 %= aR.uInt64;
991 else if( aL.eType == SbxLONG )
992 if( !aR.nLong ) SetError( SbxERR_ZERODIV );
993 else aL.nLong %= aR.nLong;
994 else
995 if( !aR.nULong ) SetError( SbxERR_ZERODIV );
996 else aL.nULong %= aR.nULong;
997 break;
998 case SbxAND:
999 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1000 aL.nInt64 &= aR.nInt64;
1001 else
1002 aL.nLong &= aR.nLong;
1003 break;
1004 case SbxOR:
1005 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1006 aL.nInt64 |= aR.nInt64;
1007 else
1008 aL.nLong |= aR.nLong;
1009 break;
1010 case SbxXOR:
1011 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1012 aL.nInt64 ^= aR.nInt64;
1013 else
1014 aL.nLong ^= aR.nLong;
1015 break;
1016 case SbxEQV:
1017 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1018 aL.nInt64 = (aL.nInt64 & aR.nInt64) | (~aL.nInt64 & ~aR.nInt64);
1019 else
1020 aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
1021 break;
1022 case SbxIMP:
1023 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1024 aL.nInt64 = ~aL.nInt64 | aR.nInt64;
1025 else
1026 aL.nLong = ~aL.nLong | aR.nLong;
1027 break;
1028 case SbxNOT:
1029 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1031 if ( aL.eType != SbxBOOL )
1032 aL.nInt64 = ~aL.nInt64;
1033 else
1034 aL.nLong = ~aL.nLong;
1036 else
1037 aL.nLong = ~aL.nLong;
1038 break;
1039 default: break;
1043 else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL )
1044 && ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
1046 aL.eType = aR.eType = SbxDECIMAL;
1047 bDecimal = true;
1048 if( rOp.Get( aR ) )
1050 if( rOp.GetType() == SbxEMPTY )
1052 releaseDecimalPtr( aL.pDecimal );
1053 goto Lbl_OpIsEmpty;
1055 if( Get( aL ) )
1057 if( aL.pDecimal && aR.pDecimal )
1059 bool bOk = true;
1060 switch( eOp )
1062 case SbxMUL:
1063 bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
1064 break;
1065 case SbxDIV:
1066 if( aR.pDecimal->isZero() )
1067 SetError( SbxERR_ZERODIV );
1068 else
1069 bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
1070 break;
1071 case SbxPLUS:
1072 bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
1073 break;
1074 case SbxMINUS:
1075 bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
1076 break;
1077 case SbxNEG:
1078 bOk = ( aL.pDecimal->neg() );
1079 break;
1080 default:
1081 SetError( SbxERR_NOTIMP );
1083 if( !bOk )
1084 SetError( SbxERR_OVERFLOW );
1086 else
1088 SetError( SbxERR_CONVERSION );
1093 else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
1095 aL.eType = SbxCURRENCY;
1096 aR.eType = SbxCURRENCY;
1098 if( rOp.Get( aR ) )
1100 if( rOp.GetType() == SbxEMPTY )
1101 goto Lbl_OpIsEmpty;
1103 if( Get( aL ) ) switch( eOp )
1105 double dTest;
1106 case SbxMUL:
1107 // first overflow check: see if product will fit - test real value of product (hence 2 curr factors)
1108 dTest = (double)aL.nInt64 * (double)aR.nInt64 / (double)CURRENCY_FACTOR_SQUARE;
1109 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1111 aL.nInt64 = SAL_MAX_INT64;
1112 if( dTest < SbxMINCURR ) aL.nInt64 = SAL_MIN_INT64;
1113 SetError( SbxERR_OVERFLOW );
1114 break;
1116 // second overflow check: see if unscaled product overflows - if so use doubles
1117 dTest = (double)aL.nInt64 * (double)aR.nInt64;
1118 if( dTest < SAL_MIN_INT64 || SAL_MAX_INT64 < dTest)
1120 aL.nInt64 = (sal_Int64)( dTest / (double)CURRENCY_FACTOR );
1121 break;
1123 // precise calc: multiply then scale back (move decimal pt)
1124 aL.nInt64 *= aR.nInt64;
1125 aL.nInt64 /= CURRENCY_FACTOR;
1126 break;
1128 case SbxDIV:
1129 if( !aR.nInt64 )
1131 SetError( SbxERR_ZERODIV );
1132 break;
1134 // first overflow check: see if quotient will fit - calc real value of quotient (curr factors cancel)
1135 dTest = (double)aL.nInt64 / (double)aR.nInt64;
1136 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1138 SetError( SbxERR_OVERFLOW );
1139 break;
1141 // second overflow check: see if scaled dividend overflows - if so use doubles
1142 dTest = (double)aL.nInt64 * (double)CURRENCY_FACTOR;
1143 if( dTest < SAL_MIN_INT64 || SAL_MAX_INT64 < dTest)
1145 aL.nInt64 = (sal_Int64)(dTest / (double)aR.nInt64);
1146 break;
1148 // precise calc: scale (move decimal pt) then divide
1149 aL.nInt64 *= CURRENCY_FACTOR;
1150 aL.nInt64 /= aR.nInt64;
1151 break;
1153 case SbxPLUS:
1154 dTest = ( (double)aL.nInt64 + (double)aR.nInt64 ) / (double)CURRENCY_FACTOR;
1155 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1157 SetError( SbxERR_OVERFLOW );
1158 break;
1160 aL.nInt64 += aR.nInt64;
1161 break;
1163 case SbxMINUS:
1164 dTest = ( (double)aL.nInt64 - (double)aR.nInt64 ) / (double)CURRENCY_FACTOR;
1165 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1167 SetError( SbxERR_OVERFLOW );
1168 break;
1170 aL.nInt64 -= aR.nInt64;
1171 break;
1172 case SbxNEG:
1173 aL.nInt64 = -aL.nInt64;
1174 break;
1175 default:
1176 SetError( SbxERR_NOTIMP );
1180 else
1181 Lbl_OpIsDouble:
1182 { // other types and operators including Date, Double and Single
1183 aL.eType = aR.eType = SbxDOUBLE;
1184 if( rOp.Get( aR ) )
1186 if( rOp.GetType() == SbxEMPTY )
1188 if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNEG ) ) )
1189 goto Lbl_OpIsEmpty;
1191 if( Get( aL ) )
1193 switch( eOp )
1195 case SbxEXP:
1196 aL.nDouble = pow( aL.nDouble, aR.nDouble );
1197 break;
1198 case SbxMUL:
1199 aL.nDouble *= aR.nDouble; break;
1200 case SbxDIV:
1201 if( !aR.nDouble ) SetError( SbxERR_ZERODIV );
1202 else aL.nDouble /= aR.nDouble; break;
1203 case SbxPLUS:
1204 aL.nDouble += aR.nDouble; break;
1205 case SbxMINUS:
1206 aL.nDouble -= aR.nDouble; break;
1207 case SbxNEG:
1208 aL.nDouble = -aL.nDouble; break;
1209 default:
1210 SetError( SbxERR_NOTIMP );
1212 // Date with "+" or "-" needs special handling that
1213 // forces the Date type. If the operation is '+' the
1214 // result is always a Date, if '-' the result is only
1215 // a Date if one of lhs or rhs ( but not both ) is already
1216 // a Date
1217 if( ( GetType() == SbxDATE || rOp.GetType() == SbxDATE ) )
1219 if( eOp == SbxPLUS || ( ( eOp == SbxMINUS ) && ( GetType() != rOp.GetType() ) ) )
1220 aL.eType = SbxDATE;
1227 if( !IsError() )
1228 Put( aL );
1229 if( bDecimal )
1231 releaseDecimalPtr( aL.pDecimal );
1232 releaseDecimalPtr( aR.pDecimal );
1235 Lbl_OpIsEmpty:
1237 bool bRes = !IsError();
1238 if( bRes && eOld != SbxERR_OK )
1239 SetError( eOld );
1240 return bRes;
1243 // The comparison routine deliver TRUE or FALSE.
1245 bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
1247 #if !HAVE_FEATURE_SCRIPTING
1248 const bool bVBAInterop = false;
1249 #else
1250 bool bVBAInterop = SbiRuntime::isVBAEnabled();
1251 #endif
1253 bool bRes = false;
1254 SbxError eOld = GetError();
1255 if( eOld != SbxERR_OK )
1256 ResetError();
1257 if( !CanRead() || !rOp.CanRead() )
1258 SetError( SbxERR_PROP_WRITEONLY );
1259 else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
1261 bRes = true;
1263 else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
1264 bRes = !bVBAInterop || ( eOp == SbxEQ );
1265 // Special rule 1: If an operand is null, the result is FALSE
1266 else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
1267 bRes = false;
1268 // Special rule 2: If both are variant and one is numeric
1269 // and the other is a String, num is < str
1270 else if( !IsFixed() && !rOp.IsFixed()
1271 && ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
1273 bRes = eOp == SbxLT || eOp == SbxLE || eOp == SbxNE;
1274 else if( !IsFixed() && !rOp.IsFixed()
1275 && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
1276 && !bVBAInterop
1278 bRes = eOp == SbxGT || eOp == SbxGE || eOp == SbxNE;
1279 else
1281 SbxValues aL, aR;
1282 // If one of the operands is a String,
1283 // a String comparing take place
1284 if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
1286 aL.eType = aR.eType = SbxSTRING;
1287 if( Get( aL ) && rOp.Get( aR ) ) switch( eOp )
1289 case SbxEQ:
1290 bRes = ( *aL.pOUString == *aR.pOUString ); break;
1291 case SbxNE:
1292 bRes = ( *aL.pOUString != *aR.pOUString ); break;
1293 case SbxLT:
1294 bRes = ( *aL.pOUString < *aR.pOUString ); break;
1295 case SbxGT:
1296 bRes = ( *aL.pOUString > *aR.pOUString ); break;
1297 case SbxLE:
1298 bRes = ( *aL.pOUString <= *aR.pOUString ); break;
1299 case SbxGE:
1300 bRes = ( *aL.pOUString >= *aR.pOUString ); break;
1301 default:
1302 SetError( SbxERR_NOTIMP );
1305 // From 1995-12-19: If SbxSINGLE participate, then convert to SINGLE,
1306 // otherwise it shows a numeric error
1307 else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
1309 aL.eType = aR.eType = SbxSINGLE;
1310 if( Get( aL ) && rOp.Get( aR ) )
1311 switch( eOp )
1313 case SbxEQ:
1314 bRes = ( aL.nSingle == aR.nSingle ); break;
1315 case SbxNE:
1316 bRes = ( aL.nSingle != aR.nSingle ); break;
1317 case SbxLT:
1318 bRes = ( aL.nSingle < aR.nSingle ); break;
1319 case SbxGT:
1320 bRes = ( aL.nSingle > aR.nSingle ); break;
1321 case SbxLE:
1322 bRes = ( aL.nSingle <= aR.nSingle ); break;
1323 case SbxGE:
1324 bRes = ( aL.nSingle >= aR.nSingle ); break;
1325 default:
1326 SetError( SbxERR_NOTIMP );
1329 else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
1331 aL.eType = aR.eType = SbxDECIMAL;
1332 Get( aL );
1333 rOp.Get( aR );
1334 if( aL.pDecimal && aR.pDecimal )
1336 SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
1337 switch( eOp )
1339 case SbxEQ:
1340 bRes = ( eRes == SbxDecimal::EQ ); break;
1341 case SbxNE:
1342 bRes = ( eRes != SbxDecimal::EQ ); break;
1343 case SbxLT:
1344 bRes = ( eRes == SbxDecimal::LT ); break;
1345 case SbxGT:
1346 bRes = ( eRes == SbxDecimal::GT ); break;
1347 case SbxLE:
1348 bRes = ( eRes != SbxDecimal::GT ); break;
1349 case SbxGE:
1350 bRes = ( eRes != SbxDecimal::LT ); break;
1351 default:
1352 SetError( SbxERR_NOTIMP );
1355 else
1357 SetError( SbxERR_CONVERSION );
1359 releaseDecimalPtr( aL.pDecimal );
1360 releaseDecimalPtr( aR.pDecimal );
1362 // Everything else comparing on a SbxDOUBLE-Basis
1363 else
1365 aL.eType = aR.eType = SbxDOUBLE;
1366 bool bGetL = Get( aL );
1367 bool bGetR = rOp.Get( aR );
1368 if( bGetL && bGetR )
1369 switch( eOp )
1371 case SbxEQ:
1372 bRes = ( aL.nDouble == aR.nDouble ); break;
1373 case SbxNE:
1374 bRes = ( aL.nDouble != aR.nDouble ); break;
1375 case SbxLT:
1376 bRes = ( aL.nDouble < aR.nDouble ); break;
1377 case SbxGT:
1378 bRes = ( aL.nDouble > aR.nDouble ); break;
1379 case SbxLE:
1380 bRes = ( aL.nDouble <= aR.nDouble ); break;
1381 case SbxGE:
1382 bRes = ( aL.nDouble >= aR.nDouble ); break;
1383 default:
1384 SetError( SbxERR_NOTIMP );
1386 // at least one value was got
1387 // if this is VBA then a conversion error for one
1388 // side will yield a false result of an equality test
1389 else if ( bGetR || bGetL )
1391 if ( bVBAInterop && eOp == SbxEQ && GetError() == SbxERR_CONVERSION )
1393 ResetError();
1394 bRes = false;
1399 if( eOld != SbxERR_OK )
1400 SetError( eOld );
1401 return bRes;
1404 ///////////////////////////// Reading/Writing
1406 bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
1408 // #TODO see if these types are really dumped to any stream
1409 // more than likely this is functionality used in the binfilter alone
1410 SbxValue::Clear();
1411 sal_uInt16 nType;
1412 r.ReadUInt16( nType );
1413 aData.eType = SbxDataType( nType );
1414 switch( nType )
1416 case SbxBOOL:
1417 case SbxINTEGER:
1418 r.ReadInt16( aData.nInteger ); break;
1419 case SbxLONG:
1420 r.ReadInt32( aData.nLong ); break;
1421 case SbxSINGLE:
1423 // Floats as ASCII
1424 OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1425 RTL_TEXTENCODING_ASCII_US);
1426 double d;
1427 SbxDataType t;
1428 if( ImpScan( aVal, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE )
1430 aData.nSingle = 0.0F;
1431 return false;
1433 aData.nSingle = (float) d;
1434 break;
1436 case SbxDATE:
1437 case SbxDOUBLE:
1439 // Floats as ASCII
1440 OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1441 RTL_TEXTENCODING_ASCII_US);
1442 SbxDataType t;
1443 if( ImpScan( aVal, aData.nDouble, t, NULL ) != SbxERR_OK )
1445 aData.nDouble = 0.0;
1446 return false;
1448 break;
1450 case SbxSALINT64:
1451 r.ReadInt64(aData.nInt64);
1452 break;
1453 case SbxSALUINT64:
1454 r.ReadUInt64( aData.uInt64 );
1455 break;
1456 case SbxCURRENCY:
1458 sal_uInt32 tmpHi = 0;
1459 sal_uInt32 tmpLo = 0;
1460 r.ReadUInt32( tmpHi ).ReadUInt32( tmpLo );
1461 aData.nInt64 = ((sal_Int64)tmpHi << 32);
1462 aData.nInt64 |= (sal_Int64)tmpLo;
1463 break;
1465 case SbxSTRING:
1467 OUString aVal = read_uInt16_lenPrefixed_uInt8s_ToOUString(r,
1468 RTL_TEXTENCODING_ASCII_US);
1469 if( !aVal.isEmpty() )
1470 aData.pOUString = new OUString( aVal );
1471 else
1472 aData.pOUString = NULL; // JSM 1995-09-22
1473 break;
1475 case SbxERROR:
1476 case SbxUSHORT:
1477 r.ReadUInt16( aData.nUShort ); break;
1478 case SbxOBJECT:
1480 sal_uInt8 nMode;
1481 r.ReadUChar( nMode );
1482 switch( nMode )
1484 case 0:
1485 aData.pObj = NULL;
1486 break;
1487 case 1:
1488 aData.pObj = SbxBase::Load( r );
1489 return ( aData.pObj != NULL );
1490 case 2:
1491 aData.pObj = this;
1492 break;
1494 break;
1496 case SbxCHAR:
1498 char c;
1499 r.ReadChar( c );
1500 aData.nChar = c;
1501 break;
1503 case SbxBYTE:
1504 r.ReadUChar( aData.nByte ); break;
1505 case SbxULONG:
1506 r.ReadUInt32( aData.nULong ); break;
1507 case SbxINT:
1509 sal_uInt8 n;
1510 r.ReadUChar( n );
1511 // Match the Int on this system?
1512 if( n > SAL_TYPES_SIZEOFINT )
1513 r.ReadInt32( aData.nLong ), aData.eType = SbxLONG;
1514 else {
1515 sal_Int32 nInt;
1516 r.ReadInt32( nInt );
1517 aData.nInt = nInt;
1519 break;
1521 case SbxUINT:
1523 sal_uInt8 n;
1524 r.ReadUChar( n );
1525 // Match the UInt on this system?
1526 if( n > SAL_TYPES_SIZEOFINT )
1527 r.ReadUInt32( aData.nULong ), aData.eType = SbxULONG;
1528 else {
1529 sal_uInt32 nUInt;
1530 r.ReadUInt32( nUInt );
1531 aData.nUInt = nUInt;
1533 break;
1535 case SbxEMPTY:
1536 case SbxNULL:
1537 case SbxVOID:
1538 break;
1539 case SbxDATAOBJECT:
1540 r.ReadInt32( aData.nLong );
1541 break;
1542 // #78919 For backwards compatibility
1543 case SbxWSTRING:
1544 case SbxWCHAR:
1545 break;
1546 default:
1547 memset (&aData,0,sizeof(aData));
1548 ResetFlag(SBX_FIXED);
1549 aData.eType = SbxNULL;
1550 DBG_ASSERT( false, "Loaded a non-supported data type" );
1552 return false;
1554 return true;
1557 bool SbxValue::StoreData( SvStream& r ) const
1559 sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
1560 r.WriteUInt16( nType );
1561 switch( nType & 0x0FFF )
1563 case SbxBOOL:
1564 case SbxINTEGER:
1565 r.WriteInt16( aData.nInteger ); break;
1566 case SbxLONG:
1567 r.WriteInt32( aData.nLong ); break;
1568 case SbxDATE:
1569 // #49935: Save as double, otherwise an error during the read in
1570 const_cast<SbxValue*>(this)->aData.eType = (SbxDataType)( ( nType & 0xF000 ) | SbxDOUBLE );
1571 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1572 const_cast<SbxValue*>(this)->aData.eType = (SbxDataType)nType;
1573 break;
1574 case SbxSINGLE:
1575 case SbxDOUBLE:
1576 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1577 break;
1578 case SbxSALUINT64:
1579 case SbxSALINT64:
1580 // see comment in SbxValue::StoreData
1581 r.WriteUInt64( aData.uInt64 );
1582 break;
1583 case SbxCURRENCY:
1585 sal_Int32 tmpHi = ( (aData.nInt64 >> 32) & 0xFFFFFFFF );
1586 sal_Int32 tmpLo = ( sal_Int32 )aData.nInt64;
1587 r.WriteInt32( tmpHi ).WriteInt32( tmpLo );
1588 break;
1590 case SbxSTRING:
1591 if( aData.pOUString )
1593 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, *aData.pOUString, RTL_TEXTENCODING_ASCII_US);
1595 else
1597 write_uInt16_lenPrefixed_uInt8s_FromOUString(r, OUString(), RTL_TEXTENCODING_ASCII_US);
1599 break;
1600 case SbxERROR:
1601 case SbxUSHORT:
1602 r.WriteUInt16( aData.nUShort ); break;
1603 case SbxOBJECT:
1604 // to save itself as Objectptr does not work!
1605 if( aData.pObj )
1607 if( PTR_CAST(SbxValue,aData.pObj) != this )
1609 r.WriteUChar( 1 );
1610 return aData.pObj->Store( r );
1612 else
1613 r.WriteUChar( 2 );
1615 else
1616 r.WriteUChar( 0 );
1617 break;
1618 case SbxCHAR:
1620 char c = sal::static_int_cast< char >(aData.nChar);
1621 r.WriteChar( c );
1622 break;
1624 case SbxBYTE:
1625 r.WriteUChar( aData.nByte ); break;
1626 case SbxULONG:
1627 r.WriteUInt32( aData.nULong ); break;
1628 case SbxINT:
1630 sal_uInt8 n = SAL_TYPES_SIZEOFINT;
1631 r.WriteUChar( n ).WriteInt32( aData.nInt );
1632 break;
1634 case SbxUINT:
1636 sal_uInt8 n = SAL_TYPES_SIZEOFINT;
1637 r.WriteUChar( n ).WriteUInt32( aData.nUInt );
1638 break;
1640 case SbxEMPTY:
1641 case SbxNULL:
1642 case SbxVOID:
1643 break;
1644 case SbxDATAOBJECT:
1645 r.WriteInt32( aData.nLong );
1646 break;
1647 // #78919 For backwards compatibility
1648 case SbxWSTRING:
1649 case SbxWCHAR:
1650 break;
1651 default:
1652 DBG_ASSERT( false, "Saving a non-supported data type" );
1653 return false;
1655 return true;
1658 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */