diff options
Diffstat (limited to 'basic/source/sbx')
30 files changed, 13950 insertions, 0 deletions
diff --git a/basic/source/sbx/format.src b/basic/source/sbx/format.src new file mode 100644 index 000000000000..8ebe6e93c4bb --- /dev/null +++ b/basic/source/sbx/format.src @@ -0,0 +1,85 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "svl/svtools.hrc" + +String STR_BASICKEY_FORMAT_ON +{ + Text [ en-US ] = "On" ; +}; +String STR_BASICKEY_FORMAT_OFF +{ + Text [ en-US ] = "Off" ; +}; +String STR_BASICKEY_FORMAT_TRUE +{ + Text [ en-US ] = "True" ; +}; +String STR_BASICKEY_FORMAT_FALSE +{ + Text [ en-US ] = "False" ; +}; +String STR_BASICKEY_FORMAT_YES +{ + Text [ en-US ] = "Yes" ; +}; +String STR_BASICKEY_FORMAT_NO +{ + Text [ en-US ] = "No" ; +}; +String STR_BASICKEY_FORMAT_CURRENCY +{ + Text [ en-US ] = "@0.00 $;@(0.00 $)" ; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/basic/source/sbx/makefile.mk b/basic/source/sbx/makefile.mk new file mode 100644 index 000000000000..dfd8e72bf4da --- /dev/null +++ b/basic/source/sbx/makefile.mk @@ -0,0 +1,77 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=basic +TARGET=sbx + +# --- Settings ----------------------------------------------------------- + +.INCLUDE : settings.mk + + +# --- Allgemein ----------------------------------------------------------- + +SRS1NAME=$(TARGET) +SRC1FILES= format.src + +SLOFILES= \ + $(SLO)$/sbxbase.obj \ + $(SLO)$/sbxres.obj \ + $(SLO)$/sbxvalue.obj \ + $(SLO)$/sbxvals.obj \ + $(SLO)$/sbxvar.obj \ + $(SLO)$/sbxarray.obj \ + $(SLO)$/sbxobj.obj \ + $(SLO)$/sbxcoll.obj \ + $(SLO)$/sbxexec.obj \ + $(SLO)$/sbxint.obj \ + $(SLO)$/sbxlng.obj \ + $(SLO)$/sbxsng.obj \ + $(SLO)$/sbxmstrm.obj \ + $(SLO)$/sbxdbl.obj \ + $(SLO)$/sbxcurr.obj \ + $(SLO)$/sbxdate.obj \ + $(SLO)$/sbxstr.obj \ + $(SLO)$/sbxbool.obj \ + $(SLO)$/sbxchar.obj \ + $(SLO)$/sbxbyte.obj \ + $(SLO)$/sbxuint.obj \ + $(SLO)$/sbxulng.obj \ + $(SLO)$/sbxform.obj \ + $(SLO)$/sbxscan.obj \ + $(SLO)$/sbxdec.obj + + +EXCEPTIONSFILES=$(SLO)$/sbxarray.obj + +# --- Targets ------------------------------------------------------------- + +.INCLUDE : target.mk + + diff --git a/basic/source/sbx/sbxarray.cxx b/basic/source/sbx/sbxarray.cxx new file mode 100644 index 000000000000..67e7ce71aded --- /dev/null +++ b/basic/source/sbx/sbxarray.cxx @@ -0,0 +1,857 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/stream.hxx> +#include <basic/sbx.hxx> +#include "runtime.hxx" +#include <vector> +using namespace std; + +struct SbxDim { // eine Array-Dimension: + SbxDim* pNext; // Link + INT32 nLbound, nUbound; // Begrenzungen + INT32 nSize; // Anzahl Elemente +}; + +class SbxVarEntry : public SbxVariableRef { +public: + XubString* pAlias; + SbxVarEntry() : SbxVariableRef(), pAlias( NULL ) {} + ~SbxVarEntry() { delete pAlias; } +}; + +typedef SbxVarEntry* SbxVarEntryPtr; +typedef vector< SbxVarEntryPtr > SbxVarEntryPtrVector; +class SbxVarRefs : public SbxVarEntryPtrVector +{ +public: + SbxVarRefs( void ) {} +}; + + +TYPEINIT1(SbxArray,SbxBase) +TYPEINIT1(SbxDimArray,SbxArray) + +////////////////////////////////////////////////////////////////////////// +// +// SbxArray +// +////////////////////////////////////////////////////////////////////////// + +SbxArray::SbxArray( SbxDataType t ) : SbxBase() +{ + pData = new SbxVarRefs; + eType = t; + if( t != SbxVARIANT ) + SetFlag( SBX_FIXED ); +} + +SbxArray::SbxArray( const SbxArray& rArray ) : + SvRefBase( rArray ), SbxBase() +{ + pData = new SbxVarRefs; + if( rArray.eType != SbxVARIANT ) + SetFlag( SBX_FIXED ); + *this = rArray; +} + +SbxArray& SbxArray::operator=( const SbxArray& rArray ) +{ + if( &rArray != this ) + { + eType = rArray.eType; + Clear(); + SbxVarRefs* pSrc = rArray.pData; + for( UINT32 i = 0; i < pSrc->size(); i++ ) + { + SbxVarEntryPtr pSrcRef = (*pSrc)[i]; + const SbxVariable* pSrc_ = *pSrcRef; + if( !pSrc_ ) + continue; + SbxVarEntryPtr pDstRef = new SbxVarEntry; + *((SbxVariableRef*) pDstRef) = *((SbxVariableRef*) pSrcRef); + if( pSrcRef->pAlias ) + pDstRef->pAlias = new XubString( *pSrcRef->pAlias ); + if( eType != SbxVARIANT ) + // Keine Objekte konvertieren + if( eType != SbxOBJECT || pSrc_->GetClass() != SbxCLASS_OBJECT ) + ((SbxVariable*) pSrc_)->Convert( eType ); + pData->push_back( pDstRef ); + } + } + return *this; +} + +SbxArray::~SbxArray() +{ + Clear(); + delete pData; +} + +SbxDataType SbxArray::GetType() const +{ + return (SbxDataType) ( eType | SbxARRAY ); +} + +SbxClassType SbxArray::GetClass() const +{ + return SbxCLASS_ARRAY; +} + +void SbxArray::Clear() +{ + UINT32 nSize = pData->size(); + for( UINT32 i = 0 ; i < nSize ; i++ ) + { + SbxVarEntry* pEntry = (*pData)[i]; + delete pEntry; + } + pData->clear(); +} + +UINT32 SbxArray::Count32() const +{ + return pData->size(); +} + +USHORT SbxArray::Count() const +{ + UINT32 nCount = pData->size(); + DBG_ASSERT( nCount <= SBX_MAXINDEX, "SBX: Array-Index > SBX_MAXINDEX" ); + return (USHORT)nCount; +} + +SbxVariableRef& SbxArray::GetRef32( UINT32 nIdx ) +{ + // Array ggf. vergroessern + DBG_ASSERT( nIdx <= SBX_MAXINDEX32, "SBX: Array-Index > SBX_MAXINDEX32" ); + // Very Hot Fix + if( nIdx > SBX_MAXINDEX32 ) + { + SetError( SbxERR_BOUNDS ); + nIdx = 0; + } + while( pData->size() <= nIdx ) + { + const SbxVarEntryPtr p = new SbxVarEntry; + pData->push_back( p ); + } + return *((*pData)[nIdx]); +} + +SbxVariableRef& SbxArray::GetRef( USHORT nIdx ) +{ + // Array ggf. vergroessern + DBG_ASSERT( nIdx <= SBX_MAXINDEX, "SBX: Array-Index > SBX_MAXINDEX" ); + // Very Hot Fix + if( nIdx > SBX_MAXINDEX ) + { + SetError( SbxERR_BOUNDS ); + nIdx = 0; + } + while( pData->size() <= nIdx ) + { + const SbxVarEntryPtr p = new SbxVarEntry; + pData->push_back( p ); + } + return *((*pData)[nIdx]); +} + +SbxVariable* SbxArray::Get32( UINT32 nIdx ) +{ + if( !CanRead() ) + { + SetError( SbxERR_PROP_WRITEONLY ); + return NULL; + } + SbxVariableRef& rRef = GetRef32( nIdx ); + + if ( !rRef.Is() ) + rRef = new SbxVariable( eType ); +#ifdef DBG_UTIL + else + DBG_CHKOBJ( rRef, SbxBase, 0 ); +#endif + + return rRef; +} + +SbxVariable* SbxArray::Get( USHORT nIdx ) +{ + if( !CanRead() ) + { + SetError( SbxERR_PROP_WRITEONLY ); + return NULL; + } + SbxVariableRef& rRef = GetRef( nIdx ); + + if ( !rRef.Is() ) + rRef = new SbxVariable( eType ); +#ifdef DBG_UTIL + else + DBG_CHKOBJ( rRef, SbxBase, 0 ); +#endif + + return rRef; +} + +void SbxArray::Put32( SbxVariable* pVar, UINT32 nIdx ) +{ + if( !CanWrite() ) + SetError( SbxERR_PROP_READONLY ); + else + { + if( pVar ) + if( eType != SbxVARIANT ) + // Keine Objekte konvertieren + if( eType != SbxOBJECT || pVar->GetClass() != SbxCLASS_OBJECT ) + pVar->Convert( eType ); + SbxVariableRef& rRef = GetRef32( nIdx ); + if( (SbxVariable*) rRef != pVar ) + { + rRef = pVar; + SetFlag( SBX_MODIFIED ); + } + } +} + +void SbxArray::Put( SbxVariable* pVar, USHORT nIdx ) +{ + if( !CanWrite() ) + SetError( SbxERR_PROP_READONLY ); + else + { + if( pVar ) + if( eType != SbxVARIANT ) + // Keine Objekte konvertieren + if( eType != SbxOBJECT || pVar->GetClass() != SbxCLASS_OBJECT ) + pVar->Convert( eType ); + SbxVariableRef& rRef = GetRef( nIdx ); + if( (SbxVariable*) rRef != pVar ) + { + rRef = pVar; + SetFlag( SBX_MODIFIED ); + } + } +} + +const XubString& SbxArray::GetAlias( USHORT nIdx ) +{ + if( !CanRead() ) + { + SetError( SbxERR_PROP_WRITEONLY ); + return String::EmptyString(); + } + SbxVarEntry& rRef = (SbxVarEntry&) GetRef( nIdx ); + + if ( !rRef.pAlias ) + return String::EmptyString(); +#ifdef DBG_UTIL + else + DBG_CHKOBJ( rRef, SbxBase, 0 ); +#endif + + return *rRef.pAlias; +} + +void SbxArray::PutAlias( const XubString& rAlias, USHORT nIdx ) +{ + if( !CanWrite() ) + SetError( SbxERR_PROP_READONLY ); + else + { + SbxVarEntry& rRef = (SbxVarEntry&) GetRef( nIdx ); + if( !rRef.pAlias ) + rRef.pAlias = new XubString( rAlias ); + else + *rRef.pAlias = rAlias; + } +} + +void SbxArray::Insert32( SbxVariable* pVar, UINT32 nIdx ) +{ + DBG_ASSERT( pData->size() <= SBX_MAXINDEX32, "SBX: Array wird zu gross" ); + if( pData->size() > SBX_MAXINDEX32 ) + return; + SbxVarEntryPtr p = new SbxVarEntry; + *((SbxVariableRef*) p) = pVar; + SbxVarEntryPtrVector::size_type nSize = pData->size(); + if( nIdx > nSize ) + nIdx = nSize; + if( eType != SbxVARIANT && pVar ) + (*p)->Convert( eType ); + if( nIdx == nSize ) + { + pData->push_back( p ); + } + else + { + pData->insert( pData->begin() + nIdx, p ); + } + SetFlag( SBX_MODIFIED ); +} + +void SbxArray::Insert( SbxVariable* pVar, USHORT nIdx ) +{ + DBG_ASSERT( pData->size() <= 0x3FF0, "SBX: Array wird zu gross" ); + if( pData->size() > 0x3FF0 ) + return; + Insert32( pVar, nIdx ); +} + +void SbxArray::Remove32( UINT32 nIdx ) +{ + if( nIdx < pData->size() ) + { + SbxVariableRef* pRef = (*pData)[nIdx]; + pData->erase( pData->begin() + nIdx ); + delete pRef; + SetFlag( SBX_MODIFIED ); + } +} + +void SbxArray::Remove( USHORT nIdx ) +{ + if( nIdx < pData->size() ) + { + SbxVariableRef* pRef = (*pData)[nIdx]; + pData->erase( pData->begin() + nIdx ); + delete pRef; + SetFlag( SBX_MODIFIED ); + } +} + +void SbxArray::Remove( SbxVariable* pVar ) +{ + if( pVar ) + { + for( UINT32 i = 0; i < pData->size(); i++ ) + { + SbxVariableRef* pRef = (*pData)[i]; + // SbxVariableRef* pRef = pData->GetObject( i ); + if( *pRef == pVar ) + { + Remove32( i ); break; + } + } + } +} + +// Uebernahme der Daten aus dem uebergebenen Array, wobei +// gleichnamige Variable ueberschrieben werden. + +void SbxArray::Merge( SbxArray* p ) +{ + if( p ) + { + UINT32 nSize = p->Count(); + for( UINT32 i = 0; i < nSize; i++ ) + { + SbxVarEntryPtr pRef1 = (*(p->pData))[i]; + // Ist das Element by name schon drin? + // Dann ueberschreiben! + SbxVariable* pVar = *pRef1; + if( pVar ) + { + XubString aName = pVar->GetName(); + USHORT nHash = pVar->GetHashCode(); + for( UINT32 j = 0; j < pData->size(); j++ ) + { + SbxVariableRef* pRef2 = (*pData)[j]; + if( (*pRef2)->GetHashCode() == nHash + && (*pRef2)->GetName().EqualsIgnoreCaseAscii( aName ) ) + { + *pRef2 = pVar; pRef1 = NULL; + break; + } + } + if( pRef1 ) + { + SbxVarEntryPtr pRef = new SbxVarEntry; + const SbxVarEntryPtr pTemp = pRef; + pData->push_back( pTemp ); + *((SbxVariableRef*) pRef) = *((SbxVariableRef*) pRef1); + if( pRef1->pAlias ) + pRef->pAlias = new XubString( *pRef1->pAlias ); + } + } + } + } +} + +// Suchen eines Elements ueber die Userdaten. Falls ein Element +// ein Objekt ist, wird dieses ebenfalls durchsucht. + +SbxVariable* SbxArray::FindUserData( UINT32 nData ) +{ + SbxVariable* p = NULL; + for( UINT32 i = 0; i < pData->size(); i++ ) + { + SbxVariableRef* pRef = (*pData)[i]; + SbxVariable* pVar = *pRef; + if( pVar ) + { + if( pVar->IsVisible() && pVar->GetUserData() == nData ) + { + p = pVar; + p->ResetFlag( SBX_EXTFOUND ); + break; // JSM 06.10.95 + } + // Haben wir ein Array/Objekt mit Extended Search? + else if( pVar->IsSet( SBX_EXTSEARCH ) ) + { + switch( pVar->GetClass() ) + { + case SbxCLASS_OBJECT: + { + // Objekte duerfen ihren Parent nicht durchsuchen + USHORT nOld = pVar->GetFlags(); + pVar->ResetFlag( SBX_GBLSEARCH ); + p = ((SbxObject*) pVar)->FindUserData( nData ); + pVar->SetFlags( nOld ); + break; + } + case SbxCLASS_ARRAY: + p = ((SbxArray*) pVar)->FindUserData( nData ); + break; + default: break; + } + if( p ) + { + p->SetFlag( SBX_EXTFOUND ); + break; + } + } + } + } + return p; +} + +// Suchen eines Elements ueber den Namen und den Typ. Falls ein Element +// ein Objekt ist, wird dieses ebenfalls durchsucht. + +SbxVariable* SbxArray::Find( const XubString& rName, SbxClassType t ) +{ + SbxVariable* p = NULL; + UINT32 nCount = pData->size(); + if( !nCount ) + return NULL; + BOOL bExtSearch = IsSet( SBX_EXTSEARCH ); + USHORT nHash = SbxVariable::MakeHashCode( rName ); + for( UINT32 i = 0; i < nCount; i++ ) + { + SbxVariableRef* pRef = (*pData)[i]; + SbxVariable* pVar = *pRef; + if( pVar && pVar->IsVisible() ) + { + // Die ganz sichere Suche klappt auch, wenn es + // keinen Hascode gibt! + USHORT nVarHash = pVar->GetHashCode(); + if( ( !nVarHash || nVarHash == nHash ) + && ( t == SbxCLASS_DONTCARE || pVar->GetClass() == t ) + && ( pVar->GetName().EqualsIgnoreCaseAscii( rName ) ) ) + { + p = pVar; + p->ResetFlag( SBX_EXTFOUND ); + break; + } + // Haben wir ein Array/Objekt mit Extended Search? + else if( bExtSearch && pVar->IsSet( SBX_EXTSEARCH ) ) + { + switch( pVar->GetClass() ) + { + case SbxCLASS_OBJECT: + { + // Objekte duerfen ihren Parent nicht durchsuchen + USHORT nOld = pVar->GetFlags(); + pVar->ResetFlag( SBX_GBLSEARCH ); + p = ((SbxObject*) pVar)->Find( rName, t ); + pVar->SetFlags( nOld ); + break; + } + case SbxCLASS_ARRAY: + p = ((SbxArray*) pVar)->Find( rName, t ); + break; + default: break; + } + if( p ) + { + p->SetFlag( SBX_EXTFOUND ); + break; + } + } + } + } + return p; +} + +BOOL SbxArray::LoadData( SvStream& rStrm, USHORT nVer ) +{ + UINT16 nElem; + Clear(); + BOOL bRes = TRUE; + USHORT f = nFlags; + nFlags |= SBX_WRITE; + rStrm >> nElem; + nElem &= 0x7FFF; + for( UINT32 n = 0; n < nElem; n++ ) + { + UINT16 nIdx; + rStrm >> nIdx; + SbxVariable* pVar = (SbxVariable*) Load( rStrm ); + if( pVar ) + { + SbxVariableRef& rRef = GetRef( nIdx ); + rRef = pVar; + } + else + { + bRes = FALSE; break; + } + } + if( bRes ) + bRes = LoadPrivateData( rStrm, nVer ); + nFlags = f; + return bRes; +} + +BOOL SbxArray::StoreData( SvStream& rStrm ) const +{ + UINT32 nElem = 0; + UINT32 n; + // Welche Elemente sind ueberhaupt definiert? + for( n = 0; n < pData->size(); n++ ) + { + SbxVariableRef* pRef = (*pData)[n]; + SbxVariable* p = *pRef; + if( p && !( p->GetFlags() & SBX_DONTSTORE ) ) + nElem++; + } + rStrm << (UINT16) nElem; + for( n = 0; n < pData->size(); n++ ) + { + SbxVariableRef* pRef = (*pData)[n]; + SbxVariable* p = *pRef; + if( p && !( p->GetFlags() & SBX_DONTSTORE ) ) + { + rStrm << (UINT16) n; + if( !p->Store( rStrm ) ) + return FALSE; + } + } + return StorePrivateData( rStrm ); +} + +// #100883 Method to set method directly to parameter array +void SbxArray::PutDirect( SbxVariable* pVar, UINT32 nIdx ) +{ + SbxVariableRef& rRef = GetRef32( nIdx ); + rRef = pVar; +} + + +////////////////////////////////////////////////////////////////////////// +// +// SbxArray +// +////////////////////////////////////////////////////////////////////////// + +SbxDimArray::SbxDimArray( SbxDataType t ) : SbxArray( t ), mbHasFixedSize( false ) +{ + pFirst = pLast = NULL; + nDim = 0; +} + +SbxDimArray::SbxDimArray( const SbxDimArray& rArray ) + : SvRefBase( rArray ), SbxArray( rArray.eType ) +{ + pFirst = pLast = NULL; + nDim = 0; + *this = rArray; +} + +SbxDimArray& SbxDimArray::operator=( const SbxDimArray& rArray ) +{ + if( &rArray != this ) + { + SbxArray::operator=( (const SbxArray&) rArray ); + SbxDim* p = rArray.pFirst; + while( p ) + { + AddDim32( p->nLbound, p->nUbound ); + p = p->pNext; + } + this->mbHasFixedSize = rArray.mbHasFixedSize; + } + return *this; +} + +SbxDimArray::~SbxDimArray() +{ + Clear(); +} + +void SbxDimArray::Clear() +{ + SbxDim* p = pFirst; + while( p ) + { + SbxDim* q = p->pNext; + delete p; + p = q; + } + pFirst = pLast = NULL; + nDim = 0; +} + +// Dimension hinzufuegen + +void SbxDimArray::AddDimImpl32( INT32 lb, INT32 ub, BOOL bAllowSize0 ) +{ + SbxError eRes = SbxERR_OK; + if( ub < lb && !bAllowSize0 ) + { + eRes = SbxERR_BOUNDS; + ub = lb; + } + SbxDim* p = new SbxDim; + p->nLbound = lb; + p->nUbound = ub; + p->nSize = ub - lb + 1; + p->pNext = NULL; + if( !pFirst ) + pFirst = pLast = p; + else + pLast->pNext = p, pLast = p; + nDim++; + if( eRes ) + SetError( eRes ); +} + +void SbxDimArray::AddDim( short lb, short ub ) +{ + AddDimImpl32( lb, ub, FALSE ); +} + +void SbxDimArray::unoAddDim( short lb, short ub ) +{ + AddDimImpl32( lb, ub, TRUE ); +} + +void SbxDimArray::AddDim32( INT32 lb, INT32 ub ) +{ + AddDimImpl32( lb, ub, FALSE ); +} + +void SbxDimArray::unoAddDim32( INT32 lb, INT32 ub ) +{ + AddDimImpl32( lb, ub, TRUE ); +} + + +// Dimensionsdaten auslesen + +BOOL SbxDimArray::GetDim32( INT32 n, INT32& rlb, INT32& rub ) const +{ + if( n < 1 || n > nDim ) + { + SetError( SbxERR_BOUNDS ); rub = rlb = 0; return FALSE; + } + SbxDim* p = pFirst; + while( --n ) + p = p->pNext; + rub = p->nUbound; + rlb = p->nLbound; + return TRUE; +} + +BOOL SbxDimArray::GetDim( short n, short& rlb, short& rub ) const +{ + INT32 rlb32, rub32; + BOOL bRet = GetDim32( n, rlb32, rub32 ); + if( bRet ) + { + if( rlb32 < -SBX_MAXINDEX || rub32 > SBX_MAXINDEX ) + { + SetError( SbxERR_BOUNDS ); + return FALSE; + } + rub = (short)rub32; + rlb = (short)rlb32; + } + return bRet; +} + +// Element-Ptr anhand einer Index-Liste + +UINT32 SbxDimArray::Offset32( const INT32* pIdx ) +{ + UINT32 nPos = 0; + for( SbxDim* p = pFirst; p; p = p->pNext ) + { + INT32 nIdx = *pIdx++; + if( nIdx < p->nLbound || nIdx > p->nUbound ) + { + nPos = (UINT32)SBX_MAXINDEX32 + 1; break; + } + nPos = nPos * p->nSize + nIdx - p->nLbound; + } + if( nDim == 0 || nPos > SBX_MAXINDEX32 ) + { + SetError( SbxERR_BOUNDS ); nPos = 0; + } + return nPos; +} + +USHORT SbxDimArray::Offset( const short* pIdx ) +{ + long nPos = 0; + for( SbxDim* p = pFirst; p; p = p->pNext ) + { + short nIdx = *pIdx++; + if( nIdx < p->nLbound || nIdx > p->nUbound ) + { + nPos = SBX_MAXINDEX + 1; break; + } + nPos = nPos * p->nSize + nIdx - p->nLbound; + } + if( nDim == 0 || nPos > SBX_MAXINDEX ) + { + SetError( SbxERR_BOUNDS ); nPos = 0; + } + return (USHORT) nPos; +} + +SbxVariableRef& SbxDimArray::GetRef( const short* pIdx ) +{ + return SbxArray::GetRef( Offset( pIdx ) ); +} + +SbxVariable* SbxDimArray::Get( const short* pIdx ) +{ + return SbxArray::Get( Offset( pIdx ) ); +} + +void SbxDimArray::Put( SbxVariable* p, const short* pIdx ) +{ + SbxArray::Put( p, Offset( pIdx ) ); +} + +SbxVariableRef& SbxDimArray::GetRef32( const INT32* pIdx ) +{ + return SbxArray::GetRef32( Offset32( pIdx ) ); +} + +SbxVariable* SbxDimArray::Get32( const INT32* pIdx ) +{ + return SbxArray::Get32( Offset32( pIdx ) ); +} + +void SbxDimArray::Put32( SbxVariable* p, const INT32* pIdx ) +{ + SbxArray::Put32( p, Offset32( pIdx ) ); +} + + +// Element-Nr anhand eines Parameter-Arrays + +UINT32 SbxDimArray::Offset32( SbxArray* pPar ) +{ + if( nDim == 0 || !pPar || ( ( nDim != ( pPar->Count() - 1 ) ) && SbiRuntime::isVBAEnabled() ) ) + { + SetError( SbxERR_BOUNDS ); return 0; + } + UINT32 nPos = 0; + USHORT nOff = 1; // Nicht Element 0! + for( SbxDim* p = pFirst; p && !IsError(); p = p->pNext ) + { + INT32 nIdx = pPar->Get( nOff++ )->GetLong(); + if( nIdx < p->nLbound || nIdx > p->nUbound ) + { + nPos = (UINT32) SBX_MAXINDEX32+1; break; + } + nPos = nPos * p->nSize + nIdx - p->nLbound; + } + if( nPos > (UINT32) SBX_MAXINDEX32 ) + { + SetError( SbxERR_BOUNDS ); nPos = 0; + } + return nPos; +} + +USHORT SbxDimArray::Offset( SbxArray* pPar ) +{ + UINT32 nPos = Offset32( pPar ); + if( nPos > (long) SBX_MAXINDEX ) + { + SetError( SbxERR_BOUNDS ); nPos = 0; + } + return (USHORT) nPos; +} + +SbxVariableRef& SbxDimArray::GetRef( SbxArray* pPar ) +{ + return SbxArray::GetRef32( Offset32( pPar ) ); +} + +SbxVariable* SbxDimArray::Get( SbxArray* pPar ) +{ + return SbxArray::Get32( Offset32( pPar ) ); +} + +void SbxDimArray::Put( SbxVariable* p, SbxArray* pPar ) +{ + SbxArray::Put32( p, Offset32( pPar ) ); +} + +BOOL SbxDimArray::LoadData( SvStream& rStrm, USHORT nVer ) +{ + short nDimension; + rStrm >> nDimension; + for( short i = 0; i < nDimension && rStrm.GetError() == SVSTREAM_OK; i++ ) + { + INT16 lb, ub; + rStrm >> lb >> ub; + AddDim( lb, ub ); + } + return SbxArray::LoadData( rStrm, nVer ); +} + +BOOL SbxDimArray::StoreData( SvStream& rStrm ) const +{ + rStrm << (INT16) nDim; + for( short i = 0; i < nDim; i++ ) + { + short lb, ub; + GetDim( i, lb, ub ); + rStrm << (INT16) lb << (INT16) ub; + } + return SbxArray::StoreData( rStrm ); +} + diff --git a/basic/source/sbx/sbxbase.cxx b/basic/source/sbx/sbxbase.cxx new file mode 100644 index 000000000000..b1815228cd99 --- /dev/null +++ b/basic/source/sbx/sbxbase.cxx @@ -0,0 +1,462 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + + +#include <tools/shl.hxx> +#include <tools/stream.hxx> + +#include <basic/sbx.hxx> +#include <basic/sbxfac.hxx> +#include <basic/sbxbase.hxx> + +// AppData-Struktur fuer SBX: + +SV_IMPL_PTRARR(SbxParams,SbxParamInfo*); +SV_IMPL_PTRARR(SbxFacs,SbxFactory*); + +TYPEINIT0(SbxBase) + +// SBX-Daten anfordern oder ggf. anlegen +// wir legen den Bereich einfach an und verzichten auf die Freigabe! + +SbxAppData* GetSbxData_Impl() +{ +#ifndef DOS + SbxAppData** ppData = (SbxAppData**) ::GetAppData( SHL_SBX ); + SbxAppData* p = *ppData; + if( !p ) + p = *ppData = new SbxAppData; + return p; +#else + SbxAppData** ppData; + SbxAppData* p; + p = *ppData = new SbxAppData; + return p; +#endif +} + +SbxAppData::~SbxAppData() +{ + if( pBasicFormater ) + delete pBasicFormater; +} + + +//////////////////////////////// SbxBase ///////////////////////////////// + +DBG_NAME(SbxBase); + +SbxBase::SbxBase() +{ + DBG_CTOR( SbxBase, 0 ); + nFlags = SBX_READWRITE; +} + +SbxBase::SbxBase( const SbxBase& r ) + : SvRefBase( r ) +{ + DBG_CTOR( SbxBase, 0 ); + nFlags = r.nFlags; +} + +SbxBase::~SbxBase() +{ + DBG_DTOR(SbxBase,0); +} + +SbxBase& SbxBase::operator=( const SbxBase& r ) +{ + DBG_CHKTHIS( SbxBase, 0 ); + nFlags = r.nFlags; + return *this; +} + +SbxDataType SbxBase::GetType() const +{ + DBG_CHKTHIS( SbxBase, 0 ); + return SbxEMPTY; +} + +SbxClassType SbxBase::GetClass() const +{ + DBG_CHKTHIS( SbxBase, 0 ); + return SbxCLASS_DONTCARE; +} + +void SbxBase::Clear() +{ + DBG_CHKTHIS( SbxBase, 0 ); +} + +BOOL SbxBase::IsFixed() const +{ + DBG_CHKTHIS( SbxBase, 0 ); + return IsSet( SBX_FIXED ); +} + +void SbxBase::SetModified( BOOL b ) +{ + DBG_CHKTHIS( SbxBase, 0 ); + if( IsSet( SBX_NO_MODIFY ) ) + return; + if( b ) + SetFlag( SBX_MODIFIED ); + else + ResetFlag( SBX_MODIFIED ); +} + +SbxError SbxBase::GetError() +{ + return GetSbxData_Impl()->eSbxError; +} + +void SbxBase::SetError( SbxError e ) +{ + SbxAppData* p = GetSbxData_Impl(); + if( e && p->eSbxError == SbxERR_OK ) + p->eSbxError = e; +} + +BOOL SbxBase::IsError() +{ + return BOOL( GetSbxData_Impl()->eSbxError != SbxERR_OK ); +} + +void SbxBase::ResetError() +{ + GetSbxData_Impl()->eSbxError = SbxERR_OK; +} + +void SbxBase::AddFactory( SbxFactory* pFac ) +{ + SbxAppData* p = GetSbxData_Impl(); + const SbxFactory* pTemp = pFac; + + // AB, 6.3.96: HandleLast-Flag beruecksichtigen + USHORT nPos = p->aFacs.Count(); // Einfuege-Position + if( !pFac->IsHandleLast() ) // Nur, wenn nicht selbst HandleLast + { + // Neue Factory vor Factories mit HandleLast einordnen + while( nPos > 0 && + (static_cast<SbxFactory*>(p->aFacs.GetObject( nPos-1 )))->IsHandleLast() ) + nPos--; + } + p->aFacs.Insert( pTemp, nPos ); +} + +void SbxBase::RemoveFactory( SbxFactory* pFac ) +{ + SbxAppData* p = GetSbxData_Impl(); + for( USHORT i = 0; i < p->aFacs.Count(); i++ ) + { + if( p->aFacs.GetObject( i ) == pFac ) + { + p->aFacs.Remove( i, 1 ); break; + } + } +} + + +SbxBase* SbxBase::Create( UINT16 nSbxId, UINT32 nCreator ) +{ + // #91626: Hack to skip old Basic dialogs + // Problem: There does not exist a factory any more, + // so we have to create a dummy SbxVariable instead + if( nSbxId == 0x65 ) // Dialog Id + return new SbxVariable; + + XubString aEmptyStr; + if( nCreator == SBXCR_SBX ) + switch( nSbxId ) + { + case SBXID_VALUE: return new SbxValue; + case SBXID_VARIABLE: return new SbxVariable; + case SBXID_ARRAY: return new SbxArray; + case SBXID_DIMARRAY: return new SbxDimArray; + case SBXID_OBJECT: return new SbxObject( aEmptyStr ); + case SBXID_COLLECTION: return new SbxCollection( aEmptyStr ); + case SBXID_FIXCOLLECTION: + return new SbxStdCollection( aEmptyStr, aEmptyStr ); + case SBXID_METHOD: return new SbxMethod( aEmptyStr, SbxEMPTY ); + case SBXID_PROPERTY: return new SbxProperty( aEmptyStr, SbxEMPTY ); + } + // Unbekanter Typ: ber die Factories gehen! + SbxAppData* p = GetSbxData_Impl(); + SbxBase* pNew = NULL; + for( USHORT i = 0; i < p->aFacs.Count(); i++ ) + { + SbxFactory* pFac = p->aFacs.GetObject( i ); + pNew = pFac->Create( nSbxId, nCreator ); + if( pNew ) + break; + } +#ifdef DBG_UTIL + if( !pNew ) + { + ByteString aMsg( "SBX: Keine Factory fuer SBX-ID " ); + aMsg += ByteString::CreateFromInt32(nSbxId); + DbgError( aMsg.GetBuffer() ); + } +#endif + return pNew; +} + +SbxObject* SbxBase::CreateObject( const XubString& rClass ) +{ + SbxAppData* p = GetSbxData_Impl(); + SbxObject* pNew = NULL; + for( USHORT i = 0; i < p->aFacs.Count(); i++ ) + { + pNew = p->aFacs.GetObject( i )->CreateObject( rClass ); + if( pNew ) + break; + } +#ifdef DBG_UTIL + if( !pNew ) + { + ByteString aMsg( "SBX: Keine Factory fuer Objektklasse " ); + ByteString aClassStr( (const UniString&)rClass, RTL_TEXTENCODING_ASCII_US ); + aMsg += aClassStr; + DbgError( (const char*)aMsg.GetBuffer() ); + } +#endif + return pNew; +} + +static BOOL bStaticEnableBroadcasting = TRUE; + +// Sbx-Loesung als Ersatz fuer SfxBroadcaster::Enable() +void SbxBase::StaticEnableBroadcasting( BOOL bEnable ) +{ + bStaticEnableBroadcasting = bEnable; +} + +BOOL SbxBase::StaticIsEnabledBroadcasting( void ) +{ + return bStaticEnableBroadcasting; +} + + +SbxBase* SbxBase::Load( SvStream& rStrm ) +{ + UINT16 nSbxId, nFlags, nVer; + UINT32 nCreator, nSize; + rStrm >> nCreator >> nSbxId >> nFlags >> nVer; + + // Eine Dummheit meinerseits korrigieren: + if( nFlags & SBX_RESERVED ) + nFlags = ( nFlags & ~SBX_RESERVED ) | SBX_GBLSEARCH; + + ULONG nOldPos = rStrm.Tell(); + rStrm >> nSize; + SbxBase* p = Create( nSbxId, nCreator ); + if( p ) + { + p->nFlags = nFlags; + if( p->LoadData( rStrm, nVer ) ) + { + ULONG nNewPos = rStrm.Tell(); + nOldPos += nSize; + DBG_ASSERT( nOldPos >= nNewPos, "SBX: Zu viele Daten eingelesen" ); + if( nOldPos != nNewPos ) + rStrm.Seek( nOldPos ); + if( !p->LoadCompleted() ) + { + // Loeschen des Objekts + SbxBaseRef aRef( p ); + p = NULL; + } + } + else + { + rStrm.SetError( SVSTREAM_FILEFORMAT_ERROR ); + // Loeschen des Objekts + SbxBaseRef aRef( p ); + p = NULL; + } + } + else + rStrm.SetError( SVSTREAM_FILEFORMAT_ERROR ); + return p; +} + +// Sbx-Objekt im Stream ueberspringen +void SbxBase::Skip( SvStream& rStrm ) +{ + UINT16 nSbxId, nFlags, nVer; + UINT32 nCreator, nSize; + rStrm >> nCreator >> nSbxId >> nFlags >> nVer; + + ULONG nStartPos = rStrm.Tell(); + rStrm >> nSize; + + rStrm.Seek( nStartPos + nSize ); +} + +BOOL SbxBase::Store( SvStream& rStrm ) +{ + DBG_CHKTHIS( SbxBase, 0 ); + if( !( nFlags & SBX_DONTSTORE ) ) + { + rStrm << (UINT32) GetCreator() + << (UINT16) GetSbxId() + << (UINT16) GetFlags() + << (UINT16) GetVersion(); + ULONG nOldPos = rStrm.Tell(); + rStrm << (UINT32) 0L; + BOOL bRes = StoreData( rStrm ); + ULONG nNewPos = rStrm.Tell(); + rStrm.Seek( nOldPos ); + rStrm << (UINT32) ( nNewPos - nOldPos ); + rStrm.Seek( nNewPos ); + if( rStrm.GetError() != SVSTREAM_OK ) + bRes = FALSE; + if( bRes ) + bRes = StoreCompleted(); + return bRes; + } + else + return TRUE; +} + +BOOL SbxBase::LoadData( SvStream&, USHORT ) +{ + DBG_CHKTHIS( SbxBase, 0 ); + return FALSE; +} + +BOOL SbxBase::StoreData( SvStream& ) const +{ + DBG_CHKTHIS( SbxBase, 0 ); + return FALSE; +} + +BOOL SbxBase::LoadPrivateData( SvStream&, USHORT ) +{ + DBG_CHKTHIS( SbxBase, 0 ); + return TRUE; +} + +BOOL SbxBase::StorePrivateData( SvStream& ) const +{ + DBG_CHKTHIS( SbxBase, 0 ); + return TRUE; +} + +BOOL SbxBase::LoadCompleted() +{ + DBG_CHKTHIS( SbxBase, 0 ); + return TRUE; +} + +BOOL SbxBase::StoreCompleted() +{ + DBG_CHKTHIS( SbxBase, 0 ); + return TRUE; +} + +//////////////////////////////// SbxFactory //////////////////////////////// + +SbxBase* SbxFactory::Create( UINT16, UINT32 ) +{ + return NULL; +} + +SbxObject* SbxFactory::CreateObject( const XubString& ) +{ + return NULL; +} + +///////////////////////////////// SbxInfo ////////////////////////////////// + +SbxInfo::~SbxInfo() +{} + +void SbxInfo::AddParam + ( const XubString& rName, SbxDataType eType, USHORT nFlags ) +{ + const SbxParamInfo* p = new SbxParamInfo( rName, eType, nFlags ); + aParams.Insert( p, aParams.Count() ); +} + +void SbxInfo::AddParam( const SbxParamInfo& r ) +{ + const SbxParamInfo* p = new SbxParamInfo + ( r.aName, r.eType, r.nFlags, r.aTypeRef ); + aParams.Insert( p, aParams.Count() ); +} + +const SbxParamInfo* SbxInfo::GetParam( USHORT n ) const +{ + if( n < 1 || n > aParams.Count() ) + return NULL; + else + return aParams.GetObject( n-1 ); +} + +BOOL SbxInfo::LoadData( SvStream& rStrm, USHORT nVer ) +{ + aParams.Remove( 0, aParams.Count() ); + UINT16 nParam; + rStrm.ReadByteString( aComment, RTL_TEXTENCODING_ASCII_US ); + rStrm.ReadByteString( aHelpFile, RTL_TEXTENCODING_ASCII_US ); + rStrm >> nHelpId >> nParam; + while( nParam-- ) + { + XubString aName; + UINT16 nType, nFlags; + UINT32 nUserData = 0; + rStrm.ReadByteString( aName, RTL_TEXTENCODING_ASCII_US ); + rStrm >> nType >> nFlags; + if( nVer > 1 ) + rStrm >> nUserData; + AddParam( aName, (SbxDataType) nType, nFlags ); + SbxParamInfo* p = aParams.GetObject( aParams.Count() - 1 ); + p->nUserData = nUserData; + } + return TRUE; +} + +BOOL SbxInfo::StoreData( SvStream& rStrm ) const +{ + rStrm.WriteByteString( aComment, RTL_TEXTENCODING_ASCII_US ); + rStrm.WriteByteString( aHelpFile, RTL_TEXTENCODING_ASCII_US ); + rStrm << nHelpId << aParams.Count(); + for( USHORT i = 0; i < aParams.Count(); i++ ) + { + SbxParamInfo* p = aParams.GetObject( i ); + rStrm.WriteByteString( p->aName, RTL_TEXTENCODING_ASCII_US ); + rStrm << (UINT16) p->eType + << (UINT16) p->nFlags + << (UINT32) p->nUserData; + } + return TRUE; +} + diff --git a/basic/source/sbx/sbxbool.cxx b/basic/source/sbx/sbxbool.cxx new file mode 100644 index 000000000000..728b8e1472b0 --- /dev/null +++ b/basic/source/sbx/sbxbool.cxx @@ -0,0 +1,252 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" +#include "sbxres.hxx" + +// AB 29.10.99 Unicode +#ifndef _USE_NO_NAMESPACE +using namespace rtl; +#endif + +enum SbxBOOL ImpGetBool( const SbxValues* p ) +{ + enum SbxBOOL nRes; + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = SbxFALSE; break; + case SbxCHAR: + nRes = p->nChar ? SbxTRUE : SbxFALSE; break; + case SbxBYTE: + nRes = p->nByte ? SbxTRUE : SbxFALSE; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger ? SbxTRUE : SbxFALSE; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort ? SbxTRUE : SbxFALSE; break; + case SbxLONG: + nRes = p->nLong ? SbxTRUE : SbxFALSE; break; + case SbxULONG: + nRes = p->nULong ? SbxTRUE : SbxFALSE; break; + case SbxSINGLE: + nRes = p->nSingle ? SbxTRUE : SbxFALSE; break; + case SbxDATE: + case SbxDOUBLE: + nRes = p->nDouble ? SbxTRUE : SbxFALSE; break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + nRes = dVal ? SbxTRUE : SbxFALSE; + } + break; + case SbxSALINT64: + nRes = p->nInt64 ? SbxTRUE : SbxFALSE; break; + case SbxSALUINT64: + nRes = p->uInt64 ? SbxTRUE : SbxFALSE; break; + case SbxULONG64: + nRes = !!p->nULong64 ? SbxTRUE : SbxFALSE; break; + case SbxLONG64: + case SbxCURRENCY: + nRes = !!p->nLong64 ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + nRes = SbxFALSE; + if( p->pString ) + { + if( p->pString->EqualsIgnoreCaseAscii( SbxRes( STRING_TRUE ) ) ) + nRes = SbxTRUE; + else if( !p->pString->EqualsIgnoreCaseAscii( SbxRes( STRING_FALSE ) ) ) + { + // Jetzt kann es noch in eine Zahl konvertierbar sein + BOOL bError = TRUE; + double n; + SbxDataType t; + USHORT nLen = 0; + String s( *p->pString ); + if( ImpScan( s, n, t, &nLen ) == SbxERR_OK ) + { + if( nLen == s.Len() ) + { + bError = FALSE; + if( n != 0.0 ) + nRes = SbxTRUE; + } + } + if( bError ) + SbxBase::SetError( SbxERR_CONVERSION ); + } + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetBool() ? SbxTRUE : SbxFALSE; + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = SbxFALSE; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = *p->pUShort ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxSINGLE: + nRes = ( *p->pSingle != 0 ) ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + nRes = ( *p->pDouble != 0 ) ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxSALINT64: + nRes = ( *p->pnInt64 ) ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxSALUINT64: + nRes = ( *p->puInt64 ) ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxULONG64: + nRes = !!*p->pULong64 ? SbxTRUE : SbxFALSE; break; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + nRes = !!*p->pLong64 ? SbxTRUE : SbxFALSE; break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = SbxFALSE; + } + return nRes; +} + +void ImpPutBool( SbxValues* p, INT16 n ) +{ + if( n ) + n = SbxTRUE; + switch( +p->eType ) + { + case SbxCHAR: + p->nChar = (xub_Unicode) n; break; + case SbxUINT: + p->nByte = (BYTE) n; break; + case SbxINTEGER: + case SbxBOOL: + p->nInteger = n; break; + case SbxLONG: + p->nLong = n; break; + case SbxULONG: + p->nULong = (UINT32) n; break; + case SbxERROR: + case SbxUSHORT: + p->nUShort = (UINT16) n; break; + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSALUINT64: + p->uInt64 = n; break; + case SbxULONG64: + p->nULong64.Set( (UINT32)n ); break; + case SbxLONG64: + case SbxCURRENCY: + p->nLong64.Set( (INT32)n ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setInt( (INT16)n ); + break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + *p->pString = SbxRes( n ? STRING_TRUE : STRING_FALSE ); + break; + + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutBool( BOOL( n != 0 ) ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + *p->pLong = n; break; + case SbxBYREF | SbxULONG: + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxULONG64: + p->pULong64->Set( (UINT32)n ); break; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + p->pLong64->Set( (INT32)n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxbyte.cxx b/basic/source/sbx/sbxbyte.cxx new file mode 100644 index 000000000000..8485b7105e21 --- /dev/null +++ b/basic/source/sbx/sbxbyte.cxx @@ -0,0 +1,329 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +BYTE ImpGetByte( const SbxValues* p ) +{ + SbxValues aTmp; + BYTE nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + if( p->nChar > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) p->nChar; + break; + case SbxBYTE: + nRes = (BYTE) p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + if( p->nInteger > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else if( p->nInteger < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) p->nInteger; + break; + case SbxERROR: + case SbxUSHORT: + if( p->nUShort > (USHORT) SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else + nRes = (BYTE) p->nUShort; + break; + case SbxLONG: + if( p->nLong > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else if( p->nLong < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) p->nLong; + break; + case SbxULONG: + if( p->nULong > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else + nRes = (BYTE) p->nULong; + break; + case SbxSALINT64: + if( p->nInt64 > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else if( p->nInt64 < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) p->nInt64; + break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else + nRes = (BYTE) p->uInt64; + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else if( p->nSingle < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) ImpRound( p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else if( dVal < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) ImpRound( dVal ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXBYTE; + } + else if( d < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (BYTE) ( d + 0.5 ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetByte(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxBYTE: + nRes = p->nByte; break; + + // ab hier wird getestet + case SbxBYREF | SbxCHAR: + aTmp.nChar = *p->pChar; goto ref; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + aTmp.nInteger = *p->pInteger; goto ref; + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutByte( SbxValues* p, BYTE n ) +{ + switch( +p->eType ) + { + case SbxBYTE: + p->nByte = n; break; + case SbxINTEGER: + case SbxBOOL: + p->nInteger = n; break; + case SbxERROR: + case SbxUSHORT: + p->nUShort = n; break; + case SbxLONG: + p->nLong = n; break; + case SbxULONG: + p->nULong = n; break; + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSALUINT64: + p->uInt64 = n; break; + case SbxULONG64: + p->nULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxLONG64: + p->nLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxCURRENCY: + p->nLong64 = ImpDoubleToCurrency( (double)n ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setByte( n ); + break; + + case SbxCHAR: + p->nChar = (xub_Unicode) n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 0, *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutByte( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + *p->pByte = n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + *p->pInteger = n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + *p->pUShort = n; break; + case SbxBYREF | SbxLONG: + *p->pLong = n; break; + case SbxBYREF | SbxULONG: + *p->pULong = n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = n; break; + case SbxBYREF | SbxULONG64: + *p->pULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxBYREF | SbxLONG64: + *p->pLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxchar.cxx b/basic/source/sbx/sbxchar.cxx new file mode 100644 index 000000000000..f9bca67a28d9 --- /dev/null +++ b/basic/source/sbx/sbxchar.cxx @@ -0,0 +1,325 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +// AB 29.10.99 Unicode +#ifndef _USE_NO_NAMESPACE +using namespace rtl; +#endif + +xub_Unicode ImpGetChar( const SbxValues* p ) +{ + SbxValues aTmp; + xub_Unicode nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = (xub_Unicode) p->nByte; + break; + case SbxINTEGER: + case SbxBOOL: + if( p->nInteger < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINCHAR; + } + else + nRes = (xub_Unicode) p->nInteger; + break; + case SbxERROR: + case SbxUSHORT: + nRes = (xub_Unicode) p->nUShort; + break; + case SbxLONG: + if( p->nLong > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else if( p->nLong < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINCHAR; + } + else + nRes = (xub_Unicode) p->nLong; + break; + case SbxULONG: + if( p->nULong > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else + nRes = (xub_Unicode) p->nULong; + break; + case SbxSALINT64: + if( p->nInt64 > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else if( p->nInt64 < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINCHAR; + } + else + nRes = (xub_Unicode) p->nInt64; + break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else + nRes = (xub_Unicode) p->uInt64; + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else if( p->nSingle < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINCHAR; + } + else + nRes = (xub_Unicode) ImpRound( p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else if( dVal < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINCHAR; + } + else + nRes = (BYTE) ImpRound( dVal ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXCHAR; + } + else if( d < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINCHAR; + } + else + nRes = (xub_Unicode) ImpRound( d ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetChar(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + // ab hier wird getestet + case SbxBYREF | SbxBYTE: + aTmp.nByte = *p->pByte; goto ref; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + aTmp.nInteger = *p->pInteger; goto ref; + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutChar( SbxValues* p, xub_Unicode n ) +{ + SbxValues aTmp; +start: + switch( +p->eType ) + { + case SbxCHAR: + p->nChar = n; break; + case SbxINTEGER: + case SbxBOOL: + p->nInteger = n; break; + case SbxLONG: + p->nLong = n; break; + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSALUINT64: + p->uInt64 = n; break; + case SbxULONG64: + p->nULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxLONG64: + p->nLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxCURRENCY: + p->nLong64 = ImpDoubleToCurrency( (double)n ); break; + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setChar( n ); + break; + + // ab hier wird getestet + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + *p->pString = n; + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutChar( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + *p->pChar = n; break; + case SbxBYREF | SbxBYTE: + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + *p->pInteger = n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxULONG64: + *p->pULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxBYREF | SbxLONG64: + *p->pLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + + diff --git a/basic/source/sbx/sbxcoll.cxx b/basic/source/sbx/sbxcoll.cxx new file mode 100644 index 000000000000..7bd32900ecc9 --- /dev/null +++ b/basic/source/sbx/sbxcoll.cxx @@ -0,0 +1,301 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + + +#include <tools/stream.hxx> + +#include <basic/sbx.hxx> +#include "sbxres.hxx" + +TYPEINIT1(SbxCollection,SbxObject) +TYPEINIT1(SbxStdCollection,SbxCollection) + +static const char* pCount; +static const char* pAdd; +static const char* pItem; +static const char* pRemove; +static USHORT nCountHash = 0, nAddHash, nItemHash, nRemoveHash; + +///////////////////////////////////////////////////////////////////////// + +SbxCollection::SbxCollection( const XubString& rClass ) + : SbxObject( rClass ) +{ + if( !nCountHash ) + { + pCount = GetSbxRes( STRING_COUNTPROP ); + pAdd = GetSbxRes( STRING_ADDMETH ); + pItem = GetSbxRes( STRING_ITEMMETH ); + pRemove = GetSbxRes( STRING_REMOVEMETH ); + nCountHash = MakeHashCode( String::CreateFromAscii( pCount ) ); + nAddHash = MakeHashCode( String::CreateFromAscii( pAdd ) ); + nItemHash = MakeHashCode( String::CreateFromAscii( pItem ) ); + nRemoveHash = MakeHashCode( String::CreateFromAscii( pRemove ) ); + } + Initialize(); + // Fuer Zugriffe auf sich selbst + StartListening( GetBroadcaster(), TRUE ); +} + +SbxCollection::SbxCollection( const SbxCollection& rColl ) + : SvRefBase( rColl ), SbxObject( rColl ) +{} + +SbxCollection& SbxCollection::operator=( const SbxCollection& r ) +{ + if( &r != this ) + SbxObject::operator=( r ); + return *this; +} + +SbxCollection::~SbxCollection() +{} + +void SbxCollection::Clear() +{ + SbxObject::Clear(); + Initialize(); +} + +void SbxCollection::Initialize() +{ + SetType( SbxOBJECT ); + SetFlag( SBX_FIXED ); + ResetFlag( SBX_WRITE ); + SbxVariable* p; + p = Make( String::CreateFromAscii( pCount ), SbxCLASS_PROPERTY, SbxINTEGER ); + p->ResetFlag( SBX_WRITE ); + p->SetFlag( SBX_DONTSTORE ); + p = Make( String::CreateFromAscii( pAdd ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); + p = Make( String::CreateFromAscii( pItem ), SbxCLASS_METHOD, SbxOBJECT ); + p->SetFlag( SBX_DONTSTORE ); + p = Make( String::CreateFromAscii( pRemove ), SbxCLASS_METHOD, SbxEMPTY ); + p->SetFlag( SBX_DONTSTORE ); +} + +SbxVariable* SbxCollection::FindUserData( UINT32 nData ) +{ + if( GetParameters() ) + { + SbxObject* pObj = (SbxObject*) GetObject(); + return pObj ? pObj->FindUserData( nData ) : NULL; + } + else + return SbxObject::FindUserData( nData ); +} + +SbxVariable* SbxCollection::Find( const XubString& rName, SbxClassType t ) +{ + if( GetParameters() ) + { + SbxObject* pObj = (SbxObject*) GetObject(); + return pObj ? pObj->Find( rName, t ) : NULL; + } + else + return SbxObject::Find( rName, t ); +} + +void SbxCollection::SFX_NOTIFY( SfxBroadcaster& rCst, const TypeId& rId1, + const SfxHint& rHint, const TypeId& rId2 ) +{ + const SbxHint* p = PTR_CAST(SbxHint,&rHint); + if( p ) + { + ULONG nId = p->GetId(); + BOOL bRead = BOOL( nId == SBX_HINT_DATAWANTED ); + BOOL bWrite = BOOL( nId == SBX_HINT_DATACHANGED ); + SbxVariable* pVar = p->GetVar(); + SbxArray* pArg = pVar->GetParameters(); + if( bRead || bWrite ) + { + XubString aVarName( pVar->GetName() ); + if( pVar == this ) + CollItem( pArg ); + else if( pVar->GetHashCode() == nCountHash + && aVarName.EqualsIgnoreCaseAscii( pCount ) ) + pVar->PutLong( pObjs->Count() ); + else if( pVar->GetHashCode() == nAddHash + && aVarName.EqualsIgnoreCaseAscii( pAdd ) ) + CollAdd( pArg ); + else if( pVar->GetHashCode() == nItemHash + && aVarName.EqualsIgnoreCaseAscii( pItem ) ) + CollItem( pArg ); + else if( pVar->GetHashCode() == nRemoveHash + && aVarName.EqualsIgnoreCaseAscii( pRemove ) ) + CollRemove( pArg ); + else + SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 ); + return; + } + } + SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 ); +} + +// Default: Argument ist Objekt + +void SbxCollection::CollAdd( SbxArray* pPar_ ) +{ + if( pPar_->Count() != 2 ) + SetError( SbxERR_WRONG_ARGS ); + else + { + SbxBase* pObj = pPar_->Get( 1 )->GetObject(); + if( !pObj || !( pObj->ISA(SbxObject) ) ) + SetError( SbxERR_NOTIMP ); + else + Insert( (SbxObject*) pObj ); + } +} + +// Default: Index ab 1 oder der Objektname + +void SbxCollection::CollItem( SbxArray* pPar_ ) +{ + if( pPar_->Count() != 2 ) + SetError( SbxERR_WRONG_ARGS ); + else + { + SbxVariable* pRes = NULL; + SbxVariable* p = pPar_->Get( 1 ); + if( p->GetType() == SbxSTRING ) + pRes = Find( p->GetString(), SbxCLASS_OBJECT ); + else + { + short n = p->GetInteger(); + if( n >= 1 && n <= (short) pObjs->Count() ) + pRes = pObjs->Get( (USHORT) n - 1 ); + } + if( !pRes ) + SetError( SbxERR_BAD_INDEX ); + pPar_->Get( 0 )->PutObject( pRes ); + } +} + +// Default: Index ab 1 + +void SbxCollection::CollRemove( SbxArray* pPar_ ) +{ + if( pPar_->Count() != 2 ) + SetError( SbxERR_WRONG_ARGS ); + else + { + short n = pPar_->Get( 1 )->GetInteger(); + if( n < 1 || n > (short) pObjs->Count() ) + SetError( SbxERR_BAD_INDEX ); + else + Remove( pObjs->Get( (USHORT) n - 1 ) ); + } +} + +BOOL SbxCollection::LoadData( SvStream& rStrm, USHORT nVer ) +{ + BOOL bRes = SbxObject::LoadData( rStrm, nVer ); + Initialize(); + return bRes; +} + +///////////////////////////////////////////////////////////////////////// + +SbxStdCollection::SbxStdCollection + ( const XubString& rClass, const XubString& rElem, BOOL b ) + : SbxCollection( rClass ), aElemClass( rElem ), + bAddRemoveOk( b ) +{} + +SbxStdCollection::SbxStdCollection( const SbxStdCollection& r ) + : SvRefBase( r ), SbxCollection( r ), + aElemClass( r.aElemClass ), bAddRemoveOk( r.bAddRemoveOk ) +{} + +SbxStdCollection& SbxStdCollection::operator=( const SbxStdCollection& r ) +{ + if( &r != this ) + { + if( !r.aElemClass.EqualsIgnoreCaseAscii( aElemClass ) ) + SetError( SbxERR_CONVERSION ); + else + SbxCollection::operator=( r ); + } + return *this; +} + +SbxStdCollection::~SbxStdCollection() +{} + +// Default: Fehler, wenn falsches Objekt + +void SbxStdCollection::Insert( SbxVariable* p ) +{ + SbxObject* pObj = PTR_CAST(SbxObject,p); + if( pObj && !pObj->IsClass( aElemClass ) ) + SetError( SbxERR_BAD_ACTION ); + else + SbxCollection::Insert( p ); +} + +void SbxStdCollection::CollAdd( SbxArray* pPar_ ) +{ + if( !bAddRemoveOk ) + SetError( SbxERR_BAD_ACTION ); + else + SbxCollection::CollAdd( pPar_ ); +} + +void SbxStdCollection::CollRemove( SbxArray* pPar_ ) +{ + if( !bAddRemoveOk ) + SetError( SbxERR_BAD_ACTION ); + else + SbxCollection::CollRemove( pPar_ ); +} + +BOOL SbxStdCollection::LoadData( SvStream& rStrm, USHORT nVer ) +{ + BOOL bRes = SbxCollection::LoadData( rStrm, nVer ); + if( bRes ) + { + rStrm.ReadByteString( aElemClass, RTL_TEXTENCODING_ASCII_US ); + rStrm >> bAddRemoveOk; + } + return bRes; +} + +BOOL SbxStdCollection::StoreData( SvStream& rStrm ) const +{ + BOOL bRes = SbxCollection::StoreData( rStrm ); + if( bRes ) + { + rStrm.WriteByteString( aElemClass, RTL_TEXTENCODING_ASCII_US ); + rStrm << bAddRemoveOk; + } + return bRes; +} + diff --git a/basic/source/sbx/sbxconv.hxx b/basic/source/sbx/sbxconv.hxx new file mode 100644 index 000000000000..c1ada75286ab --- /dev/null +++ b/basic/source/sbx/sbxconv.hxx @@ -0,0 +1,151 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SBXCONV_HXX +#define _SBXCONV_HXX + +#include "sbxdec.hxx" + +class SbxArray; + +// SBXSCAN.CXX +extern void ImpCvtNum( double nNum, short nPrec, String& rRes, BOOL bCoreString=FALSE ); +extern SbxError ImpScan + ( const String& rSrc, double& nVal, SbxDataType& rType, USHORT* pLen, + BOOL bAllowIntntl=FALSE, BOOL bOnlyIntntl=FALSE ); + +// mit erweiterter Auswertung (International, "TRUE"/"FALSE") +extern BOOL ImpConvStringExt( String& rSrc, SbxDataType eTargetType ); + +// SBXINT.CXX + +double ImpRound( double ); +INT16 ImpGetInteger( const SbxValues* ); +void ImpPutInteger( SbxValues*, INT16 ); +sal_Int64 ImpGetInt64( const SbxValues* ); +void ImpPutInt64( SbxValues*, sal_Int64 ); +sal_uInt64 ImpGetUInt64( const SbxValues* ); +void ImpPutUInt64( SbxValues*, sal_uInt64 ); + +sal_Int64 ImpDoubleToSalInt64( double d ); +sal_uInt64 ImpDoubleToSalUInt64( double d ); +double ImpSalUInt64ToDouble( sal_uInt64 n ); + +// SBXLNG.CXX + +INT32 ImpGetLong( const SbxValues* ); +void ImpPutLong( SbxValues*, INT32 ); + +// SBXSNG.CXX + +float ImpGetSingle( const SbxValues* ); +void ImpPutSingle( SbxValues*, float ); + +// SBXDBL.CXX + +double ImpGetDouble( const SbxValues* ); +void ImpPutDouble( SbxValues*, double, BOOL bCoreString=FALSE ); + +#if FALSE +// SBX64.CXX + +SbxINT64 ImpGetINT64( const SbxValues* ); +void ImpPutINT64( SbxValues*, const SbxINT64& ); +SbxUINT64 ImpGetUINT64( const SbxValues* ); +void ImpPutUINT64( SbxValues*, const SbxUINT64& ); +#endif + +// SBXCURR.CXX + +SbxUINT64 ImpDoubleToUINT64( double ); +double ImpUINT64ToDouble( const SbxUINT64& ); +SbxINT64 ImpDoubleToINT64( double ); +double ImpINT64ToDouble( const SbxINT64& ); + +#if TRUE +INT32 ImpGetCurrLong( const SbxValues* ); +void ImpPutCurrLong( SbxValues*, INT32 ); +INT32 ImpDoubleToCurrLong( double ); +double ImpCurrLongToDouble( INT32 ); +#endif + +SbxINT64 ImpGetCurrency( const SbxValues* ); +void ImpPutCurrency( SbxValues*, const SbxINT64& ); +inline +SbxINT64 ImpDoubleToCurrency( double d ) + { return ImpDoubleToINT64( d * CURRENCY_FACTOR ); } +inline +double ImpCurrencyToDouble( const SbxINT64 &r ) + { return ImpINT64ToDouble( r ) / CURRENCY_FACTOR; } + + +// SBXDEC.CXX + +SbxDecimal* ImpCreateDecimal( SbxValues* p ); +SbxDecimal* ImpGetDecimal( const SbxValues* p ); +void ImpPutDecimal( SbxValues* p, SbxDecimal* pDec ); + +// SBXDATE.CXX + +double ImpGetDate( const SbxValues* ); +void ImpPutDate( SbxValues*, double ); + +// SBXSTR.CXX + +String ImpGetString( const SbxValues* ); +String ImpGetCoreString( const SbxValues* ); +void ImpPutString( SbxValues*, const String* ); + +// SBXCHAR.CXX + +sal_Unicode ImpGetChar( const SbxValues* ); +void ImpPutChar( SbxValues*, sal_Unicode ); + +// SBXBYTE.CXX +BYTE ImpGetByte( const SbxValues* ); +void ImpPutByte( SbxValues*, BYTE ); + +// SBXUINT.CXX + +UINT16 ImpGetUShort( const SbxValues* ); +void ImpPutUShort( SbxValues*, UINT16 ); + +// SBXULNG.CXX + +UINT32 ImpGetULong( const SbxValues* ); +void ImpPutULong( SbxValues*, UINT32 ); + +// SBXBOOL.CXX + +enum SbxBOOL ImpGetBool( const SbxValues* ); +void ImpPutBool( SbxValues*, INT16 ); + +// ByteArry <--> String +SbxArray* StringToByteArray(const String& rStr); +String ByteArrayToString(SbxArray* pArr); + +#endif diff --git a/basic/source/sbx/sbxcurr.cxx b/basic/source/sbx/sbxcurr.cxx new file mode 100644 index 000000000000..74380f84a75f --- /dev/null +++ b/basic/source/sbx/sbxcurr.cxx @@ -0,0 +1,395 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include <basic/sbx.hxx> +#include <tools/errcode.hxx> + +#define _TLBIGINT_INT64 +#include <tools/bigint.hxx> + +#include <basic/sbxvar.hxx> +#include "sbxconv.hxx" + +static String ImpCurrencyToString( const SbxINT64& ); +static SbxINT64 ImpStringToCurrency( const String& ); + +SbxINT64 ImpGetCurrency( const SbxValues* p ) +{ + SbxValues aTmp; + SbxINT64 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes.SetNull(); break; + case SbxCHAR: + nRes = ImpDoubleToCurrency( (double)p->nChar ); break; + case SbxBYTE: + nRes = ImpDoubleToCurrency( (double)p->nByte ); break; + case SbxINTEGER: + case SbxBOOL: + nRes = ImpDoubleToCurrency( (double)p->nInteger ); break; + case SbxERROR: + case SbxUSHORT: + nRes = ImpDoubleToCurrency( (double)p->nUShort ); break; + case SbxCURRENCY: + nRes = p->nLong64; break; + case SbxLONG: + nRes = ImpDoubleToCurrency( (double)p->nLong ); + break; + case SbxULONG: + nRes = ImpDoubleToCurrency( (double)p->nULong ); + break; + case SbxSALINT64: + nRes = ImpDoubleToCurrency( (double)p->nInt64 ); + break; + case SbxSALUINT64: + nRes = ImpDoubleToCurrency( ImpSalUInt64ToDouble( p->uInt64 ) ); + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMax(); + } + else if( p->nSingle < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMin(); + } + else + nRes = ImpDoubleToCurrency( (double)p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + if( p->nDouble > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMax(); + } + else if( p->nDouble < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMin(); + } + else + nRes = ImpDoubleToCurrency( p->nDouble ); + break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double d = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( d ); + if( d > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMax(); + } + else if( d < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMin(); + } + else + nRes = ImpDoubleToCurrency( d ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes.SetNull(); + else + nRes = ImpStringToCurrency( *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetCurrency(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes.SetNull(); + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = ImpDoubleToCurrency( (double)*p->pChar ); break; + case SbxBYREF | SbxBYTE: + nRes = ImpDoubleToCurrency( (double)*p->pByte ); break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = ImpDoubleToCurrency( (double)*p->pInteger ); break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = ImpDoubleToCurrency( (double)*p->pUShort ); break; + case SbxBYREF | SbxCURRENCY: + nRes = *p->pLong64; break; + + // ab hier muss getestet werden + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes.SetNull(); + } + return nRes; +} + +void ImpPutCurrency( SbxValues* p, const SbxINT64 &r ) +{ + double dVal = ImpCurrencyToDouble( r ); + SbxValues aTmp; +start: + switch( +p->eType ) + { + // Hier sind Tests notwendig + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxLONG: + aTmp.pLong = &p->nLong; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // ab hier nicht mehr + case SbxSINGLE: + p->nSingle = (float)dVal; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = dVal; break; + case SbxSALINT64: + p->nInt64 = ImpDoubleToSalInt64( dVal ); break; + case SbxSALUINT64: + p->uInt64 = ImpDoubleToSalUInt64( dVal ); break; + case SbxCURRENCY: + p->nLong64 = r; break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + SbxDecimal* pDec = ImpCreateDecimal( p ); + if( !pDec->setDouble( dVal ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + + *p->pString = ImpCurrencyToString( r ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutCurrency( r ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( dVal > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXCHAR; + } + else if( dVal < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) dVal; break; + case SbxBYREF | SbxBYTE: + if( dVal > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXBYTE; + } + else if( dVal < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = 0; + } + *p->pByte = (BYTE) dVal; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( dVal > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXINT; + } + else if( dVal < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMININT; + } + *p->pInteger = (INT16) dVal; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( dVal > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXUINT; + } + else if( dVal < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = 0; + } + *p->pUShort = (UINT16) dVal; break; + case SbxBYREF | SbxLONG: + if( dVal > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXLNG; + } + else if( dVal < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMINLNG; + } + *p->pLong = (INT32) dVal; break; + case SbxBYREF | SbxULONG: + if( dVal > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXULNG; + } + else if( dVal < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); dVal = 0; + } + *p->pULong = (UINT32) dVal; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = ImpDoubleToSalInt64( dVal ); break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = ImpDoubleToSalUInt64( dVal ); break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) dVal; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) dVal; break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = r; break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + +// Hilfs-Funktionen zur Wandlung + +static String ImpCurrencyToString( const SbxINT64 &r ) +{ + BigInt a10000 = 10000; + + //return GetpApp()->GetAppInternational().GetCurr( BigInt( r ), 4 ); + BigInt aInt( r ); + aInt.Abs(); + BigInt aFrac = aInt; + aInt /= a10000; + aFrac %= a10000; + aFrac += a10000; + + String aString; + if( r.nHigh < 0 ) + aString = '-'; + aString += aInt.GetString(); + aString += '.'; + aString += aFrac.GetString().GetBuffer()+1; + return aString; +} + +static SbxINT64 ImpStringToCurrency( const String &r ) +{ + int nDec = 4; + String aStr; + const sal_Unicode* p = r.GetBuffer(); + + if( *p == '-' ) + aStr += *p++; + + while( *p >= '0' && *p <= '9' ) { + aStr += *p++; + if( *p == ',' ) + p++; + } + + if( *p == '.' ) { + p++; + while( nDec && *p >= '0' && *p <= '9' ) { + aStr += *p++; + nDec--; + } + } + while( nDec ) { + aStr += '0'; + nDec--; + } + + BigInt aBig( aStr ); + SbxINT64 nRes; + aBig.INT64( &nRes ); + return nRes; +} + +double ImpINT64ToDouble( const SbxINT64 &r ) +{ return (double)r.nHigh*(double)4294967296.0 + (double)r.nLow; } + +SbxINT64 ImpDoubleToINT64( double d ) +{ + SbxINT64 nRes; + nRes.Set( d ); + return nRes; +} + +double ImpUINT64ToDouble( const SbxUINT64 &r ) +{ return (double)r.nHigh*(double)4294967296.0 + (double)r.nLow; } + +SbxUINT64 ImpDoubleToUINT64( double d ) +{ + SbxUINT64 nRes; + nRes.Set( d ); + return nRes; +} + diff --git a/basic/source/sbx/sbxdate.cxx b/basic/source/sbx/sbxdate.cxx new file mode 100644 index 000000000000..ce532fed0482 --- /dev/null +++ b/basic/source/sbx/sbxdate.cxx @@ -0,0 +1,412 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <vcl/svapp.hxx> +#include <svl/zforlist.hxx> +#include <tools/errcode.hxx> +#include <tools/color.hxx> +#include <i18npool/lang.h> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" +#include "math.h" +#include <comphelper/processfactory.hxx> + + +double ImpGetDate( const SbxValues* p ) +{ + double nRes; + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = (double) p->nLong; break; + case SbxULONG: + nRes = (double) p->nULong; break; + case SbxSINGLE: + nRes = p->nSingle; break; + case SbxDATE: + case SbxDOUBLE: + nRes = p->nDouble; break; + case SbxULONG64: + nRes = ImpUINT64ToDouble( p->nULong64 ); break; + case SbxLONG64: + nRes = ImpINT64ToDouble( p->nLong64 ); break; + case SbxCURRENCY: + nRes = ImpCurrencyToDouble( p->nLong64 ); break; + case SbxSALINT64: + nRes = static_cast< double >(p->nInt64); break; + case SbxSALUINT64: + nRes = ImpSalUInt64ToDouble( p->uInt64 ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + if( p->pDecimal ) + p->pDecimal->getDouble( nRes ); + else + nRes = 0.0; + break; + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { +#ifndef DOS + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + + SvNumberFormatter* pFormatter; + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > + xFactory = comphelper::getProcessServiceFactory(); + pFormatter = new SvNumberFormatter( xFactory, eLangType ); + + sal_uInt32 nIndex; + xub_StrLen nCheckPos = 0; + short nType = 127; + + // Standard-Vorlagen des Formatters haben nur zweistellige + // Jahreszahl. Deshalb eigenes Format registrieren + + // HACK, da der Numberformatter in PutandConvertEntry die Platzhalter + // fuer Monat, Tag, Jahr nicht entsprechend der Systemeinstellung + // austauscht. Problem: Print Year(Date) unter engl. BS + // siehe auch basic\source\runtime\runtime.cxx + + SvtSysLocale aSysLocale; + DateFormat eDate = aSysLocale.GetLocaleData().getDateFormat(); + String aDateStr; + switch( eDate ) + { + case MDY: aDateStr.AssignAscii( "MM.TT.JJJJ" ); break; + case DMY: aDateStr.AssignAscii( "TT.MM.JJJJ" ); break; + case YMD: aDateStr.AssignAscii( "JJJJ.MM.TT" ); break; + default: aDateStr.AssignAscii( "MM.TT.JJJJ" ); + } + + String aStr( aDateStr ); + aStr.AppendAscii( " HH:MM:SS" ); + + pFormatter->PutandConvertEntry( aStr, nCheckPos, nType, + nIndex, LANGUAGE_GERMAN, eLangType ); + BOOL bSuccess = pFormatter->IsNumberFormat( *p->pString, nIndex, nRes ); + if ( bSuccess ) + { + short nType_ = pFormatter->GetType( nIndex ); + if(!(nType_ & ( NUMBERFORMAT_DATETIME | NUMBERFORMAT_DATE | + NUMBERFORMAT_TIME | NUMBERFORMAT_DEFINED ))) + bSuccess = FALSE; + } + + if ( !bSuccess ) + { + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + + delete pFormatter; +#else + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; +#endif + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetDate(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = *p->pUShort; break; + case SbxBYREF | SbxSINGLE: + nRes = *p->pSingle; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + nRes = *p->pDouble; break; + case SbxBYREF | SbxULONG64: + nRes = ImpUINT64ToDouble( *p->pULong64 ); break; + case SbxBYREF | SbxLONG64: + nRes = ImpINT64ToDouble( *p->pLong64 ); break; + case SbxBYREF | SbxCURRENCY: + nRes = ImpCurrencyToDouble( *p->pLong64 ); break; + case SbxBYREF | SbxSALINT64: + nRes = static_cast< double >(*p->pnInt64); break; + case SbxBYREF | SbxSALUINT64: + nRes = ImpSalUInt64ToDouble( *p->puInt64 ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutDate( SbxValues* p, double n ) +{ + SbxValues aTmp; + +start: + switch( +p->eType ) + { + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + + // ab hier wird getestet + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxLONG: + aTmp.pLong = &p->nLong; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxSINGLE: + aTmp.pSingle = &p->nSingle; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxSALINT64: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + SbxDecimal* pDec = ImpCreateDecimal( p ); + if( !pDec->setDouble( n ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + break; + } + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: +#ifndef DOS + { + if( !p->pString ) + p->pString = new XubString; + Color* pColor; + + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + SvNumberFormatter* pFormatter; + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > + xFactory = comphelper::getProcessServiceFactory(); + pFormatter = new SvNumberFormatter( xFactory, eLangType ); + + sal_uInt32 nIndex; + xub_StrLen nCheckPos = 0; + short nType; + + SvtSysLocale aSysLocale; + DateFormat eDate = aSysLocale.GetLocaleData().getDateFormat(); + String aStr; + // ist der ganzzahlige Teil 0, wollen wir kein Jahr! + if( n <= -1.0 || n >= 1.0 ) + { + // Time only if != 00:00:00 + if( floor( n ) == n ) + { + switch( eDate ) + { + case MDY: aStr.AssignAscii( "MM.TT.JJJJ" ); break; + case DMY: aStr.AssignAscii( "TT.MM.JJJJ" ); break; + case YMD: aStr.AssignAscii( "JJJJ.MM.TT" ); break; + default: aStr.AssignAscii( "MM.TT.JJJJ" ); + } + } + else + { + switch( eDate ) + { + case MDY: aStr.AssignAscii( "MM.TT.JJJJ HH:MM:SS" ); break; + case DMY: aStr.AssignAscii( "TT.MM.JJJJ HH:MM:SS" ); break; + case YMD: aStr.AssignAscii( "JJJJ.MM.TT HH:MM:SS" ); break; + default: aStr.AssignAscii( "MM.TT.JJJJ HH:MM:SS" ); + } + } + } + else + aStr.AppendAscii( "HH:MM:SS" ); + + pFormatter->PutandConvertEntry( aStr, + nCheckPos, + nType, + nIndex, + LANGUAGE_GERMAN, + eLangType ); + pFormatter->GetOutputString( n, nIndex, *p->pString, &pColor ); + delete pFormatter; +#endif + break; +#ifndef DOS + } +#endif + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutDate( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + else if( n < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXULNG; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + if( n > SbxMAXSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXSNG; + } + else if( n < SbxMINSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINSNG; + } + *p->pSingle = (float) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = ImpDoubleToSalInt64( n ); break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = ImpDoubleToSalUInt64( n ); break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxCURRENCY: + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCURR; + } + else if( n < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCURR; + } + *p->pLong64 = ImpDoubleToCurrency( n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxdbl.cxx b/basic/source/sbx/sbxdbl.cxx new file mode 100644 index 000000000000..460f331c59b8 --- /dev/null +++ b/basic/source/sbx/sbxdbl.cxx @@ -0,0 +1,306 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" +#include "runtime.hxx" + +double ImpGetDouble( const SbxValues* p ) +{ + double nRes; + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = p->nLong; break; + case SbxULONG: + nRes = p->nULong; break; + case SbxSINGLE: + nRes = p->nSingle; break; + case SbxDATE: + case SbxDOUBLE: + nRes = p->nDouble; break; + case SbxCURRENCY: + nRes = ImpCurrencyToDouble( p->nLong64 ); break; + case SbxSALINT64: + nRes = static_cast< double >(p->nInt64); break; + case SbxSALUINT64: + nRes = ImpSalUInt64ToDouble( p->uInt64 ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + if( p->pDecimal ) + p->pDecimal->getDouble( nRes ); + else + nRes = 0.0; + break; + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + { + nRes = 0; + if ( SbiRuntime::isVBAEnabled() )// VBA only behaviour + SbxBase::SetError( SbxERR_CONVERSION ); + } + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + { + nRes = 0; + if ( SbiRuntime::isVBAEnabled() )// VBA only behaviour + SbxBase::SetError( SbxERR_CONVERSION ); + } + else + nRes = d; + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetDouble(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = *p->pUShort; break; + case SbxBYREF | SbxSINGLE: + nRes = *p->pSingle; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + nRes = *p->pDouble; break; + case SbxBYREF | SbxCURRENCY: + nRes = ImpCurrencyToDouble( *p->pLong64 ); break; + case SbxBYREF | SbxSALINT64: + nRes = static_cast< double >(*p->pnInt64); break; + case SbxBYREF | SbxSALUINT64: + nRes = ImpSalUInt64ToDouble( *p->puInt64 ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutDouble( SbxValues* p, double n, BOOL bCoreString ) +{ + SbxValues aTmp; +start: + switch( +p->eType ) + { + // Hier sind Tests notwendig + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxLONG: + case SbxCURRENCY: + aTmp.pLong = &p->nLong; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxSINGLE: + aTmp.pSingle = &p->nSingle; goto direct; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + SbxDecimal* pDec = ImpCreateDecimal( p ); + if( !pDec->setDouble( n ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + break; + } + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // ab hier nicht mehr + case SbxSALINT64: + p->nInt64 = ImpDoubleToSalInt64( n ); break; + case SbxSALUINT64: + p->uInt64 = ImpDoubleToSalUInt64( n ); break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 14, *p->pString, bCoreString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutDouble( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + else if( n < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXULNG; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + if( n > SbxMAXSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXSNG; + } + else if( n < SbxMINSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINSNG; + } + else if( n > 0 && n < SbxMAXSNG2 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXSNG2; + } + else if( n < 0 && n > SbxMINSNG2 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINSNG2; + } + *p->pSingle = (float) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = ImpDoubleToSalInt64( n ); break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = ImpDoubleToSalUInt64( n ); break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxCURRENCY: + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCURR; + } + else if( n < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCURR; + } + *p->pLong64 = ImpDoubleToCurrency( n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxdec.cxx b/basic/source/sbx/sbxdec.cxx new file mode 100644 index 000000000000..319b0aac366c --- /dev/null +++ b/basic/source/sbx/sbxdec.cxx @@ -0,0 +1,797 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> + +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +#include <com/sun/star/bridge/oleautomation/Decimal.hpp> + + +// int GnDecCounter = 0; + +// Implementation SbxDecimal +SbxDecimal::SbxDecimal( void ) +{ + setInt( 0 ); + mnRefCount = 0; + // GnDecCounter++; +} + +SbxDecimal::SbxDecimal( const SbxDecimal& rDec ) +{ +#ifdef WIN32 + maDec = rDec.maDec; +#else + (void)rDec; +#endif + mnRefCount = 0; + // GnDecCounter++; +} + +SbxDecimal::SbxDecimal + ( const com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ) +{ +#ifdef WIN32 + maDec.scale = rAutomationDec.Scale; + maDec.sign = rAutomationDec.Sign; + maDec.Lo32 = rAutomationDec.LowValue; + maDec.Mid32 = rAutomationDec.MiddleValue; + maDec.Hi32 = rAutomationDec.HighValue; +#else + (void)rAutomationDec; +#endif + mnRefCount = 0; + // GnDecCounter++; +} + +void SbxDecimal::fillAutomationDecimal + ( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ) +{ +#ifdef WIN32 + rAutomationDec.Scale = maDec.scale; + rAutomationDec.Sign = maDec.sign; + rAutomationDec.LowValue = maDec.Lo32; + rAutomationDec.MiddleValue = maDec.Mid32; + rAutomationDec.HighValue = maDec.Hi32; +#else + (void)rAutomationDec; +#endif +} + +SbxDecimal::~SbxDecimal() +{ + // GnDecCounter--; +} + +void releaseDecimalPtr( SbxDecimal*& rpDecimal ) +{ + if( rpDecimal ) + { + rpDecimal->mnRefCount--; + if( rpDecimal->mnRefCount == 0 ) + { + delete rpDecimal; + rpDecimal = NULL; + } + } +} + +#ifdef WIN32 + +bool SbxDecimal::operator -= ( const SbxDecimal &r ) +{ + HRESULT hResult = VarDecSub( &maDec, (LPDECIMAL)&r.maDec, &maDec ); + bool bRet = ( hResult == S_OK ); + return bRet; +} + +bool SbxDecimal::operator += ( const SbxDecimal &r ) +{ + HRESULT hResult = VarDecAdd( &maDec, (LPDECIMAL)&r.maDec, &maDec ); + bool bRet = ( hResult == S_OK ); + return bRet; +} + +bool SbxDecimal::operator /= ( const SbxDecimal &r ) +{ + HRESULT hResult = VarDecDiv( &maDec, (LPDECIMAL)&r.maDec, &maDec ); + bool bRet = ( hResult == S_OK ); + return bRet; +} + +bool SbxDecimal::operator *= ( const SbxDecimal &r ) +{ + HRESULT hResult = VarDecMul( &maDec, (LPDECIMAL)&r.maDec, &maDec ); + bool bRet = ( hResult == S_OK ); + return bRet; +} + +bool SbxDecimal::neg( void ) +{ + HRESULT hResult = VarDecNeg( &maDec, &maDec ); + bool bRet = ( hResult == S_OK ); + return bRet; +} + +bool SbxDecimal::isZero( void ) +{ + SbxDecimal aZeroDec; + aZeroDec.setLong( 0 ); + bool bZero = ( EQ == compare( *this, aZeroDec ) ); + return bZero; +} + +SbxDecimal::CmpResult compare( const SbxDecimal &rLeft, const SbxDecimal &rRight ) +{ + HRESULT hResult = VarDecCmp( (LPDECIMAL)&rLeft.maDec, (LPDECIMAL)&rRight.maDec ); + SbxDecimal::CmpResult eRes = (SbxDecimal::CmpResult)hResult; + return eRes; +} + +void SbxDecimal::setChar( sal_Unicode val ) +{ + VarDecFromUI2( (USHORT)val, &maDec ); +} + +void SbxDecimal::setByte( BYTE val ) +{ + VarDecFromUI1( (BYTE)val, &maDec ); +} + +void SbxDecimal::setShort( INT16 val ) +{ + VarDecFromI2( (short)val, &maDec ); +} + +void SbxDecimal::setLong( INT32 val ) +{ + VarDecFromI4( (long)val, &maDec ); +} + +void SbxDecimal::setUShort( UINT16 val ) +{ + VarDecFromUI2( (USHORT)val, &maDec ); +} + +void SbxDecimal::setULong( UINT32 val ) +{ + VarDecFromUI4( (ULONG)val, &maDec ); +} + +bool SbxDecimal::setSingle( float val ) +{ + bool bRet = ( VarDecFromR4( val, &maDec ) == S_OK ); + return bRet; +} + +bool SbxDecimal::setDouble( double val ) +{ + bool bRet = ( VarDecFromR8( val, &maDec ) == S_OK ); + return bRet; +} + +void SbxDecimal::setInt( int val ) +{ + setLong( (INT32)val ); +} + +void SbxDecimal::setUInt( unsigned int val ) +{ + setULong( (UINT32)val ); +} + +// sbxscan.cxx +void ImpGetIntntlSep( sal_Unicode& rcDecimalSep, sal_Unicode& rcThousandSep ); + +bool SbxDecimal::setString( String* pString ) +{ + static LCID nLANGID = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ); + + // Convert delimiter + sal_Unicode cDecimalSep; + sal_Unicode cThousandSep; + ImpGetIntntlSep( cDecimalSep, cThousandSep ); + + bool bRet = false; + HRESULT hResult; + if( cDecimalSep != '.' || cThousandSep != ',' ) + { + int nLen = pString->Len(); + sal_Unicode* pBuffer = new sal_Unicode[nLen + 1]; + pBuffer[nLen] = 0; + + const sal_Unicode* pSrc = pString->GetBuffer(); + int i; + for( i = 0 ; i < nLen ; ++i ) + pBuffer[i] = pSrc[i]; + + sal_Unicode c; + i = 0; + while( (c = pBuffer[i]) != 0 ) + { + if( c == cDecimalSep ) + pBuffer[i] = '.'; + else if( c == cThousandSep ) + pBuffer[i] = ','; + i++; + } + hResult = VarDecFromStr( (OLECHAR*)pBuffer, nLANGID, 0, &maDec ); + delete pBuffer; + } + else + { + hResult = VarDecFromStr( (OLECHAR*)pString->GetBuffer(), nLANGID, 0, &maDec ); + } + bRet = ( hResult == S_OK ); + return bRet; +} + + +bool SbxDecimal::getChar( sal_Unicode& rVal ) +{ + bool bRet = ( VarUI2FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getByte( BYTE& rVal ) +{ + bool bRet = ( VarUI1FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getShort( INT16& rVal ) +{ + bool bRet = ( VarI2FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getLong( INT32& rVal ) +{ + bool bRet = ( VarI4FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getUShort( UINT16& rVal ) +{ + bool bRet = ( VarUI2FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getULong( UINT32& rVal ) +{ + bool bRet = ( VarUI4FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getSingle( float& rVal ) +{ + bool bRet = ( VarR4FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getDouble( double& rVal ) +{ + bool bRet = ( VarR8FromDec( &maDec, &rVal ) == S_OK ); + return bRet; +} + +bool SbxDecimal::getInt( int& rVal ) +{ + INT32 TmpVal; + bool bRet = getLong( TmpVal ); + rVal = TmpVal; + return bRet; +} + +bool SbxDecimal::getUInt( unsigned int& rVal ) +{ + UINT32 TmpVal; + bool bRet = getULong( TmpVal ); + rVal = TmpVal; + return bRet; +} + +#else +// !WIN32 + +bool SbxDecimal::operator -= ( const SbxDecimal &r ) +{ + (void)r; + return false; +} + +bool SbxDecimal::operator += ( const SbxDecimal &r ) +{ + (void)r; + return false; +} + +bool SbxDecimal::operator /= ( const SbxDecimal &r ) +{ + (void)r; + return false; +} + +bool SbxDecimal::operator *= ( const SbxDecimal &r ) +{ + (void)r; + return false; +} + +bool SbxDecimal::neg( void ) +{ + return false; +} + +bool SbxDecimal::isZero( void ) +{ + return false; +} + +SbxDecimal::CmpResult compare( const SbxDecimal &rLeft, const SbxDecimal &rRight ) +{ + (void)rLeft; + (void)rRight; + return (SbxDecimal::CmpResult)0; +} + +void SbxDecimal::setChar( sal_Unicode val ) { (void)val; } +void SbxDecimal::setByte( BYTE val ) { (void)val; } +void SbxDecimal::setShort( INT16 val ) { (void)val; } +void SbxDecimal::setLong( INT32 val ) { (void)val; } +void SbxDecimal::setUShort( UINT16 val ) { (void)val; } +void SbxDecimal::setULong( UINT32 val ) { (void)val; } +bool SbxDecimal::setSingle( float val ) { (void)val; return false; } +bool SbxDecimal::setDouble( double val ) { (void)val; return false; } +void SbxDecimal::setInt( int val ) { (void)val; } +void SbxDecimal::setUInt( unsigned int val ) { (void)val; } +bool SbxDecimal::setString( String* pString ) { (void)pString; return false; } + +bool SbxDecimal::getChar( sal_Unicode& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getByte( BYTE& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getShort( INT16& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getLong( INT32& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getUShort( UINT16& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getULong( UINT32& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getSingle( float& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getDouble( double& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getInt( int& rVal ) { (void)rVal; return false; } +bool SbxDecimal::getUInt( unsigned int& rVal ) { (void)rVal; return false; } + +#endif + +bool SbxDecimal::getString( String& rString ) +{ +#ifdef WIN32 + static LCID nLANGID = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ); + + bool bRet = false; + + OLECHAR sz[100]; + BSTR aBStr = SysAllocString( sz ); + if( aBStr != NULL ) + { + HRESULT hResult = VarBstrFromDec( &maDec, nLANGID, 0, &aBStr ); + bRet = ( hResult == S_OK ); + if( bRet ) + { + // Convert delimiter + sal_Unicode cDecimalSep; + sal_Unicode cThousandSep; + ImpGetIntntlSep( cDecimalSep, cThousandSep ); + + if( cDecimalSep != '.' || cThousandSep != ',' ) + { + sal_Unicode c; + int i = 0; + while( (c = aBStr[i]) != 0 ) + { + if( c == '.' ) + aBStr[i] = cDecimalSep; + else if( c == ',' ) + aBStr[i] = cThousandSep; + i++; + } + } + rString = reinterpret_cast<const sal_Unicode*>(aBStr); + } + + SysFreeString( aBStr ); + } + return bRet; +#else + (void)rString; + return false; +#endif +} + +SbxDecimal* ImpCreateDecimal( SbxValues* p ) +{ +#ifdef WIN32 + if( !p ) + return NULL; + + SbxDecimal*& rpDecimal = p->pDecimal; + if( rpDecimal == NULL ) + { + rpDecimal = new SbxDecimal(); + rpDecimal->addRef(); + } + return rpDecimal; +#else + (void)p; + return NULL; +#endif +} + +SbxDecimal* ImpGetDecimal( const SbxValues* p ) +{ +#ifdef WIN32 + SbxValues aTmp; + SbxDecimal* pnDecRes; + + SbxDataType eType = p->eType; + if( eType == SbxDECIMAL && p->pDecimal ) + { + pnDecRes = new SbxDecimal( *p->pDecimal ); + pnDecRes->addRef(); + return pnDecRes; + } + pnDecRes = new SbxDecimal(); + pnDecRes->addRef(); + +start: + switch( +eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + pnDecRes->setShort( 0 ); break; + case SbxCHAR: + pnDecRes->setChar( p->nChar ); break; + case SbxBYTE: + pnDecRes->setByte( p->nByte ); break; + case SbxINTEGER: + case SbxBOOL: + pnDecRes->setInt( p->nInteger ); break; + case SbxERROR: + case SbxUSHORT: + pnDecRes->setUShort( p->nUShort ); break; + case SbxLONG: + pnDecRes->setLong( p->nLong ); break; + case SbxULONG: + pnDecRes->setULong( p->nULong ); break; + case SbxSINGLE: + if( !pnDecRes->setSingle( p->nSingle ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + break; + case SbxSALINT64: + { + double d = (double)p->nInt64; + pnDecRes->setDouble( d ); + break; + } + case SbxSALUINT64: + { + double d = ImpSalUInt64ToDouble( p->uInt64 ); + pnDecRes->setDouble( d ); + break; + } + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else + dVal = p->nDouble; + + if( !pnDecRes->setDouble( dVal ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + break; + } + case SbxLPSTR: + case SbxSTRING: + case SbxBYREF | SbxSTRING: + pnDecRes->setString( p->pString ); break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pnDecRes->setDecimal( pVal->GetDecimal() ); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); + pnDecRes->setShort( 0 ); + } + break; + } + + case SbxBYREF | SbxCHAR: + pnDecRes->setChar( *p->pChar ); break; + case SbxBYREF | SbxBYTE: + pnDecRes->setByte( *p->pByte ); break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + pnDecRes->setInt( *p->pInteger ); break; + case SbxBYREF | SbxLONG: + pnDecRes->setLong( *p->pLong ); break; + case SbxBYREF | SbxULONG: + pnDecRes->setULong( *p->pULong ); break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + pnDecRes->setUShort( *p->pUShort ); break; + + // ab hier muss getestet werden + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); pnDecRes->setShort( 0 ); + } + return pnDecRes; +#else + (void)p; + return NULL; +#endif +} + + +void ImpPutDecimal( SbxValues* p, SbxDecimal* pDec ) +{ +#ifdef WIN32 + if( !pDec ) + return; + + SbxValues aTmp; +start: + switch( +p->eType ) + { + // hier muss getestet werden + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxLONG: + aTmp.pLong = &p->nLong; goto direct; + case SbxSALINT64: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // ab hier nicht mehr + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + if( pDec != p->pDecimal ) + { + releaseDecimalPtr( p->pDecimal ); + // if( p->pDecimal ) + // p->pDecimal->ReleaseRef(); + p->pDecimal = pDec; + if( pDec ) + pDec->addRef(); + } + break; + } + case SbxSINGLE: + { + float f; + pDec->getSingle( f ); + p->nSingle = f; + break; + } + case SbxDATE: + case SbxDOUBLE: + { + double d; + pDec->getDouble( d ); + p->nDouble = d; + break; + } + case SbxULONG64: + { + double d; + pDec->getDouble( d ); + p->nULong64 = ImpDoubleToUINT64( d ); + break; + } + case SbxLONG64: + { + double d; + pDec->getDouble( d ); + p->nLong64 = ImpDoubleToINT64( d ); + break; + } + + case SbxLPSTR: + case SbxSTRING: + case SbxBYREF | SbxSTRING: + if( !p->pString ) + p->pString = new XubString; + // ImpCvtNum( (double) n, 0, *p->pString ); + pDec->getString( *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutDecimal( pDec ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + + case SbxBYREF | SbxCHAR: + if( !pDec->getChar( *p->pChar ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pChar = 0; + } + break; + case SbxBYREF | SbxBYTE: + if( !pDec->getChar( *p->pChar ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pByte = 0; + } + break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( !pDec->getShort( *p->pInteger ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pInteger = 0; + } + break; + // *p->pInteger = n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( !pDec->getUShort( *p->pUShort ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pUShort = 0; + } + break; + case SbxBYREF | SbxLONG: + if( !pDec->getLong( *p->pLong ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pLong = 0; + } + break; + case SbxBYREF | SbxULONG: + if( !pDec->getULong( *p->pULong ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pULong = 0; + } + break; + case SbxBYREF | SbxSALINT64: + { + double d; + if( !pDec->getDouble( d ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + else + *p->pnInt64 = ImpDoubleToSalInt64( d ); + break; + } + case SbxBYREF | SbxSALUINT64: + { + double d; + if( !pDec->getDouble( d ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + else + *p->puInt64 = ImpDoubleToSalUInt64( d ); + break; + } + case SbxBYREF | SbxSINGLE: + if( !pDec->getSingle( *p->pSingle ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pSingle = 0; + } + break; + // *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + if( !pDec->getDouble( *p->pDouble ) ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + *p->pDouble = 0; + } + break; + case SbxBYREF | SbxULONG64: + { + double d; + pDec->getDouble( d ); + *p->pULong64 = ImpDoubleToUINT64( d ); + break; + } + case SbxBYREF | SbxLONG64: + { + double d; + pDec->getDouble( d ); + *p->pLong64 = ImpDoubleToINT64( d ); + break; + } + case SbxBYREF | SbxCURRENCY: + { + double d; + pDec->getDouble( d ); + *p->pLong64 = ImpDoubleToCurrency( d ); + break; + } + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +#else + (void)p; + (void)pDec; +#endif +} + diff --git a/basic/source/sbx/sbxdec.hxx b/basic/source/sbx/sbxdec.hxx new file mode 100644 index 000000000000..03f97bec5992 --- /dev/null +++ b/basic/source/sbx/sbxdec.hxx @@ -0,0 +1,122 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +#ifndef __SBX_SBX_DEC_HXX +#define __SBX_SBX_DEC_HXX + +#ifdef WIN32 + +#undef WB_LEFT +#undef WB_RIGHT +#include <tools/prewin.h> +} // close extern "C" { + +#ifndef __MINGW32__ +#include <comutil.h> +#endif +#include <oleauto.h> + +extern "C" { // reopen extern "C" { +#include <tools/postwin.h> + +#endif +#endif +#include <basic/sbx.hxx> + +#include <com/sun/star/bridge/oleautomation/Decimal.hpp> + + +// Decimal support +// Implementation only for windows + +class SbxDecimal +{ + friend void releaseDecimalPtr( SbxDecimal*& rpDecimal ); + +#ifdef WIN32 + DECIMAL maDec; +#endif + INT32 mnRefCount; + +public: + SbxDecimal( void ); + SbxDecimal( const SbxDecimal& rDec ); + SbxDecimal( const com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ); + + ~SbxDecimal(); + + void addRef( void ) + { mnRefCount++; } + + void fillAutomationDecimal( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ); + + void setChar( sal_Unicode val ); + void setByte( BYTE val ); + void setShort( INT16 val ); + void setLong( INT32 val ); + void setUShort( UINT16 val ); + void setULong( UINT32 val ); + bool setSingle( float val ); + bool setDouble( double val ); + void setInt( int val ); + void setUInt( unsigned int val ); + bool setString( String* pString ); + void setDecimal( SbxDecimal* pDecimal ) + { +#ifdef WIN32 + if( pDecimal ) + maDec = pDecimal->maDec; +#else + (void)pDecimal; +#endif + } + + bool getChar( sal_Unicode& rVal ); + bool getByte( BYTE& rVal ); + bool getShort( INT16& rVal ); + bool getLong( INT32& rVal ); + bool getUShort( UINT16& rVal ); + bool getULong( UINT32& rVal ); + bool getSingle( float& rVal ); + bool getDouble( double& rVal ); + bool getInt( int& rVal ); + bool getUInt( unsigned int& rVal ); + bool getString( String& rString ); + + bool operator -= ( const SbxDecimal &r ); + bool operator += ( const SbxDecimal &r ); + bool operator /= ( const SbxDecimal &r ); + bool operator *= ( const SbxDecimal &r ); + bool neg( void ); + + bool isZero( void ); + + enum CmpResult { LT, EQ, GT }; + friend CmpResult compare( const SbxDecimal &rLeft, const SbxDecimal &rRight ); +}; + diff --git a/basic/source/sbx/sbxexec.cxx b/basic/source/sbx/sbxexec.cxx new file mode 100644 index 000000000000..c602b130fc5e --- /dev/null +++ b/basic/source/sbx/sbxexec.cxx @@ -0,0 +1,401 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif +#include <basic/sbx.hxx> + + +class SbxSimpleCharClass +{ +public: + BOOL isAlpha( sal_Unicode c ) const + { + BOOL bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + return bRet; + } + + BOOL isDigit( sal_Unicode c ) const + { + BOOL bRet = (c >= '0' && c <= '9'); + return bRet; + } + + BOOL isAlphaNumeric( sal_Unicode c ) const + { + BOOL bRet = isDigit( c ) || isAlpha( c ); + return bRet; + } +}; + + +static SbxVariable* Element + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, + SbxClassType, const SbxSimpleCharClass& rCharClass ); + +static const xub_Unicode* SkipWhitespace( const xub_Unicode* p ) +{ + while( *p && ( *p == ' ' || *p == '\t' ) ) + p++; + return p; +} + +// Scannen eines Symbol. Das Symbol wird in rSym eingetragen, der Returnwert +// ist die neue Scanposition. Bei Fehlern ist das Symbol leer. + +static const xub_Unicode* Symbol( const xub_Unicode* p, XubString& rSym, const SbxSimpleCharClass& rCharClass ) +{ + USHORT nLen = 0; + // Haben wir ein Sondersymbol? + if( *p == '[' ) + { + rSym = ++p; + while( *p && *p != ']' ) + p++, nLen++; + p++; + } + else + { + // Ein Symbol muss mit einem Buchstaben oder einem Underline beginnen + if( !rCharClass.isAlpha( *p ) && *p != '_' ) + SbxBase::SetError( SbxERR_SYNTAX ); + else + { + rSym = p; + // Dann darf es Buchstaben, Zahlen oder Underlines enthalten + while( *p && (rCharClass.isAlphaNumeric( *p ) || *p == '_') ) + p++, nLen++; + // BASIC-Standard-Suffixe werden ignoriert + if( *p && (*p == '%' || *p == '&' || *p == '!' || *p == '#' || *p == '$' ) ) + p++; + } + } + rSym.Erase( nLen ); + return p; +} + +// Qualifizierter Name. Element.Element.... + +static SbxVariable* QualifiedName + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, SbxClassType t ) +{ + static SbxSimpleCharClass aCharClass; + + SbxVariableRef refVar; + const xub_Unicode* p = SkipWhitespace( *ppBuf ); + if( aCharClass.isAlpha( *p ) || *p == '_' || *p == '[' ) + { + // Element einlesen + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + while( refVar.Is() && (*p == '.' || *p == '!') ) + { + // Es folgt noch ein Objektelement. Das aktuelle Element + // muss also ein SBX-Objekt sein oder liefern! + pObj = PTR_CAST(SbxObject,(SbxVariable*) refVar); + if( !pObj ) + // Dann muss es ein Objekt liefern + pObj = PTR_CAST(SbxObject,refVar->GetObject()); + refVar.Clear(); + if( !pObj ) + break; + p++; + // Und das naechste Element bitte + refVar = Element( pObj, pGbl, &p, t, aCharClass ); + } + } + else + SbxBase::SetError( SbxERR_SYNTAX ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen eines Operanden. Dies kann eine Zahl, ein String oder +// eine Funktion (mit optionalen Parametern) sein. + +static SbxVariable* Operand + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, BOOL bVar ) +{ + static SbxSimpleCharClass aCharClass; + + SbxVariableRef refVar( new SbxVariable ); + const xub_Unicode* p = SkipWhitespace( *ppBuf ); + if( !bVar && ( aCharClass.isDigit( *p ) + || ( *p == '.' && aCharClass.isDigit( *( p+1 ) ) ) + || *p == '-' + || *p == '&' ) ) + { + // Eine Zahl kann direkt eingescant werden! + USHORT nLen; + if( !refVar->Scan( XubString( p ), &nLen ) ) + refVar.Clear(); + else + p += nLen; + } + else if( !bVar && *p == '"' ) + { + // Ein String + XubString aString; + p++; + for( ;; ) + { + // Das ist wohl ein Fehler + if( !*p ) + return NULL; + // Doppelte Quotes sind OK + if( *p == '"' ) + if( *++p != '"' ) + break; + aString += *p++; + } + refVar->PutString( aString ); + } + else + refVar = QualifiedName( pObj, pGbl, &p, SbxCLASS_DONTCARE ); + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen einer einfachen Term. Die Operatoren +, -, * und / +// werden unterstuetzt. + +static SbxVariable* MulDiv( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( Operand( pObj, pGbl, &p, FALSE ) ); + p = SkipWhitespace( p ); + while( refVar.Is() && ( *p == '*' || *p == '/' ) ) + { + xub_Unicode cOp = *p++; + SbxVariableRef refVar2( Operand( pObj, pGbl, &p, FALSE ) ); + if( refVar2.Is() ) + { + // temporaere Variable! + SbxVariable* pVar = refVar; + pVar = new SbxVariable( *pVar ); + refVar = pVar; + if( cOp == '*' ) + *refVar *= *refVar2; + else + *refVar /= *refVar2; + } + else + { + refVar.Clear(); + break; + } + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +static SbxVariable* PlusMinus( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( MulDiv( pObj, pGbl, &p ) ); + p = SkipWhitespace( p ); + while( refVar.Is() && ( *p == '+' || *p == '-' ) ) + { + xub_Unicode cOp = *p++; + SbxVariableRef refVar2( MulDiv( pObj, pGbl, &p ) ); + if( refVar2.Is() ) + { + // temporaere Variable! + SbxVariable* pVar = refVar; + pVar = new SbxVariable( *pVar ); + refVar = pVar; + if( cOp == '+' ) + *refVar += *refVar2; + else + *refVar -= *refVar2; + } + else + { + refVar.Clear(); + break; + } + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +static SbxVariable* Assign( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf ) +{ + const xub_Unicode* p = *ppBuf; + SbxVariableRef refVar( Operand( pObj, pGbl, &p, TRUE ) ); + p = SkipWhitespace( p ); + if( refVar.Is() ) + { + if( *p == '=' ) + { + // Nur auf Props zuweisen! + if( refVar->GetClass() != SbxCLASS_PROPERTY ) + { + SbxBase::SetError( SbxERR_BAD_ACTION ); + refVar.Clear(); + } + else + { + p++; + SbxVariableRef refVar2( PlusMinus( pObj, pGbl, &p ) ); + if( refVar2.Is() ) + { + SbxVariable* pVar = refVar; + SbxVariable* pVar2 = refVar2; + *pVar = *pVar2; + pVar->SetParameters( NULL ); + } + } + } + else + // Einfacher Aufruf: einmal aktivieren + refVar->Broadcast( SBX_HINT_DATAWANTED ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Einlesen eines Elements. Dies ist ein Symbol, optional gefolgt +// von einer Parameterliste. Das Symbol wird im angegebenen Objekt +// gesucht und die Parameterliste wird ggf. angefuegt. + +static SbxVariable* Element + ( SbxObject* pObj, SbxObject* pGbl, const xub_Unicode** ppBuf, + SbxClassType t, const SbxSimpleCharClass& rCharClass ) +{ + XubString aSym; + const xub_Unicode* p = Symbol( *ppBuf, aSym, rCharClass ); + SbxVariableRef refVar; + if( aSym.Len() ) + { + USHORT nOld = pObj->GetFlags(); + if( pObj == pGbl ) + pObj->SetFlag( SBX_GBLSEARCH ); + refVar = pObj->Find( aSym, t ); + pObj->SetFlags( nOld ); + if( refVar.Is() ) + { + refVar->SetParameters( NULL ); + // folgen noch Parameter? + p = SkipWhitespace( p ); + if( *p == '(' ) + { + p++; + SbxArrayRef refPar = new SbxArray; + USHORT nArg = 0; + // Wird sind mal relaxed und akzeptieren auch + // das Zeilen- oder Komandoende als Begrenzer + // Parameter immer global suchen! + while( *p && *p != ')' && *p != ']' ) + { + SbxVariableRef refArg = PlusMinus( pGbl, pGbl, &p ); + if( !refArg ) + { + // Fehler beim Parsing + refVar.Clear(); break; + } + else + { + // Man kopiere den Parameter, damit + // man den aktuellen Zustand hat (loest auch + // den Aufruf per Zugriff aus) + SbxVariable* pArg = refArg; + refPar->Put( new SbxVariable( *pArg ), ++nArg ); + } + p = SkipWhitespace( p ); + if( *p == ',' ) + p++; + } + if( *p == ')' ) + p++; + if( refVar.Is() ) + refVar->SetParameters( refPar ); + } + } + else + SbxBase::SetError( SbxERR_NO_METHOD ); + } + *ppBuf = p; + if( refVar.Is() ) + refVar->AddRef(); + return refVar; +} + +// Hauptroutine + +SbxVariable* SbxObject::Execute( const XubString& rTxt ) +{ + SbxVariable* pVar = NULL; + const xub_Unicode* p = rTxt.GetBuffer(); + for( ;; ) + { + p = SkipWhitespace( p ); + if( !*p ) + break; + if( *p++ != '[' ) + { + SetError( SbxERR_SYNTAX ); break; + } + pVar = Assign( this, this, &p ); + if( !pVar ) + break; + p = SkipWhitespace( p ); + if( *p++ != ']' ) + { + SetError( SbxERR_SYNTAX ); break; + } + } + return pVar; +} + +SbxVariable* SbxObject::FindQualified( const XubString& rName, SbxClassType t ) +{ + SbxVariable* pVar = NULL; + const xub_Unicode* p = rName.GetBuffer(); + p = SkipWhitespace( p ); + if( !*p ) + return NULL;; + pVar = QualifiedName( this, this, &p, t ); + p = SkipWhitespace( p ); + if( *p ) + SetError( SbxERR_SYNTAX ); + return pVar; +} + diff --git a/basic/source/sbx/sbxform.cxx b/basic/source/sbx/sbxform.cxx new file mode 100644 index 000000000000..b53612f1e642 --- /dev/null +++ b/basic/source/sbx/sbxform.cxx @@ -0,0 +1,1168 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include <stdlib.h> + +#include <basic/sbxform.hxx> + +/* +TODO: gibt es noch irgend welche Star-Basic Besonderheiten ? + + was bedeutet: * als Platzhalter + +BEMERKUNG: Visual-Basic behandelt folgende (ung"ultige) Format-Strings + wie angezeigt: + + ##0##.##0## --> ##000.000## + + (diese Klasse verh"alt sich genau so). +*/ + +#include <stdio.h> // f"ur: sprintf() +#include <float.h> // f"ur: DBL_DIG, DBL_EPSILON +#include <math.h> // f"ur: floor(), fabs(), log10(), pow() + +//================================================================= +//=========================== DEFINES ============================= +//================================================================= + +#define _NO_DIGIT -1 + +#define MAX_NO_OF_EXP_DIGITS 5 + // +4 wegen dem Wertebereich: zwischen -308 und +308 + // +1 f"ur abschliessende 0 +#define MAX_NO_OF_DIGITS DBL_DIG +#define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9 + // +1 f"ur Vorzeichen + // +1 f"ur Ziffer vor dem Dezimal-Punkt + // +1 f"ur Dezimal-Punkt + // +2 f"ur Exponent E und Exp. Vorzeichen + // +3 f"ur den Wert des Exponenten + // +1 f"ur abschliessende 0 + +// Defines f"ur die Ziffern: +#define ASCII_0 '0' // 48 +#define ASCII_9 '9' // 57 + +#define CREATE_1000SEP_CHAR '@' + +#define FORMAT_SEPARATOR ';' + +// vordefinierte Formate f"ur den Format$()-Befehl: +#define BASICFORMAT_GENERALNUMBER "General Number" +#define BASICFORMAT_CURRENCY "Currency" +#define BASICFORMAT_FIXED "Fixed" +#define BASICFORMAT_STANDARD "Standard" +#define BASICFORMAT_PERCENT "Percent" +#define BASICFORMAT_SCIENTIFIC "Scientific" +#define BASICFORMAT_YESNO "Yes/No" +#define BASICFORMAT_TRUEFALSE "True/False" +#define BASICFORMAT_ONOFF "On/Off" + +#define EMPTYFORMATSTRING "" + +// Bem.: Visual-Basic hat bei Floating-Point-Zahlen maximal 12 Stellen +// nach dem Dezimal-Punkt. +// Alle Format-Strings sind kompatibel zu Visual-Basic: +#define GENERALNUMBER_FORMAT "0.############" + // max. 12 Stellen in Visual-Basic ! +#define CURRENCY_FORMAT "@$0.00;@($0.00)" +#define FIXED_FORMAT "0.00" +#define STANDARD_FORMAT "@0.00" +#define PERCENT_FORMAT "0.00%" +#define SCIENTIFIC_FORMAT "#.00E+00" +// BEMERKUNG: das Zeichen @ bedeutet, das Tausender-Separatoren erzeugt +// weden sollen. Dies ist eine StarBasic 'Erweiterung'. + +//================================================================= + +// zur Bestimmung der Anzahl Stellen in dNumber +double get_number_of_digits( double dNumber ) +//double floor_log10_fabs( double dNumber ) +{ + if( dNumber==0.0 ) + // 0 hat zumindest auch eine Stelle ! + return 0.0; //ehemals 1.0, jetzt 0.0 wegen #40025; + else + return floor( log10( fabs( dNumber ) ) ); +} + +//================================================================= +//======================= IMPLEMENTATION ========================== +//================================================================= + +SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep, + String _sOnStrg, + String _sOffStrg, + String _sYesStrg, + String _sNoStrg, + String _sTrueStrg, + String _sFalseStrg, + String _sCurrencyStrg, + String _sCurrencyFormatStrg ) +{ + cDecPoint = _cDecPoint; + cThousandSep = _cThousandSep; + sOnStrg = _sOnStrg; + sOffStrg = _sOffStrg; + sYesStrg = _sYesStrg; + sNoStrg = _sNoStrg; + sTrueStrg = _sTrueStrg; + sFalseStrg = _sFalseStrg; + sCurrencyStrg = _sCurrencyStrg; + sCurrencyFormatStrg = _sCurrencyFormatStrg; +} + +// Funktion zur Ausgabe eines Fehler-Textes (zum Debuggen) +/* +void SbxBasicFormater::ShowError( char * sErrMsg ) +{ +// cout << "ERROR in Format$(): " << sErrMsg << endl; +} +*/ +// verschiebt alle Zeichen des Strings, angefangen von der nStartPos, +// um eine Position zu gr"osseren Indizes, d.h. es wird Platz f"ur +// ein neues (einzuf"ugendes) Zeichen geschafft. +// ACHTUNG: der String MUSS gross genug sein ! +inline void SbxBasicFormater::ShiftString( String& sStrg, USHORT nStartPos ) +{ + sStrg.Erase( nStartPos,1 ); +} + +// Funktion um ein Zeichen an einen String anzuh"angen +inline void SbxBasicFormater::StrAppendChar( String& sStrg, sal_Unicode ch ) +{ + sStrg.Insert( ch ); +} + +// h"angt die "ubergebene Ziffer nDigit an den "ubergebenen String sStrg +// an, dabei wird "uberpr"uft ob nDigit eine g"ultige Ziffer ist, +// falls dies nicht der Fall ist, wird nichts gemacht. +void SbxBasicFormater::AppendDigit( String& sStrg, short nDigit ) +{ + if( nDigit>=0 && nDigit<=9 ) + StrAppendChar( sStrg, (sal_Unicode)(nDigit+ASCII_0) ); +} + +// verschiebt den Dezimal-Punkt um eine Stelle nach links +void SbxBasicFormater::LeftShiftDecimalPoint( String& sStrg ) +{ + USHORT nPos = sStrg.Search( cDecPoint ); + + if( nPos!=STRING_NOTFOUND ) + { + // vertausche Dezimal-Punkt + sStrg.SetChar( nPos, sStrg.GetChar( nPos - 1 ) ); + sStrg.SetChar( nPos-1, cDecPoint ); + } +} + +// rundet in einem String die Ziffer an der angegebenen Stelle, +// es wird ein Flag zur"uckgeliefert, falls ein Overflow auftrat, +// d.h. 99.99 --> 100.00, d.h. ein Gr"ossenordung ge"andert wurde +// (geschieht beim Runden einer 9). +void SbxBasicFormater::StrRoundDigit( String& sStrg, short nPos, BOOL& bOverflow ) +{ + // wurde ggf ein falscher Index uebergeben --> Aufruf ignorieren + if( nPos<0 ) + return; + + bOverflow = FALSE; + // "uberspringe den Dezimalpunkt und Tausender-Trennzeichen + sal_Unicode c = sStrg.GetChar( nPos ); + if( nPos>0 && (c == cDecPoint || c == cThousandSep) ) + { + StrRoundDigit( sStrg,nPos-1,bOverflow ); + // AENDERUNG ab 9.3.1997: nach rekursivem Call die Methode SOFORT beenden ! + return; + } + // "uberspringe alle nicht-Ziffern: + // BEMERKUNG: + // in einem g"ultigen Format-String sollte die Ausgabe + // der Zahl an einem St"uck geschen, d.h. Sonderzeichen sollten + // NUR vor ODER nach der Zahl stehen und nicht mitten in der + // Format-Angabe f"ur die Zahl + while( nPos>=0 && (sStrg.GetChar( nPos )<ASCII_0 || sStrg.GetChar( nPos )>ASCII_9) ) + nPos--; + // muss ggf. noch Platz f"ur eine weitere (f"uhrende) Ziffer + // geschaffen werden ? + if( nPos==-1 ) + { + ShiftString( sStrg,0 ); + // f"uhrende 1 einf"ugen: z.B. 99.99 f"ur 0.0 + sStrg.SetChar( 0, '1' ); + bOverflow = TRUE; + } + else + { + // ist die zu rundende Position eine Ziffer ? + sal_Unicode c2 = sStrg.GetChar( nPos ); + if( c2 >= ASCII_0 && c2 <= ASCII_9 ) + { + // muss eine 9 gerundet werden? Falls: Ja --> rekursiver Aufruf + if( c2 == ASCII_9 ) + { + sStrg.SetChar( nPos, '0' ); + StrRoundDigit( sStrg,nPos-1,bOverflow ); + } + else + sStrg.SetChar( nPos, c2+1 ); + } + else + { + // --> Nein, d.h. Platz f"ur Ziffer schaffen: z.B. -99.99 f"ur #0.0 + // da gerundet wird MUSS es immer eine g"ultige Position + // nPos+1 geben ! + ShiftString( sStrg,nPos+1 ); + // f"uhrende 1 einf"ugen + sStrg.SetChar( nPos+1, '1' ); + bOverflow = TRUE; + } + } +} + +// rundet in einem String die Ziffer an der angegebenen Stelle +void SbxBasicFormater::StrRoundDigit( String& sStrg, short nPos ) +{ + BOOL bOverflow; + + StrRoundDigit( sStrg,nPos,bOverflow ); +} + +// parse den Formatstring von der "ubergebenen Position zur"uck +// und l"osche ggf. "uberf"ussige 0en, z.B. 4.50 in 0.0# +void SbxBasicFormater::ParseBack( String& sStrg, const String& sFormatStrg, + short nFormatPos ) +{ + // WICHTIG: nFormatPos kann auch negativ sein, in diesem Fall Aufruf ignorieren + for( short i=nFormatPos; + i>0 && sFormatStrg.GetChar( i ) == '#' && sStrg.GetChar( (sStrg.Len()-1) ) == '0'; + i-- ) + { sStrg.Erase( sStrg.Len()-1 ); } +} + +#ifdef _with_sprintf + +/* + Bemerkung: + Zahl wird mit maximaler (sinnvollen) Genauigkeit in einen String + umgewandelt (mit sprintf()), dieser String wird dann im Schleifen- + Durchlauf nach der entsprechenden Ziffer durchsucht. +*/ +// initialisiert die Daten der Klasse um einen Scan-Durchlauf durchzuf"uhren +void SbxBasicFormater::InitScan( double _dNum ) +{ + char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ]; + + dNum = _dNum; + InitExp( get_number_of_digits( dNum ) ); + // maximal 15 Nachkomma-Stellen, Format-Beispiel: -1.234000000000000E-001 + /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum ); + sSciNumStrg.AssignAscii( sBuffer ); +} + +void SbxBasicFormater::InitExp( double _dNewExp ) +{ + char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ]; + // bestimme den Exponenten (kann immer GENAU durch int dargestellt werden) + nNumExp = (short)_dNewExp; + // und dessen String + /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp ); + sNumExpStrg.AssignAscii( sBuffer ); + // bestimme die Anzahl der Stellen im Exponenten + nExpExp = (short)get_number_of_digits( (double)nNumExp ); +} + +// bestimmt die Ziffer an der angegebenen Stelle (gedacht zur Anwendung im +// Scan-Durchlauf) +short SbxBasicFormater::GetDigitAtPosScan( short nPos, BOOL& bFoundFirstDigit ) +{ + // Versuch eine gr"ossere Ziffer zu lesen, + // z.B. Stelle 4 in 1.234, + // oder eine Ziffer ausserhalb der Aufl"osung der + // Zahl (double) zu lesen (z.B. max. 15 Stellen). + if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS ) + return _NO_DIGIT; + // bestimme den Index der Stelle in dem Number-String: + // "uberlese das Vorzeichen + USHORT no = 1; + // falls notwendig den Dezimal-Punkt "uberlesen: + if( nPos<nNumExp ) + no++; + no += nNumExp-nPos; + // Abfrage der ersten (g"ultigen) Ziffer der Zahl --> Flag setzen + if( nPos==nNumExp ) + bFoundFirstDigit = TRUE; + return (short)(sSciNumStrg.GetChar( no ) - ASCII_0); +} + +short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, BOOL& bFoundFirstDigit ) +{ + // ist die abgefragte Stelle zu gross f"ur den Exponenten ? + if( nPos>nExpExp ) + return -1; + + // bestimme den Index der Stelle in dem Number-String: + // "uberlese das Vorzeichen + USHORT no = 1; + no += nExpExp-nPos; + // Abfrage der ersten (g"ultigen) Ziffer der Zahl --> Flag setzen + if( nPos==nExpExp ) + bFoundFirstDigit = TRUE; + return (short)(sNumExpStrg.GetChar( no ) - ASCII_0); +} + +// es kann ein Wert f"ur den Exponent angegeben werden, da ggf. die +// Zahl ggf. NICHT normiert (z.B. 1.2345e-03) dargestellt werden soll, +// sondern eventuell 123.345e-3 ! +short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos, + BOOL& bFoundFirstDigit ) +{ + // neuer Exponent wurde "ubergeben, aktualisiere + // die tempor"aren Klassen-Variablen + InitExp( dNewExponent ); + // und jetzt die Stelle bestimmen + return GetDigitAtPosExpScan( nPos,bFoundFirstDigit ); +} + +#else + +/* Probleme mit der folgenden Methode: + +TODO: ggf einen 'intelligenten' Peek-Parser um Rundungsfehler bei + double-Zahlen herauszufinden ? z.B. f"ur 0.00115 #.#e-000 + + Problem mit: format( 0.3345 , "0.000" ) + Problem mit: format( 0.00115 , "0.0000" ) + +*/ +// liefert die Ziffer an der angegebenen '10er System'-Position, +// d.h. positive nPos f"ur Stellen vor dem Komma und negative +// f"ur Stellen nach dem Komma. +// nPos==0 bedeutet erste Stelle vor dem Komma, also 10^0. +// liefert 0..9 f"ur g"ultige Ziffern und -1 f"ur nicht vorhanden, +// d.h. falls die "ubergebene Zahl zu klein ist +// (z.B. Stelle 5 bei dNumber=123). +// Weiter wird in dNextNumber die um die f"uhrenden Stellen +// (bis nPos) gek"urzte Zahl zur"uckgeliefert, z.B. +// GetDigitAtPos( 3434.565 , 2 , dNewNumber ) --> dNewNumber = 434.565 +// dies kann f"ur Schleifenabarbeitung g"unstiger sein, d.h. +// die Zahlen immer von der gr"ossten Stelle abarbeiten/scanen. +// In bFoundFirstDigit wird ggf. ein Flag gesetzt wenn eine Ziffer +// gefunden wurde, dies wird dazu verwendet um 'Fehler' beim Parsen 202 +// zu vermeiden, die +// +// ACHTUNG: anscheinend gibt es manchmal noch Probleme mit Rundungs-Fehlern! +short SbxBasicFormater::GetDigitAtPos( double dNumber, short nPos, + double& dNextNumber, BOOL& bFoundFirstDigit ) +// ACHTUNG: nPos kann auch negativ werden, f"ur Stellen nach dem Dezimal-Punkt +{ + double dTemp = dNumber; + double dDigit,dPos; + short nMaxDigit; + + // erst mal aus der Zahl eine positive Zahl machen: + dNumber = fabs( dNumber ); + dPos = (double)nPos; + + // "uberpr"ufe ob Zahl zu klein f"ur angegebene Stelle ist + nMaxDigit = (short)get_number_of_digits( dNumber ); + // f"uhrende Ziffern 'l"oschen' + // Bem.: Fehler nur bei Zahlen gr"osser 0, d.h. bei Ziffern vor dem + // Dezimal-Punkt + if( nMaxDigit<nPos && !bFoundFirstDigit && nPos>=0 ) + return _NO_DIGIT; + // Ziffer gefunden, setze Flag: + bFoundFirstDigit = TRUE; + for( short i=nMaxDigit; i>=nPos; i-- ) + { + double dI = (double)i; + double dTemp1 = pow( 10.0,dI ); + // pr"apariere nun die gesuchte Ziffer: + dDigit = floor( pow( 10.0,log10( fabs( dNumber ) )-dI ) ); + dNumber -= dTemp1 * dDigit; + } + // Zuweisung f"ur optimierte Schleifen-Durchl"aufe + dNextNumber = dNumber; + // und zum Schluss noch die float-Rundungsungenauigkeiten heraus filtern + return RoundDigit( dDigit ); +} + +// rundet eine double-Zahl zwischen 0 und 9 auf die genaue +// Integer-Zahl, z.B. 2.8 -> 3 und 2.2 -> 2 +short SbxBasicFormater::RoundDigit( double dNumber ) +{ + // ist der Wertebereich g"ultig ? + if( dNumber<0.0 || dNumber>10.0 ) + return -1; + short nTempHigh = (short)(dNumber+0.5); // ggf. floor( ) + return nTempHigh; +} + +#endif + +// kopiert den entsprechenden Teil des Format-Strings, falls vorhanden, +// und liefert diesen zur"uck. +// Somit wird ein neuer String erzeugt, der vom Aufrufer wieder freigegeben +// werden muss +String SbxBasicFormater::GetPosFormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + bFound = TRUE; + // der Format-String f"ur die positiven Zahlen ist alles + // vor dem ersten ';' + return sFormatStrg.Copy( 0,nPos ); + } + // kein ; gefunden, liefere Leerstring + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// siehe auch GetPosFormatString() +String SbxBasicFormater::GetNegFormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + // der Format-String f"ur die negative Zahlen ist alles + // zwischen dem ersten und dem zweiten ';'. + // Daher: hole erst mal alles nach dem ersten ';' + String sTempStrg = sFormatStrg.Copy( nPos+1 ); + // und suche darin ggf. ein weiteres ';' + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + bFound = TRUE; + if( nPos==STRING_NOTFOUND ) + // keins gefunden, liefere alles... + return sTempStrg; + else + // ansonsten den String zwischen den beiden ';' liefern + return sTempStrg.Copy( 0,nPos ); + } + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// siehe auch GetPosFormatString() +String SbxBasicFormater::Get0FormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + // der Format-String f"ur die Null ist alles + // was nach dem zweiten ';' kommt. + // Daher: hole erst mal alles nach dem ersten ';' + String sTempStrg = sFormatStrg.Copy( nPos+1 ); + // und suche darin ggf. ein weiteres ';' + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos!=STRING_NOTFOUND ) + { + bFound = TRUE; + sTempStrg = sTempStrg.Copy( nPos+1 ); + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos==STRING_NOTFOUND ) + // keins gefunden, liefere alles... + return sTempStrg; + else + return sTempStrg.Copy( 0,nPos ); + } + } + // kein ; gefunden, liefere Leerstring + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// siehe auch GetPosFormatString() +String SbxBasicFormater::GetNullFormatString( const String& sFormatStrg, BOOL & bFound ) +{ + bFound = FALSE; // default... + USHORT nPos = sFormatStrg.Search( FORMAT_SEPARATOR ); + + if( nPos!=STRING_NOTFOUND ) + { + // der Format-String f"ur die Null ist alles + // was nach dem dritten ';' kommt. + // Daher: hole erst mal alles nach dem ersten ';' + String sTempStrg = sFormatStrg.Copy( nPos+1 ); + // und suche darin ggf. ein weiteres ';' + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos!=STRING_NOTFOUND ) + { + // und suche nun nach dem dritten ';' + sTempStrg = sTempStrg.Copy( nPos+1 ); + nPos = sTempStrg.Search( FORMAT_SEPARATOR ); + if( nPos!=STRING_NOTFOUND ) + { + bFound = TRUE; + return sTempStrg.Copy( nPos+1 ); + } + } + } + // kein ; gefunden, liefere Leerstring + String aRetStr; + aRetStr.AssignAscii( EMPTYFORMATSTRING ); + return aRetStr; +} + +// analysiert den Format-String, liefert Wert <> 0 falls ein Fehler +// aufgetreten ist +short SbxBasicFormater::AnalyseFormatString( const String& sFormatStrg, + short& nNoOfDigitsLeft, short& nNoOfDigitsRight, + short& nNoOfOptionalDigitsLeft, + short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits, + BOOL& bPercent, BOOL& bCurrency, BOOL& bScientific, + BOOL& bGenerateThousandSeparator, + short& nMultipleThousandSeparators ) +{ + USHORT nLen; + short nState = 0; + + nLen = sFormatStrg.Len(); + // initialisiere alle Z"ahler und Flags + nNoOfDigitsLeft = 0; + nNoOfDigitsRight = 0; + nNoOfOptionalDigitsLeft = 0; + nNoOfExponentDigits = 0; + nNoOfOptionalExponentDigits = 0; + bPercent = FALSE; + bCurrency = FALSE; + bScientific = FALSE; + // ab 11.7.97: sobald ein Komma in dem Format String gefunden wird, + // werden alle 3 Zehnerpotenzen markiert (d.h. tausender, milionen, ...) + // bisher wurde nur an den gesetzten Position ein Tausender-Separator + // ausgegeben oder wenn ein @ im Format-String stand. + // Dies war ein Missverstaendnis der VB Kompatiblitaet. + bGenerateThousandSeparator = sFormatStrg.Search( ',' ) != STRING_NOTFOUND; + nMultipleThousandSeparators = 0; + // und untersuche den Format-String nach den gew"unschten Informationen + for( USHORT i=0; i<nLen; i++ ) + { + sal_Unicode c = sFormatStrg.GetChar( i ); + switch( c ) { + case '#': + case '0': + if( nState==0 ) + { + nNoOfDigitsLeft++; +// TODO hier ggf. bessere Fehler-"Uberpr"ufung der Mantisse auf g"ultige Syntax (siehe Grammatik) + // ACHTUNG: 'undefiniertes' Verhalten falls # und 0 + // gemischt werden !!! + // BEMERKUNG: eigentlich sind #-Platzhalter bei Scientific + // Darstellung vor dem Dezimal-Punkt sinnlos ! + if( c=='#' ) + nNoOfOptionalDigitsLeft++; + } + else if( nState==1 ) + nNoOfDigitsRight++; + else if( nState==-1 ) // suche 0 im Exponent + { + if( c=='#' ) // # schaltet den Zustand weiter + { + nNoOfOptionalExponentDigits++; + nState = -2; + } + nNoOfExponentDigits++; + } + else if( nState==-2 ) // suche # im Exponent + { + if( c=='0' ) + // ERROR: 0 nach # im Exponent ist NICHT erlaubt !! + return -4; + nNoOfOptionalExponentDigits++; + nNoOfExponentDigits++; + } + break; + case '.': + nState++; + if( nState>1 ) + return -1; // ERROR: zu viele Dezimal-Punkte + break; + case '%': + bPercent = TRUE; + /* old: + bPercent++; + if( bPercent>1 ) + return -2; // ERROR: zu viele Prozent-Zeichen + */ + break; + case '(': + bCurrency = TRUE; + break; + case ',': + { + sal_Unicode ch = sFormatStrg.GetChar( i+1 ); + // vorl"aufig wird NUR auf zwei aufeinanderfolgede + // Zeichen gepr"uft + if( ch!=0 && (ch==',' || ch=='.') ) + nMultipleThousandSeparators++; + } break; + case 'e': + case 'E': + // #i13821 not when no digits before + if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 ) + { + nState = -1; // breche jetzt das Z"ahlen der Stellen ab + bScientific = TRUE; + } + /* old: + bScientific++; + if( bScientific>1 ) + return -3; // ERROR: zu viele Exponent-Zeichen + */ + break; + // EIGENES Kommando-Zeichen, das die Erzeugung der + // Tausender-Trennzeichen einschaltet + case '\\': + // Ignore next char + i++; + break; + case CREATE_1000SEP_CHAR: + bGenerateThousandSeparator = TRUE; + break; + } + } + return 0; +} + +// das Flag bCreateSign zeigt an, dass bei der Mantisse ein Vorzeichen +// erzeugt werden soll +void SbxBasicFormater::ScanFormatString( double dNumber, + const String& sFormatStrg, String& sReturnStrg, + BOOL bCreateSign ) +{ + short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft, + nNoOfExponentDigits,nNoOfOptionalExponentDigits, + nMultipleThousandSeparators; + BOOL bPercent,bCurrency,bScientific,bGenerateThousandSeparator; + + // Initialisiere den Return-String + sReturnStrg = String(); + + // analysiere den Format-String, d.h. bestimme folgende Werte: + /* + - Anzahl der Ziffern vor dem Komma + - Anzahl der Ziffern nach dem Komma + - optionale Ziffern vor dem Komma + - Anzahl der Ziffern im Exponent + - optionale Ziffern im Exponent + - Prozent-Zeichen gefunden ? + - () f"ur negatives Vorzeichen ? + - Exponetial-Schreibweise ? + - sollen Tausender-Separatoren erzeugt werden ? + - wird ein Prozent-Zeichen gefunden ? --> dNumber *= 100.0; + - gibt es aufeinanderfolgende Tausender-Trennzeichen ? + ,, oder ,. --> dNumber /= 1000.0; + - sonstige Fehler ? mehrfache Dezimalpunkte, E's, etc. + --> Fehler werden zur Zeit einfach ignoriert + */ + /*nErr =*/ AnalyseFormatString( sFormatStrg,nNoOfDigitsLeft,nNoOfDigitsRight, + nNoOfOptionalDigitsLeft,nNoOfExponentDigits, + nNoOfOptionalExponentDigits, + bPercent,bCurrency,bScientific,bGenerateThousandSeparator, + nMultipleThousandSeparators ); + /* es werden alle Fehler ignoriert, wie in Visual-Basic + if( nErr!=0 ) + { + char sBuffer[512]; + + //sprintf( sBuffer,"bad format-string >%s< err=%i",sFormatStrg,nErr ); + strcpy( sBuffer,"bad format-string" ); + ShowError( sBuffer ); + } + else + */ + { + // Spezialbehandlung f"ur Spezialzeichen + if( bPercent ) + dNumber *= 100.0; +// TODO: diese Vorgabe (,, oder ,.) ist NICHT Visual-Basic kompatibel ! + // Frage: soll das hier stehen bleiben (Anforderungen) ? + if( nMultipleThousandSeparators ) + dNumber /= 1000.0; + + // einige Arbeits-Variablen + double dExponent; + short i,nLen; + short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit; + BOOL bFirstDigit,bFirstExponentDigit,bFoundFirstDigit, + bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative; + + // Initialisierung der Arbeits-Variablen + bSignHappend = FALSE; + bFoundFirstDigit = FALSE; + bIsNegative = dNumber<0.0; + nLen = sFormatStrg.Len(); + dExponent = get_number_of_digits( dNumber ); + nExponentPos = 0; + nMaxExponentDigit = 0; + nMaxDigit = (short)dExponent; + bDigitPosNegative = false; + if( bScientific ) + { + //if( nNoOfOptionalDigitsLeft>0 ) + // ShowError( "# in scientific-format in front of the decimal-point has no effect" ); + // beim Exponent ggf. "uberz"ahlige Stellen vor dem Komma abziehen + dExponent = dExponent - (double)(nNoOfDigitsLeft-1); + nDigitPos = nMaxDigit; + nMaxExponentDigit = (short)get_number_of_digits( dExponent ); + nExponentPos = nNoOfExponentDigits-1 - nNoOfOptionalExponentDigits; + } + else + { + nDigitPos = nNoOfDigitsLeft-1; // Z"ahlweise f"angt bei 0 an, 10^0 + // hier ben"otigt man keine Exponent-Daten ! + bDigitPosNegative = (nDigitPos < 0); + } + bFirstDigit = TRUE; + bFirstExponentDigit = TRUE; + nState = 0; // 0 --> Mantisse; 1 --> Exponent + bZeroSpaceOn = 0; + + +#ifdef _with_sprintf + InitScan( dNumber ); +#endif + // scanne jetzt den Format-String: + sal_Unicode cForce = 0; + for( i=0; i<nLen; i++ ) + { + sal_Unicode c; + if( cForce ) + { + c = cForce; + cForce = 0; + } + else + { + c = sFormatStrg.GetChar( i ); + } + switch( c ) { + case '0': + case '#': + if( nState==0 ) + { + // Behandlung der Mantisse + if( bFirstDigit ) + { + //org:bFirstDigit = FALSE; + // ggf. Vorzeichen erzeugen + // Bem.: bei bCurrency soll das negative + // Vorzeichen durch () angezeigt werden + if( bIsNegative && !bCreateSign/*!bCurrency*/ && !bSignHappend ) + { + // nur einmal ein Vorzeichen ausgeben + bSignHappend = TRUE; + StrAppendChar( sReturnStrg,'-' ); + } + // hier jetzt "uberz"ahlige Stellen ausgeben, + // d.h. vom Format-String nicht erfasste Stellen + if( nMaxDigit>nDigitPos ) + { + for( short j=nMaxDigit; j>nDigitPos; j-- ) + { + short nTempDigit; +#ifdef _with_sprintf + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPosScan( j,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPos( dNumber,j,dNumber,bFoundFirstDigit ) ); +#endif + // wurde wirklich eine Ziffer eingefuegt ? + if( nTempDigit!=_NO_DIGIT ) + // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen + bFirstDigit = FALSE; + // muss ggf. ein Tausender-Trennzeichen erzeugt werden? + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && j>0 && (j % 3 == 0) ) + StrAppendChar( sReturnStrg,cThousandSep ); + } + } + } + // muss f"ur eine leere Stelle eventuell eine 0 ausgegeben werden ? + if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) ) + { + AppendDigit( sReturnStrg,0 ); // Ja + // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen + bFirstDigit = FALSE; + bZeroSpaceOn = 1; + // BEM.: bei Visual-Basic schaltet die erste 0 f"ur alle + // nachfolgenden # (bis zum Dezimal-Punkt) die 0 ein, + // dieses Verhalten wird hier mit dem Flag simmuliert. + // muss ggf. ein Tausender-Trennzeichen erzeugt werden? + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) ) + StrAppendChar( sReturnStrg,cThousandSep ); + } + else + { + short nTempDigit; +#ifdef _with_sprintf + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,nTempDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ) ); +#endif + // wurde wirklich eine Ziffer eingefuegt ? + if( nTempDigit!=_NO_DIGIT ) + // jetzt wurde wirklich eine Ziffer ausgegeben, Flag setzen + bFirstDigit = FALSE; + // muss ggf. ein Tausender-Trennzeichen erzeugt werden? + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) ) + StrAppendChar( sReturnStrg,cThousandSep ); + } + // und Position aktualisieren + nDigitPos--; + } + else + { + // Behandlung des Exponenten + if( bFirstExponentDigit ) + { + // Vorzeichen wurde schon bei e/E ausgegeben + bFirstExponentDigit = FALSE; + if( nMaxExponentDigit>nExponentPos ) + // hier jetzt "uberz"ahlige Stellen ausgeben, + // d.h. vom Format-String nicht erfasste Stellen + { + for( short j=nMaxExponentDigit; j>nExponentPos; j-- ) + { +#ifdef _with_sprintf + AppendDigit( sReturnStrg,GetDigitAtPosExpScan( dExponent,j,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,GetDigitAtPos( dExponent,j,dExponent,bFoundFirstDigit ) ); +#endif + } + } + } + // muss f"ur eine leere Stelle eventuell eine 0 ausgegeben werden ? + if( nMaxExponentDigit<nExponentPos && c=='0' ) + AppendDigit( sReturnStrg,0 ); // Ja + else +#ifdef _with_sprintf + AppendDigit( sReturnStrg,GetDigitAtPosExpScan( dExponent,nExponentPos,bFoundFirstDigit ) ); +#else + AppendDigit( sReturnStrg,GetDigitAtPos( dExponent,nExponentPos,dExponent,bFoundFirstDigit ) ); +#endif + nExponentPos--; + } + break; + case '.': + if( bDigitPosNegative ) // #i13821: If no digits before . + { + bDigitPosNegative = false; + nDigitPos = 0; + cForce = '#'; + i-=2; + break; + } + // gebe Komma aus + StrAppendChar( sReturnStrg,cDecPoint ); + break; + case '%': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + // gebe Prozent-Zeichen aus + sReturnStrg.Insert('%'); + break; + case 'e': + case 'E': + // muss Mantisse noch gerundet werden, bevor der Exponent angezeigt wird ? + { + // gibt es ueberhaupt eine Mantisse ? + if( bFirstDigit ) + { + // anscheinend nicht, d.h. ungueltiger Format String, z.B. E000.00 + // d.h. ignoriere diese e bzw. E Zeichen + // ggf. einen Fehler (wie Visual Basic) ausgeben ? + + // #i13821: VB 6 behaviour + StrAppendChar( sReturnStrg,c ); + break; + } + + BOOL bOverflow = FALSE; +#ifdef _with_sprintf + short nNextDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ); +#else + short nNextDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ); +#endif + if( nNextDigit>=5 ) + StrRoundDigit( sReturnStrg,sReturnStrg.Len()-1,bOverflow ); + if( bOverflow ) + { + // es wurde eine f"uhrende 9 gerundet, d.h. + // verschiebe den Dezimal-Punkt um eine Stelle nach links + LeftShiftDecimalPoint( sReturnStrg ); + // und l"osche die letzte Ziffer, diese wird + // duch die f"uhrende 1 ersetzt: + sReturnStrg.SetChar( sReturnStrg.Len()-1 , 0 ); + // der Exponent muss um 1 erh"oht werden, + // da der Dezimalpunkt verschoben wurde + dExponent += 1.0; + } + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + } + // "andere Zustand des Scanners + nState++; + // gebe Exponent-Zeichen aus + StrAppendChar( sReturnStrg,c ); + // i++; // MANIPULATION der Schleifen-Variable ! + c = sFormatStrg.GetChar( ++i ); + // und gebe Vorzeichen / Exponent aus + if( c!=0 ) + { + if( c=='-' ) + { + // falls Exponent < 0 gebe - aus + if( dExponent<0.0 ) + StrAppendChar( sReturnStrg,'-' ); + } + else if( c=='+' ) + { + // gebe auf jeden Fall das Vorzeichen des Exponenten aus ! + if( dExponent<0.0 ) + StrAppendChar( sReturnStrg,'-' ); + else + StrAppendChar( sReturnStrg,'+' ); + } + //else + // ShowError( "operator e/E did not find + or -" ); + } + //else + // ShowError( "operator e/E ended with 0" ); + break; + case ',': + // ACHTUNG: nur falls Zahl bisher ausgegeben wurde + // das Zeichen ausgeben + ////--> Siehe Kommentar vom 11.7. in AnalyseFormatString() + ////if( !bFirstDigit ) + //// // gebe Tausender-Trennzeichen aus + //// StrAppendChar( sReturnStrg,cThousandSep ); + break; + case ';': + break; + case '(': + case ')': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + if( bIsNegative ) + StrAppendChar( sReturnStrg,c ); + break; + case '$': + // den String fuer die Waehrung dranhengen: + sReturnStrg += sCurrencyStrg; + break; + case ' ': + case '-': + case '+': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + // gebe das jeweilige Zeichen direkt aus + StrAppendChar( sReturnStrg,c ); + break; + case '\\': + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00 + // falls Sonderzeichen am Ende oder mitten in + // Format-String vorkommen + ParseBack( sReturnStrg,sFormatStrg,i-1 ); + // Sonderzeichen gefunden, gebe N"ACHSTES + // Zeichen direkt aus (falls es existiert) + // i++; + c = sFormatStrg.GetChar( ++i ); + if( c!=0 ) + StrAppendChar( sReturnStrg,c ); + //else + // ShowError( "operator \\ ended with 0" ); + break; + case CREATE_1000SEP_CHAR: + // hier ignorieren, Aktion wurde schon in + // AnalyseFormatString durchgef"uhrt + break; + default: + // auch die Zeichen und Ziffern ausgeben (wie in Visual-Basic) + if( ( c>='a' && c<='z' ) || + ( c>='A' && c<='Z' ) || + ( c>='1' && c<='9' ) ) + StrAppendChar( sReturnStrg,c ); + // else + // ignorieren ! + // ehemals: ShowError( "bad character in format-string" ); + } + } + // Format-String wurde vollst"andig gescanned, + // muss die letzte Stelle nun gerundet werden ? + // Dies hier ist jedoch NUR notwendig, falls das + // Zahlenformat NICHT Scientific-Format ist ! + if( !bScientific ) + { +#ifdef _with_sprintf + short nNextDigit = GetDigitAtPosScan( nDigitPos,bFoundFirstDigit ); +#else + short nNextDigit = GetDigitAtPos( dNumber,nDigitPos,dNumber,bFoundFirstDigit ); +#endif + if( nNextDigit>=5 ) + StrRoundDigit( sReturnStrg,sReturnStrg.Len()-1 ); + } + // und ganz zum Schluss: + // ggf. "uberf"ussige 0en l"oschen, z.B. 4.500e4 in 0.0##e-00#, + // ABER nur Stellen nach dem Dezimal-Punkt k"onnen gel"oscht werden + if( nNoOfDigitsRight>0 ) + ParseBack( sReturnStrg,sFormatStrg,sFormatStrg.Len()-1 ); + } +} + +String SbxBasicFormater::BasicFormatNull( String sFormatStrg ) +{ + BOOL bNullFormatFound; + String sNullFormatStrg = GetNullFormatString( sFormatStrg,bNullFormatFound ); + + if( bNullFormatFound ) + return sNullFormatStrg; + String aRetStr; + aRetStr.AssignAscii( "null" ); + return aRetStr; +} + +String SbxBasicFormater::BasicFormat( double dNumber, String sFormatStrg ) +{ + BOOL bPosFormatFound,bNegFormatFound,b0FormatFound; + + // analysiere Format-String auf vordefinierte Formate: + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_GENERALNUMBER ) ) + sFormatStrg.AssignAscii( GENERALNUMBER_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_CURRENCY ) ) + sFormatStrg = sCurrencyFormatStrg; // old: CURRENCY_FORMAT; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_FIXED ) ) + sFormatStrg.AssignAscii( FIXED_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_STANDARD ) ) + sFormatStrg.AssignAscii( STANDARD_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_PERCENT ) ) + sFormatStrg.AssignAscii( PERCENT_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_SCIENTIFIC ) ) + sFormatStrg.AssignAscii( SCIENTIFIC_FORMAT ); + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_YESNO ) ) + return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_TRUEFALSE ) ) + return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_ONOFF ) ) + return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ; + + // analysiere Format-String auf ';', d.h. Format-Strings f"ur + // positive-, negative- und 0-Werte + String sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound ); + String sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound ); + String s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound ); + //String sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound ); + + String sReturnStrg; + String sTempStrg; + + if( dNumber==0.0 ) + { + sTempStrg = sFormatStrg; + if( b0FormatFound ) + { + // wurde ggf. Leer-String uebergeben ? + if( s0FormatStrg.Len() == 0 && bPosFormatFound ) + // --> Ja, dann verwende String fuer positive Werte + sTempStrg = sPosFormatStrg; + else + sTempStrg = s0FormatStrg; + } + else if( bPosFormatFound ) + { + // verwende String fuer positive Werte + sTempStrg = sPosFormatStrg; + } + ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/FALSE ); + } + else + { + if( dNumber<0.0 ) + { + if( bNegFormatFound ) + { + // wurde ggf. Leer-String uebergeben ? + if( sNegFormatStrg.Len() == 0 && bPosFormatFound ) + { + // --> Ja, dann verwende String fuer positive Werte + // und setzte Minus-Zeichen davor ! + sTempStrg = String::CreateFromAscii("-"); + sTempStrg += sPosFormatStrg; + } + else + sTempStrg = sNegFormatStrg; + } + else + sTempStrg = sFormatStrg; + // falls KEIN Format-String speziell f"ur negative Werte angegeben + // wurde, so soll das Vorzeichen ausgegeben werden + ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ ); + } + else // if( dNumber>0.0 ) + { + ScanFormatString( dNumber, + (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg), + sReturnStrg,/*bCreateSign=*/FALSE ); + } + } + return sReturnStrg; +} + +BOOL SbxBasicFormater::isBasicFormat( String sFormatStrg ) +{ + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_GENERALNUMBER ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_CURRENCY ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_FIXED ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_STANDARD ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_PERCENT ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_SCIENTIFIC ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_YESNO ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_TRUEFALSE ) ) + return TRUE; + if( sFormatStrg.EqualsIgnoreCaseAscii( BASICFORMAT_ONOFF ) ) + return TRUE; + return FALSE; +} + diff --git a/basic/source/sbx/sbxint.cxx b/basic/source/sbx/sbxint.cxx new file mode 100644 index 000000000000..406b8599e568 --- /dev/null +++ b/basic/source/sbx/sbxint.cxx @@ -0,0 +1,967 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +double ImpRound( double d ) +{ + return d + ( d < 0 ? -0.5 : 0.5 ); +} + +INT16 ImpGetInteger( const SbxValues* p ) +{ + SbxValues aTmp; + INT16 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + if( p->nUShort > (USHORT) SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else + nRes = (INT16) p->nUShort; + break; + case SbxLONG: + if( p->nLong > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( p->nLong < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) p->nLong; + break; + case SbxULONG: + if( p->nULong > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else + nRes = (INT16) p->nULong; + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( p->nSingle < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) ImpRound( p->nSingle ); + break; + case SbxSALINT64: + if( p->nInt64 > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( p->nInt64 < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) p->nInt64; + break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else + nRes = (INT16) p->uInt64; + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( dVal < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) ImpRound( dVal ); + break; + } + case SbxLPSTR: + case SbxSTRING: + case SbxBYREF | SbxSTRING: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXINT; + } + else if( d < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMININT; + } + else + nRes = (INT16) ImpRound( d ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetInteger(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + + // ab hier muss getestet werden + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutInteger( SbxValues* p, INT16 n ) +{ + SbxValues aTmp; +start: + switch( +p->eType ) + { + // hier muss getestet werden + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // ab hier nicht mehr + case SbxINTEGER: + case SbxBOOL: + p->nInteger = n; break; + case SbxLONG: + p->nLong = n; break; + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxULONG64: + p->nULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxLONG64: + p->nLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxCURRENCY: + p->nLong64 = ImpDoubleToCurrency( (double)n ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setInt( n ); + break; + + case SbxLPSTR: + case SbxSTRING: + case SbxBYREF | SbxSTRING: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 0, *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutInteger( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (char) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + *p->pInteger = n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); *p->puInt64 = 0; + } + else + *p->puInt64 = n; + break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxULONG64: + *p->pULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxBYREF | SbxLONG64: + *p->pLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + + +// sal_Int64 / hyper + +sal_Int64 ImpDoubleToSalInt64( double d ) +{ + sal_Int64 nRes; + if( d > SbxMAXSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALINT64; + } + else if( d < SbxMINSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINSALINT64; + } + else + nRes = (sal_Int64) ImpRound( d ); + return nRes; +} + +sal_uInt64 ImpDoubleToSalUInt64( double d ) +{ + sal_uInt64 nRes; + if( d > SbxMAXSALUINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALUINT64; + } + else if( d < 0.0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (sal_uInt64) ImpRound( d ); + return nRes; +} + +double ImpSalUInt64ToDouble( sal_uInt64 n ) +{ + double d = 0.0; + if( n > SbxMAXSALINT64 ) + SbxBase::SetError( SbxERR_CONVERSION ); + else + d = (double)(sal_Int64) n; + return d; +} + + +sal_Int64 ImpGetInt64( const SbxValues* p ) +{ + SbxValues aTmp; + sal_Int64 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = p->nLong; break; + case SbxULONG: + nRes = (sal_Int64) p->nULong; break; + case SbxSINGLE: + nRes = ImpDoubleToSalInt64( (double)p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else + dVal = p->nDouble; + + nRes = ImpDoubleToSalInt64( dVal ); + break; + } + case SbxSALINT64: + nRes = p->nInt64; break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALINT64; + } + else + nRes = (sal_Int64) p->uInt64; + break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + ::rtl::OUString aOUStr( *p->pString ); + ::rtl::OString aOStr = ::rtl::OUStringToOString + ( aOUStr, RTL_TEXTENCODING_ASCII_US ); + nRes = aOStr.toInt64(); + if( nRes == 0 ) + { + // Check if really 0 or invalid conversion + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else + nRes = ImpDoubleToSalInt64( d ); + } + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetInt64(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + case SbxBYREF | SbxSALINT64: + nRes = *p->pnInt64; break; + + // from here the values has to be checked + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutInt64( SbxValues* p, sal_Int64 n ) +{ + SbxValues aTmp; + +start: + switch( +p->eType ) + { + // Check neccessary + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxLONG: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // Check not neccessary + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSINGLE: + p->nSingle = (float) n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = (double) n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + { + if( !p->pString ) + p->pString = new XubString; + + ::rtl::OString aOStr = ::rtl::OString::valueOf( n ); + ::rtl::OUString aOUStr = ::rtl::OStringToOUString + ( aOStr, RTL_TEXTENCODING_ASCII_US ); + (*p->pString) = aOUStr; + break; + } + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutInt64( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + else if( n < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXULNG; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxCURRENCY: + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = (sal_Int64) SbxMAXCURR; + } + else if( n < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = (sal_Int64) SbxMINCURR; + } + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->puInt64 = (sal_Int64) n; break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + +sal_uInt64 ImpGetUInt64( const SbxValues* p ) +{ + SbxValues aTmp; + sal_uInt64 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = p->nLong; break; + case SbxULONG: + nRes = (sal_uInt64) p->nULong; break; + case SbxSINGLE: + nRes = ImpDoubleToSalUInt64( (double)p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else + dVal = p->nDouble; + + nRes = ImpDoubleToSalUInt64( dVal ); + break; + } + case SbxSALINT64: + if( p->nInt64 < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (sal_uInt64) p->nInt64; + case SbxSALUINT64: + nRes = p->uInt64; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + ::rtl::OUString aOUStr( *p->pString ); + ::rtl::OString aOStr = ::rtl::OUStringToOString + ( aOUStr, RTL_TEXTENCODING_ASCII_US ); + sal_Int64 n64 = aOStr.toInt64(); + if( n64 == 0 ) + { + // Check if really 0 or invalid conversion + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXSALUINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXSALUINT64; + } + else if( d < 0.0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (sal_uInt64) ImpRound( d ); + } + else if( n64 < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + { + nRes = n64; + } + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetUInt64(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + case SbxBYREF | SbxSALUINT64: + nRes = *p->puInt64; break; + + // from here the values has to be checked + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutUInt64( SbxValues* p, sal_uInt64 n ) +{ + SbxValues aTmp; + +start: + switch( +p->eType ) + { + // Check neccessary + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxLONG: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSALINT64: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSINGLE: + aTmp.pSingle = &p->nSingle; goto direct; + case SbxDATE: + case SbxDOUBLE: + aTmp.pDouble = &p->nDouble; goto direct; + + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // Check not neccessary + case SbxSALUINT64: + p->uInt64 = n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + if( n > SbxMAXSALINT64 ) + SbxBase::SetError( SbxERR_CONVERSION ); + else + { + ::rtl::OString aOStr = ::rtl::OString::valueOf( (sal_Int64)n ); + ::rtl::OUString aOUStr = ::rtl::OStringToOUString + ( aOStr, RTL_TEXTENCODING_ASCII_US ); + (*p->pString) = aOUStr; + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutUInt64( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXULNG; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSINGLE: + *p->pDouble = (float)ImpSalUInt64ToDouble( n ); break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = ImpSalUInt64ToDouble( n ); break; + case SbxBYREF | SbxCURRENCY: + if( n > SbxMAXSALINT64 || (sal_Int64)n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = (sal_Int64) SbxMAXCURR; + } + *p->pLong64 = ImpDoubleToCurrency( (double)(sal_Int64) n ); break; + + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxSALINT64: + if( n > SbxMAXSALINT64 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pnInt64 = (sal_Int64) n; break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + + diff --git a/basic/source/sbx/sbxlng.cxx b/basic/source/sbx/sbxlng.cxx new file mode 100644 index 000000000000..c84b087dfc33 --- /dev/null +++ b/basic/source/sbx/sbxlng.cxx @@ -0,0 +1,341 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +INT32 ImpGetLong( const SbxValues* p ) +{ + SbxValues aTmp; + INT32 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = p->nLong; break; + case SbxULONG: + if( p->nULong > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXLNG; + } + else + nRes = (INT32) p->nULong; + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXLNG; + } + else if( p->nSingle < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINLNG; + } + else + nRes = (INT32) ImpRound( p->nSingle ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxSALINT64: + case SbxSALUINT64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxSALINT64 ) + dVal = static_cast< double >(p->nInt64); + else if( p->eType == SbxSALUINT64 ) + dVal = ImpSalUInt64ToDouble( p->uInt64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXLNG; + } + else if( dVal < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINLNG; + } + else + nRes = (INT32) ImpRound( dVal ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXLNG; + } + else if( d < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMINLNG; + } + else + nRes = (INT32) ImpRound( d ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetLong(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = *p->pLong; break; + + // ab hier muss getestet werden + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + aTmp.nUShort = *p->pUShort; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutLong( SbxValues* p, INT32 n ) +{ + SbxValues aTmp; + +start: + switch( +p->eType ) + { + // Ab hier muss getestet werden + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // ab hier nicht mehr + case SbxLONG: + p->nLong = n; break; + case SbxSINGLE: + p->nSingle = (float) n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setLong( n ); + break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 0, *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutLong( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + *p->pLong = n; break; + case SbxBYREF | SbxULONG: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pULong = (UINT32) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); *p->puInt64 = 0; + } + else + *p->puInt64 = n; + break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxCURRENCY: + double d; + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); d = SbxMAXCURR; + } + else if( n < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); d = SbxMINCURR; + } + else + { + d = n; + } + *p->pLong64 = ImpDoubleToCurrency( d ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxmstrm.cxx b/basic/source/sbx/sbxmstrm.cxx new file mode 100644 index 000000000000..671c0bc5d1d9 --- /dev/null +++ b/basic/source/sbx/sbxmstrm.cxx @@ -0,0 +1,39 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <basic/sbxmstrm.hxx> + +SbxDataType SbxMemoryStream::GetType() const +{ + return SbxMEMORYSTREAM; +} + +SbxMemoryStream::~SbxMemoryStream() +{ +} diff --git a/basic/source/sbx/sbxobj.cxx b/basic/source/sbx/sbxobj.cxx new file mode 100644 index 000000000000..b2b67fe3774f --- /dev/null +++ b/basic/source/sbx/sbxobj.cxx @@ -0,0 +1,1145 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/stream.hxx> +#include <vcl/sound.hxx> +#include <basic/sbx.hxx> +#include <basic/sbxbase.hxx> +#include "sbxres.hxx" +#include <svl/brdcst.hxx> + +TYPEINIT1(SbxMethod,SbxVariable) +TYPEINIT1(SbxProperty,SbxVariable) +TYPEINIT2(SbxObject,SbxVariable,SfxListener) + +static const char* pNameProp; // Name-Property +static const char* pParentProp; // Parent-Property + +static USHORT nNameHash = 0, nParentHash = 0; + +///////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////// + +SbxObject::SbxObject( const XubString& rClass ) + : SbxVariable( SbxOBJECT ), aClassName( rClass ) +{ + aData.pObj = this; + if( !nNameHash ) + { + pNameProp = GetSbxRes( STRING_NAMEPROP ); + pParentProp = GetSbxRes( STRING_PARENTPROP ); + nNameHash = MakeHashCode( String::CreateFromAscii( pNameProp ) ); + nParentHash = MakeHashCode( String::CreateFromAscii( pParentProp ) ); + } + SbxObject::Clear(); + SbxObject::SetName( rClass ); +} + +SbxObject::SbxObject( const SbxObject& rObj ) + : SvRefBase( rObj ), SbxVariable( rObj.GetType() ), + SfxListener( rObj ) +{ + *this = rObj; +} + +SbxObject& SbxObject::operator=( const SbxObject& r ) +{ + if( &r != this ) + { + SbxVariable::operator=( r ); + aClassName = r.aClassName; + pMethods = new SbxArray; + pProps = new SbxArray; + pObjs = new SbxArray( SbxOBJECT ); + // Die Arrays werden kopiert, die Inhalte uebernommen + *pMethods = *r.pMethods; + *pProps = *r.pProps; + *pObjs = *r.pObjs; + // Da die Variablen uebernommen wurden, ist dies OK + pDfltProp = r.pDfltProp; + SetName( r.GetName() ); + SetFlags( r.GetFlags() ); + SetModified( TRUE ); + } + return *this; +} + +static void CheckParentsOnDelete( SbxObject* pObj, SbxArray* p ) +{ + for( USHORT i = 0; i < p->Count(); i++ ) + { + SbxVariableRef& rRef = p->GetRef( i ); + if( rRef->IsBroadcaster() ) + pObj->EndListening( rRef->GetBroadcaster(), TRUE ); + // Hat das Element mehr als eine Referenz und noch einen Listener? + if( rRef->GetRefCount() > 1 ) + { + rRef->SetParent( NULL ); + DBG_ASSERT( !rRef->IsBroadcaster() || rRef->GetBroadcaster().GetListenerCount(), "Object element with dangling parent" ); + } + } +} + +SbxObject::~SbxObject() +{ + CheckParentsOnDelete( this, pProps ); + CheckParentsOnDelete( this, pMethods ); + CheckParentsOnDelete( this, pObjs ); +} + +SbxDataType SbxObject::GetType() const +{ + return SbxOBJECT; +} + +SbxClassType SbxObject::GetClass() const +{ + return SbxCLASS_OBJECT; +} + +void SbxObject::Clear() +{ + pMethods = new SbxArray; + pProps = new SbxArray; + pObjs = new SbxArray( SbxOBJECT ); + SbxVariable* p; + p = Make( String::CreateFromAscii( pNameProp ), SbxCLASS_PROPERTY, SbxSTRING ); + p->SetFlag( SBX_DONTSTORE ); + p = Make( String::CreateFromAscii( pParentProp ), SbxCLASS_PROPERTY, SbxOBJECT ); + p->ResetFlag( SBX_WRITE ); + p->SetFlag( SBX_DONTSTORE ); + pDfltProp = NULL; + SetModified( FALSE ); +} + +void SbxObject::SFX_NOTIFY( SfxBroadcaster&, const TypeId&, + const SfxHint& rHint, const TypeId& ) +{ + const SbxHint* p = PTR_CAST(SbxHint,&rHint); + if( p ) + { + ULONG nId = p->GetId(); + BOOL bRead = BOOL( nId == SBX_HINT_DATAWANTED ); + BOOL bWrite = BOOL( nId == SBX_HINT_DATACHANGED ); + SbxVariable* pVar = p->GetVar(); + if( bRead || bWrite ) + { + XubString aVarName( pVar->GetName() ); + USHORT nHash_ = MakeHashCode( aVarName ); + if( nHash_ == nNameHash + && aVarName.EqualsIgnoreCaseAscii( pNameProp ) ) + { + if( bRead ) + pVar->PutString( GetName() ); + else + SetName( pVar->GetString() ); + } + else if( nHash_ == nParentHash + && aVarName.EqualsIgnoreCaseAscii( pParentProp ) ) + { + SbxObject* p_ = GetParent(); + if( !p_ ) + p_ = this; + pVar->PutObject( p_ ); + } + } + } +} + +BOOL SbxObject::IsClass( const XubString& rName ) const +{ + return BOOL( aClassName.EqualsIgnoreCaseAscii( rName ) ); +} + +SbxVariable* SbxObject::FindUserData( UINT32 nData ) +{ + if( !GetAll( SbxCLASS_DONTCARE ) ) + return NULL; + + SbxVariable* pRes = pMethods->FindUserData( nData ); + if( !pRes ) + pRes = pProps->FindUserData( nData ); + if( !pRes ) + pRes = pObjs->FindUserData( nData ); + // Search in den Parents? + if( !pRes && IsSet( SBX_GBLSEARCH ) ) + { + SbxObject* pCur = this; + while( !pRes && pCur->pParent ) + { + // Ich selbst bin schon durchsucht worden! + USHORT nOwn = pCur->GetFlags(); + pCur->ResetFlag( SBX_EXTSEARCH ); + // Ich suche bereits global! + USHORT nPar = pCur->pParent->GetFlags(); + pCur->pParent->ResetFlag( SBX_GBLSEARCH ); + pRes = pCur->pParent->FindUserData( nData ); + pCur->SetFlags( nOwn ); + pCur->pParent->SetFlags( nPar ); + pCur = pCur->pParent; + } + } + return pRes; +} + +SbxVariable* SbxObject::Find( const XubString& rName, SbxClassType t ) +{ +#ifdef DBG_UTIL + static USHORT nLvl = 0; + static const char* pCls[] = + { "DontCare","Array","Value","Variable","Method","Property","Object" }; + ByteString aNameStr1( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US ); + ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); + DbgOutf( "SBX: Search %.*s %s %s in %s", + nLvl++, " ", + ( t >= SbxCLASS_DONTCARE && t <= SbxCLASS_OBJECT ) + ? pCls[ t-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); +#endif + + if( !GetAll( t ) ) + return NULL; + SbxVariable* pRes = NULL; + pObjs->SetFlag( SBX_EXTSEARCH ); + if( t == SbxCLASS_DONTCARE ) + { + pRes = pMethods->Find( rName, SbxCLASS_METHOD ); + if( !pRes ) + pRes = pProps->Find( rName, SbxCLASS_PROPERTY ); + if( !pRes ) + pRes = pObjs->Find( rName, t ); + } + else + { + SbxArray* pArray = NULL; + switch( t ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: pArray = pProps; break; + case SbxCLASS_METHOD: pArray = pMethods; break; + case SbxCLASS_OBJECT: pArray = pObjs; break; + default: + DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); + } + if( pArray ) + pRes = pArray->Find( rName, t ); + } + // Extended Search im Objekt-Array? + // Fuer Objekte und DontCare ist das Objektarray bereits + // durchsucht worden + if( !pRes && ( t == SbxCLASS_METHOD || t == SbxCLASS_PROPERTY ) ) + pRes = pObjs->Find( rName, t ); + // Search in den Parents? + if( !pRes && IsSet( SBX_GBLSEARCH ) ) + { + SbxObject* pCur = this; + while( !pRes && pCur->pParent ) + { + // Ich selbst bin schon durchsucht worden! + USHORT nOwn = pCur->GetFlags(); + pCur->ResetFlag( SBX_EXTSEARCH ); + // Ich suche bereits global! + USHORT nPar = pCur->pParent->GetFlags(); + pCur->pParent->ResetFlag( SBX_GBLSEARCH ); + pRes = pCur->pParent->Find( rName, t ); + pCur->SetFlags( nOwn ); + pCur->pParent->SetFlags( nPar ); + pCur = pCur->pParent; + } + } +#ifdef DBG_UTIL + nLvl--; + if( pRes ) + { + ByteString aNameStr3( (const UniString&)rName, RTL_TEXTENCODING_ASCII_US ); + ByteString aNameStr4( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); + DbgOutf( "SBX: Found %.*s %s in %s", + nLvl, " ", aNameStr3.GetBuffer(), aNameStr4.GetBuffer() ); + } +#endif + return pRes; +} + +// Kurzform: Die Parent-Kette wird durchsucht +// Das ganze rekursiv, da Call() ueberladen sein kann +// Qualified Names sind zugelassen + +BOOL SbxObject::Call( const XubString& rName, SbxArray* pParam ) +{ + SbxVariable* pMeth = FindQualified( rName, SbxCLASS_DONTCARE); + if( pMeth && pMeth->ISA(SbxMethod) ) + { + // FindQualified() koennte schon zugeschlagen haben! + if( pParam ) + pMeth->SetParameters( pParam ); + pMeth->Broadcast( SBX_HINT_DATAWANTED ); + pMeth->SetParameters( NULL ); + return TRUE; + } + SetError( SbxERR_NO_METHOD ); + return FALSE; +} + +SbxProperty* SbxObject::GetDfltProperty() +{ + if ( !pDfltProp && aDfltPropName.Len() ) + { + pDfltProp = (SbxProperty*) Find( aDfltPropName, SbxCLASS_PROPERTY ); + if( !pDfltProp ) + pDfltProp = (SbxProperty*) Make( aDfltPropName, SbxCLASS_PROPERTY, SbxVARIANT ); + } + return pDfltProp; +} +void SbxObject::SetDfltProperty( const XubString& rName ) +{ + if ( rName != aDfltPropName ) + pDfltProp = NULL; + aDfltPropName = rName; + SetModified( TRUE ); +} + +void SbxObject::SetDfltProperty( SbxProperty* p ) +{ + if( p ) + { + USHORT n; + SbxArray* pArray = FindVar( p, n ); + pArray->Put( p, n ); + if( p->GetParent() != this ) + p->SetParent( this ); + Broadcast( SBX_HINT_OBJECTCHANGED ); + } + pDfltProp = p; + SetModified( TRUE ); +} + +// Suchen einer bereits vorhandenen Variablen. Falls sie gefunden wurde, +// wird der Index gesetzt, sonst wird der Count des Arrays geliefert. +// In jedem Fall wird das korrekte Array geliefert. + +SbxArray* SbxObject::FindVar( SbxVariable* pVar, USHORT& nArrayIdx ) +{ + SbxArray* pArray = NULL; + if( pVar ) switch( pVar->GetClass() ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: pArray = pProps; break; + case SbxCLASS_METHOD: pArray = pMethods; break; + case SbxCLASS_OBJECT: pArray = pObjs; break; + default: + DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); + } + if( pArray ) + { + nArrayIdx = pArray->Count(); + // ist die Variable per Name vorhanden? + pArray->ResetFlag( SBX_EXTSEARCH ); + SbxVariable* pOld = pArray->Find( pVar->GetName(), pVar->GetClass() ); + if( pOld ) + for( USHORT i = 0; i < pArray->Count(); i++ ) + { + SbxVariableRef& rRef = pArray->GetRef( i ); + if( (SbxVariable*) rRef == pOld ) + { + nArrayIdx = i; break; + } + } + } + return pArray; +} + +// Falls ein neues Objekt eingerichtet wird, wird es, falls es bereits +// eines mit diesem Namen gibt, indiziert. + +SbxVariable* SbxObject::Make( const XubString& rName, SbxClassType ct, SbxDataType dt ) +{ + // Ist das Objekt bereits vorhanden? + SbxArray* pArray = NULL; + switch( ct ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: pArray = pProps; break; + case SbxCLASS_METHOD: pArray = pMethods; break; + case SbxCLASS_OBJECT: pArray = pObjs; break; + default: + DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); + } + if( !pArray ) + return NULL; + // Collections duerfen gleichnamige Objekte enthalten + if( !( ct == SbxCLASS_OBJECT && ISA(SbxCollection) ) ) + { + SbxVariable* pRes = pArray->Find( rName, ct ); + if( pRes ) + { +/* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus +#ifdef DBG_UTIL + if( pRes->GetHashCode() != nNameHash + && pRes->GetHashCode() != nParentHash ) + { + XubString aMsg( "SBX-Element \"" ); + aMsg += pRes->GetName(); + aMsg += "\"\n in Objekt \""; + aMsg += GetName(); + aMsg += "\" bereits vorhanden"; + DbgError( (const char*)aMsg.GetStr() ); + } +#endif +*/ + return pRes; + } + } + SbxVariable* pVar = NULL; + switch( ct ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: + pVar = new SbxProperty( rName, dt ); + break; + case SbxCLASS_METHOD: + pVar = new SbxMethod( rName, dt ); + break; + case SbxCLASS_OBJECT: + pVar = CreateObject( rName ); + break; + default: break; + } + pVar->SetParent( this ); + pArray->Put( pVar, pArray->Count() ); + SetModified( TRUE ); + // Das Objekt lauscht immer + StartListening( pVar->GetBroadcaster(), TRUE ); + Broadcast( SBX_HINT_OBJECTCHANGED ); + return pVar; +} + +SbxObject* SbxObject::MakeObject( const XubString& rName, const XubString& rClass ) +{ + // Ist das Objekt bereits vorhanden? + if( !ISA(SbxCollection) ) + { + SbxVariable* pRes = pObjs->Find( rName, SbxCLASS_OBJECT ); + if( pRes ) + { +/* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus +#ifdef DBG_UTIL + if( pRes->GetHashCode() != nNameHash + && pRes->GetHashCode() != nParentHash ) + { + XubString aMsg( "SBX-Objekt \"" ); + aMsg += pRes->GetName(); + aMsg += "\"\n in Objekt \""; + aMsg += GetName(); + aMsg += "\" bereits vorhanden"; + DbgError( (const char*)aMsg.GetStr() ); + } +#endif +*/ + return PTR_CAST(SbxObject,pRes); + } + } + SbxObject* pVar = CreateObject( rClass ); + if( pVar ) + { + pVar->SetName( rName ); + pVar->SetParent( this ); + pObjs->Put( pVar, pObjs->Count() ); + SetModified( TRUE ); + // Das Objekt lauscht immer + StartListening( pVar->GetBroadcaster(), TRUE ); + Broadcast( SBX_HINT_OBJECTCHANGED ); + } + return pVar; +} + +void SbxObject::Insert( SbxVariable* pVar ) +{ + USHORT nIdx; + SbxArray* pArray = FindVar( pVar, nIdx ); + if( pArray ) + { + // Hinein damit. Man sollte allerdings auf die Pointer aufpassen! + if( nIdx < pArray->Count() ) + { + // dann gibt es dieses Element bereits + // Bei Collections duerfen gleichnamige Objekte hinein + if( pArray == pObjs && ISA(SbxCollection) ) + nIdx = pArray->Count(); + else + { + SbxVariable* pOld = pArray->Get( nIdx ); + // schon drin: ueberschreiben + if( pOld == pVar ) + return; + +/* Wegen haeufiger Probleme (z.B. #67000) erstmal ganz raus +#ifdef DBG_UTIL + if( pOld->GetHashCode() != nNameHash + && pOld->GetHashCode() != nParentHash ) + { + XubString aMsg( "SBX-Element \"" ); + aMsg += pVar->GetName(); + aMsg += "\"\n in Objekt \""; + aMsg += GetName(); + aMsg += "\" bereits vorhanden"; + DbgError( (const char*)aMsg.GetStr() ); + } +#endif +*/ + EndListening( pOld->GetBroadcaster(), TRUE ); + if( pVar->GetClass() == SbxCLASS_PROPERTY ) + { + if( pOld == pDfltProp ) + pDfltProp = (SbxProperty*) pVar; + } + } + } + StartListening( pVar->GetBroadcaster(), TRUE ); + pArray->Put( pVar, nIdx ); + if( pVar->GetParent() != this ) + pVar->SetParent( this ); + SetModified( TRUE ); + Broadcast( SBX_HINT_OBJECTCHANGED ); +#ifdef DBG_UTIL + static const char* pCls[] = + { "DontCare","Array","Value","Variable","Method","Property","Object" }; + XubString aVarName( pVar->GetName() ); + if ( !aVarName.Len() && pVar->ISA(SbxObject) ) + aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); + ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); + ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); + DbgOutf( "SBX: Insert %s %s in %s", + ( pVar->GetClass() >= SbxCLASS_DONTCARE && + pVar->GetClass() <= SbxCLASS_OBJECT ) + ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); +#endif + } +} + +// AB 23.4.1997, Optimierung, Einfuegen ohne Ueberpruefung auf doppelte +// Eintraege und ohne Broadcasts, wird nur in SO2/auto.cxx genutzt +void SbxObject::QuickInsert( SbxVariable* pVar ) +{ + SbxArray* pArray = NULL; + if( pVar ) + { + switch( pVar->GetClass() ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: pArray = pProps; break; + case SbxCLASS_METHOD: pArray = pMethods; break; + case SbxCLASS_OBJECT: pArray = pObjs; break; + default: + DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); + } + } + if( pArray ) + { + StartListening( pVar->GetBroadcaster(), TRUE ); + pArray->Put( pVar, pArray->Count() ); + if( pVar->GetParent() != this ) + pVar->SetParent( this ); + SetModified( TRUE ); +#ifdef DBG_UTIL + static const char* pCls[] = + { "DontCare","Array","Value","Variable","Method","Property","Object" }; + XubString aVarName( pVar->GetName() ); + if ( !aVarName.Len() && pVar->ISA(SbxObject) ) + aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); + ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); + ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); + DbgOutf( "SBX: Insert %s %s in %s", + ( pVar->GetClass() >= SbxCLASS_DONTCARE && + pVar->GetClass() <= SbxCLASS_OBJECT ) + ? pCls[ pVar->GetClass()-1 ] : "Unknown class", aNameStr1.GetBuffer(), aNameStr1.GetBuffer() ); +#endif + } +} + +// AB 23.3.1997, Spezial-Methode, gleichnamige Controls zulassen +void SbxObject::VCPtrInsert( SbxVariable* pVar ) +{ + SbxArray* pArray = NULL; + if( pVar ) + { + switch( pVar->GetClass() ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: pArray = pProps; break; + case SbxCLASS_METHOD: pArray = pMethods; break; + case SbxCLASS_OBJECT: pArray = pObjs; break; + default: + DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); + } + } + if( pArray ) + { + StartListening( pVar->GetBroadcaster(), TRUE ); + pArray->Put( pVar, pArray->Count() ); + if( pVar->GetParent() != this ) + pVar->SetParent( this ); + SetModified( TRUE ); + Broadcast( SBX_HINT_OBJECTCHANGED ); + } +} + +void SbxObject::Remove( const XubString& rName, SbxClassType t ) +{ + Remove( SbxObject::Find( rName, t ) ); +} + +void SbxObject::Remove( SbxVariable* pVar ) +{ + USHORT nIdx; + SbxArray* pArray = FindVar( pVar, nIdx ); + if( pArray && nIdx < pArray->Count() ) + { +#ifdef DBG_UTIL + XubString aVarName( pVar->GetName() ); + if ( !aVarName.Len() && pVar->ISA(SbxObject) ) + aVarName = PTR_CAST(SbxObject,pVar)->GetClassName(); + ByteString aNameStr1( (const UniString&)aVarName, RTL_TEXTENCODING_ASCII_US ); + ByteString aNameStr2( (const UniString&)SbxVariable::GetName(), RTL_TEXTENCODING_ASCII_US ); +#endif + SbxVariableRef pVar_ = pArray->Get( nIdx ); + if( pVar_->IsBroadcaster() ) + EndListening( pVar_->GetBroadcaster(), TRUE ); + if( (SbxVariable*) pVar_ == pDfltProp ) + pDfltProp = NULL; + pArray->Remove( nIdx ); + if( pVar_->GetParent() == this ) + pVar_->SetParent( NULL ); + SetModified( TRUE ); + Broadcast( SBX_HINT_OBJECTCHANGED ); + } +} + +// AB 23.3.1997, Loeschen per Pointer fuer Controls (doppelte Namen!) +void SbxObject::VCPtrRemove( SbxVariable* pVar ) +{ + USHORT nIdx; + // Neu FindVar-Methode, sonst identisch mit normaler Methode + SbxArray* pArray = VCPtrFindVar( pVar, nIdx ); + if( pArray && nIdx < pArray->Count() ) + { + SbxVariableRef xVar = pArray->Get( nIdx ); + if( xVar->IsBroadcaster() ) + EndListening( xVar->GetBroadcaster(), TRUE ); + if( (SbxVariable*) xVar == pDfltProp ) + pDfltProp = NULL; + pArray->Remove( nIdx ); + if( xVar->GetParent() == this ) + xVar->SetParent( NULL ); + SetModified( TRUE ); + Broadcast( SBX_HINT_OBJECTCHANGED ); + } +} + +// AB 23.3.1997, Zugehoerige Spezial-Methode, nur ueber Pointer suchen +SbxArray* SbxObject::VCPtrFindVar( SbxVariable* pVar, USHORT& nArrayIdx ) +{ + SbxArray* pArray = NULL; + if( pVar ) switch( pVar->GetClass() ) + { + case SbxCLASS_VARIABLE: + case SbxCLASS_PROPERTY: pArray = pProps; break; + case SbxCLASS_METHOD: pArray = pMethods; break; + case SbxCLASS_OBJECT: pArray = pObjs; break; + default: + DBG_ASSERT( !this, "Ungueltige SBX-Klasse" ); + } + if( pArray ) + { + nArrayIdx = pArray->Count(); + for( USHORT i = 0; i < pArray->Count(); i++ ) + { + SbxVariableRef& rRef = pArray->GetRef( i ); + if( (SbxVariable*) rRef == pVar ) + { + nArrayIdx = i; break; + } + } + } + return pArray; +} + + + +void SbxObject::SetPos( SbxVariable* pVar, USHORT nPos ) +{ + USHORT nIdx; + SbxArray* pArray = FindVar( pVar, nIdx ); + if( pArray ) + { + if( nPos >= pArray->Count() ) + nPos = pArray->Count() - 1; + if( nIdx < ( pArray->Count() - 1 ) ) + { + SbxVariableRef refVar = pArray->Get( nIdx ); + pArray->Remove( nIdx ); + pArray->Insert( refVar, nPos ); + } + } +// SetModified( TRUE ); +// Broadcast( SBX_HINT_OBJECTCHANGED ); +} + +static BOOL LoadArray( SvStream& rStrm, SbxObject* pThis, SbxArray* pArray ) +{ + SbxArrayRef p = (SbxArray*) SbxBase::Load( rStrm ); + if( !p.Is() ) + return FALSE; + for( USHORT i = 0; i < p->Count(); i++ ) + { + SbxVariableRef& r = p->GetRef( i ); + SbxVariable* pVar = r; + if( pVar ) + { + pVar->SetParent( pThis ); + pThis->StartListening( pVar->GetBroadcaster(), TRUE ); + } + } + pArray->Merge( p ); + return TRUE; +} + +// Der Load eines Objekts ist additiv! + +BOOL SbxObject::LoadData( SvStream& rStrm, USHORT nVer ) +{ + // Hilfe fuer das Einlesen alter Objekte: einfach TRUE zurueck, + // LoadPrivateData() muss Default-Zustand herstellen + if( !nVer ) + return TRUE; + + pDfltProp = NULL; + if( !SbxVariable::LoadData( rStrm, nVer ) ) + return FALSE; + // Wenn kein fremdes Objekt enthalten ist, uns selbst eintragen + if( aData.eType == SbxOBJECT && !aData.pObj ) + aData.pObj = this; + sal_uInt32 nSize; + XubString aDfltProp; + rStrm.ReadByteString( aClassName, RTL_TEXTENCODING_ASCII_US ); + rStrm.ReadByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US ); + ULONG nPos = rStrm.Tell(); + rStrm >> nSize; + if( !LoadPrivateData( rStrm, nVer ) ) + return FALSE; + ULONG nNewPos = rStrm.Tell(); + nPos += nSize; + DBG_ASSERT( nPos >= nNewPos, "SBX: Zu viele Daten eingelesen" ); + if( nPos != nNewPos ) + rStrm.Seek( nPos ); + if( !LoadArray( rStrm, this, pMethods ) + || !LoadArray( rStrm, this, pProps ) + || !LoadArray( rStrm, this, pObjs ) ) + return FALSE; + // Properties setzen + if( aDfltProp.Len() ) + pDfltProp = (SbxProperty*) pProps->Find( aDfltProp, SbxCLASS_PROPERTY ); + SetModified( FALSE ); + return TRUE; +} + +BOOL SbxObject::StoreData( SvStream& rStrm ) const +{ + if( !SbxVariable::StoreData( rStrm ) ) + return FALSE; + XubString aDfltProp; + if( pDfltProp ) + aDfltProp = pDfltProp->GetName(); + rStrm.WriteByteString( aClassName, RTL_TEXTENCODING_ASCII_US ); + rStrm.WriteByteString( aDfltProp, RTL_TEXTENCODING_ASCII_US ); + ULONG nPos = rStrm.Tell(); + rStrm << (UINT32) 0L; + if( !StorePrivateData( rStrm ) ) + return FALSE; + ULONG nNew = rStrm.Tell(); + rStrm.Seek( nPos ); + rStrm << (UINT32) ( nNew - nPos ); + rStrm.Seek( nNew ); + if( !pMethods->Store( rStrm ) ) + return FALSE; + if( !pProps->Store( rStrm ) ) + return FALSE; + if( !pObjs->Store( rStrm ) ) + return FALSE; + ((SbxObject*) this)->SetModified( FALSE ); + return TRUE; +} + +XubString SbxObject::GenerateSource( const XubString &rLinePrefix, + const SbxObject* ) +{ + // Properties in einem String einsammeln + XubString aSource; + SbxArrayRef xProps( GetProperties() ); + FASTBOOL bLineFeed = FALSE; + for ( USHORT nProp = 0; nProp < xProps->Count(); ++nProp ) + { + SbxPropertyRef xProp = (SbxProperty*) xProps->Get(nProp); + XubString aPropName( xProp->GetName() ); + if ( xProp->CanWrite() + && !( xProp->GetHashCode() == nNameHash + && aPropName.EqualsIgnoreCaseAscii( pNameProp ) ) ) + { + // ausser vor dem ersten Property immer einen Umbruch einfuegen + if ( bLineFeed ) + aSource.AppendAscii( "\n" ); + else + bLineFeed = TRUE; + + aSource += rLinePrefix; + aSource += '.'; + aSource += aPropName; + aSource.AppendAscii( " = " ); + + // den Property-Wert textuell darstellen + switch ( xProp->GetType() ) + { + case SbxEMPTY: + case SbxNULL: + // kein Wert + break; + + case SbxSTRING: + { + // Strings in Anf"uhrungszeichen + aSource.AppendAscii( "\"" ); + aSource += xProp->GetString(); + aSource.AppendAscii( "\"" ); + break; + } + + default: + { + // sonstiges wie z.B. Zahlen direkt + aSource += xProp->GetString(); + break; + } + } + } + } + return aSource; +} + +static BOOL CollectAttrs( const SbxBase* p, XubString& rRes ) +{ + XubString aAttrs; + if( p->IsHidden() ) + aAttrs.AssignAscii( "Hidden" ); + if( p->IsSet( SBX_EXTSEARCH ) ) + { + if( aAttrs.Len() ) + aAttrs += ','; + aAttrs.AppendAscii( "ExtSearch" ); + } + if( !p->IsVisible() ) + { + if( aAttrs.Len() ) + aAttrs += ','; + aAttrs.AppendAscii( "Invisible" ); + } + if( p->IsSet( SBX_DONTSTORE ) ) + { + if( aAttrs.Len() ) + aAttrs += ','; + aAttrs.AppendAscii( "DontStore" ); + } + if( aAttrs.Len() ) + { + rRes.AssignAscii( " (" ); + rRes += aAttrs; + rRes += ')'; + return TRUE; + } + else + { + rRes.Erase(); + return FALSE; + } +} + +void SbxObject::Dump( SvStream& rStrm, BOOL bFill ) +{ + // Einr"uckung + static USHORT nLevel = 0; + if ( nLevel > 10 ) + { + rStrm << "<too deep>" << endl; + return; + } + ++nLevel; + String aIndent; + for ( USHORT n = 1; n < nLevel; ++n ) + aIndent.AppendAscii( " " ); + + // ggf. Objekt vervollst"andigen + if ( bFill ) + GetAll( SbxCLASS_DONTCARE ); + + // Daten des Objekts selbst ausgeben + ByteString aNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US ); + ByteString aClassNameStr( (const UniString&)aClassName, RTL_TEXTENCODING_ASCII_US ); + rStrm << "Object( " + << ByteString::CreateFromInt64( (ULONG) this ).GetBuffer() << "=='" + << ( aNameStr.Len() ? aNameStr.GetBuffer() : "<unnamed>" ) << "', " + << "of class '" << aClassNameStr.GetBuffer() << "', " + << "counts " + << ByteString::CreateFromInt64( GetRefCount() ).GetBuffer() + << " refs, "; + if ( GetParent() ) + { + ByteString aParentNameStr( (const UniString&)GetName(), RTL_TEXTENCODING_ASCII_US ); + rStrm << "in parent " + << ByteString::CreateFromInt64( (ULONG) GetParent() ).GetBuffer() + << "=='" << ( aParentNameStr.Len() ? aParentNameStr.GetBuffer() : "<unnamed>" ) << "'"; + } + else + rStrm << "no parent "; + rStrm << " )" << endl; + ByteString aIndentNameStr( (const UniString&)aIndent, RTL_TEXTENCODING_ASCII_US ); + rStrm << aIndentNameStr.GetBuffer() << "{" << endl; + + // Flags + XubString aAttrs; + if( CollectAttrs( this, aAttrs ) ) + { + ByteString aAttrStr( (const UniString&)aAttrs, RTL_TEXTENCODING_ASCII_US ); + rStrm << aIndentNameStr.GetBuffer() << "- Flags: " << aAttrStr.GetBuffer() << endl; + } + + // Methods + rStrm << aIndentNameStr.GetBuffer() << "- Methods:" << endl; + for( USHORT i = 0; i < pMethods->Count(); i++ ) + { + SbxVariableRef& r = pMethods->GetRef( i ); + SbxVariable* pVar = r; + if( pVar ) + { + XubString aLine( aIndent ); + aLine.AppendAscii( " - " ); + aLine += pVar->GetName( SbxNAME_SHORT_TYPES ); + XubString aAttrs2; + if( CollectAttrs( pVar, aAttrs2 ) ) + aLine += aAttrs2; + if( !pVar->IsA( TYPE(SbxMethod) ) ) + aLine.AppendAscii( " !! Not a Method !!" ); + rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US ); + + // bei Object-Methods auch das Object ausgeben + if ( pVar->GetValues_Impl().eType == SbxOBJECT && + pVar->GetValues_Impl().pObj && + pVar->GetValues_Impl().pObj != this && + pVar->GetValues_Impl().pObj != GetParent() ) + { + rStrm << " contains "; + ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); + } + else + rStrm << endl; + } + } + + // Properties + rStrm << aIndentNameStr.GetBuffer() << "- Properties:" << endl; + { + for( USHORT i = 0; i < pProps->Count(); i++ ) + { + SbxVariableRef& r = pProps->GetRef( i ); + SbxVariable* pVar = r; + if( pVar ) + { + XubString aLine( aIndent ); + aLine.AppendAscii( " - " ); + aLine += pVar->GetName( SbxNAME_SHORT_TYPES ); + XubString aAttrs3; + if( CollectAttrs( pVar, aAttrs3 ) ) + aLine += aAttrs3; + if( !pVar->IsA( TYPE(SbxProperty) ) ) + aLine.AppendAscii( " !! Not a Property !!" ); + rStrm.WriteByteString( aLine, RTL_TEXTENCODING_ASCII_US ); + + // bei Object-Properties auch das Object ausgeben + if ( pVar->GetValues_Impl().eType == SbxOBJECT && + pVar->GetValues_Impl().pObj && + pVar->GetValues_Impl().pObj != this && + pVar->GetValues_Impl().pObj != GetParent() ) + { + rStrm << " contains "; + ((SbxObject*) pVar->GetValues_Impl().pObj)->Dump( rStrm, bFill ); + } + else + rStrm << endl; + } + } + } + + // Objects + rStrm << aIndentNameStr.GetBuffer() << "- Objects:" << endl; + { + for( USHORT i = 0; i < pObjs->Count(); i++ ) + { + SbxVariableRef& r = pObjs->GetRef( i ); + SbxVariable* pVar = r; + if ( pVar ) + { + rStrm << aIndentNameStr.GetBuffer() << " - Sub"; + if ( pVar->ISA(SbxObject) ) + ((SbxObject*) pVar)->Dump( rStrm, bFill ); + else if ( pVar->ISA(SbxVariable) ) + ((SbxVariable*) pVar)->Dump( rStrm, bFill ); + } + } + } + + rStrm << aIndentNameStr.GetBuffer() << "}" << endl << endl; + --nLevel; +} + +SvDispatch* SbxObject::GetSvDispatch() +{ + return NULL; +} + +BOOL SbxMethod::Run( SbxValues* pValues ) +{ + SbxValues aRes; + if( !pValues ) + pValues = &aRes; + pValues->eType = SbxVARIANT; + return Get( *pValues ); +} + +SbxClassType SbxMethod::GetClass() const +{ + return SbxCLASS_METHOD; +} + +SbxClassType SbxProperty::GetClass() const +{ + return SbxCLASS_PROPERTY; +} + +void SbxObject::GarbageCollection( ULONG nObjects ) + +/* [Beschreibung] + + Diese statische Methode durchsucht die n"achsten 'nObjects' der zur Zeit + existierenden <SbxObject>-Instanzen nach zyklischen Referenzen, die sich + nur noch selbst am Leben erhalten. Ist 'nObjects==0', dann werden + alle existierenden durchsucht. + + zur Zeit nur implementiert: Object -> Parent-Property -> Parent -> Object +*/ + +{ + (void)nObjects; + + static BOOL bInGarbageCollection = FALSE; + if ( bInGarbageCollection ) + return; + bInGarbageCollection = TRUE; + +#if 0 + // erstes Object dieser Runde anspringen + BOOL bAll = !nObjects; + if ( bAll ) + rObjects.First(); + SbxObject *pObj = rObjects.GetCurObject(); + if ( !pObj ) + pObj = rObjects.First(); + + while ( pObj && 0 != nObjects-- ) + { + // hat der Parent nur noch 1 Ref-Count? + SbxObject *pParent = PTR_CAST( SbxObject, pObj->GetParent() ); + if ( pParent && 1 == pParent->GetRefCount() ) + { + // dann alle Properies des Objects durchsuchen + SbxArray *pProps = pObj->GetProperties(); + for ( USHORT n = 0; n < pProps->Count(); ++n ) + { + // verweist die Property auf den Parent des Object? + SbxVariable *pProp = pProps->Get(n); + const SbxValues &rValues = pProp->GetValues_Impl(); + if ( SbxOBJECT == rValues.eType && + pParent == rValues.pObj ) + { +#ifdef DBG_UTIL + DbgOutf( "SBX: %s.%s with Object %s was garbage", + pObj->GetName().GetStr(), + pProp->GetName().GetStr(), + pParent->GetName().GetStr() ); +#endif + // dann freigeben + pProp->SbxValue::Clear(); + Sound::Beep(); + break; + } + } + } + + // zum n"achsten + pObj = rObjects.Next(); + if ( !bAll && !pObj ) + pObj = rObjects.First(); + } +#endif + +// AB 28.10. Zur 507a vorerst raus, da SfxBroadcaster::Enable() wegfaellt +#if 0 +#ifdef DBG_UTIL + SbxVarList_Impl &rVars = GetSbxData_Impl()->aVars; + DbgOutf( "SBX: garbage collector done, %lu objects remainding", + rVars.Count() ); + if ( rVars.Count() > 200 && rVars.Count() < 210 ) + { + SvFileStream aStream( "d:\\tmp\\dump.sbx", STREAM_STD_WRITE ); + SfxBroadcaster::Enable(FALSE); + for ( ULONG n = 0; n < rVars.Count(); ++n ) + { + SbxVariable *pVar = rVars.GetObject(n); + SbxObject *pObj = PTR_CAST(SbxObject, pVar); + USHORT nFlags = pVar->GetFlags(); + pVar->SetFlag(SBX_NO_BROADCAST); + if ( pObj ) + pObj->Dump(aStream); + else if ( !pVar->GetParent() || !pVar->GetParent()->ISA(SbxObject) ) + pVar->Dump(aStream); + pVar->SetFlags(nFlags); + } + SfxBroadcaster::Enable(TRUE); + } +#endif +#endif + bInGarbageCollection = FALSE; +} + diff --git a/basic/source/sbx/sbxres.cxx b/basic/source/sbx/sbxres.cxx new file mode 100644 index 000000000000..f42c400afd91 --- /dev/null +++ b/basic/source/sbx/sbxres.cxx @@ -0,0 +1,91 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#include "sbxres.hxx" + +static const char* pSbxRes[] = { + "Empty", + "Null", + "Integer", + "Long", + "Single", + "Double", + "Currency", + "Date", + "String", + "Object", + "Error", + "Boolean", + "Variant", + "Any", + "Type14", + "Type15", + "Char", + "Byte", + "UShort", + "ULong", + "Long64", + "ULong64", + "Int", + "UInt", + "Void", + "HResult", + "Pointer", + "DimArray", + "CArray", + "Any", + "LpStr", + "LpWStr", + " As ", + "Optional ", + "Byref ", + + "Name", + "Parent", + "Application", + "Count", + "Add", + "Item", + "Remove", + + "Error ", // mit Blank! + "False", + "True" +}; + +const char* GetSbxRes( USHORT nId ) +{ + return ( ( nId > SBXRES_MAX ) ? "???" : pSbxRes[ nId ] ); +} + +SbxRes::SbxRes( USHORT nId ) + : XubString( String::CreateFromAscii( GetSbxRes( nId ) ) ) +{} + diff --git a/basic/source/sbx/sbxres.hxx b/basic/source/sbx/sbxres.hxx new file mode 100644 index 000000000000..8cd0ad26e951 --- /dev/null +++ b/basic/source/sbx/sbxres.hxx @@ -0,0 +1,87 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _SBXRES_HXX +#define _SBXRES_HXX + +#include <tools/string.hxx> + +// Zur Zeit sind Ressources im SVTOOLS-Projekt nicht vorgesehen. +// Da es sich um unkritische Ressourcen handelt (BASIC-Keywords), +// koennen wir mit Dummies arbeiten. + +#define STRING_TYPES 0 +#define STRING_EMPTY 0 +#define STRING_NULL 1 +#define STRING_INTEGER 2 +#define STRING_LONG 3 +#define STRING_SINGLE 4 +#define STRING_DOUBLE 5 +#define STRING_CURRENCY 6 +#define STRING_DATE 7 +#define STRING_STRING 8 +#define STRING_OBJECT 9 +#define STRING_ERROR 10 +#define STRING_BOOL 11 +#define STRING_VARIANT 12 +#define STRING_ANY 13 +#define STRING_CHAR 16 +#define STRING_BYTE 17 +#define STRING_USHORT 18 +#define STRING_ULONG 19 +#define STRING_INT 22 +#define STRING_UINT 23 +#define STRING_LPSTR 30 +#define STRING_LPWSTR 31 +#define STRING_AS 32 +#define STRING_OPTIONAL 33 +#define STRING_BYREF 34 + +#define STRING_NAMEPROP 35 +#define STRING_PARENTPROP 36 +#define STRING_APPLPROP 37 +#define STRING_COUNTPROP 38 +#define STRING_ADDMETH 39 +#define STRING_ITEMMETH 40 +#define STRING_REMOVEMETH 41 + +#define STRING_ERRORMSG 42 +#define STRING_FALSE 43 +#define STRING_TRUE 44 + +#define SBXRES_MAX 44 + +class SbxRes : public String +{ +public: + SbxRes( USHORT ); +}; + +const char* GetSbxRes( USHORT ); + + +#endif diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx new file mode 100644 index 000000000000..6d5d24fcb951 --- /dev/null +++ b/basic/source/sbx/sbxscan.cxx @@ -0,0 +1,963 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +#include "unotools/syslocale.hxx" + +#if defined ( UNX ) +#include <stdlib.h> +#endif + +#ifndef _APP_HXX //autogen +#include <vcl/svapp.hxx> +#endif +#include <math.h> +#include <string.h> +#include <ctype.h> + +#include "sbxres.hxx" +#include <basic/sbxbase.hxx> +#include <basic/sbxform.hxx> +#include <svl/svtools.hrc> + +#include "basrid.hxx" +#include "runtime.hxx" + +#include <svl/zforlist.hxx> +#include <comphelper/processfactory.hxx> + + +void ImpGetIntntlSep( sal_Unicode& rcDecimalSep, sal_Unicode& rcThousandSep ) +{ + SvtSysLocale aSysLocale; + const LocaleDataWrapper& rData = aSysLocale.GetLocaleData(); + rcDecimalSep = rData.getNumDecimalSep().GetBuffer()[0]; + rcThousandSep = rData.getNumThousandSep().GetBuffer()[0]; +} + +// Scannen eines Strings nach BASIC-Konventionen +// Dies entspricht den ueblichen Konventionen, nur dass der Exponent +// auch ein D sein darf, was den Datentyp auf SbxDOUBLE festlegt. +// Die Routine versucht, den Datentyp so klein wie moeglich zu gestalten. +// Das ganze gibt auch noch einen Konversionsfehler, wenn der Datentyp +// Fixed ist und das ganze nicht hineinpasst! + +SbxError ImpScan( const XubString& rWSrc, double& nVal, SbxDataType& rType, + USHORT* pLen, BOOL bAllowIntntl, BOOL bOnlyIntntl ) +{ + ByteString aBStr( rWSrc, RTL_TEXTENCODING_ASCII_US ); + + // Bei International Komma besorgen + char cIntntlComma, cIntntl1000; + char cNonIntntlComma = '.'; + + sal_Unicode cDecimalSep, cThousandSep = 0; + if( bAllowIntntl || bOnlyIntntl ) + { + ImpGetIntntlSep( cDecimalSep, cThousandSep ); + cIntntlComma = (char)cDecimalSep; + cIntntl1000 = (char)cThousandSep; + } + // Sonst einfach auch auf . setzen + else + { + cIntntlComma = cNonIntntlComma; + cIntntl1000 = cNonIntntlComma; // Unschaedlich machen + } + // Nur International -> IntnlComma uebernehmen + if( bOnlyIntntl ) + { + cNonIntntlComma = cIntntlComma; + cIntntl1000 = (char)cThousandSep; + } + + const char* pStart = aBStr.GetBuffer(); + const char* p = pStart; + char buf[ 80 ], *q = buf; + BOOL bRes = TRUE; + BOOL bMinus = FALSE; + nVal = 0; + SbxDataType eScanType = SbxSINGLE; + // Whitespace wech + while( *p &&( *p == ' ' || *p == '\t' ) ) p++; + // Zahl? Dann einlesen und konvertieren. + if( *p == '-' ) + p++, bMinus = TRUE; + if( isdigit( *p ) ||( (*p == cNonIntntlComma || *p == cIntntlComma || + *p == cIntntl1000) && isdigit( *(p+1 ) ) ) ) + { + short exp = 0; // >0: Exponentteil + short comma = 0; // >0: Nachkomma + short ndig = 0; // Anzahl Ziffern + short ncdig = 0; // Anzahl Ziffern nach Komma + ByteString aSearchStr( "0123456789DEde" ); + // Kommas ergaenzen + aSearchStr += cNonIntntlComma; + if( cIntntlComma != cNonIntntlComma ) + aSearchStr += cIntntlComma; + if( bOnlyIntntl ) + aSearchStr += cIntntl1000; + const char* pSearchStr = aSearchStr.GetBuffer(); + while( strchr( pSearchStr, *p ) && *p ) + { + // 1000er-Trenner ueberlesen + if( bOnlyIntntl && *p == cIntntl1000 ) + { + p++; + continue; + } + + // Komma oder Exponent? + if( *p == cNonIntntlComma || *p == cIntntlComma ) + { + // Immer '.' einfuegen, damit atof funktioniert + p++; + if( ++comma > 1 ) + continue; + else + *q++ = '.'; + } + else if( strchr( "DdEe", *p ) ) + { + if( ++exp > 1 ) + { + p++; continue; + } + if( toupper( *p ) == 'D' ) + eScanType = SbxDOUBLE; + *q++ = 'E'; p++; + // Vorzeichen hinter Exponent? + if( *p == '+' ) + p++; + else + if( *p == '-' ) + *q++ = *p++; + } + else + { + *q++ = *p++; + if( comma && !exp ) ncdig++; + } + if( !exp ) ndig++; + } + *q = 0; + // Komma, Exponent mehrfach vorhanden? + if( comma > 1 || exp > 1 ) + bRes = FALSE; + // Kann auf Integer gefaltet werden? + if( !comma && !exp ) + { + if( nVal >= SbxMININT && nVal <= SbxMAXINT ) + eScanType = SbxINTEGER; + else if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG ) + eScanType = SbxLONG; + } + + nVal = atof( buf ); + ndig = ndig - comma; + // zu viele Zahlen fuer SINGLE? + if( ndig > 15 || ncdig > 6 ) + eScanType = SbxDOUBLE; + + // Typkennung? + if( strchr( "%!&#", *p ) && *p ) p++; + } + // Hex/Oktalzahl? Einlesen und konvertieren: + else if( *p == '&' ) + { + p++; + eScanType = SbxLONG; + const char *cmp = "0123456789ABCDEF"; + char base = 16; + char ndig = 8; + char xch = *p++; + switch( toupper( xch ) ) + { + case 'O': cmp = "01234567"; base = 8; ndig = 11; break; + case 'H': break; + default : bRes = FALSE; + } + long l = 0; + int i; + while( isalnum( *p ) ) + { + char ch = sal::static_int_cast< char >( toupper( *p ) ); + p++; + if( strchr( cmp, ch ) ) *q++ = ch; + else bRes = FALSE; + } + *q = 0; + for( q = buf; *q; q++ ) + { + i =( *q & 0xFF ) - '0'; + if( i > 9 ) i -= 7; + l =( l * base ) + i; + if( !ndig-- ) + bRes = FALSE; + } + if( *p == '&' ) p++; + nVal = (double) l; + if( l >= SbxMININT && l <= SbxMAXINT ) + eScanType = SbxINTEGER; + } + else if ( SbiRuntime::isVBAEnabled() ) + { + OSL_TRACE("Reporting error converting"); + return SbxERR_CONVERSION; + } + if( pLen ) + *pLen = (USHORT) ( p - pStart ); + if( !bRes ) + return SbxERR_CONVERSION; + if( bMinus ) + nVal = -nVal; + rType = eScanType; + return SbxERR_OK; +} + +// Schnittstelle fuer CDbl im Basic +SbxError SbxValue::ScanNumIntnl( const String& rSrc, double& nVal, BOOL bSingle ) +{ + SbxDataType t; + USHORT nLen = 0; + SbxError nRetError = ImpScan( rSrc, nVal, t, &nLen, + /*bAllowIntntl*/FALSE, /*bOnlyIntntl*/TRUE ); + // Komplett gelesen? + if( nRetError == SbxERR_OK && nLen != rSrc.Len() ) + nRetError = SbxERR_CONVERSION; + + if( bSingle ) + { + SbxValues aValues( nVal ); + nVal = (double)ImpGetSingle( &aValues ); // Hier Error bei Overflow + } + return nRetError; +} + +//////////////////////////////////////////////////////////////////////////// + +static double roundArray[] = { + 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, 0.5e-7, + 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,0.5e-15 }; + +/*************************************************************************** +|* +|* void myftoa( double, char *, short, short, BOOL, BOOL ) +|* +|* Beschreibung: Konversion double --> ASCII +|* Parameter: double die Zahl. +|* char * der Zielpuffer +|* short Anzahl Nachkommastellen +|* short Weite des Exponenten( 0=kein E ) +|* BOOL TRUE: mit 1000er Punkten +|* BOOL TRUE: formatfreie Ausgabe +|* +***************************************************************************/ + +static void myftoa( double nNum, char * pBuf, short nPrec, short nExpWidth, + BOOL bPt, BOOL bFix, sal_Unicode cForceThousandSep = 0 ) +{ + + short nExp = 0; // Exponent + short nDig = nPrec + 1; // Anzahl Digits in Zahl + short nDec; // Anzahl Vorkommastellen + register int i, digit; + + // Komma besorgen + sal_Unicode cDecimalSep, cThousandSep; + ImpGetIntntlSep( cDecimalSep, cThousandSep ); + if( cForceThousandSep ) + cThousandSep = cForceThousandSep; + + // Exponentberechnung: + nExp = 0; + if( nNum > 0.0 ) + { + while( nNum < 1.0 ) nNum *= 10.0, nExp--; + while( nNum >= 10.0 ) nNum /= 10.0, nExp++; + } + if( !bFix && !nExpWidth ) + nDig = nDig + nExp; + else if( bFix && !nPrec ) + nDig = nExp + 1; + + // Zahl runden: + if( (nNum += roundArray [( nDig > 16 ) ? 16 : nDig] ) >= 10.0 ) + { + nNum = 1.0; + ++nExp; + if( !nExpWidth ) ++nDig; + } + + // Bestimmung der Vorkommastellen: + if( !nExpWidth ) + { + if( nExp < 0 ) + { + // #41691: Auch bei bFix eine 0 spendieren + *pBuf++ = '0'; + if( nPrec ) *pBuf++ = (char)cDecimalSep; + i = -nExp - 1; + if( nDig <= 0 ) i = nPrec; + while( i-- ) *pBuf++ = '0'; + nDec = 0; + } + else + nDec = nExp+1; + } + else + nDec = 1; + + // Zahl ausgeben: + if( nDig > 0 ) + { + for( i = 0 ; ; ++i ) + { + if( i < 16 ) + { + digit = (int) nNum; + *pBuf++ = sal::static_int_cast< char >(digit + '0'); + nNum =( nNum - digit ) * 10.0; + } else + *pBuf++ = '0'; + if( --nDig == 0 ) break; + if( nDec ) + { + nDec--; + if( !nDec ) + *pBuf++ = (char)cDecimalSep; + else if( !(nDec % 3 ) && bPt ) + *pBuf++ = (char)cThousandSep; + } + } + } + + // Exponent ausgeben: + if( nExpWidth ) + { + if( nExpWidth < 3 ) nExpWidth = 3; + nExpWidth -= 2; + *pBuf++ = 'E'; + *pBuf++ =( nExp < 0 ) ?( (nExp = -nExp ), '-' ) : '+'; + while( nExpWidth > 3 ) *pBuf++ = '0', nExpWidth--; + if( nExp >= 100 || nExpWidth == 3 ) + { + *pBuf++ = sal::static_int_cast< char >(nExp/100 + '0'); + nExp %= 100; + } + if( nExp/10 || nExpWidth >= 2 ) + *pBuf++ = sal::static_int_cast< char >(nExp/10 + '0'); + *pBuf++ = sal::static_int_cast< char >(nExp%10 + '0'); + } + *pBuf = 0; +} + +// Die Zahl wird unformatiert mit der angegebenen Anzahl NK-Stellen +// aufbereitet. Evtl. wird ein Minus vorangestellt. +// Diese Routine ist public, weil sie auch von den Put-Funktionen +// der Klasse SbxImpSTRING verwendet wird. + +#ifdef _MSC_VER +#pragma optimize( "", off ) +#pragma warning(disable: 4748) // "... because optimizations are disabled ..." +#endif + +void ImpCvtNum( double nNum, short nPrec, XubString& rRes, BOOL bCoreString ) +{ + char *q; + char cBuf[ 40 ], *p = cBuf; + + sal_Unicode cDecimalSep, cThousandSep; + ImpGetIntntlSep( cDecimalSep, cThousandSep ); + if( bCoreString ) + cDecimalSep = '.'; + + if( nNum < 0.0 ) { + nNum = -nNum; + *p++ = '-'; + } + double dMaxNumWithoutExp = (nPrec == 6) ? 1E6 : 1E14; + myftoa( nNum, p, nPrec,( nNum &&( nNum < 1E-1 || nNum > dMaxNumWithoutExp ) ) ? 4:0, + FALSE, TRUE, cDecimalSep ); + // Trailing Zeroes weg: + for( p = cBuf; *p &&( *p != 'E' ); p++ ) {} + q = p; p--; + while( nPrec && *p == '0' ) nPrec--, p--; + if( *p == cDecimalSep ) p--; + while( *q ) *++p = *q++; + *++p = 0; + rRes = String::CreateFromAscii( cBuf ); +} + +#ifdef _MSC_VER +#pragma optimize( "", on ) +#endif + +BOOL ImpConvStringExt( XubString& rSrc, SbxDataType eTargetType ) +{ + // Merken, ob ueberhaupt was geaendert wurde + BOOL bChanged = FALSE; + String aNewString; + + // Nur Spezial-Fälle behandeln, als Default tun wir nichts + switch( eTargetType ) + { + // Bei Fliesskomma International beruecksichtigen + case SbxSINGLE: + case SbxDOUBLE: + case SbxCURRENCY: + { + ByteString aBStr( rSrc, RTL_TEXTENCODING_ASCII_US ); + + // Komma besorgen + sal_Unicode cDecimalSep, cThousandSep; + ImpGetIntntlSep( cDecimalSep, cThousandSep ); + aNewString = rSrc; + + // Ersetzen, wenn DecimalSep kein '.' (nur den ersten) + if( cDecimalSep != (sal_Unicode)'.' ) + { + USHORT nPos = aNewString.Search( cDecimalSep ); + if( nPos != STRING_NOTFOUND ) + { + aNewString.SetChar( nPos, '.' ); + bChanged = TRUE; + } + } + break; + } + + // Bei BOOL TRUE und FALSE als String pruefen + case SbxBOOL: + { + if( rSrc.EqualsIgnoreCaseAscii( "true" ) ) + { + aNewString = String::CreateFromInt32(SbxTRUE); + bChanged = TRUE; + } + else + if( rSrc.EqualsIgnoreCaseAscii( "false" ) ) + { + aNewString = String::CreateFromInt32(SbxFALSE); + bChanged = TRUE; + } + break; + } + default: break; + } + // String bei Aenderung uebernehmen + if( bChanged ) + rSrc = aNewString; + return bChanged; +} + + +// Formatierte Zahlenausgabe +// Der Returnwert ist die Anzahl Zeichen, die aus dem +// Format verwendt wurden. + +#ifdef _old_format_code_ +// lasse diesen Code vorl"aufig drin, zum 'abgucken' +// der bisherigen Implementation + +static USHORT printfmtnum( double nNum, XubString& rRes, const XubString& rWFmt ) +{ + const String& rFmt = rWFmt; + char cFill = ' '; // Fuellzeichen + char cPre = 0; // Startzeichen( evtl. "$" ) + short nExpDig= 0; // Anzahl Exponentstellen + short nPrec = 0; // Anzahl Nachkommastellen + short nWidth = 0; // Zahlenweite gesamnt + short nLen; // Laenge konvertierte Zahl + BOOL bPoint = FALSE; // TRUE: mit 1000er Kommas + BOOL bTrail = FALSE; // TRUE, wenn folgendes Minus + BOOL bSign = FALSE; // TRUE: immer mit Vorzeichen + BOOL bNeg = FALSE; // TRUE: Zahl ist negativ + char cBuf [1024]; // Zahlenpuffer + char * p; + const char* pFmt = rFmt; + rRes.Erase(); + // $$ und ** abfangen. Einfach wird als Zeichen ausgegeben. + if( *pFmt == '$' ) + if( *++pFmt != '$' ) rRes += '$'; + if( *pFmt == '*' ) + if( *++pFmt != '*' ) rRes += '*'; + + switch( *pFmt++ ) + { + case 0: + break; + case '+': + bSign = TRUE; nWidth++; break; + case '*': + nWidth++; cFill = '*'; + if( *pFmt == '$' ) nWidth++, pFmt++, cPre = '$'; + break; + case '$': + nWidth++; cPre = '$'; break; + case '#': + case '.': + case ',': + pFmt--; break; + } + // Vorkomma: + for( ;; ) + { + while( *pFmt == '#' ) pFmt++, nWidth++; + // 1000er Kommas? + if( *pFmt == ',' ) + { + nWidth++; pFmt++; bPoint = TRUE; + } else break; + } + // Nachkomma: + if( *pFmt == '.' ) + { + while( *++pFmt == '#' ) nPrec++; + nWidth += nPrec + 1; + } + // Exponent: + while( *pFmt == '^' ) + pFmt++, nExpDig++, nWidth++; + // Folgendes Minus: + if( !bSign && *pFmt == '-' ) + pFmt++, bTrail = TRUE; + + // Zahl konvertieren: + if( nPrec > 15 ) nPrec = 15; + if( nNum < 0.0 ) nNum = -nNum, bNeg = TRUE; + p = cBuf; + if( bSign ) *p++ = bNeg ? '-' : '+'; + myftoa( nNum, p, nPrec, nExpDig, bPoint, FALSE ); + nLen = strlen( cBuf ); + + // Ueberlauf? + if( cPre ) nLen++; + if( nLen > nWidth ) rRes += '%'; + else { + nWidth -= nLen; + while( nWidth-- ) rRes += (xub_Unicode)cFill; + if( cPre ) rRes += (xub_Unicode)cPre; + } + rRes += (xub_Unicode*)&(cBuf[0]); + if( bTrail ) + rRes += bNeg ? '-' : ' '; + + return (USHORT) ( pFmt - (const char*) rFmt ); +} + +#endif //_old_format_code_ + +static USHORT printfmtstr( const XubString& rStr, XubString& rRes, const XubString& rFmt ) +{ + const xub_Unicode* pStr = rStr.GetBuffer(); + const xub_Unicode* pFmtStart = rFmt.GetBuffer(); + const xub_Unicode* pFmt = pFmtStart; + rRes.Erase(); + switch( *pFmt ) + { + case '!': + rRes += *pStr++; pFmt++; break; + case '\\': + do + { + rRes += *pStr ? *pStr++ : static_cast< xub_Unicode >(' '); + pFmt++; + } while( *pFmt != '\\' ); + rRes += *pStr ? *pStr++ : static_cast< xub_Unicode >(' '); + pFmt++; break; + case '&': + rRes = rStr; + pFmt++; break; + default: + rRes = rStr; + break; + } + return (USHORT) ( pFmt - pFmtStart ); +} + +///////////////////////////////////////////////////////////////////////// + +BOOL SbxValue::Scan( const XubString& rSrc, USHORT* pLen ) +{ + SbxError eRes = SbxERR_OK; + if( !CanWrite() ) + eRes = SbxERR_PROP_READONLY; + else + { + double n; + SbxDataType t; + eRes = ImpScan( rSrc, n, t, pLen ); + if( eRes == SbxERR_OK ) + { + if( !IsFixed() ) + SetType( t ); + PutDouble( n ); + } + } + if( eRes ) + { + SetError( eRes ); return FALSE; + } + else + return TRUE; +} + + +ResMgr* implGetResMgr( void ) +{ + static ResMgr* pResMgr = NULL; + if( !pResMgr ) + { + ::com::sun::star::lang::Locale aLocale = Application::GetSettings().GetUILocale(); + pResMgr = ResMgr::CreateResMgr(CREATEVERSIONRESMGR_NAME(sb), aLocale ); + } + return pResMgr; +} + +class SbxValueFormatResId : public ResId +{ +public: + SbxValueFormatResId( USHORT nId ) + : ResId( nId, *implGetResMgr() ) + {} +}; + + +enum VbaFormatType +{ + VBA_FORMAT_TYPE_OFFSET, // standard number format + VBA_FORMAT_TYPE_USERDEFINED, // user defined number format + VBA_FORMAT_TYPE_NULL +}; + +struct VbaFormatInfo +{ + VbaFormatType meType; + const char* mpVbaFormat; // Format string in vba + NfIndexTableOffset meOffset; // SvNumberFormatter format index, if meType = VBA_FORMAT_TYPE_OFFSET + const char* mpOOoFormat; // if meType = VBA_FORMAT_TYPE_USERDEFINED +}; + +#define VBA_FORMAT_OFFSET( pcUtf8, eOffset ) \ + { VBA_FORMAT_TYPE_OFFSET, pcUtf8, eOffset, 0 } + +#define VBA_FORMAT_USERDEFINED( pcUtf8, pcDefinedUtf8 ) \ + { VBA_FORMAT_TYPE_USERDEFINED, pcUtf8, NF_NUMBER_STANDARD, pcDefinedUtf8 } + +static VbaFormatInfo pFormatInfoTable[] = +{ + VBA_FORMAT_OFFSET( "Long Date", NF_DATE_SYSTEM_LONG ), + VBA_FORMAT_USERDEFINED( "Medium Date", "DD-MMM-YY" ), + VBA_FORMAT_OFFSET( "Short Date", NF_DATE_SYSTEM_SHORT ), + VBA_FORMAT_USERDEFINED( "Long Time", "H:MM:SS AM/PM" ), + VBA_FORMAT_OFFSET( "Medium Time", NF_TIME_HHMMAMPM ), + VBA_FORMAT_OFFSET( "Short Time", NF_TIME_HHMM ), + VBA_FORMAT_OFFSET( "ddddd", NF_DATE_SYSTEM_SHORT ), + VBA_FORMAT_OFFSET( "dddddd", NF_DATE_SYSTEM_LONG ), + VBA_FORMAT_USERDEFINED( "ttttt", "H:MM:SS AM/PM" ), + VBA_FORMAT_OFFSET( "ww", NF_DATE_WW ), + { VBA_FORMAT_TYPE_NULL, 0, NF_INDEX_TABLE_ENTRIES, 0 } +}; + +VbaFormatInfo* getFormatInfo( const String& rFmt ) +{ + VbaFormatInfo* pInfo = NULL; + INT16 i = 0; + while( (pInfo = pFormatInfoTable + i )->mpVbaFormat != NULL ) + { + if( rFmt.EqualsIgnoreCaseAscii( pInfo->mpVbaFormat ) ) + break; + i++; + } + return pInfo; +} + +#define VBAFORMAT_GENERALDATE "General Date" +#define VBAFORMAT_C "c" +#define VBAFORMAT_N "n" +#define VBAFORMAT_NN "nn" +#define VBAFORMAT_W "w" +#define VBAFORMAT_Y "y" +#define VBAFORMAT_LOWERCASE "<" +#define VBAFORMAT_UPPERCASE ">" + +// From methods1.cxx +INT16 implGetWeekDay( double aDate, bool bFirstDayParam = false, INT16 nFirstDay = 0 ); +// from methods.cxx +INT16 implGetMinute( double dDate ); +INT16 implGetDateYear( double aDate ); +BOOL implDateSerial( INT16 nYear, INT16 nMonth, INT16 nDay, double& rdRet ); + +void SbxValue::Format( XubString& rRes, const XubString* pFmt ) const +{ + short nComma = 0; + double d = 0; + + // pflin, It is better to use SvNumberFormatter to handle the date/time/number format. + // the SvNumberFormatter output is mostly compatible with + // VBA output besides the OOo-basic output + if( pFmt && !SbxBasicFormater::isBasicFormat( *pFmt ) ) + { + String aStr = GetString(); + + if( pFmt->EqualsIgnoreCaseAscii( VBAFORMAT_LOWERCASE ) ) + { + rRes = aStr.ToLowerAscii(); + return; + } + if( pFmt->EqualsIgnoreCaseAscii( VBAFORMAT_UPPERCASE ) ) + { + rRes = aStr.ToUpperAscii(); + return; + } + + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > + xFactory = comphelper::getProcessServiceFactory(); + SvNumberFormatter aFormatter( xFactory, eLangType ); + + sal_uInt32 nIndex; + xub_StrLen nCheckPos = 0; + short nType; + double nNumber; + Color* pCol; + + BOOL bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, nNumber ); + + // number format, use SvNumberFormatter to handle it. + if( bSuccess ) + { + String aFmtStr = *pFmt; + VbaFormatInfo* pInfo = getFormatInfo( aFmtStr ); + if( pInfo && pInfo->meType != VBA_FORMAT_TYPE_NULL ) + { + if( pInfo->meType == VBA_FORMAT_TYPE_OFFSET ) + { + nIndex = aFormatter.GetFormatIndex( pInfo->meOffset, eLangType ); + } + else + { + aFmtStr.AssignAscii( pInfo->mpOOoFormat ); + aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType ); + } + aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol ); + } + else if( aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_GENERALDATE ) + || aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_C )) + { + if( nNumber <=-1.0 || nNumber >= 1.0 ) + { + // short date + nIndex = aFormatter.GetFormatIndex( NF_DATE_SYSTEM_SHORT, eLangType ); + aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol ); + + // long time + if( floor( nNumber ) != nNumber ) + { + aFmtStr.AssignAscii( "H:MM:SS AM/PM" ); + aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType ); + String aTime; + aFormatter.GetOutputString( nNumber, nIndex, aTime, &pCol ); + rRes.AppendAscii(" "); + rRes += aTime; + } + } + else + { + // long time only + aFmtStr.AssignAscii( "H:MM:SS AM/PM" ); + aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType ); + aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol ); + } + } + else if( aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_N ) + || aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_NN )) + { + INT32 nMin = implGetMinute( nNumber ); + if( nMin < 10 && aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_NN ) ) + { + // Minute in two digits + sal_Unicode* p = rRes.AllocBuffer( 2 ); + *p++ = '0'; + *p = sal_Unicode( '0' + nMin ); + } + else + { + rRes = String::CreateFromInt32( nMin ); + } + } + else if( aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_W )) + { + INT32 nWeekDay = implGetWeekDay( nNumber ); + rRes = String::CreateFromInt32( nWeekDay ); + } + else if( aFmtStr.EqualsIgnoreCaseAscii( VBAFORMAT_Y )) + { + INT16 nYear = implGetDateYear( nNumber ); + double dBaseDate; + implDateSerial( nYear, 1, 1, dBaseDate ); + INT32 nYear32 = 1 + INT32( nNumber - dBaseDate ); + rRes = String::CreateFromInt32( nYear32 ); + } + else + { + aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType ); + aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol ); + } + + return; + } + } + + SbxDataType eType = GetType(); + switch( eType ) + { + case SbxCHAR: + case SbxBYTE: + case SbxINTEGER: + case SbxUSHORT: + case SbxLONG: + case SbxULONG: + case SbxINT: + case SbxUINT: + case SbxNULL: // #45929 NULL mit durchschummeln + nComma = 0; goto cvt; + case SbxSINGLE: + nComma = 6; goto cvt; + case SbxDOUBLE: + nComma = 14; + + cvt: + if( eType != SbxNULL ) + d = GetDouble(); + + // #45355 weiterer Einsprungpunkt fuer isnumeric-String + cvt2: + if( pFmt ) + { + // hole die 'statischen' Daten f"ur Sbx + SbxAppData* pData = GetSbxData_Impl(); + + LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); + if( pData->pBasicFormater ) + { + if( pData->eBasicFormaterLangType != eLangType ) + { + delete pData->pBasicFormater; + pData->pBasicFormater = NULL; + } + } + pData->eBasicFormaterLangType = eLangType; + + // falls bisher noch kein BasicFormater-Objekt + // existiert, so erzeuge dieses + if( !pData->pBasicFormater ) + { + SvtSysLocale aSysLocale; + const LocaleDataWrapper& rData = aSysLocale.GetLocaleData(); + sal_Unicode cComma = rData.getNumDecimalSep().GetBuffer()[0]; + sal_Unicode c1000 = rData.getNumThousandSep().GetBuffer()[0]; + String aCurrencyStrg = rData.getCurrSymbol(); + + // Initialisierung des Basic-Formater-Hilfsobjekts: + // hole die Resourcen f"ur die vordefinierten Ausgaben + // des Format()-Befehls, z.B. f"ur "On/Off". + String aOnStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_ON ) ); + String aOffStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_OFF) ); + String aYesStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_YES) ); + String aNoStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_NO) ); + String aTrueStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_TRUE) ); + String aFalseStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_FALSE) ); + String aCurrencyFormatStrg = String( SbxValueFormatResId( + STR_BASICKEY_FORMAT_CURRENCY) ); + // erzeuge das Basic-Formater-Objekt + pData->pBasicFormater + = new SbxBasicFormater( cComma,c1000,aOnStrg,aOffStrg, + aYesStrg,aNoStrg,aTrueStrg,aFalseStrg, + aCurrencyStrg,aCurrencyFormatStrg ); + } + // Bem.: Aus Performance-Gr"unden wird nur EIN BasicFormater- + // Objekt erzeugt und 'gespeichert', dadurch erspart man + // sich das teure Resourcen-Laden (f"ur landesspezifische + // vordefinierte Ausgaben, z.B. "On/Off") und die st"andige + // String-Erzeugungs Operationen. + // ABER: dadurch ist dieser Code NICHT multithreading f"ahig ! + + // hier gibt es Probleme mit ;;;Null, da diese Methode nur aufgerufen + // wird, wenn der SbxValue eine Zahl ist !!! + // dazu koennte: pData->pBasicFormater->BasicFormatNull( *pFmt ); aufgerufen werden ! + if( eType != SbxNULL ) + { + rRes = pData->pBasicFormater->BasicFormat( d ,*pFmt ); + } + else + { + rRes = pData->pBasicFormater->BasicFormatNull( *pFmt ); + } + + // Die alte Implementierung: + //old: printfmtnum( GetDouble(), rRes, *pFmt ); + } + else + ImpCvtNum( GetDouble(), nComma, rRes ); + break; + case SbxSTRING: + if( pFmt ) + { + // #45355 wenn es numerisch ist, muss gewandelt werden + if( IsNumericRTL() ) + { + ScanNumIntnl( GetString(), d, /*bSingle*/FALSE ); + goto cvt2; + } + else + { + // Sonst String-Formatierung + printfmtstr( GetString(), rRes, *pFmt ); + } + } + else + rRes = GetString(); + break; + default: + rRes = GetString(); + } +} + + diff --git a/basic/source/sbx/sbxsng.cxx b/basic/source/sbx/sbxsng.cxx new file mode 100644 index 000000000000..82507dbe15e9 --- /dev/null +++ b/basic/source/sbx/sbxsng.cxx @@ -0,0 +1,359 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +float ImpGetSingle( const SbxValues* p ) +{ + SbxValues aTmp; + float nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + nRes = p->nInteger; break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; break; + case SbxLONG: + nRes = (float) p->nLong; break; + case SbxULONG: + nRes = (float) p->nULong; break; + case SbxSINGLE: + nRes = p->nSingle; break; + case SbxSALINT64: + nRes = (float) p->nInt64; break; + case SbxSALUINT64: + nRes = (float) ImpSalUInt64ToDouble( p->uInt64 ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + if( p->pDecimal ) + p->pDecimal->getSingle( nRes ); + else + nRes = 0.0; + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else + dVal = p->nDouble; + + if( dVal > SbxMAXSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + nRes = static_cast< float >(SbxMAXSNG); + } + else if( dVal < SbxMINSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + nRes = static_cast< float >(SbxMINSNG); + } + else if( dVal > 0 && dVal < SbxMAXSNG2 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + nRes = static_cast< float >(SbxMAXSNG2); + } + else if( dVal < 0 && dVal > SbxMINSNG2 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + nRes = static_cast< float >(SbxMINSNG2); + } + else + nRes = (float) dVal; + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + nRes = static_cast< float >(SbxMAXSNG); + } + else if( d < SbxMINSNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); + nRes = static_cast< float >(SbxMINSNG); + } + else + nRes = (float) d; + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetSingle(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxCHAR: + nRes = *p->pChar; break; + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + nRes = *p->pInteger; break; + case SbxBYREF | SbxLONG: + nRes = (float) *p->pLong; break; + case SbxBYREF | SbxULONG: + nRes = (float) *p->pULong; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = *p->pUShort; break; + case SbxBYREF | SbxSINGLE: + nRes = *p->pSingle; break; + // ab hier muss getestet werden + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxSALINT64: + nRes = (float) *p->pnInt64; break; + case SbxBYREF | SbxSALUINT64: + nRes = (float) ImpSalUInt64ToDouble( *p->puInt64 ); break; + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutSingle( SbxValues* p, float n ) +{ + SbxValues aTmp; +start: + switch( +p->eType ) + { + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxLONG: + aTmp.pLong = &p->nLong; goto direct; + case SbxULONG: + aTmp.pULong = &p->nULong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + case SbxSALINT64: + aTmp.pnInt64 = &p->nInt64; goto direct; + case SbxSALUINT64: + aTmp.puInt64 = &p->uInt64; goto direct; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + SbxDecimal* pDec = ImpCreateDecimal( p ); + if( !pDec->setSingle( n ) ) + SbxBase::SetError( SbxERR_OVERFLOW ); + break; + } + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + // keine Tests ab hier + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + { + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 6, *p->pString ); + break; + } + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutSingle( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + else if( n < SbxMINCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMINCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + else if( n < SbxMININT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMININT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = 0; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + { + INT32 i; + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); i = SbxMAXLNG; + } + else if( n < SbxMINLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); i = SbxMINLNG; + } + else + { + i = sal::static_int_cast< INT32 >(n); + } + *p->pLong = i; break; + } + case SbxBYREF | SbxULONG: + { + UINT32 i; + if( n > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); i = SbxMAXULNG; + } + else if( n < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); i = 0; + } + else + { + i = sal::static_int_cast< UINT32 >(n); + } + *p->pULong = i; break; + } + case SbxBYREF | SbxSINGLE: + *p->pSingle = n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = (double) n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = ImpDoubleToSalInt64( (double) n ); break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = ImpDoubleToSalUInt64( (double) n ); break; + case SbxBYREF | SbxCURRENCY: + double d; + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); d = SbxMAXCURR; + } + else if( n < SbxMINCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); d = SbxMINCURR; + } + else + { + d = n; + } + *p->pLong64 = ImpDoubleToCurrency( n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxstr.cxx b/basic/source/sbx/sbxstr.cxx new file mode 100644 index 000000000000..6deb2da29ba1 --- /dev/null +++ b/basic/source/sbx/sbxstr.cxx @@ -0,0 +1,321 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" +#include "sbxres.hxx" +#include "runtime.hxx" +#ifndef _RTL_USTRBUF_HXX_ +#include <rtl/ustrbuf.hxx> +#endif +// AB 29.10.99 Unicode +#ifndef _USE_NO_NAMESPACE +using namespace rtl; +#endif + + +// Die Konversion eines Items auf String wird ueber die Put-Methoden +// der einzelnen Datentypen abgewickelt, um doppelten Code zu vermeiden. + +XubString ImpGetString( const SbxValues* p ) +{ + SbxValues aTmp; + XubString aRes; + aTmp.eType = SbxSTRING; + aTmp.pString = &aRes; + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + break; + case SbxCHAR: + ImpPutChar( &aTmp, p->nChar ); break; + case SbxBYTE: + ImpPutByte( &aTmp, p->nByte ); break; + case SbxINTEGER: + ImpPutInteger( &aTmp, p->nInteger ); break; + case SbxBOOL: + ImpPutBool( &aTmp, p->nUShort ); break; + case SbxUSHORT: + ImpPutUShort( &aTmp, p->nUShort ); break; + case SbxLONG: + ImpPutLong( &aTmp, p->nLong ); break; + case SbxULONG: + ImpPutULong( &aTmp, p->nULong ); break; + case SbxSINGLE: + ImpPutSingle( &aTmp, p->nSingle ); break; + case SbxDOUBLE: + ImpPutDouble( &aTmp, p->nDouble ); break; + case SbxCURRENCY: + ImpPutCurrency( &aTmp, p->nLong64 ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpPutDecimal( &aTmp, p->pDecimal ); break; + case SbxSALINT64: + ImpPutInt64( &aTmp, p->nInt64 ); break; + case SbxSALUINT64: + ImpPutUInt64( &aTmp, p->uInt64 ); break; + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( p->pString ) + aRes = *p->pString; + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + aRes = pVal->GetString(); + else if( p->pObj && p->pObj->IsFixed() + && (p->pObj->GetType() == (SbxARRAY | SbxBYTE )) ) + { + // convert byte array to string + SbxArray* pArr = PTR_CAST(SbxArray, p->pObj); + if( pArr ) + aRes = ByteArrayToString( pArr ); + } + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxERROR: + // Hier wird der String "Error n" erzeugt + aRes = SbxRes( STRING_ERRORMSG ); + aRes += p->nUShort; break; + case SbxDATE: + ImpPutDate( &aTmp, p->nDouble ); break; + + case SbxBYREF | SbxCHAR: + ImpPutChar( &aTmp, *p->pChar ); break; + case SbxBYREF | SbxBYTE: + ImpPutByte( &aTmp, *p->pByte ); break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + ImpPutInteger( &aTmp, *p->pInteger ); break; + case SbxBYREF | SbxLONG: + ImpPutLong( &aTmp, *p->pLong ); break; + case SbxBYREF | SbxULONG: + ImpPutULong( &aTmp, *p->pULong ); break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + ImpPutUShort( &aTmp, *p->pUShort ); break; + case SbxBYREF | SbxSINGLE: + ImpPutSingle( &aTmp, *p->pSingle ); break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + ImpPutDouble( &aTmp, *p->pDouble ); break; + case SbxBYREF | SbxCURRENCY: + ImpPutCurrency( &aTmp, *p->pLong64 ); break; + case SbxBYREF | SbxSALINT64: + ImpPutInt64( &aTmp, *p->pnInt64 ); break; + case SbxBYREF | SbxSALUINT64: + ImpPutUInt64( &aTmp, *p->puInt64 ); break; + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } + return aRes; +} + +// AB 10.4.97, neue Funktion fuer SbxValue::GetCoreString() +XubString ImpGetCoreString( const SbxValues* p ) +{ + // Vorerst nur fuer double + if( ( p->eType & (~SbxBYREF) ) == SbxDOUBLE ) + { + SbxValues aTmp; + XubString aRes; + aTmp.eType = SbxSTRING; + aTmp.pString = &aRes; + if( p->eType == SbxDOUBLE ) + ImpPutDouble( &aTmp, p->nDouble, /*bCoreString=*/TRUE ); + else + ImpPutDouble( &aTmp, *p->pDouble, /*bCoreString=*/TRUE ); + return aRes; + } + else + return ImpGetString( p ); +} + +void ImpPutString( SbxValues* p, const XubString* n ) +{ + SbxValues aTmp; + aTmp.eType = SbxSTRING; + XubString* pTmp = NULL; + // Sicherheitshalber, falls ein NULL-Ptr kommt + if( !n ) + n = pTmp = new XubString; + aTmp.pString = (XubString*) n; + switch( +p->eType ) + { + case SbxCHAR: + p->nChar = ImpGetChar( &aTmp ); break; + case SbxBYTE: + p->nByte = ImpGetByte( &aTmp ); break; + case SbxINTEGER: + case SbxBOOL: + p->nInteger = ImpGetInteger( &aTmp ); break; + case SbxLONG: + p->nLong = ImpGetLong( &aTmp ); break; + case SbxULONG: + p->nULong = ImpGetULong( &aTmp ); break; + case SbxERROR: + case SbxUSHORT: + p->nUShort = ImpGetUShort( &aTmp ); break; + case SbxSINGLE: + p->nSingle = ImpGetSingle( &aTmp ); break; + case SbxDATE: + p->nDouble = ImpGetDate( &aTmp ); break; + case SbxDOUBLE: + p->nDouble = ImpGetDouble( &aTmp ); break; + case SbxULONG64: + p->nLong64 = ImpGetCurrency( &aTmp ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + releaseDecimalPtr( p->pDecimal ); + p->pDecimal = ImpGetDecimal( &aTmp ); break; + case SbxSALINT64: + p->nInt64 = ImpGetInt64( &aTmp ); break; + case SbxSALUINT64: + p->uInt64 = ImpGetUInt64( &aTmp ); break; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( n->Len() ) + { + if( !p->pString ) + p->pString = new XubString; + *p->pString = *n; + } + else + delete p->pString, p->pString = NULL; + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutString( *n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + *p->pChar = ImpGetChar( p ); break; + case SbxBYREF | SbxBYTE: + *p->pByte = ImpGetByte( p ); break; + case SbxBYREF | SbxINTEGER: + *p->pInteger = ImpGetInteger( p ); break; + case SbxBYREF | SbxBOOL: + *p->pUShort = sal::static_int_cast< UINT16 >( ImpGetBool( p ) ); + break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + *p->pUShort = ImpGetUShort( p ); break; + case SbxBYREF | SbxLONG: + *p->pLong = ImpGetLong( p ); break; + case SbxBYREF | SbxULONG: + *p->pULong = ImpGetULong( p ); break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = ImpGetSingle( p ); break; + case SbxBYREF | SbxDATE: + *p->pDouble = ImpGetDate( p ); break; + case SbxBYREF | SbxDOUBLE: + *p->pDouble = ImpGetDouble( p ); break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = ImpGetCurrency( p ); break; + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } + delete pTmp; +} + +// Convert string to an array of bytes, preserving unicode (2bytes per character) +SbxArray* StringToByteArray(const String& rStr) +{ + USHORT nArraySize = rStr.Len() * 2; + const sal_Unicode* pSrc = rStr.GetBuffer(); + SbxDimArray* pArray = new SbxDimArray(SbxBYTE); + bool bIncIndex = ( IsBaseIndexOne() && SbiRuntime::isVBAEnabled() ); + if( nArraySize ) + { + if( bIncIndex ) + pArray->AddDim( 1, nArraySize ); + else + pArray->AddDim( 0, nArraySize-1 ); + } + else + { + pArray->unoAddDim( 0, -1 ); + } + + for( USHORT i=0; i< nArraySize; i++) + { + SbxVariable* pNew = new SbxVariable( SbxBYTE ); + BYTE aByte = static_cast< BYTE >( i%2 ? ((*pSrc) >> 8) & 0xff : (*pSrc) & 0xff ); + pNew->PutByte( aByte ); + pNew->SetFlag( SBX_WRITE ); + pArray->Put( pNew, i ); + if( i%2 ) + pSrc++; + } + return pArray; +} + +// Convert an array of bytes to string (2bytes per character) +String ByteArrayToString(SbxArray* pArr) +{ + USHORT nCount = pArr->Count(); + OUStringBuffer aStrBuf; + sal_Unicode aChar = 0; + for( USHORT i = 0 ; i < nCount ; i++ ) + { + sal_Unicode aTempChar = pArr->Get(i)->GetByte(); + if( i%2 ) + { + aChar = (aTempChar << 8 ) | aChar; + aStrBuf.append(aChar); + aChar = 0; + } + else + { + aChar = aTempChar; + } + } + + if( nCount%2 ) + { + aStrBuf.append(aChar); + } + + String aStr(aStrBuf.makeStringAndClear()); + + return aStr; +} diff --git a/basic/source/sbx/sbxuint.cxx b/basic/source/sbx/sbxuint.cxx new file mode 100644 index 000000000000..ce0aea70b062 --- /dev/null +++ b/basic/source/sbx/sbxuint.cxx @@ -0,0 +1,331 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +UINT16 ImpGetUShort( const SbxValues* p ) +{ + SbxValues aTmp; + UINT16 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; + break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + if( p->nInteger < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = p->nInteger; + break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; + break; + case SbxLONG: + if( p->nLong > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else if( p->nLong < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT16) p->nLong; + break; + case SbxULONG: + if( p->nULong > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else + nRes = (UINT16) p->nULong; + break; + case SbxSALINT64: + if( p->nInt64 > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else if( p->nInt64 < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT16) p->nInt64; + break; + case SbxSALUINT64: + if( p->uInt64 > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else + nRes = (UINT16) p->uInt64; + break; + case SbxSINGLE: + if( p->nSingle > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else if( p->nSingle < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT16) ( p->nSingle + 0.5 ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else if( dVal < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT16) ( dVal + 0.5 ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXUINT; + } + else if( d < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT16) ( d + 0.5 ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetUShort(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = *p->pUShort; break; + + // ab hier wird getestet + case SbxBYREF | SbxCHAR: + aTmp.nChar = *p->pChar; goto ref; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + aTmp.nInteger = *p->pInteger; goto ref; + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxULONG: + aTmp.nULong = *p->pULong; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutUShort( SbxValues* p, UINT16 n ) +{ + SbxValues aTmp; + +start: + switch( +p->eType ) + { + case SbxERROR: + case SbxUSHORT: + p->nUShort = n; break; + case SbxLONG: + p->nLong = n; break; + case SbxULONG: + p->nULong = n; break; + case SbxSINGLE: + p->nSingle = n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSALUINT64: + p->uInt64 = n; break; + case SbxULONG64: + p->nULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxLONG64: + p->nLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxCURRENCY: + p->nLong64 = ImpDoubleToCurrency( (double)n ); break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setUInt( n ); + break; + + // Tests ab hier + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxBYTE: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 0, *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutUShort( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + + case SbxBYREF | SbxCHAR: + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + *p->pUShort = n; break; + case SbxBYREF | SbxLONG: + *p->pLong = n; break; + case SbxBYREF | SbxULONG: + *p->pULong = n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxULONG64: + *p->pULong64 = ImpDoubleToUINT64( (double)n ); break; + case SbxBYREF | SbxLONG64: + *p->pLong64 = ImpDoubleToINT64( (double)n ); break; + case SbxBYREF | SbxCURRENCY: + *p->pLong64 = ImpDoubleToCurrency( (double)n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxulng.cxx b/basic/source/sbx/sbxulng.cxx new file mode 100644 index 000000000000..3dd81b8c616d --- /dev/null +++ b/basic/source/sbx/sbxulng.cxx @@ -0,0 +1,321 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" +#include <tools/errcode.hxx> +#include <basic/sbx.hxx> +#include "sbxconv.hxx" + +UINT32 ImpGetULong( const SbxValues* p ) +{ + SbxValues aTmp; + UINT32 nRes; +start: + switch( +p->eType ) + { + case SbxNULL: + SbxBase::SetError( SbxERR_CONVERSION ); + case SbxEMPTY: + nRes = 0; break; + case SbxCHAR: + nRes = p->nChar; + break; + case SbxBYTE: + nRes = p->nByte; break; + case SbxINTEGER: + case SbxBOOL: + if( p->nInteger < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = p->nInteger; + break; + case SbxERROR: + case SbxUSHORT: + nRes = p->nUShort; + break; + case SbxLONG: + if( p->nLong < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = p->nLong; + break; + case SbxULONG: + nRes = p->nULong; break; + case SbxSINGLE: + if( p->nSingle > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXULNG; + } + else if( p->nSingle < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT32) ( p->nSingle + 0.5 ); + break; + case SbxDATE: + case SbxDOUBLE: + case SbxLONG64: + case SbxULONG64: + case SbxSALINT64: + case SbxSALUINT64: + case SbxCURRENCY: + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + { + double dVal; + if( p->eType == SbxCURRENCY ) + dVal = ImpCurrencyToDouble( p->nLong64 ); + else if( p->eType == SbxLONG64 ) + dVal = ImpINT64ToDouble( p->nLong64 ); + else if( p->eType == SbxULONG64 ) + dVal = ImpUINT64ToDouble( p->nULong64 ); + else if( p->eType == SbxSALINT64 ) + dVal = static_cast< double >(p->nInt64); + else if( p->eType == SbxSALUINT64 ) + dVal = ImpSalUInt64ToDouble( p->uInt64 ); + else if( p->eType == SbxDECIMAL ) + { + dVal = 0.0; + if( p->pDecimal ) + p->pDecimal->getDouble( dVal ); + } + else + dVal = p->nDouble; + + if( dVal > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXULNG; + } + else if( dVal < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT32) ( dVal + 0.5 ); + break; + } + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + nRes = 0; + else + { + double d; + SbxDataType t; + if( ImpScan( *p->pString, d, t, NULL ) != SbxERR_OK ) + nRes = 0; + else if( d > SbxMAXULNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = SbxMAXULNG; + } + else if( d < 0 ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); nRes = 0; + } + else + nRes = (UINT32) ( d + 0.5 ); + } + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + nRes = pVal->GetULong(); + else + { + SbxBase::SetError( SbxERR_NO_OBJECT ); nRes = 0; + } + break; + } + + case SbxBYREF | SbxBYTE: + nRes = *p->pByte; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + nRes = *p->pUShort; break; + case SbxBYREF | SbxULONG: + nRes = *p->pULong; break; + + // Tests ab hier + case SbxBYREF | SbxCHAR: + aTmp.nChar = *p->pChar; goto ref; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + aTmp.nInteger = *p->pInteger; goto ref; + case SbxBYREF | SbxLONG: + aTmp.nLong = *p->pLong; goto ref; + case SbxBYREF | SbxSINGLE: + aTmp.nSingle = *p->pSingle; goto ref; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + aTmp.nDouble = *p->pDouble; goto ref; + case SbxBYREF | SbxSALINT64: + aTmp.nInt64 = *p->pnInt64; goto ref; + case SbxBYREF | SbxSALUINT64: + aTmp.uInt64 = *p->puInt64; goto ref; + case SbxBYREF | SbxULONG64: + aTmp.nULong64 = *p->pULong64; goto ref; + case SbxBYREF | SbxLONG64: + case SbxBYREF | SbxCURRENCY: + aTmp.nLong64 = *p->pLong64; goto ref; + ref: + aTmp.eType = SbxDataType( p->eType & 0x0FFF ); + p = &aTmp; goto start; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); nRes = 0; + } + return nRes; +} + +void ImpPutULong( SbxValues* p, UINT32 n ) +{ + SbxValues aTmp; +start: + switch( +p->eType ) + { + case SbxULONG: + p->nULong = n; break; + case SbxSINGLE: + p->nSingle = (float) n; break; + case SbxDATE: + case SbxDOUBLE: + p->nDouble = n; break; + case SbxSALINT64: + p->nInt64 = n; break; + case SbxSALUINT64: + p->uInt64 = n; break; + case SbxDECIMAL: + case SbxBYREF | SbxDECIMAL: + ImpCreateDecimal( p )->setULong( n ); + break; + + // Tests ab hier + case SbxCHAR: + aTmp.pChar = &p->nChar; goto direct; + case SbxUINT: + aTmp.pByte = &p->nByte; goto direct; + case SbxINTEGER: + case SbxBOOL: + aTmp.pInteger = &p->nInteger; goto direct; + case SbxLONG: + aTmp.pLong = &p->nLong; goto direct; + case SbxERROR: + case SbxUSHORT: + aTmp.pUShort = &p->nUShort; goto direct; + case SbxULONG64: + aTmp.pULong64 = &p->nULong64; goto direct; + case SbxLONG64: + case SbxCURRENCY: + aTmp.pLong64 = &p->nLong64; goto direct; + direct: + aTmp.eType = SbxDataType( p->eType | SbxBYREF ); + p = &aTmp; goto start; + + case SbxBYREF | SbxSTRING: + case SbxSTRING: + case SbxLPSTR: + if( !p->pString ) + p->pString = new XubString; + ImpCvtNum( (double) n, 0, *p->pString ); + break; + case SbxOBJECT: + { + SbxValue* pVal = PTR_CAST(SbxValue,p->pObj); + if( pVal ) + pVal->PutULong( n ); + else + SbxBase::SetError( SbxERR_NO_OBJECT ); + break; + } + case SbxBYREF | SbxCHAR: + if( n > SbxMAXCHAR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXCHAR; + } + *p->pChar = (xub_Unicode) n; break; + case SbxBYREF | SbxBYTE: + if( n > SbxMAXBYTE ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXBYTE; + } + *p->pByte = (BYTE) n; break; + case SbxBYREF | SbxINTEGER: + case SbxBYREF | SbxBOOL: + if( n > SbxMAXINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXINT; + } + *p->pInteger = (INT16) n; break; + case SbxBYREF | SbxERROR: + case SbxBYREF | SbxUSHORT: + if( n > SbxMAXUINT ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXUINT; + } + *p->pUShort = (UINT16) n; break; + case SbxBYREF | SbxLONG: + if( n > SbxMAXLNG ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); n = SbxMAXLNG; + } + *p->pLong = (INT32) n; break; + case SbxBYREF | SbxULONG: + *p->pULong = n; break; + case SbxBYREF | SbxSINGLE: + *p->pSingle = (float) n; break; + case SbxBYREF | SbxDATE: + case SbxBYREF | SbxDOUBLE: + *p->pDouble = n; break; + case SbxBYREF | SbxSALINT64: + *p->pnInt64 = n; break; + case SbxBYREF | SbxSALUINT64: + *p->puInt64 = n; break; + case SbxBYREF | SbxCURRENCY: + double d; + if( n > SbxMAXCURR ) + { + SbxBase::SetError( SbxERR_OVERFLOW ); d = SbxMAXCURR; + } + else + { + d = n; + } + *p->pLong64 = ImpDoubleToCurrency( n ); break; + + default: + SbxBase::SetError( SbxERR_CONVERSION ); + } +} + diff --git a/basic/source/sbx/sbxvals.cxx b/basic/source/sbx/sbxvals.cxx new file mode 100644 index 000000000000..e63a352879ed --- /dev/null +++ b/basic/source/sbx/sbxvals.cxx @@ -0,0 +1,109 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + +#define _TLBIGINT_INT64 +#include <tools/bigint.hxx> +#include <basic/sbx.hxx> + +///////////////////////////// BigInt/Currency ////////////////////////////// + +SbxValues::SbxValues( const BigInt &rBig ) : eType(SbxCURRENCY) +{ + rBig.INT64( &nLong64 ); +} + +//TODO: BigInt is TOOLS_DLLPUBLIC, and its four member functions only declared +// and defined within basic (#define _TLBIGINT_INT64) are a bad hack that causes +// "warning C4273: 'function' : inconsistent dll linkage" on MSC; this whole +// mess should be cleaned up properly (e.g., by completely removing Sbx[U]INT64 +// and using sal_[u]Int64 instead): +#if defined _MSC_VER +#pragma warning(disable: 4273) +#endif + +BOOL BigInt::INT64( SbxINT64 *p ) const +{ + if( bIsBig ) { + if( nLen > 4 || (nNum[3] & 0x8000) ) + return FALSE; + + p->nLow = ((UINT32)nNum[1] << 16) | (UINT32)nNum[0]; + p->nHigh = ((UINT32)nNum[3] << 16) | (UINT32)nNum[2]; + if( bIsNeg ) + p->CHS(); + } + else + p->Set( (INT32)nVal ); + + return TRUE; +} + +BigInt::BigInt( const SbxINT64 &r ) +{ + BigInt a10000 = 0x10000; + + *this = r.nHigh; + if( r.nHigh ) + *this *= a10000; + *this += (USHORT)(r.nLow >> 16); + *this *= a10000; + *this += (USHORT)r.nLow; +} + +BOOL BigInt::UINT64( SbxUINT64 *p ) const +{ + if( bIsBig ) { + if( bIsNeg || nLen > 4 ) + return FALSE; + + p->nLow = ((UINT32)nNum[1] << 16) | (UINT32)nNum[0]; + p->nHigh = ((UINT32)nNum[3] << 16) | (UINT32)nNum[2]; + } + else { + if( nVal < 0 ) + return FALSE; + + p->Set( (UINT32)nVal ); + } + + return TRUE; +} + +BigInt::BigInt( const SbxUINT64 &r ) +{ + BigInt a10000 = 0x10000; + + *this = BigInt(r.nHigh); + if( r.nHigh ) + *this *= a10000; + *this += (USHORT)(r.nLow >> 16); + *this *= a10000; + *this += (USHORT)r.nLow; +} diff --git a/basic/source/sbx/sbxvalue.cxx b/basic/source/sbx/sbxvalue.cxx new file mode 100644 index 000000000000..7ee31af70556 --- /dev/null +++ b/basic/source/sbx/sbxvalue.cxx @@ -0,0 +1,1851 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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 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 = (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 = (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.pString = (XubString*) p; break; + case SbxERROR: + case SbxUSHORT: + case SbxBOOL: n |= SbxBYREF; aData.pUShort = (UINT16*) p; break; + case SbxULONG: n |= SbxBYREF; aData.pULong = (UINT32*) p; break; + case SbxCHAR: n |= SbxBYREF; aData.pChar = (xub_Unicode*) p; break; + case SbxBYTE: n |= SbxBYREF; aData.pByte = (BYTE*) 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.pString ) + aData.pString = new XubString( *aData.pString ); + 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) ) + { + String 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 ) + { + String 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); + BOOL bParentProp = pThisVar && 5345 == + ( (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.pString; aData.pString = NULL; + break; + case SbxOBJECT: + if( aData.pObj ) + { + if( aData.pObj != this ) + { + HACK(nicht bei Parent-Prop - sonst CyclicRef) + SbxVariable *pThisVar = PTR_CAST(SbxVariable, this); + BOOL bParentProp = pThisVar && 5345 == + ( (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( ULONG ) +{} + +//////////////////////////// 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( TRUE ); +} + +// #55226 Zusaetzliche Info transportieren +SbxValue* SbxValue::TheRealValue( 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 ) + { + 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; +} + +BOOL SbxValue::Get( SbxValues& rRes ) const +{ + BOOL bRes = 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< 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.pString = &p->aPic; break; + case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData ); + rRes.pString = &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 = TRUE; + if( eOld != SbxERR_OK ) + SetError( eOld ); + } + return bRes; +} + +BOOL SbxValue::GetNoBroadcast( SbxValues& rRes ) +{ + USHORT nFlags_ = GetFlags(); + SetFlag( SBX_NO_BROADCAST ); + BOOL bRes = Get( rRes ); + SetFlags( nFlags_ ); + return bRes; +} + +const XubString& SbxValue::GetString() const +{ + SbxValues aRes; + aRes.eType = SbxSTRING; + if( Get( aRes ) ) + // Geht in Ordnung, da Ptr eine Kopie ist + return *aRes.pString; + else + { + ((SbxValue*) this)->aPic.Erase(); + return aPic; + } +} + +const XubString& SbxValue::GetCoreString() const +{ + SbxValues aRes; + aRes.eType = SbxCoreSTRING; + if( Get( aRes ) ) + // Geht in Ordnung, da Ptr eine Kopie ist + return *aRes.pString; + else + { + ((SbxValue*) this)->aPic.Erase(); + return aPic; + } +} + +BOOL SbxValue::HasObject() const +{ + ErrCode eErr = GetError(); + SbxValues aRes; + aRes.eType = SbxOBJECT; + Get( aRes ); + SetError( eErr ); + return 0 != aRes.pObj; +} + +BOOL SbxValue::GetBool() const +{ + SbxValues aRes; + aRes.eType = SbxBOOL; + Get( aRes ); + return 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, BYTE, 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, UINT16, nUShort ) +GET( GetInt, SbxINT, int, nInt ) +GET( GetInteger, SbxINTEGER, INT16, nInteger ) +GET( GetLong, SbxLONG, INT32, nLong ) +GET( GetLong64, SbxLONG64, SbxINT64, nLong64 ) +GET( GetObject, SbxOBJECT, SbxBase*, pObj ) +GET( GetSingle, SbxSINGLE, float, nSingle ) +GET( GetULong, SbxULONG, UINT32, nULong ) +GET( GetULong64, SbxULONG64, SbxUINT64, nULong64 ) +GET( GetUShort, SbxUSHORT, UINT16, nUShort ) +GET( GetInt64, SbxSALINT64, sal_Int64, nInt64 ) +GET( GetUInt64, SbxSALUINT64, sal_uInt64, uInt64 ) +GET( GetDecimal, SbxDECIMAL, SbxDecimal*, pDecimal ) + + +//////////////////////////// Daten schreiben ///////////////////////////// + +BOOL SbxValue::Put( const SbxValues& rVal ) +{ + BOOL bRes = 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( 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.pString ); break; + case SbxINT: +#if SAL_TYPES_SIZEOFINT == 2 + ImpPutInteger( &p->aData, (INT16) rVal.nInt ); +#else + ImpPutLong( &p->aData, (INT32) rVal.nInt ); +#endif + break; + case SbxUINT: +#if SAL_TYPES_SIZEOFINT == 2 + ImpPutUShort( &p->aData, (UINT16) rVal.nUInt ); +#else + ImpPutULong( &p->aData, (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); + BOOL bParentProp = pThisVar && 5345 == + ( (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( TRUE ); + p->Broadcast( SBX_HINT_DATACHANGED ); + if( eOld != SbxERR_OK ) + SetError( eOld ); + bRes = 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) +BOOL SbxValue::PutStringExt( const XubString& r ) +{ + // Kopieren, bei Unicode gleich konvertieren + String 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) + BOOL bRet; + if( ImpConvStringExt( aStr, eTargetType ) ) + aRes.pString = (XubString*)&aStr; + else + aRes.pString = (XubString*)&r; + + // #34939: Bei Strings. die eine Zahl enthalten und wenn this einen + // Num-Typ hat, Fixed-Flag setzen, damit der Typ nicht veraendert wird + USHORT 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 = 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; +} + +BOOL SbxValue::PutString( const xub_Unicode* p ) +{ + XubString aVal( p ); + SbxValues aRes; + aRes.eType = SbxSTRING; + aRes.pString = &aVal; + Put( aRes ); + return BOOL( !IsError() ); +} + +BOOL SbxValue::PutBool( BOOL b ) +{ + SbxValues aRes; + aRes.eType = SbxBOOL; + aRes.nUShort = sal::static_int_cast< UINT16 >(b ? SbxTRUE : SbxFALSE); + Put( aRes ); + return BOOL( !IsError() ); +} + +BOOL SbxValue::PutEmpty() +{ + BOOL bRet = SetType( SbxEMPTY ); + SetModified( TRUE ); + return bRet; +} + +BOOL SbxValue::PutNull() +{ + BOOL bRet = SetType( SbxNULL ); + if( bRet ) + SetModified( TRUE ); + return bRet; +} + + +// Special decimal methods +BOOL SbxValue::PutDecimal( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ) +{ + SbxValue::Clear(); + aData.pDecimal = new SbxDecimal( rAutomationDec ); + aData.pDecimal->addRef(); + aData.eType = SbxDECIMAL; + return TRUE; +} + +BOOL SbxValue::fillAutomationDecimal + ( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec ) +{ + SbxDecimal* pDecimal = GetDecimal(); + if( pDecimal != NULL ) + { + pDecimal->fillAutomationDecimal( rAutomationDec ); + return TRUE; + } + return FALSE; +} + + +BOOL SbxValue::PutpChar( const xub_Unicode* p ) +{ + XubString aVal( p ); + SbxValues aRes; + aRes.eType = SbxLPSTR; + aRes.pString = &aVal; + Put( aRes ); + return BOOL( !IsError() ); +} + +BOOL SbxValue::PutString( const XubString& r ) +{ + SbxValues aRes; + aRes.eType = SbxSTRING; + aRes.pString = (XubString*) &r; + Put( aRes ); + return BOOL( !IsError() ); +} + + +#define PUT( p, e, t, m ) \ +BOOL SbxValue::p( t n ) \ +{ SbxValues aRes(e); aRes.m = n; Put( aRes ); return BOOL( !IsError() ); } + +PUT( PutByte, SbxBYTE, BYTE, 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, UINT16, nUShort ) +PUT( PutInt, SbxINT, int, nInt ) +PUT( PutInteger, SbxINTEGER, INT16, nInteger ) +PUT( PutLong, SbxLONG, INT32, nLong ) +PUT( PutLong64, SbxLONG64, const SbxINT64&, nLong64 ) +PUT( PutObject, SbxOBJECT, SbxBase*, pObj ) +PUT( PutSingle, SbxSINGLE, float, nSingle ) +PUT( PutULong, SbxULONG, UINT32, nULong ) +PUT( PutULong64, SbxULONG64, const SbxUINT64&, nULong64 ) +PUT( PutUShort, SbxUSHORT, UINT16, nUShort ) +PUT( PutInt64, SbxSALINT64, sal_Int64, nInt64 ) +PUT( PutUInt64, SbxSALUINT64, sal_uInt64, uInt64 ) +PUT( PutDecimal, SbxDECIMAL, SbxDecimal*, pDecimal ) + + +////////////////////////// Setzen des Datentyps /////////////////////////// + +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 +BOOL SbxValue::IsNumeric() const +{ + return ImpIsNumeric( /*bOnlyIntntl*/FALSE ); +} + +BOOL SbxValue::IsNumericRTL() const +{ + return ImpIsNumeric( /*bOnlyIntntl*/TRUE ); +} + +BOOL SbxValue::ImpIsNumeric( BOOL bOnlyIntntl ) const +{ + + if( !CanRead() ) + { + SetError( SbxERR_PROP_WRITEONLY ); return FALSE; + } + // Downcast pruefen!!! + if( this->ISA(SbxVariable) ) + ((SbxVariable*)this)->Broadcast( SBX_HINT_DATAWANTED ); + SbxDataType t = GetType(); + if( t == SbxSTRING ) + { + if( aData.pString ) + { + XubString s( *aData.pString ); + double n; + SbxDataType t2; + USHORT nLen = 0; + if( ImpScan( s, n, t2, &nLen, /*bAllowIntntl*/FALSE, bOnlyIntntl ) == SbxERR_OK ) + return BOOL( nLen == s.Len() ); + } + return FALSE; + } + else + return 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; +} + +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 TRUE; + if( ( t & 0x0FFF ) == SbxVARIANT ) + { + // Versuch, den Datentyp auf Variant zu setzen + ResetFlag( SBX_FIXED ); + if( IsFixed() ) + { + SetError( SbxERR_CONVERSION ); return FALSE; + } + t = SbxEMPTY; + } + if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) ) + { + if( !CanWrite() || IsFixed() ) + { + SetError( SbxERR_CONVERSION ); return FALSE; + } + else + { + // Eventuelle Objekte freigeben + switch( aData.eType ) + { + case SbxSTRING: + delete aData.pString; + break; + case SbxOBJECT: + if( aData.pObj && aData.pObj != this ) + { + HACK(nicht bei Parent-Prop - sonst CyclicRef) + SbxVariable *pThisVar = PTR_CAST(SbxVariable, this); + UINT16 nSlotId = pThisVar + ? ( (INT16) ( pThisVar->GetUserData() & 0xFFFF ) ) + : 0; + DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName() == UniString::CreateFromAscii( "Parent" ), + "SID_PARENTOBJECT heisst nicht 'Parent'" ); + 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 TRUE; +} + +BOOL SbxValue::Convert( SbxDataType eTo ) +{ + eTo = SbxDataType( eTo & 0x0FFF ); + if( ( aData.eType & 0x0FFF ) == eTo ) + return TRUE; + if( !CanWrite() ) + return FALSE; + if( eTo == SbxVARIANT ) + { + // Versuch, den Datentyp auf Variant zu setzen + ResetFlag( SBX_FIXED ); + if( IsFixed() ) + { + SetError( SbxERR_CONVERSION ); return FALSE; + } + else + return TRUE; + } + // Convert from Null geht niemals. Einmal Null, immer Null! + if( aData.eType == SbxNULL ) + { + SetError( SbxERR_CONVERSION ); return 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( TRUE ); + } + Broadcast( SBX_HINT_CONVERTED ); + return TRUE; + } + else + return FALSE; +} +////////////////////////////////// Rechnen ///////////////////////////////// + +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.pString != NULL && aR.pString != NULL ) + { + *aL.pString += *aR.pString; + } + // Nicht einmal Left OK? + else if( aL.pString == NULL ) + { + aL.pString = new String(); + } + 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: + + BOOL bRes = BOOL( !IsError() ); + if( bRes && eOld != SbxERR_OK ) + SetError( eOld ); + return bRes; +} + +// Die Vergleichs-Routine liefert TRUE oder FALSE. + +BOOL SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const +{ + bool bVBAInterop = SbiRuntime::isVBAEnabled(); + + BOOL bRes = 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 = TRUE; + } + else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY ) + bRes = !bVBAInterop ? TRUE : ( eOp == SbxEQ ? TRUE : FALSE ); + // Sonderregel 1: Ist ein Operand Null, ist das Ergebnis FALSE + else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL ) + bRes = 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 = BOOL( eOp == SbxLT || eOp == SbxLE || eOp == SbxNE ); + else if( !IsFixed() && !rOp.IsFixed() + && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() ) +&& !bVBAInterop + ) + bRes = 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 = BOOL( *aL.pString == *aR.pString ); break; + case SbxNE: + bRes = BOOL( *aL.pString != *aR.pString ); break; + case SbxLT: + bRes = BOOL( *aL.pString < *aR.pString ); break; + case SbxGT: + bRes = BOOL( *aL.pString > *aR.pString ); break; + case SbxLE: + bRes = BOOL( *aL.pString <= *aR.pString ); break; + case SbxGE: + bRes = BOOL( *aL.pString >= *aR.pString ); 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 = BOOL( aL.nSingle == aR.nSingle ); break; + case SbxNE: + bRes = BOOL( aL.nSingle != aR.nSingle ); break; + case SbxLT: + bRes = BOOL( aL.nSingle < aR.nSingle ); break; + case SbxGT: + bRes = BOOL( aL.nSingle > aR.nSingle ); break; + case SbxLE: + bRes = BOOL( aL.nSingle <= aR.nSingle ); break; + case SbxGE: + bRes = 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 = BOOL( eRes == SbxDecimal::EQ ); break; + case SbxNE: + bRes = BOOL( eRes != SbxDecimal::EQ ); break; + case SbxLT: + bRes = BOOL( eRes == SbxDecimal::LT ); break; + case SbxGT: + bRes = BOOL( eRes == SbxDecimal::GT ); break; + case SbxLE: + bRes = BOOL( eRes != SbxDecimal::GT ); break; + case SbxGE: + bRes = 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 = BOOL( aL.nDouble == aR.nDouble ); break; + case SbxNE: + bRes = BOOL( aL.nDouble != aR.nDouble ); break; + case SbxLT: + bRes = BOOL( aL.nDouble < aR.nDouble ); break; + case SbxGT: + bRes = BOOL( aL.nDouble > aR.nDouble ); break; + case SbxLE: + bRes = BOOL( aL.nDouble <= aR.nDouble ); break; + case SbxGE: + bRes = 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 = FALSE; + } + } + } + } + if( eOld != SbxERR_OK ) + SetError( eOld ); + return bRes; +} + +///////////////////////////// Lesen/Schreiben //////////////////////////// + +BOOL SbxValue::LoadData( SvStream& r, USHORT ) +{ + SbxValue::Clear(); + 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 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 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.pString = new XubString( aVal ); + else + aData.pString = NULL; // JSM 22.09.1995 + break; + } + case SbxERROR: + case SbxUSHORT: + r >> aData.nUShort; break; + case SbxOBJECT: + { + BYTE nMode; + r >> nMode; + switch( nMode ) + { + case 0: + aData.pObj = NULL; + break; + case 1: + aData.pObj = SbxBase::Load( r ); + return 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: + { + BYTE 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: + { + BYTE 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 FALSE; + } + return TRUE; +} + +BOOL SbxValue::StoreData( SvStream& r ) const +{ + UINT16 nType = sal::static_int_cast< 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.pString ) + { + r.WriteByteString( *aData.pString, 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 << (BYTE) 1; + return aData.pObj->Store( r ); + } + else + r << (BYTE) 2; + } + else + r << (BYTE) 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: + { + BYTE n = SAL_TYPES_SIZEOFINT; + r << n << (sal_Int32)aData.nInt; + break; + } + case SbxUINT: + { + BYTE 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 FALSE; + } + return TRUE; +} + diff --git a/basic/source/sbx/sbxvar.cxx b/basic/source/sbx/sbxvar.cxx new file mode 100644 index 000000000000..9a83fb7ba578 --- /dev/null +++ b/basic/source/sbx/sbxvar.cxx @@ -0,0 +1,585 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_basic.hxx" + + +#include <tools/stream.hxx> +#include "svl/brdcst.hxx" + +#include <basic/sbx.hxx> +#include <basic/sbxbase.hxx> +#include "sbxres.hxx" +#include "sbxconv.hxx" +#include <math.h> +#include <ctype.h> + +///////////////////////////// SbxVariable ////////////////////////////// + +TYPEINIT1(SbxVariable,SbxValue) +TYPEINIT1(SbxHint,SfxSimpleHint) + +extern UINT32 nVarCreator; // in SBXBASE.CXX, fuer LoadData() +#ifdef DBG_UTIL +static ULONG nVar = 0; +#endif + +///////////////////////////// Konstruktoren ////////////////////////////// + +SbxVariable::SbxVariable() : SbxValue() +{ + pCst = NULL; + pParent = NULL; + nUserData = 0; + nHash = 0; +#ifdef DBG_UTIL + DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar ); + GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND ); +#endif +} + +SbxVariable::SbxVariable( const SbxVariable& r ) + : SvRefBase( r ), SbxValue( r ), mpPar( r.mpPar ), pInfo( r.pInfo ) +{ + pCst = NULL; + if( r.CanRead() ) + { + pParent = r.pParent; + nUserData = r.nUserData; + maName = r.maName; + nHash = r.nHash; + } + else + { + pParent = NULL; + nUserData = 0; + nHash = 0; + } +#ifdef DBG_UTIL + static sal_Char const aCellsStr[] = "Cells"; + if ( maName.EqualsAscii( aCellsStr ) ) + maName.AssignAscii( aCellsStr, sizeof( aCellsStr )-1 ); + DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar ); + GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND ); +#endif +} + +SbxVariable::SbxVariable( SbxDataType t, void* p ) : SbxValue( t, p ) +{ + pCst = NULL; + pParent = NULL; + nUserData = 0; + nHash = 0; +#ifdef DBG_UTIL + DbgOutf( "SbxVariable::Ctor %lx=%ld", (void*)this, ++nVar ); + GetSbxData_Impl()->aVars.Insert( this, LIST_APPEND ); +#endif +} + +SbxVariable::~SbxVariable() +{ +#ifdef DBG_UTIL + ByteString aBStr( (const UniString&)maName, RTL_TEXTENCODING_ASCII_US ); + DbgOutf( "SbxVariable::Dtor %lx (%s)", (void*)this, aBStr.GetBuffer() ); + static sal_Char const aCellsStr[] = "Cells"; + if ( maName.EqualsAscii( aCellsStr ) ) + maName.AssignAscii( aCellsStr, sizeof( aCellsStr )-1 ); + GetSbxData_Impl()->aVars.Remove( this ); +#endif + delete pCst; +} + +////////////////////////////// Broadcasting ////////////////////////////// + +SfxBroadcaster& SbxVariable::GetBroadcaster() +{ + if( !pCst ) + pCst = new SfxBroadcaster; + return *pCst; +} + +// Eines Tages kann man vielleicht den Parameter 0 schleifen, +// dann entfaellt die Kopiererei... + +void SbxVariable::Broadcast( ULONG nHintId ) +{ + if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() ) + { + // Da die Methode von aussen aufrufbar ist, hier noch einmal + // die Berechtigung testen + if( nHintId & SBX_HINT_DATAWANTED ) + if( !CanRead() ) + return; + if( nHintId & SBX_HINT_DATACHANGED ) + if( !CanWrite() ) + return; + // Weitere Broadcasts verhindern + SfxBroadcaster* pSave = pCst; + pCst = NULL; + USHORT nSaveFlags = GetFlags(); + SetFlag( SBX_READWRITE ); + if( mpPar.Is() ) + // this, als Element 0 eintragen, aber den Parent nicht umsetzen! + mpPar->GetRef( 0 ) = this; + pSave->Broadcast( SbxHint( nHintId, this ) ); + delete pCst; // wer weiss schon, auf welche Gedanken mancher kommt? + pCst = pSave; + SetFlags( nSaveFlags ); + } +} + +SbxInfo* SbxVariable::GetInfo() +{ + if( !pInfo ) + { + Broadcast( SBX_HINT_INFOWANTED ); + if( pInfo.Is() ) + SetModified( TRUE ); + } + return pInfo; +} + +void SbxVariable::SetInfo( SbxInfo* p ) +{ + pInfo = p; +} + +void SbxVariable::SetParameters( SbxArray* p ) +{ + mpPar = p; +} + + +/////////////////////////// Name der Variablen /////////////////////////// + +void SbxVariable::SetName( const XubString& rName ) +{ + maName = rName; + nHash = MakeHashCode( rName ); +} + +const XubString& SbxVariable::GetName( SbxNameType t ) const +{ + static char cSuffixes[] = " %&!#@ $"; + if( t == SbxNAME_NONE ) + return maName; + // Parameter-Infos anfordern (nicht fuer Objekte) + ((SbxVariable*)this)->GetInfo(); + // Nix anfuegen, wenn einfache Property (keine leeren Klammern) + if( !pInfo + || ( !pInfo->aParams.Count() && GetClass() == SbxCLASS_PROPERTY ) ) + return maName; + xub_Unicode cType = ' '; + XubString aTmp( maName ); + // Kurzer Typ? Dann holen, evtl. ist dieser 0. + SbxDataType et = GetType(); + if( t == SbxNAME_SHORT_TYPES ) + { + if( et <= SbxSTRING ) + cType = cSuffixes[ et ]; + if( cType != ' ' ) + aTmp += cType; + } + aTmp += '('; + for( USHORT i = 0; i < pInfo->aParams.Count(); i++ ) + { + const SbxParamInfo* q = pInfo->aParams.GetObject( i ); + int nt = q->eType & 0x0FFF; + if( i ) + aTmp += ','; + if( q->nFlags & SBX_OPTIONAL ) + aTmp += SbxRes( STRING_OPTIONAL ); + if( q->eType & SbxBYREF ) + aTmp += SbxRes( STRING_BYREF ); + aTmp += q->aName; + cType = ' '; + // Kurzer Typ? Dann holen, evtl. ist dieser 0. + if( t == SbxNAME_SHORT_TYPES ) + { + if( nt <= SbxSTRING ) + cType = cSuffixes[ nt ]; + } + if( cType != ' ' ) + { + aTmp += cType; + if( q->eType & SbxARRAY ) + aTmp.AppendAscii( "()" ); + } + else + { + if( q->eType & SbxARRAY ) + aTmp.AppendAscii( "()" ); + // langer Typ? + if( t != SbxNAME_SHORT ) + { + aTmp += SbxRes( STRING_AS ); + if( nt < 32 ) + aTmp += SbxRes( + sal::static_int_cast< USHORT >( STRING_TYPES + nt ) ); + else + aTmp += SbxRes( STRING_ANY ); + } + } + } + aTmp += ')'; + // Langer Typ? Dann holen + if( t == SbxNAME_LONG_TYPES && et != SbxEMPTY ) + { + aTmp += SbxRes( STRING_AS ); + if( et < 32 ) + aTmp += SbxRes( + sal::static_int_cast< USHORT >( STRING_TYPES + et ) ); + else + aTmp += SbxRes( STRING_ANY ); + } + ((SbxVariable*) this)->aPic = aTmp; + return aPic; +} + +// Einen simplen Hashcode erzeugen: Es werden die ersten 6 Zeichen gewertet. + +USHORT SbxVariable::MakeHashCode( const XubString& rName ) +{ + USHORT n = 0; + USHORT nLen = rName.Len(); + if( nLen > 6 ) + nLen = 6; + const xub_Unicode* p = rName.GetBuffer(); + while( nLen-- ) + { + BYTE c = (BYTE)*p; + p++; + // Falls wir ein Schweinezeichen haben, abbrechen!! + if( c >= 0x80 ) + return 0; + n = sal::static_int_cast< USHORT >( ( n << 3 ) + toupper( c ) ); + } + return n; +} + +////////////////////////////// Operatoren //////////////////////////////// + +SbxVariable& SbxVariable::operator=( const SbxVariable& r ) +{ + SbxValue::operator=( r ); + return *this; +} + +//////////////////////////////// Konversion //////////////////////////////// + +SbxDataType SbxVariable::GetType() const +{ + if( aData.eType == SbxOBJECT ) + return aData.pObj ? aData.pObj->GetType() : SbxOBJECT; + else if( aData.eType == SbxVARIANT ) + return aData.pObj ? aData.pObj->GetType() : SbxVARIANT; + else + return aData.eType; +} + +SbxClassType SbxVariable::GetClass() const +{ + return SbxCLASS_VARIABLE; +} + +void SbxVariable::SetModified( BOOL b ) +{ + if( IsSet( SBX_NO_MODIFY ) ) + return; + SbxBase::SetModified( b ); + if( pParent && pParent != this ) //??? HotFix: Rekursion raus MM + pParent->SetModified( b ); +} + +void SbxVariable::SetParent( SbxObject* p ) +{ +#ifdef DBG_UTIL + // wird der Parent eines SbxObjects gesetzt? + if ( p && ISA(SbxObject) ) + { + // dann mu\s dieses auch Child vom neuen Parent sein + BOOL bFound = FALSE; + SbxArray *pChilds = p->GetObjects(); + if ( pChilds ) + { + for ( USHORT nIdx = 0; !bFound && nIdx < pChilds->Count(); ++nIdx ) + bFound = ( this == pChilds->Get(nIdx) ); + } + if ( !bFound ) + { + String aMsg = String::CreateFromAscii( "dangling: [" ); + aMsg += GetName(); + aMsg.AppendAscii( "].SetParent([" ); + aMsg += p->GetName(); + aMsg.AppendAscii( "])" ); + ByteString aBStr( (const UniString&)aMsg, RTL_TEXTENCODING_ASCII_US ); + DbgOut( aBStr.GetBuffer(), DBG_OUT_WARNING, __FILE__, __LINE__); + } + } +#endif + + pParent = p; +} + +////////////////////////////// Laden/Speichern ///////////////////////////// + +BOOL SbxVariable::LoadData( SvStream& rStrm, USHORT nVer ) +{ + UINT16 nType; + BYTE cMark; + rStrm >> cMark; + if( cMark == 0xFF ) + { + if( !SbxValue::LoadData( rStrm, nVer ) ) + return FALSE; + rStrm.ReadByteString( maName, RTL_TEXTENCODING_ASCII_US ); + UINT32 nTemp; + rStrm >> nTemp; + nUserData = nTemp; + } + else + { + rStrm.SeekRel( -1L ); + rStrm >> nType; + rStrm.ReadByteString( maName, RTL_TEXTENCODING_ASCII_US ); + UINT32 nTemp; + rStrm >> nTemp; + nUserData = nTemp; + // Korrektur: Alte Methoden haben statt SbxNULL jetzt SbxEMPTY + if( nType == SbxNULL && GetClass() == SbxCLASS_METHOD ) + nType = SbxEMPTY; + SbxValues aTmp; + XubString aVal; + aTmp.eType = aData.eType = (SbxDataType) nType; + aTmp.pString = &aVal; + switch( nType ) + { + case SbxBOOL: + case SbxERROR: + case SbxINTEGER: + rStrm >> aTmp.nInteger; break; + case SbxLONG: + rStrm >> aTmp.nLong; break; + case SbxSINGLE: + { + // Floats als ASCII + rStrm.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US ); + double d; + SbxDataType t; + if( ImpScan( aVal, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE ) + { + aTmp.nSingle = 0; + return FALSE; + } + aTmp.nSingle = (float) d; + break; + } + case SbxDATE: + case SbxDOUBLE: + { + // Floats als ASCII + rStrm.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US ); + SbxDataType t; + if( ImpScan( aVal, aTmp.nDouble, t, NULL ) != SbxERR_OK ) + { + aTmp.nDouble = 0; + return FALSE; + } + break; + } + case SbxSTRING: + rStrm.ReadByteString( aVal, RTL_TEXTENCODING_ASCII_US ); + break; + case SbxEMPTY: + case SbxNULL: + break; + default: + aData.eType = SbxNULL; + DBG_ASSERT( !this, "Nicht unterstuetzer Datentyp geladen" ); + return FALSE; + } + // Wert putten + if( nType != SbxNULL && nType != SbxEMPTY && !Put( aTmp ) ) + return FALSE; + } + rStrm >> cMark; + // cMark ist auch eine Versionsnummer! + // 1: initial version + // 2: mit nUserData + if( cMark ) + { + if( cMark > 2 ) + return FALSE; + pInfo = new SbxInfo; + pInfo->LoadData( rStrm, (USHORT) cMark ); + } + // Privatdaten nur laden, wenn es eine SbxVariable ist + if( GetClass() == SbxCLASS_VARIABLE && !LoadPrivateData( rStrm, nVer ) ) + return FALSE; + ((SbxVariable*) this)->Broadcast( SBX_HINT_DATACHANGED ); + nHash = MakeHashCode( maName ); + SetModified( TRUE ); + return TRUE; +} + +BOOL SbxVariable::StoreData( SvStream& rStrm ) const +{ + rStrm << (BYTE) 0xFF; // Marker + BOOL bValStore; + if( this->IsA( TYPE(SbxMethod) ) ) + { + // #50200 Verhindern, dass Objekte, die zur Laufzeit als Return-Wert + // in der Methode als Value gespeichert sind, mit gespeichert werden + SbxVariable* pThis = (SbxVariable*)this; + USHORT nSaveFlags = GetFlags(); + pThis->SetFlag( SBX_WRITE ); + pThis->SbxValue::Clear(); + pThis->SetFlags( nSaveFlags ); + + // Damit die Methode in keinem Fall ausgefuehrt wird! + // CAST, um const zu umgehen! + pThis->SetFlag( SBX_NO_BROADCAST ); + bValStore = SbxValue::StoreData( rStrm ); + pThis->ResetFlag( SBX_NO_BROADCAST ); + } + else + bValStore = SbxValue::StoreData( rStrm ); + if( !bValStore ) + return FALSE; + // if( !SbxValue::StoreData( rStrm ) ) + // return FALSE; + rStrm.WriteByteString( maName, RTL_TEXTENCODING_ASCII_US ); + rStrm << (UINT32)nUserData; + if( pInfo.Is() ) + { + rStrm << (BYTE) 2; // Version 2: mit UserData! + pInfo->StoreData( rStrm ); + } + else + rStrm << (BYTE) 0; + // Privatdaten nur speichern, wenn es eine SbxVariable ist + if( GetClass() == SbxCLASS_VARIABLE ) + return StorePrivateData( rStrm ); + else + return TRUE; +} + +////////////////////////////// SbxInfo /////////////////////////////////// + +SbxInfo::SbxInfo() : aHelpFile(), nHelpId( 0 ), aParams() +{} + +SbxInfo::SbxInfo( const String& r, UINT32 n ) + : aHelpFile( r ), nHelpId( n ), aParams() +{} + +////////////////////////////// SbxAlias ////////////////////////////////// + +SbxAlias::SbxAlias( const XubString& rName, SbxVariable* p ) + : SbxVariable(), xAlias( p ) +{ + SetName( rName ); + SetFlags( p->GetFlags() ); + SetFlag( SBX_DONTSTORE ); + aData.eType = p->GetType(); + StartListening( p->GetBroadcaster() ); +} + +SbxAlias::SbxAlias( const SbxAlias& r ) + : SvRefBase( r ), SbxVariable( r ), + SfxListener( r ), xAlias( r.xAlias ) +{} + +SbxAlias& SbxAlias::operator=( const SbxAlias& r ) +{ + xAlias = r.xAlias; + return *this; +} + +SbxAlias::~SbxAlias() +{ + if( xAlias.Is() ) + EndListening( xAlias->GetBroadcaster() ); +} + +void SbxAlias::Broadcast( ULONG nHt ) +{ + if( xAlias.Is() && StaticIsEnabledBroadcasting() ) + { + xAlias->SetParameters( GetParameters() ); + if( nHt == SBX_HINT_DATAWANTED ) + SbxVariable::operator=( *xAlias ); + else if( nHt == SBX_HINT_DATACHANGED || nHt == SBX_HINT_CONVERTED ) + *xAlias = *this; + else if( nHt == SBX_HINT_INFOWANTED ) + { + xAlias->Broadcast( nHt ); + pInfo = xAlias->GetInfo(); + } + } +} + +void SbxAlias::SFX_NOTIFY( SfxBroadcaster&, const TypeId&, + const SfxHint& rHint, const TypeId& ) +{ + const SbxHint* p = PTR_CAST(SbxHint,&rHint); + if( p && p->GetId() == SBX_HINT_DYING ) + { + xAlias.Clear(); + // Alias loeschen? + if( pParent ) + pParent->Remove( this ); + } +} + +void SbxVariable::Dump( SvStream& rStrm, BOOL bFill ) +{ + ByteString aBNameStr( (const UniString&)GetName( SbxNAME_SHORT_TYPES ), RTL_TEXTENCODING_ASCII_US ); + rStrm << "Variable( " + << ByteString::CreateFromInt64( (ULONG) this ).GetBuffer() << "==" + << aBNameStr.GetBuffer(); + ByteString aBParentNameStr( (const UniString&)GetParent()->GetName(), RTL_TEXTENCODING_ASCII_US ); + if ( GetParent() ) + rStrm << " in parent '" << aBParentNameStr.GetBuffer() << "'"; + else + rStrm << " no parent"; + rStrm << " ) "; + + // bei Object-Vars auch das Object ausgeben + if ( GetValues_Impl().eType == SbxOBJECT && + GetValues_Impl().pObj && + GetValues_Impl().pObj != this && + GetValues_Impl().pObj != GetParent() ) + { + rStrm << " contains "; + ((SbxObject*) GetValues_Impl().pObj)->Dump( rStrm, bFill ); + } + else + rStrm << endl; +} + |