1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26
27 #include <stdlib.h>
28 #include <rtl/math.hxx>
29 #include <basic/sbuno.hxx>
30 #include "runtime.hxx"
31 #include "sbintern.hxx"
32 #include "iosys.hxx"
33 #include "image.hxx"
34 #include "sbunoobj.hxx"
35 #include "errobject.hxx"
36
37 bool checkUnoObjectType( SbUnoObject* refVal, const ::rtl::OUString& aClass );
38
39 // Laden einer numerischen Konstanten (+ID)
40
StepLOADNC(sal_uInt32 nOp1)41 void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 )
42 {
43 SbxVariable* p = new SbxVariable( SbxDOUBLE );
44
45 // #57844 Lokalisierte Funktion benutzen
46 String aStr = pImg->GetString( static_cast<short>( nOp1 ) );
47 // Auch , zulassen !!!
48 sal_uInt16 iComma = aStr.Search( ',' );
49 if( iComma != STRING_NOTFOUND )
50 {
51 String aStr1 = aStr.Copy( 0, iComma );
52 String aStr2 = aStr.Copy( iComma + 1 );
53 aStr = aStr1;
54 aStr += '.';
55 aStr += aStr2;
56 }
57 double n = ::rtl::math::stringToDouble( aStr, '.', ',', NULL, NULL );
58
59 p->PutDouble( n );
60 PushVar( p );
61 }
62
63 // Laden einer Stringkonstanten (+ID)
64
StepLOADSC(sal_uInt32 nOp1)65 void SbiRuntime::StepLOADSC( sal_uInt32 nOp1 )
66 {
67 SbxVariable* p = new SbxVariable;
68 p->PutString( pImg->GetString( static_cast<short>( nOp1 ) ) );
69 PushVar( p );
70 }
71
72 // Immediate Load (+Wert)
73
StepLOADI(sal_uInt32 nOp1)74 void SbiRuntime::StepLOADI( sal_uInt32 nOp1 )
75 {
76 SbxVariable* p = new SbxVariable;
77 p->PutInteger( static_cast<sal_Int16>( nOp1 ) );
78 PushVar( p );
79 }
80
81 // Speichern eines named Arguments in Argv (+Arg-Nr ab 1!)
82
StepARGN(sal_uInt32 nOp1)83 void SbiRuntime::StepARGN( sal_uInt32 nOp1 )
84 {
85 if( !refArgv )
86 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
87 else
88 {
89 String aAlias( pImg->GetString( static_cast<short>( nOp1 ) ) );
90 SbxVariableRef pVal = PopVar();
91 refArgv->Put( pVal, nArgc );
92 refArgv->PutAlias( aAlias, nArgc++ );
93 }
94 }
95
96 // Konvertierung des Typs eines Arguments in Argv fuer DECLARE-Fkt. (+Typ)
97
StepARGTYP(sal_uInt32 nOp1)98 void SbiRuntime::StepARGTYP( sal_uInt32 nOp1 )
99 {
100 if( !refArgv )
101 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
102 else
103 {
104 sal_Bool bByVal = (nOp1 & 0x8000) != 0; // Ist BYVAL verlangt?
105 SbxDataType t = (SbxDataType) (nOp1 & 0x7FFF);
106 SbxVariable* pVar = refArgv->Get( refArgv->Count() - 1 ); // letztes Arg
107
108 // BYVAL pr�fen
109 if( pVar->GetRefCount() > 2 ) // 2 ist normal f�r BYVAL
110 {
111 // Parameter ist eine Referenz
112 if( bByVal )
113 {
114 // Call by Value ist verlangt -> Kopie anlegen
115 pVar = new SbxVariable( *pVar );
116 pVar->SetFlag( SBX_READWRITE );
117 refExprStk->Put( pVar, refArgv->Count() - 1 );
118 }
119 else
120 pVar->SetFlag( SBX_REFERENCE ); // Ref-Flag f�r DllMgr
121 }
122 else
123 {
124 // Parameter ist KEINE Referenz
125 if( bByVal )
126 pVar->ResetFlag( SBX_REFERENCE ); // Keine Referenz -> OK
127 else
128 Error( SbERR_BAD_PARAMETERS ); // Referenz verlangt
129 }
130
131 if( pVar->GetType() != t )
132 {
133 // Variant, damit richtige Konvertierung
134 // Ausserdem Fehler, wenn SbxBYREF
135 pVar->Convert( SbxVARIANT );
136 pVar->Convert( t );
137 }
138 }
139 }
140
141 // String auf feste Laenge bringen (+Laenge)
142
StepPAD(sal_uInt32 nOp1)143 void SbiRuntime::StepPAD( sal_uInt32 nOp1 )
144 {
145 SbxVariable* p = GetTOS();
146 String& s = (String&)(const String&) *p;
147 if( s.Len() > nOp1 )
148 s.Erase( static_cast<xub_StrLen>( nOp1 ) );
149 else
150 s.Expand( static_cast<xub_StrLen>( nOp1 ), ' ' );
151 }
152
153 // Sprung (+Target)
154
StepJUMP(sal_uInt32 nOp1)155 void SbiRuntime::StepJUMP( sal_uInt32 nOp1 )
156 {
157 #ifdef DBG_UTIL
158 // #QUESTION shouln't this be
159 // if( (sal_uInt8*)( nOp1+pImagGetCode() ) >= pImg->GetCodeSize() )
160 if( nOp1 >= pImg->GetCodeSize() )
161 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
162 #endif
163 pCode = (const sal_uInt8*) pImg->GetCode() + nOp1;
164 }
165
166 // TOS auswerten, bedingter Sprung (+Target)
167
StepJUMPT(sal_uInt32 nOp1)168 void SbiRuntime::StepJUMPT( sal_uInt32 nOp1 )
169 {
170 SbxVariableRef p = PopVar();
171 if( p->GetBool() )
172 StepJUMP( nOp1 );
173 }
174
175 // TOS auswerten, bedingter Sprung (+Target)
176
StepJUMPF(sal_uInt32 nOp1)177 void SbiRuntime::StepJUMPF( sal_uInt32 nOp1 )
178 {
179 SbxVariableRef p = PopVar();
180 if( !p->GetBool() )
181 StepJUMP( nOp1 );
182 }
183
184 // TOS auswerten, Sprung in JUMP-Tabelle (+MaxVal)
185 // Sieht so aus:
186 // ONJUMP 2
187 // JUMP target1
188 // JUMP target2
189 // ...
190 //Falls im Operanden 0x8000 gesetzt ist, Returnadresse pushen (ON..GOSUB)
191
StepONJUMP(sal_uInt32 nOp1)192 void SbiRuntime::StepONJUMP( sal_uInt32 nOp1 )
193 {
194 SbxVariableRef p = PopVar();
195 sal_Int16 n = p->GetInteger();
196 if( nOp1 & 0x8000 )
197 {
198 nOp1 &= 0x7FFF;
199 //PushGosub( pCode + 3 * nOp1 );
200 PushGosub( pCode + 5 * nOp1 );
201 }
202 if( n < 1 || static_cast<sal_uInt32>(n) > nOp1 )
203 n = static_cast<sal_Int16>( nOp1 + 1 );
204 //nOp1 = (sal_uInt32) ( (const char*) pCode - pImg->GetCode() ) + 3 * --n;
205 nOp1 = (sal_uInt32) ( (const char*) pCode - pImg->GetCode() ) + 5 * --n;
206 StepJUMP( nOp1 );
207 }
208
209 // UP-Aufruf (+Target)
210
StepGOSUB(sal_uInt32 nOp1)211 void SbiRuntime::StepGOSUB( sal_uInt32 nOp1 )
212 {
213 PushGosub( pCode );
214 if( nOp1 >= pImg->GetCodeSize() )
215 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
216 pCode = (const sal_uInt8*) pImg->GetCode() + nOp1;
217 }
218
219 // UP-Return (+0 oder Target)
220
StepRETURN(sal_uInt32 nOp1)221 void SbiRuntime::StepRETURN( sal_uInt32 nOp1 )
222 {
223 PopGosub();
224 if( nOp1 )
225 StepJUMP( nOp1 );
226 }
227
228 // FOR-Variable testen (+Endlabel)
229
StepTESTFOR(sal_uInt32 nOp1)230 void SbiRuntime::StepTESTFOR( sal_uInt32 nOp1 )
231 {
232 if( !pForStk )
233 {
234 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
235 return;
236 }
237
238 bool bEndLoop = false;
239 switch( pForStk->eForType )
240 {
241 case FOR_TO:
242 {
243 SbxOperator eOp = ( pForStk->refInc->GetDouble() < 0 ) ? SbxLT : SbxGT;
244 if( pForStk->refVar->Compare( eOp, *pForStk->refEnd ) )
245 bEndLoop = true;
246 break;
247 }
248 case FOR_EACH_ARRAY:
249 {
250 SbiForStack* p = pForStk;
251 if( p->pArrayCurIndices == NULL )
252 {
253 bEndLoop = true;
254 }
255 else
256 {
257 SbxDimArray* pArray = (SbxDimArray*)(SbxVariable*)p->refEnd;
258 short nDims = pArray->GetDims();
259
260 // Empty array?
261 if( nDims == 1 && p->pArrayLowerBounds[0] > p->pArrayUpperBounds[0] )
262 {
263 bEndLoop = true;
264 break;
265 }
266 SbxVariable* pVal = pArray->Get32( p->pArrayCurIndices );
267 *(p->refVar) = *pVal;
268
269 bool bFoundNext = false;
270 for( short i = 0 ; i < nDims ; i++ )
271 {
272 if( p->pArrayCurIndices[i] < p->pArrayUpperBounds[i] )
273 {
274 bFoundNext = true;
275 p->pArrayCurIndices[i]++;
276 for( short j = i - 1 ; j >= 0 ; j-- )
277 p->pArrayCurIndices[j] = p->pArrayLowerBounds[j];
278 break;
279 }
280 }
281 if( !bFoundNext )
282 {
283 delete[] p->pArrayCurIndices;
284 p->pArrayCurIndices = NULL;
285 }
286 }
287 break;
288 }
289 case FOR_EACH_COLLECTION:
290 {
291 BasicCollection* pCollection = (BasicCollection*)(SbxVariable*)pForStk->refEnd;
292 SbxArrayRef xItemArray = pCollection->xItemArray;
293 sal_Int32 nCount = xItemArray->Count32();
294 if( pForStk->nCurCollectionIndex < nCount )
295 {
296 SbxVariable* pRes = xItemArray->Get32( pForStk->nCurCollectionIndex );
297 pForStk->nCurCollectionIndex++;
298 (*pForStk->refVar) = *pRes;
299 }
300 else
301 {
302 bEndLoop = true;
303 }
304 break;
305 }
306 case FOR_EACH_XENUMERATION:
307 {
308 SbiForStack* p = pForStk;
309 if( p->xEnumeration->hasMoreElements() )
310 {
311 Any aElem = p->xEnumeration->nextElement();
312 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
313 unoToSbxValue( (SbxVariable*)xVar, aElem );
314 (*pForStk->refVar) = *xVar;
315 }
316 else
317 {
318 bEndLoop = true;
319 }
320 break;
321 }
322 }
323 if( bEndLoop )
324 {
325 PopFor();
326 StepJUMP( nOp1 );
327 }
328 }
329
330 // Tos+1 <= Tos+2 <= Tos, 2xremove (+Target)
331
StepCASETO(sal_uInt32 nOp1)332 void SbiRuntime::StepCASETO( sal_uInt32 nOp1 )
333 {
334 if( !refCaseStk || !refCaseStk->Count() )
335 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
336 else
337 {
338 SbxVariableRef xTo = PopVar();
339 SbxVariableRef xFrom = PopVar();
340 SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 );
341 if( *xCase >= *xFrom && *xCase <= *xTo )
342 StepJUMP( nOp1 );
343 }
344 }
345
346 // Fehler-Handler
347
StepERRHDL(sal_uInt32 nOp1)348 void SbiRuntime::StepERRHDL( sal_uInt32 nOp1 )
349 {
350 const sal_uInt8* p = pCode;
351 StepJUMP( nOp1 );
352 pError = pCode;
353 pCode = p;
354 pInst->aErrorMsg = String();
355 pInst->nErr = 0;
356 pInst->nErl = 0;
357 nError = 0;
358 SbxErrObject::getUnoErrObject()->Clear();
359 }
360
361 // Resume nach Fehlern (+0=statement, 1=next or Label)
362
StepRESUME(sal_uInt32 nOp1)363 void SbiRuntime::StepRESUME( sal_uInt32 nOp1 )
364 {
365 // AB #32714 Resume ohne Error? -> Fehler
366 if( !bInError )
367 {
368 Error( SbERR_BAD_RESUME );
369 return;
370 }
371 if( nOp1 )
372 {
373 // Code-Zeiger auf naechstes Statement setzen
374 sal_uInt16 n1, n2;
375 pCode = pMod->FindNextStmnt( pErrCode, n1, n2, sal_True, pImg );
376 }
377 else
378 pCode = pErrStmnt;
379 if ( pError ) // current in error handler ( and got a Resume Next statement )
380 SbxErrObject::getUnoErrObject()->Clear();
381
382 if( nOp1 > 1 )
383 StepJUMP( nOp1 );
384 pInst->aErrorMsg = String();
385 pInst->nErr = 0;
386 pInst->nErl = 0;
387 nError = 0;
388 bInError = sal_False;
389
390 // Error-Stack loeschen
391 SbErrorStack*& rErrStack = GetSbData()->pErrStack;
392 delete rErrStack;
393 rErrStack = NULL;
394 }
395
396 // Kanal schliessen (+Kanal, 0=Alle)
StepCLOSE(sal_uInt32 nOp1)397 void SbiRuntime::StepCLOSE( sal_uInt32 nOp1 )
398 {
399 SbError err;
400 if( !nOp1 )
401 pIosys->Shutdown();
402 else
403 {
404 err = pIosys->GetError();
405 if( !err )
406 {
407 pIosys->Close();
408 }
409 }
410 err = pIosys->GetError();
411 Error( err );
412 }
413
414 // Zeichen ausgeben (+char)
415
StepPRCHAR(sal_uInt32 nOp1)416 void SbiRuntime::StepPRCHAR( sal_uInt32 nOp1 )
417 {
418 ByteString s( (char) nOp1 );
419 pIosys->Write( s );
420 Error( pIosys->GetError() );
421 }
422
423 // Check, ob TOS eine bestimmte Objektklasse ist (+StringID)
424
implIsClass(SbxObject * pObj,const String & aClass)425 bool SbiRuntime::implIsClass( SbxObject* pObj, const String& aClass )
426 {
427 bool bRet = true;
428
429 if( aClass.Len() != 0 )
430 {
431 bRet = pObj->IsClass( aClass );
432 if( !bRet )
433 bRet = aClass.EqualsIgnoreCaseAscii( String( RTL_CONSTASCII_USTRINGPARAM("object") ) );
434 if( !bRet )
435 {
436 String aObjClass = pObj->GetClassName();
437 SbModule* pClassMod = pCLASSFAC->FindClass( aObjClass );
438 SbClassData* pClassData;
439 if( pClassMod && (pClassData=pClassMod->pClassData) != NULL )
440 {
441 SbxVariable* pClassVar =
442 pClassData->mxIfaces->Find( aClass, SbxCLASS_DONTCARE );
443 bRet = (pClassVar != NULL);
444 }
445 }
446 }
447 return bRet;
448 }
449
checkClass_Impl(const SbxVariableRef & refVal,const String & aClass,bool bRaiseErrors,bool bDefault)450 bool SbiRuntime::checkClass_Impl( const SbxVariableRef& refVal,
451 const String& aClass, bool bRaiseErrors, bool bDefault )
452 {
453 bool bOk = bDefault;
454
455 SbxDataType t = refVal->GetType();
456 if( t == SbxOBJECT )
457 {
458 SbxObject* pObj;
459 SbxVariable* pVal = (SbxVariable*)refVal;
460 if( pVal->IsA( TYPE(SbxObject) ) )
461 pObj = (SbxObject*) pVal;
462 else
463 {
464 pObj = (SbxObject*) refVal->GetObject();
465 if( pObj && !pObj->IsA( TYPE(SbxObject) ) )
466 pObj = NULL;
467 }
468 if( pObj )
469 {
470 if( !implIsClass( pObj, aClass ) )
471 {
472 if ( bVBAEnabled && pObj->IsA( TYPE(SbUnoObject) ) )
473 {
474 SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pObj);
475 bOk = checkUnoObjectType( pUnoObj, aClass );
476 }
477 else
478 bOk = false;
479 if ( !bOk )
480 {
481 if( bRaiseErrors )
482 Error( SbERR_INVALID_USAGE_OBJECT );
483 }
484 }
485 else
486 {
487 bOk = true;
488
489 SbClassModuleObject* pClassModuleObject = PTR_CAST(SbClassModuleObject,pObj);
490 if( pClassModuleObject != NULL )
491 pClassModuleObject->triggerInitializeEvent();
492 }
493 }
494 }
495 else
496 {
497 if ( !bVBAEnabled )
498 {
499 if( bRaiseErrors )
500 Error( SbERR_NEEDS_OBJECT );
501 bOk = false;
502 }
503 }
504 return bOk;
505 }
506
StepSETCLASS_impl(sal_uInt32 nOp1,bool bHandleDflt)507 void SbiRuntime::StepSETCLASS_impl( sal_uInt32 nOp1, bool bHandleDflt )
508 {
509 SbxVariableRef refVal = PopVar();
510 SbxVariableRef refVar = PopVar();
511 String aClass( pImg->GetString( static_cast<short>( nOp1 ) ) );
512
513 bool bOk = checkClass_Impl( refVal, aClass, true );
514 if( bOk )
515 StepSET_Impl( refVal, refVar, bHandleDflt ); // don't do handle dflt prop for a "proper" set
516 }
517
StepVBASETCLASS(sal_uInt32 nOp1)518 void SbiRuntime::StepVBASETCLASS( sal_uInt32 nOp1 )
519 {
520 StepSETCLASS_impl( nOp1, false );
521 }
522
StepSETCLASS(sal_uInt32 nOp1)523 void SbiRuntime::StepSETCLASS( sal_uInt32 nOp1 )
524 {
525 StepSETCLASS_impl( nOp1, true );
526 }
527
StepTESTCLASS(sal_uInt32 nOp1)528 void SbiRuntime::StepTESTCLASS( sal_uInt32 nOp1 )
529 {
530 SbxVariableRef xObjVal = PopVar();
531 String aClass( pImg->GetString( static_cast<short>( nOp1 ) ) );
532 bool bDefault = !bVBAEnabled;
533 bool bOk = checkClass_Impl( xObjVal, aClass, false, bDefault );
534
535 SbxVariable* pRet = new SbxVariable;
536 pRet->PutBool( bOk );
537 PushVar( pRet );
538 }
539
540 // Library fuer anschliessenden Declare-Call definieren
541
StepLIB(sal_uInt32 nOp1)542 void SbiRuntime::StepLIB( sal_uInt32 nOp1 )
543 {
544 aLibName = pImg->GetString( static_cast<short>( nOp1 ) );
545 }
546
547 // TOS wird um BASE erhoeht, BASE davor gepusht (+BASE)
548 // Dieser Opcode wird vor DIM/REDIM-Anweisungen gepusht,
549 // wenn nur ein Index angegeben wurde.
550
StepBASED(sal_uInt32 nOp1)551 void SbiRuntime::StepBASED( sal_uInt32 nOp1 )
552 {
553 SbxVariable* p1 = new SbxVariable;
554 SbxVariableRef x2 = PopVar();
555
556 // #109275 Check compatibility mode
557 bool bCompatible = ((nOp1 & 0x8000) != 0);
558 sal_uInt16 uBase = static_cast<sal_uInt16>(nOp1 & 1); // Can only be 0 or 1
559 p1->PutInteger( uBase );
560 if( !bCompatible )
561 x2->Compute( SbxPLUS, *p1 );
562 PushVar( x2 ); // erst die Expr
563 PushVar( p1 ); // dann die Base
564 }
565
566
567
568
569
570