Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / sbx / sbxdec.cxx
blob81685f7744e2f2758d594bdea72b821377e5b7fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <o3tl/char16_t2wchar_t.hxx>
22 #include <basic/sberrors.hxx>
23 #include "sbxconv.hxx"
25 #include <com/sun/star/bridge/oleautomation/Decimal.hpp>
27 // Implementation SbxDecimal
28 SbxDecimal::SbxDecimal()
29 : mnRefCount(0)
31 setInt( 0 );
34 SbxDecimal::SbxDecimal( const SbxDecimal& rDec )
35 : mnRefCount(0)
37 #ifdef _WIN32
38 maDec = rDec.maDec;
39 #else
40 (void)rDec;
41 #endif
44 SbxDecimal::SbxDecimal
45 ( const css::bridge::oleautomation::Decimal& rAutomationDec )
46 : mnRefCount(0)
48 #ifdef _WIN32
49 maDec.scale = rAutomationDec.Scale;
50 maDec.sign = rAutomationDec.Sign;
51 maDec.Lo32 = rAutomationDec.LowValue;
52 maDec.Mid32 = rAutomationDec.MiddleValue;
53 maDec.Hi32 = rAutomationDec.HighValue;
54 #else
55 (void)rAutomationDec;
56 #endif
59 void SbxDecimal::fillAutomationDecimal
60 ( css::bridge::oleautomation::Decimal& rAutomationDec )
62 #ifdef _WIN32
63 rAutomationDec.Scale = maDec.scale;
64 rAutomationDec.Sign = maDec.sign;
65 rAutomationDec.LowValue = maDec.Lo32;
66 rAutomationDec.MiddleValue = maDec.Mid32;
67 rAutomationDec.HighValue = maDec.Hi32;
68 #else
69 (void)rAutomationDec;
70 #endif
73 SbxDecimal::~SbxDecimal()
77 void releaseDecimalPtr( SbxDecimal*& rpDecimal )
79 if( rpDecimal )
81 rpDecimal->mnRefCount--;
82 if( rpDecimal->mnRefCount == 0 )
84 delete rpDecimal;
85 rpDecimal = nullptr;
90 #ifdef _WIN32
92 bool SbxDecimal::operator -= ( const SbxDecimal &r )
94 HRESULT hResult = VarDecSub( &maDec, const_cast<LPDECIMAL>(&r.maDec), &maDec );
95 bool bRet = ( hResult == S_OK );
96 return bRet;
99 bool SbxDecimal::operator += ( const SbxDecimal &r )
101 HRESULT hResult = VarDecAdd( &maDec, const_cast<LPDECIMAL>(&r.maDec), &maDec );
102 bool bRet = ( hResult == S_OK );
103 return bRet;
106 bool SbxDecimal::operator /= ( const SbxDecimal &r )
108 HRESULT hResult = VarDecDiv( &maDec, const_cast<LPDECIMAL>(&r.maDec), &maDec );
109 bool bRet = ( hResult == S_OK );
110 return bRet;
113 bool SbxDecimal::operator *= ( const SbxDecimal &r )
115 HRESULT hResult = VarDecMul( &maDec, const_cast<LPDECIMAL>(&r.maDec), &maDec );
116 bool bRet = ( hResult == S_OK );
117 return bRet;
120 bool SbxDecimal::neg()
122 HRESULT hResult = VarDecNeg( &maDec, &maDec );
123 bool bRet = ( hResult == S_OK );
124 return bRet;
127 bool SbxDecimal::isZero() const
129 SbxDecimal aZeroDec;
130 aZeroDec.setLong( 0 );
131 bool bZero = CmpResult::EQ == compare( *this, aZeroDec );
132 return bZero;
135 SbxDecimal::CmpResult compare( const SbxDecimal &rLeft, const SbxDecimal &rRight )
137 HRESULT hResult = VarDecCmp( const_cast<LPDECIMAL>(&rLeft.maDec), const_cast<LPDECIMAL>(&rRight.maDec) );
138 SbxDecimal::CmpResult eRes = static_cast<SbxDecimal::CmpResult>(hResult);
139 return eRes;
142 void SbxDecimal::setChar( sal_Unicode val )
144 VarDecFromUI2( static_cast<sal_uInt16>(val), &maDec );
147 void SbxDecimal::setByte( sal_uInt8 val )
149 VarDecFromUI1( val, &maDec );
152 void SbxDecimal::setShort( sal_Int16 val )
154 VarDecFromI2( static_cast<short>(val), &maDec );
157 void SbxDecimal::setLong( sal_Int32 val )
159 VarDecFromI4( static_cast<long>(val), &maDec );
162 void SbxDecimal::setUShort( sal_uInt16 val )
164 VarDecFromUI2( val, &maDec );
167 void SbxDecimal::setULong( sal_uInt32 val )
169 VarDecFromUI4( static_cast<ULONG>(val), &maDec );
172 bool SbxDecimal::setSingle( float val )
174 bool bRet = ( VarDecFromR4( val, &maDec ) == S_OK );
175 return bRet;
178 bool SbxDecimal::setDouble( double val )
180 bool bRet = ( VarDecFromR8( val, &maDec ) == S_OK );
181 return bRet;
184 void SbxDecimal::setInt( int val )
186 setLong( static_cast<sal_Int32>(val) );
189 void SbxDecimal::setUInt( unsigned int val )
191 setULong( static_cast<sal_uInt32>(val) );
194 bool SbxDecimal::setString( OUString* pOUString )
196 assert(pOUString);
198 static LCID nLANGID = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
200 // Convert delimiter
201 sal_Unicode cDecimalSep;
202 sal_Unicode cThousandSep;
203 sal_Unicode cDecimalSepAlt;
204 ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt );
206 bool bRet = false;
207 HRESULT hResult;
208 if( cDecimalSep != '.' || cThousandSep != ',' )
210 int nLen = pOUString->getLength();
211 std::unique_ptr<sal_Unicode[]> pBuffer(new sal_Unicode[nLen + 1]);
212 pBuffer[nLen] = 0;
214 const sal_Unicode* pSrc = pOUString->getStr();
215 for( int i = 0 ; i < nLen ; ++i )
217 sal_Unicode c = pSrc[i];
218 if (c == cDecimalSep)
219 c = '.';
220 else if (c == cThousandSep)
221 c = ',';
223 pBuffer[i] = c;
225 hResult = VarDecFromStr( o3tl::toW(pBuffer.get()), nLANGID, 0, &maDec );
227 else
229 hResult = VarDecFromStr( o3tl::toW(pOUString->getStr()), nLANGID, 0, &maDec );
231 bRet = ( hResult == S_OK );
232 return bRet;
236 bool SbxDecimal::getChar( sal_Unicode& rVal )
238 USHORT n;
239 bool bRet = ( VarUI2FromDec( &maDec, &n ) == S_OK );
240 if (bRet) {
241 rVal = n;
243 return bRet;
246 bool SbxDecimal::getShort( sal_Int16& rVal )
248 bool bRet = ( VarI2FromDec( &maDec, &rVal ) == S_OK );
249 return bRet;
252 bool SbxDecimal::getLong( sal_Int32& rVal )
254 bool bRet = ( VarI4FromDec( &maDec, &rVal ) == S_OK );
255 return bRet;
258 bool SbxDecimal::getUShort( sal_uInt16& rVal )
260 bool bRet = ( VarUI2FromDec( &maDec, &rVal ) == S_OK );
261 return bRet;
264 bool SbxDecimal::getULong( sal_uInt32& rVal )
266 bool bRet = ( VarUI4FromDec( &maDec, &rVal ) == S_OK );
267 return bRet;
270 bool SbxDecimal::getSingle( float& rVal )
272 bool bRet = ( VarR4FromDec( &maDec, &rVal ) == S_OK );
273 return bRet;
276 bool SbxDecimal::getDouble( double& rVal )
278 bool bRet = ( VarR8FromDec( &maDec, &rVal ) == S_OK );
279 return bRet;
282 #else
283 // !_WIN32
285 bool SbxDecimal::operator -= ( const SbxDecimal & )
287 return false;
290 bool SbxDecimal::operator += ( const SbxDecimal & )
292 return false;
295 bool SbxDecimal::operator /= ( const SbxDecimal & )
297 return false;
300 bool SbxDecimal::operator *= ( const SbxDecimal & )
302 return false;
305 bool SbxDecimal::neg()
307 return false;
310 bool SbxDecimal::isZero() const
312 return false;
315 SbxDecimal::CmpResult compare( SAL_UNUSED_PARAMETER const SbxDecimal &, SAL_UNUSED_PARAMETER const SbxDecimal & )
317 return SbxDecimal::CmpResult::LT;
320 void SbxDecimal::setChar( SAL_UNUSED_PARAMETER sal_Unicode ) {}
321 void SbxDecimal::setByte( SAL_UNUSED_PARAMETER sal_uInt8 ) {}
322 void SbxDecimal::setShort( SAL_UNUSED_PARAMETER sal_Int16 ) {}
323 void SbxDecimal::setLong( SAL_UNUSED_PARAMETER sal_Int32 ) {}
324 void SbxDecimal::setUShort( SAL_UNUSED_PARAMETER sal_uInt16 ) {}
325 void SbxDecimal::setULong( SAL_UNUSED_PARAMETER sal_uInt32 ) {}
326 bool SbxDecimal::setSingle( SAL_UNUSED_PARAMETER float ) { return false; }
327 bool SbxDecimal::setDouble( SAL_UNUSED_PARAMETER double ) { return false; }
328 void SbxDecimal::setInt( SAL_UNUSED_PARAMETER int ) {}
329 void SbxDecimal::setUInt( SAL_UNUSED_PARAMETER unsigned int ) {}
330 bool SbxDecimal::setString( SAL_UNUSED_PARAMETER OUString* ) { return false; }
332 bool SbxDecimal::getChar( SAL_UNUSED_PARAMETER sal_Unicode& ) { return false; }
333 bool SbxDecimal::getShort( SAL_UNUSED_PARAMETER sal_Int16& ) { return false; }
334 bool SbxDecimal::getLong( SAL_UNUSED_PARAMETER sal_Int32& ) { return false; }
335 bool SbxDecimal::getUShort( SAL_UNUSED_PARAMETER sal_uInt16& ) { return false; }
336 bool SbxDecimal::getULong( SAL_UNUSED_PARAMETER sal_uInt32& ) { return false; }
337 bool SbxDecimal::getSingle( SAL_UNUSED_PARAMETER float& ) { return false; }
338 bool SbxDecimal::getDouble( SAL_UNUSED_PARAMETER double& ) { return false; }
340 #endif
342 void SbxDecimal::getString( OUString& rString )
344 #ifdef _WIN32
345 static LCID nLANGID = MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US );
347 BSTR pBStr = nullptr;
348 // VarBstrFromDec allocates new BSTR that needs to be released with SysFreeString
349 HRESULT hResult = VarBstrFromDec( &maDec, nLANGID, 0, &pBStr );
350 if( hResult == S_OK )
352 // Convert delimiter
353 sal_Unicode cDecimalSep;
354 sal_Unicode cThousandSep;
355 sal_Unicode cDecimalSepAlt;
356 ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt );
358 if( cDecimalSep != '.' || cThousandSep != ',' )
360 sal_Unicode c;
361 int i = 0;
362 while( (c = pBStr[i]) != 0 )
364 if( c == '.' )
365 pBStr[i] = cDecimalSep;
366 else if( c == ',' )
367 pBStr[i] = cThousandSep;
368 i++;
371 rString = o3tl::toU( pBStr );
372 SysFreeString( pBStr );
374 #else
375 (void)rString;
376 #endif
379 SbxDecimal* ImpCreateDecimal( SbxValues* p )
381 if( !p )
382 return nullptr;
384 SbxDecimal*& rpDecimal = p->pDecimal;
385 if( rpDecimal == nullptr )
387 rpDecimal = new SbxDecimal();
388 rpDecimal->addRef();
390 return rpDecimal;
393 SbxDecimal* ImpGetDecimal( const SbxValues* p )
395 SbxValues aTmp;
396 SbxDecimal* pnDecRes;
398 SbxDataType eType = p->eType;
399 if( eType == SbxDECIMAL && p->pDecimal )
401 pnDecRes = new SbxDecimal( *p->pDecimal );
402 pnDecRes->addRef();
403 return pnDecRes;
405 pnDecRes = new SbxDecimal();
406 pnDecRes->addRef();
408 start:
409 switch( +eType )
411 case SbxNULL:
412 SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
413 [[fallthrough]];
414 case SbxEMPTY:
415 pnDecRes->setShort( 0 ); break;
416 case SbxCHAR:
417 pnDecRes->setChar( p->nChar ); break;
418 case SbxBYTE:
419 pnDecRes->setByte( p->nByte ); break;
420 case SbxINTEGER:
421 case SbxBOOL:
422 pnDecRes->setInt( p->nInteger ); break;
423 case SbxERROR:
424 case SbxUSHORT:
425 pnDecRes->setUShort( p->nUShort ); break;
426 case SbxLONG:
427 pnDecRes->setLong( p->nLong ); break;
428 case SbxULONG:
429 pnDecRes->setULong( p->nULong ); break;
430 case SbxSINGLE:
431 if( !pnDecRes->setSingle( p->nSingle ) )
432 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
433 break;
434 case SbxCURRENCY:
436 if( !pnDecRes->setDouble( ImpCurrencyToDouble( p->nInt64 ) ) )
437 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
438 break;
440 case SbxSALINT64:
442 if( !pnDecRes->setDouble( static_cast<double>(p->nInt64) ) )
443 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
444 break;
446 case SbxSALUINT64:
448 if( !pnDecRes->setDouble( static_cast<double>(p->uInt64) ) )
449 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
450 break;
452 case SbxDATE:
453 case SbxDOUBLE:
455 double dVal = p->nDouble;
456 if( !pnDecRes->setDouble( dVal ) )
457 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
458 break;
460 case SbxLPSTR:
461 case SbxSTRING:
462 case SbxBYREF | SbxSTRING:
463 if ( p->pOUString )
464 pnDecRes->setString( p->pOUString );
465 break;
466 case SbxOBJECT:
468 SbxValue* pVal = dynamic_cast<SbxValue*>( p->pObj );
469 if( pVal )
470 pnDecRes->setDecimal( pVal->GetDecimal() );
471 else
473 SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
474 pnDecRes->setShort( 0 );
476 break;
479 case SbxBYREF | SbxCHAR:
480 pnDecRes->setChar( *p->pChar ); break;
481 case SbxBYREF | SbxBYTE:
482 pnDecRes->setByte( *p->pByte ); break;
483 case SbxBYREF | SbxINTEGER:
484 case SbxBYREF | SbxBOOL:
485 pnDecRes->setInt( *p->pInteger ); break;
486 case SbxBYREF | SbxLONG:
487 pnDecRes->setLong( *p->pLong ); break;
488 case SbxBYREF | SbxULONG:
489 pnDecRes->setULong( *p->pULong ); break;
490 case SbxBYREF | SbxERROR:
491 case SbxBYREF | SbxUSHORT:
492 pnDecRes->setUShort( *p->pUShort ); break;
494 // from here on had to be tested
495 case SbxBYREF | SbxSINGLE:
496 aTmp.nSingle = *p->pSingle; goto ref;
497 case SbxBYREF | SbxDATE:
498 case SbxBYREF | SbxDOUBLE:
499 aTmp.nDouble = *p->pDouble; goto ref;
500 case SbxBYREF | SbxCURRENCY:
501 case SbxBYREF | SbxSALINT64:
502 aTmp.nInt64 = *p->pnInt64; goto ref;
503 case SbxBYREF | SbxSALUINT64:
504 aTmp.uInt64 = *p->puInt64; goto ref;
505 ref:
506 aTmp.eType = SbxDataType( p->eType & 0x0FFF );
507 p = &aTmp; goto start;
509 default:
510 SbxBase::SetError( ERRCODE_BASIC_CONVERSION ); pnDecRes->setShort( 0 );
512 return pnDecRes;
515 void ImpPutDecimal( SbxValues* p, SbxDecimal* pDec )
517 if( !pDec )
518 return;
520 SbxValues aTmp;
521 start:
522 switch( +p->eType )
524 // here had to be tested
525 case SbxCHAR:
526 aTmp.pChar = &p->nChar; goto direct;
527 case SbxBYTE:
528 aTmp.pByte = &p->nByte; goto direct;
529 case SbxULONG:
530 aTmp.pULong = &p->nULong; goto direct;
531 case SbxERROR:
532 case SbxUSHORT:
533 aTmp.pUShort = &p->nUShort; goto direct;
534 case SbxINTEGER:
535 case SbxBOOL:
536 aTmp.pInteger = &p->nInteger; goto direct;
537 case SbxLONG:
538 aTmp.pLong = &p->nLong; goto direct;
539 case SbxCURRENCY:
540 case SbxSALINT64:
541 aTmp.pnInt64 = &p->nInt64; goto direct;
542 case SbxSALUINT64:
543 aTmp.puInt64 = &p->uInt64; goto direct;
545 direct:
546 aTmp.eType = SbxDataType( p->eType | SbxBYREF );
547 p = &aTmp; goto start;
549 // from here on no longer
550 case SbxDECIMAL:
551 case SbxBYREF | SbxDECIMAL:
553 if( pDec != p->pDecimal )
555 releaseDecimalPtr( p->pDecimal );
556 p->pDecimal = pDec;
557 if( pDec )
558 pDec->addRef();
560 break;
562 case SbxSINGLE:
564 float f(0.0);
565 pDec->getSingle( f );
566 p->nSingle = f;
567 break;
569 case SbxDATE:
570 case SbxDOUBLE:
572 double d(0.0);
573 pDec->getDouble( d );
574 p->nDouble = d;
575 break;
578 case SbxLPSTR:
579 case SbxSTRING:
580 case SbxBYREF | SbxSTRING:
581 if( !p->pOUString )
582 p->pOUString = new OUString;
583 pDec->getString( *p->pOUString );
584 break;
585 case SbxOBJECT:
587 SbxValue* pVal = dynamic_cast<SbxValue*>( p->pObj );
588 if( pVal )
589 pVal->PutDecimal( pDec );
590 else
591 SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
592 break;
595 case SbxBYREF | SbxCHAR:
596 if( !pDec->getChar( *p->pChar ) )
598 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
599 *p->pChar = 0;
601 break;
602 case SbxBYREF | SbxBYTE:
603 if( !pDec->getChar( *p->pChar ) )
605 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
606 *p->pByte = 0;
608 break;
609 case SbxBYREF | SbxINTEGER:
610 case SbxBYREF | SbxBOOL:
611 if( !pDec->getShort( *p->pInteger ) )
613 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
614 *p->pInteger = 0;
616 break;
617 case SbxBYREF | SbxERROR:
618 case SbxBYREF | SbxUSHORT:
619 if( !pDec->getUShort( *p->pUShort ) )
621 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
622 *p->pUShort = 0;
624 break;
625 case SbxBYREF | SbxLONG:
626 if( !pDec->getLong( *p->pLong ) )
628 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
629 *p->pLong = 0;
631 break;
632 case SbxBYREF | SbxULONG:
633 if( !pDec->getULong( *p->pULong ) )
635 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
636 *p->pULong = 0;
638 break;
639 case SbxBYREF | SbxCURRENCY:
641 double d(0.0);
642 if( !pDec->getDouble( d ) )
643 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
644 *p->pnInt64 = ImpDoubleToCurrency( d );
646 break;
647 case SbxBYREF | SbxSALINT64:
649 double d(0.0);
650 if( !pDec->getDouble( d ) )
651 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
652 else
653 *p->pnInt64 = ImpDoubleToSalInt64( d );
655 break;
656 case SbxBYREF | SbxSALUINT64:
658 double d(0.0);
659 if( !pDec->getDouble( d ) )
660 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
661 else
662 *p->puInt64 = ImpDoubleToSalUInt64( d );
664 break;
665 case SbxBYREF | SbxSINGLE:
666 if( !pDec->getSingle( *p->pSingle ) )
668 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
669 *p->pSingle = 0;
671 break;
672 case SbxBYREF | SbxDATE:
673 case SbxBYREF | SbxDOUBLE:
674 if( !pDec->getDouble( *p->pDouble ) )
676 SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
677 *p->pDouble = 0;
679 break;
680 default:
681 SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
685 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */