summaryrefslogtreecommitdiff
path: root/basic/source/runtime/runtime.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'basic/source/runtime/runtime.cxx')
-rw-r--r--basic/source/runtime/runtime.cxx1287
1 files changed, 1287 insertions, 0 deletions
diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx
new file mode 100644
index 000000000000..10d25cc2292b
--- /dev/null
+++ b/basic/source/runtime/runtime.cxx
@@ -0,0 +1,1287 @@
+/*************************************************************************
+ *
+ * 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/fsys.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/wldcrd.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/syslocale.hxx>
+#include "runtime.hxx"
+#include "sbintern.hxx"
+#include "opcodes.hxx"
+#include "codegen.hxx"
+#include "iosys.hxx"
+#include "image.hxx"
+#include "ddectrl.hxx"
+#include "dllmgr.hxx"
+#include <comphelper/processfactory.hxx>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include "sbunoobj.hxx"
+#include "errobject.hxx"
+#include "sbtrace.hxx"
+#include "comenumwrapper.hxx"
+
+using namespace ::com::sun::star;
+
+bool SbiRuntime::isVBAEnabled()
+{
+ bool result = false;
+ SbiInstance* pInst = pINST;
+ if ( pInst && pINST->pRun )
+ result = pInst->pRun->bVBAEnabled;
+ return result;
+}
+
+// #91147 Global reschedule flag
+static sal_Bool bStaticGlobalEnableReschedule = sal_True;
+
+void StarBASIC::StaticEnableReschedule( sal_Bool bReschedule )
+{
+ bStaticGlobalEnableReschedule = bReschedule;
+}
+void StarBASIC::SetVBAEnabled( sal_Bool bEnabled )
+{
+ if ( bDocBasic )
+ {
+ bVBAEnabled = bEnabled;
+ }
+}
+
+sal_Bool StarBASIC::isVBAEnabled()
+{
+ if ( bDocBasic )
+ {
+ if( SbiRuntime::isVBAEnabled() )
+ return sal_True;
+ return bVBAEnabled;
+ }
+ return sal_False;
+}
+
+
+struct SbiArgvStack { // Argv stack:
+ SbiArgvStack* pNext; // Stack Chain
+ SbxArrayRef refArgv; // Argv
+ short nArgc; // Argc
+};
+
+SbiRuntime::pStep0 SbiRuntime::aStep0[] = { // Alle Opcodes ohne Operanden
+ &SbiRuntime::StepNOP,
+ &SbiRuntime::StepEXP,
+ &SbiRuntime::StepMUL,
+ &SbiRuntime::StepDIV,
+ &SbiRuntime::StepMOD,
+ &SbiRuntime::StepPLUS,
+ &SbiRuntime::StepMINUS,
+ &SbiRuntime::StepNEG,
+ &SbiRuntime::StepEQ,
+ &SbiRuntime::StepNE,
+ &SbiRuntime::StepLT,
+ &SbiRuntime::StepGT,
+ &SbiRuntime::StepLE,
+ &SbiRuntime::StepGE,
+ &SbiRuntime::StepIDIV,
+ &SbiRuntime::StepAND,
+ &SbiRuntime::StepOR,
+ &SbiRuntime::StepXOR,
+ &SbiRuntime::StepEQV,
+ &SbiRuntime::StepIMP,
+ &SbiRuntime::StepNOT,
+ &SbiRuntime::StepCAT,
+
+ &SbiRuntime::StepLIKE,
+ &SbiRuntime::StepIS,
+ // Laden/speichern
+ &SbiRuntime::StepARGC, // neuen Argv einrichten
+ &SbiRuntime::StepARGV, // TOS ==> aktueller Argv
+ &SbiRuntime::StepINPUT, // Input ==> TOS
+ &SbiRuntime::StepLINPUT, // Line Input ==> TOS
+ &SbiRuntime::StepGET, // TOS anfassen
+ &SbiRuntime::StepSET, // Speichern Objekt TOS ==> TOS-1
+ &SbiRuntime::StepPUT, // TOS ==> TOS-1
+ &SbiRuntime::StepPUTC, // TOS ==> TOS-1, dann ReadOnly
+ &SbiRuntime::StepDIM, // DIM
+ &SbiRuntime::StepREDIM, // REDIM
+ &SbiRuntime::StepREDIMP, // REDIM PRESERVE
+ &SbiRuntime::StepERASE, // TOS loeschen
+ // Verzweigen
+ &SbiRuntime::StepSTOP, // Programmende
+ &SbiRuntime::StepINITFOR, // FOR-Variable initialisieren
+ &SbiRuntime::StepNEXT, // FOR-Variable inkrementieren
+ &SbiRuntime::StepCASE, // Anfang CASE
+ &SbiRuntime::StepENDCASE, // Ende CASE
+ &SbiRuntime::StepSTDERROR, // Standard-Fehlerbehandlung
+ &SbiRuntime::StepNOERROR, // keine Fehlerbehandlung
+ &SbiRuntime::StepLEAVE, // UP verlassen
+ // E/A
+ &SbiRuntime::StepCHANNEL, // TOS = Kanalnummer
+ &SbiRuntime::StepPRINT, // print TOS
+ &SbiRuntime::StepPRINTF, // print TOS in field
+ &SbiRuntime::StepWRITE, // write TOS
+ &SbiRuntime::StepRENAME, // Rename Tos+1 to Tos
+ &SbiRuntime::StepPROMPT, // Input Prompt aus TOS definieren
+ &SbiRuntime::StepRESTART, // Set restart point
+ &SbiRuntime::StepCHANNEL0, // E/A-Kanal 0 einstellen
+ &SbiRuntime::StepEMPTY, // Leeren Ausdruck auf Stack
+ &SbiRuntime::StepERROR, // TOS = Fehlercode
+ &SbiRuntime::StepLSET, // Speichern Objekt TOS ==> TOS-1
+ &SbiRuntime::StepRSET, // Speichern Objekt TOS ==> TOS-1
+ &SbiRuntime::StepREDIMP_ERASE,// Copy array object for REDIMP
+ &SbiRuntime::StepINITFOREACH,// Init for each loop
+ &SbiRuntime::StepVBASET,// vba-like set statement
+ &SbiRuntime::StepERASE_CLEAR,// vba-like set statement
+ &SbiRuntime::StepARRAYACCESS,// access TOS as array
+ &SbiRuntime::StepBYVAL, // access TOS as array
+};
+
+SbiRuntime::pStep1 SbiRuntime::aStep1[] = { // Alle Opcodes mit einem Operanden
+ &SbiRuntime::StepLOADNC, // Laden einer numerischen Konstanten (+ID)
+ &SbiRuntime::StepLOADSC, // Laden einer Stringkonstanten (+ID)
+ &SbiRuntime::StepLOADI, // Immediate Load (+Wert)
+ &SbiRuntime::StepARGN, // Speichern eines named Args in Argv (+StringID)
+ &SbiRuntime::StepPAD, // String auf feste Laenge bringen (+Laenge)
+ // Verzweigungen
+ &SbiRuntime::StepJUMP, // Sprung (+Target)
+ &SbiRuntime::StepJUMPT, // TOS auswerten), bedingter Sprung (+Target)
+ &SbiRuntime::StepJUMPF, // TOS auswerten), bedingter Sprung (+Target)
+ &SbiRuntime::StepONJUMP, // TOS auswerten), Sprung in JUMP-Tabelle (+MaxVal)
+ &SbiRuntime::StepGOSUB, // UP-Aufruf (+Target)
+ &SbiRuntime::StepRETURN, // UP-Return (+0 oder Target)
+ &SbiRuntime::StepTESTFOR, // FOR-Variable testen), inkrementieren (+Endlabel)
+ &SbiRuntime::StepCASETO, // Tos+1 <= Case <= Tos), 2xremove (+Target)
+ &SbiRuntime::StepERRHDL, // Fehler-Handler (+Offset)
+ &SbiRuntime::StepRESUME, // Resume nach Fehlern (+0 or 1 or Label)
+ // E/A
+ &SbiRuntime::StepCLOSE, // (+Kanal/0)
+ &SbiRuntime::StepPRCHAR, // (+char)
+ // Verwaltung
+ &SbiRuntime::StepSETCLASS, // Set + Klassennamen testen (+StringId)
+ &SbiRuntime::StepTESTCLASS, // Check TOS class (+StringId)
+ &SbiRuntime::StepLIB, // Lib fuer Declare-Call (+StringId)
+ &SbiRuntime::StepBASED, // TOS wird um BASE erhoeht, BASE davor gepusht
+ &SbiRuntime::StepARGTYP, // Letzten Parameter in Argv konvertieren (+Typ)
+ &SbiRuntime::StepVBASETCLASS,// vba-like set statement
+};
+
+SbiRuntime::pStep2 SbiRuntime::aStep2[] = {// Alle Opcodes mit zwei Operanden
+ &SbiRuntime::StepRTL, // Laden aus RTL (+StringID+Typ)
+ &SbiRuntime::StepFIND, // Laden (+StringID+Typ)
+ &SbiRuntime::StepELEM, // Laden Element (+StringID+Typ)
+ &SbiRuntime::StepPARAM, // Parameter (+Offset+Typ)
+ // Verzweigen
+ &SbiRuntime::StepCALL, // Declare-Call (+StringID+Typ)
+ &SbiRuntime::StepCALLC, // CDecl-Declare-Call (+StringID+Typ)
+ &SbiRuntime::StepCASEIS, // Case-Test (+Test-Opcode+False-Target)
+ // Verwaltung
+ &SbiRuntime::StepSTMNT, // Beginn eines Statements (+Line+Col)
+ // E/A
+ &SbiRuntime::StepOPEN, // (+SvStreamFlags+Flags)
+ // Objekte
+ &SbiRuntime::StepLOCAL, // Lokale Variable definieren (+StringId+Typ)
+ &SbiRuntime::StepPUBLIC, // Modulglobale Variable (+StringID+Typ)
+ &SbiRuntime::StepGLOBAL, // Globale Variable definieren (+StringID+Typ)
+ &SbiRuntime::StepCREATE, // Objekt kreieren (+StringId+StringId)
+ &SbiRuntime::StepSTATIC, // Statische Variable (+StringId+StringId)
+ &SbiRuntime::StepTCREATE, // User Defined Objekte (+StringId+StringId)
+ &SbiRuntime::StepDCREATE, // Objekt-Array kreieren (+StringID+StringID)
+ &SbiRuntime::StepGLOBAL_P, // Globale Variable definieren, die beim Neustart
+ // von Basic nicht ueberschrieben wird (+StringID+Typ)
+ &SbiRuntime::StepFIND_G, // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P
+ &SbiRuntime::StepDCREATE_REDIMP, // Objekt-Array redimensionieren (+StringID+StringID)
+ &SbiRuntime::StepFIND_CM, // Search inside a class module (CM) to enable global search in time
+ &SbiRuntime::StepPUBLIC_P, // Search inside a class module (CM) to enable global search in time
+ &SbiRuntime::StepFIND_STATIC, // Search inside a class module (CM) to enable global search in time
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// SbiRTLData //
+//////////////////////////////////////////////////////////////////////////
+
+SbiRTLData::SbiRTLData()
+{
+ pDir = 0;
+ nDirFlags = 0;
+ nCurDirPos = 0;
+ pWildCard = NULL;
+}
+
+SbiRTLData::~SbiRTLData()
+{
+ delete pDir;
+ pDir = 0;
+ delete pWildCard;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// SbiInstance //
+//////////////////////////////////////////////////////////////////////////
+
+// 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out
+// Die Entscheidung, ob StepPoint aufgerufen werden soll, wird anhand des
+// CallLevels getroffen. Angehalten wird, wenn der aktuelle CallLevel <=
+// nBreakCallLvl ist. Der aktuelle CallLevel kann niemals kleiner als 1
+// sein, da er beim Aufruf einer Methode (auch main) inkrementiert wird.
+// Daher bedeutet ein BreakCallLvl von 0, dass das Programm gar nicht
+// angehalten wird.
+// (siehe auch step2.cxx, SbiRuntime::StepSTMNT() )
+
+// Hilfsfunktion, um den BreakCallLevel gemaess der der Debug-Flags zu ermitteln
+void SbiInstance::CalcBreakCallLevel( sal_uInt16 nFlags )
+{
+ // Break-Flag wegfiltern
+ nFlags &= ~((sal_uInt16)SbDEBUG_BREAK);
+
+ sal_uInt16 nRet;
+ switch( nFlags )
+ {
+ case SbDEBUG_STEPINTO:
+ nRet = nCallLvl + 1; // CallLevel+1 wird auch angehalten
+ break;
+ case SbDEBUG_STEPOVER | SbDEBUG_STEPINTO:
+ nRet = nCallLvl; // Aktueller CallLevel wird angehalten
+ break;
+ case SbDEBUG_STEPOUT:
+ nRet = nCallLvl - 1; // Kleinerer CallLevel wird angehalten
+ break;
+ case SbDEBUG_CONTINUE:
+ // Basic-IDE liefert 0 statt SbDEBUG_CONTINUE, also auch default=continue
+ default:
+ nRet = 0; // CallLevel ist immer >0 -> kein StepPoint
+ }
+ nBreakCallLvl = nRet; // Ergebnis uebernehmen
+}
+
+SbiInstance::SbiInstance( StarBASIC* p )
+{
+ pBasic = p;
+ pNext = NULL;
+ pRun = NULL;
+ pIosys = new SbiIoSystem;
+ pDdeCtrl = new SbiDdeControl;
+ pDllMgr = 0; // on demand
+ pNumberFormatter = 0; // on demand
+ nCallLvl = 0;
+ nBreakCallLvl = 0;
+ nErr =
+ nErl = 0;
+ bReschedule = sal_True;
+ bCompatibility = sal_False;
+}
+
+SbiInstance::~SbiInstance()
+{
+ while( pRun )
+ {
+ SbiRuntime* p = pRun->pNext;
+ delete pRun;
+ pRun = p;
+ }
+ delete pIosys;
+ delete pDdeCtrl;
+ delete pDllMgr;
+ delete pNumberFormatter;
+
+ try
+ {
+ int nSize = ComponentVector.size();
+ if( nSize )
+ {
+ for( int i = nSize - 1 ; i >= 0 ; --i )
+ {
+ Reference< XComponent > xDlgComponent = ComponentVector[i];
+ if( xDlgComponent.is() )
+ xDlgComponent->dispose();
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_ERROR( "SbiInstance::~SbiInstance: caught an exception while disposing the components!" );
+ }
+
+ ComponentVector.clear();
+}
+
+SbiDllMgr* SbiInstance::GetDllMgr()
+{
+ if( !pDllMgr )
+ pDllMgr = new SbiDllMgr;
+ return pDllMgr;
+}
+
+// #39629 NumberFormatter jetzt ueber statische Methode anlegen
+SvNumberFormatter* SbiInstance::GetNumberFormatter()
+{
+ LanguageType eLangType = GetpApp()->GetSettings().GetLanguage();
+ SvtSysLocale aSysLocale;
+ DateFormat eDate = aSysLocale.GetLocaleData().getDateFormat();
+ if( pNumberFormatter )
+ {
+ if( eLangType != meFormatterLangType ||
+ eDate != meFormatterDateFormat )
+ {
+ delete pNumberFormatter;
+ pNumberFormatter = NULL;
+ }
+ }
+ meFormatterLangType = eLangType;
+ meFormatterDateFormat = eDate;
+ if( !pNumberFormatter )
+ PrepareNumberFormatter( pNumberFormatter, nStdDateIdx, nStdTimeIdx, nStdDateTimeIdx,
+ &meFormatterLangType, &meFormatterDateFormat );
+ return pNumberFormatter;
+}
+
+// #39629 NumberFormatter auch statisch anbieten
+void SbiInstance::PrepareNumberFormatter( SvNumberFormatter*& rpNumberFormatter,
+ sal_uInt32 &rnStdDateIdx, sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx,
+ LanguageType* peFormatterLangType, DateFormat* peFormatterDateFormat )
+{
+ com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >
+ xFactory = comphelper::getProcessServiceFactory();
+
+ LanguageType eLangType;
+ if( peFormatterLangType )
+ eLangType = *peFormatterLangType;
+ else
+ eLangType = GetpApp()->GetSettings().GetLanguage();
+
+ DateFormat eDate;
+ if( peFormatterDateFormat )
+ eDate = *peFormatterDateFormat;
+ else
+ {
+ SvtSysLocale aSysLocale;
+ eDate = aSysLocale.GetLocaleData().getDateFormat();
+ }
+
+ rpNumberFormatter = new SvNumberFormatter( xFactory, eLangType );
+
+ xub_StrLen nCheckPos = 0; short nType;
+ rnStdTimeIdx = rpNumberFormatter->GetStandardFormat( NUMBERFORMAT_TIME, eLangType );
+
+ // 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 svtools\source\sbx\sbxdate.cxx
+
+ String aDateStr;
+ switch( eDate )
+ {
+ case MDY: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("MM.TT.JJJJ") ); break;
+ case DMY: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("TT.MM.JJJJ") ); break;
+ case YMD: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("JJJJ.MM.TT") ); break;
+ default: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("MM.TT.JJJJ") );
+ }
+ String aStr( aDateStr );
+ rpNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType,
+ rnStdDateIdx, LANGUAGE_GERMAN, eLangType );
+ nCheckPos = 0;
+ String aStrHHMMSS( RTL_CONSTASCII_USTRINGPARAM(" HH:MM:SS") );
+ aStr = aDateStr;
+ aStr += aStrHHMMSS;
+ rpNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType,
+ rnStdDateTimeIdx, LANGUAGE_GERMAN, eLangType );
+}
+
+
+
+// Engine laufenlassen. Falls Flags == SbDEBUG_CONTINUE, Flags uebernehmen
+
+void SbiInstance::Stop()
+{
+ for( SbiRuntime* p = pRun; p; p = p->pNext )
+ p->Stop();
+}
+
+// Allows Basic IDE to set watch mode to suppress errors
+static bool bWatchMode = false;
+
+void setBasicWatchMode( bool bOn )
+{
+ bWatchMode = bOn;
+}
+
+void SbiInstance::Error( SbError n )
+{
+ Error( n, String() );
+}
+
+void SbiInstance::Error( SbError n, const String& rMsg )
+{
+ if( !bWatchMode )
+ {
+ aErrorMsg = rMsg;
+ pRun->Error( n );
+ }
+}
+
+void SbiInstance::ErrorVB( sal_Int32 nVBNumber, const String& rMsg )
+{
+ if( !bWatchMode )
+ {
+ SbError n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) );
+ if ( !n )
+ n = nVBNumber; // force orig number, probably should have a specific table of vb ( localized ) errors
+
+ aErrorMsg = rMsg;
+ SbiRuntime::translateErrorToVba( n, aErrorMsg );
+
+ bool bVBATranslationAlreadyDone = true;
+ pRun->Error( SbERR_BASIC_COMPAT, bVBATranslationAlreadyDone );
+ }
+}
+
+void SbiInstance::setErrorVB( sal_Int32 nVBNumber, const String& rMsg )
+{
+ SbError n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) );
+ if( !n )
+ n = nVBNumber; // force orig number, probably should have a specific table of vb ( localized ) errors
+
+ aErrorMsg = rMsg;
+ SbiRuntime::translateErrorToVba( n, aErrorMsg );
+
+ nErr = n;
+}
+
+
+void SbiInstance::FatalError( SbError n )
+{
+ pRun->FatalError( n );
+}
+
+void SbiInstance::FatalError( SbError _errCode, const String& _details )
+{
+ pRun->FatalError( _errCode, _details );
+}
+
+void SbiInstance::Abort()
+{
+ // Basic suchen, in dem der Fehler auftrat
+ StarBASIC* pErrBasic = GetCurrentBasic( pBasic );
+ pErrBasic->RTError( nErr, aErrorMsg, pRun->nLine, pRun->nCol1, pRun->nCol2 );
+ pBasic->Stop();
+}
+
+// Hilfsfunktion, um aktives Basic zu finden, kann ungleich pRTBasic sein
+StarBASIC* GetCurrentBasic( StarBASIC* pRTBasic )
+{
+ StarBASIC* pCurBasic = pRTBasic;
+ SbModule* pActiveModule = pRTBasic->GetActiveModule();
+ if( pActiveModule )
+ {
+ SbxObject* pParent = pActiveModule->GetParent();
+ if( pParent && pParent->ISA(StarBASIC) )
+ pCurBasic = (StarBASIC*)pParent;
+ }
+ return pCurBasic;
+}
+
+SbModule* SbiInstance::GetActiveModule()
+{
+ if( pRun )
+ return pRun->GetModule();
+ else
+ return NULL;
+}
+
+SbMethod* SbiInstance::GetCaller( sal_uInt16 nLevel )
+{
+ SbiRuntime* p = pRun;
+ while( nLevel-- && p )
+ p = p->pNext;
+ if( p )
+ return p->GetCaller();
+ else
+ return NULL;
+}
+
+SbxArray* SbiInstance::GetLocals( SbMethod* pMeth )
+{
+ SbiRuntime* p = pRun;
+ while( p && p->GetMethod() != pMeth )
+ p = p->pNext;
+ if( p )
+ return p->GetLocals();
+ else
+ return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// SbiInstance //
+//////////////////////////////////////////////////////////////////////////
+
+// Achtung: pMeth kann auch NULL sein (beim Aufruf des Init-Codes)
+
+SbiRuntime::SbiRuntime( SbModule* pm, SbMethod* pe, sal_uInt32 nStart )
+ : rBasic( *(StarBASIC*)pm->pParent ), pInst( pINST ),
+ pMod( pm ), pMeth( pe ), pImg( pMod->pImage ), m_nLastTime(0)
+{
+ nFlags = pe ? pe->GetDebugFlags() : 0;
+ pIosys = pInst->pIosys;
+ pArgvStk = NULL;
+ pGosubStk = NULL;
+ pForStk = NULL;
+ pError = NULL;
+ pErrCode =
+ pErrStmnt =
+ pRestart = NULL;
+ pNext = NULL;
+ pCode =
+ pStmnt = (const sal_uInt8* ) pImg->GetCode() + nStart;
+ bRun =
+ bError = sal_True;
+ bInError = sal_False;
+ bBlocked = sal_False;
+ nLine = 0;
+ nCol1 = 0;
+ nCol2 = 0;
+ nExprLvl = 0;
+ nArgc = 0;
+ nError = 0;
+ nGosubLvl = 0;
+ nForLvl = 0;
+ nOps = 0;
+ refExprStk = new SbxArray;
+ SetVBAEnabled( pMod->IsVBACompat() );
+#if defined GCC
+ SetParameters( pe ? pe->GetParameters() : (class SbxArray *)NULL );
+#else
+ SetParameters( pe ? pe->GetParameters() : NULL );
+#endif
+ pRefSaveList = NULL;
+ pItemStoreList = NULL;
+}
+
+SbiRuntime::~SbiRuntime()
+{
+ ClearGosubStack();
+ ClearArgvStack();
+ ClearForStack();
+
+ // #74254 Items zum Sichern temporaere Referenzen freigeben
+ ClearRefs();
+ while( pItemStoreList )
+ {
+ RefSaveItem* pToDeleteItem = pItemStoreList;
+ pItemStoreList = pToDeleteItem->pNext;
+ delete pToDeleteItem;
+ }
+}
+
+void SbiRuntime::SetVBAEnabled(bool bEnabled )
+{
+ bVBAEnabled = bEnabled;
+}
+
+// Aufbau der Parameterliste. Alle ByRef-Parameter werden direkt
+// uebernommen; von ByVal-Parametern werden Kopien angelegt. Falls
+// ein bestimmter Datentyp verlangt wird, wird konvertiert.
+
+void SbiRuntime::SetParameters( SbxArray* pParams )
+{
+ refParams = new SbxArray;
+ // fuer den Returnwert
+ refParams->Put( pMeth, 0 );
+
+ SbxInfo* pInfo = pMeth ? pMeth->GetInfo() : NULL;
+ sal_uInt16 nParamCount = pParams ? pParams->Count() : 1;
+ if( nParamCount > 1 )
+ {
+ for( sal_uInt16 i = 1 ; i < nParamCount ; i++ )
+ {
+ const SbxParamInfo* p = pInfo ? pInfo->GetParam( i ) : NULL;
+
+ // #111897 ParamArray
+ if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 )
+ {
+ SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
+ sal_uInt16 nParamArrayParamCount = nParamCount - i;
+ pArray->unoAddDim( 0, nParamArrayParamCount - 1 );
+ for( sal_uInt16 j = i ; j < nParamCount ; j++ )
+ {
+ SbxVariable* v = pParams->Get( j );
+ short nDimIndex = j - i;
+ pArray->Put( v, &nDimIndex );
+ }
+ SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT );
+ pArrayVar->SetFlag( SBX_READWRITE );
+ pArrayVar->PutObject( pArray );
+ refParams->Put( pArrayVar, i );
+
+ // Block ParamArray for missing parameter
+ pInfo = NULL;
+ break;
+ }
+
+ SbxVariable* v = pParams->Get( i );
+ // Methoden sind immer byval!
+ sal_Bool bByVal = v->IsA( TYPE(SbxMethod) );
+ SbxDataType t = v->GetType();
+ if( p )
+ {
+ bByVal |= sal_Bool( ( p->eType & SbxBYREF ) == 0 );
+ t = (SbxDataType) ( p->eType & 0x0FFF );
+
+ if( !bByVal && t != SbxVARIANT &&
+ (!v->IsFixed() || (SbxDataType)(v->GetType() & 0x0FFF ) != t) )
+ bByVal = sal_True;
+ }
+ if( bByVal )
+ {
+ SbxVariable* v2 = new SbxVariable( t );
+ v2->SetFlag( SBX_READWRITE );
+ *v2 = *v;
+ refParams->Put( v2, i );
+ }
+ else
+ {
+ if( t != SbxVARIANT && t != ( v->GetType() & 0x0FFF ) )
+ {
+ // Array konvertieren??
+ if( p && (p->eType & SbxARRAY) )
+ Error( SbERR_CONVERSION );
+ else
+ v->Convert( t );
+ }
+ refParams->Put( v, i );
+ }
+ if( p )
+ refParams->PutAlias( p->aName, i );
+ }
+ }
+
+ // ParamArray for missing parameter
+ if( pInfo )
+ {
+ // #111897 Check first missing parameter for ParamArray
+ const SbxParamInfo* p = pInfo->GetParam( nParamCount );
+ if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 )
+ {
+ SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
+ pArray->unoAddDim( 0, -1 );
+ SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT );
+ pArrayVar->SetFlag( SBX_READWRITE );
+ pArrayVar->PutObject( pArray );
+ refParams->Put( pArrayVar, nParamCount );
+ }
+ }
+}
+
+
+// Einen P-Code ausfuehren
+
+sal_Bool SbiRuntime::Step()
+{
+ if( bRun )
+ {
+ // Unbedingt gelegentlich die Kontrolle abgeben!
+ if( !( ++nOps & 0xF ) && pInst->IsReschedule() && bStaticGlobalEnableReschedule )
+ {
+ sal_uInt32 nTime = osl_getGlobalTimer();
+ if (nTime - m_nLastTime > 5 ) // 20 ms
+ {
+ Application::Reschedule();
+ m_nLastTime = nTime;
+ }
+ }
+
+ // #i48868 blocked by next call level?
+ while( bBlocked )
+ {
+ if( pInst->IsReschedule() && bStaticGlobalEnableReschedule )
+ Application::Reschedule();
+ }
+
+#ifdef DBG_TRACE_BASIC
+ sal_uInt32 nPC = ( pCode - (const sal_uInt8* )pImg->GetCode() );
+ dbg_traceStep( pMod, nPC, pINST->nCallLvl );
+#endif
+
+ SbiOpcode eOp = (SbiOpcode ) ( *pCode++ );
+ sal_uInt32 nOp1, nOp2;
+ if( eOp <= SbOP0_END )
+ {
+ (this->*( aStep0[ eOp ] ) )();
+ }
+ else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
+ {
+ nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24;
+
+ (this->*( aStep1[ eOp - SbOP1_START ] ) )( nOp1 );
+ }
+ else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
+ {
+ nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24;
+ nOp2 = *pCode++; nOp2 |= *pCode++ << 8; nOp2 |= *pCode++ << 16; nOp2 |= *pCode++ << 24;
+ (this->*( aStep2[ eOp - SbOP2_START ] ) )( nOp1, nOp2 );
+ }
+ else
+ StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
+
+ // SBX-Fehler aufgetreten?
+ SbError nSbError = SbxBase::GetError();
+ Error( ERRCODE_TOERROR(nSbError) ); // Warnings rausfiltern
+
+ // AB 13.2.1997, neues Error-Handling:
+ // ACHTUNG: Hier kann nError auch dann gesetzt sein, wenn !nSbError,
+ // da nError jetzt auch von anderen RT-Instanzen gesetzt werden kann
+
+ if( nError )
+ SbxBase::ResetError();
+
+ // AB,15.3.96: Fehler nur anzeigen, wenn BASIC noch aktiv
+ // (insbesondere nicht nach Compiler-Fehlern zur Laufzeit)
+ if( nError && bRun )
+ {
+#ifdef DBG_TRACE_BASIC
+ SbError nTraceErr = nError;
+ String aTraceErrMsg = GetSbData()->aErrMsg;
+ bool bTraceErrHandled = true;
+#endif
+ SbError err = nError;
+ ClearExprStack();
+ nError = 0;
+ pInst->nErr = err;
+ pInst->nErl = nLine;
+ pErrCode = pCode;
+ pErrStmnt = pStmnt;
+ // An error occured in an error handler
+ // force parent handler ( if there is one )
+ // to handle the error
+ bool bLetParentHandleThis = false;
+
+ // Im Error Handler? Dann Std-Error
+ if ( !bInError )
+ {
+ bInError = sal_True;
+
+ if( !bError ) // On Error Resume Next
+ StepRESUME( 1 );
+ else if( pError ) // On Error Goto ...
+ pCode = pError;
+ else
+ bLetParentHandleThis = true;
+ }
+ else
+ {
+ bLetParentHandleThis = true;
+ pError = NULL; //terminate the handler
+ }
+ if ( bLetParentHandleThis )
+ {
+ // AB 13.2.1997, neues Error-Handling:
+ // Uebergeordnete Error-Handler beruecksichtigen
+
+ // Wir haben keinen Error-Handler -> weiter oben suchen
+ SbiRuntime* pRtErrHdl = NULL;
+ SbiRuntime* pRt = this;
+ while( NULL != (pRt = pRt->pNext) )
+ {
+ // Gibt es einen Error-Handler?
+ if( pRt->bError == sal_False || pRt->pError != NULL )
+ {
+ pRtErrHdl = pRt;
+ break;
+ }
+ }
+
+ // Error-Hdl gefunden?
+ if( pRtErrHdl )
+ {
+ // (Neuen) Error-Stack anlegen
+ SbErrorStack*& rErrStack = GetSbData()->pErrStack;
+ if( rErrStack )
+ delete rErrStack;
+ rErrStack = new SbErrorStack();
+
+ // Alle im Call-Stack darunter stehenden RTs manipulieren
+ pRt = this;
+ do
+ {
+ // Fehler setzen
+ pRt->nError = err;
+ if( pRt != pRtErrHdl )
+ pRt->bRun = sal_False;
+
+ // In Error-Stack eintragen
+ SbErrorStackEntry *pEntry = new SbErrorStackEntry
+ ( pRt->pMeth, pRt->nLine, pRt->nCol1, pRt->nCol2 );
+ rErrStack->C40_INSERT(SbErrorStackEntry, pEntry, rErrStack->Count() );
+
+ // Nach RT mit Error-Handler aufhoeren
+ if( pRt == pRtErrHdl )
+ break;
+ pRt = pRt->pNext;
+ }
+ while( pRt );
+ }
+ // Kein Error-Hdl gefunden -> altes Vorgehen
+ else
+ {
+#ifdef DBG_TRACE_BASIC
+ bTraceErrHandled = false;
+#endif
+ pInst->Abort();
+ }
+
+ // ALT: Nur
+ // pInst->Abort();
+ }
+
+#ifdef DBG_TRACE_BASIC
+ dbg_traceNotifyError( nTraceErr, aTraceErrMsg, bTraceErrHandled, pINST->nCallLvl );
+#endif
+ }
+ }
+ return bRun;
+}
+
+void SbiRuntime::Error( SbError n, bool bVBATranslationAlreadyDone )
+{
+ if( n )
+ {
+ nError = n;
+ if( isVBAEnabled() && !bVBATranslationAlreadyDone )
+ {
+ String aMsg = pInst->GetErrorMsg();
+ sal_Int32 nVBAErrorNumber = translateErrorToVba( nError, aMsg );
+ SbxVariable* pSbxErrObjVar = SbxErrObject::getErrObject();
+ SbxErrObject* pGlobErr = static_cast< SbxErrObject* >( pSbxErrObjVar );
+ if( pGlobErr != NULL )
+ pGlobErr->setNumberAndDescription( nVBAErrorNumber, aMsg );
+
+ pInst->aErrorMsg = aMsg;
+ nError = SbERR_BASIC_COMPAT;
+ }
+ }
+}
+
+void SbiRuntime::Error( SbError _errCode, const String& _details )
+{
+ if ( _errCode )
+ {
+ // Not correct for class module usage, remove for now
+ //OSL_ENSURE( pInst->pRun == this, "SbiRuntime::Error: can't propagate the error message details!" );
+ if ( pInst->pRun == this )
+ {
+ pInst->Error( _errCode, _details );
+ //OSL_POSTCOND( nError == _errCode, "SbiRuntime::Error: the instance is expecte to propagate the error code back to me!" );
+ }
+ else
+ {
+ nError = _errCode;
+ }
+ }
+}
+
+void SbiRuntime::FatalError( SbError n )
+{
+ StepSTDERROR();
+ Error( n );
+}
+
+void SbiRuntime::FatalError( SbError _errCode, const String& _details )
+{
+ StepSTDERROR();
+ Error( _errCode, _details );
+}
+
+sal_Int32 SbiRuntime::translateErrorToVba( SbError nError, String& rMsg )
+{
+ // If a message is defined use that ( in preference to
+ // the defined one for the error ) NB #TODO
+ // if there is an error defined it more than likely
+ // is not the one you want ( some are the same though )
+ // we really need a new vba compatible error list
+ if ( !rMsg.Len() )
+ {
+ // TEST, has to be vb here always
+#ifdef DBG_UTIL
+ SbError nTmp = StarBASIC::GetSfxFromVBError( (sal_uInt16)nError );
+ DBG_ASSERT( nTmp, "No VB error!" );
+#endif
+
+ StarBASIC::MakeErrorText( nError, rMsg );
+ rMsg = StarBASIC::GetErrorText();
+ if ( !rMsg.Len() ) // no message for err no, need localized resource here
+ rMsg = String( RTL_CONSTASCII_USTRINGPARAM("Internal Object Error:") );
+ }
+ // no num? most likely then it *is* really a vba err
+ sal_uInt16 nVBErrorCode = StarBASIC::GetVBErrorCode( nError );
+ sal_Int32 nVBAErrorNumber = ( nVBErrorCode == 0 ) ? nError : nVBErrorCode;
+ return nVBAErrorNumber;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Parameter, Locals, Caller
+//
+//////////////////////////////////////////////////////////////////////////
+
+SbMethod* SbiRuntime::GetCaller()
+{
+ return pMeth;
+}
+
+SbxArray* SbiRuntime::GetLocals()
+{
+ return refLocals;
+}
+
+SbxArray* SbiRuntime::GetParams()
+{
+ return refParams;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Stacks
+//
+//////////////////////////////////////////////////////////////////////////
+
+// Der Expression-Stack steht fuer die laufende Auswertung von Expressions
+// zur Verfuegung.
+
+void SbiRuntime::PushVar( SbxVariable* pVar )
+{
+ if( pVar )
+ refExprStk->Put( pVar, nExprLvl++ );
+}
+
+SbxVariableRef SbiRuntime::PopVar()
+{
+#ifdef DBG_UTIL
+ if( !nExprLvl )
+ {
+ StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
+ return new SbxVariable;
+ }
+#endif
+ SbxVariableRef xVar = refExprStk->Get( --nExprLvl );
+#ifdef DBG_UTIL
+ if ( xVar->GetName().EqualsAscii( "Cells" ) )
+ DBG_TRACE( "" );
+#endif
+ // Methods halten im 0.Parameter sich selbst, also weghauen
+ if( xVar->IsA( TYPE(SbxMethod) ) )
+ xVar->SetParameters(0);
+ return xVar;
+}
+
+sal_Bool SbiRuntime::ClearExprStack()
+{
+ // Achtung: Clear() reicht nicht, da Methods geloescht werden muessen
+ while ( nExprLvl )
+ {
+ PopVar();
+ }
+ refExprStk->Clear();
+ return sal_False;
+}
+
+// Variable auf dem Expression-Stack holen, ohne sie zu entfernen
+// n zaehlt ab 0.
+
+SbxVariable* SbiRuntime::GetTOS( short n )
+{
+ n = nExprLvl - n - 1;
+#ifdef DBG_UTIL
+ if( n < 0 )
+ {
+ StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
+ return new SbxVariable;
+ }
+#endif
+ return refExprStk->Get( (sal_uInt16) n );
+}
+
+// Sicherstellen, dass TOS eine temporaere Variable ist
+
+void SbiRuntime::TOSMakeTemp()
+{
+ SbxVariable* p = refExprStk->Get( nExprLvl - 1 );
+ if( p->GetRefCount() != 1 )
+ {
+ SbxVariable* pNew = new SbxVariable( *p );
+ pNew->SetFlag( SBX_READWRITE );
+ refExprStk->Put( pNew, nExprLvl - 1 );
+ }
+}
+
+// Der GOSUB-Stack nimmt Returnadressen fuer GOSUBs auf
+
+void SbiRuntime::PushGosub( const sal_uInt8* pc )
+{
+ if( ++nGosubLvl > MAXRECURSION )
+ StarBASIC::FatalError( SbERR_STACK_OVERFLOW );
+ SbiGosubStack* p = new SbiGosubStack;
+ p->pCode = pc;
+ p->pNext = pGosubStk;
+ p->nStartForLvl = nForLvl;
+ pGosubStk = p;
+}
+
+void SbiRuntime::PopGosub()
+{
+ if( !pGosubStk )
+ Error( SbERR_NO_GOSUB );
+ else
+ {
+ SbiGosubStack* p = pGosubStk;
+ pCode = p->pCode;
+ pGosubStk = p->pNext;
+ delete p;
+ nGosubLvl--;
+ }
+}
+
+// Entleeren des GOSUB-Stacks
+
+void SbiRuntime::ClearGosubStack()
+{
+ SbiGosubStack* p;
+ while(( p = pGosubStk ) != NULL )
+ pGosubStk = p->pNext, delete p;
+ nGosubLvl = 0;
+}
+
+// Der Argv-Stack nimmt aktuelle Argument-Vektoren auf
+
+void SbiRuntime::PushArgv()
+{
+ SbiArgvStack* p = new SbiArgvStack;
+ p->refArgv = refArgv;
+ p->nArgc = nArgc;
+ nArgc = 1;
+ refArgv.Clear();
+ p->pNext = pArgvStk;
+ pArgvStk = p;
+}
+
+void SbiRuntime::PopArgv()
+{
+ if( pArgvStk )
+ {
+ SbiArgvStack* p = pArgvStk;
+ pArgvStk = p->pNext;
+ refArgv = p->refArgv;
+ nArgc = p->nArgc;
+ delete p;
+ }
+}
+
+// Entleeren des Argv-Stacks
+
+void SbiRuntime::ClearArgvStack()
+{
+ while( pArgvStk )
+ PopArgv();
+}
+
+// Push des For-Stacks. Der Stack hat Inkrement, Ende, Beginn und Variable.
+// Nach Aufbau des Stack-Elements ist der Stack leer.
+
+void SbiRuntime::PushFor()
+{
+ SbiForStack* p = new SbiForStack;
+ p->eForType = FOR_TO;
+ p->pNext = pForStk;
+ pForStk = p;
+ // Der Stack ist wie folgt aufgebaut:
+ p->refInc = PopVar();
+ p->refEnd = PopVar();
+ SbxVariableRef xBgn = PopVar();
+ p->refVar = PopVar();
+ *(p->refVar) = *xBgn;
+ nForLvl++;
+}
+
+void SbiRuntime::PushForEach()
+{
+ SbiForStack* p = new SbiForStack;
+ p->pNext = pForStk;
+ pForStk = p;
+
+ SbxVariableRef xObjVar = PopVar();
+ SbxBase* pObj = xObjVar.Is() ? xObjVar->GetObject() : NULL;
+ if( pObj == NULL )
+ {
+ Error( SbERR_NO_OBJECT );
+ return;
+ }
+
+ bool bError_ = false;
+ BasicCollection* pCollection;
+ SbxDimArray* pArray;
+ SbUnoObject* pUnoObj;
+ if( (pArray = PTR_CAST(SbxDimArray,pObj)) != NULL )
+ {
+ p->eForType = FOR_EACH_ARRAY;
+ p->refEnd = (SbxVariable*)pArray;
+
+ short nDims = pArray->GetDims();
+ p->pArrayLowerBounds = new sal_Int32[nDims];
+ p->pArrayUpperBounds = new sal_Int32[nDims];
+ p->pArrayCurIndices = new sal_Int32[nDims];
+ sal_Int32 lBound, uBound;
+ for( short i = 0 ; i < nDims ; i++ )
+ {
+ pArray->GetDim32( i+1, lBound, uBound );
+ p->pArrayCurIndices[i] = p->pArrayLowerBounds[i] = lBound;
+ p->pArrayUpperBounds[i] = uBound;
+ }
+ }
+ else if( (pCollection = PTR_CAST(BasicCollection,pObj)) != NULL )
+ {
+ p->eForType = FOR_EACH_COLLECTION;
+ p->refEnd = pCollection;
+ p->nCurCollectionIndex = 0;
+ }
+ else if( (pUnoObj = PTR_CAST(SbUnoObject,pObj)) != NULL )
+ {
+ // XEnumerationAccess?
+ Any aAny = pUnoObj->getUnoAny();
+ Reference< XEnumerationAccess > xEnumerationAccess;
+ if( (aAny >>= xEnumerationAccess) )
+ {
+ p->xEnumeration = xEnumerationAccess->createEnumeration();
+ p->eForType = FOR_EACH_XENUMERATION;
+ }
+ else if ( isVBAEnabled() && pUnoObj->isNativeCOMObject() )
+ {
+ uno::Reference< script::XInvocation > xInvocation;
+ if ( ( aAny >>= xInvocation ) && xInvocation.is() )
+ {
+ try
+ {
+ p->xEnumeration = new ComEnumerationWrapper( xInvocation );
+ p->eForType = FOR_EACH_XENUMERATION;
+ }
+ catch( uno::Exception& )
+ {}
+ }
+
+ if ( !p->xEnumeration.is() )
+ bError_ = true;
+ }
+ else
+ {
+ bError_ = true;
+ }
+ }
+ else
+ {
+ bError_ = true;
+ }
+
+ if( bError_ )
+ {
+ Error( SbERR_CONVERSION );
+ return;
+ }
+
+ // Container variable
+ p->refVar = PopVar();
+ nForLvl++;
+}
+
+// Poppen des FOR-Stacks
+
+void SbiRuntime::PopFor()
+{
+ if( pForStk )
+ {
+ SbiForStack* p = pForStk;
+ pForStk = p->pNext;
+ delete p;
+ nForLvl--;
+ }
+}
+
+// Entleeren des FOR-Stacks
+
+void SbiRuntime::ClearForStack()
+{
+ while( pForStk )
+ PopFor();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//
+// DLL-Aufrufe
+//
+//////////////////////////////////////////////////////////////////////////
+
+void SbiRuntime::DllCall
+ ( const String& aFuncName, // Funktionsname
+ const String& aDLLName, // Name der DLL
+ SbxArray* pArgs, // Parameter (ab Index 1, kann NULL sein)
+ SbxDataType eResType, // Returnwert
+ sal_Bool bCDecl ) // sal_True: nach C-Konventionen
+{
+ // No DllCall for "virtual" portal users
+ if( needSecurityRestrictions() )
+ {
+ StarBASIC::Error(SbERR_NOT_IMPLEMENTED);
+ return;
+ }
+
+ // MUSS NOCH IMPLEMENTIERT WERDEN
+ /*
+ String aMsg;
+ aMsg = "FUNC=";
+ aMsg += pFunc;
+ aMsg += " DLL=";
+ aMsg += pDLL;
+ MessBox( NULL, WB_OK, String( "DLL-CALL" ), aMsg ).Execute();
+ Error( SbERR_NOT_IMPLEMENTED );
+ */
+
+ SbxVariable* pRes = new SbxVariable( eResType );
+ SbiDllMgr* pDllMgr = pInst->GetDllMgr();
+ SbError nErr = pDllMgr->Call( aFuncName, aDLLName, pArgs, *pRes, bCDecl );
+ if( nErr )
+ Error( nErr );
+ PushVar( pRes );
+}
+
+sal_uInt16 SbiRuntime::GetImageFlag( sal_uInt16 n ) const
+{
+ return pImg->GetFlag( n );
+}
+
+sal_uInt16 SbiRuntime::GetBase()
+{
+ return pImg->GetBase();
+}