xref: /trunk/main/basic/source/sbx/sbxcurr.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basic.hxx"
30 
31 #include <basic/sbx.hxx>
32 #include <tools/errcode.hxx>
33 
34 #define _TLBIGINT_INT64
35 #include <tools/bigint.hxx>
36 
37 #include <basic/sbxvar.hxx>
38 #include "sbxconv.hxx"
39 
40 static ::rtl::OUString   ImpCurrencyToString( const SbxINT64& );
41 static SbxINT64 ImpStringToCurrency( const ::rtl::OUString& );
42 
43 SbxINT64 ImpGetCurrency( const SbxValues* p )
44 {
45     SbxValues aTmp;
46     SbxINT64 nRes;
47 start:
48     switch( +p->eType )
49     {
50         case SbxNULL:
51             SbxBase::SetError( SbxERR_CONVERSION );
52         case SbxEMPTY:
53             nRes.SetNull(); break;
54         case SbxCHAR:
55             nRes = ImpDoubleToCurrency( (double)p->nChar ); break;
56         case SbxBYTE:
57             nRes = ImpDoubleToCurrency( (double)p->nByte ); break;
58         case SbxINTEGER:
59         case SbxBOOL:
60             nRes = ImpDoubleToCurrency( (double)p->nInteger ); break;
61         case SbxERROR:
62         case SbxUSHORT:
63             nRes = ImpDoubleToCurrency( (double)p->nUShort ); break;
64         case SbxCURRENCY:
65             nRes = p->nLong64; break;
66         case SbxLONG:
67             nRes = ImpDoubleToCurrency( (double)p->nLong );
68             break;
69         case SbxULONG:
70             nRes = ImpDoubleToCurrency( (double)p->nULong );
71             break;
72         case SbxSALINT64:
73             nRes = ImpDoubleToCurrency( (double)p->nInt64 );
74             break;
75         case SbxSALUINT64:
76             nRes = ImpDoubleToCurrency( ImpSalUInt64ToDouble( p->uInt64 ) );
77             break;
78         case SbxSINGLE:
79             if( p->nSingle > SbxMAXCURR )
80             {
81                 SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMax();
82             }
83             else if( p->nSingle < SbxMINCURR )
84             {
85                 SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMin();
86             }
87             else
88                 nRes = ImpDoubleToCurrency( (double)p->nSingle );
89             break;
90         case SbxDATE:
91         case SbxDOUBLE:
92             if( p->nDouble > SbxMAXCURR )
93             {
94                 SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMax();
95             }
96             else if( p->nDouble < SbxMINCURR )
97             {
98                 SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMin();
99             }
100             else
101                 nRes = ImpDoubleToCurrency( p->nDouble );
102             break;
103         case SbxDECIMAL:
104         case SbxBYREF | SbxDECIMAL:
105             {
106             double d = 0.0;
107             if( p->pDecimal )
108                 p->pDecimal->getDouble( d );
109             if( d > SbxMAXCURR )
110             {
111                 SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMax();
112             }
113             else if( d < SbxMINCURR )
114             {
115                 SbxBase::SetError( SbxERR_OVERFLOW ); nRes.SetMin();
116             }
117             else
118                 nRes = ImpDoubleToCurrency( d );
119             break;
120             }
121         case SbxBYREF | SbxSTRING:
122         case SbxSTRING:
123         case SbxLPSTR:
124             if( !p->pOUString )
125                 nRes.SetNull();
126             else
127                 nRes = ImpStringToCurrency( *p->pOUString );
128             break;
129         case SbxOBJECT:
130         {
131             SbxValue* pVal = PTR_CAST(SbxValue,p->pObj);
132             if( pVal )
133                 nRes = pVal->GetCurrency();
134             else
135             {
136                 SbxBase::SetError( SbxERR_NO_OBJECT ); nRes.SetNull();
137             }
138             break;
139         }
140 
141         case SbxBYREF | SbxCHAR:
142             nRes = ImpDoubleToCurrency( (double)*p->pChar ); break;
143         case SbxBYREF | SbxBYTE:
144             nRes = ImpDoubleToCurrency( (double)*p->pByte ); break;
145         case SbxBYREF | SbxINTEGER:
146         case SbxBYREF | SbxBOOL:
147             nRes = ImpDoubleToCurrency( (double)*p->pInteger ); break;
148         case SbxBYREF | SbxERROR:
149         case SbxBYREF | SbxUSHORT:
150             nRes = ImpDoubleToCurrency( (double)*p->pUShort ); break;
151         case SbxBYREF | SbxCURRENCY:
152             nRes = *p->pLong64; break;
153 
154         // ab hier muss getestet werden
155         case SbxBYREF | SbxLONG:
156             aTmp.nLong = *p->pLong; goto ref;
157         case SbxBYREF | SbxULONG:
158             aTmp.nULong = *p->pULong; goto ref;
159         case SbxBYREF | SbxSINGLE:
160             aTmp.nSingle = *p->pSingle; goto ref;
161         case SbxBYREF | SbxDATE:
162         case SbxBYREF | SbxDOUBLE:
163             aTmp.nDouble = *p->pDouble; goto ref;
164         case SbxBYREF | SbxSALINT64:
165             aTmp.nInt64 = *p->pnInt64; goto ref;
166         case SbxBYREF | SbxSALUINT64:
167             aTmp.uInt64 = *p->puInt64; goto ref;
168         ref:
169             aTmp.eType = SbxDataType( p->eType & 0x0FFF );
170             p = &aTmp; goto start;
171 
172         default:
173             SbxBase::SetError( SbxERR_CONVERSION ); nRes.SetNull();
174     }
175     return nRes;
176 }
177 
178 void ImpPutCurrency( SbxValues* p, const SbxINT64 &r )
179 {
180     double dVal = ImpCurrencyToDouble( r );
181     SbxValues aTmp;
182 start:
183     switch( +p->eType )
184     {
185         // Hier sind Tests notwendig
186         case SbxCHAR:
187             aTmp.pChar = &p->nChar; goto direct;
188         case SbxBYTE:
189             aTmp.pByte = &p->nByte; goto direct;
190         case SbxINTEGER:
191         case SbxBOOL:
192             aTmp.pInteger = &p->nInteger; goto direct;
193         case SbxLONG:
194             aTmp.pLong = &p->nLong; goto direct;
195         case SbxULONG:
196             aTmp.pULong = &p->nULong; goto direct;
197         case SbxERROR:
198         case SbxUSHORT:
199             aTmp.pUShort = &p->nUShort; goto direct;
200         direct:
201             aTmp.eType = SbxDataType( p->eType | SbxBYREF );
202             p = &aTmp; goto start;
203 
204         // ab hier nicht mehr
205         case SbxSINGLE:
206             p->nSingle = (float)dVal; break;
207         case SbxDATE:
208         case SbxDOUBLE:
209             p->nDouble = dVal; break;
210         case SbxSALINT64:
211             p->nInt64 = ImpDoubleToSalInt64( dVal ); break;
212         case SbxSALUINT64:
213             p->uInt64 = ImpDoubleToSalUInt64( dVal ); break;
214         case SbxCURRENCY:
215             p->nLong64 = r; break;
216         case SbxDECIMAL:
217         case SbxBYREF | SbxDECIMAL:
218             {
219             SbxDecimal* pDec = ImpCreateDecimal( p );
220             if( !pDec->setDouble( dVal ) )
221                 SbxBase::SetError( SbxERR_OVERFLOW );
222             break;
223             }
224         case SbxBYREF | SbxSTRING:
225         case SbxSTRING:
226         case SbxLPSTR:
227             if( !p->pOUString )
228                 p->pOUString = new ::rtl::OUString;
229 
230             *p->pOUString = ImpCurrencyToString( r );
231             break;
232         case SbxOBJECT:
233         {
234             SbxValue* pVal = PTR_CAST(SbxValue,p->pObj);
235             if( pVal )
236                 pVal->PutCurrency( r );
237             else
238                 SbxBase::SetError( SbxERR_NO_OBJECT );
239             break;
240         }
241         case SbxBYREF | SbxCHAR:
242             if( dVal > SbxMAXCHAR )
243             {
244                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXCHAR;
245             }
246             else if( dVal < SbxMINCHAR )
247             {
248                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMINCHAR;
249             }
250             *p->pChar = (xub_Unicode) dVal; break;
251         case SbxBYREF | SbxBYTE:
252             if( dVal > SbxMAXBYTE )
253             {
254                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXBYTE;
255             }
256             else if( dVal < 0 )
257             {
258                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = 0;
259             }
260             *p->pByte = (sal_uInt8) dVal; break;
261         case SbxBYREF | SbxINTEGER:
262         case SbxBYREF | SbxBOOL:
263             if( dVal > SbxMAXINT )
264             {
265                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXINT;
266             }
267             else if( dVal < SbxMININT )
268             {
269                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMININT;
270             }
271             *p->pInteger = (sal_Int16) dVal; break;
272         case SbxBYREF | SbxERROR:
273         case SbxBYREF | SbxUSHORT:
274             if( dVal > SbxMAXUINT )
275             {
276                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXUINT;
277             }
278             else if( dVal < 0 )
279             {
280                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = 0;
281             }
282             *p->pUShort = (sal_uInt16) dVal; break;
283         case SbxBYREF | SbxLONG:
284             if( dVal > SbxMAXLNG )
285             {
286                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXLNG;
287             }
288             else if( dVal < SbxMINLNG )
289             {
290                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMINLNG;
291             }
292             *p->pLong = (sal_Int32) dVal; break;
293         case SbxBYREF | SbxULONG:
294             if( dVal > SbxMAXULNG )
295             {
296                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = SbxMAXULNG;
297             }
298             else if( dVal < 0 )
299             {
300                 SbxBase::SetError( SbxERR_OVERFLOW ); dVal = 0;
301             }
302             *p->pULong = (sal_uInt32) dVal; break;
303         case SbxBYREF | SbxSALINT64:
304             *p->pnInt64 = ImpDoubleToSalInt64( dVal ); break;
305         case SbxBYREF | SbxSALUINT64:
306             *p->puInt64 = ImpDoubleToSalUInt64( dVal ); break;
307         case SbxBYREF | SbxSINGLE:
308             *p->pSingle = (float) dVal; break;
309         case SbxBYREF | SbxDATE:
310         case SbxBYREF | SbxDOUBLE:
311             *p->pDouble = (double) dVal; break;
312         case SbxBYREF | SbxCURRENCY:
313             *p->pLong64 = r; break;
314 
315         default:
316             SbxBase::SetError( SbxERR_CONVERSION );
317     }
318 }
319 
320 // Hilfs-Funktionen zur Wandlung
321 
322 static ::rtl::OUString ImpCurrencyToString( const SbxINT64 &r )
323 {
324     BigInt a10000 = 10000;
325 
326     //return GetpApp()->GetAppInternational().GetCurr( BigInt( r ), 4 );
327     BigInt aInt( r );
328     aInt.Abs();
329     BigInt aFrac = aInt;
330     aInt  /= a10000;
331     aFrac %= a10000;
332     aFrac += a10000;
333 
334     ::rtl::OUString aString;
335     if( r.nHigh < 0 )
336         aString = ::rtl::OUString( (sal_Unicode)'-' );
337     aString += aInt.GetString();
338     aString += ::rtl::OUString( (sal_Unicode)'.' );
339     aString += aFrac.GetString().GetBuffer()+1;
340     return aString;
341 }
342 
343 static SbxINT64 ImpStringToCurrency( const ::rtl::OUString &r )
344 {
345     int nDec = 4;
346     String aStr;
347     const sal_Unicode* p = r.getStr();
348 
349     if( *p == '-' )
350         aStr += *p++;
351 
352     while( *p >= '0' && *p <= '9' ) {
353         aStr += *p++;
354         if( *p == ',' )
355             p++;
356     }
357 
358     if( *p == '.' ) {
359         p++;
360         while( nDec && *p >= '0' && *p <= '9' ) {
361             aStr += *p++;
362             nDec--;
363         }
364     }
365     while( nDec ) {
366         aStr += '0';
367         nDec--;
368     }
369 
370     BigInt aBig( aStr );
371     SbxINT64 nRes;
372     aBig.INT64( &nRes );
373     return nRes;
374 }
375 
376 double ImpINT64ToDouble( const SbxINT64 &r )
377 { return (double)r.nHigh*(double)4294967296.0 + (double)r.nLow; }
378 
379 SbxINT64 ImpDoubleToINT64( double d )
380 {
381     SbxINT64 nRes;
382     nRes.Set( d );
383     return nRes;
384 }
385 
386 double ImpUINT64ToDouble( const SbxUINT64 &r )
387 { return (double)r.nHigh*(double)4294967296.0 + (double)r.nLow; }
388 
389 SbxUINT64 ImpDoubleToUINT64( double d )
390 {
391     SbxUINT64 nRes;
392     nRes.Set( d );
393     return nRes;
394 }
395 
396