summaryrefslogtreecommitdiffstats
path: root/stoc/source/typeconv/convert.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /stoc/source/typeconv/convert.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'stoc/source/typeconv/convert.cxx')
-rw-r--r--stoc/source/typeconv/convert.cxx870
1 files changed, 870 insertions, 0 deletions
diff --git a/stoc/source/typeconv/convert.cxx b/stoc/source/typeconv/convert.cxx
new file mode 100644
index 000000000..1b50c9449
--- /dev/null
+++ b/stoc/source/typeconv/convert.cxx
@@ -0,0 +1,870 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+
+#ifdef _WIN32
+#include <cmath>
+#else
+#include <math.h>
+#endif
+#include <float.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/script/FailReason.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::script;
+using namespace cppu;
+using namespace osl;
+
+namespace stoc_tcv
+{
+
+static double round( double aVal )
+{
+ bool bPos = (aVal >= 0.0);
+ aVal = ::fabs( aVal );
+ double aUpper = ::ceil( aVal );
+
+ aVal = ((aUpper-aVal) <= 0.5) ? aUpper : (aUpper - 1.0);
+ return (bPos ? aVal : -aVal);
+}
+
+
+static bool getNumericValue( double & rfVal, const OUString & rStr )
+{
+ double fRet = rStr.toDouble();
+ if (fRet == 0.0)
+ {
+ sal_Int32 nLen = rStr.getLength();
+ if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
+ {
+ rfVal = 0.0;
+ return true;
+ }
+
+ OUString trim( rStr.trim() );
+
+ // try hex
+ sal_Int32 nX = trim.indexOf( 'x' );
+ if (nX < 0)
+ nX = trim.indexOf( 'X' );
+
+ if (nX > 0 && trim[nX-1] == '0') // 0x
+ {
+ bool bNeg = false;
+ switch (nX)
+ {
+ case 2: // (+|-)0x...
+ if (trim[0] == '-')
+ bNeg = true;
+ else if (trim[0] != '+')
+ return false;
+ break;
+ case 1: // 0x...
+ break;
+ default:
+ return false;
+ }
+
+ OUString aHexRest( trim.copy( nX+1 ) );
+ sal_uInt64 nRet = aHexRest.toUInt64( 16 );
+
+ if (nRet == 0)
+ {
+ for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
+ {
+ if (aHexRest[nPos] != '0')
+ return false;
+ }
+ }
+
+ rfVal = (bNeg ? -static_cast<double>(nRet) : static_cast<double>(nRet));
+ return true;
+ }
+
+ nLen = trim.getLength();
+ sal_Int32 nPos = 0;
+
+ // skip +/-
+ if (nLen && (trim[0] == '-' || trim[0] == '+'))
+ ++nPos;
+
+ while (nPos < nLen) // skip leading zeros
+ {
+ if (trim[nPos] != '0')
+ {
+ if (trim[nPos] != '.')
+ return false;
+ ++nPos;
+ while (nPos < nLen) // skip trailing zeros
+ {
+ if (trim[nPos] != '0')
+ return false;
+ ++nPos;
+ }
+ break;
+ }
+ ++nPos;
+ }
+ }
+ rfVal = fRet;
+ return true;
+}
+
+
+static bool getHyperValue( sal_Int64 & rnVal, const OUString & rStr )
+{
+ sal_Int32 nLen = rStr.getLength();
+ if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
+ {
+ rnVal = 0;
+ return true;
+ }
+
+ OUString trim( rStr.trim() );
+
+ // try hex
+ sal_Int32 nX = trim.indexOf( 'x' );
+ if (nX < 0)
+ nX = trim.indexOf( 'X' );
+
+ if (nX >= 0)
+ {
+ if (nX > 0 && trim[nX-1] == '0') // 0x
+ {
+ bool bNeg = false;
+ switch (nX)
+ {
+ case 2: // (+|-)0x...
+ if (trim[0] == '-')
+ bNeg = true;
+ else if (trim[0] != '+')
+ return false;
+ break;
+ case 1: // 0x...
+ break;
+ default:
+ return false;
+ }
+
+ OUString aHexRest( trim.copy( nX+1 ) );
+ sal_uInt64 nRet = aHexRest.toUInt64( 16 );
+
+ if (nRet == 0)
+ {
+ for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
+ {
+ if (aHexRest[nPos] != '0')
+ return false;
+ }
+ }
+
+ rnVal = (bNeg ? -static_cast<sal_Int64>(nRet) : nRet);
+ return true;
+ }
+ return false;
+ }
+
+ double fVal;
+ if (getNumericValue( fVal, rStr ) &&
+ fVal >= double(SAL_MIN_INT64) &&
+ fVal <= double(SAL_MAX_UINT64))
+ {
+ rnVal = static_cast<sal_Int64>(round( fVal ));
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+class TypeConverter_Impl : public WeakImplHelper< XTypeConverter, XServiceInfo >
+{
+ // ...misc helpers...
+ /// @throws CannotConvertException
+ static sal_Int64 toHyper(
+ const Any& rAny, sal_Int64 min, sal_uInt64 max = SAL_MAX_UINT64 );
+ /// @throws CannotConvertException
+ static double toDouble( const Any& rAny, double min = -DBL_MAX, double max = DBL_MAX );
+
+public:
+ TypeConverter_Impl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeConverter
+ virtual Any SAL_CALL convertTo( const Any& aFrom, const Type& DestinationType ) override;
+ virtual Any SAL_CALL convertToSimpleType( const Any& aFrom, TypeClass aDestinationType ) override;
+};
+
+}
+
+TypeConverter_Impl::TypeConverter_Impl() {}
+
+// XServiceInfo
+OUString TypeConverter_Impl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.TypeConverter";
+}
+
+// XServiceInfo
+sal_Bool TypeConverter_Impl::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > TypeConverter_Impl::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.Converter" };
+}
+
+
+sal_Int64 TypeConverter_Impl::toHyper( const Any& rAny, sal_Int64 min, sal_uInt64 max )
+{
+ sal_Int64 nRet;
+ TypeClass aDestinationClass = rAny.getValueTypeClass();
+
+ switch (aDestinationClass)
+ {
+ // ENUM
+ case TypeClass_ENUM:
+ nRet = *static_cast<sal_Int32 const *>(rAny.getValue());
+ break;
+ // BOOL
+ case TypeClass_BOOLEAN:
+ nRet = *o3tl::forceAccess<bool>(rAny) ? 1 : 0;
+ break;
+ // CHAR, BYTE
+ case TypeClass_CHAR:
+ nRet = *o3tl::forceAccess<sal_Unicode>(rAny);
+ break;
+ case TypeClass_BYTE:
+ nRet = *o3tl::forceAccess<sal_Int8>(rAny);
+ break;
+ // SHORT
+ case TypeClass_SHORT:
+ nRet = *o3tl::forceAccess<sal_Int16>(rAny);
+ break;
+ // UNSIGNED SHORT
+ case TypeClass_UNSIGNED_SHORT:
+ nRet = *o3tl::forceAccess<sal_uInt16>(rAny);
+ break;
+ // LONG
+ case TypeClass_LONG:
+ nRet = *o3tl::forceAccess<sal_Int32>(rAny);
+ break;
+ // UNSIGNED LONG
+ case TypeClass_UNSIGNED_LONG:
+ nRet = *o3tl::forceAccess<sal_uInt32>(rAny);
+ break;
+ // HYPER
+ case TypeClass_HYPER:
+ nRet = *o3tl::forceAccess<sal_Int64>(rAny);
+ break;
+ // UNSIGNED HYPER
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ auto const n = *o3tl::forceAccess<sal_uInt64>(rAny);
+ if ((min < 0 || n >= o3tl::make_unsigned(min)) && // lower bound
+ n <= max) // upper bound
+ {
+ return static_cast<sal_Int64>(n);
+ }
+ throw CannotConvertException(
+ "UNSIGNED HYPER out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ // FLOAT, DOUBLE
+ case TypeClass_FLOAT:
+ {
+ double fVal = round( *o3tl::forceAccess<float>(rAny) );
+ if (fVal >= min && fVal <= max)
+ {
+ nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
+ return nRet;
+ }
+ throw CannotConvertException(
+ "FLOAT out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+ case TypeClass_DOUBLE:
+ {
+ double fVal = round( *o3tl::forceAccess<double>(rAny) );
+ if (fVal >= min && fVal <= max)
+ {
+ nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
+ return nRet;
+ }
+ throw CannotConvertException(
+ "DOUBLE out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ // STRING
+ case TypeClass_STRING:
+ {
+ sal_Int64 nVal = SAL_CONST_INT64(0);
+ if (! getHyperValue( nVal, *o3tl::forceAccess<OUString>(rAny) ))
+ {
+ throw CannotConvertException(
+ "invalid STRING value!",
+ Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
+ }
+ nRet = nVal;
+ if (nVal >= min && (nVal < 0 || o3tl::make_unsigned(nVal) <= max))
+ return nRet;
+ throw CannotConvertException(
+ "STRING value out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ default:
+ throw CannotConvertException(
+ "TYPE is not supported!",
+ Reference<XInterface>(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
+ }
+
+ if (nRet >= min && (nRet < 0 || o3tl::make_unsigned(nRet) <= max))
+ return nRet;
+ throw CannotConvertException(
+ "VALUE is out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+}
+
+
+double TypeConverter_Impl::toDouble( const Any& rAny, double min, double max )
+{
+ double fRet;
+ TypeClass aDestinationClass = rAny.getValueTypeClass();
+
+ switch (aDestinationClass)
+ {
+ // ENUM
+ case TypeClass_ENUM:
+ fRet = *static_cast<sal_Int32 const *>(rAny.getValue());
+ break;
+ // BOOL
+ case TypeClass_BOOLEAN:
+ fRet = *o3tl::forceAccess<bool>(rAny) ? 1.0 : 0.0;
+ break;
+ // CHAR, BYTE
+ case TypeClass_CHAR:
+ fRet = *o3tl::forceAccess<sal_Unicode>(rAny);
+ break;
+ case TypeClass_BYTE:
+ fRet = *o3tl::forceAccess<sal_Int8>(rAny);
+ break;
+ // SHORT
+ case TypeClass_SHORT:
+ fRet = *o3tl::forceAccess<sal_Int16>(rAny);
+ break;
+ // UNSIGNED SHORT
+ case TypeClass_UNSIGNED_SHORT:
+ fRet = *o3tl::forceAccess<sal_uInt16>(rAny);
+ break;
+ // LONG
+ case TypeClass_LONG:
+ fRet = *o3tl::forceAccess<sal_Int32>(rAny);
+ break;
+ // UNSIGNED LONG
+ case TypeClass_UNSIGNED_LONG:
+ fRet = *o3tl::forceAccess<sal_uInt32>(rAny);
+ break;
+ // HYPER
+ case TypeClass_HYPER:
+ fRet = static_cast<double>(*o3tl::forceAccess<sal_Int64>(rAny));
+ break;
+ // UNSIGNED HYPER
+ case TypeClass_UNSIGNED_HYPER:
+ fRet = static_cast<double>(*o3tl::forceAccess<sal_uInt64>(rAny));
+ break;
+ // FLOAT, DOUBLE
+ case TypeClass_FLOAT:
+ fRet = *o3tl::forceAccess<float>(rAny);
+ break;
+ case TypeClass_DOUBLE:
+ fRet = *o3tl::forceAccess<double>(rAny);
+ break;
+
+ // STRING
+ case TypeClass_STRING:
+ {
+ if (! getNumericValue( fRet, *o3tl::forceAccess<OUString>(rAny) ))
+ {
+ throw CannotConvertException(
+ "invalid STRING value!",
+ Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
+ }
+ break;
+ }
+
+ default:
+ throw CannotConvertException(
+ "TYPE is not supported!",
+ Reference< XInterface >(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
+ }
+
+ if (fRet >= min && fRet <= max)
+ return fRet;
+ throw CannotConvertException(
+ "VALUE is out of range!",
+ Reference< XInterface >(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+}
+
+
+Any SAL_CALL TypeConverter_Impl::convertTo( const Any& rVal, const Type& aDestType )
+{
+ const Type& aSourceType = rVal.getValueType();
+ if (aSourceType == aDestType)
+ return rVal;
+
+ TypeClass aSourceClass = aSourceType.getTypeClass();
+ TypeClass aDestinationClass = aDestType.getTypeClass();
+
+ Any aRet;
+
+ // convert to...
+ switch (aDestinationClass)
+ {
+ // --- to VOID ------------------------------------------------------------------------------
+ case TypeClass_VOID:
+ return Any();
+ // --- to ANY -------------------------------------------------------------------------------
+ case TypeClass_ANY:
+ return rVal;
+
+ // --- to STRUCT, EXCEPTION ----------------------------------------------------------
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION:
+ {
+ // same types or destination type is derived source type?
+ TypeDescription aSourceTD( aSourceType );
+ TypeDescription aDestTD( aDestType );
+ if (!typelib_typedescription_isAssignableFrom( aDestTD.get(), aSourceTD.get() ))
+ {
+ throw CannotConvertException(
+ "value is not of same or derived type!",
+ Reference< XInterface >(), aDestinationClass,
+ FailReason::SOURCE_IS_NO_DERIVED_TYPE, 0 );
+ }
+ aRet.setValue( rVal.getValue(), aDestTD.get() ); // evtl. .uP.cAsT.
+ break;
+ }
+ // --- to INTERFACE -------------------------------------------------------------------------
+ case TypeClass_INTERFACE:
+ {
+ if (! rVal.hasValue())
+ {
+ // void -> interface (null)
+ void * null_ref = nullptr;
+ // coverity[var_deref_model : FALSE] - null_ref will not be derefed in this case
+ aRet.setValue( &null_ref, aDestType );
+ break;
+ }
+
+ auto ifc = o3tl::tryAccess<css::uno::Reference<css::uno::XInterface>>(
+ rVal);
+ if (!ifc || !ifc->is())
+ {
+ throw CannotConvertException(
+ "value is not interface",
+ Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
+ }
+ aRet = (*ifc)->queryInterface(aDestType );
+ if (! aRet.hasValue())
+ {
+ throw CannotConvertException(
+ "value does not implement " + aDestType.getTypeName(),
+ Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
+ }
+ break;
+ }
+ // --- to SEQUENCE --------------------------------------------------------------------------
+ case TypeClass_SEQUENCE:
+ {
+ if (aSourceClass==TypeClass_SEQUENCE)
+ {
+ if( aSourceType == aDestType )
+ return rVal;
+
+ TypeDescription aSourceTD( aSourceType );
+ TypeDescription aDestTD( aDestType );
+ // For a sequence type notation "[]...", SequenceTypeDescription in
+ // cppuhelper/source/typemanager.cxx resolves the "..." component type notation part
+ // only lazily, so it could happen here that bad user input (e.g., "[]" or "[]foo" from
+ // a Basic script CreateUnoValue call) leads to a bad but as-of-yet undetected
+ // aDestType, so check it here; this is less likely an issue for the non-sequence type
+ // classes, whose notation is not resolved lazily based on their syntax:
+ if (!aDestTD.is()) {
+ throw css::lang::IllegalArgumentException(
+ "Bad XTypeConverter::convertTo destination " + aDestType.getTypeName(),
+ static_cast<cppu::OWeakObject *>(this), 1);
+ }
+ typelib_TypeDescription * pSourceElementTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pSourceElementTD,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(aSourceTD.get())->pType );
+ typelib_TypeDescription * pDestElementTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pDestElementTD,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(aDestTD.get())->pType );
+
+ sal_uInt32 nPos = (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->nElements;
+ uno_Sequence * pRet = nullptr;
+ uno_sequence_construct(
+ &pRet, aDestTD.get(), nullptr, nPos,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ aRet.setValue( &pRet, aDestTD.get() );
+ uno_destructData(
+ &pRet, aDestTD.get(),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ // decr ref count
+
+ char * pDestElements = (*static_cast<uno_Sequence * const *>(aRet.getValue()))->elements;
+ const char * pSourceElements =
+ (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->elements;
+
+ while (nPos--)
+ {
+ char * pDestPos = pDestElements + (nPos * pDestElementTD->nSize);
+ const char * pSourcePos = pSourceElements + (nPos * pSourceElementTD->nSize);
+
+ Any aElement(
+ convertTo( Any( pSourcePos, pSourceElementTD ), pDestElementTD->pWeakRef ) );
+
+ if (!uno_assignData(
+ pDestPos, pDestElementTD,
+ (pDestElementTD->eTypeClass == typelib_TypeClass_ANY
+ ? &aElement
+ : const_cast< void * >( aElement.getValue() )),
+ pDestElementTD,
+ reinterpret_cast< uno_QueryInterfaceFunc >(
+ cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) ))
+ {
+ OSL_ASSERT( false );
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pDestElementTD );
+ TYPELIB_DANGER_RELEASE( pSourceElementTD );
+ }
+ break;
+ }
+ // --- to ENUM ------------------------------------------------------------------------------
+ case TypeClass_ENUM:
+ {
+ TypeDescription aEnumTD( aDestType );
+ aEnumTD.makeComplete();
+ sal_Int32 nPos = -1;
+
+ if (aSourceClass==TypeClass_STRING)
+ {
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (o3tl::forceAccess<OUString>(rVal)->equalsIgnoreAsciiCase(
+ OUString::unacquired(&reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]) ))
+ break;
+ }
+ }
+ else if (aSourceClass!=TypeClass_ENUM && // exclude some unwanted types for toHyper()
+ aSourceClass!=TypeClass_BOOLEAN &&
+ aSourceClass!=TypeClass_CHAR)
+ {
+ sal_Int32 nEnumValue = static_cast<sal_Int32>(toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ));
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
+ break;
+ }
+ }
+
+ if (nPos < 0)
+ {
+ throw CannotConvertException(
+ "value cannot be converted to demanded ENUM!",
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
+ }
+
+ aRet.setValue(
+ &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos],
+ aEnumTD.get() );
+
+ break;
+ }
+
+ default:
+ // else simple type conversion possible?
+ try
+ {
+ aRet = convertToSimpleType( rVal, aDestinationClass );
+ }
+ catch (IllegalArgumentException &)
+ {
+ // ...FailReason::INVALID is thrown
+ }
+ }
+
+ if (aRet.hasValue())
+ return aRet;
+
+ throw CannotConvertException(
+ "conversion not possible!",
+ Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
+}
+
+
+Any TypeConverter_Impl::convertToSimpleType( const Any& rVal, TypeClass aDestinationClass )
+{
+ switch (aDestinationClass)
+ {
+ // only simple Conversion of _simple_ types
+ case TypeClass_VOID:
+ case TypeClass_BOOLEAN:
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ case TypeClass_CHAR:
+ case TypeClass_STRING:
+ case TypeClass_ANY:
+ break;
+
+ default:
+ throw IllegalArgumentException(
+ "destination type is not simple!",
+ Reference< XInterface >(), sal_Int16(1) );
+ }
+
+ const Type& aSourceType = rVal.getValueType();
+ TypeClass aSourceClass = aSourceType.getTypeClass();
+ if (aDestinationClass == aSourceClass)
+ return rVal;
+
+ Any aRet;
+
+ // Convert to...
+ switch (aDestinationClass)
+ {
+ // --- to VOID ------------------------------------------------------------------------------
+ case TypeClass_VOID:
+ return Any();
+
+ // --- to ANY -------------------------------------------------------------------------------
+ case TypeClass_ANY:
+ return rVal;
+
+ // --- to BOOL ------------------------------------------------------------------------------
+ case TypeClass_BOOLEAN:
+ switch (aSourceClass)
+ {
+ default:
+ aRet <<= (toDouble( rVal ) != 0.0);
+ break;
+ case TypeClass_ENUM: // exclude enums
+ break;
+
+ case TypeClass_STRING:
+ {
+ const OUString & aStr = *o3tl::forceAccess<OUString>(rVal);
+ if ( aStr == "0" || aStr.equalsIgnoreAsciiCase( "false" ))
+ {
+ aRet <<= false;
+ }
+ else if ( aStr == "1" || aStr.equalsIgnoreAsciiCase( "true" ))
+ {
+ aRet <<= true;
+ }
+ else
+ {
+ throw CannotConvertException(
+ "STRING has no boolean value, " + aStr,
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_BOOL, 0 );
+ }
+ }
+ }
+ break;
+
+ // --- to CHAR, BYTE ------------------------------------------------------------------------
+ case TypeClass_CHAR:
+ {
+ if (aSourceClass==TypeClass_STRING)
+ {
+ auto const s = o3tl::forceAccess<OUString>(rVal);
+ if (s->getLength() == 1) // single char
+ aRet <<= (*s)[0];
+ }
+ else if (aSourceClass!=TypeClass_ENUM && // exclude enums, chars
+ aSourceClass!=TypeClass_CHAR)
+ {
+ aRet <<= sal_Unicode(toHyper( rVal, 0, 0xffff )); // range
+ }
+ break;
+ }
+ case TypeClass_BYTE:
+ aRet <<= static_cast<sal_Int8>( toHyper( rVal, -sal_Int64(0x80), 0x7f ) );
+ break;
+
+ // --- to SHORT, UNSIGNED SHORT -------------------------------------------------------------
+ case TypeClass_SHORT:
+ aRet <<= static_cast<sal_Int16>( toHyper( rVal, -sal_Int64(0x8000), 0x7fff ) );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ aRet <<= static_cast<sal_uInt16>( toHyper( rVal, 0, 0xffff ) );
+ break;
+
+ // --- to LONG, UNSIGNED LONG ---------------------------------------------------------------
+ case TypeClass_LONG:
+ aRet <<= static_cast<sal_Int32>( toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ aRet <<= static_cast<sal_uInt32>( toHyper( rVal, 0, 0xffffffff ) );
+ break;
+
+ // --- to HYPER, UNSIGNED HYPER--------------------------------------------
+ case TypeClass_HYPER:
+ aRet <<= toHyper( rVal, SAL_MIN_INT64, SAL_MAX_INT64 );
+ break;
+ case TypeClass_UNSIGNED_HYPER:
+ aRet <<= static_cast<sal_uInt64>( toHyper( rVal, 0 ) );
+ break;
+
+ // --- to FLOAT, DOUBLE ---------------------------------------------------------------------
+ case TypeClass_FLOAT:
+ aRet <<= static_cast<float>( toDouble( rVal, -FLT_MAX, FLT_MAX ) );
+ break;
+ case TypeClass_DOUBLE:
+ aRet <<= toDouble( rVal, -DBL_MAX, DBL_MAX );
+ break;
+
+ // --- to STRING ----------------------------------------------------------------------------
+ case TypeClass_STRING:
+ switch (aSourceClass)
+ {
+ case TypeClass_ENUM:
+ {
+ TypeDescription aEnumTD( aSourceType );
+ aEnumTD.makeComplete();
+ sal_Int32 nPos;
+ sal_Int32 nEnumValue = *static_cast<sal_Int32 const *>(rVal.getValue());
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
+ break;
+ }
+ if (nPos < 0)
+ {
+ throw CannotConvertException(
+ "value is not ENUM!",
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
+ }
+
+ aRet <<= OUString::unacquired(
+ &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]);
+
+ break;
+ }
+
+ case TypeClass_BOOLEAN:
+ aRet <<= *o3tl::forceAccess<bool>(rVal) ?
+ OUString("true") :
+ OUString("false");
+ break;
+ case TypeClass_CHAR:
+ aRet <<= OUString(*o3tl::forceAccess<sal_Unicode>(rVal));
+ break;
+
+ case TypeClass_BYTE:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int8>(rVal) );
+ break;
+ case TypeClass_SHORT:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int16>(rVal) );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt16>(rVal) );
+ break;
+ case TypeClass_LONG:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int32>(rVal) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt32>(rVal) );
+ break;
+ case TypeClass_HYPER:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int64>(rVal) );
+ break;
+// case TypeClass_UNSIGNED_HYPER:
+// aRet <<= OUString::valueOf( (sal_Int64)*(sal_uInt64 const *)rVal.getValue() );
+// break;
+ // handle unsigned hyper like double
+
+ default:
+ aRet <<= OUString::number( toDouble( rVal ) );
+ }
+ break;
+
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ if (aRet.hasValue())
+ return aRet;
+
+ throw CannotConvertException(
+ "conversion not possible!",
+ Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
+}
+
+}
+
+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 &)
+{
+ return ::cppu::acquire(new stoc_tcv::TypeConverter_Impl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */