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