bump product version to 4.1.6.2
[LibreOffice.git] / basic / source / sbx / sbxvalue.cxx
blob2f9e9694f69dfb8b61dcf0ad65a03242dad5b1f4
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 .
21 #include <math.h>
22 #include <tools/stream.hxx>
24 #include <basic/sbx.hxx>
25 #include "sbxconv.hxx"
26 #include "runtime.hxx"
28 TYPEINIT1(SbxValue,SbxBase)
30 ///////////////////////////// constructors //////////////////////////////
32 SbxValue::SbxValue() : SbxBase()
34 aData.eType = SbxEMPTY;
37 SbxValue::SbxValue( SbxDataType t, void* p ) : SbxBase()
39 int n = t & 0x0FFF;
40 if( p )
41 n |= SbxBYREF;
42 if( n == SbxVARIANT )
43 n = SbxEMPTY;
44 else
45 SetFlag( SBX_FIXED );
46 if( p )
48 switch( t & 0x0FFF )
50 case SbxINTEGER: n |= SbxBYREF; aData.pInteger = (sal_Int16*) p; break;
51 case SbxSALUINT64: n |= SbxBYREF; aData.puInt64 = (sal_uInt64*) p; break;
52 case SbxSALINT64:
53 case SbxCURRENCY: n |= SbxBYREF; aData.pnInt64 = (sal_Int64*) p; break;
54 case SbxLONG: n |= SbxBYREF; aData.pLong = (sal_Int32*) p; break;
55 case SbxSINGLE: n |= SbxBYREF; aData.pSingle = (float*) p; break;
56 case SbxDATE:
57 case SbxDOUBLE: n |= SbxBYREF; aData.pDouble = (double*) p; break;
58 case SbxSTRING: n |= SbxBYREF; aData.pOUString = (OUString*) p; break;
59 case SbxERROR:
60 case SbxUSHORT:
61 case SbxBOOL: n |= SbxBYREF; aData.pUShort = (sal_uInt16*) p; break;
62 case SbxULONG: n |= SbxBYREF; aData.pULong = (sal_uInt32*) p; break;
63 case SbxCHAR: n |= SbxBYREF; aData.pChar = (sal_Unicode*) p; break;
64 case SbxBYTE: n |= SbxBYREF; aData.pByte = (sal_uInt8*) p; break;
65 case SbxINT: n |= SbxBYREF; aData.pInt = (int*) p; break;
66 case SbxOBJECT:
67 aData.pObj = (SbxBase*) p;
68 if( p )
69 aData.pObj->AddRef();
70 break;
71 case SbxDECIMAL:
72 aData.pDecimal = (SbxDecimal*) p;
73 if( p )
74 aData.pDecimal->addRef();
75 break;
76 default:
77 DBG_ASSERT( !this, "Improper pointer argument" );
78 n = SbxNULL;
81 else
82 memset( &aData, 0, sizeof( SbxValues ) );
83 aData.eType = SbxDataType( n );
86 SbxValue::SbxValue( const SbxValue& r )
87 : SvRefBase( r ), SbxBase( r )
89 if( !r.CanRead() )
91 SetError( SbxERR_PROP_WRITEONLY );
92 if( !IsFixed() )
93 aData.eType = SbxNULL;
95 else
97 ((SbxValue*) &r)->Broadcast( SBX_HINT_DATAWANTED );
98 aData = r.aData;
99 // Copy pointer, increment references
100 switch( aData.eType )
102 case SbxSTRING:
103 if( aData.pOUString )
104 aData.pOUString = new OUString( *aData.pOUString );
105 break;
106 case SbxOBJECT:
107 if( aData.pObj )
108 aData.pObj->AddRef();
109 break;
110 case SbxDECIMAL:
111 if( aData.pDecimal )
112 aData.pDecimal->addRef();
113 break;
114 default: break;
119 SbxValue& SbxValue::operator=( const SbxValue& r )
121 if( &r != this )
123 if( !CanWrite() )
124 SetError( SbxERR_PROP_READONLY );
125 else
127 // string -> byte array
128 if( IsFixed() && (aData.eType == SbxOBJECT)
129 && aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
130 && (r.aData.eType == SbxSTRING) )
132 OUString aStr = r.GetOUString();
133 SbxArray* pArr = StringToByteArray(aStr);
134 PutObject(pArr);
135 return *this;
137 // byte array -> string
138 if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
139 && r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
140 && (aData.eType == SbxSTRING) )
142 SbxBase* pObj = r.GetObject();
143 SbxArray* pArr = PTR_CAST(SbxArray, pObj);
144 if( pArr )
146 OUString aStr = ByteArrayToString( pArr );
147 PutString(aStr);
148 return *this;
151 // Readout the content of the variables
152 SbxValues aNew;
153 if( IsFixed() )
154 // firm: then the type had to match
155 aNew.eType = aData.eType;
156 else if( r.IsFixed() )
157 // Source firm: take over the type
158 aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
159 else
160 // both variant: then it is equal
161 aNew.eType = SbxVARIANT;
162 if( r.Get( aNew ) )
163 Put( aNew );
166 return *this;
169 SbxValue::~SbxValue()
171 Broadcast( SBX_HINT_DYING );
172 SetFlag( SBX_WRITE );
173 SbxValue::Clear();
176 void SbxValue::Clear()
178 switch( aData.eType )
180 case SbxNULL:
181 case SbxEMPTY:
182 case SbxVOID:
183 break;
184 case SbxSTRING:
185 delete aData.pOUString; aData.pOUString = NULL;
186 break;
187 case SbxOBJECT:
188 if( aData.pObj )
190 if( aData.pObj != this )
192 SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
193 SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
194 sal_Bool bParentProp = pThisVar && 5345 ==
195 ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
196 if ( !bParentProp )
197 aData.pObj->ReleaseRef();
199 aData.pObj = NULL;
201 break;
202 case SbxDECIMAL:
203 if( aData.eType == SbxDECIMAL )
204 releaseDecimalPtr( aData.pDecimal );
205 break;
206 case SbxDATAOBJECT:
207 aData.pData = NULL; break;
208 default:
210 SbxValues aEmpty;
211 memset( &aEmpty, 0, sizeof( SbxValues ) );
212 aEmpty.eType = GetType();
213 Put( aEmpty );
218 // Dummy
220 void SbxValue::Broadcast( sal_uIntPtr )
223 //////////////////////////// Readout data //////////////////////////////
225 // Detect the "right" variables. If it is an object, will be addressed either
226 // the object itself or its default property.
227 // If the variable contain a variable or an object, this will be
228 // addressed.
230 SbxValue* SbxValue::TheRealValue() const
232 return TheRealValue( sal_True );
235 // #55226 ship additional information
236 bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal ); // sbunoobj.cxx
238 SbxValue* SbxValue::TheRealValue( sal_Bool bObjInObjError ) const
240 SbxValue* p = (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
256 // is not correct, because e.g. a regular variant variable with an object
257 // could be affected thereof, 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 #ifdef DISABLE_SCRIPTING // No sbunoobj
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 // Elsewise 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 sal_Bool SbxValue::Get( SbxValues& rRes ) const
313 sal_Bool bRes = sal_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 there was asked for an object or a VARIANT, don't search
325 // the real values
326 SbxValue* p = (SbxValue*) this;
327 if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
328 p = TheRealValue();
329 if( p )
331 p->Broadcast( SBX_HINT_DATAWANTED );
332 switch( rRes.eType )
334 case SbxEMPTY:
335 case SbxVOID:
336 case SbxNULL: break;
337 case SbxVARIANT: rRes = p->aData; break;
338 case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
339 case SbxLONG: rRes.nLong = ImpGetLong( &p->aData ); break;
340 case SbxSALINT64: rRes.nInt64 = ImpGetInt64( &p->aData ); break;
341 case SbxSALUINT64: rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
342 case SbxSINGLE: rRes.nSingle = ImpGetSingle( &p->aData ); break;
343 case SbxDOUBLE: rRes.nDouble = ImpGetDouble( &p->aData ); break;
344 case SbxCURRENCY:rRes.nInt64 = ImpGetCurrency( &p->aData ); break;
345 case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
346 case SbxDATE: rRes.nDouble = ImpGetDate( &p->aData ); break;
347 case SbxBOOL:
348 rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
349 ImpGetBool( &p->aData ) );
350 break;
351 case SbxCHAR: rRes.nChar = ImpGetChar( &p->aData ); break;
352 case SbxBYTE: rRes.nByte = ImpGetByte( &p->aData ); break;
353 case SbxUSHORT: rRes.nUShort = ImpGetUShort( &p->aData ); break;
354 case SbxULONG: rRes.nULong = ImpGetULong( &p->aData ); break;
355 case SbxLPSTR:
356 case SbxSTRING: p->aPic = ImpGetString( &p->aData );
357 rRes.pOUString = &p->aPic; break;
358 case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
359 rRes.pOUString = &p->aPic; break;
360 case SbxINT:
361 #if SAL_TYPES_SIZEOFINT == 2
362 rRes.nInt = (int) ImpGetInteger( &p->aData );
363 #else
364 rRes.nInt = (int) ImpGetLong( &p->aData );
365 #endif
366 break;
367 case SbxUINT:
368 #if SAL_TYPES_SIZEOFINT == 2
369 rRes.nUInt = (int) ImpGetUShort( &p->aData );
370 #else
371 rRes.nUInt = (int) ImpGetULong( &p->aData );
372 #endif
373 break;
374 case SbxOBJECT:
375 if( p->aData.eType == SbxOBJECT )
376 rRes.pObj = p->aData.pObj;
377 else
379 SetError( SbxERR_NO_OBJECT );
380 rRes.pObj = NULL;
382 break;
383 default:
384 if( p->aData.eType == rRes.eType )
385 rRes = p->aData;
386 else
388 SetError( SbxERR_CONVERSION );
389 rRes.pObj = NULL;
393 else
395 // Object contained itself
396 SbxDataType eTemp = rRes.eType;
397 memset( &rRes, 0, sizeof( SbxValues ) );
398 rRes.eType = eTemp;
401 if( !IsError() )
403 bRes = sal_True;
404 if( eOld != SbxERR_OK )
405 SetError( eOld );
407 return bRes;
410 const OUString& SbxValue::GetCoreString() const
412 SbxValues aRes;
413 aRes.eType = SbxCoreSTRING;
414 if( Get( aRes ) )
416 ((SbxValue*) this)->aToolString = *aRes.pOUString;
418 else
420 ((SbxValue*) this)->aToolString = "";
422 return aToolString;
425 OUString SbxValue::GetOUString() const
427 OUString aResult;
428 SbxValues aRes;
429 aRes.eType = SbxSTRING;
430 if( Get( aRes ) )
432 aResult = *aRes.pOUString;
434 return aResult;
437 sal_Bool SbxValue::GetBool() const
439 SbxValues aRes;
440 aRes.eType = SbxBOOL;
441 Get( aRes );
442 return sal_Bool( aRes.nUShort != 0 );
445 #define GET( g, e, t, m ) \
446 t SbxValue::g() const { SbxValues aRes(e); Get( aRes ); return aRes.m; }
448 GET( GetByte, SbxBYTE, sal_uInt8, nByte )
449 GET( GetChar, SbxCHAR, sal_Unicode, nChar )
450 GET( GetCurrency, SbxCURRENCY, sal_Int64, nInt64 )
451 GET( GetDate, SbxDATE, double, nDouble )
452 GET( GetDouble, SbxDOUBLE, double, nDouble )
453 GET( GetInteger, SbxINTEGER, sal_Int16, nInteger )
454 GET( GetLong, SbxLONG, sal_Int32, nLong )
455 GET( GetObject, SbxOBJECT, SbxBase*, pObj )
456 GET( GetSingle, SbxSINGLE, float, nSingle )
457 GET( GetULong, SbxULONG, sal_uInt32, nULong )
458 GET( GetUShort, SbxUSHORT, sal_uInt16, nUShort )
459 GET( GetInt64, SbxSALINT64, sal_Int64, nInt64 )
460 GET( GetUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
461 GET( GetDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
464 //////////////////////////// Write data /////////////////////////////
466 sal_Bool SbxValue::Put( const SbxValues& rVal )
468 sal_Bool bRes = sal_False;
469 SbxError eOld = GetError();
470 if( eOld != SbxERR_OK )
471 ResetError();
472 if( !CanWrite() )
473 SetError( SbxERR_PROP_READONLY );
474 else if( rVal.eType & 0xF000 )
475 SetError( SbxERR_NOTIMP );
476 else
478 // If there was asked for an object, don't search
479 // the real values
480 SbxValue* p = this;
481 if( rVal.eType != SbxOBJECT )
482 p = TheRealValue( sal_False ); // Don't allow an error here
483 if( p )
485 if( !p->CanWrite() )
486 SetError( SbxERR_PROP_READONLY );
487 else if( p->IsFixed() || p->SetType( (SbxDataType) ( rVal.eType & 0x0FFF ) ) )
488 switch( rVal.eType & 0x0FFF )
490 case SbxEMPTY:
491 case SbxVOID:
492 case SbxNULL: break;
493 case SbxINTEGER: ImpPutInteger( &p->aData, rVal.nInteger ); break;
494 case SbxLONG: ImpPutLong( &p->aData, rVal.nLong ); break;
495 case SbxSALINT64: ImpPutInt64( &p->aData, rVal.nInt64 ); break;
496 case SbxSALUINT64: ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
497 case SbxSINGLE: ImpPutSingle( &p->aData, rVal.nSingle ); break;
498 case SbxDOUBLE: ImpPutDouble( &p->aData, rVal.nDouble ); break;
499 case SbxCURRENCY: ImpPutCurrency( &p->aData, rVal.nInt64 ); break;
500 case SbxDECIMAL: ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
501 case SbxDATE: ImpPutDate( &p->aData, rVal.nDouble ); break;
502 case SbxBOOL: ImpPutBool( &p->aData, rVal.nInteger ); break;
503 case SbxCHAR: ImpPutChar( &p->aData, rVal.nChar ); break;
504 case SbxBYTE: ImpPutByte( &p->aData, rVal.nByte ); break;
505 case SbxUSHORT: ImpPutUShort( &p->aData, rVal.nUShort ); break;
506 case SbxULONG: ImpPutULong( &p->aData, rVal.nULong ); break;
507 case SbxLPSTR:
508 case SbxSTRING: ImpPutString( &p->aData, rVal.pOUString ); break;
509 case SbxINT:
510 #if SAL_TYPES_SIZEOFINT == 2
511 ImpPutInteger( &p->aData, (sal_Int16) rVal.nInt );
512 #else
513 ImpPutLong( &p->aData, (sal_Int32) rVal.nInt );
514 #endif
515 break;
516 case SbxUINT:
517 #if SAL_TYPES_SIZEOFINT == 2
518 ImpPutUShort( &p->aData, (sal_uInt16) rVal.nUInt );
519 #else
520 ImpPutULong( &p->aData, (sal_uInt32) rVal.nUInt );
521 #endif
522 break;
523 case SbxOBJECT:
524 if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
526 // is already inside
527 if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
528 break;
530 // Delete only the value part!
531 p->SbxValue::Clear();
533 // real allocation
534 p->aData.pObj = rVal.pObj;
536 // if necessary cont in Ref-Count
537 if( p->aData.pObj && p->aData.pObj != p )
539 if ( p != this )
541 OSL_FAIL( "TheRealValue" );
543 SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
544 SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
545 sal_Bool bParentProp = pThisVar && 5345 ==
546 ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
547 if ( !bParentProp )
548 p->aData.pObj->AddRef();
551 else
552 SetError( SbxERR_CONVERSION );
553 break;
554 default:
555 if( p->aData.eType == rVal.eType )
556 p->aData = rVal;
557 else
559 SetError( SbxERR_CONVERSION );
560 if( !p->IsFixed() )
561 p->aData.eType = SbxNULL;
564 if( !IsError() )
566 p->SetModified( sal_True );
567 p->Broadcast( SBX_HINT_DATACHANGED );
568 if( eOld != SbxERR_OK )
569 SetError( eOld );
570 bRes = sal_True;
574 return bRes;
577 // From 1996-03-28:
578 // Method to execute a pretreatment of the strings at special types.
579 // In particular necessary for BASIC-IDE, so that
580 // the output in the Watch-Window can be writen back with PutStringExt,
581 // if Float were declared with ',' as the decimal separator or BOOl
582 // explicit with "TRUE" or "FALSE".
583 // Implementation in ImpConvStringExt (SBXSCAN.CXX)
584 sal_Bool SbxValue::PutStringExt( const OUString& r )
586 // Copy; if it is Unicode convert it immediately
587 OUString aStr( r );
589 // Identify the own type (not as in Put() with TheRealValue(),
590 // Objects are not handled anyway)
591 SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
593 // tinker a Source-Value
594 SbxValues aRes;
595 aRes.eType = SbxSTRING;
597 // Only if really something was converted, take the copy,
598 // elsewise take the original (Unicode remain)
599 sal_Bool bRet;
600 if( ImpConvStringExt( aStr, eTargetType ) )
601 aRes.pOUString = (OUString*)&aStr;
602 else
603 aRes.pOUString = (OUString*)&r;
605 // #34939: Set a Fixed-Flag at Strings. which contain a number, and
606 // if this has a Num-Type, so that the type will not be changed
607 sal_uInt16 nFlags_ = GetFlags();
608 if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
609 ( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
610 eTargetType == SbxBOOL )
612 SbxValue aVal;
613 aVal.Put( aRes );
614 if( aVal.IsNumeric() )
615 SetFlag( SBX_FIXED );
618 Put( aRes );
619 bRet = sal_Bool( !IsError() );
621 // If it throwed an error with FIXED, set it back
622 // (UI-Action should not cast an error, but only fail)
623 if( !bRet )
624 ResetError();
626 SetFlags( nFlags_ );
627 return bRet;
630 sal_Bool SbxValue::PutBool( sal_Bool b )
632 SbxValues aRes;
633 aRes.eType = SbxBOOL;
634 aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
635 Put( aRes );
636 return sal_Bool( !IsError() );
639 sal_Bool SbxValue::PutEmpty()
641 sal_Bool bRet = SetType( SbxEMPTY );
642 SetModified( sal_True );
643 return bRet;
646 sal_Bool SbxValue::PutNull()
648 sal_Bool bRet = SetType( SbxNULL );
649 if( bRet )
650 SetModified( sal_True );
651 return bRet;
655 // Special decimal methods
656 sal_Bool SbxValue::PutDecimal( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec )
658 SbxValue::Clear();
659 aData.pDecimal = new SbxDecimal( rAutomationDec );
660 aData.pDecimal->addRef();
661 aData.eType = SbxDECIMAL;
662 return sal_True;
665 sal_Bool SbxValue::fillAutomationDecimal
666 ( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ) const
668 SbxDecimal* pDecimal = GetDecimal();
669 if( pDecimal != NULL )
671 pDecimal->fillAutomationDecimal( rAutomationDec );
672 return sal_True;
674 return sal_False;
678 sal_Bool SbxValue::PutString( const OUString& r )
680 SbxValues aRes;
681 aRes.eType = SbxSTRING;
682 aRes.pOUString = (OUString*) &r;
683 Put( aRes );
684 return sal_Bool( !IsError() );
688 #define PUT( p, e, t, m ) \
689 sal_Bool SbxValue::p( t n ) \
690 { SbxValues aRes(e); aRes.m = n; Put( aRes ); return sal_Bool( !IsError() ); }
692 PUT( PutByte, SbxBYTE, sal_uInt8, nByte )
693 PUT( PutChar, SbxCHAR, sal_Unicode, nChar )
694 PUT( PutCurrency, SbxCURRENCY, const sal_Int64&, nInt64 )
695 PUT( PutDate, SbxDATE, double, nDouble )
696 PUT( PutDouble, SbxDOUBLE, double, nDouble )
697 PUT( PutErr, SbxERROR, sal_uInt16, nUShort )
698 PUT( PutInteger, SbxINTEGER, sal_Int16, nInteger )
699 PUT( PutLong, SbxLONG, sal_Int32, nLong )
700 PUT( PutObject, SbxOBJECT, SbxBase*, pObj )
701 PUT( PutSingle, SbxSINGLE, float, nSingle )
702 PUT( PutULong, SbxULONG, sal_uInt32, nULong )
703 PUT( PutUShort, SbxUSHORT, sal_uInt16, nUShort )
704 PUT( PutInt64, SbxSALINT64, sal_Int64, nInt64 )
705 PUT( PutUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
706 PUT( PutDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
708 ////////////////////////// Setting of the data type ///////////////////////////
710 sal_Bool SbxValue::IsFixed() const
712 return ( (GetFlags() & SBX_FIXED) | (aData.eType & SbxBYREF) ) != 0;
715 // A variable is numeric, if it is EMPTY or realy numeric
716 // or if it contains a complete convertible String
718 // #41692, implement it for RTL and Basic-Core separately
719 sal_Bool SbxValue::IsNumeric() const
721 return ImpIsNumeric( /*bOnlyIntntl*/false );
724 sal_Bool SbxValue::IsNumericRTL() const
726 return ImpIsNumeric( /*bOnlyIntntl*/true );
729 sal_Bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const
732 if( !CanRead() )
734 SetError( SbxERR_PROP_WRITEONLY ); return sal_False;
736 // Test downcast!!!
737 if( this->ISA(SbxVariable) )
738 ((SbxVariable*)this)->Broadcast( SBX_HINT_DATAWANTED );
739 SbxDataType t = GetType();
740 if( t == SbxSTRING )
742 if( aData.pOUString )
744 OUString s( *aData.pOUString );
745 double n;
746 SbxDataType t2;
747 sal_uInt16 nLen = 0;
748 if( ImpScan( s, n, t2, &nLen, /*bAllowIntntl*/false, bOnlyIntntl ) == SbxERR_OK )
749 return sal_Bool( nLen == s.getLength() );
751 return sal_False;
753 else
754 return sal_Bool( t == SbxEMPTY
755 || ( t >= SbxINTEGER && t <= SbxCURRENCY )
756 || ( t >= SbxCHAR && t <= SbxUINT ) );
759 SbxClassType SbxValue::GetClass() const
761 return SbxCLASS_VALUE;
764 SbxDataType SbxValue::GetType() const
766 return SbxDataType( aData.eType & 0x0FFF );
769 SbxDataType SbxValue::GetFullType() const
771 return aData.eType;
774 sal_Bool SbxValue::SetType( SbxDataType t )
776 DBG_ASSERT( !( t & 0xF000 ), "SetType of BYREF|ARRAY is forbidden!" );
777 if( ( t == SbxEMPTY && aData.eType == SbxVOID )
778 || ( aData.eType == SbxEMPTY && t == SbxVOID ) )
779 return sal_True;
780 if( ( t & 0x0FFF ) == SbxVARIANT )
782 // Trial to set the data type to Variant
783 ResetFlag( SBX_FIXED );
784 if( IsFixed() )
786 SetError( SbxERR_CONVERSION ); return sal_False;
788 t = SbxEMPTY;
790 if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) )
792 if( !CanWrite() || IsFixed() )
794 SetError( SbxERR_CONVERSION ); return sal_False;
796 else
798 // De-allocate potential objects
799 switch( aData.eType )
801 case SbxSTRING:
802 delete aData.pOUString;
803 break;
804 case SbxOBJECT:
805 if( aData.pObj && aData.pObj != this )
807 SAL_WARN("basic.sbx", "Not at Parent-Prop - otherwise CyclicRef");
808 SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
809 sal_uInt16 nSlotId = pThisVar
810 ? ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) )
811 : 0;
812 DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName().equalsAscii("Parent"),
813 "SID_PARENTOBJECT is not named 'Parent'" );
814 sal_Bool bParentProp = 5345 == nSlotId;
815 if ( !bParentProp )
816 aData.pObj->ReleaseRef();
818 break;
819 default: break;
821 // This works always, because the Float representations are 0 as well.
822 memset( &aData, 0, sizeof( SbxValues ) );
823 aData.eType = t;
826 return sal_True;
829 sal_Bool SbxValue::Convert( SbxDataType eTo )
831 eTo = SbxDataType( eTo & 0x0FFF );
832 if( ( aData.eType & 0x0FFF ) == eTo )
833 return sal_True;
834 if( !CanWrite() )
835 return sal_False;
836 if( eTo == SbxVARIANT )
838 // Trial to set the data type to Variant
839 ResetFlag( SBX_FIXED );
840 if( IsFixed() )
842 SetError( SbxERR_CONVERSION ); return sal_False;
844 else
845 return sal_True;
847 // Converting from zero doesn't work. Once zero, always zero!
848 if( aData.eType == SbxNULL )
850 SetError( SbxERR_CONVERSION ); return sal_False;
853 // Conversion of the data:
854 SbxValues aNew;
855 aNew.eType = eTo;
856 if( Get( aNew ) )
858 // The data type could be converted. It ends here with fixed elements,
859 // because the data had not to be taken over
860 if( !IsFixed() )
862 SetType( eTo );
863 Put( aNew );
864 SetModified( sal_True );
866 Broadcast( SBX_HINT_CONVERTED );
867 return sal_True;
869 else
870 return sal_False;
872 ////////////////////////////////// Calculating /////////////////////////////////
874 sal_Bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
876 #ifdef DISABLE_SCRIPTING
877 bool bVBAInterop = false;
878 #else
879 bool bVBAInterop = SbiRuntime::isVBAEnabled();
880 #endif
881 SbxDataType eThisType = GetType();
882 SbxDataType eOpType = rOp.GetType();
883 SbxError eOld = GetError();
884 if( eOld != SbxERR_OK )
885 ResetError();
886 if( !CanWrite() )
887 SetError( SbxERR_PROP_READONLY );
888 else if( !rOp.CanRead() )
889 SetError( SbxERR_PROP_WRITEONLY );
890 // Special rule 1: If one operand is zero, the result is zero
891 else if( eThisType == SbxNULL || eOpType == SbxNULL )
892 SetType( SbxNULL );
893 // Special rule 2: If the operand is Empty, the result is the 2. operand
894 else if( eThisType == SbxEMPTY
895 && !bVBAInterop
897 *this = rOp;
898 // 1996-2-13: Don't test already before Get upon SbxEMPTY
899 else
901 SbxValues aL, aR;
902 bool bDecimal = false;
903 if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING && eOpType != SbxEMPTY ) ||
904 ( eThisType != SbxSTRING && eThisType != SbxEMPTY && eOpType == SbxSTRING ) ) &&
905 ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
907 goto Lbl_OpIsDouble;
909 else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && ( eOp == SbxPLUS ) ) )
911 if( eOp == SbxCAT || eOp == SbxPLUS )
913 // From 1999-11-5, keep OUString in mind
914 aL.eType = aR.eType = SbxSTRING;
915 rOp.Get( aR );
916 // From 1999-12-8, #70399: Here call GetType() again, Get() can change the type!
917 if( rOp.GetType() == SbxEMPTY )
918 goto Lbl_OpIsEmpty;
919 Get( aL );
921 // #30576: To begin with test, if the conversion worked
922 if( aL.pOUString != NULL && aR.pOUString != NULL )
924 *aL.pOUString += *aR.pOUString;
926 // Not even Left OK?
927 else if( aL.pOUString == NULL )
929 aL.pOUString = new OUString();
931 Put( aL );
933 else
934 SetError( SbxERR_CONVERSION );
936 else if( eOpType == SbxSTRING && rOp.IsFixed() )
937 { // Numeric: there is no String allowed on the right side
938 SetError( SbxERR_CONVERSION );
939 // falls all the way out
941 else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
943 if( GetType() == eOpType )
945 if( GetType() == SbxSALUINT64 || GetType() == SbxSALINT64
946 || GetType() == SbxCURRENCY || GetType() == SbxULONG )
947 aL.eType = aR.eType = GetType();
948 else if ( bVBAInterop && eOpType == SbxBOOL )
949 aL.eType = aR.eType = SbxBOOL;
950 else
951 aL.eType = aR.eType = SbxLONG;
953 else
954 aL.eType = aR.eType = SbxLONG;
956 if( rOp.Get( aR ) ) // re-do Get after type assigns above
958 if( rOp.GetType() == SbxEMPTY )
960 if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNOT ) ) )
961 goto Lbl_OpIsEmpty;
963 if( Get( aL ) ) switch( eOp )
965 case SbxIDIV:
966 if( aL.eType == SbxCURRENCY )
967 if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
968 else {
969 aL.nInt64 /= aR.nInt64;
970 aL.nInt64 *= CURRENCY_FACTOR;
972 else if( aL.eType == SbxSALUINT64 )
973 if( !aR.uInt64 ) SetError( SbxERR_ZERODIV );
974 else aL.uInt64 /= aR.uInt64;
975 else if( aL.eType == SbxSALINT64 )
976 if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
977 else aL.nInt64 /= aR.nInt64;
978 else if( aL.eType == SbxLONG )
979 if( !aR.nLong ) SetError( SbxERR_ZERODIV );
980 else aL.nLong /= aR.nLong;
981 else
982 if( !aR.nULong ) SetError( SbxERR_ZERODIV );
983 else aL.nULong /= aR.nULong;
984 break;
985 case SbxMOD:
986 if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
987 if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
988 else aL.nInt64 %= aR.nInt64;
989 else if( aL.eType == SbxSALUINT64 )
990 if( !aR.uInt64 ) SetError( SbxERR_ZERODIV );
991 else aL.uInt64 %= aR.uInt64;
992 else if( aL.eType == SbxLONG )
993 if( !aR.nLong ) SetError( SbxERR_ZERODIV );
994 else aL.nLong %= aR.nLong;
995 else
996 if( !aR.nULong ) SetError( SbxERR_ZERODIV );
997 else aL.nULong %= aR.nULong;
998 break;
999 case SbxAND:
1000 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1001 aL.nInt64 &= aR.nInt64;
1002 else
1003 aL.nLong &= aR.nLong;
1004 break;
1005 case SbxOR:
1006 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1007 aL.nInt64 |= aR.nInt64;
1008 else
1009 aL.nLong |= aR.nLong;
1010 break;
1011 case SbxXOR:
1012 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1013 aL.nInt64 ^= aR.nInt64;
1014 else
1015 aL.nLong ^= aR.nLong;
1016 break;
1017 case SbxEQV:
1018 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1019 aL.nInt64 = (aL.nInt64 & aR.nInt64) | (~aL.nInt64 & ~aR.nInt64);
1020 else
1021 aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
1022 break;
1023 case SbxIMP:
1024 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1025 aL.nInt64 = ~aL.nInt64 | aR.nInt64;
1026 else
1027 aL.nLong = ~aL.nLong | aR.nLong;
1028 break;
1029 case SbxNOT:
1030 if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1032 if ( aL.eType != SbxBOOL )
1033 aL.nInt64 = ~aL.nInt64;
1034 else
1035 aL.nLong = ~aL.nLong;
1037 else
1038 aL.nLong = ~aL.nLong;
1039 break;
1040 default: break;
1044 else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL )
1045 && ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
1047 aL.eType = aR.eType = SbxDECIMAL;
1048 bDecimal = true;
1049 if( rOp.Get( aR ) )
1051 if( rOp.GetType() == SbxEMPTY )
1053 releaseDecimalPtr( aL.pDecimal );
1054 goto Lbl_OpIsEmpty;
1056 if( Get( aL ) )
1058 if( aL.pDecimal && aR.pDecimal )
1060 bool bOk = true;
1061 switch( eOp )
1063 case SbxMUL:
1064 bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
1065 break;
1066 case SbxDIV:
1067 if( aR.pDecimal->isZero() )
1068 SetError( SbxERR_ZERODIV );
1069 else
1070 bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
1071 break;
1072 case SbxPLUS:
1073 bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
1074 break;
1075 case SbxMINUS:
1076 bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
1077 break;
1078 case SbxNEG:
1079 bOk = ( aL.pDecimal->neg() );
1080 break;
1081 default:
1082 SetError( SbxERR_NOTIMP );
1084 if( !bOk )
1085 SetError( SbxERR_OVERFLOW );
1087 else
1089 SetError( SbxERR_CONVERSION );
1094 else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
1096 aL.eType = SbxCURRENCY;
1097 aR.eType = SbxCURRENCY;
1099 if( rOp.Get( aR ) )
1101 if( rOp.GetType() == SbxEMPTY )
1102 goto Lbl_OpIsEmpty;
1104 if( Get( aL ) ) switch( eOp )
1106 double dTest;
1107 case SbxMUL:
1108 // first overflow check: see if product will fit - test real value of product (hence 2 curr factors)
1109 dTest = (double)aL.nInt64 * (double)aR.nInt64 / (double)CURRENCY_FACTOR_SQUARE;
1110 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1112 aL.nInt64 = SAL_MAX_INT64;
1113 if( dTest < SbxMINCURR ) aL.nInt64 = SAL_MIN_INT64;
1114 SetError( SbxERR_OVERFLOW );
1115 break;
1117 // second overflow check: see if unscaled product overflows - if so use doubles
1118 dTest = (double)aL.nInt64 * (double)aR.nInt64;
1119 if( dTest < SAL_MIN_INT64 || SAL_MAX_INT64 < dTest)
1121 aL.nInt64 = (sal_Int64)( dTest / (double)CURRENCY_FACTOR );
1122 break;
1124 // precise calc: multiply then scale back (move decimal pt)
1125 aL.nInt64 *= aR.nInt64;
1126 aL.nInt64 /= CURRENCY_FACTOR;
1127 break;
1129 case SbxDIV:
1130 if( !aR.nInt64 )
1132 SetError( SbxERR_ZERODIV );
1133 break;
1135 // first overflow check: see if quotient will fit - calc real value of quotient (curr factors cancel)
1136 dTest = (double)aL.nInt64 / (double)aR.nInt64;
1137 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1139 SetError( SbxERR_OVERFLOW );
1140 break;
1142 // second overflow check: see if scaled dividend overflows - if so use doubles
1143 dTest = (double)aL.nInt64 * (double)CURRENCY_FACTOR;
1144 if( dTest < SAL_MIN_INT64 || SAL_MAX_INT64 < dTest)
1146 aL.nInt64 = (sal_Int64)(dTest / (double)aR.nInt64);
1147 break;
1149 // precise calc: scale (move decimal pt) then divide
1150 aL.nInt64 *= CURRENCY_FACTOR;
1151 aL.nInt64 /= aR.nInt64;
1152 break;
1154 case SbxPLUS:
1155 dTest = ( (double)aL.nInt64 + (double)aR.nInt64 ) / (double)CURRENCY_FACTOR;
1156 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1158 SetError( SbxERR_OVERFLOW );
1159 break;
1161 aL.nInt64 += aR.nInt64;
1162 break;
1164 case SbxMINUS:
1165 dTest = ( (double)aL.nInt64 - (double)aR.nInt64 ) / (double)CURRENCY_FACTOR;
1166 if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1168 SetError( SbxERR_OVERFLOW );
1169 break;
1171 aL.nInt64 -= aR.nInt64;
1172 break;
1173 case SbxNEG:
1174 aL.nInt64 = -aL.nInt64;
1175 break;
1176 default:
1177 SetError( SbxERR_NOTIMP );
1181 else
1182 Lbl_OpIsDouble:
1183 { // other types and operators including Date, Double and Single
1184 aL.eType = aR.eType = SbxDOUBLE;
1185 if( rOp.Get( aR ) )
1187 if( rOp.GetType() == SbxEMPTY )
1189 if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNEG ) ) )
1190 goto Lbl_OpIsEmpty;
1192 if( Get( aL ) )
1194 switch( eOp )
1196 case SbxEXP:
1197 aL.nDouble = pow( aL.nDouble, aR.nDouble );
1198 break;
1199 case SbxMUL:
1200 aL.nDouble *= aR.nDouble; break;
1201 case SbxDIV:
1202 if( !aR.nDouble ) SetError( SbxERR_ZERODIV );
1203 else aL.nDouble /= aR.nDouble; break;
1204 case SbxPLUS:
1205 aL.nDouble += aR.nDouble; break;
1206 case SbxMINUS:
1207 aL.nDouble -= aR.nDouble; break;
1208 case SbxNEG:
1209 aL.nDouble = -aL.nDouble; break;
1210 default:
1211 SetError( SbxERR_NOTIMP );
1213 // Date with "+" or "-" needs special handling that
1214 // forces the Date type. If the operation is '+' the
1215 // result is always a Date, if '-' the result is only
1216 // a Date if one of lhs or rhs ( but not both ) is already
1217 // a Date
1218 if( ( GetType() == SbxDATE || rOp.GetType() == SbxDATE ) )
1220 if( eOp == SbxPLUS || ( ( eOp == SbxMINUS ) && ( GetType() != rOp.GetType() ) ) )
1221 aL.eType = SbxDATE;
1228 if( !IsError() )
1229 Put( aL );
1230 if( bDecimal )
1232 releaseDecimalPtr( aL.pDecimal );
1233 releaseDecimalPtr( aR.pDecimal );
1236 Lbl_OpIsEmpty:
1238 sal_Bool bRes = sal_Bool( !IsError() );
1239 if( bRes && eOld != SbxERR_OK )
1240 SetError( eOld );
1241 return bRes;
1244 // The comparison routine deliver TRUE or FALSE.
1246 sal_Bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
1248 #ifdef DISABLE_SCRIPTING
1249 bool bVBAInterop = false;
1250 #else
1251 bool bVBAInterop = SbiRuntime::isVBAEnabled();
1252 #endif
1254 sal_Bool bRes = sal_False;
1255 SbxError eOld = GetError();
1256 if( eOld != SbxERR_OK )
1257 ResetError();
1258 if( !CanRead() || !rOp.CanRead() )
1259 SetError( SbxERR_PROP_WRITEONLY );
1260 else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
1262 bRes = sal_True;
1264 else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
1265 bRes = !bVBAInterop ? sal_True : ( eOp == SbxEQ ? sal_True : sal_False );
1266 // Special rule 1: If an operand is zero, the result is FALSE
1267 else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
1268 bRes = sal_False;
1269 // Special rule 2: If both are variant and one is numeric
1270 // and the other is a String, num is < str
1271 else if( !IsFixed() && !rOp.IsFixed()
1272 && ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
1274 bRes = sal_Bool( eOp == SbxLT || eOp == SbxLE || eOp == SbxNE );
1275 else if( !IsFixed() && !rOp.IsFixed()
1276 && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
1277 && !bVBAInterop
1279 bRes = sal_Bool( eOp == SbxGT || eOp == SbxGE || eOp == SbxNE );
1280 else
1282 SbxValues aL, aR;
1283 // If one of the operands is a String,
1284 // a String comparing take place
1285 if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
1287 aL.eType = aR.eType = SbxSTRING;
1288 if( Get( aL ) && rOp.Get( aR ) ) switch( eOp )
1290 case SbxEQ:
1291 bRes = sal_Bool( *aL.pOUString == *aR.pOUString ); break;
1292 case SbxNE:
1293 bRes = sal_Bool( *aL.pOUString != *aR.pOUString ); break;
1294 case SbxLT:
1295 bRes = sal_Bool( *aL.pOUString < *aR.pOUString ); break;
1296 case SbxGT:
1297 bRes = sal_Bool( *aL.pOUString > *aR.pOUString ); break;
1298 case SbxLE:
1299 bRes = sal_Bool( *aL.pOUString <= *aR.pOUString ); break;
1300 case SbxGE:
1301 bRes = sal_Bool( *aL.pOUString >= *aR.pOUString ); break;
1302 default:
1303 SetError( SbxERR_NOTIMP );
1306 // From 1995-12-19: If SbxSINGLE participate, then convert to SINGLE,
1307 // elsewise it shows a numeric error
1308 else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
1310 aL.eType = aR.eType = SbxSINGLE;
1311 if( Get( aL ) && rOp.Get( aR ) )
1312 switch( eOp )
1314 case SbxEQ:
1315 bRes = sal_Bool( aL.nSingle == aR.nSingle ); break;
1316 case SbxNE:
1317 bRes = sal_Bool( aL.nSingle != aR.nSingle ); break;
1318 case SbxLT:
1319 bRes = sal_Bool( aL.nSingle < aR.nSingle ); break;
1320 case SbxGT:
1321 bRes = sal_Bool( aL.nSingle > aR.nSingle ); break;
1322 case SbxLE:
1323 bRes = sal_Bool( aL.nSingle <= aR.nSingle ); break;
1324 case SbxGE:
1325 bRes = sal_Bool( aL.nSingle >= aR.nSingle ); break;
1326 default:
1327 SetError( SbxERR_NOTIMP );
1330 else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
1332 aL.eType = aR.eType = SbxDECIMAL;
1333 Get( aL );
1334 rOp.Get( aR );
1335 if( aL.pDecimal && aR.pDecimal )
1337 SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
1338 switch( eOp )
1340 case SbxEQ:
1341 bRes = sal_Bool( eRes == SbxDecimal::EQ ); break;
1342 case SbxNE:
1343 bRes = sal_Bool( eRes != SbxDecimal::EQ ); break;
1344 case SbxLT:
1345 bRes = sal_Bool( eRes == SbxDecimal::LT ); break;
1346 case SbxGT:
1347 bRes = sal_Bool( eRes == SbxDecimal::GT ); break;
1348 case SbxLE:
1349 bRes = sal_Bool( eRes != SbxDecimal::GT ); break;
1350 case SbxGE:
1351 bRes = sal_Bool( eRes != SbxDecimal::LT ); break;
1352 default:
1353 SetError( SbxERR_NOTIMP );
1356 else
1358 SetError( SbxERR_CONVERSION );
1360 releaseDecimalPtr( aL.pDecimal );
1361 releaseDecimalPtr( aR.pDecimal );
1363 // Everything else comparing on a SbxDOUBLE-Basis
1364 else
1366 aL.eType = aR.eType = SbxDOUBLE;
1367 bool bGetL = Get( aL );
1368 bool bGetR = rOp.Get( aR );
1369 if( bGetL && bGetR )
1370 switch( eOp )
1372 case SbxEQ:
1373 bRes = sal_Bool( aL.nDouble == aR.nDouble ); break;
1374 case SbxNE:
1375 bRes = sal_Bool( aL.nDouble != aR.nDouble ); break;
1376 case SbxLT:
1377 bRes = sal_Bool( aL.nDouble < aR.nDouble ); break;
1378 case SbxGT:
1379 bRes = sal_Bool( aL.nDouble > aR.nDouble ); break;
1380 case SbxLE:
1381 bRes = sal_Bool( aL.nDouble <= aR.nDouble ); break;
1382 case SbxGE:
1383 bRes = sal_Bool( aL.nDouble >= aR.nDouble ); break;
1384 default:
1385 SetError( SbxERR_NOTIMP );
1387 // at least one value was got
1388 // if this is VBA then a conversion error for one
1389 // side will yield a false result of an equality test
1390 else if ( bGetR || bGetL )
1392 if ( bVBAInterop && eOp == SbxEQ && GetError() == SbxERR_CONVERSION )
1394 ResetError();
1395 bRes = sal_False;
1400 if( eOld != SbxERR_OK )
1401 SetError( eOld );
1402 return bRes;
1405 ///////////////////////////// Reading/Writing ////////////////////////////
1407 sal_Bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
1409 // #TODO see if these types are really dumped to any stream
1410 // more than likely this is functionality used in the binfilter alone
1411 SbxValue::Clear();
1412 sal_uInt16 nType;
1413 r >> nType;
1414 aData.eType = SbxDataType( nType );
1415 switch( nType )
1417 case SbxBOOL:
1418 case SbxINTEGER:
1419 r >> aData.nInteger; break;
1420 case SbxLONG:
1421 r >> aData.nLong; break;
1422 case SbxSINGLE:
1424 // Floats as ASCII
1425 OUString aVal = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(r,
1426 RTL_TEXTENCODING_ASCII_US);
1427 double d;
1428 SbxDataType t;
1429 if( ImpScan( aVal, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE )
1431 aData.nSingle = 0.0F;
1432 return sal_False;
1434 aData.nSingle = (float) d;
1435 break;
1437 case SbxDATE:
1438 case SbxDOUBLE:
1440 // Floats as ASCII
1441 OUString aVal = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(r,
1442 RTL_TEXTENCODING_ASCII_US);
1443 SbxDataType t;
1444 if( ImpScan( aVal, aData.nDouble, t, NULL ) != SbxERR_OK )
1446 aData.nDouble = 0.0;
1447 return sal_False;
1449 break;
1451 //#fdo39428 SvStream no longer supports operator>>(long&)
1452 case SbxSALINT64:
1453 r.ReadInt64(aData.nInt64);
1454 break;
1455 case SbxSALUINT64:
1456 r >> aData.uInt64;
1457 break;
1458 case SbxCURRENCY:
1460 sal_uInt32 tmpHi = 0;
1461 sal_uInt32 tmpLo = 0;
1462 r >> tmpHi >> tmpLo;
1463 aData.nInt64 = ((sal_Int64)tmpHi << 32);
1464 aData.nInt64 |= (sal_Int64)tmpLo;
1465 break;
1467 case SbxSTRING:
1469 OUString aVal = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(r,
1470 RTL_TEXTENCODING_ASCII_US);
1471 if( !aVal.isEmpty() )
1472 aData.pOUString = new OUString( aVal );
1473 else
1474 aData.pOUString = NULL; // JSM 1995-09-22
1475 break;
1477 case SbxERROR:
1478 case SbxUSHORT:
1479 r >> aData.nUShort; break;
1480 case SbxOBJECT:
1482 sal_uInt8 nMode;
1483 r >> nMode;
1484 switch( nMode )
1486 case 0:
1487 aData.pObj = NULL;
1488 break;
1489 case 1:
1490 aData.pObj = SbxBase::Load( r );
1491 return sal_Bool( aData.pObj != NULL );
1492 case 2:
1493 aData.pObj = this;
1494 break;
1496 break;
1498 case SbxCHAR:
1500 char c;
1501 r >> c;
1502 aData.nChar = c;
1503 break;
1505 case SbxBYTE:
1506 r >> aData.nByte; break;
1507 case SbxULONG:
1508 r >> aData.nULong; break;
1509 case SbxINT:
1511 sal_uInt8 n;
1512 r >> n;
1513 // Match the Int on this system?
1514 if( n > SAL_TYPES_SIZEOFINT )
1515 r >> aData.nLong, aData.eType = SbxLONG;
1516 else {
1517 sal_Int32 nInt;
1518 r >> nInt;
1519 aData.nInt = nInt;
1521 break;
1523 case SbxUINT:
1525 sal_uInt8 n;
1526 r >> n;
1527 // Match the UInt on this system?
1528 if( n > SAL_TYPES_SIZEOFINT )
1529 r >> aData.nULong, aData.eType = SbxULONG;
1530 else {
1531 sal_uInt32 nUInt;
1532 r >> nUInt;
1533 aData.nUInt = nUInt;
1535 break;
1537 case SbxEMPTY:
1538 case SbxNULL:
1539 case SbxVOID:
1540 break;
1541 case SbxDATAOBJECT:
1542 r >> aData.nLong;
1543 break;
1544 // #78919 For backwards compatibility
1545 case SbxWSTRING:
1546 case SbxWCHAR:
1547 break;
1548 default:
1549 memset (&aData,0,sizeof(aData));
1550 ResetFlag(SBX_FIXED);
1551 aData.eType = SbxNULL;
1552 DBG_ASSERT( !this, "Loaded a non-supported data type" );
1554 return sal_False;
1556 return sal_True;
1559 sal_Bool SbxValue::StoreData( SvStream& r ) const
1561 sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
1562 r << nType;
1563 switch( nType & 0x0FFF )
1565 case SbxBOOL:
1566 case SbxINTEGER:
1567 r << aData.nInteger; break;
1568 case SbxLONG:
1569 r << aData.nLong; break;
1570 case SbxDATE:
1571 // #49935: Save as double, elsewise an error during the read in
1572 ((SbxValue*)this)->aData.eType = (SbxDataType)( ( nType & 0xF000 ) | SbxDOUBLE );
1573 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1574 ((SbxValue*)this)->aData.eType = (SbxDataType)nType;
1575 break;
1576 case SbxSINGLE:
1577 case SbxDOUBLE:
1578 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1579 break;
1580 case SbxSALUINT64:
1581 case SbxSALINT64:
1582 // see comment in SbxValue::StoreData
1583 r << aData.uInt64;
1584 break;
1585 case SbxCURRENCY:
1587 sal_Int32 tmpHi = ( (aData.nInt64 >> 32) & 0xFFFFFFFF );
1588 sal_Int32 tmpLo = ( sal_Int32 )aData.nInt64;
1589 r << tmpHi << tmpLo;
1590 break;
1592 case SbxSTRING:
1593 if( aData.pOUString )
1595 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, *aData.pOUString, RTL_TEXTENCODING_ASCII_US);
1597 else
1599 write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, OUString(), RTL_TEXTENCODING_ASCII_US);
1601 break;
1602 case SbxERROR:
1603 case SbxUSHORT:
1604 r << aData.nUShort; break;
1605 case SbxOBJECT:
1606 // to save itself as Objectptr does not work!
1607 if( aData.pObj )
1609 if( PTR_CAST(SbxValue,aData.pObj) != this )
1611 r << (sal_uInt8) 1;
1612 return aData.pObj->Store( r );
1614 else
1615 r << (sal_uInt8) 2;
1617 else
1618 r << (sal_uInt8) 0;
1619 break;
1620 case SbxCHAR:
1622 char c = sal::static_int_cast< char >(aData.nChar);
1623 r << c;
1624 break;
1626 case SbxBYTE:
1627 r << aData.nByte; break;
1628 case SbxULONG:
1629 r << aData.nULong; break;
1630 case SbxINT:
1632 sal_uInt8 n = SAL_TYPES_SIZEOFINT;
1633 r << n << (sal_Int32)aData.nInt;
1634 break;
1636 case SbxUINT:
1638 sal_uInt8 n = SAL_TYPES_SIZEOFINT;
1639 r << n << (sal_uInt32)aData.nUInt;
1640 break;
1642 case SbxEMPTY:
1643 case SbxNULL:
1644 case SbxVOID:
1645 break;
1646 case SbxDATAOBJECT:
1647 r << aData.nLong;
1648 break;
1649 // #78919 For backwards compatibility
1650 case SbxWSTRING:
1651 case SbxWCHAR:
1652 break;
1653 default:
1654 DBG_ASSERT( !this, "Saving a non-supported data type" );
1655 return sal_False;
1657 return sal_True;
1660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */