| /************************************************************** |
| * |
| * 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; |
| } |
| |