blob: 3530eb6bc311da129ce7e6e95e77dc6b7063b9d4 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#define _TLBIGINT_INT64
#include <tools/bigint.hxx>
#include <tools/stream.hxx>
#include <basic/sbx.hxx>
#include "sbxconv.hxx"
#include <math.h>
#include "runtime.hxx"
// AB 29.10.99 Unicode
#ifndef _USE_NO_NAMESPACE
using namespace rtl;
#endif
TYPEINIT1(SbxValue,SbxBase)
/////////////////////////// SbxINT64 /////////////////////////////////////
SbxINT64 &SbxINT64::operator -= ( const SbxINT64 &r )
{
BigInt b( *this );
b -= BigInt( r );
b.INT64( this );
return *this;
}
SbxINT64 &SbxINT64::operator += ( const SbxINT64 &r )
{
BigInt b( *this );
b += BigInt( r );
b.INT64( this );
return *this;
}
SbxINT64 &SbxINT64::operator *= ( const SbxINT64 &r )
{
BigInt b( *this );
b *= BigInt( r );
b.INT64( this );
return *this;
}
SbxINT64 &SbxINT64::operator %= ( const SbxINT64 &r )
{
BigInt b( *this );
b %= BigInt( r );
b.INT64( this );
return *this;
}
SbxINT64 &SbxINT64::operator /= ( const SbxINT64 &r )
{
BigInt b( *this );
b /= BigInt( r );
b.INT64( this );
return *this;
}
SbxINT64 &SbxINT64::operator &= ( const SbxINT64 &r )
{
nHigh &= r.nHigh;
nLow &= r.nLow;
return *this;
}
SbxINT64 &SbxINT64::operator |= ( const SbxINT64 &r )
{
nHigh |= r.nHigh;
nLow |= r.nLow;
return *this;
}
SbxINT64 &SbxINT64::operator ^= ( const SbxINT64 &r )
{
nHigh ^= r.nHigh;
nLow ^= r.nLow;
return *this;
}
SbxINT64 operator - ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a(l);
a -= r;
return a;
}
SbxINT64 operator + ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a(l);
a += r;
return a;
}
SbxINT64 operator / ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a(l);
a /= r;
return a;
}
SbxINT64 operator % ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a(l);
a %= r;
return a;
}
SbxINT64 operator * ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a(l);
a *= r;
return a;
}
SbxINT64 operator & ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a;
a.nHigh = r.nHigh & l.nHigh;
a.nLow = r.nLow & l.nLow;
return a;
}
SbxINT64 operator | ( const SbxINT64 &l, const SbxINT64 &r )
{
SbxINT64 a;
a.nHigh = r.nHigh | l.nHigh;
a.nLow = r.nLow | l.nLow;
return a;
}
SbxINT64 operator ^ ( const SbxINT64 &r, const SbxINT64 &l )
{
SbxINT64 a;
a.nHigh = r.nHigh ^ l.nHigh;
a.nLow = r.nLow ^ l.nLow;
return a;
}
SbxINT64 operator - ( const SbxINT64 &r )
{
SbxINT64 a( r );
a.CHS();
return a;
}
SbxINT64 operator ~ ( const SbxINT64 &r )
{
SbxINT64 a;
a.nHigh = ~r.nHigh;
a.nLow = ~r.nLow;
return a;
}
SbxUINT64 &SbxUINT64::operator %= ( const SbxUINT64 &r )
{
BigInt b( *this );
b %= BigInt( r );
b.UINT64( this );
return *this;
}
SbxUINT64 &SbxUINT64::operator /= ( const SbxUINT64 &r )
{
BigInt b( *this );
b /= BigInt( r );
b.UINT64( this );
return *this;
}
/////////////////////////// Fehlerbehandlung /////////////////////////////
#ifdef _USED
// NOCH NACHZUBAUEN!
// Das Default-Handling setzt nur den Fehlercode.
#ifndef WNT
#if defined ( UNX )
int matherr( struct exception* p )
#else
int matherr( struct _exception* p )
#endif
{
switch( p->type )
{
#if defined ( UNX )
case OVERFLOW: SbxBase::SetError( SbxERR_OVERFLOW ); break;
#else
case _OVERFLOW: SbxBase::SetError( SbxERR_OVERFLOW ); break;
#endif
default: SbxBase::SetError( SbxERR_NOTIMP ); break;
}
return sal_True;
}
#endif
#endif // _USED
///////////////////////////// Konstruktoren //////////////////////////////
SbxValue::SbxValue() : SbxBase()
{
aData.eType = SbxEMPTY;
}
SbxValue::SbxValue( SbxDataType t, void* p ) : SbxBase()
{
int n = t & 0x0FFF;
if( p )
n |= SbxBYREF;
if( n == SbxVARIANT )
n = SbxEMPTY;
else
SetFlag( SBX_FIXED );
if( p )
switch( t & 0x0FFF )
{
case SbxINTEGER: n |= SbxBYREF; aData.pInteger = (sal_Int16*) p; break;
case SbxULONG64: n |= SbxBYREF; aData.pULong64 = (SbxUINT64*) p; break;
case SbxLONG64:
case SbxCURRENCY: n |= SbxBYREF; aData.pLong64 = (SbxINT64*) p; break;
case SbxLONG: n |= SbxBYREF; aData.pLong = (sal_Int32*) p; break;
case SbxSINGLE: n |= SbxBYREF; aData.pSingle = (float*) p; break;
case SbxDATE:
case SbxDOUBLE: n |= SbxBYREF; aData.pDouble = (double*) p; break;
case SbxSTRING: n |= SbxBYREF; aData.pOUString = (::rtl::OUString*) p; break;
case SbxERROR:
case SbxUSHORT:
case SbxBOOL: n |= SbxBYREF; aData.pUShort = (sal_uInt16*) p; break;
case SbxULONG: n |= SbxBYREF; aData.pULong = (sal_uInt32*) p; break;
case SbxCHAR: n |= SbxBYREF; aData.pChar = (xub_Unicode*) p; break;
case SbxBYTE: n |= SbxBYREF; aData.pByte = (sal_uInt8*) p; break;
case SbxINT: n |= SbxBYREF; aData.pInt = (int*) p; break;
case SbxOBJECT:
aData.pObj = (SbxBase*) p;
if( p )
aData.pObj->AddRef();
break;
case SbxDECIMAL:
aData.pDecimal = (SbxDecimal*) p;
if( p )
aData.pDecimal->addRef();
break;
default:
DBG_ASSERT( !this, "Angabe eines Pointers unzulaessig" );
n = SbxNULL;
}
else
memset( &aData, 0, sizeof( SbxValues ) );
aData.eType = SbxDataType( n );
}
SbxValue::SbxValue( const SbxValue& r )
: SvRefBase( r ), SbxBase( r )
{
if( !r.CanRead() )
{
SetError( SbxERR_PROP_WRITEONLY );
if( !IsFixed() )
aData.eType = SbxNULL;
}
else
{
((SbxValue*) &r)->Broadcast( SBX_HINT_DATAWANTED );
aData = r.aData;
// Pointer kopieren, Referenzen inkrementieren
switch( aData.eType )
{
case SbxSTRING:
if( aData.pOUString )
aData.pOUString = new ::rtl::OUString( *aData.pOUString );
break;
case SbxOBJECT:
if( aData.pObj )
aData.pObj->AddRef();
break;
case SbxDECIMAL:
if( aData.pDecimal )
aData.pDecimal->addRef();
break;
default: break;
}
}
}
SbxValue& SbxValue::operator=( const SbxValue& r )
{
if( &r != this )
{
if( !CanWrite() )
SetError( SbxERR_PROP_READONLY );
else
{
// string -> byte array
if( IsFixed() && (aData.eType == SbxOBJECT)
&& aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
&& (r.aData.eType == SbxSTRING) )
{
::rtl::OUString aStr = r.GetString();
SbxArray* pArr = StringToByteArray(aStr);
PutObject(pArr);
return *this;
}
// byte array -> string
if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
&& r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
&& (aData.eType == SbxSTRING) )
{
SbxBase* pObj = r.GetObject();
SbxArray* pArr = PTR_CAST(SbxArray, pObj);
if( pArr )
{
::rtl::OUString aStr = ByteArrayToString( pArr );
PutString(aStr);
return *this;
}
}
// Den Inhalt der Variablen auslesen
SbxValues aNew;
if( IsFixed() )
// fest: dann muss der Typ stimmen
aNew.eType = aData.eType;
else if( r.IsFixed() )
// Quelle fest: Typ uebernehmen
aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
else
// beides Variant: dann isses egal
aNew.eType = SbxVARIANT;
if( r.Get( aNew ) )
Put( aNew );
}
}
return *this;
}
SbxValue::~SbxValue()
{
#ifndef C50
Broadcast( SBX_HINT_DYING );
SetFlag( SBX_WRITE );
SbxValue::Clear();
#else
// Provisorischer Fix fuer Solaris 5.0 Compiler Bug
// bei Nutzung virtueller Vererbung. Virtuelle Calls
// im Destruktor vermeiden. Statt Clear() zu rufen
// moegliche Objekt-Referenzen direkt freigeben.
if( aData.eType == SbxOBJECT )
{
if( aData.pObj && aData.pObj != this )
{
HACK(nicht bei Parent-Prop - sonst CyclicRef)
SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
sal_Bool bParentProp = pThisVar && 5345 ==
( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
if ( !bParentProp )
aData.pObj->ReleaseRef();
}
}
else if( aData.eType == SbxDECIMAL )
{
releaseDecimalPtr( aData.pDecimal );
}
#endif
}
void SbxValue::Clear()
{
switch( aData.eType )
{
case SbxNULL:
case SbxEMPTY:
case SbxVOID:
break;
case SbxSTRING:
delete aData.pOUString; aData.pOUString = NULL;
break;
case SbxOBJECT:
if( aData.pObj )
{
if( aData.pObj != this )
{
HACK(nicht bei Parent-Prop - sonst CyclicRef)
SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
sal_Bool bParentProp = pThisVar && 5345 ==
( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
if ( !bParentProp )
aData.pObj->ReleaseRef();
}
aData.pObj = NULL;
}
break;
case SbxDECIMAL:
if( aData.eType == SbxDECIMAL )
releaseDecimalPtr( aData.pDecimal );
break;
case SbxDATAOBJECT:
aData.pData = NULL; break;
default:
{
SbxValues aEmpty;
memset( &aEmpty, 0, sizeof( SbxValues ) );
aEmpty.eType = GetType();
Put( aEmpty );
}
}
}
// Dummy
void SbxValue::Broadcast( sal_uIntPtr )
{}
//////////////////////////// Daten auslesen //////////////////////////////
// Ermitteln der "richtigen" Variablen. Falls es ein Objekt ist, wird
// entweder das Objekt selbst oder dessen Default-Property angesprochen.
// Falls die Variable eine Variable oder ein Objekt enthaelt, wird
// dieses angesprochen.
SbxValue* SbxValue::TheRealValue() const
{
return TheRealValue( sal_True );
}
// #55226 Zusaetzliche Info transportieren
bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal ); // sbunoobj.cxx
SbxValue* SbxValue::TheRealValue( sal_Bool bObjInObjError ) const
{
SbxValue* p = (SbxValue*) this;
for( ;; )
{
SbxDataType t = SbxDataType( p->aData.eType & 0x0FFF );
if( t == SbxOBJECT )
{
// Der Block enthaelt ein Objekt oder eine Variable
SbxObject* pObj = PTR_CAST(SbxObject,p->aData.pObj);
if( pObj )
{
// Hat das Objekt eine Default-Property?
SbxVariable* pDflt = pObj->GetDfltProperty();
// Falls dies ein Objekt ist und sich selbst enthaelt,
// koennen wir nicht darauf zugreifen
// #55226# Die alte Bedingung, um einen Fehler zu setzen,
// ist nicht richtig, da z.B. eine ganz normale Variant-
// Variable mit Objekt davon betroffen sein kann, wenn ein
// anderer Wert zugewiesen werden soll. Daher mit Flag.
if( bObjInObjError && !pDflt &&
((SbxValue*) pObj)->aData.eType == SbxOBJECT &&
((SbxValue*) pObj)->aData.pObj == pObj )
{
bool bSuccess = handleToStringForCOMObjects( pObj, p );
if( !bSuccess )
{
SetError( SbxERR_BAD_PROP_VALUE );
p = NULL;
}
}
else if( pDflt )
p = pDflt;
/* ALT:
else
p = pDflt ? pDflt : (SbxVariable*) pObj;
*/
break;
}
// Haben wir ein Array?
SbxArray* pArray = PTR_CAST(SbxArray,p->aData.pObj);
if( pArray )
{
// Ggf. Parameter holen
SbxArray* pPar = NULL;
SbxVariable* pVar = PTR_CAST(SbxVariable,p);
if( pVar )
pPar = pVar->GetParameters();
if( pPar )
{
// Haben wir ein dimensioniertes Array?
SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,p->aData.pObj);
if( pDimArray )
p = pDimArray->Get( pPar );
else
p = pArray->Get( pPar->Get( 1 )->GetInteger() );
break;
}
}
// Sonst einen SbxValue annehmen
SbxValue* pVal = PTR_CAST(SbxValue,p->aData.pObj);
if( pVal )
p = pVal;
else
break;
}
else
break;
}
return p;
}
sal_Bool SbxValue::Get( SbxValues& rRes ) const
{
sal_Bool bRes = sal_False;
SbxError eOld = GetError();
if( eOld != SbxERR_OK )
ResetError();
if( !CanRead() )
{
SetError( SbxERR_PROP_WRITEONLY );
rRes.pObj = NULL;
}
else
{
// Falls nach einem Objekt oder einem VARIANT gefragt wird, nicht
// die wahren Werte suchen
SbxValue* p = (SbxValue*) this;
if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
p = TheRealValue();
if( p )
{
p->Broadcast( SBX_HINT_DATAWANTED );
switch( rRes.eType )
{
case SbxEMPTY:
case SbxVOID:
case SbxNULL: break;
case SbxVARIANT: rRes = p->aData; break;
case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
case SbxLONG: rRes.nLong = ImpGetLong( &p->aData ); break;
case SbxSALINT64: rRes.nInt64 = ImpGetInt64( &p->aData ); break;
case SbxSALUINT64: rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
case SbxSINGLE: rRes.nSingle = ImpGetSingle( &p->aData ); break;
case SbxDOUBLE: rRes.nDouble = ImpGetDouble( &p->aData ); break;
case SbxCURRENCY:rRes.nLong64 = ImpGetCurrency( &p->aData ); break;
case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
case SbxDATE: rRes.nDouble = ImpGetDate( &p->aData ); break;
case SbxBOOL:
rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
ImpGetBool( &p->aData ) );
break;
case SbxCHAR: rRes.nChar = ImpGetChar( &p->aData ); break;
case SbxBYTE: rRes.nByte = ImpGetByte( &p->aData ); break;
case SbxUSHORT: rRes.nUShort = ImpGetUShort( &p->aData ); break;
case SbxULONG: rRes.nULong = ImpGetULong( &p->aData ); break;
case SbxLPSTR:
case SbxSTRING: p->aPic = ImpGetString( &p->aData );
rRes.pOUString = &p->aPic; break;
case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
rRes.pOUString = &p->aPic; break;
case SbxINT:
#if SAL_TYPES_SIZEOFINT == 2
rRes.nInt = (int) ImpGetInteger( &p->aData );
#else
rRes.nInt = (int) ImpGetLong( &p->aData );
#endif
break;
case SbxUINT:
#if SAL_TYPES_SIZEOFINT == 2
rRes.nUInt = (int) ImpGetUShort( &p->aData );
#else
rRes.nUInt = (int) ImpGetULong( &p->aData );
#endif
break;
case SbxOBJECT:
if( p->aData.eType == SbxOBJECT )
rRes.pObj = p->aData.pObj;
else
{
SetError( SbxERR_NO_OBJECT );
rRes.pObj = NULL;
}
break;
default:
if( p->aData.eType == rRes.eType )
rRes = p->aData;
else
{
SetError( SbxERR_CONVERSION );
rRes.pObj = NULL;
}
}
}
else
{
// Objekt enthielt sich selbst
SbxDataType eTemp = rRes.eType;
memset( &rRes, 0, sizeof( SbxValues ) );
rRes.eType = eTemp;
}
}
if( !IsError() )
{
bRes = sal_True;
if( eOld != SbxERR_OK )
SetError( eOld );
}
return bRes;
}
sal_Bool SbxValue::GetNoBroadcast( SbxValues& rRes )
{
sal_uInt16 nFlags_ = GetFlags();
SetFlag( SBX_NO_BROADCAST );
sal_Bool bRes = Get( rRes );
SetFlags( nFlags_ );
return bRes;
}
const XubString& SbxValue::GetString() const
{
SbxValues aRes;
aRes.eType = SbxSTRING;
if( Get( aRes ) )
((SbxValue*) this)->aToolString = *aRes.pOUString;
else
((SbxValue*) this)->aToolString.Erase();
return aToolString;
}
const XubString& SbxValue::GetCoreString() const
{
SbxValues aRes;
aRes.eType = SbxCoreSTRING;
if( Get( aRes ) )
((SbxValue*) this)->aToolString = *aRes.pOUString;
else
((SbxValue*) this)->aToolString.Erase();
return aToolString;
}
::rtl::OUString SbxValue::GetOUString() const
{
::rtl::OUString aResult;
SbxValues aRes;
aRes.eType = SbxSTRING;
if( Get( aRes ) )
aResult = *aRes.pOUString;
return aResult;
}
sal_Bool SbxValue::HasObject() const
{
ErrCode eErr = GetError();
SbxValues aRes;
aRes.eType = SbxOBJECT;
Get( aRes );
SetError( eErr );
return 0 != aRes.pObj;
}
sal_Bool SbxValue::GetBool() const
{
SbxValues aRes;
aRes.eType = SbxBOOL;
Get( aRes );
return sal_Bool( aRes.nUShort != 0 );
}
#define GET( g, e, t, m ) \
t SbxValue::g() const { SbxValues aRes(e); Get( aRes ); return aRes.m; }
GET( GetByte, SbxBYTE, sal_uInt8, nByte )
GET( GetChar, SbxCHAR, xub_Unicode, nChar )
GET( GetCurrency, SbxCURRENCY, SbxINT64, nLong64 )
GET( GetDate, SbxDATE, double, nDouble )
GET( GetData, SbxDATAOBJECT, void*, pData )
GET( GetDouble, SbxDOUBLE, double, nDouble )
GET( GetErr, SbxERROR, sal_uInt16, nUShort )
GET( GetInt, SbxINT, int, nInt )
GET( GetInteger, SbxINTEGER, sal_Int16, nInteger )
GET( GetLong, SbxLONG, sal_Int32, nLong )
GET( GetLong64, SbxLONG64, SbxINT64, nLong64 )
GET( GetObject, SbxOBJECT, SbxBase*, pObj )
GET( GetSingle, SbxSINGLE, float, nSingle )
GET( GetULong, SbxULONG, sal_uInt32, nULong )
GET( GetULong64, SbxULONG64, SbxUINT64, nULong64 )
GET( GetUShort, SbxUSHORT, sal_uInt16, nUShort )
GET( GetInt64, SbxSALINT64, sal_Int64, nInt64 )
GET( GetUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
GET( GetDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
//////////////////////////// Daten schreiben /////////////////////////////
sal_Bool SbxValue::Put( const SbxValues& rVal )
{
sal_Bool bRes = sal_False;
SbxError eOld = GetError();
if( eOld != SbxERR_OK )
ResetError();
if( !CanWrite() )
SetError( SbxERR_PROP_READONLY );
else if( rVal.eType & 0xF000 )
SetError( SbxERR_NOTIMP );
else
{
// Falls nach einem Objekt gefragt wird, nicht
// die wahren Werte suchen
SbxValue* p = this;
if( rVal.eType != SbxOBJECT )
p = TheRealValue( sal_False ); // #55226 Hier keinen Fehler erlauben
if( p )
{
if( !p->CanWrite() )
SetError( SbxERR_PROP_READONLY );
else if( p->IsFixed() || p->SetType( (SbxDataType) ( rVal.eType & 0x0FFF ) ) )
switch( rVal.eType & 0x0FFF )
{
case SbxEMPTY:
case SbxVOID:
case SbxNULL: break;
case SbxINTEGER: ImpPutInteger( &p->aData, rVal.nInteger ); break;
case SbxLONG: ImpPutLong( &p->aData, rVal.nLong ); break;
case SbxSALINT64: ImpPutInt64( &p->aData, rVal.nInt64 ); break;
case SbxSALUINT64: ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
case SbxSINGLE: ImpPutSingle( &p->aData, rVal.nSingle ); break;
case SbxDOUBLE: ImpPutDouble( &p->aData, rVal.nDouble ); break;
case SbxCURRENCY: ImpPutCurrency( &p->aData, rVal.nLong64 ); break;
case SbxDECIMAL: ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
case SbxDATE: ImpPutDate( &p->aData, rVal.nDouble ); break;
case SbxBOOL: ImpPutBool( &p->aData, rVal.nInteger ); break;
case SbxCHAR: ImpPutChar( &p->aData, rVal.nChar ); break;
case SbxBYTE: ImpPutByte( &p->aData, rVal.nByte ); break;
case SbxUSHORT: ImpPutUShort( &p->aData, rVal.nUShort ); break;
case SbxULONG: ImpPutULong( &p->aData, rVal.nULong ); break;
case SbxLPSTR:
case SbxSTRING: ImpPutString( &p->aData, rVal.pOUString ); break;
case SbxINT:
#if SAL_TYPES_SIZEOFINT == 2
ImpPutInteger( &p->aData, (sal_Int16) rVal.nInt );
#else
ImpPutLong( &p->aData, (sal_Int32) rVal.nInt );
#endif
break;
case SbxUINT:
#if SAL_TYPES_SIZEOFINT == 2
ImpPutUShort( &p->aData, (sal_uInt16) rVal.nUInt );
#else
ImpPutULong( &p->aData, (sal_uInt32) rVal.nUInt );
#endif
break;
case SbxOBJECT:
if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
{
// ist schon drin
if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
break;
// Nur den Werteteil loeschen!
p->SbxValue::Clear();
// eingentliche Zuweisung
p->aData.pObj = rVal.pObj;
// ggf. Ref-Count mitzaehlen
if( p->aData.pObj && p->aData.pObj != p )
{
if ( p != this )
{
DBG_ERROR( "TheRealValue" );
}
HACK(nicht bei Parent-Prop - sonst CyclicRef)
SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
sal_Bool bParentProp = pThisVar && 5345 ==
( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
if ( !bParentProp )
p->aData.pObj->AddRef();
}
}
else
SetError( SbxERR_CONVERSION );
break;
default:
if( p->aData.eType == rVal.eType )
p->aData = rVal;
else
{
SetError( SbxERR_CONVERSION );
if( !p->IsFixed() )
p->aData.eType = SbxNULL;
}
}
if( !IsError() )
{
p->SetModified( sal_True );
p->Broadcast( SBX_HINT_DATACHANGED );
if( eOld != SbxERR_OK )
SetError( eOld );
bRes = sal_True;
}
}
}
return bRes;
}
// AB, 28.3.96:
// Methode, um bei speziellen Typen eine Vorbehandlung des Strings
// durchzufuehren. Insbesondere erforderlich fuer BASIC-IDE, damit
// die Ausgaben im Watch-Fenster mit PutStringExt zurueckgeschrieben
// werden koennen, wenn Floats mit ',' als Dezimaltrenner oder BOOLs
// explizit mit "TRUE" oder "FALSE" angegeben werden.
// Implementierung in ImpConvStringExt (SBXSCAN.CXX)
sal_Bool SbxValue::PutStringExt( const ::rtl::OUString& r )
{
// Kopieren, bei Unicode gleich konvertieren
::rtl::OUString aStr( r );
// Eigenen Typ bestimmen (nicht wie in Put() mit TheRealValue(),
// Objekte werden sowieso nicht behandelt)
SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
// Source-Value basteln
SbxValues aRes;
aRes.eType = SbxSTRING;
// Nur, wenn wirklich was konvertiert wurde, Kopie nehmen,
// sonst Original (Unicode bleibt erhalten)
sal_Bool bRet;
if( ImpConvStringExt( aStr, eTargetType ) )
aRes.pOUString = (::rtl::OUString*)&aStr;
else
aRes.pOUString = (::rtl::OUString*)&r;
// #34939: Bei Strings. die eine Zahl enthalten und wenn this einen
// Num-Typ hat, Fixed-Flag setzen, damit der Typ nicht veraendert wird
sal_uInt16 nFlags_ = GetFlags();
if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
eTargetType == SbxBOOL )
{
SbxValue aVal;
aVal.Put( aRes );
if( aVal.IsNumeric() )
SetFlag( SBX_FIXED );
}
Put( aRes );
bRet = sal_Bool( !IsError() );
// Falls das mit dem FIXED einen Error gegeben hat, zuruecksetzen
// (UI-Aktion sollte keinen Error ergeben, sondern nur scheitern)
if( !bRet )
ResetError();
SetFlags( nFlags_ );
return bRet;
}
sal_Bool SbxValue::PutString( const xub_Unicode* p )
{
::rtl::OUString aVal( p );
SbxValues aRes;
aRes.eType = SbxSTRING;
aRes.pOUString = &aVal;
Put( aRes );
return sal_Bool( !IsError() );
}
sal_Bool SbxValue::PutBool( sal_Bool b )
{
SbxValues aRes;
aRes.eType = SbxBOOL;
aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
Put( aRes );
return sal_Bool( !IsError() );
}
sal_Bool SbxValue::PutEmpty()
{
sal_Bool bRet = SetType( SbxEMPTY );
SetModified( sal_True );
return bRet;
}
sal_Bool SbxValue::PutNull()
{
sal_Bool bRet = SetType( SbxNULL );
if( bRet )
SetModified( sal_True );
return bRet;
}
// Special decimal methods
sal_Bool SbxValue::PutDecimal( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec )
{
SbxValue::Clear();
aData.pDecimal = new SbxDecimal( rAutomationDec );
aData.pDecimal->addRef();
aData.eType = SbxDECIMAL;
return sal_True;
}
sal_Bool SbxValue::fillAutomationDecimal
( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec )
{
SbxDecimal* pDecimal = GetDecimal();
if( pDecimal != NULL )
{
pDecimal->fillAutomationDecimal( rAutomationDec );
return sal_True;
}
return sal_False;
}
sal_Bool SbxValue::PutpChar( const xub_Unicode* p )
{
::rtl::OUString aVal( p );
SbxValues aRes;
aRes.eType = SbxLPSTR;
aRes.pOUString = &aVal;
Put( aRes );
return sal_Bool( !IsError() );
}
sal_Bool SbxValue::PutString( const ::rtl::OUString& r )
{
SbxValues aRes;
aRes.eType = SbxSTRING;
aRes.pOUString = (::rtl::OUString*) &r;
Put( aRes );
return sal_Bool( !IsError() );
}
#define PUT( p, e, t, m ) \
sal_Bool SbxValue::p( t n ) \
{ SbxValues aRes(e); aRes.m = n; Put( aRes ); return sal_Bool( !IsError() ); }
PUT( PutByte, SbxBYTE, sal_uInt8, nByte )
PUT( PutChar, SbxCHAR, xub_Unicode, nChar )
PUT( PutCurrency, SbxCURRENCY, const SbxINT64&, nLong64 )
PUT( PutDate, SbxDATE, double, nDouble )
PUT( PutData, SbxDATAOBJECT, void*, pData )
PUT( PutDouble, SbxDOUBLE, double, nDouble )
PUT( PutErr, SbxERROR, sal_uInt16, nUShort )
PUT( PutInt, SbxINT, int, nInt )
PUT( PutInteger, SbxINTEGER, sal_Int16, nInteger )
PUT( PutLong, SbxLONG, sal_Int32, nLong )
PUT( PutLong64, SbxLONG64, const SbxINT64&, nLong64 )
PUT( PutObject, SbxOBJECT, SbxBase*, pObj )
PUT( PutSingle, SbxSINGLE, float, nSingle )
PUT( PutULong, SbxULONG, sal_uInt32, nULong )
PUT( PutULong64, SbxULONG64, const SbxUINT64&, nULong64 )
PUT( PutUShort, SbxUSHORT, sal_uInt16, nUShort )
PUT( PutInt64, SbxSALINT64, sal_Int64, nInt64 )
PUT( PutUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
PUT( PutDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
////////////////////////// Setzen des Datentyps ///////////////////////////
sal_Bool SbxValue::IsFixed() const
{
return ( (GetFlags() & SBX_FIXED) | (aData.eType & SbxBYREF) ) != 0;
}
// Eine Variable ist numerisch, wenn sie EMPTY oder wirklich numerisch ist
// oder einen vollstaendig konvertierbaren String enthaelt
// #41692, fuer RTL und Basic-Core getrennt implementieren
sal_Bool SbxValue::IsNumeric() const
{
return ImpIsNumeric( /*bOnlyIntntl*/sal_False );
}
sal_Bool SbxValue::IsNumericRTL() const
{
return ImpIsNumeric( /*bOnlyIntntl*/sal_True );
}
sal_Bool SbxValue::ImpIsNumeric( sal_Bool bOnlyIntntl ) const
{
if( !CanRead() )
{
SetError( SbxERR_PROP_WRITEONLY ); return sal_False;
}
// Downcast pruefen!!!
if( this->ISA(SbxVariable) )
((SbxVariable*)this)->Broadcast( SBX_HINT_DATAWANTED );
SbxDataType t = GetType();
if( t == SbxSTRING )
{
if( aData.pOUString )
{
::rtl::OUString s( *aData.pOUString );
double n;
SbxDataType t2;
sal_uInt16 nLen = 0;
if( ImpScan( s, n, t2, &nLen, /*bAllowIntntl*/sal_False, bOnlyIntntl ) == SbxERR_OK )
return sal_Bool( nLen == s.getLength() );
}
return sal_False;
}
else
return sal_Bool( t == SbxEMPTY
|| ( t >= SbxINTEGER && t <= SbxCURRENCY )
|| ( t >= SbxCHAR && t <= SbxUINT ) );
}
SbxClassType SbxValue::GetClass() const
{
return SbxCLASS_VALUE;
}
SbxDataType SbxValue::GetType() const
{
return SbxDataType( aData.eType & 0x0FFF );
}
SbxDataType SbxValue::GetFullType() const
{
return aData.eType;
}
sal_Bool SbxValue::SetType( SbxDataType t )
{
DBG_ASSERT( !( t & 0xF000 ), "Setzen von BYREF|ARRAY verboten!" );
if( ( t == SbxEMPTY && aData.eType == SbxVOID )
|| ( aData.eType == SbxEMPTY && t == SbxVOID ) )
return sal_True;
if( ( t & 0x0FFF ) == SbxVARIANT )
{
// Versuch, den Datentyp auf Variant zu setzen
ResetFlag( SBX_FIXED );
if( IsFixed() )
{
SetError( SbxERR_CONVERSION ); return sal_False;
}
t = SbxEMPTY;
}
if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) )
{
if( !CanWrite() || IsFixed() )
{
SetError( SbxERR_CONVERSION ); return sal_False;
}
else
{
// Eventuelle Objekte freigeben
switch( aData.eType )
{
case SbxSTRING:
delete aData.pOUString;
break;
case SbxOBJECT:
if( aData.pObj && aData.pObj != this )
{
HACK(nicht bei Parent-Prop - sonst CyclicRef)
SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
sal_uInt16 nSlotId = pThisVar
? ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) )
: 0;
DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName() == UniString::CreateFromAscii( "Parent" ),
"SID_PARENTOBJECT heisst nicht 'Parent'" );
sal_Bool bParentProp = 5345 == nSlotId;
if ( !bParentProp )
aData.pObj->ReleaseRef();
}
break;
default: break;
}
// Das klappt immer, da auch die Float-Repraesentationen 0 sind.
memset( &aData, 0, sizeof( SbxValues ) );
aData.eType = t;
}
}
return sal_True;
}
sal_Bool SbxValue::Convert( SbxDataType eTo )
{
eTo = SbxDataType( eTo & 0x0FFF );
if( ( aData.eType & 0x0FFF ) == eTo )
return sal_True;
if( !CanWrite() )
return sal_False;
if( eTo == SbxVARIANT )
{
// Versuch, den Datentyp auf Variant zu setzen
ResetFlag( SBX_FIXED );
if( IsFixed() )
{
SetError( SbxERR_CONVERSION ); return sal_False;
}
else
return sal_True;
}
// Convert from Null geht niemals. Einmal Null, immer Null!
if( aData.eType == SbxNULL )
{
SetError( SbxERR_CONVERSION ); return sal_False;
}
// Konversion der Daten:
SbxValues aNew;
aNew.eType = eTo;
if( Get( aNew ) )
{
// Der Datentyp konnte konvertiert werden. Bei Fixed-Elementen
// ist hier Ende, da die Daten nicht uebernommen zu werden brauchen
if( !IsFixed() )
{
SetType( eTo );
Put( aNew );
SetModified( sal_True );
}
Broadcast( SBX_HINT_CONVERTED );
return sal_True;
}
else
return sal_False;
}
////////////////////////////////// Rechnen /////////////////////////////////
sal_Bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
{
bool bVBAInterop = SbiRuntime::isVBAEnabled();
SbxDataType eThisType = GetType();
SbxDataType eOpType = rOp.GetType();
SbxError eOld = GetError();
if( eOld != SbxERR_OK )
ResetError();
if( !CanWrite() )
SetError( SbxERR_PROP_READONLY );
else if( !rOp.CanRead() )
SetError( SbxERR_PROP_WRITEONLY );
// Sonderregel 1: Ist ein Operand Null, ist das Ergebnis Null
else if( eThisType == SbxNULL || eOpType == SbxNULL )
SetType( SbxNULL );
// Sonderregel 2: Ist ein Operand Empty, ist das Ergebnis der 2. Operand
else if( eThisType == SbxEMPTY
&& !bVBAInterop
)
*this = rOp;
// 13.2.96: Nicht schon vor Get auf SbxEMPTY pruefen
else
{
SbxValues aL, aR;
bool bDecimal = false;
if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING ) ||
( eThisType != SbxSTRING && eOpType == SbxSTRING ) ) &&
( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
{
goto Lbl_OpIsDouble;
}
else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && ( eOp == SbxPLUS ) ) )
{
if( eOp == SbxCAT || eOp == SbxPLUS )
{
// AB 5.11.1999, OUString beruecksichtigen
aL.eType = aR.eType = SbxSTRING;
rOp.Get( aR );
// AB 8.12.1999, #70399: Hier wieder GetType() rufen, Get() kann Typ aendern!
if( rOp.GetType() == SbxEMPTY )
goto Lbl_OpIsEmpty;
Get( aL );
// #30576: Erstmal testen, ob Wandlung geklappt hat
if( aL.pOUString != NULL && aR.pOUString != NULL )
{
*aL.pOUString += *aR.pOUString;
}
// Nicht einmal Left OK?
else if( aL.pOUString == NULL )
{
aL.pOUString = new ::rtl::OUString();
}
Put( aL );
}
else
SetError( SbxERR_CONVERSION );
}
else if( eOpType == SbxSTRING && rOp.IsFixed() )
{ // Numerisch: rechts darf kein String stehen
SetError( SbxERR_CONVERSION );
}
else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
{
if( GetType() == eOpType )
{
if( GetType() == SbxULONG64
|| GetType() == SbxLONG64
|| GetType() == SbxCURRENCY
|| GetType() == SbxULONG )
aL.eType = aR.eType = GetType();
// else if( GetType() == SbxDouble || GetType() == SbxSingle )
// aL.eType = aR.eType = SbxLONG64;
else
aL.eType = aR.eType = SbxLONG;
}
else if( GetType() == SbxCURRENCY || eOpType == SbxCURRENCY
|| GetType() == SbxULONG64 || eOpType == SbxULONG64
|| GetType() == SbxLONG64 || eOpType == SbxLONG64 )
aL.eType = aR.eType = SbxLONG64;
// else if( GetType() == SbxDouble || rOP.GetType() == SbxDouble
// || GetType() == SbxSingle || rOP.GetType() == SbxSingle )
// aL.eType = aR.eType = SbxLONG64;
else
aL.eType = aR.eType = SbxLONG;
if( rOp.Get( aR ) )
{
if( rOp.GetType() == SbxEMPTY )
{
if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNOT ) ) )
goto Lbl_OpIsEmpty;
}
if( Get( aL ) ) switch( eOp )
{
case SbxIDIV:
if( aL.eType == SbxCURRENCY )
aL.eType = SbxLONG64;
if( aL.eType == SbxLONG64 )
if( !aR.nLong64 ) SetError( SbxERR_ZERODIV );
else aL.nLong64 /= aR.nLong64;
else if( aL.eType == SbxULONG64 )
if( !aR.nULong64 ) SetError( SbxERR_ZERODIV );
else aL.nULong64 /= aR.nULong64;
else if( aL.eType == SbxLONG )
if( !aR.nLong ) SetError( SbxERR_ZERODIV );
else aL.nLong /= aR.nLong;
else
if( !aR.nULong ) SetError( SbxERR_ZERODIV );
else aL.nULong /= aR.nULong;
break;
case SbxMOD:
if( aL.eType == SbxCURRENCY )
aL.eType = SbxLONG64;
if( aL.eType == SbxLONG64 )
if( !aR.nLong64 ) SetError( SbxERR_ZERODIV );
else aL.nLong64 %= aR.nLong64;
else if( aL.eType == SbxULONG64 )
if( !aR.nULong64 ) SetError( SbxERR_ZERODIV );
else aL.nULong64 %= aR.nULong64;
else if( aL.eType == SbxLONG )
if( !aR.nLong ) SetError( SbxERR_ZERODIV );
else aL.nLong %= aR.nLong;
else
if( !aR.nULong ) SetError( SbxERR_ZERODIV );
else aL.nULong %= aR.nULong;
break;
case SbxAND:
if( aL.eType != SbxLONG && aL.eType != SbxULONG )
aL.nLong64 &= aR.nLong64;
else
aL.nLong &= aR.nLong;
break;
case SbxOR:
if( aL.eType != SbxLONG && aL.eType != SbxULONG )
aL.nLong64 |= aR.nLong64;
else
aL.nLong |= aR.nLong;
break;
case SbxXOR:
if( aL.eType != SbxLONG && aL.eType != SbxULONG )
aL.nLong64 ^= aR.nLong64;
else
aL.nLong ^= aR.nLong;
break;
case SbxEQV:
if( aL.eType != SbxLONG && aL.eType != SbxULONG )
aL.nLong64 = (aL.nLong64 & aR.nLong64) | (~aL.nLong64 & ~aR.nLong64);
else
aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
break;
case SbxIMP:
if( aL.eType != SbxLONG && aL.eType != SbxULONG )
aL.nLong64 = ~aL.nLong64 | aR.nLong64;
else
aL.nLong = ~aL.nLong | aR.nLong;
break;
case SbxNOT:
if( aL.eType != SbxLONG && aL.eType != SbxULONG )
aL.nLong64 = ~aL.nLong64;
else
aL.nLong = ~aL.nLong;
break;
default: break;
}
}
}
else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL ) &&
( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
{
aL.eType = aR.eType = SbxDECIMAL;
bDecimal = true;
if( rOp.Get( aR ) )
{
if( rOp.GetType() == SbxEMPTY )
{
releaseDecimalPtr( aL.pDecimal );
goto Lbl_OpIsEmpty;
}
if( Get( aL ) )
{
if( aL.pDecimal && aR.pDecimal )
{
bool bOk = true;
switch( eOp )
{
case SbxMUL:
bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
break;
case SbxDIV:
if( aR.pDecimal->isZero() )
SetError( SbxERR_ZERODIV );
else
bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
break;
case SbxPLUS:
bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
break;
case SbxMINUS:
bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
break;
case SbxNEG:
bOk = ( aL.pDecimal->neg() );
break;
default:
SetError( SbxERR_NOTIMP );
}
if( !bOk )
SetError( SbxERR_OVERFLOW );
}
else
{
SetError( SbxERR_CONVERSION );
}
}
}
}
else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
{
aL.eType = SbxCURRENCY;
aR.eType = SbxCURRENCY;
if( rOp.Get( aR ) )
{
static BigInt n10K( 10000 );
if( rOp.GetType() == SbxEMPTY )
goto Lbl_OpIsEmpty;
if( Get( aL ) ) switch( eOp )
{
case SbxMUL:
{
// #i20704 Implement directly
BigInt b1( aL.nLong64 );
BigInt b2( aR.nLong64 );
b1 *= b2;
b1 /= n10K;
double d = double( b1 ) / 10000.0;
if( d > SbxMAXCURR || d < SbxMINCURR )
SetError( SbxERR_OVERFLOW );
else
b1.INT64( &aL.nLong64 );
break;
}
case SbxDIV:
if( !aR.nLong64 )
{
SetError( SbxERR_ZERODIV );
}
else
{
// #i20704 Implement directly
BigInt b1( aL.nLong64 );
BigInt b2( aR.nLong64 );
b1 *= n10K;
b1 /= b2;
double d = double( b1 ) / 10000.0;
if( d > SbxMAXCURR || d < SbxMINCURR )
SetError( SbxERR_OVERFLOW );
else
b1.INT64( &aL.nLong64 );
}
break;
case SbxPLUS:
aL.nLong64 += aR.nLong64; break;
case SbxMINUS:
aL.nLong64 -= aR.nLong64; break;
case SbxNEG:
aL.nLong64 = -aL.nLong64; break;
default:
SetError( SbxERR_NOTIMP );
}
}
}
else
Lbl_OpIsDouble:
{ // Andere Operatoren
aL.eType = aR.eType = SbxDOUBLE;
if( rOp.Get( aR ) )
{
if( rOp.GetType() == SbxEMPTY )
{
if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNEG ) ) )
goto Lbl_OpIsEmpty;
}
if( Get( aL ) )
{
switch( eOp )
{
case SbxEXP:
aL.nDouble = pow( aL.nDouble, aR.nDouble );
break;
case SbxMUL:
aL.nDouble *= aR.nDouble; break;
case SbxDIV:
if( !aR.nDouble ) SetError( SbxERR_ZERODIV );
else aL.nDouble /= aR.nDouble; break;
case SbxPLUS:
aL.nDouble += aR.nDouble; break;
case SbxMINUS:
aL.nDouble -= aR.nDouble; break;
case SbxNEG:
aL.nDouble = -aL.nDouble; break;
default:
SetError( SbxERR_NOTIMP );
}
// #45465 Date braucht bei + eine Spezial-Behandlung
if( eOp == SbxPLUS && (GetType() == SbxDATE || rOp.GetType() == SbxDATE ) )
aL.eType = SbxDATE;
}
}
}
if( !IsError() )
Put( aL );
if( bDecimal )
{
releaseDecimalPtr( aL.pDecimal );
releaseDecimalPtr( aR.pDecimal );
}
}
Lbl_OpIsEmpty:
sal_Bool bRes = sal_Bool( !IsError() );
if( bRes && eOld != SbxERR_OK )
SetError( eOld );
return bRes;
}
// Die Vergleichs-Routine liefert sal_True oder sal_False.
sal_Bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
{
bool bVBAInterop = SbiRuntime::isVBAEnabled();
sal_Bool bRes = sal_False;
SbxError eOld = GetError();
if( eOld != SbxERR_OK )
ResetError();
if( !CanRead() || !rOp.CanRead() )
SetError( SbxERR_PROP_WRITEONLY );
else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
{
bRes = sal_True;
}
else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
bRes = !bVBAInterop ? sal_True : ( eOp == SbxEQ ? sal_True : sal_False );
// Sonderregel 1: Ist ein Operand Null, ist das Ergebnis FALSE
else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
bRes = sal_False;
// Sonderregel 2: Wenn beide Variant sind und einer ist numerisch,
// und der andere ein String, ist num < str
else if( !IsFixed() && !rOp.IsFixed()
&& ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
)
bRes = sal_Bool( eOp == SbxLT || eOp == SbxLE || eOp == SbxNE );
else if( !IsFixed() && !rOp.IsFixed()
&& ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
&& !bVBAInterop
)
bRes = sal_Bool( eOp == SbxGT || eOp == SbxGE || eOp == SbxNE );
else
{
SbxValues aL, aR;
// Wenn einer der Operanden ein String ist,
// findet ein Stringvergleich statt
if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
{
aL.eType = aR.eType = SbxSTRING;
if( Get( aL ) && rOp.Get( aR ) ) switch( eOp )
{
case SbxEQ:
bRes = sal_Bool( *aL.pOUString == *aR.pOUString ); break;
case SbxNE:
bRes = sal_Bool( *aL.pOUString != *aR.pOUString ); break;
case SbxLT:
bRes = sal_Bool( *aL.pOUString < *aR.pOUString ); break;
case SbxGT:
bRes = sal_Bool( *aL.pOUString > *aR.pOUString ); break;
case SbxLE:
bRes = sal_Bool( *aL.pOUString <= *aR.pOUString ); break;
case SbxGE:
bRes = sal_Bool( *aL.pOUString >= *aR.pOUString ); break;
default:
SetError( SbxERR_NOTIMP );
}
}
// AB 19.12.95: Wenn SbxSINGLE beteiligt, auf SINGLE konvertieren,
// sonst gibt es numerische Fehler
else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
{
aL.eType = aR.eType = SbxSINGLE;
if( Get( aL ) && rOp.Get( aR ) )
switch( eOp )
{
case SbxEQ:
bRes = sal_Bool( aL.nSingle == aR.nSingle ); break;
case SbxNE:
bRes = sal_Bool( aL.nSingle != aR.nSingle ); break;
case SbxLT:
bRes = sal_Bool( aL.nSingle < aR.nSingle ); break;
case SbxGT:
bRes = sal_Bool( aL.nSingle > aR.nSingle ); break;
case SbxLE:
bRes = sal_Bool( aL.nSingle <= aR.nSingle ); break;
case SbxGE:
bRes = sal_Bool( aL.nSingle >= aR.nSingle ); break;
default:
SetError( SbxERR_NOTIMP );
}
}
else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
{
aL.eType = aR.eType = SbxDECIMAL;
Get( aL );
rOp.Get( aR );
if( aL.pDecimal && aR.pDecimal )
{
SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
switch( eOp )
{
case SbxEQ:
bRes = sal_Bool( eRes == SbxDecimal::EQ ); break;
case SbxNE:
bRes = sal_Bool( eRes != SbxDecimal::EQ ); break;
case SbxLT:
bRes = sal_Bool( eRes == SbxDecimal::LT ); break;
case SbxGT:
bRes = sal_Bool( eRes == SbxDecimal::GT ); break;
case SbxLE:
bRes = sal_Bool( eRes != SbxDecimal::GT ); break;
case SbxGE:
bRes = sal_Bool( eRes != SbxDecimal::LT ); break;
default:
SetError( SbxERR_NOTIMP );
}
}
else
{
SetError( SbxERR_CONVERSION );
}
releaseDecimalPtr( aL.pDecimal );
releaseDecimalPtr( aR.pDecimal );
}
// Alles andere auf SbxDOUBLE-Basis vergleichen
else
{
aL.eType = aR.eType = SbxDOUBLE;
//if( Get( aL ) && rOp.Get( aR ) )
bool bGetL = Get( aL );
bool bGetR = rOp.Get( aR );
if( bGetL && bGetR )
switch( eOp )
{
case SbxEQ:
bRes = sal_Bool( aL.nDouble == aR.nDouble ); break;
case SbxNE:
bRes = sal_Bool( aL.nDouble != aR.nDouble ); break;
case SbxLT:
bRes = sal_Bool( aL.nDouble < aR.nDouble ); break;
case SbxGT:
bRes = sal_Bool( aL.nDouble > aR.nDouble ); break;
case SbxLE:
bRes = sal_Bool( aL.nDouble <= aR.nDouble ); break;
case SbxGE:
bRes = sal_Bool( aL.nDouble >= aR.nDouble ); break;
default:
SetError( SbxERR_NOTIMP );
}
// at least one value was got
// if this is VBA then a conversion error for one
// side will yield a false result of an equality test
else if ( bGetR || bGetL )
{
if ( bVBAInterop && eOp == SbxEQ && GetError() == SbxERR_CONVERSION )
{
ResetError();
bRes = sal_False;
}
}
}
}
if( eOld != SbxERR_OK )
SetError( eOld );
return bRes;
}
///////////////////////////// Lesen/Schreiben ////////////////////////////
sal_Bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
{
SbxValue::Clear();
sal_uInt16 nType;
r >> nType;
aData.eType = SbxDataType( nType );
switch( nType )
{
case SbxBOOL:
case SbxINTEGER:
r >> aData.nInteger; break;
case SbxLONG:
r >> aData.nLong; break;
case SbxSINGLE:
{
// Floats als ASCII
XubString aVal;
r.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US );
double d;
SbxDataType t;
if( ImpScan( aVal, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE )
{
aData.nSingle = 0.0F;
return sal_False;
}
aData.nSingle = (float) d;
break;
}
case SbxDATE:
case SbxDOUBLE:
{
// Floats als ASCII
XubString aVal;
r.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US );
SbxDataType t;
if( ImpScan( aVal, aData.nDouble, t, NULL ) != SbxERR_OK )
{
aData.nDouble = 0.0;
return sal_False;
}
break;
}
case SbxULONG64:
{
r >> aData.nULong64.nHigh >> aData.nULong64.nLow;
break;
}
case SbxLONG64:
case SbxCURRENCY:
{
r >> aData.nLong64.nHigh >> aData.nLong64.nLow;
break;
}
case SbxSTRING:
{
XubString aVal;
r.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US );
if( aVal.Len() )
aData.pOUString = new ::rtl::OUString( aVal );
else
aData.pOUString = NULL; // JSM 22.09.1995
break;
}
case SbxERROR:
case SbxUSHORT:
r >> aData.nUShort; break;
case SbxOBJECT:
{
sal_uInt8 nMode;
r >> nMode;
switch( nMode )
{
case 0:
aData.pObj = NULL;
break;
case 1:
aData.pObj = SbxBase::Load( r );
return sal_Bool( aData.pObj != NULL );
case 2:
aData.pObj = this;
break;
}
break;
}
case SbxCHAR:
{
char c;
r >> c;
aData.nChar = c;
break;
}
case SbxBYTE:
r >> aData.nByte; break;
case SbxULONG:
r >> aData.nULong; break;
case SbxINT:
{
sal_uInt8 n;
r >> n;
// Passt der Int auf diesem System?
if( n > SAL_TYPES_SIZEOFINT )
r >> aData.nLong, aData.eType = SbxLONG;
else
r >> aData.nInt;
break;
}
case SbxUINT:
{
sal_uInt8 n;
r >> n;
// Passt der UInt auf diesem System?
if( n > SAL_TYPES_SIZEOFINT )
r >> aData.nULong, aData.eType = SbxULONG;
else
r >> (sal_uInt32&)aData.nUInt;
break;
}
case SbxEMPTY:
case SbxNULL:
case SbxVOID:
break;
case SbxDATAOBJECT:
r >> aData.nLong;
break;
// #78919 For backwards compatibility
case SbxWSTRING:
case SbxWCHAR:
break;
default:
memset (&aData,0,sizeof(aData));
ResetFlag(SBX_FIXED);
aData.eType = SbxNULL;
DBG_ASSERT( !this, "Nicht unterstuetzer Datentyp geladen" );
return sal_False;
}
return sal_True;
}
sal_Bool SbxValue::StoreData( SvStream& r ) const
{
sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
r << nType;
switch( nType & 0x0FFF )
{
case SbxBOOL:
case SbxINTEGER:
r << aData.nInteger; break;
case SbxLONG:
r << aData.nLong; break;
case SbxDATE:
// #49935: Als double speichern, sonst Fehler beim Einlesen
((SbxValue*)this)->aData.eType = (SbxDataType)( ( nType & 0xF000 ) | SbxDOUBLE );
r.WriteByteString( GetCoreString(), RTL_TEXTENCODING_ASCII_US );
((SbxValue*)this)->aData.eType = (SbxDataType)nType;
break;
case SbxSINGLE:
case SbxDOUBLE:
r.WriteByteString( GetCoreString(), RTL_TEXTENCODING_ASCII_US );
break;
case SbxULONG64:
{
r << aData.nULong64.nHigh << aData.nULong64.nLow;
break;
}
case SbxLONG64:
case SbxCURRENCY:
{
r << aData.nLong64.nHigh << aData.nLong64.nLow;
break;
}
case SbxSTRING:
if( aData.pOUString )
{
r.WriteByteString( *aData.pOUString, RTL_TEXTENCODING_ASCII_US );
}
else
{
String aEmpty;
r.WriteByteString( aEmpty, RTL_TEXTENCODING_ASCII_US );
}
break;
case SbxERROR:
case SbxUSHORT:
r << aData.nUShort; break;
case SbxOBJECT:
// sich selbst als Objektptr speichern geht nicht!
if( aData.pObj )
{
if( PTR_CAST(SbxValue,aData.pObj) != this )
{
r << (sal_uInt8) 1;
return aData.pObj->Store( r );
}
else
r << (sal_uInt8) 2;
}
else
r << (sal_uInt8) 0;
break;
case SbxCHAR:
{
char c = sal::static_int_cast< char >(aData.nChar);
r << c;
break;
}
case SbxBYTE:
r << aData.nByte; break;
case SbxULONG:
r << aData.nULong; break;
case SbxINT:
{
sal_uInt8 n = SAL_TYPES_SIZEOFINT;
r << n << (sal_Int32)aData.nInt;
break;
}
case SbxUINT:
{
sal_uInt8 n = SAL_TYPES_SIZEOFINT;
r << n << (sal_uInt32)aData.nUInt;
break;
}
case SbxEMPTY:
case SbxNULL:
case SbxVOID:
break;
case SbxDATAOBJECT:
r << aData.nLong;
break;
// #78919 For backwards compatibility
case SbxWSTRING:
case SbxWCHAR:
break;
default:
DBG_ASSERT( !this, "Speichern eines nicht unterstuetzten Datentyps" );
return sal_False;
}
return sal_True;
}