Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include <math.h>
22 : #include <tools/stream.hxx>
23 :
24 : #include <basic/sbx.hxx>
25 : #include "sbxconv.hxx"
26 : #include "runtime.hxx"
27 :
28 30483 : TYPEINIT1(SbxValue,SbxBase)
29 :
30 : ///////////////////////////// constructors //////////////////////////////
31 :
32 41 : SbxValue::SbxValue() : SbxBase()
33 : {
34 41 : aData.eType = SbxEMPTY;
35 41 : }
36 :
37 8357 : SbxValue::SbxValue( SbxDataType t, void* p ) : SbxBase()
38 : {
39 8357 : int n = t & 0x0FFF;
40 8357 : if( p )
41 0 : n |= SbxBYREF;
42 8357 : if( n == SbxVARIANT )
43 9 : n = SbxEMPTY;
44 : else
45 8348 : SetFlag( SBX_FIXED );
46 8357 : if( p )
47 0 : switch( t & 0x0FFF )
48 : {
49 0 : case SbxINTEGER: n |= SbxBYREF; aData.pInteger = (sal_Int16*) p; break;
50 0 : case SbxSALUINT64: n |= SbxBYREF; aData.puInt64 = (sal_uInt64*) p; break;
51 : case SbxSALINT64:
52 0 : case SbxCURRENCY: n |= SbxBYREF; aData.pnInt64 = (sal_Int64*) p; break;
53 0 : case SbxLONG: n |= SbxBYREF; aData.pLong = (sal_Int32*) p; break;
54 0 : case SbxSINGLE: n |= SbxBYREF; aData.pSingle = (float*) p; break;
55 : case SbxDATE:
56 0 : case SbxDOUBLE: n |= SbxBYREF; aData.pDouble = (double*) p; break;
57 0 : case SbxSTRING: n |= SbxBYREF; aData.pOUString = (::rtl::OUString*) p; break;
58 : case SbxERROR:
59 : case SbxUSHORT:
60 0 : case SbxBOOL: n |= SbxBYREF; aData.pUShort = (sal_uInt16*) p; break;
61 0 : case SbxULONG: n |= SbxBYREF; aData.pULong = (sal_uInt32*) p; break;
62 0 : case SbxCHAR: n |= SbxBYREF; aData.pChar = (sal_Unicode*) p; break;
63 0 : case SbxBYTE: n |= SbxBYREF; aData.pByte = (sal_uInt8*) p; break;
64 0 : case SbxINT: n |= SbxBYREF; aData.pInt = (int*) p; break;
65 : case SbxOBJECT:
66 0 : aData.pObj = (SbxBase*) p;
67 0 : if( p )
68 0 : aData.pObj->AddRef();
69 0 : break;
70 : case SbxDECIMAL:
71 0 : aData.pDecimal = (SbxDecimal*) p;
72 0 : if( p )
73 0 : aData.pDecimal->addRef();
74 0 : break;
75 : default:
76 : DBG_ASSERT( !this, "Angabe eines Pointers unzulaessig" );
77 0 : n = SbxNULL;
78 : }
79 : else
80 8357 : memset( &aData, 0, sizeof( SbxValues ) );
81 8357 : aData.eType = SbxDataType( n );
82 8357 : }
83 :
84 75 : SbxValue::SbxValue( const SbxValue& r )
85 75 : : SvRefBase( r ), SbxBase( r )
86 : {
87 75 : if( !r.CanRead() )
88 : {
89 0 : SetError( SbxERR_PROP_WRITEONLY );
90 0 : if( !IsFixed() )
91 0 : aData.eType = SbxNULL;
92 : }
93 : else
94 : {
95 75 : ((SbxValue*) &r)->Broadcast( SBX_HINT_DATAWANTED );
96 75 : aData = r.aData;
97 : // Copy pointer, increment references
98 75 : switch( aData.eType )
99 : {
100 : case SbxSTRING:
101 4 : if( aData.pOUString )
102 2 : aData.pOUString = new ::rtl::OUString( *aData.pOUString );
103 4 : break;
104 : case SbxOBJECT:
105 0 : if( aData.pObj )
106 0 : aData.pObj->AddRef();
107 0 : break;
108 : case SbxDECIMAL:
109 0 : if( aData.pDecimal )
110 0 : aData.pDecimal->addRef();
111 0 : break;
112 71 : default: break;
113 : }
114 : }
115 75 : }
116 :
117 29 : SbxValue& SbxValue::operator=( const SbxValue& r )
118 : {
119 29 : if( &r != this )
120 : {
121 29 : if( !CanWrite() )
122 0 : SetError( SbxERR_PROP_READONLY );
123 : else
124 : {
125 : // string -> byte array
126 29 : if( IsFixed() && (aData.eType == SbxOBJECT)
127 0 : && aData.pObj && ( aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
128 : && (r.aData.eType == SbxSTRING) )
129 : {
130 0 : OUString aStr = r.GetOUString();
131 0 : SbxArray* pArr = StringToByteArray(aStr);
132 0 : PutObject(pArr);
133 0 : return *this;
134 : }
135 : // byte array -> string
136 29 : if( r.IsFixed() && (r.aData.eType == SbxOBJECT)
137 0 : && r.aData.pObj && ( r.aData.pObj->GetType() == (SbxARRAY | SbxBYTE) )
138 : && (aData.eType == SbxSTRING) )
139 : {
140 0 : SbxBase* pObj = r.GetObject();
141 0 : SbxArray* pArr = PTR_CAST(SbxArray, pObj);
142 0 : if( pArr )
143 : {
144 0 : ::rtl::OUString aStr = ByteArrayToString( pArr );
145 0 : PutString(aStr);
146 0 : return *this;
147 : }
148 : }
149 : // Readout the content of the variables
150 29 : SbxValues aNew;
151 29 : if( IsFixed() )
152 : // firm: then the type had to match
153 16 : aNew.eType = aData.eType;
154 13 : else if( r.IsFixed() )
155 : // Source firm: take over the type
156 1 : aNew.eType = SbxDataType( r.aData.eType & 0x0FFF );
157 : else
158 : // both variant: then it is equal
159 12 : aNew.eType = SbxVARIANT;
160 29 : if( r.Get( aNew ) )
161 29 : Put( aNew );
162 : }
163 : }
164 29 : return *this;
165 : }
166 :
167 12146 : SbxValue::~SbxValue()
168 : {
169 6073 : Broadcast( SBX_HINT_DYING );
170 6073 : SetFlag( SBX_WRITE );
171 6073 : SbxValue::Clear();
172 12146 : }
173 :
174 6131 : void SbxValue::Clear()
175 : {
176 6131 : switch( aData.eType )
177 : {
178 : case SbxNULL:
179 : case SbxEMPTY:
180 : case SbxVOID:
181 865 : break;
182 : case SbxSTRING:
183 1897 : delete aData.pOUString; aData.pOUString = NULL;
184 1897 : break;
185 : case SbxOBJECT:
186 3274 : if( aData.pObj )
187 : {
188 1370 : if( aData.pObj != this )
189 : {
190 : SAL_WARN("basic.sbx", "nicht bei Parent-Prop - sonst CyclicRef");
191 28 : SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
192 : sal_Bool bParentProp = pThisVar && 5345 ==
193 28 : ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
194 28 : if ( !bParentProp )
195 28 : aData.pObj->ReleaseRef();
196 : }
197 1370 : aData.pObj = NULL;
198 : }
199 3274 : break;
200 : case SbxDECIMAL:
201 14 : if( aData.eType == SbxDECIMAL )
202 14 : releaseDecimalPtr( aData.pDecimal );
203 14 : break;
204 : case SbxDATAOBJECT:
205 0 : aData.pData = NULL; break;
206 : default:
207 : {
208 81 : SbxValues aEmpty;
209 81 : memset( &aEmpty, 0, sizeof( SbxValues ) );
210 81 : aEmpty.eType = GetType();
211 81 : Put( aEmpty );
212 : }
213 : }
214 6131 : }
215 :
216 : // Dummy
217 :
218 6312 : void SbxValue::Broadcast( sal_uIntPtr )
219 6312 : {}
220 :
221 : //////////////////////////// Readout data //////////////////////////////
222 :
223 : // Detect the "right" variables. If it is an object, will be addressed either
224 : // the object itself or its default property.
225 : // If the variable contain a variable or an object, this will be
226 : // addressed.
227 :
228 55 : SbxValue* SbxValue::TheRealValue() const
229 : {
230 55 : return TheRealValue( sal_True );
231 : }
232 :
233 : // #55226 ship additional information
234 : bool handleToStringForCOMObjects( SbxObject* pObj, SbxValue* pVal ); // sbunoobj.cxx
235 :
236 299 : SbxValue* SbxValue::TheRealValue( sal_Bool bObjInObjError ) const
237 : {
238 299 : SbxValue* p = (SbxValue*) this;
239 0 : for( ;; )
240 : {
241 299 : SbxDataType t = SbxDataType( p->aData.eType & 0x0FFF );
242 299 : if( t == SbxOBJECT )
243 : {
244 : // The block contains an object or a variable
245 0 : SbxObject* pObj = PTR_CAST(SbxObject,p->aData.pObj);
246 0 : if( pObj )
247 : {
248 : // Has the object a default property?
249 0 : SbxVariable* pDflt = pObj->GetDfltProperty();
250 :
251 : // If this is an object and contains itself,
252 : // we cannot access on it
253 : // The old condition to set an error
254 : // is not correct, because e.g. a regular variant variable with an object
255 : // could be affected thereof, if another value should be assigned.
256 : // Therefore with flag.
257 0 : if( bObjInObjError && !pDflt &&
258 : ((SbxValue*) pObj)->aData.eType == SbxOBJECT &&
259 : ((SbxValue*) pObj)->aData.pObj == pObj )
260 : {
261 : #ifdef DISABLE_SCRIPTING // No sbunoobj
262 : const bool bSuccess = false;
263 : #else
264 0 : bool bSuccess = handleToStringForCOMObjects( pObj, p );
265 : #endif
266 0 : if( !bSuccess )
267 : {
268 0 : SetError( SbxERR_BAD_PROP_VALUE );
269 0 : p = NULL;
270 0 : }
271 : }
272 0 : else if( pDflt )
273 0 : p = pDflt;
274 0 : break;
275 : }
276 : // Did we have an array?
277 0 : SbxArray* pArray = PTR_CAST(SbxArray,p->aData.pObj);
278 0 : if( pArray )
279 : {
280 : // When indicated get the parameter
281 0 : SbxArray* pPar = NULL;
282 0 : SbxVariable* pVar = PTR_CAST(SbxVariable,p);
283 0 : if( pVar )
284 0 : pPar = pVar->GetParameters();
285 0 : if( pPar )
286 : {
287 : // Did we have a dimensioned array?
288 0 : SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,p->aData.pObj);
289 0 : if( pDimArray )
290 0 : p = pDimArray->Get( pPar );
291 : else
292 0 : p = pArray->Get( pPar->Get( 1 )->GetInteger() );
293 0 : break;
294 : }
295 : }
296 : // Elsewise guess a SbxValue
297 0 : SbxValue* pVal = PTR_CAST(SbxValue,p->aData.pObj);
298 0 : if( pVal )
299 0 : p = pVal;
300 : else
301 0 : break;
302 : }
303 : else
304 299 : break;
305 : }
306 299 : return p;
307 : }
308 :
309 4165 : sal_Bool SbxValue::Get( SbxValues& rRes ) const
310 : {
311 4165 : sal_Bool bRes = sal_False;
312 4165 : SbxError eOld = GetError();
313 4165 : if( eOld != SbxERR_OK )
314 0 : ResetError();
315 4165 : if( !CanRead() )
316 : {
317 0 : SetError( SbxERR_PROP_WRITEONLY );
318 0 : rRes.pObj = NULL;
319 : }
320 : else
321 : {
322 : // If there was asked for an object or a VARIANT, don't search
323 : // the real values
324 4165 : SbxValue* p = (SbxValue*) this;
325 4165 : if( rRes.eType != SbxOBJECT && rRes.eType != SbxVARIANT )
326 55 : p = TheRealValue();
327 4165 : if( p )
328 : {
329 4165 : p->Broadcast( SBX_HINT_DATAWANTED );
330 4165 : switch( rRes.eType )
331 : {
332 : case SbxEMPTY:
333 : case SbxVOID:
334 0 : case SbxNULL: break;
335 12 : case SbxVARIANT: rRes = p->aData; break;
336 26 : case SbxINTEGER: rRes.nInteger = ImpGetInteger( &p->aData ); break;
337 2 : case SbxLONG: rRes.nLong = ImpGetLong( &p->aData ); break;
338 0 : case SbxSALINT64: rRes.nInt64 = ImpGetInt64( &p->aData ); break;
339 0 : case SbxSALUINT64: rRes.uInt64 = ImpGetUInt64( &p->aData ); break;
340 0 : case SbxSINGLE: rRes.nSingle = ImpGetSingle( &p->aData ); break;
341 9 : case SbxDOUBLE: rRes.nDouble = ImpGetDouble( &p->aData ); break;
342 0 : case SbxCURRENCY:rRes.nInt64 = ImpGetCurrency( &p->aData ); break;
343 0 : case SbxDECIMAL: rRes.pDecimal = ImpGetDecimal( &p->aData ); break;
344 0 : case SbxDATE: rRes.nDouble = ImpGetDate( &p->aData ); break;
345 : case SbxBOOL:
346 : rRes.nUShort = sal::static_int_cast< sal_uInt16 >(
347 4 : ImpGetBool( &p->aData ) );
348 4 : break;
349 0 : case SbxCHAR: rRes.nChar = ImpGetChar( &p->aData ); break;
350 0 : case SbxBYTE: rRes.nByte = ImpGetByte( &p->aData ); break;
351 0 : case SbxUSHORT: rRes.nUShort = ImpGetUShort( &p->aData ); break;
352 0 : case SbxULONG: rRes.nULong = ImpGetULong( &p->aData ); break;
353 : case SbxLPSTR:
354 14 : case SbxSTRING: p->aPic = ImpGetString( &p->aData );
355 14 : rRes.pOUString = &p->aPic; break;
356 0 : case SbxCoreSTRING: p->aPic = ImpGetCoreString( &p->aData );
357 0 : rRes.pOUString = &p->aPic; break;
358 : case SbxINT:
359 : #if SAL_TYPES_SIZEOFINT == 2
360 : rRes.nInt = (int) ImpGetInteger( &p->aData );
361 : #else
362 0 : rRes.nInt = (int) ImpGetLong( &p->aData );
363 : #endif
364 0 : break;
365 : case SbxUINT:
366 : #if SAL_TYPES_SIZEOFINT == 2
367 : rRes.nUInt = (int) ImpGetUShort( &p->aData );
368 : #else
369 0 : rRes.nUInt = (int) ImpGetULong( &p->aData );
370 : #endif
371 0 : break;
372 : case SbxOBJECT:
373 4098 : if( p->aData.eType == SbxOBJECT )
374 4098 : rRes.pObj = p->aData.pObj;
375 : else
376 : {
377 0 : SetError( SbxERR_NO_OBJECT );
378 0 : rRes.pObj = NULL;
379 : }
380 4098 : break;
381 : default:
382 0 : if( p->aData.eType == rRes.eType )
383 0 : rRes = p->aData;
384 : else
385 : {
386 0 : SetError( SbxERR_CONVERSION );
387 0 : rRes.pObj = NULL;
388 : }
389 : }
390 : }
391 : else
392 : {
393 : // Object contained itself
394 0 : SbxDataType eTemp = rRes.eType;
395 0 : memset( &rRes, 0, sizeof( SbxValues ) );
396 0 : rRes.eType = eTemp;
397 : }
398 : }
399 4165 : if( !IsError() )
400 : {
401 4165 : bRes = sal_True;
402 4165 : if( eOld != SbxERR_OK )
403 0 : SetError( eOld );
404 : }
405 4165 : return bRes;
406 : }
407 :
408 0 : const OUString& SbxValue::GetCoreString() const
409 : {
410 0 : SbxValues aRes;
411 0 : aRes.eType = SbxCoreSTRING;
412 0 : if( Get( aRes ) )
413 : {
414 0 : ((SbxValue*) this)->aToolString = *aRes.pOUString;
415 : }
416 : else
417 : {
418 0 : ((SbxValue*) this)->aToolString = "";
419 : }
420 0 : return aToolString;
421 : }
422 :
423 2 : OUString SbxValue::GetOUString() const
424 : {
425 2 : OUString aResult;
426 2 : SbxValues aRes;
427 2 : aRes.eType = SbxSTRING;
428 2 : if( Get( aRes ) )
429 : {
430 2 : aResult = *aRes.pOUString;
431 : }
432 2 : return aResult;
433 : }
434 :
435 4 : sal_Bool SbxValue::GetBool() const
436 : {
437 4 : SbxValues aRes;
438 4 : aRes.eType = SbxBOOL;
439 4 : Get( aRes );
440 4 : return sal_Bool( aRes.nUShort != 0 );
441 : }
442 :
443 : #define GET( g, e, t, m ) \
444 : t SbxValue::g() const { SbxValues aRes(e); Get( aRes ); return aRes.m; }
445 :
446 0 : GET( GetByte, SbxBYTE, sal_uInt8, nByte )
447 0 : GET( GetChar, SbxCHAR, sal_Unicode, nChar )
448 0 : GET( GetCurrency, SbxCURRENCY, sal_Int64, nInt64 )
449 0 : GET( GetDate, SbxDATE, double, nDouble )
450 3 : GET( GetDouble, SbxDOUBLE, double, nDouble )
451 13 : GET( GetInteger, SbxINTEGER, sal_Int16, nInteger )
452 2 : GET( GetLong, SbxLONG, sal_Int32, nLong )
453 4098 : GET( GetObject, SbxOBJECT, SbxBase*, pObj )
454 0 : GET( GetSingle, SbxSINGLE, float, nSingle )
455 0 : GET( GetULong, SbxULONG, sal_uInt32, nULong )
456 0 : GET( GetUShort, SbxUSHORT, sal_uInt16, nUShort )
457 0 : GET( GetInt64, SbxSALINT64, sal_Int64, nInt64 )
458 0 : GET( GetUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
459 0 : GET( GetDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
460 :
461 :
462 : //////////////////////////// Write data /////////////////////////////
463 :
464 272 : sal_Bool SbxValue::Put( const SbxValues& rVal )
465 : {
466 272 : sal_Bool bRes = sal_False;
467 272 : SbxError eOld = GetError();
468 272 : if( eOld != SbxERR_OK )
469 0 : ResetError();
470 272 : if( !CanWrite() )
471 0 : SetError( SbxERR_PROP_READONLY );
472 272 : else if( rVal.eType & 0xF000 )
473 0 : SetError( SbxERR_NOTIMP );
474 : else
475 : {
476 : // If there was asked for an object, don't search
477 : // the real values
478 272 : SbxValue* p = this;
479 272 : if( rVal.eType != SbxOBJECT )
480 244 : p = TheRealValue( sal_False ); // Don't allow an error here
481 272 : if( p )
482 : {
483 272 : if( !p->CanWrite() )
484 0 : SetError( SbxERR_PROP_READONLY );
485 272 : else if( p->IsFixed() || p->SetType( (SbxDataType) ( rVal.eType & 0x0FFF ) ) )
486 272 : switch( rVal.eType & 0x0FFF )
487 : {
488 : case SbxEMPTY:
489 : case SbxVOID:
490 0 : case SbxNULL: break;
491 72 : case SbxINTEGER: ImpPutInteger( &p->aData, rVal.nInteger ); break;
492 54 : case SbxLONG: ImpPutLong( &p->aData, rVal.nLong ); break;
493 0 : case SbxSALINT64: ImpPutInt64( &p->aData, rVal.nInt64 ); break;
494 0 : case SbxSALUINT64: ImpPutUInt64( &p->aData, rVal.uInt64 ); break;
495 0 : case SbxSINGLE: ImpPutSingle( &p->aData, rVal.nSingle ); break;
496 24 : case SbxDOUBLE: ImpPutDouble( &p->aData, rVal.nDouble ); break;
497 0 : case SbxCURRENCY: ImpPutCurrency( &p->aData, rVal.nInt64 ); break;
498 0 : case SbxDECIMAL: ImpPutDecimal( &p->aData, rVal.pDecimal ); break;
499 0 : case SbxDATE: ImpPutDate( &p->aData, rVal.nDouble ); break;
500 21 : case SbxBOOL: ImpPutBool( &p->aData, rVal.nInteger ); break;
501 0 : case SbxCHAR: ImpPutChar( &p->aData, rVal.nChar ); break;
502 0 : case SbxBYTE: ImpPutByte( &p->aData, rVal.nByte ); break;
503 0 : case SbxUSHORT: ImpPutUShort( &p->aData, rVal.nUShort ); break;
504 0 : case SbxULONG: ImpPutULong( &p->aData, rVal.nULong ); break;
505 : case SbxLPSTR:
506 73 : case SbxSTRING: ImpPutString( &p->aData, rVal.pOUString ); break;
507 : case SbxINT:
508 : #if SAL_TYPES_SIZEOFINT == 2
509 : ImpPutInteger( &p->aData, (sal_Int16) rVal.nInt );
510 : #else
511 0 : ImpPutLong( &p->aData, (sal_Int32) rVal.nInt );
512 : #endif
513 0 : break;
514 : case SbxUINT:
515 : #if SAL_TYPES_SIZEOFINT == 2
516 : ImpPutUShort( &p->aData, (sal_uInt16) rVal.nUInt );
517 : #else
518 0 : ImpPutULong( &p->aData, (sal_uInt32) rVal.nUInt );
519 : #endif
520 0 : break;
521 : case SbxOBJECT:
522 28 : if( !p->IsFixed() || p->aData.eType == SbxOBJECT )
523 : {
524 : // is already inside
525 28 : if( p->aData.eType == SbxOBJECT && p->aData.pObj == rVal.pObj )
526 0 : break;
527 :
528 : // Delete only the value part!
529 28 : p->SbxValue::Clear();
530 :
531 : // real allocation
532 28 : p->aData.pObj = rVal.pObj;
533 :
534 : // if necessary cont in Ref-Count
535 28 : if( p->aData.pObj && p->aData.pObj != p )
536 : {
537 : if ( p != this )
538 : {
539 : OSL_FAIL( "TheRealValue" );
540 : }
541 : SAL_WARN("basic.sbx", "nicht bei Parent-Prop - sonst CyclicRef");
542 28 : SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
543 : sal_Bool bParentProp = pThisVar && 5345 ==
544 28 : ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) );
545 28 : if ( !bParentProp )
546 28 : p->aData.pObj->AddRef();
547 : }
548 : }
549 : else
550 0 : SetError( SbxERR_CONVERSION );
551 28 : break;
552 : default:
553 0 : if( p->aData.eType == rVal.eType )
554 0 : p->aData = rVal;
555 : else
556 : {
557 0 : SetError( SbxERR_CONVERSION );
558 0 : if( !p->IsFixed() )
559 0 : p->aData.eType = SbxNULL;
560 : }
561 : }
562 272 : if( !IsError() )
563 : {
564 272 : p->SetModified( sal_True );
565 272 : p->Broadcast( SBX_HINT_DATACHANGED );
566 272 : if( eOld != SbxERR_OK )
567 0 : SetError( eOld );
568 272 : bRes = sal_True;
569 : }
570 : }
571 : }
572 272 : return bRes;
573 : }
574 :
575 : // From 1996-03-28:
576 : // Method to execute a pretreatment of the strings at special types.
577 : // In particular necessary for BASIC-IDE, so that
578 : // the output in the Watch-Window can be writen back with PutStringExt,
579 : // if Float were declared with ',' as the decimal seperator or BOOl
580 : // explicit with "TRUE" or "FALSE".
581 : // Implementation in ImpConvStringExt (SBXSCAN.CXX)
582 0 : sal_Bool SbxValue::PutStringExt( const ::rtl::OUString& r )
583 : {
584 : // Copy; if it is Unicode convert it immediately
585 0 : ::rtl::OUString aStr( r );
586 :
587 : // Identify the own type (not as in Put() with TheRealValue(),
588 : // Objects are not handled anyway)
589 0 : SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF );
590 :
591 : // tinker a Source-Value
592 0 : SbxValues aRes;
593 0 : aRes.eType = SbxSTRING;
594 :
595 : // Only if really something was converted, take the copy,
596 : // elsewise take the original (Unicode remain)
597 : sal_Bool bRet;
598 0 : if( ImpConvStringExt( aStr, eTargetType ) )
599 0 : aRes.pOUString = (::rtl::OUString*)&aStr;
600 : else
601 0 : aRes.pOUString = (::rtl::OUString*)&r;
602 :
603 : // #34939: Set a Fixed-Flag at Strings. which contain a number, and
604 : // if this has a Num-Type, so that the type will not be changed
605 0 : sal_uInt16 nFlags_ = GetFlags();
606 0 : if( ( eTargetType >= SbxINTEGER && eTargetType <= SbxCURRENCY ) ||
607 : ( eTargetType >= SbxCHAR && eTargetType <= SbxUINT ) ||
608 : eTargetType == SbxBOOL )
609 : {
610 0 : SbxValue aVal;
611 0 : aVal.Put( aRes );
612 0 : if( aVal.IsNumeric() )
613 0 : SetFlag( SBX_FIXED );
614 : }
615 :
616 0 : Put( aRes );
617 0 : bRet = sal_Bool( !IsError() );
618 :
619 : // If it throwed an error with FIXED, set it back
620 : // (UI-Action should not cast an error, but only fail)
621 0 : if( !bRet )
622 0 : ResetError();
623 :
624 0 : SetFlags( nFlags_ );
625 0 : return bRet;
626 : }
627 :
628 7 : sal_Bool SbxValue::PutBool( sal_Bool b )
629 : {
630 7 : SbxValues aRes;
631 7 : aRes.eType = SbxBOOL;
632 7 : aRes.nUShort = sal::static_int_cast< sal_uInt16 >(b ? SbxTRUE : SbxFALSE);
633 7 : Put( aRes );
634 7 : return sal_Bool( !IsError() );
635 : }
636 :
637 0 : sal_Bool SbxValue::PutEmpty()
638 : {
639 0 : sal_Bool bRet = SetType( SbxEMPTY );
640 0 : SetModified( sal_True );
641 0 : return bRet;
642 : }
643 :
644 0 : sal_Bool SbxValue::PutNull()
645 : {
646 0 : sal_Bool bRet = SetType( SbxNULL );
647 0 : if( bRet )
648 0 : SetModified( sal_True );
649 0 : return bRet;
650 : }
651 :
652 :
653 : // Special decimal methods
654 0 : sal_Bool SbxValue::PutDecimal( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec )
655 : {
656 0 : SbxValue::Clear();
657 0 : aData.pDecimal = new SbxDecimal( rAutomationDec );
658 0 : aData.pDecimal->addRef();
659 0 : aData.eType = SbxDECIMAL;
660 0 : return sal_True;
661 : }
662 :
663 0 : sal_Bool SbxValue::fillAutomationDecimal
664 : ( com::sun::star::bridge::oleautomation::Decimal& rAutomationDec )
665 : {
666 0 : SbxDecimal* pDecimal = GetDecimal();
667 0 : if( pDecimal != NULL )
668 : {
669 0 : pDecimal->fillAutomationDecimal( rAutomationDec );
670 0 : return sal_True;
671 : }
672 0 : return sal_False;
673 : }
674 :
675 :
676 63 : sal_Bool SbxValue::PutString( const ::rtl::OUString& r )
677 : {
678 63 : SbxValues aRes;
679 63 : aRes.eType = SbxSTRING;
680 63 : aRes.pOUString = (::rtl::OUString*) &r;
681 63 : Put( aRes );
682 63 : return sal_Bool( !IsError() );
683 : }
684 :
685 :
686 : #define PUT( p, e, t, m ) \
687 : sal_Bool SbxValue::p( t n ) \
688 : { SbxValues aRes(e); aRes.m = n; Put( aRes ); return sal_Bool( !IsError() ); }
689 :
690 0 : PUT( PutByte, SbxBYTE, sal_uInt8, nByte )
691 0 : PUT( PutChar, SbxCHAR, sal_Unicode, nChar )
692 0 : PUT( PutCurrency, SbxCURRENCY, const sal_Int64&, nInt64 )
693 0 : PUT( PutDate, SbxDATE, double, nDouble )
694 4 : PUT( PutDouble, SbxDOUBLE, double, nDouble )
695 0 : PUT( PutErr, SbxERROR, sal_uInt16, nUShort )
696 18 : PUT( PutInteger, SbxINTEGER, sal_Int16, nInteger )
697 32 : PUT( PutLong, SbxLONG, sal_Int32, nLong )
698 28 : PUT( PutObject, SbxOBJECT, SbxBase*, pObj )
699 0 : PUT( PutSingle, SbxSINGLE, float, nSingle )
700 0 : PUT( PutULong, SbxULONG, sal_uInt32, nULong )
701 0 : PUT( PutUShort, SbxUSHORT, sal_uInt16, nUShort )
702 0 : PUT( PutInt64, SbxSALINT64, sal_Int64, nInt64 )
703 0 : PUT( PutUInt64, SbxSALUINT64, sal_uInt64, uInt64 )
704 0 : PUT( PutDecimal, SbxDECIMAL, SbxDecimal*, pDecimal )
705 :
706 : ////////////////////////// Setting of the data type ///////////////////////////
707 :
708 533 : sal_Bool SbxValue::IsFixed() const
709 : {
710 533 : return ( (GetFlags() & SBX_FIXED) | (aData.eType & SbxBYREF) ) != 0;
711 : }
712 :
713 : // A variable is numeric, if it is EMPTY or realy numeric
714 : // or if it contains a complete convertible String
715 :
716 : // #41692, implement it for RTL and Basic-Core seperably
717 0 : sal_Bool SbxValue::IsNumeric() const
718 : {
719 0 : return ImpIsNumeric( /*bOnlyIntntl*/false );
720 : }
721 :
722 0 : sal_Bool SbxValue::IsNumericRTL() const
723 : {
724 0 : return ImpIsNumeric( /*bOnlyIntntl*/true );
725 : }
726 :
727 0 : sal_Bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const
728 : {
729 :
730 0 : if( !CanRead() )
731 : {
732 0 : SetError( SbxERR_PROP_WRITEONLY ); return sal_False;
733 : }
734 : // Test downcast!!!
735 0 : if( this->ISA(SbxVariable) )
736 0 : ((SbxVariable*)this)->Broadcast( SBX_HINT_DATAWANTED );
737 0 : SbxDataType t = GetType();
738 0 : if( t == SbxSTRING )
739 : {
740 0 : if( aData.pOUString )
741 : {
742 0 : ::rtl::OUString s( *aData.pOUString );
743 : double n;
744 : SbxDataType t2;
745 0 : sal_uInt16 nLen = 0;
746 0 : if( ImpScan( s, n, t2, &nLen, /*bAllowIntntl*/false, bOnlyIntntl ) == SbxERR_OK )
747 0 : return sal_Bool( nLen == s.getLength() );
748 : }
749 0 : return sal_False;
750 : }
751 : else
752 : return sal_Bool( t == SbxEMPTY
753 : || ( t >= SbxINTEGER && t <= SbxCURRENCY )
754 0 : || ( t >= SbxCHAR && t <= SbxUINT ) );
755 : }
756 :
757 0 : SbxClassType SbxValue::GetClass() const
758 : {
759 0 : return SbxCLASS_VALUE;
760 : }
761 :
762 3278 : SbxDataType SbxValue::GetType() const
763 : {
764 3278 : return SbxDataType( aData.eType & 0x0FFF );
765 : }
766 :
767 0 : SbxDataType SbxValue::GetFullType() const
768 : {
769 0 : return aData.eType;
770 : }
771 :
772 221 : sal_Bool SbxValue::SetType( SbxDataType t )
773 : {
774 : DBG_ASSERT( !( t & 0xF000 ), "Setzen von BYREF|ARRAY verboten!" );
775 221 : if( ( t == SbxEMPTY && aData.eType == SbxVOID )
776 : || ( aData.eType == SbxEMPTY && t == SbxVOID ) )
777 1 : return sal_True;
778 220 : if( ( t & 0x0FFF ) == SbxVARIANT )
779 : {
780 : // Trial to set the data type to Variant
781 11 : ResetFlag( SBX_FIXED );
782 11 : if( IsFixed() )
783 : {
784 0 : SetError( SbxERR_CONVERSION ); return sal_False;
785 : }
786 11 : t = SbxEMPTY;
787 : }
788 220 : if( ( t & 0x0FFF ) != ( aData.eType & 0x0FFF ) )
789 : {
790 109 : if( !CanWrite() || IsFixed() )
791 : {
792 0 : SetError( SbxERR_CONVERSION ); return sal_False;
793 : }
794 : else
795 : {
796 : // De-allocate potential objects
797 109 : switch( aData.eType )
798 : {
799 : case SbxSTRING:
800 4 : delete aData.pOUString;
801 4 : break;
802 : case SbxOBJECT:
803 0 : if( aData.pObj && aData.pObj != this )
804 : {
805 : SAL_WARN("basic.sbx", "nicht bei Parent-Prop - sonst CyclicRef");
806 0 : SbxVariable *pThisVar = PTR_CAST(SbxVariable, this);
807 : sal_uInt16 nSlotId = pThisVar
808 0 : ? ( (sal_Int16) ( pThisVar->GetUserData() & 0xFFFF ) )
809 0 : : 0;
810 : DBG_ASSERT( nSlotId != 5345 || pThisVar->GetName().equalsAscii("Parent"),
811 : "SID_PARENTOBJECT heisst nicht 'Parent'" );
812 0 : sal_Bool bParentProp = 5345 == nSlotId;
813 0 : if ( !bParentProp )
814 0 : aData.pObj->ReleaseRef();
815 : }
816 0 : break;
817 105 : default: break;
818 : }
819 : // This works always, because the Float representations are 0 as well.
820 109 : memset( &aData, 0, sizeof( SbxValues ) );
821 109 : aData.eType = t;
822 : }
823 : }
824 220 : return sal_True;
825 : }
826 :
827 0 : sal_Bool SbxValue::Convert( SbxDataType eTo )
828 : {
829 0 : eTo = SbxDataType( eTo & 0x0FFF );
830 0 : if( ( aData.eType & 0x0FFF ) == eTo )
831 0 : return sal_True;
832 0 : if( !CanWrite() )
833 0 : return sal_False;
834 0 : if( eTo == SbxVARIANT )
835 : {
836 : // Trial to set the data type to Variant
837 0 : ResetFlag( SBX_FIXED );
838 0 : if( IsFixed() )
839 : {
840 0 : SetError( SbxERR_CONVERSION ); return sal_False;
841 : }
842 : else
843 0 : return sal_True;
844 : }
845 : // Converting from zero doesn't work. Once zero, always zero!
846 0 : if( aData.eType == SbxNULL )
847 : {
848 0 : SetError( SbxERR_CONVERSION ); return sal_False;
849 : }
850 :
851 : // Conversion of the data:
852 0 : SbxValues aNew;
853 0 : aNew.eType = eTo;
854 0 : if( Get( aNew ) )
855 : {
856 : // The data type could be converted. It ends here with fixed elements,
857 : // because the data had not to be taken over
858 0 : if( !IsFixed() )
859 : {
860 0 : SetType( eTo );
861 0 : Put( aNew );
862 0 : SetModified( sal_True );
863 : }
864 0 : Broadcast( SBX_HINT_CONVERTED );
865 0 : return sal_True;
866 : }
867 : else
868 0 : return sal_False;
869 : }
870 : ////////////////////////////////// Calculating /////////////////////////////////
871 :
872 3 : sal_Bool SbxValue::Compute( SbxOperator eOp, const SbxValue& rOp )
873 : {
874 : #ifdef DISABLE_SCRIPTING
875 : bool bVBAInterop = false;
876 : #else
877 3 : bool bVBAInterop = SbiRuntime::isVBAEnabled();
878 : #endif
879 3 : SbxDataType eThisType = GetType();
880 3 : SbxDataType eOpType = rOp.GetType();
881 3 : SbxError eOld = GetError();
882 3 : if( eOld != SbxERR_OK )
883 0 : ResetError();
884 3 : if( !CanWrite() )
885 0 : SetError( SbxERR_PROP_READONLY );
886 3 : else if( !rOp.CanRead() )
887 0 : SetError( SbxERR_PROP_WRITEONLY );
888 : // Special rule 1: If one operand is zero, the result is zero
889 3 : else if( eThisType == SbxNULL || eOpType == SbxNULL )
890 0 : SetType( SbxNULL );
891 : // Special rule 2: If the operand is Empty, the result is the 2. operand
892 3 : else if( eThisType == SbxEMPTY
893 0 : && !bVBAInterop
894 : )
895 0 : *this = rOp;
896 : // 1996-2-13: Don't test already before Get upon SbxEMPTY
897 : else
898 : {
899 3 : SbxValues aL, aR;
900 3 : bool bDecimal = false;
901 3 : if( bVBAInterop && ( ( eThisType == SbxSTRING && eOpType != SbxSTRING && eOpType != SbxEMPTY ) ||
902 : ( eThisType != SbxSTRING && eThisType != SbxEMPTY && eOpType == SbxSTRING ) ) &&
903 : ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS ) )
904 : {
905 : goto Lbl_OpIsDouble;
906 : }
907 3 : else if( eThisType == SbxSTRING || eOp == SbxCAT || ( bVBAInterop && ( eOpType == SbxSTRING ) && ( eOp == SbxPLUS ) ) )
908 : {
909 0 : if( eOp == SbxCAT || eOp == SbxPLUS )
910 : {
911 : // From 1999-11-5, keep OUString in mind
912 0 : aL.eType = aR.eType = SbxSTRING;
913 0 : rOp.Get( aR );
914 : // From 1999-12-8, #70399: Here call GetType() again, Get() can change the type!
915 0 : if( rOp.GetType() == SbxEMPTY )
916 : goto Lbl_OpIsEmpty;
917 0 : Get( aL );
918 :
919 : // #30576: To begin with test, if the conversion worked
920 0 : if( aL.pOUString != NULL && aR.pOUString != NULL )
921 : {
922 0 : *aL.pOUString += *aR.pOUString;
923 : }
924 : // Not even Left OK?
925 0 : else if( aL.pOUString == NULL )
926 : {
927 0 : aL.pOUString = new ::rtl::OUString();
928 : }
929 0 : Put( aL );
930 : }
931 : else
932 0 : SetError( SbxERR_CONVERSION );
933 : }
934 3 : else if( eOpType == SbxSTRING && rOp.IsFixed() )
935 : { // Numeric: there is no String allowed on the right side
936 0 : SetError( SbxERR_CONVERSION );
937 : // falls all the way out
938 : }
939 3 : else if( ( eOp >= SbxIDIV && eOp <= SbxNOT ) || eOp == SbxMOD )
940 : {
941 0 : if( GetType() == eOpType )
942 : {
943 0 : if( GetType() == SbxSALUINT64 || GetType() == SbxSALINT64
944 0 : || GetType() == SbxCURRENCY || GetType() == SbxULONG )
945 0 : aL.eType = aR.eType = GetType();
946 0 : else if ( bVBAInterop && eOpType == SbxBOOL )
947 0 : aL.eType = aR.eType = SbxBOOL;
948 : else
949 0 : aL.eType = aR.eType = SbxLONG;
950 : }
951 : else
952 0 : aL.eType = aR.eType = SbxLONG;
953 :
954 0 : if( rOp.Get( aR ) ) // re-do Get after type assigns above
955 : {
956 0 : if( rOp.GetType() == SbxEMPTY )
957 : {
958 0 : if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNOT ) ) )
959 : goto Lbl_OpIsEmpty;
960 : }
961 0 : if( Get( aL ) ) switch( eOp )
962 : {
963 : case SbxIDIV:
964 0 : if( aL.eType == SbxCURRENCY )
965 0 : if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
966 : else {
967 0 : aL.nInt64 /= aR.nInt64;
968 0 : aL.nInt64 *= CURRENCY_FACTOR;
969 : }
970 0 : else if( aL.eType == SbxSALUINT64 )
971 0 : if( !aR.uInt64 ) SetError( SbxERR_ZERODIV );
972 0 : else aL.uInt64 /= aR.uInt64;
973 0 : else if( aL.eType == SbxSALINT64 )
974 0 : if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
975 0 : else aL.nInt64 /= aR.nInt64;
976 0 : else if( aL.eType == SbxLONG )
977 0 : if( !aR.nLong ) SetError( SbxERR_ZERODIV );
978 0 : else aL.nLong /= aR.nLong;
979 : else
980 0 : if( !aR.nULong ) SetError( SbxERR_ZERODIV );
981 0 : else aL.nULong /= aR.nULong;
982 0 : break;
983 : case SbxMOD:
984 0 : if( aL.eType == SbxCURRENCY || aL.eType == SbxSALINT64 )
985 0 : if( !aR.nInt64 ) SetError( SbxERR_ZERODIV );
986 0 : else aL.nInt64 %= aR.nInt64;
987 0 : else if( aL.eType == SbxSALUINT64 )
988 0 : if( !aR.uInt64 ) SetError( SbxERR_ZERODIV );
989 0 : else aL.uInt64 %= aR.uInt64;
990 0 : else if( aL.eType == SbxLONG )
991 0 : if( !aR.nLong ) SetError( SbxERR_ZERODIV );
992 0 : else aL.nLong %= aR.nLong;
993 : else
994 0 : if( !aR.nULong ) SetError( SbxERR_ZERODIV );
995 0 : else aL.nULong %= aR.nULong;
996 0 : break;
997 : case SbxAND:
998 0 : if( aL.eType != SbxLONG && aL.eType != SbxULONG )
999 0 : aL.nInt64 &= aR.nInt64;
1000 : else
1001 0 : aL.nLong &= aR.nLong;
1002 0 : break;
1003 : case SbxOR:
1004 0 : if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1005 0 : aL.nInt64 |= aR.nInt64;
1006 : else
1007 0 : aL.nLong |= aR.nLong;
1008 0 : break;
1009 : case SbxXOR:
1010 0 : if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1011 0 : aL.nInt64 ^= aR.nInt64;
1012 : else
1013 0 : aL.nLong ^= aR.nLong;
1014 0 : break;
1015 : case SbxEQV:
1016 0 : if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1017 0 : aL.nInt64 = (aL.nInt64 & aR.nInt64) | (~aL.nInt64 & ~aR.nInt64);
1018 : else
1019 0 : aL.nLong = (aL.nLong & aR.nLong) | (~aL.nLong & ~aR.nLong);
1020 0 : break;
1021 : case SbxIMP:
1022 0 : if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1023 0 : aL.nInt64 = ~aL.nInt64 | aR.nInt64;
1024 : else
1025 0 : aL.nLong = ~aL.nLong | aR.nLong;
1026 0 : break;
1027 : case SbxNOT:
1028 0 : if( aL.eType != SbxLONG && aL.eType != SbxULONG )
1029 : {
1030 0 : if ( aL.eType != SbxBOOL )
1031 0 : aL.nInt64 = ~aL.nInt64;
1032 : else
1033 0 : aL.nLong = ~aL.nLong;
1034 : }
1035 : else
1036 0 : aL.nLong = ~aL.nLong;
1037 0 : break;
1038 0 : default: break;
1039 : }
1040 : }
1041 : }
1042 3 : else if( ( GetType() == SbxDECIMAL || rOp.GetType() == SbxDECIMAL )
1043 : && ( eOp == SbxMUL || eOp == SbxDIV || eOp == SbxPLUS || eOp == SbxMINUS || eOp == SbxNEG ) )
1044 : {
1045 0 : aL.eType = aR.eType = SbxDECIMAL;
1046 0 : bDecimal = true;
1047 0 : if( rOp.Get( aR ) )
1048 : {
1049 0 : if( rOp.GetType() == SbxEMPTY )
1050 : {
1051 0 : releaseDecimalPtr( aL.pDecimal );
1052 : goto Lbl_OpIsEmpty;
1053 : }
1054 0 : if( Get( aL ) )
1055 : {
1056 0 : if( aL.pDecimal && aR.pDecimal )
1057 : {
1058 0 : bool bOk = true;
1059 0 : switch( eOp )
1060 : {
1061 : case SbxMUL:
1062 0 : bOk = ( *(aL.pDecimal) *= *(aR.pDecimal) );
1063 0 : break;
1064 : case SbxDIV:
1065 0 : if( aR.pDecimal->isZero() )
1066 0 : SetError( SbxERR_ZERODIV );
1067 : else
1068 0 : bOk = ( *(aL.pDecimal) /= *(aR.pDecimal) );
1069 0 : break;
1070 : case SbxPLUS:
1071 0 : bOk = ( *(aL.pDecimal) += *(aR.pDecimal) );
1072 0 : break;
1073 : case SbxMINUS:
1074 0 : bOk = ( *(aL.pDecimal) -= *(aR.pDecimal) );
1075 0 : break;
1076 : case SbxNEG:
1077 0 : bOk = ( aL.pDecimal->neg() );
1078 0 : break;
1079 : default:
1080 0 : SetError( SbxERR_NOTIMP );
1081 : }
1082 0 : if( !bOk )
1083 0 : SetError( SbxERR_OVERFLOW );
1084 : }
1085 : else
1086 : {
1087 0 : SetError( SbxERR_CONVERSION );
1088 : }
1089 : }
1090 : }
1091 : }
1092 3 : else if( GetType() == SbxCURRENCY || rOp.GetType() == SbxCURRENCY )
1093 : {
1094 0 : aL.eType = SbxCURRENCY;
1095 0 : aR.eType = SbxCURRENCY;
1096 :
1097 0 : if( rOp.Get( aR ) )
1098 : {
1099 0 : if( rOp.GetType() == SbxEMPTY )
1100 : goto Lbl_OpIsEmpty;
1101 :
1102 0 : if( Get( aL ) ) switch( eOp )
1103 : {
1104 : double dTest;
1105 : case SbxMUL:
1106 : // first overflow check: see if product will fit - test real value of product (hence 2 curr factors)
1107 0 : dTest = (double)aL.nInt64 * (double)aR.nInt64 / (double)CURRENCY_FACTOR_SQUARE;
1108 0 : if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1109 : {
1110 0 : aL.nInt64 = SAL_MAX_INT64;
1111 0 : if( dTest < SbxMINCURR ) aL.nInt64 = SAL_MIN_INT64;
1112 0 : SetError( SbxERR_OVERFLOW );
1113 0 : break;
1114 : }
1115 : // second overflow check: see if unscaled product overflows - if so use doubles
1116 0 : dTest = (double)aL.nInt64 * (double)aR.nInt64;
1117 0 : if( dTest < SAL_MIN_INT64 || SAL_MAX_INT64 < dTest)
1118 : {
1119 0 : aL.nInt64 = (sal_Int64)( dTest / (double)CURRENCY_FACTOR );
1120 0 : break;
1121 : }
1122 : // precise calc: multiply then scale back (move decimal pt)
1123 0 : aL.nInt64 *= aR.nInt64;
1124 0 : aL.nInt64 /= CURRENCY_FACTOR;
1125 0 : break;
1126 :
1127 : case SbxDIV:
1128 0 : if( !aR.nInt64 )
1129 : {
1130 0 : SetError( SbxERR_ZERODIV );
1131 0 : break;
1132 : }
1133 : // first overflow check: see if quotient will fit - calc real value of quotient (curr factors cancel)
1134 0 : dTest = (double)aL.nInt64 / (double)aR.nInt64;
1135 0 : if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1136 : {
1137 0 : SetError( SbxERR_OVERFLOW );
1138 0 : break;
1139 : }
1140 : // second overflow check: see if scaled dividend overflows - if so use doubles
1141 0 : dTest = (double)aL.nInt64 * (double)CURRENCY_FACTOR;
1142 0 : if( dTest < SAL_MIN_INT64 || SAL_MAX_INT64 < dTest)
1143 : {
1144 0 : aL.nInt64 = (sal_Int64)(dTest / (double)aR.nInt64);
1145 0 : break;
1146 : }
1147 : // precise calc: scale (move decimal pt) then divide
1148 0 : aL.nInt64 *= CURRENCY_FACTOR;
1149 0 : aL.nInt64 /= aR.nInt64;
1150 0 : break;
1151 :
1152 : case SbxPLUS:
1153 0 : dTest = ( (double)aL.nInt64 + (double)aR.nInt64 ) / (double)CURRENCY_FACTOR;
1154 0 : if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1155 : {
1156 0 : SetError( SbxERR_OVERFLOW );
1157 0 : break;
1158 : }
1159 0 : aL.nInt64 += aR.nInt64;
1160 0 : break;
1161 :
1162 : case SbxMINUS:
1163 0 : dTest = ( (double)aL.nInt64 - (double)aR.nInt64 ) / (double)CURRENCY_FACTOR;
1164 0 : if( dTest < SbxMINCURR || SbxMAXCURR < dTest)
1165 : {
1166 0 : SetError( SbxERR_OVERFLOW );
1167 0 : break;
1168 : }
1169 0 : aL.nInt64 -= aR.nInt64;
1170 0 : break;
1171 : case SbxNEG:
1172 0 : aL.nInt64 = -aL.nInt64;
1173 0 : break;
1174 : default:
1175 0 : SetError( SbxERR_NOTIMP );
1176 : }
1177 : }
1178 : }
1179 : else
1180 : Lbl_OpIsDouble:
1181 : { // other types and operators including Date, Double and Single
1182 3 : aL.eType = aR.eType = SbxDOUBLE;
1183 3 : if( rOp.Get( aR ) )
1184 : {
1185 3 : if( rOp.GetType() == SbxEMPTY )
1186 : {
1187 0 : if ( !bVBAInterop || ( bVBAInterop && ( eOp != SbxNEG ) ) )
1188 : goto Lbl_OpIsEmpty;
1189 : }
1190 3 : if( Get( aL ) )
1191 : {
1192 3 : switch( eOp )
1193 : {
1194 : case SbxEXP:
1195 0 : aL.nDouble = pow( aL.nDouble, aR.nDouble );
1196 0 : break;
1197 : case SbxMUL:
1198 0 : aL.nDouble *= aR.nDouble; break;
1199 : case SbxDIV:
1200 0 : if( !aR.nDouble ) SetError( SbxERR_ZERODIV );
1201 0 : else aL.nDouble /= aR.nDouble; break;
1202 : case SbxPLUS:
1203 3 : aL.nDouble += aR.nDouble; break;
1204 : case SbxMINUS:
1205 0 : aL.nDouble -= aR.nDouble; break;
1206 : case SbxNEG:
1207 0 : aL.nDouble = -aL.nDouble; break;
1208 : default:
1209 0 : SetError( SbxERR_NOTIMP );
1210 : }
1211 : // Date with "+" or "-" needs special handling that
1212 : // forces the Date type. If the operation is '+' the
1213 : // result is always a Date, if '-' the result is only
1214 : // a Date if one of lhs or rhs ( but not both ) is already
1215 : // a Date
1216 3 : if( ( GetType() == SbxDATE || rOp.GetType() == SbxDATE ) )
1217 : {
1218 0 : if( eOp == SbxPLUS || ( ( eOp == SbxMINUS ) && ( GetType() != rOp.GetType() ) ) )
1219 0 : aL.eType = SbxDATE;
1220 : }
1221 :
1222 : }
1223 : }
1224 :
1225 : }
1226 3 : if( !IsError() )
1227 3 : Put( aL );
1228 3 : if( bDecimal )
1229 : {
1230 0 : releaseDecimalPtr( aL.pDecimal );
1231 0 : releaseDecimalPtr( aR.pDecimal );
1232 : }
1233 : }
1234 : Lbl_OpIsEmpty:
1235 :
1236 3 : sal_Bool bRes = sal_Bool( !IsError() );
1237 3 : if( bRes && eOld != SbxERR_OK )
1238 0 : SetError( eOld );
1239 3 : return bRes;
1240 : }
1241 :
1242 : // The comparison routine deliver TRUE or FALSE.
1243 :
1244 4 : sal_Bool SbxValue::Compare( SbxOperator eOp, const SbxValue& rOp ) const
1245 : {
1246 : #ifdef DISABLE_SCRIPTING
1247 : bool bVBAInterop = false;
1248 : #else
1249 4 : bool bVBAInterop = SbiRuntime::isVBAEnabled();
1250 : #endif
1251 :
1252 4 : sal_Bool bRes = sal_False;
1253 4 : SbxError eOld = GetError();
1254 4 : if( eOld != SbxERR_OK )
1255 0 : ResetError();
1256 4 : if( !CanRead() || !rOp.CanRead() )
1257 0 : SetError( SbxERR_PROP_WRITEONLY );
1258 4 : else if( GetType() == SbxNULL && rOp.GetType() == SbxNULL && !bVBAInterop )
1259 : {
1260 0 : bRes = sal_True;
1261 : }
1262 4 : else if( GetType() == SbxEMPTY && rOp.GetType() == SbxEMPTY )
1263 0 : bRes = !bVBAInterop ? sal_True : ( eOp == SbxEQ ? sal_True : sal_False );
1264 : // Special rule 1: If an operand is zero, the result is FALSE
1265 4 : else if( GetType() == SbxNULL || rOp.GetType() == SbxNULL )
1266 0 : bRes = sal_False;
1267 : // Special rule 2: If both are variant and one is numeric
1268 : // and the other is a String, num is < str
1269 8 : else if( !IsFixed() && !rOp.IsFixed()
1270 4 : && ( rOp.GetType() == SbxSTRING && GetType() != SbxSTRING && IsNumeric() ) && !bVBAInterop
1271 : )
1272 0 : bRes = sal_Bool( eOp == SbxLT || eOp == SbxLE || eOp == SbxNE );
1273 8 : else if( !IsFixed() && !rOp.IsFixed()
1274 4 : && ( GetType() == SbxSTRING && rOp.GetType() != SbxSTRING && rOp.IsNumeric() )
1275 0 : && !bVBAInterop
1276 : )
1277 0 : bRes = sal_Bool( eOp == SbxGT || eOp == SbxGE || eOp == SbxNE );
1278 : else
1279 : {
1280 4 : SbxValues aL, aR;
1281 : // If one of the operands is a String,
1282 : // a String comparing take place
1283 4 : if( GetType() == SbxSTRING || rOp.GetType() == SbxSTRING )
1284 : {
1285 4 : aL.eType = aR.eType = SbxSTRING;
1286 4 : if( Get( aL ) && rOp.Get( aR ) ) switch( eOp )
1287 : {
1288 : case SbxEQ:
1289 2 : bRes = sal_Bool( *aL.pOUString == *aR.pOUString ); break;
1290 : case SbxNE:
1291 2 : bRes = sal_Bool( *aL.pOUString != *aR.pOUString ); break;
1292 : case SbxLT:
1293 0 : bRes = sal_Bool( *aL.pOUString < *aR.pOUString ); break;
1294 : case SbxGT:
1295 0 : bRes = sal_Bool( *aL.pOUString > *aR.pOUString ); break;
1296 : case SbxLE:
1297 0 : bRes = sal_Bool( *aL.pOUString <= *aR.pOUString ); break;
1298 : case SbxGE:
1299 0 : bRes = sal_Bool( *aL.pOUString >= *aR.pOUString ); break;
1300 : default:
1301 0 : SetError( SbxERR_NOTIMP );
1302 : }
1303 : }
1304 : // From 1995-12-19: If SbxSINGLE participate, then convert to SINGLE,
1305 : // elsewise it shows a numeric error
1306 0 : else if( GetType() == SbxSINGLE || rOp.GetType() == SbxSINGLE )
1307 : {
1308 0 : aL.eType = aR.eType = SbxSINGLE;
1309 0 : if( Get( aL ) && rOp.Get( aR ) )
1310 0 : switch( eOp )
1311 : {
1312 : case SbxEQ:
1313 0 : bRes = sal_Bool( aL.nSingle == aR.nSingle ); break;
1314 : case SbxNE:
1315 0 : bRes = sal_Bool( aL.nSingle != aR.nSingle ); break;
1316 : case SbxLT:
1317 0 : bRes = sal_Bool( aL.nSingle < aR.nSingle ); break;
1318 : case SbxGT:
1319 0 : bRes = sal_Bool( aL.nSingle > aR.nSingle ); break;
1320 : case SbxLE:
1321 0 : bRes = sal_Bool( aL.nSingle <= aR.nSingle ); break;
1322 : case SbxGE:
1323 0 : bRes = sal_Bool( aL.nSingle >= aR.nSingle ); break;
1324 : default:
1325 0 : SetError( SbxERR_NOTIMP );
1326 : }
1327 : }
1328 0 : else if( GetType() == SbxDECIMAL && rOp.GetType() == SbxDECIMAL )
1329 : {
1330 0 : aL.eType = aR.eType = SbxDECIMAL;
1331 0 : Get( aL );
1332 0 : rOp.Get( aR );
1333 0 : if( aL.pDecimal && aR.pDecimal )
1334 : {
1335 0 : SbxDecimal::CmpResult eRes = compare( *aL.pDecimal, *aR.pDecimal );
1336 0 : switch( eOp )
1337 : {
1338 : case SbxEQ:
1339 0 : bRes = sal_Bool( eRes == SbxDecimal::EQ ); break;
1340 : case SbxNE:
1341 0 : bRes = sal_Bool( eRes != SbxDecimal::EQ ); break;
1342 : case SbxLT:
1343 0 : bRes = sal_Bool( eRes == SbxDecimal::LT ); break;
1344 : case SbxGT:
1345 0 : bRes = sal_Bool( eRes == SbxDecimal::GT ); break;
1346 : case SbxLE:
1347 0 : bRes = sal_Bool( eRes != SbxDecimal::GT ); break;
1348 : case SbxGE:
1349 0 : bRes = sal_Bool( eRes != SbxDecimal::LT ); break;
1350 : default:
1351 0 : SetError( SbxERR_NOTIMP );
1352 0 : }
1353 : }
1354 : else
1355 : {
1356 0 : SetError( SbxERR_CONVERSION );
1357 : }
1358 0 : releaseDecimalPtr( aL.pDecimal );
1359 0 : releaseDecimalPtr( aR.pDecimal );
1360 : }
1361 : // Everything else comparing on a SbxDOUBLE-Basis
1362 : else
1363 : {
1364 0 : aL.eType = aR.eType = SbxDOUBLE;
1365 0 : bool bGetL = Get( aL );
1366 0 : bool bGetR = rOp.Get( aR );
1367 0 : if( bGetL && bGetR )
1368 0 : switch( eOp )
1369 : {
1370 : case SbxEQ:
1371 0 : bRes = sal_Bool( aL.nDouble == aR.nDouble ); break;
1372 : case SbxNE:
1373 0 : bRes = sal_Bool( aL.nDouble != aR.nDouble ); break;
1374 : case SbxLT:
1375 0 : bRes = sal_Bool( aL.nDouble < aR.nDouble ); break;
1376 : case SbxGT:
1377 0 : bRes = sal_Bool( aL.nDouble > aR.nDouble ); break;
1378 : case SbxLE:
1379 0 : bRes = sal_Bool( aL.nDouble <= aR.nDouble ); break;
1380 : case SbxGE:
1381 0 : bRes = sal_Bool( aL.nDouble >= aR.nDouble ); break;
1382 : default:
1383 0 : SetError( SbxERR_NOTIMP );
1384 : }
1385 : // at least one value was got
1386 : // if this is VBA then a conversion error for one
1387 : // side will yield a false result of an equality test
1388 0 : else if ( bGetR || bGetL )
1389 : {
1390 0 : if ( bVBAInterop && eOp == SbxEQ && GetError() == SbxERR_CONVERSION )
1391 : {
1392 0 : ResetError();
1393 0 : bRes = sal_False;
1394 : }
1395 : }
1396 : }
1397 : }
1398 4 : if( eOld != SbxERR_OK )
1399 0 : SetError( eOld );
1400 4 : return bRes;
1401 : }
1402 :
1403 : ///////////////////////////// Reading/Writing ////////////////////////////
1404 :
1405 0 : sal_Bool SbxValue::LoadData( SvStream& r, sal_uInt16 )
1406 : {
1407 : // #TODO see if these types are really dumped to any stream
1408 : // more than likely this is functionality used in the binfilter alone
1409 0 : SbxValue::Clear();
1410 : sal_uInt16 nType;
1411 0 : r >> nType;
1412 0 : aData.eType = SbxDataType( nType );
1413 0 : switch( nType )
1414 : {
1415 : case SbxBOOL:
1416 : case SbxINTEGER:
1417 0 : r >> aData.nInteger; break;
1418 : case SbxLONG:
1419 0 : r >> aData.nLong; break;
1420 : case SbxSINGLE:
1421 : {
1422 : // Floats as ASCII
1423 : XubString aVal = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(r,
1424 0 : RTL_TEXTENCODING_ASCII_US);
1425 : double d;
1426 : SbxDataType t;
1427 0 : if( ImpScan( aVal, d, t, NULL ) != SbxERR_OK || t == SbxDOUBLE )
1428 : {
1429 0 : aData.nSingle = 0.0F;
1430 0 : return sal_False;
1431 : }
1432 0 : aData.nSingle = (float) d;
1433 0 : break;
1434 : }
1435 : case SbxDATE:
1436 : case SbxDOUBLE:
1437 : {
1438 : // Floats as ASCII
1439 : XubString aVal = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(r,
1440 0 : RTL_TEXTENCODING_ASCII_US);
1441 : SbxDataType t;
1442 0 : if( ImpScan( aVal, aData.nDouble, t, NULL ) != SbxERR_OK )
1443 : {
1444 0 : aData.nDouble = 0.0;
1445 0 : return sal_False;
1446 : }
1447 0 : break;
1448 : }
1449 : //#fdo39428 SvStream no longer supports operator>>(long&)
1450 : //SvStream now has operator>>(sal_Int64&)
1451 : case SbxSALINT64:
1452 0 : r >> aData.nInt64;
1453 0 : break;
1454 : case SbxSALUINT64:
1455 0 : r >> aData.uInt64;
1456 0 : break;
1457 : case SbxCURRENCY:
1458 : {
1459 0 : sal_uInt32 tmpHi = 0;
1460 0 : sal_uInt32 tmpLo = 0;
1461 0 : r >> tmpHi >> tmpLo;
1462 0 : aData.nInt64 = ((sal_Int64)tmpHi << 32);
1463 0 : aData.nInt64 |= (sal_Int64)tmpLo;
1464 : break;
1465 : }
1466 : case SbxSTRING:
1467 : {
1468 : rtl::OUString aVal = read_lenPrefixed_uInt8s_ToOUString<sal_uInt16>(r,
1469 0 : RTL_TEXTENCODING_ASCII_US);
1470 0 : if( aVal.getLength() )
1471 0 : aData.pOUString = new ::rtl::OUString( aVal );
1472 : else
1473 0 : aData.pOUString = NULL; // JSM 1995-09-22
1474 0 : break;
1475 : }
1476 : case SbxERROR:
1477 : case SbxUSHORT:
1478 0 : r >> aData.nUShort; break;
1479 : case SbxOBJECT:
1480 : {
1481 : sal_uInt8 nMode;
1482 0 : r >> nMode;
1483 0 : switch( nMode )
1484 : {
1485 : case 0:
1486 0 : aData.pObj = NULL;
1487 0 : break;
1488 : case 1:
1489 0 : aData.pObj = SbxBase::Load( r );
1490 0 : return sal_Bool( aData.pObj != NULL );
1491 : case 2:
1492 0 : aData.pObj = this;
1493 0 : break;
1494 : }
1495 : break;
1496 : }
1497 : case SbxCHAR:
1498 : {
1499 : char c;
1500 0 : r >> c;
1501 0 : aData.nChar = c;
1502 : break;
1503 : }
1504 : case SbxBYTE:
1505 0 : r >> aData.nByte; break;
1506 : case SbxULONG:
1507 0 : r >> aData.nULong; break;
1508 : case SbxINT:
1509 : {
1510 : sal_uInt8 n;
1511 0 : r >> n;
1512 : // Match the Int on this system?
1513 0 : if( n > SAL_TYPES_SIZEOFINT )
1514 0 : r >> aData.nLong, aData.eType = SbxLONG;
1515 : else {
1516 : sal_Int32 nInt;
1517 0 : r >> nInt;
1518 0 : aData.nInt = nInt;
1519 : }
1520 : break;
1521 : }
1522 : case SbxUINT:
1523 : {
1524 : sal_uInt8 n;
1525 0 : r >> n;
1526 : // Match the UInt on this system?
1527 0 : if( n > SAL_TYPES_SIZEOFINT )
1528 0 : r >> aData.nULong, aData.eType = SbxULONG;
1529 : else {
1530 : sal_uInt32 nUInt;
1531 0 : r >> nUInt;
1532 0 : aData.nUInt = nUInt;
1533 : }
1534 : break;
1535 : }
1536 : case SbxEMPTY:
1537 : case SbxNULL:
1538 : case SbxVOID:
1539 0 : break;
1540 : case SbxDATAOBJECT:
1541 0 : r >> aData.nLong;
1542 0 : break;
1543 : // #78919 For backwards compatibility
1544 : case SbxWSTRING:
1545 : case SbxWCHAR:
1546 0 : break;
1547 : default:
1548 0 : memset (&aData,0,sizeof(aData));
1549 0 : ResetFlag(SBX_FIXED);
1550 0 : aData.eType = SbxNULL;
1551 : DBG_ASSERT( !this, "Nicht unterstuetzer Datentyp geladen" );
1552 0 : return sal_False;
1553 : }
1554 0 : return sal_True;
1555 : }
1556 :
1557 0 : sal_Bool SbxValue::StoreData( SvStream& r ) const
1558 : {
1559 0 : sal_uInt16 nType = sal::static_int_cast< sal_uInt16 >(aData.eType);
1560 0 : r << nType;
1561 0 : switch( nType & 0x0FFF )
1562 : {
1563 : case SbxBOOL:
1564 : case SbxINTEGER:
1565 0 : r << aData.nInteger; break;
1566 : case SbxLONG:
1567 0 : r << aData.nLong; break;
1568 : case SbxDATE:
1569 : // #49935: Save as double, elsewise an error during the read in
1570 0 : ((SbxValue*)this)->aData.eType = (SbxDataType)( ( nType & 0xF000 ) | SbxDOUBLE );
1571 0 : write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1572 0 : ((SbxValue*)this)->aData.eType = (SbxDataType)nType;
1573 0 : break;
1574 : case SbxSINGLE:
1575 : case SbxDOUBLE:
1576 0 : write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, GetCoreString(), RTL_TEXTENCODING_ASCII_US);
1577 0 : break;
1578 : case SbxSALUINT64:
1579 : case SbxSALINT64:
1580 : // see comment in SbxValue::StoreData
1581 0 : r << aData.uInt64;
1582 0 : break;
1583 : case SbxCURRENCY:
1584 : {
1585 0 : sal_Int32 tmpHi = ( (aData.nInt64 >> 32) & 0xFFFFFFFF );
1586 0 : sal_Int32 tmpLo = ( sal_Int32 )aData.nInt64;
1587 0 : r << tmpHi << tmpLo;
1588 0 : break;
1589 : }
1590 : case SbxSTRING:
1591 0 : if( aData.pOUString )
1592 : {
1593 0 : write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, *aData.pOUString, RTL_TEXTENCODING_ASCII_US);
1594 : }
1595 : else
1596 : {
1597 0 : write_lenPrefixed_uInt8s_FromOUString<sal_uInt16>(r, rtl::OUString(), RTL_TEXTENCODING_ASCII_US);
1598 : }
1599 0 : break;
1600 : case SbxERROR:
1601 : case SbxUSHORT:
1602 0 : r << aData.nUShort; break;
1603 : case SbxOBJECT:
1604 : // to save itself as Objectptr does not work!
1605 0 : if( aData.pObj )
1606 : {
1607 0 : if( PTR_CAST(SbxValue,aData.pObj) != this )
1608 : {
1609 0 : r << (sal_uInt8) 1;
1610 0 : return aData.pObj->Store( r );
1611 : }
1612 : else
1613 0 : r << (sal_uInt8) 2;
1614 : }
1615 : else
1616 0 : r << (sal_uInt8) 0;
1617 0 : break;
1618 : case SbxCHAR:
1619 : {
1620 0 : char c = sal::static_int_cast< char >(aData.nChar);
1621 0 : r << c;
1622 0 : break;
1623 : }
1624 : case SbxBYTE:
1625 0 : r << aData.nByte; break;
1626 : case SbxULONG:
1627 0 : r << aData.nULong; break;
1628 : case SbxINT:
1629 : {
1630 0 : sal_uInt8 n = SAL_TYPES_SIZEOFINT;
1631 0 : r << n << (sal_Int32)aData.nInt;
1632 0 : break;
1633 : }
1634 : case SbxUINT:
1635 : {
1636 0 : sal_uInt8 n = SAL_TYPES_SIZEOFINT;
1637 0 : r << n << (sal_uInt32)aData.nUInt;
1638 0 : break;
1639 : }
1640 : case SbxEMPTY:
1641 : case SbxNULL:
1642 : case SbxVOID:
1643 0 : break;
1644 : case SbxDATAOBJECT:
1645 0 : r << aData.nLong;
1646 0 : break;
1647 : // #78919 For backwards compatibility
1648 : case SbxWSTRING:
1649 : case SbxWCHAR:
1650 0 : break;
1651 : default:
1652 : DBG_ASSERT( !this, "Speichern eines nicht unterstuetzten Datentyps" );
1653 0 : return sal_False;
1654 : }
1655 0 : return sal_True;
1656 : }
1657 :
1658 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|