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