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 <vcl/svapp.hxx>
21 #include <vcl/settings.hxx>
22 #include <svl/zforlist.hxx>
23 #include <tools/color.hxx>
24 #include <i18nlangtag/lang.h>
25 #include <basic/sberrors.hxx>
26 #include "sbxconv.hxx"
27 #include <runtime.hxx>
28 #include <sbintern.hxx>
29 #include <math.h>
30 #include <memory>
31 #include <config_features.h>
32 
33 
ImpGetDate(const SbxValues * p)34 double ImpGetDate( const SbxValues* p )
35 {
36     double nRes;
37     SbxValue* pVal;
38 
39     switch( +p->eType )
40     {
41     case SbxNULL:
42         SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
43         [[fallthrough]];
44     case SbxEMPTY:
45         nRes = 0;
46         break;
47     case SbxCHAR:
48         nRes = p->nChar;
49         break;
50     case SbxBYTE:
51         nRes = p->nByte;
52         break;
53     case SbxINTEGER:
54     case SbxBOOL:
55         nRes = p->nInteger;
56         break;
57     case SbxERROR:
58     case SbxUSHORT:
59         nRes = p->nUShort;
60         break;
61     case SbxLONG:
62         nRes = static_cast<double>(p->nLong);
63         break;
64     case SbxULONG:
65         nRes = static_cast<double>(p->nULong);
66         break;
67     case SbxSINGLE:
68         nRes = p->nSingle;
69         break;
70     case SbxDATE:
71     case SbxDOUBLE:
72         nRes = p->nDouble;
73         break;
74     case SbxCURRENCY:
75         nRes = ImpCurrencyToDouble( p->nInt64 );
76         break;
77     case SbxSALINT64:
78         nRes = static_cast< double >(p->nInt64);
79         break;
80     case SbxSALUINT64:
81         nRes = ImpSalUInt64ToDouble( p->uInt64 );
82         break;
83     case SbxDECIMAL:
84     case SbxBYREF | SbxDECIMAL:
85         if( p->pDecimal )
86         {
87             p->pDecimal->getDouble( nRes );
88         }
89         else
90         {
91             nRes = 0.0;
92         }
93         break;
94     case SbxBYREF | SbxSTRING:
95     case SbxSTRING:
96     case SbxLPSTR:
97 #if HAVE_FEATURE_SCRIPTING
98         if( !p->pOUString )
99         {
100             nRes = 0;
101         }
102         else
103         {
104             LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
105             std::shared_ptr<SvNumberFormatter> pFormatter;
106             if (GetSbData()->pInst)
107             {
108                 pFormatter = GetSbData()->pInst->GetNumberFormatter();
109             }
110             else
111             {
112                 sal_uInt32 nDummy;
113                 pFormatter = SbiInstance::PrepareNumberFormatter( nDummy, nDummy, nDummy );
114             }
115 
116             sal_uInt32 nIndex;
117             sal_Int32 nCheckPos = 0;
118             SvNumFormatType nType = SvNumFormatType::DEFINED | SvNumFormatType::DATE | SvNumFormatType::TIME | SvNumFormatType::CURRENCY
119                                     | SvNumFormatType::NUMBER | SvNumFormatType::SCIENTIFIC | SvNumFormatType::FRACTION;
120 
121             // Default templates of the formatter have only two-digit
122             // date. Therefore register an own format.
123 
124             // HACK, because the number formatter in PutandConvertEntry replace the wildcard
125             // for month, day, year not according to the configuration.
126             // Problem: Print Year(Date) under Engl. OS
127             // quod vide basic/source/runtime/runtime.cxx
128 
129             SvtSysLocale aSysLocale;
130             DateOrder eDate = aSysLocale.GetLocaleData().getDateOrder();
131             OUString aDateStr;
132             switch( eDate )
133             {
134                 default:
135                 case DateOrder::MDY: aDateStr = "MM/DD/YYYY"; break;
136                 case DateOrder::DMY: aDateStr = "DD/MM/YYYY"; break;
137                 case DateOrder::YMD: aDateStr = "YYYY/MM/DD"; break;
138             }
139 
140             OUString aStr = aDateStr + " HH:MM:SS";
141 
142             pFormatter->PutandConvertEntry( aStr, nCheckPos, nType,
143                                             nIndex, LANGUAGE_ENGLISH_US, eLangType, true);
144             bool bSuccess = pFormatter->IsNumberFormat( *p->pOUString, nIndex, nRes );
145             if ( bSuccess )
146             {
147                 SvNumFormatType nType_ = pFormatter->GetType( nIndex );
148                 if(!(nType_ & ( SvNumFormatType::DATETIME | SvNumFormatType::DATE |
149                                 SvNumFormatType::TIME | SvNumFormatType::DEFINED )))
150                 {
151                     bSuccess = false;
152                 }
153             }
154 
155             if ( !bSuccess )
156             {
157                 SbxBase::SetError( ERRCODE_BASIC_CONVERSION ); nRes = 0;
158             }
159         }
160 #else
161         nRes = 0;
162 #endif
163         break;
164     case SbxOBJECT:
165         pVal = dynamic_cast<SbxValue*>( p->pObj );
166         if( pVal )
167         {
168             nRes = pVal->GetDate();
169         }
170         else
171         {
172             SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT ); nRes = 0;
173         }
174         break;
175     case SbxBYREF | SbxCHAR:
176         nRes = *p->pChar;
177         break;
178     case SbxBYREF | SbxBYTE:
179         nRes = *p->pByte;
180         break;
181     case SbxBYREF | SbxINTEGER:
182     case SbxBYREF | SbxBOOL:
183         nRes = *p->pInteger;
184         break;
185     case SbxBYREF | SbxLONG:
186         nRes = *p->pLong;
187         break;
188     case SbxBYREF | SbxULONG:
189         nRes = *p->pULong;
190         break;
191     case SbxBYREF | SbxERROR:
192     case SbxBYREF | SbxUSHORT:
193         nRes = *p->pUShort;
194         break;
195     case SbxBYREF | SbxSINGLE:
196         nRes = *p->pSingle;
197         break;
198     case SbxBYREF | SbxDATE:
199     case SbxBYREF | SbxDOUBLE:
200         nRes = *p->pDouble;
201         break;
202     case SbxBYREF | SbxCURRENCY:
203         nRes = ImpCurrencyToDouble( *p->pnInt64 );
204         break;
205     case SbxBYREF | SbxSALINT64:
206         nRes = static_cast< double >(*p->pnInt64);
207         break;
208     case SbxBYREF | SbxSALUINT64:
209         nRes = ImpSalUInt64ToDouble( *p->puInt64 );
210         break;
211     default:
212         SbxBase::SetError( ERRCODE_BASIC_CONVERSION ); nRes = 0;
213         break;
214     }
215     return nRes;
216 }
217 
ImpPutDate(SbxValues * p,double n)218 void ImpPutDate( SbxValues* p, double n )
219 {
220     SbxValues aTmp;
221     SbxDecimal* pDec;
222     SbxValue* pVal;
223 
224 start:
225     switch( +p->eType )
226     {
227     case SbxDATE:
228     case SbxDOUBLE:
229         p->nDouble = n;
230         break;
231         // from here will be tested
232     case SbxCHAR:
233         aTmp.pChar = &p->nChar;
234         goto direct;
235     case SbxBYTE:
236         aTmp.pByte = &p->nByte;
237         goto direct;
238     case SbxINTEGER:
239     case SbxBOOL:
240         aTmp.pInteger = &p->nInteger;
241         goto direct;
242     case SbxLONG:
243         aTmp.pLong = &p->nLong;
244         goto direct;
245     case SbxULONG:
246         aTmp.pULong = &p->nULong;
247         goto direct;
248     case SbxERROR:
249     case SbxUSHORT:
250         aTmp.pUShort = &p->nUShort;
251         goto direct;
252     case SbxSINGLE:
253         aTmp.pSingle = &p->nSingle;
254         goto direct;
255     case SbxCURRENCY:
256     case SbxSALINT64:
257         aTmp.pnInt64 = &p->nInt64;
258         goto direct;
259     case SbxSALUINT64:
260         aTmp.puInt64 = &p->uInt64;
261         goto direct;
262     case SbxDECIMAL:
263     case SbxBYREF | SbxDECIMAL:
264         pDec = ImpCreateDecimal( p );
265         if( !pDec->setDouble( n ) )
266         {
267             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW );
268         }
269         break;
270     direct:
271         aTmp.eType = SbxDataType( p->eType | SbxBYREF );
272         p = &aTmp; goto start;
273 
274     case SbxBYREF | SbxSTRING:
275     case SbxSTRING:
276     case SbxLPSTR:
277         {
278 #if HAVE_FEATURE_SCRIPTING
279             if( !p->pOUString )
280             {
281                 p->pOUString = new OUString;
282             }
283             Color* pColor;
284 
285             LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
286             std::shared_ptr<SvNumberFormatter> pFormatter;
287             if (GetSbData()->pInst)
288             {
289                 pFormatter = GetSbData()->pInst->GetNumberFormatter();
290             }
291             else
292             {
293                 sal_uInt32 nDummy;
294                 pFormatter = SbiInstance::PrepareNumberFormatter( nDummy, nDummy, nDummy );
295             }
296 
297             sal_uInt32 nIndex;
298             sal_Int32 nCheckPos = 0;
299             SvNumFormatType nType;
300 
301             SvtSysLocale aSysLocale;
302             DateOrder eDate = aSysLocale.GetLocaleData().getDateOrder();
303             OUString aStr;
304             // if the whole-number part is 0, we want no year!
305             if( n <= -1.0 || n >= 1.0 )
306             {
307                 // Time only if != 00:00:00
308                 if( rtl::math::approxEqual(floor( n ), n) )
309                 {
310                     switch( eDate )
311                     {
312                         default:
313                         case DateOrder::MDY: aStr = "MM/DD/YYYY"; break;
314                         case DateOrder::DMY: aStr = "DD/MM/YYYY"; break;
315                         case DateOrder::YMD: aStr = "YYYY/MM/DD"; break;
316                     }
317                 }
318                 else
319                 {
320                     switch( eDate )
321                     {
322                         default:
323                         case DateOrder::MDY: aStr = "MM/DD/YYYY HH:MM:SS"; break;
324                         case DateOrder::DMY: aStr = "DD/MM/YYYY HH:MM:SS"; break;
325                         case DateOrder::YMD: aStr = "YYYY/MM/DD HH:MM:SS"; break;
326                     }
327                 }
328             }
329             else
330             {
331                 aStr = "HH:MM:SS";
332             }
333             pFormatter->PutandConvertEntry( aStr,
334                                             nCheckPos,
335                                             nType,
336                                             nIndex,
337                                             LANGUAGE_ENGLISH_US,
338                                             eLangType, true);
339             pFormatter->GetOutputString( n, nIndex, *p->pOUString, &pColor );
340 #endif
341             break;
342         }
343     case SbxOBJECT:
344         pVal = dynamic_cast<SbxValue*>( p->pObj );
345         if( pVal )
346         {
347             pVal->PutDate( n );
348         }
349         else
350         {
351             SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
352         }
353         break;
354     case SbxBYREF | SbxCHAR:
355         if( n > SbxMAXCHAR )
356         {
357             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXCHAR;
358         }
359         else if( n < SbxMINCHAR )
360         {
361             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMINCHAR;
362         }
363         *p->pChar = static_cast<sal_Unicode>(n);
364         break;
365     case SbxBYREF | SbxBYTE:
366         if( n > SbxMAXBYTE )
367         {
368             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXBYTE;
369         }
370         else if( n < 0 )
371         {
372             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = 0;
373         }
374         *p->pByte = static_cast<sal_uInt8>(n);
375         break;
376     case SbxBYREF | SbxINTEGER:
377     case SbxBYREF | SbxBOOL:
378         if( n > SbxMAXINT )
379         {
380             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXINT;
381         }
382         else if( n < SbxMININT )
383         {
384             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMININT;
385         }
386         *p->pInteger = static_cast<sal_Int16>(n);
387         break;
388     case SbxBYREF | SbxERROR:
389     case SbxBYREF | SbxUSHORT:
390         if( n > SbxMAXUINT )
391         {
392             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXUINT;
393         }
394         else if( n < 0 )
395         {
396             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = 0;
397         }
398         *p->pUShort = static_cast<sal_uInt16>(n);
399         break;
400     case SbxBYREF | SbxLONG:
401         if( n > SbxMAXLNG )
402         {
403             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXLNG;
404         }
405         else if( n < SbxMINLNG )
406         {
407             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMINLNG;
408         }
409         *p->pLong = static_cast<sal_Int32>(n);
410         break;
411     case SbxBYREF | SbxULONG:
412         if( n > SbxMAXULNG )
413         {
414             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXULNG;
415         }
416         else if( n < 0 )
417         {
418             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = 0;
419         }
420         *p->pULong = static_cast<sal_uInt32>(n);
421         break;
422     case SbxBYREF | SbxSINGLE:
423         if( n > SbxMAXSNG )
424         {
425             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXSNG;
426         }
427         else if( n < SbxMINSNG )
428         {
429             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMINSNG;
430         }
431         *p->pSingle = static_cast<float>(n);
432         break;
433     case SbxBYREF | SbxSALINT64:
434         *p->pnInt64 = ImpDoubleToSalInt64( n );
435         break;
436     case SbxBYREF | SbxSALUINT64:
437         *p->puInt64 = ImpDoubleToSalUInt64( n );
438         break;
439     case SbxBYREF | SbxDATE:
440     case SbxBYREF | SbxDOUBLE:
441         *p->pDouble = n;
442         break;
443     case SbxBYREF | SbxCURRENCY:
444         if( n > SbxMAXCURR )
445         {
446             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMAXCURR;
447         }
448         else if( n < SbxMINCURR )
449         {
450             SbxBase::SetError( ERRCODE_BASIC_MATH_OVERFLOW ); n = SbxMINCURR;
451         }
452         *p->pnInt64 = ImpDoubleToCurrency( n );
453         break;
454     default:
455         SbxBase::SetError( ERRCODE_BASIC_CONVERSION );
456         break;
457     }
458 }
459 
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
461