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