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 <sal/config.h>
21 
22 #include <o3tl/any.hxx>
23 #include <osl/diagnose.h>
24 #include <cppuhelper/implbase.hxx>
25 #include <cppuhelper/supportsservice.hxx>
26 
27 #include <typelib/typedescription.hxx>
28 #include <uno/data.h>
29 
30 #ifdef _WIN32
31 #include <cmath>
32 #else
33 #include <math.h>
34 #endif
35 #include <float.h>
36 
37 #include <com/sun/star/lang/IllegalArgumentException.hpp>
38 #include <com/sun/star/lang/XServiceInfo.hpp>
39 #include <com/sun/star/script/CannotConvertException.hpp>
40 #include <com/sun/star/script/XTypeConverter.hpp>
41 #include <com/sun/star/script/FailReason.hpp>
42 
43 namespace com { namespace sun { namespace star { namespace uno { class XComponentContext; } } } }
44 
45 using namespace css::uno;
46 using namespace css::lang;
47 using namespace css::script;
48 using namespace cppu;
49 using namespace osl;
50 
51 namespace stoc_tcv
52 {
53 
round(double aVal)54 static double round( double aVal )
55 {
56     bool bPos   = (aVal >= 0.0);
57     aVal            = ::fabs( aVal );
58     double aUpper   = ::ceil( aVal );
59 
60     aVal            = ((aUpper-aVal) <= 0.5) ? aUpper : (aUpper - 1.0);
61     return (bPos ? aVal : -aVal);
62 }
63 
64 
getNumericValue(double & rfVal,const OUString & rStr)65 static bool getNumericValue( double & rfVal, const OUString & rStr )
66 {
67     double fRet = rStr.toDouble();
68     if (fRet == 0.0)
69     {
70         sal_Int32 nLen = rStr.getLength();
71         if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
72         {
73             rfVal = 0.0;
74             return true;
75         }
76 
77         OUString trim( rStr.trim() );
78 
79         // try hex
80         sal_Int32 nX = trim.indexOf( 'x' );
81         if (nX < 0)
82             nX = trim.indexOf( 'X' );
83 
84         if (nX > 0 && trim[nX-1] == '0') // 0x
85         {
86             bool bNeg = false;
87             switch (nX)
88             {
89             case 2: // (+|-)0x...
90                 if (trim[0] == '-')
91                     bNeg = true;
92                 else if (trim[0] != '+')
93                     return false;
94                 break;
95             case 1: // 0x...
96                 break;
97             default:
98                 return false;
99             }
100 
101             OUString aHexRest( trim.copy( nX+1 ) );
102             sal_uInt64 nRet = aHexRest.toUInt64( 16 );
103 
104             if (nRet == 0)
105             {
106                 for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
107                 {
108                     if (aHexRest[nPos] != '0')
109                         return false;
110                 }
111             }
112 
113             rfVal = (bNeg ? -static_cast<double>(nRet) : static_cast<double>(nRet));
114             return true;
115         }
116 
117         nLen = trim.getLength();
118         sal_Int32 nPos = 0;
119 
120         // skip +/-
121         if (nLen && (trim[0] == '-' || trim[0] == '+'))
122             ++nPos;
123 
124         while (nPos < nLen) // skip leading zeros
125         {
126             if (trim[nPos] != '0')
127             {
128                 if (trim[nPos] != '.')
129                     return false;
130                 ++nPos;
131                 while (nPos < nLen) // skip trailing zeros
132                 {
133                     if (trim[nPos] != '0')
134                         return false;
135                     ++nPos;
136                 }
137                 break;
138             }
139             ++nPos;
140         }
141     }
142     rfVal = fRet;
143     return true;
144 }
145 
146 
getHyperValue(sal_Int64 & rnVal,const OUString & rStr)147 static bool getHyperValue( sal_Int64 & rnVal, const OUString & rStr )
148 {
149     sal_Int32 nLen = rStr.getLength();
150     if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
151     {
152         rnVal = 0;
153         return true;
154     }
155 
156     OUString trim( rStr.trim() );
157 
158     // try hex
159     sal_Int32 nX = trim.indexOf( 'x' );
160     if (nX < 0)
161         nX = trim.indexOf( 'X' );
162 
163     if (nX >= 0)
164     {
165         if (nX > 0 && trim[nX-1] == '0') // 0x
166         {
167             bool bNeg = false;
168             switch (nX)
169             {
170             case 2: // (+|-)0x...
171                 if (trim[0] == '-')
172                     bNeg = true;
173                 else if (trim[0] != '+')
174                     return false;
175                 break;
176             case 1: // 0x...
177                 break;
178             default:
179                 return false;
180             }
181 
182             OUString aHexRest( trim.copy( nX+1 ) );
183             sal_uInt64 nRet = aHexRest.toUInt64( 16 );
184 
185             if (nRet == 0)
186             {
187                 for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
188                 {
189                     if (aHexRest[nPos] != '0')
190                         return false;
191                 }
192             }
193 
194             rnVal = (bNeg ? -static_cast<sal_Int64>(nRet) : nRet);
195             return true;
196         }
197         return false;
198     }
199 
200     double fVal;
201     if (getNumericValue( fVal, rStr ) &&
202         fVal >= double(SAL_MIN_INT64) &&
203         fVal <= double(SAL_MAX_UINT64))
204     {
205         rnVal = static_cast<sal_Int64>(round( fVal ));
206         return true;
207     }
208     return false;
209 }
210 
211 
212 class TypeConverter_Impl : public WeakImplHelper< XTypeConverter, XServiceInfo >
213 {
214     // ...misc helpers...
215     /// @throws CannotConvertException
216     static sal_Int64 toHyper(
217         const Any& rAny, sal_Int64 min, sal_uInt64 max = SAL_MAX_UINT64 );
218     /// @throws CannotConvertException
219     static double toDouble( const Any& rAny, double min = -DBL_MAX, double max = DBL_MAX );
220 
221 public:
222     TypeConverter_Impl();
223 
224     // XServiceInfo
225     virtual OUString SAL_CALL getImplementationName() override;
226     virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
227     virtual  Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
228 
229     // XTypeConverter
230     virtual Any SAL_CALL convertTo( const Any& aFrom, const Type& DestinationType ) override;
231     virtual Any SAL_CALL convertToSimpleType( const Any& aFrom, TypeClass aDestinationType ) override;
232 };
233 
TypeConverter_Impl()234 TypeConverter_Impl::TypeConverter_Impl() {}
235 
236 // XServiceInfo
getImplementationName()237 OUString TypeConverter_Impl::getImplementationName()
238 {
239     return "com.sun.star.comp.stoc.TypeConverter";
240 }
241 
242 // XServiceInfo
supportsService(const OUString & ServiceName)243 sal_Bool TypeConverter_Impl::supportsService(const OUString& ServiceName)
244 {
245     return cppu::supportsService(this, ServiceName);
246 }
247 
248 // XServiceInfo
getSupportedServiceNames()249 Sequence< OUString > TypeConverter_Impl::getSupportedServiceNames()
250 {
251     Sequence< OUString > seqNames { "com.sun.star.script.Converter" };
252     return seqNames;
253 }
254 
255 
toHyper(const Any & rAny,sal_Int64 min,sal_uInt64 max)256 sal_Int64 TypeConverter_Impl::toHyper( const Any& rAny, sal_Int64 min, sal_uInt64 max )
257 {
258     sal_Int64 nRet;
259     TypeClass aDestinationClass = rAny.getValueTypeClass();
260 
261     switch (aDestinationClass)
262     {
263     // ENUM
264     case TypeClass_ENUM:
265         nRet = *static_cast<sal_Int32 const *>(rAny.getValue());
266         break;
267     // BOOL
268     case TypeClass_BOOLEAN:
269         nRet = *o3tl::forceAccess<bool>(rAny) ? 1 : 0;
270         break;
271     // CHAR, BYTE
272     case TypeClass_CHAR:
273         nRet = *o3tl::forceAccess<sal_Unicode>(rAny);
274         break;
275     case TypeClass_BYTE:
276         nRet = *o3tl::forceAccess<sal_Int8>(rAny);
277         break;
278     // SHORT
279     case TypeClass_SHORT:
280         nRet = *o3tl::forceAccess<sal_Int16>(rAny);
281         break;
282     // UNSIGNED SHORT
283     case TypeClass_UNSIGNED_SHORT:
284         nRet = *o3tl::forceAccess<sal_uInt16>(rAny);
285         break;
286     // LONG
287     case TypeClass_LONG:
288         nRet = *o3tl::forceAccess<sal_Int32>(rAny);
289         break;
290     // UNSIGNED LONG
291     case TypeClass_UNSIGNED_LONG:
292         nRet = *o3tl::forceAccess<sal_uInt32>(rAny);
293         break;
294     // HYPER
295     case TypeClass_HYPER:
296         nRet = *o3tl::forceAccess<sal_Int64>(rAny);
297         break;
298     // UNSIGNED HYPER
299     case TypeClass_UNSIGNED_HYPER:
300     {
301         nRet = static_cast<sal_Int64>(*o3tl::forceAccess<sal_uInt64>(rAny));
302         if ((min < 0 || static_cast<sal_uInt64>(nRet) >= static_cast<sal_uInt64>(min)) && // lower bound
303             static_cast<sal_uInt64>(nRet) <= max)                            // upper bound
304         {
305             return nRet;
306         }
307         throw CannotConvertException(
308             "UNSIGNED HYPER out of range!",
309             Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
310     }
311 
312     // FLOAT, DOUBLE
313     case TypeClass_FLOAT:
314     {
315         double fVal = round( *o3tl::forceAccess<float>(rAny) );
316         if (fVal >= min && fVal <= max)
317         {
318             nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
319             return nRet;
320         }
321         throw CannotConvertException(
322             "FLOAT out of range!",
323             Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
324     }
325     case TypeClass_DOUBLE:
326     {
327         double fVal = round( *o3tl::forceAccess<double>(rAny) );
328         if (fVal >= min && fVal <= max)
329         {
330             nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
331             return nRet;
332         }
333         throw CannotConvertException(
334             "DOUBLE out of range!",
335             Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
336     }
337 
338     // STRING
339     case TypeClass_STRING:
340     {
341         sal_Int64 nVal = SAL_CONST_INT64(0);
342         if (! getHyperValue( nVal, *o3tl::forceAccess<OUString>(rAny) ))
343         {
344             throw CannotConvertException(
345                 "invalid STRING value!",
346                 Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
347         }
348         nRet = nVal;
349         if (nVal >= min && (nVal < 0 || static_cast<sal_uInt64>(nVal) <= max))
350             return nRet;
351         throw CannotConvertException(
352             "STRING value out of range!",
353             Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
354     }
355 
356     default:
357         throw CannotConvertException(
358             "TYPE is not supported!",
359             Reference<XInterface>(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
360     }
361 
362     if (nRet >= min && (nRet < 0 || static_cast<sal_uInt64>(nRet) <= max))
363         return nRet;
364     throw CannotConvertException(
365         "VALUE is out of range!",
366         Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
367 }
368 
369 
toDouble(const Any & rAny,double min,double max)370 double TypeConverter_Impl::toDouble( const Any& rAny, double min, double max )
371 {
372     double fRet;
373     TypeClass aDestinationClass = rAny.getValueTypeClass();
374 
375     switch (aDestinationClass)
376     {
377     // ENUM
378     case TypeClass_ENUM:
379         fRet = *static_cast<sal_Int32 const *>(rAny.getValue());
380         break;
381     // BOOL
382     case TypeClass_BOOLEAN:
383         fRet = *o3tl::forceAccess<bool>(rAny) ? 1.0 : 0.0;
384         break;
385     // CHAR, BYTE
386     case TypeClass_CHAR:
387         fRet = *o3tl::forceAccess<sal_Unicode>(rAny);
388         break;
389     case TypeClass_BYTE:
390         fRet = *o3tl::forceAccess<sal_Int8>(rAny);
391         break;
392     // SHORT
393     case TypeClass_SHORT:
394         fRet = *o3tl::forceAccess<sal_Int16>(rAny);
395         break;
396     // UNSIGNED SHORT
397     case TypeClass_UNSIGNED_SHORT:
398         fRet = *o3tl::forceAccess<sal_uInt16>(rAny);
399         break;
400     // LONG
401     case TypeClass_LONG:
402         fRet = *o3tl::forceAccess<sal_Int32>(rAny);
403         break;
404     // UNSIGNED LONG
405     case TypeClass_UNSIGNED_LONG:
406         fRet = *o3tl::forceAccess<sal_uInt32>(rAny);
407         break;
408     // HYPER
409     case TypeClass_HYPER:
410         fRet = static_cast<double>(*o3tl::forceAccess<sal_Int64>(rAny));
411         break;
412     // UNSIGNED HYPER
413     case TypeClass_UNSIGNED_HYPER:
414         fRet = static_cast<double>(*o3tl::forceAccess<sal_uInt64>(rAny));
415         break;
416     // FLOAT, DOUBLE
417     case TypeClass_FLOAT:
418         fRet = *o3tl::forceAccess<float>(rAny);
419         break;
420     case TypeClass_DOUBLE:
421         fRet = *o3tl::forceAccess<double>(rAny);
422         break;
423 
424     // STRING
425     case TypeClass_STRING:
426     {
427         if (! getNumericValue( fRet, *o3tl::forceAccess<OUString>(rAny) ))
428         {
429             throw CannotConvertException(
430                 "invalid STRING value!",
431                 Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
432         }
433         break;
434     }
435 
436     default:
437         throw CannotConvertException(
438             "TYPE is not supported!",
439             Reference< XInterface >(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
440     }
441 
442     if (fRet >= min && fRet <= max)
443         return fRet;
444     throw CannotConvertException(
445         "VALUE is out of range!",
446         Reference< XInterface >(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
447 }
448 
449 
convertTo(const Any & rVal,const Type & aDestType)450 Any SAL_CALL TypeConverter_Impl::convertTo( const Any& rVal, const Type& aDestType )
451 {
452     const Type& aSourceType = rVal.getValueType();
453     if (aSourceType == aDestType)
454         return rVal;
455 
456     TypeClass aSourceClass = aSourceType.getTypeClass();
457     TypeClass aDestinationClass = aDestType.getTypeClass();
458 
459     Any aRet;
460 
461     // convert to...
462     switch (aDestinationClass)
463     {
464     // --- to VOID ------------------------------------------------------------------------------
465     case TypeClass_VOID:
466         return Any();
467     // --- to ANY -------------------------------------------------------------------------------
468     case TypeClass_ANY:
469         return rVal;
470 
471     // --- to STRUCT, EXCEPTION ----------------------------------------------------------
472     case TypeClass_STRUCT:
473     case TypeClass_EXCEPTION:
474     {
475         // same types or destination type is derived source type?
476         TypeDescription aSourceTD( aSourceType );
477         TypeDescription aDestTD( aDestType );
478         if (!typelib_typedescription_isAssignableFrom( aDestTD.get(), aSourceTD.get() ))
479         {
480             throw CannotConvertException(
481                 "value is not of same or derived type!",
482                 Reference< XInterface >(), aDestinationClass,
483                 FailReason::SOURCE_IS_NO_DERIVED_TYPE, 0 );
484         }
485         aRet.setValue( rVal.getValue(), aDestTD.get() ); // evtl. .uP.cAsT.
486         break;
487     }
488     // --- to INTERFACE -------------------------------------------------------------------------
489     case TypeClass_INTERFACE:
490     {
491         if (! rVal.hasValue())
492         {
493             // void -> interface (null)
494             void * null_ref = nullptr;
495             aRet.setValue( &null_ref, aDestType );
496             break;
497         }
498 
499         auto ifc = o3tl::tryAccess<css::uno::Reference<css::uno::XInterface>>(
500             rVal);
501         if (!ifc || !ifc->is())
502         {
503             throw CannotConvertException(
504                 "value is not interface",
505                 Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
506         }
507         if (! (aRet = (*ifc)->queryInterface(aDestType )).hasValue())
508         {
509             throw CannotConvertException(
510                 "value does not implement " + aDestType.getTypeName(),
511                 Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
512         }
513         break;
514     }
515     // --- to SEQUENCE --------------------------------------------------------------------------
516     case TypeClass_SEQUENCE:
517     {
518         if (aSourceClass==TypeClass_SEQUENCE)
519         {
520             if( aSourceType == aDestType )
521                 return rVal;
522 
523             TypeDescription aSourceTD( aSourceType );
524             TypeDescription aDestTD( aDestType );
525             typelib_TypeDescription * pSourceElementTD = nullptr;
526             TYPELIB_DANGER_GET(
527                 &pSourceElementTD,
528                 reinterpret_cast<typelib_IndirectTypeDescription *>(aSourceTD.get())->pType );
529             typelib_TypeDescription * pDestElementTD = nullptr;
530             TYPELIB_DANGER_GET(
531                 &pDestElementTD,
532                 reinterpret_cast<typelib_IndirectTypeDescription *>(aDestTD.get())->pType );
533 
534             sal_uInt32 nPos = (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->nElements;
535             uno_Sequence * pRet = nullptr;
536             uno_sequence_construct(
537                 &pRet, aDestTD.get(), nullptr, nPos,
538                 reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
539             aRet.setValue( &pRet, aDestTD.get() );
540             uno_destructData(
541                 &pRet, aDestTD.get(),
542                 reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
543                 // decr ref count
544 
545             char * pDestElements = (*static_cast<uno_Sequence * const *>(aRet.getValue()))->elements;
546             const char * pSourceElements =
547                 (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->elements;
548 
549             while (nPos--)
550             {
551                 char * pDestPos = pDestElements + (nPos * pDestElementTD->nSize);
552                 const char * pSourcePos = pSourceElements + (nPos * pSourceElementTD->nSize);
553 
554                 Any aElement(
555                     convertTo( Any( pSourcePos, pSourceElementTD ), pDestElementTD->pWeakRef ) );
556 
557                 if (!uno_assignData(
558                         pDestPos, pDestElementTD,
559                         (pDestElementTD->eTypeClass == typelib_TypeClass_ANY
560                          ? &aElement
561                          : const_cast< void * >( aElement.getValue() )),
562                         pDestElementTD,
563                         reinterpret_cast< uno_QueryInterfaceFunc >(
564                             cpp_queryInterface),
565                         reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
566                         reinterpret_cast< uno_ReleaseFunc >(cpp_release) ))
567                 {
568                     OSL_ASSERT( false );
569                 }
570             }
571             TYPELIB_DANGER_RELEASE( pDestElementTD );
572             TYPELIB_DANGER_RELEASE( pSourceElementTD );
573         }
574         break;
575     }
576     // --- to ENUM ------------------------------------------------------------------------------
577     case TypeClass_ENUM:
578     {
579         TypeDescription aEnumTD( aDestType );
580         aEnumTD.makeComplete();
581         sal_Int32 nPos = -1;
582 
583         if (aSourceClass==TypeClass_STRING)
584         {
585             for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
586             {
587                 if (o3tl::forceAccess<OUString>(rVal)->equalsIgnoreAsciiCase(
588                         reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos] ))
589                     break;
590             }
591         }
592         else if (aSourceClass!=TypeClass_ENUM && // exclude some unwanted types for toHyper()
593                  aSourceClass!=TypeClass_BOOLEAN &&
594                  aSourceClass!=TypeClass_CHAR)
595         {
596             sal_Int32 nEnumValue = static_cast<sal_Int32>(toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ));
597             for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
598             {
599                 if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
600                     break;
601             }
602         }
603 
604         if (nPos < 0)
605         {
606             throw CannotConvertException(
607                 "value cannot be converted to demanded ENUM!",
608                 Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
609         }
610 
611         aRet.setValue(
612             &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos],
613             aEnumTD.get() );
614 
615         break;
616     }
617 
618     default:
619         // else simple type conversion possible?
620         try
621         {
622             aRet = convertToSimpleType( rVal, aDestinationClass );
623         }
624         catch (IllegalArgumentException &)
625         {
626             // ...FailReason::INVALID is thrown
627         }
628     }
629 
630     if (aRet.hasValue())
631         return aRet;
632 
633     throw CannotConvertException(
634         "conversion not possible!",
635         Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
636 }
637 
638 
convertToSimpleType(const Any & rVal,TypeClass aDestinationClass)639 Any TypeConverter_Impl::convertToSimpleType( const Any& rVal, TypeClass aDestinationClass )
640 {
641     switch (aDestinationClass)
642     {
643         // only simple Conversion of _simple_ types
644     case TypeClass_VOID:
645     case TypeClass_BOOLEAN:
646     case TypeClass_BYTE:
647     case TypeClass_SHORT:
648     case TypeClass_UNSIGNED_SHORT:
649     case TypeClass_LONG:
650     case TypeClass_UNSIGNED_LONG:
651     case TypeClass_HYPER:
652     case TypeClass_UNSIGNED_HYPER:
653     case TypeClass_FLOAT:
654     case TypeClass_DOUBLE:
655     case TypeClass_CHAR:
656     case TypeClass_STRING:
657     case TypeClass_ANY:
658         break;
659 
660     default:
661         throw IllegalArgumentException(
662             "destination type is not simple!",
663             Reference< XInterface >(), sal_Int16(1) );
664     }
665 
666     const Type& aSourceType = rVal.getValueType();
667     TypeClass aSourceClass = aSourceType.getTypeClass();
668     if (aDestinationClass == aSourceClass)
669         return rVal;
670 
671     Any aRet;
672 
673     // Convert to...
674     switch (aDestinationClass)
675     {
676     // --- to VOID ------------------------------------------------------------------------------
677     case TypeClass_VOID:
678         return Any();
679 
680     // --- to ANY -------------------------------------------------------------------------------
681     case TypeClass_ANY:
682         return rVal;
683 
684     // --- to BOOL ------------------------------------------------------------------------------
685     case TypeClass_BOOLEAN:
686         switch (aSourceClass)
687         {
688         default:
689             aRet <<= (toDouble( rVal ) != 0.0);
690             break;
691         case TypeClass_ENUM:  // exclude enums
692             break;
693 
694         case TypeClass_STRING:
695         {
696             const OUString & aStr = *o3tl::forceAccess<OUString>(rVal);
697             if ( aStr == "0" || aStr.equalsIgnoreAsciiCase( "false" ))
698             {
699                 aRet <<= false;
700             }
701             else if ( aStr == "1" || aStr.equalsIgnoreAsciiCase( "true" ))
702             {
703                 aRet <<= true;
704             }
705             else
706             {
707                 throw CannotConvertException(
708                     "STRING has no boolean value, " + aStr,
709                     Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_BOOL, 0 );
710             }
711         }
712         }
713         break;
714 
715     // --- to CHAR, BYTE ------------------------------------------------------------------------
716     case TypeClass_CHAR:
717     {
718         if (aSourceClass==TypeClass_STRING)
719         {
720             auto const s = o3tl::forceAccess<OUString>(rVal);
721             if (s->getLength() == 1)      // single char
722                 aRet <<= (*s)[0];
723         }
724         else if (aSourceClass!=TypeClass_ENUM &&        // exclude enums, chars
725                  aSourceClass!=TypeClass_CHAR)
726         {
727             aRet <<= sal_Unicode(toHyper( rVal, 0, 0xffff ));    // range
728         }
729         break;
730     }
731     case TypeClass_BYTE:
732         aRet <<= static_cast<sal_Int8>( toHyper( rVal, -sal_Int64(0x80), 0x7f ) );
733         break;
734 
735     // --- to SHORT, UNSIGNED SHORT -------------------------------------------------------------
736     case TypeClass_SHORT:
737         aRet <<= static_cast<sal_Int16>( toHyper( rVal, -sal_Int64(0x8000), 0x7fff ) );
738         break;
739     case TypeClass_UNSIGNED_SHORT:
740         aRet <<= static_cast<sal_uInt16>( toHyper( rVal, 0, 0xffff ) );
741         break;
742 
743     // --- to LONG, UNSIGNED LONG ---------------------------------------------------------------
744     case TypeClass_LONG:
745         aRet <<= static_cast<sal_Int32>( toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ) );
746         break;
747     case TypeClass_UNSIGNED_LONG:
748         aRet <<= static_cast<sal_uInt32>( toHyper( rVal, 0, 0xffffffff ) );
749         break;
750 
751     // --- to HYPER, UNSIGNED HYPER--------------------------------------------
752     case TypeClass_HYPER:
753         aRet <<= toHyper( rVal, SAL_MIN_INT64, SAL_MAX_INT64 );
754         break;
755     case TypeClass_UNSIGNED_HYPER:
756         aRet <<= static_cast<sal_uInt64>( toHyper( rVal, 0 ) );
757         break;
758 
759     // --- to FLOAT, DOUBLE ---------------------------------------------------------------------
760     case TypeClass_FLOAT:
761         aRet <<= static_cast<float>( toDouble( rVal, -FLT_MAX, FLT_MAX ) );
762         break;
763     case TypeClass_DOUBLE:
764         aRet <<= toDouble( rVal, -DBL_MAX, DBL_MAX );
765         break;
766 
767     // --- to STRING ----------------------------------------------------------------------------
768     case TypeClass_STRING:
769         switch (aSourceClass)
770         {
771         case TypeClass_ENUM:
772         {
773             TypeDescription aEnumTD( aSourceType );
774             aEnumTD.makeComplete();
775             sal_Int32 nPos;
776             sal_Int32 nEnumValue = *static_cast<sal_Int32 const *>(rVal.getValue());
777             for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
778             {
779                 if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
780                     break;
781             }
782             if (nPos < 0)
783             {
784                 throw CannotConvertException(
785                     "value is not ENUM!",
786                     Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
787             }
788 
789             aRet <<= OUString::unacquired(
790                 &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]);
791 
792             break;
793         }
794 
795         case TypeClass_BOOLEAN:
796             aRet <<= *o3tl::forceAccess<bool>(rVal) ?
797                 OUString("true") :
798                 OUString("false");
799             break;
800         case TypeClass_CHAR:
801             aRet <<= OUString(*o3tl::forceAccess<sal_Unicode>(rVal));
802             break;
803 
804         case TypeClass_BYTE:
805             aRet <<= OUString::number( *o3tl::forceAccess<sal_Int8>(rVal) );
806             break;
807         case TypeClass_SHORT:
808             aRet <<= OUString::number( *o3tl::forceAccess<sal_Int16>(rVal) );
809             break;
810         case TypeClass_UNSIGNED_SHORT:
811             aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt16>(rVal) );
812             break;
813         case TypeClass_LONG:
814             aRet <<= OUString::number( *o3tl::forceAccess<sal_Int32>(rVal) );
815             break;
816         case TypeClass_UNSIGNED_LONG:
817             aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt32>(rVal) );
818             break;
819         case TypeClass_HYPER:
820             aRet <<= OUString::number( *o3tl::forceAccess<sal_Int64>(rVal) );
821             break;
822 //      case TypeClass_UNSIGNED_HYPER:
823 //             aRet <<= OUString::valueOf( (sal_Int64)*(sal_uInt64 const *)rVal.getValue() );
824 //          break;
825             // handle unsigned hyper like double
826 
827         default:
828             aRet <<= OUString::number( toDouble( rVal ) );
829         }
830         break;
831 
832     default:
833         OSL_ASSERT(false);
834         break;
835     }
836 
837     if (aRet.hasValue())
838         return aRet;
839 
840     throw CannotConvertException(
841         "conversion not possible!",
842         Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
843 }
844 
845 }
846 
847 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
com_sun_star_comp_stoc_TypeConverter_get_implementation(css::uno::XComponentContext *,css::uno::Sequence<css::uno::Any> const &)848 com_sun_star_comp_stoc_TypeConverter_get_implementation(css::uno::XComponentContext*,
849         css::uno::Sequence<css::uno::Any> const &)
850 {
851     return ::cppu::acquire(new stoc_tcv::TypeConverter_Impl());
852 }
853 
854 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
855