diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /cppu | |
parent | Initial commit. (diff) | |
download | libreoffice-1ad18e38974bb28c3d98d0be8f7d8c18fc56de29.tar.xz libreoffice-1ad18e38974bb28c3d98d0be8f7d8c18fc56de29.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
135 files changed, 37315 insertions, 0 deletions
diff --git a/cppu/CppunitTest_cppu_any-external.mk b/cppu/CppunitTest_cppu_any-external.mk new file mode 100644 index 000000000..e56b957ea --- /dev/null +++ b/cppu/CppunitTest_cppu_any-external.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_any-external)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_any-external, \ + cppu/qa/any-external \ +)) + +$(eval $(call gb_CppunitTest_set_external_code,cppu_any-external)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_any-external, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_udk_api,cppu_any-external)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/CppunitTest_cppu_qa_any.mk b/cppu/CppunitTest_cppu_qa_any.mk new file mode 100644 index 000000000..d565b0fd3 --- /dev/null +++ b/cppu/CppunitTest_cppu_qa_any.mk @@ -0,0 +1,29 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_qa_any)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_qa_any, \ + cppu/qa/test_any \ +)) + +$(eval $(call gb_CppunitTest_use_external,cppu_qa_any,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_qa_any, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_internal_comprehensive_api,cppu_qa_any, \ + cppu_qa_types \ + udkapi \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/CppunitTest_cppu_qa_recursion.mk b/cppu/CppunitTest_cppu_qa_recursion.mk new file mode 100644 index 000000000..9a238fba4 --- /dev/null +++ b/cppu/CppunitTest_cppu_qa_recursion.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_qa_recursion)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_qa_recursion, \ + cppu/qa/test_recursion \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_qa_recursion, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_internal_comprehensive_api,cppu_qa_recursion, \ + cppu_qa_types \ + udkapi \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/CppunitTest_cppu_qa_reference.mk b/cppu/CppunitTest_cppu_qa_reference.mk new file mode 100644 index 000000000..426902b5a --- /dev/null +++ b/cppu/CppunitTest_cppu_qa_reference.mk @@ -0,0 +1,29 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_qa_reference)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_qa_reference, \ + cppu/qa/test_reference \ +)) + +$(eval $(call gb_CppunitTest_use_external,cppu_qa_reference,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_qa_reference, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_internal_comprehensive_api,cppu_qa_reference, \ + cppu_qa_types \ + udkapi \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/CppunitTest_cppu_qa_unotype.mk b/cppu/CppunitTest_cppu_qa_unotype.mk new file mode 100644 index 000000000..a8eb53aa8 --- /dev/null +++ b/cppu/CppunitTest_cppu_qa_unotype.mk @@ -0,0 +1,26 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_qa_unotype)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_qa_unotype, \ + cppu/qa/test_unotype \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_qa_unotype, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_internal_comprehensive_api,cppu_qa_unotype, \ + udkapi \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/CppunitTest_cppu_test_cppumaker.mk b/cppu/CppunitTest_cppu_test_cppumaker.mk new file mode 100644 index 000000000..c812d94de --- /dev/null +++ b/cppu/CppunitTest_cppu_test_cppumaker.mk @@ -0,0 +1,29 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_test_cppumaker)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_test_cppumaker, \ + cppu/qa/cppumaker/test_cppumaker \ +)) + +$(eval $(call gb_CppunitTest_use_external,cppu_test_cppumaker,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_test_cppumaker, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_internal_comprehensive_api,cppu_test_cppumaker, \ + cppu_qa_cppumaker_types \ + udkapi \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/CppunitTest_cppu_typelib.mk b/cppu/CppunitTest_cppu_typelib.mk new file mode 100644 index 000000000..ba9236f61 --- /dev/null +++ b/cppu/CppunitTest_cppu_typelib.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*- +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppu_typelib)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppu_typelib, \ + cppu/qa/typelib \ +)) + +$(eval $(call gb_CppunitTest_use_api,cppu_typelib, \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppu_typelib, \ + cppu \ + sal \ +)) + +$(eval $(call gb_CppunitTest_use_ure,cppu_typelib)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/InternalUnoApi_cppu_qa_cppumaker_types.mk b/cppu/InternalUnoApi_cppu_qa_cppumaker_types.mk new file mode 100644 index 000000000..3464bd4ec --- /dev/null +++ b/cppu/InternalUnoApi_cppu_qa_cppumaker_types.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_InternalUnoApi_InternalUnoApi,cppu_qa_cppumaker_types,cppu/qa/cppumaker/types.idl)) + +$(eval $(call gb_InternalUnoApi_use_api,cppu_qa_cppumaker_types,\ + udkapi \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/cppu/InternalUnoApi_cppu_qa_types.mk b/cppu/InternalUnoApi_cppu_qa_types.mk new file mode 100644 index 000000000..345722689 --- /dev/null +++ b/cppu/InternalUnoApi_cppu_qa_types.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_InternalUnoApi_InternalUnoApi,cppu_qa_types,cppu/qa/types.idl)) + +$(eval $(call gb_InternalUnoApi_use_api,cppu_qa_types,\ + udkapi \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/cppu/IwyuFilter_cppu.yaml b/cppu/IwyuFilter_cppu.yaml new file mode 100644 index 000000000..a6ffcd3df --- /dev/null +++ b/cppu/IwyuFilter_cppu.yaml @@ -0,0 +1,26 @@ +--- +assumeFilename: cppu/source/uno/data.cxx +blacklist: + cppu/qa/test_any.cxx: + # No hpp -> hdl replacement needed + - Enum1.hpp + - Enum2.hpp + - Interface1.hpp + - Interface2.hpp + - Interface2a.hpp + - Interface2b.hpp + - Interface3.hpp + cppu/source/cppu/cppu_opt.cxx: + # Unit test fails without uno/Any.hxx + - com/sun/star/uno/Any.hxx + cppu/source/helper/purpenv/helper_purpenv_Environment.cxx: + # Needed by the implementation of Environment_initWithEnterable + - cppu/helper/purpenv/Environment.hxx + cppu/source/threadpool/current.cxx: + # FIXME removing this makes linking fail in binaryurp + - uno/current_context.h + cppu/source/threadpool/threadident.cxx: + # Don't replace hxx -> h in URE API + - rtl/byteseq.hxx + # FIXME removing this makes linking fail in binaryurp + - uno/threadpool.h diff --git a/cppu/Library_affine_uno_uno.mk b/cppu/Library_affine_uno_uno.mk new file mode 100644 index 000000000..10b5389b5 --- /dev/null +++ b/cppu/Library_affine_uno_uno.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Library_Library,affine_uno_uno)) + +$(eval $(call gb_Library_use_udk_api,affine_uno_uno)) + +$(eval $(call gb_Library_use_libraries,affine_uno_uno,\ + purpenvhelper \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,affine_uno_uno,\ + cppu/source/AffineBridge/AffineBridge \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/Library_cppu.mk b/cppu/Library_cppu.mk new file mode 100644 index 000000000..8031487af --- /dev/null +++ b/cppu/Library_cppu.mk @@ -0,0 +1,51 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Library_Library,cppu)) + +$(eval $(call gb_Library_set_soversion_script,cppu,$(SRCDIR)/cppu/util/cppu.map)) + +$(eval $(call gb_Library_use_udk_api,cppu)) + +$(eval $(call gb_Library_add_defs,cppu,\ + -DCPPU_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_external,cppu,boost_headers)) + +$(eval $(call gb_Library_use_libraries,cppu,\ + sal \ + salhelper \ +)) + +$(eval $(call gb_Library_add_exception_objects,cppu,\ + cppu/source/cppu/compat \ + cppu/source/cppu/cppu_opt \ + cppu/source/threadpool/current \ + cppu/source/threadpool/jobqueue \ + cppu/source/threadpool/thread \ + cppu/source/threadpool/threadident \ + cppu/source/threadpool/threadpool \ + cppu/source/typelib/static_types \ + cppu/source/typelib/typelib \ + cppu/source/uno/any \ + cppu/source/uno/cascade_mapping \ + cppu/source/uno/check \ + cppu/source/uno/data \ + cppu/source/uno/EnvDcp \ + cppu/source/uno/EnvStack \ + cppu/source/uno/IdentityMapping \ + cppu/source/uno/lbenv \ + cppu/source/uno/lbmap \ + cppu/source/uno/loadmodule \ + cppu/source/uno/sequence \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/Library_log_uno_uno.mk b/cppu/Library_log_uno_uno.mk new file mode 100644 index 000000000..92d287ea7 --- /dev/null +++ b/cppu/Library_log_uno_uno.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Library_Library,log_uno_uno)) + +$(eval $(call gb_Library_use_external,log_uno_uno,boost_headers)) + +$(eval $(call gb_Library_use_udk_api,log_uno_uno)) + +$(eval $(call gb_Library_use_libraries,log_uno_uno,\ + cppu \ + purpenvhelper \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,log_uno_uno,\ + cppu/source/LogBridge/LogBridge \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/Library_purpenvhelper.mk b/cppu/Library_purpenvhelper.mk new file mode 100644 index 000000000..42c03749a --- /dev/null +++ b/cppu/Library_purpenvhelper.mk @@ -0,0 +1,32 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Library_Library,purpenvhelper)) + +$(eval $(call gb_Library_set_soversion_script,purpenvhelper,$(SRCDIR)/cppu/util/uno_purpenvhelpergcc3.map)) + +$(eval $(call gb_Library_add_defs,purpenvhelper,\ + -DPURPENV_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_udk_api,purpenvhelper)) + +$(eval $(call gb_Library_use_libraries,purpenvhelper,\ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,purpenvhelper,\ + cppu/source/helper/purpenv/helper_purpenv_Environment \ + cppu/source/helper/purpenv/helper_purpenv_Mapping \ + cppu/source/helper/purpenv/helper_purpenv_Proxy \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/Library_unsafe_uno_uno.mk b/cppu/Library_unsafe_uno_uno.mk new file mode 100644 index 000000000..9733f7216 --- /dev/null +++ b/cppu/Library_unsafe_uno_uno.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Library_Library,unsafe_uno_uno)) + +$(eval $(call gb_Library_use_udk_api,unsafe_uno_uno)) + +$(eval $(call gb_Library_use_libraries,unsafe_uno_uno,\ + purpenvhelper \ + sal \ +)) + +$(eval $(call gb_Library_add_exception_objects,unsafe_uno_uno,\ + cppu/source/UnsafeBridge/UnsafeBridge \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/Makefile b/cppu/Makefile new file mode 100644 index 000000000..ccb1c85a0 --- /dev/null +++ b/cppu/Makefile @@ -0,0 +1,7 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/cppu/Module_cppu.mk b/cppu/Module_cppu.mk new file mode 100644 index 000000000..17f6936f7 --- /dev/null +++ b/cppu/Module_cppu.mk @@ -0,0 +1,33 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Module_Module,cppu)) + +$(eval $(call gb_Module_add_targets,cppu,\ + InternalUnoApi_cppu_qa_cppumaker_types \ + InternalUnoApi_cppu_qa_types \ + Library_affine_uno_uno \ + Library_cppu \ + Library_log_uno_uno \ + Library_purpenvhelper \ + Library_unsafe_uno_uno \ +)) + +$(eval $(call gb_Module_add_check_targets,cppu,\ + CppunitTest_cppu_any-external \ + CppunitTest_cppu_qa_any \ + CppunitTest_cppu_qa_recursion \ + CppunitTest_cppu_qa_reference \ + CppunitTest_cppu_qa_unotype \ + CppunitTest_cppu_test_cppumaker \ + CppunitTest_cppu_typelib \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppu/README b/cppu/README new file mode 100644 index 000000000..066170cd7 --- /dev/null +++ b/cppu/README @@ -0,0 +1,4 @@ +Type definitions/implementations for the core of UNO. The exported API is in C. + +See also: +[http://wiki.openoffice.org/wiki/Uno/Binary/Modules/CPPU] diff --git a/cppu/qa/any-external.cxx b/cppu/qa/any-external.cxx new file mode 100644 index 000000000..bac613427 --- /dev/null +++ b/cppu/qa/any-external.cxx @@ -0,0 +1,63 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <com/sun/star/uno/Any.hxx> +#include <sal/types.h> + +namespace { + +class Test: public CppUnit::TestFixture { +private: + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testGet); + CPPUNIT_TEST(testHas); + CPPUNIT_TEST(testExtract); + CPPUNIT_TEST(testInsert); + CPPUNIT_TEST_SUITE_END(); + + void testGet() { + css::uno::Any a(false); + CPPUNIT_ASSERT_EQUAL(a, a.get<css::uno::Any>()); + CPPUNIT_ASSERT_EQUAL(false, a.get<bool>()); + } + + void testHas() { + css::uno::Any a(false); + CPPUNIT_ASSERT_EQUAL(true, a.has<css::uno::Any>()); + CPPUNIT_ASSERT_EQUAL(true, a.has<bool>()); + } + + void testExtract() { + css::uno::Any a1(false); + css::uno::Any a2; + CPPUNIT_ASSERT(a1 >>= a2); + CPPUNIT_ASSERT_EQUAL(a1, a2); + } + + void testInsert() { + css::uno::Any a; + a <<= css::uno::Any(false); + CPPUNIT_ASSERT_EQUAL(css::uno::Any(false), a); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cppu/qa/cppumaker/test_cppumaker.cxx b/cppu/qa/cppumaker/test_cppumaker.cxx new file mode 100644 index 000000000..78097e26e --- /dev/null +++ b/cppu/qa/cppumaker/test_cppumaker.cxx @@ -0,0 +1,559 @@ +/* -*- 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/types.h> + +#include <FILE.hpp> +#include <lconv.hpp> +#include <tm.hpp> +#include <std.hpp> +#include <test/codemaker/cppumaker/XTest.hpp> +#include <test/codemaker/cppumaker/S1.hpp> +#include <test/codemaker/cppumaker/services/asm.hpp> +#include <test/codemaker/cppumaker/services/auto.hpp> +#include <test/codemaker/cppumaker/services/bool.hpp> +#include <test/codemaker/cppumaker/services/break.hpp> +//TODO: #include "test/codemaker/cppumaker/services/case.hpp" +#include <test/codemaker/cppumaker/services/catch.hpp> +//TODO: #include "test/codemaker/cppumaker/services/char.hpp" +#include <test/codemaker/cppumaker/services/class.hpp> +//TODO: #include "test/codemaker/cppumaker/services/const.hpp" +#include <test/codemaker/cppumaker/services/continue.hpp> +//TODO: #include "test/codemaker/cppumaker/services/default.hpp" +#include <test/codemaker/cppumaker/services/delete.hpp> +#include <test/codemaker/cppumaker/services/do.hpp> +//TODO: #include "test/codemaker/cppumaker/services/double.hpp" +#include <test/codemaker/cppumaker/services/else.hpp> +//TODO: #include "test/codemaker/cppumaker/services/enum.hpp" +#include <test/codemaker/cppumaker/services/explicit.hpp> +#include <test/codemaker/cppumaker/services/export.hpp> +#include <test/codemaker/cppumaker/services/extern.hpp> +#include <test/codemaker/cppumaker/services/false.hpp> +//TODO: #include "test/codemaker/cppumaker/services/float.hpp" +#include <test/codemaker/cppumaker/services/for.hpp> +#include <test/codemaker/cppumaker/services/friend.hpp> +#include <test/codemaker/cppumaker/services/goto.hpp> +#include <test/codemaker/cppumaker/services/if.hpp> +#include <test/codemaker/cppumaker/services/inline.hpp> +#include <test/codemaker/cppumaker/services/int.hpp> +//TODO: #include "test/codemaker/cppumaker/services/long.hpp" +#include <test/codemaker/cppumaker/services/mutable.hpp> +#include <test/codemaker/cppumaker/services/namespace.hpp> +#include <test/codemaker/cppumaker/services/new.hpp> +#include <test/codemaker/cppumaker/services/operator.hpp> +#include <test/codemaker/cppumaker/services/private.hpp> +#include <test/codemaker/cppumaker/services/protected.hpp> +#include <test/codemaker/cppumaker/services/public.hpp> +#include <test/codemaker/cppumaker/services/register.hpp> +#include <test/codemaker/cppumaker/services/return.hpp> +//TODO: #include "test/codemaker/cppumaker/services/short.hpp" +#include <test/codemaker/cppumaker/services/signed.hpp> +#include <test/codemaker/cppumaker/services/sizeof.hpp> +#include <test/codemaker/cppumaker/services/static.hpp> +//TODO: #include "test/codemaker/cppumaker/services/struct.hpp" +//TODO: #include "test/codemaker/cppumaker/services/switch.hpp" +#include <test/codemaker/cppumaker/services/template.hpp> +#include <test/codemaker/cppumaker/services/this.hpp> +#include <test/codemaker/cppumaker/services/throw.hpp> +#include <test/codemaker/cppumaker/services/true.hpp> +#include <test/codemaker/cppumaker/services/try.hpp> +//TODO: #include "test/codemaker/cppumaker/services/typedef.hpp" +#include <test/codemaker/cppumaker/services/typeid.hpp> +#include <test/codemaker/cppumaker/services/typename.hpp> +//TODO: #include "test/codemaker/cppumaker/services/union.hpp" +//TODO: #include "test/codemaker/cppumaker/services/unsigned.hpp" +#include <test/codemaker/cppumaker/services/using.hpp> +#include <test/codemaker/cppumaker/services/virtual.hpp> +//TODO: #include "test/codemaker/cppumaker/services/void.hpp" +#include <test/codemaker/cppumaker/services/volatile.hpp> +#include <test/codemaker/cppumaker/services/while.hpp> +#include <test/codemaker/cppumaker/services/and.hpp> +#include <test/codemaker/cppumaker/services/bitand.hpp> +#include <test/codemaker/cppumaker/services/bitor.hpp> +#include <test/codemaker/cppumaker/services/compl.hpp> +#include <test/codemaker/cppumaker/services/not.hpp> +#include <test/codemaker/cppumaker/services/or.hpp> +#include <test/codemaker/cppumaker/services/xor.hpp> +#include <test/codemaker/cppumaker/services/BUFSIZ.hpp> +#include <test/codemaker/cppumaker/services/CLOCKS_PER_SEC.hpp> +#include <test/codemaker/cppumaker/services/EDOM.hpp> +#include <test/codemaker/cppumaker/services/EOF.hpp> +#include <test/codemaker/cppumaker/services/ERANGE.hpp> +#include <test/codemaker/cppumaker/services/EXIT_FAILURE.hpp> +#include <test/codemaker/cppumaker/services/EXIT_SUCCESS.hpp> +#include <test/codemaker/cppumaker/services/FILENAME_MAX.hpp> +#include <test/codemaker/cppumaker/services/FOPEN_MAX.hpp> +#include <test/codemaker/cppumaker/services/HUGE_VAL.hpp> +#include <test/codemaker/cppumaker/services/LC_ALL.hpp> +#include <test/codemaker/cppumaker/services/LC_COLLATE.hpp> +#include <test/codemaker/cppumaker/services/LC_CTYPE.hpp> +#include <test/codemaker/cppumaker/services/LC_MONETARY.hpp> +#include <test/codemaker/cppumaker/services/LC_NUMERIC.hpp> +#include <test/codemaker/cppumaker/services/LC_TIME.hpp> +#include <test/codemaker/cppumaker/services/L_tmpnam.hpp> +#include <test/codemaker/cppumaker/services/MB_CUR_MAX.hpp> +#include <test/codemaker/cppumaker/services/NULL.hpp> +#include <test/codemaker/cppumaker/services/RAND_MAX.hpp> +#include <test/codemaker/cppumaker/services/SEEK_CUR.hpp> +#include <test/codemaker/cppumaker/services/SEEK_END.hpp> +#include <test/codemaker/cppumaker/services/SEEK_SET.hpp> +#include <test/codemaker/cppumaker/services/SIGABRT.hpp> +#include <test/codemaker/cppumaker/services/SIGFPE.hpp> +#include <test/codemaker/cppumaker/services/SIGILL.hpp> +#include <test/codemaker/cppumaker/services/SIGINT.hpp> +#include <test/codemaker/cppumaker/services/SIGSEGV.hpp> +#include <test/codemaker/cppumaker/services/SIGTERM.hpp> +#include <test/codemaker/cppumaker/services/SIG_DFL.hpp> +#include <test/codemaker/cppumaker/services/SIG_ERR.hpp> +#include <test/codemaker/cppumaker/services/SIG_IGN.hpp> +#include <test/codemaker/cppumaker/services/TMP_MAX.hpp> +#include <test/codemaker/cppumaker/services/WCHAR_MAX.hpp> +#include <test/codemaker/cppumaker/services/WCHAR_MIN.hpp> +#include <test/codemaker/cppumaker/services/WEOF.hpp> +#include <test/codemaker/cppumaker/services/assert.hpp> +#include <test/codemaker/cppumaker/services/errno.hpp> +#include <test/codemaker/cppumaker/services/offsetof.hpp> +#include <test/codemaker/cppumaker/services/setjmp.hpp> +#include <test/codemaker/cppumaker/services/stderr.hpp> +#include <test/codemaker/cppumaker/services/stdin.hpp> +#include <test/codemaker/cppumaker/services/stdout.hpp> +#include <test/codemaker/cppumaker/services/CHAR_BIT.hpp> +#include <test/codemaker/cppumaker/services/CHAR_MAX.hpp> +#include <test/codemaker/cppumaker/services/CHAR_MIN.hpp> +#include <test/codemaker/cppumaker/services/DBL_DIG.hpp> +#include <test/codemaker/cppumaker/services/DBL_EPSILON.hpp> +#include <test/codemaker/cppumaker/services/DBL_MANT_DIG.hpp> +#include <test/codemaker/cppumaker/services/DBL_MAX.hpp> +#include <test/codemaker/cppumaker/services/DBL_MAX_10_EXP.hpp> +#include <test/codemaker/cppumaker/services/DBL_MAX_EXP.hpp> +#include <test/codemaker/cppumaker/services/DBL_MIN.hpp> +#include <test/codemaker/cppumaker/services/DBL_MIN_10_EXP.hpp> +#include <test/codemaker/cppumaker/services/DBL_MIN_EXP.hpp> +#include <test/codemaker/cppumaker/services/FLT_DIG.hpp> +#include <test/codemaker/cppumaker/services/FLT_EPSILON.hpp> +#include <test/codemaker/cppumaker/services/FLT_MANT_DIG.hpp> +#include <test/codemaker/cppumaker/services/FLT_MAX.hpp> +#include <test/codemaker/cppumaker/services/FLT_MAX_10_EXP.hpp> +#include <test/codemaker/cppumaker/services/FLT_MAX_EXP.hpp> +#include <test/codemaker/cppumaker/services/FLT_MIN.hpp> +#include <test/codemaker/cppumaker/services/FLT_MIN_10_EXP.hpp> +#include <test/codemaker/cppumaker/services/FLT_MIN_EXP.hpp> +#include <test/codemaker/cppumaker/services/FLT_RADIX.hpp> +#include <test/codemaker/cppumaker/services/FLT_ROUNDS.hpp> +#include <test/codemaker/cppumaker/services/INT_MAX.hpp> +#include <test/codemaker/cppumaker/services/INT_MIN.hpp> +#include <test/codemaker/cppumaker/services/LDBL_DIG.hpp> +#include <test/codemaker/cppumaker/services/LDBL_EPSILON.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MANT_DIG.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MAX.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MAX_10_EXP.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MAX_EXP.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MIN.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MIN_10_EXP.hpp> +#include <test/codemaker/cppumaker/services/LDBL_MIN_EXP.hpp> +#include <test/codemaker/cppumaker/services/LONG_MAX.hpp> +#include <test/codemaker/cppumaker/services/LONG_MIN.hpp> +#include <test/codemaker/cppumaker/services/MB_LEN_MAX.hpp> +#include <test/codemaker/cppumaker/services/SCHAR_MAX.hpp> +#include <test/codemaker/cppumaker/services/SCHAR_MIN.hpp> +#include <test/codemaker/cppumaker/services/SHRT_MAX.hpp> +#include <test/codemaker/cppumaker/services/SHRT_MIN.hpp> +#include <test/codemaker/cppumaker/services/UCHAR_MAX.hpp> +#include <test/codemaker/cppumaker/services/UINT_MAX.hpp> +#include <test/codemaker/cppumaker/services/ULONG_MAX.hpp> +#include <test/codemaker/cppumaker/services/USHRT_MAX.hpp> +#include <test/codemaker/cppumaker/services/FILE.hpp> +#include <test/codemaker/cppumaker/services/lconv.hpp> +#include <test/codemaker/cppumaker/services/tm.hpp> +#include <test/codemaker/cppumaker/services/std.hpp> +#include <test/codemaker/cppumaker/services/NDEBUG.hpp> +#include <test/codemaker/cppumaker/services/create.hpp> +#include <test/codemaker/cppumaker/singletons/asm.hpp> +#include <test/codemaker/cppumaker/singletons/auto.hpp> +#include <test/codemaker/cppumaker/singletons/bool.hpp> +#include <test/codemaker/cppumaker/singletons/break.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/case.hpp" +#include <test/codemaker/cppumaker/singletons/catch.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/char.hpp" +#include <test/codemaker/cppumaker/singletons/class.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/const.hpp" +#include <test/codemaker/cppumaker/singletons/continue.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/default.hpp" +#include <test/codemaker/cppumaker/singletons/delete.hpp> +#include <test/codemaker/cppumaker/singletons/do.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/double.hpp" +#include <test/codemaker/cppumaker/singletons/else.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/enum.hpp" +#include <test/codemaker/cppumaker/singletons/explicit.hpp> +#include <test/codemaker/cppumaker/singletons/export.hpp> +#include <test/codemaker/cppumaker/singletons/extern.hpp> +#include <test/codemaker/cppumaker/singletons/false.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/float.hpp" +#include <test/codemaker/cppumaker/singletons/for.hpp> +#include <test/codemaker/cppumaker/singletons/friend.hpp> +#include <test/codemaker/cppumaker/singletons/goto.hpp> +#include <test/codemaker/cppumaker/singletons/if.hpp> +#include <test/codemaker/cppumaker/singletons/inline.hpp> +#include <test/codemaker/cppumaker/singletons/int.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/long.hpp" +#include <test/codemaker/cppumaker/singletons/mutable.hpp> +#include <test/codemaker/cppumaker/singletons/namespace.hpp> +#include <test/codemaker/cppumaker/singletons/new.hpp> +#include <test/codemaker/cppumaker/singletons/operator.hpp> +#include <test/codemaker/cppumaker/singletons/private.hpp> +#include <test/codemaker/cppumaker/singletons/protected.hpp> +#include <test/codemaker/cppumaker/singletons/public.hpp> +#include <test/codemaker/cppumaker/singletons/register.hpp> +#include <test/codemaker/cppumaker/singletons/return.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/short.hpp" +#include <test/codemaker/cppumaker/singletons/signed.hpp> +#include <test/codemaker/cppumaker/singletons/sizeof.hpp> +#include <test/codemaker/cppumaker/singletons/static.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/struct.hpp" +//TODO: #include "test/codemaker/cppumaker/singletons/switch.hpp" +#include <test/codemaker/cppumaker/singletons/template.hpp> +#include <test/codemaker/cppumaker/singletons/this.hpp> +#include <test/codemaker/cppumaker/singletons/throw.hpp> +#include <test/codemaker/cppumaker/singletons/true.hpp> +#include <test/codemaker/cppumaker/singletons/try.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/typedef.hpp" +#include <test/codemaker/cppumaker/singletons/typeid.hpp> +#include <test/codemaker/cppumaker/singletons/typename.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/union.hpp" +//TODO: #include "test/codemaker/cppumaker/singletons/unsigned.hpp" +#include <test/codemaker/cppumaker/singletons/using.hpp> +#include <test/codemaker/cppumaker/singletons/virtual.hpp> +//TODO: #include "test/codemaker/cppumaker/singletons/void.hpp" +#include <test/codemaker/cppumaker/singletons/volatile.hpp> +#include <test/codemaker/cppumaker/singletons/while.hpp> +#include <test/codemaker/cppumaker/singletons/and.hpp> +#include <test/codemaker/cppumaker/singletons/bitand.hpp> +#include <test/codemaker/cppumaker/singletons/bitor.hpp> +#include <test/codemaker/cppumaker/singletons/compl.hpp> +#include <test/codemaker/cppumaker/singletons/not.hpp> +#include <test/codemaker/cppumaker/singletons/or.hpp> +#include <test/codemaker/cppumaker/singletons/xor.hpp> +#include <test/codemaker/cppumaker/singletons/BUFSIZ.hpp> +#include <test/codemaker/cppumaker/singletons/CLOCKS_PER_SEC.hpp> +#include <test/codemaker/cppumaker/singletons/EDOM.hpp> +#include <test/codemaker/cppumaker/singletons/EOF.hpp> +#include <test/codemaker/cppumaker/singletons/ERANGE.hpp> +#include <test/codemaker/cppumaker/singletons/EXIT_FAILURE.hpp> +#include <test/codemaker/cppumaker/singletons/EXIT_SUCCESS.hpp> +#include <test/codemaker/cppumaker/singletons/FILENAME_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/FOPEN_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/HUGE_VAL.hpp> +#include <test/codemaker/cppumaker/singletons/LC_ALL.hpp> +#include <test/codemaker/cppumaker/singletons/LC_COLLATE.hpp> +#include <test/codemaker/cppumaker/singletons/LC_CTYPE.hpp> +#include <test/codemaker/cppumaker/singletons/LC_MONETARY.hpp> +#include <test/codemaker/cppumaker/singletons/LC_NUMERIC.hpp> +#include <test/codemaker/cppumaker/singletons/LC_TIME.hpp> +#include <test/codemaker/cppumaker/singletons/L_tmpnam.hpp> +#include <test/codemaker/cppumaker/singletons/MB_CUR_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/NULL.hpp> +#include <test/codemaker/cppumaker/singletons/RAND_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/SEEK_CUR.hpp> +#include <test/codemaker/cppumaker/singletons/SEEK_END.hpp> +#include <test/codemaker/cppumaker/singletons/SEEK_SET.hpp> +#include <test/codemaker/cppumaker/singletons/SIGABRT.hpp> +#include <test/codemaker/cppumaker/singletons/SIGFPE.hpp> +#include <test/codemaker/cppumaker/singletons/SIGILL.hpp> +#include <test/codemaker/cppumaker/singletons/SIGINT.hpp> +#include <test/codemaker/cppumaker/singletons/SIGSEGV.hpp> +#include <test/codemaker/cppumaker/singletons/SIGTERM.hpp> +#include <test/codemaker/cppumaker/singletons/SIG_DFL.hpp> +#include <test/codemaker/cppumaker/singletons/SIG_ERR.hpp> +#include <test/codemaker/cppumaker/singletons/SIG_IGN.hpp> +#include <test/codemaker/cppumaker/singletons/TMP_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/WCHAR_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/WCHAR_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/WEOF.hpp> +#include <test/codemaker/cppumaker/singletons/assert.hpp> +#include <test/codemaker/cppumaker/singletons/errno.hpp> +#include <test/codemaker/cppumaker/singletons/offsetof.hpp> +#include <test/codemaker/cppumaker/singletons/setjmp.hpp> +#include <test/codemaker/cppumaker/singletons/stderr.hpp> +#include <test/codemaker/cppumaker/singletons/stdin.hpp> +#include <test/codemaker/cppumaker/singletons/stdout.hpp> +#include <test/codemaker/cppumaker/singletons/CHAR_BIT.hpp> +#include <test/codemaker/cppumaker/singletons/CHAR_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/CHAR_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_DIG.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_EPSILON.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MANT_DIG.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MAX_10_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MAX_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MIN_10_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/DBL_MIN_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_DIG.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_EPSILON.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MANT_DIG.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MAX_10_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MAX_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MIN_10_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_MIN_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_RADIX.hpp> +#include <test/codemaker/cppumaker/singletons/FLT_ROUNDS.hpp> +#include <test/codemaker/cppumaker/singletons/INT_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/INT_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_DIG.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_EPSILON.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MANT_DIG.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MAX_10_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MAX_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MIN_10_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/LDBL_MIN_EXP.hpp> +#include <test/codemaker/cppumaker/singletons/LONG_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/LONG_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/MB_LEN_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/SCHAR_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/SCHAR_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/SHRT_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/SHRT_MIN.hpp> +#include <test/codemaker/cppumaker/singletons/UCHAR_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/UINT_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/ULONG_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/USHRT_MAX.hpp> +#include <test/codemaker/cppumaker/singletons/FILE.hpp> +#include <test/codemaker/cppumaker/singletons/lconv.hpp> +#include <test/codemaker/cppumaker/singletons/tm.hpp> +#include <test/codemaker/cppumaker/singletons/std.hpp> +#include <test/codemaker/cppumaker/singletons/NDEBUG.hpp> +#include <test/codemaker/cppumaker/singletons/get.hpp> +#include <test/codemaker/cppumaker/HelperEnum.hpp> +#include <test/codemaker/cppumaker/HelperStruct.hpp> +#include <test/codemaker/cppumaker/BigStruct.hpp> +#include <test/codemaker/cppumaker/Struct.hpp> +#include <test/codemaker/cppumaker/StructUsage.hpp> +#include <test/codemaker/cppumaker/AlignmentDerivedStruct.hpp> +#include <test/codemaker/cppumaker/TestException1.hpp> +#include <test/codemaker/cppumaker/TestException2.hpp> +#include <test/codemaker/cppumaker/Constants.hpp> + +#include <memory> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/TypeClass.hpp> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <o3tl/cppunittraitshelper.hxx> +#include <rtl/ustring.hxx> + +#include <cstddef> + +namespace test::codemaker::cppumaker { + +static bool operator ==( + test::codemaker::cppumaker::TestException1 const & e1, + test::codemaker::cppumaker::TestException1 const & e2) +{ + return e1.Message == e2.Message && e1.Context == e2.Context + && e1.m1 == e2.m1 && e1.m2 == e2.m2 && e1.m3 == e2.m3 + && e1.m4.member1 == e2.m4.member1 && e1.m4.member2 == e2.m4.member2; +} + +} + +namespace { + +class Test: public CppUnit::TestFixture { +public: + void testBigStruct(); + + void testPolyStruct(); + + void testExceptions(); + + void testConstants(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testBigStruct); + CPPUNIT_TEST(testPolyStruct); + CPPUNIT_TEST(testExceptions); + CPPUNIT_TEST(testConstants); + CPPUNIT_TEST_SUITE_END(); +}; + +struct Guard { + explicit Guard(void * buffer): + p(new(buffer) test::codemaker::cppumaker::BigStruct) {} + + ~Guard() { p->test::codemaker::cppumaker::BigStruct::~BigStruct(); } + + test::codemaker::cppumaker::BigStruct * const p; +}; + +void Test::testBigStruct() { + // Default-initialize a BigStruct instance on top of a memory buffer filled + // with random data, and make sure that all members are default-initialized: + std::unique_ptr< char []> buffer( + new char[sizeof (test::codemaker::cppumaker::BigStruct)]); + for (std::size_t i = 0; i < sizeof (test::codemaker::cppumaker::BigStruct); + ++i) + { + buffer[i] = '\x56'; + } + Guard guard(buffer.get()); + CPPUNIT_ASSERT_EQUAL(sal_False, guard.p->m1); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int8 >(0), guard.p->m2); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int16 >(0), guard.p->m3); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt16 >(0), guard.p->m4); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), guard.p->m5); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt32 >(0), guard.p->m6); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int64 >(0), guard.p->m7); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_uInt64 >(0), guard.p->m8); + CPPUNIT_ASSERT_EQUAL(0.0f, guard.p->m9); + CPPUNIT_ASSERT_EQUAL(0.0, guard.p->m10); + CPPUNIT_ASSERT_EQUAL( u'\0', guard.p->m11); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), guard.p->m12.getLength()); + CPPUNIT_ASSERT_EQUAL(sal_Int32(css::uno::TypeClass_VOID), static_cast<sal_Int32>(guard.p->m13.getTypeClass())); + CPPUNIT_ASSERT_EQUAL(false, guard.p->m14.hasValue()); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), guard.p->m15.getLength()); + CPPUNIT_ASSERT_EQUAL(int(test::codemaker::cppumaker::HelperEnum_ZERO), static_cast<int>(guard.p->m16)); + CPPUNIT_ASSERT_EQUAL(sal_False, guard.p->m17.m1); + CPPUNIT_ASSERT_EQUAL(false, guard.p->m17.m2.is()); + CPPUNIT_ASSERT_EQUAL(false, guard.p->m18.is()); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int8 >(0), guard.p->m19); + CPPUNIT_ASSERT_EQUAL(sal_Int32(test::codemaker::cppumaker::HelperEnum_ZERO), static_cast<sal_Int32>(guard.p->m20)); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), guard.p->m21.getLength()); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), guard.p->m22.getLength()); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), guard.p->m23.getLength()); + +//This is a very platform specific test. +#if defined __GNUC__ // see CPPU_GCC3_ALIGN +#if defined(LINUX) && (defined (X86_64) || defined(X86) || defined(PPC)) + static_assert( + sizeof (test::codemaker::cppumaker::AlignmentDerivedStruct) == +#if defined X86_64 || defined PPC + 24 +#else + 16 +#endif + ); +#endif +#endif + + css::uno::Type t( + cppu::UnoType< test::codemaker::cppumaker::BigStruct >::get()); + typelib_TypeDescription * td = nullptr; + t.getDescription(&td); + typelib_typedescription_complete(&td); + fprintf(stdout, "#### 1\n"); + CPPUNIT_ASSERT(td != nullptr); + CPPUNIT_ASSERT_EQUAL(+typelib_TypeClass_STRUCT, +td->eTypeClass); + typelib_StructTypeDescription * std = + reinterpret_cast< typelib_StructTypeDescription * >(td); + CPPUNIT_ASSERT_EQUAL(+typelib_TypeClass_UNSIGNED_SHORT, +std->aBase.ppTypeRefs[3]->eTypeClass); // unsigned short m4; + CPPUNIT_ASSERT_EQUAL(+typelib_TypeClass_CHAR, +std->aBase.ppTypeRefs[10]->eTypeClass); // char m11; +} + +void Test::testPolyStruct() { + CPPUNIT_ASSERT_EQUAL( + OUString( + "test.codemaker.cppumaker.Struct<char,short>"), + (css::uno::makeAny( + test::codemaker::cppumaker::Struct< sal_Unicode, sal_Int16 >()). + getValueType().getTypeName())); + + css::uno::Sequence< css::uno::Sequence< css::uno::Any > > + aEmptySequence; + + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_uInt32 >(5), + (test::codemaker::cppumaker::make_Struct< sal_uInt32, sal_Bool >(5, + aEmptySequence).member1)); +} + +void Test::testExceptions() { + css::uno::Sequence< css::uno::Sequence< css::uno::Any > > + aEmptySequence; + + test::codemaker::cppumaker::TestException1 e11( + "abc", nullptr, 1, + css::uno::makeAny(123.0), + test::codemaker::cppumaker::HelperEnum_ONE, + test::codemaker::cppumaker::Struct<sal_Int32, sal_Int32>(5, aEmptySequence), 2); + test::codemaker::cppumaker::TestException1 e12(e11); + CPPUNIT_ASSERT_EQUAL(e11, e12); + test::codemaker::cppumaker::TestException1 e13; + e13 = e11; + CPPUNIT_ASSERT_EQUAL(e11, e13); + test::codemaker::cppumaker::TestException2 e21( + "abc", nullptr, 1, + css::uno::makeAny(123.0), + test::codemaker::cppumaker::HelperEnum_ONE, + test::codemaker::cppumaker::Struct<sal_Int32, sal_Int32>(5, aEmptySequence), 2); + test::codemaker::cppumaker::TestException2 e22(e21); + CPPUNIT_ASSERT_EQUAL(e21, e22); + test::codemaker::cppumaker::TestException2 e23; + e23 = e21; + CPPUNIT_ASSERT_EQUAL(e21, e23); +} + +void Test::testConstants() { + CPPUNIT_ASSERT_EQUAL( + SAL_MIN_INT8, test::codemaker::cppumaker::Constants::byteMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_INT8, test::codemaker::cppumaker::Constants::byteMax); + CPPUNIT_ASSERT_EQUAL( + SAL_MIN_INT16, test::codemaker::cppumaker::Constants::shortMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_INT16, test::codemaker::cppumaker::Constants::shortMax); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_uInt16 >(0), + test::codemaker::cppumaker::Constants::unsignedShortMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_UINT16, + test::codemaker::cppumaker::Constants::unsignedShortMax); + CPPUNIT_ASSERT_EQUAL( + SAL_MIN_INT32, test::codemaker::cppumaker::Constants::longMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_INT32, test::codemaker::cppumaker::Constants::longMax); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_uInt32 >(0), + test::codemaker::cppumaker::Constants::unsignedLongMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_UINT32, test::codemaker::cppumaker::Constants::unsignedLongMax); + CPPUNIT_ASSERT_EQUAL( + SAL_MIN_INT64, test::codemaker::cppumaker::Constants::hyperMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_INT64, test::codemaker::cppumaker::Constants::hyperMax); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_uInt64 >(0), + test::codemaker::cppumaker::Constants::unsignedHyperMin); + CPPUNIT_ASSERT_EQUAL( + SAL_MAX_UINT64, + test::codemaker::cppumaker::Constants::unsignedHyperMax); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/qa/cppumaker/types.idl b/cppu/qa/cppumaker/types.idl new file mode 100644 index 000000000..98ed1f867 --- /dev/null +++ b/cppu/qa/cppumaker/types.idl @@ -0,0 +1,710 @@ +/* -*- 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 . + */ + +/*TODO: Do not depend on types for which C++ header files are only generated + later in the build process in offuh: */ +#include <com/sun/star/lang/ClassNotFoundException.idl> +#include <com/sun/star/lang/IllegalAccessException.idl> +#include <com/sun/star/lang/Locale.idl> +#include <com/sun/star/uno/DeploymentException.idl> +#include <com/sun/star/uno/Exception.idl> +#include <com/sun/star/uno/RuntimeException.idl> +#include <com/sun/star/uno/XInterface.idl> +#include <com/sun/star/uno/XNamingService.idl> + +singleton FILE: com::sun::star::uno::XInterface; +singleton lconv: com::sun::star::uno::XInterface; +singleton tm: com::sun::star::uno::XInterface; + +singleton std: com::sun::star::uno::XInterface; + +module test { module codemaker { module cppumaker { + +interface XTest { + boolean test(); + + [attribute, bound] long A1; + [attribute, bound, readonly] long A2; + [attribute] long A3 { + get raises + (com::sun::star::uno::Exception, + com::sun::star::lang::ClassNotFoundException); + set raises (com::sun::star::uno::RuntimeException); + }; + [attribute, readonly] long A4 { + get raises (com::sun::star::uno::DeploymentException); + }; +}; + +typedef boolean Boolean; +typedef byte Byte; +typedef short Short; +typedef unsigned short UnsignedShort; +typedef long Long; +typedef unsigned long UnsignedLong; +typedef hyper Hyper; +typedef unsigned hyper UnsignedHyper; +typedef float Float; +typedef double Double; +typedef char Char; +typedef string String; +typedef type Type; +typedef any Any; +typedef com::sun::star::lang::Locale Locale; +typedef com::sun::star::uno::XInterface XInterface; +typedef com::sun::star::uno::XNamingService XNamingService; + +typedef sequence< Boolean > SequenceBoolean; +typedef sequence< Byte > SequenceByte; +typedef sequence< Short > SequenceShort; +typedef sequence< UnsignedShort > SequenceUnsignedShort; +typedef sequence< Long > SequenceLong; +typedef sequence< UnsignedLong > SequenceUnsignedLong; +typedef sequence< Hyper > SequenceHyper; +typedef sequence< UnsignedHyper > SequenceUnsignedHyper; +typedef sequence< Float > SequenceFloat; +typedef sequence< Double > SequenceDouble; +typedef sequence< Char > SequenceChar; +typedef sequence< String > SequenceString; +typedef sequence< Type > SequenceType; +typedef sequence< Any > SequenceAny; +typedef sequence< Locale > SequenceLocale; +typedef sequence< XInterface > SequenceXInterface; +typedef sequence< XNamingService > SequenceXNamingService; + +service S1: XTest { + create1(); + + create2([in] any... create2) + raises (com::sun::star::uno::RuntimeException, + com::sun::star::lang::ClassNotFoundException, + com::sun::star::uno::Exception, + com::sun::star::lang::IllegalAccessException, + com::sun::star::uno::DeploymentException); + + create3([in] sequence<any> S1) + raises (com::sun::star::uno::RuntimeException, + com::sun::star::lang::ClassNotFoundException, + com::sun::star::lang::IllegalAccessException, + com::sun::star::uno::DeploymentException); + + create4([in] long javamaker, [in] long S1, [in] long create4); + + create5( + [in] boolean p1, + [in] byte p2, + [in] short p3, + [in] unsigned short p4, + [in] long p5, + [in] unsigned long p6, + [in] hyper p7, + [in] unsigned hyper p8, + [in] float p9, + [in] double p10, + [in] char p11, + [in] string p12, + [in] type p13, + [in] any p14, + [in] com::sun::star::lang::Locale p15, + [in] com::sun::star::uno::XInterface p16, + [in] com::sun::star::uno::XNamingService p17, + [in] Boolean t1, + [in] Byte t2, + [in] Short t3, + [in] UnsignedShort t4, + [in] Long t5, + [in] UnsignedLong t6, + [in] Hyper t7, + [in] UnsignedHyper t8, + [in] Float t9, + [in] Double t10, + [in] Char t11, + [in] String t12, + [in] Type t13, + [in] Any t14, + [in] Locale t15, + [in] XInterface t16, + [in] XNamingService t17, + [in] sequence< sequence< boolean > > a1, + [in] sequence< sequence< byte > > a2, + [in] sequence< sequence< short > > a3, + [in] sequence< sequence< unsigned short > > a4, + [in] sequence< sequence< long > > a5, + [in] sequence< sequence< unsigned long > > a6, + [in] sequence< sequence< hyper > > a7, + [in] sequence< sequence< unsigned hyper > > a8, + [in] sequence< sequence< float > > a9, + [in] sequence< sequence< double > > a10, + [in] sequence< sequence< char > > a11, + [in] sequence< sequence< string > > a12, + [in] sequence< sequence< type > > a13, + [in] sequence< sequence< any > > a14, + [in] sequence< sequence< com::sun::star::lang::Locale > > a15, + [in] sequence< sequence< com::sun::star::uno::XInterface > > a16, + [in] sequence< sequence< + com::sun::star::uno::XNamingService > > a17, + [in] sequence< SequenceBoolean > at1, + [in] sequence< SequenceByte > at2, + [in] sequence< SequenceShort > at3, + [in] sequence< SequenceUnsignedShort > at4, + [in] sequence< SequenceLong > at5, + [in] sequence< SequenceUnsignedLong > at6, + [in] sequence< SequenceHyper > at7, + [in] sequence< SequenceUnsignedHyper > at8, + [in] sequence< SequenceFloat > at9, + [in] sequence< SequenceDouble > at10, + [in] sequence< SequenceChar > at11, + [in] sequence< SequenceString > at12, + [in] sequence< SequenceType > at13, + [in] sequence< SequenceAny > at14, + [in] sequence< SequenceLocale > at15, + [in] sequence< SequenceXInterface > at16, + [in] sequence< SequenceXNamingService > at17); +}; + +service S2: XTest; + +service S3 { interface XTest; }; + +singleton S4 { service S3; }; + +module services { + +service asm: com::sun::star::uno::XInterface { asm([in] long asm); }; +service auto: com::sun::star::uno::XInterface { auto([in] long auto); }; +service bool: com::sun::star::uno::XInterface { bool([in] long bool); }; +service break: com::sun::star::uno::XInterface { break([in] long break); }; +//TODO: service case: com::sun::star::uno::XInterface { case([in] long case); }; +service catch: com::sun::star::uno::XInterface { catch([in] long catch); }; +//TODO: service char: com::sun::star::uno::XInterface { char([in] long char); }; +service class: com::sun::star::uno::XInterface { class([in] long class); }; +//TODO: service const: com::sun::star::uno::XInterface { +// const([in] long const); }; +service continue: com::sun::star::uno::XInterface { + continue([in] long continue); }; +//TODO: service default: com::sun::star::uno::XInterface { +// default([in] long default); }; +service delete: com::sun::star::uno::XInterface { delete([in] long delete); }; +service do: com::sun::star::uno::XInterface { do([in] long do); }; +//TODO: service double: com::sun::star::uno::XInterface { +// double([in] long double); }; +service else: com::sun::star::uno::XInterface { else([in] long else); }; +//TODO: service enum: com::sun::star::uno::XInterface { enum([in] long enum); }; +service explicit: com::sun::star::uno::XInterface { + explicit([in] long explicit); }; +service export: com::sun::star::uno::XInterface { export([in] long export); }; +service extern: com::sun::star::uno::XInterface { extern([in] long extern); }; +service false: com::sun::star::uno::XInterface { false([in] long false); }; +//TODO: service float: com::sun::star::uno::XInterface { +// float([in] long float); }; +service for: com::sun::star::uno::XInterface { for([in] long for); }; +service friend: com::sun::star::uno::XInterface { friend([in] long friend); }; +service goto: com::sun::star::uno::XInterface { goto([in] long goto); }; +service if: com::sun::star::uno::XInterface { if([in] long if); }; +service inline: com::sun::star::uno::XInterface { inline([in] long inline); }; +service int: com::sun::star::uno::XInterface { int([in] long int); }; +//TODO: service long: com::sun::star::uno::XInterface { long([in] long long); }; +service mutable: com::sun::star::uno::XInterface { + mutable([in] long mutable); }; +service namespace: com::sun::star::uno::XInterface { + namespace([in] long namespace); }; +service new: com::sun::star::uno::XInterface { new([in] long new); }; +service operator: com::sun::star::uno::XInterface { + operator([in] long operator); }; +service private: com::sun::star::uno::XInterface { + private([in] long private); }; +service protected: com::sun::star::uno::XInterface { + protected([in] long protected); }; +service public: com::sun::star::uno::XInterface { public([in] long public); }; +service register: com::sun::star::uno::XInterface { + register([in] long register); }; +service return: com::sun::star::uno::XInterface { return([in] long return); }; +//TODO: service short: com::sun::star::uno::XInterface { +// short([in] long short); }; +service signed: com::sun::star::uno::XInterface { signed([in] long signed); }; +service sizeof: com::sun::star::uno::XInterface { sizeof([in] long sizeof); }; +service static: com::sun::star::uno::XInterface { static([in] long static); }; +//TODO: service struct: com::sun::star::uno::XInterface { +// struct([in] long struct); }; +//TODO: service switch: com::sun::star::uno::XInterface { +// switch([in] long switch); }; +service template: com::sun::star::uno::XInterface { + template([in] long template); }; +service this: com::sun::star::uno::XInterface { this([in] long this); }; +service throw: com::sun::star::uno::XInterface { throw([in] long throw); }; +service true: com::sun::star::uno::XInterface { true([in] long true); }; +service try: com::sun::star::uno::XInterface { try([in] long try); }; +//TODO: service typedef: com::sun::star::uno::XInterface { +// typedef([in] long typedef); }; +service typeid: com::sun::star::uno::XInterface { typeid([in] long typeid); }; +service typename: com::sun::star::uno::XInterface { + typename([in] long typename); }; +//TODO: service union: com::sun::star::uno::XInterface { +// union([in] long union); }; +//TODO: service unsigned: com::sun::star::uno::XInterface { +// unsigned([in] long unsigned); }; +service using: com::sun::star::uno::XInterface { using([in] long using); }; +service virtual: com::sun::star::uno::XInterface { + virtual([in] long virtual); }; +//TODO: service void: com::sun::star::uno::XInterface { void([in] long void); }; +service volatile: com::sun::star::uno::XInterface { + volatile([in] long volatile); }; +service while: com::sun::star::uno::XInterface { while([in] long while); }; + +service and: com::sun::star::uno::XInterface { and([in] long and); }; +service bitand: com::sun::star::uno::XInterface { bitand([in] long bitand); }; +service bitor: com::sun::star::uno::XInterface { bitor([in] long bitor); }; +service compl: com::sun::star::uno::XInterface { compl([in] long compl); }; +service not: com::sun::star::uno::XInterface { not([in] long not); }; +service or: com::sun::star::uno::XInterface { or([in] long or); }; +service xor: com::sun::star::uno::XInterface { xor([in] long xor); }; + +service BUFSIZ: com::sun::star::uno::XInterface { BUFSIZ([in] long BUFSIZ); }; +service CLOCKS_PER_SEC: com::sun::star::uno::XInterface { + CLOCKS_PER_SEC([in] long CLOCKS_PER_SEC); }; +service EDOM: com::sun::star::uno::XInterface { EDOM([in] long EDOM); }; +service EOF: com::sun::star::uno::XInterface { EOF([in] long EOF); }; +service ERANGE: com::sun::star::uno::XInterface { ERANGE([in] long ERANGE); }; +service EXIT_FAILURE: com::sun::star::uno::XInterface { + EXIT_FAILURE([in] long EXIT_FAILURE); }; +service EXIT_SUCCESS: com::sun::star::uno::XInterface { + EXIT_SUCCESS([in] long EXIT_SUCCESS); }; +service FILENAME_MAX: com::sun::star::uno::XInterface { + FILENAME_MAX([in] long FILENAME_MAX); }; +service FOPEN_MAX: com::sun::star::uno::XInterface { + FOPEN_MAX([in] long FOPEN_MAX); }; +service HUGE_VAL: com::sun::star::uno::XInterface { + HUGE_VAL([in] long HUGE_VAL); }; +service LC_ALL: com::sun::star::uno::XInterface { LC_ALL([in] long LC_ALL); }; +service LC_COLLATE: com::sun::star::uno::XInterface { + LC_COLLATE([in] long LC_COLLATE); }; +service LC_CTYPE: com::sun::star::uno::XInterface { + LC_CTYPE([in] long LC_CTYPE); }; +service LC_MONETARY: com::sun::star::uno::XInterface { + LC_MONETARY([in] long LC_MONETARY); }; +service LC_NUMERIC: com::sun::star::uno::XInterface { + LC_NUMERIC([in] long LC_NUMERIC); }; +service LC_TIME: com::sun::star::uno::XInterface { + LC_TIME([in] long LC_TIME); }; +service L_tmpnam: com::sun::star::uno::XInterface { + L_tmpnam([in] long L_tmpnam); }; +service MB_CUR_MAX: com::sun::star::uno::XInterface { + MB_CUR_MAX([in] long MB_CUR_MAX); }; +service NULL: com::sun::star::uno::XInterface { NULL([in] long NULL); }; +service RAND_MAX: com::sun::star::uno::XInterface { + RAND_MAX([in] long RAND_MAX); }; +service SEEK_CUR: com::sun::star::uno::XInterface { + SEEK_CUR([in] long SEEK_CUR); }; +service SEEK_END: com::sun::star::uno::XInterface { + SEEK_END([in] long SEEK_END); }; +service SEEK_SET: com::sun::star::uno::XInterface { + SEEK_SET([in] long SEEK_SET); }; +service SIGABRT: com::sun::star::uno::XInterface { + SIGABRT([in] long SIGABRT); }; +service SIGFPE: com::sun::star::uno::XInterface { SIGFPE([in] long SIGFPE); }; +service SIGILL: com::sun::star::uno::XInterface { SIGILL([in] long SIGILL); }; +service SIGINT: com::sun::star::uno::XInterface { SIGINT([in] long SIGINT); }; +service SIGSEGV: com::sun::star::uno::XInterface { + SIGSEGV([in] long SIGSEGV); }; +service SIGTERM: com::sun::star::uno::XInterface { + SIGTERM([in] long SIGTERM); }; +service SIG_DFL: com::sun::star::uno::XInterface { + SIG_DFL([in] long SIG_DFL); }; +service SIG_ERR: com::sun::star::uno::XInterface { + SIG_ERR([in] long SIG_ERR); }; +service SIG_IGN: com::sun::star::uno::XInterface { + SIG_IGN([in] long SIG_IGN); }; +service TMP_MAX: com::sun::star::uno::XInterface { + TMP_MAX([in] long TMP_MAX); }; +service WCHAR_MAX: com::sun::star::uno::XInterface { + WCHAR_MAX([in] long WCHAR_MAX); }; +service WCHAR_MIN: com::sun::star::uno::XInterface { + WCHAR_MIN([in] long WCHAR_MIN); }; +service WEOF: com::sun::star::uno::XInterface { WEOF([in] long WEOF); }; +service assert: com::sun::star::uno::XInterface { assert([in] long assert); }; +service errno: com::sun::star::uno::XInterface { errno([in] long errno); }; +service offsetof: com::sun::star::uno::XInterface { + offsetof([in] long offsetof); }; +service setjmp: com::sun::star::uno::XInterface { setjmp([in] long setjmp); }; +service stderr: com::sun::star::uno::XInterface { stderr([in] long stderr); }; +service stdin: com::sun::star::uno::XInterface { stdin([in] long stdin); }; +service stdout: com::sun::star::uno::XInterface { stdout([in] long stdout); }; + +service CHAR_BIT: com::sun::star::uno::XInterface { + CHAR_BIT([in] long CHAR_BIT); }; +service CHAR_MAX: com::sun::star::uno::XInterface { + CHAR_MAX([in] long CHAR_MAX); }; +service CHAR_MIN: com::sun::star::uno::XInterface { + CHAR_MIN([in] long CHAR_MIN); }; +service DBL_DIG: com::sun::star::uno::XInterface { + DBL_DIG([in] long DBL_DIG); }; +service DBL_EPSILON: com::sun::star::uno::XInterface { + DBL_EPSILON([in] long DBL_EPSILON); }; +service DBL_MANT_DIG: com::sun::star::uno::XInterface { + DBL_MANT_DIG([in] long DBL_MANT_DIG); }; +service DBL_MAX: com::sun::star::uno::XInterface { + DBL_MAX([in] long DBL_MAX); }; +service DBL_MAX_10_EXP: com::sun::star::uno::XInterface { + DBL_MAX_10_EXP([in] long DBL_MAX_10_EXP); }; +service DBL_MAX_EXP: com::sun::star::uno::XInterface { + DBL_MAX_EXP([in] long DBL_MAX_EXP); }; +service DBL_MIN: com::sun::star::uno::XInterface { + DBL_MIN([in] long DBL_MIN); }; +service DBL_MIN_10_EXP: com::sun::star::uno::XInterface { + DBL_MIN_10_EXP([in] long DBL_MIN_10_EXP); }; +service DBL_MIN_EXP: com::sun::star::uno::XInterface { + DBL_MIN_EXP([in] long DBL_MIN_EXP); }; +service FLT_DIG: com::sun::star::uno::XInterface { + FLT_DIG([in] long FLT_DIG); }; +service FLT_EPSILON: com::sun::star::uno::XInterface { + FLT_EPSILON([in] long FLT_EPSILON); }; +service FLT_MANT_DIG: com::sun::star::uno::XInterface { + FLT_MANT_DIG([in] long FLT_MANT_DIG); }; +service FLT_MAX: com::sun::star::uno::XInterface { + FLT_MAX([in] long FLT_MAX); }; +service FLT_MAX_10_EXP: com::sun::star::uno::XInterface { + FLT_MAX_10_EXP([in] long FLT_MAX_10_EXP); }; +service FLT_MAX_EXP: com::sun::star::uno::XInterface { + FLT_MAX_EXP([in] long FLT_MAX_EXP); }; +service FLT_MIN: com::sun::star::uno::XInterface { + FLT_MIN([in] long FLT_MIN); }; +service FLT_MIN_10_EXP: com::sun::star::uno::XInterface { + FLT_MIN_10_EXP([in] long FLT_MIN_10_EXP); }; +service FLT_MIN_EXP: com::sun::star::uno::XInterface { + FLT_MIN_EXP([in] long FLT_MIN_EXP); }; +service FLT_RADIX: com::sun::star::uno::XInterface { + FLT_RADIX([in] long FLT_RADIX); }; +service FLT_ROUNDS: com::sun::star::uno::XInterface { + FLT_ROUNDS([in] long FLT_ROUNDS); }; +service INT_MAX: com::sun::star::uno::XInterface { + INT_MAX([in] long INT_MAX); }; +service INT_MIN: com::sun::star::uno::XInterface { + INT_MIN([in] long INT_MIN); }; +service LDBL_DIG: com::sun::star::uno::XInterface { + LDBL_DIG([in] long LDBL_DIG); }; +service LDBL_EPSILON: com::sun::star::uno::XInterface { + LDBL_EPSILON([in] long LDBL_EPSILON); }; +service LDBL_MANT_DIG: com::sun::star::uno::XInterface { + LDBL_MANT_DIG([in] long LDBL_MANT_DIG); }; +service LDBL_MAX: com::sun::star::uno::XInterface { + LDBL_MAX([in] long LDBL_MAX); }; +service LDBL_MAX_10_EXP: com::sun::star::uno::XInterface { + LDBL_MAX_10_EXP([in] long LDBL_MAX_10_EXP); }; +service LDBL_MAX_EXP: com::sun::star::uno::XInterface { + LDBL_MAX_EXP([in] long LDBL_MAX_EXP); }; +service LDBL_MIN: com::sun::star::uno::XInterface { + LDBL_MIN([in] long LDBL_MIN); }; +service LDBL_MIN_10_EXP: com::sun::star::uno::XInterface { + LDBL_MIN_10_EXP([in] long LDBL_MIN_10_EXP); }; +service LDBL_MIN_EXP: com::sun::star::uno::XInterface { + LDBL_MIN_EXP([in] long LDBL_MIN_EXP); }; +service LONG_MAX: com::sun::star::uno::XInterface { + LONG_MAX([in] long LONG_MAX); }; +service LONG_MIN: com::sun::star::uno::XInterface { + LONG_MIN([in] long LONG_MIN); }; +service MB_LEN_MAX: com::sun::star::uno::XInterface { + MB_LEN_MAX([in] long MB_LEN_MAX); }; +service SCHAR_MAX: com::sun::star::uno::XInterface { + SCHAR_MAX([in] long SCHAR_MAX); }; +service SCHAR_MIN: com::sun::star::uno::XInterface { + SCHAR_MIN([in] long SCHAR_MIN); }; +service SHRT_MAX: com::sun::star::uno::XInterface { + SHRT_MAX([in] long SHRT_MAX); }; +service SHRT_MIN: com::sun::star::uno::XInterface { + SHRT_MIN([in] long SHRT_MIN); }; +service UCHAR_MAX: com::sun::star::uno::XInterface { + UCHAR_MAX([in] long UCHAR_MAX); }; +service UINT_MAX: com::sun::star::uno::XInterface { + UINT_MAX([in] long UINT_MAX); }; +service ULONG_MAX: com::sun::star::uno::XInterface { + ULONG_MAX([in] long ULONG_MAX); }; +service USHRT_MAX: com::sun::star::uno::XInterface { + USHRT_MAX([in] long USHRT_MAX); }; + +service FILE: com::sun::star::uno::XInterface { FILE([in] long FILE); }; +service lconv: com::sun::star::uno::XInterface { lconv([in] long lconv); }; +service tm: com::sun::star::uno::XInterface { tm([in] long tm); }; + +service std: com::sun::star::uno::XInterface { std([in] long std); }; + +service NDEBUG: com::sun::star::uno::XInterface { NDEBUG([in] long NDEBUG); }; + +service create: com::sun::star::uno::XInterface; + +}; + +module singletons { + +singleton asm: com::sun::star::uno::XInterface; +singleton auto: com::sun::star::uno::XInterface; +singleton bool: com::sun::star::uno::XInterface; +singleton break: com::sun::star::uno::XInterface; +//TODO: singleton case: com::sun::star::uno::XInterface; +singleton catch: com::sun::star::uno::XInterface; +//TODO: singleton char: com::sun::star::uno::XInterface; +singleton class: com::sun::star::uno::XInterface; +//TODO: singleton const: com::sun::star::uno::XInterface; +singleton continue: com::sun::star::uno::XInterface; +//TODO: singleton default: com::sun::star::uno::XInterface; +singleton delete: com::sun::star::uno::XInterface; +singleton do: com::sun::star::uno::XInterface; +//TODO: singleton double: com::sun::star::uno::XInterface; +singleton else: com::sun::star::uno::XInterface; +//TODO: singleton enum: com::sun::star::uno::XInterface; +singleton explicit: com::sun::star::uno::XInterface; +singleton export: com::sun::star::uno::XInterface; +singleton extern: com::sun::star::uno::XInterface; +singleton false: com::sun::star::uno::XInterface; +//TODO: singleton float: com::sun::star::uno::XInterface; +singleton for: com::sun::star::uno::XInterface; +singleton friend: com::sun::star::uno::XInterface; +singleton goto: com::sun::star::uno::XInterface; +singleton if: com::sun::star::uno::XInterface; +singleton inline: com::sun::star::uno::XInterface; +singleton int: com::sun::star::uno::XInterface; +//TODO: singleton long: com::sun::star::uno::XInterface; +singleton mutable: com::sun::star::uno::XInterface; +singleton namespace: com::sun::star::uno::XInterface; +singleton new: com::sun::star::uno::XInterface; +singleton operator: com::sun::star::uno::XInterface; +singleton private: com::sun::star::uno::XInterface; +singleton protected: com::sun::star::uno::XInterface; +singleton public: com::sun::star::uno::XInterface; +singleton register: com::sun::star::uno::XInterface; +singleton return: com::sun::star::uno::XInterface; +//TODO: singleton short: com::sun::star::uno::XInterface; +singleton signed: com::sun::star::uno::XInterface; +singleton sizeof: com::sun::star::uno::XInterface; +singleton static: com::sun::star::uno::XInterface; +//TODO: singleton struct: com::sun::star::uno::XInterface; +//TODO: singleton switch: com::sun::star::uno::XInterface; +singleton template: com::sun::star::uno::XInterface; +singleton this: com::sun::star::uno::XInterface; +singleton throw: com::sun::star::uno::XInterface; +singleton true: com::sun::star::uno::XInterface; +singleton try: com::sun::star::uno::XInterface; +//TODO: singleton typedef: com::sun::star::uno::XInterface; +singleton typeid: com::sun::star::uno::XInterface; +singleton typename: com::sun::star::uno::XInterface; +//TODO: singleton union: com::sun::star::uno::XInterface; +//TODO: singleton unsigned: com::sun::star::uno::XInterface; +singleton using: com::sun::star::uno::XInterface; +singleton virtual: com::sun::star::uno::XInterface; +//TODO: singleton void: com::sun::star::uno::XInterface; +singleton volatile: com::sun::star::uno::XInterface; +singleton while: com::sun::star::uno::XInterface; + +singleton and: com::sun::star::uno::XInterface; +singleton bitand: com::sun::star::uno::XInterface; +singleton bitor: com::sun::star::uno::XInterface; +singleton compl: com::sun::star::uno::XInterface; +singleton not: com::sun::star::uno::XInterface; +singleton or: com::sun::star::uno::XInterface; +singleton xor: com::sun::star::uno::XInterface; + +singleton BUFSIZ: com::sun::star::uno::XInterface; +singleton CLOCKS_PER_SEC: com::sun::star::uno::XInterface; +singleton EDOM: com::sun::star::uno::XInterface; +singleton EOF: com::sun::star::uno::XInterface; +singleton ERANGE: com::sun::star::uno::XInterface; +singleton EXIT_FAILURE: com::sun::star::uno::XInterface; +singleton EXIT_SUCCESS: com::sun::star::uno::XInterface; +singleton FILENAME_MAX: com::sun::star::uno::XInterface; +singleton FOPEN_MAX: com::sun::star::uno::XInterface; +singleton HUGE_VAL: com::sun::star::uno::XInterface; +singleton LC_ALL: com::sun::star::uno::XInterface; +singleton LC_COLLATE: com::sun::star::uno::XInterface; +singleton LC_CTYPE: com::sun::star::uno::XInterface; +singleton LC_MONETARY: com::sun::star::uno::XInterface; +singleton LC_NUMERIC: com::sun::star::uno::XInterface; +singleton LC_TIME: com::sun::star::uno::XInterface; +singleton L_tmpnam: com::sun::star::uno::XInterface; +singleton MB_CUR_MAX: com::sun::star::uno::XInterface; +singleton NULL: com::sun::star::uno::XInterface; +singleton RAND_MAX: com::sun::star::uno::XInterface; +singleton SEEK_CUR: com::sun::star::uno::XInterface; +singleton SEEK_END: com::sun::star::uno::XInterface; +singleton SEEK_SET: com::sun::star::uno::XInterface; +singleton SIGABRT: com::sun::star::uno::XInterface; +singleton SIGFPE: com::sun::star::uno::XInterface; +singleton SIGILL: com::sun::star::uno::XInterface; +singleton SIGINT: com::sun::star::uno::XInterface; +singleton SIGSEGV: com::sun::star::uno::XInterface; +singleton SIGTERM: com::sun::star::uno::XInterface; +singleton SIG_DFL: com::sun::star::uno::XInterface; +singleton SIG_ERR: com::sun::star::uno::XInterface; +singleton SIG_IGN: com::sun::star::uno::XInterface; +singleton TMP_MAX: com::sun::star::uno::XInterface; +singleton WCHAR_MAX: com::sun::star::uno::XInterface; +singleton WCHAR_MIN: com::sun::star::uno::XInterface; +singleton WEOF: com::sun::star::uno::XInterface; +singleton assert: com::sun::star::uno::XInterface; +singleton errno: com::sun::star::uno::XInterface; +singleton offsetof: com::sun::star::uno::XInterface; +singleton setjmp: com::sun::star::uno::XInterface; +singleton stderr: com::sun::star::uno::XInterface; +singleton stdin: com::sun::star::uno::XInterface; +singleton stdout: com::sun::star::uno::XInterface; + +singleton CHAR_BIT: com::sun::star::uno::XInterface; +singleton CHAR_MAX: com::sun::star::uno::XInterface; +singleton CHAR_MIN: com::sun::star::uno::XInterface; +singleton DBL_DIG: com::sun::star::uno::XInterface; +singleton DBL_EPSILON: com::sun::star::uno::XInterface; +singleton DBL_MANT_DIG: com::sun::star::uno::XInterface; +singleton DBL_MAX: com::sun::star::uno::XInterface; +singleton DBL_MAX_10_EXP: com::sun::star::uno::XInterface; +singleton DBL_MAX_EXP: com::sun::star::uno::XInterface; +singleton DBL_MIN: com::sun::star::uno::XInterface; +singleton DBL_MIN_10_EXP: com::sun::star::uno::XInterface; +singleton DBL_MIN_EXP: com::sun::star::uno::XInterface; +singleton FLT_DIG: com::sun::star::uno::XInterface; +singleton FLT_EPSILON: com::sun::star::uno::XInterface; +singleton FLT_MANT_DIG: com::sun::star::uno::XInterface; +singleton FLT_MAX: com::sun::star::uno::XInterface; +singleton FLT_MAX_10_EXP: com::sun::star::uno::XInterface; +singleton FLT_MAX_EXP: com::sun::star::uno::XInterface; +singleton FLT_MIN: com::sun::star::uno::XInterface; +singleton FLT_MIN_10_EXP: com::sun::star::uno::XInterface; +singleton FLT_MIN_EXP: com::sun::star::uno::XInterface; +singleton FLT_RADIX: com::sun::star::uno::XInterface; +singleton FLT_ROUNDS: com::sun::star::uno::XInterface; +singleton INT_MAX: com::sun::star::uno::XInterface; +singleton INT_MIN: com::sun::star::uno::XInterface; +singleton LDBL_DIG: com::sun::star::uno::XInterface; +singleton LDBL_EPSILON: com::sun::star::uno::XInterface; +singleton LDBL_MANT_DIG: com::sun::star::uno::XInterface; +singleton LDBL_MAX: com::sun::star::uno::XInterface; +singleton LDBL_MAX_10_EXP: com::sun::star::uno::XInterface; +singleton LDBL_MAX_EXP: com::sun::star::uno::XInterface; +singleton LDBL_MIN: com::sun::star::uno::XInterface; +singleton LDBL_MIN_10_EXP: com::sun::star::uno::XInterface; +singleton LDBL_MIN_EXP: com::sun::star::uno::XInterface; +singleton LONG_MAX: com::sun::star::uno::XInterface; +singleton LONG_MIN: com::sun::star::uno::XInterface; +singleton MB_LEN_MAX: com::sun::star::uno::XInterface; +singleton SCHAR_MAX: com::sun::star::uno::XInterface; +singleton SCHAR_MIN: com::sun::star::uno::XInterface; +singleton SHRT_MAX: com::sun::star::uno::XInterface; +singleton SHRT_MIN: com::sun::star::uno::XInterface; +singleton UCHAR_MAX: com::sun::star::uno::XInterface; +singleton UINT_MAX: com::sun::star::uno::XInterface; +singleton ULONG_MAX: com::sun::star::uno::XInterface; +singleton USHRT_MAX: com::sun::star::uno::XInterface; + +singleton FILE: com::sun::star::uno::XInterface; +singleton lconv: com::sun::star::uno::XInterface; +singleton tm: com::sun::star::uno::XInterface; + +singleton std: com::sun::star::uno::XInterface; + +singleton NDEBUG: com::sun::star::uno::XInterface; + +singleton get: com::sun::star::uno::XInterface; + +}; + +enum HelperEnum { ZERO, ONE }; + +struct HelperStruct { boolean m1; com::sun::star::uno::XInterface m2; }; + +typedef byte TDByte; +typedef HelperEnum TDEnum1; +typedef TDEnum1 TDEnum; + +struct BigStruct { + boolean m1; + byte m2; + short m3; + unsigned short m4; + long m5; + unsigned long m6; + hyper m7; + unsigned hyper m8; + float m9; + double m10; + char m11; + string m12; + type m13; + any m14; + sequence<boolean> m15; + HelperEnum m16; + HelperStruct m17; + com::sun::star::uno::XInterface m18; + TDByte m19; + TDEnum m20; + sequence<unsigned short> m21; + sequence<char> m22; + sequence< sequence<char> > m23; +}; + +struct Struct<T, U> { + T member1; + sequence<SequenceAny> member2; +}; + +struct StructUsage { + Struct< long, short > member1; + sequence< + sequence< + Struct< + sequence< Struct< any, boolean > >, + com::sun::star::uno::XInterface > > > + member2; +}; + +struct AlignmentBaseStruct { + double member1; + short member2; +}; + +struct AlignmentDerivedStruct: AlignmentBaseStruct { + short member3; +}; + +exception TestException1: com::sun::star::uno::RuntimeException { + long m1; + any m2; + HelperEnum m3; + Struct<long, long> m4; + unsigned short m5; +}; + +exception TestException2: TestException1 {}; + +constants Constants { + const byte byteMin = -128; + const byte byteMax = 127; + const short shortMin = -32768; + const short shortMax = 32767; + const unsigned short unsignedShortMin = 0; + const unsigned short unsignedShortMax = 65535; + const long longMin = -2147483648; + const long longMax = 2147483647; + const unsigned long unsignedLongMin = 0; + const unsigned long unsignedLongMax = 4294967295; + const hyper hyperMin = -9223372036854775808; + const hyper hyperMax = 9223372036854775807; + const unsigned hyper unsignedHyperMin = 0; + const unsigned hyper unsignedHyperMax = 18446744073709551615; +}; + +}; }; }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/qa/test_any.cxx b/cppu/qa/test_any.cxx new file mode 100644 index 000000000..7dfed7a71 --- /dev/null +++ b/cppu/qa/test_any.cxx @@ -0,0 +1,2127 @@ +/* -*- 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/types.h> + +#include <stdlib.h> +#include <type_traits> + +#include <cppunit/TestFixture.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <Enum1.hpp> +#include <Enum2.hpp> +#include <Exception1.hpp> +#include <Exception2.hpp> +#include <Exception2a.hpp> +#include <Exception2b.hpp> +#include <Interface1.hpp> +#include <Interface2.hpp> +#include <Interface2a.hpp> +#include <Interface2b.hpp> +#include <Interface3.hpp> +#include <Poly.hpp> +#include <Struct1.hpp> +#include <Struct2.hpp> +#include <Struct2a.hpp> +#include <Struct2b.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <o3tl/cppunittraitshelper.hxx> +#include <osl/interlck.h> +#include <rtl/ustring.hxx> + +namespace { + +class Base { +public: + Base(): m_count(0) {} + + Base(const Base&) = delete; + const Base& operator=(const Base&) = delete; + + void acquire() { + if (osl_atomic_increment(&m_count) == SAL_MAX_INT32) { + abort(); + } + } + + void release() { + if (osl_atomic_decrement(&m_count) == 0) { + delete this; + } + } + +protected: + virtual ~Base() {} + +private: + oslInterlockedCount m_count; +}; + +class Impl1: public Interface1, private Base { +public: + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) override + { + if (type == cppu::UnoType<css::uno::XInterface>::get()) { + css::uno::Reference< css::uno::XInterface > ref( + static_cast< css::uno::XInterface * >(this)); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface1>::get()) { + css::uno::Reference< Interface1 > ref(this); + return css::uno::Any(&ref, type); + } + return css::uno::Any(); + } + + virtual void SAL_CALL acquire() throw () override { + Base::acquire(); + } + + virtual void SAL_CALL release() throw () override { + Base::release(); + } +}; + +class Impl2: public Interface2a, public Interface3, private Base { +public: + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) override + { + if (type == cppu::UnoType<css::uno::XInterface>::get()) { + css::uno::Reference< css::uno::XInterface > ref( + static_cast< css::uno::XInterface * >( + static_cast< Interface2a * >(this))); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface2>::get()) { + css::uno::Reference< Interface2 > ref(this); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface2a>::get()) { + css::uno::Reference< Interface2a > ref(this); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface3>::get()) { + css::uno::Reference< Interface3 > ref(this); + return css::uno::Any(&ref, type); + } + return css::uno::Any(); + } + + virtual void SAL_CALL acquire() throw () override { + Base::acquire(); + } + + virtual void SAL_CALL release() throw () override { + Base::release(); + } +}; + +class Impl2b: public Interface2b, private Base { +public: + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) override + { + if (type == cppu::UnoType<css::uno::XInterface>::get()) { + css::uno::Reference< css::uno::XInterface > ref( + static_cast< css::uno::XInterface * >( + static_cast< Interface2a * >(this))); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface2>::get()) { + css::uno::Reference< Interface2 > ref(this); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface2a>::get()) { + css::uno::Reference< Interface2a > ref(this); + return css::uno::Any(&ref, type); + } + if (type == cppu::UnoType<Interface2b>::get()) { + css::uno::Reference< Interface2b > ref(this); + return css::uno::Any(&ref, type); + } + return css::uno::Any(); + } + + virtual void SAL_CALL acquire() throw () override { + Base::acquire(); + } + + virtual void SAL_CALL release() throw () override { + Base::release(); + } +}; + +class Test: public CppUnit::TestFixture { +public: + void testVoid(); + void testBoolean(); + void testByte(); + void testShort(); + void testUnsignedShort(); + void testLong(); + void testUnsignedLong(); + void testHyper(); + void testUnsignedHyper(); + void testFloat(); + void testDouble(); + void testChar(); + void testString(); + void testType(); + void testSequence(); + void testEnum(); + void testStruct(); + void testPoly(); + void testException(); + void testInterface(); + void testNull(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testVoid); + CPPUNIT_TEST(testBoolean); + CPPUNIT_TEST(testByte); + CPPUNIT_TEST(testShort); + CPPUNIT_TEST(testUnsignedShort); + CPPUNIT_TEST(testLong); + CPPUNIT_TEST(testUnsignedLong); + CPPUNIT_TEST(testHyper); + CPPUNIT_TEST(testUnsignedHyper); + CPPUNIT_TEST(testFloat); + CPPUNIT_TEST(testDouble); + CPPUNIT_TEST(testChar); + CPPUNIT_TEST(testString); + CPPUNIT_TEST(testType); + CPPUNIT_TEST(testSequence); + CPPUNIT_TEST(testEnum); + CPPUNIT_TEST(testStruct); + CPPUNIT_TEST(testPoly); + CPPUNIT_TEST(testException); + CPPUNIT_TEST(testInterface); + CPPUNIT_TEST(testNull); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testVoid() { + css::uno::Any a; + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<void>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b)); + CPPUNIT_ASSERT_MESSAGE("bool", b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b)); + CPPUNIT_ASSERT_MESSAGE("sal_Bool", b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int8", sal_Int8(2), b); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int16", sal_Int16(2), b); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt16", sal_uInt16(2), b); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int32", sal_Int32(2), b); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt32", sal_uInt32(2), b); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int64", sal_Int64(2), b); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt64", sal_uInt64(2), b); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("float", 2.0f, b); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("double", 2.0, b); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Unicode", u'2', b); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "OUString", OUString("2"), b ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "css::uno::Type", + cppu::UnoType<OUString>::get(), b); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "css::uno::Sequence<OUString>", sal_Int32(2), b.getLength()); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Enum1", Enum1_M2, b); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Struct1", sal_Int32(2), b.member); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception1", sal_Int32(2), b.member); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Interface1", i, b); + } +} + +void Test::testBoolean() { + css::uno::Any a(false); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<bool>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", (a >>= b)); + CPPUNIT_ASSERT_MESSAGE("bool", !b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", (a >>= b)); + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int8", sal_Int8(2), b); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int16", sal_Int16(2), b); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt16", sal_uInt16(2), b); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int32", sal_Int32(2), b); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt32", sal_uInt32(2), b); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int64", sal_Int64(2), b); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_uInt64", sal_uInt64(2), b); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("float", 2.0f, b); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("double", 2.0, b); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Unicode", u'2', b); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "OUString", OUString("2"), b ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "css::uno::Type", + cppu::UnoType<OUString>::get(), b); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "css::uno::Sequence<OUString>", + sal_Int32(2), b.getLength()); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Enum1", Enum1_M2, b); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Struct1", sal_Int32(2), b.member); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Exception1", sal_Int32(2), b.member); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Interface1", i, b); + } +} + +void Test::testByte() { + css::uno::Any a(static_cast< sal_Int8 >(1)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<sal_Int8>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b)); + CPPUNIT_ASSERT_MESSAGE("bool", b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b)); + CPPUNIT_ASSERT_MESSAGE("sal_Bool", b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", (a >>= b)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("sal_Int8", sal_Int8(1), b); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", (a >>= b) && b == 1); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", (a >>= b) && b == 1); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", (a >>= b) && b == 1); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", (a >>= b) && b == 1); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", (a >>= b) && b == 1); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + if (std::is_same< sal_Unicode, sal_uInt16 >::value) { + CPPUNIT_ASSERT_MESSAGE("@sal_Unicode", (a >>= b) && b == 1); + } else { + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testShort() { + css::uno::Any a(static_cast< sal_Int16 >(1)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<sal_Int16>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", (a >>= b) && b == 1); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", (a >>= b) && b == 1); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", (a >>= b) && b == 1); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", (a >>= b) && b == 1); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", (a >>= b) && b == 1); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + if (std::is_same< sal_Unicode, sal_uInt16 >::value) { + CPPUNIT_ASSERT_MESSAGE("@sal_Unicode", (a >>= b) && b == 1); + } else { + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testUnsignedShort() { + sal_uInt16 n = 1; + css::uno::Any a(&n, cppu::UnoType<cppu::UnoUnsignedShortType>::get()); + CPPUNIT_ASSERT( + bool(a.getValueType() == cppu::UnoType<cppu::UnoUnsignedShortType>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", (a >>= b) && b == 1); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", (a >>= b) && b == 1); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", (a >>= b) && b == 1); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", (a >>= b) && b == 1); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", (a >>= b) && b == 1); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + if (std::is_same< sal_Unicode, sal_uInt16 >::value) { + CPPUNIT_ASSERT_MESSAGE("@sal_Unicode", (a >>= b) && b == 1); + } else { + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testLong() { + css::uno::Any a(static_cast< sal_Int32 >(1)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<sal_Int32>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", (a >>= b) && b == 1); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", (a >>= b) && b == 1); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testUnsignedLong() { + css::uno::Any a(static_cast< sal_uInt32 >(1)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<sal_uInt32>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", (a >>= b) && b == 1); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", (a >>= b) && b == 1); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testHyper() { + css::uno::Any a(static_cast< sal_Int64 >(1)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<sal_Int64>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testUnsignedHyper() { + css::uno::Any a(static_cast< sal_uInt64 >(1)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<sal_uInt64>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", (a >>= b) && b == 1); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", (a >>= b) && b == 1); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testFloat() { + css::uno::Any a(1.f); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<float>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", (a >>= b) && b == 1); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testDouble() { + css::uno::Any a(1.); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<double>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", (a >>= b) && b == 1); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testChar() { + sal_Unicode c = '1'; + css::uno::Any a(&c, cppu::UnoType<cppu::UnoCharType>::get()); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<cppu::UnoCharType>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + if (std::is_same< sal_Unicode, sal_uInt16 >::value) { + CPPUNIT_ASSERT_MESSAGE("@sal_Unicode", !(a >>= b) && b == '2'); + } else { + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", (a >>= b) && b == '1'); + } + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testString() { + css::uno::Any a(OUString("1")); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<OUString>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", (a >>= b) && b == "1" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testType() { + css::uno::Any a(cppu::UnoType<sal_Int32>::get()); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<css::uno::Type>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", (a >>= b) && b == cppu::UnoType<sal_Int32>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testSequence() { + sal_Int32 n = 1; + css::uno::Any a(css::uno::Sequence< sal_Int32 >(&n, 1)); + CPPUNIT_ASSERT( + bool(a.getValueType() + == cppu::UnoType<css::uno::Sequence<sal_Int32>>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + css::uno::Sequence< sal_Int32 > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<sal_Int32>", + (a >>= b) && b.getLength() == 1 && b[0] == 1); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testEnum() { + css::uno::Any a(Enum2_M1); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<Enum2>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Enum2 b = Enum2_M2; + CPPUNIT_ASSERT_MESSAGE("Enum2", (a >>= b) && b == Enum2_M1); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testStruct() { + css::uno::Any a(Struct2a(1, 3)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<Struct2a>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Struct2 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct2", (a >>= b) && b.member == 1); + } + { + Struct2a b(2, 2); + CPPUNIT_ASSERT_MESSAGE( + "Struct2a", (a >>= b) && b.member == 1 && b.member2 == 3); + } + { + Struct2b b(2, 2, 2); + CPPUNIT_ASSERT_MESSAGE("Struct2b", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testPoly() { + css::uno::Any a; + a <<= Poly< css::uno::Sequence< ::sal_Unicode > >(); + CPPUNIT_ASSERT_EQUAL_MESSAGE( "type name", OUString("Poly<[]char>"), a.getValueType().getTypeName() ); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "constructor", + css::uno::Any(Poly< css::uno::Sequence< ::sal_Unicode > >()), a); +} + +void Test::testException() { + css::uno::Any a( + Exception2a( + OUString(), css::uno::Reference< css::uno::XInterface >(), 1, + 3)); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<Exception2a>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + Exception2 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception2", (a >>= b) && b.member == 1); + } + { + Exception2a b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2, + 2); + CPPUNIT_ASSERT_MESSAGE( + "Exception2a", (a >>= b) && b.member == 1 && b.member2 == 3); + } + { + Exception2b b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2, + 2); + CPPUNIT_ASSERT_MESSAGE("Exception2b", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } +} + +void Test::testInterface() { + css::uno::Reference< Interface2a > i2(new Impl2); + css::uno::Any a(i2); + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<Interface2a>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > i(new Impl1); + css::uno::Reference< Interface1 > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface1", !(a >>= b) && b == i); + } + { + css::uno::Reference< Interface2 > b(new Impl2); + CPPUNIT_ASSERT_MESSAGE("Interface2", (a >>= b) && b == i2); + } + { + css::uno::Reference< Interface2a > b(new Impl2); + CPPUNIT_ASSERT_MESSAGE("Interface2a", (a >>= b) && b == i2); + } + { + css::uno::Reference< Interface2b > i(new Impl2b); + css::uno::Reference< Interface2b > b(i); + CPPUNIT_ASSERT_MESSAGE("Interface2b", !(a >>= b) && b == i); + } + { + css::uno::Reference< Interface3 > b(new Impl2); + CPPUNIT_ASSERT_MESSAGE("Interface3", (a >>= b) && b == i2); + } +} + +void Test::testNull() { + css::uno::Any a { css::uno::Reference< Interface2a >() }; + CPPUNIT_ASSERT(bool(a.getValueType() == cppu::UnoType<Interface2a>::get())); + { + bool b = true; + CPPUNIT_ASSERT_MESSAGE("bool", !(a >>= b) && b); + } + { + sal_Bool b = true; + CPPUNIT_ASSERT_MESSAGE("sal_Bool", !(a >>= b) && b); + } + { + sal_Int8 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int8", !(a >>= b) && b == 2); + } + { + sal_Int16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int16", !(a >>= b) && b == 2); + } + { + sal_uInt16 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt16", !(a >>= b) && b == 2); + } + { + sal_Int32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int32", !(a >>= b) && b == 2); + } + { + sal_uInt32 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt32", !(a >>= b) && b == 2); + } + { + sal_Int64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_Int64", !(a >>= b) && b == 2); + } + { + sal_uInt64 b = 2; + CPPUNIT_ASSERT_MESSAGE("sal_uInt64", !(a >>= b) && b == 2); + } + { + float b = 2; + CPPUNIT_ASSERT_MESSAGE("float", !(a >>= b) && b == 2); + } + { + double b = 2; + CPPUNIT_ASSERT_MESSAGE("double", !(a >>= b) && b == 2); + } + { + sal_Unicode b = '2'; + CPPUNIT_ASSERT_MESSAGE("sal_Unicode", !(a >>= b) && b == '2'); + } + { + OUString b("2"); + CPPUNIT_ASSERT_MESSAGE( "OUString", !(a >>= b) && b == "2" ); + } + { + css::uno::Type b(cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Type", + !(a >>= b) && b == cppu::UnoType<OUString>::get()); + } + { + css::uno::Sequence< OUString > b(2); + CPPUNIT_ASSERT_MESSAGE( + "css::uno::Sequence<OUString>", + !(a >>= b) && b.getLength() == 2); + } + { + Enum1 b = Enum1_M2; + CPPUNIT_ASSERT_MESSAGE("Enum1", !(a >>= b) && b == Enum1_M2); + } + { + Struct1 b(2); + CPPUNIT_ASSERT_MESSAGE("Struct1", !(a >>= b) && b.member == 2); + } + { + Exception1 b( + OUString(), css::uno::Reference< css::uno::XInterface >(), 2); + CPPUNIT_ASSERT_MESSAGE("Exception1", !(a >>= b) && b.member == 2); + } + { + css::uno::Reference< Interface1 > b(new Impl1); + CPPUNIT_ASSERT_MESSAGE( + "Interface1", (a >>= b) && !b.is()); + } + { + css::uno::Reference< Interface2 > b(new Impl2); + CPPUNIT_ASSERT_MESSAGE( + "Interface2", (a >>= b) && !b.is()); + } + { + css::uno::Reference< Interface2a > b(new Impl2); + CPPUNIT_ASSERT_MESSAGE("Interface2a", (a >>= b) && !b.is()); + } + { + css::uno::Reference< Interface2b > b(new Impl2b); + CPPUNIT_ASSERT_MESSAGE( + "Interface2b", (a >>= b) && !b.is()); + } + { + css::uno::Reference< Interface3 > b(new Impl2); + CPPUNIT_ASSERT_MESSAGE( + "Interface3", (a >>= b) && !b.is()); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/qa/test_recursion.cxx b/cppu/qa/test_recursion.cxx new file mode 100644 index 000000000..40aee4c30 --- /dev/null +++ b/cppu/qa/test_recursion.cxx @@ -0,0 +1,53 @@ +/* -*- 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/types.h> + +#include <cppunit/TestSuite.h> +#include <cppunit/TestFixture.h> +#include <cppunit/TestCase.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <Rec.hpp> + +namespace +{ + +class Test: public CppUnit::TestFixture { + +public: + void testRecursion(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testRecursion); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testRecursion() { + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), Rec().x.getLength()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/qa/test_reference.cxx b/cppu/qa/test_reference.cxx new file mode 100644 index 000000000..79ff90ae4 --- /dev/null +++ b/cppu/qa/test_reference.cxx @@ -0,0 +1,203 @@ +/* -*- 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/types.h> + +#include <cppunit/TestFixture.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <Interface1.hpp> + +namespace +{ + +using ::com::sun::star::uno::Type; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::RuntimeException; +using ::com::sun::star::uno::UNO_SET_THROW; + +class Foo: public Interface1 +{ +public: + Foo() + :m_refCount(0) + { + } + + Foo(const Foo&) = delete; + const Foo& operator=(const Foo&) = delete; + + virtual Any SAL_CALL queryInterface(const Type & _type) override + { + if (_type == cppu::UnoType<XInterface>::get()) + { + return css::uno::makeAny<css::uno::Reference<css::uno::XInterface>>( + this); + } + if (_type == cppu::UnoType<Interface1>::get()) + { + return css::uno::makeAny<css::uno::Reference<Interface1>>(this); + } + + return Any(); + } + + virtual void SAL_CALL acquire() throw () override + { + osl_atomic_increment( &m_refCount ); + } + + virtual void SAL_CALL release() throw () override + { + if ( 0 == osl_atomic_decrement( &m_refCount ) ) + delete this; + } + +protected: + virtual ~Foo() + { + } + +private: + oslInterlockedCount m_refCount; +}; + +// Check that the up-casting Reference conversion constructor catches the +// intended cases: + +struct Base1: public css::uno::XInterface { + virtual ~Base1() = delete; + static ::css::uno::Type const & static_type(void * = nullptr) // loplugin:refcounting + { return ::cppu::UnoType<Base1>::get(); } +}; +struct Base2: public Base1 { + virtual ~Base2() override = delete; +}; +struct Base3: public Base1 { virtual ~Base3() override = delete; }; +struct Derived: public Base2, public Base3 { + virtual ~Derived() override = delete; +}; + +// The special case using the conversion operator instead: +css::uno::Reference< css::uno::XInterface > testUpcast1( + css::uno::Reference< Derived > const & ref) +{ + Base1::static_type(); // prevent loplugin:unreffun firing + return ref; +} + +// The normal up-cast case: +css::uno::Reference< Base1 > testUpcast2( + css::uno::Reference< Base2 > const & ref) +{ return ref; } + +// Commenting this in should cause a compiler error due to an ambiguous up-cast: +/* +css::uno::Reference< Base1 > testFailingUpcast3( + css::uno::Reference< Derived > const & ref) +{ return ref; } +*/ + +// Commenting this in should cause a compiler error due to a down-cast: +/* +css::uno::Reference< Base2 > testFailingUpcast4( + css::uno::Reference< Base1 > const & ref) +{ return ref; } +*/ + +// Commenting this in should cause a compiler error due to a down-cast: +/* +css::uno::Reference< Base1 > testFailingUpcast5( + css::uno::Reference< css::uno::XInterface > const & ref) +{ return ref; } +*/ + +class Test: public ::CppUnit::TestFixture +{ + +public: + void testUnoSetThrow(); + void testUpcastCompilation(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testUnoSetThrow); + CPPUNIT_TEST(testUpcastCompilation); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testUnoSetThrow() +{ + Reference< Interface1 > xNull; + Reference< Interface1 > xFoo( new Foo ); + + // ctor taking Reference< interface_type > + bool bCaughtException = false; + try { Reference< Interface1 > x( xNull, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( true, bCaughtException ); + + bCaughtException = false; + try { Reference< Interface1 > x( xFoo, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( false, bCaughtException ); + + // ctor taking interface_type* + bCaughtException = false; + try { Reference< Interface1 > x( xNull.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( true, bCaughtException ); + + bCaughtException = false; + try { Reference< Interface1 > x( xFoo.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( false, bCaughtException ); + + Reference< Interface1 > x; + // "set" taking Reference< interface_type > + bCaughtException = false; + try { x.set( xNull, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( true, bCaughtException ); + + bCaughtException = false; + try { x.set( xFoo, UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( false, bCaughtException ); + + // "set" taking interface_type* + bCaughtException = false; + try { x.set( xNull.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( true, bCaughtException ); + + bCaughtException = false; + try { x.set( xFoo.get(), UNO_SET_THROW ); } catch( const RuntimeException& ) { bCaughtException = true; } + CPPUNIT_ASSERT_EQUAL( false, bCaughtException ); +} + +// Include a dummy test calling those functions, to avoid warnings about those +// functions being unused: +void Test::testUpcastCompilation() +{ + testUpcast1(css::uno::Reference< Derived >()); + testUpcast2(css::uno::Reference< Base2 >()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} // namespace + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/qa/test_unotype.cxx b/cppu/qa/test_unotype.cxx new file mode 100644 index 000000000..829676a14 --- /dev/null +++ b/cppu/qa/test_unotype.cxx @@ -0,0 +1,558 @@ +/* -*- 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/types.h> + +#include <cppunit/TestFixture.h> +#include <cppunit/plugin/TestPlugIn.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <typeinfo> + +#include <com/sun/star/beans/Optional.hpp> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/TypeClass.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <cppu/unotype.hxx> +#include <rtl/ustring.hxx> + +namespace com::sun::star::uno { + class Any; +} + +namespace com::sun::star::uno { template <class interface_type> class Reference; } + +namespace { + +struct DerivedStruct1: css::lang::EventObject {}; + +struct DerivedStruct2: css::beans::PropertyChangeEvent {}; + +struct DerivedException1: css::uno::Exception {}; + +struct DerivedException2: css::uno::RuntimeException {}; + +struct DerivedInterface1: css::uno::XInterface { +private: + ~DerivedInterface1() {} + // avoid warnings about virtual members and non-virtual dtor + +public: + static void dummy(DerivedInterface1 * p) + { p->DerivedInterface1::~DerivedInterface1(); } + // ...and avoid warnings about unused ~DerivedInterface1 (see below) +}; + +struct DerivedInterface2: css::uno::XComponentContext { +private: + ~DerivedInterface2() {} + // avoid warnings about virtual members and non-virtual dtor + +public: + static void dummy(DerivedInterface2 * p) + { p->DerivedInterface2::~DerivedInterface2(); } + // ...and avoid warnings about unused ~DerivedInterface2 (see below) +}; + +class Test: public CppUnit::TestFixture { +public: + void testUnoType(); + + void testGetTypeFavourUnsigned(); + + void testGetTypeFavourChar(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testUnoType); + CPPUNIT_TEST(testGetTypeFavourUnsigned); + CPPUNIT_TEST(testGetTypeFavourChar); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testUnoType() { + // Avoid warnings about unused ~DerivedInterface1/2 (see above): + if ((false)) { + DerivedInterface1::dummy(nullptr); + DerivedInterface2::dummy(nullptr); + } + + css::uno::Type t; + t = cppu::UnoType<cppu::UnoVoidType>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_VOID, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("void"), t.getTypeName()); + CPPUNIT_ASSERT(bool(cppu::UnoType<void>::get() == t)); + t = cppu::UnoType<bool>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_BOOLEAN, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("boolean"), t.getTypeName()); + CPPUNIT_ASSERT(bool(cppu::UnoType<sal_Bool>::get() == t)); + t = cppu::UnoType<sal_Int8>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_BYTE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("byte"), t.getTypeName()); + t = cppu::UnoType<sal_Int16>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SHORT, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("short"), t.getTypeName()); + t = cppu::UnoType<cppu::UnoUnsignedShortType>::get(); + CPPUNIT_ASSERT_EQUAL( + css::uno::TypeClass_UNSIGNED_SHORT, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("unsigned short"), t.getTypeName()); + t = cppu::UnoType<sal_Int32>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_LONG, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("long"), t.getTypeName()); + t = cppu::UnoType<sal_uInt32>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_UNSIGNED_LONG, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("unsigned long"), t.getTypeName()); + t = cppu::UnoType<sal_Int64>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_HYPER, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("hyper"), t.getTypeName()); + t = cppu::UnoType<sal_uInt64>::get(); + CPPUNIT_ASSERT_EQUAL( + css::uno::TypeClass_UNSIGNED_HYPER, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("unsigned hyper"), t.getTypeName()); + t = cppu::UnoType<float>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_FLOAT, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("float"), t.getTypeName()); + t = cppu::UnoType<double>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_DOUBLE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("double"), t.getTypeName()); + t = cppu::UnoType<cppu::UnoCharType>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_CHAR, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("char"), t.getTypeName()); + t = cppu::UnoType<OUString>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_STRING, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("string"), t.getTypeName()); + t = cppu::UnoType<css::uno::Type>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_TYPE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("type"), t.getTypeName()); + t = cppu::UnoType<css::uno::Any>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_ANY, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("any"), t.getTypeName()); + t = cppu::UnoType<cppu::UnoSequenceType<sal_Int8>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SEQUENCE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("[]byte"), t.getTypeName()); + CPPUNIT_ASSERT(bool(cppu::UnoType<css::uno::Sequence<sal_Int8>>::get() == t)); + t = cppu::UnoType<cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SEQUENCE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("[]unsigned short"), t.getTypeName()); + t = cppu::UnoType<cppu::UnoSequenceType<cppu::UnoCharType>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SEQUENCE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("[]char"), t.getTypeName()); + t = cppu::UnoType< + cppu::UnoSequenceType<cppu::UnoSequenceType<sal_Int8>>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SEQUENCE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("[][]byte"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL( + cppu::UnoType<css::uno::Sequence<css::uno::Sequence<sal_Int8>>>::get(), + t); + t = cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SEQUENCE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("[][]unsigned short"), t.getTypeName()); + t = cppu::UnoType< + cppu::UnoSequenceType<cppu::UnoSequenceType<cppu::UnoCharType>>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_SEQUENCE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL(OUString("[][]char"), t.getTypeName()); + t = cppu::UnoType<css::uno::TypeClass>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_ENUM, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.uno.TypeClass"), t.getTypeName()); + t = cppu::UnoType<css::lang::EventObject>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_STRUCT, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.lang.EventObject"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<DerivedStruct1>::get(), t); + t = cppu::UnoType<css::beans::PropertyChangeEvent>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_STRUCT, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.beans.PropertyChangeEvent"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<DerivedStruct2>::get(), t); + t = cppu::UnoType<css::beans::Optional<sal_Int8>>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_STRUCT, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.beans.Optional<byte>"), t.getTypeName()); + t = cppu::UnoType<css::uno::Exception>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_EXCEPTION, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.uno.Exception"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<DerivedException1>::get(), t); + t = cppu::UnoType<css::uno::RuntimeException>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_EXCEPTION, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.uno.RuntimeException"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<DerivedException2>::get(), t); + t = cppu::UnoType<css::uno::XInterface>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_INTERFACE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.uno.XInterface"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL( + cppu::UnoType<css::uno::Reference<css::uno::XInterface>>::get(), t); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<DerivedInterface1>::get(), t); + CPPUNIT_ASSERT_EQUAL( + cppu::UnoType<css::uno::Reference<DerivedInterface1>>::get(), t); + t = cppu::UnoType<css::uno::XComponentContext>::get(); + CPPUNIT_ASSERT_EQUAL(css::uno::TypeClass_INTERFACE, t.getTypeClass()); + CPPUNIT_ASSERT_EQUAL( + OUString("com.sun.star.uno.XComponentContext"), t.getTypeName()); + CPPUNIT_ASSERT_EQUAL( + cppu::UnoType<css::uno::Reference<css::uno::XComponentContext>>::get(), + t); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<DerivedInterface2>::get(), t); + CPPUNIT_ASSERT_EQUAL( + cppu::UnoType<css::uno::Reference<DerivedInterface2>>::get(), t); +} + +void Test::testGetTypeFavourUnsigned() { + CPPUNIT_ASSERT(typeid(sal_Unicode) != typeid(sal_uInt16)); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<cppu::UnoVoidType *>(nullptr)), + cppu::UnoType<cppu::UnoVoidType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<bool *>(nullptr)), + cppu::UnoType<bool>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_Bool *>(nullptr)), + cppu::UnoType<bool>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_Int8 *>(nullptr)), + cppu::UnoType<sal_Int8>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_Int16 *>(nullptr)), + cppu::UnoType<sal_Int16>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<cppu::UnoUnsignedShortType *>(nullptr)), + cppu::UnoType<cppu::UnoUnsignedShortType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_uInt16 *>(nullptr)), + cppu::UnoType<cppu::UnoUnsignedShortType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_Int32 *>(nullptr)), + cppu::UnoType<sal_Int32>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_uInt32 *>(nullptr)), + cppu::UnoType<sal_uInt32>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_Int64 *>(nullptr)), + cppu::UnoType<sal_Int64>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_uInt64 *>(nullptr)), + cppu::UnoType<sal_uInt64>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<float *>(nullptr)), + cppu::UnoType<float>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<double *>(nullptr)), + cppu::UnoType<double>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<cppu::UnoCharType *>(nullptr)), + cppu::UnoType<cppu::UnoCharType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<sal_Unicode *>(nullptr)), + cppu::UnoType<cppu::UnoCharType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<OUString *>(nullptr)), + cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<css::uno::Type *>(nullptr)), + cppu::UnoType<css::uno::Type>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<css::uno::Any *>(nullptr)), + cppu::UnoType<css::uno::Any>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::Sequence<sal_uInt16> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast< + cppu::UnoSequenceType< + cppu::UnoSequenceType< + cppu::UnoUnsignedShortType>> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast< + css::uno::Sequence<css::uno::Sequence<sal_uInt16>> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::Sequence<sal_Unicode> *>(nullptr)), + cppu::UnoType<cppu::UnoSequenceType<cppu::UnoCharType>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast< + css::uno::Sequence< + css::uno::Sequence<sal_Unicode>> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoCharType>>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::TypeClass *>(nullptr)), + cppu::UnoType<css::uno::TypeClass>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::lang::EventObject *>(nullptr)), + cppu::UnoType<css::lang::EventObject>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<DerivedStruct1 *>(nullptr)), + cppu::UnoType<css::lang::EventObject>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::beans::PropertyChangeEvent *>(nullptr)), + cppu::UnoType<css::beans::PropertyChangeEvent>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<DerivedStruct2 *>(nullptr)), + cppu::UnoType<css::beans::PropertyChangeEvent>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::beans::Optional<sal_Int8> *>(nullptr)), + cppu::UnoType<css::beans::Optional<sal_Int8>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::Exception *>(nullptr)), + cppu::UnoType<css::uno::Exception>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<DerivedException1 *>(nullptr)), + cppu::UnoType<css::uno::Exception>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::RuntimeException *>(nullptr)), + cppu::UnoType<css::uno::RuntimeException>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<DerivedException2 *>(nullptr)), + cppu::UnoType<css::uno::RuntimeException>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::XInterface *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::Reference<css::uno::XInterface> *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<DerivedInterface1 *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::Reference<DerivedInterface1> *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::XComponentContext *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast< + css::uno::Reference<css::uno::XComponentContext> *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned(static_cast<DerivedInterface2 *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourUnsigned( + static_cast<css::uno::Reference<DerivedInterface2> *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); +} + +void Test::testGetTypeFavourChar() { + CPPUNIT_ASSERT(typeid(sal_Unicode) != typeid(sal_uInt16)); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<cppu::UnoVoidType *>(nullptr)), + cppu::UnoType<cppu::UnoVoidType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<bool *>(nullptr)), + cppu::UnoType<bool>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_Bool *>(nullptr)), + cppu::UnoType<bool>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_Int8 *>(nullptr)), + cppu::UnoType<sal_Int8>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_Int16 *>(nullptr)), + cppu::UnoType<sal_Int16>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<cppu::UnoUnsignedShortType *>(nullptr)), + cppu::UnoType<cppu::UnoUnsignedShortType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_uInt16 *>(nullptr)), + cppu::UnoType<cppu::UnoUnsignedShortType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_Int32 *>(nullptr)), + cppu::UnoType<sal_Int32>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_uInt32 *>(nullptr)), + cppu::UnoType<sal_uInt32>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_Int64 *>(nullptr)), + cppu::UnoType<sal_Int64>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_uInt64 *>(nullptr)), + cppu::UnoType<sal_uInt64>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<float *>(nullptr)), + cppu::UnoType<float>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<double *>(nullptr)), + cppu::UnoType<double>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<cppu::UnoCharType *>(nullptr)), + cppu::UnoType<cppu::UnoCharType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<sal_Unicode *>(nullptr)), + cppu::UnoType<cppu::UnoCharType>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<OUString *>(nullptr)), + cppu::UnoType<OUString>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<css::uno::Type *>(nullptr)), + cppu::UnoType<css::uno::Type>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<css::uno::Any *>(nullptr)), + cppu::UnoType<css::uno::Any>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::Sequence<sal_uInt16> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast< + cppu::UnoSequenceType< + cppu::UnoSequenceType< + cppu::UnoUnsignedShortType>> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast< + css::uno::Sequence<css::uno::Sequence<sal_uInt16>> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoUnsignedShortType>>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::Sequence<sal_Unicode> *>(nullptr)), + cppu::UnoType<cppu::UnoSequenceType<cppu::UnoCharType>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast< + css::uno::Sequence< + css::uno::Sequence<sal_Unicode>> *>(nullptr)), + cppu::UnoType< + cppu::UnoSequenceType< + cppu::UnoSequenceType<cppu::UnoCharType>>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<css::uno::TypeClass *>(nullptr)), + cppu::UnoType<css::uno::TypeClass>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<css::lang::EventObject *>(nullptr)), + cppu::UnoType<css::lang::EventObject>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<DerivedStruct1 *>(nullptr)), + cppu::UnoType<css::lang::EventObject>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::beans::PropertyChangeEvent *>(nullptr)), + cppu::UnoType<css::beans::PropertyChangeEvent>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<DerivedStruct2 *>(nullptr)), + cppu::UnoType<css::beans::PropertyChangeEvent>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::beans::Optional<sal_Int8> *>(nullptr)), + cppu::UnoType<css::beans::Optional<sal_Int8>>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<css::uno::Exception *>(nullptr)), + cppu::UnoType<css::uno::Exception>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<DerivedException1 *>(nullptr)), + cppu::UnoType<css::uno::Exception>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::RuntimeException *>(nullptr)), + cppu::UnoType<css::uno::RuntimeException>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<DerivedException2 *>(nullptr)), + cppu::UnoType<css::uno::RuntimeException>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<css::uno::XInterface *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::Reference<css::uno::XInterface> *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<DerivedInterface1 *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::Reference<DerivedInterface1> *>(nullptr)), + cppu::UnoType<css::uno::XInterface>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::XComponentContext *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast< + css::uno::Reference<css::uno::XComponentContext> *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar(static_cast<DerivedInterface2 *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); + CPPUNIT_ASSERT_EQUAL( + cppu::getTypeFavourChar( + static_cast<css::uno::Reference<DerivedInterface2> *>(nullptr)), + cppu::UnoType<css::uno::XComponentContext>::get()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/qa/typelib.cxx b/cppu/qa/typelib.cxx new file mode 100644 index 000000000..227e5731c --- /dev/null +++ b/cppu/qa/typelib.cxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <sal/config.h> + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XTextInputStream.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/script/FinishReason.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/XInterface.hpp> +#include <cppu/unotype.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <typelib/typedescription.h> +#include <typelib/typedescription.hxx> + +// Test that typelib_typedescription_register as called from typelib_typedescription_complete +// returns a correct typelib_TypeDescription and keeps pointers from the original +// typelib_TypeDescription intact (see tdf#115399 "Data race in typelib_typedescription_register"). +// This code uses sufficiently "obscure" types in typelib_static_*_type_init to make it unlikely +// that they are already instantiated and registered with the type description manager, which might +// cause inconsistencies. + +namespace +{ +class Test : public CppUnit::TestFixture +{ +public: + void testEnum() + { + typelib_TypeDescriptionReference* ref = nullptr; + typelib_static_enum_type_init(&ref, "com.sun.star.script.MemberType", 0); + CPPUNIT_ASSERT(ref != nullptr); + typelib_TypeDescription* td = ref->pType; + CPPUNIT_ASSERT(td != nullptr); + typelib_typedescription_acquire(td); + CPPUNIT_ASSERT(!td->bComplete); + auto t = reinterpret_cast<typelib_EnumTypeDescription*>(td); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nDefaultEnumValue); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nEnumValues); + CPPUNIT_ASSERT(t->ppEnumNames == nullptr); + CPPUNIT_ASSERT(t->pEnumValues == nullptr); + CPPUNIT_ASSERT(typelib_typedescription_complete(&td)); + CPPUNIT_ASSERT(td != nullptr); + CPPUNIT_ASSERT(td->bComplete); + t = reinterpret_cast<typelib_EnumTypeDescription*>(td); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nDefaultEnumValue); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), t->nEnumValues); + CPPUNIT_ASSERT(t->ppEnumNames != nullptr); + CPPUNIT_ASSERT_EQUAL(OUString("METHOD"), OUString::unacquired(&t->ppEnumNames[0])); + CPPUNIT_ASSERT_EQUAL(OUString("PROPERTY"), OUString::unacquired(&t->ppEnumNames[1])); + CPPUNIT_ASSERT_EQUAL(OUString("UNKNOWN"), OUString::unacquired(&t->ppEnumNames[2])); + CPPUNIT_ASSERT(t->pEnumValues != nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->pEnumValues[0]); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), t->pEnumValues[1]); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t->pEnumValues[2]); + typelib_typedescription_release(td); + typelib_typedescriptionreference_release(ref); + } + + void testStruct() + { + auto const t0 = cppu::UnoType<css::lang::EventObject>::get(); + auto const t1 = cppu::UnoType<css::script::FinishReason>::get(); + auto const t2 = cppu::UnoType<OUString>::get(); + auto const t3 = cppu::UnoType<css::uno::Any>::get(); + typelib_TypeDescriptionReference* ref = nullptr; + typelib_TypeDescriptionReference* members[3] + = { t1.getTypeLibType(), t2.getTypeLibType(), t3.getTypeLibType() }; + typelib_static_struct_type_init(&ref, "com.sun.star.script.FinishEngineEvent", + t0.getTypeLibType(), 3, members, nullptr); + CPPUNIT_ASSERT(ref != nullptr); + typelib_TypeDescription* td = ref->pType; + CPPUNIT_ASSERT(td != nullptr); + typelib_typedescription_acquire(td); + CPPUNIT_ASSERT(!td->bComplete); + auto t = reinterpret_cast<typelib_StructTypeDescription*>(td); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->aBase.pBaseTypeDescription->aBase).equals(t0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), t->aBase.nMembers); + auto const offsets = t->aBase.pMemberOffsets; + CPPUNIT_ASSERT(offsets != nullptr); + auto const typerefs = t->aBase.ppTypeRefs; + CPPUNIT_ASSERT(typerefs != nullptr); + CPPUNIT_ASSERT_EQUAL(t1, css::uno::Type(typerefs[0])); + CPPUNIT_ASSERT_EQUAL(t2, css::uno::Type(typerefs[1])); + CPPUNIT_ASSERT_EQUAL(t3, css::uno::Type(typerefs[2])); + CPPUNIT_ASSERT(t->aBase.ppMemberNames == nullptr); + CPPUNIT_ASSERT(t->pParameterizedTypes == nullptr); + CPPUNIT_ASSERT(typelib_typedescription_complete(&td)); + CPPUNIT_ASSERT(td != nullptr); + CPPUNIT_ASSERT(td->bComplete); + t = reinterpret_cast<typelib_StructTypeDescription*>(td); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->aBase.pBaseTypeDescription->aBase).equals(t0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(3), t->aBase.nMembers); + CPPUNIT_ASSERT(t->aBase.pMemberOffsets != nullptr); + CPPUNIT_ASSERT(t->aBase.ppTypeRefs != nullptr); + CPPUNIT_ASSERT_EQUAL(t1, css::uno::Type(t->aBase.ppTypeRefs[0])); + CPPUNIT_ASSERT_EQUAL(t2, css::uno::Type(t->aBase.ppTypeRefs[1])); + CPPUNIT_ASSERT_EQUAL(t3, css::uno::Type(t->aBase.ppTypeRefs[2])); + CPPUNIT_ASSERT(t->aBase.ppMemberNames != nullptr); + CPPUNIT_ASSERT_EQUAL(OUString("Finish"), OUString::unacquired(&t->aBase.ppMemberNames[0])); + CPPUNIT_ASSERT_EQUAL(OUString("ErrorMessage"), + OUString::unacquired(&t->aBase.ppMemberNames[1])); + CPPUNIT_ASSERT_EQUAL(OUString("Return"), OUString::unacquired(&t->aBase.ppMemberNames[2])); + CPPUNIT_ASSERT(t->pParameterizedTypes == nullptr); + // `offsets` and `typerefs` must still be valid: + CPPUNIT_ASSERT_EQUAL(t->aBase.pMemberOffsets[0], offsets[0]); + CPPUNIT_ASSERT_EQUAL(t->aBase.pMemberOffsets[1], offsets[1]); + CPPUNIT_ASSERT_EQUAL(t->aBase.pMemberOffsets[2], offsets[2]); + CPPUNIT_ASSERT_EQUAL(css::uno::Type(t->aBase.ppTypeRefs[0]), css::uno::Type(typerefs[0])); + CPPUNIT_ASSERT_EQUAL(css::uno::Type(t->aBase.ppTypeRefs[1]), css::uno::Type(typerefs[1])); + CPPUNIT_ASSERT_EQUAL(css::uno::Type(t->aBase.ppTypeRefs[2]), css::uno::Type(typerefs[2])); + typelib_typedescription_release(td); + typelib_typedescriptionreference_release(ref); + } + + void testPolyStruct() + { + auto const t1 = cppu::UnoType<bool>::get(); + auto const t2 = cppu::UnoType<sal_Int32>::get(); + typelib_TypeDescriptionReference* ref = nullptr; + typelib_TypeDescriptionReference* members[2] = { t1.getTypeLibType(), t2.getTypeLibType() }; + sal_Bool const param[2] = { false, true }; + typelib_static_struct_type_init(&ref, "com.sun.star.beans.Optional<long>", nullptr, 2, + members, param); + CPPUNIT_ASSERT(ref != nullptr); + typelib_TypeDescription* td = ref->pType; + CPPUNIT_ASSERT(td != nullptr); + typelib_typedescription_acquire(td); + CPPUNIT_ASSERT(!td->bComplete); + auto t = reinterpret_cast<typelib_StructTypeDescription*>(td); + CPPUNIT_ASSERT(t->aBase.pBaseTypeDescription == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t->aBase.nMembers); + auto const offsets = t->aBase.pMemberOffsets; + CPPUNIT_ASSERT(offsets != nullptr); + auto const typerefs = t->aBase.ppTypeRefs; + CPPUNIT_ASSERT(typerefs != nullptr); + CPPUNIT_ASSERT_EQUAL(t1, css::uno::Type(typerefs[0])); + CPPUNIT_ASSERT_EQUAL(t2, css::uno::Type(typerefs[1])); + CPPUNIT_ASSERT(t->aBase.ppMemberNames == nullptr); + CPPUNIT_ASSERT(t->pParameterizedTypes != nullptr); + CPPUNIT_ASSERT_EQUAL(param[0], t->pParameterizedTypes[0]); + CPPUNIT_ASSERT_EQUAL(param[1], t->pParameterizedTypes[1]); + CPPUNIT_ASSERT(typelib_typedescription_complete(&td)); + CPPUNIT_ASSERT(td != nullptr); + CPPUNIT_ASSERT(td->bComplete); + t = reinterpret_cast<typelib_StructTypeDescription*>(td); + CPPUNIT_ASSERT(t->aBase.pBaseTypeDescription == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t->aBase.nMembers); + CPPUNIT_ASSERT(t->aBase.pMemberOffsets != nullptr); + CPPUNIT_ASSERT(t->aBase.ppTypeRefs != nullptr); + CPPUNIT_ASSERT_EQUAL(t1, css::uno::Type(t->aBase.ppTypeRefs[0])); + CPPUNIT_ASSERT_EQUAL(t2, css::uno::Type(t->aBase.ppTypeRefs[1])); + CPPUNIT_ASSERT(t->aBase.ppMemberNames != nullptr); + CPPUNIT_ASSERT_EQUAL(OUString("IsPresent"), + OUString::unacquired(&t->aBase.ppMemberNames[0])); + CPPUNIT_ASSERT_EQUAL(OUString("Value"), OUString::unacquired(&t->aBase.ppMemberNames[1])); + CPPUNIT_ASSERT(t->pParameterizedTypes != nullptr); + CPPUNIT_ASSERT_EQUAL(param[0], t->pParameterizedTypes[0]); + CPPUNIT_ASSERT_EQUAL(param[1], t->pParameterizedTypes[1]); + // `offsets` and `typerefs` must still be valid: + CPPUNIT_ASSERT_EQUAL(t->aBase.pMemberOffsets[0], offsets[0]); + CPPUNIT_ASSERT_EQUAL(t->aBase.pMemberOffsets[1], offsets[1]); + CPPUNIT_ASSERT_EQUAL(css::uno::Type(t->aBase.ppTypeRefs[0]), css::uno::Type(typerefs[0])); + CPPUNIT_ASSERT_EQUAL(css::uno::Type(t->aBase.ppTypeRefs[1]), css::uno::Type(typerefs[1])); + typelib_typedescription_release(td); + typelib_typedescriptionreference_release(ref); + } + + void testInterface() + { + auto const t0 = cppu::UnoType<css::uno::XInterface>::get(); + typelib_TypeDescriptionReference* ref = nullptr; + typelib_TypeDescriptionReference* bases[1] = { t0.getTypeLibType() }; + typelib_static_mi_interface_type_init(&ref, "com.sun.star.script.XTypeConverter", 1, bases); + CPPUNIT_ASSERT(ref != nullptr); + typelib_TypeDescription* td = ref->pType; + CPPUNIT_ASSERT(td != nullptr); + typelib_typedescription_acquire(td); + CPPUNIT_ASSERT(!td->bComplete); + auto t = reinterpret_cast<typelib_InterfaceTypeDescription*>(td); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->pBaseTypeDescription->aBase).equals(t0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nMembers); + CPPUNIT_ASSERT(t->ppMembers == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nAllMembers); + CPPUNIT_ASSERT(t->ppAllMembers == nullptr); + CPPUNIT_ASSERT(t->pMapMemberIndexToFunctionIndex == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nMapFunctionIndexToMemberIndex); + CPPUNIT_ASSERT(t->pMapFunctionIndexToMemberIndex == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), t->nBaseTypes); + auto const basetypes = t->ppBaseTypes; + CPPUNIT_ASSERT(basetypes != nullptr); + CPPUNIT_ASSERT(css::uno::TypeDescription(&basetypes[0]->aBase).equals(t0)); + CPPUNIT_ASSERT(typelib_typedescription_complete(&td)); + CPPUNIT_ASSERT(td != nullptr); + CPPUNIT_ASSERT(td->bComplete); + t = reinterpret_cast<typelib_InterfaceTypeDescription*>(td); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->pBaseTypeDescription->aBase).equals(t0)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t->nMembers); + CPPUNIT_ASSERT(t->ppMembers != nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), t->nAllMembers); + CPPUNIT_ASSERT(t->ppAllMembers != nullptr); + CPPUNIT_ASSERT(t->pMapMemberIndexToFunctionIndex != nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(5), t->nMapFunctionIndexToMemberIndex); + CPPUNIT_ASSERT(t->pMapFunctionIndexToMemberIndex != nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(1), t->nBaseTypes); + CPPUNIT_ASSERT(t->ppBaseTypes != nullptr); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->ppBaseTypes[0]->aBase).equals(t0)); + // `basetypes` must still be valid: + CPPUNIT_ASSERT( + css::uno::TypeDescription(&basetypes[0]->aBase).equals(&t->ppBaseTypes[0]->aBase)); + typelib_typedescription_release(td); + typelib_typedescriptionreference_release(ref); + } + + void testMultiInterface() + { + auto const t1 = cppu::UnoType<css::io::XTextInputStream>::get(); + auto const t2 = cppu::UnoType<css::io::XActiveDataSink>::get(); + typelib_TypeDescriptionReference* ref = nullptr; + typelib_TypeDescriptionReference* bases[2] = { t1.getTypeLibType(), t2.getTypeLibType() }; + typelib_static_mi_interface_type_init(&ref, "com.sun.star.io.XTextInputStream2", 2, bases); + CPPUNIT_ASSERT(ref != nullptr); + typelib_TypeDescription* td = ref->pType; + CPPUNIT_ASSERT(td != nullptr); + typelib_typedescription_acquire(td); + CPPUNIT_ASSERT(!td->bComplete); + auto t = reinterpret_cast<typelib_InterfaceTypeDescription*>(td); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->pBaseTypeDescription->aBase).equals(t1)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nMembers); + CPPUNIT_ASSERT(t->ppMembers == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nAllMembers); + CPPUNIT_ASSERT(t->ppAllMembers == nullptr); + CPPUNIT_ASSERT(t->pMapMemberIndexToFunctionIndex == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nMapFunctionIndexToMemberIndex); + CPPUNIT_ASSERT(t->pMapFunctionIndexToMemberIndex == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t->nBaseTypes); + auto const basetypes = t->ppBaseTypes; + CPPUNIT_ASSERT(basetypes != nullptr); + CPPUNIT_ASSERT(css::uno::TypeDescription(&basetypes[0]->aBase).equals(t1)); + CPPUNIT_ASSERT(css::uno::TypeDescription(&basetypes[1]->aBase).equals(t2)); + CPPUNIT_ASSERT(typelib_typedescription_complete(&td)); + CPPUNIT_ASSERT(td != nullptr); + CPPUNIT_ASSERT(td->bComplete); + t = reinterpret_cast<typelib_InterfaceTypeDescription*>(td); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->pBaseTypeDescription->aBase).equals(t1)); + CPPUNIT_ASSERT_EQUAL(sal_Int32(0), t->nMembers); + CPPUNIT_ASSERT(t->ppMembers == nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(14), t->nAllMembers); + CPPUNIT_ASSERT(t->ppAllMembers != nullptr); + CPPUNIT_ASSERT(t->pMapMemberIndexToFunctionIndex != nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(14), t->nMapFunctionIndexToMemberIndex); + CPPUNIT_ASSERT(t->pMapFunctionIndexToMemberIndex != nullptr); + CPPUNIT_ASSERT_EQUAL(sal_Int32(2), t->nBaseTypes); + CPPUNIT_ASSERT(t->ppBaseTypes != nullptr); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->ppBaseTypes[0]->aBase).equals(t1)); + CPPUNIT_ASSERT(css::uno::TypeDescription(&t->ppBaseTypes[1]->aBase).equals(t2)); + // `basetypes` must still be valid: + CPPUNIT_ASSERT( + css::uno::TypeDescription(&basetypes[0]->aBase).equals(&t->ppBaseTypes[0]->aBase)); + CPPUNIT_ASSERT( + css::uno::TypeDescription(&basetypes[1]->aBase).equals(&t->ppBaseTypes[1]->aBase)); + typelib_typedescription_release(td); + typelib_typedescriptionreference_release(ref); + } + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testEnum); + CPPUNIT_TEST(testStruct); + CPPUNIT_TEST(testPolyStruct); + CPPUNIT_TEST(testInterface); + CPPUNIT_TEST(testMultiInterface); + CPPUNIT_TEST_SUITE_END(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cppu/qa/types.idl b/cppu/qa/types.idl new file mode 100644 index 000000000..a17b035e0 --- /dev/null +++ b/cppu/qa/types.idl @@ -0,0 +1,57 @@ +/* -*- 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 <com/sun/star/uno/Exception.idl> +#include <com/sun/star/uno/XInterface.idl> + +enum Enum1 { M0, M1, M2 }; + +enum Enum2 { M0, M1, M2 }; + +struct Struct1 { long member; }; + +struct Struct2 { long member; }; + +struct Struct2a: Struct2 { long member2; }; + +struct Struct2b: Struct2a { long member3; }; + +struct Poly< T > { long member; }; + +struct Rec { sequence< Rec > x; }; + +exception Exception1: com::sun::star::uno::Exception { long member; }; + +exception Exception2: com::sun::star::uno::Exception { long member; }; + +exception Exception2a: Exception2 { long member2; }; + +exception Exception2b: Exception2a {}; + +interface Interface1 {}; + +interface Interface2 {}; + +interface Interface2a: Interface2 {}; + +interface Interface2b: Interface2a {}; + +interface Interface3 {}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/AffineBridge/AffineBridge.cxx b/cppu/source/AffineBridge/AffineBridge.cxx new file mode 100644 index 000000000..156d6eb9c --- /dev/null +++ b/cppu/source/AffineBridge/AffineBridge.cxx @@ -0,0 +1,361 @@ +/* -*- 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 <osl/thread.hxx> +#include <osl/conditn.hxx> +#include <osl/mutex.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> + +#include <cppu/Enterable.hxx> +#include <cppu/helper/purpenv/Environment.hxx> +#include <cppu/helper/purpenv/Mapping.hxx> +#include <memory> + +namespace { + +class InnerThread; +class OuterThread; + +class AffineBridge : public cppu::Enterable +{ +public: + enum Msg + { + CB_DONE, + CB_FPOINTER + }; + + Msg m_message; + uno_EnvCallee * m_pCallee; + va_list * m_pParam; + + osl::Mutex m_innerMutex; + oslThreadIdentifier m_innerThreadId; + std::unique_ptr<InnerThread> m_pInnerThread; + osl::Condition m_innerCondition; + sal_Int32 m_enterCount; + + osl::Mutex m_outerMutex; + oslThreadIdentifier m_outerThreadId; + osl::Condition m_outerCondition; + std::unique_ptr<OuterThread> m_pOuterThread; + + explicit AffineBridge(); + virtual ~AffineBridge() override; + + virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override; + virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override; + + virtual void v_enter() override; + virtual void v_leave() override; + + virtual bool v_isValid(OUString * pReason) override; + + void innerDispatch(); + void outerDispatch(bool loop); +}; + +class InnerThread : public osl::Thread +{ + virtual void SAL_CALL run() override; + + AffineBridge * m_pAffineBridge; + +public: + explicit InnerThread(AffineBridge * threadEnvironment) + : m_pAffineBridge(threadEnvironment) + { + create(); + } +}; + +} + +void InnerThread::run() +{ + osl_setThreadName("UNO AffineBridge InnerThread"); + + m_pAffineBridge->enter(); + m_pAffineBridge->innerDispatch(); + m_pAffineBridge->leave(); +} + +namespace { + +class OuterThread : public osl::Thread +{ + virtual void SAL_CALL run() override; + + AffineBridge * m_pAffineBridge; + +public: + explicit OuterThread(AffineBridge * threadEnvironment); +}; + +} + +OuterThread::OuterThread(AffineBridge * threadEnvironment) + : m_pAffineBridge(threadEnvironment) +{ + create(); +} + +void OuterThread::run() +{ + osl_setThreadName("UNO AffineBridge OuterThread"); + + osl::MutexGuard guard(m_pAffineBridge->m_outerMutex); + + m_pAffineBridge->m_outerThreadId = getIdentifier(); + m_pAffineBridge->outerDispatch(false); + m_pAffineBridge->m_outerThreadId = 0; + + m_pAffineBridge->m_pOuterThread = nullptr; + m_pAffineBridge = nullptr; +} + + +AffineBridge::AffineBridge() + : m_message (CB_DONE), + m_pCallee (nullptr), + m_pParam (nullptr), + m_innerThreadId(0), + m_enterCount (0), + m_outerThreadId(0) +{ + SAL_INFO("cppu.affinebridge", "LIFE: AffineBridge::AffineBridge(uno_Environment * pEnv) -> " << this); +} + +AffineBridge::~AffineBridge() +{ + SAL_INFO("cppu.affinebridge", "LIFE: AffineBridge::~AffineBridge() -> " << this); + + if (m_pInnerThread && osl::Thread::getCurrentIdentifier() != m_innerThreadId) + { + m_message = CB_DONE; + m_innerCondition.set(); + + m_pInnerThread->join(); + } + + m_pInnerThread.reset(); + + if (m_pOuterThread) + { + m_pOuterThread->join(); + } +} + + +void AffineBridge::outerDispatch(bool loop) +{ + OSL_ASSERT(m_outerThreadId == osl::Thread::getCurrentIdentifier()); + OSL_ASSERT(m_innerThreadId != m_outerThreadId); + + Msg mm; + + do + { + // FIXME: created outer thread must not wait + // in case of no message + // note: no message can happen in case newly created + // outer thread acquire outerMutex after a real outer + // thread enters outerDispatch! + m_outerCondition.wait(); + m_outerCondition.reset(); + + mm = m_message; + + switch(mm) + { + case CB_DONE: + break; + + case CB_FPOINTER: + { + m_pCallee(m_pParam); + + m_message = CB_DONE; + m_innerCondition.set(); + break; + } + default: + abort(); + } + } + while(mm != CB_DONE && loop); +} + +void AffineBridge::innerDispatch() +{ + OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier()); + OSL_ASSERT(m_innerThreadId != m_outerThreadId); + + Msg mm; + + do + { + m_innerCondition.wait(); + m_innerCondition.reset(); + + mm = m_message; + + switch(mm) + { + case CB_DONE: + break; + + case CB_FPOINTER: + { + m_pCallee(m_pParam); + + m_message = CB_DONE; + m_outerCondition.set(); + break; + } + default: + abort(); + } + } + while(mm != CB_DONE); +} + +void AffineBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + osl::MutexGuard guard(m_outerMutex); // only one thread at a time can call into + + if (m_innerThreadId == 0) // no inner thread yet + { + m_pInnerThread.reset(new InnerThread(this)); + m_pInnerThread->resume(); + } + + bool bResetId = false; + if (!m_outerThreadId) + { + m_outerThreadId = osl::Thread::getCurrentIdentifier(); + bResetId = true; + } + + m_message = CB_FPOINTER; + m_pCallee = pCallee; + m_pParam = pParam; + m_innerCondition.set(); + + outerDispatch(true); + + if (bResetId) + m_outerThreadId = 0; +} + +void AffineBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + OSL_ASSERT(m_innerThreadId); + + osl::MutexGuard guard(m_innerMutex); + + if (m_outerThreadId == 0) // no outer thread yet + { + osl::MutexGuard guard_m_outerMutex(m_outerMutex); + + if (m_outerThreadId == 0) + { + if (m_pOuterThread) + { + m_pOuterThread->join(); + } + + m_pOuterThread.reset(new OuterThread(this)); + } + } + + m_message = CB_FPOINTER; + m_pCallee = pCallee; + m_pParam = pParam; + m_outerCondition.set(); + + innerDispatch(); +} + +void AffineBridge::v_enter() +{ + m_innerMutex.acquire(); + + if (!m_enterCount) + m_innerThreadId = osl::Thread::getCurrentIdentifier(); + + OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier()); + + ++ m_enterCount; +} + +void AffineBridge::v_leave() +{ + OSL_ASSERT(m_innerThreadId == osl::Thread::getCurrentIdentifier()); + + -- m_enterCount; + if (!m_enterCount) + m_innerThreadId = 0; + + m_innerMutex.release(); +} + +bool AffineBridge::v_isValid(OUString * pReason) +{ + bool result = m_enterCount > 0; + if (!result) + *pReason = "not entered"; + + else + { + result = m_innerThreadId == osl::Thread::getCurrentIdentifier(); + + if (!result) + *pReason = "wrong thread"; + } + + if (result) + *pReason = "OK"; + + return result; +} + +#ifdef DISABLE_DYNLOADING + +#define uno_initEnvironment affine_uno_uno_initEnvironment +#define uno_ext_getMapping affine_uno_uno_ext_getMapping + +#endif + +extern "C" void SAL_DLLPUBLIC_EXPORT uno_initEnvironment(uno_Environment * pEnv) + SAL_THROW_EXTERN_C() +{ + cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new AffineBridge()); +} + +extern "C" void SAL_DLLPUBLIC_EXPORT uno_ext_getMapping(uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo ) +{ + cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/LogBridge/LogBridge.cxx b/cppu/source/LogBridge/LogBridge.cxx new file mode 100644 index 000000000..c0dc02c24 --- /dev/null +++ b/cppu/source/LogBridge/LogBridge.cxx @@ -0,0 +1,261 @@ +/* -*- 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 <osl/mutex.hxx> +#include <osl/thread.h> +#include <osl/thread.hxx> +#include <osl/diagnose.h> +#include <cppu/Enterable.hxx> +#include <cppu/helper/purpenv/Environment.hxx> +#include <cppu/helper/purpenv/Mapping.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <sal/log.hxx> + +namespace +{ +class LogBridge : public cppu::Enterable +{ + osl::Mutex m_mutex; + sal_Int32 m_count; + oslThreadIdentifier m_threadId; + + virtual ~LogBridge() override; + +public: + explicit LogBridge(); + + virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override; + virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override; + + virtual void v_enter() override; + virtual void v_leave() override; + + virtual bool v_isValid(OUString * pReason) override; +}; + +LogBridge::LogBridge() + : m_count (0) + ,m_threadId(0) +{ +} + +LogBridge::~LogBridge() +{ + OSL_ASSERT(m_count >= 0); +} + +void LogBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + enter(); + pCallee(pParam); + leave(); +} + +void LogBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + OSL_ASSERT(m_count > 0); + + -- m_count; + pCallee(pParam); + ++ m_count; + + if (!m_threadId) + m_threadId = osl::Thread::getCurrentIdentifier(); +} + +void LogBridge::v_enter() +{ + m_mutex.acquire(); + + OSL_ASSERT(m_count >= 0); + + if (m_count == 0) + m_threadId = osl::Thread::getCurrentIdentifier(); + + ++ m_count; +} + +void LogBridge::v_leave() +{ + OSL_ASSERT(m_count > 0); + + -- m_count; + if (!m_count) + m_threadId = 0; + + + m_mutex.release(); +} + +bool LogBridge::v_isValid(OUString * pReason) +{ + bool result = m_count > 0; + if (!result) + { + *pReason = "not entered"; + } + else + { + result = m_threadId == osl::Thread::getCurrentIdentifier(); + + if (!result) + *pReason = "wrong thread"; + } + + if (result) + *pReason = "OK"; + + return result; +} + + void traceValue(typelib_TypeDescriptionReference* _pTypeRef,void* pArg) + { + switch(_pTypeRef->eTypeClass) + { + case typelib_TypeClass_STRING: + SAL_INFO("cppu.log", "" << *static_cast< OUString*>(pArg)); + break; + case typelib_TypeClass_BOOLEAN: + SAL_INFO("cppu.log", "" << *static_cast<sal_Bool*>(pArg)); + break; + case typelib_TypeClass_BYTE: + SAL_INFO("cppu.log", "" << *static_cast<sal_Int8*>(pArg)); + break; + case typelib_TypeClass_CHAR: + SAL_INFO("cppu.log", "" << *static_cast<char*>(pArg)); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + SAL_INFO("cppu.log", "" << *static_cast<sal_Int16*>(pArg)); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_ENUM: + SAL_INFO("cppu.log", "" << *static_cast<sal_Int32*>(pArg)); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + SAL_INFO("cppu.log", "" << *static_cast<sal_Int64*>(pArg)); + break; + case typelib_TypeClass_FLOAT: + SAL_INFO("cppu.log", "" << *static_cast<float*>(pArg)); + break; + case typelib_TypeClass_DOUBLE: + SAL_INFO("cppu.log", "" << *static_cast<double*>(pArg)); + break; + case typelib_TypeClass_TYPE: + SAL_INFO("cppu.log", "" << static_cast<css::uno::Type*>(pArg)->getTypeName()); + break; + case typelib_TypeClass_ANY: + if ( static_cast<uno_Any*>(pArg)->pData ) + traceValue(static_cast<uno_Any*>(pArg)->pType,static_cast<uno_Any*>(pArg)->pData); + else + SAL_INFO("cppu.log", "void"); + break; + case typelib_TypeClass_EXCEPTION: + SAL_INFO("cppu.log", "exception"); + break; + case typelib_TypeClass_INTERFACE: + SAL_INFO("cppu.log", "" << _pTypeRef->pTypeName << "0x" << std::hex << pArg); + break; + case typelib_TypeClass_VOID: + SAL_INFO("cppu.log", "void"); + break; + default: + SAL_INFO("cppu.log", "0x" << std::hex << pArg); + break; + } // switch(pParams[i].pTypeRef->eTypeClass) + } +} + +static void LogProbe( + bool pre, + SAL_UNUSED_PARAMETER void * /*pThis*/, + SAL_UNUSED_PARAMETER void * /*pContext*/, + typelib_TypeDescriptionReference * pReturnTypeRef, + typelib_MethodParameter * pParams, + sal_Int32 nParams, + typelib_TypeDescription const * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ) +{ + OString sTemp; + if ( pMemberType && pMemberType->pTypeName ) + sTemp = OUStringToOString(pMemberType->pTypeName,RTL_TEXTENCODING_ASCII_US); + if ( pre ) + { + SAL_INFO("cppu.log", "{ LogBridge () " << sTemp ); + if ( nParams ) + { + SAL_INFO("cppu.log", "\n| : ( LogBridge "); + for(sal_Int32 i = 0;i < nParams;++i) + { + if ( i > 0 ) + SAL_INFO("cppu.log", ","); + traceValue(pParams[i].pTypeRef,pArgs[i]); + + } + SAL_INFO("cppu.log", ")"); + } // if ( nParams ) + SAL_INFO("cppu.log", "\n"); + } + else if ( !pre ) + { + SAL_INFO("cppu.log", "} LogBridge () " << sTemp); + if ( ppException && *ppException ) + { + SAL_INFO("cppu.log", " exception occurred : "); + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, (*ppException)->pType ); + SAL_INFO("cppu.log", "" << pElementTypeDescr->pTypeName); + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + } + else if ( pReturnTypeRef ) + { + SAL_INFO("cppu.log", " return : "); + traceValue(pReturnTypeRef,pReturn); + } // if ( pReturn && pReturnTypeRef ) + + SAL_INFO("cppu.log", "\n"); + } +} + +#ifdef DISABLE_DYNLOADING + +#define uno_initEnvironment log_uno_uno_initEnvironment +#define uno_ext_getMapping log_uno_uno_ext_getMapping + +#endif + +extern "C" void SAL_DLLPUBLIC_EXPORT uno_initEnvironment(uno_Environment * pEnv) + SAL_THROW_EXTERN_C() +{ + cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new LogBridge()); +} + +extern "C" void SAL_DLLPUBLIC_EXPORT uno_ext_getMapping(uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo ) +{ + cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo,LogProbe); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/UnsafeBridge/UnsafeBridge.cxx b/cppu/source/UnsafeBridge/UnsafeBridge.cxx new file mode 100644 index 000000000..491a888c3 --- /dev/null +++ b/cppu/source/UnsafeBridge/UnsafeBridge.cxx @@ -0,0 +1,144 @@ +/* -*- 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 <osl/mutex.hxx> +#include <osl/thread.h> +#include <osl/thread.hxx> +#include <sal/log.hxx> + +#include <cppu/Enterable.hxx> +#include <cppu/helper/purpenv/Environment.hxx> +#include <cppu/helper/purpenv/Mapping.hxx> + +namespace { + +class UnsafeBridge : public cppu::Enterable +{ + osl::Mutex m_mutex; + sal_Int32 m_count; + oslThreadIdentifier m_threadId; + + virtual ~UnsafeBridge() override; + +public: + explicit UnsafeBridge(); + + virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override; + virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override; + + virtual void v_enter() override; + virtual void v_leave() override; + + virtual bool v_isValid(OUString * pReason) override; +}; + +} + +UnsafeBridge::UnsafeBridge() + : m_count (0), + m_threadId(0) +{ + SAL_INFO("cppu.unsafebridge", "LIFE: UnsafeBridge::UnsafeBridge(uno_Environment * pEnv) -> " << this); +} + +UnsafeBridge::~UnsafeBridge() +{ + SAL_INFO("cppu.unsafebridge", "LIFE: UnsafeBridge::~UnsafeBridge() -> " << this); + + SAL_WARN_IF(m_count < 0, "cppu.unsafebridge", "m_count is less than 0"); +} + +void UnsafeBridge::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + enter(); + pCallee(pParam); + leave(); +} + +void UnsafeBridge::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + SAL_WARN_IF(m_count <= 0, "cppu.unsafebridge", "m_count is less than or equal to 0"); + + -- m_count; + pCallee(pParam); + ++ m_count; + + if (!m_threadId) + m_threadId = osl::Thread::getCurrentIdentifier(); +} + +void UnsafeBridge::v_enter() +{ + m_mutex.acquire(); + + SAL_WARN_IF(m_count < 0, "cppu.unsafebridge", "m_count is less than 0"); + + if (m_count == 0) + m_threadId = osl::Thread::getCurrentIdentifier(); + + ++ m_count; +} + +void UnsafeBridge::v_leave() +{ + SAL_WARN_IF(m_count <= 0, "cppu.unsafebridge", "m_count is less than or equal to 0"); + + -- m_count; + if (!m_count) + m_threadId = 0; + + + m_mutex.release(); +} + +bool UnsafeBridge::v_isValid(OUString * pReason) +{ + bool result = m_count > 0; + if (!result) + { + *pReason = "not entered"; + } + else + { + result = m_threadId == osl::Thread::getCurrentIdentifier(); + + if (!result) + *pReason = "wrong thread"; + } + + if (result) + *pReason = "OK"; + + return result; +} + +extern "C" void SAL_DLLPUBLIC_EXPORT uno_initEnvironment(uno_Environment * pEnv) + SAL_THROW_EXTERN_C() +{ + cppu::helper::purpenv::Environment_initWithEnterable(pEnv, new UnsafeBridge()); +} + +extern "C" void SAL_DLLPUBLIC_EXPORT uno_ext_getMapping(uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo ) +{ + cppu::helper::purpenv::createMapping(ppMapping, pFrom, pTo); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/cppu/compat.cxx b/cppu/source/cppu/compat.cxx new file mode 100644 index 000000000..06181e6ef --- /dev/null +++ b/cppu/source/cppu/compat.cxx @@ -0,0 +1,47 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <cstdlib> + +#include <typelib/typedescription.h> +#include <rtl/ustring.h> +#include <sal/types.h> + +// Stubs for removed functionality, to be killed when we bump sal SONAME + +extern "C" { + +SAL_DLLPUBLIC_EXPORT void SAL_CALL typelib_static_array_type_init( + typelib_TypeDescriptionReference **, typelib_TypeDescriptionReference *, + sal_Int32, ...) SAL_THROW_EXTERN_C() +{ + std::abort(); +} + +SAL_DLLPUBLIC_EXPORT void SAL_CALL typelib_typedescription_newArray( + typelib_TypeDescription **, typelib_TypeDescriptionReference *, + sal_Int32, sal_Int32 *) SAL_THROW_EXTERN_C() +{ + std::abort(); +} + +SAL_DLLPUBLIC_EXPORT void SAL_CALL typelib_typedescription_newUnion( + typelib_TypeDescription **, rtl_uString *, + typelib_TypeDescriptionReference *, sal_Int64, + typelib_TypeDescriptionReference *, sal_Int32, void *) + SAL_THROW_EXTERN_C() +{ + std::abort(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/cppu/cppu_opt.cxx b/cppu/source/cppu/cppu_opt.cxx new file mode 100644 index 000000000..40f90de6e --- /dev/null +++ b/cppu/source/cppu/cppu_opt.cxx @@ -0,0 +1,66 @@ +/* -*- 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 <com/sun/star/uno/Any.hxx> +#include <typelib/typedescription.h> +#include <uno/any2.h> +#include <rtl/ustring.hxx> + + +using namespace ::rtl; + + +extern "C" rtl_uString * SAL_CALL cppu_unsatisfied_iquery_msg( + typelib_TypeDescriptionReference * pType ) + SAL_THROW_EXTERN_C() +{ + OUString ret = "unsatisfied query for interface of type " + + OUString::unacquired( &pType->pTypeName ) + "!"; + rtl_uString_acquire( ret.pData ); + return ret.pData; +} + + +extern "C" rtl_uString * SAL_CALL cppu_unsatisfied_iset_msg( + typelib_TypeDescriptionReference * pType ) + SAL_THROW_EXTERN_C() +{ + OUString ret = "invalid attempt to assign an empty interface of type " + + OUString::unacquired( &pType->pTypeName ) + "!"; + rtl_uString_acquire( ret.pData ); + return ret.pData; +} + + +extern "C" rtl_uString * SAL_CALL cppu_Any_extraction_failure_msg( + uno_Any const * pAny, typelib_TypeDescriptionReference * pType ) + SAL_THROW_EXTERN_C() +{ + OUString ret = "Cannot extract an Any(" + + OUString::unacquired(&pAny->pType->pTypeName) + + ") to " + + OUString::unacquired(&pType->pTypeName) + + "!"; + rtl_uString_acquire( ret.pData ); + return ret.pData; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/helper/purpenv/Proxy.hxx b/cppu/source/helper/purpenv/Proxy.hxx new file mode 100644 index 000000000..6f99ee7d4 --- /dev/null +++ b/cppu/source/helper/purpenv/Proxy.hxx @@ -0,0 +1,79 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_HELPER_PURPENV_PROXY_HXX +#define INCLUDED_CPPU_SOURCE_HELPER_PURPENV_PROXY_HXX + +#include <osl/interlck.h> + +#include <uno/environment.hxx> +#include <uno/mapping.hxx> +#include <uno/dispatcher.h> + +#include <cppu/helper/purpenv/Mapping.hxx> + + +class Proxy : public uno_Interface +{ + oslInterlockedCount m_nRef; + + css::uno::Environment m_from; + css::uno::Environment m_to; + + css::uno::Mapping m_from_to; + css::uno::Mapping m_to_from; + + // mapping information + uno_Interface * m_pUnoI; // wrapped interface + typelib_InterfaceTypeDescription * m_pTypeDescr; + OUString m_aOId; + + cppu::helper::purpenv::ProbeFun * m_probeFun; + void * m_pProbeContext; + +public: + explicit Proxy(css::uno::Mapping const & to_from, + uno_Environment * pTo, + uno_Environment * pFrom, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr, + OUString const & rOId, + cppu::helper::purpenv::ProbeFun * probeFun, + void * pProbeContext); + ~Proxy(); + + void acquire(); + void release(); + + void dispatch( + typelib_TypeDescriptionReference * pReturnTypeRef, + typelib_MethodParameter * pParams, + sal_Int32 nParams, + typelib_TypeDescription const * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ); + +}; + +extern "C" void Proxy_free(uno_ExtEnvironment * pEnv, void * pProxy) SAL_THROW_EXTERN_C(); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx b/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx new file mode 100644 index 000000000..a0163939f --- /dev/null +++ b/cppu/source/helper/purpenv/helper_purpenv_Environment.cxx @@ -0,0 +1,522 @@ +/* -*- 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 <cppu/helper/purpenv/Environment.hxx> + +#include <osl/diagnose.h> +#include <sal/log.hxx> +#include <uno/lbnames.h> +#include <cppu/Enterable.hxx> + +#include <typelib/typedescription.h> +#include <osl/interlck.h> +#include <memory> + +extern "C" { +typedef void EnvFun_P (uno_Environment *); +typedef void EnvFun_PP_P(uno_Environment ** ppHardEnv, uno_Environment *); +typedef void ExtEnv_registerProxyInterface (uno_ExtEnvironment *, + void ** ppProxy, + uno_freeProxyFunc freeProxy, + rtl_uString * pOId, + typelib_InterfaceTypeDescription * pTypeDescr); +typedef void ExtEnv_revokeInterface (uno_ExtEnvironment *, + void * pInterface); +typedef void ExtEnv_getObjectIdentifier (uno_ExtEnvironment *, + rtl_uString **, + void *); +typedef void ExtEnv_getRegisteredInterface (uno_ExtEnvironment *, + void **, + rtl_uString *, + typelib_InterfaceTypeDescription *); +typedef void ExtEnv_getRegisteredInterfaces(uno_ExtEnvironment *, + void *** pppInterfaces, + sal_Int32 * pnLen, + uno_memAlloc memAlloc); +typedef void ExtEnv_computeObjectIdentifier(uno_ExtEnvironment *, + rtl_uString ** ppOId, + void * pInterface); +typedef void ExtEnv_acquireInterface (uno_ExtEnvironment *, + void * pInterface); +typedef void ExtEnv_releaseInterface (uno_ExtEnvironment *, + void * pInterface); +} + +namespace { + +class Base : public cppu::Enterable +{ +public: + explicit Base(uno_Environment * pEnv, cppu::Enterable * pEnterable); + + void acquireWeak(); + void releaseWeak(); + void harden (uno_Environment ** ppHardEnv); + void acquire(); + void release(); + + void registerProxyInterface (void ** ppProxy, + uno_freeProxyFunc freeProxy, + OUString const & oid, + typelib_InterfaceTypeDescription * pTypeDescr); + void revokeInterface (void * pInterface); + void getObjectIdentifier (void * pInterface, + OUString * pOid); + void getRegisteredInterface (void **, + OUString const & oid, + typelib_InterfaceTypeDescription *); + void getRegisteredInterfaces(void ***, + sal_Int32 * pnLen, + uno_memAlloc memAlloc); + void computeObjectIdentifier(void * pInterface, + OUString * pOid); + void acquireInterface (void * pInterface); + void releaseInterface (void * pInterface); + + virtual void v_enter() override; + virtual void v_leave() override; + virtual void v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) override; + virtual void v_callOut_v (uno_EnvCallee * pCallee, va_list * pParam) override; + virtual bool v_isValid (OUString * pReason) override; + +protected: + oslInterlockedCount m_nRef; + uno_Environment * m_pEnv; + std::unique_ptr<cppu::Enterable> m_pEnterable; + + EnvFun_P * m_env_acquire; + EnvFun_P * m_env_release; + EnvFun_PP_P * m_env_harden; + EnvFun_P * m_env_acquireWeak; + EnvFun_P * m_env_releaseWeak; + + ExtEnv_registerProxyInterface * m_env_registerProxyInterface; + ExtEnv_revokeInterface * m_env_revokeInterface; + ExtEnv_getObjectIdentifier * m_env_getObjectIdentifier; + ExtEnv_getRegisteredInterface * m_env_getRegisteredInterface; + ExtEnv_getRegisteredInterfaces * m_env_getRegisteredInterfaces; + ExtEnv_computeObjectIdentifier * m_env_computeObjectIdentifier; + ExtEnv_acquireInterface * m_env_acquireInterface; + ExtEnv_releaseInterface * m_env_releaseInterface; + + virtual ~Base() override; +}; + +} + +extern "C" { +static void s_acquire(uno_Environment * pEnv) //SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast<Base *>(pEnv->pReserved); + pBase->acquire(); +} + +static void s_release(uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast<Base *>(pEnv->pReserved); + pBase->release(); +} + +static void s_harden(uno_Environment ** ppHardEnv, uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast<Base *>(pEnv->pReserved); + pBase->harden(ppHardEnv); +} + +static void s_acquireWeak(uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast<Base *>(pEnv->pReserved); + pBase->acquireWeak(); +} + +static void s_releaseWeak(uno_Environment * pEnv) SAL_THROW_EXTERN_C() +{ + Base * pBase = static_cast<Base *>(pEnv->pReserved); + pBase->releaseWeak(); +} + + +static void s_registerProxyInterface(uno_ExtEnvironment * pExtEnv, + void ** ppProxy, + uno_freeProxyFunc freeProxy, + rtl_uString * pOId, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->registerProxyInterface(ppProxy, freeProxy, pOId, pTypeDescr); +} + +static void s_revokeInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) +{ + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->revokeInterface(pInterface); +} + +static void s_getObjectIdentifier(uno_ExtEnvironment * pExtEnv, + rtl_uString ** ppOId, + void * pInterface) +{ + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->getObjectIdentifier(pInterface, reinterpret_cast<OUString *>(ppOId)); +} + +static void s_getRegisteredInterface(uno_ExtEnvironment * pExtEnv, + void ** ppInterface, + rtl_uString * pOId, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->getRegisteredInterface(ppInterface, pOId, pTypeDescr); +} + +static void s_getRegisteredInterfaces(uno_ExtEnvironment * pExtEnv, + void *** pppInterface, + sal_Int32 * pnLen, + uno_memAlloc memAlloc) +{ + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->getRegisteredInterfaces(pppInterface, pnLen, memAlloc); +} + +static void s_computeObjectIdentifier(uno_ExtEnvironment * pExtEnv, + rtl_uString ** ppOId, + void * pInterface) +{ + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->computeObjectIdentifier(pInterface, reinterpret_cast<OUString *>(ppOId)); +} + +static void s_acquireInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) { + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->acquireInterface(pInterface); +} + +static void s_releaseInterface(uno_ExtEnvironment * pExtEnv, void * pInterface) { + Base * pBase = static_cast<Base *>(pExtEnv->aBase.pReserved); + pBase->releaseInterface(pInterface); +} + +} + +Base::Base(uno_Environment * pEnv, cppu::Enterable * pEnterable) + :m_nRef(1), + m_pEnv(pEnv), + m_pEnterable (pEnterable), + m_env_acquire (pEnv->acquire), + m_env_release (pEnv->release), + m_env_harden (pEnv->harden), + m_env_acquireWeak(pEnv->acquireWeak), + m_env_releaseWeak(pEnv->releaseWeak), + m_env_registerProxyInterface (pEnv->pExtEnv->registerProxyInterface), + m_env_revokeInterface (pEnv->pExtEnv->revokeInterface), + m_env_getObjectIdentifier (pEnv->pExtEnv->getObjectIdentifier), + m_env_getRegisteredInterface (pEnv->pExtEnv->getRegisteredInterface), + m_env_getRegisteredInterfaces(pEnv->pExtEnv->getRegisteredInterfaces), + m_env_computeObjectIdentifier(pEnv->pExtEnv->computeObjectIdentifier), + m_env_acquireInterface (pEnv->pExtEnv->acquireInterface), + m_env_releaseInterface (pEnv->pExtEnv->releaseInterface) +{ + SAL_INFO("cppu.purpenv", "LIFE: cppu::helper::purpenv::Base::Base(uno_Environment * pEnv) -> " << this); + OSL_ENSURE( + rtl_ustr_ascii_compare_WithLength(pEnv->pTypeName->buffer, rtl_str_getLength(UNO_LB_UNO), UNO_LB_UNO) + == 0, + "### wrong environment type!"); + + pEnv->acquire = s_acquire; + pEnv->release = s_release; + pEnv->harden = s_harden; + pEnv->acquireWeak = s_acquireWeak; + pEnv->releaseWeak = s_releaseWeak; + + pEnv->pExtEnv->registerProxyInterface = s_registerProxyInterface; + pEnv->pExtEnv->revokeInterface = s_revokeInterface; + pEnv->pExtEnv->getObjectIdentifier = s_getObjectIdentifier; + pEnv->pExtEnv->getRegisteredInterface = s_getRegisteredInterface; + pEnv->pExtEnv->getRegisteredInterfaces = s_getRegisteredInterfaces; + pEnv->pExtEnv->computeObjectIdentifier = s_computeObjectIdentifier; + pEnv->pExtEnv->acquireInterface = s_acquireInterface; + pEnv->pExtEnv->releaseInterface = s_releaseInterface; + + pEnv->pReserved = this; +} + +Base::~Base() +{ + SAL_INFO("cppu.purpenv", "LIFE: cppu::helper::purpenv::Base::~Base() -> " << this); + + m_pEnv->acquire = m_env_acquire; + m_pEnv->release = m_env_release; + m_pEnv->harden = m_env_harden; + m_pEnv->acquireWeak = m_env_acquireWeak; + m_pEnv->releaseWeak = m_env_releaseWeak; + + m_pEnv->pReserved = nullptr; + + m_pEnterable.reset(); + m_pEnv->release(m_pEnv); +} + +void Base::acquire() +{ + m_env_acquire(m_pEnv); + + osl_atomic_increment(&m_nRef); +} + +void Base::release() +{ + if (osl_atomic_decrement(&m_nRef) == 0) + delete this; + + else + m_env_release(m_pEnv); +} + +void Base::harden(uno_Environment ** ppHardEnv) +{ + m_env_harden(ppHardEnv, m_pEnv); + osl_atomic_increment(&m_nRef); +} + +void Base::acquireWeak() +{ + m_env_acquireWeak(m_pEnv); +} + +void Base::releaseWeak() +{ + m_env_releaseWeak(m_pEnv); +} + + +extern "C" { static void s_registerProxyInterface_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void ** ppProxy = va_arg(*pParam, void **); + uno_freeProxyFunc freeProxy = va_arg(*pParam, uno_freeProxyFunc); + rtl_uString * pOId = va_arg(*pParam, rtl_uString *); + typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *); + ExtEnv_registerProxyInterface * pRegisterProxyInterface + = va_arg(*pParam, ExtEnv_registerProxyInterface *); + + pRegisterProxyInterface(pExtEnv, ppProxy, freeProxy, pOId, pTypeDescr); +}} + +void Base::registerProxyInterface(void ** ppProxy, + uno_freeProxyFunc freeProxy, + OUString const & oid, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + uno_Environment_invoke(m_pEnv, + s_registerProxyInterface_v, + m_pEnv->pExtEnv, + ppProxy, + freeProxy, + oid.pData, + pTypeDescr, + m_env_registerProxyInterface); +} + + +extern "C" { static void s_revokeInterface_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void * pInterface = va_arg(*pParam, void *); + ExtEnv_revokeInterface * pRevokeInterface = va_arg(*pParam, ExtEnv_revokeInterface *); + + pRevokeInterface(pExtEnv, pInterface); +}} + +void Base::revokeInterface(void * pInterface) +{ + uno_Environment_invoke(m_pEnv, + s_revokeInterface_v, + m_pEnv->pExtEnv, + pInterface, + m_env_revokeInterface); +} + + +extern "C" { static void s_getObjectIdentifier_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void * pInterface = va_arg(*pParam, void *); + OUString * pOId = va_arg(*pParam, OUString *); + ExtEnv_getObjectIdentifier * pGetObjectIdentifier + = va_arg(*pParam, ExtEnv_getObjectIdentifier *); + + pGetObjectIdentifier(pExtEnv, reinterpret_cast<rtl_uString **>(pOId), pInterface); +}} + +void Base::getObjectIdentifier(void * pInterface, OUString * pOid) +{ + uno_Environment_invoke(m_pEnv, + s_getObjectIdentifier_v, + m_pEnv->pExtEnv, + pInterface, + pOid, + m_env_getObjectIdentifier); +} + + +extern "C" { static void s_getRegisteredInterface_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void ** ppInterface = va_arg(*pParam, void **); + rtl_uString * pOId = va_arg(*pParam, rtl_uString *); + typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *); + ExtEnv_getRegisteredInterface * pGetRegisteredInterface + = va_arg(*pParam, ExtEnv_getRegisteredInterface *); + + pGetRegisteredInterface(pExtEnv, ppInterface, pOId, pTypeDescr); +}} + +void Base::getRegisteredInterface(void ** ppInterface, + OUString const & oid, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + uno_Environment_invoke(m_pEnv, + s_getRegisteredInterface_v, + m_pEnv->pExtEnv, + ppInterface, + oid.pData, + pTypeDescr, + m_env_getRegisteredInterface); +} + + +extern "C" { static void s_getRegisteredInterfaces_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void *** pppInterface = va_arg(*pParam, void ***); + sal_Int32 * pnLen = va_arg(*pParam, sal_Int32 *); + uno_memAlloc memAlloc = va_arg(*pParam, uno_memAlloc); + ExtEnv_getRegisteredInterfaces * pGetRegisteredInterfaces + = va_arg(*pParam, ExtEnv_getRegisteredInterfaces *); + + pGetRegisteredInterfaces(pExtEnv, pppInterface, pnLen, memAlloc); +}} + +void Base::getRegisteredInterfaces(void *** pppInterface, + sal_Int32 * pnLen, + uno_memAlloc memAlloc) +{ + uno_Environment_invoke(m_pEnv, + s_getRegisteredInterfaces_v, + m_pEnv->pExtEnv, + pppInterface, + pnLen, + memAlloc, + m_env_getRegisteredInterfaces); +} + + +extern "C" { static void s_computeObjectIdentifier_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void * pInterface = va_arg(*pParam, void *); + OUString * pOId = va_arg(*pParam, OUString *); + ExtEnv_computeObjectIdentifier * pComputeObjectIdentifier + = va_arg(*pParam, ExtEnv_computeObjectIdentifier *); + + pComputeObjectIdentifier(pExtEnv, reinterpret_cast<rtl_uString **>(pOId), pInterface); +}} + +void Base::computeObjectIdentifier(void * pInterface, OUString * pOid) +{ + uno_Environment_invoke(m_pEnv, + s_computeObjectIdentifier_v, + m_pEnv->pExtEnv, + pInterface, + pOid, + m_env_computeObjectIdentifier); +} + + +extern "C" { static void s_acquireInterface_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void * pInterface = va_arg(*pParam, void *); + ExtEnv_acquireInterface * pAcquireInterface + = va_arg(*pParam, ExtEnv_acquireInterface *); + + pAcquireInterface(pExtEnv, pInterface); +}} + +void Base::acquireInterface(void * pInterface) +{ + uno_Environment_invoke(m_pEnv, s_acquireInterface_v, m_pEnv->pExtEnv, pInterface, m_env_acquireInterface); +} + + +extern "C" { static void s_releaseInterface_v(va_list * pParam) +{ + uno_ExtEnvironment * pExtEnv = va_arg(*pParam, uno_ExtEnvironment *); + void * pInterface = va_arg(*pParam, void *); + ExtEnv_releaseInterface * pReleaseInterface + = va_arg(*pParam, ExtEnv_releaseInterface *); + + pReleaseInterface(pExtEnv, pInterface); +}} + +void Base::releaseInterface(void * pInterface) +{ + uno_Environment_invoke(m_pEnv, + s_releaseInterface_v, + m_pEnv->pExtEnv, + pInterface, + m_env_releaseInterface); +} + +void Base::v_enter() +{ + m_pEnterable->enter(); +} + +void Base::v_leave() +{ + m_pEnterable->leave(); +} + +void Base::v_callInto_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + m_pEnterable->callInto_v(pCallee, pParam); +} + +void Base::v_callOut_v(uno_EnvCallee * pCallee, va_list * pParam) +{ + m_pEnterable->callOut_v(pCallee, pParam); +} + +bool Base::v_isValid(OUString * pReason) +{ + return m_pEnterable->isValid(pReason); +} + +namespace cppu::helper::purpenv { + +void Environment_initWithEnterable(uno_Environment * pEnvironment, cppu::Enterable * pEnterable) +{ + new Base(pEnvironment, pEnterable); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx b/cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx new file mode 100644 index 000000000..f68a47390 --- /dev/null +++ b/cppu/source/helper/purpenv/helper_purpenv_Mapping.cxx @@ -0,0 +1,215 @@ +/* -*- 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 <cppu/helper/purpenv/Mapping.hxx> + +#include "Proxy.hxx" + +#include <osl/interlck.h> +#include <sal/log.hxx> +#include <uno/environment.hxx> +#include <uno/dispatcher.h> + +using namespace com::sun::star; + +namespace { + +class Mapping : public uno_Mapping +{ + uno::Environment m_from; + uno::Environment m_to; + + oslInterlockedCount m_nCount; + + cppu::helper::purpenv::ProbeFun * m_probeFun; + void * m_pContext; + +public: + explicit Mapping(uno_Environment * pFrom, + uno_Environment * pTo, + cppu::helper::purpenv::ProbeFun * probeFun, + void * pProbeContext); + virtual ~Mapping(); + + void mapInterface( + uno_Interface ** ppOut, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr); + + void acquire(); + void release(); +}; + +} + +static void s_mapInterface( + uno_Mapping * puno_Mapping, + void ** ppOut, + void * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr ) + SAL_THROW_EXTERN_C() +{ + Mapping * pMapping = static_cast<Mapping *>(puno_Mapping); + pMapping->mapInterface( + reinterpret_cast<uno_Interface **>(ppOut), + static_cast<uno_Interface *>(pUnoI), pTypeDescr); +} + +extern "C" { +static void s_acquire(uno_Mapping * puno_Mapping) + SAL_THROW_EXTERN_C() +{ + Mapping * pMapping = static_cast<Mapping *>(puno_Mapping); + pMapping->acquire(); +} + +static void s_release(uno_Mapping * puno_Mapping) + SAL_THROW_EXTERN_C() +{ + Mapping * pMapping = static_cast<Mapping * >(puno_Mapping); + pMapping->release(); +} + + +static void s_getIdentifier_v(va_list * pParam) +{ + uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *); + rtl_uString ** ppOid = va_arg(*pParam, rtl_uString **); + uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *); + + pEnv->getObjectIdentifier(pEnv, ppOid, pUnoI); +} + +static void s_free(uno_Mapping * puno_Mapping) + SAL_THROW_EXTERN_C() +{ + Mapping * pMapping = static_cast<Mapping *>(puno_Mapping); + delete pMapping; +} +} + +Mapping::Mapping(uno_Environment * pFrom, + uno_Environment * pTo, + cppu::helper::purpenv::ProbeFun * probeFun, + void * pProbeContext +) + : m_from (pFrom), + m_to (pTo), + m_nCount (1), + m_probeFun(probeFun), + m_pContext(pProbeContext) +{ + SAL_INFO("cppu.purpenv", "LIFE: Mapping::Mapping(uno_Environment * pFrom, uno_Environment * pTo -> " << this); + + uno_Mapping::acquire = s_acquire; + uno_Mapping::release = s_release; + uno_Mapping::mapInterface = s_mapInterface; +} + +Mapping::~Mapping() +{ + SAL_INFO("cppu.purpenv", "LIFE: Mapping:~Mapping() -> " << this); +} + + +void Mapping::mapInterface( + uno_Interface ** ppOut, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr) +{ + OSL_ASSERT(ppOut && pTypeDescr); + if (*ppOut) + { + (*ppOut)->release(*ppOut); + *ppOut = nullptr; + } + + if (!pUnoI) + return; + + // get object id of uno interface to be wrapped + // need to enter environment because of potential "queryInterface" call + rtl_uString * pOId = nullptr; + uno_Environment_invoke(m_from.get(), s_getIdentifier_v, m_from.get(), &pOId, pUnoI); + OSL_ASSERT(pOId); + + // try to get any known interface from target environment + m_to.get()->pExtEnv->getRegisteredInterface(m_to.get()->pExtEnv, reinterpret_cast<void **>(ppOut), pOId, pTypeDescr); + + if (!*ppOut) // not yet there, register new proxy interface + { + // try to publish a new proxy (ref count initially 1) + uno_Interface * pProxy = new Proxy(this, + m_from.get(), + m_to.get(), + pUnoI, + pTypeDescr, + pOId, + m_probeFun, + m_pContext); + + // proxy may be exchanged during registration + m_to.get()->pExtEnv->registerProxyInterface(m_to.get()->pExtEnv, + reinterpret_cast<void **>(&pProxy), + Proxy_free, + pOId, + pTypeDescr); + + *ppOut = pProxy; + } + + rtl_uString_release(pOId); +} + + +void Mapping::acquire() +{ + if (osl_atomic_increment(&m_nCount) == 1) + { + uno_Mapping * pMapping = this; + + ::uno_registerMapping(&pMapping, s_free, m_from.get(), m_to.get(), nullptr); + } +} + +void Mapping::release() +{ + if (osl_atomic_decrement(&m_nCount) == 0) + ::uno_revokeMapping(this); +} + + +namespace cppu::helper::purpenv { + +void createMapping(uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo, + ProbeFun * probeFun, + void * pContext + ) +{ + *ppMapping = new Mapping(pFrom, pTo, probeFun, pContext); + + ::uno_registerMapping(ppMapping, s_free, pFrom, pTo, nullptr); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx b/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx new file mode 100644 index 000000000..f62241fe1 --- /dev/null +++ b/cppu/source/helper/purpenv/helper_purpenv_Proxy.cxx @@ -0,0 +1,503 @@ +/* -*- 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 "Proxy.hxx" + +#include <sal/log.hxx> +#include <uno/dispatcher.h> +#include <typelib/typedescription.hxx> + +using namespace com::sun::star; + +static bool relatesToInterface(typelib_TypeDescription * pTypeDescr) +{ + switch (pTypeDescr->eTypeClass) + { +// case typelib_TypeClass_TYPEDEF: + case typelib_TypeClass_SEQUENCE: + { + switch (reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_ANY: // might relate to interface + return true; + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType ); + bool bRel = relatesToInterface( pTD ); + TYPELIB_DANGER_RELEASE( pTD ); + return bRel; + } + default: + ; + } + return false; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + // ...optimized... to avoid getDescription() calls! + typelib_CompoundTypeDescription * pComp = reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr); + typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs; + for ( sal_Int32 nPos = pComp->nMembers; nPos--; ) + { + switch (pTypes[nPos]->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_ANY: // might relate to interface + return true; +// case typelib_TypeClass_TYPEDEF: + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( &pTD, pTypes[nPos] ); + bool bRel = relatesToInterface( pTD ); + TYPELIB_DANGER_RELEASE( pTD ); + if (bRel) + return true; + break; + } + default: + break; + } + } + if (pComp->pBaseTypeDescription) + return relatesToInterface( &pComp->pBaseTypeDescription->aBase ); + break; + } + case typelib_TypeClass_ANY: // might relate to interface + case typelib_TypeClass_INTERFACE: + return true; + + default: + ; + } + return false; +} + +extern "C" { static void s_Proxy_dispatch( + uno_Interface * pUnoI, + typelib_TypeDescription const * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException) + SAL_THROW_EXTERN_C() +{ + Proxy * pThis = static_cast<Proxy *>(pUnoI); + + typelib_MethodParameter param; + sal_Int32 nParams = 0; + typelib_MethodParameter * pParams = nullptr; + typelib_TypeDescriptionReference * pReturnTypeRef = nullptr; + // sal_Int32 nOutParams = 0; + + switch (pMemberType->eTypeClass) + { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (pReturn) + { + pReturnTypeRef = + reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>( + pMemberType)->pAttributeTypeRef; + nParams = 0; + pParams = nullptr; + } + else + { + param.pTypeRef = reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>( + pMemberType)->pAttributeTypeRef; + param.bIn = true; + param.bOut = false; + nParams = 1; + pParams = ¶m; + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription const * method_td = + reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType); + pReturnTypeRef = method_td->pReturnTypeRef; + nParams = method_td->nParams; + pParams = method_td->pParams; + break; + } + default: + OSL_FAIL( "### illegal member typeclass!" ); + abort(); + } + + pThis->dispatch( pReturnTypeRef, + pParams, + nParams, + pMemberType, + pReturn, + pArgs, + ppException ); +}} + +extern "C" void Proxy_free(SAL_UNUSED_PARAMETER uno_ExtEnvironment * /*pEnv*/, void * pProxy) SAL_THROW_EXTERN_C() +{ + Proxy * pThis = static_cast<Proxy * >(static_cast<uno_Interface *>(pProxy)); + delete pThis; +} + +extern "C" { +static void s_Proxy_acquire(uno_Interface * pUnoI) SAL_THROW_EXTERN_C() +{ + Proxy * pProxy = static_cast<Proxy *>(pUnoI); + pProxy->acquire(); +} + +static void s_Proxy_release(uno_Interface * pUnoI) SAL_THROW_EXTERN_C() +{ + Proxy * pProxy = static_cast<Proxy *>(pUnoI); + pProxy->release(); +} + +static void s_acquireAndRegister_v(va_list * pParam) +{ + uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *); + rtl_uString * pOid = va_arg(*pParam, rtl_uString *); + typelib_InterfaceTypeDescription * pTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *); + uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *); + + pUnoI->acquire(pUnoI); + pEnv->registerInterface(pEnv, reinterpret_cast<void **>(&pUnoI), pOid, pTypeDescr); +} +} + +Proxy::Proxy(uno::Mapping const & to_from, + uno_Environment * pTo, + uno_Environment * pFrom, + uno_Interface * pUnoI, + typelib_InterfaceTypeDescription * pTypeDescr, + OUString const & rOId, + cppu::helper::purpenv::ProbeFun * probeFun, + void * pProbeContext +) + : m_nRef (1), + m_from (pFrom), + m_to (pTo), + m_from_to (pFrom, pTo), + m_to_from (to_from), + m_pUnoI (pUnoI), + m_pTypeDescr (pTypeDescr), + m_aOId (rOId), + m_probeFun (probeFun), + m_pProbeContext(pProbeContext) +{ + SAL_INFO("cppu.purpenv", "LIFE: Proxy::Proxy(<>) -> " << this); + + typelib_typedescription_acquire(&m_pTypeDescr->aBase); + if (!m_pTypeDescr->aBase.bComplete) + typelib_typedescription_complete(reinterpret_cast<typelib_TypeDescription **>(&m_pTypeDescr)); + + OSL_ENSURE(m_pTypeDescr->aBase.bComplete, "### type is incomplete!"); + + uno_Environment_invoke(m_to.get(), s_acquireAndRegister_v, m_pUnoI, rOId.pData, pTypeDescr, m_to.get()); + + // uno_Interface + uno_Interface::acquire = s_Proxy_acquire; + uno_Interface::release = s_Proxy_release; + uno_Interface::pDispatcher = s_Proxy_dispatch; +} + +extern "C" { static void s_releaseAndRevoke_v(va_list * pParam) +{ + uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *); + uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *); + + pEnv->revokeInterface(pEnv, pUnoI); + pUnoI->release(pUnoI); +}} + +Proxy::~Proxy() +{ + SAL_INFO("cppu.purpenv", "LIFE: Proxy::~Proxy() -> " << this); + + uno_Environment_invoke(m_to.get(), s_releaseAndRevoke_v, m_to.get(), m_pUnoI); + + typelib_typedescription_release(&m_pTypeDescr->aBase); +} + +static uno::TypeDescription getAcquireMethod() +{ + typelib_TypeDescriptionReference * type_XInterface = + * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE); + + typelib_TypeDescription * pTXInterfaceDescr = nullptr; + TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface); + uno::TypeDescription acquire( + reinterpret_cast< typelib_InterfaceTypeDescription * >( + pTXInterfaceDescr)->ppAllMembers[1]); + TYPELIB_DANGER_RELEASE(pTXInterfaceDescr); + + return acquire; +} + +static uno::TypeDescription getReleaseMethod() +{ + typelib_TypeDescriptionReference * type_XInterface = + * typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE); + + typelib_TypeDescription * pTXInterfaceDescr = nullptr; + TYPELIB_DANGER_GET (&pTXInterfaceDescr, type_XInterface); + uno::TypeDescription release( + reinterpret_cast< typelib_InterfaceTypeDescription * >( + pTXInterfaceDescr)->ppAllMembers[2]); + TYPELIB_DANGER_RELEASE(pTXInterfaceDescr); + + return release; +} + +static uno::TypeDescription s_acquireMethod(getAcquireMethod()); +static uno::TypeDescription s_releaseMethod(getReleaseMethod()); + +void Proxy::acquire() +{ + if (m_probeFun) + m_probeFun(true, + this, + m_pProbeContext, + *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID), + nullptr, + 0, + s_acquireMethod.get(), + nullptr, + nullptr, + nullptr); + + if (osl_atomic_increment(&m_nRef) == 1) + { + // rebirth of proxy zombie + void * pThis = this; + m_from.get()->pExtEnv->registerProxyInterface(m_from.get()->pExtEnv, + &pThis, + Proxy_free, + m_aOId.pData, + m_pTypeDescr); + OSL_ASSERT(pThis == this); + } + + if (m_probeFun) + m_probeFun(false, + this, + m_pProbeContext, + *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID), + nullptr, + 0, + s_acquireMethod.get(), + nullptr, + nullptr, + nullptr); + +} + +void Proxy::release() +{ + cppu::helper::purpenv::ProbeFun * probeFun = m_probeFun; + void * pProbeContext = m_pProbeContext; + + if (m_probeFun) + m_probeFun(true, + this, + m_pProbeContext, + *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID), + nullptr, + 0, + s_releaseMethod.get(), + nullptr, + nullptr, + nullptr); + + if (osl_atomic_decrement(&m_nRef) == 0) + m_from.get()->pExtEnv->revokeInterface(m_from.get()->pExtEnv, this); + + if (probeFun) + probeFun(false, + this, + pProbeContext, + *typelib_static_type_getByTypeClass(typelib_TypeClass_VOID), + nullptr, + 0, + s_releaseMethod.get(), + nullptr, + nullptr, + nullptr); + +} + + +extern "C" { +static void s_type_destructData_v(va_list * pParam) +{ + void * ret = va_arg(*pParam, void *); + typelib_TypeDescriptionReference * pReturnTypeRef = va_arg(*pParam, typelib_TypeDescriptionReference *); + + uno_type_destructData(ret, pReturnTypeRef, nullptr); +} + +static void s_dispatcher_v(va_list * pParam) +{ + uno_Interface * pUnoI = va_arg(*pParam, uno_Interface *); + typelib_TypeDescription const * pMemberType = va_arg(*pParam, typelib_TypeDescription const *); + void * pReturn = va_arg(*pParam, void *); + void ** pArgs = va_arg(*pParam, void **); + uno_Any ** ppException = va_arg(*pParam, uno_Any **); + + pUnoI->pDispatcher(pUnoI, pMemberType, pReturn, pArgs, ppException); +} +} + +void Proxy::dispatch(typelib_TypeDescriptionReference * pReturnTypeRef, + typelib_MethodParameter * pParams, + sal_Int32 nParams, + typelib_TypeDescription const * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException) +{ + if (m_probeFun) + m_probeFun(true, + this, + m_pProbeContext, + pReturnTypeRef, + pParams, + nParams, + pMemberType, + pReturn, + pArgs, + ppException); + + void ** args = static_cast<void **>(alloca( sizeof (void *) * nParams )); + + typelib_TypeDescription * return_td = nullptr; + void * ret = pReturn; + if (pReturnTypeRef) + { + TYPELIB_DANGER_GET(&return_td, pReturnTypeRef); + + if (relatesToInterface(return_td)) + ret = alloca(return_td->nSize); + + TYPELIB_DANGER_RELEASE(return_td); + } + + for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos) + { + typelib_MethodParameter const & param = pParams[nPos]; + typelib_TypeDescription * td = nullptr; + TYPELIB_DANGER_GET( &td, param.pTypeRef ); + if (relatesToInterface(td)) + { + args[nPos] = alloca(td->nSize); + if (param.bIn) + { + uno_copyAndConvertData(args[nPos], pArgs[nPos], td, m_from_to.get()); + } + } + else + { + args[nPos] = pArgs[nPos]; + } + TYPELIB_DANGER_RELEASE( td ); + } + + uno_Any exc_data; + uno_Any * exc = &exc_data; + + // do the UNO call... + uno_Environment_invoke(m_to.get(), s_dispatcher_v, m_pUnoI, pMemberType, ret, args, &exc); + + if (exc == nullptr) + { + for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos) + { + if (args[nPos] != pArgs[nPos]) + { + typelib_MethodParameter const & param = pParams[nPos]; + if (param.bOut) + { + if (param.bIn) // is inout + { + uno_type_destructData(pArgs[nPos], param.pTypeRef, nullptr); + } + uno_type_copyAndConvertData(pArgs[ nPos ], + args[ nPos ], + param.pTypeRef, + m_to_from.get()); + } + uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0); + } + } + if (ret != pReturn) + { + uno_type_copyAndConvertData(pReturn, + ret, + pReturnTypeRef, + m_to_from.get()); + + uno_Environment_invoke(m_to.get(), s_type_destructData_v, ret, pReturnTypeRef, 0); + } + + *ppException = nullptr; + } + else // exception occurred + { + for (sal_Int32 nPos = 0; nPos < nParams; ++ nPos) + { + if (args[nPos] != pArgs[nPos]) + { + typelib_MethodParameter const & param = pParams[nPos]; + if (param.bIn) + { + uno_Environment_invoke(m_to.get(), s_type_destructData_v, args[nPos], param.pTypeRef, 0); + } + } + } + + uno_type_any_constructAndConvert(*ppException, + exc->pData, + exc->pType, + m_to_from.get()); + + // FIXME: need to destruct in m_to + uno_any_destruct(exc, nullptr); + } + + if (m_probeFun) + m_probeFun(false, + this, + m_pProbeContext, + pReturnTypeRef, + pParams, + nParams, + pMemberType, + pReturn, + pArgs, + ppException); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/current.cxx b/cppu/source/threadpool/current.cxx new file mode 100644 index 000000000..7dbfc9050 --- /dev/null +++ b/cppu/source/threadpool/current.cxx @@ -0,0 +1,265 @@ +/* -*- 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 <rtl/byteseq.h> +#include <osl/thread.h> +#include <osl/mutex.hxx> + +#include <uno/current_context.h> +#include <uno/environment.hxx> +#include <uno/mapping.hxx> +#include <typelib/typedescription.h> + +#include "current.hxx" + + +using namespace ::osl; +using namespace ::rtl; +using namespace ::cppu; +using namespace ::com::sun::star::uno; + +namespace cppu +{ + +static typelib_InterfaceTypeDescription * get_type_XCurrentContext() +{ + static typelib_InterfaceTypeDescription* s_type_XCurrentContext = []() { + OUString sTypeName("com.sun.star.uno.XCurrentContext"); + typelib_InterfaceTypeDescription* pTD = nullptr; + typelib_TypeDescriptionReference* pMembers[1] = { nullptr }; + OUString sMethodName0("com.sun.star.uno.XCurrentContext::getValueByName"); + typelib_typedescriptionreference_new(&pMembers[0], typelib_TypeClass_INTERFACE_METHOD, + sMethodName0.pData); + typelib_typedescription_newInterface( + &pTD, sTypeName.pData, 0, 0, 0, 0, 0, + *typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE), 1, pMembers); + + typelib_typedescription_register(reinterpret_cast<typelib_TypeDescription**>(&pTD)); + typelib_typedescriptionreference_release(pMembers[0]); + + typelib_InterfaceMethodTypeDescription* pMethod = nullptr; + typelib_Parameter_Init aParameters[1]; + OUString sParamName0("Name"); + OUString sParamType0("string"); + aParameters[0].pParamName = sParamName0.pData; + aParameters[0].eTypeClass = typelib_TypeClass_STRING; + aParameters[0].pTypeName = sParamType0.pData; + aParameters[0].bIn = true; + aParameters[0].bOut = false; + rtl_uString* pExceptions[1]; + OUString sExceptionName0("com.sun.star.uno.RuntimeException"); + pExceptions[0] = sExceptionName0.pData; + OUString sReturnType0("any"); + typelib_typedescription_newInterfaceMethod(&pMethod, 3, false, sMethodName0.pData, + typelib_TypeClass_ANY, sReturnType0.pData, 1, + aParameters, 1, pExceptions); + typelib_typedescription_register(reinterpret_cast<typelib_TypeDescription**>(&pMethod)); + typelib_typedescription_release(&pMethod->aBase.aBase); + // another static ref: + ++reinterpret_cast<typelib_TypeDescription*>(pTD)->nStaticRefCount; + return pTD; + }(); + + return s_type_XCurrentContext; +} + +namespace { + +class ThreadKey +{ + bool _bInit; + oslThreadKey _hThreadKey; + oslThreadKeyCallbackFunction _pCallback; + +public: + oslThreadKey getThreadKey() + { + if (! _bInit) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! _bInit) + { + _hThreadKey = ::osl_createThreadKey( _pCallback ); + _bInit = true; + } + } + return _hThreadKey; + } + + explicit ThreadKey( oslThreadKeyCallbackFunction pCallback ) + : _bInit(false) + , _hThreadKey(nullptr) + , _pCallback(pCallback) + { + } + + ~ThreadKey() + { + if (_bInit) + { + ::osl_destroyThreadKey( _hThreadKey ); + } + } +}; + +} + +extern "C" { + +static void delete_IdContainer( void * p ) +{ + if (!p) + return; + + IdContainer * pId = static_cast< IdContainer * >( p ); + if (pId->pCurrentContext) + { + (*pId->pCurrentContextEnv->releaseInterface)( + pId->pCurrentContextEnv, pId->pCurrentContext ); + (*pId->pCurrentContextEnv->aBase.release)( + &pId->pCurrentContextEnv->aBase ); + } + if (pId->bInit) + { + ::rtl_byte_sequence_release( pId->pLocalThreadId ); + ::rtl_byte_sequence_release( pId->pCurrentId ); + } + delete pId; +} + +} + +IdContainer * getIdContainer() +{ + static ThreadKey s_key( delete_IdContainer ); + oslThreadKey aKey = s_key.getThreadKey(); + + IdContainer * pId = static_cast< IdContainer * >( ::osl_getThreadKeyData( aKey ) ); + if (! pId) + { + pId = new IdContainer; + pId->pCurrentContext = nullptr; + pId->pCurrentContextEnv = nullptr; + pId->bInit = false; + ::osl_setThreadKeyData( aKey, pId ); + } + return pId; +} + +} + + +extern "C" sal_Bool SAL_CALL uno_setCurrentContext( + void * pCurrentContext, + rtl_uString * pEnvTypeName, void * pEnvContext ) + SAL_THROW_EXTERN_C() +{ + IdContainer * pId = getIdContainer(); + OSL_ASSERT( pId ); + + // free old one + if (pId->pCurrentContext) + { + (*pId->pCurrentContextEnv->releaseInterface)( + pId->pCurrentContextEnv, pId->pCurrentContext ); + (*pId->pCurrentContextEnv->aBase.release)( + &pId->pCurrentContextEnv->aBase ); + pId->pCurrentContextEnv = nullptr; + + pId->pCurrentContext = nullptr; + } + + if (pCurrentContext) + { + uno_Environment * pEnv = nullptr; + ::uno_getEnvironment( &pEnv, pEnvTypeName, pEnvContext ); + OSL_ASSERT( pEnv && pEnv->pExtEnv ); + if (pEnv) + { + if (pEnv->pExtEnv) + { + pId->pCurrentContextEnv = pEnv->pExtEnv; + (*pId->pCurrentContextEnv->acquireInterface)( + pId->pCurrentContextEnv, pCurrentContext ); + pId->pCurrentContext = pCurrentContext; + } + else + { + (*pEnv->release)( pEnv ); + return false; + } + } + else + { + return false; + } + } + return true; +} + +extern "C" sal_Bool SAL_CALL uno_getCurrentContext( + void ** ppCurrentContext, rtl_uString * pEnvTypeName, void * pEnvContext ) + SAL_THROW_EXTERN_C() +{ + IdContainer * pId = getIdContainer(); + OSL_ASSERT( pId ); + + Environment target_env; + + // release inout parameter + if (*ppCurrentContext) + { + target_env = Environment(OUString(pEnvTypeName), pEnvContext); + OSL_ASSERT( target_env.is() ); + if (! target_env.is()) + return false; + uno_ExtEnvironment * pEnv = target_env.get()->pExtEnv; + OSL_ASSERT( nullptr != pEnv ); + if (nullptr == pEnv) + return false; + (*pEnv->releaseInterface)( pEnv, *ppCurrentContext ); + + *ppCurrentContext = nullptr; + } + + // case: null-ref + if (nullptr == pId->pCurrentContext) + return true; + + if (! target_env.is()) + { + target_env = Environment(OUString(pEnvTypeName), pEnvContext); + OSL_ASSERT( target_env.is() ); + if (! target_env.is()) + return false; + } + + Mapping mapping(&pId->pCurrentContextEnv->aBase, target_env.get()); + OSL_ASSERT( mapping.is() ); + if (! mapping.is()) + return false; + + mapping.mapInterface(ppCurrentContext, pId->pCurrentContext, ::cppu::get_type_XCurrentContext() ); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/current.hxx b/cppu/source/threadpool/current.hxx new file mode 100644 index 000000000..ea26851dd --- /dev/null +++ b/cppu/source/threadpool/current.hxx @@ -0,0 +1,47 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_THREADPOOL_CURRENT_HXX +#define INCLUDED_CPPU_SOURCE_THREADPOOL_CURRENT_HXX + +#include <sal/config.h> + +#include <sal/types.h> + +struct _uno_ExtEnvironment; + +namespace cppu +{ +struct IdContainer +{ + void * pCurrentContext; + _uno_ExtEnvironment * pCurrentContextEnv; + + bool bInit; + sal_Sequence * pLocalThreadId; + sal_Int32 nRefCountOfCurrentId; + sal_Sequence * pCurrentId; +}; + +IdContainer * getIdContainer(); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/jobqueue.cxx b/cppu/source/threadpool/jobqueue.cxx new file mode 100644 index 000000000..b4974fdc1 --- /dev/null +++ b/cppu/source/threadpool/jobqueue.cxx @@ -0,0 +1,191 @@ +/* -*- 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 "jobqueue.hxx" +#include "threadpool.hxx" + +#include <osl/diagnose.h> + +using namespace ::osl; + +namespace cppu_threadpool { + + JobQueue::JobQueue() : + m_nToDo( 0 ), + m_bSuspended( false ), + m_DisposedCallerAdmin( DisposedCallerAdmin::getInstance() ) + { + } + + void JobQueue::add( void *pThreadSpecificData, RequestFun * doRequest ) + { + MutexGuard guard( m_mutex ); + Job job = { pThreadSpecificData , doRequest }; + m_lstJob.push_back( job ); + if( ! m_bSuspended ) + { + m_cndWait.set(); + } + m_nToDo ++; + } + + void *JobQueue::enter( sal_Int64 nDisposeId , bool bReturnWhenNoJob ) + { + void *pReturn = nullptr; + { + // synchronize with the dispose calls + MutexGuard guard( m_mutex ); + if( m_DisposedCallerAdmin->isDisposed( nDisposeId ) ) + { + return nullptr; + } + m_lstCallstack.push_front( nDisposeId ); + } + + + while( true ) + { + if( bReturnWhenNoJob ) + { + MutexGuard guard( m_mutex ); + if( m_lstJob.empty() ) + { + break; + } + } + + m_cndWait.wait(); + + struct Job job={nullptr,nullptr}; + { + // synchronize with add and dispose calls + MutexGuard guard( m_mutex ); + + if( 0 == m_lstCallstack.front() ) + { + // disposed ! + if (!m_lstJob.empty() && m_lstJob.front().doRequest == nullptr) { + // If this thread was waiting for a remote response, that response may or + // may not have been enqueued; if it has not been enqueued, there cannot be + // another enqueued response, so it is always correct to remove any enqueued + // response here: + m_lstJob.pop_front(); + } + if( m_lstJob.empty() + && (m_lstCallstack.empty() + || m_lstCallstack.front() != 0) ) + { + m_cndWait.reset(); + } + break; + } + + OSL_ASSERT( ! m_lstJob.empty() ); + if( ! m_lstJob.empty() ) + { + job = m_lstJob.front(); + m_lstJob.pop_front(); + } + if( m_lstJob.empty() + && (m_lstCallstack.empty() || m_lstCallstack.front() != 0) ) + { + m_cndWait.reset(); + } + } + + if( job.doRequest ) + { + job.doRequest( job.pThreadSpecificData ); + MutexGuard guard( m_mutex ); + m_nToDo --; + } + else + { + pReturn = job.pThreadSpecificData; + MutexGuard guard( m_mutex ); + m_nToDo --; + break; + } + } + + { + // synchronize with the dispose calls + MutexGuard guard( m_mutex ); + m_lstCallstack.pop_front(); + } + + return pReturn; + } + + void JobQueue::dispose( sal_Int64 nDisposeId ) + { + MutexGuard guard( m_mutex ); + for( auto& rId : m_lstCallstack ) + { + if( rId == nDisposeId ) + { + rId = 0; + } + } + + if( !m_lstCallstack.empty() && ! m_lstCallstack.front() ) + { + // The thread is waiting for a disposed pCallerId, let it go + m_cndWait.set(); + } + } + + void JobQueue::suspend() + { + MutexGuard guard( m_mutex ); + m_bSuspended = true; + } + + void JobQueue::resume() + { + MutexGuard guard( m_mutex ); + m_bSuspended = false; + if( ! m_lstJob.empty() ) + { + m_cndWait.set(); + } + } + + bool JobQueue::isEmpty() const + { + MutexGuard guard( m_mutex ); + return m_lstJob.empty(); + } + + bool JobQueue::isCallstackEmpty() const + { + MutexGuard guard( m_mutex ); + return m_lstCallstack.empty(); + } + + bool JobQueue::isBusy() const + { + MutexGuard guard( m_mutex ); + return m_nToDo > 0; + } + + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/jobqueue.hxx b/cppu/source/threadpool/jobqueue.hxx new file mode 100644 index 000000000..abfdfa19d --- /dev/null +++ b/cppu/source/threadpool/jobqueue.hxx @@ -0,0 +1,73 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_THREADPOOL_JOBQUEUE_HXX +#define INCLUDED_CPPU_SOURCE_THREADPOOL_JOBQUEUE_HXX + +#include <deque> +#include <memory> +#include <sal/types.h> + +#include <osl/conditn.hxx> +#include <osl/mutex.hxx> + +namespace cppu_threadpool +{ + extern "C" typedef void (RequestFun)(void *); + + struct Job + { + void *pThreadSpecificData; + RequestFun * doRequest; + }; + + class DisposedCallerAdmin; + typedef std::shared_ptr<DisposedCallerAdmin> DisposedCallerAdminHolder; + + class JobQueue + { + public: + JobQueue(); + + void add( void *pThreadSpecificData, RequestFun * doRequest ); + + void *enter( sal_Int64 nDisposeId , bool bReturnWhenNoJob = false ); + void dispose( sal_Int64 nDisposeId ); + + void suspend(); + void resume(); + + bool isEmpty() const; + bool isCallstackEmpty() const; + bool isBusy() const; + + private: + mutable ::osl::Mutex m_mutex; + std::deque < struct Job > m_lstJob; + std::deque<sal_Int64> m_lstCallstack; + sal_Int32 m_nToDo; + bool m_bSuspended; + osl::Condition m_cndWait; + DisposedCallerAdminHolder m_DisposedCallerAdmin; + }; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/thread.cxx b/cppu/source/threadpool/thread.cxx new file mode 100644 index 000000000..2af33eff7 --- /dev/null +++ b/cppu/source/threadpool/thread.cxx @@ -0,0 +1,199 @@ +/* -*- 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 <algorithm> +#include <cstdlib> +#include <osl/diagnose.h> +#include <uno/threadpool.h> +#include <sal/log.hxx> + +#include "thread.hxx" +#include "jobqueue.hxx" +#include "threadpool.hxx" + +using namespace osl; +using namespace rtl; + +namespace cppu_threadpool { + + + ThreadAdmin::ThreadAdmin(): m_disposed(false) {} + + ThreadAdmin::~ThreadAdmin() + { + SAL_WARN_IF(m_deque.size(), "cppu.threadpool", m_deque.size() << "Threads left"); + } + + bool ThreadAdmin::add( rtl::Reference< ORequestThread > const & p ) + { + MutexGuard aGuard( m_mutex ); + if( m_disposed ) + { + return false; + } + m_deque.push_back( p ); + return true; + } + + void ThreadAdmin::remove_locked( rtl::Reference< ORequestThread > const & p ) + { + m_deque.erase(std::find( m_deque.begin(), m_deque.end(), p ), m_deque.end()); + } + + void ThreadAdmin::remove( rtl::Reference< ORequestThread > const & p ) + { + MutexGuard aGuard( m_mutex ); + remove_locked( p ); + } + + void ThreadAdmin::join() + { + { + MutexGuard aGuard( m_mutex ); + m_disposed = true; + } + for (;;) + { + rtl::Reference< ORequestThread > pCurrent; + { + MutexGuard aGuard( m_mutex ); + if( m_deque.empty() ) + { + break; + } + pCurrent = m_deque.front(); + m_deque.pop_front(); + } + if (pCurrent->getIdentifier() + != osl::Thread::getCurrentIdentifier()) + { + pCurrent->join(); + } + } + } + + + ORequestThread::ORequestThread( ThreadPoolHolder const &aThreadPool, + JobQueue *pQueue, + const ByteSequence &aThreadId, + bool bAsynchron ) + : m_aThreadPool( aThreadPool ) + , m_pQueue( pQueue ) + , m_aThreadId( aThreadId ) + , m_bAsynchron( bAsynchron ) + {} + + ORequestThread::~ORequestThread() {} + + void ORequestThread::setTask( JobQueue *pQueue, + const ByteSequence &aThreadId, + bool bAsynchron ) + { + m_pQueue = pQueue; + m_aThreadId = aThreadId; + m_bAsynchron = bAsynchron; + } + + bool ORequestThread::launch() + { + // Assumption is that osl::Thread::create returns normally with a true + // return value iff it causes osl::Thread::run to start executing: + acquire(); + ThreadAdmin & rThreadAdmin = m_aThreadPool->getThreadAdmin(); + osl::ClearableMutexGuard g(rThreadAdmin.m_mutex); + if (!rThreadAdmin.add( this )) { + return false; + } + try { + if (!create()) { + std::abort(); + } + } catch (...) { + rThreadAdmin.remove_locked( this ); + g.clear(); + release(); + throw; + } + return true; + } + + void ORequestThread::onTerminated() + { + m_aThreadPool->getThreadAdmin().remove( this ); + release(); + } + + void ORequestThread::run() + { + osl_setThreadName("cppu_threadpool::ORequestThread"); + + try + { + while ( m_pQueue ) + { + if( ! m_bAsynchron ) + { + if ( !uno_bindIdToCurrentThread( m_aThreadId.getHandle() ) ) + { + OSL_ASSERT( false ); + } + } + + while( ! m_pQueue->isEmpty() ) + { + // Note : Oneways should not get a disposable disposeid, + // It does not make sense to dispose a call in this state. + // That's way we put it a disposeid, that can't be used otherwise. + m_pQueue->enter( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(this)), + true ); + + if( m_pQueue->isEmpty() ) + { + m_aThreadPool->revokeQueue( m_aThreadId , m_bAsynchron ); + // Note : revokeQueue might have failed because m_pQueue.isEmpty() + // may be false (race). + } + } + + delete m_pQueue; + m_pQueue = nullptr; + + if( ! m_bAsynchron ) + { + uno_releaseIdFromCurrentThread(); + } + + m_aThreadPool->waitInPool( this ); + } + } + catch (...) + { + // Work around the problem that onTerminated is not called if run + // throws an exception: + onTerminated(); + throw; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/thread.hxx b/cppu/source/threadpool/thread.hxx new file mode 100644 index 000000000..e9258a97b --- /dev/null +++ b/cppu/source/threadpool/thread.hxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_THREADPOOL_THREAD_HXX +#define INCLUDED_CPPU_SOURCE_THREADPOOL_THREAD_HXX + +#include <osl/thread.hxx> +#include <sal/types.h> +#include <salhelper/simplereferenceobject.hxx> + +#include "threadpool.hxx" + +namespace cppu_threadpool { + + class JobQueue; + + + // private thread class for the threadpool + + class ORequestThread: + public salhelper::SimpleReferenceObject, public osl::Thread + { + public: + ORequestThread( ThreadPoolHolder const &aThreadPool, + JobQueue * , + const ::rtl::ByteSequence &aThreadId, + bool bAsynchron ); + virtual ~ORequestThread() override; + + void setTask( JobQueue * , const ::rtl::ByteSequence & aThreadId , bool bAsynchron ); + + bool launch(); + + static void * operator new(std::size_t size) + { return SimpleReferenceObject::operator new(size); } + + static void operator delete(void * pointer) + { SimpleReferenceObject::operator delete(pointer); } + + private: + virtual void SAL_CALL run() override; + virtual void SAL_CALL onTerminated() override; + + ThreadPoolHolder m_aThreadPool; + JobQueue *m_pQueue; + ::rtl::ByteSequence m_aThreadId; + bool m_bAsynchron; + }; + +} // end cppu_threadpool + + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/threadident.cxx b/cppu/source/threadpool/threadident.cxx new file mode 100644 index 000000000..544acc7af --- /dev/null +++ b/cppu/source/threadpool/threadident.cxx @@ -0,0 +1,125 @@ +/* -*- 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 <osl/thread.hxx> +#include <osl/diagnose.h> + +#include <rtl/process.h> +#include <rtl/byteseq.hxx> + +#include <uno/threadpool.h> + +#include "current.hxx" + + +using namespace ::std; +using namespace ::osl; +using namespace ::cppu; + + +static void createLocalId( sal_Sequence **ppThreadId ) +{ + rtl_byte_sequence_constructNoDefault( ppThreadId , 4 + 16 ); + sal_uInt32 id = osl::Thread::getCurrentIdentifier(); + (*ppThreadId)->elements[0] = id & 0xFF; + (*ppThreadId)->elements[1] = (id >> 8) & 0xFF; + (*ppThreadId)->elements[2] = (id >> 16) & 0xFF; + (*ppThreadId)->elements[3] = (id >> 24) & 0xFF; + rtl_getGlobalProcessId( reinterpret_cast<sal_uInt8 *>(&(*ppThreadId)->elements[4]) ); +} + + +extern "C" void SAL_CALL +uno_getIdOfCurrentThread( sal_Sequence **ppThreadId ) + SAL_THROW_EXTERN_C() +{ + IdContainer * p = getIdContainer(); + if( ! p->bInit ) + { + // first time, that the thread enters the bridge + createLocalId( ppThreadId ); + + // TODO + // note : this is a leak ! + p->pLocalThreadId = *ppThreadId; + p->pCurrentId = *ppThreadId; + p->nRefCountOfCurrentId = 1; + rtl_byte_sequence_acquire( p->pLocalThreadId ); + rtl_byte_sequence_acquire( p->pCurrentId ); + p->bInit = true; + } + else + { + p->nRefCountOfCurrentId ++; + if( *ppThreadId ) + { + rtl_byte_sequence_release( *ppThreadId ); + } + *ppThreadId = p->pCurrentId; + rtl_byte_sequence_acquire( *ppThreadId ); + } +} + + +extern "C" void SAL_CALL uno_releaseIdFromCurrentThread() + SAL_THROW_EXTERN_C() +{ + IdContainer *p = getIdContainer(); + OSL_ASSERT( p ); + OSL_ASSERT( p->bInit ); + OSL_ASSERT( p->nRefCountOfCurrentId ); + + p->nRefCountOfCurrentId --; + if( ! p->nRefCountOfCurrentId && (p->pLocalThreadId != p->pCurrentId) ) + { + rtl_byte_sequence_assign( &(p->pCurrentId) , p->pLocalThreadId ); + } +} + +extern "C" sal_Bool SAL_CALL uno_bindIdToCurrentThread( sal_Sequence *pThreadId ) + SAL_THROW_EXTERN_C() +{ + IdContainer *p = getIdContainer(); + if( ! p->bInit ) + { + p->pLocalThreadId = nullptr; + createLocalId( &(p->pLocalThreadId) ); + p->nRefCountOfCurrentId = 1; + p->pCurrentId = pThreadId; + rtl_byte_sequence_acquire( p->pCurrentId ); + p->bInit = true; + } + else + { + OSL_ASSERT( 0 == p->nRefCountOfCurrentId ); + if( 0 == p->nRefCountOfCurrentId ) + { + rtl_byte_sequence_assign(&( p->pCurrentId ), pThreadId ); + p->nRefCountOfCurrentId ++; + } + else + { + return false; + } + + } + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/threadpool.cxx b/cppu/source/threadpool/threadpool.cxx new file mode 100644 index 000000000..d11268b85 --- /dev/null +++ b/cppu/source/threadpool/threadpool.cxx @@ -0,0 +1,487 @@ +/* -*- 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 <cassert> +#include <chrono> +#include <algorithm> +#include <unordered_map> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <rtl/instance.hxx> +#include <sal/log.hxx> + +#include <uno/threadpool.h> + +#include "threadpool.hxx" +#include "thread.hxx" + +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; + +namespace cppu_threadpool +{ + WaitingThread::WaitingThread( + rtl::Reference<ORequestThread> const & theThread): thread(theThread) + {} + + namespace { + + struct theDisposedCallerAdmin : + public rtl::StaticWithInit< DisposedCallerAdminHolder, theDisposedCallerAdmin > + { + DisposedCallerAdminHolder operator () () { + return std::make_shared<DisposedCallerAdmin>(); + } + }; + + } + + DisposedCallerAdminHolder const & DisposedCallerAdmin::getInstance() + { + return theDisposedCallerAdmin::get(); + } + + DisposedCallerAdmin::~DisposedCallerAdmin() + { + SAL_WARN_IF( !m_vector.empty(), "cppu.threadpool", "DisposedCallerList : " << m_vector.size() << " left"); + } + + void DisposedCallerAdmin::dispose( sal_Int64 nDisposeId ) + { + MutexGuard guard( m_mutex ); + m_vector.push_back( nDisposeId ); + } + + void DisposedCallerAdmin::destroy( sal_Int64 nDisposeId ) + { + MutexGuard guard( m_mutex ); + m_vector.erase(std::remove(m_vector.begin(), m_vector.end(), nDisposeId), m_vector.end()); + } + + bool DisposedCallerAdmin::isDisposed( sal_Int64 nDisposeId ) + { + MutexGuard guard( m_mutex ); + return (std::find(m_vector.begin(), m_vector.end(), nDisposeId) != m_vector.end()); + } + + + ThreadPool::ThreadPool() : + m_DisposedCallerAdmin( DisposedCallerAdmin::getInstance() ) + { + } + + ThreadPool::~ThreadPool() + { + SAL_WARN_IF( m_mapQueue.size(), "cppu.threadpool", "ThreadIdHashMap: " << m_mapQueue.size() << " left"); + } + + void ThreadPool::dispose( sal_Int64 nDisposeId ) + { + m_DisposedCallerAdmin->dispose( nDisposeId ); + + MutexGuard guard( m_mutex ); + for (auto const& item : m_mapQueue) + { + if( item.second.first ) + { + item.second.first->dispose( nDisposeId ); + } + if( item.second.second ) + { + item.second.second->dispose( nDisposeId ); + } + } + } + + void ThreadPool::destroy( sal_Int64 nDisposeId ) + { + m_DisposedCallerAdmin->destroy( nDisposeId ); + } + + /****************** + * This methods lets the thread wait a certain amount of time. If within this timespan + * a new request comes in, this thread is reused. This is done only to improve performance, + * it is not required for threadpool functionality. + ******************/ + void ThreadPool::waitInPool( rtl::Reference< ORequestThread > const & pThread ) + { + WaitingThread waitingThread(pThread); + { + MutexGuard guard( m_mutexWaitingThreadList ); + m_dequeThreads.push_front( &waitingThread ); + } + + // let the thread wait 2 seconds + waitingThread.condition.wait( std::chrono::seconds(2) ); + + { + MutexGuard guard ( m_mutexWaitingThreadList ); + if( waitingThread.thread.is() ) + { + // thread wasn't reused, remove it from the list + WaitingThreadDeque::iterator ii = find( + m_dequeThreads.begin(), m_dequeThreads.end(), &waitingThread ); + OSL_ASSERT( ii != m_dequeThreads.end() ); + m_dequeThreads.erase( ii ); + } + } + } + + void ThreadPool::joinWorkers() + { + { + MutexGuard guard( m_mutexWaitingThreadList ); + for (auto const& thread : m_dequeThreads) + { + // wake the threads up + thread->condition.set(); + } + } + m_aThreadAdmin.join(); + } + + bool ThreadPool::createThread( JobQueue *pQueue , + const ByteSequence &aThreadId, + bool bAsynchron ) + { + { + // Can a thread be reused ? + MutexGuard guard( m_mutexWaitingThreadList ); + if( ! m_dequeThreads.empty() ) + { + // inform the thread and let it go + struct WaitingThread *pWaitingThread = m_dequeThreads.back(); + pWaitingThread->thread->setTask( pQueue , aThreadId , bAsynchron ); + pWaitingThread->thread = nullptr; + + // remove from list + m_dequeThreads.pop_back(); + + // let the thread go + pWaitingThread->condition.set(); + return true; + } + } + + rtl::Reference pThread( + new ORequestThread( this, pQueue , aThreadId, bAsynchron) ); + return pThread->launch(); + } + + bool ThreadPool::revokeQueue( const ByteSequence &aThreadId, bool bAsynchron ) + { + MutexGuard guard( m_mutex ); + + ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId ); + OSL_ASSERT( ii != m_mapQueue.end() ); + + if( bAsynchron ) + { + if( ! (*ii).second.second->isEmpty() ) + { + // another thread has put something into the queue + return false; + } + + (*ii).second.second = nullptr; + if( (*ii).second.first ) + { + // all oneway request have been processed, now + // synchronous requests may go on + (*ii).second.first->resume(); + } + } + else + { + if( ! (*ii).second.first->isEmpty() ) + { + // another thread has put something into the queue + return false; + } + (*ii).second.first = nullptr; + } + + if( nullptr == (*ii).second.first && nullptr == (*ii).second.second ) + { + m_mapQueue.erase( ii ); + } + + return true; + } + + + bool ThreadPool::addJob( + const ByteSequence &aThreadId , + bool bAsynchron, + void *pThreadSpecificData, + RequestFun * doRequest ) + { + bool bCreateThread = false; + JobQueue *pQueue = nullptr; + { + MutexGuard guard( m_mutex ); + + ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId ); + + if( ii == m_mapQueue.end() ) + { + m_mapQueue[ aThreadId ] = pair < JobQueue * , JobQueue * > ( nullptr , nullptr ); + ii = m_mapQueue.find( aThreadId ); + OSL_ASSERT( ii != m_mapQueue.end() ); + } + + if( bAsynchron ) + { + if( ! (*ii).second.second ) + { + (*ii).second.second = new JobQueue(); + bCreateThread = true; + } + pQueue = (*ii).second.second; + } + else + { + if( ! (*ii).second.first ) + { + (*ii).second.first = new JobQueue(); + bCreateThread = true; + } + pQueue = (*ii).second.first; + + if( (*ii).second.second && ( (*ii).second.second->isBusy() ) ) + { + pQueue->suspend(); + } + } + pQueue->add( pThreadSpecificData , doRequest ); + } + + return !bCreateThread || createThread( pQueue , aThreadId , bAsynchron); + } + + void ThreadPool::prepare( const ByteSequence &aThreadId ) + { + MutexGuard guard( m_mutex ); + + ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId ); + + if( ii == m_mapQueue.end() ) + { + JobQueue *p = new JobQueue(); + m_mapQueue[ aThreadId ] = pair< JobQueue * , JobQueue * > ( p , nullptr ); + } + else if( nullptr == (*ii).second.first ) + { + (*ii).second.first = new JobQueue(); + } + } + + void * ThreadPool::enter( const ByteSequence & aThreadId , sal_Int64 nDisposeId ) + { + JobQueue *pQueue = nullptr; + { + MutexGuard guard( m_mutex ); + + ThreadIdHashMap::iterator ii = m_mapQueue.find( aThreadId ); + + OSL_ASSERT( ii != m_mapQueue.end() ); + pQueue = (*ii).second.first; + } + + OSL_ASSERT( pQueue ); + void *pReturn = pQueue->enter( nDisposeId ); + + if( pQueue->isCallstackEmpty() ) + { + if( revokeQueue( aThreadId , false) ) + { + // remove queue + delete pQueue; + } + } + return pReturn; + } +} + +// All uno_ThreadPool handles in g_pThreadpoolHashSet with overlapping life +// spans share one ThreadPool instance. When g_pThreadpoolHashSet becomes empty +// (within the last uno_threadpool_destroy) all worker threads spawned by that +// ThreadPool instance are joined (which implies that uno_threadpool_destroy +// must never be called from a worker thread); afterwards, the next call to +// uno_threadpool_create (if any) will lead to a new ThreadPool instance. + +using namespace cppu_threadpool; + +namespace { + +struct uno_ThreadPool_Equal +{ + bool operator () ( const uno_ThreadPool &a , const uno_ThreadPool &b ) const + { + return a == b; + } +}; + +struct uno_ThreadPool_Hash +{ + std::size_t operator () ( const uno_ThreadPool &a ) const + { + return reinterpret_cast<std::size_t>( a ); + } +}; + +} + +typedef std::unordered_map< uno_ThreadPool, ThreadPoolHolder, uno_ThreadPool_Hash, uno_ThreadPool_Equal > ThreadpoolHashSet; + +static ThreadpoolHashSet *g_pThreadpoolHashSet; + +struct _uno_ThreadPool +{ + sal_Int32 dummy; +}; + +namespace { + +ThreadPoolHolder getThreadPool( uno_ThreadPool hPool ) +{ + MutexGuard guard( Mutex::getGlobalMutex() ); + assert( g_pThreadpoolHashSet != nullptr ); + ThreadpoolHashSet::iterator i( g_pThreadpoolHashSet->find(hPool) ); + assert( i != g_pThreadpoolHashSet->end() ); + return i->second; +} + +} + +extern "C" uno_ThreadPool SAL_CALL +uno_threadpool_create() SAL_THROW_EXTERN_C() +{ + MutexGuard guard( Mutex::getGlobalMutex() ); + ThreadPoolHolder p; + if( ! g_pThreadpoolHashSet ) + { + g_pThreadpoolHashSet = new ThreadpoolHashSet; + p = new ThreadPool; + } + else + { + assert( !g_pThreadpoolHashSet->empty() ); + p = g_pThreadpoolHashSet->begin()->second; + } + + // Just ensure that the handle is unique in the process (via heap) + uno_ThreadPool h = new struct _uno_ThreadPool; + g_pThreadpoolHashSet->emplace( h, p ); + return h; +} + +extern "C" void SAL_CALL +uno_threadpool_attach( uno_ThreadPool hPool ) SAL_THROW_EXTERN_C() +{ + sal_Sequence *pThreadId = nullptr; + uno_getIdOfCurrentThread( &pThreadId ); + getThreadPool( hPool )->prepare( pThreadId ); + rtl_byte_sequence_release( pThreadId ); + uno_releaseIdFromCurrentThread(); +} + +extern "C" void SAL_CALL +uno_threadpool_enter( uno_ThreadPool hPool , void **ppJob ) + SAL_THROW_EXTERN_C() +{ + sal_Sequence *pThreadId = nullptr; + uno_getIdOfCurrentThread( &pThreadId ); + *ppJob = + getThreadPool( hPool )->enter( + pThreadId, + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(hPool)) ); + rtl_byte_sequence_release( pThreadId ); + uno_releaseIdFromCurrentThread(); +} + +extern "C" void SAL_CALL +uno_threadpool_detach(SAL_UNUSED_PARAMETER uno_ThreadPool) SAL_THROW_EXTERN_C() +{ + // we might do here some tidying up in case a thread called attach but never detach +} + +extern "C" void SAL_CALL +uno_threadpool_putJob( + uno_ThreadPool hPool, + sal_Sequence *pThreadId, + void *pJob, + void ( SAL_CALL * doRequest ) ( void *pThreadSpecificData ), + sal_Bool bIsOneway ) SAL_THROW_EXTERN_C() +{ + if (!getThreadPool(hPool)->addJob( pThreadId, bIsOneway, pJob ,doRequest )) + { + SAL_WARN( + "cppu.threadpool", + "uno_threadpool_putJob in parallel with uno_threadpool_destroy"); + } +} + +extern "C" void SAL_CALL +uno_threadpool_dispose( uno_ThreadPool hPool ) SAL_THROW_EXTERN_C() +{ + getThreadPool(hPool)->dispose( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(hPool)) ); +} + +extern "C" void SAL_CALL +uno_threadpool_destroy( uno_ThreadPool hPool ) SAL_THROW_EXTERN_C() +{ + ThreadPoolHolder p( getThreadPool(hPool) ); + p->destroy( + sal::static_int_cast< sal_Int64 >( + reinterpret_cast< sal_IntPtr >(hPool)) ); + + bool empty; + { + OSL_ASSERT( g_pThreadpoolHashSet ); + + MutexGuard guard( Mutex::getGlobalMutex() ); + + ThreadpoolHashSet::iterator ii = g_pThreadpoolHashSet->find( hPool ); + OSL_ASSERT( ii != g_pThreadpoolHashSet->end() ); + g_pThreadpoolHashSet->erase( ii ); + delete hPool; + + empty = g_pThreadpoolHashSet->empty(); + if( empty ) + { + delete g_pThreadpoolHashSet; + g_pThreadpoolHashSet = nullptr; + } + } + + if( empty ) + { + p->joinWorkers(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/threadpool/threadpool.hxx b/cppu/source/threadpool/threadpool.hxx new file mode 100644 index 000000000..85188fc52 --- /dev/null +++ b/cppu/source/threadpool/threadpool.hxx @@ -0,0 +1,163 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_THREADPOOL_THREADPOOL_HXX +#define INCLUDED_CPPU_SOURCE_THREADPOOL_THREADPOOL_HXX + +#include <vector> +#include <unordered_map> + +#include <osl/conditn.hxx> + +#include <rtl/byteseq.hxx> +#include <rtl/ref.hxx> +#include <salhelper/simplereferenceobject.hxx> + +#include "jobqueue.hxx" + + +namespace cppu_threadpool { + class ORequestThread; + + struct EqualThreadId + { + bool operator () ( const ::rtl::ByteSequence &a , const ::rtl::ByteSequence &b ) const + { + return a == b; + } + }; + + struct HashThreadId + { + sal_Int32 operator () ( const ::rtl::ByteSequence &a ) const + { + if( a.getLength() >= 4 ) + { + return *reinterpret_cast<sal_Int32 const *>(a.getConstArray()); + } + return 0; + } + }; + + typedef std::unordered_map + < + ::rtl::ByteSequence, // ThreadID + std::pair < JobQueue * , JobQueue * >, + HashThreadId, + EqualThreadId + > ThreadIdHashMap; + + struct WaitingThread + { + osl::Condition condition; + rtl::Reference< ORequestThread > thread; + + explicit WaitingThread( + rtl::Reference<ORequestThread> const & theThread); + }; + + typedef std::deque< struct ::cppu_threadpool::WaitingThread * > WaitingThreadDeque; + + class DisposedCallerAdmin; + typedef std::shared_ptr<DisposedCallerAdmin> DisposedCallerAdminHolder; + + class DisposedCallerAdmin + { + public: + ~DisposedCallerAdmin(); + + static DisposedCallerAdminHolder const & getInstance(); + + void dispose( sal_Int64 nDisposeId ); + void destroy( sal_Int64 nDisposeId ); + bool isDisposed( sal_Int64 nDisposeId ); + + private: + ::osl::Mutex m_mutex; + std::vector< sal_Int64 > m_vector; + }; + + class ThreadAdmin + { + public: + ThreadAdmin(); + ~ThreadAdmin (); + + bool add( rtl::Reference< ORequestThread > const & ); + void remove( rtl::Reference< ORequestThread > const & ); + void join(); + + void remove_locked( rtl::Reference< ORequestThread > const & ); + ::osl::Mutex m_mutex; + + private: + std::deque< rtl::Reference< ORequestThread > > m_deque; + bool m_disposed; + }; + + class ThreadPool; + typedef rtl::Reference<ThreadPool> ThreadPoolHolder; + + class ThreadPool: public salhelper::SimpleReferenceObject + { + public: + ThreadPool(); + virtual ~ThreadPool() override; + + void dispose( sal_Int64 nDisposeId ); + void destroy( sal_Int64 nDisposeId ); + + bool addJob( const ::rtl::ByteSequence &aThreadId, + bool bAsynchron, + void *pThreadSpecificData, + RequestFun * doRequest ); + + void prepare( const ::rtl::ByteSequence &aThreadId ); + void * enter( const ::rtl::ByteSequence &aThreadId, sal_Int64 nDisposeId ); + + /******** + * @return true, if queue could be successfully revoked. + ********/ + bool revokeQueue( const ::rtl::ByteSequence & aThreadId , bool bAsynchron ); + + void waitInPool( rtl::Reference< ORequestThread > const & pThread ); + + void joinWorkers(); + + ThreadAdmin & getThreadAdmin() { return m_aThreadAdmin; } + + private: + bool createThread( JobQueue *pQueue, const ::rtl::ByteSequence &aThreadId, bool bAsynchron); + + + ThreadIdHashMap m_mapQueue; + ::osl::Mutex m_mutex; + + ::osl::Mutex m_mutexWaitingThreadList; + WaitingThreadDeque m_dequeThreads; + + DisposedCallerAdminHolder m_DisposedCallerAdmin; + ThreadAdmin m_aThreadAdmin; + }; + +} // end namespace cppu_threadpool + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/typelib/static_types.cxx b/cppu/source/typelib/static_types.cxx new file mode 100644 index 000000000..6ff99b1f4 --- /dev/null +++ b/cppu/source/typelib/static_types.cxx @@ -0,0 +1,552 @@ +/* -*- 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 <algorithm> +#include <cassert> + +#include <osl/mutex.hxx> +#include <rtl/ustring.hxx> +#include <rtl/instance.hxx> + +#include <typelib/typedescription.h> +#include "typelib.hxx" + + +using namespace osl; + +extern "C" +{ + + +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + +namespace { + +/** + * The double member determines the alignment. + * Under OS2 and MS-Windows the Alignment is min( 8, sizeof( type ) ). + * The alignment of a structure is min( 8, sizeof( max basic type ) ), the greatest basic type + * determines the alignment. + */ +struct AlignSize_Impl +{ + sal_Int16 nInt16; +#ifdef AIX + //double: doubleword aligned if -qalign=natural/-malign=natural + //which isn't the default ABI. Otherwise word aligned, While a long long int + //is always doubleword aligned, so use that instead. + sal_Int64 dDouble; +#else + double dDouble; +#endif +}; + +} + +#ifdef _WIN32 +#pragma pack(pop) +#endif + +// the value of the maximal alignment +static const sal_Int32 nMaxAlignment = static_cast<sal_Int32>( reinterpret_cast<sal_Size>(&reinterpret_cast<AlignSize_Impl *>(16)->dDouble) - 16); + +static sal_Int32 adjustAlignment( sal_Int32 nRequestedAlignment ) +{ + if( nRequestedAlignment > nMaxAlignment ) + nRequestedAlignment = nMaxAlignment; + return nRequestedAlignment; +} + +/** + * Calculate the new size of the struktur. + */ +static sal_Int32 newAlignedSize( + sal_Int32 OldSize, sal_Int32 ElementSize, sal_Int32 NeededAlignment ) +{ + NeededAlignment = adjustAlignment( NeededAlignment ); + return (OldSize + NeededAlignment -1) / NeededAlignment * NeededAlignment + ElementSize; +} + + +namespace +{ + struct typelib_StaticInitMutex : public rtl::Static< Mutex, typelib_StaticInitMutex > {}; +} + +// !for NOT REALLY WEAK TYPES only! +static typelib_TypeDescriptionReference * igetTypeByName( rtl_uString const * pTypeName ) +{ + typelib_TypeDescriptionReference * pRef = nullptr; + ::typelib_typedescriptionreference_getByName( &pRef, pTypeName ); + if (pRef && pRef->pType && pRef->pType->pWeakRef) // found initialized td + { + return pRef; + } + return nullptr; +} + +extern "C" +{ + +typelib_TypeDescriptionReference ** SAL_CALL typelib_static_type_getByTypeClass( + typelib_TypeClass eTypeClass ) + SAL_THROW_EXTERN_C() +{ + static typelib_TypeDescriptionReference * s_aTypes[] = { + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr }; + + if (! s_aTypes[eTypeClass]) + { + MutexGuard aGuard( typelib_StaticInitMutex::get() ); + if (! s_aTypes[eTypeClass]) + { + static const char * s_aTypeNames[] = { + "void", "char", "boolean", "byte", + "short", "unsigned short", "long", "unsigned long", + "hyper", "unsigned hyper", "float", "double", + "string", "type", "any" }; + + switch (eTypeClass) + { + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_INTERFACE: + { + // type + if (! s_aTypes[typelib_TypeClass_TYPE]) + { + OUString sTypeName("type"); + ::typelib_typedescriptionreference_new( + &s_aTypes[typelib_TypeClass_TYPE], typelib_TypeClass_TYPE, sTypeName.pData ); + // another static ref: + ++s_aTypes[typelib_TypeClass_TYPE]->nStaticRefCount; + } + // any + if (! s_aTypes[typelib_TypeClass_ANY]) + { + OUString sTypeName("any"); + ::typelib_typedescriptionreference_new( + &s_aTypes[typelib_TypeClass_ANY], typelib_TypeClass_ANY, sTypeName.pData ); + // another static ref: + ++s_aTypes[typelib_TypeClass_ANY]->nStaticRefCount; + } + // string + if (! s_aTypes[typelib_TypeClass_STRING]) + { + OUString sTypeName("string"); + ::typelib_typedescriptionreference_new( + &s_aTypes[typelib_TypeClass_STRING], typelib_TypeClass_STRING, sTypeName.pData ); + // another static ref: + ++s_aTypes[typelib_TypeClass_STRING]->nStaticRefCount; + } + // XInterface + if (! s_aTypes[typelib_TypeClass_INTERFACE]) + { + OUString sTypeName("com.sun.star.uno.XInterface"); + + typelib_InterfaceTypeDescription * pTD = nullptr; + + typelib_TypeDescriptionReference * pMembers[3] = { nullptr,nullptr,nullptr }; + OUString sMethodName0("com.sun.star.uno.XInterface::queryInterface"); + ::typelib_typedescriptionreference_new( + &pMembers[0], typelib_TypeClass_INTERFACE_METHOD, sMethodName0.pData ); + OUString sMethodName1("com.sun.star.uno.XInterface::acquire"); + ::typelib_typedescriptionreference_new( + &pMembers[1], typelib_TypeClass_INTERFACE_METHOD, sMethodName1.pData ); + OUString sMethodName2("com.sun.star.uno.XInterface::release"); + ::typelib_typedescriptionreference_new( + &pMembers[2], typelib_TypeClass_INTERFACE_METHOD, sMethodName2.pData ); + + ::typelib_typedescription_newInterface( + &pTD, sTypeName.pData, 0, 0, 0, 0, 0, nullptr, 3, pMembers ); + + ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription **>(&pTD) ); + s_aTypes[typelib_TypeClass_INTERFACE] = pTD->aBase.pWeakRef; + ::typelib_typedescriptionreference_acquire( + s_aTypes[typelib_TypeClass_INTERFACE] ); + // another static ref: + ++s_aTypes[typelib_TypeClass_INTERFACE]->nStaticRefCount; + ::typelib_typedescription_release( &pTD->aBase ); + + ::typelib_typedescriptionreference_release( pMembers[0] ); + ::typelib_typedescriptionreference_release( pMembers[1] ); + ::typelib_typedescriptionreference_release( pMembers[2] ); + // Exception + assert( ! s_aTypes[typelib_TypeClass_EXCEPTION] ); + { + typelib_TypeDescription * pTD1 = nullptr; + OUString sTypeName1("com.sun.star.uno.Exception"); + + typelib_CompoundMember_Init aMembers[2]; + OUString sMemberType0("string"); + OUString sMemberName0("Message"); + aMembers[0].eTypeClass = typelib_TypeClass_STRING; + aMembers[0].pTypeName = sMemberType0.pData; + aMembers[0].pMemberName = sMemberName0.pData; + OUString sMemberType1("com.sun.star.uno.XInterface"); + OUString sMemberName1("Context"); + aMembers[1].eTypeClass = typelib_TypeClass_INTERFACE; + aMembers[1].pTypeName = sMemberType1.pData; + aMembers[1].pMemberName = sMemberName1.pData; + + ::typelib_typedescription_new( + &pTD1, typelib_TypeClass_EXCEPTION, sTypeName1.pData, nullptr, 2, aMembers ); + typelib_typedescription_register( &pTD1 ); + s_aTypes[typelib_TypeClass_EXCEPTION] = pTD1->pWeakRef; + typelib_typedescriptionreference_acquire( + s_aTypes[typelib_TypeClass_EXCEPTION]); + // another static ref: + ++s_aTypes[typelib_TypeClass_EXCEPTION]->nStaticRefCount; + // RuntimeException + OUString sTypeName2("com.sun.star.uno.RuntimeException"); + ::typelib_typedescription_new( + &pTD1, typelib_TypeClass_EXCEPTION, sTypeName2.pData, s_aTypes[typelib_TypeClass_EXCEPTION], 0, nullptr ); + ::typelib_typedescription_register( &pTD1 ); + ::typelib_typedescription_release( pTD1 ); + } + // XInterface members + typelib_InterfaceMethodTypeDescription * pMethod = nullptr; + typelib_Parameter_Init aParameters[1]; + OUString sParamName0("aType"); + OUString sParamType0("type"); + aParameters[0].pParamName = sParamName0.pData; + aParameters[0].eTypeClass = typelib_TypeClass_TYPE; + aParameters[0].pTypeName = sParamType0.pData; + aParameters[0].bIn = true; + aParameters[0].bOut = false; + rtl_uString * pExceptions[1]; + OUString sExceptionName0("com.sun.star.uno.RuntimeException"); + pExceptions[0] = sExceptionName0.pData; + OUString sReturnType0("any"); + typelib_typedescription_newInterfaceMethod( + &pMethod, 0, false, sMethodName0.pData, + typelib_TypeClass_ANY, sReturnType0.pData, + 1, aParameters, 1, pExceptions ); + ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription**>(&pMethod) ); + + OUString sReturnType1("void"); + ::typelib_typedescription_newInterfaceMethod( + &pMethod, 1, true, sMethodName1.pData, + typelib_TypeClass_VOID, sReturnType1.pData, 0, nullptr, 0, nullptr ); + ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription**>(&pMethod) ); + + ::typelib_typedescription_newInterfaceMethod( + &pMethod, 2, true, sMethodName2.pData, + typelib_TypeClass_VOID, sReturnType1.pData, + 0, nullptr, 0, nullptr ); + ::typelib_typedescription_register( reinterpret_cast<typelib_TypeDescription**>(&pMethod) ); + ::typelib_typedescription_release( &pMethod->aBase.aBase ); + } + break; + } + default: + { + OUString aTypeName( OUString::createFromAscii( s_aTypeNames[eTypeClass] ) ); + ::typelib_typedescriptionreference_new( &s_aTypes[eTypeClass], eTypeClass, aTypeName.pData ); + // another static ref: + ++s_aTypes[eTypeClass]->nStaticRefCount; + } + } + } + } + return &s_aTypes[eTypeClass]; +} + +void SAL_CALL typelib_static_type_init( + typelib_TypeDescriptionReference ** ppRef, + typelib_TypeClass eTypeClass, const char * pTypeName ) + SAL_THROW_EXTERN_C() +{ + if (! *ppRef) + { + MutexGuard aGuard( typelib_StaticInitMutex::get() ); + if (! *ppRef) + { + OUString aTypeName( OUString::createFromAscii( pTypeName ) ); + ::typelib_typedescriptionreference_new( ppRef, eTypeClass, aTypeName.pData ); + + assert(*ppRef && "coverity[var_deref_op] - shouldn't be possible"); + ++((*ppRef)->nStaticRefCount); + } + } +} + +void SAL_CALL typelib_static_sequence_type_init( + typelib_TypeDescriptionReference ** ppRef, + typelib_TypeDescriptionReference * pElementType ) + SAL_THROW_EXTERN_C() +{ + if ( *ppRef) + return; + + MutexGuard aGuard( typelib_StaticInitMutex::get() ); + if ( *ppRef) + return; + + OUString aTypeName = "[]" + OUString::unacquired(&pElementType->pTypeName); + + static_assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_SEQUENCE) ); + *ppRef = igetTypeByName( aTypeName.pData ); + if (!*ppRef) + { + typelib_TypeDescription * pReg = nullptr; + ::typelib_typedescription_new( + &pReg, typelib_TypeClass_SEQUENCE, + aTypeName.pData, pElementType, 0, nullptr ); + + ::typelib_typedescription_register( &pReg ); + *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + assert( *ppRef == pReg->pWeakRef ); + } + // another static ref: + ++((*ppRef)->nStaticRefCount); +} + + +namespace { + +void init( + typelib_TypeDescriptionReference ** ppRef, + typelib_TypeClass eTypeClass, const char * pTypeName, + typelib_TypeDescriptionReference * pBaseType, + sal_Int32 nMembers, typelib_TypeDescriptionReference ** ppMembers, + sal_Bool const * pParameterizedTypes) +{ + assert( eTypeClass == typelib_TypeClass_STRUCT || eTypeClass == typelib_TypeClass_EXCEPTION ); + + if ( *ppRef) + return; + + MutexGuard aGuard( typelib_StaticInitMutex::get() ); + if ( *ppRef) + return; + + assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(eTypeClass) ); + OUString aTypeName( OUString::createFromAscii( pTypeName ) ); + *ppRef = igetTypeByName( aTypeName.pData ); + if (!*ppRef) + { + typelib_CompoundTypeDescription * pComp = nullptr; + ::typelib_typedescription_newEmpty( + reinterpret_cast<typelib_TypeDescription **>(&pComp), eTypeClass, aTypeName.pData ); + + sal_Int32 nOffset = 0; + if (pBaseType) + { + ::typelib_typedescriptionreference_getDescription( + reinterpret_cast<typelib_TypeDescription **>(&pComp->pBaseTypeDescription), pBaseType ); + assert( pComp->pBaseTypeDescription ); + nOffset = pComp->pBaseTypeDescription->aBase.nSize; + assert( newAlignedSize( 0, pComp->pBaseTypeDescription->aBase.nSize, pComp->pBaseTypeDescription->aBase.nAlignment ) == pComp->pBaseTypeDescription->aBase.nSize ); // unexpected offset + } + + if (nMembers) + { + pComp->nMembers = nMembers; + pComp->pMemberOffsets = new sal_Int32[ nMembers ]; + pComp->ppTypeRefs = new typelib_TypeDescriptionReference *[ nMembers ]; + if (pParameterizedTypes != nullptr) { + reinterpret_cast< typelib_StructTypeDescription * >( + pComp)->pParameterizedTypes + = new sal_Bool[nMembers]; + } + for ( sal_Int32 i = 0 ; i < nMembers; ++i ) + { + pComp->ppTypeRefs[i] = ppMembers[i]; + ::typelib_typedescriptionreference_acquire( + pComp->ppTypeRefs[i] ); + // write offset + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( &pTD, pComp->ppTypeRefs[i] ); + assert( pTD->nSize ); // void member? + nOffset = newAlignedSize( nOffset, pTD->nSize, pTD->nAlignment ); + pComp->pMemberOffsets[i] = nOffset - pTD->nSize; + TYPELIB_DANGER_RELEASE( pTD ); + + if (pParameterizedTypes != nullptr) { + reinterpret_cast< typelib_StructTypeDescription * >( + pComp)->pParameterizedTypes[i] + = pParameterizedTypes[i]; + } + } + } + + typelib_TypeDescription * pReg = &pComp->aBase; + pReg->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + // sizeof(void) not allowed + pReg->nSize = ::typelib_typedescription_getAlignedUnoSize( pReg, 0, pReg->nAlignment ); + pReg->nAlignment = adjustAlignment( pReg->nAlignment ); + pReg->bComplete = false; + + ::typelib_typedescription_register( &pReg ); + *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + assert( *ppRef == pReg->pWeakRef ); + } + // another static ref: + ++((*ppRef)->nStaticRefCount); +} + +} + +void SAL_CALL typelib_static_compound_type_init( + typelib_TypeDescriptionReference ** ppRef, + typelib_TypeClass eTypeClass, const char * pTypeName, + typelib_TypeDescriptionReference * pBaseType, + sal_Int32 nMembers, typelib_TypeDescriptionReference ** ppMembers ) + SAL_THROW_EXTERN_C() +{ + init(ppRef, eTypeClass, pTypeName, pBaseType, nMembers, ppMembers, nullptr); +} + +void SAL_CALL typelib_static_struct_type_init( + typelib_TypeDescriptionReference ** ppRef, const char * pTypeName, + typelib_TypeDescriptionReference * pBaseType, + sal_Int32 nMembers, typelib_TypeDescriptionReference ** ppMembers, + sal_Bool const * pParameterizedTypes ) + SAL_THROW_EXTERN_C() +{ + init( + ppRef, typelib_TypeClass_STRUCT, pTypeName, pBaseType, nMembers, + ppMembers, pParameterizedTypes); +} + +void SAL_CALL typelib_static_interface_type_init( + typelib_TypeDescriptionReference ** ppRef, + const char * pTypeName, + typelib_TypeDescriptionReference * pBaseType ) + SAL_THROW_EXTERN_C() +{ + // coverity[callee_ptr_arith] - not a bug + typelib_static_mi_interface_type_init( + ppRef, pTypeName, pBaseType == nullptr ? 0 : 1, &pBaseType); +} + +void SAL_CALL typelib_static_mi_interface_type_init( + typelib_TypeDescriptionReference ** ppRef, + const char * pTypeName, + sal_Int32 nBaseTypes, + typelib_TypeDescriptionReference ** ppBaseTypes ) + SAL_THROW_EXTERN_C() +{ + if ( *ppRef) + return; + + MutexGuard aGuard( typelib_StaticInitMutex::get() ); + if ( *ppRef) + return; + + static_assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_INTERFACE) ); + OUString aTypeName( OUString::createFromAscii( pTypeName ) ); + *ppRef = igetTypeByName( aTypeName.pData ); + if (!*ppRef) + { + typelib_InterfaceTypeDescription * pIface = nullptr; + ::typelib_typedescription_newEmpty( + reinterpret_cast<typelib_TypeDescription **>(&pIface), typelib_TypeClass_INTERFACE, aTypeName.pData ); + + pIface->nBaseTypes = std::max< sal_Int32 >(nBaseTypes, 1); + pIface->ppBaseTypes = new typelib_InterfaceTypeDescription *[ + pIface->nBaseTypes]; + if (nBaseTypes > 0) + { + for (sal_Int32 i = 0; i < nBaseTypes; ++i) { + pIface->ppBaseTypes[i] = nullptr; + ::typelib_typedescriptionreference_getDescription( + reinterpret_cast<typelib_TypeDescription **>(&pIface->ppBaseTypes[i]), ppBaseTypes[i] ); + assert( pIface->ppBaseTypes[i] ); + } + } + else + { + pIface->ppBaseTypes[0] = nullptr; + ::typelib_typedescriptionreference_getDescription( + reinterpret_cast<typelib_TypeDescription **>(&pIface->ppBaseTypes[0]), + * ::typelib_static_type_getByTypeClass( typelib_TypeClass_INTERFACE ) ); + assert( pIface->ppBaseTypes[0] ); + } + pIface->pBaseTypeDescription = pIface->ppBaseTypes[0]; + typelib_typedescription_acquire( + &pIface->pBaseTypeDescription->aBase); + + typelib_TypeDescription * pReg = &pIface->aBase; + pReg->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + // sizeof(void) not allowed + pReg->nSize = ::typelib_typedescription_getAlignedUnoSize( pReg, 0, pReg->nAlignment ); + + pReg->nAlignment = adjustAlignment( pReg->nAlignment ); + pReg->bComplete = false; + + ::typelib_typedescription_register( &pReg ); + *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + assert( *ppRef == pReg->pWeakRef ); + } + // another static ref: + ++((*ppRef)->nStaticRefCount); +} + + +void SAL_CALL typelib_static_enum_type_init( + typelib_TypeDescriptionReference ** ppRef, + const char * pTypeName, + sal_Int32 nDefaultValue ) + SAL_THROW_EXTERN_C() +{ + if ( *ppRef) + return; + + MutexGuard aGuard( typelib_StaticInitMutex::get() ); + if ( *ppRef) + return; + + static_assert( ! TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_ENUM) ); + OUString aTypeName( OUString::createFromAscii( pTypeName ) ); + *ppRef = igetTypeByName( aTypeName.pData ); + if (!*ppRef) + { + typelib_TypeDescription * pReg = nullptr; + ::typelib_typedescription_newEmpty( + &pReg, typelib_TypeClass_ENUM, aTypeName.pData ); + typelib_EnumTypeDescription * pEnum = reinterpret_cast<typelib_EnumTypeDescription *>(pReg); + + pEnum->nDefaultEnumValue = nDefaultValue; + + pReg->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + // sizeof(void) not allowed + pReg->nSize = ::typelib_typedescription_getAlignedUnoSize( pReg, 0, pReg->nAlignment ); + pReg->nAlignment = ::adjustAlignment( pReg->nAlignment ); + pReg->bComplete = false; + + ::typelib_typedescription_register( &pReg ); + *ppRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pReg); + assert( *ppRef == pReg->pWeakRef ); + } + // another static ref: + ++((*ppRef)->nStaticRefCount); +} + +} // extern "C" + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/typelib/typelib.cxx b/cppu/source/typelib/typelib.cxx new file mode 100644 index 000000000..e16c2eb90 --- /dev/null +++ b/cppu/source/typelib/typelib.cxx @@ -0,0 +1,2461 @@ +/* -*- 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 <algorithm> +#include <unordered_map> +#include <cassert> +#include <list> +#include <set> +#include <utility> +#include <vector> +#include <memory> + +#include <stdlib.h> +#include <string.h> +#include <sal/log.hxx> +#include <osl/interlck.h> +#include <osl/mutex.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/instance.hxx> +#include <osl/diagnose.h> +#include <typelib/typedescription.h> +#include <uno/any2.h> +#include "typelib.hxx" + +using namespace std; +using namespace osl; + +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + +namespace { + +/** + * The double member determines the alignment. + * Under OS2 and MS-Windows the Alignment is min( 8, sizeof( type ) ). + * The alignment of a structure is min( 8, sizeof( max basic type ) ), the greatest basic type + * determines the alignment. + */ +struct AlignSize_Impl +{ + sal_Int16 nInt16; +#ifdef AIX + //double: doubleword aligned if -qalign=natural/-malign=natural + //which isn't the default ABI. Otherwise word aligned, While a long long int + //is always doubleword aligned, so use that instead. + sal_Int64 dDouble; +#else + double dDouble; +#endif +}; + +} + +#ifdef _WIN32 +#pragma pack(pop) +#endif + +// the value of the maximal alignment +static const sal_Int32 nMaxAlignment = static_cast<sal_Int32>( reinterpret_cast<sal_Size>(&reinterpret_cast<AlignSize_Impl *>(16)->dDouble) - 16); + +static sal_Int32 adjustAlignment( sal_Int32 nRequestedAlignment ) +{ + if( nRequestedAlignment > nMaxAlignment ) + nRequestedAlignment = nMaxAlignment; + return nRequestedAlignment; +} + +/** + * Calculate the new size of the structure. + */ +static sal_Int32 newAlignedSize( + sal_Int32 OldSize, sal_Int32 ElementSize, sal_Int32 NeededAlignment ) +{ + NeededAlignment = adjustAlignment( NeededAlignment ); + return (OldSize + NeededAlignment -1) / NeededAlignment * NeededAlignment + ElementSize; +} + +static sal_Int32 getDescriptionSize( typelib_TypeClass eTypeClass ) +{ + OSL_ASSERT( typelib_TypeClass_TYPEDEF != eTypeClass ); + + sal_Int32 nSize; + // The reference is the description + // if the description is empty, then it must be filled with + // the new description + switch( eTypeClass ) + { + case typelib_TypeClass_SEQUENCE: + nSize = sal_Int32(sizeof( typelib_IndirectTypeDescription )); + break; + + case typelib_TypeClass_STRUCT: + nSize = sal_Int32(sizeof( typelib_StructTypeDescription )); + break; + + case typelib_TypeClass_EXCEPTION: + nSize = sal_Int32(sizeof( typelib_CompoundTypeDescription )); + break; + + case typelib_TypeClass_ENUM: + nSize = sal_Int32(sizeof( typelib_EnumTypeDescription )); + break; + + case typelib_TypeClass_INTERFACE: + nSize = sal_Int32(sizeof( typelib_InterfaceTypeDescription )); + break; + + case typelib_TypeClass_INTERFACE_METHOD: + nSize = sal_Int32(sizeof( typelib_InterfaceMethodTypeDescription )); + break; + + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + nSize = sal_Int32(sizeof( typelib_InterfaceAttributeTypeDescription )); + break; + + default: + nSize = sal_Int32(sizeof( typelib_TypeDescription )); + } + return nSize; +} + +namespace { + +struct equalStr_Impl +{ + bool operator()(const sal_Unicode * const & s1, const sal_Unicode * const & s2) const + { return 0 == rtl_ustr_compare( s1, s2 ); } +}; + + +struct hashStr_Impl +{ + size_t operator()(const sal_Unicode * const & s) const + { return rtl_ustr_hashCode( s ); } +}; + +} + +// Heavy hack, the const sal_Unicode * is hold by the typedescription reference +typedef std::unordered_map< const sal_Unicode *, typelib_TypeDescriptionReference *, + hashStr_Impl, equalStr_Impl > WeakMap_Impl; + +typedef pair< void *, typelib_typedescription_Callback > CallbackEntry; +typedef list< CallbackEntry > CallbackSet_Impl; +typedef list< typelib_TypeDescription * > TypeDescriptionList_Impl; + +// # of cached elements +static sal_Int32 nCacheSize = 256; + +namespace { + +struct TypeDescriptor_Init_Impl +{ + //sal_Bool bDesctructorCalled; + // all type description references + std::unique_ptr<WeakMap_Impl> pWeakMap; + // all type description callbacks + std::unique_ptr<CallbackSet_Impl> pCallbacks; + // A cache to hold descriptions + std::unique_ptr<TypeDescriptionList_Impl> pCache; + // The mutex to guard all type library accesses + std::unique_ptr<Mutex> pMutex; + + inline Mutex & getMutex(); + + inline void callChain( typelib_TypeDescription ** ppRet, rtl_uString * pName ); + +#if OSL_DEBUG_LEVEL > 0 + // only for debugging + sal_Int32 nTypeDescriptionCount; + sal_Int32 nCompoundTypeDescriptionCount; + sal_Int32 nIndirectTypeDescriptionCount; + sal_Int32 nEnumTypeDescriptionCount; + sal_Int32 nInterfaceMethodTypeDescriptionCount; + sal_Int32 nInterfaceAttributeTypeDescriptionCount; + sal_Int32 nInterfaceTypeDescriptionCount; + sal_Int32 nTypeDescriptionReferenceCount; +#endif + + TypeDescriptor_Init_Impl() +#if OSL_DEBUG_LEVEL > 0 + : nTypeDescriptionCount(0), nCompoundTypeDescriptionCount(0), + nIndirectTypeDescriptionCount(0), + nEnumTypeDescriptionCount(0), + nInterfaceMethodTypeDescriptionCount(0), + nInterfaceAttributeTypeDescriptionCount(0), + nInterfaceTypeDescriptionCount(0), nTypeDescriptionReferenceCount(0) +#endif + {} + + ~TypeDescriptor_Init_Impl(); +}; + +} + +inline Mutex & TypeDescriptor_Init_Impl::getMutex() +{ + if( !pMutex ) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if( !pMutex ) + pMutex.reset(new Mutex()); + } + return * pMutex; +} + +inline void TypeDescriptor_Init_Impl::callChain( + typelib_TypeDescription ** ppRet, rtl_uString * pName ) +{ + assert(ppRet != nullptr); + assert(*ppRet == nullptr); + if (pCallbacks) + { + for( const CallbackEntry & rEntry : *pCallbacks ) + { + (*rEntry.second)( rEntry.first, ppRet, pName ); + if( *ppRet ) + return; + } + } +} + + +TypeDescriptor_Init_Impl::~TypeDescriptor_Init_Impl() +{ + if( pCache ) + { + for( typelib_TypeDescription* pItem : *pCache ) + { + typelib_typedescription_release( pItem ); + } + } + + if( pWeakMap ) + { + std::vector< typelib_TypeDescriptionReference * > ppTDR; + ppTDR.reserve( pWeakMap->size() ); + + // save all weak references + for( const auto& rEntry : *pWeakMap ) + { + ppTDR.push_back( rEntry.second ); + typelib_typedescriptionreference_acquire( ppTDR.back() ); + } + + for( typelib_TypeDescriptionReference * pTDR : ppTDR ) + { + OSL_ASSERT( pTDR->nRefCount > pTDR->nStaticRefCount ); + pTDR->nRefCount -= pTDR->nStaticRefCount; + + if( pTDR->pType && !pTDR->pType->bOnDemand ) + { + pTDR->pType->bOnDemand = true; + typelib_typedescription_release( pTDR->pType ); + } + typelib_typedescriptionreference_release( pTDR ); + } + +#if defined SAL_LOG_INFO + for( const auto& rEntry : *pWeakMap ) + { + typelib_TypeDescriptionReference * pTDR = rEntry.second; + if (pTDR) + { + OString aTypeName( OUStringToOString( pTDR->pTypeName, RTL_TEXTENCODING_ASCII_US ) ); + SAL_INFO("cppu.typelib", "remaining type: " << aTypeName << "; ref count = " << pTDR->nRefCount); + } + else + { + SAL_INFO("cppu.typelib", "remaining null type entry!?"); + } + } +#endif + } +#if OSL_DEBUG_LEVEL > 0 + SAL_INFO_IF( nTypeDescriptionCount, "cppu.typelib", "nTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nCompoundTypeDescriptionCount, "cppu.typelib", "nCompoundTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nIndirectTypeDescriptionCount, "cppu.typelib", "nIndirectTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nEnumTypeDescriptionCount, "cppu.typelib", "nEnumTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nInterfaceMethodTypeDescriptionCount, "cppu.typelib", "nInterfaceMethodTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nInterfaceAttributeTypeDescriptionCount, "cppu.typelib", "nInterfaceAttributeTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nInterfaceTypeDescriptionCount, "cppu.typelib", "nInterfaceTypeDescriptionCount is not zero" ); + SAL_INFO_IF( nTypeDescriptionReferenceCount, "cppu.typelib", "nTypeDescriptionReferenceCount is not zero" ); +#endif + + SAL_INFO_IF( pCallbacks && !pCallbacks->empty(), "cppu.typelib", "pCallbacks is not NULL or empty" ); + pCallbacks.reset(); +}; + +namespace { struct Init : public rtl::Static< TypeDescriptor_Init_Impl, Init > {}; } + +extern "C" void SAL_CALL typelib_typedescription_registerCallback( + void * pContext, typelib_typedescription_Callback pCallback ) + SAL_THROW_EXTERN_C() +{ + // todo mt safe: guard is no solution, can not acquire while calling callback! + TypeDescriptor_Init_Impl &rInit = Init::get(); +// OslGuard aGuard( rInit.getMutex() ); + if( !rInit.pCallbacks ) + rInit.pCallbacks.reset(new CallbackSet_Impl); + rInit.pCallbacks->push_back( CallbackEntry( pContext, pCallback ) ); +} + + +extern "C" void SAL_CALL typelib_typedescription_revokeCallback( + void * pContext, typelib_typedescription_Callback pCallback ) + SAL_THROW_EXTERN_C() +{ + TypeDescriptor_Init_Impl &rInit = Init::get(); + if( rInit.pCallbacks ) + { + // todo mt safe: guard is no solution, can not acquire while calling callback! +// OslGuard aGuard( rInit.getMutex() ); + CallbackEntry aEntry( pContext, pCallback ); + rInit.pCallbacks->erase(std::remove(rInit.pCallbacks->begin(), rInit.pCallbacks->end(), aEntry), + rInit.pCallbacks->end()); + } +} + +static void typelib_typedescription_initTables( + typelib_TypeDescription * pTD ) +{ + typelib_InterfaceTypeDescription * pITD = reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD); + + std::vector<bool> aReadWriteAttributes(pITD->nAllMembers); + for ( sal_Int32 i = pITD->nAllMembers; i--; ) + { + aReadWriteAttributes[i] = false; + if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pITD->ppAllMembers[i]->eTypeClass ) + { + typelib_TypeDescription * pM = nullptr; + TYPELIB_DANGER_GET( &pM, pITD->ppAllMembers[i] ); + OSL_ASSERT( pM ); + if (pM) + { + aReadWriteAttributes[i] = !reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(pM)->bReadOnly; + TYPELIB_DANGER_RELEASE( pM ); + } + else + { + SAL_INFO( "cppu.typelib", "cannot get attribute type description: " << pITD->ppAllMembers[i]->pTypeName ); + } + } + } + + MutexGuard aGuard( Init::get().getMutex() ); + if( pTD->bComplete ) + return; + + // create the index table from member to function table + pITD->pMapMemberIndexToFunctionIndex = new sal_Int32[ pITD->nAllMembers ]; + sal_Int32 nAdditionalOffset = 0; // +1 for read/write attributes + sal_Int32 i; + for( i = 0; i < pITD->nAllMembers; i++ ) + { + // index to the get method of the attribute + pITD->pMapMemberIndexToFunctionIndex[i] = i + nAdditionalOffset; + // extra offset if it is a read/write attribute? + if (aReadWriteAttributes[i]) + { + // a read/write attribute + nAdditionalOffset++; + } + } + + // create the index table from function to member table + pITD->pMapFunctionIndexToMemberIndex = new sal_Int32[ pITD->nAllMembers + nAdditionalOffset ]; + nAdditionalOffset = 0; // +1 for read/write attributes + for( i = 0; i < pITD->nAllMembers; i++ ) + { + // index to the get method of the attribute + pITD->pMapFunctionIndexToMemberIndex[i + nAdditionalOffset] = i; + // extra offset if it is a read/write attribute? + if (aReadWriteAttributes[i]) + { + // a read/write attribute + pITD->pMapFunctionIndexToMemberIndex[i + ++nAdditionalOffset] = i; + } + } + // must be the last action after all initialization is done + pITD->nMapFunctionIndexToMemberIndex = pITD->nAllMembers + nAdditionalOffset; + pTD->bComplete = true; +} + +namespace { + +template<typename T> T * allocTypeDescription() { + return reinterpret_cast<T *>(new char[sizeof (T)]); +} + +void freeTypeDescription(typelib_TypeDescription const * desc) { + delete[] reinterpret_cast<char const *>(desc); +} + +// In some situations (notably typelib_typedescription_newInterfaceMethod and +// typelib_typedescription_newInterfaceAttribute), only the members nMembers, +// ppMembers, nAllMembers, and ppAllMembers of an incomplete interface type +// description are necessary, but not the additional +// pMapMemberIndexToFunctionIndex, nMapFunctionIndexToMemberIndex, and +// pMapFunctionIndexToMemberIndex (which are computed by +// typelib_typedescription_initTables). Furthermore, in those situations, it +// might be illegal to compute those tables, as the creation of the interface +// member type descriptions would recursively require a complete interface type +// description. The parameter initTables controls whether or not to call +// typelib_typedescription_initTables in those situations. +bool complete(typelib_TypeDescription ** ppTypeDescr, bool initTables) { + if (! (*ppTypeDescr)->bComplete) + { + OSL_ASSERT( (typelib_TypeClass_STRUCT == (*ppTypeDescr)->eTypeClass || + typelib_TypeClass_EXCEPTION == (*ppTypeDescr)->eTypeClass || + typelib_TypeClass_ENUM == (*ppTypeDescr)->eTypeClass || + typelib_TypeClass_INTERFACE == (*ppTypeDescr)->eTypeClass) && + !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( (*ppTypeDescr)->eTypeClass ) ); + + if (typelib_TypeClass_INTERFACE == (*ppTypeDescr)->eTypeClass && + reinterpret_cast<typelib_InterfaceTypeDescription *>(*ppTypeDescr)->ppAllMembers) + { + if (initTables) { + typelib_typedescription_initTables( *ppTypeDescr ); + } + return true; + } + + typelib_TypeDescription * pTD = nullptr; + // on demand access of complete td + TypeDescriptor_Init_Impl &rInit = Init::get(); + rInit.callChain( &pTD, (*ppTypeDescr)->pTypeName ); + if (pTD) + { + if (typelib_TypeClass_TYPEDEF == pTD->eTypeClass) + { + typelib_typedescriptionreference_getDescription( + &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(pTD)->pType ); + OSL_ASSERT( pTD ); + if (! pTD) + return false; + } + + OSL_ASSERT( typelib_TypeClass_TYPEDEF != pTD->eTypeClass ); + // typedescription found + // set to on demand + pTD->bOnDemand = true; + + if (pTD->eTypeClass == typelib_TypeClass_INTERFACE + && !pTD->bComplete && initTables) + { + // mandatory info from callback chain + OSL_ASSERT( reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD)->ppAllMembers ); + // complete except of tables init + typelib_typedescription_initTables( pTD ); + pTD->bComplete = true; + } + + // The type description is hold by the reference until + // on demand is activated. + ::typelib_typedescription_register( &pTD ); // replaces incomplete one + OSL_ASSERT( pTD == *ppTypeDescr ); // has to merge into existing one + + // insert into the cache + MutexGuard aGuard( rInit.getMutex() ); + if( !rInit.pCache ) + rInit.pCache.reset( new TypeDescriptionList_Impl ); + if( static_cast<sal_Int32>(rInit.pCache->size()) >= nCacheSize ) + { + typelib_typedescription_release( rInit.pCache->front() ); + rInit.pCache->pop_front(); + } + // descriptions in the cache must be acquired! + typelib_typedescription_acquire( pTD ); + rInit.pCache->push_back( pTD ); + + OSL_ASSERT( + pTD->bComplete + || (pTD->eTypeClass == typelib_TypeClass_INTERFACE + && !initTables)); + + ::typelib_typedescription_release( *ppTypeDescr ); + *ppTypeDescr = pTD; + } + else + { + SAL_INFO( + "cppu.typelib", + "type cannot be completed: " << OUString::unacquired(&(*ppTypeDescr)->pTypeName)); + return false; + } + } + return true; +} + +} + + +extern "C" void typelib_typedescription_newEmpty( + typelib_TypeDescription ** ppRet, + typelib_TypeClass eTypeClass, rtl_uString * pTypeName ) + SAL_THROW_EXTERN_C() +{ + if( *ppRet ) + { + typelib_typedescription_release( *ppRet ); + *ppRet = nullptr; + } + + OSL_ASSERT( typelib_TypeClass_TYPEDEF != eTypeClass ); + + typelib_TypeDescription * pRet; + switch( eTypeClass ) + { + case typelib_TypeClass_SEQUENCE: + { + auto pTmp = allocTypeDescription<typelib_IndirectTypeDescription>(); + pRet = &pTmp->aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nIndirectTypeDescriptionCount ); +#endif + pTmp->pType = nullptr; + // coverity[leaked_storage] - this is on purpose + } + break; + + case typelib_TypeClass_STRUCT: + { + // FEATURE_EMPTYCLASS + auto pTmp = allocTypeDescription<typelib_StructTypeDescription>(); + pRet = &pTmp->aBase.aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nCompoundTypeDescriptionCount ); +#endif + pTmp->aBase.pBaseTypeDescription = nullptr; + pTmp->aBase.nMembers = 0; + pTmp->aBase.pMemberOffsets = nullptr; + pTmp->aBase.ppTypeRefs = nullptr; + pTmp->aBase.ppMemberNames = nullptr; + pTmp->pParameterizedTypes = nullptr; + // coverity[leaked_storage] - this is on purpose + } + break; + + case typelib_TypeClass_EXCEPTION: + { + // FEATURE_EMPTYCLASS + auto pTmp = allocTypeDescription<typelib_CompoundTypeDescription>(); + pRet = &pTmp->aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nCompoundTypeDescriptionCount ); +#endif + pTmp->pBaseTypeDescription = nullptr; + pTmp->nMembers = 0; + pTmp->pMemberOffsets = nullptr; + pTmp->ppTypeRefs = nullptr; + pTmp->ppMemberNames = nullptr; + // coverity[leaked_storage] - this is on purpose + } + break; + + case typelib_TypeClass_ENUM: + { + auto pTmp = allocTypeDescription<typelib_EnumTypeDescription>(); + pRet = &pTmp->aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nEnumTypeDescriptionCount ); +#endif + pTmp->nDefaultEnumValue = 0; + pTmp->nEnumValues = 0; + pTmp->ppEnumNames = nullptr; + pTmp->pEnumValues = nullptr; + // coverity[leaked_storage] - this is on purpose + } + break; + + case typelib_TypeClass_INTERFACE: + { + auto pTmp = allocTypeDescription< + typelib_InterfaceTypeDescription>(); + pRet = &pTmp->aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nInterfaceTypeDescriptionCount ); +#endif + pTmp->pBaseTypeDescription = nullptr; + pTmp->nMembers = 0; + pTmp->ppMembers = nullptr; + pTmp->nAllMembers = 0; + pTmp->ppAllMembers = nullptr; + pTmp->nMapFunctionIndexToMemberIndex = 0; + pTmp->pMapFunctionIndexToMemberIndex = nullptr; + pTmp->pMapMemberIndexToFunctionIndex= nullptr; + pTmp->nBaseTypes = 0; + pTmp->ppBaseTypes = nullptr; + // coverity[leaked_storage] - this is on purpose + } + break; + + case typelib_TypeClass_INTERFACE_METHOD: + { + auto pTmp = allocTypeDescription< + typelib_InterfaceMethodTypeDescription>(); + pRet = &pTmp->aBase.aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nInterfaceMethodTypeDescriptionCount ); +#endif + pTmp->aBase.pMemberName = nullptr; + pTmp->pReturnTypeRef = nullptr; + pTmp->nParams = 0; + pTmp->pParams = nullptr; + pTmp->nExceptions = 0; + pTmp->ppExceptions = nullptr; + pTmp->pInterface = nullptr; + pTmp->pBaseRef = nullptr; + pTmp->nIndex = 0; + // coverity[leaked_storage] - this is on purpose + } + break; + + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + auto * pTmp = allocTypeDescription< + typelib_InterfaceAttributeTypeDescription>(); + pRet = &pTmp->aBase.aBase; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nInterfaceAttributeTypeDescriptionCount ); +#endif + pTmp->aBase.pMemberName = nullptr; + pTmp->pAttributeTypeRef = nullptr; + pTmp->pInterface = nullptr; + pTmp->pBaseRef = nullptr; + pTmp->nIndex = 0; + pTmp->nGetExceptions = 0; + pTmp->ppGetExceptions = nullptr; + pTmp->nSetExceptions = 0; + pTmp->ppSetExceptions = nullptr; + // coverity[leaked_storage] - this is on purpose + } + break; + + default: + { + pRet = allocTypeDescription<typelib_TypeDescription>(); +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &Init::get().nTypeDescriptionCount ); +#endif + } + } + + pRet->nRefCount = 1; // reference count is initially 1 + pRet->nStaticRefCount = 0; + pRet->eTypeClass = eTypeClass; + pRet->pUniqueIdentifier = nullptr; + pRet->pReserved = nullptr; + pRet->pTypeName = pTypeName; + rtl_uString_acquire( pRet->pTypeName ); + pRet->pSelf = pRet; + pRet->bComplete = true; + pRet->nSize = 0; + pRet->nAlignment = 0; + pRet->pWeakRef = nullptr; + pRet->bOnDemand = false; + *ppRet = pRet; +} + + +namespace { + +void newTypeDescription( + typelib_TypeDescription ** ppRet, typelib_TypeClass eTypeClass, + rtl_uString * pTypeName, typelib_TypeDescriptionReference * pType, + sal_Int32 nMembers, typelib_CompoundMember_Init * pCompoundMembers, + typelib_StructMember_Init * pStructMembers) +{ + OSL_ASSERT( + (pCompoundMembers == nullptr || pStructMembers == nullptr) + && (pStructMembers == nullptr || eTypeClass == typelib_TypeClass_STRUCT)); + if (typelib_TypeClass_TYPEDEF == eTypeClass) + { + SAL_WARN("cppu.typelib", "unexpected typedef!" ); + typelib_typedescriptionreference_getDescription( ppRet, pType ); + return; + } + + typelib_typedescription_newEmpty( ppRet, eTypeClass, pTypeName ); + + switch( eTypeClass ) + { + case typelib_TypeClass_SEQUENCE: + { + OSL_ASSERT( nMembers == 0 ); + typelib_typedescriptionreference_acquire( pType ); + reinterpret_cast<typelib_IndirectTypeDescription *>(*ppRet)->pType = pType; + } + break; + + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + { + // FEATURE_EMPTYCLASS + typelib_CompoundTypeDescription * pTmp = reinterpret_cast<typelib_CompoundTypeDescription*>(*ppRet); + + sal_Int32 nOffset = 0; + if( pType ) + { + typelib_typedescriptionreference_getDescription( + reinterpret_cast<typelib_TypeDescription **>(&pTmp->pBaseTypeDescription), pType ); + nOffset = pTmp->pBaseTypeDescription->aBase.nSize; + OSL_ENSURE( newAlignedSize( 0, pTmp->pBaseTypeDescription->aBase.nSize, pTmp->pBaseTypeDescription->aBase.nAlignment ) == pTmp->pBaseTypeDescription->aBase.nSize, "### unexpected offset!" ); + } + if( nMembers ) + { + pTmp->nMembers = nMembers; + pTmp->pMemberOffsets = new sal_Int32[ nMembers ]; + pTmp->ppTypeRefs = new typelib_TypeDescriptionReference *[ nMembers ]; + pTmp->ppMemberNames = new rtl_uString *[ nMembers ]; + bool polymorphic = eTypeClass == typelib_TypeClass_STRUCT + && OUString::unacquired(&pTypeName).indexOf('<') >= 0; + OSL_ASSERT(!polymorphic || pStructMembers != nullptr); + if (polymorphic) { + reinterpret_cast< typelib_StructTypeDescription * >(pTmp)-> + pParameterizedTypes = new sal_Bool[nMembers]; + } + for( sal_Int32 i = 0 ; i < nMembers; i++ ) + { + // read the type and member names + pTmp->ppTypeRefs[i] = nullptr; + if (pCompoundMembers != nullptr) { + typelib_typedescriptionreference_new( + pTmp->ppTypeRefs +i, pCompoundMembers[i].eTypeClass, + pCompoundMembers[i].pTypeName ); + pTmp->ppMemberNames[i] + = pCompoundMembers[i].pMemberName; + rtl_uString_acquire( pTmp->ppMemberNames[i] ); + } else { + typelib_typedescriptionreference_new( + pTmp->ppTypeRefs +i, + pStructMembers[i].aBase.eTypeClass, + pStructMembers[i].aBase.pTypeName ); + pTmp->ppMemberNames[i] + = pStructMembers[i].aBase.pMemberName; + rtl_uString_acquire(pTmp->ppMemberNames[i]); + } + // write offset + sal_Int32 size; + sal_Int32 alignment; + if (pTmp->ppTypeRefs[i]->eTypeClass == + typelib_TypeClass_SEQUENCE) + { + // Take care of recursion like + // struct S { sequence<S> x; }; + size = sizeof(void *); + alignment = adjustAlignment(size); + } else { + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( &pTD, pTmp->ppTypeRefs[i] ); + OSL_ENSURE( pTD->nSize, "### void member?" ); + size = pTD->nSize; + alignment = pTD->nAlignment; + TYPELIB_DANGER_RELEASE( pTD ); + } + nOffset = newAlignedSize( nOffset, size, alignment ); + pTmp->pMemberOffsets[i] = nOffset - size; + + if (polymorphic) { + reinterpret_cast< typelib_StructTypeDescription * >( + pTmp)->pParameterizedTypes[i] + = pStructMembers[i].bParameterizedType; + } + } + } + } + break; + + default: + break; + } + + if( !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( eTypeClass ) ) + (*ppRet)->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(*ppRet); + if( eTypeClass != typelib_TypeClass_VOID ) + { + // sizeof(void) not allowed + (*ppRet)->nSize = typelib_typedescription_getAlignedUnoSize( (*ppRet), 0, (*ppRet)->nAlignment ); + (*ppRet)->nAlignment = adjustAlignment( (*ppRet)->nAlignment ); + } +} + +} + +extern "C" void SAL_CALL typelib_typedescription_new( + typelib_TypeDescription ** ppRet, + typelib_TypeClass eTypeClass, + rtl_uString * pTypeName, + typelib_TypeDescriptionReference * pType, + sal_Int32 nMembers, + typelib_CompoundMember_Init * pMembers ) + SAL_THROW_EXTERN_C() +{ + newTypeDescription( + ppRet, eTypeClass, pTypeName, pType, nMembers, pMembers, nullptr); +} + +extern "C" void SAL_CALL typelib_typedescription_newStruct( + typelib_TypeDescription ** ppRet, + rtl_uString * pTypeName, + typelib_TypeDescriptionReference * pType, + sal_Int32 nMembers, + typelib_StructMember_Init * pMembers ) + SAL_THROW_EXTERN_C() +{ + newTypeDescription( + ppRet, typelib_TypeClass_STRUCT, pTypeName, pType, nMembers, nullptr, + pMembers); +} + + +extern "C" void SAL_CALL typelib_typedescription_newEnum( + typelib_TypeDescription ** ppRet, + rtl_uString * pTypeName, + sal_Int32 nDefaultValue, + sal_Int32 nEnumValues, + rtl_uString ** ppEnumNames, + sal_Int32 * pEnumValues ) + SAL_THROW_EXTERN_C() +{ + typelib_typedescription_newEmpty( ppRet, typelib_TypeClass_ENUM, pTypeName ); + typelib_EnumTypeDescription * pEnum = reinterpret_cast<typelib_EnumTypeDescription *>(*ppRet); + + pEnum->nDefaultEnumValue = nDefaultValue; + pEnum->nEnumValues = nEnumValues; + pEnum->ppEnumNames = new rtl_uString * [ nEnumValues ]; + for ( sal_Int32 nPos = nEnumValues; nPos--; ) + { + pEnum->ppEnumNames[nPos] = ppEnumNames[nPos]; + rtl_uString_acquire( pEnum->ppEnumNames[nPos] ); + } + pEnum->pEnumValues = new sal_Int32[ nEnumValues ]; + ::memcpy( pEnum->pEnumValues, pEnumValues, nEnumValues * sizeof(sal_Int32) ); + + static_assert(!TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(typelib_TypeClass_ENUM)); + (*ppRet)->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(*ppRet); + // sizeof(void) not allowed + (*ppRet)->nSize = typelib_typedescription_getAlignedUnoSize( (*ppRet), 0, (*ppRet)->nAlignment ); + (*ppRet)->nAlignment = adjustAlignment( (*ppRet)->nAlignment ); +} + + +extern "C" void SAL_CALL typelib_typedescription_newInterface( + typelib_InterfaceTypeDescription ** ppRet, + rtl_uString * pTypeName, + SAL_UNUSED_PARAMETER sal_uInt32, SAL_UNUSED_PARAMETER sal_uInt16, + SAL_UNUSED_PARAMETER sal_uInt16, SAL_UNUSED_PARAMETER sal_uInt32, + SAL_UNUSED_PARAMETER sal_uInt32, + typelib_TypeDescriptionReference * pBaseInterface, + sal_Int32 nMembers, + typelib_TypeDescriptionReference ** ppMembers ) + SAL_THROW_EXTERN_C() +{ + // coverity[callee_ptr_arith] - not a bug + typelib_typedescription_newMIInterface( + ppRet, pTypeName, 0, 0, 0, 0, 0, pBaseInterface == nullptr ? 0 : 1, + &pBaseInterface, nMembers, ppMembers); +} + +namespace { + +class BaseList { +public: + struct Entry { + sal_Int32 memberOffset; + sal_Int32 directBaseIndex; + sal_Int32 directBaseMemberOffset; + typelib_InterfaceTypeDescription const * base; + }; + + typedef std::vector< Entry > List; + + explicit BaseList(typelib_InterfaceTypeDescription const * desc); + + List const & getList() const { return list; } + + sal_Int32 getBaseMembers() const { return members; } + +private: + typedef std::set< OUString > Set; + + void calculate( + sal_Int32 directBaseIndex, Set & directBaseSet, + sal_Int32 * directBaseMembers, + typelib_InterfaceTypeDescription const * desc); + + Set set; + List list; + sal_Int32 members; +}; + +BaseList::BaseList(typelib_InterfaceTypeDescription const * desc) + : members(0) +{ + for (sal_Int32 i = 0; i < desc->nBaseTypes; ++i) { + Set directBaseSet; + sal_Int32 directBaseMembers = 0; + calculate(i, directBaseSet, &directBaseMembers, desc->ppBaseTypes[i]); + } +} + +void BaseList::calculate( + sal_Int32 directBaseIndex, Set & directBaseSet, + sal_Int32 * directBaseMembers, + typelib_InterfaceTypeDescription const * desc) +{ + for (sal_Int32 i = 0; i < desc->nBaseTypes; ++i) { + calculate( + directBaseIndex, directBaseSet, directBaseMembers, + desc->ppBaseTypes[i]); + } + if (set.insert(desc->aBase.pTypeName).second) { + Entry e; + e.memberOffset = members; + e.directBaseIndex = directBaseIndex; + e.directBaseMemberOffset = *directBaseMembers; + e.base = desc; + list.push_back(e); + OSL_ASSERT(desc->ppAllMembers != nullptr); + members += desc->nMembers; + } + if (directBaseSet.insert(desc->aBase.pTypeName).second) { + OSL_ASSERT(desc->ppAllMembers != nullptr); + *directBaseMembers += desc->nMembers; + } +} + +} + +extern "C" void SAL_CALL typelib_typedescription_newMIInterface( + typelib_InterfaceTypeDescription ** ppRet, + rtl_uString * pTypeName, + SAL_UNUSED_PARAMETER sal_uInt32, SAL_UNUSED_PARAMETER sal_uInt16, + SAL_UNUSED_PARAMETER sal_uInt16, SAL_UNUSED_PARAMETER sal_uInt32, + SAL_UNUSED_PARAMETER sal_uInt32, + sal_Int32 nBaseInterfaces, + typelib_TypeDescriptionReference ** ppBaseInterfaces, + sal_Int32 nMembers, + typelib_TypeDescriptionReference ** ppMembers ) + SAL_THROW_EXTERN_C() +{ + if (*ppRet != nullptr) { + typelib_typedescription_release(&(*ppRet)->aBase); + *ppRet = nullptr; + } + + typelib_InterfaceTypeDescription * pITD = nullptr; + typelib_typedescription_newEmpty( + reinterpret_cast<typelib_TypeDescription **>(&pITD), typelib_TypeClass_INTERFACE, pTypeName ); + + pITD->nBaseTypes = nBaseInterfaces; + pITD->ppBaseTypes = new typelib_InterfaceTypeDescription *[nBaseInterfaces]; + for (sal_Int32 i = 0; i < nBaseInterfaces; ++i) { + pITD->ppBaseTypes[i] = nullptr; + typelib_typedescriptionreference_getDescription( + reinterpret_cast< typelib_TypeDescription ** >( + &pITD->ppBaseTypes[i]), + ppBaseInterfaces[i]); + if (pITD->ppBaseTypes[i] == nullptr + || !complete( + reinterpret_cast< typelib_TypeDescription ** >( + &pITD->ppBaseTypes[i]), + false)) + { + OSL_ASSERT(false); + return; + } + OSL_ASSERT(pITD->ppBaseTypes[i] != nullptr); + } + if (nBaseInterfaces > 0) { + pITD->pBaseTypeDescription = pITD->ppBaseTypes[0]; + } + // set the + pITD->aUik.m_Data1 = 0; + pITD->aUik.m_Data2 = 0; + pITD->aUik.m_Data3 = 0; + pITD->aUik.m_Data4 = 0; + pITD->aUik.m_Data5 = 0; + + BaseList aBaseList(pITD); + pITD->nAllMembers = nMembers + aBaseList.getBaseMembers(); + pITD->nMembers = nMembers; + + if( pITD->nAllMembers ) + { + // at minimum one member exist, allocate the memory + pITD->ppAllMembers = new typelib_TypeDescriptionReference *[ pITD->nAllMembers ]; + sal_Int32 n = 0; + + BaseList::List const & rList = aBaseList.getList(); + for (const auto& rEntry : rList) + { + typelib_InterfaceTypeDescription const * pBase = rEntry.base; + typelib_InterfaceTypeDescription const * pDirectBase + = pITD->ppBaseTypes[rEntry.directBaseIndex]; + OSL_ASSERT(pBase->ppAllMembers != nullptr); + for (sal_Int32 j = 0; j < pBase->nMembers; ++j) { + typelib_TypeDescriptionReference const * pDirectBaseMember + = pDirectBase->ppAllMembers[rEntry.directBaseMemberOffset + j]; + OUString aName = OUString::unacquired(&pDirectBaseMember->pTypeName) + + ":@" + + OUString::number(rEntry.directBaseIndex) + + "," + + OUString::number(rEntry.memberOffset + j) + + ":" + + OUString::unacquired(&pITD->aBase.pTypeName); + typelib_TypeDescriptionReference * pDerivedMember = nullptr; + typelib_typedescriptionreference_new( + &pDerivedMember, pDirectBaseMember->eTypeClass, + aName.pData); + pITD->ppAllMembers[n++] = pDerivedMember; + } + } + + if( nMembers ) + { + pITD->ppMembers = pITD->ppAllMembers + aBaseList.getBaseMembers(); + } + + // add own members + for( sal_Int32 i = 0; i < nMembers; i++ ) + { + typelib_typedescriptionreference_acquire( ppMembers[i] ); + pITD->ppAllMembers[n++] = ppMembers[i]; + } + } + + typelib_TypeDescription * pTmp = &pITD->aBase; + static_assert( !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( typelib_TypeClass_INTERFACE ) ); + pTmp->pWeakRef = reinterpret_cast<typelib_TypeDescriptionReference *>(pTmp); + pTmp->nSize = typelib_typedescription_getAlignedUnoSize( pTmp, 0, pTmp->nAlignment ); + pTmp->nAlignment = adjustAlignment( pTmp->nAlignment ); + pTmp->bComplete = false; + + *ppRet = pITD; +} + + +namespace { + +typelib_TypeDescriptionReference ** copyExceptions( + sal_Int32 count, rtl_uString ** typeNames) +{ + OSL_ASSERT(count >= 0); + if (count == 0) { + return nullptr; + } + typelib_TypeDescriptionReference ** p + = new typelib_TypeDescriptionReference *[count]; + for (sal_Int32 i = 0; i < count; ++i) { + p[i] = nullptr; + typelib_typedescriptionreference_new( + p + i, typelib_TypeClass_EXCEPTION, typeNames[i]); + } + return p; +} + +} + +extern "C" void SAL_CALL typelib_typedescription_newInterfaceMethod( + typelib_InterfaceMethodTypeDescription ** ppRet, + sal_Int32 nAbsolutePosition, + sal_Bool bOneWay, + rtl_uString * pTypeName, + typelib_TypeClass eReturnTypeClass, + rtl_uString * pReturnTypeName, + sal_Int32 nParams, + typelib_Parameter_Init * pParams, + sal_Int32 nExceptions, + rtl_uString ** ppExceptionNames ) + SAL_THROW_EXTERN_C() +{ + if (*ppRet != nullptr) { + typelib_typedescription_release(&(*ppRet)->aBase.aBase); + *ppRet = nullptr; + } + sal_Int32 nOffset = rtl_ustr_lastIndexOfChar_WithLength( + pTypeName->buffer, pTypeName->length, ':'); + if (nOffset <= 0 || pTypeName->buffer[nOffset - 1] != ':') { + OSL_FAIL("Bad interface method type name"); + return; + } + OUString aInterfaceTypeName(pTypeName->buffer, nOffset - 1); + typelib_InterfaceTypeDescription * pInterface = nullptr; + typelib_typedescription_getByName( + reinterpret_cast< typelib_TypeDescription ** >(&pInterface), + aInterfaceTypeName.pData); + if (pInterface == nullptr + || pInterface->aBase.eTypeClass != typelib_TypeClass_INTERFACE + || !complete( + reinterpret_cast< typelib_TypeDescription ** >(&pInterface), false)) + { + OSL_FAIL("No interface corresponding to interface method"); + return; + } + + typelib_typedescription_newEmpty( + reinterpret_cast<typelib_TypeDescription **>(ppRet), typelib_TypeClass_INTERFACE_METHOD, pTypeName ); + + rtl_uString_newFromStr_WithLength( &(*ppRet)->aBase.pMemberName, + pTypeName->buffer + nOffset +1, + pTypeName->length - nOffset -1 ); + (*ppRet)->aBase.nPosition = nAbsolutePosition; + (*ppRet)->bOneWay = bOneWay; + typelib_typedescriptionreference_new( &(*ppRet)->pReturnTypeRef, eReturnTypeClass, pReturnTypeName ); + (*ppRet)->nParams = nParams; + if( nParams ) + { + (*ppRet)->pParams = new typelib_MethodParameter[ nParams ]; + + for( sal_Int32 i = 0; i < nParams; i++ ) + { + // get the name of the parameter + (*ppRet)->pParams[ i ].pName = pParams[i].pParamName; + rtl_uString_acquire( (*ppRet)->pParams[ i ].pName ); + (*ppRet)->pParams[ i ].pTypeRef = nullptr; + // get the type name of the parameter and create the weak reference + typelib_typedescriptionreference_new( + &(*ppRet)->pParams[ i ].pTypeRef, pParams[i].eTypeClass, pParams[i].pTypeName ); + (*ppRet)->pParams[ i ].bIn = pParams[i].bIn; + (*ppRet)->pParams[ i ].bOut = pParams[i].bOut; + } + } + (*ppRet)->nExceptions = nExceptions; + (*ppRet)->ppExceptions = copyExceptions(nExceptions, ppExceptionNames); + (*ppRet)->pInterface = pInterface; + (*ppRet)->pBaseRef = nullptr; + OSL_ASSERT( + (nAbsolutePosition >= pInterface->nAllMembers - pInterface->nMembers) + && nAbsolutePosition < pInterface->nAllMembers); + (*ppRet)->nIndex = nAbsolutePosition + - (pInterface->nAllMembers - pInterface->nMembers); + static_assert( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( typelib_TypeClass_INTERFACE_METHOD ) ); + assert(reinterpret_cast<typelib_TypeDescription *>(*ppRet)->pWeakRef == nullptr); +} + + +extern "C" void SAL_CALL typelib_typedescription_newInterfaceAttribute( + typelib_InterfaceAttributeTypeDescription ** ppRet, + sal_Int32 nAbsolutePosition, + rtl_uString * pTypeName, + typelib_TypeClass eAttributeTypeClass, + rtl_uString * pAttributeTypeName, + sal_Bool bReadOnly ) + SAL_THROW_EXTERN_C() +{ + typelib_typedescription_newExtendedInterfaceAttribute( + ppRet, nAbsolutePosition, pTypeName, eAttributeTypeClass, + pAttributeTypeName, bReadOnly, 0, nullptr, 0, nullptr); +} + + +extern "C" void SAL_CALL typelib_typedescription_newExtendedInterfaceAttribute( + typelib_InterfaceAttributeTypeDescription ** ppRet, + sal_Int32 nAbsolutePosition, + rtl_uString * pTypeName, + typelib_TypeClass eAttributeTypeClass, + rtl_uString * pAttributeTypeName, + sal_Bool bReadOnly, + sal_Int32 nGetExceptions, rtl_uString ** ppGetExceptionNames, + sal_Int32 nSetExceptions, rtl_uString ** ppSetExceptionNames ) + SAL_THROW_EXTERN_C() +{ + if (*ppRet != nullptr) { + typelib_typedescription_release(&(*ppRet)->aBase.aBase); + *ppRet = nullptr; + } + sal_Int32 nOffset = rtl_ustr_lastIndexOfChar_WithLength( + pTypeName->buffer, pTypeName->length, ':'); + if (nOffset <= 0 || pTypeName->buffer[nOffset - 1] != ':') { + OSL_FAIL("Bad interface attribute type name"); + return; + } + OUString aInterfaceTypeName(pTypeName->buffer, nOffset - 1); + typelib_InterfaceTypeDescription * pInterface = nullptr; + typelib_typedescription_getByName( + reinterpret_cast< typelib_TypeDescription ** >(&pInterface), + aInterfaceTypeName.pData); + if (pInterface == nullptr + || pInterface->aBase.eTypeClass != typelib_TypeClass_INTERFACE + || !complete( + reinterpret_cast< typelib_TypeDescription ** >(&pInterface), false)) + { + OSL_FAIL("No interface corresponding to interface attribute"); + return; + } + + typelib_typedescription_newEmpty( + reinterpret_cast<typelib_TypeDescription **>(ppRet), typelib_TypeClass_INTERFACE_ATTRIBUTE, pTypeName ); + + rtl_uString_newFromStr_WithLength( &(*ppRet)->aBase.pMemberName, + pTypeName->buffer + nOffset +1, + pTypeName->length - nOffset -1 ); + (*ppRet)->aBase.nPosition = nAbsolutePosition; + typelib_typedescriptionreference_new( &(*ppRet)->pAttributeTypeRef, eAttributeTypeClass, pAttributeTypeName ); + (*ppRet)->bReadOnly = bReadOnly; + (*ppRet)->pInterface = pInterface; + (*ppRet)->pBaseRef = nullptr; + OSL_ASSERT( + (nAbsolutePosition >= pInterface->nAllMembers - pInterface->nMembers) + && nAbsolutePosition < pInterface->nAllMembers); + (*ppRet)->nIndex = nAbsolutePosition + - (pInterface->nAllMembers - pInterface->nMembers); + (*ppRet)->nGetExceptions = nGetExceptions; + (*ppRet)->ppGetExceptions = copyExceptions( + nGetExceptions, ppGetExceptionNames); + (*ppRet)->nSetExceptions = nSetExceptions; + (*ppRet)->ppSetExceptions = copyExceptions( + nSetExceptions, ppSetExceptionNames); + static_assert( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( typelib_TypeClass_INTERFACE_ATTRIBUTE ) ); + assert(reinterpret_cast<typelib_TypeDescription *>(*ppRet)->pWeakRef == nullptr); +} + + +extern "C" void SAL_CALL typelib_typedescription_acquire( + typelib_TypeDescription * pTypeDescription ) + SAL_THROW_EXTERN_C() +{ + osl_atomic_increment( &pTypeDescription->nRefCount ); +} + + +namespace { + +void deleteExceptions( + sal_Int32 count, typelib_TypeDescriptionReference ** exceptions) +{ + for (sal_Int32 i = 0; i < count; ++i) { + typelib_typedescriptionreference_release(exceptions[i]); + } + delete[] exceptions; +} + +} + +// frees anything except typelib_TypeDescription base! +static void typelib_typedescription_destructExtendedMembers( + typelib_TypeDescription * pTD ) +{ + OSL_ASSERT( typelib_TypeClass_TYPEDEF != pTD->eTypeClass ); + + switch( pTD->eTypeClass ) + { + case typelib_TypeClass_SEQUENCE: + if( reinterpret_cast<typelib_IndirectTypeDescription*>(pTD)->pType ) + typelib_typedescriptionreference_release( reinterpret_cast<typelib_IndirectTypeDescription*>(pTD)->pType ); + break; + case typelib_TypeClass_STRUCT: + delete[] reinterpret_cast< typelib_StructTypeDescription * >(pTD)-> + pParameterizedTypes; + [[fallthrough]]; + case typelib_TypeClass_EXCEPTION: + { + typelib_CompoundTypeDescription * pCTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD); + if( pCTD->pBaseTypeDescription ) + typelib_typedescription_release( &pCTD->pBaseTypeDescription->aBase ); + sal_Int32 i; + for( i = 0; i < pCTD->nMembers; i++ ) + { + typelib_typedescriptionreference_release( pCTD->ppTypeRefs[i] ); + } + if (pCTD->ppMemberNames) + { + for ( i = 0; i < pCTD->nMembers; i++ ) + { + rtl_uString_release( pCTD->ppMemberNames[i] ); + } + delete [] pCTD->ppMemberNames; + } + delete [] pCTD->ppTypeRefs; + delete [] pCTD->pMemberOffsets; + } + break; + case typelib_TypeClass_INTERFACE: + { + typelib_InterfaceTypeDescription * pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD); + for( sal_Int32 i = 0; i < pITD->nAllMembers; i++ ) + { + typelib_typedescriptionreference_release( pITD->ppAllMembers[i] ); + } + delete [] pITD->ppAllMembers; + delete [] pITD->pMapMemberIndexToFunctionIndex; + delete [] pITD->pMapFunctionIndexToMemberIndex; + for (sal_Int32 i = 0; i < pITD->nBaseTypes; ++i) { + typelib_typedescription_release( + reinterpret_cast< typelib_TypeDescription * >( + pITD->ppBaseTypes[i])); + } + delete[] pITD->ppBaseTypes; + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * pIMTD = reinterpret_cast<typelib_InterfaceMethodTypeDescription*>(pTD); + if( pIMTD->pReturnTypeRef ) + typelib_typedescriptionreference_release( pIMTD->pReturnTypeRef ); + for( sal_Int32 i = 0; i < pIMTD->nParams; i++ ) + { + rtl_uString_release( pIMTD->pParams[ i ].pName ); + typelib_typedescriptionreference_release( pIMTD->pParams[ i ].pTypeRef ); + } + delete [] pIMTD->pParams; + deleteExceptions(pIMTD->nExceptions, pIMTD->ppExceptions); + rtl_uString_release( pIMTD->aBase.pMemberName ); + typelib_typedescription_release(&pIMTD->pInterface->aBase); + if (pIMTD->pBaseRef != nullptr) { + typelib_typedescriptionreference_release(pIMTD->pBaseRef); + } + } + break; + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription * pIATD = reinterpret_cast<typelib_InterfaceAttributeTypeDescription*>(pTD); + deleteExceptions(pIATD->nGetExceptions, pIATD->ppGetExceptions); + deleteExceptions(pIATD->nSetExceptions, pIATD->ppSetExceptions); + if( pIATD->pAttributeTypeRef ) + typelib_typedescriptionreference_release( pIATD->pAttributeTypeRef ); + if( pIATD->aBase.pMemberName ) + rtl_uString_release( pIATD->aBase.pMemberName ); + typelib_typedescription_release(&pIATD->pInterface->aBase); + if (pIATD->pBaseRef != nullptr) { + typelib_typedescriptionreference_release(pIATD->pBaseRef); + } + } + break; + case typelib_TypeClass_ENUM: + { + typelib_EnumTypeDescription * pEnum = reinterpret_cast<typelib_EnumTypeDescription *>(pTD); + for ( sal_Int32 nPos = pEnum->nEnumValues; nPos--; ) + { + rtl_uString_release( pEnum->ppEnumNames[nPos] ); + } + delete [] pEnum->ppEnumNames; + delete [] pEnum->pEnumValues; + } + break; + default: + break; + } +} + + +extern "C" void SAL_CALL typelib_typedescription_release( + typelib_TypeDescription * pTD ) + SAL_THROW_EXTERN_C() +{ + sal_Int32 ref = osl_atomic_decrement( &pTD->nRefCount ); + OSL_ASSERT(ref >= 0); + if (0 == ref) + { + TypeDescriptor_Init_Impl &rInit = Init::get(); + if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pTD->eTypeClass ) ) + { + if( pTD->pWeakRef ) + { + { + MutexGuard aGuard( rInit.getMutex() ); + // remove this description from the weak reference + pTD->pWeakRef->pType = nullptr; + } + typelib_typedescriptionreference_release( pTD->pWeakRef ); + } + } + else + { + // this description is a reference too, so remove it from the hash table + if( rInit.pWeakMap ) + { + MutexGuard aGuard( rInit.getMutex() ); + WeakMap_Impl::iterator aIt = rInit.pWeakMap->find( pTD->pTypeName->buffer ); + if( aIt != rInit.pWeakMap->end() && static_cast<void *>((*aIt).second) == static_cast<void *>(pTD) ) + { + // remove only if it contains the same object + rInit.pWeakMap->erase( aIt ); + } + } + } + + typelib_typedescription_destructExtendedMembers( pTD ); + rtl_uString_release( pTD->pTypeName ); + +#if OSL_DEBUG_LEVEL > 0 + switch( pTD->eTypeClass ) + { + case typelib_TypeClass_SEQUENCE: + osl_atomic_decrement( &rInit.nIndirectTypeDescriptionCount ); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + osl_atomic_decrement( &rInit.nCompoundTypeDescriptionCount ); + break; + case typelib_TypeClass_INTERFACE: + osl_atomic_decrement( &rInit.nInterfaceTypeDescriptionCount ); + break; + case typelib_TypeClass_INTERFACE_METHOD: + osl_atomic_decrement( &rInit.nInterfaceMethodTypeDescriptionCount ); + break; + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + osl_atomic_decrement( &rInit.nInterfaceAttributeTypeDescriptionCount ); + break; + case typelib_TypeClass_ENUM: + osl_atomic_decrement( &rInit.nEnumTypeDescriptionCount ); + break; + default: + osl_atomic_decrement( &rInit.nTypeDescriptionCount ); + } +#endif + + freeTypeDescription(pTD); + } +} + + +extern "C" void SAL_CALL typelib_typedescription_register( + typelib_TypeDescription ** ppNewDescription ) + SAL_THROW_EXTERN_C() +{ + // connect the description with the weak reference + TypeDescriptor_Init_Impl &rInit = Init::get(); + ClearableMutexGuard aGuard( rInit.getMutex() ); + + typelib_TypeDescriptionReference * pTDR = nullptr; + typelib_typedescriptionreference_getByName( &pTDR, (*ppNewDescription)->pTypeName ); + + OSL_ASSERT( (*ppNewDescription)->pWeakRef || TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( (*ppNewDescription)->eTypeClass ) ); + if( pTDR ) + { + OSL_ASSERT( (*ppNewDescription)->eTypeClass == pTDR->eTypeClass ); + if( pTDR->pType ) + { + if (TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pTDR->eTypeClass )) + { + // pRef->pType->pWeakRef == 0 means that the description is empty + if (pTDR->pType->pWeakRef) + { + if (osl_atomic_increment( &pTDR->pType->nRefCount ) > 1) + { + // The reference is incremented. The object cannot be destroyed. + // Release the guard at the earliest point. + aGuard.clear(); + ::typelib_typedescription_release( *ppNewDescription ); + *ppNewDescription = pTDR->pType; + ::typelib_typedescriptionreference_release( pTDR ); + return; + } + // destruction of this type in progress (another thread!) + (void)osl_atomic_decrement( &pTDR->pType->nRefCount ); + } + // take new descr + pTDR->pType = *ppNewDescription; + OSL_ASSERT( ! (*ppNewDescription)->pWeakRef ); + (*ppNewDescription)->pWeakRef = pTDR; + return; + } + // !reallyWeak + + if ((static_cast<void *>(pTDR) != static_cast<void *>(*ppNewDescription)) && // if different + (!pTDR->pType->pWeakRef || // uninit: ref data only set + // new one is complete: + (!pTDR->pType->bComplete && (*ppNewDescription)->bComplete) || + // new one may be partly initialized interface (except of tables): + (typelib_TypeClass_INTERFACE == pTDR->pType->eTypeClass && + !reinterpret_cast<typelib_InterfaceTypeDescription *>(pTDR->pType)->ppAllMembers && + (*reinterpret_cast<typelib_InterfaceTypeDescription **>(ppNewDescription))->ppAllMembers))) + { + // uninitialized or incomplete + + if (pTDR->pType->pWeakRef) // if init + { + switch (pTDR->pType->eTypeClass) { + case typelib_TypeClass_ENUM: + { + auto const src = reinterpret_cast<typelib_EnumTypeDescription *>( + *ppNewDescription); + auto const dst = reinterpret_cast<typelib_EnumTypeDescription *>( + pTDR->pType); + assert(dst->nEnumValues == 0); + assert(dst->ppEnumNames == nullptr); + assert(dst->pEnumValues == nullptr); + std::swap(src->nEnumValues, dst->nEnumValues); + std::swap(src->ppEnumNames, dst->ppEnumNames); + std::swap(src->pEnumValues, dst->pEnumValues); + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + auto const src = reinterpret_cast<typelib_CompoundTypeDescription *>( + *ppNewDescription); + auto const dst = reinterpret_cast<typelib_CompoundTypeDescription *>( + pTDR->pType); + assert( + (dst->pBaseTypeDescription == nullptr) + == (src->pBaseTypeDescription == nullptr)); + assert(dst->nMembers == src->nMembers); + assert((dst->pMemberOffsets == nullptr) == (dst->nMembers == 0)); + assert((dst->ppTypeRefs == nullptr) == (dst->nMembers == 0)); + assert(dst->ppMemberNames == nullptr); + assert( + pTDR->pType->eTypeClass != typelib_TypeClass_STRUCT + || ((reinterpret_cast<typelib_StructTypeDescription *>( + dst)->pParameterizedTypes + == nullptr) + == (reinterpret_cast<typelib_StructTypeDescription *>( + src)->pParameterizedTypes + == nullptr))); + std::swap(src->ppMemberNames, dst->ppMemberNames); + break; + } + case typelib_TypeClass_INTERFACE: + { + auto const src = reinterpret_cast<typelib_InterfaceTypeDescription *>( + *ppNewDescription); + auto const dst = reinterpret_cast<typelib_InterfaceTypeDescription *>( + pTDR->pType); + assert( + (dst->pBaseTypeDescription == nullptr) + == (src->pBaseTypeDescription == nullptr)); + assert(dst->nMembers == 0); + assert(dst->ppMembers == nullptr); + assert(dst->nAllMembers == 0); + assert(dst->ppAllMembers == nullptr); + assert(dst->pMapMemberIndexToFunctionIndex == nullptr); + assert(dst->nMapFunctionIndexToMemberIndex == 0); + assert(dst->pMapFunctionIndexToMemberIndex == nullptr); + assert(dst->nBaseTypes == src->nBaseTypes); + assert((dst->ppBaseTypes == nullptr) == (src->ppBaseTypes == nullptr)); + std::swap(src->nMembers, dst->nMembers); + std::swap(src->ppMembers, dst->ppMembers); + std::swap(src->nAllMembers, dst->nAllMembers); + std::swap(src->ppAllMembers, dst->ppAllMembers); + std::swap( + src->pMapMemberIndexToFunctionIndex, + dst->pMapMemberIndexToFunctionIndex); + std::swap( + src->nMapFunctionIndexToMemberIndex, + dst->nMapFunctionIndexToMemberIndex); + std::swap( + src->pMapFunctionIndexToMemberIndex, + dst->pMapFunctionIndexToMemberIndex); + break; + } + default: + assert(false); // this cannot happen + } + } + else + { + // pTDR->pType->pWeakRef == 0 means that the description is empty + // description is not weak and the not the same + sal_Int32 nSize = getDescriptionSize( (*ppNewDescription)->eTypeClass ); + + // copy all specific data for the descriptions + memcpy( + pTDR->pType +1, + *ppNewDescription +1, + nSize - sizeof(typelib_TypeDescription) ); + + memset( + *ppNewDescription +1, + 0, + nSize - sizeof( typelib_TypeDescription ) ); + } + + pTDR->pType->bComplete = (*ppNewDescription)->bComplete; + pTDR->pType->nSize = (*ppNewDescription)->nSize; + pTDR->pType->nAlignment = (*ppNewDescription)->nAlignment; + + if( pTDR->pType->bOnDemand && !(*ppNewDescription)->bOnDemand ) + { + // switch from OnDemand to !OnDemand, so the description must be acquired + typelib_typedescription_acquire( pTDR->pType ); + } + else if( !pTDR->pType->bOnDemand && (*ppNewDescription)->bOnDemand ) + { + // switch from !OnDemand to OnDemand, so the description must be released + assert(pTDR->pType->nRefCount > 1); + // coverity[freed_arg] - pType's nRefCount is > 1 here + typelib_typedescription_release( pTDR->pType ); + } + + pTDR->pType->bOnDemand = (*ppNewDescription)->bOnDemand; + // initialized + pTDR->pType->pWeakRef = pTDR; + } + + typelib_typedescription_release( *ppNewDescription ); + // pTDR was acquired by getByName(), so it must not be acquired again + *ppNewDescription = pTDR->pType; + return; + } + } + else if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( (*ppNewDescription)->eTypeClass) ) + { + typelib_typedescriptionreference_new( + &pTDR, (*ppNewDescription)->eTypeClass, (*ppNewDescription)->pTypeName ); + } + else + { + pTDR = reinterpret_cast<typelib_TypeDescriptionReference *>(*ppNewDescription); + if( !rInit.pWeakMap ) + rInit.pWeakMap.reset( new WeakMap_Impl ); + + // description is the weak itself, so register it + (*rInit.pWeakMap)[pTDR->pTypeName->buffer] = pTDR; + OSL_ASSERT( static_cast<void *>(*ppNewDescription) == static_cast<void *>(pTDR) ); + } + + // By default this reference is not really weak. The reference hold the description + // and the description hold the reference. + if( !(*ppNewDescription)->bOnDemand ) + { + // nor OnDemand so the description must be acquired if registered + typelib_typedescription_acquire( *ppNewDescription ); + } + + pTDR->pType = *ppNewDescription; + (*ppNewDescription)->pWeakRef = pTDR; + OSL_ASSERT( rtl_ustr_compare( pTDR->pTypeName->buffer, (*ppNewDescription)->pTypeName->buffer ) == 0 ); + OSL_ASSERT( pTDR->eTypeClass == (*ppNewDescription)->eTypeClass ); +} + + +static bool type_equals( + typelib_TypeDescriptionReference const * p1, typelib_TypeDescriptionReference const * p2 ) +{ + return (p1 == p2 || + (p1->eTypeClass == p2->eTypeClass && + p1->pTypeName->length == p2->pTypeName->length && + rtl_ustr_compare( p1->pTypeName->buffer, p2->pTypeName->buffer ) == 0)); +} +extern "C" sal_Bool SAL_CALL typelib_typedescription_equals( + const typelib_TypeDescription * p1, const typelib_TypeDescription * p2 ) + SAL_THROW_EXTERN_C() +{ + return type_equals( + reinterpret_cast<typelib_TypeDescriptionReference const *>(p1), reinterpret_cast<typelib_TypeDescriptionReference const *>(p2) ); +} + + +extern "C" sal_Int32 typelib_typedescription_getAlignedUnoSize( + const typelib_TypeDescription * pTypeDescription, + sal_Int32 nOffset, sal_Int32 & rMaxIntegralTypeSize ) + SAL_THROW_EXTERN_C() +{ + sal_Int32 nSize; + if( pTypeDescription->nSize ) + { + // size and alignment are set + rMaxIntegralTypeSize = pTypeDescription->nAlignment; + nSize = pTypeDescription->nSize; + } + else + { + nSize = 0; + rMaxIntegralTypeSize = 1; + + OSL_ASSERT( typelib_TypeClass_TYPEDEF != pTypeDescription->eTypeClass ); + + switch( pTypeDescription->eTypeClass ) + { + case typelib_TypeClass_INTERFACE: + // FEATURE_INTERFACE + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( void * )); + break; + case typelib_TypeClass_ENUM: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( typelib_TypeClass )); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + // FEATURE_EMPTYCLASS + { + typelib_CompoundTypeDescription const * pTmp = reinterpret_cast<typelib_CompoundTypeDescription const *>(pTypeDescription); + sal_Int32 nStructSize = 0; + if( pTmp->pBaseTypeDescription ) + { + // inherit structs extends the base struct. + nStructSize = pTmp->pBaseTypeDescription->aBase.nSize; + rMaxIntegralTypeSize = pTmp->pBaseTypeDescription->aBase.nAlignment; + } + for( sal_Int32 i = 0; i < pTmp->nMembers; i++ ) + { + typelib_TypeDescription * pMemberType = nullptr; + typelib_TypeDescriptionReference * pMemberRef = pTmp->ppTypeRefs[i]; + + sal_Int32 nMaxIntegral; + if (pMemberRef->eTypeClass == typelib_TypeClass_INTERFACE + || pMemberRef->eTypeClass == typelib_TypeClass_SEQUENCE) + { + nMaxIntegral = sal_Int32(sizeof(void *)); + nStructSize = newAlignedSize( nStructSize, nMaxIntegral, nMaxIntegral ); + } + else + { + TYPELIB_DANGER_GET( &pMemberType, pMemberRef ); + nStructSize = typelib_typedescription_getAlignedUnoSize( + pMemberType, nStructSize, nMaxIntegral ); + TYPELIB_DANGER_RELEASE( pMemberType ); + } + if( nMaxIntegral > rMaxIntegralTypeSize ) + rMaxIntegralTypeSize = nMaxIntegral; + } +#ifdef __m68k__ + // Anything that is at least 16 bits wide is aligned on a 16-bit + // boundary on the m68k default abi + sal_Int32 nMaxAlign = std::min(rMaxIntegralTypeSize, sal_Int32( 2 )); + nStructSize = (nStructSize + nMaxAlign -1) / nMaxAlign * nMaxAlign; +#else + // Example: A { double; int; } structure has a size of 16 instead of 10. The + // compiler must follow this rule if it is possible to access members in arrays through: + // (Element *)((char *)pArray + sizeof( Element ) * ElementPos) + nStructSize = (nStructSize + rMaxIntegralTypeSize -1) + / rMaxIntegralTypeSize * rMaxIntegralTypeSize; +#endif + nSize += nStructSize; + } + break; + case typelib_TypeClass_SEQUENCE: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( void * )); + break; + case typelib_TypeClass_ANY: + // FEATURE_ANY + nSize = sal_Int32(sizeof( uno_Any )); + rMaxIntegralTypeSize = sal_Int32(sizeof( void * )); + break; + case typelib_TypeClass_TYPE: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( typelib_TypeDescriptionReference * )); + break; + case typelib_TypeClass_BOOLEAN: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Bool )); + break; + case typelib_TypeClass_CHAR: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Unicode )); + break; + case typelib_TypeClass_STRING: + // FEATURE_STRING + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( rtl_uString * )); + break; + case typelib_TypeClass_FLOAT: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( float )); + break; + case typelib_TypeClass_DOUBLE: +#ifdef AIX + //See previous AIX ifdef comment for an explanation + nSize = (sal_Int32)(sizeof(double)); + rMaxIntegralTypeSize = (sal_Int32)(sizeof(void*)); +#else + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( double )); +#endif + break; + case typelib_TypeClass_BYTE: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int8 )); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int16 )); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int32 )); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + nSize = rMaxIntegralTypeSize = sal_Int32(sizeof( sal_Int64 )); + break; + case typelib_TypeClass_UNKNOWN: + case typelib_TypeClass_SERVICE: + case typelib_TypeClass_MODULE: + default: + OSL_FAIL( "not convertible type" ); + }; + } + + return newAlignedSize( nOffset, nSize, rMaxIntegralTypeSize ); +} + + +namespace { + +typelib_TypeDescriptionReference ** copyExceptions( + sal_Int32 count, typelib_TypeDescriptionReference ** source) +{ + typelib_TypeDescriptionReference ** p + = new typelib_TypeDescriptionReference *[count]; + for (sal_Int32 i = 0; i < count; ++i) { + p[i] = source[i]; + typelib_typedescriptionreference_acquire(p[i]); + } + return p; +} + +bool createDerivedInterfaceMemberDescription( + typelib_TypeDescription ** result, OUString const & name, + typelib_TypeDescriptionReference * baseRef, + typelib_TypeDescription const * base, typelib_TypeDescription * interface, + sal_Int32 index, sal_Int32 position) +{ + if (baseRef != nullptr && base != nullptr && interface != nullptr) { + switch (base->eTypeClass) { + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_typedescription_newEmpty( + result, typelib_TypeClass_INTERFACE_METHOD, name.pData); + typelib_InterfaceMethodTypeDescription const * baseMethod + = reinterpret_cast< + typelib_InterfaceMethodTypeDescription const * >(base); + typelib_InterfaceMethodTypeDescription * newMethod + = reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >(*result); + newMethod->aBase.nPosition = position; + newMethod->aBase.pMemberName + = baseMethod->aBase.pMemberName; + rtl_uString_acquire( + newMethod->aBase.pMemberName); + newMethod->pReturnTypeRef = baseMethod->pReturnTypeRef; + typelib_typedescriptionreference_acquire( + newMethod->pReturnTypeRef); + newMethod->nParams = baseMethod->nParams; + newMethod->pParams = new typelib_MethodParameter[ + newMethod->nParams]; + for (sal_Int32 i = 0; i < newMethod->nParams; ++i) { + newMethod->pParams[i].pName + = baseMethod->pParams[i].pName; + rtl_uString_acquire( + newMethod->pParams[i].pName); + newMethod->pParams[i].pTypeRef + = baseMethod->pParams[i].pTypeRef; + typelib_typedescriptionreference_acquire( + newMethod->pParams[i].pTypeRef); + newMethod->pParams[i].bIn = baseMethod->pParams[i].bIn; + newMethod->pParams[i].bOut = baseMethod->pParams[i].bOut; + } + newMethod->nExceptions = baseMethod->nExceptions; + newMethod->ppExceptions = copyExceptions( + baseMethod->nExceptions, baseMethod->ppExceptions); + newMethod->bOneWay = baseMethod->bOneWay; + newMethod->pInterface + = reinterpret_cast< typelib_InterfaceTypeDescription * >( + interface); + newMethod->pBaseRef = baseRef; + newMethod->nIndex = index; + return true; + } + + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_typedescription_newEmpty( + result, typelib_TypeClass_INTERFACE_ATTRIBUTE, name.pData); + typelib_InterfaceAttributeTypeDescription const * baseAttribute + = reinterpret_cast< + typelib_InterfaceAttributeTypeDescription const * >(base); + typelib_InterfaceAttributeTypeDescription * newAttribute + = reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >(*result); + newAttribute->aBase.nPosition = position; + newAttribute->aBase.pMemberName + = baseAttribute->aBase.pMemberName; + rtl_uString_acquire(newAttribute->aBase.pMemberName); + newAttribute->bReadOnly = baseAttribute->bReadOnly; + newAttribute->pAttributeTypeRef + = baseAttribute->pAttributeTypeRef; + typelib_typedescriptionreference_acquire(newAttribute->pAttributeTypeRef); + newAttribute->pInterface + = reinterpret_cast< typelib_InterfaceTypeDescription * >( + interface); + newAttribute->pBaseRef = baseRef; + newAttribute->nIndex = index; + newAttribute->nGetExceptions = baseAttribute->nGetExceptions; + newAttribute->ppGetExceptions = copyExceptions( + baseAttribute->nGetExceptions, + baseAttribute->ppGetExceptions); + newAttribute->nSetExceptions = baseAttribute->nSetExceptions; + newAttribute->ppSetExceptions = copyExceptions( + baseAttribute->nSetExceptions, + baseAttribute->ppSetExceptions); + return true; + } + + default: + break; + } + } + return false; +} + +} + +extern "C" void SAL_CALL typelib_typedescription_getByName( + typelib_TypeDescription ** ppRet, rtl_uString * pName ) + SAL_THROW_EXTERN_C() +{ + if( *ppRet ) + { + typelib_typedescription_release( *ppRet ); + *ppRet = nullptr; + } + + static bool bInited = false; + TypeDescriptor_Init_Impl &rInit = Init::get(); + + if( !bInited ) + { + // guard against multi thread access + MutexGuard aGuard( rInit.getMutex() ); + if( !bInited ) + { + // avoid recursion during the next ...new calls + bInited = true; + + typelib_TypeDescription * pType = nullptr; + typelib_typedescription_new( &pType, typelib_TypeClass_TYPE, OUString("type").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_VOID, OUString("void").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_BOOLEAN, OUString("boolean").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_CHAR, OUString("char").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_BYTE, OUString("byte").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_STRING, OUString("string").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_SHORT, OUString("short").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_UNSIGNED_SHORT, OUString("unsigned short").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_LONG, OUString("long").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_UNSIGNED_LONG, OUString("unsigned long").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_HYPER, OUString("hyper").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_UNSIGNED_HYPER, OUString("unsigned hyper").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_FLOAT, OUString("float").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_DOUBLE, OUString("double").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_new( &pType, typelib_TypeClass_ANY, OUString("any").pData, nullptr, 0, nullptr ); + typelib_typedescription_register( &pType ); + typelib_typedescription_release( pType ); + } + } + + typelib_TypeDescriptionReference * pTDR = nullptr; + typelib_typedescriptionreference_getByName( &pTDR, pName ); + if( pTDR ) + { + { + // guard against multi thread access + MutexGuard aGuard( rInit.getMutex() ); + // pTDR->pType->pWeakRef == 0 means that the description is empty + if( pTDR->pType && pTDR->pType->pWeakRef ) + { + typelib_typedescription_acquire( pTDR->pType ); + *ppRet = pTDR->pType; + } + } + typelib_typedescriptionreference_release( pTDR ); + } + + if (nullptr != *ppRet) + return; + + // check for sequence + OUString const & name = OUString::unacquired( &pName ); + if (2 < name.getLength() && '[' == name[ 0 ]) + { + OUString element_name( name.copy( 2 ) ); + typelib_TypeDescription * element_td = nullptr; + typelib_typedescription_getByName( &element_td, element_name.pData ); + if (nullptr != element_td) + { + typelib_typedescription_new( + ppRet, typelib_TypeClass_SEQUENCE, pName, element_td->pWeakRef, 0, nullptr ); + // register? + typelib_typedescription_release( element_td ); + } + } + if (nullptr == *ppRet) + { + // Check for derived interface member type: + sal_Int32 i1 = name.lastIndexOf(":@"); + if (i1 >= 0) { + sal_Int32 i2 = i1 + RTL_CONSTASCII_LENGTH(":@"); + sal_Int32 i3 = name.indexOf(',', i2); + if (i3 >= 0) { + sal_Int32 i4 = name.indexOf(':', i3); + if (i4 >= 0) { + typelib_TypeDescriptionReference * pBaseRef = nullptr; + typelib_TypeDescription * pBase = nullptr; + typelib_TypeDescription * pInterface = nullptr; + typelib_typedescriptionreference_getByName( + &pBaseRef, name.copy(0, i1).pData); + if (pBaseRef != nullptr) { + typelib_typedescriptionreference_getDescription( + &pBase, pBaseRef); + } + typelib_typedescription_getByName( + &pInterface, name.copy(i4 + 1).pData); + if (!createDerivedInterfaceMemberDescription( + ppRet, name, pBaseRef, pBase, pInterface, + name.copy(i2, i3 - i2).toInt32(), + name.copy(i3 + 1, i4 - i3 - 1).toInt32())) + { + if (pInterface != nullptr) { + typelib_typedescription_release(pInterface); + } + if (pBase != nullptr) { + typelib_typedescription_release(pBase); + } + if (pBaseRef != nullptr) { + typelib_typedescriptionreference_release( + pBaseRef); + } + } + } + } + } + } + if (nullptr == *ppRet) + { + // on demand access + rInit.callChain( ppRet, pName ); + } + + if( !(*ppRet) ) + return; + + // typedescription found + if (typelib_TypeClass_TYPEDEF == (*ppRet)->eTypeClass) + { + typelib_TypeDescription * pTD = nullptr; + typelib_typedescriptionreference_getDescription( + &pTD, reinterpret_cast<typelib_IndirectTypeDescription *>(*ppRet)->pType ); + typelib_typedescription_release( *ppRet ); + *ppRet = pTD; + } + else + { + // set to on demand + (*ppRet)->bOnDemand = true; + // The type description is hold by the reference until + // on demand is activated. + typelib_typedescription_register( ppRet ); + + // insert into the cache + MutexGuard aGuard( rInit.getMutex() ); + if( !rInit.pCache ) + rInit.pCache.reset( new TypeDescriptionList_Impl ); + if( static_cast<sal_Int32>(rInit.pCache->size()) >= nCacheSize ) + { + typelib_typedescription_release( rInit.pCache->front() ); + rInit.pCache->pop_front(); + } + // descriptions in the cache must be acquired! + typelib_typedescription_acquire( *ppRet ); + rInit.pCache->push_back( *ppRet ); + } +} + +extern "C" void SAL_CALL typelib_typedescriptionreference_newByAsciiName( + typelib_TypeDescriptionReference ** ppTDR, + typelib_TypeClass eTypeClass, + const char * pTypeName ) + SAL_THROW_EXTERN_C() +{ + OUString aTypeName( OUString::createFromAscii( pTypeName ) ); + typelib_typedescriptionreference_new( ppTDR, eTypeClass, aTypeName.pData ); +} + +extern "C" void SAL_CALL typelib_typedescriptionreference_new( + typelib_TypeDescriptionReference ** ppTDR, + typelib_TypeClass eTypeClass, rtl_uString * pTypeName ) + SAL_THROW_EXTERN_C() +{ + TypeDescriptor_Init_Impl &rInit = Init::get(); + if( eTypeClass == typelib_TypeClass_TYPEDEF ) + { + // on demand access + typelib_TypeDescription * pRet = nullptr; + rInit.callChain( &pRet, pTypeName ); + if( pRet ) + { + // typedescription found + if (typelib_TypeClass_TYPEDEF == pRet->eTypeClass) + { + typelib_typedescriptionreference_acquire( + reinterpret_cast<typelib_IndirectTypeDescription *>(pRet)->pType ); + if (*ppTDR) + typelib_typedescriptionreference_release( *ppTDR ); + *ppTDR = reinterpret_cast<typelib_IndirectTypeDescription *>(pRet)->pType; + typelib_typedescription_release( pRet ); + } + else + { + // set to on demand + pRet->bOnDemand = true; + // The type description is hold by the reference until + // on demand is activated. + typelib_typedescription_register( &pRet ); + + // insert into the cache + MutexGuard aGuard( rInit.getMutex() ); + if( !rInit.pCache ) + rInit.pCache.reset( new TypeDescriptionList_Impl ); + if( static_cast<sal_Int32>(rInit.pCache->size()) >= nCacheSize ) + { + typelib_typedescription_release( rInit.pCache->front() ); + rInit.pCache->pop_front(); + } + rInit.pCache->push_back( pRet ); + // pRet kept acquired for cache + + typelib_typedescriptionreference_acquire( pRet->pWeakRef ); + if (*ppTDR) + typelib_typedescriptionreference_release( *ppTDR ); + *ppTDR = pRet->pWeakRef; + } + } + else if (*ppTDR) + { + SAL_INFO("cppu.typelib", "typedef not found : " << pTypeName); + typelib_typedescriptionreference_release( *ppTDR ); + *ppTDR = nullptr; + } + return; + } + + MutexGuard aGuard( rInit.getMutex() ); + typelib_typedescriptionreference_getByName( ppTDR, pTypeName ); + if( *ppTDR ) + return; + + if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( eTypeClass ) ) + { + typelib_TypeDescriptionReference * pTDR = new typelib_TypeDescriptionReference; +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_increment( &rInit.nTypeDescriptionReferenceCount ); +#endif + pTDR->nRefCount = 1; + pTDR->nStaticRefCount = 0; + pTDR->eTypeClass = eTypeClass; + pTDR->pUniqueIdentifier = nullptr; + pTDR->pReserved = nullptr; + pTDR->pTypeName = pTypeName; + rtl_uString_acquire( pTDR->pTypeName ); + pTDR->pType = nullptr; + *ppTDR = pTDR; + } + else + { + typelib_typedescription_newEmpty( reinterpret_cast<typelib_TypeDescription ** >(ppTDR), eTypeClass, pTypeName ); + // description will be registered but not acquired + (*reinterpret_cast<typelib_TypeDescription **>(ppTDR))->bOnDemand = true; + (*reinterpret_cast<typelib_TypeDescription **>(ppTDR))->bComplete = false; + } + + if( !rInit.pWeakMap ) + rInit.pWeakMap.reset( new WeakMap_Impl ); + // Heavy hack, the const sal_Unicode * is hold by the typedescription reference + // not registered + rInit.pWeakMap->operator[]( (*ppTDR)->pTypeName->buffer ) = *ppTDR; +} + + +extern "C" void SAL_CALL typelib_typedescriptionreference_acquire( + typelib_TypeDescriptionReference * pRef ) + SAL_THROW_EXTERN_C() +{ + osl_atomic_increment( &pRef->nRefCount ); +} + + +extern "C" void SAL_CALL typelib_typedescriptionreference_release( + typelib_TypeDescriptionReference * pRef ) + SAL_THROW_EXTERN_C() +{ + // Is it a type description? + if( TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pRef->eTypeClass ) ) + { + if( ! osl_atomic_decrement( &pRef->nRefCount ) ) + { + TypeDescriptor_Init_Impl &rInit = Init::get(); + if( rInit.pWeakMap ) + { + MutexGuard aGuard( rInit.getMutex() ); + WeakMap_Impl::iterator aIt = rInit.pWeakMap->find( pRef->pTypeName->buffer ); + if( aIt != rInit.pWeakMap->end() && (*aIt).second == pRef ) + { + // remove only if it contains the same object + rInit.pWeakMap->erase( aIt ); + } + } + + rtl_uString_release( pRef->pTypeName ); + OSL_ASSERT( pRef->pType == nullptr ); +#if OSL_DEBUG_LEVEL > 0 + osl_atomic_decrement( &rInit.nTypeDescriptionReferenceCount ); +#endif + delete pRef; + } + } + else + { + typelib_typedescription_release( reinterpret_cast<typelib_TypeDescription *>(pRef) ); + } +} + + +extern "C" void SAL_CALL typelib_typedescriptionreference_getDescription( + typelib_TypeDescription ** ppRet, typelib_TypeDescriptionReference * pRef ) + SAL_THROW_EXTERN_C() +{ + if( *ppRet ) + { + typelib_typedescription_release( *ppRet ); + *ppRet = nullptr; + } + + if( !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK( pRef->eTypeClass ) && pRef->pType && pRef->pType->pWeakRef ) + { + // reference is a description and initialized + osl_atomic_increment( &reinterpret_cast<typelib_TypeDescription *>(pRef)->nRefCount ); + *ppRet = reinterpret_cast<typelib_TypeDescription *>(pRef); + return; + } + + { + MutexGuard aGuard( Init::get().getMutex() ); + // pRef->pType->pWeakRef == 0 means that the description is empty + if( pRef->pType && pRef->pType->pWeakRef ) + { + sal_Int32 n = osl_atomic_increment( &pRef->pType->nRefCount ); + if( n > 1 ) + { + // The reference is incremented. The object cannot be destroyed. + // Release the guard at the earliest point. + *ppRet = pRef->pType; + return; + } + (void)osl_atomic_decrement( &pRef->pType->nRefCount ); + // destruction of this type in progress (another thread!) + // no access through this weak reference + pRef->pType = nullptr; + } + } + + typelib_typedescription_getByName( ppRet, pRef->pTypeName ); + OSL_ASSERT( !*ppRet || rtl_ustr_compare( pRef->pTypeName->buffer, (*ppRet)->pTypeName->buffer ) == 0 ); + OSL_ASSERT( !*ppRet || pRef->eTypeClass == (*ppRet)->eTypeClass ); + OSL_ASSERT( !*ppRet || pRef == (*ppRet)->pWeakRef ); + pRef->pType = *ppRet; +} + + +extern "C" void typelib_typedescriptionreference_getByName( + typelib_TypeDescriptionReference ** ppRet, rtl_uString const * pName ) + SAL_THROW_EXTERN_C() +{ + if( *ppRet ) + { + typelib_typedescriptionreference_release( *ppRet ); + *ppRet = nullptr; + } + TypeDescriptor_Init_Impl &rInit = Init::get(); + if( !rInit.pWeakMap ) + return; + + MutexGuard aGuard( rInit.getMutex() ); + WeakMap_Impl::const_iterator aIt = rInit.pWeakMap->find( pName->buffer ); + if( aIt == rInit.pWeakMap->end() ) + return; + + sal_Int32 n = osl_atomic_increment( &(*aIt).second->nRefCount ); + if( n > 1 ) + { + // The reference is incremented. The object cannot be destroyed. + // Release the guard at the earliest point. + *ppRet = (*aIt).second; + } + else + { + // destruction of this type in progress (another thread!) + // no access through this weak reference + (void)osl_atomic_decrement( &(*aIt).second->nRefCount ); + } +} + + +extern "C" sal_Bool SAL_CALL typelib_typedescriptionreference_equals( + const typelib_TypeDescriptionReference * p1, + const typelib_TypeDescriptionReference * p2 ) + SAL_THROW_EXTERN_C() +{ + return (p1 == p2 || + (p1->eTypeClass == p2->eTypeClass && + p1->pTypeName->length == p2->pTypeName->length && + rtl_ustr_compare( p1->pTypeName->buffer, p2->pTypeName->buffer ) == 0)); +} + + +extern "C" void SAL_CALL typelib_typedescriptionreference_assign( + typelib_TypeDescriptionReference ** ppDest, + typelib_TypeDescriptionReference * pSource ) + SAL_THROW_EXTERN_C() +{ + if (*ppDest != pSource) + { + ::typelib_typedescriptionreference_acquire( pSource ); + ::typelib_typedescriptionreference_release( *ppDest ); + *ppDest = pSource; + } +} + + +extern "C" void SAL_CALL typelib_setCacheSize( sal_Int32 nNewSize ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( nNewSize >= 0, "### illegal cache size given!" ); + if (nNewSize < 0) + return; + + TypeDescriptor_Init_Impl &rInit = Init::get(); + MutexGuard aGuard( rInit.getMutex() ); + if ((nNewSize < nCacheSize) && rInit.pCache) + { + while (static_cast<sal_Int32>(rInit.pCache->size()) != nNewSize) + { + typelib_typedescription_release( rInit.pCache->front() ); + rInit.pCache->pop_front(); + } + } + nCacheSize = nNewSize; +} + + +static const bool s_aAssignableFromTab[11][11] = +{ + /* from CH, BO, BY, SH, US, LO, UL, HY, UH, FL, DO */ +/* TypeClass_CHAR */ { true, false, false, false, false, false, false, false, false, false, false }, +/* TypeClass_BOOLEAN */ { false, true, false, false, false, false, false, false, false, false, false }, +/* TypeClass_BYTE */ { false, false, true, false, false, false, false, false, false, false, false }, +/* TypeClass_SHORT */ { false, false, true, true, true, false, false, false, false, false, false }, +/* TypeClass_UNSIGNED_SHORT */ { false, false, true, true, true, false, false, false, false, false, false }, +/* TypeClass_LONG */ { false, false, true, true, true, true, true, false, false, false, false }, +/* TypeClass_UNSIGNED_LONG */ { false, false, true, true, true, true, true, false, false, false, false }, +/* TypeClass_HYPER */ { false, false, true, true, true, true, true, true, true, false, false }, +/* TypeClass_UNSIGNED_HYPER */ { false, false, true, true, true, true, true, true, true, false, false }, +/* TypeClass_FLOAT */ { false, false, true, true, true, false, false, false, false, true, false }, +/* TypeClass_DOUBLE */ { false, false, true, true, true, true, true, false, false, true, true } +}; + + +extern "C" sal_Bool SAL_CALL typelib_typedescriptionreference_isAssignableFrom( + typelib_TypeDescriptionReference * pAssignable, + typelib_TypeDescriptionReference * pFrom ) + SAL_THROW_EXTERN_C() +{ + if (pAssignable && pFrom) + { + typelib_TypeClass eAssignable = pAssignable->eTypeClass; + typelib_TypeClass eFrom = pFrom->eTypeClass; + + if (eAssignable == typelib_TypeClass_ANY) // anything can be assigned to an any .) + return true; + if (eAssignable == eFrom) + { + if (type_equals( pAssignable, pFrom )) // first shot + { + return true; + } + switch (eAssignable) + { + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pFromDescr = nullptr; + TYPELIB_DANGER_GET( &pFromDescr, pFrom ); + if (!reinterpret_cast<typelib_CompoundTypeDescription *>(pFromDescr)->pBaseTypeDescription) + { + TYPELIB_DANGER_RELEASE( pFromDescr ); + return false; + } + bool bRet = typelib_typedescriptionreference_isAssignableFrom( + pAssignable, + reinterpret_cast<typelib_CompoundTypeDescription *>(pFromDescr)->pBaseTypeDescription->aBase.pWeakRef ); + TYPELIB_DANGER_RELEASE( pFromDescr ); + return bRet; + } + case typelib_TypeClass_INTERFACE: + { + typelib_TypeDescription * pFromDescr = nullptr; + TYPELIB_DANGER_GET( &pFromDescr, pFrom ); + typelib_InterfaceTypeDescription * pFromIfc + = reinterpret_cast< + typelib_InterfaceTypeDescription * >(pFromDescr); + bool bRet = false; + for (sal_Int32 i = 0; i < pFromIfc->nBaseTypes; ++i) { + if (typelib_typedescriptionreference_isAssignableFrom( + pAssignable, + pFromIfc->ppBaseTypes[i]->aBase.pWeakRef)) + { + bRet = true; + break; + } + } + TYPELIB_DANGER_RELEASE( pFromDescr ); + return bRet; + } + default: + { + return false; + } + } + } + return (eAssignable >= typelib_TypeClass_CHAR && eAssignable <= typelib_TypeClass_DOUBLE && + eFrom >= typelib_TypeClass_CHAR && eFrom <= typelib_TypeClass_DOUBLE && + s_aAssignableFromTab[eAssignable-1][eFrom-1]); + } + return false; +} + +extern "C" sal_Bool SAL_CALL typelib_typedescription_isAssignableFrom( + typelib_TypeDescription * pAssignable, + typelib_TypeDescription * pFrom ) + SAL_THROW_EXTERN_C() +{ + return typelib_typedescriptionreference_isAssignableFrom( + pAssignable->pWeakRef, pFrom->pWeakRef ); +} + + +extern "C" sal_Bool SAL_CALL typelib_typedescription_complete( + typelib_TypeDescription ** ppTypeDescr ) + SAL_THROW_EXTERN_C() +{ + return complete(ppTypeDescr, true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/typelib/typelib.hxx b/cppu/source/typelib/typelib.hxx new file mode 100644 index 000000000..b10b6eba8 --- /dev/null +++ b/cppu/source/typelib/typelib.hxx @@ -0,0 +1,43 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_TYPELIB_HXX +#define INCLUDED_CPPU_SOURCE_TYPELIB_HXX + +extern "C" sal_Int32 typelib_typedescription_getAlignedUnoSize( + const typelib_TypeDescription * pTypeDescription, + sal_Int32 nOffset, + sal_Int32 & rMaxIntegralTypeSize ) + SAL_THROW_EXTERN_C(); + + +extern "C" void typelib_typedescription_newEmpty( + typelib_TypeDescription ** ppRet, + typelib_TypeClass eTypeClass, + rtl_uString * pTypeName ) + SAL_THROW_EXTERN_C(); + +extern "C" void typelib_typedescriptionreference_getByName( + typelib_TypeDescriptionReference ** ppRet, + rtl_uString const * pName ) + SAL_THROW_EXTERN_C(); + +#endif // INCLUDED_CPPU_SOURCE_TYPELIB_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/EnvDcp.cxx b/cppu/source/uno/EnvDcp.cxx new file mode 100644 index 000000000..c5597dec4 --- /dev/null +++ b/cppu/source/uno/EnvDcp.cxx @@ -0,0 +1,43 @@ +/* -*- 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 <uno/EnvDcp.h> + + +void uno_EnvDcp_getTypeName(rtl_uString const * pEnvDcp, rtl_uString ** ppEnvTypeName) +{ + sal_Int32 colIdx = rtl_ustr_indexOfChar_WithLength(pEnvDcp->buffer, pEnvDcp->length, ':'); + if (colIdx >= 0) + rtl_uString_newFromStr_WithLength(ppEnvTypeName, pEnvDcp->buffer, colIdx); + + else + rtl_uString_newFromStr(ppEnvTypeName, pEnvDcp->buffer); +} + +void uno_EnvDcp_getPurpose(rtl_uString const * pEnvDcp, rtl_uString ** ppEnvPurpose) +{ + sal_Int32 colIdx = rtl_ustr_indexOfChar_WithLength(pEnvDcp->buffer, pEnvDcp->length, ':'); + if (colIdx >= 0) + rtl_uString_newFromStr_WithLength(ppEnvPurpose, pEnvDcp->buffer + colIdx, pEnvDcp->length - colIdx); + + else + rtl_uString_new(ppEnvPurpose); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/EnvStack.cxx b/cppu/source/uno/EnvStack.cxx new file mode 100644 index 000000000..f6b11352c --- /dev/null +++ b/cppu/source/uno/EnvStack.cxx @@ -0,0 +1,385 @@ +/* -*- 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 <uno/environment.hxx> +#include <uno/lbnames.h> + +#include <cppu/EnvDcp.hxx> +#include <cppu/Enterable.hxx> + +#include <rtl/instance.hxx> + +#include <osl/thread.h> +#include <osl/thread.hxx> +#include <osl/mutex.hxx> + +#include <unordered_map> + +using namespace com::sun::star; + +namespace { + +struct oslThreadIdentifier_equal +{ + bool operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const; +}; + +} + +bool oslThreadIdentifier_equal::operator()(oslThreadIdentifier s1, oslThreadIdentifier s2) const +{ + bool result = s1 == s2; + + return result; +} + +namespace { + +struct oslThreadIdentifier_hash +{ + size_t operator()(oslThreadIdentifier s1) const; +}; + +} + +size_t oslThreadIdentifier_hash::operator()(oslThreadIdentifier s1) const +{ + return s1; +} + +typedef std::unordered_map<oslThreadIdentifier, + uno_Environment *, + oslThreadIdentifier_hash, + oslThreadIdentifier_equal> ThreadMap; + +namespace +{ + struct s_threadMap_mutex : public rtl::Static< osl::Mutex, s_threadMap_mutex > {}; + struct s_threadMap : public rtl::Static< ThreadMap, s_threadMap > {}; +} + +static void s_setCurrent(uno_Environment * pEnv) +{ + oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier(); + + osl::MutexGuard guard(s_threadMap_mutex::get()); + ThreadMap &rThreadMap = s_threadMap::get(); + if (pEnv) + { + rThreadMap[threadId] = pEnv; + } + else + { + ThreadMap::iterator iEnv = rThreadMap.find(threadId); + if( iEnv != rThreadMap.end()) + rThreadMap.erase(iEnv); + } +} + +static uno_Environment * s_getCurrent() +{ + uno_Environment * pEnv = nullptr; + + oslThreadIdentifier threadId = osl::Thread::getCurrentIdentifier(); + + osl::MutexGuard guard(s_threadMap_mutex::get()); + ThreadMap &rThreadMap = s_threadMap::get(); + ThreadMap::iterator iEnv = rThreadMap.find(threadId); + if(iEnv != rThreadMap.end()) + pEnv = iEnv->second; + + return pEnv; +} + + +extern "C" void SAL_CALL uno_getCurrentEnvironment(uno_Environment ** ppEnv, rtl_uString * pTypeName) + SAL_THROW_EXTERN_C() +{ + if (*ppEnv) + { + (*ppEnv)->release(*ppEnv); + *ppEnv = nullptr; + } + + OUString currPurpose; + + uno_Environment * pCurrEnv = s_getCurrent(); + if (pCurrEnv) // no environment means no purpose + currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName); + + if (pTypeName && rtl_uString_getLength(pTypeName)) + { + OUString envDcp = OUString::unacquired(&pTypeName) + currPurpose; + + uno_getEnvironment(ppEnv, envDcp.pData, nullptr); + } + else + { + if (pCurrEnv) + { + *ppEnv = pCurrEnv; + (*ppEnv)->acquire(*ppEnv); + } + else + { + OUString uno_envDcp(UNO_LB_UNO); + uno_getEnvironment(ppEnv, uno_envDcp.pData, nullptr); + } + } +} + +static OUString s_getPrefix(OUString const & str1, OUString const & str2) +{ + sal_Int32 nIndex1 = 0; + sal_Int32 nIndex2 = 0; + sal_Int32 sim = 0; + + OUString token1; + OUString token2; + + do + { + token1 = str1.getToken(0, ':', nIndex1); + token2 = str2.getToken(0, ':', nIndex2); + + if (token1 == token2) + sim += token1.getLength() + 1; + } + while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2); + + OUString result; + + if (sim) + result = str1.copy(0, sim - 1); + + return result; +} + +static int s_getNextEnv(uno_Environment ** ppEnv, uno_Environment * pCurrEnv, uno_Environment * pTargetEnv) +{ + int res = 0; + + OUString nextPurpose; + + OUString currPurpose; + if (pCurrEnv) + currPurpose = cppu::EnvDcp::getPurpose(pCurrEnv->pTypeName); + + OUString targetPurpose; + if (pTargetEnv) + targetPurpose = cppu::EnvDcp::getPurpose(pTargetEnv->pTypeName); + + OUString intermPurpose(s_getPrefix(currPurpose, targetPurpose)); + if (currPurpose.getLength() > intermPurpose.getLength()) + { + sal_Int32 idx = currPurpose.lastIndexOf(':'); + nextPurpose = currPurpose.copy(0, idx); + + res = -1; + } + else if (intermPurpose.getLength() < targetPurpose.getLength()) + { + sal_Int32 idx = targetPurpose.indexOf(':', intermPurpose.getLength() + 1); + if (idx == -1) + nextPurpose = targetPurpose; + + else + nextPurpose = targetPurpose.copy(0, idx); + + res = 1; + } + + if (!nextPurpose.isEmpty()) + { + OUString next_envDcp = UNO_LB_UNO + nextPurpose; + uno_getEnvironment(ppEnv, next_envDcp.pData, nullptr); + } + else + { + if (*ppEnv) + (*ppEnv)->release(*ppEnv); + + *ppEnv = nullptr; + } + + return res; +} + +extern "C" { static void s_pull(va_list * pParam) +{ + uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *); + va_list * pXparam = va_arg(*pParam, va_list *); + + pCallee(pXparam); +}} + +static void s_callInto_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam) +{ + cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved); + if (pEnterable) + pEnterable->callInto(s_pull, pCallee, pParam); + + else + pCallee(pParam); +} + +static void s_callInto(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...) +{ + va_list param; + + va_start(param, pCallee); + s_callInto_v(pEnv, pCallee, ¶m); + va_end(param); +} + +static void s_callOut_v(uno_Environment * pEnv, uno_EnvCallee * pCallee, va_list * pParam) +{ + cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved); + if (pEnterable) + pEnterable->callOut_v(pCallee, pParam); + + else + pCallee(pParam); +} + +static void s_callOut(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...) +{ + va_list param; + + va_start(param, pCallee); + s_callOut_v(pEnv, pCallee, ¶m); + va_end(param); +} + +static void s_environment_invoke_v(uno_Environment *, uno_Environment *, uno_EnvCallee *, va_list *); + +extern "C" { static void s_environment_invoke_vv(va_list * pParam) +{ + uno_Environment * pCurrEnv = va_arg(*pParam, uno_Environment *); + uno_Environment * pTargetEnv = va_arg(*pParam, uno_Environment *); + uno_EnvCallee * pCallee = va_arg(*pParam, uno_EnvCallee *); + va_list * pXparam = va_arg(*pParam, va_list *); + + s_environment_invoke_v(pCurrEnv, pTargetEnv, pCallee, pXparam); +}} + +static void s_environment_invoke_v(uno_Environment * pCurrEnv, uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam) +{ + uno_Environment * pNextEnv = nullptr; + switch(s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) + { + case -1: + s_setCurrent(pNextEnv); + s_callOut(pCurrEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam); + s_setCurrent(pCurrEnv); + break; + + case 0: { + uno_Environment * hld = s_getCurrent(); + s_setCurrent(pCurrEnv); + pCallee(pParam); + s_setCurrent(hld); + } + break; + + case 1: + s_setCurrent(pNextEnv); + s_callInto(pNextEnv, s_environment_invoke_vv, pNextEnv, pTargetEnv, pCallee, pParam); + s_setCurrent(pCurrEnv); + break; + } + + if (pNextEnv) + pNextEnv->release(pNextEnv); +} + +extern "C" void SAL_CALL uno_Environment_invoke_v(uno_Environment * pTargetEnv, uno_EnvCallee * pCallee, va_list * pParam) + SAL_THROW_EXTERN_C() +{ + s_environment_invoke_v(s_getCurrent(), pTargetEnv, pCallee, pParam); +} + +extern "C" void SAL_CALL uno_Environment_invoke(uno_Environment * pEnv, uno_EnvCallee * pCallee, ...) + SAL_THROW_EXTERN_C() +{ + va_list param; + + va_start(param, pCallee); + uno_Environment_invoke_v(pEnv, pCallee, ¶m); + va_end(param); +} + +extern "C" void SAL_CALL uno_Environment_enter(uno_Environment * pTargetEnv) + SAL_THROW_EXTERN_C() +{ + uno_Environment * pNextEnv = nullptr; + uno_Environment * pCurrEnv = s_getCurrent(); + + int res; + while ( (res = s_getNextEnv(&pNextEnv, pCurrEnv, pTargetEnv)) != 0) + { + cppu::Enterable * pEnterable; + + switch(res) + { + case -1: + pEnterable = static_cast<cppu::Enterable *>(pCurrEnv->pReserved); + if (pEnterable) + pEnterable->leave(); + pCurrEnv->release(pCurrEnv); + break; + + case 1: + pNextEnv->acquire(pNextEnv); + pEnterable = static_cast<cppu::Enterable *>(pNextEnv->pReserved); + if (pEnterable) + pEnterable->enter(); + break; + } + + s_setCurrent(pNextEnv); + pCurrEnv = pNextEnv; + } +} + +int SAL_CALL uno_Environment_isValid(uno_Environment * pEnv, rtl_uString ** pReason) + SAL_THROW_EXTERN_C() +{ + int result = 1; + + OUString typeName(cppu::EnvDcp::getTypeName(pEnv->pTypeName)); + if (typeName == UNO_LB_UNO) + { + cppu::Enterable * pEnterable = static_cast<cppu::Enterable *>(pEnv->pReserved); + if (pEnterable) + result = pEnterable->isValid(reinterpret_cast<OUString *>(pReason)); + } + else + { + OUString envDcp = UNO_LB_UNO + cppu::EnvDcp::getPurpose(pEnv->pTypeName); + + uno::Environment env(envDcp); + + result = env.isValid(reinterpret_cast<OUString *>(pReason)); + } + + return result; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/IdentityMapping.cxx b/cppu/source/uno/IdentityMapping.cxx new file mode 100644 index 000000000..c6dab40ce --- /dev/null +++ b/cppu/source/uno/IdentityMapping.cxx @@ -0,0 +1,104 @@ +/* -*- 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 "IdentityMapping.hxx" + +#include <typelib/typedescription.h> +#include <uno/mapping.h> +#include <uno/environment.hxx> + +#include <osl/interlck.h> + + +using namespace ::com::sun::star; + +namespace { + +struct IdentityMapping : public uno_Mapping +{ + sal_Int32 m_nRef; + uno::Environment m_env; + + explicit IdentityMapping(uno::Environment const & rEnv); +}; + +} + +extern "C" +{ + +static void s_free(uno_Mapping * pMapping) +{ + delete static_cast<IdentityMapping *>(pMapping); +} + +static void s_acquire(uno_Mapping * pMapping) +{ + static OUString s_purpose; + + if (1 == osl_atomic_increment(&static_cast<IdentityMapping *>(pMapping)->m_nRef)) + { + uno_registerMapping( + &pMapping, + s_free, + static_cast<IdentityMapping *>(pMapping)->m_env.get(), + static_cast<IdentityMapping *>(pMapping)->m_env.get(), + s_purpose.pData); + } +} + +static void s_release(uno_Mapping * pMapping) +{ + if (!osl_atomic_decrement(&static_cast<IdentityMapping *>(pMapping )->m_nRef)) + uno_revokeMapping(pMapping); +} + +static void s_mapInterface(uno_Mapping * pMapping, + void ** ppOut, + void * pInterface, + SAL_UNUSED_PARAMETER typelib_InterfaceTypeDescription * /*pInterfaceTypeDescr*/) +{ + *ppOut = pInterface; + + if (pInterface) + { + IdentityMapping * that = static_cast<IdentityMapping *>(pMapping); + + (that->m_env.get()->pExtEnv->acquireInterface)(that->m_env.get()->pExtEnv, pInterface); + } +} +} + + +IdentityMapping::IdentityMapping(uno::Environment const & rEnv) + : m_nRef(0), + m_env(rEnv) +{ + uno_Mapping::acquire = s_acquire; + uno_Mapping::release = s_release; + uno_Mapping::mapInterface = s_mapInterface; +} + + +uno_Mapping * createIdentityMapping(uno::Environment const & rEnv) +{ + return new IdentityMapping(rEnv); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/IdentityMapping.hxx b/cppu/source/uno/IdentityMapping.hxx new file mode 100644 index 000000000..fe2a64406 --- /dev/null +++ b/cppu/source/uno/IdentityMapping.hxx @@ -0,0 +1,31 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_UNO_IDENTITYMAPPING_HXX +#define INCLUDED_CPPU_SOURCE_UNO_IDENTITYMAPPING_HXX + +#include <uno/mapping.h> + +namespace com::sun::star::uno { class Environment; } + +uno_Mapping * createIdentityMapping(const css::uno::Environment & rEnv); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/any.cxx b/cppu/source/uno/any.cxx new file mode 100644 index 000000000..e26b97286 --- /dev/null +++ b/cppu/source/uno/any.cxx @@ -0,0 +1,142 @@ +/* -*- 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 "copy.hxx" +#include "destr.hxx" + +using namespace cppu; + + +extern "C" +{ + +void SAL_CALL uno_type_any_assign( + uno_Any * pDest, void * pSource, + typelib_TypeDescriptionReference * pType, + uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + _destructAny( pDest, release ); + if (pType) + { + _copyConstructAny( pDest, pSource, pType, nullptr, acquire, nullptr ); + } + else + { + CONSTRUCT_EMPTY_ANY( pDest ); + } +} + +void SAL_CALL uno_any_assign( + uno_Any * pDest, void * pSource, + typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + _destructAny( pDest, release ); + if (pTypeDescr) + { + _copyConstructAny( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, acquire, nullptr ); + } + else + { + CONSTRUCT_EMPTY_ANY( pDest ); + } +} + +void SAL_CALL uno_type_any_construct( + uno_Any * pDest, void * pSource, + typelib_TypeDescriptionReference * pType, + uno_AcquireFunc acquire ) + SAL_THROW_EXTERN_C() +{ + if (pType) + { + _copyConstructAny( pDest, pSource, pType, nullptr, acquire, nullptr ); + } + else + { + CONSTRUCT_EMPTY_ANY( pDest ); + } +} + +void SAL_CALL uno_any_construct( + uno_Any * pDest, void * pSource, + typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire ) + SAL_THROW_EXTERN_C() +{ + if (pTypeDescr) + { + _copyConstructAny( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, acquire, nullptr ); + } + else + { + CONSTRUCT_EMPTY_ANY( pDest ); + } +} + +void SAL_CALL uno_type_any_constructAndConvert( + uno_Any * pDest, void * pSource, + typelib_TypeDescriptionReference * pType, + uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + if (pType) + { + _copyConstructAny( pDest, pSource, pType, nullptr, nullptr, mapping ); + } + else + { + CONSTRUCT_EMPTY_ANY( pDest ); + } +} + +void SAL_CALL uno_any_constructAndConvert( + uno_Any * pDest, void * pSource, + typelib_TypeDescription * pTypeDescr, + uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + if (pTypeDescr) + { + _copyConstructAny( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, nullptr, mapping ); + } + else + { + CONSTRUCT_EMPTY_ANY( pDest ); + } +} + +void SAL_CALL uno_any_destruct( uno_Any * pValue, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + _destructAny( pValue, release ); +} + +void SAL_CALL uno_any_clear( uno_Any * pValue, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + _destructAny( pValue, release ); + CONSTRUCT_EMPTY_ANY( pValue ); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/assign.hxx b/cppu/source/uno/assign.hxx new file mode 100644 index 000000000..97ee9cd5b --- /dev/null +++ b/cppu/source/uno/assign.hxx @@ -0,0 +1,455 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_UNO_ASSIGN_HXX +#define INCLUDED_CPPU_SOURCE_UNO_ASSIGN_HXX + +#include "prim.hxx" +#include "destr.hxx" +#include "constr.hxx" +#include "copy.hxx" + + +namespace cppu +{ + + +//#### assignment ################################################################################## + + +inline void _assignInterface( + void ** ppDest, void * pSource, + uno_AcquireFunc acquire, uno_ReleaseFunc release ) + +{ + _acquire( pSource, acquire ); + void * const pToBeReleased = *ppDest; + *ppDest = pSource; + _release( pToBeReleased, release ); +} + +inline void * _queryInterface( + void * pSource, + typelib_TypeDescriptionReference * pDestType, + uno_QueryInterfaceFunc queryInterface ) +{ + if (pSource) + { + if (nullptr == queryInterface) + queryInterface = binuno_queryInterface; + pSource = (*queryInterface)( pSource, pDestType ); + } + return pSource; +} + +bool assignStruct( + void * pDest, void * pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release ); + +inline bool _assignStruct( + void * pDest, void * pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release ) +{ + if (pTypeDescr->pBaseTypeDescription) + { + // copy base value + if (! assignStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription, + queryInterface, acquire, release )) + { + return false; + } + } + // then copy members + typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs; + sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets; + sal_Int32 nDescr = pTypeDescr->nMembers; + while (nDescr--) + { + if (! ::uno_type_assignData( static_cast<char *>(pDest) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], + static_cast<char *>(pSource) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], + queryInterface, acquire, release )) + { + return false; + } + } + return true; +} + +inline bool _assignData( + void * pDest, + typelib_TypeDescriptionReference * pDestType, typelib_TypeDescription * pDestTypeDescr, + void * pSource, + typelib_TypeDescriptionReference * pSourceType, typelib_TypeDescription * pSourceTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release ) +{ + if (pDest == pSource) + return _type_equals( pDestType, pSourceType ); + + if (! pSource) + { + _destructData( pDest, pDestType, pDestTypeDescr, release ); + _defaultConstructData( pDest, pDestType, pDestTypeDescr ); + return true; + } + while (typelib_TypeClass_ANY == pSourceType->eTypeClass) + { + pSourceTypeDescr = nullptr; + pSourceType = static_cast<uno_Any *>(pSource)->pType; + pSource = static_cast<uno_Any *>(pSource)->pData; + if (pDest == pSource) + return true; + } + + switch (pDestType->eTypeClass) + { + case typelib_TypeClass_VOID: + return pSourceType->eTypeClass == typelib_TypeClass_VOID; + case typelib_TypeClass_CHAR: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_CHAR: + *static_cast<sal_Unicode *>(pDest) = *static_cast<sal_Unicode *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_BOOLEAN: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BOOLEAN: + *static_cast<sal_Bool *>(pDest) = bool(*static_cast<sal_Bool *>(pSource)); + return true; + default: + return false; + } + case typelib_TypeClass_BYTE: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_Int8 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_SHORT: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_Int16 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_Int16 *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_UNSIGNED_SHORT: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_uInt16 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_uInt16 *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_LONG: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_UNSIGNED_LONG: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<sal_uInt32 *>(pDest) = *static_cast<sal_uInt32 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_HYPER: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + case typelib_TypeClass_LONG: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int32 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_uInt32 *>(pSource); + return true; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int64 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_UNSIGNED_HYPER: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + case typelib_TypeClass_LONG: + *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_Int32 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_uInt32 *>(pSource); + return true; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast<sal_uInt64 *>(pDest) = *static_cast<sal_uInt64 *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_FLOAT: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<float *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast<float *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<float *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + case typelib_TypeClass_FLOAT: + *static_cast<float *>(pDest) = *static_cast<float *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_DOUBLE: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_BYTE: + *static_cast<double *>(pDest) = *static_cast<sal_Int8 *>(pSource); + return true; + case typelib_TypeClass_SHORT: + *static_cast<double *>(pDest) = *static_cast<sal_Int16 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<double *>(pDest) = *static_cast<sal_uInt16 *>(pSource); + return true; + case typelib_TypeClass_LONG: + *static_cast<double *>(pDest) = *static_cast<sal_Int32 *>(pSource); + return true; + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<double *>(pDest) = *static_cast<sal_uInt32 *>(pSource); + return true; + case typelib_TypeClass_FLOAT: + *static_cast<double *>(pDest) = *static_cast<float *>(pSource); + return true; + case typelib_TypeClass_DOUBLE: + *static_cast<double *>(pDest) = *static_cast<double *>(pSource); + return true; + default: + return false; + } + case typelib_TypeClass_STRING: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_STRING: + ::rtl_uString_assign( static_cast<rtl_uString **>(pDest), *static_cast<rtl_uString **>(pSource) ); + return true; + default: + return false; + } + case typelib_TypeClass_TYPE: + switch (pSourceType->eTypeClass) + { + case typelib_TypeClass_TYPE: + { + typelib_TypeDescriptionReference ** pp = static_cast<typelib_TypeDescriptionReference **>(pDest); + ::typelib_typedescriptionreference_release( *pp ); + *pp = *static_cast<typelib_TypeDescriptionReference **>(pSource); + TYPE_ACQUIRE( *pp ); + return true; + } + default: + return false; + } + case typelib_TypeClass_ANY: + _destructAny( static_cast<uno_Any *>(pDest), release ); + _copyConstructAny( static_cast<uno_Any *>(pDest), pSource, pSourceType, pSourceTypeDescr, acquire, nullptr ); + return true; + case typelib_TypeClass_ENUM: + if (_type_equals( pDestType, pSourceType )) + { + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource); + return true; + } + return false; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (typelib_TypeClass_STRUCT == pSourceType->eTypeClass || + typelib_TypeClass_EXCEPTION == pSourceType->eTypeClass) + { + bool bRet = false; + if (pSourceTypeDescr) + { + typelib_CompoundTypeDescription * pTypeDescr = + reinterpret_cast<typelib_CompoundTypeDescription *>(pSourceTypeDescr); + while (pTypeDescr && + !_type_equals(pTypeDescr->aBase.pWeakRef, pDestType)) + { + pTypeDescr = pTypeDescr->pBaseTypeDescription; + } + if (pTypeDescr) + { + bRet = _assignStruct( + pDest, pSource, pTypeDescr, queryInterface, acquire, release ); + } + } + else + { + TYPELIB_DANGER_GET( &pSourceTypeDescr, pSourceType ); + typelib_CompoundTypeDescription * pTypeDescr = + reinterpret_cast<typelib_CompoundTypeDescription *>(pSourceTypeDescr); + while (pTypeDescr && + !_type_equals(pTypeDescr->aBase.pWeakRef, pDestType)) + { + pTypeDescr = pTypeDescr->pBaseTypeDescription; + } + if (pTypeDescr) + { + bRet = _assignStruct( + pDest, pSource, pTypeDescr, queryInterface, acquire, release ); + } + TYPELIB_DANGER_RELEASE( pSourceTypeDescr ); + } + return bRet; + } + return false; + case typelib_TypeClass_SEQUENCE: + if (typelib_TypeClass_SEQUENCE != pSourceType->eTypeClass) + return false; + // self assignment: + if (*static_cast<uno_Sequence **>(pSource) == *static_cast<uno_Sequence **>(pDest)) + return true; + if (_type_equals( pDestType, pSourceType )) + { + osl_atomic_increment( &(*static_cast<uno_Sequence **>(pSource))->nRefCount ); + idestructSequence( + *static_cast<uno_Sequence **>(pDest), pDestType, pDestTypeDescr, release ); + *static_cast<uno_Sequence **>(pDest) = *static_cast<uno_Sequence **>(pSource); + return true; + } + return false; + case typelib_TypeClass_INTERFACE: + if (typelib_TypeClass_INTERFACE != pSourceType->eTypeClass) + return false; + if (_type_equals( pDestType, pSourceType )) + { + _assignInterface( static_cast<void **>(pDest), *static_cast<void **>(pSource), acquire, release ); + return true; + } + else if (*static_cast< void ** >(pSource) == nullptr) + { + // A null reference of any interface type can be converted to a null + // reference of any other interface type: + void * const pToBeReleased = *static_cast< void ** >(pDest); + *static_cast< void ** >(pDest) = nullptr; + _release( pToBeReleased, release ); + return true; + } + else + { + if (pSourceTypeDescr) + { + typelib_TypeDescription * pTD = pSourceTypeDescr; + while (pTD && !_type_equals( pTD->pWeakRef, pDestType )) + { + pTD = &reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD)->pBaseTypeDescription->aBase; + } + if (pTD) // is base of dest + { + _assignInterface( static_cast<void **>(pDest), *static_cast<void **>(pSource), acquire, release ); + return true; + } + } + + // query for interface: + void * pQueried = _queryInterface( *static_cast<void **>(pSource), + pDestType, queryInterface ); + if (pQueried != nullptr) { + void * const pToBeReleased = *static_cast<void **>(pDest); + *static_cast<void **>(pDest) = pQueried; + _release( pToBeReleased, release ); + } + return (pQueried != nullptr); + } + default: + OSL_ASSERT(false); + return false; + } +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/cascade_mapping.cxx b/cppu/source/uno/cascade_mapping.cxx new file mode 100644 index 000000000..f57f7dc0a --- /dev/null +++ b/cppu/source/uno/cascade_mapping.cxx @@ -0,0 +1,307 @@ +/* -*- 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 <osl/interlck.h> +#include <rtl/ustring.hxx> +#include <uno/environment.hxx> +#include <uno/lbnames.h> +#include <uno/mapping.hxx> +#include <uno/dispatcher.h> + +#include <cppu/EnvDcp.hxx> + +#include "cascade_mapping.hxx" + +using namespace com::sun::star; + +namespace { + +class MediatorMapping : public uno_Mapping +{ + oslInterlockedCount m_refCount; + + uno::Mapping m_from2uno; + uno::Mapping m_uno2to; + + uno::Environment m_from; + uno::Environment m_interm; + uno::Environment m_to; + +public: + void acquire(); + void release(); + + void mapInterface(void ** ppOut, + void * pInterface, + typelib_InterfaceTypeDescription * pInterfaceTypeDescr); + MediatorMapping(uno_Environment * pFrom, + uno_Environment * pInterm, + uno_Environment * pTo); +}; + +} + +extern "C" { +static void s_acquire(uno_Mapping * mapping) +{ + MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping); + pMediatorMapping->acquire(); +} + +static void s_release(uno_Mapping * mapping) +{ + MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping); + pMediatorMapping->release(); +} + +static void s_mapInterface( + uno_Mapping * mapping, + void ** ppOut, + void * pInterface, + typelib_InterfaceTypeDescription * pInterfaceTypeDescr) +{ + MediatorMapping * pMediatorMapping = static_cast<MediatorMapping *>(mapping); + pMediatorMapping->mapInterface(ppOut, pInterface, pInterfaceTypeDescr); +} +} + +MediatorMapping::MediatorMapping(uno_Environment * pFrom, + uno_Environment * pInterm, + uno_Environment * pTo) + : m_refCount(0), + m_from2uno(pFrom, pInterm), + m_uno2to (pInterm, pTo), + m_from (pFrom), + m_interm (pInterm), + m_to (pTo) +{ + if (!m_from2uno.get() || !m_uno2to.get()) + abort(); + + uno_Mapping::acquire = s_acquire; + uno_Mapping::release = s_release; + uno_Mapping::mapInterface = s_mapInterface; +} + +void MediatorMapping::acquire() +{ + osl_atomic_increment(&m_refCount); +} + +void MediatorMapping::release() +{ + if (osl_atomic_decrement(&m_refCount) == 0) + { + ::uno_revokeMapping(this); + } +} + +extern "C" { static void s_mapInterface_v(va_list * pParam) +{ + void ** ppOut = va_arg(*pParam, void **); + void * pInterface = va_arg(*pParam, void *); + typelib_InterfaceTypeDescription * pInterfaceTypeDescr = va_arg(*pParam, typelib_InterfaceTypeDescription *); + uno_Mapping * pMapping = va_arg(*pParam, uno_Mapping *); + + pMapping->mapInterface(pMapping, ppOut, pInterface, pInterfaceTypeDescr); +}} + +void MediatorMapping::mapInterface( + void ** ppOut, + void * pInterface, + typelib_InterfaceTypeDescription * pInterfaceTypeDescr) +{ + if (*ppOut != nullptr) + { + uno_ExtEnvironment * env = m_to.get()->pExtEnv; + OSL_ASSERT( env != nullptr ); + env->releaseInterface( env, *ppOut ); + *ppOut = nullptr; + } + + void * ret = nullptr; + uno_Interface * pUnoI = nullptr; + + m_from.invoke(s_mapInterface_v, &pUnoI, pInterface, pInterfaceTypeDescr, m_from2uno.get()); + + m_uno2to.mapInterface(&ret, pUnoI, pInterfaceTypeDescr); + + if (pUnoI) + m_interm.get()->pExtEnv->releaseInterface(m_interm.get()->pExtEnv, pUnoI); + + *ppOut = ret; +} + +extern "C" { static void s_MediatorMapping_free(uno_Mapping * pMapping) + SAL_THROW_EXTERN_C() +{ + delete static_cast<MediatorMapping *>(pMapping); +}} + + +static OUString getPrefix(OUString const & str1, OUString const & str2) +{ + sal_Int32 nIndex1 = 0; + sal_Int32 nIndex2 = 0; + sal_Int32 sim = 0; + + OUString token1; + OUString token2; + + do + { + token1 = str1.getToken(0, ':', nIndex1); + token2 = str2.getToken(0, ':', nIndex2); + + if (token1 == token2) + sim += token1.getLength() + 1; + } + while(nIndex1 == nIndex2 && nIndex1 >= 0 && token1 == token2); + + OUString result; + + if (sim) + result = str1.copy(0, sim - 1); + + return result; +} + +// OUString str1("abc:def:ghi"); +// OUString str2("abc:def"); +// OUString str3("abc"); +// OUString str4(""); + +// OUString pref; + +// pref = getPrefix(str1, str1); +// pref = getPrefix(str1, str2); +// pref = getPrefix(str1, str3); +// pref = getPrefix(str1, str4); + +// pref = getPrefix(str2, str1); +// pref = getPrefix(str3, str1); +// pref = getPrefix(str4, str1); + + +void getCascadeMapping(uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo, + rtl_uString * pAddPurpose) +{ + if (pAddPurpose && pAddPurpose->length) + return; + + OUString uno_envType(UNO_LB_UNO); + + OUString from_envType = cppu::EnvDcp::getTypeName(pFrom->pTypeName); + OUString to_envType = cppu::EnvDcp::getTypeName(pTo->pTypeName); + OUString from_envPurpose = cppu::EnvDcp::getPurpose(pFrom->pTypeName); + OUString to_envPurpose = cppu::EnvDcp::getPurpose(pTo->pTypeName); + +#ifdef LOG_CALLING_named_purpose_getMapping + OString s_from_name = OUStringToOString(pFrom->pTypeName, RTL_TEXTENCODING_ASCII_US); + OString s_to_name = OUStringToOString(pTo->pTypeName, RTL_TEXTENCODING_ASCII_US); + + std::cerr << __FUNCTION__ << " - creating mediation "; + std::cerr << "pFrom: " << s_from_name.getStr(); + std::cerr <<" pTo: " << s_to_name.getStr() << std::endl; +#endif + + if (from_envPurpose == to_envPurpose) // gcc:bla => uno:bla + return; + + // reaching this point means, we need a mediated mapping!!! + // we generally mediate via uno[:free] + uno_Environment * pInterm = nullptr; + + // chained uno -> uno + if (from_envType == uno_envType && to_envType == uno_envType) + { + OUString purpose = getPrefix(from_envPurpose, to_envPurpose); + + OUString uno_envDcp = uno_envType + purpose; + + // direct mapping possible? + // uno:bla-->uno:bla:blubb + if (from_envPurpose == purpose) + { + OUString rest = to_envPurpose.copy(purpose.getLength()); + + sal_Int32 index = rest.indexOf(':', 1); + if (index == -1) + { + uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData); + return; + } + + uno_envDcp += rest.copy(0, index); + } + else if (to_envPurpose == purpose) + { + OUString rest = from_envPurpose.copy(purpose.getLength()); + + sal_Int32 index = rest.indexOf(':', 1); + if (index == -1) + { + uno_getMapping(ppMapping, pFrom, pTo, rest.copy(1).pData); + return; + } + + uno_envDcp += rest.copy(0, index); + } + + uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr); + } + else if (from_envType != uno_envType && to_envType == uno_envType) // <ANY> -> UNO ? + // mediate via uno:purpose(fromEnv) + { + OUString envDcp = uno_envType + from_envPurpose; + uno_getEnvironment(&pInterm, envDcp.pData, nullptr); + } + else if (from_envType == uno_envType && to_envType != uno_envType) // UNO -> <ANY>? + // mediate via uno(context) + { + OUString envDcp = uno_envType + to_envPurpose; + uno_getEnvironment(&pInterm, envDcp.pData, nullptr); + } + else // everything else + // mediate via uno:purpose + { + OUString purpose = getPrefix(from_envPurpose, to_envPurpose); + + OUString uno_envDcp = uno_envType + purpose; + + uno_getEnvironment(&pInterm, uno_envDcp.pData, nullptr); + } + + uno_Mapping * pMapping = new MediatorMapping(pFrom, pInterm, pTo); + pInterm->release(pInterm); + + + pMapping->acquire(pMapping); + + ::uno_registerMapping(&pMapping, s_MediatorMapping_free, pFrom, pTo, pAddPurpose); + + if (*ppMapping) + (*ppMapping)->release(*ppMapping); + + *ppMapping = pMapping; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/cascade_mapping.hxx b/cppu/source/uno/cascade_mapping.hxx new file mode 100644 index 000000000..37f0f1d5b --- /dev/null +++ b/cppu/source/uno/cascade_mapping.hxx @@ -0,0 +1,35 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_UNO_CASCADE_MAPPING_HXX +#define INCLUDED_CPPU_SOURCE_UNO_CASCADE_MAPPING_HXX + +#include <uno/environment.h> +#include <uno/mapping.h> +#include <rtl/ustring.h> + + +void getCascadeMapping(uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo, + rtl_uString * pAddPurpose ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/check.cxx b/cppu/source/uno/check.cxx new file mode 100644 index 000000000..3dc0fc5ac --- /dev/null +++ b/cppu/source/uno/check.cxx @@ -0,0 +1,320 @@ +/* -*- 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 <cassert> + +#include <cppu/macros.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <uno/any2.h> + + +namespace { + +#if defined( _WIN32) +#pragma pack(push, 8) +#endif + +struct C1 +{ + sal_Int16 n1; +}; +struct C2 : public C1 +{ + sal_Int32 n2 CPPU_GCC3_ALIGN( C1 ); +}; +struct C3 : public C2 +{ + double d3; + sal_Int32 n3; +}; +struct C4 : public C3 +{ + sal_Int32 n4 CPPU_GCC3_ALIGN( C3 ); + double d4; +}; +struct C5 : public C4 +{ + sal_Int64 n5; + sal_Bool b5; +}; +struct C6 : public C1 +{ + C5 c6 CPPU_GCC3_ALIGN( C1 ); + sal_Bool b6; +}; + +struct D +{ + sal_Int16 d; + sal_Int32 e; +}; +struct E +{ + sal_Bool a; + sal_Bool b; + sal_Bool c; + sal_Int16 d; + sal_Int32 e; +}; + +struct M +{ + sal_Int32 n; + sal_Int16 o; +}; + +struct N : public M +{ + sal_Int16 p CPPU_GCC3_ALIGN( M ); +}; +struct N2 +{ + M m; + sal_Int16 p; +}; + +struct O : public M +{ + double p; + sal_Int16 q; +}; +struct O2 : public O +{ + sal_Int16 p2 CPPU_GCC3_ALIGN( O ); +}; + +struct P : public N +{ + double p2; +}; + +struct empty +{ +}; +struct second : public empty +{ + int a; +}; + +struct AlignSize_Impl +{ + sal_Int16 nInt16; + double dDouble; +}; + +struct Char1 +{ + char c1; +}; +struct Char2 : public Char1 +{ + char c2 CPPU_GCC3_ALIGN( Char1 ); +}; +struct Char3 : public Char2 +{ + char c3 CPPU_GCC3_ALIGN( Char2 ); +}; +struct Char4 +{ + Char3 chars; + char c; +}; +enum Enum +{ + v = SAL_MAX_ENUM +}; + +#ifdef _WIN32 +# pragma pack(pop) +#endif + +static_assert( static_cast<sal_Bool>(true) == sal_True, + "must be binary compatible" ); +static_assert( static_cast<sal_Bool>(false) == sal_False, + "must be binary compatible" ); +#if SAL_TYPES_ALIGNMENT8 == 2 +static_assert(offsetof(AlignSize_Impl, dDouble) == 2, "offsetof(AlignSize_Impl, dDouble) != 2"); +static_assert(sizeof(AlignSize_Impl) == 10, "sizeof(AlignSize_Impl) != 10"); +#elif SAL_TYPES_ALIGNMENT8 == 4 +static_assert(offsetof(AlignSize_Impl, dDouble) == 4, "offsetof(AlignSize_Impl, dDouble) != 4"); +static_assert(sizeof(AlignSize_Impl) == 12, "sizeof(AlignSize_Impl) != 12"); +#elif SAL_TYPES_ALIGNMENT8 == 8 +static_assert(offsetof(AlignSize_Impl, dDouble) == 8, "offsetof(AlignSize_Impl, dDouble) != 8"); +static_assert(sizeof(AlignSize_Impl) == 16, "sizeof(AlignSize_Impl) != 16"); +#else +# error unexpected alignment of 8 byte types +#endif + +// sequence +static_assert((SAL_SEQUENCE_HEADER_SIZE % 8) == 0, "binary compatibility test failed: (SAL_SEQUENCE_HEADER_SIZE % 8) == 0!!!"); +// enum +static_assert(sizeof(Enum) == sizeof(sal_Int32), "binary compatibility test failed: (sizeof(Enum) == sizeof(sal_Int32))"); +// any +static_assert(sizeof(void *) >= sizeof(sal_Int32), "binary compatibility test failed: (sizeof(void *) >= sizeof(sal_Int32))"); +static_assert(sizeof(uno_Any) == sizeof(void *) * 3, "binary compatibility test failed: (sizeof(uno_Any) == sizeof(void *) * 3"); +static_assert(offsetof(uno_Any, pType) == 0, "offsetof(uno_Any, pType) != 0"); +static_assert(offsetof(uno_Any, pData) == 1 * sizeof(void *), "offsetof(uno_Any, pTData) != (1 * sizeof(void *))"); +static_assert(offsetof(uno_Any, pReserved) == 2 * sizeof(void *), "offsetof(uno_Any, pReserved) != (2 * sizeof(void *))"); +// string +static_assert(sizeof(OUString) == sizeof(rtl_uString *), "binary compatibility test failed: sizeof(OUString) != sizeof(rtl_uString *)"); +// struct +#if SAL_TYPES_ALIGNMENT8 == 2 +static_assert(sizeof(M) == 6, "sizeof(M) != 6"); +static_assert(sizeof(N) == 8, "sizeof(N) != 8"); +static_assert(sizeof(N2) == 8, "sizeof(N2) != 8"); +static_assert(offsetof(N2, p) == 6, "offsetof(N2, p) != 6"); +#else +static_assert(sizeof(M) == 8, "sizeof(M) != 8"); +static_assert(sizeof(N) == 12, "sizeof(N) != 12"); +static_assert(sizeof(N2) == 12, "sizeof(N2) != 12"); +static_assert(offsetof(N2, p) == 8, "offsetof(N2, p) != 8"); +#endif +static_assert(offsetof(M, o) == 4, "offsetof(M, o) != 4"); + +#if SAL_TYPES_ALIGNMENT8 == 2 +static_assert(sizeof(O) == 16, "sizeof(O) != 16"); +#elif SAL_TYPES_ALIGNMENT8 == 4 +static_assert(sizeof(O) == 20, "sizeof(O) != 20"); +#elif SAL_TYPES_ALIGNMENT8 == 8 +static_assert(sizeof(O) == 24, "sizeof(O) != 24"); +#else +# error unexpected alignment of 8 byte types +#endif + +#if SAL_TYPES_ALIGNMENT8 == 2 +static_assert(sizeof(C2) == 6, "sizeof(C2) != 6"); +static_assert(sizeof(D) == 6, "sizeof(D) != 6"); +static_assert(offsetof(D, e) == 2, "offsetof(D, e) != 2"); +static_assert(offsetof(E, e) == 6, "offsetof(E, e) != 6"); +#else +static_assert(sizeof(C2) == 8, "sizeof(C2) != 8"); +static_assert(sizeof(D) == 8, "sizeof(D) != 8"); +static_assert(offsetof(D, e) == 4, "offsetof(D, e) != 4"); +static_assert(offsetof(E, e) == 8, "offsetof(E, e) != 8"); +#endif + +static_assert(sizeof(C1) == 2, "sizeof(C1) != 2"); +static_assert(offsetof(E, d) == 4, "offsetof(E, d) != 4"); + +#if SAL_TYPES_ALIGNMENT8 == 2 +static_assert(sizeof(C3) == 18, "sizeof(C3) != 18"); +static_assert(sizeof(C4) == 30, "sizeof(C4) != 30"); +static_assert(sizeof(C5) == 40, "sizeof(C5) != 40"); +static_assert(sizeof(C6) == 44, "sizeof(C6) != 44"); + +static_assert(sizeof(O2) == 18, "sizeof(O2) != 18"); +#elif SAL_TYPES_ALIGNMENT8 == 4 +static_assert(sizeof(C3) == 20, "sizeof(C3) != 20"); +static_assert(sizeof(C4) == 32, "sizeof(C4) != 32"); +static_assert(sizeof(C5) == 44, "sizeof(C5) != 44"); +static_assert(sizeof(C6) == 52, "sizeof(C6) != 52"); + +static_assert(sizeof(O2) == 24, "sizeof(O2) != 24"); +#elif SAL_TYPES_ALIGNMENT8 == 8 +static_assert(sizeof(C3) == 24, "sizeof(C3) != 24"); +static_assert(sizeof(C4) == 40, "sizeof(C4) != 40"); +static_assert(sizeof(C5) == 56, "sizeof(C5) != 56"); +static_assert(sizeof(C6) == 72, "sizeof(C6) != 72"); + +static_assert(sizeof(O2) == 32, "sizeof(O2) != 32"); +#else +# error unexpected alignment of 8 byte types +#endif + +static_assert(sizeof(Char3) == 3, "sizeof(Char3) != 3"); + +#if SAL_TYPES_ALIGNMENT8 == 2 +// max alignment is 2 +static_assert(sizeof(P) == 16, "sizeof(P) != 16"); +#elif SAL_TYPES_ALIGNMENT8 == 4 +// max alignment is 4 +static_assert(sizeof(P) == 20, "sizeof(P) != 20"); +#elif SAL_TYPES_ALIGNMENT8 == 8 +// alignment of P is 8, because of P[] ... +static_assert(sizeof(P) == 24, "sizeof(P) != 24"); +static_assert(sizeof(second) == sizeof(int), "sizeof(second) != sizeof(int)"); +#else +# error unexpected alignment of 8 byte types +#endif + +#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG + +#define OFFSET_OF( s, m ) reinterpret_cast< size_t >(reinterpret_cast<char *>(&reinterpret_cast<s *>(16)->m) -16) + +class BinaryCompatible_Impl +{ +public: + BinaryCompatible_Impl(); +}; +BinaryCompatible_Impl::BinaryCompatible_Impl() +{ + assert(OFFSET_OF(N, p) == 8); + + assert(OFFSET_OF(C2, n2) == 4); + +#if SAL_TYPES_ALIGNMENT8 == 2 + assert(OFFSET_OF(C3, d3) == 6); + assert(OFFSET_OF(C3, n3) == 14); + assert(OFFSET_OF(C4, n4) == 18); + assert(OFFSET_OF(C4, d4) == 22); + assert(OFFSET_OF(C5, n5) == 30); + assert(OFFSET_OF(C5, b5) == 38); + assert(OFFSET_OF(C6, c6) == 2); + assert(OFFSET_OF(C6, b6) == 42); + + assert(OFFSET_OF(O2, p2) == 16); +#elif SAL_TYPES_ALIGNMENT8 == 4 + assert(OFFSET_OF(C3, d3) == 8); + assert(OFFSET_OF(C3, n3) == 16); + assert(OFFSET_OF(C4, n4) == 20); + assert(OFFSET_OF(C4, d4) == 24); + assert(OFFSET_OF(C5, n5) == 32); + assert(OFFSET_OF(C5, b5) == 40); + assert(OFFSET_OF(C6, c6) == 4); + assert(OFFSET_OF(C6, b6) == 48); + + assert(OFFSET_OF(O2, p2) == 20); +#elif SAL_TYPES_ALIGNMENT8 == 8 + assert(OFFSET_OF(C3, d3) == 8); + assert(OFFSET_OF(C3, n3) == 16); + assert(OFFSET_OF(C4, n4) == 24); + assert(OFFSET_OF(C4, d4) == 32); + assert(OFFSET_OF(C5, n5) == 40); + assert(OFFSET_OF(C5, b5) == 48); + assert(OFFSET_OF(C6, c6) == 8); + assert(OFFSET_OF(C6, b6) == 64); + + assert(OFFSET_OF(O2, p2) == 24); +#else +# error unexpected alignment of 8 byte types +#endif + + assert(OFFSET_OF(Char4, c) == 3); +} + +static BinaryCompatible_Impl aTest; + +#endif + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/constr.hxx b/cppu/source/uno/constr.hxx new file mode 100644 index 000000000..73d89b915 --- /dev/null +++ b/cppu/source/uno/constr.hxx @@ -0,0 +1,141 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_UNO_CONSTR_HXX +#define INCLUDED_CPPU_SOURCE_UNO_CONSTR_HXX + +#include "prim.hxx" +#include <osl/diagnose.h> + +namespace cppu +{ + + +//#### construction ################################################################################ + + +void defaultConstructStruct( + void * pMem, + typelib_CompoundTypeDescription * pCompType ); + +inline void _defaultConstructStruct( + void * pMem, + typelib_CompoundTypeDescription * pTypeDescr ) +{ + if (pTypeDescr->pBaseTypeDescription) + { + defaultConstructStruct( pMem, pTypeDescr->pBaseTypeDescription ); + } + + typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs; + sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets; + sal_Int32 nDescr = pTypeDescr->nMembers; + + while (nDescr--) + { + ::uno_type_constructData( static_cast<char *>(pMem) + pMemberOffsets[nDescr], ppTypeRefs[nDescr] ); + } +} + + +inline void _defaultConstructData( + void * pMem, + typelib_TypeDescriptionReference * pType, + typelib_TypeDescription * pTypeDescr ) +{ + switch (pType->eTypeClass) + { + case typelib_TypeClass_CHAR: + *static_cast<sal_Unicode *>(pMem) = '\0'; + break; + case typelib_TypeClass_BOOLEAN: + *static_cast<sal_Bool *>(pMem) = false; + break; + case typelib_TypeClass_BYTE: + *static_cast<sal_Int8 *>(pMem) = 0; + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_Int16 *>(pMem) = 0; + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<sal_Int32 *>(pMem) = 0; + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast<sal_Int64 *>(pMem) = 0; + break; + case typelib_TypeClass_FLOAT: + *static_cast<float *>(pMem) = 0.0; + break; + case typelib_TypeClass_DOUBLE: + *static_cast<double *>(pMem) = 0.0; + break; + case typelib_TypeClass_STRING: + *static_cast<rtl_uString **>(pMem) = nullptr; + ::rtl_uString_new( static_cast<rtl_uString **>(pMem) ); + break; + case typelib_TypeClass_TYPE: + *static_cast<typelib_TypeDescriptionReference **>(pMem) = _getVoidType(); + break; + case typelib_TypeClass_ANY: + CONSTRUCT_EMPTY_ANY( static_cast<uno_Any *>(pMem) ); + break; + case typelib_TypeClass_ENUM: + if (pTypeDescr) + { + *static_cast<sal_Int32 *>(pMem) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue; + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast<sal_Int32 *>(pMem) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue; + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + _defaultConstructStruct( pMem, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _defaultConstructStruct( pMem, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + *static_cast<uno_Sequence **>(pMem) = createEmptySequence(); + break; + case typelib_TypeClass_INTERFACE: + *static_cast<void **>(pMem) = nullptr; // either cpp or c-uno interface + break; + default: + OSL_ASSERT(false); + break; + } +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/copy.hxx b/cppu/source/uno/copy.hxx new file mode 100644 index 000000000..b61973ec0 --- /dev/null +++ b/cppu/source/uno/copy.hxx @@ -0,0 +1,658 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_UNO_COPY_HXX +#define INCLUDED_CPPU_SOURCE_UNO_COPY_HXX + +#include "prim.hxx" +#include "constr.hxx" +#include <cassert> +#include <cstddef> +#include <cstdlib> +#include <type_traits> + +namespace cppu +{ + + +//#### copy construction ########################################################################### + +namespace { + +// The non-dynamic prefix of sal_Sequence (aka uno_Sequence): +struct SequencePrefix { + sal_Int32 nRefCount; + sal_Int32 nElements; +}; +static_assert(sizeof (SequencePrefix) < sizeof (uno_Sequence)); +static_assert(offsetof(SequencePrefix, nRefCount) == offsetof(uno_Sequence, nRefCount)); +static_assert( + std::is_same_v<decltype(SequencePrefix::nRefCount), decltype(uno_Sequence::nRefCount)>); +static_assert(offsetof(SequencePrefix, nElements) == offsetof(uno_Sequence, nElements)); +static_assert( + std::is_same_v<decltype(SequencePrefix::nElements), decltype(uno_Sequence::nElements)>); + +} + +inline uno_Sequence * allocSeq( + sal_Int32 nElementSize, sal_Int32 nElements ) +{ + OSL_ASSERT( nElements >= 0 && nElementSize >= 0 ); + uno_Sequence * pSeq = nullptr; + sal_uInt32 nSize = calcSeqMemSize( nElementSize, nElements ); + if (nSize > 0) + { + pSeq = static_cast<uno_Sequence *>(std::malloc( nSize )); + if (pSeq != nullptr) + { + // header init, going via SequencePrefix to avoid UBSan insufficient-object-size + // warnings when `nElements == 0` and thus `nSize < sizeof (uno_Sequence)`: + auto const header = reinterpret_cast<SequencePrefix *>(pSeq); + header->nRefCount = 1; + header->nElements = nElements; + } + } + return pSeq; +} + + +void copyConstructStruct( + void * pDest, void * pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_Mapping * mapping ); + +inline void _copyConstructStruct( + void * pDest, void * pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + if (pTypeDescr->pBaseTypeDescription) + { + // copy base value + copyConstructStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription, acquire, mapping ); + } + + // then copy members + typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs; + sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets; + sal_Int32 nDescr = pTypeDescr->nMembers; + + if (mapping) + { + while (nDescr--) + { + ::uno_type_copyAndConvertData( + static_cast<char *>(pDest) + pMemberOffsets[nDescr], + static_cast<char *>(pSource) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], mapping ); + } + } + else + { + while (nDescr--) + { + ::uno_type_copyData( + static_cast<char *>(pDest) + pMemberOffsets[nDescr], + static_cast<char *>(pSource) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], acquire ); + } + } +} + + +uno_Sequence * copyConstructSequence( + uno_Sequence * pSource, + typelib_TypeDescriptionReference * pElementType, + uno_AcquireFunc acquire, uno_Mapping * mapping ); + + +inline void _copyConstructAnyFromData( + uno_Any * pDestAny, void * pSource, + typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + TYPE_ACQUIRE( pType ); + pDestAny->pType = pType; + + switch (pType->eTypeClass) + { + case typelib_TypeClass_CHAR: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Unicode *>(pDestAny->pData) = *static_cast<sal_Unicode *>(pSource); + break; + case typelib_TypeClass_BOOLEAN: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Bool *>(pDestAny->pData) = bool(*static_cast<sal_Bool *>(pSource)); + break; + case typelib_TypeClass_BYTE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Int8 *>(pDestAny->pData) = *static_cast<sal_Int8 *>(pSource); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Int16 *>(pDestAny->pData) = *static_cast<sal_Int16 *>(pSource); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Int32 *>(pDestAny->pData) = *static_cast<sal_Int32 *>(pSource); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof(void *) >= sizeof(sal_Int64)) + pDestAny->pData = &pDestAny->pReserved; + else + pDestAny->pData = std::malloc( sizeof(sal_Int64) ); + assert(pDestAny->pData); + *static_cast<sal_Int64 *>(pDestAny->pData) = *static_cast<sal_Int64 *>(pSource); + break; + case typelib_TypeClass_FLOAT: + if (sizeof(void *) >= sizeof(float)) + pDestAny->pData = &pDestAny->pReserved; + else + pDestAny->pData = std::malloc( sizeof(float) ); + assert(pDestAny->pData); + *static_cast<float *>(pDestAny->pData) = *static_cast<float *>(pSource); + break; + case typelib_TypeClass_DOUBLE: + if (sizeof(void *) >= sizeof(double)) + pDestAny->pData = &pDestAny->pReserved; + else + pDestAny->pData = std::malloc( sizeof(double) ); + assert(pDestAny->pData); + *static_cast<double *>(pDestAny->pData) = *static_cast<double *>(pSource); + break; + case typelib_TypeClass_STRING: + ::rtl_uString_acquire( *static_cast<rtl_uString **>(pSource) ); + pDestAny->pData = &pDestAny->pReserved; + *static_cast<rtl_uString **>(pDestAny->pData) = *static_cast<rtl_uString **>(pSource); + break; + case typelib_TypeClass_TYPE: + TYPE_ACQUIRE( *static_cast<typelib_TypeDescriptionReference **>(pSource) ); + pDestAny->pData = &pDestAny->pReserved; + *static_cast<typelib_TypeDescriptionReference **>(pDestAny->pData) = *static_cast<typelib_TypeDescriptionReference **>(pSource); + break; + case typelib_TypeClass_ANY: + OSL_FAIL( "### unexpected nested any!" ); + break; + case typelib_TypeClass_ENUM: + pDestAny->pData = &pDestAny->pReserved; + // enum is forced to 32bit long + *static_cast<sal_Int32 *>(pDestAny->pData) = *static_cast<sal_Int32 *>(pSource); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _copyConstructStruct( + pDestAny->pData, pSource, + reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _copyConstructStruct( + pDestAny->pData, pSource, + reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + pDestAny->pData = &pDestAny->pReserved; + if (pTypeDescr) + { + *static_cast<uno_Sequence **>(pDestAny->pData) = copyConstructSequence( + *static_cast<uno_Sequence **>(pSource), + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast<uno_Sequence **>(pDestAny->pData) = copyConstructSequence( + *static_cast<uno_Sequence **>(pSource), + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_INTERFACE: + pDestAny->pData = &pDestAny->pReserved; + if (mapping) + { + pDestAny->pReserved = _map( *static_cast<void **>(pSource), pType, pTypeDescr, mapping ); + } + else + { + pDestAny->pReserved = *static_cast<void **>(pSource); + _acquire( pDestAny->pReserved, acquire ); + } + break; + default: + OSL_ASSERT(false); + break; + } +} + +inline void _copyConstructAny( + uno_Any * pDestAny, void * pSource, + typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + if (typelib_TypeClass_VOID == pType->eTypeClass) + { + CONSTRUCT_EMPTY_ANY( pDestAny ); + } + else + { + if (typelib_TypeClass_ANY == pType->eTypeClass) + { + if (pSource) + { + pType = static_cast<uno_Any *>(pSource)->pType; + if (typelib_TypeClass_VOID == pType->eTypeClass) + { + CONSTRUCT_EMPTY_ANY( pDestAny ); + return; + } + pTypeDescr = nullptr; + pSource = static_cast<uno_Any *>(pSource)->pData; + } + else + { + CONSTRUCT_EMPTY_ANY( pDestAny ); + return; + } + } + if (pSource) + { + _copyConstructAnyFromData( pDestAny, pSource, pType, pTypeDescr, acquire, mapping ); + } + else // default construct + { + TYPE_ACQUIRE( pType ); + pDestAny->pType = pType; + switch (pType->eTypeClass) + { + case typelib_TypeClass_CHAR: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Unicode *>(pDestAny->pData) = '\0'; + break; + case typelib_TypeClass_BOOLEAN: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Bool *>(pDestAny->pData) = false; + break; + case typelib_TypeClass_BYTE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Int8 *>(pDestAny->pData) = 0; + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Int16 *>(pDestAny->pData) = 0; + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<sal_Int32 *>(pDestAny->pData) = 0; + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof(void *) >= sizeof(sal_Int64)) + pDestAny->pData = &pDestAny->pReserved; + else + pDestAny->pData = std::malloc( sizeof(sal_Int64) ); + assert(pDestAny->pData); + *static_cast<sal_Int64 *>(pDestAny->pData) = 0; + break; + case typelib_TypeClass_FLOAT: + if (sizeof(void *) >= sizeof(float)) + pDestAny->pData = &pDestAny->pReserved; + else + pDestAny->pData = std::malloc( sizeof(float) ); + assert(pDestAny->pData); + *static_cast<float *>(pDestAny->pData) = 0.0; + break; + case typelib_TypeClass_DOUBLE: + if (sizeof(void *) >= sizeof(double)) + pDestAny->pData = &pDestAny->pReserved; + else + pDestAny->pData = std::malloc( sizeof(double) ); + assert(pDestAny->pData); + *static_cast<double *>(pDestAny->pData) = 0.0; + break; + case typelib_TypeClass_STRING: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<rtl_uString **>(pDestAny->pData) = nullptr; + ::rtl_uString_new( static_cast<rtl_uString **>(pDestAny->pData) ); + break; + case typelib_TypeClass_TYPE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<typelib_TypeDescriptionReference **>(pDestAny->pData) = _getVoidType(); + break; + case typelib_TypeClass_ENUM: + pDestAny->pData = &pDestAny->pReserved; + if (pTypeDescr) + { + *static_cast<sal_Int32 *>(pDestAny->pData) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue; + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast<sal_Int32 *>(pDestAny->pData) = reinterpret_cast<typelib_EnumTypeDescription *>(pTypeDescr)->nDefaultEnumValue; + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _defaultConstructStruct( + pDestAny->pData, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + pDestAny->pData = std::malloc( pTypeDescr->nSize ); + _defaultConstructStruct( + pDestAny->pData, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr) ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + pDestAny->pData = &pDestAny->pReserved; + *static_cast<uno_Sequence **>(pDestAny->pData) = createEmptySequence(); + break; + case typelib_TypeClass_INTERFACE: + pDestAny->pData = &pDestAny->pReserved; + pDestAny->pReserved = nullptr; // either cpp or c-uno interface + break; + default: + OSL_ASSERT(false); + break; + } + } + } +} + +inline uno_Sequence * icopyConstructSequence( + uno_Sequence * pSource, + typelib_TypeDescriptionReference * pElementType, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + typelib_TypeClass eTypeClass = pElementType->eTypeClass; + if (!mapping || + (eTypeClass <= typelib_TypeClass_ENUM && + eTypeClass != typelib_TypeClass_ANY)) + { + osl_atomic_increment( &pSource->nRefCount ); + return pSource; + } + else // create new sequence + { + uno_Sequence * pDest; + sal_Int32 nElements = pSource->nElements; + if (nElements) + { + switch (eTypeClass) + { + case typelib_TypeClass_ANY: + { + pDest = allocSeq( sizeof (uno_Any), nElements ); + if (pDest != nullptr) + { + uno_Any * pDestElements = reinterpret_cast<uno_Any *>(pDest->elements); + uno_Any * pSourceElements = reinterpret_cast<uno_Any *>(pSource->elements); + for ( sal_Int32 nPos = nElements; nPos--; ) + { + typelib_TypeDescriptionReference * pType = + pSourceElements[nPos].pType; + if (typelib_TypeClass_VOID == pType->eTypeClass) + { + CONSTRUCT_EMPTY_ANY( &pDestElements[nPos] ); + } + else + { + _copyConstructAnyFromData( + &pDestElements[nPos], + pSourceElements[nPos].pData, + pType, nullptr, + acquire, mapping ); + } + } + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + sal_Int32 nElementSize = pElementTypeDescr->nSize; + char * pSourceElements = pSource->elements; + pDest = allocSeq( nElementSize, nElements ); + if (pDest != nullptr) + { + char * pElements = pDest->elements; + for ( sal_Int32 nPos = nElements; nPos--; ) + { + _copyConstructStruct( + pElements + (nPos * nElementSize), + pSourceElements + (nPos * nElementSize), + reinterpret_cast<typelib_CompoundTypeDescription *>( + pElementTypeDescr), + acquire, mapping ); + } + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + break; + } + case typelib_TypeClass_SEQUENCE: // sequence of sequence + { + // coverity[suspicious_sizeof] - sizeof(uno_Sequence*) is correct here + pDest = allocSeq( sizeof (uno_Sequence *), nElements ); + if (pDest != nullptr) + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + typelib_TypeDescriptionReference * pSeqElementType = + reinterpret_cast<typelib_IndirectTypeDescription *>( + pElementTypeDescr)->pType; + + uno_Sequence ** pDestElements = + reinterpret_cast<uno_Sequence **>(pDest->elements); + uno_Sequence ** pSourceElements = + reinterpret_cast<uno_Sequence **>(pSource->elements); + for ( sal_Int32 nPos = nElements; nPos--; ) + { + uno_Sequence * pNew = copyConstructSequence( + pSourceElements[nPos], + pSeqElementType, + acquire, mapping ); + OSL_ASSERT( pNew != nullptr ); + // ought never be a memory allocation problem, + // because of reference counted sequence handles + pDestElements[ nPos ] = pNew; + } + + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + } + break; + } + case typelib_TypeClass_INTERFACE: + { + pDest = allocSeq( sizeof (void *), nElements ); + if (pDest != nullptr) + { + char * pElements = pDest->elements; + void ** pSourceElements = reinterpret_cast<void **>(pSource->elements); + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + for ( sal_Int32 nPos = nElements; nPos--; ) + { + reinterpret_cast<void **>(pElements)[nPos] = nullptr; + if (pSourceElements[nPos]) + { + (*mapping->mapInterface)( + mapping, reinterpret_cast<void **>(pElements) + nPos, + pSourceElements[nPos], + reinterpret_cast<typelib_InterfaceTypeDescription *>( + pElementTypeDescr) ); + } + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + } + break; + } + default: + OSL_FAIL( "### unexpected sequence element type!" ); + pDest = nullptr; + break; + } + } + else // empty sequence + { + pDest = allocSeq( 0, 0 ); + } + + return pDest; + } +} + + +inline void _copyConstructData( + void * pDest, void * pSource, + typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + switch (pType->eTypeClass) + { + case typelib_TypeClass_CHAR: + *static_cast<sal_Unicode *>(pDest) = *static_cast<sal_Unicode *>(pSource); + break; + case typelib_TypeClass_BOOLEAN: + *static_cast<sal_Bool *>(pDest) = bool(*static_cast<sal_Bool *>(pSource)); + break; + case typelib_TypeClass_BYTE: + *static_cast<sal_Int8 *>(pDest) = *static_cast<sal_Int8 *>(pSource); + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + *static_cast<sal_Int16 *>(pDest) = *static_cast<sal_Int16 *>(pSource); + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource); + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + *static_cast<sal_Int64 *>(pDest) = *static_cast<sal_Int64 *>(pSource); + break; + case typelib_TypeClass_FLOAT: + *static_cast<float *>(pDest) = *static_cast<float *>(pSource); + break; + case typelib_TypeClass_DOUBLE: + *static_cast<double *>(pDest) = *static_cast<double *>(pSource); + break; + case typelib_TypeClass_STRING: + ::rtl_uString_acquire( *static_cast<rtl_uString **>(pSource) ); + *static_cast<rtl_uString **>(pDest) = *static_cast<rtl_uString **>(pSource); + break; + case typelib_TypeClass_TYPE: + TYPE_ACQUIRE( *static_cast<typelib_TypeDescriptionReference **>(pSource) ); + *static_cast<typelib_TypeDescriptionReference **>(pDest) = *static_cast<typelib_TypeDescriptionReference **>(pSource); + break; + case typelib_TypeClass_ANY: + _copyConstructAny( + static_cast<uno_Any *>(pDest), static_cast<uno_Any *>(pSource)->pData, + static_cast<uno_Any *>(pSource)->pType, nullptr, + acquire, mapping ); + break; + case typelib_TypeClass_ENUM: + *static_cast<sal_Int32 *>(pDest) = *static_cast<sal_Int32 *>(pSource); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + _copyConstructStruct( + pDest, pSource, + reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _copyConstructStruct( + pDest, pSource, + reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + if (mapping) + { + if (pTypeDescr) + { + *static_cast<uno_Sequence **>(pDest) = icopyConstructSequence( + *static_cast<uno_Sequence **>(pSource), + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + acquire, mapping ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + *static_cast<uno_Sequence **>(pDest) = icopyConstructSequence( + *static_cast<uno_Sequence **>(pSource), + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + acquire, mapping ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + } + else + { + osl_atomic_increment( &(*static_cast<uno_Sequence **>(pSource))->nRefCount ); + *static_cast<uno_Sequence **>(pDest) = *static_cast<uno_Sequence **>(pSource); + } + break; + case typelib_TypeClass_INTERFACE: + if (mapping) + *static_cast<void **>(pDest) = _map( *static_cast<void **>(pSource), pType, pTypeDescr, mapping ); + else + { + *static_cast<void **>(pDest) = *static_cast<void **>(pSource); + _acquire( *static_cast<void **>(pDest), acquire ); + } + break; + default: + break; + } +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/data.cxx b/cppu/source/uno/data.cxx new file mode 100644 index 000000000..339e650fe --- /dev/null +++ b/cppu/source/uno/data.cxx @@ -0,0 +1,316 @@ +/* -*- 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/log.hxx> +#include <uno/data.h> + +#include "constr.hxx" +#include "destr.hxx" +#include "copy.hxx" +#include "assign.hxx" +#include "eq.hxx" + +using namespace ::cppu; + +namespace cppu +{ + +// Sequence<>() (default ctor) relies on this being static: +uno_Sequence g_emptySeq = { 1, 0, { 0 } }; +typelib_TypeDescriptionReference * g_pVoidType = nullptr; + + +void * binuno_queryInterface( void * pUnoI, typelib_TypeDescriptionReference * pDestType ) +{ + // init queryInterface() td + static typelib_TypeDescription* g_pQITD = []() { + typelib_TypeDescriptionReference* type_XInterface + = *typelib_static_type_getByTypeClass(typelib_TypeClass_INTERFACE); + typelib_InterfaceTypeDescription* pTXInterfaceDescr = nullptr; + TYPELIB_DANGER_GET(reinterpret_cast<typelib_TypeDescription**>(&pTXInterfaceDescr), + type_XInterface); + assert(pTXInterfaceDescr->ppAllMembers); + typelib_TypeDescription* pQITD = nullptr; + typelib_typedescriptionreference_getDescription(&pQITD, + pTXInterfaceDescr->ppAllMembers[0]); + // coverity[callee_ptr_arith] - not a bug + TYPELIB_DANGER_RELEASE(&pTXInterfaceDescr->aBase); + return pQITD; + }(); + + uno_Any aRet, aExc; + uno_Any * pExc = &aExc; + void * aArgs[ 1 ]; + aArgs[ 0 ] = &pDestType; + (*static_cast<uno_Interface *>(pUnoI)->pDispatcher)( + static_cast<uno_Interface *>(pUnoI), g_pQITD, &aRet, aArgs, &pExc ); + + uno_Interface * ret = nullptr; + if (nullptr == pExc) + { + typelib_TypeDescriptionReference * ret_type = aRet.pType; + switch (ret_type->eTypeClass) + { + case typelib_TypeClass_VOID: // common case + typelib_typedescriptionreference_release( ret_type ); + break; + case typelib_TypeClass_INTERFACE: + // tweaky... avoiding acquire/ release pair + typelib_typedescriptionreference_release( ret_type ); + ret = static_cast<uno_Interface *>(aRet.pReserved); // serving acquired interface + break; + default: + _destructAny( &aRet, nullptr ); + break; + } + } + else + { + SAL_WARN( + "cppu", + "exception occurred querying for interface " + << OUString(pDestType->pTypeName) << ": [" + << OUString(pExc->pType->pTypeName) << "] " + << *static_cast<OUString const *>(pExc->pData)); + // Message is very first member + uno_any_destruct( pExc, nullptr ); + } + return ret; +} + + +void defaultConstructStruct( + void * pMem, + typelib_CompoundTypeDescription * pCompType ) +{ + _defaultConstructStruct( pMem, pCompType ); +} + +void copyConstructStruct( + void * pDest, void * pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + _copyConstructStruct( pDest, pSource, pTypeDescr, acquire, mapping ); +} + +void destructStruct( + void * pValue, + typelib_CompoundTypeDescription * pTypeDescr, + uno_ReleaseFunc release ) +{ + _destructStruct( pValue, pTypeDescr, release ); +} + +bool equalStruct( + void * pDest, void *pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) +{ + return _equalStruct( pDest, pSource, pTypeDescr, queryInterface, release ); +} + +bool assignStruct( + void * pDest, void * pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release ) +{ + return _assignStruct( pDest, pSource, pTypeDescr, queryInterface, acquire, release ); +} + + +uno_Sequence * copyConstructSequence( + uno_Sequence * pSource, + typelib_TypeDescriptionReference * pElementType, + uno_AcquireFunc acquire, uno_Mapping * mapping ) +{ + return icopyConstructSequence( pSource, pElementType, acquire, mapping ); +} + + +void destructSequence( + uno_Sequence * pSequence, + typelib_TypeDescriptionReference * pType, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ) +{ + idestructSequence( pSequence, pType, pTypeDescr, release ); +} + + +bool equalSequence( + uno_Sequence * pDest, uno_Sequence * pSource, + typelib_TypeDescriptionReference * pElementType, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) +{ + return _equalSequence( pDest, pSource, pElementType, queryInterface, release ); +} + +} + +extern "C" +{ + +void SAL_CALL uno_type_constructData( + void * pMem, typelib_TypeDescriptionReference * pType ) + SAL_THROW_EXTERN_C() +{ + _defaultConstructData( pMem, pType, nullptr ); +} + +void SAL_CALL uno_constructData( + void * pMem, typelib_TypeDescription * pTypeDescr ) + SAL_THROW_EXTERN_C() +{ + _defaultConstructData( pMem, pTypeDescr->pWeakRef, pTypeDescr ); +} + +void SAL_CALL uno_type_destructData( + void * pValue, typelib_TypeDescriptionReference * pType, + uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + _destructData( pValue, pType, nullptr, release ); +} + +void SAL_CALL uno_destructData( + void * pValue, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + _destructData( pValue, pTypeDescr->pWeakRef, pTypeDescr, release ); +} + +void SAL_CALL uno_type_copyData( + void * pDest, void * pSource, + typelib_TypeDescriptionReference * pType, + uno_AcquireFunc acquire ) + SAL_THROW_EXTERN_C() +{ + _copyConstructData( pDest, pSource, pType, nullptr, acquire, nullptr ); +} + +void SAL_CALL uno_copyData( + void * pDest, void * pSource, + typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire ) + SAL_THROW_EXTERN_C() +{ + _copyConstructData( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, acquire, nullptr ); +} + +void SAL_CALL uno_type_copyAndConvertData( + void * pDest, void * pSource, + typelib_TypeDescriptionReference * pType, + uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + _copyConstructData( pDest, pSource, pType, nullptr, nullptr, mapping ); +} + +void SAL_CALL uno_copyAndConvertData( + void * pDest, void * pSource, + typelib_TypeDescription * pTypeDescr, + uno_Mapping * mapping ) + SAL_THROW_EXTERN_C() +{ + _copyConstructData( pDest, pSource, pTypeDescr->pWeakRef, pTypeDescr, nullptr, mapping ); +} + +sal_Bool SAL_CALL uno_type_equalData( + void * pVal1, typelib_TypeDescriptionReference * pVal1Type, + void * pVal2, typelib_TypeDescriptionReference * pVal2Type, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + return _equalData( + pVal1, pVal1Type, nullptr, + pVal2, pVal2Type, + queryInterface, release ); +} + +sal_Bool SAL_CALL uno_equalData( + void * pVal1, typelib_TypeDescription * pVal1TD, + void * pVal2, typelib_TypeDescription * pVal2TD, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + return _equalData( + pVal1, pVal1TD->pWeakRef, pVal1TD, + pVal2, pVal2TD->pWeakRef, + queryInterface, release ); +} + +sal_Bool SAL_CALL uno_type_assignData( + void * pDest, typelib_TypeDescriptionReference * pDestType, + void * pSource, typelib_TypeDescriptionReference * pSourceType, + uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + return _assignData( + pDest, pDestType, nullptr, + pSource, pSourceType, nullptr, + queryInterface, acquire, release ); +} + +sal_Bool SAL_CALL uno_assignData( + void * pDest, typelib_TypeDescription * pDestTD, + void * pSource, typelib_TypeDescription * pSourceTD, + uno_QueryInterfaceFunc queryInterface, uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + return _assignData( + pDest, pDestTD->pWeakRef, pDestTD, + pSource, pSourceTD->pWeakRef, pSourceTD, + queryInterface, acquire, release ); +} + +sal_Bool SAL_CALL uno_type_isAssignableFromData( + typelib_TypeDescriptionReference * pAssignable, + void * pFrom, typelib_TypeDescriptionReference * pFromType, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + if (::typelib_typedescriptionreference_isAssignableFrom( pAssignable, pFromType )) + return true; + if (typelib_TypeClass_INTERFACE != pFromType->eTypeClass || + typelib_TypeClass_INTERFACE != pAssignable->eTypeClass) + { + return false; + } + + // query + if (nullptr == pFrom) + return false; + void * pInterface = *static_cast<void **>(pFrom); + if (nullptr == pInterface) + return false; + + if (nullptr == queryInterface) + queryInterface = binuno_queryInterface; + void * p = (*queryInterface)( pInterface, pAssignable ); + _release( p, release ); + return (nullptr != p); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/destr.hxx b/cppu/source/uno/destr.hxx new file mode 100644 index 000000000..1b964e36a --- /dev/null +++ b/cppu/source/uno/destr.hxx @@ -0,0 +1,355 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_UNO_DESTR_HXX +#define INCLUDED_CPPU_SOURCE_UNO_DESTR_HXX + +#include <sal/config.h> +#include <osl/diagnose.h> + +#include <cassert> +#include <cstdlib> + +#include "prim.hxx" + +namespace cppu +{ + + +//#### destruction ################################################################################# + + +void destructStruct( + void * pValue, + typelib_CompoundTypeDescription * pTypeDescr, + uno_ReleaseFunc release ); + +inline void _destructStruct( + void * pValue, + typelib_CompoundTypeDescription * pTypeDescr, + uno_ReleaseFunc release ) +{ + if (pTypeDescr->pBaseTypeDescription) + { + destructStruct( pValue, pTypeDescr->pBaseTypeDescription, release ); + } + + typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs; + sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets; + sal_Int32 nDescr = pTypeDescr->nMembers; + while (nDescr--) + { + ::uno_type_destructData( + static_cast<char *>(pValue) + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], release ); + } +} + + +void destructSequence( + uno_Sequence * pSequence, + typelib_TypeDescriptionReference * pType, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ); + + +inline void _destructAny( + uno_Any * pAny, + uno_ReleaseFunc release ) +{ + typelib_TypeDescriptionReference * pType = pAny->pType; + + switch (pType->eTypeClass) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof(void *) < sizeof(sal_Int64)) + { + std::free( pAny->pData ); + } + break; + case typelib_TypeClass_FLOAT: + if (sizeof(void *) < sizeof(float)) + { + std::free( pAny->pData ); + } + break; + case typelib_TypeClass_DOUBLE: + if (sizeof(void *) < sizeof(double)) + { + std::free( pAny->pData ); + } + break; + case typelib_TypeClass_STRING: + ::rtl_uString_release( static_cast<rtl_uString *>(pAny->pReserved) ); + break; + case typelib_TypeClass_TYPE: + ::typelib_typedescriptionreference_release( + static_cast<typelib_TypeDescriptionReference *>(pAny->pReserved) ); + break; + case typelib_TypeClass_ANY: + OSL_FAIL( "### unexpected nested any!" ); + ::uno_any_destruct( static_cast<uno_Any *>(pAny->pData), release ); + std::free( pAny->pData ); + break; + case typelib_TypeClass_TYPEDEF: + OSL_FAIL( "### unexpected typedef!" ); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _destructStruct( pAny->pData, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), release ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + std::free( pAny->pData ); + break; + } + case typelib_TypeClass_SEQUENCE: + { + destructSequence( + static_cast<uno_Sequence *>(pAny->pReserved), pType, nullptr, release ); + break; + } + case typelib_TypeClass_INTERFACE: + _release( pAny->pReserved, release ); + break; + default: + break; + } +#if OSL_DEBUG_LEVEL > 0 + pAny->pData = reinterpret_cast<void *>(uintptr_t(0xdeadbeef)); +#endif + + ::typelib_typedescriptionreference_release( pType ); +} + +inline sal_Int32 idestructElements( + void * pElements, typelib_TypeDescriptionReference * pElementType, + sal_Int32 nStartIndex, sal_Int32 nStopIndex, + uno_ReleaseFunc release ) +{ + switch (pElementType->eTypeClass) + { + case typelib_TypeClass_CHAR: + return sal_Int32(sizeof(sal_Unicode)); + case typelib_TypeClass_BOOLEAN: + return sal_Int32(sizeof(sal_Bool)); + case typelib_TypeClass_BYTE: + return sal_Int32(sizeof(sal_Int8)); + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + return sal_Int32(sizeof(sal_Int16)); + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + return sal_Int32(sizeof(sal_Int32)); + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + return sal_Int32(sizeof(sal_Int64)); + case typelib_TypeClass_FLOAT: + return sal_Int32(sizeof(float)); + case typelib_TypeClass_DOUBLE: + return sal_Int32(sizeof(double)); + + case typelib_TypeClass_STRING: + { + rtl_uString ** pDest = static_cast<rtl_uString **>(pElements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + ::rtl_uString_release( pDest[nPos] ); + } + return sal_Int32(sizeof(rtl_uString *)); + } + case typelib_TypeClass_TYPE: + { + typelib_TypeDescriptionReference ** pDest = static_cast<typelib_TypeDescriptionReference **>(pElements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + ::typelib_typedescriptionreference_release( pDest[nPos] ); + } + return sal_Int32(sizeof(typelib_TypeDescriptionReference *)); + } + case typelib_TypeClass_ANY: + { + uno_Any * pDest = static_cast<uno_Any *>(pElements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + _destructAny( &pDest[nPos], release ); + } + return sal_Int32(sizeof(uno_Any)); + } + case typelib_TypeClass_ENUM: + return sal_Int32(sizeof(sal_Int32)); + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + sal_Int32 nElementSize = pElementTypeDescr->nSize; + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + _destructStruct( + static_cast<char *>(pElements) + (nElementSize * nPos), + reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr), + release ); + } + sal_Int32 nSize = pElementTypeDescr->nSize; + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + return nSize; + } + case typelib_TypeClass_SEQUENCE: + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + uno_Sequence ** pDest = static_cast<uno_Sequence **>(pElements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + destructSequence( + pDest[nPos], + pElementTypeDescr->pWeakRef, pElementTypeDescr, + release ); + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + return sal_Int32(sizeof(uno_Sequence *)); + } + case typelib_TypeClass_INTERFACE: + { + if (release) + { + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + void * p = static_cast<void **>(pElements)[nPos]; + if (p) + { + (*release)( p ); + } + } + } + else + { + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + uno_Interface * p = static_cast<uno_Interface **>(pElements)[nPos]; + if (p) + { + (*p->release)( p ); + } + } + } + return sal_Int32(sizeof(void *)); + } + default: + OSL_ASSERT(false); + return 0; + } +} + +inline void idestroySequence( + uno_Sequence * pSeq, + typelib_TypeDescriptionReference * pType, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ) +{ + assert(pSeq != nullptr); + assert(pSeq->nRefCount == 0); + if (pSeq->nElements > 0) + { + if (pTypeDescr) + { + idestructElements( + pSeq->elements, + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, 0, + pSeq->nElements, release ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + idestructElements( + pSeq->elements, + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, 0, + pSeq->nElements, release ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + } + std::free( pSeq ); +} + +inline void idestructSequence( + uno_Sequence * pSeq, + typelib_TypeDescriptionReference * pType, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ) +{ + if (osl_atomic_decrement( &pSeq->nRefCount ) == 0) + { + idestroySequence(pSeq, pType, pTypeDescr, release); + } +} + +inline void _destructData( + void * pValue, + typelib_TypeDescriptionReference * pType, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ) +{ + switch (pType->eTypeClass) + { + case typelib_TypeClass_STRING: + ::rtl_uString_release( *static_cast<rtl_uString **>(pValue) ); + break; + case typelib_TypeClass_TYPE: + ::typelib_typedescriptionreference_release( *static_cast<typelib_TypeDescriptionReference **>(pValue) ); + break; + case typelib_TypeClass_ANY: + _destructAny( static_cast<uno_Any *>(pValue), release ); + break; + case typelib_TypeClass_TYPEDEF: + OSL_FAIL( "### unexpected typedef!" ); + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (pTypeDescr) + { + _destructStruct( pValue, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), release ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + _destructStruct( pValue, reinterpret_cast<typelib_CompoundTypeDescription *>(pTypeDescr), release ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + break; + case typelib_TypeClass_SEQUENCE: + { + idestructSequence( + *static_cast<uno_Sequence **>(pValue), pType, pTypeDescr, release ); + break; + } + case typelib_TypeClass_INTERFACE: + _release( *static_cast<void **>(pValue), release ); + break; + default: + break; + } +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/eq.hxx b/cppu/source/uno/eq.hxx new file mode 100644 index 000000000..59401ad34 --- /dev/null +++ b/cppu/source/uno/eq.hxx @@ -0,0 +1,596 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_UNO_EQ_HXX +#define INCLUDED_CPPU_SOURCE_UNO_EQ_HXX + +#include <cmath> +#include <string.h> + +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> + +#include "prim.hxx" + + +namespace cppu +{ + + +//#### equality #################################################################################### + + +inline bool _equalObject( + void * pI1, void * pI2, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) +{ + if (pI1 == pI2) + return true; + if ((nullptr == pI1) || (nullptr == pI2)) + return false; + bool bRet = false; + + typelib_TypeDescriptionReference * type_XInterface = + * typelib_static_type_getByTypeClass( typelib_TypeClass_INTERFACE ); + if (nullptr == queryInterface) + queryInterface = binuno_queryInterface; + pI1 = (*queryInterface)( pI1, type_XInterface ); + if (nullptr != pI1) + { + pI2 = (*queryInterface)( pI2, type_XInterface ); + if (nullptr != pI2) + { + bRet = (pI1 == pI2); + _release( pI2, release ); + } + _release( pI1, release ); + } + return bRet; +} + + +bool equalStruct( + void * pDest, void *pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ); + +inline bool _equalStruct( + void * pDest, void *pSource, + typelib_CompoundTypeDescription * pTypeDescr, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) +{ + if (pTypeDescr->pBaseTypeDescription && + !equalStruct( pDest, pSource, pTypeDescr->pBaseTypeDescription, queryInterface, release )) + { + return false; + } + + typelib_TypeDescriptionReference ** ppTypeRefs = pTypeDescr->ppTypeRefs; + sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets; + sal_Int32 nDescr = pTypeDescr->nMembers; + + while (nDescr--) + { + sal_Int32 nOffset = pMemberOffsets[nDescr]; + if (! ::uno_type_equalData( static_cast<char *>(pDest) + nOffset, + ppTypeRefs[nDescr], + static_cast<char *>(pSource) + nOffset, + ppTypeRefs[nDescr], + queryInterface, release )) + { + return false; + } + } + return true; +} + +bool equalSequence( + uno_Sequence * pDest, uno_Sequence * pSource, + typelib_TypeDescriptionReference * pElementType, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ); + +inline bool _equalSequence( + uno_Sequence * pDest, uno_Sequence * pSource, + typelib_TypeDescriptionReference * pElementType, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) +{ + if (pDest == pSource) + return true; + sal_Int32 nElements = pDest->nElements; + if (nElements != pSource->nElements) + return false; + if (! nElements) + return true; + + void * pDestElements = pDest->elements; + void * pSourceElements = pSource->elements; + + switch (pElementType->eTypeClass) + { + case typelib_TypeClass_CHAR: + return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Unicode) * nElements )); + case typelib_TypeClass_BOOLEAN: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (bool(static_cast<sal_Bool *>(pDestElements)[nPos]) != + bool(static_cast<sal_Bool *>(pSourceElements)[nPos])) + { + return false; + } + } + return true; + } + case typelib_TypeClass_BYTE: + return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int8) * nElements )); + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int16) * nElements )); + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int32) * nElements )); + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int64) * nElements )); + case typelib_TypeClass_FLOAT: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (static_cast<float *>(pDestElements)[nPos] != static_cast<float *>(pSourceElements)[nPos]) + return false; + } + return true; + } + case typelib_TypeClass_DOUBLE: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (static_cast<double *>(pDestElements)[nPos] != static_cast<double *>(pSourceElements)[nPos]) + return false; + } + return true; + } + case typelib_TypeClass_STRING: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if ( static_cast<OUString *>(pDestElements)[nPos] != static_cast<const OUString *>(pSourceElements)[nPos] ) + return false; + } + return true; + } + case typelib_TypeClass_TYPE: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (! _type_equals( static_cast<typelib_TypeDescriptionReference **>(pDestElements)[nPos], + static_cast<typelib_TypeDescriptionReference **>(pSourceElements)[nPos] )) + { + return false; + } + } + return true; + } + case typelib_TypeClass_ANY: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + uno_Any * pDest2 = static_cast<uno_Any *>(pDestElements) + nPos; + uno_Any * pSource2 = static_cast<uno_Any *>(pSourceElements) + nPos; + if (! ::uno_type_equalData( pDest2->pData, pDest2->pType, + pSource2->pData, pSource2->pType, + queryInterface, release )) + { + return false; + } + } + return true; + } + case typelib_TypeClass_ENUM: + return (0 == memcmp( pDestElements, pSourceElements, sizeof(sal_Int32) * nElements )); + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + sal_Int32 nElementSize = pElementTypeDescr->nSize; + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (! _equalStruct( static_cast<char *>(pDestElements) + (nPos * nElementSize), + static_cast<char *>(pSourceElements) + (nPos * nElementSize), + reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr), + queryInterface, release )) + { + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + return false; + } + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + return true; + } + case typelib_TypeClass_SEQUENCE: // sequence of sequence + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + typelib_TypeDescriptionReference * pSeqElementType = + reinterpret_cast<typelib_IndirectTypeDescription *>(pElementTypeDescr)->pType; + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (! equalSequence( static_cast<uno_Sequence **>(pDestElements)[nPos], + static_cast<uno_Sequence **>(pSourceElements)[nPos], + pSeqElementType, queryInterface, release )) + { + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + return false; + } + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + return true; + } + case typelib_TypeClass_INTERFACE: + { + for ( sal_Int32 nPos = nElements; nPos--; ) + { + if (! _equalObject( static_cast<void **>(pDestElements)[nPos], static_cast<void **>(pSourceElements)[nPos], + queryInterface, release )) + { + return false; + } + } + return true; + } + default: + OSL_ASSERT(false); + return false; + } +} + +inline bool _equalData( + void * pDest, + typelib_TypeDescriptionReference * pDestType, typelib_TypeDescription * pDestTypeDescr, + void * pSource, + typelib_TypeDescriptionReference * pSourceType, + uno_QueryInterfaceFunc queryInterface, uno_ReleaseFunc release ) +{ + typelib_TypeClass eSourceTypeClass, eDestTypeClass; + while (typelib_TypeClass_ANY == (eDestTypeClass = pDestType->eTypeClass)) + { + pDestTypeDescr = nullptr; + pDestType = static_cast<uno_Any *>(pDest)->pType; + pDest = static_cast<uno_Any *>(pDest)->pData; + } + while (typelib_TypeClass_ANY == (eSourceTypeClass = pSourceType->eTypeClass)) + { + pSourceType = static_cast<uno_Any *>(pSource)->pType; + pSource = static_cast<uno_Any *>(pSource)->pData; + } + + switch (eDestTypeClass) + { + case typelib_TypeClass_VOID: + return eSourceTypeClass == typelib_TypeClass_VOID; + case typelib_TypeClass_CHAR: + return eSourceTypeClass == typelib_TypeClass_CHAR + && *static_cast<sal_Unicode *>(pDest) == *static_cast<sal_Unicode *>(pSource); + case typelib_TypeClass_BOOLEAN: + return eSourceTypeClass == typelib_TypeClass_BOOLEAN + && (bool(*static_cast<sal_Bool *>(pDest)) + == bool(*static_cast<sal_Bool *>(pSource))); + case typelib_TypeClass_BYTE: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<sal_Int8 *>(pDest) == *static_cast<sal_Int8 *>(pSource)); + case typelib_TypeClass_SHORT: + return (static_cast<sal_Int16>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<sal_Int16 *>(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return (static_cast<sal_Int32>(*static_cast<sal_Int8 *>(pDest)) == static_cast<sal_Int32>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (static_cast<sal_Int32>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<sal_Int32 *>(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return (static_cast<sal_Int64>(*static_cast<sal_Int8 *>(pDest)) == static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (static_cast<sal_Int64>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return (*static_cast<sal_Int8 *>(pDest) >= 0 && + static_cast<sal_Int64>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); // same size + case typelib_TypeClass_FLOAT: + return (static_cast<float>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<sal_Int8 *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_SHORT: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<sal_Int16 *>(pDest) == static_cast<sal_Int16>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast<sal_Int16 *>(pDest) == *static_cast<sal_Int16 *>(pSource)); + case typelib_TypeClass_UNSIGNED_SHORT: + return (static_cast<sal_Int32>(*static_cast<sal_Int16 *>(pDest)) == static_cast<sal_Int32>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (static_cast<sal_Int32>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<sal_Int32 *>(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return (static_cast<sal_Int64>(*static_cast<sal_Int16 *>(pDest)) == static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (static_cast<sal_Int64>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return (*static_cast<sal_Int16 *>(pDest) >= 0 && + static_cast<sal_Int64>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); // same size + case typelib_TypeClass_FLOAT: + return (static_cast<float>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<sal_Int16 *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_UNSIGNED_SHORT: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (static_cast<sal_Int32>(*static_cast<sal_uInt16 *>(pDest)) == static_cast<sal_Int32>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (static_cast<sal_Int32>(*static_cast<sal_uInt16 *>(pDest)) == static_cast<sal_Int32>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<sal_uInt16 *>(pDest) == *static_cast<sal_uInt16 *>(pSource)); + case typelib_TypeClass_LONG: + return (static_cast<sal_Int32>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<sal_Int32 *>(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return (static_cast<sal_uInt32>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<sal_uInt32 *>(pSource)); + case typelib_TypeClass_HYPER: + return (static_cast<sal_Int64>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return (static_cast<sal_uInt64>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<sal_uInt64 *>(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast<float>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<sal_uInt16 *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_LONG: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<sal_Int32 *>(pDest) == static_cast<sal_Int32>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast<sal_Int32 *>(pDest) == static_cast<sal_Int32>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<sal_Int32 *>(pDest) == static_cast<sal_Int32>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast<sal_Int32 *>(pDest) == *static_cast<sal_Int32 *>(pSource)); + case typelib_TypeClass_UNSIGNED_LONG: + return (static_cast<sal_Int64>(*static_cast<sal_Int32 *>(pDest)) == static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (static_cast<sal_Int64>(*static_cast<sal_Int32 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return (*static_cast<sal_Int32 *>(pDest) >= 0 && + static_cast<sal_Int64>(*static_cast<sal_Int32 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); // same size + case typelib_TypeClass_FLOAT: + return (static_cast<float>(*static_cast<sal_Int32 *>(pDest)) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<sal_Int32 *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_UNSIGNED_LONG: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pDest)) == static_cast<sal_Int64>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pDest)) == static_cast<sal_Int64>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<sal_uInt32 *>(pDest) == static_cast<sal_uInt32>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pDest)) == static_cast<sal_Int64>(*static_cast<sal_Int32 *>(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast<sal_uInt32 *>(pDest) == *static_cast<sal_uInt32 *>(pSource)); + case typelib_TypeClass_HYPER: + return (static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pDest)) == *static_cast<sal_Int64 *>(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return (static_cast<sal_uInt64>(*static_cast<sal_uInt32 *>(pDest)) == *static_cast<sal_uInt64 *>(pSource)); + case typelib_TypeClass_FLOAT: + return (static_cast<float>(*static_cast<sal_uInt32 *>(pDest)) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<sal_uInt32 *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_HYPER: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<sal_Int64 *>(pDest) == static_cast<sal_Int64>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast<sal_Int64 *>(pDest) == static_cast<sal_Int64>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<sal_Int64 *>(pDest) == static_cast<sal_Int64>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast<sal_Int64 *>(pDest) == static_cast<sal_Int64>(*static_cast<sal_Int32 *>(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast<sal_Int64 *>(pDest) == static_cast<sal_Int64>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (*static_cast<sal_Int64 *>(pDest) == *static_cast<sal_Int64 *>(pSource)); + case typelib_TypeClass_UNSIGNED_HYPER: + return (*static_cast<sal_Int64 *>(pDest) >= 0 && + *static_cast<sal_Int64 *>(pDest) == *static_cast<sal_Int64 *>(pSource)); // same size + case typelib_TypeClass_FLOAT: + return (static_cast<float>(*static_cast<sal_Int64 *>(pDest)) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<sal_Int64 *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_UNSIGNED_HYPER: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<sal_Int8 *>(pSource) >= 0 && + *static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast<sal_Int16 *>(pSource) >= 0 && + *static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast<sal_Int32 *>(pSource) >= 0 && + *static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<sal_Int32 *>(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (*static_cast<sal_Int64 *>(pSource) >= 0 && + *static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<sal_Int64 *>(pSource))); + case typelib_TypeClass_UNSIGNED_HYPER: + return (*static_cast<sal_uInt64 *>(pDest) == *static_cast<sal_uInt64 *>(pSource)); + case typelib_TypeClass_FLOAT: + if (::floor( *static_cast<float *>(pSource) ) != *static_cast<float *>(pSource) || *static_cast<float *>(pSource) < 0) + return false; + return (*static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<float *>(pSource))); + case typelib_TypeClass_DOUBLE: + if (::floor( *static_cast<double *>(pSource) ) != *static_cast<double *>(pSource) || *static_cast<double *>(pSource) < 0) + return false; + return (*static_cast<sal_uInt64 *>(pDest) == static_cast<sal_uInt64>(*static_cast<double *>(pSource))); + default: + return false; + } + case typelib_TypeClass_FLOAT: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int32 *>(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (*static_cast<float *>(pDest) == static_cast<float>(*static_cast<sal_Int64 *>(pSource))); + case typelib_TypeClass_UNSIGNED_HYPER: + if (::floor( *static_cast<float *>(pDest) ) != *static_cast<float *>(pDest) || *static_cast<float *>(pDest) < 0) + return false; + return (static_cast<sal_uInt64>(*static_cast<float *>(pDest)) == *static_cast<sal_uInt64 *>(pSource)); + case typelib_TypeClass_FLOAT: + return (*static_cast<float *>(pDest) == *static_cast<float *>(pSource)); + case typelib_TypeClass_DOUBLE: + return (static_cast<double>(*static_cast<float *>(pDest)) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_DOUBLE: + switch (eSourceTypeClass) + { + case typelib_TypeClass_BYTE: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int8 *>(pSource))); + case typelib_TypeClass_SHORT: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int16 *>(pSource))); + case typelib_TypeClass_UNSIGNED_SHORT: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_uInt16 *>(pSource))); + case typelib_TypeClass_LONG: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int32 *>(pSource))); + case typelib_TypeClass_UNSIGNED_LONG: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_uInt32 *>(pSource))); + case typelib_TypeClass_HYPER: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<sal_Int64 *>(pSource))); + case typelib_TypeClass_UNSIGNED_HYPER: + if (::floor( *static_cast<double *>(pDest) ) != *static_cast<double *>(pDest) || *static_cast<double *>(pDest) < 0) + return false; + return (static_cast<sal_uInt64>(*static_cast<double *>(pDest)) == *static_cast<sal_uInt64 *>(pSource)); + case typelib_TypeClass_FLOAT: + return (*static_cast<double *>(pDest) == static_cast<double>(*static_cast<float *>(pSource))); + case typelib_TypeClass_DOUBLE: + return (*static_cast<double *>(pDest) == *static_cast<double *>(pSource)); + default: + return false; + } + case typelib_TypeClass_STRING: + return eSourceTypeClass == typelib_TypeClass_STRING + && *static_cast<OUString *>(pDest) == + *static_cast<OUString const *>(pSource); + case typelib_TypeClass_TYPE: + return eSourceTypeClass == typelib_TypeClass_TYPE + && _type_equals( + *static_cast<typelib_TypeDescriptionReference **>(pDest), + *static_cast<typelib_TypeDescriptionReference **>(pSource) ); + case typelib_TypeClass_ENUM: + return (_type_equals( pDestType, pSourceType ) && + *static_cast<sal_Int32 *>(pDest) == *static_cast<sal_Int32 *>(pSource)); + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + if (! _type_equals( pDestType, pSourceType )) + return false; + if (pDestTypeDescr) + { + return _equalStruct( + pDest, pSource, + reinterpret_cast<typelib_CompoundTypeDescription *>(pDestTypeDescr), + queryInterface, release ); + } + else + { + TYPELIB_DANGER_GET( &pDestTypeDescr, pDestType ); + bool bRet = _equalStruct( + pDest, pSource, + reinterpret_cast<typelib_CompoundTypeDescription *>(pDestTypeDescr), + queryInterface, release ); + TYPELIB_DANGER_RELEASE( pDestTypeDescr ); + return bRet; + } + case typelib_TypeClass_SEQUENCE: + if (_type_equals( pDestType, pSourceType )) + { + if (pDestTypeDescr) + { + return _equalSequence( + *static_cast<uno_Sequence **>(pDest), *static_cast<uno_Sequence **>(pSource), + reinterpret_cast<typelib_IndirectTypeDescription *>(pDestTypeDescr)->pType, + queryInterface, release ); + } + else + { + TYPELIB_DANGER_GET( &pDestTypeDescr, pDestType ); + bool bRet = _equalSequence( + *static_cast<uno_Sequence **>(pDest), *static_cast<uno_Sequence **>(pSource), + reinterpret_cast<typelib_IndirectTypeDescription *>(pDestTypeDescr)->pType, + queryInterface, release ); + TYPELIB_DANGER_RELEASE( pDestTypeDescr ); + return bRet; + } + } + return false; + case typelib_TypeClass_INTERFACE: + if (typelib_TypeClass_INTERFACE == eSourceTypeClass) + return _equalObject( *static_cast<void **>(pDest), *static_cast<void **>(pSource), queryInterface, release ); + break; + default: + OSL_ASSERT(false); + break; + } + return false; +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/lbenv.cxx b/cppu/source/uno/lbenv.cxx new file mode 100644 index 000000000..c67d47dc9 --- /dev/null +++ b/cppu/source/uno/lbenv.cxx @@ -0,0 +1,1154 @@ +/* -*- 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 . + */ + +#ifdef DISABLE_DYNLOADING +#include <config_java.h> +#endif + +#include <cppu/EnvDcp.hxx> + +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <osl/interlck.h> +#include <osl/mutex.hxx> +#include <osl/module.hxx> +#include <osl/process.h> +#include <rtl/process.h> +#include <rtl/string.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/instance.hxx> +#include <typelib/typedescription.h> +#include <uno/dispatcher.h> +#include <uno/environment.h> +#include <uno/lbnames.h> +#include "prim.hxx" +#include "loadmodule.hxx" + +#include <unordered_map> +#include <vector> +#include <stdio.h> + + +namespace +{ + + +bool td_equals( typelib_InterfaceTypeDescription const * pTD1, + typelib_InterfaceTypeDescription const * pTD2 ) +{ + return (pTD1 == pTD2 || + (pTD1->aBase.pTypeName->length == pTD2->aBase.pTypeName->length && + ::rtl_ustr_compare( + pTD1->aBase.pTypeName->buffer, + pTD2->aBase.pTypeName->buffer ) == 0)); +} + +struct uno_DefaultEnvironment; + + +struct InterfaceEntry +{ + sal_Int32 refCount; + void * pInterface; + uno_freeProxyFunc fpFreeProxy; + typelib_InterfaceTypeDescription * pTypeDescr; +}; + +struct ObjectEntry +{ + OUString oid; + sal_Int32 nRef; + std::vector< InterfaceEntry > aInterfaces; + bool mixedObject; + + explicit ObjectEntry( const OUString & rOId_ ); + + void append( + uno_DefaultEnvironment * pEnv, + void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr, + uno_freeProxyFunc fpFreeProxy ); + InterfaceEntry * find( + typelib_InterfaceTypeDescription * pTypeDescr ); + sal_Int32 find( void const * iface_ptr, std::size_t pos ) const; +}; + + +struct FctPtrHash +{ + std::size_t operator () ( const void * pKey ) const + { return reinterpret_cast< std::size_t>( pKey ); } +}; + + +// mapping from environment name to environment +typedef std::unordered_map< + OUString, uno_Environment * > OUString2EnvironmentMap; + +// mapping from ptr to object entry +typedef std::unordered_map< + void *, ObjectEntry *, FctPtrHash > Ptr2ObjectMap; +// mapping from oid to object entry +typedef std::unordered_map< + OUString, ObjectEntry * > OId2ObjectMap; + +struct EnvironmentsData +{ + ::osl::Mutex mutex; + OUString2EnvironmentMap aName2EnvMap; + + EnvironmentsData() : isDisposing(false) {} + ~EnvironmentsData(); + + void getEnvironment( + uno_Environment ** ppEnv, const OUString & rEnvDcp, void * pContext ); + void registerEnvironment( uno_Environment ** ppEnv ); + void getRegisteredEnvironments( + uno_Environment *** pppEnvs, sal_Int32 * pnLen, + uno_memAlloc memAlloc, const OUString & rEnvDcp ); + + bool isDisposing; +}; + +struct theEnvironmentsData : public rtl::Static< EnvironmentsData, theEnvironmentsData > {}; + +struct uno_DefaultEnvironment : public uno_ExtEnvironment +{ + sal_Int32 nRef; + sal_Int32 nWeakRef; + + ::osl::Mutex mutex; + Ptr2ObjectMap aPtr2ObjectMap; + OId2ObjectMap aOId2ObjectMap; + + uno_DefaultEnvironment( + const OUString & rEnvDcp_, void * pContext_ ); + ~uno_DefaultEnvironment(); +}; + + +ObjectEntry::ObjectEntry( OUString const & rOId_ ) + : oid( rOId_ ), + nRef( 0 ), + mixedObject( false ) +{ + aInterfaces.reserve( 2 ); +} + + +void ObjectEntry::append( + uno_DefaultEnvironment * pEnv, + void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr, + uno_freeProxyFunc fpFreeProxy ) +{ + InterfaceEntry aNewEntry; + if (! fpFreeProxy) + (*pEnv->acquireInterface)( pEnv, pInterface ); + aNewEntry.refCount = 1; + aNewEntry.pInterface = pInterface; + aNewEntry.fpFreeProxy = fpFreeProxy; + typelib_typedescription_acquire( &pTypeDescr->aBase ); + aNewEntry.pTypeDescr = pTypeDescr; + + std::pair< Ptr2ObjectMap::iterator, bool > i( + pEnv->aPtr2ObjectMap.emplace( pInterface, this ) ); + SAL_WARN_IF( + !i.second && (find(pInterface, 0) == -1 || i.first->second != this), + "cppu", + "map already contains " << i.first->second << " != " << this << " for " + << pInterface); + aInterfaces.push_back( aNewEntry ); +} + + +InterfaceEntry * ObjectEntry::find( + typelib_InterfaceTypeDescription * pTypeDescr_ ) +{ + OSL_ASSERT( ! aInterfaces.empty() ); + if (aInterfaces.empty()) + return nullptr; + + // shortcut common case: + OUString const & type_name = + OUString::unacquired( &pTypeDescr_->aBase.pTypeName ); + if ( type_name == "com.sun.star.uno.XInterface" ) + { + return aInterfaces.data(); + } + + std::size_t nSize = aInterfaces.size(); + for ( std::size_t nPos = 0; nPos < nSize; ++nPos ) + { + typelib_InterfaceTypeDescription * pITD = + aInterfaces[ nPos ].pTypeDescr; + while (pITD) + { + if (td_equals( pITD, pTypeDescr_ )) + return &aInterfaces[ nPos ]; + pITD = pITD->pBaseTypeDescription; + } + } + return nullptr; +} + + +sal_Int32 ObjectEntry::find( + void const * iface_ptr, std::size_t pos ) const +{ + std::size_t size = aInterfaces.size(); + for ( ; pos < size; ++pos ) + { + if (aInterfaces[ pos ].pInterface == iface_ptr) + return pos; + } + return -1; +} + +extern "C" +{ + + +static void defenv_registerInterface( + uno_ExtEnvironment * pEnv, void ** ppInterface, + rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr ) +{ + OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr, "### null ptr!" ); + OUString const & rOId = OUString::unacquired( &pOId ); + + uno_DefaultEnvironment * that = + static_cast< uno_DefaultEnvironment * >( pEnv ); + ::osl::ClearableMutexGuard guard( that->mutex ); + + // try to insert dummy 0: + std::pair<OId2ObjectMap::iterator, bool> const insertion( + that->aOId2ObjectMap.emplace( rOId, nullptr ) ); + if (insertion.second) + { + ObjectEntry * pOEntry = new ObjectEntry( rOId ); + insertion.first->second = pOEntry; + ++pOEntry->nRef; // another register call on object + pOEntry->append( that, *ppInterface, pTypeDescr, nullptr ); + } + else // object entry exists + { + ObjectEntry * pOEntry = insertion.first->second; + ++pOEntry->nRef; // another register call on object + InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr ); + + if (pIEntry) // type entry exists + { + ++pIEntry->refCount; + if (pIEntry->pInterface != *ppInterface) + { + void * pInterface = pIEntry->pInterface; + (*pEnv->acquireInterface)( pEnv, pInterface ); + guard.clear(); + (*pEnv->releaseInterface)( pEnv, *ppInterface ); + *ppInterface = pInterface; + } + } + else + { + pOEntry->append( that, *ppInterface, pTypeDescr, nullptr ); + } + } +} + + +static void defenv_registerProxyInterface( + uno_ExtEnvironment * pEnv, void ** ppInterface, uno_freeProxyFunc freeProxy, + rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr ) +{ + OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr && freeProxy, + "### null ptr!" ); + OUString const & rOId = OUString::unacquired( &pOId ); + + uno_DefaultEnvironment * that = + static_cast< uno_DefaultEnvironment * >( pEnv ); + ::osl::ClearableMutexGuard guard( that->mutex ); + + // try to insert dummy 0: + std::pair<OId2ObjectMap::iterator, bool> const insertion( + that->aOId2ObjectMap.emplace( rOId, nullptr ) ); + if (insertion.second) + { + ObjectEntry * pOEntry = new ObjectEntry( rOId ); + insertion.first->second = pOEntry; + ++pOEntry->nRef; // another register call on object + pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy ); + } + else // object entry exists + { + ObjectEntry * pOEntry = insertion.first->second; + + // first registration was an original, then registerProxyInterface(): + pOEntry->mixedObject |= + (!pOEntry->aInterfaces.empty() && + pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr); + + ++pOEntry->nRef; // another register call on object + InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr ); + + if (pIEntry) // type entry exists + { + if (pIEntry->pInterface == *ppInterface) + { + ++pIEntry->refCount; + } + else + { + void * pInterface = pIEntry->pInterface; + (*pEnv->acquireInterface)( pEnv, pInterface ); + --pOEntry->nRef; // manual revoke of proxy to be freed + guard.clear(); + (*freeProxy)( pEnv, *ppInterface ); + *ppInterface = pInterface; + } + } + else + { + pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy ); + } + } +} + + +static void s_stub_defenv_revokeInterface(va_list * pParam) +{ + uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *); + void * pInterface = va_arg(*pParam, void *); + + OSL_ENSURE( pEnv && pInterface, "### null ptr!" ); + uno_DefaultEnvironment * that = + static_cast< uno_DefaultEnvironment * >( pEnv ); + ::osl::ClearableMutexGuard guard( that->mutex ); + + Ptr2ObjectMap::const_iterator const iFind( + that->aPtr2ObjectMap.find( pInterface ) ); + OSL_ASSERT( iFind != that->aPtr2ObjectMap.end() ); + ObjectEntry * pOEntry = iFind->second; + if (! --pOEntry->nRef) + { + // cleanup maps + that->aOId2ObjectMap.erase( pOEntry->oid ); + sal_Int32 nPos; + for ( nPos = pOEntry->aInterfaces.size(); nPos--; ) + { + that->aPtr2ObjectMap.erase( pOEntry->aInterfaces[nPos].pInterface ); + } + + // the last proxy interface of the environment might kill this + // environment, because of releasing its language binding!!! + guard.clear(); + + // release interfaces + for ( nPos = pOEntry->aInterfaces.size(); nPos--; ) + { + InterfaceEntry const & rEntry = pOEntry->aInterfaces[nPos]; + typelib_typedescription_release( &rEntry.pTypeDescr->aBase ); + if (rEntry.fpFreeProxy) // is proxy or used interface? + { + (*rEntry.fpFreeProxy)( pEnv, rEntry.pInterface ); + } + else + { + (*pEnv->releaseInterface)( pEnv, rEntry.pInterface ); + } + } + + delete pOEntry; + } + else if (pOEntry->mixedObject) + { + OSL_ASSERT( !pOEntry->aInterfaces.empty() && + pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr ); + + sal_Int32 index = pOEntry->find( pInterface, 1 ); + OSL_ASSERT( index > 0 ); + if (index > 0) + { + InterfaceEntry & entry = pOEntry->aInterfaces[ index ]; + OSL_ASSERT( entry.pInterface == pInterface ); + if (entry.fpFreeProxy != nullptr) + { + --entry.refCount; + if (entry.refCount == 0) + { + uno_freeProxyFunc fpFreeProxy = entry.fpFreeProxy; + typelib_TypeDescription * pTypeDescr = + reinterpret_cast< typelib_TypeDescription * >( + entry.pTypeDescr ); + + pOEntry->aInterfaces.erase( + pOEntry->aInterfaces.begin() + index ); + if (pOEntry->find( pInterface, index ) < 0) + { + // proxy ptr not registered for another interface: + // remove from ptr map + std::size_t erased = + that->aPtr2ObjectMap.erase( pInterface ); + OSL_ASSERT( erased == 1 ); + } + + guard.clear(); + + typelib_typedescription_release( pTypeDescr ); + (*fpFreeProxy)( pEnv, pInterface ); + } + } + } + } +} + +static void defenv_revokeInterface(uno_ExtEnvironment * pEnv, void * pInterface) +{ + uno_Environment_invoke(&pEnv->aBase, s_stub_defenv_revokeInterface, pEnv, pInterface); +} + + +static void defenv_getObjectIdentifier( + uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface ) +{ + OSL_ENSURE( pEnv && ppOId && pInterface, "### null ptr!" ); + if (*ppOId) + { + ::rtl_uString_release( *ppOId ); + *ppOId = nullptr; + } + + uno_DefaultEnvironment * that = + static_cast< uno_DefaultEnvironment * >( pEnv ); + ::osl::ClearableMutexGuard guard( that->mutex ); + + Ptr2ObjectMap::const_iterator const iFind( + that->aPtr2ObjectMap.find( pInterface ) ); + if (iFind == that->aPtr2ObjectMap.end()) + { + guard.clear(); + (*pEnv->computeObjectIdentifier)( pEnv, ppOId, pInterface ); + } + else + { + rtl_uString * hstr = iFind->second->oid.pData; + rtl_uString_acquire( hstr ); + *ppOId = hstr; + } +} + + +static void defenv_getRegisteredInterface( + uno_ExtEnvironment * pEnv, void ** ppInterface, + rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr ) +{ + OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr, "### null ptr!" ); + if (*ppInterface) + { + (*pEnv->releaseInterface)( pEnv, *ppInterface ); + *ppInterface = nullptr; + } + + OUString const & rOId = OUString::unacquired( &pOId ); + uno_DefaultEnvironment * that = + static_cast< uno_DefaultEnvironment * >( pEnv ); + ::osl::MutexGuard guard( that->mutex ); + + OId2ObjectMap::const_iterator const iFind + ( that->aOId2ObjectMap.find( rOId ) ); + if (iFind != that->aOId2ObjectMap.end()) + { + InterfaceEntry const * pIEntry = iFind->second->find( pTypeDescr ); + if (pIEntry) + { + (*pEnv->acquireInterface)( pEnv, pIEntry->pInterface ); + *ppInterface = pIEntry->pInterface; + } + } +} + + +static void defenv_getRegisteredInterfaces( + uno_ExtEnvironment * pEnv, void *** pppInterfaces, sal_Int32 * pnLen, + uno_memAlloc memAlloc ) +{ + assert(pEnv && pppInterfaces && pnLen && memAlloc && "### null ptr!"); + uno_DefaultEnvironment * that = + static_cast< uno_DefaultEnvironment * >( pEnv ); + ::osl::MutexGuard guard( that->mutex ); + + sal_Int32 nLen = that->aPtr2ObjectMap.size(); + sal_Int32 nPos = 0; + void ** ppInterfaces = static_cast<void **>((*memAlloc)( nLen * sizeof (void *) )); + + for (const auto& rEntry : that->aPtr2ObjectMap) + { + ppInterfaces[nPos] = rEntry.first; + (*pEnv->acquireInterface)( pEnv, ppInterfaces[nPos] ); + nPos++; + } + + *pppInterfaces = ppInterfaces; + *pnLen = nLen; +} + + +static void defenv_acquire( uno_Environment * pEnv ) +{ + uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv); + osl_atomic_increment( &that->nWeakRef ); + osl_atomic_increment( &that->nRef ); +} + + +static void defenv_release( uno_Environment * pEnv ) +{ + uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv); + if (! osl_atomic_decrement( &that->nRef )) + { + // invoke dispose callback + if (pEnv->environmentDisposing) + { + (*pEnv->environmentDisposing)( pEnv ); + } + + OSL_ENSURE( that->aOId2ObjectMap.empty(), "### object entries left!" ); + } + // free memory if no weak refs left + if (! osl_atomic_decrement( &that->nWeakRef )) + { + delete that; + } +} + + +static void defenv_acquireWeak( uno_Environment * pEnv ) +{ + uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv); + osl_atomic_increment( &that->nWeakRef ); +} + + +static void defenv_releaseWeak( uno_Environment * pEnv ) +{ + uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv); + if (! osl_atomic_decrement( &that->nWeakRef )) + { + delete that; + } +} + + +static void defenv_harden( + uno_Environment ** ppHardEnv, uno_Environment * pEnv ) +{ + if (*ppHardEnv) + { + (*(*ppHardEnv)->release)( *ppHardEnv ); + *ppHardEnv = nullptr; + } + + EnvironmentsData & rData = theEnvironmentsData::get(); + + if (rData.isDisposing) + return; + + uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv); + { + ::osl::MutexGuard guard( rData.mutex ); + if (1 == osl_atomic_increment( &that->nRef )) // is dead + { + that->nRef = 0; + return; + } + } + osl_atomic_increment( &that->nWeakRef ); + *ppHardEnv = pEnv; +} + + +static void defenv_dispose( SAL_UNUSED_PARAMETER uno_Environment * ) +{ +} +} + + +uno_DefaultEnvironment::uno_DefaultEnvironment( + const OUString & rEnvDcp_, void * pContext_ ) + : nRef( 0 ), + nWeakRef( 0 ) +{ + uno_Environment * that = reinterpret_cast< uno_Environment * >(this); + that->pReserved = nullptr; + // functions + that->acquire = defenv_acquire; + that->release = defenv_release; + that->acquireWeak = defenv_acquireWeak; + that->releaseWeak = defenv_releaseWeak; + that->harden = defenv_harden; + that->dispose = defenv_dispose; + that->pExtEnv = this; + // identifier + ::rtl_uString_acquire( rEnvDcp_.pData ); + that->pTypeName = rEnvDcp_.pData; + that->pContext = pContext_; + + // will be late initialized + that->environmentDisposing = nullptr; + + uno_ExtEnvironment::registerInterface = defenv_registerInterface; + uno_ExtEnvironment::registerProxyInterface = defenv_registerProxyInterface; + uno_ExtEnvironment::revokeInterface = defenv_revokeInterface; + uno_ExtEnvironment::getObjectIdentifier = defenv_getObjectIdentifier; + uno_ExtEnvironment::getRegisteredInterface = defenv_getRegisteredInterface; + uno_ExtEnvironment::getRegisteredInterfaces = + defenv_getRegisteredInterfaces; + +} + + +uno_DefaultEnvironment::~uno_DefaultEnvironment() +{ + ::rtl_uString_release( aBase.pTypeName ); +} + + +void writeLine( + void * stream, const char * pLine, const char * pFilter ) +{ + if (pFilter && *pFilter) + { + // lookup pFilter in pLine + while (*pLine) + { + if (*pLine == *pFilter) + { + sal_Int32 nPos = 1; + while (pLine[nPos] && pFilter[nPos] == pLine[nPos]) + { + ++nPos; + } + if (! pFilter[nPos]) + { + if (stream) + { + fprintf( static_cast<FILE *>(stream), "%s\n", pLine ); + } + else + { + SAL_WARN("cppu", pLine ); + } + } + } + ++pLine; + } + } + else + { + if (stream) + { + fprintf( static_cast<FILE *>(stream), "%s\n", pLine ); + } + else + { + fprintf( stderr, "%s\n", pLine ); + } + } +} + + +void writeLine( + void * stream, const OUString & rLine, const char * pFilter ) +{ + OString aLine( OUStringToOString( + rLine, RTL_TEXTENCODING_ASCII_US ) ); + writeLine( stream, aLine.getStr(), pFilter ); +} + +} + +extern "C" void SAL_CALL uno_dumpEnvironment( + void * stream, uno_Environment * pEnv, const char * pFilter ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( pEnv, "### null ptr!" ); + OUStringBuffer buf; + + if (! pEnv->pExtEnv) + { + writeLine( stream, "###################################" + "###########################################", pFilter ); + buf.append( "environment: " ); + buf.append( pEnv->pTypeName ); + writeLine( stream, buf.makeStringAndClear(), pFilter ); + writeLine( stream, "NO INTERFACE INFORMATION AVAILABLE!", pFilter ); + return; + } + + writeLine( stream, "########################################" + "######################################", pFilter ); + buf.append( "environment dump: " ); + buf.append( pEnv->pTypeName ); + writeLine( stream, buf.makeStringAndClear(), pFilter ); + + uno_DefaultEnvironment * that = + reinterpret_cast< uno_DefaultEnvironment * >(pEnv); + ::osl::MutexGuard guard( that->mutex ); + + Ptr2ObjectMap ptr2obj( that->aPtr2ObjectMap ); + for (const auto& rEntry : that->aOId2ObjectMap) + { + ObjectEntry * pOEntry = rEntry.second; + + buf.append( "+ " ); + if (pOEntry->mixedObject) + buf.append( "mixed " ); + buf.append( "object entry: nRef=" ); + buf.append( pOEntry->nRef ); + buf.append( "; oid=\"" ); + buf.append( pOEntry->oid ); + buf.append( '\"' ); + writeLine( stream, buf.makeStringAndClear(), pFilter ); + + for ( std::size_t nPos = 0; + nPos < pOEntry->aInterfaces.size(); ++nPos ) + { + const InterfaceEntry & rIEntry = pOEntry->aInterfaces[nPos]; + + buf.append( " - " ); + buf.append( rIEntry.pTypeDescr->aBase.pTypeName ); + if (rIEntry.fpFreeProxy) + { + buf.append( "; proxy free=0x" ); + buf.append( + reinterpret_cast< sal_IntPtr >(rIEntry.fpFreeProxy), 16 ); + } + else + { + buf.append( "; original" ); + } + buf.append( "; ptr=0x" ); + buf.append( + reinterpret_cast< sal_IntPtr >(rIEntry.pInterface), 16 ); + + if (pOEntry->find( rIEntry.pInterface, nPos + 1 ) < 0) + { + std::size_t erased = ptr2obj.erase( rIEntry.pInterface ); + if (erased != 1) + { + buf.append( " (ptr not found in map!)" ); + } + } + writeLine( stream, buf.makeStringAndClear(), pFilter ); + } + } + if (! ptr2obj.empty()) + writeLine( stream, "ptr map inconsistency!!!", pFilter ); + writeLine( stream, "#####################################" + "#########################################", pFilter ); +} + + +extern "C" void SAL_CALL uno_dumpEnvironmentByName( + void * stream, rtl_uString * pEnvDcp, const char * pFilter ) + SAL_THROW_EXTERN_C() +{ + uno_Environment * pEnv = nullptr; + uno_getEnvironment( &pEnv, pEnvDcp, nullptr ); + if (pEnv) + { + ::uno_dumpEnvironment( stream, pEnv, pFilter ); + (*pEnv->release)( pEnv ); + } + else + { + writeLine( + stream, "environment \"" + OUString::unacquired(&pEnvDcp) + "\" does not exist!", + pFilter ); + } +} + +namespace +{ + class makeOIdPart + { + private: + OUString m_sOidPart; + public: + makeOIdPart() + { + OUStringBuffer aRet( 64 ); + aRet.append( "];" ); + // pid + oslProcessInfo info; + info.Size = sizeof(oslProcessInfo); + if (::osl_getProcessInfo( nullptr, osl_Process_IDENTIFIER, &info ) == + osl_Process_E_None) + { + aRet.append( static_cast<sal_Int64>(info.Ident), 16 ); + } + else + { + aRet.append( "unknown process id" ); + } + // good guid + sal_uInt8 ar[16]; + ::rtl_getGlobalProcessId( ar ); + aRet.append( ';' ); + for (unsigned char i : ar) + aRet.append( static_cast<sal_Int32>(i), 16 ); + + m_sOidPart = aRet.makeStringAndClear(); + } + const OUString& getOIdPart() const { return m_sOidPart; } + }; + + class theStaticOIdPart : public rtl::Static<makeOIdPart, theStaticOIdPart> {}; + +const OUString & unoenv_getStaticOIdPart() +{ + return theStaticOIdPart::get().getOIdPart(); +} + +} + +extern "C" +{ + + +static void unoenv_computeObjectIdentifier( + uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface ) +{ + assert(pEnv && ppOId && pInterface && "### null ptr!"); + if (*ppOId) + { + ::rtl_uString_release( *ppOId ); + *ppOId = nullptr; + } + + uno_Interface * pUnoI = static_cast<uno_Interface *>( + ::cppu::binuno_queryInterface( + pInterface, *typelib_static_type_getByTypeClass( + typelib_TypeClass_INTERFACE ) )); + if (nullptr == pUnoI) + return; + + (*pUnoI->release)( pUnoI ); + // interface + OUStringBuffer oid( 64 ); + oid.append( reinterpret_cast< sal_Int64 >(pUnoI), 16 ); + oid.append( ';' ); + // environment[context] + oid.append( pEnv->aBase.pTypeName ); + oid.append( '[' ); + oid.append( reinterpret_cast< sal_Int64 >( + reinterpret_cast< + uno_Environment * >(pEnv)->pContext ), 16 ); + // process;good guid + oid.append( unoenv_getStaticOIdPart() ); + OUString aStr( oid.makeStringAndClear() ); + *ppOId = aStr.pData; + ::rtl_uString_acquire( *ppOId ); +} + + +static void unoenv_acquireInterface( + SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ ) +{ + uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_); + (*pUnoI->acquire)( pUnoI ); +} + + +static void unoenv_releaseInterface( + SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ ) +{ + uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_); + (*pUnoI->release)( pUnoI ); +} +} + +namespace { + +EnvironmentsData::~EnvironmentsData() +{ + ::osl::MutexGuard guard( mutex ); + isDisposing = true; + + for ( const auto& rEntry : aName2EnvMap ) + { + uno_Environment * pWeak = rEntry.second; + uno_Environment * pHard = nullptr; + (*pWeak->harden)( &pHard, pWeak ); + (*pWeak->releaseWeak)( pWeak ); + + if (pHard) + { + (*pHard->dispose)( pHard ); // send explicit dispose + (*pHard->release)( pHard ); + } + } +} + + +void EnvironmentsData::getEnvironment( + uno_Environment ** ppEnv, const OUString & rEnvDcp, void * pContext ) +{ + if (*ppEnv) + { + (*(*ppEnv)->release)( *ppEnv ); + *ppEnv = nullptr; + } + + OUString aKey = OUString::number( reinterpret_cast< sal_IntPtr >(pContext) ) + rEnvDcp; + + // try to find registered mapping + OUString2EnvironmentMap::const_iterator const iFind( + aName2EnvMap.find( aKey ) ); + if (iFind != aName2EnvMap.end()) + { + uno_Environment * pWeak = iFind->second; + (*pWeak->harden)( ppEnv, pWeak ); + } +} + + +void EnvironmentsData::registerEnvironment( uno_Environment ** ppEnv ) +{ + OSL_ENSURE( ppEnv, "### null ptr!" ); + uno_Environment * pEnv = *ppEnv; + + OUString aKey = + OUString::number( reinterpret_cast< sal_IntPtr >(pEnv->pContext) ) + + OUString::unacquired(&pEnv->pTypeName); + + // try to find registered environment + OUString2EnvironmentMap::const_iterator const iFind( + aName2EnvMap.find( aKey ) ); + if (iFind == aName2EnvMap.end()) + { + (*pEnv->acquireWeak)( pEnv ); + std::pair< OUString2EnvironmentMap::iterator, bool > insertion ( + aName2EnvMap.emplace( aKey, pEnv ) ); + SAL_WARN_IF( !insertion.second, "cppu", "key " << aKey << " already in env map" ); + } + else + { + uno_Environment * pHard = nullptr; + uno_Environment * pWeak = iFind->second; + (*pWeak->harden)( &pHard, pWeak ); + if (pHard) + { + (*pEnv->release)( pEnv ); + *ppEnv = pHard; + } + else // registered one is dead + { + (*pWeak->releaseWeak)( pWeak ); + (*pEnv->acquireWeak)( pEnv ); + aName2EnvMap[ aKey ] = pEnv; + } + } +} + + +void EnvironmentsData::getRegisteredEnvironments( + uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc, + const OUString & rEnvDcp ) +{ + assert(pppEnvs && pnLen && memAlloc && "### null ptr!"); + + // max size + std::vector<uno_Environment*> aFounds(aName2EnvMap.size()); + sal_Int32 nSize = 0; + + // find matching environment + for ( const auto& rEntry : aName2EnvMap ) + { + uno_Environment * pWeak = rEntry.second; + if (rEnvDcp.isEmpty() || + rEnvDcp == pWeak->pTypeName ) + { + aFounds[nSize] = nullptr; + (*pWeak->harden)( &aFounds[nSize], pWeak ); + if (aFounds[nSize]) + ++nSize; + } + } + + *pnLen = nSize; + if (nSize) + { + *pppEnvs = static_cast<uno_Environment **>((*memAlloc)( + sizeof (uno_Environment *) * nSize )); + OSL_ASSERT( *pppEnvs ); + while (nSize--) + { + (*pppEnvs)[nSize] = aFounds[nSize]; + } + } + else + { + *pppEnvs = nullptr; + } +} + +bool loadEnv(OUString const & cLibStem, + uno_Environment * pEnv) +{ +#ifdef DISABLE_DYNLOADING + uno_initEnvironmentFunc fpInit; + + if ( cLibStem == CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" ) + fpInit = CPPU_ENV_uno_initEnvironment; +#if HAVE_FEATURE_JAVA + else if ( cLibStem == "java_uno" ) + fpInit = java_uno_initEnvironment; +#endif + else + { + SAL_INFO("cppu", ": Unhandled env: " << cLibStem); + return false; + } +#else + // late init with some code from matching uno language binding + // will be unloaded by environment + osl::Module aMod; + try { + bool bMod = cppu::detail::loadModule(aMod, cLibStem); + if (!bMod) + return false; + } + catch(...) { + // Catch everything and convert to return false + return false; + } + + + uno_initEnvironmentFunc fpInit = reinterpret_cast<uno_initEnvironmentFunc>(aMod.getSymbol(UNO_INIT_ENVIRONMENT)); + + if (!fpInit) + return false; + + aMod.release(); +#endif + + (*fpInit)( pEnv ); // init of environment + return true; +} + +} + +extern "C" +{ + + +static uno_Environment * initDefaultEnvironment( + const OUString & rEnvDcp, void * pContext ) +{ + // coverity[leaked_storage : FALSE] - lifetime is controlled by acquire()/release() calls + uno_Environment * pEnv = &(new uno_DefaultEnvironment( rEnvDcp, pContext ))->aBase; + (*pEnv->acquire)( pEnv ); + + OUString envTypeName = cppu::EnvDcp::getTypeName(rEnvDcp); + + // create default environment + if ( envTypeName == UNO_LB_UNO ) + { + uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv); + that->computeObjectIdentifier = unoenv_computeObjectIdentifier; + that->acquireInterface = unoenv_acquireInterface; + that->releaseInterface = unoenv_releaseInterface; + + OUString envPurpose = cppu::EnvDcp::getPurpose(rEnvDcp); + if (!envPurpose.isEmpty()) + { + OUString libStem( + envPurpose.copy(envPurpose.lastIndexOf(':') + 1) + "_uno_uno"); + if(!loadEnv(libStem, pEnv)) + { + pEnv->release(pEnv); + return nullptr; + } + } + } + else + { + // late init with some code from matching uno language binding + OUString aStr( envTypeName + "_uno" ); + + if (!loadEnv(aStr, pEnv)) + { + pEnv->release(pEnv); + return nullptr; + } + } + + return pEnv; +} + + +void SAL_CALL uno_createEnvironment( + uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext ) + SAL_THROW_EXTERN_C() +{ + assert(ppEnv && "### null ptr!"); + if (*ppEnv) + (*(*ppEnv)->release)( *ppEnv ); + + OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp ); + *ppEnv = initDefaultEnvironment( rEnvDcp, pContext ); +} + +void SAL_CALL uno_getEnvironment( + uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext ) + SAL_THROW_EXTERN_C() +{ + assert(ppEnv && "### null ptr!"); + OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp ); + + EnvironmentsData & rData = theEnvironmentsData::get(); + + ::osl::MutexGuard guard( rData.mutex ); + rData.getEnvironment( ppEnv, rEnvDcp, pContext ); + if (! *ppEnv) + { + *ppEnv = initDefaultEnvironment( rEnvDcp, pContext ); + if (*ppEnv) + { + // register new environment: + rData.registerEnvironment( ppEnv ); + } + } +} + +void SAL_CALL uno_getRegisteredEnvironments( + uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc, + rtl_uString * pEnvDcp ) + SAL_THROW_EXTERN_C() +{ + EnvironmentsData & rData = theEnvironmentsData::get(); + + ::osl::MutexGuard guard( rData.mutex ); + rData.getRegisteredEnvironments( + pppEnvs, pnLen, memAlloc, + (pEnvDcp ? OUString(pEnvDcp) : OUString()) ); +} + +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/lbmap.cxx b/cppu/source/uno/lbmap.cxx new file mode 100644 index 000000000..1e8655a99 --- /dev/null +++ b/cppu/source/uno/lbmap.cxx @@ -0,0 +1,752 @@ +/* -*- 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 . + */ + +#ifdef DISABLE_DYNLOADING +#include <config_java.h> +#endif + +#include "IdentityMapping.hxx" + +#include <cassert> +#include <set> +#include <unordered_map> + +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <osl/module.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <osl/interlck.h> +#include <sal/log.hxx> + +#include <uno/dispatcher.h> +#include <uno/mapping.h> +#include <uno/lbnames.h> +#include <uno/environment.hxx> + +#include <typelib/typedescription.h> + +#include <cppu/EnvDcp.hxx> +#include "cascade_mapping.hxx" +#include "loadmodule.hxx" + +using namespace std; +using namespace osl; +using namespace com::sun::star::uno; + +namespace cppu +{ + +namespace { + +class Mapping +{ + uno_Mapping * _pMapping; + +public: + inline explicit Mapping( uno_Mapping * pMapping = nullptr ); + inline Mapping( const Mapping & rMapping ); + Mapping(Mapping && other) noexcept : _pMapping(other._pMapping) + { other._pMapping = nullptr; } + inline ~Mapping(); + inline Mapping & operator = ( uno_Mapping * pMapping ); + Mapping & operator = ( const Mapping & rMapping ) + { return operator = ( rMapping._pMapping ); } + Mapping & operator =(Mapping && other) noexcept { + if (_pMapping != nullptr) { + (*_pMapping->release)(_pMapping); + } + _pMapping = other._pMapping; + other._pMapping = nullptr; + return *this; + } + uno_Mapping * get() const + { return _pMapping; } + bool is() const + { return (_pMapping != nullptr); } +}; + +} + +inline Mapping::Mapping( uno_Mapping * pMapping ) + : _pMapping( pMapping ) +{ + if (_pMapping) + (*_pMapping->acquire)( _pMapping ); +} + +inline Mapping::Mapping( const Mapping & rMapping ) + : _pMapping( rMapping._pMapping ) +{ + if (_pMapping) + (*_pMapping->acquire)( _pMapping ); +} + +inline Mapping::~Mapping() +{ + if (_pMapping) + (*_pMapping->release)( _pMapping ); +} + +inline Mapping & Mapping::operator = ( uno_Mapping * pMapping ) +{ + if (pMapping) + (*pMapping->acquire)( pMapping ); + if (_pMapping) + (*_pMapping->release)( _pMapping ); + _pMapping = pMapping; + return *this; +} + +namespace { + +struct MappingEntry +{ + sal_Int32 nRef; + uno_Mapping * pMapping; + uno_freeMappingFunc freeMapping; + OUString aMappingName; + + MappingEntry( + uno_Mapping * pMapping_, uno_freeMappingFunc freeMapping_, + const OUString & rMappingName_ ) + : nRef( 1 ) + , pMapping( pMapping_ ) + , freeMapping( freeMapping_ ) + , aMappingName( rMappingName_ ) + {} +}; + +struct FctPtrHash +{ + size_t operator()( uno_Mapping * pKey ) const + { return reinterpret_cast<size_t>(pKey); } +}; + +} + +typedef std::unordered_map< + OUString, MappingEntry * > t_OUString2Entry; +typedef std::unordered_map< + uno_Mapping *, MappingEntry *, FctPtrHash > t_Mapping2Entry; + +namespace { + +struct MappingsData +{ + Mutex aMappingsMutex; + t_OUString2Entry aName2Entry; + t_Mapping2Entry aMapping2Entry; + + Mutex aCallbacksMutex; + set< uno_getMappingFunc > + aCallbacks; + + Mutex aNegativeLibsMutex; + set<OUString> aNegativeLibs; +}; + +} + +static MappingsData & getMappingsData() +{ + //TODO This memory is leaked; see #i63473# for when this should be + // changed again: + static MappingsData * s_p(new MappingsData); + + return *s_p; +} + +namespace { + +/** + * This class mediates two different mapping via uno, e.g. form any language to uno, + * then from uno to any other language. + */ +struct uno_Mediate_Mapping : public uno_Mapping +{ + sal_Int32 nRef; + + Environment aFrom; + Environment aTo; + + Mapping aFrom2Uno; + Mapping aUno2To; + + OUString aAddPurpose; + + uno_Mediate_Mapping( + const Environment & rFrom_, const Environment & rTo_, + const Mapping & rFrom2Uno_, const Mapping & rUno2To_, + const OUString & rAddPurpose ); +}; + +} + +extern "C" +{ + +static void mediate_free( uno_Mapping * pMapping ) +{ + delete static_cast< uno_Mediate_Mapping * >( pMapping ); +} + +static void mediate_acquire( uno_Mapping * pMapping ) +{ + if (1 == osl_atomic_increment( + & static_cast< uno_Mediate_Mapping * >( pMapping )->nRef )) + { + uno_registerMapping( + &pMapping, mediate_free, + static_cast< uno_Mediate_Mapping * >( pMapping )->aFrom.get(), + static_cast< uno_Mediate_Mapping * >( pMapping )->aTo.get(), + static_cast< uno_Mediate_Mapping * >( pMapping )->aAddPurpose.pData ); + } +} + +static void mediate_release( uno_Mapping * pMapping ) +{ + if (! osl_atomic_decrement( + & static_cast< uno_Mediate_Mapping * >( pMapping )->nRef )) + { + uno_revokeMapping( pMapping ); + } +} + +static void mediate_mapInterface( + uno_Mapping * pMapping, + void ** ppOut, void * pInterface, + typelib_InterfaceTypeDescription * pInterfaceTypeDescr ) +{ + OSL_ENSURE( pMapping && ppOut, "### null ptr!" ); + if (!(pMapping && ppOut)) + return; + + uno_Mediate_Mapping * that = static_cast< uno_Mediate_Mapping * >( pMapping ); + uno_Mapping * pFrom2Uno = that->aFrom2Uno.get(); + + uno_Interface * pUnoI = nullptr; + (*pFrom2Uno->mapInterface)( pFrom2Uno, reinterpret_cast<void **>(&pUnoI), pInterface, pInterfaceTypeDescr ); + if (nullptr == pUnoI) + { + void * pOut = *ppOut; + if (nullptr != pOut) + { + uno_ExtEnvironment * pTo = that->aTo.get()->pExtEnv; + OSL_ENSURE( nullptr != pTo, "### cannot release out interface: leaking!" ); + if (nullptr != pTo) + (*pTo->releaseInterface)( pTo, pOut ); + *ppOut = nullptr; // set to 0 anyway, because mapping was not successful! + } + } + else + { + uno_Mapping * pUno2To = that->aUno2To.get(); + (*pUno2To->mapInterface)( pUno2To, ppOut, pUnoI, pInterfaceTypeDescr ); + (*pUnoI->release)( pUnoI ); + } +} +} + +uno_Mediate_Mapping::uno_Mediate_Mapping( + const Environment & rFrom_, const Environment & rTo_, + const Mapping & rFrom2Uno_, const Mapping & rUno2To_, + const OUString & rAddPurpose_ ) + : nRef( 1 ) + , aFrom( rFrom_ ) + , aTo( rTo_ ) + , aFrom2Uno( rFrom2Uno_ ) + , aUno2To( rUno2To_ ) + , aAddPurpose( rAddPurpose_ ) +{ + uno_Mapping::acquire = mediate_acquire; + uno_Mapping::release = mediate_release; + uno_Mapping::mapInterface = mediate_mapInterface; +} + + +static OUString getMappingName( + const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose ) +{ + OUStringBuffer aKey( 64 ); + aKey.append( rAddPurpose ); + aKey.append( ';' ); + aKey.append( rFrom.getTypeName() ); + aKey.append( '[' ); + aKey.append( reinterpret_cast< sal_IntPtr >(rFrom.get()), 16 ); + aKey.append( "];" ); + aKey.append( rTo.getTypeName() ); + aKey.append( '[' ); + aKey.append( reinterpret_cast< sal_IntPtr >(rTo.get()), 16 ); + aKey.append( ']' ); + return aKey.makeStringAndClear(); +} + +static OUString getBridgeName( + const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose ) +{ + OUStringBuffer aBridgeName( 16 ); + if (!rAddPurpose.isEmpty()) + { + aBridgeName.append( rAddPurpose ); + aBridgeName.append( '_' ); + } + aBridgeName.append( EnvDcp::getTypeName(rFrom.getTypeName()) ); + aBridgeName.append( '_' ); + aBridgeName.append( EnvDcp::getTypeName(rTo.getTypeName()) ); + return aBridgeName.makeStringAndClear(); +} + +#ifndef DISABLE_DYNLOADING + +static void setNegativeBridge( const OUString & rBridgeName ) +{ + MappingsData & rData = getMappingsData(); + MutexGuard aGuard( rData.aNegativeLibsMutex ); + rData.aNegativeLibs.insert( rBridgeName ); +} + +#endif + +#ifdef DISABLE_DYNLOADING + +static uno_ext_getMappingFunc selectMapFunc( const OUString & rBridgeName ) +{ + if (rBridgeName.equalsAscii( CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" )) + return CPPU_ENV_uno_ext_getMapping; +#if HAVE_FEATURE_JAVA + if (rBridgeName.equalsAscii( "java" "_uno" )) + return java_uno_ext_getMapping; +#endif + +#if 0 + // I don't think the affine or log bridges will be needed on any + // DISABLE_DYNLOADING platform (iOS at least, possibly Android), but if + // somebody wants to experiment, need to find out then whether these are + // needed. + if (rBridgeName.equalsAscii( "affine_uno_uno" )) + return affine_uno_uno_ext_getMapping; + if (rBridgeName.equalsAscii( "log_uno_uno" )) + return log_uno_uno_ext_getMapping; +#endif + return 0; +} + +#else + +static bool loadModule(osl::Module & rModule, const OUString & rBridgeName) +{ + bool bNeg; + { + MappingsData & rData = getMappingsData(); + MutexGuard aGuard( rData.aNegativeLibsMutex ); + const auto iFind( rData.aNegativeLibs.find( rBridgeName ) ); + bNeg = (iFind != rData.aNegativeLibs.end()); + } + + if (!bNeg) + { + bool bModule; + try { + bModule = cppu::detail::loadModule(rModule, rBridgeName); + } + catch(...) { + // convert throw to return false + bModule = false; + } + + if (bModule) + return true; + + setNegativeBridge( rBridgeName ); // no load again + } + return false; +} + +#endif + + +static Mapping loadExternalMapping( + const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose ) +{ + OSL_ASSERT( rFrom.is() && rTo.is() ); + if (rFrom.is() && rTo.is()) + { +#ifdef DISABLE_DYNLOADING + OUString aName; + uno_ext_getMappingFunc fpGetMapFunc = 0; + + if (EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO) + { + aName = getBridgeName( rTo, rFrom, rAddPurpose ); + fpGetMapFunc = selectMapFunc( aName ); + } + if (! fpGetMapFunc) + { + aName = getBridgeName( rFrom, rTo, rAddPurpose ); + fpGetMapFunc = selectMapFunc( aName ); + } + if (! fpGetMapFunc) + { + aName = getBridgeName( rTo, rFrom, rAddPurpose ); + fpGetMapFunc = selectMapFunc( aName ); + } + + if (! fpGetMapFunc) + { + SAL_INFO("cppu", "Could not find mapfunc for " << aName); + return Mapping(); + } + + if (fpGetMapFunc) + { + Mapping aExt; + (*fpGetMapFunc)( (uno_Mapping **)&aExt, rFrom.get(), rTo.get() ); + OSL_ASSERT( aExt.is() ); + if (aExt.is()) + return aExt; + } +#else + // find proper lib + osl::Module aModule; + bool bModule(false); + OUString aName; + + if ( EnvDcp::getTypeName(rFrom.getTypeName()) == UNO_LB_UNO ) + { + aName = getBridgeName( rTo, rFrom, rAddPurpose ); + bModule = loadModule( aModule, aName ); + } + if (!bModule) + { + aName = getBridgeName( rFrom, rTo, rAddPurpose ); + bModule = loadModule( aModule, aName ); + } + if (!bModule) + { + aName = getBridgeName( rTo, rFrom, rAddPurpose ); + bModule = loadModule( aModule, aName ); + } + + if (bModule) + { + uno_ext_getMappingFunc fpGetMapFunc = + reinterpret_cast<uno_ext_getMappingFunc>(aModule.getSymbol( UNO_EXT_GETMAPPING )); + + if (fpGetMapFunc) + { + Mapping aExt; + (*fpGetMapFunc)( reinterpret_cast<uno_Mapping **>(&aExt), rFrom.get(), rTo.get() ); + OSL_ASSERT( aExt.is() ); + if (aExt.is()) + { + aModule.release(); + return aExt; + } + } + aModule.unload(); + setNegativeBridge( aName ); + } +#endif + } + return Mapping(); +} + + +static Mapping getDirectMapping( + const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose = OUString() ) + +{ + OSL_ASSERT( rFrom.is() && rTo.is() ); + if (rFrom.is() && rTo.is()) + { + MappingsData & rData = getMappingsData(); + ClearableMutexGuard aGuard( rData.aMappingsMutex ); + + // try to find registered mapping + const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find( + getMappingName( rFrom, rTo, rAddPurpose ) ) ); + + if (iFind == rData.aName2Entry.end()) + { + aGuard.clear(); + return loadExternalMapping( rFrom, rTo, rAddPurpose ); + } + return Mapping( (*iFind).second->pMapping ); + } + return Mapping(); +} + + +static Mapping createMediateMapping( + const Environment & rFrom, const Environment & rTo, + const Mapping & rFrom2Uno, const Mapping & rUno2To, + const OUString & rAddPurpose ) +{ + uno_Mapping * pRet = new uno_Mediate_Mapping( + rFrom, rTo, rFrom2Uno, rUno2To, rAddPurpose ); // ref count initially 1 + uno_registerMapping( + &pRet, mediate_free, rFrom.get(), rTo.get(), rAddPurpose.pData ); + Mapping aRet( pRet ); + (*pRet->release)( pRet ); + return aRet; +} + +static Mapping getMediateMapping( + const Environment & rFrom, const Environment & rTo, const OUString & rAddPurpose ) +{ + Environment aUno; + Mapping aUno2To; + + // backwards: from dest to source of mapping chain + + // connect to uno + OUString aUnoEnvTypeName( UNO_LB_UNO ); + if (rTo.getTypeName() == aUnoEnvTypeName) // to is uno + { + aUno = rTo; + // no Uno2To mapping necessary + } + else + { + // get registered uno env + ::uno_getEnvironment( reinterpret_cast<uno_Environment **>(&aUno), aUnoEnvTypeName.pData, nullptr ); + + aUno2To = getDirectMapping( aUno, rTo ); + // : uno <-> to + if (! aUno2To.is()) + return Mapping(); + } + + // connect to uno + if (!rAddPurpose.isEmpty()) // insert purpose mapping between new ano_uno <-> uno + { + // create anonymous uno env + Environment aAnUno; + ::uno_createEnvironment( reinterpret_cast<uno_Environment **>(&aAnUno), aUnoEnvTypeName.pData, nullptr ); + + Mapping aAnUno2Uno( getDirectMapping( aAnUno, aUno, rAddPurpose ) ); + if (! aAnUno2Uno.is()) + return Mapping(); + + if (aUno2To.is()) // to is not uno + { + // create another purposed mediate mapping + aUno2To = createMediateMapping( aAnUno, rTo, aAnUno2Uno, aUno2To, rAddPurpose ); + // : ano_uno <-> uno <-> to + } + else + { + aUno2To = aAnUno2Uno; + // : ano_uno <-> to (i.e., uno) + } + aUno = aAnUno; + } + + Mapping aFrom2Uno( getDirectMapping( rFrom, aUno ) ); + if (aFrom2Uno.is() && aUno2To.is()) + { + return createMediateMapping( rFrom, rTo, aFrom2Uno, aUno2To, rAddPurpose ); + // : from <-> some uno ... + } + + return Mapping(); +} +} + +using namespace ::cppu; + +extern "C" +{ + +void SAL_CALL uno_getMapping( + uno_Mapping ** ppMapping, uno_Environment * pFrom, uno_Environment * pTo, + rtl_uString * pAddPurpose ) + SAL_THROW_EXTERN_C() +{ + assert(ppMapping != nullptr); + assert(pFrom != nullptr); + assert(pTo != nullptr); + if (*ppMapping) + { + (*(*ppMapping)->release)( *ppMapping ); + *ppMapping = nullptr; + } + + Mapping aRet; + Environment aFrom( pFrom ), aTo( pTo ); + + OUString aAddPurpose; + if (pAddPurpose) + aAddPurpose = pAddPurpose; + + MappingsData & rData = getMappingsData(); + + // try registered mapping + { + MutexGuard aGuard( rData.aMappingsMutex ); + const t_OUString2Entry::const_iterator iFind( rData.aName2Entry.find( + getMappingName( aFrom, aTo, aAddPurpose ) ) ); + if (iFind != rData.aName2Entry.end()) + aRet = (*iFind).second->pMapping; + } + + // See if an identity mapping does fit. + if (!aRet.is() && pFrom == pTo && aAddPurpose.isEmpty()) + aRet = createIdentityMapping(pFrom); + + if (!aRet.is()) + { + getCascadeMapping(ppMapping, pFrom, pTo, pAddPurpose); + + if (*ppMapping) + return; + + // try callback chain + { + MutexGuard aGuard(rData.aCallbacksMutex); + for (const auto& rCallback : rData.aCallbacks) + { + (*rCallback)(ppMapping, pFrom, pTo, aAddPurpose.pData); + if (*ppMapping) + return; + } + } + + aRet = loadExternalMapping( aFrom, aTo, aAddPurpose ); // direct try + if (! aRet.is()) + aRet = getMediateMapping( aFrom, aTo, aAddPurpose ); // try via uno + } + + if (aRet.is()) + { + (*aRet.get()->acquire)( aRet.get() ); + *ppMapping = aRet.get(); + } +} + +void SAL_CALL uno_getMappingByName( + uno_Mapping ** ppMapping, rtl_uString * pFrom, rtl_uString * pTo, + rtl_uString * pAddPurpose ) + SAL_THROW_EXTERN_C() +{ + assert(ppMapping && pFrom && pTo && "### null ptr!"); + if (*ppMapping) + { + (*(*ppMapping)->release)( *ppMapping ); + *ppMapping = nullptr; + } + + uno_Environment * pEFrom = nullptr; + uno_getEnvironment( &pEFrom, pFrom, nullptr ); + OSL_ENSURE( pEFrom, "### cannot get source environment!" ); + if (pEFrom) + { + uno_Environment * pETo = nullptr; + uno_getEnvironment( &pETo, pTo, nullptr ); + OSL_ENSURE( pETo, "### cannot get target environment!" ); + if (pETo) + { + ::uno_getMapping( ppMapping, pEFrom, pETo, pAddPurpose ); + (*pETo->release)( pETo ); + } + (*pEFrom->release)( pEFrom ); + } +} + + +void SAL_CALL uno_registerMapping( + uno_Mapping ** ppMapping, uno_freeMappingFunc freeMapping, + uno_Environment * pFrom, uno_Environment * pTo, rtl_uString * pAddPurpose ) + SAL_THROW_EXTERN_C() +{ + MappingsData & rData = getMappingsData(); + ClearableMutexGuard aGuard( rData.aMappingsMutex ); + + const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( *ppMapping ) ); + if (iFind == rData.aMapping2Entry.end()) + { + OUString aMappingName( + getMappingName( pFrom, pTo, pAddPurpose ? OUString(pAddPurpose) : OUString() ) ); + SAL_INFO("cppu", "> inserting new mapping: " << aMappingName); + // count initially 1 + MappingEntry * pEntry = new MappingEntry( *ppMapping, freeMapping, aMappingName ); + rData.aName2Entry[ aMappingName ] = pEntry; + rData.aMapping2Entry[ *ppMapping ] = pEntry; + } + else + { + MappingEntry * pEntry = (*iFind).second; + ++pEntry->nRef; + + if (pEntry->pMapping != *ppMapping) // exchange mapping to be registered + { + (*pEntry->pMapping->acquire)( pEntry->pMapping ); + --pEntry->nRef; // correct count; kill mapping to be registered + aGuard.clear(); + (*freeMapping)( *ppMapping ); + *ppMapping = pEntry->pMapping; + } + } +} + +void SAL_CALL uno_revokeMapping( + uno_Mapping * pMapping ) + SAL_THROW_EXTERN_C() +{ + MappingsData & rData = getMappingsData(); + ClearableMutexGuard aGuard( rData.aMappingsMutex ); + + const t_Mapping2Entry::const_iterator iFind( rData.aMapping2Entry.find( pMapping ) ); + OSL_ASSERT( iFind != rData.aMapping2Entry.end() ); + MappingEntry * pEntry = (*iFind).second; + if (! --pEntry->nRef) + { + rData.aMapping2Entry.erase( pEntry->pMapping ); + rData.aName2Entry.erase( pEntry->aMappingName ); + aGuard.clear(); + SAL_INFO("cppu", "> revoking mapping " << pEntry->aMappingName); + (*pEntry->freeMapping)( pEntry->pMapping ); + delete pEntry; + } +} + + +void SAL_CALL uno_registerMappingCallback( + uno_getMappingFunc pCallback ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( pCallback, "### null ptr!" ); + MappingsData & rData = getMappingsData(); + MutexGuard aGuard( rData.aCallbacksMutex ); + rData.aCallbacks.insert( pCallback ); +} + +void SAL_CALL uno_revokeMappingCallback( + uno_getMappingFunc pCallback ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( pCallback, "### null ptr!" ); + MappingsData & rData = getMappingsData(); + MutexGuard aGuard( rData.aCallbacksMutex ); + rData.aCallbacks.erase( pCallback ); +} +} // extern "C" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/loadmodule.cxx b/cppu/source/uno/loadmodule.cxx new file mode 100644 index 000000000..f3ba0ba21 --- /dev/null +++ b/cppu/source/uno/loadmodule.cxx @@ -0,0 +1,76 @@ +/* -*- 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 <cassert> + +#include <osl/module.h> +#include <osl/module.hxx> +#include <rtl/malformeduriexception.hxx> +#include <rtl/uri.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> + +#include "loadmodule.hxx" + +namespace cppu::detail { + +#ifndef DISABLE_DYNLOADING + +bool loadModule(osl::Module& rModule, OUString const & name) { + static OUString base = [] { + OUString url; + if (!osl::Module::getUrlFromAddress( + reinterpret_cast<oslGenericFunction>(&loadModule), url)) + { + SAL_WARN("cppu", "osl::Module::getUrlFromAddress failed"); + return OUString(); + } + assert(!url.isEmpty()); + return url; + }(); + if (base.isEmpty()) { + SAL_INFO("cppu", "osl::Module::getUrlFromAddress had failed"); + return false; + } + OUString b = +#if defined SAL_DLLPREFIX + SAL_DLLPREFIX + +#endif + name + + SAL_DLLEXTENSION; + try { + b = rtl::Uri::convertRelToAbs(base, b); + } catch (rtl::MalformedUriException & e) { + SAL_INFO("cppu", "rtl::MalformedUriException <" << e.getMessage() << ">"); + return false; + } + return rModule.load( + b, + SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_LAZY); +} + +#endif + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/loadmodule.hxx b/cppu/source/uno/loadmodule.hxx new file mode 100644 index 000000000..cde33594c --- /dev/null +++ b/cppu/source/uno/loadmodule.hxx @@ -0,0 +1,48 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPU_SOURCE_UNO_LOADMODULE_HXX +#define INCLUDED_CPPU_SOURCE_UNO_LOADMODULE_HXX + +#include <sal/config.h> +#include <rtl/ustring.hxx> + +namespace osl { class Module; } + +namespace cppu::detail { + +#ifndef DISABLE_DYNLOADING + +/** Load a module. + + @param name + the nucleus of a module name (without any "lib...so", ".dll", etc. + decoration, and without a path). + + @return false if the module could not be loaded, otherwise true +*/ +bool loadModule(osl::Module & rModule, OUString const & name); + +#endif + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/prim.hxx b/cppu/source/uno/prim.hxx new file mode 100644 index 000000000..84f96e7fd --- /dev/null +++ b/cppu/source/uno/prim.hxx @@ -0,0 +1,156 @@ +/* -*- 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 . + */ +#ifndef INCLUDED_CPPU_SOURCE_UNO_PRIM_HXX +#define INCLUDED_CPPU_SOURCE_UNO_PRIM_HXX + +#include <typelib/typedescription.h> +#include <typelib/typeclass.h> +#include <uno/sequence2.h> +#include <uno/any2.h> +#include <uno/data.h> +#include <uno/mapping.h> +#include <uno/dispatcher.h> + +#include <osl/interlck.h> +#include <stdint.h> + +namespace cppu +{ + +extern uno_Sequence g_emptySeq; +extern typelib_TypeDescriptionReference * g_pVoidType; + + +inline void * _map( + void * p, + typelib_TypeDescriptionReference * pType, typelib_TypeDescription * pTypeDescr, + uno_Mapping * mapping ) + +{ + void * pRet = nullptr; + if (p) + { + if (pTypeDescr) + { + (*mapping->mapInterface)( + mapping, &pRet, p, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTypeDescr) ); + } + else + { + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + (*mapping->mapInterface)( + mapping, &pRet, p, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTypeDescr) ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + } + return pRet; +} + +inline void _acquire( void * p, uno_AcquireFunc acquire ) +{ + if (p) + { + if (acquire) + { + (*acquire)( p ); + } + else + { + (*static_cast<uno_Interface *>(p)->acquire)( static_cast<uno_Interface *>(p) ); + } + } +} + +inline void _release( void * p, uno_ReleaseFunc release ) +{ + if (p) + { + if (release) + { + (*release)( p ); + } + else + { + (*static_cast<uno_Interface *>(p)->release)( static_cast<uno_Interface *>(p) ); + } + } +} + + +inline sal_uInt32 calcSeqMemSize( + sal_Int32 nElementSize, sal_Int32 nElements ) +{ + sal_uInt64 nSize = + static_cast<sal_uInt64>(SAL_SEQUENCE_HEADER_SIZE) + + (static_cast<sal_uInt64>(nElementSize) * static_cast<sal_uInt64>(nElements)); + if (nSize > 0xffffffffU) + return 0; + else + return static_cast<sal_uInt32>(nSize); +} + + +inline uno_Sequence * createEmptySequence() +{ + osl_atomic_increment( &g_emptySeq.nRefCount ); + return &g_emptySeq; +} + +inline typelib_TypeDescriptionReference * _getVoidType() +{ + if (! g_pVoidType) + { + g_pVoidType = * ::typelib_static_type_getByTypeClass( typelib_TypeClass_VOID ); + } + ::typelib_typedescriptionreference_acquire( g_pVoidType ); + return g_pVoidType; +} + +inline void CONSTRUCT_EMPTY_ANY(uno_Any * pAny) { + pAny->pType = _getVoidType(); +#if OSL_DEBUG_LEVEL > 0 + pAny->pData = reinterpret_cast<void *>(uintptr_t(0xdeadbeef)); +#else + pAny->pData = pAny; +#endif +} + +#define TYPE_ACQUIRE( pType ) \ + osl_atomic_increment( &(pType)->nRefCount ); + + +extern "C" void * binuno_queryInterface( + void * pUnoI, typelib_TypeDescriptionReference * pDestType ); + + +inline bool _type_equals( + typelib_TypeDescriptionReference const * pType1, typelib_TypeDescriptionReference const * pType2 ) + +{ + return (pType1 == pType2 || + (pType1->eTypeClass == pType2->eTypeClass && + pType1->pTypeName->length == pType2->pTypeName->length && + ::rtl_ustr_compare( pType1->pTypeName->buffer, pType2->pTypeName->buffer ) == 0)); +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/source/uno/sequence.cxx b/cppu/source/uno/sequence.cxx new file mode 100644 index 000000000..72d3e3ead --- /dev/null +++ b/cppu/source/uno/sequence.cxx @@ -0,0 +1,913 @@ +/* -*- 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 <cassert> +#include <string.h> + +#include <osl/diagnose.h> +#include <osl/interlck.h> +#include <typelib/typedescription.h> +#include <uno/data.h> +#include <uno/sequence2.h> + +#include "constr.hxx" +#include "copy.hxx" +#include "destr.hxx" + + +using namespace cppu; + +namespace cppu +{ + + +static uno_Sequence * reallocSeq( + uno_Sequence * pReallocate, std::size_t nElementSize, sal_Int32 nElements ) +{ + OSL_ASSERT( nElements >= 0 ); + uno_Sequence * pNew = nullptr; + sal_uInt32 nSize = calcSeqMemSize( nElementSize, nElements ); + if (nSize > 0) + { + if (pReallocate == nullptr) + { + pNew = static_cast<uno_Sequence *>(std::malloc( nSize )); + } + else + { + pNew = static_cast<uno_Sequence *>(std::realloc( pReallocate, nSize )); + } + if (pNew != nullptr) + { + // header init + pNew->nRefCount = 1; + pNew->nElements = nElements; + } + } + return pNew; +} + + +static bool idefaultConstructElements( + uno_Sequence ** ppSeq, + typelib_TypeDescriptionReference * pElementType, + sal_Int32 nStartIndex, sal_Int32 nStopIndex, + sal_Int32 nAlloc ) // >= 0 means (re)alloc memory for nAlloc elements +{ + uno_Sequence * pSeq = *ppSeq; + switch (pElementType->eTypeClass) + { + case typelib_TypeClass_CHAR: + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Unicode), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(sal_Unicode) * nStartIndex), + 0, + sizeof(sal_Unicode) * (nStopIndex - nStartIndex) ); + } + break; + case typelib_TypeClass_BOOLEAN: + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Bool), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(sal_Bool) * nStartIndex), + 0, + sizeof(sal_Bool) * (nStopIndex - nStartIndex) ); + } + break; + case typelib_TypeClass_BYTE: + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Int8), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(sal_Int8) * nStartIndex), + 0, + sizeof(sal_Int8) * (nStopIndex - nStartIndex) ); + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Int16), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(sal_Int16) * nStartIndex), + 0, + sizeof(sal_Int16) * (nStopIndex - nStartIndex) ); + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(sal_Int32) * nStartIndex), + 0, + sizeof(sal_Int32) * (nStopIndex - nStartIndex) ); + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Int64), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(sal_Int64) * nStartIndex), + 0, + sizeof(sal_Int64) * (nStopIndex - nStartIndex) ); + } + break; + case typelib_TypeClass_FLOAT: + { + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(float), nAlloc ); + if (pSeq != nullptr) + { + float * pElements = reinterpret_cast<float *>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + pElements[nPos] = 0.0; + } + } + break; + } + case typelib_TypeClass_DOUBLE: + { + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(double), nAlloc ); + if (pSeq != nullptr) + { + double * pElements = reinterpret_cast<double *>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + pElements[nPos] = 0.0; + } + } + break; + } + case typelib_TypeClass_STRING: + { + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(rtl_uString *), nAlloc ); + if (pSeq != nullptr) + { + rtl_uString ** pElements = reinterpret_cast<rtl_uString **>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + pElements[nPos] = nullptr; + rtl_uString_new( &pElements[nPos] ); + } + } + break; + } + case typelib_TypeClass_TYPE: + { + if (nAlloc >= 0) + { + pSeq = reallocSeq( + pSeq, sizeof(typelib_TypeDescriptionReference *), nAlloc ); + } + if (pSeq != nullptr) + { + typelib_TypeDescriptionReference ** pElements = + reinterpret_cast<typelib_TypeDescriptionReference **>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + pElements[nPos] = _getVoidType(); + } + } + break; + } + case typelib_TypeClass_ANY: + { + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(uno_Any), nAlloc ); + if (pSeq != nullptr) + { + uno_Any * pElements = reinterpret_cast<uno_Any *>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + CONSTRUCT_EMPTY_ANY( &pElements[nPos] ); + } + } + break; + } + case typelib_TypeClass_ENUM: + { + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc ); + if (pSeq != nullptr) + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + sal_Int32 eEnum = + reinterpret_cast<typelib_EnumTypeDescription *>( + pElementTypeDescr)->nDefaultEnumValue; + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + + sal_Int32 * pElements = reinterpret_cast<sal_Int32 *>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + pElements[nPos] = eEnum; + } + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + sal_Int32 nElementSize = pElementTypeDescr->nSize; + + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, nElementSize, nAlloc ); + if (pSeq != nullptr) + { + char * pElements = pSeq->elements; + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + _defaultConstructStruct( + pElements + (nElementSize * nPos), + reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr) ); + } + } + + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + break; + } + case typelib_TypeClass_SEQUENCE: + { + if (nAlloc >= 0) + { + // coverity[suspicious_sizeof : FALSE] - sizeof(uno_Sequence*) is correct here + pSeq = reallocSeq(pSeq, sizeof(uno_Sequence*), nAlloc); + } + if (pSeq != nullptr) + { + uno_Sequence ** pElements = + reinterpret_cast<uno_Sequence **>(pSeq->elements); + for ( sal_Int32 nPos = nStartIndex; nPos < nStopIndex; ++nPos ) + { + pElements[nPos] = createEmptySequence(); + } + } + break; + } + case typelib_TypeClass_INTERFACE: // either C++ or C-UNO interface + if (nAlloc >= 0) + pSeq = reallocSeq( pSeq, sizeof(void *), nAlloc ); + if (pSeq != nullptr) + { + memset( + pSeq->elements + (sizeof(void *) * nStartIndex), + 0, + sizeof(void *) * (nStopIndex - nStartIndex) ); + } + break; + default: + OSL_FAIL( "### unexpected element type!" ); + pSeq = nullptr; + break; + } + + if (pSeq == nullptr) + { + OSL_ASSERT( nAlloc >= 0 ); // must have been an allocation failure + return false; + } + *ppSeq = pSeq; + return true; +} + + +static bool icopyConstructFromElements( + uno_Sequence ** ppSeq, void * pSourceElements, + typelib_TypeDescriptionReference * pElementType, + sal_Int32 nStopIndex, + uno_AcquireFunc acquire, + sal_Int32 nAlloc ) +{ + uno_Sequence * pSeq = *ppSeq; + switch (pElementType->eTypeClass) + { + case typelib_TypeClass_CHAR: + pSeq = reallocSeq( pSeq, sizeof(sal_Unicode), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Unicode) * nStopIndex ); + } + break; + case typelib_TypeClass_BOOLEAN: + pSeq = reallocSeq( pSeq, sizeof(sal_Bool), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Bool) * nStopIndex ); + } + break; + case typelib_TypeClass_BYTE: + pSeq = reallocSeq( pSeq, sizeof(sal_Int8), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Int8) * nStopIndex ); + } + break; + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + pSeq = reallocSeq( pSeq, sizeof(sal_Int16), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Int16) * nStopIndex ); + } + break; + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Int32) * nStopIndex ); + } + break; + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + pSeq = reallocSeq( pSeq, sizeof(sal_Int64), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Int64) * nStopIndex ); + } + break; + case typelib_TypeClass_FLOAT: + pSeq = reallocSeq( pSeq, sizeof(float), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(float) * nStopIndex ); + } + break; + case typelib_TypeClass_DOUBLE: + pSeq = reallocSeq( pSeq, sizeof(double), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(double) * nStopIndex ); + } + break; + case typelib_TypeClass_ENUM: + pSeq = reallocSeq( pSeq, sizeof(sal_Int32), nAlloc ); + if (pSeq != nullptr) + { + memcpy( + pSeq->elements, + pSourceElements, + sizeof(sal_Int32) * nStopIndex ); + } + break; + case typelib_TypeClass_STRING: + { + pSeq = reallocSeq( pSeq, sizeof(rtl_uString *), nAlloc ); + if (pSeq != nullptr) + { + rtl_uString ** pDestElements = reinterpret_cast<rtl_uString **>(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + // This code tends to trigger coverity's overrun-buffer-arg warning + // coverity[index_parm_via_loop_bound] - https://communities.coverity.com/thread/2993 + ::rtl_uString_acquire( + static_cast<rtl_uString **>(pSourceElements)[nPos] ); + pDestElements[nPos] = static_cast<rtl_uString **>(pSourceElements)[nPos]; + } + } + break; + } + case typelib_TypeClass_TYPE: + { + pSeq = reallocSeq( + pSeq, sizeof(typelib_TypeDescriptionReference *), nAlloc ); + if (pSeq != nullptr) + { + typelib_TypeDescriptionReference ** pDestElements = + reinterpret_cast<typelib_TypeDescriptionReference **>(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + TYPE_ACQUIRE( + static_cast<typelib_TypeDescriptionReference **>( + pSourceElements)[nPos] ); + pDestElements[nPos] = + static_cast<typelib_TypeDescriptionReference **>( + pSourceElements)[nPos]; + } + } + break; + } + case typelib_TypeClass_ANY: + { + pSeq = reallocSeq( pSeq, sizeof(uno_Any), nAlloc ); + if (pSeq != nullptr) + { + uno_Any * pDestElements = reinterpret_cast<uno_Any *>(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + uno_Any * pSource = static_cast<uno_Any *>(pSourceElements) + nPos; + _copyConstructAny( + &pDestElements[nPos], + pSource->pData, + pSource->pType, nullptr, + acquire, nullptr ); + } + } + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + sal_Int32 nElementSize = pElementTypeDescr->nSize; + + pSeq = reallocSeq( pSeq, nElementSize, nAlloc ); + if (pSeq != nullptr) + { + char * pDestElements = pSeq->elements; + + typelib_CompoundTypeDescription * pTypeDescr = + reinterpret_cast<typelib_CompoundTypeDescription *>(pElementTypeDescr); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + char * pDest = + pDestElements + (nElementSize * nPos); + char * pSource = + static_cast<char *>(pSourceElements) + (nElementSize * nPos); + + if (pTypeDescr->pBaseTypeDescription) + { + // copy base value + _copyConstructStruct( + pDest, pSource, + pTypeDescr->pBaseTypeDescription, acquire, nullptr ); + } + + // then copy members + typelib_TypeDescriptionReference ** ppTypeRefs = + pTypeDescr->ppTypeRefs; + sal_Int32 * pMemberOffsets = pTypeDescr->pMemberOffsets; + sal_Int32 nDescr = pTypeDescr->nMembers; + + while (nDescr--) + { + ::uno_type_copyData( + pDest + pMemberOffsets[nDescr], + pSource + pMemberOffsets[nDescr], + ppTypeRefs[nDescr], acquire ); + } + } + } + + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + break; + } + case typelib_TypeClass_SEQUENCE: // sequence of sequence + { + // coverity[suspicious_sizeof : FALSE] - sizeof(uno_Sequence*) is correct here + pSeq = reallocSeq(pSeq, sizeof(uno_Sequence*), nAlloc); + if (pSeq != nullptr) + { + typelib_TypeDescription * pElementTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pElementTypeDescr, pElementType ); + typelib_TypeDescriptionReference * pSeqElementType = + reinterpret_cast<typelib_IndirectTypeDescription *>(pElementTypeDescr)->pType; + uno_Sequence ** pDestElements = reinterpret_cast<uno_Sequence **>(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + uno_Sequence * pNew = icopyConstructSequence( + static_cast<uno_Sequence **>(pSourceElements)[nPos], + pSeqElementType, acquire, nullptr ); + OSL_ASSERT( pNew != nullptr ); + // ought never be a memory allocation problem, + // because of reference counted sequence handles + pDestElements[ nPos ] = pNew; + } + TYPELIB_DANGER_RELEASE( pElementTypeDescr ); + } + break; + } + case typelib_TypeClass_INTERFACE: + { + pSeq = reallocSeq( pSeq, sizeof(void *), nAlloc ); + if (pSeq != nullptr) + { + void ** pDestElements = reinterpret_cast<void **>(pSeq->elements); + for ( sal_Int32 nPos = 0; nPos < nStopIndex; ++nPos ) + { + pDestElements[nPos] = static_cast<void **>(pSourceElements)[nPos]; + _acquire( pDestElements[nPos], acquire ); + } + } + break; + } + default: + OSL_FAIL( "### unexpected element type!" ); + pSeq = nullptr; + break; + } + + if (pSeq == nullptr) + { + return false; // allocation failure + } + *ppSeq = pSeq; + return true; +} + + +static bool ireallocSequence( + uno_Sequence ** ppSequence, + typelib_TypeDescriptionReference * pElementType, + sal_Int32 nSize, + uno_AcquireFunc acquire, uno_ReleaseFunc release ) +{ + bool ret = true; + uno_Sequence * pSeq = *ppSequence; + sal_Int32 nElements = pSeq->nElements; + + if (pSeq->nRefCount > 1 || + // not mem-copyable elements? + typelib_TypeClass_ANY == pElementType->eTypeClass || + typelib_TypeClass_STRUCT == pElementType->eTypeClass || + typelib_TypeClass_EXCEPTION == pElementType->eTypeClass) + { + // split sequence and construct new one from scratch + uno_Sequence * pNew = nullptr; + + sal_Int32 nRest = nSize - nElements; + sal_Int32 nCopy = (nRest > 0 ? nElements : nSize); + + if (nCopy >= 0) + { + ret = icopyConstructFromElements( + &pNew, pSeq->elements, pElementType, + nCopy, acquire, + nSize ); // alloc to nSize + } + if (ret && nRest > 0) + { + ret = idefaultConstructElements( + &pNew, pElementType, + nCopy, nSize, + nCopy >= 0 ? -1 /* no mem allocation */ : nSize ); + } + + if (ret) + { + // destruct sequence + if (osl_atomic_decrement( &pSeq->nRefCount ) == 0) + { + if (nElements > 0) + { + idestructElements( + pSeq->elements, pElementType, + 0, nElements, release ); + } + std::free( pSeq ); + } + *ppSequence = pNew; + } + } + else + { + OSL_ASSERT( pSeq->nRefCount == 1 ); + if (nSize > nElements) // default construct the rest + { + ret = idefaultConstructElements( + ppSequence, pElementType, + nElements, nSize, + nSize ); // realloc to nSize + } + else // or destruct the rest and realloc mem + { + sal_Int32 nElementSize = idestructElements( + pSeq->elements, pElementType, + nSize, nElements, release ); + // warning: it is assumed that the following will never fail, + // else this leads to a sequence null handle + *ppSequence = reallocSeq( pSeq, nElementSize, nSize ); + OSL_ASSERT( *ppSequence != nullptr ); + ret = (*ppSequence != nullptr); + } + } + + return ret; +} + +} + +extern "C" +{ + + +sal_Bool SAL_CALL uno_type_sequence_construct( + uno_Sequence ** ppSequence, typelib_TypeDescriptionReference * pType, + void * pElements, sal_Int32 len, + uno_AcquireFunc acquire ) + SAL_THROW_EXTERN_C() +{ + assert( len >= 0 ); + bool ret; + if (len) + { + typelib_TypeDescription * pTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + + typelib_TypeDescriptionReference * pElementType = + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType; + + *ppSequence = nullptr; + if (pElements == nullptr) + { + ret = idefaultConstructElements( + ppSequence, pElementType, + 0, len, + len ); // alloc to len + } + else + { + ret = icopyConstructFromElements( + ppSequence, pElements, pElementType, + len, acquire, + len ); // alloc to len + } + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + else + { + *ppSequence = createEmptySequence(); + ret = true; + } + + OSL_ASSERT( (*ppSequence != nullptr) == ret ); + return ret; +} + + +sal_Bool SAL_CALL uno_sequence_construct( + uno_Sequence ** ppSequence, typelib_TypeDescription * pTypeDescr, + void * pElements, sal_Int32 len, + uno_AcquireFunc acquire ) + SAL_THROW_EXTERN_C() +{ + bool ret; + if (len > 0) + { + typelib_TypeDescriptionReference * pElementType = + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType; + + *ppSequence = nullptr; + if (pElements == nullptr) + { + ret = idefaultConstructElements( + ppSequence, pElementType, + 0, len, + len ); // alloc to len + } + else + { + ret = icopyConstructFromElements( + ppSequence, pElements, pElementType, + len, acquire, + len ); // alloc to len + } + } + else + { + *ppSequence = createEmptySequence(); + ret = true; + } + + OSL_ASSERT( (*ppSequence != nullptr) == ret ); + return ret; +} + + +sal_Bool SAL_CALL uno_type_sequence_realloc( + uno_Sequence ** ppSequence, typelib_TypeDescriptionReference * pType, + sal_Int32 nSize, uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + assert(ppSequence && "### null ptr!"); + assert(nSize >= 0 && "### new size must be at least 0!"); + + bool ret = true; + if (nSize != (*ppSequence)->nElements) + { + typelib_TypeDescription * pTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + ret = ireallocSequence( + ppSequence, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + nSize, acquire, release ); + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + return ret; +} + + +sal_Bool SAL_CALL uno_sequence_realloc( + uno_Sequence ** ppSequence, typelib_TypeDescription * pTypeDescr, + sal_Int32 nSize, uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( ppSequence, "### null ptr!" ); + OSL_ENSURE( nSize >= 0, "### new size must be at least 0!" ); + + bool ret = true; + if (nSize != (*ppSequence)->nElements) + { + ret = ireallocSequence( + ppSequence, reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + nSize, acquire, release ); + } + return ret; +} + + +sal_Bool SAL_CALL uno_type_sequence_reference2One( + uno_Sequence ** ppSequence, + typelib_TypeDescriptionReference * pType, + uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( ppSequence, "### null ptr!" ); + bool ret = true; + uno_Sequence * pSequence = *ppSequence; + if (pSequence->nRefCount > 1) + { + uno_Sequence * pNew = nullptr; + if (pSequence->nElements > 0) + { + typelib_TypeDescription * pTypeDescr = nullptr; + TYPELIB_DANGER_GET( &pTypeDescr, pType ); + + ret = icopyConstructFromElements( + &pNew, pSequence->elements, + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + pSequence->nElements, acquire, + pSequence->nElements ); // alloc nElements + if (ret) + { + idestructSequence( *ppSequence, pType, pTypeDescr, release ); + *ppSequence = pNew; + } + + TYPELIB_DANGER_RELEASE( pTypeDescr ); + } + else + { + pNew = allocSeq( 0, 0 ); + ret = (pNew != nullptr); + if (ret) + { + // easy destruction of empty sequence: + if (osl_atomic_decrement( &pSequence->nRefCount ) == 0) + std::free( pSequence ); + *ppSequence = pNew; + } + } + } + return ret; +} + + +sal_Bool SAL_CALL uno_sequence_reference2One( + uno_Sequence ** ppSequence, + typelib_TypeDescription * pTypeDescr, + uno_AcquireFunc acquire, uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + OSL_ENSURE( ppSequence, "### null ptr!" ); + bool ret = true; + uno_Sequence * pSequence = *ppSequence; + if (pSequence->nRefCount > 1) + { + uno_Sequence * pNew = nullptr; + if (pSequence->nElements > 0) + { + ret = icopyConstructFromElements( + &pNew, pSequence->elements, + reinterpret_cast<typelib_IndirectTypeDescription *>(pTypeDescr)->pType, + pSequence->nElements, acquire, + pSequence->nElements ); // alloc nElements + if (ret) + { + idestructSequence( + pSequence, pTypeDescr->pWeakRef, pTypeDescr, release ); + *ppSequence = pNew; + } + } + else + { + pNew = allocSeq( 0, 0 ); + ret = (pNew != nullptr); + if (ret) + { + // easy destruction of empty sequence: + if (osl_atomic_decrement( &pSequence->nRefCount ) == 0) + std::free( pSequence ); + *ppSequence = pNew; + } + } + + } + return ret; +} + + +void SAL_CALL uno_sequence_assign( + uno_Sequence ** ppDest, + uno_Sequence * pSource, + typelib_TypeDescription * pTypeDescr, + uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + if (*ppDest != pSource) + { + osl_atomic_increment( &pSource->nRefCount ); + idestructSequence( *ppDest, pTypeDescr->pWeakRef, pTypeDescr, release ); + *ppDest = pSource; + } +} + + +void SAL_CALL uno_type_sequence_assign( + uno_Sequence ** ppDest, + uno_Sequence * pSource, + typelib_TypeDescriptionReference * pType, + uno_ReleaseFunc release ) + SAL_THROW_EXTERN_C() +{ + if (*ppDest != pSource) + { + osl_atomic_increment( &pSource->nRefCount ); + idestructSequence( *ppDest, pType, nullptr, release ); + *ppDest = pSource; + } +} + +void uno_type_sequence_destroy( + uno_Sequence * sequence, typelib_TypeDescriptionReference * type, + uno_ReleaseFunc release) + SAL_THROW_EXTERN_C() +{ + idestroySequence(sequence, type, nullptr, release); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppu/util/cppu.map b/cppu/util/cppu.map new file mode 100644 index 000000000..df724a5c9 --- /dev/null +++ b/cppu/util/cppu.map @@ -0,0 +1,158 @@ +# +# 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 . +# +UDK_3_0_0 { + global: + _ZTI*; _ZTS*; # weak RTTI symbols for C++ exceptions + + typelib_typedescription_new; + typelib_typedescription_newInterface; + typelib_typedescription_newInterfaceMethod; + typelib_typedescription_newInterfaceAttribute; + typelib_typedescription_newEnum; + typelib_typedescription_newUnion; + typelib_typedescription_newArray; + typelib_typedescription_acquire; + typelib_typedescription_release; + typelib_typedescription_register; + typelib_typedescription_equals; + typelib_typedescription_isAssignableFrom; + typelib_typedescription_getByName; + typelib_typedescription_registerCallback; + typelib_typedescription_revokeCallback; + typelib_typedescriptionreference_new; + typelib_typedescriptionreference_acquire; + typelib_typedescriptionreference_release; + typelib_typedescriptionreference_getDescription; + typelib_typedescriptionreference_equals; + typelib_typedescriptionreference_assign; + typelib_typedescriptionreference_isAssignableFrom; + + typelib_setCacheSize; + + typelib_typedescriptionreference_newByAsciiName; + typelib_static_type_getByTypeClass; + typelib_static_type_init; + typelib_static_sequence_type_init; + typelib_static_compound_type_init; + typelib_static_interface_type_init; + typelib_static_enum_type_init; + typelib_static_array_type_init; + typelib_typedescription_complete; + + uno_equalData; + uno_type_equalData; + uno_constructData; + uno_type_constructData; + uno_destructData; + uno_type_destructData; + uno_copyData; + uno_type_copyData; + uno_copyAndConvertData; + uno_type_copyAndConvertData; + uno_assignData; + uno_type_assignData; + uno_type_isAssignableFromData; + + uno_any_assign; + uno_type_any_assign; + uno_any_construct; + uno_type_any_construct; + uno_any_constructAndConvert; + uno_type_any_constructAndConvert; + uno_any_destruct; + uno_any_clear; + + uno_sequence_assign; + uno_type_sequence_assign; + uno_sequence_construct; + uno_type_sequence_construct; + uno_sequence_reference2One; + uno_type_sequence_reference2One; + uno_sequence_realloc; + uno_type_sequence_realloc; + + uno_createEnvironment; + uno_getEnvironment; + uno_getRegisteredEnvironments; + uno_dumpEnvironment; + uno_dumpEnvironmentByName; + uno_getMapping; + uno_getMappingByName; + uno_registerMapping; + uno_revokeMapping; + uno_registerMappingCallback; + uno_revokeMappingCallback; + + uno_getCurrentContext; + uno_setCurrentContext; + + uno_bindIdToCurrentThread; + uno_getIdOfCurrentThread; + uno_releaseIdFromCurrentThread; + uno_threadpool_enter; + uno_threadpool_create; + uno_threadpool_destroy; + uno_threadpool_putJob; + uno_threadpool_dispose; + uno_threadpool_attach; + uno_threadpool_detach; + + cppu_unsatisfied_iquery_msg; + local: + *; +}; + +UDK_3.1 { + global: + typelib_static_mi_interface_type_init; + typelib_static_struct_type_init; + typelib_typedescription_newExtendedInterfaceAttribute; + typelib_typedescription_newMIInterface; + typelib_typedescription_newStruct; + cppu_Any_extraction_failure_msg; +} UDK_3_0_0; + +UDK_3.2 { + global: + uno_EnvDcp_getTypeName; + uno_EnvDcp_getPurpose; + + uno_getCurrentEnvironment; + uno_Environment_invoke_v; + uno_Environment_invoke; + uno_Environment_enter; + + uno_Environment_isValid; +} UDK_3.1; + +UDK_3.3 { # OOo 2.4 + global: + cppu_unsatisfied_iset_msg; +} UDK_3.2; + +LIBO_UDK_4.4 { # symbols available in >= LibO 4.4 + global: + uno_type_sequence_destroy; +} UDK_3.3; + +# Unique libstdc++ symbols: +GLIBCXX_3.4 { + global: + _ZGVNSt7num_put*; _ZNSt7num_put*; + _ZNSs4_Rep20_S_empty_rep_storageE; +}; diff --git a/cppu/util/uno_purpenvhelpergcc3.map b/cppu/util/uno_purpenvhelpergcc3.map new file mode 100644 index 000000000..7aec7b55f --- /dev/null +++ b/cppu/util/uno_purpenvhelpergcc3.map @@ -0,0 +1,34 @@ +# +# 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 . +# +UDK_3_0_0 { + global: + _ZTI*; _ZTS*; # weak RTTI symbols for C++ exceptions + + _ZN4cppu6helper7purpenv13createMappingEPP12_uno_MappingP16_uno_EnvironmentS6_PFvbPvS7_P33_typelib_TypeDescriptionReferenceP24_typelib_MethodParameter?PK24_typelib_TypeDescriptionS7_PS7_PP8_uno_AnyES7_; + _ZN4cppu6helper7purpenv29Environment_initWithEnterableEP16_uno_EnvironmentPNS_9EnterableE; + + local: + *; +}; + +# Unique libstdc++ symbols: +GLIBCXX_3.4 { + global: + _ZGVNSt7num_put*; _ZNSt7num_put*; + _ZNSs4_Rep20_S_empty_rep_storageE; +}; diff --git a/cppuhelper/CppunitTest_cppuhelper_cppu_ifcontainer.mk b/cppuhelper/CppunitTest_cppuhelper_cppu_ifcontainer.mk new file mode 100644 index 000000000..1d745b641 --- /dev/null +++ b/cppuhelper/CppunitTest_cppuhelper_cppu_ifcontainer.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppuhelper_cppu_ifcontainer)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppuhelper_cppu_ifcontainer,\ + cppuhelper/qa/ifcontainer/cppu_ifcontainer \ +)) + +$(eval $(call gb_CppunitTest_use_api,cppuhelper_cppu_ifcontainer,\ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppuhelper_cppu_ifcontainer,\ + cppu \ + cppuhelper \ + sal \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/CppunitTest_cppuhelper_cppu_unourl.mk b/cppuhelper/CppunitTest_cppuhelper_cppu_unourl.mk new file mode 100644 index 000000000..d973e748d --- /dev/null +++ b/cppuhelper/CppunitTest_cppuhelper_cppu_unourl.mk @@ -0,0 +1,23 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppuhelper_cppu_unourl)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppuhelper_cppu_unourl,\ + cppuhelper/qa/unourl/cppu_unourl \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppuhelper_cppu_unourl,\ + cppu \ + cppuhelper \ + sal \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/CppunitTest_cppuhelper_qa_misc.mk b/cppuhelper/CppunitTest_cppuhelper_qa_misc.mk new file mode 100644 index 000000000..c83ebee59 --- /dev/null +++ b/cppuhelper/CppunitTest_cppuhelper_qa_misc.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppuhelper_qa_misc)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppuhelper_qa_misc,\ + cppuhelper/qa/misc/test_misc \ +)) + +$(eval $(call gb_CppunitTest_use_api,cppuhelper_qa_misc,\ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppuhelper_qa_misc,\ + cppu \ + cppuhelper \ + sal \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/CppunitTest_cppuhelper_qa_weak.mk b/cppuhelper/CppunitTest_cppuhelper_qa_weak.mk new file mode 100644 index 000000000..9a6322caf --- /dev/null +++ b/cppuhelper/CppunitTest_cppuhelper_qa_weak.mk @@ -0,0 +1,27 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,cppuhelper_qa_weak)) + +$(eval $(call gb_CppunitTest_add_exception_objects,cppuhelper_qa_weak,\ + cppuhelper/qa/weak/test_weak \ +)) + +$(eval $(call gb_CppunitTest_use_api,cppuhelper_qa_weak,\ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,cppuhelper_qa_weak,\ + cppu \ + cppuhelper \ + sal \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/InternalUnoApi_cppuhelper.mk b/cppuhelper/InternalUnoApi_cppuhelper.mk new file mode 100644 index 000000000..d2849b0a3 --- /dev/null +++ b/cppuhelper/InternalUnoApi_cppuhelper.mk @@ -0,0 +1,20 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_InternalUnoApi_InternalUnoApi,cppuhelper,cppuhelper/unotypes)) + +$(eval $(call gb_InternalUnoApi_use_api,cppuhelper,\ + udkapi \ +)) + +$(eval $(call gb_InternalUnoApi_add_idlfiles,cppuhelper,cppuhelper/detail,\ + XExceptionThrower \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/cppuhelper/IwyuFilter_cppuhelper.yaml b/cppuhelper/IwyuFilter_cppuhelper.yaml new file mode 100644 index 000000000..323b86606 --- /dev/null +++ b/cppuhelper/IwyuFilter_cppuhelper.yaml @@ -0,0 +1,48 @@ +--- +assumeFilename: cppuhelper/source/implbase.cxx +blacklist: + cppuhelper/source/typemanager.hxx: + # base class needs full type + - com/sun/star/container/XHierarchicalNameAccess.hpp + - com/sun/star/container/XSet.hpp + - com/sun/star/lang/XServiceInfo.hpp + - com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp + - cppuhelper/compbase.hxx + cppuhelper/source/access_control.cxx: + # Needed for UnoType + - com/sun/star/security/RuntimePermission.hpp + - com/sun/star/io/FilePermission.hpp + - com/sun/star/connection/SocketPermission.hpp + cppuhelper/source/bootstrap.cxx: + # Needed on win32 + - o3tl/char16_t2wchar_t.hxx + cppuhelper/source/defaultbootstrap.cxx: + # Needed for template specialization + - com/sun/star/lang/XSingleComponentFactory.hpp + cppuhelper/source/exc_thrower.cxx: + # No hpp -> hdl switch + - cppuhelper/detail/XExceptionThrower.hpp + # Needed for cppu::throwException + - cppuhelper/exc_hlp.hxx + cppuhelper/source/findsofficepath.c: + # Needed for cppuhelper_detail_findSofficePath + - cppuhelper/findsofficepath.h + cppuhelper/source/macro_expander.cxx: + # Needed for template specialization + - com/sun/star/lang/XSingleComponentFactory.hpp + cppuhelper/source/paths.cxx: + # Needed on mac OS for LIBO_LIB_FOLDER + LIBO_URE_ETC_FOLDER + - config_folders.h + cppuhelper/source/shlib.cxx: + # Needed for UnoType + - com/sun/star/registry/XRegistryKey.hpp + # Needed for loadSharedLibComponentFactory & writeSharedLibComponentInfo + - cppuhelper/shlib.hxx + # Needed for cppuhelper::detail::getEnvironment + - loadsharedlibcomponentfactory.hxx + cppuhelper/source/supportsservice.cxx: + # Needed for supportsService + - cppuhelper/supportsservice.hxx + cppuhelper/source/tdmgr.cxx: + # Needed to inherit linker visibility from function declaration + - cppuhelper/bootstrap.hxx diff --git a/cppuhelper/Library_cppuhelper.mk b/cppuhelper/Library_cppuhelper.mk new file mode 100644 index 000000000..5741eea64 --- /dev/null +++ b/cppuhelper/Library_cppuhelper.mk @@ -0,0 +1,67 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Library_Library,cppuhelper)) + +$(eval $(call gb_Library_set_soversion_script,cppuhelper,$(SRCDIR)/cppuhelper/source/gcc3.map)) + +$(eval $(call gb_Library_use_internal_comprehensive_api,cppuhelper,\ + cppuhelper \ + udkapi \ + offapi \ +)) + +$(eval $(call gb_Library_add_defs,cppuhelper,\ + -DCPPUHELPER_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_set_precompiled_header,cppuhelper,cppuhelper/inc/pch/precompiled_cppuhelper)) + +$(eval $(call gb_Library_use_libraries,cppuhelper,\ + cppu \ + reg \ + sal \ + salhelper \ + unoidl \ + xmlreader \ +)) + +$(eval $(call gb_Library_use_static_libraries,cppuhelper,\ + findsofficepath \ +)) + +$(eval $(call gb_Library_add_exception_objects,cppuhelper,\ + cppuhelper/source/access_control \ + cppuhelper/source/bootstrap \ + cppuhelper/source/compat \ + cppuhelper/source/component_context \ + cppuhelper/source/component \ + cppuhelper/source/defaultbootstrap \ + cppuhelper/source/exc_thrower \ + cppuhelper/source/factory \ + cppuhelper/source/implbase \ + cppuhelper/source/implbase_ex \ + cppuhelper/source/implementationentry \ + cppuhelper/source/interfacecontainer \ + cppuhelper/source/macro_expander \ + cppuhelper/source/paths \ + cppuhelper/source/propertysetmixin \ + cppuhelper/source/propshlp \ + cppuhelper/source/servicemanager \ + cppuhelper/source/shlib \ + cppuhelper/source/supportsservice \ + cppuhelper/source/tdmgr \ + cppuhelper/source/typemanager \ + cppuhelper/source/typeprovider \ + cppuhelper/source/unourl \ + cppuhelper/source/weak \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/Makefile b/cppuhelper/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/cppuhelper/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/Module_cppuhelper.mk b/cppuhelper/Module_cppuhelper.mk new file mode 100644 index 000000000..35b95e5ab --- /dev/null +++ b/cppuhelper/Module_cppuhelper.mk @@ -0,0 +1,26 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# 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/. +# + +$(eval $(call gb_Module_Module,cppuhelper)) + +$(eval $(call gb_Module_add_targets,cppuhelper,\ + InternalUnoApi_cppuhelper \ + Library_cppuhelper \ + StaticLibrary_findsofficepath \ +)) + +$(eval $(call gb_Module_add_check_targets,cppuhelper,\ + CppunitTest_cppuhelper_cppu_ifcontainer \ + CppunitTest_cppuhelper_cppu_unourl \ + CppunitTest_cppuhelper_qa_misc \ + CppunitTest_cppuhelper_qa_weak \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/README b/cppuhelper/README new file mode 100644 index 000000000..4ea500109 --- /dev/null +++ b/cppuhelper/README @@ -0,0 +1,4 @@ +Helpers for using cppu in C++, e.g. templates for implementing UNO components, bootstrapping stuff. Get UNO up and running. + +See also: +[http://wiki.openoffice.org/wiki/Uno/Cpp/Modules/CPPUhelper] diff --git a/cppuhelper/StaticLibrary_findsofficepath.mk b/cppuhelper/StaticLibrary_findsofficepath.mk new file mode 100644 index 000000000..080f20b54 --- /dev/null +++ b/cppuhelper/StaticLibrary_findsofficepath.mk @@ -0,0 +1,16 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_StaticLibrary_StaticLibrary,findsofficepath)) + +$(eval $(call gb_StaticLibrary_add_cobjects,findsofficepath,\ + cppuhelper/source/findsofficepath \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/cppuhelper/inc/pch/precompiled_cppuhelper.cxx b/cppuhelper/inc/pch/precompiled_cppuhelper.cxx new file mode 100644 index 000000000..1c3b45036 --- /dev/null +++ b/cppuhelper/inc/pch/precompiled_cppuhelper.cxx @@ -0,0 +1,12 @@ +/* -*- 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/. + */ + +#include "precompiled_cppuhelper.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/inc/pch/precompiled_cppuhelper.hxx b/cppuhelper/inc/pch/precompiled_cppuhelper.hxx new file mode 100644 index 000000000..d84b33f5b --- /dev/null +++ b/cppuhelper/inc/pch/precompiled_cppuhelper.hxx @@ -0,0 +1,113 @@ +/* -*- 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 has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-02-01 10:57:30 using: + ./bin/update_pch cppuhelper cppuhelper --cutoff=3 --exclude:system --exclude:module --exclude:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./cppuhelper/inc/pch/precompiled_cppuhelper.hxx "make cppuhelper.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstdlib> +#include <memory> +#include <new> +#include <type_traits> +#include <vector> +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include <osl/diagnose.h> +#include <osl/doublecheckedlocking.h> +#include <osl/file.hxx> +#include <osl/interlck.h> +#include <osl/module.h> +#include <osl/module.hxx> +#include <osl/mutex.hxx> +#include <osl/process.h> +#include <osl/security.hxx> +#include <osl/thread.hxx> +#include <osl/time.h> +#include <rtl/alloc.h> +#include <rtl/bootstrap.hxx> +#include <rtl/character.hxx> +#include <rtl/malformeduriexception.hxx> +#include <rtl/random.h> +#include <rtl/ref.hxx> +#include <rtl/textcvt.h> +#include <rtl/unload.h> +#include <rtl/uri.h> +#include <rtl/uri.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.h> +#include <rtl/ustring.hxx> +#include <rtl/uuid.h> +#include <sal/config.h> +#include <sal/log.hxx> +#include <sal/macros.h> +#include <sal/saldllapi.h> +#include <sal/types.h> +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/reflection/XIndirectTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp> +#include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp> +#include <com/sun/star/reflection/XStructTypeDescription.hpp> +#include <com/sun/star/reflection/XTypeDescription.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/DeploymentException.hpp> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.h> +#include <com/sun/star/uno/XAggregation.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/sequence.hxx> +#include <cppu/cppudllapi.h> +#include <salhelper/simplereferenceobject.hxx> +#include <typelib/typeclass.h> +#include <typelib/typedescription.h> +#include <typelib/uik.h> +#include <uno/lbnames.h> +#include <uno/mapping.hxx> +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/component_context.hxx> +#include <cppuhelper/cppuhelperdllapi.h> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/weakagg.hxx> +#include <cppuhelper/weakref.hxx> +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/qa/ifcontainer/cppu_ifcontainer.cxx b/cppuhelper/qa/ifcontainer/cppu_ifcontainer.cxx new file mode 100644 index 000000000..0dcebbbac --- /dev/null +++ b/cppuhelper/qa/ifcontainer/cppu_ifcontainer.cxx @@ -0,0 +1,263 @@ +/* -*- 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/types.h> + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <com/sun/star/lang/XEventListener.hpp> +#include <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/propshlp.hxx> + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +namespace { + +struct ContainerStats { + int m_nAlive; + int m_nDisposed; + ContainerStats() : m_nAlive(0), m_nDisposed(0) {} +}; + +class ContainerListener : public ::cppu::WeakImplHelper< XEventListener > +{ + ContainerStats *m_pStats; +public: + explicit ContainerListener(ContainerStats *pStats) + : m_pStats(pStats) { m_pStats->m_nAlive++; } + virtual ~ContainerListener() override { m_pStats->m_nAlive--; } + virtual void SAL_CALL disposing( const EventObject& ) override + { + m_pStats->m_nDisposed++; + } +}; + +} + +namespace cppu_ifcontainer +{ + class IfTest : public CppUnit::TestFixture + { + osl::Mutex m_aGuard; + static const int nTests = 10; + public: + void testCreateDispose() + { + ContainerStats aStats; + cppu::OInterfaceContainerHelper *pContainer; + + pContainer = new cppu::OInterfaceContainerHelper(m_aGuard); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Empty container not empty", + static_cast<sal_Int32>(0), pContainer->getLength()); + + int i; + for (i = 0; i < nTests; i++) + { + Reference<XEventListener> xRef = new ContainerListener(&aStats); + int nNewLen = pContainer->addInterface(xRef); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("addition length mismatch", + i + 1, nNewLen); + CPPUNIT_ASSERT_EQUAL_MESSAGE("addition length mismatch", + static_cast<sal_Int32>(i + 1), pContainer->getLength()); + } + CPPUNIT_ASSERT_MESSAGE("alive count mismatch", + bool(aStats.m_nAlive == nTests)); + + EventObject aObj; + pContainer->disposeAndClear(aObj); + + CPPUNIT_ASSERT_MESSAGE("dispose count mismatch", + bool(aStats.m_nDisposed == nTests)); + CPPUNIT_ASSERT_EQUAL_MESSAGE("leaked container left alive", + 0, aStats.m_nAlive); + + delete pContainer; + } + + void testEnumerate() + { + int i; + ContainerStats aStats; + cppu::OInterfaceContainerHelper *pContainer; + pContainer = new cppu::OInterfaceContainerHelper(m_aGuard); + + std::vector< Reference< XEventListener > > aListeners; + for (i = 0; i < nTests; i++) + { + Reference<XEventListener> xRef = new ContainerListener(&aStats); + pContainer->addInterface(xRef); + aListeners.push_back(xRef); + } + Sequence< Reference< XInterface > > aElements = pContainer->getElements(); + + CPPUNIT_ASSERT_MESSAGE("query contents", + bool(static_cast<int>(aElements.getLength()) == nTests)); + if (static_cast<int>(aElements.getLength()) == nTests) + { + for (i = 0; i < nTests; i++) + { + CPPUNIT_ASSERT_MESSAGE("mismatching elements", + bool(aElements[i] == aListeners[i])); + } + } + pContainer->clear(); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("non-empty container post clear", + static_cast<sal_Int32>(0), pContainer->getLength()); + delete pContainer; + } + + template < typename ContainerType, typename ContainedType > + void doContainerTest(const ContainedType *pTypes) + { + ContainerStats aStats; + ContainerType *pContainer; + pContainer = new ContainerType(m_aGuard); + + int i; + Reference<XEventListener> xRefs[nTests * 2]; + + // add these interfaces + for (i = 0; i < nTests * 2; i++) + { + xRefs[i] = new ContainerListener(&aStats); + pContainer->addInterface(pTypes[i / 2], xRefs[i]); + } + + // check it is all there + for (i = 0; i < nTests; i++) + { + cppu::OInterfaceContainerHelper *pHelper; + + pHelper = pContainer->getContainer(pTypes[i]); + + CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != nullptr); + Sequence<Reference< XInterface > > aSeq = pHelper->getElements(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong num elements", static_cast<sal_Int32>(2), aSeq.getLength()); + CPPUNIT_ASSERT_MESSAGE("match", bool(aSeq[0] == xRefs[i*2])); + CPPUNIT_ASSERT_MESSAGE("match", bool(aSeq[1] == xRefs[i*2+1])); + } + + // remove every other interface + for (i = 0; i < nTests; i++) + pContainer->removeInterface(pTypes[i], xRefs[i*2+1]); + + // check it is half there + for (i = 0; i < nTests; i++) + { + cppu::OInterfaceContainerHelper *pHelper; + + pHelper = pContainer->getContainer(pTypes[i]); + + CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != nullptr); + Sequence<Reference< XInterface > > aSeq = pHelper->getElements(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong num elements", static_cast<sal_Int32>(1), aSeq.getLength()); + CPPUNIT_ASSERT_MESSAGE("match", bool(aSeq[0] == xRefs[i*2])); + } + + // remove the 1st half of the rest + for (i = 0; i < nTests / 2; i++) + pContainer->removeInterface(pTypes[i], xRefs[i*2]); + + // check it is half there + for (i = 0; i < nTests / 2; i++) + { + cppu::OInterfaceContainerHelper *pHelper; + + pHelper = pContainer->getContainer(pTypes[i]); + CPPUNIT_ASSERT_MESSAGE("no helper", pHelper != nullptr); + Sequence<Reference< XInterface > > aSeq = pHelper->getElements(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("wrong num elements", static_cast<sal_Int32>(0), aSeq.getLength()); + } + + delete pContainer; + } + + void testOMultiTypeInterfaceContainerHelper() + { + uno::Type pTypes[nTests] = + { + ::cppu::UnoType< bool >::get(), + ::cppu::UnoType< float >::get(), + ::cppu::UnoType< double >::get(), + ::cppu::UnoType< ::sal_uInt64 >::get(), + ::cppu::UnoType< ::sal_Int64 >::get(), + ::cppu::UnoType< ::sal_uInt32 >::get(), + ::cppu::UnoType< ::sal_Int32 >::get(), + ::cppu::UnoType< ::sal_Int16 >::get(), + ::cppu::UnoType< OUString >::get(), + ::cppu::UnoType< ::sal_Int8 >::get() + }; + doContainerTest< cppu::OMultiTypeInterfaceContainerHelper, + uno::Type> (pTypes); + } + + void testOMultiTypeInterfaceContainerHelperInt32() + { + sal_Int32 const pTypes[nTests] = + { + 0, + -1, + 1, + 256, + 1024, + 3, + 7, + 8, + 9, + 10 + }; + doContainerTest< cppu::OMultiTypeInterfaceContainerHelperInt32, sal_Int32> (pTypes); + } + + void testOMultiTypeInterfaceContainerHelperVar() + { + typedef cppu::OMultiTypeInterfaceContainerHelperVar< + char const *, void, rtl::CStringEqual> StrContainer; + + const char * const pTypes[nTests] = + { + "this_is", "such", "fun", "writing", "unit", "tests", "when", "it", "works", "anyway" + }; + doContainerTest< StrContainer, const char *> (pTypes); + } + + // Automatic registration code + CPPUNIT_TEST_SUITE(IfTest); + CPPUNIT_TEST(testCreateDispose); + CPPUNIT_TEST(testEnumerate); + CPPUNIT_TEST(testOMultiTypeInterfaceContainerHelper); + CPPUNIT_TEST(testOMultiTypeInterfaceContainerHelperVar); + CPPUNIT_TEST(testOMultiTypeInterfaceContainerHelperInt32); + CPPUNIT_TEST_SUITE_END(); + }; +} // namespace cppu_ifcontainer + +CPPUNIT_TEST_SUITE_REGISTRATION(cppu_ifcontainer::IfTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/qa/misc/test_misc.cxx b/cppuhelper/qa/misc/test_misc.cxx new file mode 100644 index 000000000..0e4fdf9ef --- /dev/null +++ b/cppuhelper/qa/misc/test_misc.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <cppuhelper/exc_hlp.hxx> + +namespace +{ +class Test : public ::CppUnit::TestFixture +{ +public: + void testCatchThrow(); + void testgetCaughtException(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testCatchThrow); + CPPUNIT_TEST(testgetCaughtException); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testCatchThrow() +{ + css::uno::Any aSavedException; + try + { + throw css::uno::RuntimeException("RuntimeException"); + } + catch (const css::uno::RuntimeException&) + { + aSavedException = cppu::getCaughtException(); + } + CPPUNIT_ASSERT(aSavedException.hasValue()); + try + { + cppu::throwException(aSavedException); + } + catch (const css::uno::RuntimeException&) + { + // the expected case + } + catch (...) + { + CPPUNIT_ASSERT(false); + } +} + +void Test::testgetCaughtException() +{ + css::uno::Any aSavedExceptionAny; + std::exception_ptr + aSavedException; /// exception caught during unzipping is saved to be thrown during reading + try + { + throw css::uno::RuntimeException("RuntimeException"); + } + catch (...) + { + aSavedException = std::current_exception(); + } + CPPUNIT_ASSERT(bool(aSavedException)); + try + { + std::rethrow_exception(aSavedException); + } + catch (const css::uno::RuntimeException&) + { + // the expected case + aSavedExceptionAny = cppu::getCaughtException(); + } + catch (...) + { + CPPUNIT_ASSERT(false); + } + CPPUNIT_ASSERT(aSavedExceptionAny.hasValue()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/cppuhelper/qa/propertysetmixin/JavaSupplier.java b/cppuhelper/qa/propertysetmixin/JavaSupplier.java new file mode 100644 index 000000000..a82e2bd7f --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/JavaSupplier.java @@ -0,0 +1,308 @@ +/* + * 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 . + */ + +package test.cppuhelper.propertysetmixin.comp; + +import com.sun.star.beans.Ambiguous; +import com.sun.star.beans.Defaulted; +import com.sun.star.beans.Optional; +import com.sun.star.beans.UnknownPropertyException; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.PropertyVetoException; +import com.sun.star.beans.XFastPropertySet; +import com.sun.star.beans.XPropertyAccess; +import com.sun.star.beans.XPropertyChangeListener; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertySetInfo; +import com.sun.star.beans.XVetoableChangeListener; +import com.sun.star.comp.loader.FactoryHelper; +import com.sun.star.lang.WrappedTargetException; +import com.sun.star.lang.XComponent; +import com.sun.star.lang.XEventListener; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.lib.uno.helper.PropertySetMixin; +import com.sun.star.registry.XRegistryKey; +import com.sun.star.uno.Any; +import com.sun.star.uno.IQueryInterface; +import com.sun.star.uno.Type; +import com.sun.star.uno.XComponentContext; +import test.cppuhelper.propertysetmixin.XSupplier; +import test.cppuhelper.propertysetmixin.XTest3; + +public final class JavaSupplier extends WeakBase implements XSupplier { + public JavaSupplier(XComponentContext context) { + this.context = context; + } + + public XComponent getEmpty1() { return new Empty1(); } + + public XComponent getEmpty2() { return new Empty2(); } + + public XTest3 getFull() { return new Full(); } + + public static XSingleServiceFactory __getServiceFactory( + String implName, XMultiServiceFactory multiFactory, XRegistryKey regKey) + { + return implName.equals(implementationName) + ? FactoryHelper.getServiceFactory( + JavaSupplier.class, serviceName, multiFactory, regKey) + : null; + } + + private static final String implementationName + = JavaSupplier.class.getName(); + private static final String serviceName + = "test.cppuhelper.propertysetmixin.JavaSupplier"; + + private final class Empty1 extends WeakBase implements XComponent { + public Empty1() {} + + public void dispose() { + prop.dispose(); + } + + public void addEventListener(XEventListener listener) {} + + public void removeEventListener(XEventListener listener) {} + + private final PropertySetMixin prop = new PropertySetMixin( + context, this, new Type(XComponent.class), null); + } + + private final class Empty2 extends WeakBase + implements XComponent, XPropertySet, XFastPropertySet, XPropertyAccess + { + public Empty2() {} + + public void dispose() { + prop.dispose(); + } + + public void addEventListener(XEventListener listener) {} + + public void removeEventListener(XEventListener listener) {} + + public com.sun.star.beans.XPropertySetInfo getPropertySetInfo() { + return prop.getPropertySetInfo(); + } + + public void setPropertyValue(String propertyName, Object value) + throws UnknownPropertyException, PropertyVetoException, + com.sun.star.lang.IllegalArgumentException, WrappedTargetException + { + prop.setPropertyValue(propertyName, value); + } + + public Object getPropertyValue(String propertyName) + throws UnknownPropertyException, WrappedTargetException + { + return prop.getPropertyValue(propertyName); + } + + public void addPropertyChangeListener( + String propertyName, XPropertyChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener( + String propertyName, XPropertyChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.removePropertyChangeListener(propertyName, listener); + } + + public void addVetoableChangeListener( + String propertyName, XVetoableChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.addVetoableChangeListener(propertyName, listener); + } + + public void removeVetoableChangeListener( + String propertyName, XVetoableChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.removeVetoableChangeListener(propertyName, listener); + } + + public void setFastPropertyValue(int handle, Object value) + throws UnknownPropertyException, PropertyVetoException, + com.sun.star.lang.IllegalArgumentException, WrappedTargetException + { + prop.setFastPropertyValue(handle, value); + } + + public Object getFastPropertyValue(int handle) + throws UnknownPropertyException, WrappedTargetException + { + return prop.getFastPropertyValue(handle); + } + + public PropertyValue[] getPropertyValues() { + return prop.getPropertyValues(); + } + + public void setPropertyValues(PropertyValue[] props) + throws UnknownPropertyException, PropertyVetoException, + com.sun.star.lang.IllegalArgumentException, WrappedTargetException + { + prop.setPropertyValues(props); + } + + private final PropertySetMixin prop = new PropertySetMixin( + context, this, new Type(XComponent.class), null); + } + + private final class Full extends WeakBase + implements XTest3, XPropertySet, XFastPropertySet, XPropertyAccess + { + public Full() {} + + public synchronized int getFirst() { + return a1; + } + + public void setFirst(int value) { + prop.prepareSet("First", null); + synchronized (this) { + a1 = value; + } + } + + public synchronized Ambiguous getSecond() + throws UnknownPropertyException + { + return a2; + } + + public void setSecond(Ambiguous value) + throws PropertyVetoException, UnknownPropertyException + { + PropertySetMixin.BoundListeners l + = new PropertySetMixin.BoundListeners(); + prop.prepareSet( + "Second", Any.VOID, + (((Optional) ((Defaulted) value.Value).Value).IsPresent + ? ((Optional) ((Defaulted) value.Value).Value).Value + : Any.VOID), + l); + synchronized (this) { + a2 = value; + } + l.notifyListeners(); + } + + public int getThird() throws UnknownPropertyException { + throw new UnknownPropertyException("Third", this); + } + + public void setThird(int value) throws UnknownPropertyException { + throw new UnknownPropertyException("Third", this); + } + + public int getFourth() throws UnknownPropertyException { + throw new UnknownPropertyException("Fourth", this); + } + + public void setFourth(int value) throws UnknownPropertyException { + throw new UnknownPropertyException("Fourth", this); + } + + public com.sun.star.beans.XPropertySetInfo getPropertySetInfo() { + return prop.getPropertySetInfo(); + } + + public void setPropertyValue(String propertyName, Object value) + throws UnknownPropertyException, PropertyVetoException, + com.sun.star.lang.IllegalArgumentException, WrappedTargetException + { + prop.setPropertyValue(propertyName, value); + } + + public Object getPropertyValue(String propertyName) + throws UnknownPropertyException, WrappedTargetException + { + return prop.getPropertyValue(propertyName); + } + + public void addPropertyChangeListener( + String propertyName, XPropertyChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.addPropertyChangeListener(propertyName, listener); + } + + public void removePropertyChangeListener( + String propertyName, XPropertyChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.removePropertyChangeListener(propertyName, listener); + } + + public void addVetoableChangeListener( + String propertyName, XVetoableChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.addVetoableChangeListener(propertyName, listener); + } + + public void removeVetoableChangeListener( + String propertyName, XVetoableChangeListener listener) + throws UnknownPropertyException, WrappedTargetException + { + prop.removeVetoableChangeListener(propertyName, listener); + } + + public void setFastPropertyValue(int handle, Object value) + throws UnknownPropertyException, PropertyVetoException, + com.sun.star.lang.IllegalArgumentException, WrappedTargetException + { + prop.setFastPropertyValue(handle, value); + } + + public Object getFastPropertyValue(int handle) + throws UnknownPropertyException, WrappedTargetException + { + return prop.getFastPropertyValue(handle); + } + + public PropertyValue[] getPropertyValues() { + return prop.getPropertyValues(); + } + + public void setPropertyValues(PropertyValue[] props) + throws UnknownPropertyException, PropertyVetoException, + com.sun.star.lang.IllegalArgumentException, WrappedTargetException + { + prop.setPropertyValues(props); + } + + private final PropertySetMixin prop = new PropertySetMixin( + context, this, new Type(XTest3.class), new String[] { "Third" }); + + private int a1 = 0; + private Ambiguous a2 = new Ambiguous( + new Defaulted(new Optional(), true), false); + } + + private final XComponentContext context; +} diff --git a/cppuhelper/qa/propertysetmixin/comp_propertysetmixin.cxx b/cppuhelper/qa/propertysetmixin/comp_propertysetmixin.cxx new file mode 100644 index 000000000..4de84ba3a --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/comp_propertysetmixin.cxx @@ -0,0 +1,407 @@ +/* -*- 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 <test/cppuhelper/propertysetmixin/XSupplier.hpp> +#include <test/cppuhelper/propertysetmixin/XTest3.hpp> + +#include <com/sun/star/beans/Ambiguous.hpp> +#include <com/sun/star/beans/Defaulted.hpp> +#include <com/sun/star/beans/Optional.hpp> +#include <com/sun/star/beans/PropertyVetoException.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <cppuhelper/propertysetmixin.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/weak.hxx> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <osl/mutex.hxx> +#include <rtl/ustring.h> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +namespace com::sun::star { + class XEventListener; +} } } + +namespace { + +class Empty1: + public cppu::OWeakObject, public css::lang::XComponent, + public cppu::PropertySetMixin< css::lang::XComponent > +{ +public: + explicit Empty1( + css::uno::Reference< css::uno::XComponentContext > const & context): + cppu::PropertySetMixin< css::lang::XComponent >( + context, static_cast< Implements >(0), + css::uno::Sequence< OUString >()) + {} + + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL acquire() throw () { OWeakObject::acquire(); } + + virtual void SAL_CALL release() throw () { OWeakObject::release(); } + + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException) { + cppu::PropertySetMixin< css::lang::XComponent >::dispose(); + } + + virtual void SAL_CALL addEventListener( + css::uno::Reference< css::lang::XEventListener > const &) + throw (css::uno::RuntimeException) + {} + + virtual void SAL_CALL removeEventListener( + css::uno::Reference< css::lang::XEventListener > const &) + throw (css::uno::RuntimeException) + {} + +private: + Empty1(Empty1 &); // not defined + void operator =(Empty1 &); // not defined + + virtual ~Empty1() {} +}; + +css::uno::Any Empty1::queryInterface(css::uno::Type const & type) + throw (css::uno::RuntimeException) +{ + css::uno::Any a(OWeakObject::queryInterface(type)); + if (a.hasValue()) { + return a; + } + a = cppu::queryInterface( + type, static_cast< css::lang::XComponent * >(this)); + return a.hasValue() + ? a + : cppu::PropertySetMixin< css::lang::XComponent >::queryInterface( + type); +} + +class Empty2: + public cppu::OWeakObject, public css::lang::XComponent, + public cppu::PropertySetMixin< css::lang::XComponent > +{ +public: + explicit Empty2( + css::uno::Reference< css::uno::XComponentContext > const & context): + cppu::PropertySetMixin< css::lang::XComponent >( + context, + static_cast< Implements >( + IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET + | IMPLEMENTS_PROPERTY_ACCESS), + css::uno::Sequence< OUString >()) + {} + + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL acquire() throw () { OWeakObject::acquire(); } + + virtual void SAL_CALL release() throw () { OWeakObject::release(); } + + virtual void SAL_CALL dispose() throw (css::uno::RuntimeException) { + cppu::PropertySetMixin< css::lang::XComponent >::dispose(); + } + + virtual void SAL_CALL addEventListener( + css::uno::Reference< css::lang::XEventListener > const &) + throw (css::uno::RuntimeException) + {} + + virtual void SAL_CALL removeEventListener( + css::uno::Reference< css::lang::XEventListener > const &) + throw (css::uno::RuntimeException) + {} + +private: + Empty2(Empty2 &); // not defined + void operator =(Empty2 &); // not defined + + virtual ~Empty2() {} +}; + +css::uno::Any Empty2::queryInterface(css::uno::Type const & type) + throw (css::uno::RuntimeException) +{ + css::uno::Any a(OWeakObject::queryInterface(type)); + if (a.hasValue()) { + return a; + } + a = cppu::queryInterface( + type, static_cast< css::lang::XComponent * >(this)); + return a.hasValue() + ? a + : cppu::PropertySetMixin< css::lang::XComponent >::queryInterface( + type); +} + +css::uno::Sequence< OUString > sequenceThird() { + css::uno::Sequence<OUString> s { OUString("Third") }; + return s; +} + +class Full: + public cppu::OWeakObject, public test::cppuhelper::propertysetmixin::XTest3, + public cppu::PropertySetMixin< + test::cppuhelper::propertysetmixin::XTest3 > +{ +public: + explicit Full( + css::uno::Reference< css::uno::XComponentContext > const & context): + cppu::PropertySetMixin< + test::cppuhelper::propertysetmixin::XTest3 >( + context, + static_cast< Implements >( + IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET + | IMPLEMENTS_PROPERTY_ACCESS), + sequenceThird()), + m_a1(0), + m_a2( + css::beans::Defaulted< css::beans::Optional< sal_Int32 > >( + css::beans::Optional< sal_Int32 >(), true), + false) + {} + + virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL acquire() throw () { OWeakObject::acquire(); } + + virtual void SAL_CALL release() throw () { OWeakObject::release(); } + + virtual sal_Int32 SAL_CALL getFirst() throw (css::uno::RuntimeException); + + virtual void SAL_CALL setFirst(sal_Int32 value) + throw (css::uno::RuntimeException); + + virtual + css::beans::Ambiguous< + css::beans::Defaulted< css::beans::Optional< sal_Int32 > > > + SAL_CALL getSecond() + throw ( + css::beans::UnknownPropertyException, css::uno::RuntimeException); + + virtual void SAL_CALL setSecond( + css::beans::Ambiguous< + css::beans::Defaulted< css::beans::Optional< ::sal_Int32 > > > const & + value) + throw ( + css::beans::PropertyVetoException, + css::beans::UnknownPropertyException, css::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getThird() + throw ( + css::beans::UnknownPropertyException, css::uno::RuntimeException); + + virtual void SAL_CALL setThird(sal_Int32 value) + throw ( + css::beans::UnknownPropertyException, css::uno::RuntimeException); + + virtual sal_Int32 SAL_CALL getFourth() + throw ( + css::beans::UnknownPropertyException, css::uno::RuntimeException); + + virtual void SAL_CALL setFourth(sal_Int32 value) + throw ( + css::beans::UnknownPropertyException, css::uno::RuntimeException); + +private: + Full(Full &); // not defined + void operator =(Full &); // not defined + + virtual ~Full() {} + + osl::Mutex m_mutex; + sal_Int32 m_a1; + css::beans::Ambiguous< + css::beans::Defaulted< css::beans::Optional< sal_Int32 > > > m_a2; +}; + +css::uno::Any Full::queryInterface(css::uno::Type const & type) + throw (css::uno::RuntimeException) +{ + css::uno::Any a(OWeakObject::queryInterface(type)); + if (a.hasValue()) { + return a; + } + a = cppu::queryInterface( + type, + static_cast< test::cppuhelper::propertysetmixin::XTest3 * >(this)); + return a.hasValue() + ? a + : (cppu::PropertySetMixin< + test::cppuhelper::propertysetmixin::XTest3 >::queryInterface( + type)); +} + +sal_Int32 Full::getFirst() throw (css::uno::RuntimeException) { + osl::MutexGuard g(m_mutex); + return m_a1; +} + +void Full::setFirst(sal_Int32 value) throw (css::uno::RuntimeException) { + prepareSet( + OUString("First"), css::uno::Any(), + css::uno::Any(), 0); + osl::MutexGuard g(m_mutex); + m_a1 = value; +} + +css::beans::Ambiguous< + css::beans::Defaulted< css::beans::Optional< sal_Int32 > > > +Full::getSecond() + throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) +{ + osl::MutexGuard g(m_mutex); + return m_a2; +} + +void Full::setSecond( + css::beans::Ambiguous< + css::beans::Defaulted< css::beans::Optional< ::sal_Int32 > > > const & + value) + throw ( + css::beans::PropertyVetoException, css::beans::UnknownPropertyException, + css::uno::RuntimeException) +{ + css::uno::Any v; + if (value.Value.Value.IsPresent) { + v <<= value.Value.Value.Value; + } + BoundListeners l; + prepareSet( + OUString("Second"), css::uno::Any(), + v, &l); + { + osl::MutexGuard g(m_mutex); + m_a2 = value; + } + l.notify(); +} + +sal_Int32 Full::getThird() + throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) +{ + throw css::beans::UnknownPropertyException( + OUString("Third"), + static_cast< cppu::OWeakObject * >(this)); +} + +void Full::setThird(sal_Int32) + throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) +{ + throw css::beans::UnknownPropertyException( + OUString("Third"), + static_cast< cppu::OWeakObject * >(this)); +} + +sal_Int32 Full::getFourth() + throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) +{ + throw css::beans::UnknownPropertyException( + OUString("Fourth"), + static_cast< cppu::OWeakObject * >(this)); +} + +void Full::setFourth(sal_Int32) + throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) +{ + throw css::beans::UnknownPropertyException( + OUString("Fourth"), + static_cast< cppu::OWeakObject * >(this)); +} + +class Supplier: + public cppu::WeakImplHelper< + test::cppuhelper::propertysetmixin::XSupplier > +{ +public: + explicit Supplier( + css::uno::Reference< css::uno::XComponentContext > const & context): + m_context(context) {} + + virtual css::uno::Reference< css::lang::XComponent > SAL_CALL getEmpty1() + throw (css::uno::RuntimeException) + { return new Empty1(m_context); } + + virtual css::uno::Reference< css::lang::XComponent > SAL_CALL getEmpty2() + throw (css::uno::RuntimeException) + { return new Empty2(m_context); } + + virtual css::uno::Reference< test::cppuhelper::propertysetmixin::XTest3 > + SAL_CALL getFull() throw (css::uno::RuntimeException) + { return new Full(m_context); } + +private: + Supplier(Supplier &); // not defined + void operator =(Supplier &); // not defined + + virtual ~Supplier() {} + + css::uno::Reference< css::uno::XComponentContext > m_context; +}; + +css::uno::Reference< css::uno::XInterface > SAL_CALL create( + css::uno::Reference< css::uno::XComponentContext > const & context) +{ + return static_cast< cppu::OWeakObject * >(new Supplier(context)); +} + +OUString SAL_CALL getImplementationName() { + return OUString( + "test.cppuhelper.propertysetmixin.comp.CppSupplier"); +} + +css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() +{ + css::uno::Sequence< OUString > s { "test.cppuhelper.propertysetmixin.CppSupplier") }; + return s; +} + +cppu::ImplementationEntry entries[] = { + { &create, &getImplementationName, &getSupportedServiceNames, + &cppu::createSingleComponentFactory, 0, 0 }, + { 0, 0, 0, 0, 0, 0 } }; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL mixin_component_getFactory( + char const * implName, void * serviceManager, void * registryKey) +{ + return cppu::component_getFactoryHelper( + implName, serviceManager, registryKey, entries); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/qa/propertysetmixin/manifest b/cppuhelper/qa/propertysetmixin/manifest new file mode 100644 index 000000000..168f4bc19 --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/manifest @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +RegistrationClassName: test.cppuhelper.propertysetmixin.comp.JavaSupplier diff --git a/cppuhelper/qa/propertysetmixin/qa_propertysetmixin.cpp.component b/cppuhelper/qa/propertysetmixin/qa_propertysetmixin.cpp.component new file mode 100644 index 000000000..eebe9b725 --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/qa_propertysetmixin.cpp.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="mixin" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="test.cppuhelper.propertysetmixin.comp.CppSupplier"> + <service name="test.cppuhelper.propertysetmixin.CppSupplier"/> + </implementation> +</component> diff --git a/cppuhelper/qa/propertysetmixin/qa_propertysetmixin.java.component b/cppuhelper/qa/propertysetmixin/qa_propertysetmixin.java.component new file mode 100644 index 000000000..887dfe6f0 --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/qa_propertysetmixin.java.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.Java2" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="test.cppuhelper.propertysetmixin.comp.JavaSupplier"> + <service name="test.cppuhelper.propertysetmixin.JavaSupplier"/> + </implementation> +</component> diff --git a/cppuhelper/qa/propertysetmixin/test_propertysetmixin.cxx b/cppuhelper/qa/propertysetmixin/test_propertysetmixin.cxx new file mode 100644 index 000000000..d6679dae5 --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/test_propertysetmixin.cxx @@ -0,0 +1,639 @@ +/* -*- 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 <test/cppuhelper/propertysetmixin/CppSupplier.hpp> +#include <test/cppuhelper/propertysetmixin/JavaSupplier.hpp> +#include <test/cppuhelper/propertysetmixin/XSupplier.hpp> +#include <test/cppuhelper/propertysetmixin/XTest3.hpp> + +#include <com/sun/star/beans/Ambiguous.hpp> +#include <com/sun/star/beans/Defaulted.hpp> +#include <com/sun/star/beans/Optional.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyVetoException.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XVetoableChangeListener.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/implbase.hxx> +#include "cppunit/TestAssert.h" +#include "cppunit/TestFixture.h" +#include "cppunit/extensions/HelperMacros.h" +#include "cppunit/plugin/TestPlugIn.h" +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> +#include <rtl/string.h> +#include <rtl/textenc.h> +#include <rtl/ustring.h> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include <limits> +#include <ostream> + +namespace com::sun::star { + struct EventObject; +} } } + +namespace { + +std::ostream & operator <<(std::ostream & out, OUString const & value) { + return out << OUStringToOString(value, RTL_TEXTENCODING_UTF8).getStr(); +} + +std::ostream & operator <<(std::ostream & out, css::uno::Type const & value) { + return out << "com::sun::star::uno::Type[" << value.getTypeName() << ']'; +} + +std::ostream & operator <<(std::ostream & out, css::uno::Any const & value) { + return + out << "com::sun::star::uno::Any[" << value.getValueType() << ", ...]"; +} + +class BoundListener: + public cppu::WeakImplHelper< css::beans::XPropertyChangeListener > +{ +public: + BoundListener(): m_count(0) {} + + int count() const { + osl::MutexGuard g(m_mutex); + return m_count; + } + + virtual void SAL_CALL disposing(css::lang::EventObject const &) + throw (css::uno::RuntimeException) + { + osl::MutexGuard g(m_mutex); + CPPUNIT_ASSERT(m_count < std::numeric_limits< int >::max()); + ++m_count; + } + + virtual void SAL_CALL propertyChange( + css::beans::PropertyChangeEvent const &) + throw (css::uno::RuntimeException) + { CPPUNIT_FAIL("BoundListener::propertyChange called"); } + +private: + BoundListener(BoundListener &); // not defined + void operator =(BoundListener &); // not defined + + virtual ~BoundListener() {} + + mutable osl::Mutex m_mutex; + int m_count; +}; + +class VetoListener: + public cppu::WeakImplHelper< css::beans::XVetoableChangeListener > +{ +public: + VetoListener(): m_count(0) {} + + int count() const { + osl::MutexGuard g(m_mutex); + return m_count; + } + + virtual void SAL_CALL disposing(css::lang::EventObject const &) + throw (css::uno::RuntimeException) + { + osl::MutexGuard g(m_mutex); + CPPUNIT_ASSERT(m_count < std::numeric_limits< int >::max()); + ++m_count; + } + + virtual void SAL_CALL vetoableChange( + css::beans::PropertyChangeEvent const &) + throw (css::beans::PropertyVetoException, css::uno::RuntimeException) + { CPPUNIT_FAIL("VetoListener::vetoableChange called"); } + +private: + VetoListener(VetoListener &); // not defined + void operator =(VetoListener &); // not defined + + virtual ~VetoListener() {} + + mutable osl::Mutex m_mutex; + int m_count; +}; + +class Test: public CppUnit::TestFixture { +public: + virtual void setUp(); + + virtual void tearDown(); + + void testCppEmpty1() { testEmpty1(getCppSupplier()); } + + void testCppEmpty2() { testEmpty2(getCppSupplier()); } + + void testCppFull() { testFull(getCppSupplier()); } + + void testJavaEmpty1() { testEmpty1(getJavaSupplier()); } + + void testJavaEmpty2() { testEmpty2(getJavaSupplier()); } + + void testJavaFull() { testFull(getJavaSupplier()); } + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testCppEmpty1); + CPPUNIT_TEST(testCppEmpty2); + CPPUNIT_TEST(testCppFull); + CPPUNIT_TEST(testJavaEmpty1); + CPPUNIT_TEST(testJavaEmpty2); + CPPUNIT_TEST(testJavaFull); + CPPUNIT_TEST_SUITE_END(); + +private: + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + getCppSupplier() const; + + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + getJavaSupplier() const; + + void testEmpty1( + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + const & supplier) const; + + void testEmpty2( + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + const & supplier) const; + + void testFull( + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + const & supplier) const; + + css::uno::Reference< css::uno::XComponentContext > m_context; +}; + +void Test::setUp() { + m_context = cppu::defaultBootstrap_InitialComponentContext(); + CPPUNIT_ASSERT(m_context.is()); +} + +void Test::tearDown() { + css::uno::Reference< css::lang::XComponent >( + m_context, css::uno::UNO_QUERY_THROW)->dispose(); +} + +css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > +Test::getCppSupplier() const +{ + return test::cppuhelper::propertysetmixin::CppSupplier::create(m_context); +} + +css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > +Test::getJavaSupplier() const +{ + return test::cppuhelper::propertysetmixin::JavaSupplier::create(m_context); +} + +void Test::testEmpty1( + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + const & supplier) const +{ + css::uno::Reference< css::lang::XComponent > empty1( + supplier->getEmpty1(), css::uno::UNO_QUERY_THROW); + CPPUNIT_ASSERT( + !css::uno::Reference< css::beans::XPropertySet >( + empty1, css::uno::UNO_QUERY).is()); + CPPUNIT_ASSERT( + !css::uno::Reference< css::beans::XFastPropertySet >( + empty1, css::uno::UNO_QUERY).is()); + CPPUNIT_ASSERT( + !css::uno::Reference< css::beans::XPropertyAccess >( + empty1, css::uno::UNO_QUERY).is()); + empty1->dispose(); +} + +void Test::testEmpty2( + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + const & supplier) const +{ + css::uno::Reference< css::lang::XComponent > empty2( + supplier->getEmpty2(), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::beans::XPropertySet > empty2p( + empty2, css::uno::UNO_QUERY); + CPPUNIT_ASSERT(empty2p.is()); + css::uno::Reference< css::beans::XPropertySetInfo > info( + empty2p->getPropertySetInfo()); + CPPUNIT_ASSERT(info.is()); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int32 >(0), info->getProperties().getLength()); + try { + info->getPropertyByName( + OUString("any")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + CPPUNIT_ASSERT( + !info->hasPropertyByName( + OUString("any"))); + try { + empty2p->setPropertyValue( + OUString("any"), css::uno::Any()); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + empty2p->getPropertyValue( + OUString("any")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + rtl::Reference boundListener1(new BoundListener); + empty2p->addPropertyChangeListener(OUString(), boundListener1.get()); + empty2p->addPropertyChangeListener(OUString(), boundListener1.get()); + rtl::Reference boundListener2(new BoundListener); + empty2p->removePropertyChangeListener( + OUString(), boundListener2.get()); + rtl::Reference vetoListener1(new VetoListener); + empty2p->addVetoableChangeListener(OUString(), vetoListener1.get()); + empty2p->addVetoableChangeListener(OUString(), vetoListener1.get()); + rtl::Reference vetoListener2(new VetoListener); + empty2p->addVetoableChangeListener(OUString(), vetoListener2.get()); + empty2p->removeVetoableChangeListener(OUString(), vetoListener2.get()); + css::uno::Reference< css::beans::XFastPropertySet > empty2f( + empty2, css::uno::UNO_QUERY); + CPPUNIT_ASSERT(empty2f.is()); + try { + empty2f->setFastPropertyValue(-1, css::uno::Any()); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + empty2f->setFastPropertyValue(0, css::uno::Any()); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + empty2f->getFastPropertyValue(-1); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + empty2f->getFastPropertyValue(0); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + css::uno::Reference< css::beans::XPropertyAccess > empty2a( + empty2, css::uno::UNO_QUERY); + CPPUNIT_ASSERT(empty2a.is()); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int32 >(0), empty2a->getPropertyValues().getLength()); + empty2a->setPropertyValues( + css::uno::Sequence< css::beans::PropertyValue >()); + css::uno::Sequence< css::beans::PropertyValue > vs(2); + vs[0].Name = OUString("any1"); + vs[0].Handle = -1; + vs[0].State = css::beans::PropertyState_DIRECT_VALUE; + vs[0].Name = OUString("any2"); + vs[0].Handle = -1; + vs[0].State = css::beans::PropertyState_DIRECT_VALUE; + try { + empty2a->setPropertyValues(vs); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + CPPUNIT_ASSERT_EQUAL(0, boundListener1->count()); + CPPUNIT_ASSERT_EQUAL(0, boundListener2->count()); + CPPUNIT_ASSERT_EQUAL(0, vetoListener1->count()); + CPPUNIT_ASSERT_EQUAL(0, vetoListener2->count()); + empty2->dispose(); + CPPUNIT_ASSERT_EQUAL(2, boundListener1->count()); + CPPUNIT_ASSERT_EQUAL(0, boundListener2->count()); + CPPUNIT_ASSERT_EQUAL(2, vetoListener1->count()); + CPPUNIT_ASSERT_EQUAL(0, vetoListener2->count()); + empty2p->removePropertyChangeListener( + OUString(), boundListener1.get()); + empty2p->removePropertyChangeListener( + OUString(), boundListener2.get()); + empty2p->removeVetoableChangeListener(OUString(), vetoListener1.get()); + empty2p->removeVetoableChangeListener(OUString(), vetoListener2.get()); + empty2p->addPropertyChangeListener(OUString(), boundListener1.get()); + empty2p->addPropertyChangeListener(OUString(), boundListener2.get()); + empty2p->addVetoableChangeListener(OUString(), vetoListener1.get()); + empty2p->addVetoableChangeListener(OUString(), vetoListener2.get()); + try { + empty2p->addPropertyChangeListener( + OUString(), + css::uno::Reference< css::beans::XPropertyChangeListener >()); + } catch (css::uno::RuntimeException &) {} + try { + empty2p->addVetoableChangeListener( + OUString(), + css::uno::Reference< css::beans::XVetoableChangeListener >()); + } catch (css::uno::RuntimeException &) {} + CPPUNIT_ASSERT_EQUAL(3, boundListener1->count()); + CPPUNIT_ASSERT_EQUAL(1, boundListener2->count()); + CPPUNIT_ASSERT_EQUAL(3, vetoListener1->count()); + CPPUNIT_ASSERT_EQUAL(1, vetoListener2->count()); +} + +void Test::testFull( + css::uno::Reference< test::cppuhelper::propertysetmixin::XSupplier > + const & supplier) const +{ + css::uno::Reference< test::cppuhelper::propertysetmixin::XTest3 > full( + supplier->getFull(), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::beans::XPropertySet > fullp( + full, css::uno::UNO_QUERY); + CPPUNIT_ASSERT(fullp.is()); + css::uno::Reference< css::beans::XPropertySetInfo > info( + fullp->getPropertySetInfo()); + CPPUNIT_ASSERT(info.is()); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int32 >(3), info->getProperties().getLength()); + css::beans::Property prop( + info->getPropertyByName( + OUString("First"))); + CPPUNIT_ASSERT_EQUAL( + OUString("First"), prop.Name); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), prop.Handle); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<sal_Int32>::get(), prop.Type); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int16 >(0), prop.Attributes); + prop = info->getPropertyByName( + OUString("Second")); + CPPUNIT_ASSERT_EQUAL( + OUString("Second"), prop.Name); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(1), prop.Handle); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<sal_Int32>::get(), prop.Type); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int16 >( + css::beans::PropertyAttribute::MAYBEVOID + | css::beans::PropertyAttribute::BOUND + | css::beans::PropertyAttribute::CONSTRAINED + | css::beans::PropertyAttribute::MAYBEAMBIGUOUS + | css::beans::PropertyAttribute::MAYBEDEFAULT + | css::beans::PropertyAttribute::OPTIONAL), + prop.Attributes); + try { + info->getPropertyByName( + OUString("Third")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + prop = info->getPropertyByName( + OUString("Fourth")); + CPPUNIT_ASSERT_EQUAL( + OUString("Fourth"), prop.Name); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(3), prop.Handle); + CPPUNIT_ASSERT_EQUAL(cppu::UnoType<sal_Int32>::get(), prop.Type); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int16 >(css::beans::PropertyAttribute::OPTIONAL), + prop.Attributes); + try { + info->getPropertyByName( + OUString("first")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + CPPUNIT_ASSERT( + info->hasPropertyByName( + OUString("First"))); + CPPUNIT_ASSERT( + info->hasPropertyByName( + OUString("Second"))); + CPPUNIT_ASSERT( + !info->hasPropertyByName( + OUString("Third"))); + CPPUNIT_ASSERT( + info->hasPropertyByName( + OUString("Fourth"))); + CPPUNIT_ASSERT( + !info->hasPropertyByName( + OUString("first"))); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(0)), + fullp->getPropertyValue( + OUString("First"))); + fullp->setPropertyValue( + OUString("First"), + css::uno::Any(static_cast< sal_Int32 >(-100))); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(-100)), + fullp->getPropertyValue( + OUString("First"))); + css::uno::Any voidAny; + CPPUNIT_ASSERT_EQUAL( + voidAny, + fullp->getPropertyValue( + OUString("Second"))); + fullp->setPropertyValue( + OUString("Second"), + css::uno::Any(static_cast< sal_Int32 >(100))); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(100)), + fullp->getPropertyValue( + OUString("Second"))); + CPPUNIT_ASSERT(full->getSecond().Value.Value.IsPresent); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int32 >(100), full->getSecond().Value.Value.Value); + CPPUNIT_ASSERT(!full->getSecond().Value.IsDefaulted); + CPPUNIT_ASSERT(!full->getSecond().IsAmbiguous); + fullp->setPropertyValue( + OUString("Second"), + css::uno::Any()); + CPPUNIT_ASSERT_EQUAL( + voidAny, + fullp->getPropertyValue( + OUString("Second"))); + CPPUNIT_ASSERT(!full->getSecond().Value.Value.IsPresent); + CPPUNIT_ASSERT(!full->getSecond().Value.IsDefaulted); + CPPUNIT_ASSERT(!full->getSecond().IsAmbiguous); + try { + fullp->setPropertyValue( + OUString("Third"), + css::uno::Any(static_cast< sal_Int32 >(100))); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->getPropertyValue( + OUString("Third")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->setPropertyValue( + OUString("Fourth"), + css::uno::Any(static_cast< sal_Int32 >(100))); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->getPropertyValue( + OUString("Fourth")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->setPropertyValue( + OUString("first"), + css::uno::Any()); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->getPropertyValue( + OUString("first")); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + css::uno::Reference< css::beans::XFastPropertySet > fullf( + full, css::uno::UNO_QUERY); + CPPUNIT_ASSERT(fullf.is()); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(-100)), + fullf->getFastPropertyValue(0)); + fullf->setFastPropertyValue( + 0, css::uno::Any(static_cast< sal_Int32 >(0))); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(0)), + fullf->getFastPropertyValue(0)); + try { + fullf->getFastPropertyValue(-1); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullf->setFastPropertyValue(-1, css::uno::Any()); + } catch (css::beans::UnknownPropertyException &) {} + css::uno::Reference< css::beans::XPropertyAccess > fulla( + full, css::uno::UNO_QUERY); + CPPUNIT_ASSERT(fulla.is()); + css::uno::Sequence< css::beans::PropertyValue > vs( + fulla->getPropertyValues()); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(2), vs.getLength()); + CPPUNIT_ASSERT_EQUAL( + OUString("First"), vs[0].Name); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(0), vs[0].Handle); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(0)), vs[0].Value); + CPPUNIT_ASSERT_EQUAL(css::beans::PropertyState_DIRECT_VALUE, vs[0].State); + CPPUNIT_ASSERT_EQUAL( + OUString("Second"), vs[1].Name); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(1), vs[1].Handle); + CPPUNIT_ASSERT_EQUAL(voidAny, vs[1].Value); + CPPUNIT_ASSERT_EQUAL(css::beans::PropertyState_DIRECT_VALUE, vs[1].State); + vs[0].Value <<= static_cast< sal_Int32 >(-100); + vs[1].Value <<= static_cast< sal_Int32 >(100); + vs[1].State = css::beans::PropertyState_AMBIGUOUS_VALUE; + fulla->setPropertyValues(vs); + vs = fulla->getPropertyValues(); + CPPUNIT_ASSERT_EQUAL(static_cast< sal_Int32 >(2), vs.getLength()); + CPPUNIT_ASSERT_EQUAL( + OUString("First"), vs[0].Name); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(-100)), vs[0].Value); + CPPUNIT_ASSERT_EQUAL(css::beans::PropertyState_DIRECT_VALUE, vs[0].State); + CPPUNIT_ASSERT_EQUAL( + OUString("Second"), vs[1].Name); + CPPUNIT_ASSERT_EQUAL( + css::uno::Any(static_cast< sal_Int32 >(100)), vs[1].Value); + CPPUNIT_ASSERT_EQUAL( + css::beans::PropertyState_AMBIGUOUS_VALUE, vs[1].State); + CPPUNIT_ASSERT(full->getSecond().Value.Value.IsPresent); + CPPUNIT_ASSERT_EQUAL( + static_cast< sal_Int32 >(100), full->getSecond().Value.Value.Value); + CPPUNIT_ASSERT(!full->getSecond().Value.IsDefaulted); + CPPUNIT_ASSERT(full->getSecond().IsAmbiguous); + css::uno::Reference< css::beans::XPropertyChangeListener > boundListener( + new BoundListener); + fullp->addPropertyChangeListener( + OUString("First"), boundListener); + fullp->removePropertyChangeListener( + OUString("First"), boundListener); + fullp->addPropertyChangeListener( + OUString("Second"), boundListener); + fullp->removePropertyChangeListener( + OUString("Second"), boundListener); + try { + fullp->addPropertyChangeListener( + OUString("Third"), + boundListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->removePropertyChangeListener( + OUString("Third"), + boundListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + fullp->addPropertyChangeListener( + OUString("Fourth"), boundListener); + fullp->removePropertyChangeListener( + OUString("Fourth"), boundListener); + try { + fullp->addPropertyChangeListener( + OUString("Fifth"), + boundListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->removePropertyChangeListener( + OUString("Fifth"), + boundListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + css::uno::Reference< css::beans::XVetoableChangeListener > vetoListener( + new VetoListener); + fullp->addVetoableChangeListener( + OUString("First"), vetoListener); + fullp->removeVetoableChangeListener( + OUString("First"), vetoListener); + fullp->addVetoableChangeListener( + OUString("Second"), vetoListener); + fullp->removeVetoableChangeListener( + OUString("Second"), vetoListener); + try { + fullp->addVetoableChangeListener( + OUString("Third"), + vetoListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->removeVetoableChangeListener( + OUString("Third"), + vetoListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + fullp->addVetoableChangeListener( + OUString("Fourth"), vetoListener); + fullp->removeVetoableChangeListener( + OUString("Fourth"), vetoListener); + try { + fullp->addVetoableChangeListener( + OUString("Fifth"), + vetoListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} + try { + fullp->removeVetoableChangeListener( + OUString("Fifth"), + vetoListener); + CPPUNIT_FAIL("exception expected"); + } catch (css::beans::UnknownPropertyException &) {} +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/qa/propertysetmixin/types.idl b/cppuhelper/qa/propertysetmixin/types.idl new file mode 100644 index 000000000..ee1958032 --- /dev/null +++ b/cppuhelper/qa/propertysetmixin/types.idl @@ -0,0 +1,79 @@ +/* -*- 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 . + */ + +#ifndef __testtools_servicetests_TestService1_idl__ +#define __testtools_servicetests_TestService1_idl__ + +#include <com/sun/star/beans/Ambiguous.idl> +#include <com/sun/star/beans/Defaulted.idl> +#include <com/sun/star/beans/Optional.idl> +#include <com/sun/star/beans/PropertyVetoException.idl> +#include <com/sun/star/beans/UnknownPropertyException.idl> +#include <com/sun/star/lang/XComponent.idl> +#include <com/sun/star/uno/XInterface.idl> + +module test { module cppuhelper { module propertysetmixin { + +interface XTest1 { + [attribute] long First; +}; + +interface XTest2 { + [attribute, bound] + com::sun::star::beans::Ambiguous< + com::sun::star::beans::Defaulted< + com::sun::star::beans::Optional< long > > > Second + { + get raises (com::sun::star::beans::UnknownPropertyException); + set raises ( + com::sun::star::beans::PropertyVetoException, + com::sun::star::beans::UnknownPropertyException); + }; +}; + +interface XTest3 { + interface XTest1; + interface XTest2; + [attribute] long Third { + get raises (com::sun::star::beans::UnknownPropertyException); + set raises (com::sun::star::beans::UnknownPropertyException); + }; + [attribute] long Fourth { + get raises (com::sun::star::beans::UnknownPropertyException); + set raises (com::sun::star::beans::UnknownPropertyException); + }; +}; + +interface XSupplier { + com::sun::star::lang::XComponent getEmpty1(); + + com::sun::star::lang::XComponent getEmpty2(); + + XTest3 getFull(); +}; + +service CppSupplier: XSupplier; + +service JavaSupplier: XSupplier; + +}; }; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/qa/sce/test_unourl.sce b/cppuhelper/qa/sce/test_unourl.sce new file mode 100644 index 000000000..d937ca311 --- /dev/null +++ b/cppuhelper/qa/sce/test_unourl.sce @@ -0,0 +1 @@ +UnoUrl diff --git a/cppuhelper/qa/unourl/cppu_unourl.cxx b/cppuhelper/qa/unourl/cppu_unourl.cxx new file mode 100644 index 000000000..1a9ba70f7 --- /dev/null +++ b/cppuhelper/qa/unourl/cppu_unourl.cxx @@ -0,0 +1,473 @@ +/* -*- 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 <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <cppuhelper/unourl.hxx> +#include <rtl/malformeduriexception.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +namespace cppu_unourl +{ + class UrlTest : public CppUnit::TestFixture + { + public: + void testDescriptorParsing() + { + struct Test + { + char const * pInput; + bool bValid; + }; + static Test const aTests[] + = { { "", false }, + { "abc", true }, + { "Abc", true }, + { "aBC", true }, + { "ABC", true }, + { "1abc", true }, + { "123", true }, + { "abc-1", false }, + { "ab%63", false }, + { "abc,", false }, + { "abc,def=", true }, + { "abc,Def=", true }, + { "abc,DEF=", true }, + { "abc,1def=", true }, + { "abc,123=", true }, + { "abc,def-1=", false }, + { "abc,def", false }, + { "abc,def=xxx,def=xxx", false }, + { "abc,def=xxx,ghi=xxx", true }, + { "abc,,def=xxx", false }, + { "abc,def=xxx,,ghi=xxx", false }, + { "abc,def=xxx,ghi=xxx,", false }, + { "abc,def=%", true }, + { "abc,def=%1", true }, + { "abc,def=%00", true }, + { "abc,def=%22", true }, + { "abc,def=\"", true }, + { "abc,def=%ed%a0%80", true } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + try + { + cppu::UnoUrlDescriptor aDescriptor(OUString::createFromAscii( + aTests[i].pInput)); + (void)aDescriptor; + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + + if (aTests[i].bValid) + { + CPPUNIT_ASSERT_MESSAGE("Valid uri parsed as invalid", bValid); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Invalid uri parsed as valid", !bValid); + } + } + } + + void testDescriptorDescriptor() + { + struct Test + { + char const * pInput; + char const * pDescriptor; + }; + static Test const aTests[] + = {{ "abc", "abc" }, + { "Abc", "Abc" }, + { "aBC", "aBC" }, + { "ABC", "ABC" }, + { "1abc", "1abc" }, + { "123", "123" }, + { "abc,def=", "abc,def=" }, + { "abc,Def=", "abc,Def=" }, + { "abc,DEF=", "abc,DEF=" }, + { "abc,1def=", "abc,1def=" }, + { "abc,123=", "abc,123=" }, + { "abc,def=xxx,ghi=xxx", "abc,def=xxx,ghi=xxx" }, + { "abc,def=%", "abc,def=%" }, + { "abc,def=%1", "abc,def=%1" }, + { "abc,def=%00", "abc,def=%00" }, + { "abc,def=%22", "abc,def=%22" }, + { "abc,def=\"", "abc,def=\"" }, + { "abc,def=%ed%a0%80", "abc,def=%ed%a0%80" } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + OUString aDescriptor; + try + { + aDescriptor = cppu::UnoUrlDescriptor(OUString::createFromAscii( + aTests[i].pInput)). + getDescriptor(); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI correctly", + aDescriptor.equalsAscii( + aTests[i].pDescriptor)); + } + } + + + void testDescriptorName() + { + struct Test + { + char const * pInput; + char const * pName; + }; + static Test const aTests[] + = { { "abc", "abc" }, + { "Abc", "abc" }, + { "aBC", "abc" }, + { "ABC", "abc" }, + { "1abc", "1abc" }, + { "123", "123" }, + { "abc,def=", "abc" }, + { "abc,Def=", "abc" }, + { "abc,DEF=", "abc" }, + { "abc,1def=", "abc" }, + { "abc,123=", "abc" }, + { "abc,def=xxx,ghi=xxx", "abc" }, + { "abc,def=%", "abc" }, + { "abc,def=%1", "abc" }, + { "abc,def=%00", "abc" }, + { "abc,def=%22", "abc" }, + { "abc,def=\"", "abc" }, + { "abc,def=%ed%a0%80", "abc" } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + OUString aName; + try + { + aName = cppu::UnoUrlDescriptor(OUString::createFromAscii( + aTests[i].pInput)).getName(); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI correctly", + aName.equalsAscii(aTests[i].pName)); + } + } + + void testDescriptorKey() + { + struct Test + { + char const * pInput; + char const * pKey; + bool bPresent; + }; + static Test const aTests[] + = { { "abc", "abc", false }, + { "abc", "def", false }, + { "1abc", "def", false }, + { "123", "def", false }, + { "abc,def=", "abc", false }, + { "abc,def=", "def", true }, + { "abc,def=", "defg", false }, + { "abc,def=", "de", false }, + { "abc,def=", "ghi", false }, + { "abc,Def=", "def", true }, + { "abc,Def=", "Def", true }, + { "abc,Def=", "dEF", true }, + { "abc,Def=", "DEF", true }, + { "abc,def=xxx,ghi=xxx", "abc", false }, + { "abc,def=xxx,ghi=xxx", "def", true }, + { "abc,def=xxx,ghi=xxx", "ghi", true }, + { "abc,def=xxx,ghi=xxx", "jkl", false } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + bool bPresent = false; + try + { + bPresent = cppu::UnoUrlDescriptor(OUString::createFromAscii( + aTests[i].pInput)). + hasParameter(OUString::createFromAscii(aTests[i].pKey)); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Failed to detect parameter correctly", + aTests[i].bPresent, bPresent); + } + } + + void testDescriptorValue() + { + struct Test + { + char const * pInput; + char const * pKey; + char const * pValue; + }; + static Test const aTests[] + = { { "abc", "abc", "" }, + { "abc", "def", "" }, + { "1abc", "def", "" }, + { "123", "def", "" }, + { "abc,def=", "abc", "" }, + { "abc,def=", "def", "" }, + { "abc,def=", "defg", "" }, + { "abc,def=", "de", "" }, + { "abc,def=", "ghi", "" }, + { "abc,Def=", "def", "" }, + { "abc,Def=", "Def", "" }, + { "abc,Def=", "dEF", "" }, + { "abc,Def=", "DEF", "" }, + { "abc,def=xxx,ghi=xxx", "abc", "" }, + { "abc,def=xxx,ghi=xxx", "def", "xxx" }, + { "abc,def=xxx,ghi=xxx", "ghi", "xxx" }, + { "abc,def=xxx,ghi=xxx", "jkl", "" }, + { "abc,def=%", "def", "%" }, + { "abc,def=%1", "def", "%1" }, + { "abc,def=%22", "def", "\"" }, + { "abc,def=\"", "def", "\"" }, + { "abc,def=abc", "def", "abc" }, + { "abc,def=Abc", "def", "Abc" }, + { "abc,def=aBC", "def", "aBC" }, + { "abc,def=ABC", "def", "ABC" }, + { "abc,def=%,ghi=", "def", "%" }, + { "abc,def=%1,ghi=", "def", "%1" }, + { "abc,def=%22,ghi=", "def", "\"" }, + { "abc,def=\",ghi=", "def", "\"" }, + { "abc,def=abc,ghi=", "def", "abc" }, + { "abc,def=Abc,ghi=", "def", "Abc" }, + { "abc,def=aBC,ghi=", "def", "aBC" }, + { "abc,def=ABC,ghi=", "def", "ABC" }, + { "abc,abc=,def=%", "def", "%" }, + { "abc,abc=,def=%1", "def", "%1" }, + { "abc,abc=,def=%22", "def", "\"" }, + { "abc,abc=,def=\"", "def", "\"" }, + { "abc,abc=,def=abc", "def", "abc" }, + { "abc,abc=,def=Abc", "def", "Abc" }, + { "abc,abc=,def=aBC", "def", "aBC" }, + { "abc,abc=,def=ABC", "def", "ABC" } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + OUString aValue; + try + { + aValue = cppu::UnoUrlDescriptor(OUString::createFromAscii( + aTests[i].pInput)). + getParameter(OUString::createFromAscii(aTests[i].pKey)); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_MESSAGE("Failed to get param correctly", + aValue.equalsAscii(aTests[i].pValue)); + } + } + + void testUrlParsing() + { + struct Test + { + char const * pInput; + bool bValid; + }; + static Test const aTests[] + = { { "", false }, + { "abc", false }, + { "uno", false }, + { "uno:", false }, + { "uno:abc;def;ghi", true }, + { "Uno:abc;def;ghi", true }, + { "uNO:abc;def;ghi", true }, + { "UNO:abc;def;ghi", true }, + { "uno:abc,def=xxx,ghi=xxx;def,ghi=xxx,jkl=xxx;ghi", true }, + { "uno:abc,def=xxx,ghi=xxx;def,ghi=xxx,jkl=xxx,;ghi", false }, + { "uno:abc;def;", false }, + { "uno:abc;def;a", true }, + { "uno:abc;def;A", true }, + { "uno:abc;def;1", true }, + { "uno:abc;def;$&+,/:=?@", true }, + { "uno:abc;def;%24&+,/:=?@", false } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + try + { + cppu::UnoUrl aUrl(OUString::createFromAscii(aTests[i].pInput)); + (void)aUrl; + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + + if (aTests[i].bValid) + { + CPPUNIT_ASSERT_MESSAGE("Valid uri parsed as invalid", bValid); + } + else + { + CPPUNIT_ASSERT_MESSAGE("Invalid uri parsed as valid", !bValid); + } + + } + } + + void testUrlConnection() + { + struct Test + { + char const * pInput; + char const * pConnection; + }; + static Test const aTests[] + = { { "uno:abc;def;ghi", "abc" }, + { "uno:Abc;def;ghi", "Abc" }, + { "uno:aBC;def;ghi", "aBC" }, + { "uno:ABC;def;ghi", "ABC" }, + { "uno:abc,def=xxx,ghi=xxx;def,ghi=xxx,jkl=xxx;ghi", + "abc,def=xxx,ghi=xxx" } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + OUString aConnection; + try + { + aConnection = cppu::UnoUrl(OUString::createFromAscii( + aTests[i].pInput)). + getConnection().getDescriptor(); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_MESSAGE("Failed to get param correctly", + aConnection.equalsAscii( + aTests[i].pConnection)); + } + } + + void testUrlProtocol() + { + struct Test + { + char const * pInput; + char const * pProtocol; + }; + static Test const aTests[] + = { { "uno:abc;def;ghi", "def" }, + { "uno:abc;Def;ghi", "Def" }, + { "uno:abc;dEF;ghi", "dEF" }, + { "uno:abc;DEF;ghi", "DEF" }, + { "uno:abc,def=xxx,ghi=xxx;def,ghi=xxx,jkl=xxx;ghi", + "def,ghi=xxx,jkl=xxx" } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + OUString aProtocol; + try + { + aProtocol = cppu::UnoUrl(OUString::createFromAscii( + aTests[i].pInput)). + getProtocol().getDescriptor(); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_MESSAGE("Failed to get protocol correctly", + aProtocol.equalsAscii( + aTests[i].pProtocol)); + } + } + + void testUrlObjectName() + { + struct Test + { + char const * pInput; + char const * pObjectName; + }; + static Test const aTests[] + = { { "uno:abc;def;ghi", "ghi" }, + { "uno:abc;def;Ghi", "Ghi" }, + { "uno:abc;def;gHI", "gHI" }, + { "uno:abc;def;GHI", "GHI" }, + { "uno:abc,def=xxx,ghi=xxx;def,ghi=xxx,jkl=xxx;ghi", "ghi" }, + { "uno:abc;def;a", "a" }, + { "uno:abc;def;A", "A" }, + { "uno:abc;def;1", "1" }, + { "uno:abc;def;$&+,/:=?@", "$&+,/:=?@" } }; + for (size_t i = 0; i < SAL_N_ELEMENTS(aTests); ++i) + { + bool bValid = false; + OUString aObjectName; + try + { + aObjectName = cppu::UnoUrl(OUString::createFromAscii( + aTests[i].pInput)).getObjectName(); + bValid = true; + } + catch (rtl::MalformedUriException &) + {} + CPPUNIT_ASSERT_MESSAGE("Failed to parse URI", bValid); + CPPUNIT_ASSERT_MESSAGE("Failed to get protocol correctly", + aObjectName.equalsAscii( + aTests[i].pObjectName)); + } + } + + // Automatic registration code + CPPUNIT_TEST_SUITE(UrlTest); + CPPUNIT_TEST(testDescriptorParsing); + CPPUNIT_TEST(testDescriptorDescriptor); + CPPUNIT_TEST(testDescriptorName); + CPPUNIT_TEST(testDescriptorKey); + CPPUNIT_TEST(testDescriptorValue); + CPPUNIT_TEST(testUrlParsing); + CPPUNIT_TEST(testUrlConnection); + CPPUNIT_TEST(testUrlProtocol); + CPPUNIT_TEST(testUrlObjectName); + CPPUNIT_TEST_SUITE_END(); + }; +} // namespace cppu_ifcontainer + +CPPUNIT_TEST_SUITE_REGISTRATION(cppu_unourl::UrlTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/qa/weak/test_weak.cxx b/cppuhelper/qa/weak/test_weak.cxx new file mode 100644 index 000000000..e37131c9f --- /dev/null +++ b/cppuhelper/qa/weak/test_weak.cxx @@ -0,0 +1,99 @@ +/* -*- 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 <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/XAdapter.hpp> +#include <com/sun/star/uno/XReference.hpp> +#include <com/sun/star/uno/XWeak.hpp> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/weak.hxx> +#include <rtl/ref.hxx> +#include <sal/types.h> + +namespace { + +class Reference: public cppu::WeakImplHelper< css::uno::XReference > { +public: + Reference(): m_disposed(false) {} + + void SAL_CALL dispose() override { + m_disposed = true; + handleDispose(); + } + + bool isDisposed() const { return m_disposed; } + +protected: + virtual void handleDispose() {}; + +private: + bool m_disposed; +}; + +class RuntimeExceptionReference: public Reference { +protected: + void handleDispose() override { + throw css::uno::RuntimeException(); + } +}; + +class DisposedExceptionReference: public Reference { +protected: + void handleDispose() override { + throw css::lang::DisposedException(); + } +}; + +class Test: public ::CppUnit::TestFixture { +public: + void testReferenceDispose(); + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testReferenceDispose); + CPPUNIT_TEST_SUITE_END(); +}; + +void Test::testReferenceDispose() { + css::uno::Reference< css::uno::XWeak > w(new ::cppu::OWeakObject); + css::uno::Reference< css::uno::XAdapter > a(w->queryAdapter()); + ::rtl::Reference< Reference > r1(new RuntimeExceptionReference); + ::rtl::Reference< Reference > r2(new Reference); + ::rtl::Reference< Reference > r3(new DisposedExceptionReference); + a->addReference(r1.get()); + a->addReference(r2.get()); + a->addReference(r3.get()); + w.clear(); + CPPUNIT_ASSERT(r1->isDisposed()); + CPPUNIT_ASSERT(r2->isDisposed()); + CPPUNIT_ASSERT(r3->isDisposed()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Test); + +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/access_control.cxx b/cppuhelper/source/access_control.cxx new file mode 100644 index 000000000..0e18ef786 --- /dev/null +++ b/cppuhelper/source/access_control.cxx @@ -0,0 +1,131 @@ +/* -*- 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 <cppuhelper/access_control.hxx> + +#include <com/sun/star/security/XAccessController.hpp> +#include <com/sun/star/security/RuntimePermission.hpp> +#include <com/sun/star/io/FilePermission.hpp> +#include <com/sun/star/connection/SocketPermission.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace +{ + OUString str_ac_singleton() + { + return "/singletons/com.sun.star.security.theAccessController"; + } +} + +namespace cppu +{ + +AccessControl::AccessControl( Reference< XComponentContext > const & xContext ) +{ + if (! (xContext->getValueByName( str_ac_singleton() ) >>= m_xController)) + { + throw SecurityException( "no access controller!" ); + } +} + +AccessControl::AccessControl( + Reference< security::XAccessController > const & xController ) + : m_xController( xController ) +{ + if (! m_xController.is()) + { + throw SecurityException( "no access controller!" ); + } +} + +AccessControl::AccessControl( AccessControl const & ac ) + : m_xController( ac.m_xController ) +{ + if (! m_xController.is()) + { + throw SecurityException( "no access controller!" ); + } +} + +namespace { + +#ifdef _WIN32 +#pragma pack(push, 8) +#endif + // binary comp. to all Permission structs + struct permission + { + rtl_uString * m_str1; + rtl_uString * m_str2; + }; +#ifdef _WIN32 +#pragma pack(pop) +#endif + +void checkPermission( + Reference< security::XAccessController > const & xController, + Type const & type, rtl_uString * str1, rtl_uString * str2 ) +{ + permission perm; + perm.m_str1 = str1; + perm.m_str2 = str2; + + uno_Any a; + a.pType = type.getTypeLibType(); + a.pData = &perm; + + xController->checkPermission( * static_cast< Any * >( &a ) ); +} + +} + +void AccessControl::checkRuntimePermission( + OUString const & name ) +{ + checkPermission( + m_xController, + cppu::UnoType<security::RuntimePermission>::get(), name.pData, nullptr ); +} + +void AccessControl::checkFilePermission( + OUString const & url, + OUString const & actions ) +{ + checkPermission( + m_xController, + cppu::UnoType<io::FilePermission>::get(), url.pData, actions.pData ); +} + +void AccessControl::checkSocketPermission( + OUString const & host, + OUString const & actions ) +{ + checkPermission( + m_xController, + cppu::UnoType<connection::SocketPermission>::get(), host.pData, actions.pData ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/bootstrap.cxx b/cppuhelper/source/bootstrap.cxx new file mode 100644 index 000000000..34ae38823 --- /dev/null +++ b/cppuhelper/source/bootstrap.cxx @@ -0,0 +1,242 @@ +/* -*- 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 <chrono> +#include <cstring> + +#include <rtl/bootstrap.hxx> +#include <rtl/random.h> +#include <rtl/ustrbuf.hxx> +#include <rtl/uri.hxx> +#include <osl/file.hxx> +#include <osl/security.hxx> +#include <osl/thread.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <osl/process.h> + +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/findsofficepath.h> + +#include <com/sun/star/bridge/UnoUrlResolver.hpp> +#include <com/sun/star/bridge/XUnoUrlResolver.hpp> + +#include "macro_expander.hxx" + +namespace com :: sun :: star :: uno { class XComponentContext; } + +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using rtl::Bootstrap; + +namespace cppu +{ + +BootstrapException::BootstrapException() +{ +} + +BootstrapException::BootstrapException( const OUString & rMessage ) + :m_aMessage( rMessage ) +{ +} + +BootstrapException::BootstrapException( const BootstrapException & e ) +{ + m_aMessage = e.m_aMessage; +} + +BootstrapException::~BootstrapException() +{ +} + +BootstrapException & BootstrapException::operator=( const BootstrapException & e ) +{ + m_aMessage = e.m_aMessage; + return *this; +} + +const OUString & BootstrapException::getMessage() const +{ + return m_aMessage; +} + +Reference< XComponentContext > SAL_CALL bootstrap() +{ + Reference< XComponentContext > xRemoteContext; + + try + { + auto* p1 = cppuhelper_detail_findSofficePath(); + if (p1 == nullptr) { + throw BootstrapException( + "no soffice installation found!"); + } + OUString p2; +#if defined(_WIN32) + p2 = o3tl::toU(p1); + free(p1); +#else + bool bOk = rtl_convertStringToUString( + &p2.pData, p1, std::strlen(p1), osl_getThreadTextEncoding(), + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR | + RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)); + free(p1); + if (!bOk) + { + throw BootstrapException( + "bad characters in soffice installation path!"); + } +#endif + OUString path; + if (osl::FileBase::getFileURLFromSystemPath(p2, path) != + osl::FileBase::E_None) + { + throw BootstrapException( + "cannot convert soffice installation path to URL!"); + } + if (!path.isEmpty() && !path.endsWith("/")) { + path += "/"; + } + + OUString uri; + if (!Bootstrap::get("URE_BOOTSTRAP", uri)) { + Bootstrap::set( + "URE_BOOTSTRAP", + Bootstrap::encode( + path + +#if defined MACOSX + "../Resources/" +#endif + SAL_CONFIGFILE("fundamental"))); + } + + // create default local component context + Reference< XComponentContext > xLocalContext( + defaultBootstrap_InitialComponentContext() ); + if ( !xLocalContext.is() ) + throw BootstrapException( "no local component context!" ); + + // create a random pipe name + rtlRandomPool hPool = rtl_random_createPool(); + if ( hPool == nullptr ) + throw BootstrapException( "cannot create random pool!" ); + sal_uInt8 bytes[ 16 ]; + if ( rtl_random_getBytes( hPool, bytes, SAL_N_ELEMENTS( bytes ) ) + != rtl_Random_E_None ) + throw BootstrapException( "random pool error!" ); + rtl_random_destroyPool( hPool ); + OUStringBuffer buf("uno"); + for (unsigned char byte : bytes) + buf.append( static_cast< sal_Int32 >( byte ) ); + OUString sPipeName( buf.makeStringAndClear() ); + + // arguments + OUString args [] = { + OUString("--nologo"), + OUString("--nodefault"), + OUString("--norestore"), + OUString("--nolockcheck"), + OUString("--accept=pipe,name=" + sPipeName + ";urp;") + }; + rtl_uString * ar_args [] = { + args[ 0 ].pData, + args[ 1 ].pData, + args[ 2 ].pData, + args[ 3 ].pData, + args[ 4 ].pData + }; + ::osl::Security sec; + + // start office process + oslProcess hProcess = nullptr; + oslProcessError rc = osl_executeProcess( + OUString(path + "soffice").pData, ar_args, SAL_N_ELEMENTS( ar_args ), + osl_Process_DETACHED, + sec.getHandle(), + nullptr, // => current working dir + nullptr, 0, // => no env vars + &hProcess ); + switch ( rc ) + { + case osl_Process_E_None: + osl_freeProcessHandle( hProcess ); + break; + case osl_Process_E_NotFound: + throw BootstrapException( "image not found!" ); + case osl_Process_E_TimedOut: + throw BootstrapException( "timeout occurred!" ); + case osl_Process_E_NoPermission: + throw BootstrapException( "permission denied!" ); + case osl_Process_E_Unknown: + throw BootstrapException( "unknown error!" ); + case osl_Process_E_InvalidError: + default: + throw BootstrapException( "unmapped error!" ); + } + + // create a URL resolver + Reference< bridge::XUnoUrlResolver > xUrlResolver( + bridge::UnoUrlResolver::create( xLocalContext ) ); + + // connection string + OUString sConnectString( "uno:pipe,name=" + sPipeName + ";urp;StarOffice.ComponentContext" ); + + // wait until office is started + for ( ; ; ) + { + try + { + // try to connect to office + xRemoteContext.set( + xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW ); + break; + } + catch ( connection::NoConnectException & ) + { + // wait 500 ms, then try to connect again + ::osl::Thread::wait( std::chrono::milliseconds(500) ); + } + } + } + catch ( Exception & e ) + { + throw BootstrapException( + "unexpected UNO exception caught: " + e.Message ); + } + + return xRemoteContext; +} + +OUString bootstrap_expandUri(OUString const & uri) { + OUString rest; + return uri.startsWith("vnd.sun.star.expand:", &rest) + ? cppuhelper::detail::expandMacros( + rtl::Uri::decode( + rest, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8)) + : uri; +} + +} // namespace cppu + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/compat.cxx b/cppuhelper/source/compat.cxx new file mode 100644 index 000000000..f6572ea47 --- /dev/null +++ b/cppuhelper/source/compat.cxx @@ -0,0 +1,172 @@ +/* -*- 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 <cstdlib> + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <osl/module.h> +#include <sal/types.h> + +namespace com::sun::star { + namespace lang { + class XMultiComponentFactory; + class XMultiServiceFactory; + class XTypeProvider; + } + namespace reflection { class XIdlClass; } + namespace registry { + class XRegistryKey; + class XSimpleRegistry; + } + namespace uno { + class XComponentContext; + class XInterface; + } +} + +// Stubs for removed functionality, to be killed when we bump cppuhelper SONAME + +namespace cppu { + +SAL_DLLPUBLIC_EXPORT +css::uno::Reference< css::lang::XMultiComponentFactory > bootstrapInitialSF( + OUString const &) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::uno::Reference< css::uno::XComponentContext > SAL_CALL +bootstrap_InitialComponentContext( + css::uno::Reference< css::registry::XSimpleRegistry > const &, + OUString const &) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::uno::Reference< css::registry::XSimpleRegistry > +SAL_CALL createNestedRegistry(OUString const &) { + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::uno::Reference< css::lang::XMultiServiceFactory > +SAL_CALL createRegistryServiceFactory( + OUString const &, OUString const &, sal_Bool, + OUString const &) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::uno::Reference< css::registry::XSimpleRegistry > +SAL_CALL createSimpleRegistry(OUString const &) { + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::reflection::XIdlClass * SAL_CALL +createStandardClassWithSequence( + css::uno::Reference< css::lang::XMultiServiceFactory > const &, + OUString const &, + css::uno::Reference< css::reflection::XIdlClass > const &, + css::uno::Sequence< OUString > const &) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::uno::Reference<css::uno::XInterface> SAL_CALL +invokeStaticComponentFactory( + oslGenericFunction, OUString const &, + css::uno::Reference<css::lang::XMultiServiceFactory> const &, + css::uno::Reference<css::registry::XRegistryKey> const &, + OUString const &) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +SAL_DLLPUBLIC_EXPORT css::uno::Reference<css::uno::XInterface> SAL_CALL +loadSharedLibComponentFactory( + OUString const &, OUString const &, OUString const &, + css::uno::Reference<css::lang::XMultiServiceFactory> const &, + css::uno::Reference<css::registry::XRegistryKey> const &, + OUString const &) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +struct SAL_DLLPUBLIC_EXPORT ClassData { + css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId(); + + css::uno::Sequence<css::uno::Type> SAL_CALL getTypes(); + + void SAL_CALL initTypeProvider(); + + css::uno::Any SAL_CALL query( + css::uno::Type const &, css::lang::XTypeProvider *); + + void SAL_CALL writeTypeOffset(css::uno::Type const &, sal_Int32); +}; + +css::uno::Sequence<sal_Int8> ClassData::getImplementationId() { + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +css::uno::Sequence<css::uno::Type> ClassData::getTypes() { + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +void ClassData::initTypeProvider() { + std::abort(); +} + +css::uno::Any ClassData::query( + css::uno::Type const &, css::lang::XTypeProvider *) +{ + for (;;) { std::abort(); } // avoid "must return a value" warnings +} + +void ClassData::writeTypeOffset(css::uno::Type const &, sal_Int32) { + std::abort(); +} + +SAL_WNOUNREACHABLE_CODE_PUSH +struct SAL_DLLPUBLIC_EXPORT ClassDataBase { + ClassDataBase(); + + explicit ClassDataBase(sal_Int32); + + ~ClassDataBase(); +}; + +ClassDataBase::ClassDataBase() { + std::abort(); +} + +ClassDataBase::ClassDataBase(sal_Int32) { + std::abort(); +} + +ClassDataBase::~ClassDataBase() { + std::abort(); +} +SAL_WNOUNREACHABLE_CODE_POP + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/component.cxx b/cppuhelper/source/component.cxx new file mode 100644 index 000000000..c88713287 --- /dev/null +++ b/cppuhelper/source/component.cxx @@ -0,0 +1,223 @@ +/* -*- 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 <osl/diagnose.h> +#include <sal/log.hxx> +#include <cppuhelper/component.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/typeprovider.hxx> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> + +using namespace osl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +namespace cppu +{ + + +// class OComponentHelper + + +OComponentHelper::OComponentHelper( Mutex & rMutex ) + : rBHelper( rMutex ) +{ +} +OComponentHelper::~OComponentHelper() +{ +} + +Any OComponentHelper::queryInterface( Type const & rType ) +{ + return OWeakAggObject::queryInterface( rType ); +} +Any OComponentHelper::queryAggregation( Type const & rType ) +{ + if (rType == cppu::UnoType<lang::XComponent>::get()) + { + void * p = static_cast< lang::XComponent * >( this ); + return Any( &p, rType ); + } + if (rType == cppu::UnoType<lang::XTypeProvider>::get()) + { + void * p = static_cast< lang::XTypeProvider * >( this ); + return Any( &p, rType ); + } + return OWeakAggObject::queryAggregation( rType ); +} +void OComponentHelper::acquire() throw () +{ + OWeakAggObject::acquire(); +} + +void OComponentHelper::release() throw() +{ + Reference<XInterface > x( xDelegator ); + if (! x.is()) + { + if (osl_atomic_decrement( &m_refCount ) == 0) + { + if (! rBHelper.bDisposed) + { + // *before* again incrementing our ref count, ensure that our weak connection point + // will not create references to us anymore (via XAdapter::queryAdapted) + disposeWeakConnectionPoint(); + + Reference<XInterface > xHoldAlive( *this ); + // First dispose + try + { + dispose(); + } + catch (css::uno::RuntimeException & exc) + { + // release should not throw exceptions + SAL_WARN( "cppuhelper", exc ); + } + + // only the alive ref holds the object + OSL_ASSERT( m_refCount == 1 ); + // destroy the object if xHoldAlive decrement the refcount to 0 + return; + } + } + // restore the reference count + osl_atomic_increment( &m_refCount ); + } + OWeakAggObject::release(); +} + +Sequence< Type > OComponentHelper::getTypes() +{ + static OTypeCollection s_aTypes( + cppu::UnoType<lang::XComponent>::get(), + cppu::UnoType<lang::XTypeProvider>::get(), + cppu::UnoType<XAggregation>::get(), + cppu::UnoType<XWeak>::get() ); + + return s_aTypes.getTypes(); +} + +// XComponent +void OComponentHelper::disposing() +{ +} + +// XComponent +void OComponentHelper::dispose() +{ + // An frequently programming error is to release the last + // reference to this object in the disposing message. + // Make it robust, hold a self Reference. + Reference<XComponent > xSelf( this ); + + // Guard dispose against multiple threading + // Remark: It is an error to call dispose more than once + bool bDoDispose = false; + { + MutexGuard aGuard( rBHelper.rMutex ); + if( !rBHelper.bDisposed && !rBHelper.bInDispose ) + { + // only one call go into this section + rBHelper.bInDispose = true; + bDoDispose = true; + } + } + + // Do not hold the mutex because we are broadcasting + if( bDoDispose ) + { + // Create an event with this as sender + try + { + try + { + Reference<XInterface > xSource( + Reference<XInterface >::query( static_cast<XComponent *>(this) ) ); + EventObject aEvt; + aEvt.Source = xSource; + // inform all listeners to release this object + // The listener container are automatically cleared + rBHelper.aLC.disposeAndClear( aEvt ); + // notify subclasses to do their dispose + disposing(); + } + catch (...) + { + MutexGuard aGuard( rBHelper.rMutex ); + // bDispose and bInDisposing must be set in this order: + rBHelper.bDisposed = true; + rBHelper.bInDispose = false; + throw; + } + MutexGuard aGuard( rBHelper.rMutex ); + // bDispose and bInDisposing must be set in this order: + rBHelper.bDisposed = true; + rBHelper.bInDispose = false; + } + catch (RuntimeException &) + { + throw; + } + catch (Exception & exc) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException( + "unexpected UNO exception caught: " + exc.Message, + nullptr, anyEx ); + } + } + else + { + // in a multithreaded environment, it can't be avoided + // that dispose is called twice. + // However this condition is traced, because it MAY indicate an error. + SAL_WARN("cppuhelper", "OComponentHelper::dispose() - dispose called twice" ); + } +} + +// XComponent +void OComponentHelper::addEventListener( + const Reference<XEventListener > & rxListener ) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + Reference< XInterface > x( static_cast<XComponent *>(this), UNO_QUERY ); + rxListener->disposing( EventObject( x ) ); + } + else + { + rBHelper.addListener( cppu::UnoType<decltype(rxListener)>::get(), rxListener ); + } +} + +// XComponent +void OComponentHelper::removeEventListener( + const Reference<XEventListener > & rxListener ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(rxListener)>::get(), rxListener ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/component_context.cxx b/cppuhelper/source/component_context.cxx new file mode 100644 index 000000000..739be2800 --- /dev/null +++ b/cppuhelper/source/component_context.cxx @@ -0,0 +1,596 @@ +/* -*- 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 <unordered_map> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +#include <sal/log.hxx> + +#include <uno/lbnames.h> +#include <uno/mapping.hxx> + +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/component_context.hxx> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/uno/DeploymentException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> + +#include <comphelper/sequence.hxx> + +#include <memory> + +#define SMGR_SINGLETON "/singletons/com.sun.star.lang.theServiceManager" +#define TDMGR_SINGLETON "/singletons/com.sun.star.reflection.theTypeDescriptionManager" +#define AC_SINGLETON "/singletons/com.sun.star.security.theAccessController" + +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +namespace cppu +{ + +static void try_dispose( Reference< XInterface > const & xInstance ) +{ + Reference< lang::XComponent > xComp( xInstance, UNO_QUERY ); + if (xComp.is()) + { + xComp->dispose(); + } +} + +static void try_dispose( Reference< lang::XComponent > const & xComp ) +{ + if (xComp.is()) + { + xComp->dispose(); + } +} + +namespace { + +class DisposingForwarder + : public WeakImplHelper< lang::XEventListener > +{ + Reference< lang::XComponent > m_xTarget; + + explicit DisposingForwarder( Reference< lang::XComponent > const & xTarget ) + : m_xTarget( xTarget ) + { + OSL_ASSERT( m_xTarget.is() ); + } +public: + // listens at source for disposing, then disposes target + static inline void listen( + Reference< lang::XComponent > const & xSource, + Reference< lang::XComponent > const & xTarget ); + + virtual void SAL_CALL disposing( lang::EventObject const & rSource ) override; +}; + +} + +inline void DisposingForwarder::listen( + Reference< lang::XComponent > const & xSource, + Reference< lang::XComponent > const & xTarget ) +{ + if (xSource.is()) + { + xSource->addEventListener( new DisposingForwarder( xTarget ) ); + } +} + +void DisposingForwarder::disposing( lang::EventObject const & ) +{ + m_xTarget->dispose(); + m_xTarget.clear(); +} + +namespace { + +struct MutexHolder +{ +protected: + Mutex m_mutex; +}; + + +class ComponentContext + : private MutexHolder + , public WeakComponentImplHelper< XComponentContext, + container::XNameContainer > +{ +protected: + Reference< XComponentContext > m_xDelegate; + + struct ContextEntry + { + Any value; + bool lateInit; + + ContextEntry( Any const & value_, bool lateInit_ ) + : value( value_ ) + , lateInit( lateInit_ ) + {} + }; + typedef std::unordered_map< OUString, ContextEntry > t_map; + t_map m_map; + + Reference< lang::XMultiComponentFactory > m_xSMgr; + +protected: + Any lookupMap( OUString const & rName ); + + virtual void SAL_CALL disposing() override; +public: + ComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ); + + // XComponentContext + virtual Any SAL_CALL getValueByName( OUString const & rName ) override; + virtual Reference<lang::XMultiComponentFactory> SAL_CALL getServiceManager() override; + + // XNameContainer + virtual void SAL_CALL insertByName( + OUString const & name, Any const & element ) override; + virtual void SAL_CALL removeByName( OUString const & name ) override; + // XNameReplace + virtual void SAL_CALL replaceByName( + OUString const & name, Any const & element ) override; + // XNameAccess + virtual Any SAL_CALL getByName( OUString const & name ) override; + virtual Sequence<OUString> SAL_CALL getElementNames() override; + virtual sal_Bool SAL_CALL hasByName( OUString const & name ) override; + // XElementAccess + virtual Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; +}; + +} + +// XNameContainer + +void ComponentContext::insertByName( + OUString const & name, Any const & element ) +{ + ContextEntry entry( + element, + /* lateInit_: */ + name.startsWith( "/singletons/" ) && + !element.hasValue() ); + MutexGuard guard( m_mutex ); + std::pair<t_map::iterator, bool> insertion( m_map.emplace( + name, entry ) ); + if (! insertion.second) + throw container::ElementExistException( + "element already exists: " + name, + static_cast<OWeakObject *>(this) ); +} + + +void ComponentContext::removeByName( OUString const & name ) +{ + MutexGuard guard( m_mutex ); + t_map::iterator iFind( m_map.find( name ) ); + if (iFind == m_map.end()) + throw container::NoSuchElementException( + "no such element: " + name, + static_cast<OWeakObject *>(this) ); + + m_map.erase(iFind); +} + +// XNameReplace + +void ComponentContext::replaceByName( + OUString const & name, Any const & element ) +{ + MutexGuard guard( m_mutex ); + t_map::iterator iFind( m_map.find( name ) ); + if (iFind == m_map.end()) + throw container::NoSuchElementException( + "no such element: " + name, + static_cast<OWeakObject *>(this) ); + if (name.startsWith( "/singletons/" ) && + !element.hasValue()) + { + iFind->second.value.clear(); + iFind->second.lateInit = true; + } + else + { + iFind->second.value = element; + iFind->second.lateInit = false; + } +} + +// XNameAccess + +Any ComponentContext::getByName( OUString const & name ) +{ + return getValueByName( name ); +} + + +Sequence<OUString> ComponentContext::getElementNames() +{ + MutexGuard guard( m_mutex ); + return comphelper::mapKeysToSequence(m_map); +} + + +sal_Bool ComponentContext::hasByName( OUString const & name ) +{ + MutexGuard guard( m_mutex ); + return m_map.find( name ) != m_map.end(); +} + +// XElementAccess + +Type ComponentContext::getElementType() +{ + return cppu::UnoType<void>::get(); +} + + +sal_Bool ComponentContext::hasElements() +{ + MutexGuard guard( m_mutex ); + return ! m_map.empty(); +} + + +Any ComponentContext::lookupMap( OUString const & rName ) +{ + ResettableMutexGuard guard( m_mutex ); + t_map::iterator iFind( m_map.find( rName ) ); + if (iFind == m_map.end()) + return Any(); + + ContextEntry& rFindEntry = iFind->second; + if (! rFindEntry.lateInit) + return rFindEntry.value; + + // late init singleton entry + Reference< XInterface > xInstance; + guard.clear(); + + try + { + Any usesService( getValueByName( rName + "/service" ) ); + Any args_( getValueByName( rName + "/arguments" ) ); + Sequence<Any> args; + if (args_.hasValue() && !(args_ >>= args)) + { + args.realloc( 1 ); + args[ 0 ] = args_; + } + + Reference< lang::XSingleComponentFactory > xFac; + if (usesService >>= xFac) // try via factory + { + xInstance = args.hasElements() + ? xFac->createInstanceWithArgumentsAndContext( args, this ) + : xFac->createInstanceWithContext( this ); + } + else + { + Reference< lang::XSingleServiceFactory > xFac2; + if (usesService >>= xFac2) + { + // try via old XSingleServiceFactory + xInstance = args.hasElements() + ? xFac2->createInstanceWithArguments( args ) + : xFac2->createInstance(); + } + else if (m_xSMgr.is()) // optionally service name + { + OUString serviceName; + if ((usesService >>= serviceName) && + !serviceName.isEmpty()) + { + xInstance = args.hasElements() + ? m_xSMgr->createInstanceWithArgumentsAndContext( + serviceName, args, this ) + : m_xSMgr->createInstanceWithContext( + serviceName, this ); + } + } + } + } + catch (const RuntimeException &) + { + throw; + } + catch (const Exception & exc) + { + SAL_WARN( + "cppuhelper", + "exception occurred raising singleton \"" << rName << "\": " + << exc); + } + + SAL_WARN_IF(!xInstance.is(), + "cppuhelper", "no service object raising singleton " << rName); + + Any ret; + guard.reset(); + iFind = m_map.find( rName ); + if (iFind != m_map.end()) + { + ContextEntry & rEntry = iFind->second; + if (rEntry.lateInit) + { + rEntry.value <<= xInstance; + rEntry.lateInit = false; + return rEntry.value; + } + ret = rEntry.value; + } + guard.clear(); + if (ret != xInstance) { + try_dispose( xInstance ); + } + return ret; +} + + +Any ComponentContext::getValueByName( OUString const & rName ) +{ + // to determine the root context: + if ( rName == "_root" ) + { + if (m_xDelegate.is()) + return m_xDelegate->getValueByName( rName ); + return Any( Reference<XComponentContext>(this) ); + } + + Any ret( lookupMap( rName ) ); + if (!ret.hasValue() && m_xDelegate.is()) + { + return m_xDelegate->getValueByName( rName ); + } + return ret; +} + +Reference< lang::XMultiComponentFactory > ComponentContext::getServiceManager() +{ + if ( !m_xSMgr.is() ) + { + throw DeploymentException( + "null component context service manager", + static_cast<OWeakObject *>(this) ); + } + return m_xSMgr; +} + +void ComponentContext::disposing() +{ + Reference< lang::XComponent > xTDMgr, xAC; // to be disposed separately + + // dispose all context objects + for ( auto& [rName, rEntry] : m_map ) + { + // service manager disposed separately + if (!m_xSMgr.is() || + !rName.startsWith( SMGR_SINGLETON )) + { + if (rEntry.lateInit) + { + // late init + MutexGuard guard( m_mutex ); + if (rEntry.lateInit) + { + rEntry.value.clear(); // release factory + rEntry.lateInit = false; + continue; + } + } + + Reference< lang::XComponent > xComp; + rEntry.value >>= xComp; + if (xComp.is()) + { + if ( rName == TDMGR_SINGLETON ) + { + xTDMgr = xComp; + } + else if ( rName == AC_SINGLETON ) + { + xAC = xComp; + } + else // dispose immediately + { + xComp->dispose(); + } + } + } + } + + // dispose service manager + try_dispose( m_xSMgr ); + m_xSMgr.clear(); + // dispose ac + try_dispose( xAC ); + // dispose tdmgr; revokes callback from cppu runtime + try_dispose( xTDMgr ); + + m_map.clear(); + + // Hack to terminate any JNI bridge's AsynchronousFinalizer thread (as JNI + // proxies get finalized with arbitrary delay, so the bridge typically does + // not dispose itself early enough before the process exits): + uno_Environment ** envs; + sal_Int32 envCount; + uno_getRegisteredEnvironments( + &envs, &envCount, &rtl_allocateMemory, OUString("java").pData); + assert(envCount >= 0); + assert(envCount == 0 || envs != nullptr); + if (envs) { + for (sal_Int32 i = 0; i != envCount; ++i) { + assert(envs[i] != nullptr); + assert(envs[i]->dispose != nullptr); + (*envs[i]->dispose)(envs[i]); + } + std::free(envs); + } +} + +ComponentContext::ComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ) + : WeakComponentImplHelper( m_mutex ), + m_xDelegate( xDelegate ) +{ + for ( sal_Int32 nPos = 0; nPos < nEntries; ++nPos ) + { + ContextEntry_Init const & rEntry = pEntries[ nPos ]; + + if ( rEntry.name == SMGR_SINGLETON ) + { + rEntry.value >>= m_xSMgr; + } + + if (rEntry.bLateInitService) + { + // singleton entry + m_map.emplace( rEntry.name, ContextEntry( Any(), true ) ); + // service + m_map.emplace( rEntry.name + "/service", ContextEntry( rEntry.value, false ) ); + // initial-arguments are provided as optional context entry + } + else + { + // only value, no late init factory nor string + m_map.emplace( rEntry.name, ContextEntry( rEntry.value, false ) ); + } + } + + if (!(!m_xSMgr.is() && m_xDelegate.is())) + return; + + // wrap delegate's smgr XPropertySet into new smgr + Reference< lang::XMultiComponentFactory > xMgr( m_xDelegate->getServiceManager() ); + if (!xMgr.is()) + return; + + osl_atomic_increment( &m_refCount ); + try + { + // create new smgr based on delegate's one + m_xSMgr.set( + xMgr->createInstanceWithContext( + "com.sun.star.comp.stoc.OServiceManagerWrapper", xDelegate ), + UNO_QUERY ); + // patch DefaultContext property of new one + Reference< beans::XPropertySet > xProps( m_xSMgr, UNO_QUERY ); + OSL_ASSERT( xProps.is() ); + if (xProps.is()) + { + Reference< XComponentContext > xThis( this ); + xProps->setPropertyValue( "DefaultContext", Any( xThis ) ); + } + } + catch (...) + { + osl_atomic_decrement( &m_refCount ); + throw; + } + osl_atomic_decrement( &m_refCount ); + OSL_ASSERT( m_xSMgr.is() ); +} + + +extern "C" { static void s_createComponentContext_v(va_list * pParam) +{ + ContextEntry_Init const * pEntries = va_arg(*pParam, ContextEntry_Init const *); + sal_Int32 nEntries = va_arg(*pParam, sal_Int32); + XComponentContext * pDelegatee = va_arg(*pParam, XComponentContext *); + void ** ppContext = va_arg(*pParam, void **); + uno::Mapping * pTarget2curr = va_arg(*pParam, uno::Mapping *); + + Reference<XComponentContext> xDelegate(pDelegatee, SAL_NO_ACQUIRE); + Reference<XComponentContext> xContext; + + if (nEntries > 0) + { + try + { + ComponentContext * p = new ComponentContext( pEntries, nEntries, xDelegate ); + xContext.set(p); + // listen delegate for disposing, to dispose this (wrapping) context first. + DisposingForwarder::listen( Reference< lang::XComponent >::query( xDelegate ), p ); + } + catch (Exception & exc) + { + SAL_WARN( "cppuhelper", exc ); + xContext.clear(); + } + } + else + { + xContext = xDelegate; + } + + *ppContext = pTarget2curr->mapInterface(xContext.get(), cppu::UnoType<decltype(xContext)>::get()); +}} + +Reference< XComponentContext > SAL_CALL createComponentContext( + ContextEntry_Init const * pEntries, sal_Int32 nEntries, + Reference< XComponentContext > const & xDelegate ) +{ + uno::Environment curr_env(Environment::getCurrent()); + uno::Environment source_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME); + + uno::Mapping curr2source(curr_env, source_env); + uno::Mapping source2curr(source_env, curr_env); + + std::unique_ptr<ContextEntry_Init[]> mapped_entries(new ContextEntry_Init[nEntries]); + for (sal_Int32 nPos = 0; nPos < nEntries; ++ nPos) + { + mapped_entries[nPos].bLateInitService = pEntries[nPos].bLateInitService; + mapped_entries[nPos].name = pEntries[nPos].name; + + uno_type_any_constructAndConvert(&mapped_entries[nPos].value, + const_cast<void *>(pEntries[nPos].value.getValue()), + pEntries[nPos].value.getValueTypeRef(), + curr2source.get()); + } + + void * mapped_delegate = curr2source.mapInterface(xDelegate.get(), cppu::UnoType<decltype(xDelegate)>::get()); + XComponentContext * pXComponentContext = nullptr; + source_env.invoke(s_createComponentContext_v, mapped_entries.get(), nEntries, mapped_delegate, &pXComponentContext, &source2curr); + mapped_entries.reset(); + + return Reference<XComponentContext>(pXComponentContext, SAL_NO_ACQUIRE); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/defaultbootstrap.cxx b/cppuhelper/source/defaultbootstrap.cxx new file mode 100644 index 000000000..4796c92e9 --- /dev/null +++ b/cppuhelper/source/defaultbootstrap.cxx @@ -0,0 +1,107 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <cassert> +#include <vector> + +#include <com/sun/star/uno/DeploymentException.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/component_context.hxx> +#include <cppuhelper/weak.hxx> +#include <rtl/bootstrap.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> + +#include "macro_expander.hxx" +#include "paths.hxx" +#include "servicemanager.hxx" +#include "typemanager.hxx" + +namespace com :: sun :: star :: uno { class XComponentContext; } + +namespace { + +OUString getBootstrapVariable( + rtl::Bootstrap const & bootstrap, OUString const & name) +{ + OUString v; + if (!bootstrap.getFrom(name, v)) { + throw css::uno::DeploymentException( + "Cannot obtain " + name + " from uno ini"); + } + return v; +} + +} + +css::uno::Reference< css::uno::XComponentContext > +cppu::defaultBootstrap_InitialComponentContext(OUString const & iniUri) +{ + rtl::Bootstrap bs(iniUri); + if (bs.getHandle() == nullptr) { + throw css::uno::DeploymentException( + "Cannot open uno ini " + iniUri); + } + rtl::Reference smgr( + new cppuhelper::ServiceManager); + smgr->init(getBootstrapVariable(bs, "UNO_SERVICES")); + rtl::Reference tmgr(new cppuhelper::TypeManager); + tmgr->init(getBootstrapVariable(bs, "UNO_TYPES")); + std::vector< cppu::ContextEntry_Init > context_values; + context_values.push_back( + cppu::ContextEntry_Init( + "/singletons/com.sun.star.lang.theServiceManager", + css::uno::Any( + css::uno::Reference< css::uno::XInterface >( + static_cast< cppu::OWeakObject * >(smgr.get()))), + false)); + context_values.push_back( + cppu::ContextEntry_Init( + "/singletons/com.sun.star.reflection.theTypeDescriptionManager", + css::uno::Any( + css::uno::Reference< css::uno::XInterface >( + static_cast< cppu::OWeakObject * >(tmgr.get()))), + false)); + context_values.push_back( //TODO: from services.rdb? + cppu::ContextEntry_Init( + "/singletons/com.sun.star.util.theMacroExpander", + css::uno::Any( + cppuhelper::detail::create_bootstrap_macro_expander_factory()), + true)); + smgr->addSingletonContextEntries(&context_values); + context_values.push_back( + cppu::ContextEntry_Init( + "/services/com.sun.star.security.AccessController/mode", + css::uno::Any(OUString("off")), false)); + context_values.push_back( + cppu::ContextEntry_Init( + "/singletons/com.sun.star.security.theAccessController", + css::uno::Any( + OUString("com.sun.star.security.AccessController")), + true)); + assert(!context_values.empty()); + css::uno::Reference< css::uno::XComponentContext > context( + createComponentContext(context_values.data(), context_values.size())); + smgr->setContext(context); + cppu::installTypeDescriptionManager(tmgr.get()); + return context; +} + +css::uno::Reference< css::uno::XComponentContext > +cppu::defaultBootstrap_InitialComponentContext() +{ + return defaultBootstrap_InitialComponentContext(getUnoIniUri()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/exc_thrower.cxx b/cppuhelper/source/exc_thrower.cxx new file mode 100644 index 000000000..7c40d12db --- /dev/null +++ b/cppuhelper/source/exc_thrower.cxx @@ -0,0 +1,312 @@ +/* -*- 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 <config_features.h> + +#include <rtl/instance.hxx> +#include <osl/diagnose.h> +#include <osl/doublecheckedlocking.h> +#include <sal/log.hxx> +#include <uno/dispatcher.hxx> +#include <uno/lbnames.h> +#include <uno/mapping.hxx> +#include <cppuhelper/detail/XExceptionThrower.hpp> +#include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp> +#include <com/sun/star/ucb/NameClashException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> + +#include <cppuhelper/exc_hlp.hxx> + +using namespace ::osl; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace +{ + +using cppuhelper::detail::XExceptionThrower; + + +struct ExceptionThrower : public uno_Interface, XExceptionThrower +{ + ExceptionThrower(); + + virtual ~ExceptionThrower() {} + + static Type const & getCppuType() + { + return cppu::UnoType<XExceptionThrower>::get(); + } + + // XInterface + virtual Any SAL_CALL queryInterface( Type const & type ) override; + virtual void SAL_CALL acquire() throw () override; + virtual void SAL_CALL release() throw () override; + + // XExceptionThrower + virtual void SAL_CALL throwException( Any const & exc ) override; + virtual void SAL_CALL rethrowException() override; +}; + +extern "C" +{ + + +void ExceptionThrower_acquire_release_nop( + SAL_UNUSED_PARAMETER uno_Interface * ) +{} + + +void ExceptionThrower_dispatch( + uno_Interface * pUnoI, typelib_TypeDescription const * pMemberType, + void * pReturn, void * pArgs [], uno_Any ** ppException ) +{ + OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ); + + switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription * >( + const_cast< typelib_TypeDescription * >( pMemberType ) )-> + nPosition) + { + case 0: // queryInterface() + { + Type const & rType_demanded = + *static_cast< Type const * >( pArgs[ 0 ] ); + if (rType_demanded.equals( cppu::UnoType<XInterface>::get() ) || + rType_demanded.equals( ExceptionThrower::getCppuType() )) + { + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( &pTD, rType_demanded.getTypeLibType() ); + uno_any_construct( + static_cast< uno_Any * >( pReturn ), &pUnoI, pTD, nullptr ); + TYPELIB_DANGER_RELEASE( pTD ); + } + else + { + uno_any_construct( + static_cast< uno_Any * >( pReturn ), nullptr, nullptr, nullptr ); + } + *ppException = nullptr; + break; + } + case 1: // acquire() + case 2: // release() + *ppException = nullptr; + break; + case 3: // throwException() + { + uno_Any * pAny = static_cast< uno_Any * >( pArgs[ 0 ] ); + OSL_ASSERT( pAny->pType->eTypeClass == typelib_TypeClass_EXCEPTION ); + uno_type_any_construct( *ppException, pAny->pData, pAny->pType, nullptr ); + break; + } + default: + { + OSL_ASSERT( false ); + RuntimeException exc( "not implemented!" ); + uno_type_any_construct( + *ppException, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), nullptr ); + break; + } + } +} + +} // extern "C" + + +Any ExceptionThrower::queryInterface( Type const & type ) +{ + if (type.equals( cppu::UnoType<XInterface>::get() ) || + type.equals( ExceptionThrower::getCppuType() )) + { + XExceptionThrower * that = this; + return Any( &that, type ); + } + return Any(); +} + + +void ExceptionThrower::acquire() throw () +{ +} + +void ExceptionThrower::release() throw () +{ +} + + +void ExceptionThrower::throwException( Any const & exc ) +{ + OSL_FAIL( "unexpected!" ); + cppu::throwException( exc ); +} + + +void ExceptionThrower::rethrowException() +{ + throw; +} + + +ExceptionThrower::ExceptionThrower() +{ + uno_Interface::acquire = ExceptionThrower_acquire_release_nop; + uno_Interface::release = ExceptionThrower_acquire_release_nop; + uno_Interface::pDispatcher = ExceptionThrower_dispatch; +} + +class theExceptionThrower : public rtl::Static<ExceptionThrower, theExceptionThrower> {}; + +#if defined(IOS) || (defined(__aarch64__) && defined(ANDROID)) +// In the native iOS / Android app, where we don't have any Java, Python, +// BASIC, or other scripting, the only thing that would use the C++/UNO bridge +// functionality that invokes codeSnippet() was cppu::throwException(). +// +// codeSnippet() is part of what corresponds to the code that uses +// run-time-generated machine code on other platforms. We can't generate code +// at run-time on iOS, that has been known forever. +// +// Instead of digging in and trying to understand what is wrong, another +// solution was chosen. It turns out that the number of types of exception +// objects thrown by cppu::throwException() is fairly small. During startup of +// the LibreOffice code, and loading of an .odt document, only one kind of +// exception is thrown this way... (The lovely +// css::ucb:InteractiveAugmentedIOException.) +// +// So we can simply have code that checks what the type of object being thrown +// is, and explicitly throws such an object then with a normal C++ throw +// statement. Seems to work. +template <class E> void tryThrow(css::uno::Any const& aException) +{ + E aSpecificException; + if (aException >>= aSpecificException) + throw aSpecificException; +} + +void lo_mobile_throwException(css::uno::Any const& aException) +{ + assert(aException.getValueTypeClass() == css::uno::TypeClass_EXCEPTION); + + tryThrow<css::ucb::InteractiveAugmentedIOException>(aException); + tryThrow<css::ucb::NameClashException>(aException); + tryThrow<css::uno::RuntimeException>(aException); + + SAL_WARN("cppuhelper", "lo_mobile_throwException: Unhandled exception type: " << aException.getValueTypeName()); + + assert(false); +} +#endif // defined(IOS) || (defined(__aarch64__) && defined(ANDROID)) + +} // anonymous namespace + + +namespace cppu +{ + + +void SAL_CALL throwException( Any const & exc ) +{ + if (exc.getValueTypeClass() != TypeClass_EXCEPTION) + { + throw RuntimeException( + "no UNO exception given " + "(must be derived from com::sun::star::uno::Exception)!" ); + } + +#if defined(IOS) || (defined(__aarch64__) && defined(ANDROID)) + lo_mobile_throwException(exc); +#else + Mapping uno2cpp(Environment(UNO_LB_UNO), Environment::getCurrent()); + if (! uno2cpp.is()) + { + throw RuntimeException( + "cannot get binary UNO to C++ mapping!" ); + } + + Reference< XExceptionThrower > xThrower; + uno2cpp.mapInterface( + reinterpret_cast< void ** >( &xThrower ), + static_cast< uno_Interface * >( &theExceptionThrower::get() ), + ExceptionThrower::getCppuType() ); + OSL_ASSERT( xThrower.is() ); + xThrower->throwException( exc ); +#endif +} + + +Any SAL_CALL getCaughtException() +{ +#if defined(__aarch64__) && defined(ANDROID) + // FIXME This stuff works on 32bit ARM, let's use the shortcut only for + // the 64bit ARM. + return Any(); +#else + Mapping cpp2uno(Environment::getCurrent(), Environment(UNO_LB_UNO)); + if (! cpp2uno.is()) + { + throw RuntimeException( + "cannot get C++ to binary UNO mapping!" ); + } + Mapping uno2cpp(Environment(UNO_LB_UNO), Environment::getCurrent()); + if (! uno2cpp.is()) + { + throw RuntimeException( + "cannot get binary UNO to C++ mapping!" ); + } + + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( + &pTD, ExceptionThrower::getCppuType().getTypeLibType() ); + + UnoInterfaceReference unoI; + cpp2uno.mapInterface( + reinterpret_cast< void ** >( &unoI.m_pUnoI ), + static_cast< XExceptionThrower * >( &theExceptionThrower::get() ), pTD ); + OSL_ASSERT( unoI.is() ); + + typelib_TypeDescription * pMemberTD = nullptr; + TYPELIB_DANGER_GET( + &pMemberTD, + reinterpret_cast< typelib_InterfaceTypeDescription * >( pTD )-> + ppMembers[ 1 ] /* rethrowException() */ ); + + uno_Any exc_mem; + uno_Any * exc = &exc_mem; + unoI.dispatch( pMemberTD, nullptr, nullptr, &exc ); + + TYPELIB_DANGER_RELEASE( pMemberTD ); + TYPELIB_DANGER_RELEASE( pTD ); + + if (exc == nullptr) + { + throw RuntimeException( "rethrowing C++ exception failed!" ); + } + + Any ret; + uno_any_destruct( &ret, reinterpret_cast< uno_ReleaseFunc >(cpp_release) ); + uno_type_any_constructAndConvert( + &ret, exc->pData, exc->pType, uno2cpp.get() ); + uno_any_destruct( exc, nullptr ); + return ret; +#endif +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/factory.cxx b/cppuhelper/source/factory.cxx new file mode 100644 index 000000000..8a951033c --- /dev/null +++ b/cppuhelper/source/factory.cxx @@ -0,0 +1,967 @@ +/* -*- 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/log.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/component.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <rtl/unload.h> + +#include <cppuhelper/propshlp.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/loader/XImplementationLoader.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/uno/XUnloadingPreference.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +#include <memory> + + +using namespace osl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::loader; +using namespace com::sun::star::registry; + +namespace cppu +{ + +namespace { + +class OSingleFactoryHelper + : public XServiceInfo + , public XSingleServiceFactory + , public lang::XSingleComponentFactory + , public XUnloadingPreference +{ +public: + OSingleFactoryHelper( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName_, + ComponentInstantiation pCreateFunction_, + ComponentFactoryFunc fptr, + const Sequence< OUString > * pServiceNames_ ) + : xSMgr( rServiceManager ) + , pCreateFunction( pCreateFunction_ ) + , m_fptr( fptr ) + , aImplementationName( rImplementationName_ ) + { + if( pServiceNames_ ) + aServiceNames = *pServiceNames_; + } + + virtual ~OSingleFactoryHelper(); + + // XInterface + Any SAL_CALL queryInterface( const Type & rType ) override; + + // XSingleServiceFactory + Reference<XInterface > SAL_CALL createInstance() override; + virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const Sequence<Any>& Arguments) override; + // XSingleComponentFactory + virtual Reference< XInterface > SAL_CALL createInstanceWithContext( + Reference< XComponentContext > const & xContext ) override; + virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +protected: + /** + * Create an instance specified by the factory. The one instance logic is implemented + * in the createInstance and createInstanceWithArguments methods. + * @return the newly created instance. Do not return a previous (one instance) instance. + * @throw css::uno::Exception + * @throw css::uno::RuntimeException + */ + virtual Reference<XInterface > createInstanceEveryTime( + Reference< XComponentContext > const & xContext ); + + Reference<XMultiServiceFactory > xSMgr; + ComponentInstantiation pCreateFunction; + ComponentFactoryFunc m_fptr; + Sequence< OUString > aServiceNames; + OUString aImplementationName; +}; + +} + +OSingleFactoryHelper::~OSingleFactoryHelper() +{ +} + + +Any OSingleFactoryHelper::queryInterface( const Type & rType ) +{ + return ::cppu::queryInterface( + rType, + static_cast< XSingleComponentFactory * >( this ), + static_cast< XSingleServiceFactory * >( this ), + static_cast< XServiceInfo * >( this ) , + static_cast< XUnloadingPreference * >( this )); +} + +// OSingleFactoryHelper +Reference<XInterface > OSingleFactoryHelper::createInstanceEveryTime( + Reference< XComponentContext > const & xContext ) +{ + if (m_fptr) + { + return (*m_fptr)( xContext ); + } + if( pCreateFunction ) + { + if (xContext.is()) + { + Reference< lang::XMultiServiceFactory > xContextMgr( + xContext->getServiceManager(), UNO_QUERY ); + if (xContextMgr.is()) + return (*pCreateFunction)( xContextMgr ); + } + return (*pCreateFunction)( xSMgr ); + } + return Reference< XInterface >(); +} + +// XSingleServiceFactory +Reference<XInterface > OSingleFactoryHelper::createInstance() +{ + return createInstanceWithContext( Reference< XComponentContext >() ); +} + +// XSingleServiceFactory +Reference<XInterface > OSingleFactoryHelper::createInstanceWithArguments( + const Sequence<Any>& Arguments ) +{ + return createInstanceWithArgumentsAndContext( + Arguments, Reference< XComponentContext >() ); +} + +// XSingleComponentFactory + +Reference< XInterface > OSingleFactoryHelper::createInstanceWithContext( + Reference< XComponentContext > const & xContext ) +{ + return createInstanceEveryTime( xContext ); +} + +Reference< XInterface > OSingleFactoryHelper::createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) +{ + Reference< XInterface > xRet( createInstanceWithContext( xContext ) ); + + Reference< lang::XInitialization > xInit( xRet, UNO_QUERY ); + // always call initialize, even if there are no arguments. #i63511# + if (xInit.is()) + { + xInit->initialize( rArguments ); + } + else + { + if ( rArguments.hasElements() ) + { + // dispose the here created UNO object before throwing out exception + // to avoid risk of memory leaks #i113722# + Reference<XComponent> xComp( xRet, UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); + + throw lang::IllegalArgumentException( + "cannot pass arguments to component => no XInitialization implemented!", + Reference< XInterface >(), 0 ); + } + } + + return xRet; +} + +// XServiceInfo +OUString OSingleFactoryHelper::getImplementationName() +{ + return aImplementationName; +} + +// XServiceInfo +sal_Bool OSingleFactoryHelper::supportsService( + const OUString& ServiceName ) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OSingleFactoryHelper::getSupportedServiceNames() +{ + return aServiceNames; +} + +namespace { + +struct OFactoryComponentHelper_Mutex +{ + Mutex aMutex; +}; + +class OFactoryComponentHelper + : public OFactoryComponentHelper_Mutex + , public OComponentHelper + , public OSingleFactoryHelper +{ +public: + OFactoryComponentHelper( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName_, + ComponentInstantiation pCreateFunction_, + ComponentFactoryFunc fptr, + const Sequence< OUString > * pServiceNames_, + bool bOneInstance_ ) + : OComponentHelper( aMutex ) + , OSingleFactoryHelper( rServiceManager, rImplementationName_, pCreateFunction_, fptr, pServiceNames_ ) + , bOneInstance( bOneInstance_ ) + { + } + + // XInterface + Any SAL_CALL queryInterface( const Type & rType ) override; + void SAL_CALL acquire() throw() override + { OComponentHelper::acquire(); } + void SAL_CALL release() throw() override + { OComponentHelper::release(); } + + // XSingleServiceFactory + Reference<XInterface > SAL_CALL createInstance() override; + Reference<XInterface > SAL_CALL createInstanceWithArguments( const Sequence<Any>& Arguments ) override; + // XSingleComponentFactory + virtual Reference< XInterface > SAL_CALL createInstanceWithContext( + Reference< XComponentContext > const & xContext ) override; + virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) override; + + // XTypeProvider + virtual Sequence< Type > SAL_CALL getTypes() override; + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + + // XAggregation + Any SAL_CALL queryAggregation( const Type & rType ) override; + + // XUnloadingPreference + virtual sal_Bool SAL_CALL releaseOnNotification() override; + + // OComponentHelper + void SAL_CALL dispose() override; + +private: + Reference<XInterface > xTheInstance; + bool bOneInstance; +protected: + // needed for implementing XUnloadingPreference in inheriting classes + bool isOneInstance() const {return bOneInstance;} + bool isInstance() const {return xTheInstance.is();} +}; + +} + +Any SAL_CALL OFactoryComponentHelper::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XUnloadingPreference>::get() ) + { + return Any( + Reference< XUnloadingPreference >( + static_cast< XUnloadingPreference * >(this) ) ); + } + return OComponentHelper::queryInterface( rType ); +} + +// XAggregation +Any OFactoryComponentHelper::queryAggregation( const Type & rType ) +{ + Any aRet( OComponentHelper::queryAggregation( rType ) ); + return (aRet.hasValue() ? aRet : OSingleFactoryHelper::queryInterface( rType )); +} + +// XTypeProvider +Sequence< Type > OFactoryComponentHelper::getTypes() +{ + Type ar[ 4 ]; + ar[ 0 ] = cppu::UnoType<XSingleServiceFactory>::get(); + ar[ 1 ] = cppu::UnoType<XServiceInfo>::get(); + ar[ 2 ] = cppu::UnoType<XUnloadingPreference>::get(); + + if (m_fptr) + ar[ 3 ] = cppu::UnoType<XSingleComponentFactory>::get(); + + return Sequence< Type >( ar, m_fptr ? 4 : 3 ); +} + +Sequence< sal_Int8 > OFactoryComponentHelper::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XSingleServiceFactory +Reference<XInterface > OFactoryComponentHelper::createInstance() +{ + if( bOneInstance ) + { + if( !xTheInstance.is() ) + { + MutexGuard aGuard( aMutex ); + if( !xTheInstance.is() ) + xTheInstance = OSingleFactoryHelper::createInstance(); + } + return xTheInstance; + } + return OSingleFactoryHelper::createInstance(); +} + +Reference<XInterface > OFactoryComponentHelper::createInstanceWithArguments( + const Sequence<Any>& Arguments ) +{ + if( bOneInstance ) + { + if( !xTheInstance.is() ) + { + MutexGuard aGuard( aMutex ); +// OSL_ENSURE( !xTheInstance.is(), "### arguments will be ignored!" ); + if( !xTheInstance.is() ) + xTheInstance = OSingleFactoryHelper::createInstanceWithArguments( Arguments ); + } + return xTheInstance; + } + return OSingleFactoryHelper::createInstanceWithArguments( Arguments ); +} + +// XSingleComponentFactory + +Reference< XInterface > OFactoryComponentHelper::createInstanceWithContext( + Reference< XComponentContext > const & xContext ) +{ + if( bOneInstance ) + { + if( !xTheInstance.is() ) + { + MutexGuard aGuard( aMutex ); +// OSL_ENSURE( !xTheInstance.is(), "### context will be ignored!" ); + if( !xTheInstance.is() ) + xTheInstance = OSingleFactoryHelper::createInstanceWithContext( xContext ); + } + return xTheInstance; + } + return OSingleFactoryHelper::createInstanceWithContext( xContext ); +} + +Reference< XInterface > OFactoryComponentHelper::createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) +{ + if( bOneInstance ) + { + if( !xTheInstance.is() ) + { + MutexGuard aGuard( aMutex ); +// OSL_ENSURE( !xTheInstance.is(), "### context and arguments will be ignored!" ); + if( !xTheInstance.is() ) + xTheInstance = OSingleFactoryHelper::createInstanceWithArgumentsAndContext( rArguments, xContext ); + } + return xTheInstance; + } + return OSingleFactoryHelper::createInstanceWithArgumentsAndContext( rArguments, xContext ); +} + + +// OComponentHelper +void OFactoryComponentHelper::dispose() +{ + OComponentHelper::dispose(); + + Reference<XInterface > x; + { + // do not delete in the guard section + MutexGuard aGuard( aMutex ); + x = xTheInstance; + xTheInstance.clear(); + } + // if it is a component call dispose at the component + Reference<XComponent > xComp( x, UNO_QUERY ); + if( xComp.is() ) + xComp->dispose(); +} + +// XUnloadingPreference +// This class is used for single factories, component factories and +// one-instance factories. Depending on the usage this function has +// to return different values. +// one-instance factory: sal_False +// single factory: sal_True +// component factory: sal_True +sal_Bool SAL_CALL OFactoryComponentHelper::releaseOnNotification() +{ + if( bOneInstance) + return false; + return true; +} + +namespace { + +class ORegistryFactoryHelper : public OFactoryComponentHelper, + public OPropertySetHelper + +{ +public: + ORegistryFactoryHelper( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName_, + const Reference<XRegistryKey > & xImplementationKey_, + bool bOneInstance_ ) + : OFactoryComponentHelper( + rServiceManager, rImplementationName_, nullptr, nullptr, nullptr, bOneInstance_ ), + OPropertySetHelper( OComponentHelper::rBHelper ), + xImplementationKey( xImplementationKey_ ) + {} + + // XInterface + virtual Any SAL_CALL queryInterface( Type const & type ) override; + virtual void SAL_CALL acquire() throw () override; + virtual void SAL_CALL release() throw () override; + // XTypeProvider + virtual Sequence< Type > SAL_CALL getTypes() override; + // XPropertySet + virtual Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + + // OPropertySetHelper + virtual IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + Any & rConvertedValue, Any & rOldValue, + sal_Int32 nHandle, Any const & rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, Any const & rValue ) override; + using OPropertySetHelper::getFastPropertyValue; + virtual void SAL_CALL getFastPropertyValue( + Any & rValue, sal_Int32 nHandle ) const override; + + // OSingleFactoryHelper + Reference<XInterface > createInstanceEveryTime( + Reference< XComponentContext > const & xContext ) override; + + // XSingleServiceFactory + Reference<XInterface > SAL_CALL createInstanceWithArguments(const Sequence<Any>& Arguments) override; + // XSingleComponentFactory + Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) override; + + // XServiceInfo + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + // XUnloadingPreference + sal_Bool SAL_CALL releaseOnNotification() override; + + +private: + /// @throws css::uno::Exception + /// @throws css::uno::RuntimeException + Reference< XInterface > createModuleFactory(); + + /** The registry key of the implementation section */ + Reference<XRegistryKey > xImplementationKey; + /** The factory created with the loader. */ + Reference<XSingleComponentFactory > xModuleFactory; + Reference<XSingleServiceFactory > xModuleFactoryDepr; + Reference< beans::XPropertySetInfo > m_xInfo; + std::unique_ptr< IPropertyArrayHelper > m_property_array_helper; +protected: + using OPropertySetHelper::getTypes; +}; + +} + +// XInterface + +Any SAL_CALL ORegistryFactoryHelper::queryInterface( + Type const & type ) +{ + Any ret( OFactoryComponentHelper::queryInterface( type ) ); + if (ret.hasValue()) + return ret; + return OPropertySetHelper::queryInterface( type ); +} + + +void ORegistryFactoryHelper::acquire() throw () +{ + OFactoryComponentHelper::acquire(); +} + + +void ORegistryFactoryHelper::release() throw () +{ + OFactoryComponentHelper::release(); +} + +// XTypeProvider + +Sequence< Type > ORegistryFactoryHelper::getTypes() +{ + Sequence< Type > types( OFactoryComponentHelper::getTypes() ); + sal_Int32 pos = types.getLength(); + types.realloc( pos + 3 ); + Type * p = types.getArray(); + p[ pos++ ] = cppu::UnoType<beans::XMultiPropertySet>::get(); + p[ pos++ ] = cppu::UnoType<beans::XFastPropertySet>::get(); + p[ pos++ ] = cppu::UnoType<beans::XPropertySet>::get(); + return types; +} + +// XPropertySet + +Reference< beans::XPropertySetInfo > +ORegistryFactoryHelper::getPropertySetInfo() +{ + ::osl::MutexGuard guard( aMutex ); + if (! m_xInfo.is()) + m_xInfo = createPropertySetInfo( getInfoHelper() ); + return m_xInfo; +} + +// OPropertySetHelper + +IPropertyArrayHelper & ORegistryFactoryHelper::getInfoHelper() +{ + ::osl::MutexGuard guard( aMutex ); + if (m_property_array_helper == nullptr) + { + beans::Property prop( + "ImplementationKey" /* name */, + 0 /* handle */, + cppu::UnoType<decltype(xImplementationKey)>::get(), + beans::PropertyAttribute::READONLY | + beans::PropertyAttribute::OPTIONAL ); + m_property_array_helper.reset( + new ::cppu::OPropertyArrayHelper( &prop, 1 ) ); + } + return *m_property_array_helper; +} + + +sal_Bool ORegistryFactoryHelper::convertFastPropertyValue( + Any &, Any &, sal_Int32, Any const & ) +{ + OSL_FAIL( "unexpected!" ); + return false; +} + + +void ORegistryFactoryHelper::setFastPropertyValue_NoBroadcast( + sal_Int32, Any const & ) +{ + throw beans::PropertyVetoException( + "unexpected: only readonly properties!", + static_cast< OWeakObject * >(this) ); +} + + +void ORegistryFactoryHelper::getFastPropertyValue( + Any & rValue, sal_Int32 nHandle ) const +{ + if (nHandle == 0) + { + rValue <<= xImplementationKey; + } + else + { + rValue.clear(); + throw beans::UnknownPropertyException( + "unknown property!", static_cast< OWeakObject * >( + const_cast< ORegistryFactoryHelper * >(this) ) ); + } +} + +Reference<XInterface > ORegistryFactoryHelper::createInstanceEveryTime( + Reference< XComponentContext > const & xContext ) +{ + if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) + { + Reference< XInterface > x( createModuleFactory() ); + if (x.is()) + { + MutexGuard aGuard( aMutex ); + if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) + { + xModuleFactory.set( x, UNO_QUERY ); + xModuleFactoryDepr.set( x, UNO_QUERY ); + } + } + } + if( xModuleFactory.is() ) + { + return xModuleFactory->createInstanceWithContext( xContext ); + } + if( xModuleFactoryDepr.is() ) + { + return xModuleFactoryDepr->createInstance(); + } + + return Reference<XInterface >(); +} + +Reference<XInterface > SAL_CALL ORegistryFactoryHelper::createInstanceWithArguments( + const Sequence<Any>& Arguments ) +{ + if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) + { + Reference< XInterface > x( createModuleFactory() ); + if (x.is()) + { + MutexGuard aGuard( aMutex ); + if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) + { + xModuleFactory.set( x, UNO_QUERY ); + xModuleFactoryDepr.set( x, UNO_QUERY ); + } + } + } + if( xModuleFactoryDepr.is() ) + { + return xModuleFactoryDepr->createInstanceWithArguments( Arguments ); + } + if( xModuleFactory.is() ) + { + SAL_INFO("cppuhelper", "no context ORegistryFactoryHelper::createInstanceWithArgumentsAndContext()!"); + return xModuleFactory->createInstanceWithArgumentsAndContext( Arguments, Reference< XComponentContext >() ); + } + + return Reference<XInterface >(); +} + +Reference< XInterface > ORegistryFactoryHelper::createInstanceWithArgumentsAndContext( + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) +{ + if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) + { + Reference< XInterface > x( createModuleFactory() ); + if (x.is()) + { + MutexGuard aGuard( aMutex ); + if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) + { + xModuleFactory.set( x, UNO_QUERY ); + xModuleFactoryDepr.set( x, UNO_QUERY ); + } + } + } + if( xModuleFactory.is() ) + { + return xModuleFactory->createInstanceWithArgumentsAndContext( rArguments, xContext ); + } + if( xModuleFactoryDepr.is() ) + { + SAL_INFO_IF(xContext.is(), "cppuhelper", "ignoring context calling ORegistryFactoryHelper::createInstaceWithArgumentsAndContext()!"); + return xModuleFactoryDepr->createInstanceWithArguments( rArguments ); + } + + return Reference<XInterface >(); +} + + +// OSingleFactoryHelper +Reference< XInterface > ORegistryFactoryHelper::createModuleFactory() +{ + OUString aActivatorUrl; + OUString aActivatorName; + OUString aLocation; + + Reference<XRegistryKey > xActivatorKey = xImplementationKey->openKey( + "/UNO/ACTIVATOR" ); + if( xActivatorKey.is() && xActivatorKey->getValueType() == RegistryValueType_ASCII ) + { + aActivatorUrl = xActivatorKey->getAsciiValue(); + + aActivatorName = aActivatorUrl.getToken(0, ':'); + + Reference<XRegistryKey > xLocationKey = xImplementationKey->openKey( + "/UNO/LOCATION" ); + if( xLocationKey.is() && xLocationKey->getValueType() == RegistryValueType_ASCII ) + aLocation = xLocationKey->getAsciiValue(); + } + else + { + // old style"url" + // the location of the program code of the implementation + Reference<XRegistryKey > xLocationKey = xImplementationKey->openKey( + "/UNO/URL" ); + // is the key of the right type ? + if( xLocationKey.is() && xLocationKey->getValueType() == RegistryValueType_ASCII ) + { + // one implementation found -> try to activate + aLocation = xLocationKey->getAsciiValue(); + + // search protocol delimiter + sal_Int32 nPos = aLocation.indexOf("://"); + if( nPos != -1 ) + { + aActivatorName = aLocation.copy( 0, nPos ); + if( aActivatorName == "java" ) + aActivatorName = "com.sun.star.loader.Java"; + else if( aActivatorName == "module" ) + aActivatorName = "com.sun.star.loader.SharedLibrary"; + aLocation = aLocation.copy( nPos + 3 ); + } + } + } + + Reference< XInterface > xFactory; + if( !aActivatorName.isEmpty() ) + { + Reference<XInterface > x = xSMgr->createInstance( aActivatorName ); + Reference<XImplementationLoader > xLoader( x, UNO_QUERY ); + if (xLoader.is()) + { + xFactory = xLoader->activate( aImplementationName, aActivatorUrl, aLocation, xImplementationKey ); + } + } + return xFactory; +} + +// XServiceInfo +Sequence< OUString > ORegistryFactoryHelper::getSupportedServiceNames() +{ + MutexGuard aGuard( aMutex ); + if( !aServiceNames.hasElements() ) + { + // not yet loaded + try + { + Reference<XRegistryKey > xKey = xImplementationKey->openKey( "UNO/SERVICES" ); + + if (xKey.is()) + { + // length of prefix. +1 for the '/' at the end + sal_Int32 nPrefixLen = xKey->getKeyName().getLength() + 1; + + // Full qualified names like "IMPLEMENTATIONS/TEST/UNO/SERVICES/com.sun.star..." + Sequence<OUString> seqKeys = xKey->getKeyNames(); + for( OUString & key : seqKeys ) + key = key.copy(nPrefixLen); + + aServiceNames = seqKeys; + } + } + catch (InvalidRegistryException &) + { + } + } + return aServiceNames; +} + +sal_Bool SAL_CALL ORegistryFactoryHelper::releaseOnNotification() +{ + bool retVal= true; + if( isOneInstance() && isInstance()) + { + retVal= false; + } + else if( ! isOneInstance()) + { + // try to delegate + if( xModuleFactory.is()) + { + Reference<XUnloadingPreference> xunloading( xModuleFactory, UNO_QUERY); + if( xunloading.is()) + retVal= xunloading->releaseOnNotification(); + } + else if( xModuleFactoryDepr.is()) + { + Reference<XUnloadingPreference> xunloading( xModuleFactoryDepr, UNO_QUERY); + if( xunloading.is()) + retVal= xunloading->releaseOnNotification(); + } + } + return retVal; +} + +namespace { + +class OFactoryProxyHelper : public WeakImplHelper< XServiceInfo, XSingleServiceFactory, + XUnloadingPreference > +{ + Reference<XSingleServiceFactory > xFactory; + +public: + + explicit OFactoryProxyHelper( const Reference<XSingleServiceFactory > & rFactory ) + : xFactory( rFactory ) + {} + + // XSingleServiceFactory + Reference<XInterface > SAL_CALL createInstance() override; + Reference<XInterface > SAL_CALL createInstanceWithArguments(const Sequence<Any>& Arguments) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + //XUnloadingPreference + sal_Bool SAL_CALL releaseOnNotification() override; + +}; + +} + +// XSingleServiceFactory +Reference<XInterface > OFactoryProxyHelper::createInstance() +{ + return xFactory->createInstance(); +} + +// XSingleServiceFactory +Reference<XInterface > OFactoryProxyHelper::createInstanceWithArguments +( + const Sequence<Any>& Arguments +) +{ + return xFactory->createInstanceWithArguments( Arguments ); +} + +// XServiceInfo +OUString OFactoryProxyHelper::getImplementationName() +{ + Reference<XServiceInfo > xInfo( xFactory, UNO_QUERY ); + if( xInfo.is() ) + return xInfo->getImplementationName(); + return OUString(); +} + +// XServiceInfo +sal_Bool OFactoryProxyHelper::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OFactoryProxyHelper::getSupportedServiceNames() +{ + Reference<XServiceInfo > xInfo( xFactory, UNO_QUERY ); + if( xInfo.is() ) + return xInfo->getSupportedServiceNames(); + return Sequence< OUString >(); +} + +sal_Bool SAL_CALL OFactoryProxyHelper::releaseOnNotification() +{ + + Reference<XUnloadingPreference> pref( xFactory, UNO_QUERY); + if( pref.is()) + return pref->releaseOnNotification(); + return true; +} + +// global function +Reference<XSingleServiceFactory > SAL_CALL createSingleFactory( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName, + ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount * ) +{ + return new OFactoryComponentHelper( + rServiceManager, rImplementationName, pCreateFunction, nullptr, &rServiceNames, false ); +} + +// global function +Reference<XSingleServiceFactory > SAL_CALL createFactoryProxy( + SAL_UNUSED_PARAMETER const Reference<XMultiServiceFactory > &, + const Reference<XSingleServiceFactory > & rFactory ) +{ + return new OFactoryProxyHelper( rFactory ); +} + +// global function +Reference<XSingleServiceFactory > SAL_CALL createOneInstanceFactory( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName, + ComponentInstantiation pCreateFunction, + const Sequence< OUString > & rServiceNames, + rtl_ModuleCount * ) +{ + return new OFactoryComponentHelper( + rServiceManager, rImplementationName, pCreateFunction, nullptr, &rServiceNames, true ); +} + +// global function +Reference<XSingleServiceFactory > SAL_CALL createSingleRegistryFactory( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName, + const Reference<XRegistryKey > & rImplementationKey ) +{ + return new ORegistryFactoryHelper( + rServiceManager, rImplementationName, rImplementationKey, false ); +} + +// global function +Reference<XSingleServiceFactory > SAL_CALL createOneInstanceRegistryFactory( + const Reference<XMultiServiceFactory > & rServiceManager, + const OUString & rImplementationName, + const Reference<XRegistryKey > & rImplementationKey ) +{ + return new ORegistryFactoryHelper( + rServiceManager, rImplementationName, rImplementationKey, true ); +} + + +Reference< lang::XSingleComponentFactory > SAL_CALL createSingleComponentFactory( + ComponentFactoryFunc fptr, + OUString const & rImplementationName, + Sequence< OUString > const & rServiceNames, + rtl_ModuleCount *) +{ + return new OFactoryComponentHelper( + Reference< XMultiServiceFactory >(), rImplementationName, nullptr, fptr, &rServiceNames, false ); +} + +Reference< lang::XSingleComponentFactory > SAL_CALL createOneInstanceComponentFactory( + ComponentFactoryFunc fptr, + OUString const & rImplementationName, + Sequence< OUString > const & rServiceNames, + rtl_ModuleCount *) +{ + return new OFactoryComponentHelper( + Reference< XMultiServiceFactory >(), rImplementationName, nullptr, fptr, &rServiceNames, true ); +} + +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/findsofficepath.c b/cppuhelper/source/findsofficepath.c new file mode 100644 index 000000000..75d370981 --- /dev/null +++ b/cppuhelper/source/findsofficepath.c @@ -0,0 +1,219 @@ +/* -*- 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 <stdlib.h> +#include <string.h> + +#include <cppuhelper/findsofficepath.h> + +#if defined(_WIN32) + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +/* + * Gets the installation path from the Windows Registry for the specified + * registry key. + * + * @param hroot open handle to predefined root registry key + * @param subKeyName name of the subkey to open + * + * @return the installation path or NULL, if no installation was found or + * if an error occurred + */ +static wchar_t* getPathFromRegistryKey( HKEY hroot, const wchar_t* subKeyName ) +{ + HKEY hkey; + DWORD type; + wchar_t* data = NULL; + DWORD size; + + /* open the specified registry key */ + if ( RegOpenKeyExW( hroot, subKeyName, 0, KEY_READ, &hkey ) != ERROR_SUCCESS ) + { + return NULL; + } + + /* find the type and size of the default value */ + if ( RegQueryValueExW( hkey, NULL, NULL, &type, NULL, &size) != ERROR_SUCCESS ) + { + RegCloseKey( hkey ); + return NULL; + } + + /* get memory to hold the default value */ + data = (wchar_t*) malloc( size + sizeof(wchar_t) ); + + /* read the default value */ + if ( RegQueryValueExW( hkey, NULL, NULL, &type, (LPBYTE) data, &size ) != ERROR_SUCCESS ) + { + RegCloseKey( hkey ); + free( data ); + return NULL; + } + + // According to https://msdn.microsoft.com/en-us/ms724911, If the data has the REG_SZ, + // REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been stored with the + // proper terminating null characters + data[size / sizeof(wchar_t)] = 0; + + /* release registry key handle */ + RegCloseKey( hkey ); + + return data; +} + +/* + * Gets the installation path from the Windows Registry. + * + * @return the installation path or NULL, if no installation was found or + * if an error occurred + */ +static wchar_t* platformSpecific() +{ + const wchar_t* UNOPATHVARNAME = L"UNO_PATH"; + + /* get the installation path from the UNO_PATH environment variable */ + wchar_t* env = _wgetenv(UNOPATHVARNAME); + + if (env && env[0]) + { + return wcsdup(env); + } + + const wchar_t* SUBKEYNAME = L"Software\\LibreOffice\\UNO\\InstallPath"; + + /* read the key's default value from HKEY_CURRENT_USER */ + wchar_t* path = getPathFromRegistryKey( HKEY_CURRENT_USER, SUBKEYNAME ); + + if ( path == NULL ) + { + /* read the key's default value from HKEY_LOCAL_MACHINE */ + path = getPathFromRegistryKey( HKEY_LOCAL_MACHINE, SUBKEYNAME ); + } + + return path; +} + +#else + +#include <limits.h> + +/* + * Gets the installation path from the PATH environment variable. + * + * <p>An installation is found, if the executable 'soffice' or a symbolic link + * is in one of the directories listed in the PATH environment variable.</p> + * + * @return the installation path or NULL, if no installation was found or + * if an error occurred + */ +static char* platformSpecific(void) +{ + const char* UNOPATHVARNAME = "UNO_PATH"; + + /* get the installation path from the UNO_PATH environment variable */ + char* env = getenv(UNOPATHVARNAME); + + const int SEPARATOR = '/'; + const char* PATHSEPARATOR = ":"; + const char* PATHVARNAME = "PATH"; + const char* APPENDIX = "/libreoffice"; + + char* path = NULL; + char* str = NULL; + char* dir = NULL; + char* sep = NULL; + + char buffer[PATH_MAX]; + int pos; + + if (env && env[0]) + { + return strdup(env); + } + + /* get the value of the PATH environment variable */ + env = getenv( PATHVARNAME ); + if (env == NULL) + return NULL; + + str = strdup( env ); + if (str == NULL) + return NULL; + + /* get the tokens separated by ':' */ + dir = strtok( str, PATHSEPARATOR ); + + while ( dir ) + { + /* construct soffice file path */ + char* resolved = NULL; + char* file = (char*) malloc( strlen( dir ) + strlen( APPENDIX ) + 1 ); + if (file == NULL) + { + free(str); + return NULL; + } + + strcpy( file, dir ); + strcat( file, APPENDIX ); + + /* resolve symbolic link */ + resolved = realpath( file, buffer ); + if ( resolved != NULL ) + { + /* get path to program directory */ + sep = strrchr( resolved, SEPARATOR ); + + if ( sep != NULL ) + { + pos = sep - resolved; + path = (char*) malloc( pos + 1 ); + strncpy( path, resolved, pos ); + path[ pos ] = '\0'; + free( file ); + break; + } + } + + dir = strtok( NULL, PATHSEPARATOR ); + free( file ); + } + + free( str ); + + return path; +} + +#endif + +#if defined(_WIN32) +wchar_t* +#else +char* +#endif +cppuhelper_detail_findSofficePath() +{ + return platformSpecific(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/gcc3.map b/cppuhelper/source/gcc3.map new file mode 100644 index 000000000..d5af50655 --- /dev/null +++ b/cppuhelper/source/gcc3.map @@ -0,0 +1,443 @@ +# +# 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 . +# +UDK_3_0_0 { + global: + _ZTI*; _ZTS*; # weak RTTI symbols for C++ exceptions + +_ZN3com3sun4star3uno19WeakReferenceHelperC1ERKNS2_9ReferenceINS2_10XInterfaceEEE; +_ZN3com3sun4star3uno19WeakReferenceHelperC1ERKS3_; +_ZN3com3sun4star3uno19WeakReferenceHelperC2ERKNS2_9ReferenceINS2_10XInterfaceEEE; +_ZN3com3sun4star3uno19WeakReferenceHelperC2ERKS3_; +_ZN3com3sun4star3uno19WeakReferenceHelperaSERKS3_; +_ZN3com3sun4star3uno19WeakReferenceHelperD1Ev; +_ZN3com3sun4star3uno19WeakReferenceHelperD2Ev; +_ZN4cppu11OWeakObject12queryAdapterEv; +_ZN4cppu11OWeakObject14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZN4cppu11OWeakObject7acquireEv; +_ZN4cppu11OWeakObject7releaseEv; +_ZN4cppu11OWeakObjectD0Ev; +_ZN4cppu11OWeakObjectD1Ev; +_ZN4cppu11OWeakObjectD2Ev; +_ZN4cppu13ClassDataBaseC1E?; +_ZN4cppu13ClassDataBaseC1Ev; +_ZN4cppu13ClassDataBaseC2E?; +_ZN4cppu13ClassDataBaseC2Ev; +_ZN4cppu13ClassDataBaseD1Ev; +_ZN4cppu13ClassDataBaseD2Ev; +_ZN4cppu14OWeakAggObject12setDelegatorERKN3com3sun4star3uno9ReferenceINS4_10XInterfaceEEE; +_ZN4cppu14OWeakAggObject14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZN4cppu14OWeakAggObject16queryAggregationERKN3com3sun4star3uno4TypeE; +_ZN4cppu14OWeakAggObject7acquireEv; +_ZN4cppu14OWeakAggObject7releaseEv; +_ZN4cppu14OWeakAggObjectD0Ev; +_ZN4cppu14OWeakAggObjectD1Ev; +_ZN4cppu14OWeakAggObjectD2Ev; +_ZN4cppu14throwExceptionERKN3com3sun4star3uno3AnyE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeERKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC1ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeERKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu15OTypeCollectionC2ERKN3com3sun4star3uno4TypeES7_S7_S7_S7_S7_S7_S7_S7_S7_S7_S7_RKNS4_8SequenceIS5_EE; +_ZN4cppu16ImplHelper_queryERKN3com3sun4star3uno4TypeEPNS_10class_dataEPv; +_ZN4cppu16OComponentHelper14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZN4cppu16OComponentHelper16addEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZN4cppu16OComponentHelper16queryAggregationERKN3com3sun4star3uno4TypeE; +_ZN4cppu16OComponentHelper19removeEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZN4cppu16OComponentHelper7acquireEv; +_ZN4cppu16OComponentHelper7disposeEv; +_ZN4cppu16OComponentHelper7releaseEv; +_ZN4cppu16OComponentHelper8getTypesEv; +_ZN4cppu16OComponentHelper9disposingEv; +_ZN4cppu16OComponentHelperC1ERN3osl5MutexE; +_ZN4cppu16OComponentHelperC2ERN3osl5MutexE; +_ZN4cppu16OComponentHelperD0Ev; +_ZN4cppu16OComponentHelperD1Ev; +_ZN4cppu16OComponentHelperD2Ev; +_ZN4cppu17OImplementationIdD1Ev; +_ZN4cppu17OImplementationIdD2Ev; +_ZN4cppu18OPropertySetHelper14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZN4cppu18OPropertySetHelper16getPropertyValueERKN3rtl8OUStringE; +_ZN4cppu18OPropertySetHelper16setPropertyValueERKN3rtl8OUStringERKN3com3sun4star3uno3AnyE; +_ZN4cppu18OPropertySetHelper17getPropertyValuesERKN3com3sun4star3uno8SequenceIN3rtl8OUStringEEE; +_ZN4cppu18OPropertySetHelper17setPropertyValuesERKN3com3sun4star3uno8SequenceIN3rtl8OUStringEEERKNS5_INS4_3AnyEEE; +_ZN4cppu18OPropertySetHelper20getFastPropertyValueE?; +_ZN4cppu18OPropertySetHelper20setFastPropertyValueE?RKN3com3sun4star3uno3AnyE; +_ZN4cppu18OPropertySetHelper21createPropertySetInfoERNS_20IPropertyArrayHelperE; +_ZN4cppu18OPropertySetHelper21setFastPropertyValuesE?P?PKN3com3sun4star3uno3AnyE?; +_ZN4cppu18OPropertySetHelper25addPropertyChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XPropertyChangeListenerEEE; +_ZN4cppu18OPropertySetHelper25addVetoableChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XVetoableChangeListenerEEE; +_ZN4cppu18OPropertySetHelper25firePropertiesChangeEventERKN3com3sun4star3uno8SequenceIN3rtl8OUStringEEERKNS4_9ReferenceINS3_5beans25XPropertiesChangeListenerEEE; +_ZN4cppu18OPropertySetHelper27addPropertiesChangeListenerERKN3com3sun4star3uno8SequenceIN3rtl8OUStringEEERKNS4_9ReferenceINS3_5beans25XPropertiesChangeListenerEEE; +_ZN4cppu18OPropertySetHelper28removePropertyChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XPropertyChangeListenerEEE; +_ZN4cppu18OPropertySetHelper28removeVetoableChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XVetoableChangeListenerEEE; +_ZN4cppu18OPropertySetHelper30removePropertiesChangeListenerERKN3com3sun4star3uno9ReferenceINS3_5beans25XPropertiesChangeListenerEEE; +_ZN4cppu18OPropertySetHelper4fireEP?PKN3com3sun4star3uno3AnyES8_?h; +_ZN4cppu18OPropertySetHelper9disposingEv; +_ZN4cppu18OPropertySetHelperC1ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEE; +_ZN4cppu18OPropertySetHelperC2ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEE; +_ZN4cppu18OPropertySetHelperD1Ev; +_ZN4cppu18OPropertySetHelperD2Ev; +_ZN4cppu18bootstrapInitialSFERKN3rtl8OUStringE; +_ZN4cppu18createFactoryProxyERKN3com3sun4star3uno9ReferenceINS2_4lang20XMultiServiceFactoryEEERKNS4_INS5_21XSingleServiceFactoryEEE; +_ZN4cppu19ImplHelper_getTypesEPNS_10class_dataE; +_ZN4cppu19createSingleFactoryERKN3com3sun4star3uno9ReferenceINS2_4lang20XMultiServiceFactoryEEERKN3rtl8OUStringEPFNS4_INS3_10XInterfaceEEES9_ERKNS3_8SequenceISB_EEP16_rtl_ModuleCount; +_ZN4cppu20IPropertyArrayHelperD0Ev; +_ZN4cppu20IPropertyArrayHelperD1Ev; +_ZN4cppu20IPropertyArrayHelperD2Ev; +_ZN4cppu20OPropertyArrayHelper11fillHandlesEP?RKN3com3sun4star3uno8SequenceIN3rtl8OUStringEEE; +_ZN4cppu20OPropertyArrayHelper13getPropertiesEv; +_ZN4cppu20OPropertyArrayHelper15getHandleByNameERKN3rtl8OUStringE; +_ZN4cppu20OPropertyArrayHelper17getPropertyByNameERKN3rtl8OUStringE; +_ZN4cppu20OPropertyArrayHelper17hasPropertyByNameERKN3rtl8OUStringE; +_ZN4cppu20OPropertyArrayHelper27fillPropertyMembersByHandleEPN3rtl8OUStringEPs?; +_ZN4cppu20OPropertyArrayHelper4initEh; +_ZN4cppu20OPropertyArrayHelperC1EPN3com3sun4star5beans8PropertyE?h; +_ZN4cppu20OPropertyArrayHelperC1ERKN3com3sun4star3uno8SequenceINS3_5beans8PropertyEEEh; +_ZN4cppu20OPropertyArrayHelperC2EPN3com3sun4star5beans8PropertyE?h; +_ZN4cppu20OPropertyArrayHelperC2ERKN3com3sun4star3uno8SequenceINS3_5beans8PropertyEEEh; +_ZN4cppu20WeakImplHelper_queryERKN3com3sun4star3uno4TypeEPNS_10class_dataEPvPNS_11OWeakObjectE; +_ZN4cppu20createNestedRegistryERKN3rtl8OUStringE; +_ZN4cppu20createSimpleRegistryERKN3rtl8OUStringE; +_ZN4cppu22ImplInhHelper_getTypesEPNS_10class_dataERKN3com3sun4star3uno8SequenceINS5_4TypeEEE; +_ZN4cppu22createComponentContextEPKNS_17ContextEntry_InitE?RKN3com3sun4star3uno9ReferenceINS6_17XComponentContextEEE; +_ZN4cppu22getImplHelperInitMutexEv; +_ZN4cppu23WeakImplHelper_getTypesEPNS_10class_dataE; +_ZN4cppu24OInterfaceIteratorHelper4nextEv; +_ZN4cppu24OInterfaceIteratorHelper6removeEv; +_ZN4cppu24OInterfaceIteratorHelperC1ERNS_25OInterfaceContainerHelperE; +_ZN4cppu24OInterfaceIteratorHelperC2ERNS_25OInterfaceContainerHelperE; +_ZN4cppu24OInterfaceIteratorHelperD1Ev; +_ZN4cppu24OInterfaceIteratorHelperD2Ev; +_ZN4cppu24createOneInstanceFactoryERKN3com3sun4star3uno9ReferenceINS2_4lang20XMultiServiceFactoryEEERKN3rtl8OUStringEPFNS4_INS3_10XInterfaceEEES9_ERKNS3_8SequenceISB_EEP16_rtl_ModuleCount; +_ZN4cppu25OInterfaceContainerHelper12addInterfaceERKN3com3sun4star3uno9ReferenceINS4_10XInterfaceEEE; +_ZN4cppu25OInterfaceContainerHelper15disposeAndClearERKN3com3sun4star4lang11EventObjectE; +_ZN4cppu25OInterfaceContainerHelper15removeInterfaceERKN3com3sun4star3uno9ReferenceINS4_10XInterfaceEEE; +_ZN4cppu25OInterfaceContainerHelper17copyAndResetInUseEv; +_ZN4cppu25OInterfaceContainerHelper5clearEv; +_ZN4cppu25OInterfaceContainerHelperC1ERN3osl5MutexE; +_ZN4cppu25OInterfaceContainerHelperC2ERN3osl5MutexE; +_ZN4cppu25OInterfaceContainerHelperD1Ev; +_ZN4cppu25OInterfaceContainerHelperD2Ev; +_ZN4cppu25component_writeInfoHelperEPvS0_PKNS_19ImplementationEntryE; +_ZN4cppu26WeakAggImplHelper_getTypesEPNS_10class_dataE; +_ZN4cppu26WeakAggImplHelper_queryAggERKN3com3sun4star3uno4TypeEPNS_10class_dataEPvPNS_14OWeakAggObjectE; +_ZN4cppu26component_getFactoryHelperEPKcPvS2_PKNS_19ImplementationEntryE; +_ZN4cppu27WeakComponentImplHelperBase14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZN4cppu27WeakComponentImplHelperBase16addEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZN4cppu27WeakComponentImplHelperBase19removeEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZN4cppu27WeakComponentImplHelperBase7acquireEv; +_ZN4cppu27WeakComponentImplHelperBase7disposeEv; +_ZN4cppu27WeakComponentImplHelperBase7releaseEv; +_ZN4cppu27WeakComponentImplHelperBase9disposingEv; +_ZN4cppu27WeakComponentImplHelperBaseC1ERN3osl5MutexE; +_ZN4cppu27WeakComponentImplHelperBaseC2ERN3osl5MutexE; +_ZN4cppu27WeakComponentImplHelperBaseD0Ev; +_ZN4cppu27WeakComponentImplHelperBaseD1Ev; +_ZN4cppu27WeakComponentImplHelperBaseD2Ev; +_ZN4cppu27createSingleRegistryFactoryERKN3com3sun4star3uno9ReferenceINS2_4lang20XMultiServiceFactoryEEERKN3rtl8OUStringERKNS4_INS2_8registry12XRegistryKeyEEE; +_ZN4cppu27writeSharedLibComponentInfoERKN3rtl8OUStringES3_RKN3com3sun4star3uno9ReferenceINS6_4lang20XMultiServiceFactoryEEERKNS8_INS6_8registry12XRegistryKeyEEE; +_ZN4cppu28ImplHelper_queryNoXInterfaceERKN3com3sun4star3uno4TypeEPNS_10class_dataEPv; +_ZN4cppu28createRegistryServiceFactoryERKN3rtl8OUStringES3_hS3_; +_ZN4cppu28createSingleComponentFactoryEPFN3com3sun4star3uno9ReferenceINS3_10XInterfaceEEERKNS4_INS3_17XComponentContextEEEERKN3rtl8OUStringERKNS3_8SequenceISE_EEP16_rtl_ModuleCount; +_ZN4cppu29WeakComponentImplHelper_queryERKN3com3sun4star3uno4TypeEPNS_10class_dataEPvPNS_27WeakComponentImplHelperBaseE; +_ZN4cppu29installTypeDescriptionManagerERKN3com3sun4star3uno9ReferenceINS2_9container23XHierarchicalNameAccessEEE; +_ZN4cppu28invokeStaticComponentFactoryEPFvvERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS8_4lang20XMultiServiceFactoryEEERKNSA_INS8_8registry12XRegistryKeyEEES5_; +_ZN4cppu29loadSharedLibComponentFactoryERKN3rtl8OUStringES3_S3_RKN3com3sun4star3uno9ReferenceINS6_4lang20XMultiServiceFactoryEEERKNS8_INS6_8registry12XRegistryKeyEEE; +_ZN4cppu29loadSharedLibComponentFactoryERKN3rtl8OUStringES3_S3_RKN3com3sun4star3uno9ReferenceINS6_4lang20XMultiServiceFactoryEEERKNS8_INS6_8registry12XRegistryKeyEEES3_; +_ZN4cppu30ImplHelper_getImplementationIdEPNS_10class_dataE; +_ZN4cppu30WeakAggComponentImplHelperBase14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZN4cppu30WeakAggComponentImplHelperBase16addEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZN4cppu30WeakAggComponentImplHelperBase16queryAggregationERKN3com3sun4star3uno4TypeE; +_ZN4cppu30WeakAggComponentImplHelperBase19removeEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZN4cppu30WeakAggComponentImplHelperBase7acquireEv; +_ZN4cppu30WeakAggComponentImplHelperBase7disposeEv; +_ZN4cppu30WeakAggComponentImplHelperBase7releaseEv; +_ZN4cppu30WeakAggComponentImplHelperBase9disposingEv; +_ZN4cppu30WeakAggComponentImplHelperBaseC1ERN3osl5MutexE; +_ZN4cppu30WeakAggComponentImplHelperBaseC2ERN3osl5MutexE; +_ZN4cppu30WeakAggComponentImplHelperBaseD0Ev; +_ZN4cppu30WeakAggComponentImplHelperBaseD1Ev; +_ZN4cppu30WeakAggComponentImplHelperBaseD2Ev; +_ZN4cppu31createStandardClassWithSequenceERKN3com3sun4star3uno9ReferenceINS2_4lang20XMultiServiceFactoryEEERKN3rtl8OUStringERKNS4_INS2_10reflection9XIdlClassEEERKNS3_8SequenceISB_EE; +_ZN4cppu32WeakComponentImplHelper_getTypesEPNS_10class_dataE; +_ZN4cppu32createOneInstanceRegistryFactoryERKN3com3sun4star3uno9ReferenceINS2_4lang20XMultiServiceFactoryEEERKN3rtl8OUStringERKNS4_INS2_8registry12XRegistryKeyEEE; +_ZN4cppu33bootstrap_InitialComponentContextERKN3com3sun4star3uno9ReferenceINS2_8registry15XSimpleRegistryEEERKN3rtl8OUStringE; +_ZN4cppu34OMultiTypeInterfaceContainerHelper12addInterfaceERKN3com3sun4star3uno4TypeERKNS4_9ReferenceINS4_10XInterfaceEEE; +_ZN4cppu34OMultiTypeInterfaceContainerHelper15disposeAndClearERKN3com3sun4star4lang11EventObjectE; +_ZN4cppu34OMultiTypeInterfaceContainerHelper15removeInterfaceERKN3com3sun4star3uno4TypeERKNS4_9ReferenceINS4_10XInterfaceEEE; +_ZN4cppu34OMultiTypeInterfaceContainerHelper5clearEv; +_ZN4cppu34OMultiTypeInterfaceContainerHelperC1ERN3osl5MutexE; +_ZN4cppu34OMultiTypeInterfaceContainerHelperC2ERN3osl5MutexE; +_ZN4cppu34OMultiTypeInterfaceContainerHelperD1Ev; +_ZN4cppu34OMultiTypeInterfaceContainerHelperD2Ev; +_ZN4cppu35WeakAggComponentImplHelper_getTypesEPNS_10class_dataE; +_ZN4cppu35WeakAggComponentImplHelper_queryAggERKN3com3sun4star3uno4TypeEPNS_10class_dataEPvPNS_30WeakAggComponentImplHelperBaseE; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt3212addInterfaceERK?RKN3com3sun4star3uno9ReferenceINS6_10XInterfaceEEE; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt3215disposeAndClearERKN3com3sun4star4lang11EventObjectE; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt3215removeInterfaceERK?RKN3com3sun4star3uno9ReferenceINS6_10XInterfaceEEE; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt325clearEv; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt32C1ERN3osl5MutexE; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt32C2ERN3osl5MutexE; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt32D1Ev; +_ZN4cppu39OMultiTypeInterfaceContainerHelperInt32D2Ev; +_ZN4cppu40defaultBootstrap_InitialComponentContextERKN3rtl8OUStringE; +_ZN4cppu40defaultBootstrap_InitialComponentContextEv; +_ZN4cppu9ClassData15writeTypeOffsetERKN3com3sun4star3uno4TypeE?; +_ZN4cppu9ClassData16initTypeProviderEv; +_ZN4cppu9ClassData19getImplementationIdEv; +_ZN4cppu9ClassData5queryERKN3com3sun4star3uno4TypeEPNS3_4lang13XTypeProviderE; +_ZN4cppu9ClassData8getTypesEv; +_ZNK3com3sun4star3uno19WeakReferenceHelper3getEv; +_ZNK4cppu17OImplementationId19getImplementationIdEv; +_ZNK4cppu20OPropertyArrayHelper8getCountEv; +_ZNK4cppu25OInterfaceContainerHelper11getElementsEv; +_ZNK4cppu25OInterfaceContainerHelper9getLengthEv; +_ZNK4cppu34OMultiTypeInterfaceContainerHelper12getContainerERKN3com3sun4star3uno4TypeE; +_ZNK4cppu34OMultiTypeInterfaceContainerHelper17getContainedTypesEv; +_ZNK4cppu39OMultiTypeInterfaceContainerHelperInt3212getContainerERK?; +_ZNK4cppu39OMultiTypeInterfaceContainerHelperInt3217getContainedTypesEv; +_ZTVN4cppu11OWeakObjectE; +_ZTVN4cppu14OWeakAggObjectE; +_ZTVN4cppu16OComponentHelperE; +_ZTVN4cppu18OPropertySetHelperE; +_ZTVN4cppu20IPropertyArrayHelperE; +_ZTVN4cppu20OPropertyArrayHelperE; +_ZTVN4cppu27WeakComponentImplHelperBaseE; +_ZTVN4cppu30WeakAggComponentImplHelperBaseE; +_ZN4cppu20OPropertyArrayHelperD0Ev; +_ZN4cppu20OPropertyArrayHelperD1Ev; +_ZThn*_N4cppu14OWeakAggObject12setDelegatorERKN3com3sun4star3uno9ReferenceINS4_10XInterfaceEEE; +_ZThn*_N4cppu14OWeakAggObject14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu14OWeakAggObject16queryAggregationERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu14OWeakAggObject7acquireEv; +_ZThn*_N4cppu14OWeakAggObject7releaseEv; +_ZThn*_N4cppu16OComponentHelper14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu16OComponentHelper16queryAggregationERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu16OComponentHelper7acquireEv; +_ZThn*_N4cppu16OComponentHelper7releaseEv; +_ZThn*_N4cppu27WeakComponentImplHelperBase14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu27WeakComponentImplHelperBase16addEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZThn*_N4cppu27WeakComponentImplHelperBase19removeEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZThn*_N4cppu27WeakComponentImplHelperBase7acquireEv; +_ZThn*_N4cppu27WeakComponentImplHelperBase7disposeEv; +_ZThn*_N4cppu27WeakComponentImplHelperBase7releaseEv; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase16queryAggregationERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase7acquireEv; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase7releaseEv; +_ZThn*_N4cppu16OComponentHelper14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu16OComponentHelper7acquireEv; +_ZThn*_N4cppu16OComponentHelper7releaseEv; +_ZThn*_N4cppu16OComponentHelper8getTypesEv; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase16addEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase19removeEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase7acquireEv; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase7disposeEv; +_ZThn*_N4cppu30WeakAggComponentImplHelperBase7releaseEv; +_ZThn*_N4cppu16OComponentHelper14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu16OComponentHelper16addEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZThn*_N4cppu16OComponentHelper19removeEventListenerERKN3com3sun4star3uno9ReferenceINS3_4lang14XEventListenerEEE; +_ZThn*_N4cppu16OComponentHelper7acquireEv; +_ZThn*_N4cppu16OComponentHelper7disposeEv; +_ZThn*_N4cppu16OComponentHelper7releaseEv; +_ZThn*_N4cppu18OPropertySetHelper14queryInterfaceERKN3com3sun4star3uno4TypeE; +_ZThn*_N4cppu18OPropertySetHelper20getFastPropertyValueE?; +_ZThn*_N4cppu18OPropertySetHelper20setFastPropertyValueE?RKN3com3sun4star3uno3AnyE; +_ZThn*_N4cppu18OPropertySetHelper16getPropertyValueERKN3rtl8OUStringE; +_ZThn*_N4cppu18OPropertySetHelper16setPropertyValueERKN3rtl8OUStringERKN3com3sun4star3uno3AnyE; +_ZThn*_N4cppu18OPropertySetHelper25addPropertyChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XPropertyChangeListenerEEE; +_ZThn*_N4cppu18OPropertySetHelper25addVetoableChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XVetoableChangeListenerEEE; +_ZThn*_N4cppu18OPropertySetHelper28removePropertyChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XPropertyChangeListenerEEE; +_ZThn*_N4cppu18OPropertySetHelper28removeVetoableChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XVetoableChangeListenerEEE; + +_ZN4cppu13AccessControl19checkFilePermissionERKN3rtl8OUStringES4_; +_ZN4cppu13AccessControl21checkSocketPermissionERKN3rtl8OUStringES4_; +_ZN4cppu13AccessControl22checkRuntimePermissionERKN3rtl8OUStringE; +_ZN4cppu13AccessControlC1ERKN3com3sun4star3uno9ReferenceINS3_8security17XAccessControllerEEE; +_ZN4cppu13AccessControlC2ERKN3com3sun4star3uno9ReferenceINS3_8security17XAccessControllerEEE; +_ZN4cppu13AccessControlC1ERKN3com3sun4star3uno9ReferenceINS4_17XComponentContextEEE; +_ZN4cppu13AccessControlC2ERKN3com3sun4star3uno9ReferenceINS4_17XComponentContextEEE; +_ZN4cppu13AccessControlC1ERKS0_; +_ZN4cppu13AccessControlC2ERKS0_; + +_ZN4cppu16UnoUrlDescriptorC1ERKN3rtl8OUStringE; +_ZN4cppu16UnoUrlDescriptorC1ERKS0_; +_ZN4cppu16UnoUrlDescriptorC2ERKN3rtl8OUStringE; +_ZN4cppu16UnoUrlDescriptorC2ERKS0_; +_ZN4cppu16UnoUrlDescriptorD1Ev; +_ZN4cppu16UnoUrlDescriptorD2Ev; +_ZN4cppu16UnoUrlDescriptoraSERKS0_; +_ZN4cppu6UnoUrlC1ERKN3rtl8OUStringE; +_ZN4cppu6UnoUrlC1ERKS0_; +_ZN4cppu6UnoUrlC2ERKN3rtl8OUStringE; +_ZN4cppu6UnoUrlC2ERKS0_; +_ZN4cppu6UnoUrlD1Ev; +_ZN4cppu6UnoUrlD2Ev; +_ZN4cppu6UnoUrlaSERKS0_; +_ZNK4cppu16UnoUrlDescriptor12getParameterERKN3rtl8OUStringE; +_ZNK4cppu16UnoUrlDescriptor12hasParameterERKN3rtl8OUStringE; +_ZNK4cppu16UnoUrlDescriptor13getDescriptorEv; +_ZNK4cppu16UnoUrlDescriptor7getNameEv; +_ZNK4cppu6UnoUrl11getProtocolEv; +_ZNK4cppu6UnoUrl13getConnectionEv; +_ZNK4cppu6UnoUrl13getObjectNameEv; + + local: + *; +}; + +UDK_3.1 { + global: + _ZN4cppu18getCaughtExceptionEv; + + _ZN4cppu18OPropertySetHelperC1ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEEb; + _ZN4cppu18OPropertySetHelperC2ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEEb; + + _ZN4cppu9bootstrapEv; + _ZN4cppu18BootstrapExceptionC1Ev; + _ZN4cppu18BootstrapExceptionC2Ev; + _ZN4cppu18BootstrapExceptionC1ERKN3rtl8OUStringE; + _ZN4cppu18BootstrapExceptionC2ERKN3rtl8OUStringE; + _ZN4cppu18BootstrapExceptionC1ERKS0_; + _ZN4cppu18BootstrapExceptionC2ERKS0_; + _ZN4cppu18BootstrapExceptionD0Ev; + _ZN4cppu18BootstrapExceptionD1Ev; + _ZN4cppu18BootstrapExceptionD2Ev; + _ZN4cppu18BootstrapExceptionaSERKS0_; + _ZNK4cppu18BootstrapException10getMessageEv; + # _ZTIN4cppu18BootstrapExceptionE; + # _ZTSN4cppu18BootstrapExceptionE; +} UDK_3_0_0; + +UDK_3.2 { + global: + _ZN4cppu20PropertySetMixinImpl10prepareSetERKN3rtl8OUStringERKN3com3sun4star3uno3AnyESB_PNS0_14BoundListenersE; + _ZN4cppu20PropertySetMixinImpl14BoundListenersC1Ev; + _ZN4cppu20PropertySetMixinImpl14BoundListenersC2Ev; + _ZN4cppu20PropertySetMixinImpl14BoundListenersD1Ev; + _ZN4cppu20PropertySetMixinImpl14BoundListenersD2Ev; + _ZN4cppu20PropertySetMixinImpl14queryInterfaceERKN3com3sun4star3uno4TypeE; + _ZN4cppu20PropertySetMixinImpl16getPropertyValueERKN3rtl8OUStringE; + _ZN4cppu20PropertySetMixinImpl16setPropertyValueERKN3rtl8OUStringERKN3com3sun4star3uno3AnyE; + _ZN4cppu20PropertySetMixinImpl17getPropertyValuesEv; + _ZN4cppu20PropertySetMixinImpl17setPropertyValuesERKN3com3sun4star3uno8SequenceINS3_5beans13PropertyValueEEE; + _ZN4cppu20PropertySetMixinImpl18getPropertySetInfoEv; + _ZN4cppu20PropertySetMixinImpl20getFastPropertyValueE?; + _ZN4cppu20PropertySetMixinImpl20setFastPropertyValueE?RKN3com3sun4star3uno3AnyE; + _ZN4cppu20PropertySetMixinImpl25addPropertyChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XPropertyChangeListenerEEE; + _ZN4cppu20PropertySetMixinImpl25addVetoableChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XVetoableChangeListenerEEE; + _ZN4cppu20PropertySetMixinImpl28removePropertyChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XPropertyChangeListenerEEE; + _ZN4cppu20PropertySetMixinImpl28removeVetoableChangeListenerERKN3rtl8OUStringERKN3com3sun4star3uno9ReferenceINS7_5beans23XVetoableChangeListenerEEE; + _ZN4cppu20PropertySetMixinImpl7disposeEv; + _ZN4cppu20PropertySetMixinImplC1ERKN3com3sun4star3uno9ReferenceINS4_17XComponentContextEEENS0_10ImplementsERKNS4_8SequenceIN3rtl8OUStringEEERKNS4_4TypeE; + _ZN4cppu20PropertySetMixinImplC2ERKN3com3sun4star3uno9ReferenceINS4_17XComponentContextEEENS0_10ImplementsERKNS4_8SequenceIN3rtl8OUStringEEERKNS4_4TypeE; + _ZN4cppu20PropertySetMixinImplD1Ev; + _ZN4cppu20PropertySetMixinImplD2Ev; + _ZNK4cppu20PropertySetMixinImpl14BoundListeners6notifyEv; + _ZThn*_N4cppu20PropertySetMixinImpl14queryInterfaceERKN3com3sun4star3uno4TypeE; + _ZThn*_N4cppu20PropertySetMixinImpl20getFastPropertyValueE?; + _ZThn*_N4cppu20PropertySetMixinImpl20setFastPropertyValueE?RKN3com3sun4star3uno3AnyE; + _ZThn*_N4cppu20PropertySetMixinImpl14queryInterfaceERKN3com3sun4star3uno4TypeE; + _ZThn*_N4cppu20PropertySetMixinImpl17getPropertyValuesEv; + _ZThn*_N4cppu20PropertySetMixinImpl17setPropertyValuesERKN3com3sun4star3uno8SequenceINS3_5beans13PropertyValueEEE; +} UDK_3.1; + +UDK_3.3 { # OOo 2.3 + global: + _ZN4cppu18OPropertySetHelper8getTypesEv; +} UDK_3.2; + +UDK_3.4 { # OOo 2.4 + global: + _ZN4cppu19bootstrap_expandUriERKN3rtl8OUStringE; # OUString cppu::bootstrap_expandUri(OUString const &) +} UDK_3.3; + +UDK_3.5 { # OOo 3.0 + global: + _ZN4cppu18OPropertySetHelperC1ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEEPNS_22IEventNotificationHookEb; + _ZN4cppu18OPropertySetHelperC2ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEEPNS_22IEventNotificationHookEb; +} UDK_3.4; + +UDK_3.6 { # OOo 3.3 + global: + _ZN4cppu11OWeakObject26disposeWeakConnectionPointEv; + _ZN3com3sun4star3uno19WeakReferenceHelperaSERKNS2_9ReferenceINS2_10XInterfaceEEE; + _ZN3com3sun4star3uno19WeakReferenceHelper5clearEv; + _ZN4cppu33createOneInstanceComponentFactoryEPFN3com3sun4star3uno9ReferenceINS3_10XInterfaceEEERKNS4_INS3_17XComponentContextEEEERKN3rtl8OUStringERKNS3_8SequenceISE_EEP16_rtl_ModuleCount; +} UDK_3.5; + + +UDK_3.7 { # OOo 3.4 + global: + _ZN4cppu18OPropertySetHelper29setDependentFastPropertyValueE?RKN3com3sun4star3uno3AnyE; +} UDK_3.6; + +UDK_3.8 { # LibO 3.5 +global: + ## class OPropertySetHelper2 + # constructors + _ZN4cppu19OPropertySetHelper2C1ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEEPNS_22IEventNotificationHookEb; + _ZN4cppu19OPropertySetHelper2C2ERNS_19OBroadcastHelperVarINS_34OMultiTypeInterfaceContainerHelperEN3com3sun4star3uno4TypeEEEPNS_22IEventNotificationHookEb; + # destructors + _ZN4cppu19OPropertySetHelper2D0Ev; + _ZN4cppu19OPropertySetHelper2D1Ev; + _ZN4cppu19OPropertySetHelper2D2Ev; + # queryInterface + _ZN4cppu19OPropertySetHelper214queryInterfaceERKN3com3sun4star3uno4TypeE; + _ZThn*_N4cppu19OPropertySetHelper214queryInterfaceERKN3com3sun4star3uno4TypeE; + # enableChangeListenerNotification + _ZN4cppu19OPropertySetHelper232enableChangeListenerNotificationEh; + _ZThn*_N4cppu19OPropertySetHelper232enableChangeListenerNotificationEh; +} UDK_3.7; + +LIBO_UDK_3.9 { # LibO 3.7 +global: + _ZN4cppu15supportsServiceEPN3com3sun4star4lang12XServiceInfoERKN3rtl8OUStringE; # cppu::supportsService(com::sun::star::lang::XServiceInfo*, OUString const&) +} UDK_3.8; + +LIBO_UDK_5.3 { # LibO 5.3 +global: + _ZN3com3sun4star3uno19WeakReferenceHelperaSEOS3_; # com::sun::star::uno::WeakReferenceHelper::operator=(com::sun::star::uno::WeakReferenceHelper&&) +} LIBO_UDK_3.9; + +# Unique libstdc++ symbols: +GLIBCXX_3.4 { + global: + _ZGVNSt7num_put*; _ZNSt7num_put*; + _ZNSs4_Rep20_S_empty_rep_storageE; +}; diff --git a/cppuhelper/source/implbase.cxx b/cppuhelper/source/implbase.cxx new file mode 100644 index 000000000..1f00accec --- /dev/null +++ b/cppuhelper/source/implbase.cxx @@ -0,0 +1,285 @@ +/* -*- 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 <cppuhelper/compbase_ex.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> + +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/uno/RuntimeException.hpp> + +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +namespace cppu +{ + +// WeakComponentImplHelperBase + +WeakComponentImplHelperBase::WeakComponentImplHelperBase( Mutex & rMutex ) + : rBHelper( rMutex ) +{ +} + +WeakComponentImplHelperBase::~WeakComponentImplHelperBase() +{ +} + +void WeakComponentImplHelperBase::disposing() +{ +} + +Any WeakComponentImplHelperBase::queryInterface( Type const & rType ) +{ + if (rType == cppu::UnoType<lang::XComponent>::get()) + { + void * p = static_cast< lang::XComponent * >( this ); + return Any( &p, rType ); + } + return OWeakObject::queryInterface( rType ); +} + +void WeakComponentImplHelperBase::acquire() + throw () +{ + OWeakObject::acquire(); +} + +void WeakComponentImplHelperBase::release() + throw () +{ + if (osl_atomic_decrement( &m_refCount ) != 0) + return; + + // ensure no other references are created, via the weak connection point, from now on + disposeWeakConnectionPoint(); + // restore reference count: + osl_atomic_increment( &m_refCount ); + if (! rBHelper.bDisposed) { + try { + dispose(); + } + catch (RuntimeException const& exc) { // don't break throw () + SAL_WARN( "cppuhelper", exc ); + } + OSL_ASSERT( rBHelper.bDisposed ); + } + OWeakObject::release(); +} + +void WeakComponentImplHelperBase::dispose() +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if (rBHelper.bDisposed || rBHelper.bInDispose) + return; + + rBHelper.bInDispose = true; + aGuard.clear(); + try + { + // side effect: keeping a reference to this + lang::EventObject aEvt( static_cast< OWeakObject * >( this ) ); + try + { + rBHelper.aLC.disposeAndClear( aEvt ); + disposing(); + } + catch (...) + { + MutexGuard aGuard2( rBHelper.rMutex ); + // bDisposed and bInDispose must be set in this order: + rBHelper.bDisposed = true; + rBHelper.bInDispose = false; + throw; + } + MutexGuard aGuard2( rBHelper.rMutex ); + // bDisposed and bInDispose must be set in this order: + rBHelper.bDisposed = true; + rBHelper.bInDispose = false; + } + catch (RuntimeException &) + { + throw; + } + catch (Exception & exc) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException( + "unexpected UNO exception caught: " + exc.Message, + nullptr, anyEx ); + } +} + +void WeakComponentImplHelperBase::addEventListener( + Reference< lang::XEventListener > const & xListener ) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + lang::EventObject aEvt( static_cast< OWeakObject * >( this ) ); + xListener->disposing( aEvt ); + } + else + { + rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener ); + } +} + +void WeakComponentImplHelperBase::removeEventListener( + Reference< lang::XEventListener > const & xListener ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + +// WeakAggComponentImplHelperBase + +WeakAggComponentImplHelperBase::WeakAggComponentImplHelperBase( Mutex & rMutex ) + : rBHelper( rMutex ) +{ +} + +WeakAggComponentImplHelperBase::~WeakAggComponentImplHelperBase() +{ +} + +void WeakAggComponentImplHelperBase::disposing() +{ +} + +Any WeakAggComponentImplHelperBase::queryInterface( Type const & rType ) +{ + return OWeakAggObject::queryInterface( rType ); +} + +Any WeakAggComponentImplHelperBase::queryAggregation( Type const & rType ) +{ + if (rType == cppu::UnoType<lang::XComponent>::get()) + { + void * p = static_cast< lang::XComponent * >( this ); + return Any( &p, rType ); + } + return OWeakAggObject::queryAggregation( rType ); +} + +void WeakAggComponentImplHelperBase::acquire() + throw () +{ + OWeakAggObject::acquire(); +} + +void WeakAggComponentImplHelperBase::release() + throw () +{ + Reference<XInterface> const xDelegator_(xDelegator); + if (xDelegator_.is()) { + OWeakAggObject::release(); + } + else if (osl_atomic_decrement( &m_refCount ) == 0) { + // ensure no other references are created, via the weak connection point, from now on + disposeWeakConnectionPoint(); + // restore reference count: + osl_atomic_increment( &m_refCount ); + if (! rBHelper.bDisposed) { + try { + dispose(); + } + catch (RuntimeException const& exc) { // don't break throw () + SAL_WARN( "cppuhelper", exc ); + } + OSL_ASSERT( rBHelper.bDisposed ); + } + OWeakAggObject::release(); + } +} + +void WeakAggComponentImplHelperBase::dispose() +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if (rBHelper.bDisposed || rBHelper.bInDispose) + return; + + rBHelper.bInDispose = true; + aGuard.clear(); + try + { + // side effect: keeping a reference to this + lang::EventObject aEvt( static_cast< OWeakObject * >( this ) ); + try + { + rBHelper.aLC.disposeAndClear( aEvt ); + disposing(); + } + catch (...) + { + MutexGuard aGuard2( rBHelper.rMutex ); + // bDisposed and bInDispose must be set in this order: + rBHelper.bDisposed = true; + rBHelper.bInDispose = false; + throw; + } + MutexGuard aGuard2( rBHelper.rMutex ); + // bDisposed and bInDispose must be set in this order: + rBHelper.bDisposed = true; + rBHelper.bInDispose = false; + } + catch (RuntimeException &) + { + throw; + } + catch (Exception & exc) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException( + "unexpected UNO exception caught: " + exc.Message, + nullptr, anyEx ); + } +} + +void WeakAggComponentImplHelperBase::addEventListener( + Reference< lang::XEventListener > const & xListener ) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if (rBHelper.bDisposed || rBHelper.bInDispose) + { + aGuard.clear(); + lang::EventObject aEvt( static_cast< OWeakObject * >( this ) ); + xListener->disposing( aEvt ); + } + else + { + rBHelper.addListener( cppu::UnoType<decltype(xListener)>::get(), xListener ); + } +} + +void WeakAggComponentImplHelperBase::removeEventListener( + Reference< lang::XEventListener > const & xListener ) +{ + // if we have disposed, then we have cleared the list already + MutexGuard aGuard( rBHelper.rMutex ); + if (!rBHelper.bDisposed) + rBHelper.removeListener( cppu::UnoType<decltype(xListener)>::get(), xListener ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/implbase_ex.cxx b/cppuhelper/source/implbase_ex.cxx new file mode 100644 index 000000000..00eeaf376 --- /dev/null +++ b/cppuhelper/source/implbase_ex.cxx @@ -0,0 +1,413 @@ +/* -*- 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 <osl/diagnose.h> +#include <sal/log.hxx> +#include <cppuhelper/compbase_ex.hxx> +#include <cppuhelper/implbase_ex.hxx> + +#include <com/sun/star/uno/RuntimeException.hpp> + +using namespace ::cppu; +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace +{ + class theImplHelperInitMutex : public rtl::Static<Mutex, theImplHelperInitMutex>{}; +} + +namespace cppu +{ + +/** Shared mutex for implementation helper initialization. + Not for public use. +*/ +static ::osl::Mutex & getImplHelperInitMutex() +{ + return theImplHelperInitMutex::get(); +} + + +static void checkInterface( Type const & rType ) +{ + if (TypeClass_INTERFACE != rType.getTypeClass()) + { + OUString msg( "querying for interface \"" + rType.getTypeName() + "\": no interface type!" ); + SAL_WARN( "cppuhelper", msg ); + throw RuntimeException( msg ); + } +} + +static bool isXInterface( rtl_uString * pStr ) +{ + return OUString::unacquired(&pStr) == "com.sun.star.uno.XInterface"; +} + +static void * makeInterface( sal_IntPtr nOffset, void * that ) +{ + return (static_cast<char *>(that) + nOffset); +} + +static bool td_equals( + typelib_TypeDescriptionReference const * pTDR1, + typelib_TypeDescriptionReference const * pTDR2 ) +{ + return ((pTDR1 == pTDR2) || + OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName)); +} + +static type_entry * getTypeEntries( class_data * cd ) +{ + type_entry * pEntries = cd->m_typeEntries; + if (! cd->m_storedTypeRefs) // not inited? + { + MutexGuard guard( getImplHelperInitMutex() ); + if (! cd->m_storedTypeRefs) // not inited? + { + // get all types + for ( sal_Int32 n = cd->m_nTypes; n--; ) + { + type_entry * pEntry = &pEntries[ n ]; + Type const & rType = (*pEntry->m_type.getCppuType)( nullptr ); + OSL_ENSURE( rType.getTypeClass() == TypeClass_INTERFACE, "### wrong helper init: expected interface!" ); + OSL_ENSURE( ! isXInterface( rType.getTypeLibType()->pTypeName ), "### want to implement XInterface: template argument is XInterface?!?!?!" ); + if (rType.getTypeClass() != TypeClass_INTERFACE) + { + OUString msg( "type \"" + rType.getTypeName() + "\" is no interface type!" ); + SAL_WARN( "cppuhelper", msg ); + throw RuntimeException( msg ); + } + // ref is statically held by getCppuType() + pEntry->m_type.typeRef = rType.getTypeLibType(); + } + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + cd->m_storedTypeRefs = true; + } + } + else + { + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + } + return pEntries; +} + +static void fillTypes( Type * types, class_data * cd ) +{ + type_entry * pEntries = getTypeEntries( cd ); + for ( sal_Int32 n = cd->m_nTypes; n--; ) + { + types[ n ] = pEntries[ n ].m_type.typeRef; + } +} + +namespace { + +bool recursivelyFindType( + typelib_TypeDescriptionReference const * demandedType, + typelib_InterfaceTypeDescription const * type, sal_IntPtr * offset) +{ + // This code assumes that the vtables of a multiple-inheritance class (the + // offset amount by which to adjust the this pointer) follow one another in + // the object layout, and that they contain slots for the inherited classes + // in a specific order. In theory, that need not hold for any given + // platform; in practice, it seems to work well on all supported platforms: + next: + for (sal_Int32 i = 0; i < type->nBaseTypes; ++i) { + if (i > 0) { + *offset += sizeof (void *); + } + typelib_InterfaceTypeDescription const * base = type->ppBaseTypes[i]; + // ignore XInterface: + if (base->nBaseTypes > 0) { + if (td_equals( + reinterpret_cast< + typelib_TypeDescriptionReference const * >(base), + demandedType)) + { + return true; + } + // Profiling showed that it is important to speed up the common case + // of only one base: + if (type->nBaseTypes == 1) { + type = base; + goto next; + } + if (recursivelyFindType(demandedType, base, offset)) { + return true; + } + } + } + return false; +} + +} + +static void * queryDeepNoXInterface( + typelib_TypeDescriptionReference const * pDemandedTDR, class_data * cd, void * that ) +{ + type_entry * pEntries = getTypeEntries( cd ); + sal_Int32 nTypes = cd->m_nTypes; + sal_Int32 n; + + // try top interfaces without getting td + for ( n = 0; n < nTypes; ++n ) + { + if (td_equals( pEntries[ n ].m_type.typeRef, pDemandedTDR )) + { + return makeInterface( pEntries[ n ].m_offset, that ); + } + } + // query deep getting td + for ( n = 0; n < nTypes; ++n ) + { + typelib_TypeDescription * pTD = nullptr; + TYPELIB_DANGER_GET( &pTD, pEntries[ n ].m_type.typeRef ); + if (pTD) + { + // exclude top (already tested) and bottom (XInterface) interface + OSL_ENSURE( + reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD)-> + nBaseTypes > 0, + "### want to implement XInterface:" + " template argument is XInterface?!?!?!" ); + sal_IntPtr offset = pEntries[n].m_offset; + bool found = recursivelyFindType( + pDemandedTDR, + reinterpret_cast< typelib_InterfaceTypeDescription * >(pTD), + &offset); + TYPELIB_DANGER_RELEASE( pTD ); + if (found) { + return makeInterface( offset, that ); + } + } + else + { + OUString msg( "cannot get type description for type \"" + OUString::unacquired(&pEntries[ n ].m_type.typeRef->pTypeName) + "\"!" ); + SAL_WARN( "cppuhelper", msg ); + throw RuntimeException( msg ); + } + } + return nullptr; +} + +// ImplHelper + +Any SAL_CALL ImplHelper_query( + Type const & rType, class_data * cd, void * that ) +{ + checkInterface( rType ); + typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); + + void * p; + // shortcut for XInterface + if (isXInterface( pTDR->pTypeName )) + { + // take first one + p = makeInterface( cd->m_typeEntries[ 0 ].m_offset, that ); + } + else + { + p = queryDeepNoXInterface( pTDR, cd, that ); + if (! p) + { + return Any(); + } + } + return Any( &p, pTDR ); +} + +Any SAL_CALL ImplHelper_queryNoXInterface( + Type const & rType, class_data * cd, void * that ) +{ + checkInterface( rType ); + typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); + + void * p = queryDeepNoXInterface( pTDR, cd, that ); + if (p) + { + return Any( &p, pTDR ); + } + return Any(); +} + +css::uno::Sequence<sal_Int8> ImplHelper_getImplementationId( + SAL_UNUSED_PARAMETER class_data *) +{ + return css::uno::Sequence<sal_Int8>(); +} + +Sequence< Type > SAL_CALL ImplHelper_getTypes( + class_data * cd ) +{ + Sequence< Type > types( cd->m_nTypes ); + Type * pTypes = types.getArray(); + fillTypes( pTypes, cd ); + return types; +} + +Sequence< Type > SAL_CALL ImplInhHelper_getTypes( + class_data * cd, Sequence< Type > const & rAddTypes ) +{ + sal_Int32 nImplTypes = cd->m_nTypes; + sal_Int32 nAddTypes = rAddTypes.getLength(); + Sequence< Type > types( nImplTypes + nAddTypes ); + Type * pTypes = types.getArray(); + fillTypes( pTypes, cd ); + // append base types + Type const * pAddTypes = rAddTypes.getConstArray(); + while (nAddTypes--) + { + pTypes[ nImplTypes + nAddTypes ] = pAddTypes[ nAddTypes ]; + } + return types; +} + +// WeakImplHelper + +Any SAL_CALL WeakImplHelper_query( + Type const & rType, class_data * cd, void * that, OWeakObject * pBase ) +{ + checkInterface( rType ); + typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); + + // shortcut XInterface to OWeakObject + if (! isXInterface( pTDR->pTypeName )) + { + void * p = queryDeepNoXInterface( pTDR, cd, that ); + if (p) + { + return Any( &p, pTDR ); + } + } + return pBase->OWeakObject::queryInterface( rType ); +} + +Sequence< Type > SAL_CALL WeakImplHelper_getTypes( + class_data * cd ) +{ + sal_Int32 nTypes = cd->m_nTypes; + Sequence< Type > types( nTypes +1 ); + Type * pTypes = types.getArray(); + fillTypes( pTypes, cd ); + pTypes[ nTypes ] = cppu::UnoType<XWeak>::get(); + return types; +} + +// WeakAggImplHelper + +Any SAL_CALL WeakAggImplHelper_queryAgg( + Type const & rType, class_data * cd, void * that, OWeakAggObject * pBase ) +{ + checkInterface( rType ); + typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); + + // shortcut XInterface to OWeakAggObject + if (! isXInterface( pTDR->pTypeName )) + { + void * p = queryDeepNoXInterface( pTDR, cd, that ); + if (p) + { + return Any( &p, pTDR ); + } + } + return pBase->OWeakAggObject::queryAggregation( rType ); +} + +Sequence< Type > SAL_CALL WeakAggImplHelper_getTypes( + class_data * cd ) +{ + sal_Int32 nTypes = cd->m_nTypes; + Sequence< Type > types( nTypes +2 ); + Type * pTypes = types.getArray(); + fillTypes( pTypes, cd ); + pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get(); + pTypes[ nTypes ] = cppu::UnoType<XAggregation>::get(); + return types; +} + +// WeakComponentImplHelper + +Any SAL_CALL WeakComponentImplHelper_query( + Type const & rType, class_data * cd, void * that, WeakComponentImplHelperBase * pBase ) +{ + checkInterface( rType ); + typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); + + // shortcut XInterface to WeakComponentImplHelperBase + if (! isXInterface( pTDR->pTypeName )) + { + void * p = queryDeepNoXInterface( pTDR, cd, that ); + if (p) + { + return Any( &p, pTDR ); + } + } + return pBase->WeakComponentImplHelperBase::queryInterface( rType ); +} + +Sequence< Type > SAL_CALL WeakComponentImplHelper_getTypes( + class_data * cd ) +{ + sal_Int32 nTypes = cd->m_nTypes; + Sequence< Type > types( nTypes +2 ); + Type * pTypes = types.getArray(); + fillTypes( pTypes, cd ); + pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get(); + pTypes[ nTypes ] = cppu::UnoType<lang::XComponent>::get(); + return types; +} + +// WeakAggComponentImplHelper + +Any SAL_CALL WeakAggComponentImplHelper_queryAgg( + Type const & rType, class_data * cd, void * that, WeakAggComponentImplHelperBase * pBase ) +{ + checkInterface( rType ); + typelib_TypeDescriptionReference * pTDR = rType.getTypeLibType(); + + // shortcut XInterface to WeakAggComponentImplHelperBase + if (! isXInterface( pTDR->pTypeName )) + { + void * p = queryDeepNoXInterface( pTDR, cd, that ); + if (p) + { + return Any( &p, pTDR ); + } + } + return pBase->WeakAggComponentImplHelperBase::queryAggregation( rType ); +} + +Sequence< Type > SAL_CALL WeakAggComponentImplHelper_getTypes( + class_data * cd ) +{ + sal_Int32 nTypes = cd->m_nTypes; + Sequence< Type > types( nTypes +3 ); + Type * pTypes = types.getArray(); + fillTypes( pTypes, cd ); + pTypes[ nTypes++ ] = cppu::UnoType<XWeak>::get(); + pTypes[ nTypes++ ] = cppu::UnoType<XAggregation>::get(); + pTypes[ nTypes ] = cppu::UnoType<lang::XComponent>::get(); + return types; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/implementationentry.cxx b/cppuhelper/source/implementationentry.cxx new file mode 100644 index 000000000..f28547dfa --- /dev/null +++ b/cppuhelper/source/implementationentry.cxx @@ -0,0 +1,94 @@ +/* -*- 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 <cppuhelper/implementationentry.hxx> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> + +#include <osl/diagnose.h> + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +namespace cppu { + +sal_Bool component_writeInfoHelper( + SAL_UNUSED_PARAMETER void *, void * pRegistryKey, + const struct ImplementationEntry entries[]) +{ + bool bRet = false; + try + { + if( pRegistryKey ) + { + for( sal_Int32 i = 0; entries[i].create ; i ++ ) + { + OUString sKey = "/" + entries[i].getImplementationName() + "/UNO/SERVICES"; + Reference< XRegistryKey > xNewKey( + static_cast< XRegistryKey * >( pRegistryKey )->createKey( sKey ) ); + + Sequence< OUString > seq = entries[i].getSupportedServiceNames(); + const OUString *pArray = seq.getConstArray(); + for ( sal_Int32 nPos = 0 ; nPos < seq.getLength(); nPos ++ ) + xNewKey->createKey( pArray[nPos] ); + } + bRet = true; + } + } + catch ( InvalidRegistryException & ) + { + OSL_FAIL( "### InvalidRegistryException!" ); + } + return bRet; +} + + +void * component_getFactoryHelper( + char const * pImplName, SAL_UNUSED_PARAMETER void *, + SAL_UNUSED_PARAMETER void *, const struct ImplementationEntry entries[]) +{ + + void * pRet = nullptr; + Reference< XSingleComponentFactory > xFactory; + + for( sal_Int32 i = 0 ; entries[i].create ; i ++ ) + { + OUString implName = entries[i].getImplementationName(); + if( implName.equalsAscii( pImplName ) ) + { + xFactory = entries[i].createFactory( + entries[i].create, + implName, + entries[i].getSupportedServiceNames(), + entries[i].moduleCounter ); + } + } + + if( xFactory.is() ) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + return pRet; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/interfacecontainer.cxx b/cppuhelper/source/interfacecontainer.cxx new file mode 100644 index 000000000..035f93848 --- /dev/null +++ b/cppuhelper/source/interfacecontainer.cxx @@ -0,0 +1,595 @@ +/* -*- 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 <cppuhelper/interfacecontainer.hxx> +#include <cppuhelper/propshlp.hxx> +#include <comphelper/sequence.hxx> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <sal/log.hxx> + +#include <memory> + +#include <com/sun/star/lang/XEventListener.hpp> + + +using namespace osl; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; + +namespace cppu +{ + +OInterfaceIteratorHelper::OInterfaceIteratorHelper( OInterfaceContainerHelper & rCont_ ) + : rCont( rCont_ ) +{ + MutexGuard aGuard( rCont.rMutex ); + if( rCont.bInUse ) + // worst case, two iterators at the same time + rCont.copyAndResetInUse(); + bIsList = rCont_.bIsList; + aData = rCont_.aData; + if( bIsList ) + { + rCont.bInUse = true; + nRemain = aData.pAsVector->size(); + } + else if( aData.pAsInterface ) + { + aData.pAsInterface->acquire(); + nRemain = 1; + } + else + nRemain = 0; +} + +OInterfaceIteratorHelper::~OInterfaceIteratorHelper() +{ + bool bShared; + { + MutexGuard aGuard( rCont.rMutex ); + // bResetInUse protect the iterator against recursion + bShared = aData.pAsVector == rCont.aData.pAsVector && rCont.bIsList; + if( bShared ) + { + OSL_ENSURE( rCont.bInUse, "OInterfaceContainerHelper must be in use" ); + rCont.bInUse = false; + } + } + + if( !bShared ) + { + if( bIsList ) + // Sequence owned by the iterator + delete aData.pAsVector; + else if( aData.pAsInterface ) + // Interface is acquired by the iterator + aData.pAsInterface->release(); + } +} + +XInterface * OInterfaceIteratorHelper::next() +{ + if( nRemain ) + { + nRemain--; + if( bIsList ) + // typecase to const,so the getArray method is faster + return (*aData.pAsVector)[nRemain].get(); + if( aData.pAsInterface ) + return aData.pAsInterface; + } + // exception + return nullptr; +} + +void OInterfaceIteratorHelper::remove() +{ + if( bIsList ) + { + OSL_ASSERT( nRemain >= 0 && + nRemain < static_cast<sal_Int32>(aData.pAsVector->size()) ); + XInterface * p = (*aData.pAsVector)[nRemain].get(); + rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >( &p ) ); + } + else + { + OSL_ASSERT( 0 == nRemain ); + rCont.removeInterface( * reinterpret_cast< const Reference< XInterface > * >(&aData.pAsInterface)); + } +} + +OInterfaceContainerHelper::OInterfaceContainerHelper( Mutex & rMutex_ ) + : rMutex( rMutex_ ) + , bInUse( false ) + , bIsList( false ) +{ +} + +OInterfaceContainerHelper::~OInterfaceContainerHelper() +{ + OSL_ENSURE( !bInUse, "~OInterfaceContainerHelper but is in use" ); + if( bIsList ) + delete aData.pAsVector; + else if( aData.pAsInterface ) + aData.pAsInterface->release(); +} + +sal_Int32 OInterfaceContainerHelper::getLength() const +{ + MutexGuard aGuard( rMutex ); + if( bIsList ) + return aData.pAsVector->size(); + if( aData.pAsInterface ) + return 1; + return 0; +} + +Sequence< Reference<XInterface> > OInterfaceContainerHelper::getElements() const +{ + MutexGuard aGuard( rMutex ); + if( bIsList ) + return comphelper::containerToSequence(*aData.pAsVector); + if( aData.pAsInterface ) + { + Reference<XInterface> x( aData.pAsInterface ); + return Sequence< Reference< XInterface > >( &x, 1 ); + } + return Sequence< Reference< XInterface > >(); +} + +void OInterfaceContainerHelper::copyAndResetInUse() +{ + OSL_ENSURE( bInUse, "OInterfaceContainerHelper not in use" ); + if( bInUse ) + { + // this should be the worst case. If an iterator is active + // and a new Listener is added. + if( bIsList ) + aData.pAsVector= new std::vector< Reference< XInterface > >( *aData.pAsVector ); + else if( aData.pAsInterface ) + aData.pAsInterface->acquire(); + + bInUse = false; + } +} + +sal_Int32 OInterfaceContainerHelper::addInterface( const Reference<XInterface> & rListener ) +{ + SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" ); + MutexGuard aGuard( rMutex ); + if( bInUse ) + copyAndResetInUse(); + + if( bIsList ) + { + aData.pAsVector->push_back(rListener); + return aData.pAsVector->size(); + } + if( aData.pAsInterface ) + { + Reference<XInterface> tmp(aData.pAsInterface); + aData.pAsInterface->release(); + aData.pAsVector = new std::vector<Reference<XInterface>>(2); + (*aData.pAsVector)[0] = std::move(tmp); + (*aData.pAsVector)[1] = rListener; + bIsList = true; + return 2; + } + aData.pAsInterface = rListener.get(); + if( rListener.is() ) + rListener->acquire(); + return 1; +} + +sal_Int32 OInterfaceContainerHelper::removeInterface( const Reference<XInterface> & rListener ) +{ + SAL_WARN_IF( !rListener.is(), "cppuhelper", "rListener is empty" ); + MutexGuard aGuard( rMutex ); + if( bInUse ) + copyAndResetInUse(); + + if( bIsList ) + { + // It is not valid to compare the pointer directly, but it's faster. + auto findIt = std::find_if(aData.pAsVector->begin(), aData.pAsVector->end(), + [&](const Reference<XInterface>& r) + { return r.get() == rListener.get(); }); + if (findIt != aData.pAsVector->end()) + { + aData.pAsVector->erase(findIt); + } + else + { + // interface not found, use the correct compare method + for( auto it = aData.pAsVector->begin(); it != aData.pAsVector->end(); ++it ) + { + if( *it == rListener ) + { + aData.pAsVector->erase(it); + break; + } + } + } + + if( aData.pAsVector->size() == 1 ) + { + XInterface * p = (*aData.pAsVector)[0].get(); + p->acquire(); + delete aData.pAsVector; + aData.pAsInterface = p; + bIsList = false; + return 1; + } + return aData.pAsVector->size(); + } + if( aData.pAsInterface && Reference<XInterface>( aData.pAsInterface ) == rListener ) + { + aData.pAsInterface->release(); + aData.pAsInterface = nullptr; + } + return aData.pAsInterface ? 1 : 0; +} + +void OInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt ) +{ + ClearableMutexGuard aGuard( rMutex ); + OInterfaceIteratorHelper aIt( *this ); + // Release container, in case new entries come while disposing + OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" ); + if( !bIsList && aData.pAsInterface ) + aData.pAsInterface->release(); + // set the member to null, use the iterator to delete the values + aData.pAsInterface = nullptr; + bIsList = false; + bInUse = false; + aGuard.clear(); + while( aIt.hasMoreElements() ) + { + try + { + Reference<XEventListener > xLst( aIt.next(), UNO_QUERY ); + if( xLst.is() ) + xLst->disposing( rEvt ); + } + catch ( RuntimeException & ) + { + // be robust, if e.g. a remote bridge has disposed already. + // there is no way to delegate the error to the caller :o(. + } + } +} + + +void OInterfaceContainerHelper::clear() +{ + MutexGuard aGuard( rMutex ); + // Release container, in case new entries come while disposing + OSL_ENSURE( !bIsList || bInUse, "OInterfaceContainerHelper not in use" ); + if (bInUse) + copyAndResetInUse(); + if (bIsList) + delete aData.pAsVector; + else if (aData.pAsInterface) + aData.pAsInterface->release(); + aData.pAsInterface = nullptr; + bIsList = false; +} + +// specialized class for type + +typedef std::vector< std::pair < Type , void* > > t_type2ptr; + +OMultiTypeInterfaceContainerHelper::OMultiTypeInterfaceContainerHelper( Mutex & rMutex_ ) + : rMutex( rMutex_ ) +{ + m_pMap = new t_type2ptr; +} + +OMultiTypeInterfaceContainerHelper::~OMultiTypeInterfaceContainerHelper() +{ + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + + for (auto& rItem : *pMap) + { + delete static_cast<OInterfaceContainerHelper*>(rItem.second); + rItem.second = nullptr; + } + delete pMap; +} + +Sequence< Type > OMultiTypeInterfaceContainerHelper::getContainedTypes() const +{ + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + t_type2ptr::size_type nSize; + + ::osl::MutexGuard aGuard( rMutex ); + nSize = pMap->size(); + if( nSize ) + { + css::uno::Sequence< Type > aInterfaceTypes( nSize ); + Type * pArray = aInterfaceTypes.getArray(); + + sal_Int32 i = 0; + for (const auto& rItem : *pMap) + { + // are interfaces added to this container? + if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() ) + // yes, put the type in the array + pArray[i++] = rItem.first; + } + if( static_cast<t_type2ptr::size_type>(i) != nSize ) { + // may be empty container, reduce the sequence to the right size + aInterfaceTypes = css::uno::Sequence< Type >( pArray, i ); + } + return aInterfaceTypes; + } + return css::uno::Sequence< Type >(); +} + +static t_type2ptr::iterator findType(t_type2ptr *pMap, const Type & rKey ) +{ + return std::find_if(pMap->begin(), pMap->end(), + [&rKey](const t_type2ptr::value_type& rItem) { return rItem.first == rKey; }); +} + +OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelper::getContainer( const Type & rKey ) const +{ + ::osl::MutexGuard aGuard( rMutex ); + + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + t_type2ptr::iterator iter = findType( pMap, rKey ); + if( iter != pMap->end() ) + return static_cast<OInterfaceContainerHelper*>((*iter).second); + return nullptr; +} + +sal_Int32 OMultiTypeInterfaceContainerHelper::addInterface( + const Type & rKey, const Reference< XInterface > & rListener ) +{ + ::osl::MutexGuard aGuard( rMutex ); + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + t_type2ptr::iterator iter = findType( pMap, rKey ); + if( iter == pMap->end() ) + { + OInterfaceContainerHelper * pLC = new OInterfaceContainerHelper( rMutex ); + pMap->push_back(std::pair<Type, void*>(rKey, pLC)); + return pLC->addInterface( rListener ); + } + return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener ); +} + +sal_Int32 OMultiTypeInterfaceContainerHelper::removeInterface( + const Type & rKey, const Reference< XInterface > & rListener ) +{ + ::osl::MutexGuard aGuard( rMutex ); + + // search container with id nUik + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + t_type2ptr::iterator iter = findType( pMap, rKey ); + // container found? + if( iter != pMap->end() ) + return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener ); + + // no container with this id. Always return 0 + return 0; +} + +void OMultiTypeInterfaceContainerHelper::disposeAndClear( const EventObject & rEvt ) +{ + t_type2ptr::size_type nSize = 0; + std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers; + { + ::osl::MutexGuard aGuard( rMutex ); + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + nSize = pMap->size(); + if( nSize ) + { + typedef OInterfaceContainerHelper* ppp; + ppListenerContainers.reset(new ppp[nSize]); + //ppListenerContainers = new (ListenerContainer*)[nSize]; + + t_type2ptr::size_type i = 0; + for (const auto& rItem : *pMap) + { + ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second); + } + } + } + + // create a copy, because do not fire event in a guarded section + for( t_type2ptr::size_type i = 0; + i < nSize; i++ ) + { + if( ppListenerContainers[i] ) + ppListenerContainers[i]->disposeAndClear( rEvt ); + } +} + +void OMultiTypeInterfaceContainerHelper::clear() +{ + ::osl::MutexGuard aGuard( rMutex ); + t_type2ptr * pMap = static_cast<t_type2ptr *>(m_pMap); + + for (auto& rItem : *pMap) + { + static_cast<OInterfaceContainerHelper*>(rItem.second)->clear(); + } +} + +// specialized class for long + +typedef std::vector< std::pair < sal_Int32 , void* > > t_long2ptr; + +static t_long2ptr::iterator findLong(t_long2ptr *pMap, sal_Int32 nKey ) +{ + return std::find_if(pMap->begin(), pMap->end(), + [&nKey](const t_long2ptr::value_type& rItem) { return rItem.first == nKey; }); +} + +OMultiTypeInterfaceContainerHelperInt32::OMultiTypeInterfaceContainerHelperInt32( Mutex & rMutex_ ) + : m_pMap( nullptr ) + , rMutex( rMutex_ ) +{ + // delay pMap allocation until necessary. +} + +OMultiTypeInterfaceContainerHelperInt32::~OMultiTypeInterfaceContainerHelperInt32() +{ + if (!m_pMap) + return; + + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + + for (auto& rItem : *pMap) + { + delete static_cast<OInterfaceContainerHelper*>(rItem.second); + rItem.second = nullptr; + } + delete pMap; +} + +Sequence< sal_Int32 > OMultiTypeInterfaceContainerHelperInt32::getContainedTypes() const +{ + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + t_long2ptr::size_type nSize; + + ::osl::MutexGuard aGuard( rMutex ); + nSize = pMap ? pMap->size() : 0; + if( nSize ) + { + css::uno::Sequence< sal_Int32 > aInterfaceTypes( nSize ); + sal_Int32 * pArray = aInterfaceTypes.getArray(); + + sal_Int32 i = 0; + for (const auto& rItem : *pMap) + { + // are interfaces added to this container? + if( static_cast<OInterfaceContainerHelper*>(rItem.second)->getLength() ) + // yes, put the type in the array + pArray[i++] = rItem.first; + } + if( static_cast<t_long2ptr::size_type>(i) != nSize ) { + // may be empty container, reduce the sequence to the right size + aInterfaceTypes = css::uno::Sequence< sal_Int32 >( pArray, i ); + } + return aInterfaceTypes; + } + return css::uno::Sequence< sal_Int32 >(); +} + +OInterfaceContainerHelper * OMultiTypeInterfaceContainerHelperInt32::getContainer( const sal_Int32 & rKey ) const +{ + ::osl::MutexGuard aGuard( rMutex ); + + if (!m_pMap) + return nullptr; + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + t_long2ptr::iterator iter = findLong( pMap, rKey ); + if( iter != pMap->end() ) + return static_cast<OInterfaceContainerHelper*>((*iter).second); + return nullptr; +} + +sal_Int32 OMultiTypeInterfaceContainerHelperInt32::addInterface( + const sal_Int32 & rKey, const Reference< XInterface > & rListener ) +{ + ::osl::MutexGuard aGuard( rMutex ); + if (!m_pMap) + m_pMap = new t_long2ptr; + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + t_long2ptr::iterator iter = findLong( pMap, rKey ); + if( iter == pMap->end() ) + { + OInterfaceContainerHelper * pLC = new OInterfaceContainerHelper( rMutex ); + pMap->push_back(std::pair< sal_Int32, void* >(rKey, pLC)); + return pLC->addInterface( rListener ); + } + return static_cast<OInterfaceContainerHelper*>((*iter).second)->addInterface( rListener ); +} + +sal_Int32 OMultiTypeInterfaceContainerHelperInt32::removeInterface( + const sal_Int32 & rKey, const Reference< XInterface > & rListener ) +{ + ::osl::MutexGuard aGuard( rMutex ); + + if (!m_pMap) + return 0; + // search container with id nUik + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + t_long2ptr::iterator iter = findLong( pMap, rKey ); + // container found? + if( iter != pMap->end() ) + return static_cast<OInterfaceContainerHelper*>((*iter).second)->removeInterface( rListener ); + + // no container with this id. Always return 0 + return 0; +} + +void OMultiTypeInterfaceContainerHelperInt32::disposeAndClear( const EventObject & rEvt ) +{ + t_long2ptr::size_type nSize = 0; + std::unique_ptr<OInterfaceContainerHelper *[]> ppListenerContainers; + { + ::osl::MutexGuard aGuard( rMutex ); + if (!m_pMap) + return; + + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + nSize = pMap->size(); + if( nSize ) + { + typedef OInterfaceContainerHelper* ppp; + ppListenerContainers.reset(new ppp[nSize]); + + t_long2ptr::size_type i = 0; + for (const auto& rItem : *pMap) + { + ppListenerContainers[i++] = static_cast<OInterfaceContainerHelper*>(rItem.second); + } + } + } + + // create a copy, because do not fire event in a guarded section + for( t_long2ptr::size_type i = 0; + i < nSize; i++ ) + { + if( ppListenerContainers[i] ) + ppListenerContainers[i]->disposeAndClear( rEvt ); + } +} + +void OMultiTypeInterfaceContainerHelperInt32::clear() +{ + ::osl::MutexGuard aGuard( rMutex ); + if (!m_pMap) + return; + t_long2ptr * pMap = static_cast<t_long2ptr *>(m_pMap); + + for (auto& rItem : *pMap) + { + static_cast<OInterfaceContainerHelper*>(rItem.second)->clear(); + } +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/loadsharedlibcomponentfactory.hxx b/cppuhelper/source/loadsharedlibcomponentfactory.hxx new file mode 100644 index 000000000..033fc8f32 --- /dev/null +++ b/cppuhelper/source/loadsharedlibcomponentfactory.hxx @@ -0,0 +1,44 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_LOADSHAREDLIBCOMPONENTFACTORY_HXX +#define INCLUDED_CPPUHELPER_SOURCE_LOADSHAREDLIBCOMPONENTFACTORY_HXX + +#include <sal/config.h> + +#include <com/sun/star/uno/Reference.hxx> + +#include "servicemanager.hxx" + +namespace com::sun::star { + namespace lang { class XMultiServiceFactory; } + namespace uno { + class Environment; + class XInterface; + } +} + +namespace cppuhelper::detail { + +css::uno::Environment getEnvironment( + OUString const & name, OUString const & implementation); + +void loadSharedLibComponentFactory( + OUString const & uri, OUString const & environment, + OUString const & prefix, OUString const & implementation, + OUString const & constructor, + css::uno::Reference<css::lang::XMultiServiceFactory> const & serviceManager, + WrapperConstructorFn * constructorFunction, + css::uno::Reference<css::uno::XInterface> * factory); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/macro_expander.cxx b/cppuhelper/source/macro_expander.cxx new file mode 100644 index 000000000..e9a6cce3f --- /dev/null +++ b/cppuhelper/source/macro_expander.cxx @@ -0,0 +1,182 @@ +/* -*- 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 <rtl/bootstrap.hxx> + +#include <uno/lbnames.h> +#include <uno/mapping.hxx> + +#include <cppuhelper/factory.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/util/XMacroExpander.hpp> + +#include "macro_expander.hxx" +#include "paths.hxx" + +#define SERVICE_NAME_A "com.sun.star.lang.MacroExpander" +#define SERVICE_NAME_B "com.sun.star.lang.BootstrapMacroExpander" +#define IMPL_NAME "com.sun.star.lang.comp.cppuhelper.BootstrapMacroExpander" + +using namespace ::osl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +using rtl::Bootstrap; + +namespace cppu +{ + +static Bootstrap const & get_unorc() +{ + static rtlBootstrapHandle s_bstrap = rtl_bootstrap_args_open(getUnoIniUri().pData); + return *reinterpret_cast<Bootstrap const *>(&s_bstrap); +} + +} + +namespace cppuhelper::detail { + +OUString expandMacros(OUString const & text) { + OUString t(text); + rtl_bootstrap_expandMacros_from_handle( + cppu::get_unorc().getHandle(), &t.pData); + return t; +} + +} + +namespace +{ + +class ImplNames +{ +private: + Sequence<OUString> m_aNames; +public: + ImplNames() : m_aNames(2) + { + m_aNames[0] = SERVICE_NAME_A; + m_aNames[1] = SERVICE_NAME_B; + } + const Sequence<OUString>& getNames() const { return m_aNames; } +}; + +class theImplNames : public rtl::Static<ImplNames, theImplNames> {}; + +OUString s_impl_name() +{ + return IMPL_NAME; +} + +Sequence< OUString > const & s_get_service_names() +{ + return theImplNames::get().getNames(); +} + +typedef cppu::WeakComponentImplHelper< + util::XMacroExpander, lang::XServiceInfo > t_uno_impl; + +struct mutex_holder +{ + Mutex m_mutex; +}; + +class Bootstrap_MacroExpander : public mutex_holder, public t_uno_impl +{ +protected: + virtual void SAL_CALL disposing() override; + +public: + Bootstrap_MacroExpander() + : t_uno_impl( m_mutex ) + {} + + // XMacroExpander impl + virtual OUString SAL_CALL expandMacros( OUString const & exp ) override; + // XServiceInfo impl + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + + +void Bootstrap_MacroExpander::disposing() +{} + +// XServiceInfo impl + +OUString Bootstrap_MacroExpander::getImplementationName() +{ + return s_impl_name(); +} + +sal_Bool Bootstrap_MacroExpander::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + +Sequence< OUString > Bootstrap_MacroExpander::getSupportedServiceNames() +{ + return s_get_service_names(); +} + +// XMacroExpander impl + +OUString Bootstrap_MacroExpander::expandMacros( OUString const & exp ) +{ + return cppuhelper::detail::expandMacros( exp ); +} + + +Reference< XInterface > service_create( + SAL_UNUSED_PARAMETER Reference< XComponentContext > const & ) +{ + return static_cast< ::cppu::OWeakObject * >( new Bootstrap_MacroExpander ); +} + +} + +namespace cppuhelper::detail { + +Reference< lang::XSingleComponentFactory > create_bootstrap_macro_expander_factory() +{ + Reference< lang::XSingleComponentFactory > free(::cppu::createSingleComponentFactory( + service_create, + s_impl_name(), + s_get_service_names() )); + + uno::Environment curr_env(Environment::getCurrent()); + uno::Environment target_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME); + + uno::Mapping target2curr(target_env, curr_env); + + return Reference<lang::XSingleComponentFactory>( + static_cast<lang::XSingleComponentFactory *>( + target2curr.mapInterface(free.get(), cppu::UnoType<decltype(free)>::get())), + SAL_NO_ACQUIRE); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/macro_expander.hxx b/cppuhelper/source/macro_expander.hxx new file mode 100644 index 000000000..4a2740beb --- /dev/null +++ b/cppuhelper/source/macro_expander.hxx @@ -0,0 +1,59 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_MACRO_EXPANDER_HXX +#define INCLUDED_CPPUHELPER_SOURCE_MACRO_EXPANDER_HXX + +#include <sal/config.h> + +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star::lang { class XSingleComponentFactory; } + +namespace cppuhelper { + +namespace detail { + +/** + * Helper function to expand macros based on the unorc/uno.ini. + * + * @internal + * + * @param text + * Some text. + * + * @return + * The expanded text. + * + * @exception com::sun::star::lang::IllegalArgumentException + * If uriReference is a vnd.sun.star.expand URL reference that contains unknown + * macros. + */ +OUString expandMacros(OUString const & text); + +css::uno::Reference< css::lang::XSingleComponentFactory > +create_bootstrap_macro_expander_factory(); + +} + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/paths.cxx b/cppuhelper/source/paths.cxx new file mode 100644 index 000000000..49144f715 --- /dev/null +++ b/cppuhelper/source/paths.cxx @@ -0,0 +1,135 @@ +/* -*- 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 <config_folders.h> + +#include <sal/config.h> + +#include <cassert> + +#include <com/sun/star/uno/DeploymentException.hpp> +#include <osl/file.hxx> +#include <osl/module.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +#include "paths.hxx" + +namespace { + +#ifndef ANDROID +OUString get_this_libpath() { + static OUString s_uri = []() { + OUString uri; + osl::Module::getUrlFromAddress(reinterpret_cast<oslGenericFunction>(get_this_libpath), uri); + sal_Int32 i = uri.lastIndexOf('/'); + if (i == -1) + { + throw css::uno::DeploymentException("URI " + uri + " is expected to contain a slash"); + } + return uri.copy(0, i); + }(); + + return s_uri; +} +#endif +} + +OUString cppu::getUnoIniUri() { +#if defined ANDROID + // Wouldn't it be lovely to avoid this ugly hard-coding. + // The problem is that the 'create_bootstrap_macro_expander_factory()' + // required for bootstrapping services, calls cppu::get_unorc directly + // instead of re-using the BootstrapHandle from: + // defaultBootstrap_InitialComponentContext + // and since rtlBootstrapHandle is not ref-counted doing anything + // clean here is hardish. + OUString uri("file:///assets/program"); +#else + OUString uri(get_this_libpath()); +#ifdef MACOSX + // We keep both the LO and URE dylibs directly in "Frameworks" + // (that is, LIBO_LIB_FOLDER) and rc files in "Resources" + // (LIBO_ETC_FOLDER). Except for unorc, of which there are two, + // the "LO" one (which is in "Resources") and the "URE" one (which + // is in "Resources/ure/etc" (LIBO_URE_ETC_FOLDER)). As this code + // goes into the cppuhelper library which is part of URE, we are + // looking for the latter one here. I think... + if (uri.endsWith( "/" LIBO_LIB_FOLDER ) ) + { + uri = uri.copy( 0, uri.getLength() - (sizeof(LIBO_LIB_FOLDER)-1) ) + LIBO_URE_ETC_FOLDER; + } +#endif +#endif + return uri + "/" SAL_CONFIGFILE("uno"); +} + +bool cppu::nextDirectoryItem(osl::Directory & directory, OUString * url) { + assert(url != nullptr); + for (;;) { + osl::DirectoryItem i; + switch (directory.getNextItem(i, SAL_MAX_UINT32)) { + case osl::FileBase::E_None: + break; + case osl::FileBase::E_NOENT: + return false; + default: + throw css::uno::DeploymentException( + "Cannot iterate directory"); + } + osl::FileStatus stat( + osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName | + osl_FileStatus_Mask_FileURL); + if (i.getFileStatus(stat) != osl::FileBase::E_None) { + throw css::uno::DeploymentException( + "Cannot stat in directory"); + } + if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks + // Ignore backup files: + OUString name(stat.getFileName()); + if (!(name.match(".") || name.endsWith("~"))) { + *url = stat.getFileURL(); + return true; + } + } + } +} + +void cppu::decodeRdbUri(OUString * uri, bool * optional, bool * directory) +{ + assert(uri != nullptr && optional != nullptr && directory != nullptr); + if(!(uri->isEmpty())) + { + *optional = (*uri)[0] == '?'; + if (*optional) { + *uri = uri->copy(1); + } + *directory = uri->startsWith("<") && uri->endsWith(">*"); + if (*directory) { + *uri = uri->copy(1, uri->getLength() - 3); + } + } + else + { + *optional = false; + *directory = false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/paths.hxx b/cppuhelper/source/paths.hxx new file mode 100644 index 000000000..baad8c68c --- /dev/null +++ b/cppuhelper/source/paths.hxx @@ -0,0 +1,40 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_PATHS_HXX +#define INCLUDED_CPPUHELPER_SOURCE_PATHS_HXX + +#include <sal/config.h> +#include <rtl/ustring.hxx> + +namespace osl { class Directory; } + +namespace cppu { + +OUString getUnoIniUri(); + +bool nextDirectoryItem(osl::Directory & directory, OUString * url); + +void decodeRdbUri(OUString * uri, bool * optional, bool * directory); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/propertysetmixin.cxx b/cppuhelper/source/propertysetmixin.cxx new file mode 100644 index 000000000..c7c815489 --- /dev/null +++ b/cppuhelper/source/propertysetmixin.cxx @@ -0,0 +1,1140 @@ +/* -*- 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 <algorithm> +#include <cassert> +#include <map> +#include <set> +#include <vector> + +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyChangeEvent.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/PropertyVetoException.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/beans/XVetoableChangeListener.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/lang/IllegalAccessException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/reflection/XCompoundTypeDescription.hpp> +#include <com/sun/star/reflection/XIdlClass.hpp> +#include <com/sun/star/reflection/XIdlField2.hpp> +#include <com/sun/star/reflection/XIndirectTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp> +#include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp> +#include <com/sun/star/reflection/XStructTypeDescription.hpp> +#include <com/sun/star/reflection/XTypeDescription.hpp> +#include <com/sun/star/reflection/theCoreReflection.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/TypeClass.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/propertysetmixin.hxx> +#include <cppuhelper/weak.hxx> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> +#include <salhelper/simplereferenceobject.hxx> + +using cppu::PropertySetMixinImpl; + +namespace { + +struct PropertyData { + explicit PropertyData( + css::beans::Property const & theProperty, bool thePresent): + property(theProperty), present(thePresent) {} + + css::beans::Property property; + bool present; +}; + +struct Data: public salhelper::SimpleReferenceObject { + typedef std::map< OUString, PropertyData > PropertyMap; + + PropertyMap properties; + + PropertyMap::const_iterator get( + css::uno::Reference< css::uno::XInterface > const & object, + OUString const & name) const; + +protected: + void initProperties( + css::uno::Reference< css::reflection::XTypeDescription > const & type, + css::uno::Sequence< OUString > const & absentOptional, + std::vector< OUString > * handleNames) + { + std::set<OUString> seen; + initProperties(type, absentOptional, handleNames, &seen); + } + +private: + void initProperties( + css::uno::Reference< css::reflection::XTypeDescription > const & type, + css::uno::Sequence< OUString > const & absentOptional, + std::vector< OUString > * handleNames, std::set<OUString> * seen); + + static css::uno::Reference< css::reflection::XTypeDescription > + resolveTypedefs( + css::uno::Reference< css::reflection::XTypeDescription > const & type); +}; + +Data::PropertyMap::const_iterator Data::get( + css::uno::Reference< css::uno::XInterface > const & object, + OUString const & name) const +{ + PropertyMap::const_iterator i(properties.find(name)); + if (i == properties.end() || !i->second.present) { + throw css::beans::UnknownPropertyException(name, object); + } + return i; +} + +void Data::initProperties( + css::uno::Reference< css::reflection::XTypeDescription > const & type, + css::uno::Sequence< OUString > const & absentOptional, + std::vector< OUString > * handleNames, std::set<OUString> * seen) +{ + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > ifc( + resolveTypedefs(type), css::uno::UNO_QUERY_THROW); + if (!seen->insert(ifc->getName()).second) + return; + + const css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > bases( + ifc->getBaseTypes()); + for (const auto & i : bases) { + initProperties(i, absentOptional, handleNames, seen); + } + const css::uno::Sequence< + css::uno::Reference< + css::reflection::XInterfaceMemberTypeDescription > > members( + ifc->getMembers()); + OUString const * absentBegin = absentOptional.getConstArray(); + OUString const * absentEnd = + absentBegin + absentOptional.getLength(); + for (const auto & m : members) { + if (m->getTypeClass() + == css::uno::TypeClass_INTERFACE_ATTRIBUTE) + { + css::uno::Reference< + css::reflection::XInterfaceAttributeTypeDescription2 > attr( + m, css::uno::UNO_QUERY_THROW); + sal_Int16 attrAttribs = 0; + if (attr->isBound()) { + attrAttribs |= css::beans::PropertyAttribute::BOUND; + } + bool bSetUnknown = false; + if (attr->isReadOnly()) { + attrAttribs |= css::beans::PropertyAttribute::READONLY; + bSetUnknown = true; + } + css::uno::Sequence< + css::uno::Reference< + css::reflection::XCompoundTypeDescription > > excs( + attr->getGetExceptions()); + bool bGetUnknown = false; + //XXX Special interpretation of getter/setter exceptions only + // works if the specified exceptions are of the exact type, not + // of a supertype: + for (const auto & ex : std::as_const(excs)) { + if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" ) + { + bGetUnknown = true; + break; + } + } + excs = attr->getSetExceptions(); + for (const auto & ex : std::as_const(excs)) { + if ( ex->getName() == "com.sun.star.beans.UnknownPropertyException" ) + { + bSetUnknown = true; + } else if ( ex->getName() == "com.sun.star.beans.PropertyVetoException" ) + { + attrAttribs + |= css::beans::PropertyAttribute::CONSTRAINED; + } + } + if (bGetUnknown && bSetUnknown) { + attrAttribs |= css::beans::PropertyAttribute::OPTIONAL; + } + css::uno::Reference< css::reflection::XTypeDescription > t( + attr->getType()); + for (;;) + { + t = resolveTypedefs(t); + sal_Int16 n; + if (t->getName().startsWith( + "com.sun.star.beans.Ambiguous<")) + { + n = css::beans::PropertyAttribute::MAYBEAMBIGUOUS; + } else if (t->getName().startsWith( + "com.sun.star.beans.Defaulted<")) + { + n = css::beans::PropertyAttribute::MAYBEDEFAULT; + } else if (t->getName().startsWith( + "com.sun.star.beans.Optional<")) + { + n = css::beans::PropertyAttribute::MAYBEVOID; + } else { + break; + } + if ((attrAttribs & n) != 0) { + break; + } + attrAttribs |= n; + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + args( + css::uno::Reference< + css::reflection::XStructTypeDescription >( + t, css::uno::UNO_QUERY_THROW)-> + getTypeArguments()); + if (args.getLength() != 1) { + throw css::uno::RuntimeException( + "inconsistent UNO type registry"); + } + t = args[0]; + } + std::vector< OUString >::size_type handles + = handleNames->size(); + if (handles > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + "interface type has too many attributes"); + } + OUString name(m->getMemberName()); + if (!properties.emplace( + name, + PropertyData( + css::beans::Property( + name, static_cast< sal_Int32 >(handles), + css::uno::Type( + t->getTypeClass(), t->getName()), + attrAttribs), + (std::find(absentBegin, absentEnd, name) + == absentEnd))). + second) + { + throw css::uno::RuntimeException( + "inconsistent UNO type registry"); + } + handleNames->push_back(name); + } + } +} + +css::uno::Reference< css::reflection::XTypeDescription > Data::resolveTypedefs( + css::uno::Reference< css::reflection::XTypeDescription > const & type) +{ + css::uno::Reference< css::reflection::XTypeDescription > t(type); + while (t->getTypeClass() == css::uno::TypeClass_TYPEDEF) { + t = css::uno::Reference< css::reflection::XIndirectTypeDescription >( + t, css::uno::UNO_QUERY_THROW)->getReferencedType(); + } + return t; +} + +class Info: public cppu::WeakImplHelper< css::beans::XPropertySetInfo > { +public: + explicit Info(Data * data): m_data(data) {} + + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() override; + + virtual css::beans::Property SAL_CALL getPropertyByName( + OUString const & name) override; + + virtual sal_Bool SAL_CALL hasPropertyByName(OUString const & name) override; + +private: + rtl::Reference< Data > m_data; +}; + +css::uno::Sequence< css::beans::Property > Info::getProperties() +{ + assert(m_data->properties.size() <= SAL_MAX_INT32); + css::uno::Sequence< css::beans::Property > s( + static_cast< sal_Int32 >(m_data->properties.size())); + sal_Int32 n = 0; + for (const auto& rEntry : m_data->properties) + { + if (rEntry.second.present) { + s[n++] = rEntry.second.property; + } + } + s.realloc(n); + return s; +} + +css::beans::Property Info::getPropertyByName(OUString const & name) +{ + return m_data->get(static_cast< cppu::OWeakObject * >(this), name)-> + second.property; +} + +sal_Bool Info::hasPropertyByName(OUString const & name) +{ + Data::PropertyMap::iterator i(m_data->properties.find(name)); + return i != m_data->properties.end() && i->second.present; +} + +typedef +std::multiset< css::uno::Reference< css::beans::XPropertyChangeListener > > +BoundListenerBag; + +} + +class PropertySetMixinImpl::BoundListeners::Impl { +public: + BoundListenerBag specificListeners; + BoundListenerBag unspecificListeners; + css::beans::PropertyChangeEvent event; +}; + +PropertySetMixinImpl::BoundListeners::BoundListeners(): m_impl(new Impl) {} + +PropertySetMixinImpl::BoundListeners::~BoundListeners() { + delete m_impl; +} + +void PropertySetMixinImpl::BoundListeners::notify() const { + for (const auto& rxListener : m_impl->specificListeners) + { + try { + rxListener->propertyChange(m_impl->event); + } catch (css::lang::DisposedException &) {} + } + for (const auto& rxListener : m_impl->unspecificListeners) + { + try { + rxListener->propertyChange(m_impl->event); + } catch (css::lang::DisposedException &) {} + } +} + +class PropertySetMixinImpl::Impl: public Data { +public: + Impl( + css::uno::Reference< css::uno::XComponentContext > const & context, + Implements theImplements, + css::uno::Sequence< OUString > const & absentOptional, + css::uno::Type const & type); + + OUString const & translateHandle( + css::uno::Reference< css::uno::XInterface > const & object, + sal_Int32 handle) const; + + void setProperty( + css::uno::Reference< css::uno::XInterface > const & object, + OUString const & name, css::uno::Any const & value, + bool isAmbiguous, bool isDefaulted, sal_Int16 illegalArgumentPosition) + const; + + css::uno::Any getProperty( + css::uno::Reference< css::uno::XInterface > const & object, + OUString const & name, css::beans::PropertyState * state) const; + + PropertySetMixinImpl::Implements implements; + css::uno::Sequence< OUString > handleMap; + + typedef std::map< OUString, BoundListenerBag > BoundListenerMap; + + typedef + std::multiset< css::uno::Reference< css::beans::XVetoableChangeListener > > + VetoListenerBag; + + typedef std::map< OUString, VetoListenerBag > VetoListenerMap; + + mutable osl::Mutex mutex; + BoundListenerMap boundListeners; + VetoListenerMap vetoListeners; + bool disposed; + +private: + css::uno::Reference< css::reflection::XIdlClass > getReflection( + OUString const & typeName) const; + + static css::uno::Any wrapValue( + css::uno::Reference< css::uno::XInterface > const & object, + css::uno::Any const & value, + css::uno::Reference< css::reflection::XIdlClass > const & type, + bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, + bool isDefaulted, bool wrapOptional); + + css::uno::Reference< css::uno::XComponentContext > const & m_context; + css::uno::Type m_type; + css::uno::Reference< css::reflection::XIdlClass > m_idlClass; +}; + +PropertySetMixinImpl::Impl::Impl( + css::uno::Reference< css::uno::XComponentContext > const & context, + Implements theImplements, + css::uno::Sequence< OUString > const & absentOptional, + css::uno::Type const & type): + implements(theImplements), disposed(false), m_context(context), + m_type(type) +{ + assert(context.is()); + assert( + (implements + & ~(IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET + | IMPLEMENTS_PROPERTY_ACCESS)) + == 0); + m_idlClass = getReflection(m_type.getTypeName()); + css::uno::Reference< css::reflection::XTypeDescription > ifc; + try { + ifc.set( + css::uno::Reference< css::container::XHierarchicalNameAccess >( + m_context->getValueByName( + "/singletons/com.sun.star.reflection." + "theTypeDescriptionManager"), + css::uno::UNO_QUERY_THROW)->getByHierarchicalName( + m_type.getTypeName()), + css::uno::UNO_QUERY_THROW); + } catch (css::container::NoSuchElementException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.container.NoSuchElementException: " + + e.Message, + nullptr, anyEx ); + } + std::vector< OUString > handleNames; + initProperties(ifc, absentOptional, &handleNames); + std::vector< OUString >::size_type size = handleNames.size(); + assert(size <= SAL_MAX_INT32); + handleMap.realloc(static_cast< sal_Int32 >(size)); + std::copy(handleNames.begin(), handleNames.end(), handleMap.getArray()); +} + +OUString const & PropertySetMixinImpl::Impl::translateHandle( + css::uno::Reference< css::uno::XInterface > const & object, + sal_Int32 handle) const +{ + if (handle < 0 || handle >= handleMap.getLength()) { + throw css::beans::UnknownPropertyException( + "bad handle " + OUString::number(handle), object); + } + return handleMap[handle]; +} + +void PropertySetMixinImpl::Impl::setProperty( + css::uno::Reference< css::uno::XInterface > const & object, + OUString const & name, css::uno::Any const & value, bool isAmbiguous, + bool isDefaulted, sal_Int16 illegalArgumentPosition) const +{ + PropertyMap::const_iterator i(properties.find(name)); + if (i == properties.end()) { + throw css::beans::UnknownPropertyException(name, object); + } + if ((isAmbiguous + && ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEAMBIGUOUS) + == 0)) + || (isDefaulted + && ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEDEFAULT) + == 0))) + { + throw css::lang::IllegalArgumentException( + ("flagging as ambiguous/defaulted non-ambiguous/defaulted property " + + name), + object, illegalArgumentPosition); + } + css::uno::Reference< css::reflection::XIdlField2 > f( + m_idlClass->getField(name), css::uno::UNO_QUERY_THROW); + css::uno::Any o(object->queryInterface(m_type)); + css::uno::Any v( + wrapValue( + object, value, + (css::uno::Reference< css::reflection::XIdlField2 >( + m_idlClass->getField(name), css::uno::UNO_QUERY_THROW)-> + getType()), + ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEAMBIGUOUS) + != 0), + isAmbiguous, + ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEDEFAULT) + != 0), + isDefaulted, + ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEVOID) + != 0))); + try { + f->set(o, v); + } catch (css::lang::IllegalArgumentException & e) { + if (e.ArgumentPosition == 1) { + throw css::lang::IllegalArgumentException( + e.Message, object, illegalArgumentPosition); + } else { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } + } catch (css::lang::IllegalAccessException &) { + //TODO Clarify whether PropertyVetoException is the correct exception + // to throw when trying to set a read-only property: + throw css::beans::PropertyVetoException( + "cannot set read-only property " + name, object); + } catch (css::lang::WrappedTargetRuntimeException & e) { + //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not + // guaranteed to originate directly within XIdlField2.get (and thus have + // the expected semantics); it might also be passed through from lower + // layers. + if (e.TargetException.isExtractableTo( + cppu::UnoType<css::beans::UnknownPropertyException>::get()) + && ((i->second.property.Attributes + & css::beans::PropertyAttribute::OPTIONAL) + != 0)) + { + throw css::beans::UnknownPropertyException(name, object); + } else if (e.TargetException.isExtractableTo( + cppu::UnoType<css::beans::PropertyVetoException>::get()) + && ((i->second.property.Attributes + & css::beans::PropertyAttribute::CONSTRAINED) + != 0)) + { + css::beans::PropertyVetoException exc; + e.TargetException >>= exc; + if (exc.Message.isEmpty() ) + throw css::beans::PropertyVetoException("Invalid " + name, object); + else + throw exc; + } else { + throw css::lang::WrappedTargetException( + e.Message, object, e.TargetException); + } + } +} + +css::uno::Any PropertySetMixinImpl::Impl::getProperty( + css::uno::Reference< css::uno::XInterface > const & object, + OUString const & name, css::beans::PropertyState * state) const +{ + PropertyMap::const_iterator i(properties.find(name)); + if (i == properties.end()) { + throw css::beans::UnknownPropertyException(name, object); + } + css::uno::Reference< css::reflection::XIdlField2 > field( + m_idlClass->getField(name), css::uno::UNO_QUERY_THROW); + css::uno::Any value; + try { + value = field->get(object->queryInterface(m_type)); + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } catch (css::lang::WrappedTargetRuntimeException & e) { + //FIXME A WrappedTargetRuntimeException from XIdlField2.get is not + // guaranteed to originate directly within XIdlField2.get (and thus have + // the expected semantics); it might also be passed through from lower + // layers. + if (e.TargetException.isExtractableTo( + cppu::UnoType<css::beans::UnknownPropertyException>::get()) + && ((i->second.property.Attributes + & css::beans::PropertyAttribute::OPTIONAL) + != 0)) + { + throw css::beans::UnknownPropertyException(name, object); + } else { + throw css::lang::WrappedTargetException( + e.Message, object, e.TargetException); + } + } + bool undoAmbiguous + = ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEAMBIGUOUS) + != 0); + bool undoDefaulted + = ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEDEFAULT) + != 0); + bool undoOptional + = ((i->second.property.Attributes + & css::beans::PropertyAttribute::MAYBEVOID) + != 0); + bool isAmbiguous = false; + bool isDefaulted = false; + while (undoAmbiguous || undoDefaulted || undoOptional) { + if (undoAmbiguous + && value.getValueTypeName().startsWith( + "com.sun.star.beans.Ambiguous<")) + { + css::uno::Reference< css::reflection::XIdlClass > ambiguous( + getReflection(value.getValueTypeName())); + try { + if (!(css::uno::Reference< css::reflection::XIdlField2 >( + ambiguous->getField("IsAmbiguous"), + css::uno::UNO_QUERY_THROW)->get(value) + >>= isAmbiguous)) + { + throw css::uno::RuntimeException( + ("unexpected type of com.sun.star.beans.Ambiguous" + " IsAmbiguous member"), + object); + } + value = css::uno::Reference< css::reflection::XIdlField2 >( + ambiguous->getField("Value"), css::uno::UNO_QUERY_THROW)-> + get(value); + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } + undoAmbiguous = false; + } else if (undoDefaulted + && value.getValueTypeName().startsWith( + "com.sun.star.beans.Defaulted<")) + { + css::uno::Reference< css::reflection::XIdlClass > defaulted( + getReflection(value.getValueTypeName())); + try { + + if (!(css::uno::Reference< css::reflection::XIdlField2 >( + defaulted->getField("IsDefaulted"), + css::uno::UNO_QUERY_THROW)->get(value) + >>= isDefaulted)) + { + throw css::uno::RuntimeException( + ("unexpected type of com.sun.star.beans.Defaulted" + " IsDefaulted member"), + object); + } + value = css::uno::Reference< css::reflection::XIdlField2 >( + defaulted->getField("Value"), css::uno::UNO_QUERY_THROW)-> + get(value); + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } + undoDefaulted = false; + } else if (undoOptional + && value.getValueTypeName().startsWith( + "com.sun.star.beans.Optional<")) + { + css::uno::Reference< css::reflection::XIdlClass > optional( + getReflection(value.getValueTypeName())); + try { + bool present = false; + if (!(css::uno::Reference< css::reflection::XIdlField2 >( + optional->getField("IsPresent"), + css::uno::UNO_QUERY_THROW)->get(value) + >>= present)) + { + throw css::uno::RuntimeException( + ("unexpected type of com.sun.star.beans.Optional" + " IsPresent member"), + object); + } + if (!present) { + value.clear(); + break; + } + value = css::uno::Reference< css::reflection::XIdlField2 >( + optional->getField("Value"), css::uno::UNO_QUERY_THROW)-> + get(value); + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } + undoOptional = false; + } else { + throw css::uno::RuntimeException( + "unexpected type of attribute " + name, object); + } + } + if (state != nullptr) { + //XXX If isAmbiguous && isDefaulted, arbitrarily choose AMBIGUOUS_VALUE + // over DEFAULT_VALUE: + *state = isAmbiguous + ? css::beans::PropertyState_AMBIGUOUS_VALUE + : isDefaulted + ? css::beans::PropertyState_DEFAULT_VALUE + : css::beans::PropertyState_DIRECT_VALUE; + } + return value; +} + +css::uno::Reference< css::reflection::XIdlClass > +PropertySetMixinImpl::Impl::getReflection(OUString const & typeName) const +{ + return css::uno::Reference< css::reflection::XIdlClass >( + css::reflection::theCoreReflection::get(m_context)->forName(typeName), + css::uno::UNO_SET_THROW); +} + +css::uno::Any PropertySetMixinImpl::Impl::wrapValue( + css::uno::Reference< css::uno::XInterface > const & object, + css::uno::Any const & value, + css::uno::Reference< css::reflection::XIdlClass > const & type, + bool wrapAmbiguous, bool isAmbiguous, bool wrapDefaulted, bool isDefaulted, + bool wrapOptional) +{ + assert(wrapAmbiguous || !isAmbiguous); + assert(wrapDefaulted || !isDefaulted); + if (wrapAmbiguous + && type->getName().startsWith("com.sun.star.beans.Ambiguous<")) + { + css::uno::Any strct; + type->createObject(strct); + try { + css::uno::Reference< css::reflection::XIdlField2 > field( + type->getField("Value"), css::uno::UNO_QUERY_THROW); + field->set( + strct, + wrapValue( + object, value, field->getType(), false, false, + wrapDefaulted, isDefaulted, wrapOptional)); + css::uno::Reference< css::reflection::XIdlField2 >( + type->getField("IsAmbiguous"), css::uno::UNO_QUERY_THROW)->set( + strct, css::uno::Any(isAmbiguous)); + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } catch (css::lang::IllegalAccessException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalAccessException: " + + e.Message, + object, anyEx ); + } + return strct; + } + if (wrapDefaulted + && type->getName().startsWith("com.sun.star.beans.Defaulted<")) + { + css::uno::Any strct; + type->createObject(strct); + try { + css::uno::Reference< css::reflection::XIdlField2 > field( + type->getField("Value"), css::uno::UNO_QUERY_THROW); + field->set( + strct, + wrapValue( + object, value, field->getType(), wrapAmbiguous, isAmbiguous, + false, false, wrapOptional)); + css::uno::Reference< css::reflection::XIdlField2 >( + type->getField("IsDefaulted"), css::uno::UNO_QUERY_THROW)->set( + strct, css::uno::Any(isDefaulted)); + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } catch (css::lang::IllegalAccessException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalAccessException: " + + e.Message, + object, anyEx ); + } + return strct; + } + if (wrapOptional + && type->getName().startsWith("com.sun.star.beans.Optional<")) + { + css::uno::Any strct; + type->createObject(strct); + bool present = value.hasValue(); + try { + css::uno::Reference< css::reflection::XIdlField2 >( + type->getField("IsPresent"), css::uno::UNO_QUERY_THROW)->set( + strct, css::uno::Any(present)); + if (present) { + css::uno::Reference< css::reflection::XIdlField2 > field( + type->getField("Value"), css::uno::UNO_QUERY_THROW); + field->set( + strct, + wrapValue( + object, value, field->getType(), wrapAmbiguous, + isAmbiguous, wrapDefaulted, isDefaulted, false)); + } + } catch (css::lang::IllegalArgumentException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalArgumentException: " + + e.Message, + object, anyEx ); + } catch (css::lang::IllegalAccessException & e) { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "unexpected com.sun.star.lang.IllegalAccessException: " + + e.Message, + object, anyEx ); + } + return strct; + } + if (wrapAmbiguous || wrapDefaulted || wrapOptional) { + throw css::uno::RuntimeException( + "unexpected type of attribute", object); + } + return value; +} + +PropertySetMixinImpl::PropertySetMixinImpl( + css::uno::Reference< css::uno::XComponentContext > const & context, + Implements implements, + css::uno::Sequence< OUString > const & absentOptional, + css::uno::Type const & type) +{ + m_impl = new Impl(context, implements, absentOptional, type); + m_impl->acquire(); +} + +PropertySetMixinImpl::~PropertySetMixinImpl() { + m_impl->release(); +} + +void PropertySetMixinImpl::checkUnknown(OUString const & propertyName) { + if (!propertyName.isEmpty()) { + m_impl->get( + static_cast< css::beans::XPropertySet * >(this), propertyName); + } +} + +void PropertySetMixinImpl::prepareSet( + OUString const & propertyName, css::uno::Any const & oldValue, + css::uno::Any const & newValue, BoundListeners * boundListeners) +{ + Impl::PropertyMap::const_iterator it(m_impl->properties.find(propertyName)); + assert(it != m_impl->properties.end()); + Impl::VetoListenerBag specificVeto; + Impl::VetoListenerBag unspecificVeto; + { + osl::MutexGuard g(m_impl->mutex); + if (m_impl->disposed) { + throw css::lang::DisposedException( + "disposed", static_cast< css::beans::XPropertySet * >(this)); + } + if ((it->second.property.Attributes + & css::beans::PropertyAttribute::CONSTRAINED) + != 0) + { + Impl::VetoListenerMap::const_iterator i( + m_impl->vetoListeners.find(propertyName)); + if (i != m_impl->vetoListeners.end()) { + specificVeto = i->second; + } + i = m_impl->vetoListeners.find(""); + if (i != m_impl->vetoListeners.end()) { + unspecificVeto = i->second; + } + } + if ((it->second.property.Attributes + & css::beans::PropertyAttribute::BOUND) + != 0) + { + assert(boundListeners != nullptr); + Impl::BoundListenerMap::const_iterator i( + m_impl->boundListeners.find(propertyName)); + if (i != m_impl->boundListeners.end()) { + boundListeners->m_impl->specificListeners = i->second; + } + i = m_impl->boundListeners.find(""); + if (i != m_impl->boundListeners.end()) { + boundListeners->m_impl->unspecificListeners = i->second; + } + } + } + if ((it->second.property.Attributes + & css::beans::PropertyAttribute::CONSTRAINED) + != 0) + { + css::beans::PropertyChangeEvent event( + static_cast< css::beans::XPropertySet * >(this), propertyName, + false, it->second.property.Handle, oldValue, newValue); + for (auto& rxVetoListener : specificVeto) + { + try { + rxVetoListener->vetoableChange(event); + } catch (css::lang::DisposedException &) {} + } + for (auto& rxVetoListener : unspecificVeto) + { + try { + rxVetoListener->vetoableChange(event); + } catch (css::lang::DisposedException &) {} + } + } + if ((it->second.property.Attributes & css::beans::PropertyAttribute::BOUND) + != 0) + { + assert(boundListeners != nullptr); + boundListeners->m_impl->event = css::beans::PropertyChangeEvent( + static_cast< css::beans::XPropertySet * >(this), propertyName, + false, it->second.property.Handle, oldValue, newValue); + } +} + +void PropertySetMixinImpl::dispose() { + Impl::BoundListenerMap boundListeners; + Impl::VetoListenerMap vetoListeners; + { + osl::MutexGuard g(m_impl->mutex); + boundListeners.swap(m_impl->boundListeners); + vetoListeners.swap(m_impl->vetoListeners); + m_impl->disposed = true; + } + css::lang::EventObject event( + static_cast< css::beans::XPropertySet * >(this)); + for (const auto& rEntry : boundListeners) + { + for (auto& rxBoundListener : rEntry.second) + { + rxBoundListener->disposing(event); + } + } + for (const auto& rEntry : vetoListeners) + { + for (auto& rxVetoListener : rEntry.second) + { + rxVetoListener->disposing(event); + } + } +} + +css::uno::Any PropertySetMixinImpl::queryInterface(css::uno::Type const & type) +{ + if ((m_impl->implements & IMPLEMENTS_PROPERTY_SET) != 0 + && type == css::beans::XPropertySet::static_type()) + { + css::uno::Reference< css::uno::XInterface > ifc( + static_cast< css::beans::XPropertySet * >(this)); + return css::uno::Any(&ifc, type); + } + if ((m_impl->implements & IMPLEMENTS_FAST_PROPERTY_SET) != 0 + && type == css::beans::XFastPropertySet::static_type()) + { + css::uno::Reference< css::uno::XInterface > ifc( + static_cast< css::beans::XFastPropertySet * >(this)); + return css::uno::Any(&ifc, type); + } + if ((m_impl->implements & IMPLEMENTS_PROPERTY_ACCESS) != 0 + && type == css::beans::XPropertyAccess::static_type()) + { + css::uno::Reference< css::uno::XInterface > ifc( + static_cast< css::beans::XPropertyAccess * >(this)); + return css::uno::Any(&ifc, type); + } + return css::uno::Any(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > +PropertySetMixinImpl::getPropertySetInfo() +{ + return new Info(m_impl); +} + +void PropertySetMixinImpl::setPropertyValue( + OUString const & propertyName, css::uno::Any const & value) +{ + m_impl->setProperty( + static_cast< css::beans::XPropertySet * >(this), propertyName, value, + false, false, 1); +} + +css::uno::Any PropertySetMixinImpl::getPropertyValue( + OUString const & propertyName) +{ + return m_impl->getProperty( + static_cast< css::beans::XPropertySet * >(this), propertyName, nullptr); +} + +void PropertySetMixinImpl::addPropertyChangeListener( + OUString const & propertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & listener) +{ + css::uno::Reference< css::beans::XPropertyChangeListener >( + listener, css::uno::UNO_SET_THROW); // reject NULL listener + checkUnknown(propertyName); + bool disposed; + { + osl::MutexGuard g(m_impl->mutex); + disposed = m_impl->disposed; + if (!disposed) { + m_impl->boundListeners[propertyName].insert(listener); + } + } + if (disposed) { + listener->disposing( + css::lang::EventObject( + static_cast< css::beans::XPropertySet * >(this))); + } +} + +void PropertySetMixinImpl::removePropertyChangeListener( + OUString const & propertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & listener) +{ + assert(listener.is()); + checkUnknown(propertyName); + osl::MutexGuard g(m_impl->mutex); + Impl::BoundListenerMap::iterator i( + m_impl->boundListeners.find(propertyName)); + if (i != m_impl->boundListeners.end()) { + BoundListenerBag::iterator j(i->second.find(listener)); + if (j != i->second.end()) { + i->second.erase(j); + } + } +} + +void PropertySetMixinImpl::addVetoableChangeListener( + OUString const & propertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & listener) +{ + css::uno::Reference< css::beans::XVetoableChangeListener >( + listener, css::uno::UNO_SET_THROW); // reject NULL listener + checkUnknown(propertyName); + bool disposed; + { + osl::MutexGuard g(m_impl->mutex); + disposed = m_impl->disposed; + if (!disposed) { + m_impl->vetoListeners[propertyName].insert(listener); + } + } + if (disposed) { + listener->disposing( + css::lang::EventObject( + static_cast< css::beans::XPropertySet * >(this))); + } +} + +void PropertySetMixinImpl::removeVetoableChangeListener( + OUString const & propertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & listener) +{ + assert(listener.is()); + checkUnknown(propertyName); + osl::MutexGuard g(m_impl->mutex); + Impl::VetoListenerMap::iterator i(m_impl->vetoListeners.find(propertyName)); + if (i != m_impl->vetoListeners.end()) { + Impl::VetoListenerBag::iterator j(i->second.find(listener)); + if (j != i->second.end()) { + i->second.erase(j); + } + } +} + +void PropertySetMixinImpl::setFastPropertyValue( + sal_Int32 handle, css::uno::Any const & value) +{ + m_impl->setProperty( + static_cast< css::beans::XPropertySet * >(this), + m_impl->translateHandle( + static_cast< css::beans::XPropertySet * >(this), handle), + value, false, false, 1); +} + +css::uno::Any PropertySetMixinImpl::getFastPropertyValue(sal_Int32 handle) +{ + return m_impl->getProperty( + static_cast< css::beans::XPropertySet * >(this), + m_impl->translateHandle( + static_cast< css::beans::XPropertySet * >(this), handle), + nullptr); +} + +css::uno::Sequence< css::beans::PropertyValue > +PropertySetMixinImpl::getPropertyValues() +{ + css::uno::Sequence< css::beans::PropertyValue > s( + m_impl->handleMap.getLength()); + sal_Int32 n = 0; + for (sal_Int32 i = 0; i < m_impl->handleMap.getLength(); ++i) { + try { + s[n].Value = m_impl->getProperty( + static_cast< css::beans::XPropertySet * >(this), + m_impl->handleMap[i], &s[n].State); + } catch (css::beans::UnknownPropertyException &) { + continue; + } catch (css::lang::WrappedTargetException & e) { + throw css::lang::WrappedTargetRuntimeException( + e.Message, static_cast< css::beans::XPropertySet * >(this), + e.TargetException); + } + s[n].Name = m_impl->handleMap[i]; + s[n].Handle = i; + ++n; + } + s.realloc(n); + return s; +} + +void PropertySetMixinImpl::setPropertyValues( + css::uno::Sequence< css::beans::PropertyValue > const & props) +{ + for (const auto & p : props) { + if (p.Handle != -1 + && (p.Name + != m_impl->translateHandle( + static_cast< css::beans::XPropertySet * >(this), + p.Handle))) + { + throw css::beans::UnknownPropertyException( + ("name " + p.Name + " does not match handle " + + OUString::number(p.Handle)), + static_cast< css::beans::XPropertySet * >(this)); + } + m_impl->setProperty( + static_cast< css::beans::XPropertySet * >(this), p.Name, + p.Value, + p.State == css::beans::PropertyState_AMBIGUOUS_VALUE, + p.State == css::beans::PropertyState_DEFAULT_VALUE, 0); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/propshlp.cxx b/cppuhelper/source/propshlp.cxx new file mode 100644 index 000000000..3af4cda49 --- /dev/null +++ b/cppuhelper/source/propshlp.cxx @@ -0,0 +1,1184 @@ +/* -*- 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 <osl/diagnose.h> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <memory> +#include <sal/log.hxx> + +using namespace osl; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace cppu; + +namespace cppu { + +IPropertyArrayHelper::~IPropertyArrayHelper() +{ +} + +static const css::uno::Type & getPropertyTypeIdentifier( ) +{ + return cppu::UnoType<XPropertyChangeListener>::get(); +} +static const css::uno::Type & getPropertiesTypeIdentifier() +{ + return cppu::UnoType<XPropertiesChangeListener>::get(); +} +static const css::uno::Type & getVetoableTypeIdentifier() +{ + return cppu::UnoType<XVetoableChangeListener>::get(); +} + +extern "C" { + +static int compare_OUString_Property_Impl( const void *arg1, const void *arg2 ) + SAL_THROW_EXTERN_C() +{ + return static_cast<OUString const *>(arg1)->compareTo( static_cast<Property const *>(arg2)->Name ); +} + +} + +/** + * The class which implements the PropertySetInfo interface. + */ + +namespace { + +class OPropertySetHelperInfo_Impl + : public WeakImplHelper< css::beans::XPropertySetInfo > +{ + Sequence < Property > aInfos; + +public: + explicit OPropertySetHelperInfo_Impl( IPropertyArrayHelper & rHelper_ ); + + // XPropertySetInfo-methods + virtual Sequence< Property > SAL_CALL getProperties() override; + virtual Property SAL_CALL getPropertyByName(const OUString& PropertyName) override; + virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& PropertyName) override; +}; + +} + +/** + * Create an object that implements XPropertySetInfo IPropertyArrayHelper. + */ +OPropertySetHelperInfo_Impl::OPropertySetHelperInfo_Impl( + IPropertyArrayHelper & rHelper_ ) + :aInfos( rHelper_.getProperties() ) +{ +} + +/** + * Return the sequence of properties, which are provided through the constructor. + */ +Sequence< Property > OPropertySetHelperInfo_Impl::getProperties() +{ + return aInfos; +} + +/** + * Return the sequence of properties, which are provided through the constructor. + */ +Property OPropertySetHelperInfo_Impl::getPropertyByName( const OUString & PropertyName ) +{ + Property * pR; + pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(), + sizeof( Property ), + compare_OUString_Property_Impl )); + if( !pR ) { + throw UnknownPropertyException(PropertyName); + } + + return *pR; +} + +/** + * Return the sequence of properties, which are provided through the constructor. + */ +sal_Bool OPropertySetHelperInfo_Impl::hasPropertyByName( const OUString & PropertyName ) +{ + Property * pR; + pR = static_cast<Property *>(bsearch( &PropertyName, aInfos.getConstArray(), aInfos.getLength(), + sizeof( Property ), + compare_OUString_Property_Impl )); + return pR != nullptr; +} + + + +class OPropertySetHelper::Impl { + +public: + Impl( bool i_bIgnoreRuntimeExceptionsWhileFiring, + IEventNotificationHook *i_pFireEvents + ) + :m_bIgnoreRuntimeExceptionsWhileFiring( i_bIgnoreRuntimeExceptionsWhileFiring ) + ,m_bFireEvents(true) + ,m_pFireEvents( i_pFireEvents ) + { + } + + bool m_bIgnoreRuntimeExceptionsWhileFiring; + bool m_bFireEvents; + class IEventNotificationHook * const m_pFireEvents; + + std::vector< sal_Int32 > m_handles; + std::vector< Any > m_newValues; + std::vector< Any > m_oldValues; +}; + + + +OPropertySetHelper::OPropertySetHelper( + OBroadcastHelper & rBHelper_ ) + : rBHelper( rBHelper_ ), + aBoundLC( rBHelper_.rMutex ), + aVetoableLC( rBHelper_.rMutex ), + m_pReserved( new Impl(false, nullptr) ) +{ +} + +OPropertySetHelper::OPropertySetHelper( + OBroadcastHelper & rBHelper_, bool bIgnoreRuntimeExceptionsWhileFiring ) + : rBHelper( rBHelper_ ), + aBoundLC( rBHelper_.rMutex ), + aVetoableLC( rBHelper_.rMutex ), + m_pReserved( new Impl( bIgnoreRuntimeExceptionsWhileFiring, nullptr ) ) +{ +} + +OPropertySetHelper::OPropertySetHelper( + OBroadcastHelper & rBHelper_, IEventNotificationHook * i_pFireEvents, + bool bIgnoreRuntimeExceptionsWhileFiring) + : rBHelper( rBHelper_ ), + aBoundLC( rBHelper_.rMutex ), + aVetoableLC( rBHelper_.rMutex ), + m_pReserved( + new Impl( bIgnoreRuntimeExceptionsWhileFiring, i_pFireEvents) ) +{ +} + +OPropertySetHelper2::OPropertySetHelper2( + OBroadcastHelper & irBHelper, + IEventNotificationHook *i_pFireEvents, + bool bIgnoreRuntimeExceptionsWhileFiring) + :OPropertySetHelper( irBHelper, i_pFireEvents, bIgnoreRuntimeExceptionsWhileFiring ) +{ +} + +/** + * You must call disposing before. + */ +OPropertySetHelper::~OPropertySetHelper() +{ + delete m_pReserved; +} +OPropertySetHelper2::~OPropertySetHelper2() +{ +} + +// XInterface +Any OPropertySetHelper::queryInterface( const css::uno::Type & rType ) +{ + return ::cppu::queryInterface( + rType, + static_cast< XPropertySet * >( this ), + static_cast< XMultiPropertySet * >( this ), + static_cast< XFastPropertySet * >( this ) ); +} + +Any OPropertySetHelper2::queryInterface( const css::uno::Type & rType ) +{ + Any cnd(cppu::queryInterface(rType, static_cast< XPropertySetOption * >(this))); + if ( cnd.hasValue() ) + return cnd; + return OPropertySetHelper::queryInterface(rType); +} + +/** + * called from the derivee's XTypeProvider::getTypes implementation + */ +css::uno::Sequence< css::uno::Type > OPropertySetHelper::getTypes() +{ + return { + UnoType<css::beans::XPropertySet>::get(), + UnoType<css::beans::XMultiPropertySet>::get(), + UnoType<css::beans::XFastPropertySet>::get()}; +} + +// ComponentHelper +void OPropertySetHelper::disposing() +{ + // Create an event with this as sender + Reference < XPropertySet > rSource = this; + EventObject aEvt; + aEvt.Source = rSource; + + // inform all listeners to release this object + // The listener containers are automatically cleared + aBoundLC.disposeAndClear( aEvt ); + aVetoableLC.disposeAndClear( aEvt ); +} + +Reference < XPropertySetInfo > OPropertySetHelper::createPropertySetInfo( + IPropertyArrayHelper & rProperties ) +{ + return new OPropertySetHelperInfo_Impl(rProperties); +} + +// XPropertySet +void OPropertySetHelper::setPropertyValue( + const OUString& rPropertyName, const Any& rValue ) +{ + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // map the name to the handle + sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); + // call the method of the XFastPropertySet interface + setFastPropertyValue( nHandle, rValue ); +} + +// XPropertySet +Any OPropertySetHelper::getPropertyValue( + const OUString& rPropertyName ) +{ + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // map the name to the handle + sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); + // call the method of the XFastPropertySet interface + return getFastPropertyValue( nHandle ); +} + +// XPropertySet +void OPropertySetHelper::addPropertyChangeListener( + const OUString& rPropertyName, + const Reference < XPropertyChangeListener > & rxListener ) +{ + MutexGuard aGuard( rBHelper.rMutex ); + OSL_ENSURE( !rBHelper.bInDispose, "do not addPropertyChangeListener in the dispose call" ); + OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); + if( rBHelper.bInDispose || rBHelper.bDisposed ) + return; + + // only add listeners if you are not disposed + // a listener with no name means all properties + if( !rPropertyName.isEmpty() ) + { + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // map the name to the handle + sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); + if( nHandle == -1 ) { + // property not known throw exception + throw UnknownPropertyException(rPropertyName); + } + + sal_Int16 nAttributes; + rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle ); + if( !(nAttributes & css::beans::PropertyAttribute::BOUND) ) + { + OSL_FAIL( "add listener to an unbound property" ); + // silent ignore this + return; + } + // add the change listener to the helper container + + aBoundLC.addInterface( nHandle, rxListener ); + } + else + // add the change listener to the helper container + rBHelper.aLC.addInterface( + getPropertyTypeIdentifier( ), + rxListener + ); +} + + +// XPropertySet +void OPropertySetHelper::removePropertyChangeListener( + const OUString& rPropertyName, + const Reference < XPropertyChangeListener >& rxListener ) +{ + MutexGuard aGuard( rBHelper.rMutex ); + OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); + // all listeners are automatically released in a dispose call + if( rBHelper.bInDispose || rBHelper.bDisposed ) + return; + + if( !rPropertyName.isEmpty() ) + { + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // map the name to the handle + sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); + if( nHandle == -1 ) + // property not known throw exception + throw UnknownPropertyException(rPropertyName); + aBoundLC.removeInterface( nHandle, rxListener ); + } + else { + // remove the change listener to the helper container + rBHelper.aLC.removeInterface( + getPropertyTypeIdentifier( ), + rxListener + ); + } +} + +// XPropertySet +void OPropertySetHelper::addVetoableChangeListener( + const OUString& rPropertyName, + const Reference< XVetoableChangeListener > & rxListener ) +{ + MutexGuard aGuard( rBHelper.rMutex ); + OSL_ENSURE( !rBHelper.bInDispose, "do not addVetoableChangeListener in the dispose call" ); + OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); + if( rBHelper.bInDispose || rBHelper.bDisposed ) + return; + + // only add listeners if you are not disposed + // a listener with no name means all properties + if( !rPropertyName.isEmpty() ) + { + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // map the name to the handle + sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); + if( nHandle == -1 ) { + // property not known throw exception + throw UnknownPropertyException(rPropertyName); + } + + sal_Int16 nAttributes; + rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle ); + if( !(nAttributes & PropertyAttribute::CONSTRAINED) ) + { + OSL_FAIL( "addVetoableChangeListener, and property is not constrained" ); + // silent ignore this + return; + } + // add the vetoable listener to the helper container + aVetoableLC.addInterface( nHandle, rxListener ); + } + else + // add the vetoable listener to the helper container + rBHelper.aLC.addInterface( + getVetoableTypeIdentifier( ), + rxListener + ); +} + +// XPropertySet +void OPropertySetHelper::removeVetoableChangeListener( + const OUString& rPropertyName, + const Reference < XVetoableChangeListener > & rxListener ) +{ + MutexGuard aGuard( rBHelper.rMutex ); + OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); + // all listeners are automatically released in a dispose call + if( rBHelper.bInDispose || rBHelper.bDisposed ) + return; + + if( !rPropertyName.isEmpty() ) + { + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // map the name to the handle + sal_Int32 nHandle = rPH.getHandleByName( rPropertyName ); + if( nHandle == -1 ) { + // property not known throw exception + throw UnknownPropertyException(rPropertyName); + } + // remove the vetoable listener to the helper container + aVetoableLC.removeInterface( nHandle, rxListener ); + } + else + // add the vetoable listener to the helper container + rBHelper.aLC.removeInterface( + getVetoableTypeIdentifier( ), + rxListener + ); +} + +void OPropertySetHelper::setDependentFastPropertyValue( sal_Int32 i_handle, const css::uno::Any& i_value ) +{ + //OSL_PRECOND( rBHelper.rMutex.isAcquired(), "OPropertySetHelper::setDependentFastPropertyValue: to be called with a locked mutex only!" ); + // there is no such thing as Mutex.isAcquired, sadly ... + + sal_Int16 nAttributes(0); + IPropertyArrayHelper& rInfo = getInfoHelper(); + if ( !rInfo.fillPropertyMembersByHandle( nullptr, &nAttributes, i_handle ) ) + // unknown property + throw UnknownPropertyException(OUString::number(i_handle)); + + // no need to check for READONLY-ness of the property. The method is intended to be called internally, which + // implies it might be invoked for properties which are read-only to the instance's clients, but well allowed + // to change their value. + + Any aConverted, aOld; + bool bChanged = convertFastPropertyValue( aConverted, aOld, i_handle, i_value ); + if ( !bChanged ) + return; + + // don't fire vetoable events. This method is called with our mutex locked, so calling into listeners would not be + // a good idea. The caller is responsible for not invoking this for constrained properties. + OSL_ENSURE( ( nAttributes & PropertyAttribute::CONSTRAINED ) == 0, + "OPropertySetHelper::setDependentFastPropertyValue: not to be used for constrained properties!" ); + + // actually set the new value + try + { + setFastPropertyValue_NoBroadcast( i_handle, aConverted ); + } + catch (const UnknownPropertyException& ) { throw; /* allowed to leave */ } + catch (const PropertyVetoException& ) { throw; /* allowed to leave */ } + catch (const IllegalArgumentException& ) { throw; /* allowed to leave */ } + catch (const WrappedTargetException& ) { throw; /* allowed to leave */ } + catch (const RuntimeException& ) { throw; /* allowed to leave */ } + catch (const Exception& ) + { + // not allowed to leave this method + WrappedTargetException aWrapped; + aWrapped.TargetException = ::cppu::getCaughtException(); + aWrapped.Context = static_cast< XPropertySet* >( this ); + throw aWrapped; + } + + // remember the handle/values, for the events to be fired later + m_pReserved->m_handles.push_back( i_handle ); + m_pReserved->m_newValues.push_back( aConverted ); // TODO: setFastPropertyValue notifies the unconverted value here ...? + m_pReserved->m_oldValues.push_back( aOld ); +} + +// XFastPropertySet +void OPropertySetHelper::setFastPropertyValue( sal_Int32 nHandle, const Any& rValue ) +{ + OSL_ENSURE( !rBHelper.bInDispose, "do not setFastPropertyValue in the dispose call" ); + OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); + + IPropertyArrayHelper & rInfo = getInfoHelper(); + sal_Int16 nAttributes; + if( !rInfo.fillPropertyMembersByHandle( nullptr, &nAttributes, nHandle ) ) { + // unknown property + throw UnknownPropertyException(OUString::number(nHandle)); + } + if( nAttributes & PropertyAttribute::READONLY ) + throw PropertyVetoException(); + + Any aConvertedVal; + Any aOldVal; + + // Will the property change? + bool bChanged; + { + MutexGuard aGuard( rBHelper.rMutex ); + bChanged = convertFastPropertyValue( aConvertedVal, aOldVal, nHandle, rValue ); + // release guard to fire events + } + if( !bChanged ) + return; + + // Is it a constrained property? + if( nAttributes & PropertyAttribute::CONSTRAINED ) + { + // In aValue is the converted rValue + // fire a constrained event + // second parameter NULL means constrained + fire( &nHandle, &rValue, &aOldVal, 1, true ); + } + + { + MutexGuard aGuard( rBHelper.rMutex ); + try + { + // set the property to the new value + setFastPropertyValue_NoBroadcast( nHandle, aConvertedVal ); + } + catch (const css::beans::UnknownPropertyException& ) { throw; /* allowed to leave */ } + catch (const css::beans::PropertyVetoException& ) { throw; /* allowed to leave */ } + catch (const css::lang::IllegalArgumentException& ) { throw; /* allowed to leave */ } + catch (const css::lang::WrappedTargetException& ) { throw; /* allowed to leave */ } + catch (const css::uno::RuntimeException& ) { throw; /* allowed to leave */ } + catch (const css::uno::Exception& e ) + { + // not allowed to leave this method + css::lang::WrappedTargetException aWrap; + aWrap.Context = static_cast< css::beans::XPropertySet* >( this ); + aWrap.TargetException <<= e; + + throw aWrap; + } + + // release guard to fire events + } + // file a change event, if the value changed + impl_fireAll( &nHandle, &rValue, &aOldVal, 1 ); +} + +// XFastPropertySet +Any OPropertySetHelper::getFastPropertyValue( sal_Int32 nHandle ) + +{ + IPropertyArrayHelper & rInfo = getInfoHelper(); + if( !rInfo.fillPropertyMembersByHandle( nullptr, nullptr, nHandle ) ) + // unknown property + throw UnknownPropertyException(OUString::number(nHandle)); + + Any aRet; + MutexGuard aGuard( rBHelper.rMutex ); + getFastPropertyValue( aRet, nHandle ); + return aRet; +} + + +void OPropertySetHelper::impl_fireAll( sal_Int32* i_handles, const Any* i_newValues, const Any* i_oldValues, sal_Int32 i_count ) +{ + ClearableMutexGuard aGuard( rBHelper.rMutex ); + if ( m_pReserved->m_handles.empty() ) + { + aGuard.clear(); + fire( i_handles, i_newValues, i_oldValues, i_count, false ); + return; + } + + const size_t additionalEvents = m_pReserved->m_handles.size(); + OSL_ENSURE( additionalEvents == m_pReserved->m_newValues.size() + && additionalEvents == m_pReserved->m_oldValues.size(), + "OPropertySetHelper::impl_fireAll: inconsistency!" ); + + std::vector< sal_Int32 > allHandles( additionalEvents + i_count ); + std::copy( m_pReserved->m_handles.begin(), m_pReserved->m_handles.end(), allHandles.begin() ); + std::copy( i_handles, i_handles + i_count, allHandles.begin() + additionalEvents ); + + std::vector< Any > allNewValues( additionalEvents + i_count ); + std::copy( m_pReserved->m_newValues.begin(), m_pReserved->m_newValues.end(), allNewValues.begin() ); + std::copy( i_newValues, i_newValues + i_count, allNewValues.begin() + additionalEvents ); + + std::vector< Any > allOldValues( additionalEvents + i_count ); + std::copy( m_pReserved->m_oldValues.begin(), m_pReserved->m_oldValues.end(), allOldValues.begin() ); + std::copy( i_oldValues, i_oldValues + i_count, allOldValues.begin() + additionalEvents ); + + m_pReserved->m_handles.clear(); + m_pReserved->m_newValues.clear(); + m_pReserved->m_oldValues.clear(); + + aGuard.clear(); + fire( allHandles.data(), allNewValues.data(), allOldValues.data(), additionalEvents + i_count, false ); +} + + +void OPropertySetHelper::fire +( + sal_Int32 * pnHandles, + const Any * pNewValues, + const Any * pOldValues, + sal_Int32 nHandles, // This is the Count of the array + sal_Bool bVetoable +) +{ + if (! m_pReserved->m_bFireEvents) + return; + + if (m_pReserved->m_pFireEvents) { + m_pReserved->m_pFireEvents->fireEvents( + pnHandles, nHandles, bVetoable, + m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring); + } + + // Only fire, if one or more properties changed + if( !nHandles ) + return; + + // create the event sequence of all changed properties + Sequence< PropertyChangeEvent > aEvts( nHandles ); + PropertyChangeEvent * pEvts = aEvts.getArray(); + Reference < XInterface > xSource( static_cast<XPropertySet *>(this), UNO_QUERY ); + sal_Int32 i; + sal_Int32 nChangesLen = 0; + // Loop over all changed properties to fill the event struct + for( i = 0; i < nHandles; i++ ) + { + // Vetoable fire and constrained attribute set or + // Change fire and Changed and bound attribute set + IPropertyArrayHelper & rInfo = getInfoHelper(); + sal_Int16 nAttributes; + OUString aPropName; + rInfo.fillPropertyMembersByHandle( &aPropName, &nAttributes, pnHandles[i] ); + + if( + (bVetoable && (nAttributes & PropertyAttribute::CONSTRAINED)) || + (!bVetoable && (nAttributes & PropertyAttribute::BOUND)) + ) + { + pEvts[nChangesLen].Source = xSource; + pEvts[nChangesLen].PropertyName = aPropName; + pEvts[nChangesLen].PropertyHandle = pnHandles[i]; + pEvts[nChangesLen].OldValue = pOldValues[i]; + pEvts[nChangesLen].NewValue = pNewValues[i]; + nChangesLen++; + } + } + + bool bIgnoreRuntimeExceptionsWhileFiring = + m_pReserved->m_bIgnoreRuntimeExceptionsWhileFiring; + + // fire the events for all changed properties + for( i = 0; i < nChangesLen; i++ ) + { + // get the listener container for the property name + OInterfaceContainerHelper * pLC; + if( bVetoable ) // fire change Events? + pLC = aVetoableLC.getContainer( pEvts[i].PropertyHandle ); + else + pLC = aBoundLC.getContainer( pEvts[i].PropertyHandle ); + if( pLC ) + { + // Iterate over all listeners and send events + OInterfaceIteratorHelper aIt( *pLC); + while( aIt.hasMoreElements() ) + { + XInterface * pL = aIt.next(); + try + { + try + { + if( bVetoable ) // fire change Events? + { + static_cast<XVetoableChangeListener *>(pL)->vetoableChange( + pEvts[i] ); + } + else + { + static_cast<XPropertyChangeListener *>(pL)->propertyChange( + pEvts[i] ); + } + } + catch (DisposedException & exc) + { + OSL_ENSURE( exc.Context.is(), + "DisposedException without Context!" ); + if (exc.Context == pL) + aIt.remove(); + else + throw; + } + } + catch (RuntimeException & exc) + { + SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc); + if (! bIgnoreRuntimeExceptionsWhileFiring) + throw; + } + } + } + // broadcast to all listeners with "" property name + if( bVetoable ){ + // fire change Events? + pLC = rBHelper.aLC.getContainer( + getVetoableTypeIdentifier() + ); + } + else { + pLC = rBHelper.aLC.getContainer( + getPropertyTypeIdentifier( ) + ); + } + if( pLC ) + { + // Iterate over all listeners and send events. + OInterfaceIteratorHelper aIt( *pLC); + while( aIt.hasMoreElements() ) + { + XInterface * pL = aIt.next(); + try + { + try + { + if( bVetoable ) // fire change Events? + { + static_cast<XVetoableChangeListener *>(pL)->vetoableChange( + pEvts[i] ); + } + else + { + static_cast<XPropertyChangeListener *>(pL)->propertyChange( + pEvts[i] ); + } + } + catch (DisposedException & exc) + { + OSL_ENSURE( exc.Context.is(), + "DisposedException without Context!" ); + if (exc.Context == pL) + aIt.remove(); + else + throw; + } + } + catch (RuntimeException & exc) + { + SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc); + if (! bIgnoreRuntimeExceptionsWhileFiring) + throw; + } + } + } + } + + // reduce array to changed properties + aEvts.realloc( nChangesLen ); + + if( bVetoable ) + return; + + auto pCont = rBHelper.aLC.getContainer(getPropertiesTypeIdentifier()); + if (!pCont) + return; + + // Here is a Bug, unbound properties are also fired + OInterfaceIteratorHelper aIt( *pCont ); + while( aIt.hasMoreElements() ) + { + XPropertiesChangeListener * pL = + static_cast<XPropertiesChangeListener *>(aIt.next()); + try + { + try + { + // fire the whole event sequence to the + // XPropertiesChangeListener's + pL->propertiesChange( aEvts ); + } + catch (DisposedException & exc) + { + OSL_ENSURE( exc.Context.is(), + "DisposedException without Context!" ); + if (exc.Context == pL) + aIt.remove(); + else + throw; + } + } + catch (RuntimeException & exc) + { + SAL_INFO("cppuhelper", "caught RuntimeException while firing listeners: " << exc); + if (! bIgnoreRuntimeExceptionsWhileFiring) + throw; + } + } +} + +// OPropertySetHelper +void OPropertySetHelper::setFastPropertyValues( + sal_Int32 nSeqLen, + sal_Int32 * pHandles, + const Any * pValues, + sal_Int32 nHitCount ) +{ + OSL_ENSURE( !rBHelper.bInDispose, "do not getFastPropertyValue in the dispose call" ); + OSL_ENSURE( !rBHelper.bDisposed, "object is disposed" ); + + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + + std::unique_ptr<Any[]> pConvertedValues(new Any[ nHitCount ]); + std::unique_ptr<Any[]> pOldValues(new Any[ nHitCount ]); + sal_Int32 n = 0; + sal_Int32 i; + + { + // must lock the mutex outside the loop. So all values are consistent. + MutexGuard aGuard( rBHelper.rMutex ); + for( i = 0; i < nSeqLen; i++ ) + { + if( pHandles[i] != -1 ) + { + sal_Int16 nAttributes; + rPH.fillPropertyMembersByHandle( nullptr, &nAttributes, pHandles[i] ); + if( nAttributes & PropertyAttribute::READONLY ) { + throw PropertyVetoException(); + } + // Will the property change? + if( convertFastPropertyValue( pConvertedValues[ n ], pOldValues[n], + pHandles[i], pValues[i] ) ) + { + // only increment if the property really change + pHandles[n] = pHandles[i]; + n++; + } + } + } + // release guard to fire events + } + + // fire vetoable events + fire( pHandles, pConvertedValues.get(), pOldValues.get(), n, true ); + + { + // must lock the mutex outside the loop. + MutexGuard aGuard( rBHelper.rMutex ); + // Loop over all changed properties + for( i = 0; i < n; i++ ) + { + // Will the property change? + setFastPropertyValue_NoBroadcast( pHandles[i], pConvertedValues[i] ); + } + // release guard to fire events + } + + // fire change events + impl_fireAll( pHandles, pConvertedValues.get(), pOldValues.get(), n ); +} + +// XMultiPropertySet +/** + * The sequence may be contain not known properties. The implementation + * must ignore these properties. + */ +void OPropertySetHelper::setPropertyValues( + const Sequence<OUString>& rPropertyNames, + const Sequence<Any>& rValues ) +{ + sal_Int32 nSeqLen = rPropertyNames.getLength(); + std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nSeqLen ]); + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // fill the handle array + sal_Int32 nHitCount = rPH.fillHandles( pHandles.get(), rPropertyNames ); + if( nHitCount != 0 ) + setFastPropertyValues( nSeqLen, pHandles.get(), rValues.getConstArray(), nHitCount ); +} + +// XMultiPropertySet +Sequence<Any> OPropertySetHelper::getPropertyValues( const Sequence<OUString>& rPropertyNames ) +{ + sal_Int32 nSeqLen = rPropertyNames.getLength(); + std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[ nSeqLen ]); + Sequence< Any > aValues( nSeqLen ); + + // get the map table + IPropertyArrayHelper & rPH = getInfoHelper(); + // fill the handle array + rPH.fillHandles( pHandles.get(), rPropertyNames ); + + Any * pValues = aValues.getArray(); + + MutexGuard aGuard( rBHelper.rMutex ); + // fill the sequence with the values + for( sal_Int32 i = 0; i < nSeqLen; i++ ) + getFastPropertyValue( pValues[i], pHandles[i] ); + + return aValues; +} + +// XMultiPropertySet +void OPropertySetHelper::addPropertiesChangeListener( + const Sequence<OUString> & , + const Reference < XPropertiesChangeListener > & rListener ) +{ + rBHelper.addListener( cppu::UnoType<decltype(rListener)>::get(), rListener ); +} + +// XMultiPropertySet +void OPropertySetHelper::removePropertiesChangeListener( + const Reference < XPropertiesChangeListener > & rListener ) +{ + rBHelper.removeListener( cppu::UnoType<decltype(rListener)>::get(), rListener ); +} + +// XMultiPropertySet +void OPropertySetHelper::firePropertiesChangeEvent( + const Sequence<OUString>& rPropertyNames, + const Reference < XPropertiesChangeListener >& rListener ) +{ + sal_Int32 nLen = rPropertyNames.getLength(); + std::unique_ptr<sal_Int32[]> pHandles(new sal_Int32[nLen]); + IPropertyArrayHelper & rPH = getInfoHelper(); + rPH.fillHandles( pHandles.get(), rPropertyNames ); + const OUString* pNames = rPropertyNames.getConstArray(); + + // get the count of matching properties + sal_Int32 nFireLen = 0; + sal_Int32 i; + for( i = 0; i < nLen; i++ ) + if( pHandles[i] != -1 ) + nFireLen++; + + Sequence<PropertyChangeEvent> aChanges( nFireLen ); + PropertyChangeEvent* pChanges = aChanges.getArray(); + + { + // must lock the mutex outside the loop. So all values are consistent. + MutexGuard aGuard( rBHelper.rMutex ); + Reference < XInterface > xSource( static_cast<XPropertySet *>(this), UNO_QUERY ); + sal_Int32 nFirePos = 0; + for( i = 0; i < nLen; i++ ) + { + if( pHandles[i] != -1 ) + { + pChanges[nFirePos].Source = xSource; + pChanges[nFirePos].PropertyName = pNames[i]; + pChanges[nFirePos].PropertyHandle = pHandles[i]; + getFastPropertyValue( pChanges[nFirePos].OldValue, pHandles[i] ); + pChanges[nFirePos].NewValue = pChanges[nFirePos].OldValue; + nFirePos++; + } + } + // release guard to fire events + } + if( nFireLen ) + rListener->propertiesChange( aChanges ); +} + +void OPropertySetHelper2::enableChangeListenerNotification( sal_Bool bEnable ) +{ + m_pReserved->m_bFireEvents = bEnable; +} + +extern "C" { + +static int compare_Property_Impl( const void *arg1, const void *arg2 ) + SAL_THROW_EXTERN_C() +{ + return static_cast<Property const *>(arg1)->Name.compareTo( static_cast<Property const *>(arg2)->Name ); +} + +} + +void OPropertyArrayHelper::init( sal_Bool bSorted ) +{ + sal_Int32 i, nElements = aInfos.getLength(); + const Property* pProperties = aInfos.getConstArray(); + + for( i = 1; i < nElements; i++ ) + { + if( pProperties[i-1].Name > pProperties[i].Name ) + { + if (bSorted) { + OSL_FAIL( "Property array is not sorted" ); + } + // not sorted + qsort( aInfos.getArray(), nElements, sizeof( Property ), + compare_Property_Impl ); + pProperties = aInfos.getConstArray(); + break; + } + } + for( i = 0; i < nElements; i++ ) + if( pProperties[i].Handle != i ) + return; + // The handle is the index + bRightOrdered = true; +} + +OPropertyArrayHelper::OPropertyArrayHelper( + Property * pProps, + sal_Int32 nEle, + sal_Bool bSorted ) + : m_pReserved(nullptr) + , aInfos(pProps, nEle) + , bRightOrdered( false ) +{ + init( bSorted ); +} + +OPropertyArrayHelper::OPropertyArrayHelper( + const Sequence< Property > & aProps, + sal_Bool bSorted ) + : m_pReserved(nullptr) + , aInfos(aProps) + , bRightOrdered( false ) +{ + init( bSorted ); +} + + +sal_Int32 OPropertyArrayHelper::getCount() const +{ + return aInfos.getLength(); +} + + +sal_Bool OPropertyArrayHelper::fillPropertyMembersByHandle +( + OUString * pPropName, + sal_Int16 * pAttributes, + sal_Int32 nHandle +) +{ + const Property* pProperties = aInfos.getConstArray(); + sal_Int32 nElements = aInfos.getLength(); + + if( bRightOrdered ) + { + if( nHandle < 0 || nHandle >= nElements ) + return false; + if( pPropName ) + *pPropName = pProperties[ nHandle ].Name; + if( pAttributes ) + *pAttributes = pProperties[ nHandle ].Attributes; + return true; + } + // normally the array is sorted + for( sal_Int32 i = 0; i < nElements; i++ ) + { + if( pProperties[i].Handle == nHandle ) + { + if( pPropName ) + *pPropName = pProperties[ i ].Name; + if( pAttributes ) + *pAttributes = pProperties[ i ].Attributes; + return true; + } + } + return false; +} + + +Sequence< Property > OPropertyArrayHelper::getProperties() +{ + return aInfos; +} + + +Property OPropertyArrayHelper::getPropertyByName(const OUString& aPropertyName) +{ + Property * pR; + pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(), + sizeof( Property ), + compare_OUString_Property_Impl )); + if( !pR ) { + throw UnknownPropertyException(aPropertyName); + } + return *pR; +} + + +sal_Bool OPropertyArrayHelper::hasPropertyByName(const OUString& aPropertyName) +{ + Property * pR; + pR = static_cast<Property *>(bsearch( &aPropertyName, aInfos.getConstArray(), aInfos.getLength(), + sizeof( Property ), + compare_OUString_Property_Impl )); + return pR != nullptr; +} + + +sal_Int32 OPropertyArrayHelper::getHandleByName( const OUString & rPropName ) +{ + Property * pR; + pR = static_cast<Property *>(bsearch( &rPropName, aInfos.getConstArray(), aInfos.getLength(), + sizeof( Property ), + compare_OUString_Property_Impl )); + return pR ? pR->Handle : -1; +} + + +sal_Int32 OPropertyArrayHelper::fillHandles( sal_Int32 * pHandles, const Sequence< OUString > & rPropNames ) +{ + sal_Int32 nHitCount = 0; + const OUString * pReqProps = rPropNames.getConstArray(); + sal_Int32 nReqLen = rPropNames.getLength(); + const Property * pCur = aInfos.getConstArray(); + const Property * pEnd = pCur + aInfos.getLength(); + + for( sal_Int32 i = 0; i < nReqLen; i++ ) + { + // Calculate logarithm + sal_Int32 n = static_cast<sal_Int32>(pEnd - pCur); + sal_Int32 nLog = 0; + while( n ) + { + nLog += 1; + n = n >> 1; + } + + // Number of properties to search for * Log2 of the number of remaining + // properties to search in. + if( (nReqLen - i) * nLog >= pEnd - pCur ) + { + // linear search is better + while( pCur < pEnd && pReqProps[i] > pCur->Name ) + { + pCur++; + } + if( pCur < pEnd && pReqProps[i] == pCur->Name ) + { + pHandles[i] = pCur->Handle; + nHitCount++; + } + else + pHandles[i] = -1; + } + else + { + // binary search is better + sal_Int32 nCompVal = 1; + const Property * pOldEnd = pEnd--; + const Property * pMid = pCur; + + while( nCompVal != 0 && pCur <= pEnd ) + { + pMid = (pEnd - pCur) / 2 + pCur; + + nCompVal = pReqProps[i].compareTo( pMid->Name ); + + if( nCompVal > 0 ) + pCur = pMid + 1; + else + pEnd = pMid - 1; + } + + if( nCompVal == 0 ) + { + pHandles[i] = pMid->Handle; + nHitCount++; + pCur = pMid +1; + } + else if( nCompVal > 0 ) + { + pHandles[i] = -1; + pCur = pMid +1; + } + else + { + pHandles[i] = -1; + pCur = pMid; + } + pEnd = pOldEnd; + } + } + return nHitCount; +} + +} // end namespace cppu + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/servicemanager.cxx b/cppuhelper/source/servicemanager.cxx new file mode 100644 index 000000000..2ba6ae51a --- /dev/null +++ b/cppuhelper/source/servicemanager.cxx @@ -0,0 +1,1988 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <algorithm> +#include <cassert> +#include <iostream> +#include <vector> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/container/ElementExistException.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/loader/XImplementationLoader.hpp> +#include <com/sun/star/registry/InvalidRegistryException.hpp> +#include <com/sun/star/uno/DeploymentException.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/component_context.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <cppuhelper/factory.hxx> +#include <o3tl/safeint.hxx> +#include <osl/file.hxx> +#include <osl/module.hxx> +#include <rtl/ref.hxx> +#include <rtl/uri.hxx> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <uno/environment.hxx> +#include <uno/mapping.hxx> + +#include "loadsharedlibcomponentfactory.hxx" + +#include <registry/registry.hxx> +#include <xmlreader/xmlreader.hxx> + +#include "paths.hxx" +#include "servicemanager.hxx" + +namespace { + +void insertImplementationMap( + cppuhelper::ServiceManager::Data::ImplementationMap * destination, + cppuhelper::ServiceManager::Data::ImplementationMap const & source) +{ + assert(destination != nullptr); + for (const auto& [rName, rImpls] : source) + { + std::vector< + std::shared_ptr< + cppuhelper::ServiceManager::Data::Implementation > > & impls + = (*destination)[rName]; + impls.insert(impls.end(), rImpls.begin(), rImpls.end()); + } +} + +void removeFromImplementationMap( + cppuhelper::ServiceManager::Data::ImplementationMap * map, + std::vector< OUString > const & elements, + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > + const & implementation) +{ + // The underlying data structures make this function somewhat inefficient, + // but the assumption is that it is rarely called: + assert(map != nullptr); + for (const auto& rElement : elements) + { + cppuhelper::ServiceManager::Data::ImplementationMap::iterator j( + map->find(rElement)); + assert(j != map->end()); + std::vector< + std::shared_ptr< + cppuhelper::ServiceManager::Data::Implementation > >::iterator + k(std::find(j->second.begin(), j->second.end(), implementation)); + assert(k != j->second.end()); + j->second.erase(k); + if (j->second.empty()) { + map->erase(j); + } + } +} + +// For simplicity, this code keeps throwing +// css::registry::InvalidRegistryException for invalid XML rdbs (even though +// that does not fit the exception's name): +class Parser { +public: + Parser( + OUString const & uri, + css::uno::Reference< css::uno::XComponentContext > const & alienContext, + cppuhelper::ServiceManager::Data * data); + + Parser(const Parser&) = delete; + const Parser& operator=(const Parser&) = delete; + +private: + void handleComponent(); + + void handleImplementation(); + + void handleService(); + + void handleSingleton(); + + OUString getNameAttribute(); + + xmlreader::XmlReader reader_; + css::uno::Reference< css::uno::XComponentContext > alienContext_; + cppuhelper::ServiceManager::Data * data_; + OUString attrLoader_; + OUString attrUri_; + OUString attrEnvironment_; + OUString attrPrefix_; + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > + implementation_; +}; + +Parser::Parser( + OUString const & uri, + css::uno::Reference< css::uno::XComponentContext > const & alienContext, + cppuhelper::ServiceManager::Data * data): + reader_(uri), alienContext_(alienContext), data_(data) +{ + assert(data != nullptr); + int ucNsId = reader_.registerNamespaceIri( + xmlreader::Span( + RTL_CONSTASCII_STRINGPARAM( + "http://openoffice.org/2010/uno-components"))); + enum State { + STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL, + STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON }; + for (State state = STATE_BEGIN;;) { + xmlreader::Span name; + int nsId; + xmlreader::XmlReader::Result res = reader_.nextItem( + xmlreader::XmlReader::Text::NONE, &name, &nsId); + switch (state) { + case STATE_BEGIN: + if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("components"))) + { + state = STATE_COMPONENTS; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in outer level"); + case STATE_END: + if (res == xmlreader::XmlReader::Result::Done) { + return; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in outer level"); + case STATE_COMPONENTS: + if (res == xmlreader::XmlReader::Result::End) { + state = STATE_END; + break; + } + if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("component"))) + { + handleComponent(); + state = STATE_COMPONENT_INITIAL; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in <components>"); + case STATE_COMPONENT: + if (res == xmlreader::XmlReader::Result::End) { + state = STATE_COMPONENTS; + break; + } + [[fallthrough]]; + case STATE_COMPONENT_INITIAL: + if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation"))) + { + handleImplementation(); + state = STATE_IMPLEMENTATION; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in <component>"); + case STATE_IMPLEMENTATION: + if (res == xmlreader::XmlReader::Result::End) { + state = STATE_COMPONENT; + break; + } + if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("service"))) + { + handleService(); + state = STATE_SERVICE; + break; + } + if (res == xmlreader::XmlReader::Result::Begin && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton"))) + { + handleSingleton(); + state = STATE_SINGLETON; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in <implementation>"); + case STATE_SERVICE: + if (res == xmlreader::XmlReader::Result::End) { + state = STATE_IMPLEMENTATION; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in <service>"); + case STATE_SINGLETON: + if (res == xmlreader::XmlReader::Result::End) { + state = STATE_IMPLEMENTATION; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in <service>"); + } + } +} + +void Parser::handleComponent() { + attrLoader_ = OUString(); + attrUri_ = OUString(); + attrEnvironment_ = OUString(); + attrPrefix_ = OUString(); + xmlreader::Span name; + int nsId; + while (reader_.nextAttribute(&nsId, &name)) { + if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("loader"))) + { + if (!attrLoader_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has multiple \"loader\" attributes"); + } + attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrLoader_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has empty \"loader\" attribute"); + } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("uri"))) + { + if (!attrUri_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has multiple \"uri\" attributes"); + } + attrUri_ = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrUri_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has empty \"uri\" attribute"); + } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("environment"))) + { + if (!attrEnvironment_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has multiple \"environment\" attributes"); + } + attrEnvironment_ = reader_.getAttributeValue(false) + .convertFromUtf8(); + if (attrEnvironment_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has empty \"environment\" attribute"); + } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix"))) + { + if (!attrPrefix_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has multiple \"prefix\" attributes"); + } + attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrPrefix_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <component> has empty \"prefix\" attribute"); + } + } else { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected attribute \"" + + name.convertFromUtf8() + "\" in <component>"); + } + } + if (attrLoader_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": <component> is missing \"loader\" attribute"); + } + if (attrUri_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": <component> is missing \"uri\" attribute"); + } +#ifndef DISABLE_DYNLOADING + try { + attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_); + } catch (const rtl::MalformedUriException & e) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage()); + } +#endif +} + +void Parser::handleImplementation() { + OUString attrName; + OUString attrConstructor; + xmlreader::Span name; + int nsId; + while (reader_.nextAttribute(&nsId, &name)) { + if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("name"))) + { + if (!attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <implementation> has multiple \"name\" attributes"); + } + attrName = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <implementation> has empty \"name\" attribute"); + } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("constructor"))) + { + if (!attrConstructor.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <implementation> has multiple \"constructor\"" + " attributes"); + } + attrConstructor = reader_.getAttributeValue(false) + .convertFromUtf8(); + if (attrConstructor.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": element has empty \"constructor\" attribute"); + } + if (attrEnvironment_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <implementation> has \"constructor\" attribute but" + " <component> has no \"environment\" attribute"); + } + } else { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected element attribute \"" + + name.convertFromUtf8() + "\" in <implementation>"); + } + } + if (attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": <implementation> is missing \"name\" attribute"); + } + implementation_ = + std::make_shared<cppuhelper::ServiceManager::Data::Implementation>( + attrName, attrLoader_, attrUri_, attrEnvironment_, attrConstructor, + attrPrefix_, alienContext_, reader_.getUrl()); + if (!data_->namedImplementations.emplace(attrName, implementation_). + second) + { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": duplicate <implementation name=\"" + attrName + + "\">"); + } +} + +void Parser::handleService() { + OUString name(getNameAttribute()); + implementation_->services.push_back(name); + data_->services[name].push_back(implementation_); +} + +void Parser::handleSingleton() { + OUString name(getNameAttribute()); + implementation_->singletons.push_back(name); + data_->singletons[name].push_back(implementation_); +} + +OUString Parser::getNameAttribute() { + OUString attrName; + xmlreader::Span name; + int nsId; + while (reader_.nextAttribute(&nsId, &name)) { + if (nsId != xmlreader::XmlReader::NAMESPACE_NONE + || !name.equals(RTL_CONSTASCII_STRINGPARAM("name"))) + { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": expected element attribute \"name\""); + } + if (!attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + + ": element has multiple \"name\" attributes"); + } + attrName = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": element has empty \"name\" attribute"); + } + } + if (attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": element is missing \"name\" attribute"); + } + return attrName; +} + +class ContentEnumeration: + public cppu::WeakImplHelper< css::container::XEnumeration > +{ +public: + explicit ContentEnumeration(std::vector< css::uno::Any > const & factories): + factories_(factories), iterator_(factories_.begin()) {} + + ContentEnumeration(const ContentEnumeration&) = delete; + const ContentEnumeration& operator=(const ContentEnumeration&) = delete; + +private: + virtual ~ContentEnumeration() override {} + + virtual sal_Bool SAL_CALL hasMoreElements() override; + + virtual css::uno::Any SAL_CALL nextElement() override; + + osl::Mutex mutex_; + std::vector< css::uno::Any > factories_; + std::vector< css::uno::Any >::const_iterator iterator_; +}; + +sal_Bool ContentEnumeration::hasMoreElements() +{ + osl::MutexGuard g(mutex_); + return iterator_ != factories_.end(); +} + +css::uno::Any ContentEnumeration::nextElement() +{ + osl::MutexGuard g(mutex_); + if (iterator_ == factories_.end()) { + throw css::container::NoSuchElementException( + "Bootstrap service manager service enumerator has no more elements", + static_cast< cppu::OWeakObject * >(this)); + } + return *iterator_++; +} + +css::beans::Property getDefaultContextProperty() { + return css::beans::Property( + "DefaultContext", -1, + cppu::UnoType< css::uno::XComponentContext >::get(), + css::beans::PropertyAttribute::READONLY); +} + +class SingletonFactory: + public cppu::WeakImplHelper<css::lang::XSingleComponentFactory> +{ +public: + SingletonFactory( + rtl::Reference< cppuhelper::ServiceManager > const & manager, + std::shared_ptr< + cppuhelper::ServiceManager::Data::Implementation > const & + implementation): + manager_(manager), implementation_(implementation) + { assert(manager.is()); assert(implementation.get() != nullptr); } + + SingletonFactory(const SingletonFactory&) = delete; + const SingletonFactory& operator=(const SingletonFactory&) = delete; + +private: + virtual ~SingletonFactory() override {} + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithContext( + css::uno::Reference< css::uno::XComponentContext > const & Context) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArgumentsAndContext( + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) override; + + rtl::Reference< cppuhelper::ServiceManager > manager_; + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > + implementation_; +}; + +css::uno::Reference< css::uno::XInterface > +SingletonFactory::createInstanceWithContext( + css::uno::Reference< css::uno::XComponentContext > const & Context) +{ + manager_->loadImplementation(Context, implementation_); + return implementation_->createInstance(Context, true); +} + +css::uno::Reference< css::uno::XInterface > +SingletonFactory::createInstanceWithArgumentsAndContext( + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) +{ + manager_->loadImplementation(Context, implementation_); + return implementation_->createInstanceWithArguments( + Context, true, Arguments); +} + +class ImplementationWrapper: + public cppu::WeakImplHelper< + css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory, + css::lang::XServiceInfo > +{ +public: + ImplementationWrapper( + rtl::Reference< cppuhelper::ServiceManager > const & manager, + std::shared_ptr< + cppuhelper::ServiceManager::Data::Implementation > const & + implementation): + manager_(manager), implementation_(implementation) + { assert(manager.is()); assert(implementation.get() != nullptr); } + + ImplementationWrapper(const ImplementationWrapper&) = delete; + const ImplementationWrapper& operator=(const ImplementationWrapper&) = delete; + +private: + virtual ~ImplementationWrapper() override {} + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithContext( + css::uno::Reference< css::uno::XComponentContext > const & Context) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArgumentsAndContext( + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstance() override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArguments( + css::uno::Sequence< css::uno::Any > const & Arguments) override; + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + rtl::Reference< cppuhelper::ServiceManager > manager_; + std::weak_ptr< cppuhelper::ServiceManager::Data::Implementation > + implementation_; +}; + +css::uno::Reference< css::uno::XInterface > +ImplementationWrapper::createInstanceWithContext( + css::uno::Reference< css::uno::XComponentContext > const & Context) +{ + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock(); + assert(impl); + manager_->loadImplementation(Context, impl); + return impl->createInstance(Context, false); +} + +css::uno::Reference< css::uno::XInterface > +ImplementationWrapper::createInstanceWithArgumentsAndContext( + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) +{ + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock(); + assert(impl); + manager_->loadImplementation(Context, impl); + return impl->createInstanceWithArguments( + Context, false, Arguments); +} + +css::uno::Reference< css::uno::XInterface > +ImplementationWrapper::createInstance() +{ + return createInstanceWithContext(manager_->getContext()); +} + +css::uno::Reference< css::uno::XInterface > +ImplementationWrapper::createInstanceWithArguments( + css::uno::Sequence< css::uno::Any > const & Arguments) +{ + return createInstanceWithArgumentsAndContext( + Arguments, manager_->getContext()); +} + +OUString ImplementationWrapper::getImplementationName() +{ + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock(); + assert(impl); + return impl->name; +} + +sal_Bool ImplementationWrapper::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > +ImplementationWrapper::getSupportedServiceNames() +{ + std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock(); + assert(impl); + if (impl->services.size() + > o3tl::make_unsigned(SAL_MAX_INT32)) + { + throw css::uno::RuntimeException( + ("Implementation " + impl->name + + " supports too many services"), + static_cast< cppu::OWeakObject * >(this)); + } + return comphelper::containerToSequence(impl->services); +} + +} + +css::uno::Reference<css::uno::XInterface> +cppuhelper::ServiceManager::Data::Implementation::createInstance( + css::uno::Reference<css::uno::XComponentContext> const & context, + bool singletonRequest) +{ + css::uno::Reference<css::uno::XInterface> inst; + if (constructorFn) { + inst.set( + constructorFn(context.get(), css::uno::Sequence<css::uno::Any>()), + SAL_NO_ACQUIRE); + } else if (factory1.is()) { + inst = factory1->createInstanceWithContext(context); + } else { + assert(factory2.is()); + inst = factory2->createInstance(); + } + updateDisposeSingleton(singletonRequest, inst); + return inst; +} + +css::uno::Reference<css::uno::XInterface> +cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments( + css::uno::Reference<css::uno::XComponentContext> const & context, + bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments) +{ + css::uno::Reference<css::uno::XInterface> inst; + if (constructorFn) { + inst.set(constructorFn(context.get(), arguments), SAL_NO_ACQUIRE); + //HACK: The constructor will either observe arguments and return inst + // that does not implement XInitialization (or null), or ignore + // arguments and return inst that implements XInitialization; this + // should be removed again once XInitialization-based implementations + // have become rare: + css::uno::Reference<css::lang::XInitialization> init( + inst, css::uno::UNO_QUERY); + if (init.is()) { + init->initialize(arguments); + } + } else if (factory1.is()) { + inst = factory1->createInstanceWithArgumentsAndContext( + arguments, context); + } else { + assert(factory2.is()); + inst = factory2->createInstanceWithArguments(arguments); + } + updateDisposeSingleton(singletonRequest, inst); + return inst; +} + +void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton( + bool singletonRequest, + css::uno::Reference<css::uno::XInterface> const & instance) +{ + // This is an optimization, to only call dispose once (from the component + // context) on a singleton that is obtained both via the component context + // and via the service manager; however, there is a harmless race here that + // may cause two calls to dispose nevertheless (also, this calls dispose on + // at most one of the instances obtained via the service manager, in case + // the implementation hands out different instances): + if (singletonRequest) { + osl::MutexGuard g(mutex); + disposeSingleton.clear(); + dispose = false; + } else if (!singletons.empty()) { + css::uno::Reference<css::lang::XComponent> comp( + instance, css::uno::UNO_QUERY); + if (comp.is()) { + osl::MutexGuard g(mutex); + if (dispose) { + disposeSingleton = comp; + } + } + } +} + +void cppuhelper::ServiceManager::addSingletonContextEntries( + std::vector< cppu::ContextEntry_Init > * entries) +{ + assert(entries != nullptr); + for (const auto& [rName, rImpls] : data_.singletons) + { + assert(!rImpls.empty()); + assert(rImpls[0].get() != nullptr); + SAL_INFO_IF( + rImpls.size() > 1, "cppuhelper", + "Arbitrarily choosing " << rImpls[0]->name + << " among multiple implementations for " << rName); + entries->push_back( + cppu::ContextEntry_Init( + "/singletons/" + rName, + css::uno::makeAny< + css::uno::Reference<css::lang::XSingleComponentFactory> >( + new SingletonFactory(this, rImpls[0])), + true)); + } +} + +void cppuhelper::ServiceManager::loadImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + std::shared_ptr< Data::Implementation > const & implementation) +{ + assert(implementation.get() != nullptr); + { + osl::MutexGuard g(rBHelper.rMutex); + if (implementation->status == Data::Implementation::STATUS_LOADED) { + return; + } + } + OUString uri; + try { + uri = cppu::bootstrap_expandUri(implementation->uri); + } catch (css::lang::IllegalArgumentException & e) { + throw css::uno::DeploymentException( + "Cannot expand URI" + implementation->uri + ": " + e.Message, + static_cast< cppu::OWeakObject * >(this)); + } + cppuhelper::WrapperConstructorFn ctor; + css::uno::Reference< css::uno::XInterface > f0; + // Special handling of SharedLibrary loader, with support for environment, + // constructor, and prefix arguments: + if (!implementation->alienContext.is() + && implementation->loader == "com.sun.star.loader.SharedLibrary") + { + cppuhelper::detail::loadSharedLibComponentFactory( + uri, implementation->environment, + implementation->prefix, implementation->name, + implementation->constructorName, this, &ctor, &f0); + if (ctor) { + assert(!implementation->environment.isEmpty()); + } + } else { + SAL_WARN_IF( + !implementation->environment.isEmpty(), "cppuhelper", + "Loader " << implementation->loader + << " and non-empty environment " + << implementation->environment); + SAL_WARN_IF( + !implementation->prefix.isEmpty(), "cppuhelper", + "Loader " << implementation->loader + << " and non-empty constructor " + << implementation->constructorName); + SAL_WARN_IF( + !implementation->prefix.isEmpty(), "cppuhelper", + "Loader " << implementation->loader + << " and non-empty prefix " << implementation->prefix); + css::uno::Reference< css::uno::XComponentContext > ctxt; + css::uno::Reference< css::lang::XMultiComponentFactory > smgr; + if (implementation->alienContext.is()) { + ctxt = implementation->alienContext; + smgr.set(ctxt->getServiceManager(), css::uno::UNO_SET_THROW); + } else { + assert(context.is()); + ctxt = context; + smgr = this; + } + css::uno::Reference< css::loader::XImplementationLoader > loader( + smgr->createInstanceWithContext(implementation->loader, ctxt), + css::uno::UNO_QUERY_THROW); + f0 = loader->activate( + implementation->name, OUString(), uri, + css::uno::Reference< css::registry::XRegistryKey >()); + } + css::uno::Reference<css::lang::XSingleComponentFactory> f1; + css::uno::Reference<css::lang::XSingleServiceFactory> f2; + if (!ctor) { + f1.set(f0, css::uno::UNO_QUERY); + if (!f1.is()) { + f2.set(f0, css::uno::UNO_QUERY); + if (!f2.is()) { + throw css::uno::DeploymentException( + ("Implementation " + implementation->name + + " does not provide a constructor or factory"), + static_cast< cppu::OWeakObject * >(this)); + } + } + } + //TODO: There is a race here, as the relevant service factory can be removed + // while the mutex is unlocked and loading can thus fail, as the entity from + // which to load can disappear once the service factory is removed. + osl::MutexGuard g(rBHelper.rMutex); + if (!(isDisposed() + || implementation->status == Data::Implementation::STATUS_LOADED)) + { + implementation->status = Data::Implementation::STATUS_LOADED; + implementation->constructorFn = ctor; + implementation->factory1 = f1; + implementation->factory2 = f2; + } +} + +void cppuhelper::ServiceManager::disposing() { + std::vector< css::uno::Reference<css::lang::XComponent> > sngls; + std::vector< css::uno::Reference< css::lang::XComponent > > comps; + Data clear; + { + osl::MutexGuard g(rBHelper.rMutex); + for (const auto& rEntry : data_.namedImplementations) + { + assert(rEntry.second.get() != nullptr); + if (!rEntry.second->singletons.empty()) { + osl::MutexGuard g2(rEntry.second->mutex); + if (rEntry.second->disposeSingleton.is()) { + sngls.push_back(rEntry.second->disposeSingleton); + } + } + } + for (const auto& rEntry : data_.dynamicImplementations) + { + assert(rEntry.second.get() != nullptr); + if (!rEntry.second->singletons.empty()) { + osl::MutexGuard g2(rEntry.second->mutex); + if (rEntry.second->disposeSingleton.is()) { + sngls.push_back(rEntry.second->disposeSingleton); + } + } + if (rEntry.second->component.is()) { + comps.push_back(rEntry.second->component); + } + } + data_.namedImplementations.swap(clear.namedImplementations); + data_.dynamicImplementations.swap(clear.dynamicImplementations); + data_.services.swap(clear.services); + data_.singletons.swap(clear.singletons); + } + for (const auto& rxSngl : sngls) + { + try { + rxSngl->dispose(); + } catch (css::uno::RuntimeException & e) { + SAL_WARN("cppuhelper", "Ignoring " << e << " while disposing singleton"); + } + } + for (const auto& rxComp : comps) + { + removeEventListenerFromComponent(rxComp); + } +} + +void cppuhelper::ServiceManager::initialize( + css::uno::Sequence<css::uno::Any> const & aArguments) +{ + OUString arg; + if (aArguments.getLength() != 1 || !(aArguments[0] >>= arg) + || arg != "preload") + { + throw css::lang::IllegalArgumentException( + "invalid ServiceManager::initialize argument", + css::uno::Reference<css::uno::XInterface>(), 0); + } + preloadImplementations(); +} + +OUString cppuhelper::ServiceManager::getImplementationName() +{ + return + "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager"; +} + +sal_Bool cppuhelper::ServiceManager::supportsService( + OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > +cppuhelper::ServiceManager::getSupportedServiceNames() +{ + return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" }; +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstance( + OUString const & aServiceSpecifier) +{ + assert(context_.is()); + return createInstanceWithContext(aServiceSpecifier, context_); +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstanceWithArguments( + OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments) +{ + assert(context_.is()); + return createInstanceWithArgumentsAndContext( + ServiceSpecifier, Arguments, context_); +} + +css::uno::Sequence< OUString > +cppuhelper::ServiceManager::getAvailableServiceNames() +{ + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + return css::uno::Sequence< OUString >(); + } + if (data_.services.size() > o3tl::make_unsigned(SAL_MAX_INT32)) { + throw css::uno::RuntimeException( + "getAvailableServiceNames: too many services", + static_cast< cppu::OWeakObject * >(this)); + } + return comphelper::mapKeysToSequence(data_.services); +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstanceWithContext( + OUString const & aServiceSpecifier, + css::uno::Reference< css::uno::XComponentContext > const & Context) +{ + std::shared_ptr< Data::Implementation > impl( + findServiceImplementation(Context, aServiceSpecifier)); + return impl == nullptr ? css::uno::Reference<css::uno::XInterface>() + : impl->createInstance(Context, false); +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext( + OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) +{ + std::shared_ptr< Data::Implementation > impl( + findServiceImplementation(Context, ServiceSpecifier)); + return impl == nullptr ? css::uno::Reference<css::uno::XInterface>() + : impl->createInstanceWithArguments(Context, false, Arguments); +} + +css::uno::Type cppuhelper::ServiceManager::getElementType() +{ + return css::uno::Type(); +} + +sal_Bool cppuhelper::ServiceManager::hasElements() +{ + osl::MutexGuard g(rBHelper.rMutex); + return + !(data_.namedImplementations.empty() + && data_.dynamicImplementations.empty()); +} + +css::uno::Reference< css::container::XEnumeration > +cppuhelper::ServiceManager::createEnumeration() +{ + throw css::uno::RuntimeException( + "ServiceManager createEnumeration: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &) +{ + throw css::uno::RuntimeException( + "ServiceManager has: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement) +{ + css::uno::Sequence< css::beans::NamedValue > args; + if (aElement >>= args) { + std::vector< OUString > uris; + css::uno::Reference< css::uno::XComponentContext > alienContext; + for (const auto & arg : std::as_const(args)) { + if (arg.Name == "uri") { + OUString uri; + if (!(arg.Value >>= uri)) { + throw css::lang::IllegalArgumentException( + "Bad uri argument", + static_cast< cppu::OWeakObject * >(this), 0); + } + uris.push_back(uri); + } else if (arg.Name == "component-context") { + if (alienContext.is()) { + throw css::lang::IllegalArgumentException( + "Multiple component-context arguments", + static_cast< cppu::OWeakObject * >(this), 0); + } + if (!(arg.Value >>= alienContext) || !alienContext.is()) { + throw css::lang::IllegalArgumentException( + "Bad component-context argument", + static_cast< cppu::OWeakObject * >(this), 0); + } + } else { + throw css::lang::IllegalArgumentException( + "Bad argument " + arg.Name, + static_cast< cppu::OWeakObject * >(this), 0); + } + } + insertRdbFiles(uris, alienContext); + return; + } + css::uno::Reference< css::lang::XServiceInfo > info; + if ((aElement >>= info) && info.is()) { + insertLegacyFactory(info); + return; + } +// At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in +// module languagetool) contain an (actively registered) factory that does not +// implement XServiceInfo (see <http://sourceforge.net/tracker/? +// func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should +// implement XServiceInfo"); the old OServiceManager::insert +// (stoc/source/servicemanager/servicemanager.cxx) silently did not add such +// broken factories to its m_ImplementationNameMap, so ignore them here for +// backwards compatibility of live-insertion of extensions, too. + +// (The plan was that this warning would go away (and we would do the +// throw instead) for the incompatible LO 4, but we changed our mind): + css::uno::Reference< css::lang::XSingleComponentFactory > legacy; + if ((aElement >>= legacy) && legacy.is()) { + SAL_WARN( + "cppuhelper", + "Ignored XSingleComponentFactory not implementing XServiceInfo"); + return; + } + + throw css::lang::IllegalArgumentException( + "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0); +} + +void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement) +{ + css::uno::Sequence< css::beans::NamedValue > args; + if (aElement >>= args) { + std::vector< OUString > uris; + for (const auto & i : std::as_const(args)) { + if (i.Name != "uri") { + throw css::lang::IllegalArgumentException( + "Bad argument " + i.Name, + static_cast< cppu::OWeakObject * >(this), 0); + } + OUString uri; + if (!(i.Value >>= uri)) { + throw css::lang::IllegalArgumentException( + "Bad uri argument", + static_cast< cppu::OWeakObject * >(this), 0); + } + uris.push_back(uri); + } + removeRdbFiles(uris); + return; + } + css::uno::Reference< css::lang::XServiceInfo > info; + if ((aElement >>= info) && info.is()) { + if (!removeLegacyFactory(info, true)) { + throw css::container::NoSuchElementException( + "Remove non-inserted factory object", + static_cast< cppu::OWeakObject * >(this)); + } + return; + } + OUString impl; + if (aElement >>= impl) { + // For live-removal of extensions: + removeImplementation(impl); + return; + } + throw css::lang::IllegalArgumentException( + "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0); +} + +css::uno::Reference< css::container::XEnumeration > +cppuhelper::ServiceManager::createContentEnumeration( + OUString const & aServiceName) +{ + std::vector< std::shared_ptr< Data::Implementation > > impls; + { + osl::MutexGuard g(rBHelper.rMutex); + Data::ImplementationMap::const_iterator i( + data_.services.find(aServiceName)); + if (i != data_.services.end()) { + impls = i->second; + } + } + std::vector< css::uno::Any > factories; + for (const auto& rxImpl : impls) + { + Data::Implementation * impl = rxImpl.get(); + assert(impl != nullptr); + { + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + factories.clear(); + break; + } + if (impl->status == Data::Implementation::STATUS_NEW) { + // Postpone actual implementation instantiation as long as + // possible (so that e.g. opening LO's "Tools - Macros" menu + // does not try to instantiate a JVM, which can lead to a + // synchronous error dialog when no JVM is specified, and + // showing the dialog while hovering over a menu can cause + // trouble): + impl->factory1 = new ImplementationWrapper(this, rxImpl); + impl->status = Data::Implementation::STATUS_WRAPPER; + } + if (impl->constructorFn != nullptr && !impl->factory1.is()) { + impl->factory1 = new ImplementationWrapper(this, rxImpl); + } + } + if (impl->factory1.is()) { + factories.push_back(css::uno::Any(impl->factory1)); + } else { + assert(impl->factory2.is()); + factories.push_back(css::uno::Any(impl->factory2)); + } + } + return new ContentEnumeration(factories); +} + +css::uno::Reference< css::beans::XPropertySetInfo > +cppuhelper::ServiceManager::getPropertySetInfo() +{ + return this; +} + +void cppuhelper::ServiceManager::setPropertyValue( + OUString const & aPropertyName, css::uno::Any const &) +{ + if (aPropertyName == "DefaultContext") { + throw css::beans::PropertyVetoException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } else { + throw css::beans::UnknownPropertyException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } +} + +css::uno::Any cppuhelper::ServiceManager::getPropertyValue( + OUString const & PropertyName) +{ + if (PropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + assert(context_.is()); + return css::uno::Any(context_); +} + +void cppuhelper::ServiceManager::addPropertyChangeListener( + OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + xListener) +{ + if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return addEventListener(xListener); +} + +void cppuhelper::ServiceManager::removePropertyChangeListener( + OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + aListener) +{ + if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return removeEventListener(aListener); +} + +void cppuhelper::ServiceManager::addVetoableChangeListener( + OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) +{ + if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return addEventListener(aListener); +} + +void cppuhelper::ServiceManager::removeVetoableChangeListener( + OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) +{ + if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return removeEventListener(aListener); +} + +css::uno::Sequence< css::beans::Property > +cppuhelper::ServiceManager::getProperties() { + css::uno::Sequence< css::beans::Property > props(1); + props[0] = getDefaultContextProperty(); + return props; +} + +css::beans::Property cppuhelper::ServiceManager::getPropertyByName( + OUString const & aName) +{ + if (aName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + aName, static_cast< cppu::OWeakObject * >(this)); + } + return getDefaultContextProperty(); +} + +sal_Bool cppuhelper::ServiceManager::hasPropertyByName( + OUString const & Name) +{ + return Name == "DefaultContext"; +} + +cppuhelper::ServiceManager::~ServiceManager() {} + +void cppuhelper::ServiceManager::disposing( + css::lang::EventObject const & Source) +{ + removeLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo >( + Source.Source, css::uno::UNO_QUERY_THROW), + false); +} + +void cppuhelper::ServiceManager::removeEventListenerFromComponent( + css::uno::Reference< css::lang::XComponent > const & component) +{ + assert(component.is()); + try { + component->removeEventListener(this); + } catch (css::uno::RuntimeException & e) { + SAL_INFO( + "cppuhelper", + "Ignored removeEventListener RuntimeException " + e.Message); + } +} + +void cppuhelper::ServiceManager::init(OUString const & rdbUris) { + for (sal_Int32 i = 0; i != -1;) { + OUString uri(rdbUris.getToken(0, ' ', i)); + if (uri.isEmpty()) { + continue; + } + bool optional; + bool directory; + cppu::decodeRdbUri(&uri, &optional, &directory); + if (directory) { + readRdbDirectory(uri, optional); + } else { + readRdbFile(uri, optional); + } + } +} + +void cppuhelper::ServiceManager::readRdbDirectory( + OUString const & uri, bool optional) +{ + osl::Directory dir(uri); + switch (dir.open()) { + case osl::FileBase::E_None: + break; + case osl::FileBase::E_NOENT: + if (optional) { + SAL_INFO("cppuhelper", "Ignored optional " << uri); + return; + } + [[fallthrough]]; + default: + throw css::uno::DeploymentException( + "Cannot open directory " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (;;) { + OUString url; + if (!cppu::nextDirectoryItem(dir, &url)) { + break; + } + readRdbFile(url, false); + } +} + +void cppuhelper::ServiceManager::readRdbFile( + OUString const & uri, bool optional) +{ + try { + Parser( + uri, css::uno::Reference< css::uno::XComponentContext >(), &data_); + } catch (css::container::NoSuchElementException &) { + if (!optional) { + throw css::uno::DeploymentException( + uri + ": no such file", + static_cast< cppu::OWeakObject * >(this)); + } + SAL_INFO("cppuhelper", "Ignored optional " << uri); + } catch (css::registry::InvalidRegistryException & e) { + if (!readLegacyRdbFile(uri)) { + throw css::uno::DeploymentException( + "InvalidRegistryException: " + e.Message, + static_cast< cppu::OWeakObject * >(this)); + } + } catch (css::uno::RuntimeException &) { + if (!readLegacyRdbFile(uri)) { + throw; + } + } +} + +bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString const & uri) { + Registry reg; + switch (reg.open(uri, RegAccessMode::READONLY)) { + case RegError::NO_ERROR: + break; + case RegError::REGISTRY_NOT_EXISTS: + case RegError::INVALID_REGISTRY: + { + // Ignore empty rdb files (which are at least seen by subordinate + // uno processes during extension registration; Registry::open can + // fail on them if mmap(2) returns EINVAL for a zero length): + osl::DirectoryItem item; + if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) { + osl::FileStatus status(osl_FileStatus_Mask_FileSize); + if (item.getFileStatus(status) == osl::FileBase::E_None + && status.getFileSize() == 0) + { + return true; + } + } + } + [[fallthrough]]; + default: + return false; + } + RegistryKey rootKey; + if (reg.openRootKey(rootKey) != RegError::NO_ERROR) { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + RegistryKeyArray impls; + switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) { + case RegError::NO_ERROR: + break; + case RegError::KEY_NOT_EXISTS: + return true; + default: + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (sal_uInt32 i = 0; i != impls.getLength(); ++i) { + RegistryKey implKey(impls.getElement(i)); + assert(implKey.getName().match("/IMPLEMENTATIONS/")); + OUString name( + implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/"))); + std::shared_ptr< Data::Implementation > impl = + std::make_shared<Data::Implementation>( + name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"), + readLegacyRdbString(uri, implKey, "UNO/LOCATION"), "", "", "", + css::uno::Reference< css::uno::XComponentContext >(), uri); + if (!data_.namedImplementations.emplace(name, impl).second) + { + throw css::registry::InvalidRegistryException( + uri + ": duplicate <implementation name=\"" + name + "\">"); + } + readLegacyRdbStrings( + uri, implKey, "UNO/SERVICES", &impl->services); + for (const auto& rService : impl->services) + { + data_.services[rService].push_back(impl); + } + readLegacyRdbStrings( + uri, implKey, "UNO/SINGLETONS", &impl->singletons); + for (const auto& rSingleton : impl->singletons) + { + data_.singletons[rSingleton].push_back(impl); + } + } + return true; +} + +OUString cppuhelper::ServiceManager::readLegacyRdbString( + OUString const & uri, RegistryKey & key, OUString const & path) +{ + RegistryKey subkey; + RegValueType t; + sal_uInt32 s(0); + if (key.openKey(path, subkey) != RegError::NO_ERROR + || subkey.getValueInfo(OUString(), &t, &s) != RegError::NO_ERROR + || t != RegValueType::STRING + || s == 0 || s > o3tl::make_unsigned(SAL_MAX_INT32)) + { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + OUString val; + std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type + if (subkey.getValue(OUString(), v.data()) != RegError::NO_ERROR + || v.back() != '\0' + || !rtl_convertStringToUString( + &val.pData, v.data(), static_cast< sal_Int32 >(s - 1), + RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + return val; +} + +void cppuhelper::ServiceManager::readLegacyRdbStrings( + OUString const & uri, RegistryKey & key, OUString const & path, + std::vector< OUString > * strings) +{ + assert(strings != nullptr); + RegistryKey subkey; + switch (key.openKey(path, subkey)) { + case RegError::NO_ERROR: + break; + case RegError::KEY_NOT_EXISTS: + return; + default: + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + OUString prefix(subkey.getName() + "/"); + RegistryKeyNames names; + if (subkey.getKeyNames(OUString(), names) != RegError::NO_ERROR) { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (sal_uInt32 i = 0; i != names.getLength(); ++i) { + assert(names.getElement(i).match(prefix)); + strings->push_back(names.getElement(i).copy(prefix.getLength())); + } +} + +void cppuhelper::ServiceManager::insertRdbFiles( + std::vector< OUString > const & uris, + css::uno::Reference< css::uno::XComponentContext > const & alienContext) +{ + Data extra; + for (const auto& rUri : uris) + { + try { + Parser(rUri, alienContext, &extra); + } catch (css::container::NoSuchElementException &) { + throw css::lang::IllegalArgumentException( + rUri + ": no such file", static_cast< cppu::OWeakObject * >(this), + 0); + } catch (css::registry::InvalidRegistryException & e) { + throw css::lang::IllegalArgumentException( + "InvalidRegistryException: " + e.Message, + static_cast< cppu::OWeakObject * >(this), 0); + } + } + insertExtraData(extra); +} + +void cppuhelper::ServiceManager::insertLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo) +{ + assert(factoryInfo.is()); + OUString name(factoryInfo->getImplementationName()); + css::uno::Reference< css::lang::XSingleComponentFactory > f1( + factoryInfo, css::uno::UNO_QUERY); + css::uno::Reference< css::lang::XSingleServiceFactory > f2; + if (!f1.is()) { + f2.set(factoryInfo, css::uno::UNO_QUERY); + if (!f2.is()) { + throw css::lang::IllegalArgumentException( + ("Bad XServiceInfo argument implements neither" + " XSingleComponentFactory nor XSingleServiceFactory"), + static_cast< cppu::OWeakObject * >(this), 0); + } + } + css::uno::Reference< css::lang::XComponent > comp( + factoryInfo, css::uno::UNO_QUERY); + std::shared_ptr< Data::Implementation > impl = + std::make_shared<Data::Implementation>(name, f1, f2, comp); + Data extra; + if (!name.isEmpty()) { + extra.namedImplementations.emplace(name, impl); + } + extra.dynamicImplementations.emplace(factoryInfo, impl); + const css::uno::Sequence< OUString > services( + factoryInfo->getSupportedServiceNames()); + for (const auto & i : services) { + impl->services.push_back(i); + extra.services[i].push_back(impl); + } + if (insertExtraData(extra) && comp.is()) { + comp->addEventListener(this); + } +} + +bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) { + { + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + return false; + } + auto i = std::find_if(extra.namedImplementations.begin(), extra.namedImplementations.end(), + [this](const Data::NamedImplementations::value_type& rEntry) { + return data_.namedImplementations.find(rEntry.first) != data_.namedImplementations.end(); }); + if (i != extra.namedImplementations.end()) + { + throw css::lang::IllegalArgumentException( + "Insert duplicate implementation name " + i->first, + static_cast< cppu::OWeakObject * >(this), 0); + } + bool bDuplicate = std::any_of(extra.dynamicImplementations.begin(), extra.dynamicImplementations.end(), + [this](const Data::DynamicImplementations::value_type& rEntry) { + return data_.dynamicImplementations.find(rEntry.first) != data_.dynamicImplementations.end(); }); + if (bDuplicate) + { + throw css::lang::IllegalArgumentException( + "Insert duplicate factory object", + static_cast< cppu::OWeakObject * >(this), 0); + } + //TODO: The below leaves data_ in an inconsistent state upon exceptions: + data_.namedImplementations.insert( + extra.namedImplementations.begin(), + extra.namedImplementations.end()); + data_.dynamicImplementations.insert( + extra.dynamicImplementations.begin(), + extra.dynamicImplementations.end()); + insertImplementationMap(&data_.services, extra.services); + insertImplementationMap(&data_.singletons, extra.singletons); + } + //TODO: Updating the component context singleton data should be part of the + // atomic service manager update: + if (!extra.singletons.empty()) { + assert(context_.is()); + css::uno::Reference< css::container::XNameContainer > cont( + context_, css::uno::UNO_QUERY_THROW); + for (const auto& [rName, rImpls] : extra.singletons) + { + OUString name("/singletons/" + rName); + //TODO: Update should be atomic: + try { + cont->removeByName(name + "/arguments"); + } catch (const css::container::NoSuchElementException &) {} + assert(!rImpls.empty()); + assert(rImpls[0].get() != nullptr); + SAL_INFO_IF( + rImpls.size() > 1, "cppuhelper", + "Arbitrarily choosing " << rImpls[0]->name + << " among multiple implementations for singleton " + << rName); + try { + cont->insertByName( + name + "/service", css::uno::Any(rImpls[0]->name)); + } catch (css::container::ElementExistException &) { + cont->replaceByName( + name + "/service", css::uno::Any(rImpls[0]->name)); + } + try { + cont->insertByName(name, css::uno::Any()); + } catch (css::container::ElementExistException &) { + SAL_INFO("cppuhelper", "Overwriting singleton " << rName); + cont->replaceByName(name, css::uno::Any()); + } + } + } + return true; +} + +void cppuhelper::ServiceManager::removeRdbFiles( + std::vector< OUString > const & uris) +{ + // The underlying data structures make this function somewhat inefficient, + // but the assumption is that it is rarely called (and that if it is called, + // it is called with a uris vector of size one): + std::vector< std::shared_ptr< Data::Implementation > > clear; + { + osl::MutexGuard g(rBHelper.rMutex); + for (const auto& rUri : uris) + { + for (Data::NamedImplementations::iterator j( + data_.namedImplementations.begin()); + j != data_.namedImplementations.end();) + { + assert(j->second.get() != nullptr); + if (j->second->rdbFile == rUri) { + clear.push_back(j->second); + //TODO: The below leaves data_ in an inconsistent state upon + // exceptions: + removeFromImplementationMap( + &data_.services, j->second->services, j->second); + removeFromImplementationMap( + &data_.singletons, j->second->singletons, + j->second); + j = data_.namedImplementations.erase(j); + } else { + ++j; + } + } + } + } + //TODO: Update the component context singleton data +} + +bool cppuhelper::ServiceManager::removeLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo, + bool removeListener) +{ + assert(factoryInfo.is()); + std::shared_ptr< Data::Implementation > clear; + css::uno::Reference< css::lang::XComponent > comp; + { + osl::MutexGuard g(rBHelper.rMutex); + Data::DynamicImplementations::iterator i( + data_.dynamicImplementations.find(factoryInfo)); + if (i == data_.dynamicImplementations.end()) { + return isDisposed(); + } + assert(i->second.get() != nullptr); + clear = i->second; + if (removeListener) { + comp = i->second->component; + } + //TODO: The below leaves data_ in an inconsistent state upon exceptions: + removeFromImplementationMap( + &data_.services, i->second->services, i->second); + removeFromImplementationMap( + &data_.singletons, i->second->singletons, i->second); + if (!i->second->name.isEmpty()) { + data_.namedImplementations.erase(i->second->name); + } + data_.dynamicImplementations.erase(i); + } + if (comp.is()) { + removeEventListenerFromComponent(comp); + } + return true; +} + +void cppuhelper::ServiceManager::removeImplementation(const OUString & name) { + // The underlying data structures make this function somewhat inefficient, + // but the assumption is that it is rarely called: + std::shared_ptr< Data::Implementation > clear; + { + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + return; + } + Data::NamedImplementations::iterator i( + data_.namedImplementations.find(name)); + if (i == data_.namedImplementations.end()) { + throw css::container::NoSuchElementException( + "Remove non-inserted implementation " + name, + static_cast< cppu::OWeakObject * >(this)); + } + assert(i->second.get() != nullptr); + clear = i->second; + //TODO: The below leaves data_ in an inconsistent state upon exceptions: + removeFromImplementationMap( + &data_.services, i->second->services, i->second); + removeFromImplementationMap( + &data_.singletons, i->second->singletons, i->second); + auto j = std::find_if(data_.dynamicImplementations.begin(), data_.dynamicImplementations.end(), + [&i](const Data::DynamicImplementations::value_type& rEntry) { return rEntry.second == i->second; }); + if (j != data_.dynamicImplementations.end()) + data_.dynamicImplementations.erase(j); + data_.namedImplementations.erase(i); + } +} + +std::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > +cppuhelper::ServiceManager::findServiceImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + OUString const & specifier) +{ + std::shared_ptr< Data::Implementation > impl; + bool loaded; + { + osl::MutexGuard g(rBHelper.rMutex); + Data::ImplementationMap::const_iterator i( + data_.services.find(specifier)); + if (i == data_.services.end()) { + Data::NamedImplementations::const_iterator j( + data_.namedImplementations.find(specifier)); + if (j == data_.namedImplementations.end()) { + SAL_INFO("cppuhelper", "No implementation for " << specifier); + return std::shared_ptr< Data::Implementation >(); + } + impl = j->second; + } else { + assert(!i->second.empty()); + SAL_INFO_IF( + i->second.size() > 1, "cppuhelper", + "Arbitrarily choosing " << i->second[0]->name + << " among multiple implementations for " << i->first); + impl = i->second[0]; + } + assert(impl.get() != nullptr); + loaded = impl->status == Data::Implementation::STATUS_LOADED; + } + if (!loaded) { + loadImplementation(context, impl); + } + return impl; +} + +/// Make a simpler unique name for preload / progress reporting. +#ifndef DISABLE_DYNLOADING +static OUString simplifyModule(const OUString &uri) +{ + sal_Int32 nIdx; + OUStringBuffer edit(uri); + if ((nIdx = edit.lastIndexOf('/')) > 0) + edit.remove(0,nIdx+1); + if ((nIdx = edit.lastIndexOf(':')) > 0) + edit.remove(0,nIdx+1); + if ((nIdx = edit.lastIndexOf("lo.so")) > 0) + edit.truncate(nIdx); + if ((nIdx = edit.lastIndexOf(".3")) > 0) + edit.truncate(nIdx); + if ((nIdx = edit.lastIndexOf("gcc3.so")) > 0) + edit.truncate(nIdx); + if ((nIdx = edit.lastIndexOf(".so")) > 0) + edit.truncate(nIdx); + if ((nIdx = edit.lastIndexOf("_uno")) > 0) + edit.truncate(nIdx); + if ((nIdx = edit.lastIndexOf(".jar")) > 0) + edit.truncate(nIdx); + if (edit.indexOf("lib") == 0) + edit.remove(0,3); + return edit.makeStringAndClear(); +} +#endif + +/// Used only by LibreOfficeKit when used by Online to pre-initialize +void cppuhelper::ServiceManager::preloadImplementations() { +#ifdef DISABLE_DYNLOADING + abort(); +#else + OUString aUri; + osl::MutexGuard g(rBHelper.rMutex); + css::uno::Environment aSourceEnv(css::uno::Environment::getCurrent()); + + std::cerr << "preload:"; + std::vector<OUString> aReported; + std::vector<OUString> aDisabled; + OUStringBuffer aDisabledMsg; + OUStringBuffer aMissingMsg; + + /// Allow external callers & testers to disable certain components + const char *pDisable = getenv("UNODISABLELIBRARY"); + if (pDisable) + { + OUString aDisable(pDisable, strlen(pDisable), RTL_TEXTENCODING_UTF8); + for (sal_Int32 i = 0; i >= 0; ) + { + OUString tok = aDisable.getToken(0, ' ', i); + tok = tok.trim(); + if (!tok.isEmpty()) + aDisabled.push_back(tok); + } + } + + // loop all implementations + for (const auto& rEntry : data_.namedImplementations) + { + if (rEntry.second->loader != "com.sun.star.loader.SharedLibrary" || + rEntry.second->status == Data::Implementation::STATUS_LOADED) + continue; + + OUString simplified; + try + { + const OUString &aLibrary = rEntry.second->uri; + + if (aLibrary.isEmpty()) + continue; + + simplified = simplifyModule(aLibrary); + + bool bDisabled = + std::find(aDisabled.begin(), aDisabled.end(), simplified) != aDisabled.end(); + + if (std::find(aReported.begin(), aReported.end(), aLibrary) == aReported.end()) + { + if (bDisabled) + { + aDisabledMsg.append(simplified); + aDisabledMsg.append(" "); + } + else + { + std::cerr << " " << simplified; + std::cerr.flush(); + } + aReported.push_back(aLibrary); + } + + if (bDisabled) + continue; + + // expand absolute URI implementation component library + aUri = cppu::bootstrap_expandUri(aLibrary); + } + catch (css::lang::IllegalArgumentException& aError) + { + throw css::uno::DeploymentException( + "Cannot expand URI" + rEntry.second->uri + ": " + aError.Message, + static_cast< cppu::OWeakObject * >(this)); + } + + // load component library + osl::Module aModule(aUri, SAL_LOADMODULE_NOW | SAL_LOADMODULE_GLOBAL); + + if (!aModule.is()) + { + aMissingMsg.append(simplified); + aMissingMsg.append(" "); + } + + if (aModule.is() && + !rEntry.second->environment.isEmpty()) + { + OUString aSymFactory; + oslGenericFunction fpFactory; + css::uno::Environment aTargetEnv; + css::uno::Reference<css::uno::XInterface> xFactory; + + if(rEntry.second->constructorName.isEmpty()) + { + // expand full name component factory symbol + if (rEntry.second->prefix == "direct") + aSymFactory = rEntry.second->name.replace('.', '_') + "_" COMPONENT_GETFACTORY; + else if (!rEntry.second->prefix.isEmpty()) + aSymFactory = rEntry.second->prefix + "_" COMPONENT_GETFACTORY; + else + aSymFactory = COMPONENT_GETFACTORY; + + // get function symbol component factory + fpFactory = aModule.getFunctionSymbol(aSymFactory); + if (fpFactory == nullptr) + { + throw css::loader::CannotActivateFactoryException( + ("no factory symbol \"" + aSymFactory + "\" in component library :" + aUri), + css::uno::Reference<css::uno::XInterface>()); + } + + aTargetEnv = cppuhelper::detail::getEnvironment(rEntry.second->environment, rEntry.second->name); + component_getFactoryFunc fpComponentFactory = reinterpret_cast<component_getFactoryFunc>(fpFactory); + + if (aSourceEnv.get() == aTargetEnv.get()) + { + // invoke function component factory + OString aImpl(OUStringToOString(rEntry.second->name, RTL_TEXTENCODING_ASCII_US)); + xFactory.set(css::uno::Reference<css::uno::XInterface>(static_cast<css::uno::XInterface *>( + (*fpComponentFactory)(aImpl.getStr(), this, nullptr)), SAL_NO_ACQUIRE)); + } + } + else + { + // get function symbol component factory + aTargetEnv = cppuhelper::detail::getEnvironment(rEntry.second->environment, rEntry.second->name); + fpFactory = (aSourceEnv.get() == aTargetEnv.get()) ? + aModule.getFunctionSymbol(rEntry.second->constructorName) : nullptr; + } + + css::uno::Reference<css::lang::XSingleComponentFactory> xSCFactory; + css::uno::Reference<css::lang::XSingleServiceFactory> xSSFactory; + + // query interface XSingleComponentFactory or XSingleServiceFactory + if (xFactory.is()) + { + xSCFactory.set(xFactory, css::uno::UNO_QUERY); + if (!xSCFactory.is()) + { + xSSFactory.set(xFactory, css::uno::UNO_QUERY); + if (!xSSFactory.is()) + throw css::uno::DeploymentException( + ("Implementation " + rEntry.second->name + + " does not provide a constructor or factory"), + static_cast< cppu::OWeakObject * >(this)); + } + } + + if (!rEntry.second->constructorName.isEmpty() && fpFactory) + rEntry.second->constructorFn = WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn *>(fpFactory)); + + rEntry.second->factory1 = xSCFactory; + rEntry.second->factory2 = xSSFactory; + rEntry.second->status = Data::Implementation::STATUS_LOADED; + + } + + // Some libraries use other (non-UNO) libraries requiring preinit + oslGenericFunction fpPreload = aModule.getFunctionSymbol( "lok_preload_hook" ); + if (fpPreload) + { + static std::vector<oslGenericFunction> aPreloaded; + if (std::find(aPreloaded.begin(), aPreloaded.end(), fpPreload) == aPreloaded.end()) + { + aPreloaded.push_back(fpPreload); + fpPreload(); + } + } + + // leak aModule + aModule.release(); + } + std::cerr << std::endl; + + if (aMissingMsg.getLength() > 0) + { + OUString aMsg = aMissingMsg.makeStringAndClear(); + std::cerr << "Absent (often optional): " << aMsg << "\n"; + } + if (aDisabledMsg.getLength() > 0) + { + OUString aMsg = aDisabledMsg.makeStringAndClear(); + std::cerr << "Disabled: " << aMsg << "\n"; + } + std::cerr.flush(); + + // Various rather important uno mappings. + static struct { + const char *mpFrom; + const char *mpTo; + const char *mpPurpose; + } const aMappingLoad[] = { + { "gcc3", "uno", "" }, + { "uno", "gcc3", "" }, + }; + + static std::vector<css::uno::Mapping> maMaps; + for (auto &it : aMappingLoad) + { + maMaps.push_back(css::uno::Mapping( + OUString::createFromAscii(it.mpFrom), + OUString::createFromAscii(it.mpTo), + OUString::createFromAscii(it.mpPurpose))); + } +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/servicemanager.hxx b/cppuhelper/source/servicemanager.hxx new file mode 100644 index 000000000..ceac7c15a --- /dev/null +++ b/cppuhelper/source/servicemanager.hxx @@ -0,0 +1,351 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_SERVICEMANAGER_HXX +#define INCLUDED_CPPUHELPER_SOURCE_SERVICEMANAGER_HXX + +#include <sal/config.h> + +#include <cassert> +#include <map> +#include <memory> +#include <vector> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <osl/mutex.hxx> +#include <rtl/ustring.hxx> + +namespace com::sun::star::lang { + class XSingleComponentFactory; +} +namespace cppu { struct ContextEntry_Init; } +namespace com :: sun :: star :: lang { class XSingleServiceFactory; } +namespace com :: sun :: star :: uno { class XComponentContext; } + +class RegistryKey; + +namespace cppuhelper { + +extern "C" { + +typedef css::uno::XInterface * ImplementationConstructorFn( + css::uno::XComponentContext *, css::uno::Sequence<css::uno::Any> const &); + +} + +typedef std::function<css::uno::XInterface * (css::uno::XComponentContext *, css::uno::Sequence<css::uno::Any> const&)> WrapperConstructorFn; + +typedef cppu::WeakComponentImplHelper< + css::lang::XServiceInfo, css::lang::XMultiServiceFactory, + css::lang::XMultiComponentFactory, css::container::XSet, + css::container::XContentEnumerationAccess, css::beans::XPropertySet, + css::beans::XPropertySetInfo, css::lang::XEventListener, + css::lang::XInitialization> +ServiceManagerBase; + +class ServiceManager: + private cppu::BaseMutex, public ServiceManagerBase +{ +public: + struct Data { + Data() = default; + Data(const Data&) = delete; + const Data& operator=(const Data&) = delete; + + struct Implementation { + Implementation( + OUString const & theName, OUString const & theLoader, + OUString const & theUri, OUString const & theEnvironment, + OUString const & theConstructorName, + OUString const & thePrefix, + css::uno::Reference< css::uno::XComponentContext > const & + theAlienContext, + OUString const & theRdbFile): + name(theName), loader(theLoader), uri(theUri), environment(theEnvironment), + constructorName(theConstructorName), prefix(thePrefix), + alienContext(theAlienContext), rdbFile(theRdbFile), + constructorFn(nullptr), status(STATUS_NEW), dispose(true) + {} + + Implementation( + OUString const & theName, + css::uno::Reference< css::lang::XSingleComponentFactory > + const & theFactory1, + css::uno::Reference< css::lang::XSingleServiceFactory > const & + theFactory2, + css::uno::Reference< css::lang::XComponent > const & + theComponent): + name(theName), constructorFn(nullptr), + factory1(theFactory1), factory2(theFactory2), + component(theComponent), status(STATUS_LOADED), dispose(true) + { assert(theFactory1.is() || theFactory2.is()); } + + Implementation(const Implementation&) = delete; + const Implementation& operator=(const Implementation&) = delete; + + css::uno::Reference<css::uno::XInterface> createInstance( + css::uno::Reference<css::uno::XComponentContext> const & + context, + bool singletonRequest); + + css::uno::Reference<css::uno::XInterface> + createInstanceWithArguments( + css::uno::Reference<css::uno::XComponentContext> const & + context, + bool singletonRequest, + css::uno::Sequence<css::uno::Any> const & arguments); + + enum Status { STATUS_NEW, STATUS_WRAPPER, STATUS_LOADED }; + + // Logically, exactly one of constructorFn, factory1, factory2 should + // be set. However, there are two exceptions: For one, when + // constructorFn is set, ServiceManager::createContentEnumeration will + // store the necessary ImplementationWrapper in factory1 (so that + // multiple calls to createContentEnumeration will return the same + // wrapper). For another, when factory1 should be set but status is + // STATUS_NEW, factory1 is not yet set (and when status is + // STATUS_WRAPPER, factory1 is merely set to an + // ImplementationWrapper---also due to a + // ServiceManager::createContentEnumeration call---and will be + // loaded later). + OUString name; + OUString loader; + OUString uri; + OUString environment; + OUString constructorName; + OUString prefix; + css::uno::Reference< css::uno::XComponentContext > alienContext; + OUString rdbFile; + std::vector< OUString > services; + std::vector< OUString > singletons; + WrapperConstructorFn constructorFn; + css::uno::Reference< css::lang::XSingleComponentFactory > factory1; + css::uno::Reference< css::lang::XSingleServiceFactory > factory2; + css::uno::Reference< css::lang::XComponent > component; + Status status; + + osl::Mutex mutex; + css::uno::Reference< css::lang::XComponent > disposeSingleton; + bool dispose; + + private: + void updateDisposeSingleton( + bool singletonRequest, + css::uno::Reference<css::uno::XInterface> const & instance); + }; + + typedef std::map< OUString, std::shared_ptr< Implementation > > + NamedImplementations; + + typedef + std::map< + css::uno::Reference< css::lang::XServiceInfo >, + std::shared_ptr< Implementation > > + DynamicImplementations; + + typedef + std::map< + OUString, + std::vector< std::shared_ptr< Implementation > > > + ImplementationMap; + + NamedImplementations namedImplementations; + DynamicImplementations dynamicImplementations; + ImplementationMap services; + ImplementationMap singletons; + }; + + ServiceManager(): ServiceManagerBase(m_aMutex) {} + + ServiceManager(const ServiceManager&) = delete; + const ServiceManager& operator=(const ServiceManager&) = delete; + + using ServiceManagerBase::acquire; + using ServiceManagerBase::release; + + void init(OUString const & rdbUris); + + void setContext( + css::uno::Reference< css::uno::XComponentContext > const & context) + { + assert(context.is()); + assert(!context_.is()); + context_ = context; + } + + void addSingletonContextEntries( + std::vector< cppu::ContextEntry_Init > * entries); + + css::uno::Reference< css::uno::XComponentContext > const & getContext() + const + { + assert(context_.is()); + return context_; + } + + void loadImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + std::shared_ptr< Data::Implementation > const & implementation); + +private: + virtual ~ServiceManager() override; + + virtual void SAL_CALL disposing() override; + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( + OUString const & aServiceSpecifier) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArguments( + OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments) override; + + virtual css::uno::Sequence< OUString > SAL_CALL + getAvailableServiceNames() override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithContext( + OUString const & aServiceSpecifier, + css::uno::Reference< css::uno::XComponentContext > const & Context) override; + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArgumentsAndContext( + OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) override; + + virtual css::uno::Type SAL_CALL getElementType() override; + + virtual sal_Bool SAL_CALL hasElements() override; + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL + createEnumeration() override; + + virtual sal_Bool SAL_CALL has(css::uno::Any const & aElement) override; + + virtual void SAL_CALL insert(css::uno::Any const & aElement) override; + + virtual void SAL_CALL remove(css::uno::Any const & aElement) override; + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL + createContentEnumeration(OUString const & aServiceName) override; + + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override; + + virtual void SAL_CALL setPropertyValue( + OUString const & aPropertyName, css::uno::Any const & aValue) override; + + virtual css::uno::Any SAL_CALL getPropertyValue( + OUString const & PropertyName) override; + + virtual void SAL_CALL addPropertyChangeListener( + OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + xListener) override; + + virtual void SAL_CALL removePropertyChangeListener( + OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + aListener) override; + + virtual void SAL_CALL addVetoableChangeListener( + OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) override; + + virtual void SAL_CALL removeVetoableChangeListener( + OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) override; + + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() override; + + virtual css::beans::Property SAL_CALL getPropertyByName( + OUString const & aName) override; + + virtual sal_Bool SAL_CALL hasPropertyByName(OUString const & Name) override; + + virtual void SAL_CALL disposing(css::lang::EventObject const & Source) override; + + virtual void SAL_CALL initialize( + css::uno::Sequence<css::uno::Any> const & aArguments) + override; + + // needs to be called with rBHelper.rMutex locked: + bool isDisposed() const { return rBHelper.bDisposed || rBHelper.bInDispose; } + + void removeEventListenerFromComponent( + css::uno::Reference< css::lang::XComponent > const & component); + + void readRdbDirectory(OUString const & uri, bool optional); + + void readRdbFile(OUString const & uri, bool optional); + + bool readLegacyRdbFile(OUString const & uri); + + OUString readLegacyRdbString( + OUString const & uri, RegistryKey & key, + OUString const & path); + + void readLegacyRdbStrings( + OUString const & uri, RegistryKey & key, + OUString const & path, std::vector< OUString > * strings); + + void insertRdbFiles( + std::vector< OUString > const & uris, + css::uno::Reference< css::uno::XComponentContext > const & + alientContext); + + void insertLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo); + + bool insertExtraData(Data const & extra); + + void removeRdbFiles(std::vector< OUString > const & uris); + + bool removeLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo, + bool removeListener); + + void removeImplementation(const OUString & name); + + std::shared_ptr< Data::Implementation > findServiceImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + OUString const & specifier); + + void preloadImplementations(); + + css::uno::Reference< css::uno::XComponentContext > context_; + Data data_; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/shlib.cxx b/cppuhelper/source/shlib.cxx new file mode 100644 index 000000000..89ce8b855 --- /dev/null +++ b/cppuhelper/source/shlib.cxx @@ -0,0 +1,423 @@ +/* -*- 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 <cassert> +#include <cstdlib> + +#include <com/sun/star/loader/CannotActivateFactoryException.hpp> +#include <com/sun/star/registry/CannotRegisterImplementationException.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/shlib.hxx> +#include <osl/module.hxx> +#include <sal/log.hxx> +#include <uno/environment.hxx> +#include <uno/mapping.hxx> + +#include "loadsharedlibcomponentfactory.hxx" + +#if defined DISABLE_DYNLOADING +#include <osl/detail/component-mapping.h> +#endif + +css::uno::Environment cppuhelper::detail::getEnvironment( + OUString const & name, OUString const & implementation) +{ + OUString n(name); + if (!implementation.isEmpty()) { + static char const * log = std::getenv("UNO_ENV_LOG"); + if (log != nullptr && *log != 0) { + OString imps(log); + for (sal_Int32 i = 0; i != -1;) { + OString imp(imps.getToken(0, ';', i)); + //TODO: this assumes UNO_ENV_LOG only contains ASCII characters: + if (implementation.equalsAsciiL(imp.getStr(), imp.getLength())) + { + n += ":log"; + break; + } + } + } + } + return css::uno::Environment(n); +} + +namespace { + +#if !defined DISABLE_DYNLOADING + +css::uno::Environment getEnvironmentFromModule( + osl::Module const & module, css::uno::Environment const & target, + OUString const & implementation, OUString const & prefix) +{ + char const * name = nullptr; + css::uno::Environment env; + OUString fullPrefix(prefix); + if (!fullPrefix.isEmpty()) { + fullPrefix += "_"; + } + component_getImplementationEnvironmentExtFunc fp1 + = reinterpret_cast<component_getImplementationEnvironmentExtFunc>( + module.getFunctionSymbol(fullPrefix + COMPONENT_GETENVEXT)); + if (fp1 != nullptr) { + (*fp1)( + &name, reinterpret_cast<uno_Environment **>(&env), + (OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US) + .getStr()), + target.get()); + } else { + component_getImplementationEnvironmentFunc fp2 + = reinterpret_cast<component_getImplementationEnvironmentFunc>( + module.getFunctionSymbol(fullPrefix + COMPONENT_GETENV)); + if (fp2 != nullptr) { + (*fp2)(&name, reinterpret_cast<uno_Environment **>(&env)); + } else { + name = CPPU_CURRENT_LANGUAGE_BINDING_NAME; //TODO: fail + } + } + if (!env.is() && name != nullptr) { + env = cppuhelper::detail::getEnvironment( + OUString::createFromAscii(name), implementation); + } + return env; +} + +#endif + +extern "C" void getFactory(va_list * args) { + component_getFactoryFunc fn = va_arg(*args, component_getFactoryFunc); + OString const * implementation = va_arg(*args, OString const *); + void * smgr = va_arg(*args, void *); + void ** factory = va_arg(*args, void **); + *factory = (*fn)(implementation->getStr(), smgr, nullptr); +} + +css::uno::Reference<css::uno::XInterface> invokeComponentFactory( + css::uno::Environment const & source, css::uno::Environment const & target, + component_getFactoryFunc function, OUString const & uri, + OUString const & implementation, + css::uno::Reference<css::lang::XMultiServiceFactory> const & serviceManager) +{ + if (!(source.is() && target.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get environments", + css::uno::Reference<css::uno::XInterface>()); + } + OString impl( + OUStringToOString(implementation, RTL_TEXTENCODING_ASCII_US)); + if (source.get() == target.get()) { + return css::uno::Reference<css::uno::XInterface>( + static_cast<css::uno::XInterface *>( + (*function)(impl.getStr(), serviceManager.get(), nullptr)), + SAL_NO_ACQUIRE); + } + css::uno::Mapping mapTo(source, target); + css::uno::Mapping mapFrom(target, source); + if (!(mapTo.is() && mapFrom.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get mappings", + css::uno::Reference<css::uno::XInterface>()); + } + void * smgr = mapTo.mapInterface( + serviceManager.get(), + cppu::UnoType<css::lang::XMultiServiceFactory>::get()); + void * factory = nullptr; + target.invoke(getFactory, function, &impl, smgr, &factory); + if (smgr != nullptr) { + (*target.get()->pExtEnv->releaseInterface)( + target.get()->pExtEnv, smgr); + } + if (factory == nullptr) { + throw css::loader::CannotActivateFactoryException( + ("calling factory function for \"" + implementation + "\" in <" + + uri + "> returned null"), + css::uno::Reference<css::uno::XInterface>()); + } + css::uno::Reference<css::uno::XInterface> res; + mapFrom.mapInterface( + reinterpret_cast<void **>(&res), factory, + cppu::UnoType<css::uno::XInterface>::get()); + (*target.get()->pExtEnv->releaseInterface)( + target.get()->pExtEnv, factory); + return res; +} + +#if !defined DISABLE_DYNLOADING + +extern "C" void getInstance(va_list * args) { + cppuhelper::ImplementationConstructorFn * fn = va_arg(*args, cppuhelper::ImplementationConstructorFn *); + void * ctxt = va_arg(*args, void *); + assert(ctxt); + void * argseq = va_arg(*args, void *); + assert(argseq); + void ** instance = va_arg(*args, void **); + assert(instance); + assert(*instance == nullptr); + *instance = (*fn)(static_cast<css::uno::XComponentContext*>(ctxt), + *static_cast<css::uno::Sequence<css::uno::Any> const*>(argseq)); +} + +cppuhelper::WrapperConstructorFn mapConstructorFn( + css::uno::Environment const & source, css::uno::Environment const & target, + cppuhelper::ImplementationConstructorFn *const constructorFunction) +{ + if (!(source.is() && target.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get environments", + css::uno::Reference<css::uno::XInterface>()); + } + if (source.get() == target.get()) { + return cppuhelper::WrapperConstructorFn(constructorFunction); + } + // note: it should be valid to capture these mappings because they are + // ref-counted, and the returned closure will always be invoked in the + // "source" environment + css::uno::Mapping mapTo(source, target); + css::uno::Mapping mapFrom(target, source); + if (!(mapTo.is() && mapFrom.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get mappings", + css::uno::Reference<css::uno::XInterface>()); + } + return [mapFrom, mapTo, target, constructorFunction] + (css::uno::XComponentContext *const context, css::uno::Sequence<css::uno::Any> const& args) + { + void *const ctxt = mapTo.mapInterface( + context, + cppu::UnoType<css::uno::XComponentContext>::get()); + if (args.hasElements()) { + std::abort(); // TODO map args + } + void * instance = nullptr; + target.invoke(getInstance, constructorFunction, ctxt, &args, &instance); + if (ctxt != nullptr) { + (*target.get()->pExtEnv->releaseInterface)( + target.get()->pExtEnv, ctxt); + } + css::uno::XInterface * res = nullptr; + if (instance == nullptr) { + return res; + } + mapFrom.mapInterface( + reinterpret_cast<void **>(&res), instance, + cppu::UnoType<css::uno::XInterface>::get()); + (*target.get()->pExtEnv->releaseInterface)( + target.get()->pExtEnv, instance); + return res; + }; +} + +#endif + +} + +void cppuhelper::detail::loadSharedLibComponentFactory( + OUString const & uri, OUString const & environment, + OUString const & prefix, OUString const & implementation, + OUString const & constructor, + css::uno::Reference<css::lang::XMultiServiceFactory> const & serviceManager, + WrapperConstructorFn * constructorFunction, + css::uno::Reference<css::uno::XInterface> * factory) +{ + assert(constructor.isEmpty() || !environment.isEmpty()); + assert( + (constructorFunction == nullptr && constructor.isEmpty()) + || !*constructorFunction); + assert(factory != nullptr && !factory->is()); +#if defined DISABLE_DYNLOADING + assert(!environment.isEmpty()); + if (constructor.isEmpty()) { + css::uno::Environment curEnv(css::uno::Environment::getCurrent()); + css::uno::Environment env(getEnvironment(environment, implementation)); + if (!(curEnv.is() && env.is())) { + throw css::loader::CannotActivateFactoryException( + "cannot get environments", + css::uno::Reference<css::uno::XInterface>()); + } + if (curEnv.get() != env.get()) { + std::abort();//TODO + } + SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri); + lib_to_factory_mapping const * map = lo_get_factory_map(); + component_getFactoryFunc fp = 0; + for (int i = 0; map[i].name != 0; ++i) { + if (uri.equalsAscii(map[i].name)) { + fp = map[i].component_getFactory_function; + break; + } + } + if (fp == 0) { + SAL_WARN("cppuhelper", "unknown factory name \"" << uri << "\""); + throw css::loader::CannotActivateFactoryException( + "unknown factory name \"" + uri + "\"", + css::uno::Reference<css::uno::XInterface>()); + } + *factory = invokeComponentFactory( + css::uno::Environment::getCurrent(), + getEnvironment(environment, implementation), fp, uri, + implementation, serviceManager); + } else { + SAL_INFO("cppuhelper.shlib", "constructor=" << constructor); + lib_to_constructor_mapping const * map = lo_get_constructor_map(); + for (int i = 0; map[i].name != 0; ++i) { + if (constructor.equalsAscii(map[i].name)) { + *constructorFunction + = reinterpret_cast<ImplementationConstructorFn *>( + map[i].constructor_function); + return; + } + } + SAL_WARN("cppuhelper", "unknown constructor name \"" << constructor << "\""); + throw css::loader::CannotActivateFactoryException( + "unknown constructor name \"" + constructor + "\"", + css::uno::Reference<css::uno::XInterface>()); + } +#else + osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL); + if (!mod.is()) { + throw css::loader::CannotActivateFactoryException( + "loading component library <" + uri + "> failed", + css::uno::Reference<css::uno::XInterface>()); + } + if (constructor.isEmpty()) { + OUString sym; + SAL_INFO("cppuhelper.shlib", "prefix=" << prefix << " implementation=" << implementation << " uri=" << uri); + if (!prefix.isEmpty()) { + sym = prefix + "_" COMPONENT_GETFACTORY; + } else { + sym = COMPONENT_GETFACTORY; + } + oslGenericFunction fp = mod.getFunctionSymbol(sym); + if (fp == nullptr) { + throw css::loader::CannotActivateFactoryException( + ("no factory symbol \"" + sym + "\" in component library <" + + uri + ">"), + css::uno::Reference<css::uno::XInterface>()); + } + css::uno::Environment curEnv(css::uno::Environment::getCurrent()); + *factory = invokeComponentFactory( + curEnv, + (environment.isEmpty() + ? getEnvironmentFromModule(mod, curEnv, implementation, prefix) + : getEnvironment(environment, implementation)), + reinterpret_cast<component_getFactoryFunc>(fp), uri, implementation, + serviceManager); + } else { + SAL_INFO("cppuhelper.shlib", "constructor=" << constructor); + oslGenericFunction fp = mod.getFunctionSymbol(constructor); + if (fp == nullptr) { + throw css::loader::CannotActivateFactoryException( + ("no constructor symbol \"" + constructor + + "\" in component library <" + uri + ">"), + css::uno::Reference<css::uno::XInterface>()); + } + css::uno::Environment curEnv(css::uno::Environment::getCurrent()); + *constructorFunction = mapConstructorFn( + curEnv, + (environment.isEmpty() + ? getEnvironmentFromModule(mod, curEnv, implementation, prefix) + : getEnvironment(environment, implementation)), + reinterpret_cast<ImplementationConstructorFn *>(fp)); + } + mod.release(); +#endif +} + +css::uno::Reference<css::uno::XInterface> cppu::loadSharedLibComponentFactory( + OUString const & uri, OUString const & rPath, + OUString const & rImplName, + css::uno::Reference<css::lang::XMultiServiceFactory> const & xMgr, + css::uno::Reference<css::registry::XRegistryKey> const & xKey) +{ + assert(rPath.isEmpty()); (void) rPath; + assert(!xKey.is()); (void) xKey; + css::uno::Reference<css::uno::XInterface> fac; + cppuhelper::detail::loadSharedLibComponentFactory( + uri, "", "", rImplName, "", xMgr, nullptr, &fac); + return fac; +} + +#if !defined DISABLE_DYNLOADING + +namespace { + +extern "C" void writeInfo(va_list * args) { + component_writeInfoFunc fn = va_arg(*args, component_writeInfoFunc); + void * smgr = va_arg(*args, void *); + void * key = va_arg(*args, void *); + sal_Bool * ok = va_arg(*args, sal_Bool *); + *ok = (*fn)(smgr, key); +} + +} + +void cppu::writeSharedLibComponentInfo( + OUString const & uri, OUString const & rPath, + css::uno::Reference<css::lang::XMultiServiceFactory> const & xMgr, + css::uno::Reference<css::registry::XRegistryKey> const & xKey) +{ + assert(rPath.isEmpty()); (void) rPath; + osl::Module mod(uri, SAL_LOADMODULE_LAZY | SAL_LOADMODULE_GLOBAL); + if (!mod.is()) { + throw css::registry::CannotRegisterImplementationException( + "loading component library <" + uri + "> failed", + css::uno::Reference<css::uno::XInterface>()); + } + oslGenericFunction fp = mod.getFunctionSymbol(COMPONENT_WRITEINFO); + if (fp == nullptr) { + throw css::registry::CannotRegisterImplementationException( + ("no symbol \"" COMPONENT_WRITEINFO "\" in component library <" + + uri + ">"), + css::uno::Reference<css::uno::XInterface>()); + } + css::uno::Environment curEnv(css::uno::Environment::getCurrent()); + css::uno::Environment env(getEnvironmentFromModule(mod, curEnv, "", "")); + if (!(curEnv.is() && env.is())) { + throw css::registry::CannotRegisterImplementationException( + "cannot get environments", + css::uno::Reference<css::uno::XInterface>()); + } + css::uno::Mapping map(curEnv, env); + if (!map.is()) { + throw css::registry::CannotRegisterImplementationException( + "cannot get mapping", css::uno::Reference<css::uno::XInterface>()); + } + void * smgr = map.mapInterface( + xMgr.get(), cppu::UnoType<css::lang::XMultiServiceFactory>::get()); + void * key = map.mapInterface( + xKey.get(), cppu::UnoType<css::registry::XRegistryKey>::get()); + sal_Bool ok; + env.invoke(writeInfo, fp, smgr, key, &ok); + (*env.get()->pExtEnv->releaseInterface)(env.get()->pExtEnv, key); + if (smgr != nullptr) { + (*env.get()->pExtEnv->releaseInterface)(env.get()->pExtEnv, smgr); + } + if (!ok) { + throw css::registry::CannotRegisterImplementationException( + ("calling \"" COMPONENT_WRITEINFO "\" in component library <" + uri + + "> returned false"), + css::uno::Reference<css::uno::XInterface>()); + } +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/supportsservice.cxx b/cppuhelper/source/supportsservice.cxx new file mode 100644 index 000000000..eea82602a --- /dev/null +++ b/cppuhelper/source/supportsservice.cxx @@ -0,0 +1,30 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <algorithm> +#include <cassert> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <rtl/ustring.hxx> +#include <sal/types.h> + +bool cppu::supportsService( + css::lang::XServiceInfo * implementation, OUString const & name) +{ + assert(implementation != nullptr); + const css::uno::Sequence< OUString > s( + implementation->getSupportedServiceNames()); + return std::find(s.begin(), s.end(), name) != s.end(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/tdmgr.cxx b/cppuhelper/source/tdmgr.cxx new file mode 100644 index 000000000..1e5826e24 --- /dev/null +++ b/cppuhelper/source/tdmgr.cxx @@ -0,0 +1,660 @@ +/* -*- 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 <sal/log.hxx> + +#include <vector> + +#include <osl/diagnose.h> +#include <rtl/ustring.hxx> + +#include <uno/lbnames.h> +#include <uno/mapping.hxx> + +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/implbase.hxx> +#include <typelib/typedescription.h> + +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/reflection/XTypeDescription.hpp> +#include <com/sun/star/reflection/XEnumTypeDescription.hpp> +#include <com/sun/star/reflection/XIndirectTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp> +#include <com/sun/star/reflection/XMethodParameter.hpp> +#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp> +#include <com/sun/star/reflection/XCompoundTypeDescription.hpp> +#include <com/sun/star/reflection/XStructTypeDescription.hpp> + +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::reflection; + +namespace cppu +{ + +static typelib_TypeDescription * createCTD( + Reference< container::XHierarchicalNameAccess > const & access, + const Reference< XTypeDescription > & xType ); + + +static typelib_TypeDescription * createCTD( + const Reference< XCompoundTypeDescription > & xType ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xType.is()) + { + typelib_TypeDescription * pBaseType = createCTD( + Reference< XCompoundTypeDescription >::query( xType->getBaseType() ) ); + if (pBaseType) + typelib_typedescription_register( &pBaseType ); + + // construct member init array + const Sequence<Reference< XTypeDescription > > & rMemberTypes = xType->getMemberTypes(); + const Sequence< OUString > & rMemberNames = xType->getMemberNames(); + + const Reference< XTypeDescription > * pMemberTypes = rMemberTypes.getConstArray(); + const OUString * pMemberNames = rMemberNames.getConstArray(); + + sal_Int32 nMembers = rMemberTypes.getLength(); + OSL_ENSURE( nMembers == rMemberNames.getLength(), "### lens differ!" ); + + OUString aTypeName( xType->getName() ); + + typelib_CompoundMember_Init * pMemberInits = static_cast<typelib_CompoundMember_Init *>(alloca( + sizeof(typelib_CompoundMember_Init) * nMembers )); + + sal_Int32 nPos; + for ( nPos = nMembers; nPos--; ) + { + typelib_CompoundMember_Init & rInit = pMemberInits[nPos]; + rInit.eTypeClass = static_cast<typelib_TypeClass>(pMemberTypes[nPos]->getTypeClass()); + + OUString aMemberTypeName( pMemberTypes[nPos]->getName() ); + rInit.pTypeName = aMemberTypeName.pData; + rtl_uString_acquire( rInit.pTypeName ); + + // string is held by rMemberNames + rInit.pMemberName = pMemberNames[nPos].pData; + } + + typelib_typedescription_new( + &pRet, + static_cast<typelib_TypeClass>(xType->getTypeClass()), + aTypeName.pData, + (pBaseType ? pBaseType->pWeakRef : nullptr), + nMembers, pMemberInits ); + + // cleanup + for ( nPos = nMembers; nPos--; ) + { + rtl_uString_release( pMemberInits[nPos].pTypeName ); + } + if (pBaseType) + typelib_typedescription_release( pBaseType ); + } + return pRet; +} + +static typelib_TypeDescription * createCTD( + Reference< container::XHierarchicalNameAccess > const & access, + const Reference< XStructTypeDescription > & xType ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xType.is() && !xType->getTypeParameters().hasElements()) + { + typelib_TypeDescription * pBaseType = createCTD( + access, xType->getBaseType() ); + if (pBaseType) + typelib_typedescription_register( &pBaseType ); + + // construct member init array + const Sequence<Reference< XTypeDescription > > & rMemberTypes = xType->getMemberTypes(); + const Sequence< OUString > & rMemberNames = xType->getMemberNames(); + + const Reference< XTypeDescription > * pMemberTypes = rMemberTypes.getConstArray(); + const OUString * pMemberNames = rMemberNames.getConstArray(); + + sal_Int32 nMembers = rMemberTypes.getLength(); + OSL_ENSURE( nMembers == rMemberNames.getLength(), "### lens differ!" ); + + OUString aTypeName( xType->getName() ); + + typelib_StructMember_Init * pMemberInits = static_cast<typelib_StructMember_Init *>(alloca( + sizeof(typelib_StructMember_Init) * nMembers )); + + Sequence< Reference< XTypeDescription > > templateMemberTypes; + sal_Int32 i = aTypeName.indexOf('<'); + if (i >= 0) { + Reference< XStructTypeDescription > templateDesc( + access->getByHierarchicalName(aTypeName.copy(0, i)), + UNO_QUERY_THROW); + OSL_ASSERT( + templateDesc->getTypeParameters().getLength() + == xType->getTypeArguments().getLength()); + templateMemberTypes = templateDesc->getMemberTypes(); + OSL_ASSERT(templateMemberTypes.getLength() == nMembers); + } + + sal_Int32 nPos; + for ( nPos = nMembers; nPos--; ) + { + typelib_StructMember_Init & rInit = pMemberInits[nPos]; + rInit.aBase.eTypeClass + = static_cast<typelib_TypeClass>(pMemberTypes[nPos]->getTypeClass()); + + OUString aMemberTypeName( pMemberTypes[nPos]->getName() ); + rInit.aBase.pTypeName = aMemberTypeName.pData; + rtl_uString_acquire( rInit.aBase.pTypeName ); + + // string is held by rMemberNames + rInit.aBase.pMemberName = pMemberNames[nPos].pData; + + rInit.bParameterizedType = templateMemberTypes.hasElements() + && (templateMemberTypes[nPos]->getTypeClass() + == TypeClass_UNKNOWN); + } + + typelib_typedescription_newStruct( + &pRet, + aTypeName.pData, + (pBaseType ? pBaseType->pWeakRef : nullptr), + nMembers, pMemberInits ); + + // cleanup + for ( nPos = nMembers; nPos--; ) + { + rtl_uString_release( pMemberInits[nPos].aBase.pTypeName ); + } + if (pBaseType) + typelib_typedescription_release( pBaseType ); + } + return pRet; +} + +static typelib_TypeDescription * createCTD( + const Reference< XInterfaceAttributeTypeDescription2 > & xAttribute ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xAttribute.is()) + { + OUString aMemberName( xAttribute->getName() ); + Reference< XTypeDescription > xType( xAttribute->getType() ); + OUString aMemberTypeName( xType->getName() ); + std::vector< rtl_uString * > getExc; + const Sequence< Reference< XCompoundTypeDescription > > getExcs( + xAttribute->getGetExceptions() ); + for (const auto & ctd : getExcs) + { + OSL_ASSERT( ctd.is() ); + getExc.push_back( ctd->getName().pData ); + } + std::vector< rtl_uString * > setExc; + const Sequence< Reference< XCompoundTypeDescription > > setExcs( + xAttribute->getSetExceptions() ); + for (const auto & ctd : setExcs) + { + OSL_ASSERT( ctd.is() ); + setExc.push_back( ctd->getName().pData ); + } + typelib_typedescription_newExtendedInterfaceAttribute( + reinterpret_cast<typelib_InterfaceAttributeTypeDescription **>(&pRet), + xAttribute->getPosition(), + aMemberName.pData, // name + static_cast<typelib_TypeClass>(xType->getTypeClass()), + aMemberTypeName.pData, // type name + xAttribute->isReadOnly(), + getExc.size(), getExc.data(), + setExc.size(), setExc.data() ); + } + return pRet; +} + +static typelib_TypeDescription * createCTD( + const Reference< XInterfaceMethodTypeDescription > & xMethod ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xMethod.is()) + { + Reference< XTypeDescription > xReturnType( xMethod->getReturnType() ); + + // init all params + const Sequence<Reference< XMethodParameter > > & rParams = xMethod->getParameters(); + const Reference< XMethodParameter > * pParams = rParams.getConstArray(); + sal_Int32 nParams = rParams.getLength(); + + typelib_Parameter_Init * pParamInit = static_cast<typelib_Parameter_Init *>(alloca( + sizeof(typelib_Parameter_Init) * nParams )); + + sal_Int32 nPos; + for ( nPos = nParams; nPos--; ) + { + const Reference< XMethodParameter > & xParam = pParams[nPos]; + const Reference< XTypeDescription > & xType = xParam->getType(); + typelib_Parameter_Init & rInit = pParamInit[xParam->getPosition()]; + + rInit.eTypeClass = static_cast<typelib_TypeClass>(xType->getTypeClass()); + OUString aParamTypeName( xType->getName() ); + rInit.pTypeName = aParamTypeName.pData; + rtl_uString_acquire( rInit.pTypeName ); + OUString aParamName( xParam->getName() ); + rInit.pParamName = aParamName.pData; + rtl_uString_acquire( rInit.pParamName ); + rInit.bIn = xParam->isIn(); + rInit.bOut = xParam->isOut(); + } + + // init all exception strings + const Sequence<Reference< XTypeDescription > > & rExceptions = xMethod->getExceptions(); + const Reference< XTypeDescription > * pExceptions = rExceptions.getConstArray(); + sal_Int32 nExceptions = rExceptions.getLength(); + rtl_uString ** ppExceptionNames = static_cast<rtl_uString **>(alloca( + sizeof(rtl_uString *) * nExceptions )); + + for ( nPos = nExceptions; nPos--; ) + { + OUString aExceptionTypeName( pExceptions[nPos]->getName() ); + ppExceptionNames[nPos] = aExceptionTypeName.pData; + rtl_uString_acquire( ppExceptionNames[nPos] ); + } + + OUString aTypeName( xMethod->getName() ); + OUString aReturnTypeName( xReturnType->getName() ); + + typelib_typedescription_newInterfaceMethod( + reinterpret_cast<typelib_InterfaceMethodTypeDescription **>(&pRet), + xMethod->getPosition(), + xMethod->isOneway(), + aTypeName.pData, + static_cast<typelib_TypeClass>(xReturnType->getTypeClass()), + aReturnTypeName.pData, + nParams, pParamInit, + nExceptions, ppExceptionNames ); + + for ( nPos = nParams; nPos--; ) + { + rtl_uString_release( pParamInit[nPos].pTypeName ); + rtl_uString_release( pParamInit[nPos].pParamName ); + } + for ( nPos = nExceptions; nPos--; ) + { + rtl_uString_release( ppExceptionNames[nPos] ); + } + } + return pRet; +} + +static typelib_TypeDescription * createCTD( + Reference< container::XHierarchicalNameAccess > const & access, + const Reference< XInterfaceTypeDescription2 > & xType ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xType.is()) + { + Sequence< Reference< XTypeDescription > > aBases(xType->getBaseTypes()); + sal_Int32 nBases = aBases.getLength(); + // Exploit the fact that a typelib_TypeDescription for an interface type + // is also the typelib_TypeDescriptionReference for that type: + std::unique_ptr< typelib_TypeDescription * []> aBaseTypes( + new typelib_TypeDescription *[nBases]); + for (sal_Int32 i = 0; i < nBases; ++i) { + typelib_TypeDescription * p = createCTD(access, aBases[i]); + OSL_ASSERT( + !TYPELIB_TYPEDESCRIPTIONREFERENCE_ISREALLYWEAK(p->eTypeClass)); + typelib_typedescription_register(&p); + aBaseTypes[i] = p; + } + typelib_TypeDescriptionReference ** pBaseTypeRefs + = reinterpret_cast< typelib_TypeDescriptionReference ** >( + aBaseTypes.get()); + + // construct all member refs + const Sequence<Reference< XInterfaceMemberTypeDescription > > & rMembers = xType->getMembers(); + sal_Int32 nMembers = rMembers.getLength(); + + typelib_TypeDescriptionReference ** ppMemberRefs = static_cast<typelib_TypeDescriptionReference **>(alloca( + sizeof(typelib_TypeDescriptionReference *) * nMembers )); + + const Reference< XInterfaceMemberTypeDescription > * pMembers = rMembers.getConstArray(); + + OUString aTypeName( xType->getName() ); + + sal_Int32 nPos; + for ( nPos = nMembers; nPos--; ) + { + OUString aMemberTypeName( pMembers[nPos]->getName() ); + ppMemberRefs[nPos] = nullptr; + typelib_typedescriptionreference_new( + ppMemberRefs + nPos, + static_cast<typelib_TypeClass>(pMembers[nPos]->getTypeClass()), + aMemberTypeName.pData ); + } + + typelib_typedescription_newMIInterface( + reinterpret_cast<typelib_InterfaceTypeDescription **>(&pRet), + aTypeName.pData, + 0, 0, 0, 0, 0, + nBases, pBaseTypeRefs, + nMembers, ppMemberRefs ); + + // cleanup refs and base type + for (int i = 0; i < nBases; ++i) { + typelib_typedescription_release(aBaseTypes[i]); + } + + for ( nPos = nMembers; nPos--; ) + { + typelib_typedescriptionreference_release( ppMemberRefs[nPos] ); + } + } + return pRet; +} + +static typelib_TypeDescription * createCTD( const Reference< XEnumTypeDescription > & xType ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xType.is()) + { + OUString aTypeName( xType->getName() ); + Sequence< OUString > aNames( xType->getEnumNames() ); + OSL_ASSERT( sizeof(OUString) == sizeof(rtl_uString *) ); // !!! + Sequence< sal_Int32 > aValues( xType->getEnumValues() ); + + typelib_typedescription_newEnum( + &pRet, aTypeName.pData, xType->getDefaultEnumValue(), + aNames.getLength(), + const_cast<rtl_uString **>(reinterpret_cast<rtl_uString * const *>(aNames.getConstArray())), + const_cast< sal_Int32 * >( aValues.getConstArray() ) ); + } + return pRet; +} + +static typelib_TypeDescription * createCTD( + Reference< container::XHierarchicalNameAccess > const & access, + const Reference< XIndirectTypeDescription > & xType ) +{ + typelib_TypeDescription * pRet = nullptr; + if (xType.is()) + { + typelib_TypeDescription * pRefType = createCTD( + access, xType->getReferencedType() ); + typelib_typedescription_register( &pRefType ); + + OUString aTypeName( xType->getName() ); + + typelib_typedescription_new( + &pRet, + static_cast<typelib_TypeClass>(xType->getTypeClass()), + aTypeName.pData, + pRefType->pWeakRef, + 0, nullptr ); + + // cleanup + typelib_typedescription_release( pRefType ); + } + return pRet; +} + + +static typelib_TypeDescription * createCTD( + Reference< container::XHierarchicalNameAccess > const & access, + const Reference< XTypeDescription > & xType ) +{ + typelib_TypeDescription * pRet = nullptr; + + if (xType.is()) + { + switch (xType->getTypeClass()) + { + // built in types + case TypeClass_VOID: + { + OUString aTypeName("void"); + typelib_typedescription_new( &pRet, typelib_TypeClass_VOID, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_CHAR: + { + OUString aTypeName("char"); + typelib_typedescription_new( &pRet, typelib_TypeClass_CHAR, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_BOOLEAN: + { + OUString aTypeName("boolean"); + typelib_typedescription_new( &pRet, typelib_TypeClass_BOOLEAN, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_BYTE: + { + OUString aTypeName("byte"); + typelib_typedescription_new( &pRet, typelib_TypeClass_BYTE, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_SHORT: + { + OUString aTypeName("short"); + typelib_typedescription_new( &pRet, typelib_TypeClass_SHORT, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_UNSIGNED_SHORT: + { + OUString aTypeName("unsigned short"); + typelib_typedescription_new( &pRet, typelib_TypeClass_UNSIGNED_SHORT, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_LONG: + { + OUString aTypeName("long"); + typelib_typedescription_new( &pRet, typelib_TypeClass_LONG, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_UNSIGNED_LONG: + { + OUString aTypeName("unsigned long"); + typelib_typedescription_new( &pRet, typelib_TypeClass_UNSIGNED_LONG, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_HYPER: + { + OUString aTypeName("hyper"); + typelib_typedescription_new( &pRet, typelib_TypeClass_HYPER, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_UNSIGNED_HYPER: + { + OUString aTypeName("unsigned hyper"); + typelib_typedescription_new( &pRet, typelib_TypeClass_UNSIGNED_HYPER, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_FLOAT: + { + OUString aTypeName("float"); + typelib_typedescription_new( &pRet, typelib_TypeClass_FLOAT, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_DOUBLE: + { + OUString aTypeName("double"); + typelib_typedescription_new( &pRet, typelib_TypeClass_DOUBLE, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_STRING: + { + OUString aTypeName("string"); + typelib_typedescription_new( &pRet, typelib_TypeClass_STRING, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_TYPE: + { + OUString aTypeName("type"); + typelib_typedescription_new( &pRet, typelib_TypeClass_TYPE, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + case TypeClass_ANY: + { + OUString aTypeName("any"); + typelib_typedescription_new( &pRet, typelib_TypeClass_ANY, aTypeName.pData, nullptr, 0, nullptr ); + break; + } + + case TypeClass_EXCEPTION: + pRet = createCTD( Reference< XCompoundTypeDescription >::query( xType ) ); + break; + case TypeClass_STRUCT: + pRet = createCTD( + access, Reference< XStructTypeDescription >::query( xType ) ); + break; + case TypeClass_ENUM: + pRet = createCTD( Reference< XEnumTypeDescription >::query( xType ) ); + break; + case TypeClass_TYPEDEF: + { + Reference< XIndirectTypeDescription > xTypedef( xType, UNO_QUERY ); + if (xTypedef.is()) + pRet = createCTD( access, xTypedef->getReferencedType() ); + break; + } + case TypeClass_SEQUENCE: + pRet = createCTD( + access, Reference< XIndirectTypeDescription >::query( xType ) ); + break; + case TypeClass_INTERFACE: + pRet = createCTD( + access, + Reference< XInterfaceTypeDescription2 >::query( xType ) ); + break; + case TypeClass_INTERFACE_METHOD: + pRet = createCTD( Reference< XInterfaceMethodTypeDescription >::query( xType ) ); + break; + case TypeClass_INTERFACE_ATTRIBUTE: + pRet = createCTD( Reference< XInterfaceAttributeTypeDescription2 >::query( xType ) ); + break; + default: + break; + } + } + + return pRet; +} + + +extern "C" +{ +static void typelib_callback( + void * pContext, typelib_TypeDescription ** ppRet, rtl_uString * pTypeName ) +{ + OSL_ENSURE( pContext && ppRet && pTypeName, "### null ptr!" ); + if (!ppRet) + return; + + if (*ppRet) + { + ::typelib_typedescription_release( *ppRet ); + *ppRet = nullptr; + } + if (!(pContext && pTypeName)) + return; + + Reference< container::XHierarchicalNameAccess > access( + static_cast< container::XHierarchicalNameAccess * >( + pContext)); + try + { + OUString const & rTypeName = OUString::unacquired( &pTypeName ); + Reference< XTypeDescription > xTD; + if (access->getByHierarchicalName(rTypeName ) >>= xTD) + { + *ppRet = createCTD( access, xTD ); + } + } + catch (const container::NoSuchElementException & exc) + { + SAL_INFO("cppuhelper", "typelibrary type not available: " << exc ); + } + catch (const Exception & exc) + { + SAL_INFO("cppuhelper", exc ); + } +} +} + +namespace { + +class EventListenerImpl + : public WeakImplHelper< lang::XEventListener > +{ + Reference< container::XHierarchicalNameAccess > m_xTDMgr; + +public: + explicit EventListenerImpl( + Reference< container::XHierarchicalNameAccess > const & xTDMgr ) + : m_xTDMgr( xTDMgr ) + {} + + // XEventListener + virtual void SAL_CALL disposing( lang::EventObject const & rEvt ) override; +}; + +} + +void EventListenerImpl::disposing( lang::EventObject const & rEvt ) +{ + if (rEvt.Source != m_xTDMgr) { + OSL_ASSERT(false); + } + // deregister of c typelib callback + ::typelib_typedescription_revokeCallback( m_xTDMgr.get(), typelib_callback ); +} + + +sal_Bool SAL_CALL installTypeDescriptionManager( + Reference< container::XHierarchicalNameAccess > const & xTDMgr_c ) +{ + uno::Environment curr_env(Environment::getCurrent()); + uno::Environment target_env(CPPU_CURRENT_LANGUAGE_BINDING_NAME); + + uno::Mapping curr2target(curr_env, target_env); + + + Reference<container::XHierarchicalNameAccess> xTDMgr( + static_cast<container::XHierarchicalNameAccess *>( + curr2target.mapInterface(xTDMgr_c.get(), cppu::UnoType<decltype(xTDMgr_c)>::get())), + SAL_NO_ACQUIRE); + + Reference< lang::XComponent > xComp( xTDMgr, UNO_QUERY ); + if (xComp.is()) + { + xComp->addEventListener( new EventListenerImpl( xTDMgr ) ); + // register c typelib callback + ::typelib_typedescription_registerCallback( xTDMgr.get(), typelib_callback ); + return true; + } + return false; +} + +} // end namespace cppu + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/typemanager.cxx b/cppuhelper/source/typemanager.cxx new file mode 100644 index 000000000..3a3866b60 --- /dev/null +++ b/cppuhelper/source/typemanager.cxx @@ -0,0 +1,2279 @@ +/* -*- 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/. + */ + +#include <sal/config.h> + +#include <cassert> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <set> +#include <stack> +#include <vector> + +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#include <com/sun/star/reflection/NoSuchTypeNameException.hpp> +#include <com/sun/star/reflection/TypeDescriptionSearchDepth.hpp> +#include <com/sun/star/reflection/XConstantTypeDescription.hpp> +#include <com/sun/star/reflection/XConstantsTypeDescription.hpp> +#include <com/sun/star/reflection/XEnumTypeDescription.hpp> +#include <com/sun/star/reflection/XIndirectTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp> +#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp> +#include <com/sun/star/reflection/XInterfaceTypeDescription2.hpp> +#include <com/sun/star/reflection/XModuleTypeDescription.hpp> +#include <com/sun/star/reflection/XPublished.hpp> +#include <com/sun/star/reflection/XServiceTypeDescription2.hpp> +#include <com/sun/star/reflection/XSingletonTypeDescription2.hpp> +#include <com/sun/star/reflection/XStructTypeDescription.hpp> +#include <com/sun/star/reflection/XTypeDescription.hpp> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/DeploymentException.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/TypeClass.hpp> +#include <cppu/unotype.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <osl/file.hxx> +#include <osl/mutex.hxx> +#include <rtl/ref.hxx> +#include <rtl/ustring.hxx> +#include <sal/log.hxx> +#include <sal/macros.h> +#include <sal/types.h> + +#include <unoidl/unoidl.hxx> + +#include "paths.hxx" +#include "typemanager.hxx" + +namespace { + +OUString makePrefix(OUString const & name) { + return name.isEmpty() ? name : name + "."; +} + +css::uno::Any resolveTypedefs(css::uno::Any const & type) { + for (css::uno::Any t(type);;) { + css::uno::Reference< css::reflection::XIndirectTypeDescription > ind( + type, css::uno::UNO_QUERY); + if (!ind.is() || ind->getTypeClass() != css::uno::TypeClass_TYPEDEF) { + return t; + } + t <<= ind->getReferencedType(); + } +} + +class SimpleTypeDescription: + public cppu::WeakImplHelper< css::reflection::XTypeDescription > +{ +public: + SimpleTypeDescription( + css::uno::TypeClass typeClass, OUString const & name): + typeClass_(typeClass), name_(name) + {} + +private: + virtual ~SimpleTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return typeClass_; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + css::uno::TypeClass typeClass_; + OUString name_; +}; + +class SequenceTypeDescription: + public cppu::WeakImplHelper< css::reflection::XIndirectTypeDescription > +{ +public: + SequenceTypeDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, OUString const & componentType): + manager_(manager), name_(name), componentType_(componentType) + { assert(manager.is()); } + +private: + virtual ~SequenceTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_SEQUENCE; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getReferencedType() override + { return manager_->resolve(componentType_); } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + OUString componentType_; +}; + +class PublishableDescription: + public cppu::WeakImplHelper< css::reflection::XPublished > +{ +protected: + explicit PublishableDescription(bool published): published_(published) {} + + virtual ~PublishableDescription() override {} + +private: + virtual sal_Bool SAL_CALL isPublished() override + { return published_; } + + bool published_; +}; + +class ModuleDescription: + public cppu::WeakImplHelper< css::reflection::XModuleTypeDescription > +{ +public: + ModuleDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::ModuleEntity > const & entity): + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~ModuleDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_MODULE; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getMembers() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::ModuleEntity > entity_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +ModuleDescription::getMembers() { + try { + std::vector< OUString > names(entity_->getMemberNames()); + assert(names.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(names.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(makePrefix(name_) + names[i]); + } + return s; + } catch (unoidl::FileFormatException & e) { + throw css::uno::DeploymentException( + e.getUri() + ": " + e.getDetail(), + static_cast< cppu::OWeakObject * >(this)); + } +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XEnumTypeDescription > +EnumTypeDescription_Base; + +class EnumTypeDescription: public EnumTypeDescription_Base { +public: + EnumTypeDescription( + OUString const & name, + rtl::Reference< unoidl::EnumTypeEntity > const & entity): + EnumTypeDescription_Base(entity->isPublished()), name_(name), + entity_(entity) + { assert(entity.is()); } + +private: + virtual ~EnumTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_ENUM; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual sal_Int32 SAL_CALL getDefaultEnumValue() override + { return entity_->getMembers()[0].value; } + + virtual css::uno::Sequence< OUString > SAL_CALL getEnumNames() override; + + virtual css::uno::Sequence< sal_Int32 > SAL_CALL getEnumValues() override; + + OUString name_; + rtl::Reference< unoidl::EnumTypeEntity > entity_; +}; + +css::uno::Sequence< OUString > EnumTypeDescription::getEnumNames() +{ + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< OUString > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getMembers()[i].name; + } + return s; +} + +css::uno::Sequence< sal_Int32 > EnumTypeDescription::getEnumValues() +{ + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< sal_Int32 > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getMembers()[i].value; + } + return s; +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XStructTypeDescription > +PlainStructTypeDescription_Base; + +class PlainStructTypeDescription: public PlainStructTypeDescription_Base { +public: + PlainStructTypeDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::PlainStructTypeEntity > const & entity): + PlainStructTypeDescription_Base(entity->isPublished()), + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~PlainStructTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_STRUCT; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getBaseType() override { + return entity_->getDirectBase().isEmpty() + ? css::uno::Reference< css::reflection::XTypeDescription >() + : manager_->resolve(entity_->getDirectBase()); + } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getMemberTypes() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getMemberNames() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getTypeParameters() override + { return css::uno::Sequence< OUString >(); } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getTypeArguments() override { + return css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > >(); + } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::PlainStructTypeEntity > entity_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +PlainStructTypeDescription::getMemberTypes() +{ + assert(entity_->getDirectMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getDirectMembers().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(entity_->getDirectMembers()[i].type); + } + return s; +} + +css::uno::Sequence< OUString > PlainStructTypeDescription::getMemberNames() +{ + assert(entity_->getDirectMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getDirectMembers().size()); + css::uno::Sequence< OUString > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getDirectMembers()[i].name; + } + return s; +} + +class ParameterizedMemberTypeDescription: + public cppu::WeakImplHelper< css::reflection::XTypeDescription > +{ +public: + explicit ParameterizedMemberTypeDescription( + OUString const & typeParameterName): + typeParameterName_(typeParameterName) + {} + +private: + virtual ~ParameterizedMemberTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_UNKNOWN; } + + virtual OUString SAL_CALL getName() override + { return typeParameterName_; } + + OUString typeParameterName_; +}; + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XStructTypeDescription > +PolymorphicStructTypeTemplateDescription_Base; + +class PolymorphicStructTypeTemplateDescription: + public PolymorphicStructTypeTemplateDescription_Base +{ +public: + PolymorphicStructTypeTemplateDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > const & + entity): + PolymorphicStructTypeTemplateDescription_Base(entity->isPublished()), + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~PolymorphicStructTypeTemplateDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_STRUCT; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getBaseType() override + { return css::uno::Reference< css::reflection::XTypeDescription >(); } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getMemberTypes() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getMemberNames() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getTypeParameters() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getTypeArguments() override { + return css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > >(); + } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > entity_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +PolymorphicStructTypeTemplateDescription::getMemberTypes() +{ + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getMembers()[i].parameterized + ? new ParameterizedMemberTypeDescription( + entity_->getMembers()[i].type) + : manager_->resolve(entity_->getMembers()[i].type); + } + return s; +} + +css::uno::Sequence< OUString > +PolymorphicStructTypeTemplateDescription::getMemberNames() +{ + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< OUString > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getMembers()[i].name; + } + return s; +} + +css::uno::Sequence< OUString > +PolymorphicStructTypeTemplateDescription::getTypeParameters() +{ + assert(entity_->getTypeParameters().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getTypeParameters().size()); + css::uno::Sequence< OUString > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getTypeParameters()[i]; + } + return s; +} + +class InstantiatedPolymorphicStructTypeDescription: + public cppu::WeakImplHelper< css::reflection::XStructTypeDescription > +{ +public: + InstantiatedPolymorphicStructTypeDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > const & + entity, + std::vector< OUString > const & arguments): + manager_(manager), name_(name), entity_(entity), arguments_(arguments) + { + assert(manager.is()); + assert(entity.is()); + assert(arguments.size() == entity->getTypeParameters().size()); + } + +private: + virtual ~InstantiatedPolymorphicStructTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_STRUCT; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getBaseType() override + { return css::uno::Reference< css::reflection::XTypeDescription >(); } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getMemberTypes() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getMemberNames() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getTypeParameters() override + { return css::uno::Sequence< OUString >(); } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getTypeArguments() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > entity_; + std::vector< OUString > arguments_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +InstantiatedPolymorphicStructTypeDescription::getMemberTypes() +{ + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + OUString type(entity_->getMembers()[i].type); + if (entity_->getMembers()[i].parameterized) { + auto j = std::find(entity_->getTypeParameters().begin(), entity_->getTypeParameters().end(), type); + if (j != entity_->getTypeParameters().end()) { + type = arguments_[j - entity_->getTypeParameters().begin()]; + goto found; + } + assert(false); // this cannot happen //TODO! + found:; + } + s[i] = manager_->resolve(type); + } + return s; +} + +css::uno::Sequence< OUString > +InstantiatedPolymorphicStructTypeDescription::getMemberNames() +{ + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< OUString > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getMembers()[i].name; + } + return s; +} +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +InstantiatedPolymorphicStructTypeDescription::getTypeArguments() +{ + assert(arguments_.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(arguments_.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(arguments_[i]); + } + return s; +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XCompoundTypeDescription > +ExceptionTypeDescription_Base; + +class ExceptionTypeDescription: public ExceptionTypeDescription_Base { +public: + ExceptionTypeDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::ExceptionTypeEntity > const & entity): + ExceptionTypeDescription_Base(entity->isPublished()), manager_(manager), + name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~ExceptionTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_EXCEPTION; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getBaseType() override { + return entity_->getDirectBase().isEmpty() + ? css::uno::Reference< css::reflection::XTypeDescription >() + : manager_->resolve(entity_->getDirectBase()); + } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getMemberTypes() override; + + virtual css::uno::Sequence< OUString > SAL_CALL getMemberNames() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::ExceptionTypeEntity > entity_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +ExceptionTypeDescription::getMemberTypes() { + assert(entity_->getDirectMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getDirectMembers().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(entity_->getDirectMembers()[i].type); + } + return s; +} + +css::uno::Sequence< OUString > ExceptionTypeDescription::getMemberNames() +{ + assert(entity_->getDirectMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getDirectMembers().size()); + css::uno::Sequence< OUString > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = entity_->getDirectMembers()[i].name; + } + return s; +} + +class AttributeDescription: + public cppu::WeakImplHelper< + css::reflection::XInterfaceAttributeTypeDescription2 > +{ +public: + AttributeDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + unoidl::InterfaceTypeEntity::Attribute const & attribute, + sal_Int32 position): + manager_(manager), name_(name), attribute_(attribute), + position_(position) + { assert(manager.is()); } + +private: + virtual ~AttributeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_INTERFACE_ATTRIBUTE; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual OUString SAL_CALL getMemberName() override + { return attribute_.name; } + + virtual sal_Int32 SAL_CALL getPosition() override + { return position_; } + + virtual sal_Bool SAL_CALL isReadOnly() override + { return attribute_.readOnly; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getType() override + { return manager_->resolve(attribute_.type); } + + virtual sal_Bool SAL_CALL isBound() override + { return attribute_.bound; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > + SAL_CALL getGetExceptions() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > + SAL_CALL getSetExceptions() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + unoidl::InterfaceTypeEntity::Attribute attribute_; + sal_Int32 position_; +}; + +css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > +AttributeDescription::getGetExceptions() { + assert(attribute_.getExceptions.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(attribute_.getExceptions.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + manager_->resolve(attribute_.getExceptions[i]), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > +AttributeDescription::getSetExceptions() { + assert(attribute_.setExceptions.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(attribute_.setExceptions.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + manager_->resolve(attribute_.setExceptions[i]), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +class MethodParameter: + public cppu::WeakImplHelper< css::reflection::XMethodParameter > +{ +public: + MethodParameter( + rtl::Reference< cppuhelper::TypeManager > const & manager, + unoidl::InterfaceTypeEntity::Method::Parameter const & parameter, + sal_Int32 position): + manager_(manager), parameter_(parameter), position_(position) + { assert(manager.is()); } + +private: + virtual ~MethodParameter() override {} + + virtual OUString SAL_CALL getName() override + { return parameter_.name; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getType() override + { return manager_->resolve(parameter_.type); } + + virtual sal_Bool SAL_CALL isIn() override { + return + (parameter_.direction + == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_IN) + || (parameter_.direction + == unoidl::InterfaceTypeEntity::Method::Parameter:: + DIRECTION_IN_OUT); + } + + virtual sal_Bool SAL_CALL isOut() override { + return + (parameter_.direction + == unoidl::InterfaceTypeEntity::Method::Parameter::DIRECTION_OUT) + || (parameter_.direction + == unoidl::InterfaceTypeEntity::Method::Parameter:: + DIRECTION_IN_OUT); + } + + virtual sal_Int32 SAL_CALL getPosition() override + { return position_; } + + rtl::Reference< cppuhelper::TypeManager > manager_; + unoidl::InterfaceTypeEntity::Method::Parameter parameter_; + sal_Int32 position_; +}; + +class MethodDescription: + public cppu::WeakImplHelper< + css::reflection::XInterfaceMethodTypeDescription > +{ +public: + MethodDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + unoidl::InterfaceTypeEntity::Method const & method, sal_Int32 position): + manager_(manager), name_(name), method_(method), position_(position) + { assert(manager.is()); } + +private: + virtual ~MethodDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_INTERFACE_METHOD; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual OUString SAL_CALL getMemberName() override + { return method_.name; } + + virtual sal_Int32 SAL_CALL getPosition() override + { return position_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getReturnType() override + { return manager_->resolve(method_.returnType); } + + virtual sal_Bool SAL_CALL isOneway() override + { return false; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XMethodParameter > > + SAL_CALL getParameters() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getExceptions() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + unoidl::InterfaceTypeEntity::Method method_; + sal_Int32 position_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XMethodParameter > > +MethodDescription::getParameters() { + assert(method_.parameters.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(method_.parameters.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XMethodParameter > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = new MethodParameter(manager_, method_.parameters[i], i); + } + return s; +} + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +MethodDescription::getExceptions() { + assert(method_.exceptions.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(method_.exceptions.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(method_.exceptions[i]); + } + return s; +} + +class BaseOffset { +public: + explicit BaseOffset( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > + const & description); + + BaseOffset(const BaseOffset&) = delete; + const BaseOffset& operator=(const BaseOffset&) = delete; + + sal_Int32 get() const { return offset_; } + +private: + void calculateBases( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > + const & description); + + void calculate( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > + const & description); + + std::set< OUString > set_; + sal_Int32 offset_; +}; + +BaseOffset::BaseOffset( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > const & + description): + offset_(0) +{ + calculateBases(description); +} + +void BaseOffset::calculateBases( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > const & + description) +{ + const css::uno::Sequence< + css::uno::Reference < css::reflection::XTypeDescription > > bases( + description->getBaseTypes()); + for (const auto & i : bases) { + calculate( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 >( + resolveTypedefs(css::uno::makeAny(i)), + css::uno::UNO_QUERY_THROW)); + } +} + +void BaseOffset::calculate( + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > const & + description) +{ + if (set_.insert(description->getName()).second) { + calculateBases(description); + offset_ += description->getMembers().getLength(); + } +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XInterfaceTypeDescription2 > +InterfaceTypeDescription_Base; + +class InterfaceTypeDescription: public InterfaceTypeDescription_Base { +public: + InterfaceTypeDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::InterfaceTypeEntity > const & entity): + InterfaceTypeDescription_Base(entity->isPublished()), manager_(manager), + name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~InterfaceTypeDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_INTERFACE; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getBaseType() override { + return entity_->getDirectMandatoryBases().empty() + ? css::uno::Reference< css::reflection::XTypeDescription >() + : manager_->resolve(entity_->getDirectMandatoryBases()[0].name); + } + + virtual css::uno::Uik SAL_CALL getUik() override + { return css::uno::Uik(); } + + virtual + css::uno::Sequence< + css::uno::Reference< + css::reflection::XInterfaceMemberTypeDescription > > + SAL_CALL getMembers() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getBaseTypes() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > + SAL_CALL getOptionalBaseTypes() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::InterfaceTypeEntity > entity_; +}; + +css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceMemberTypeDescription > > +InterfaceTypeDescription::getMembers() { + assert( + entity_->getDirectAttributes().size() <= SAL_MAX_INT32 + && (entity_->getDirectMethods().size() + <= SAL_MAX_INT32 - entity_->getDirectAttributes().size())); + sal_Int32 n1 = static_cast< sal_Int32 >( + entity_->getDirectAttributes().size()); + sal_Int32 n2 = static_cast< sal_Int32 >(entity_->getDirectMethods().size()); + css::uno::Sequence< + css::uno::Reference< + css::reflection::XInterfaceMemberTypeDescription > > s(n1 + n2); + sal_Int32 off = BaseOffset(this).get(); + for (sal_Int32 i = 0; i != n1; ++i) { + s[i] = new AttributeDescription( + manager_, name_ + "::" + entity_->getDirectAttributes()[i].name, + entity_->getDirectAttributes()[i], off + i); + } + for (sal_Int32 i = 0; i != n2; ++i) { + s[n1 + i] = new MethodDescription( + manager_, name_ + "::" + entity_->getDirectMethods()[i].name, + entity_->getDirectMethods()[i], off + n1 + i); + } + return s; +} + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +InterfaceTypeDescription::getBaseTypes() { + assert(entity_->getDirectMandatoryBases().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectMandatoryBases().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(entity_->getDirectMandatoryBases()[i].name); + } + return s; +} + +css::uno::Sequence< css::uno::Reference< css::reflection::XTypeDescription > > +InterfaceTypeDescription::getOptionalBaseTypes() +{ + assert(entity_->getDirectOptionalBases().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectOptionalBases().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = manager_->resolve(entity_->getDirectOptionalBases()[i].name); + } + return s; +} + +class ConstantDescription: + public cppu::WeakImplHelper< css::reflection::XConstantTypeDescription > +{ +public: + ConstantDescription( + OUString const & constantGroupName, + unoidl::ConstantGroupEntity::Member const & member); + +private: + virtual ~ConstantDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_CONSTANT; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Any SAL_CALL getConstantValue() override + { return value_; } + + OUString name_; + css::uno::Any value_; +}; + +ConstantDescription::ConstantDescription( + OUString const & constantGroupName, + unoidl::ConstantGroupEntity::Member const & member): + name_(makePrefix(constantGroupName) + member.name) +{ + switch (member.value.type) { + case unoidl::ConstantValue::TYPE_BOOLEAN: + value_ <<= member.value.booleanValue; + break; + case unoidl::ConstantValue::TYPE_BYTE: + value_ <<= member.value.byteValue; + break; + case unoidl::ConstantValue::TYPE_SHORT: + value_ <<= member.value.shortValue; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT: + value_ <<= member.value.unsignedShortValue; + break; + case unoidl::ConstantValue::TYPE_LONG: + value_ <<= member.value.longValue; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_LONG: + value_ <<= member.value.unsignedLongValue; + break; + case unoidl::ConstantValue::TYPE_HYPER: + value_ <<= member.value.hyperValue; + break; + case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER: + value_ <<= member.value.unsignedHyperValue; + break; + case unoidl::ConstantValue::TYPE_FLOAT: + value_ <<= member.value.floatValue; + break; + case unoidl::ConstantValue::TYPE_DOUBLE: + value_ <<= member.value.doubleValue; + break; + default: + for (;;) { std::abort(); } // this cannot happen + } +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XConstantsTypeDescription > +ConstantGroupDescription_Base; + +class ConstantGroupDescription: public ConstantGroupDescription_Base { +public: + ConstantGroupDescription( + OUString const & name, + rtl::Reference< unoidl::ConstantGroupEntity > const & entity): + ConstantGroupDescription_Base(entity->isPublished()), name_(name), + entity_(entity) + { assert(entity.is()); } + +private: + virtual ~ConstantGroupDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_CONSTANTS; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XConstantTypeDescription > > + SAL_CALL getConstants() override; + + OUString name_; + rtl::Reference< unoidl::ConstantGroupEntity > entity_; +}; + +css::uno::Sequence< + css::uno::Reference< css::reflection::XConstantTypeDescription > > +ConstantGroupDescription::getConstants() { + assert(entity_->getMembers().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getMembers().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XConstantTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = new ConstantDescription(name_, entity_->getMembers()[i]); + } + return s; +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XIndirectTypeDescription > +TypedefDescription_Base; + +class TypedefDescription: public TypedefDescription_Base { +public: + TypedefDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::TypedefEntity > const & entity): + TypedefDescription_Base(entity->isPublished()), manager_(manager), + name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~TypedefDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_TYPEDEF; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getReferencedType() override + { return manager_->resolve(entity_->getType()); } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::TypedefEntity > entity_; +}; + +class ConstructorParameter: + public cppu::WeakImplHelper< css::reflection::XParameter > +{ +public: + ConstructorParameter( + rtl::Reference< cppuhelper::TypeManager > const & manager, + unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter + const & parameter, + sal_Int32 position): + manager_(manager), parameter_(parameter), position_(position) + { assert(manager.is()); } + +private: + virtual ~ConstructorParameter() override {} + + virtual OUString SAL_CALL getName() override + { return parameter_.name; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getType() override + { return manager_->resolve(parameter_.type); } + + virtual sal_Bool SAL_CALL isIn() override + { return true; } + + virtual sal_Bool SAL_CALL isOut() override + { return false; } + + virtual sal_Int32 SAL_CALL getPosition() override + { return position_; } + + virtual sal_Bool SAL_CALL isRestParameter() override + { return parameter_.rest; } + + rtl::Reference< cppuhelper::TypeManager > manager_; + unoidl::SingleInterfaceBasedServiceEntity::Constructor::Parameter + parameter_; + sal_Int32 position_; +}; + +class ConstructorDescription: + public cppu::WeakImplHelper< + css::reflection::XServiceConstructorDescription > +{ +public: + ConstructorDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + unoidl::SingleInterfaceBasedServiceEntity::Constructor const & + constructor): + manager_(manager), constructor_(constructor) + { assert(manager.is()); } + +private: + virtual ~ConstructorDescription() override {} + + virtual sal_Bool SAL_CALL isDefaultConstructor() override + { return constructor_.defaultConstructor; } + + virtual OUString SAL_CALL getName() override + { return constructor_.name; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XParameter > > + SAL_CALL getParameters() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > + SAL_CALL getExceptions() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + unoidl::SingleInterfaceBasedServiceEntity::Constructor constructor_; +}; + +css::uno::Sequence< css::uno::Reference< css::reflection::XParameter > > +ConstructorDescription::getParameters() { + assert(constructor_.parameters.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(constructor_.parameters.size()); + css::uno::Sequence< css::uno::Reference< css::reflection::XParameter > > s( + n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = new ConstructorParameter( + manager_, constructor_.parameters[i], i); + } + return s; +} + +css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > +ConstructorDescription::getExceptions() { + assert(constructor_.exceptions.size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(constructor_.exceptions.size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XCompoundTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + manager_->resolve(constructor_.exceptions[i]), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XServiceTypeDescription2 > +SingleInterfaceBasedServiceDescription_Base; + +class SingleInterfaceBasedServiceDescription: + public SingleInterfaceBasedServiceDescription_Base +{ +public: + SingleInterfaceBasedServiceDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > const & + entity): + SingleInterfaceBasedServiceDescription_Base(entity->isPublished()), + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~SingleInterfaceBasedServiceDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_SERVICE; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > + SAL_CALL getMandatoryServices() override + { + return css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > >(); + } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > + SAL_CALL getOptionalServices() override + { + return css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > >(); + } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > + SAL_CALL getMandatoryInterfaces() override + { + return css::uno::Sequence< + css::uno::Reference< + css::reflection::XInterfaceTypeDescription > >(); + } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > + SAL_CALL getOptionalInterfaces() override + { + return css::uno::Sequence< + css::uno::Reference< + css::reflection::XInterfaceTypeDescription > >(); + } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XPropertyTypeDescription > > + SAL_CALL getProperties() override + { + return css::uno::Sequence< + css::uno::Reference< + css::reflection::XPropertyTypeDescription > >(); + } + + virtual sal_Bool SAL_CALL isSingleInterfaceBased() override + { return true; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getInterface() override + { return manager_->resolve(entity_->getBase()); } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceConstructorDescription > > + SAL_CALL getConstructors() override; + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::SingleInterfaceBasedServiceEntity > entity_; +}; + +css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceConstructorDescription > > +SingleInterfaceBasedServiceDescription::getConstructors() +{ + assert(entity_->getConstructors().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >(entity_->getConstructors().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceConstructorDescription > > + s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = new ConstructorDescription( + manager_, entity_->getConstructors()[i]); + } + return s; +} + +class PropertyDescription: + public cppu::WeakImplHelper< css::reflection::XPropertyTypeDescription > +{ +public: + PropertyDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + unoidl::AccumulationBasedServiceEntity::Property const & property): + manager_(manager), property_(property) + { assert(manager.is()); } + +private: + virtual ~PropertyDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_PROPERTY; } + + virtual OUString SAL_CALL getName() override + { return property_.name; } + + virtual sal_Int16 SAL_CALL getPropertyFlags() override + { return property_.attributes; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getPropertyTypeDescription() override + { return manager_->resolve(property_.type); } + + rtl::Reference< cppuhelper::TypeManager > manager_; + unoidl::AccumulationBasedServiceEntity::Property property_; +}; + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XServiceTypeDescription2 > +AccumulationBasedServiceDescription_Base; + +class AccumulationBasedServiceDescription: + public AccumulationBasedServiceDescription_Base +{ +public: + AccumulationBasedServiceDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::AccumulationBasedServiceEntity > const & + entity): + AccumulationBasedServiceDescription_Base(entity->isPublished()), + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~AccumulationBasedServiceDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_SERVICE; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > + SAL_CALL getMandatoryServices() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > + SAL_CALL getOptionalServices() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > + SAL_CALL getMandatoryInterfaces() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > + SAL_CALL getOptionalInterfaces() override; + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XPropertyTypeDescription > > + SAL_CALL getProperties() override; + + virtual sal_Bool SAL_CALL isSingleInterfaceBased() override + { return false; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + getInterface() override + { return css::uno::Reference< css::reflection::XTypeDescription >(); } + + virtual + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceConstructorDescription > > + SAL_CALL getConstructors() override + { + return css::uno::Sequence< + css::uno::Reference< + css::reflection::XServiceConstructorDescription > >(); + } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::AccumulationBasedServiceEntity > entity_; +}; + +css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > +AccumulationBasedServiceDescription::getMandatoryServices() +{ + assert(entity_->getDirectMandatoryBaseServices().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectMandatoryBaseServices().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + manager_->resolve( + entity_->getDirectMandatoryBaseServices()[i].name), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > +AccumulationBasedServiceDescription::getOptionalServices() +{ + assert(entity_->getDirectOptionalBaseServices().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectOptionalBaseServices().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XServiceTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + manager_->resolve(entity_->getDirectOptionalBaseServices()[i].name), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > +AccumulationBasedServiceDescription::getMandatoryInterfaces() +{ + assert(entity_->getDirectMandatoryBaseInterfaces().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectMandatoryBaseInterfaces().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > s( + n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + resolveTypedefs( + manager_->find( + entity_->getDirectMandatoryBaseInterfaces()[i].name)), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > +AccumulationBasedServiceDescription::getOptionalInterfaces() +{ + assert(entity_->getDirectOptionalBaseInterfaces().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectOptionalBaseInterfaces().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XInterfaceTypeDescription > > s( + n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i].set( + resolveTypedefs( + manager_->find( + entity_->getDirectOptionalBaseInterfaces()[i].name)), + css::uno::UNO_QUERY_THROW); + } + return s; +} + +css::uno::Sequence< + css::uno::Reference< css::reflection::XPropertyTypeDescription > > +AccumulationBasedServiceDescription::getProperties() +{ + assert(entity_->getDirectProperties().size() <= SAL_MAX_INT32); + sal_Int32 n = static_cast< sal_Int32 >( + entity_->getDirectProperties().size()); + css::uno::Sequence< + css::uno::Reference< css::reflection::XPropertyTypeDescription > > s(n); + for (sal_Int32 i = 0; i != n; ++i) { + s[i] = new PropertyDescription( + manager_, entity_->getDirectProperties()[i]); + } + return s; +} + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XSingletonTypeDescription2 > +InterfaceBasedSingletonDescription_Base; + +class InterfaceBasedSingletonDescription: + public InterfaceBasedSingletonDescription_Base +{ +public: + InterfaceBasedSingletonDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::InterfaceBasedSingletonEntity > const & entity): + InterfaceBasedSingletonDescription_Base(entity->isPublished()), + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~InterfaceBasedSingletonDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_SINGLETON; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XServiceTypeDescription > + SAL_CALL getService() override + { + return + css::uno::Reference< css::reflection::XServiceTypeDescription >(); + } + + virtual sal_Bool SAL_CALL isInterfaceBased() override + { return true; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > + SAL_CALL getInterface() override + { return manager_->resolve(entity_->getBase()); } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::InterfaceBasedSingletonEntity > entity_; +}; + +typedef cppu::ImplInheritanceHelper< + PublishableDescription, css::reflection::XSingletonTypeDescription2 > +ServiceBasedSingletonDescription_Base; + +class ServiceBasedSingletonDescription: + public ServiceBasedSingletonDescription_Base +{ +public: + ServiceBasedSingletonDescription( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & name, + rtl::Reference< unoidl::ServiceBasedSingletonEntity > const & entity): + ServiceBasedSingletonDescription_Base(entity_->isPublished()), + manager_(manager), name_(name), entity_(entity) + { assert(manager.is()); assert(entity.is()); } + +private: + virtual ~ServiceBasedSingletonDescription() override {} + + virtual css::uno::TypeClass SAL_CALL getTypeClass() override + { return css::uno::TypeClass_SINGLETON; } + + virtual OUString SAL_CALL getName() override + { return name_; } + + virtual css::uno::Reference< css::reflection::XServiceTypeDescription > + SAL_CALL getService() override + { + return css::uno::Reference< css::reflection::XServiceTypeDescription >( + manager_->resolve(entity_->getBase()), css::uno::UNO_QUERY_THROW); + } + + virtual sal_Bool SAL_CALL isInterfaceBased() override + { return false; } + + virtual css::uno::Reference< css::reflection::XTypeDescription > + SAL_CALL getInterface() override + { return css::uno::Reference< css::reflection::XTypeDescription >(); } + + rtl::Reference< cppuhelper::TypeManager > manager_; + OUString name_; + rtl::Reference< unoidl::ServiceBasedSingletonEntity > entity_; +}; + +class Enumeration: + public cppu::WeakImplHelper< css::reflection::XTypeDescriptionEnumeration > +{ +public: + Enumeration( + rtl::Reference< cppuhelper::TypeManager > const & manager, + OUString const & prefix, + rtl::Reference< unoidl::MapCursor > const & cursor, + css::uno::Sequence< css::uno::TypeClass > const & types, bool deep): + manager_(manager), types_(types), deep_(deep) + { + assert(manager.is()); + positions_.push(Position(prefix, cursor)); + findNextMatch(); + } + +private: + virtual ~Enumeration() override {} + + virtual sal_Bool SAL_CALL hasMoreElements() override + { return !positions_.empty(); } + + virtual css::uno::Any SAL_CALL nextElement() override + { return css::uno::makeAny(nextTypeDescription()); } + + virtual css::uno::Reference< css::reflection::XTypeDescription > SAL_CALL + nextTypeDescription() override; + + bool matches(css::uno::TypeClass tc) const; + + void findNextMatch(); + + struct Position { + Position( + OUString const & thePrefix, + rtl::Reference< unoidl::MapCursor > const & theCursor): + prefix(thePrefix), cursor(theCursor) + { assert(theCursor.is()); } + + Position( + OUString const & thePrefix, + rtl::Reference< unoidl::ConstantGroupEntity > const & + theConstantGroup): + prefix(thePrefix), constantGroup(theConstantGroup), + constantGroupIndex(constantGroup->getMembers().begin()) + { assert(theConstantGroup.is()); } + + Position(Position const & other): + prefix(other.prefix), cursor(other.cursor), + constantGroup(other.constantGroup) + { + if (constantGroup.is()) { + constantGroupIndex = other.constantGroupIndex; + } + } + + OUString prefix; + rtl::Reference< unoidl::MapCursor > cursor; + rtl::Reference< unoidl::ConstantGroupEntity > constantGroup; + std::vector< unoidl::ConstantGroupEntity::Member >::const_iterator + constantGroupIndex; + }; + + rtl::Reference< cppuhelper::TypeManager > manager_; + css::uno::Sequence< css::uno::TypeClass > types_; + bool deep_; + + osl::Mutex mutex_; + std::stack< Position > positions_; + OUString current_; +}; + +css::uno::Reference< css::reflection::XTypeDescription > +Enumeration::nextTypeDescription() +{ + OUString name; + { + osl::MutexGuard g(mutex_); + if (positions_.empty()) { + throw css::container::NoSuchElementException( + "exhausted XTypeDescriptionEnumeration", + static_cast< cppu::OWeakObject * >(this)); + } + name = current_; + findNextMatch(); + } + return manager_->resolve(name); +} + +bool Enumeration::matches(css::uno::TypeClass tc) const { + if (!types_.hasElements()) { + return true; + } + for (const auto & i : types_) { + if (i == tc) { + return true; + } + } + return false; +} + +void Enumeration::findNextMatch() { + try { + for (;;) { + assert(!positions_.empty()); + OUString name; + if (positions_.top().cursor.is()) { // root or module + rtl::Reference< unoidl::Entity > ent( + positions_.top().cursor->getNext(&name)); + if (!ent.is()) { + positions_.pop(); + if (positions_.empty()) { + break; + } + continue; + } + name = positions_.top().prefix + name; + css::uno::TypeClass tc; + switch (ent->getSort()) { + case unoidl::Entity::SORT_MODULE: + tc = css::uno::TypeClass_MODULE; + if (deep_) { + positions_.push( + Position( + makePrefix(name), + static_cast< unoidl::ModuleEntity * >( + ent.get())->createCursor())); + } + break; + case unoidl::Entity::SORT_ENUM_TYPE: + tc = css::uno::TypeClass_ENUM; + break; + case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE: + case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE: + tc = css::uno::TypeClass_STRUCT; + break; + case unoidl::Entity::SORT_EXCEPTION_TYPE: + tc = css::uno::TypeClass_EXCEPTION; + break; + case unoidl::Entity::SORT_INTERFACE_TYPE: + tc = css::uno::TypeClass_INTERFACE; + break; + case unoidl::Entity::SORT_TYPEDEF: + tc = css::uno::TypeClass_TYPEDEF; + break; + case unoidl::Entity::SORT_CONSTANT_GROUP: + tc = css::uno::TypeClass_CONSTANTS; + if (deep_ && matches(css::uno::TypeClass_CONSTANT)) { + positions_.push( + Position( + makePrefix(name), + static_cast< unoidl::ConstantGroupEntity * >( + ent.get()))); + } + break; + case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE: + case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE: + tc = css::uno::TypeClass_SERVICE; + break; + case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON: + case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON: + tc = css::uno::TypeClass_SINGLETON; + break; + default: + for (;;) { std::abort(); } // this cannot happen + } + if (matches(tc)) { + current_ = name; + break; + } + } else { // constant group + if (positions_.top().constantGroupIndex + == positions_.top().constantGroup->getMembers().end()) + { + positions_.pop(); + if (positions_.empty()) { + break; + } + continue; + } + current_ = positions_.top().prefix + + positions_.top().constantGroupIndex++->name; + break; + } + } + } catch (unoidl::FileFormatException & e) { + throw css::uno::DeploymentException( + e.getUri() + ": " + e.getDetail(), + static_cast< cppu::OWeakObject * >(this)); + } +} + +} + +cppuhelper::TypeManager::TypeManager(): + TypeManager_Base(m_aMutex), + manager_(new unoidl::Manager) +{} + +css::uno::Any cppuhelper::TypeManager::find(OUString const & name) { + //TODO: caching? (here or in unoidl::Manager?) + struct Simple { + OUStringLiteral name; + css::uno::TypeClass typeClass; + }; + static Simple const simple[] = { + { OUStringLiteral("void"), css::uno::TypeClass_VOID }, + { OUStringLiteral("boolean"), css::uno::TypeClass_BOOLEAN }, + { OUStringLiteral("byte"), css::uno::TypeClass_BYTE }, + { OUStringLiteral("short"), css::uno::TypeClass_SHORT }, + { OUStringLiteral("unsigned short"), + css::uno::TypeClass_UNSIGNED_SHORT }, + { OUStringLiteral("long"), css::uno::TypeClass_LONG }, + { OUStringLiteral("unsigned long"), css::uno::TypeClass_UNSIGNED_LONG }, + { OUStringLiteral("hyper"), css::uno::TypeClass_HYPER }, + { OUStringLiteral("unsigned hyper"), + css::uno::TypeClass_UNSIGNED_HYPER }, + { OUStringLiteral("float"), css::uno::TypeClass_FLOAT }, + { OUStringLiteral("double"), css::uno::TypeClass_DOUBLE }, + { OUStringLiteral("char"), css::uno::TypeClass_CHAR }, + { OUStringLiteral("string"), css::uno::TypeClass_STRING }, + { OUStringLiteral("type"), css::uno::TypeClass_TYPE }, + { OUStringLiteral("any"), css::uno::TypeClass_ANY } }; + for (std::size_t i = 0; i != SAL_N_ELEMENTS(simple); ++i) { + if (name == simple[i].name) { + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new SimpleTypeDescription(simple[i].typeClass, name)); + } + } + if (name.startsWith("[]")) { + return getSequenceType(name); + } + sal_Int32 i = name.indexOf('<'); + if (i != -1) { + return getInstantiatedStruct(name, i); + } + i = name.indexOf("::"); + if (i != -1) { + return getInterfaceMember(name, i); + } + rtl::Reference< unoidl::Entity > ent(findEntity(name)); + if (ent.is()) { + return getNamed(name, ent); + } + i = name.lastIndexOf('.'); + if (i != -1) { + OUString parent(name.copy(0, i)); + ent = findEntity(parent); + if (ent.is()) { + switch (ent->getSort()) { + case unoidl::Entity::SORT_ENUM_TYPE: + return getEnumMember( + static_cast< unoidl::EnumTypeEntity * >(ent.get()), + name.copy(i + 1)); + case unoidl::Entity::SORT_CONSTANT_GROUP: + return getConstant( + parent, + static_cast< unoidl::ConstantGroupEntity * >(ent.get()), + name.copy(i + 1)); + default: + break; + } + } + } + return css::uno::Any(); +} + +css::uno::Reference< css::reflection::XTypeDescription > +cppuhelper::TypeManager::resolve(OUString const & name) { + css::uno::Reference< css::reflection::XTypeDescription > desc( + find(name), css::uno::UNO_QUERY); + if (!desc.is()) { + throw css::uno::DeploymentException( + "cannot resolve type \"" + name + "\"", + static_cast< cppu::OWeakObject * >(this)); + } + return desc; +} + +cppuhelper::TypeManager::~TypeManager() throw () {} + +void cppuhelper::TypeManager::disposing() {} //TODO + +OUString cppuhelper::TypeManager::getImplementationName() +{ + return + "com.sun.star.comp.cppuhelper.bootstrap.TypeManager"; +} + +sal_Bool cppuhelper::TypeManager::supportsService( + OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< OUString > +cppuhelper::TypeManager::getSupportedServiceNames() +{ + css::uno::Sequence<OUString> names { "com.sun.star.reflection.TypeDescriptionManager" }; //TODO + return names; +} + +css::uno::Any cppuhelper::TypeManager::getByHierarchicalName( + OUString const & aName) +{ + css::uno::Any desc(find(aName)); + if (!desc.hasValue()) { + throw css::container::NoSuchElementException( + aName, static_cast< cppu::OWeakObject * >(this)); + } + return desc; +} + +sal_Bool cppuhelper::TypeManager::hasByHierarchicalName( + OUString const & aName) +{ + return find(aName).hasValue(); +} + +css::uno::Type cppuhelper::TypeManager::getElementType() +{ + return cppu::UnoType< OUString >::get(); +} + +sal_Bool cppuhelper::TypeManager::hasElements() +{ + throw css::uno::RuntimeException( + "TypeManager hasElements: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +css::uno::Reference< css::container::XEnumeration > +cppuhelper::TypeManager::createEnumeration() +{ + throw css::uno::RuntimeException( + "TypeManager createEnumeration: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +sal_Bool cppuhelper::TypeManager::has(css::uno::Any const &) +{ + throw css::uno::RuntimeException( + "TypeManager has: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +void cppuhelper::TypeManager::insert(css::uno::Any const & aElement) +{ + OUString uri; + if (!(aElement >>= uri)) { + throw css::lang::IllegalArgumentException( + ("css.uno.theTypeDescriptionManager.insert expects a string URI" + " argument"), + static_cast< cppu::OWeakObject * >(this), 0); + } + //TODO: check for ElementExistException + //TODO: check for consistency with existing data + readRdbFile(uri, false); +} + +void cppuhelper::TypeManager::remove(css::uno::Any const & aElement) +{ + OUString uri; + if (!(aElement >>= uri)) { + throw css::lang::IllegalArgumentException( + ("css.uno.theTypeDescriptionManager.remove expects a string URI" + " argument"), + static_cast< cppu::OWeakObject * >(this), 0); + } + //TODO: remove requests are silently ignored for now +} + +css::uno::Reference< css::reflection::XTypeDescriptionEnumeration > +cppuhelper::TypeManager::createTypeDescriptionEnumeration( + OUString const & moduleName, + css::uno::Sequence< css::uno::TypeClass > const & types, + css::reflection::TypeDescriptionSearchDepth depth) +{ + rtl::Reference< unoidl::MapCursor > cursor; + try { + cursor = manager_->createCursor(moduleName); + } catch (unoidl::FileFormatException & e) { + throw css::uno::DeploymentException( + ("unoidl::FileFormatException for <" + e.getUri() + ">: " + + e.getDetail()), + static_cast< cppu::OWeakObject * >(this)); + } + if (!cursor.is()) { + //TODO: css::reflection::InvalidTypeNameException if moduleName names a + // non-module + throw css::reflection::NoSuchTypeNameException( + moduleName, static_cast< cppu::OWeakObject * >(this)); + } + return new Enumeration( + this, makePrefix(moduleName), cursor, types, + depth == css::reflection::TypeDescriptionSearchDepth_INFINITE); +} + +void cppuhelper::TypeManager::init(OUString const & rdbUris) { + for (sal_Int32 i = 0; i != -1;) { + OUString uri(rdbUris.getToken(0, ' ', i)); + if (uri.isEmpty()) { + continue; + } + bool optional; + bool directory; + cppu::decodeRdbUri(&uri, &optional, &directory); + if (directory) { + readRdbDirectory(uri, optional); + } else { + readRdbFile(uri, optional); + } + } +} + +void cppuhelper::TypeManager::readRdbDirectory( + OUString const & uri, bool optional) +{ + osl::Directory dir(uri); + switch (dir.open()) { + case osl::FileBase::E_None: + break; + case osl::FileBase::E_NOENT: + if (optional) { + SAL_INFO("cppuhelper", "Ignored optional " << uri); + return; + } + [[fallthrough]]; + default: + throw css::uno::DeploymentException( + "Cannot open directory " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (;;) { + OUString url; + if (!cppu::nextDirectoryItem(dir, &url)) { + break; + } + readRdbFile(url, false); + } +} + +void cppuhelper::TypeManager::readRdbFile( + OUString const & uri, bool optional) +{ + try { + manager_->addProvider(uri); + } catch (unoidl::NoSuchFileException &) { + if (!optional) { + throw css::uno::DeploymentException( + uri + ": no such file", + static_cast< cppu::OWeakObject * >(this)); + } + SAL_INFO("cppuhelper", "Ignored optional " << uri); + } catch (unoidl::FileFormatException & e) { + throw css::uno::DeploymentException( + ("unoidl::FileFormatException for <" + e.getUri() + ">: " + + e.getDetail()), + static_cast< cppu::OWeakObject * >(this)); + } +} + +css::uno::Any cppuhelper::TypeManager::getSequenceType( + OUString const & name) +{ + assert(name.startsWith("[]")); + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new SequenceTypeDescription( + this, name, name.copy(std::strlen("[]")))); +} + +css::uno::Any cppuhelper::TypeManager::getInstantiatedStruct( + OUString const & name, sal_Int32 separator) +{ + assert(name.indexOf('<') == separator && separator != -1); + rtl::Reference< unoidl::Entity > ent(findEntity(name.copy(0, separator))); + if (!ent.is() + || (ent->getSort() + != unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE)) + { + return css::uno::Any(); + } + rtl::Reference< unoidl::PolymorphicStructTypeTemplateEntity > ent2( + static_cast< unoidl::PolymorphicStructTypeTemplateEntity * >( + ent.get())); + std::vector< OUString > args; + sal_Int32 i = separator; + do { + ++i; // skip '<' or ',' + sal_Int32 j = i; + for (sal_Int32 level = 0; j != name.getLength(); ++j) { + sal_Unicode c = name[j]; + if (c == ',') { + if (level == 0) { + break; + } + } else if (c == '<') { + ++level; + } else if (c == '>') { + if (level == 0) { + break; + } + --level; + } + } + if (j != name.getLength()) { + args.push_back(name.copy(i, j - i)); + } + i = j; + } while (i != name.getLength() && name[i] != '>'); + if (i != name.getLength() - 1 || name[i] != '>' + || args.size() != ent2->getTypeParameters().size()) + { + return css::uno::Any(); + } + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new InstantiatedPolymorphicStructTypeDescription( + this, name, ent2, args)); +} + +css::uno::Any cppuhelper::TypeManager::getInterfaceMember( + OUString const & name, sal_Int32 separator) +{ + assert(name.indexOf("::") == separator && separator != -1); + css::uno::Reference< css::reflection::XInterfaceTypeDescription2 > ifc( + resolveTypedefs(find(name.copy(0, separator))), css::uno::UNO_QUERY); + if (!ifc.is()) { + return css::uno::Any(); + } + OUString member(name.copy(separator + std::strlen("::"))); + const css::uno::Sequence< + css::uno::Reference< + css::reflection::XInterfaceMemberTypeDescription > > mems( + ifc->getMembers()); + for (const auto & m : mems) { + if (m->getMemberName() == member) { + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >(m); + } + } + return css::uno::Any(); +} + +css::uno::Any cppuhelper::TypeManager::getNamed( + OUString const & name, rtl::Reference< unoidl::Entity > const & entity) +{ + assert(entity.is()); + switch (entity->getSort()) { + case unoidl::Entity::SORT_MODULE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new ModuleDescription( + this, name, + static_cast< unoidl::ModuleEntity * >(entity.get()))); + case unoidl::Entity::SORT_ENUM_TYPE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new EnumTypeDescription( + name, + static_cast< unoidl::EnumTypeEntity * >(entity.get()))); + case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new PlainStructTypeDescription( + this, name, + static_cast< unoidl::PlainStructTypeEntity * >( + entity.get()))); + case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new PolymorphicStructTypeTemplateDescription( + this, name, + static_cast< + unoidl::PolymorphicStructTypeTemplateEntity * >( + entity.get()))); + case unoidl::Entity::SORT_EXCEPTION_TYPE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new ExceptionTypeDescription( + this, name, + static_cast< unoidl::ExceptionTypeEntity * >( + entity.get()))); + case unoidl::Entity::SORT_INTERFACE_TYPE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new InterfaceTypeDescription( + this, name, + static_cast< unoidl::InterfaceTypeEntity * >( + entity.get()))); + case unoidl::Entity::SORT_TYPEDEF: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new TypedefDescription( + this, name, + static_cast< unoidl::TypedefEntity * >(entity.get()))); + case unoidl::Entity::SORT_CONSTANT_GROUP: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new ConstantGroupDescription( + name, + static_cast< unoidl::ConstantGroupEntity * >( + entity.get()))); + case unoidl::Entity::SORT_SINGLE_INTERFACE_BASED_SERVICE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new SingleInterfaceBasedServiceDescription( + this, name, + static_cast< unoidl::SingleInterfaceBasedServiceEntity * >( + entity.get()))); + case unoidl::Entity::SORT_ACCUMULATION_BASED_SERVICE: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new AccumulationBasedServiceDescription( + this, name, + static_cast< unoidl::AccumulationBasedServiceEntity * >( + entity.get()))); + case unoidl::Entity::SORT_INTERFACE_BASED_SINGLETON: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new InterfaceBasedSingletonDescription( + this, name, + static_cast< unoidl::InterfaceBasedSingletonEntity * >( + entity.get()))); + case unoidl::Entity::SORT_SERVICE_BASED_SINGLETON: + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new ServiceBasedSingletonDescription( + this, name, + static_cast< unoidl::ServiceBasedSingletonEntity * >( + entity.get()))); + default: + for (;;) { std::abort(); } // this cannot happen + } +} + +css::uno::Any cppuhelper::TypeManager::getEnumMember( + rtl::Reference< unoidl::EnumTypeEntity > const & entity, + OUString const & member) +{ + auto i = std::find_if(entity->getMembers().begin(), entity->getMembers().end(), + [&member](const unoidl::EnumTypeEntity::Member& rMember) { return rMember.name == member; }); + if (i != entity->getMembers().end()) + return css::uno::makeAny(i->value); + return css::uno::Any(); +} + +css::uno::Any cppuhelper::TypeManager::getConstant( + OUString const & constantGroupName, + rtl::Reference< unoidl::ConstantGroupEntity > const & entity, + OUString const & member) +{ + auto i = std::find_if(entity->getMembers().begin(), entity->getMembers().end(), + [&member](const unoidl::ConstantGroupEntity::Member& rMember) { return rMember.name == member; }); + if (i != entity->getMembers().end()) + return css::uno::makeAny< + css::uno::Reference< css::reflection::XTypeDescription > >( + new ConstantDescription(constantGroupName, *i)); + return css::uno::Any(); +} + +rtl::Reference< unoidl::Entity > cppuhelper::TypeManager::findEntity( + OUString const & name) +{ + try { + return manager_->findEntity(name); + } catch (unoidl::FileFormatException & e) { + throw css::uno::DeploymentException( + ("unoidl::FileFormatException for <" + e.getUri() + ">: " + + e.getDetail()), + static_cast< cppu::OWeakObject * >(this)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/typemanager.hxx b/cppuhelper/source/typemanager.hxx new file mode 100644 index 000000000..bc086693a --- /dev/null +++ b/cppuhelper/source/typemanager.hxx @@ -0,0 +1,128 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_TYPEMANAGER_HXX +#define INCLUDED_CPPUHELPER_SOURCE_TYPEMANAGER_HXX + +#include <sal/config.h> + +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/reflection/TypeDescriptionSearchDepth.hpp> +#include <com/sun/star/reflection/XTypeDescriptionEnumerationAccess.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <rtl/ref.hxx> +#include <sal/types.h> + +namespace com::sun::star { + namespace reflection { class XTypeDescription; } +} +namespace unoidl { + class ConstantGroupEntity; + class Entity; + class EnumTypeEntity; + class Manager; +} + +namespace cppuhelper { + +typedef cppu::WeakComponentImplHelper< + css::lang::XServiceInfo, css::container::XHierarchicalNameAccess, + css::container::XSet, css::reflection::XTypeDescriptionEnumerationAccess > +TypeManager_Base; + +class TypeManager: private cppu::BaseMutex, public TypeManager_Base { +public: + TypeManager(); + + using TypeManager_Base::acquire; + using TypeManager_Base::release; + + void init(OUString const & rdbUris); + + css::uno::Any find(OUString const & name); + + css::uno::Reference< css::reflection::XTypeDescription > resolve( + OUString const & name); + +private: + virtual ~TypeManager() throw () override; + + virtual void SAL_CALL disposing() override; + + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + virtual css::uno::Sequence< OUString > SAL_CALL + getSupportedServiceNames() override; + + virtual css::uno::Any SAL_CALL getByHierarchicalName( + OUString const & aName) override; + + virtual sal_Bool SAL_CALL hasByHierarchicalName(OUString const & aName) override; + + virtual css::uno::Type SAL_CALL getElementType() override; + + virtual sal_Bool SAL_CALL hasElements() override; + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL + createEnumeration() override; + + virtual sal_Bool SAL_CALL has(css::uno::Any const & aElement) override; + + virtual void SAL_CALL insert(css::uno::Any const & aElement) override; + + virtual void SAL_CALL remove(css::uno::Any const & aElement) override; + + virtual css::uno::Reference< css::reflection::XTypeDescriptionEnumeration > + SAL_CALL createTypeDescriptionEnumeration( + OUString const & moduleName, + css::uno::Sequence< css::uno::TypeClass > const & types, + css::reflection::TypeDescriptionSearchDepth depth) override; + + void readRdbDirectory(OUString const & uri, bool optional); + + void readRdbFile(OUString const & uri, bool optional); + + css::uno::Any getSequenceType(OUString const & name); + + css::uno::Any getInstantiatedStruct( + OUString const & name, sal_Int32 separator); + + css::uno::Any getInterfaceMember( + OUString const & name, sal_Int32 separator); + + css::uno::Any getNamed( + OUString const & name, + rtl::Reference< unoidl::Entity > const & entity); + + static css::uno::Any getEnumMember( + rtl::Reference< unoidl::EnumTypeEntity > const & entity, + OUString const & member); + + static css::uno::Any getConstant( + OUString const & constantGroupName, + rtl::Reference< unoidl::ConstantGroupEntity > const & entity, + OUString const & member); + + rtl::Reference< unoidl::Entity > findEntity(OUString const & name); + + rtl::Reference< unoidl::Manager > manager_; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/typeprovider.cxx b/cppuhelper/source/typeprovider.cxx new file mode 100644 index 000000000..c4258ef61 --- /dev/null +++ b/cppuhelper/source/typeprovider.cxx @@ -0,0 +1,305 @@ +/* -*- 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 <cppuhelper/typeprovider.hxx> + +#include <rtl/uuid.h> +#include <osl/mutex.hxx> + +using namespace osl; +using namespace com::sun::star::uno; + +namespace cppu +{ + + +OImplementationId::~OImplementationId() +{ + delete _pSeq; +} + +Sequence< sal_Int8 > OImplementationId::getImplementationId() const +{ + if (! _pSeq) + { + MutexGuard aGuard( Mutex::getGlobalMutex() ); + if (! _pSeq) + { + Sequence< sal_Int8 > * pSeq = new Sequence< sal_Int8 >( 16 ); + ::rtl_createUuid( reinterpret_cast<sal_uInt8 *>(pSeq->getArray()), nullptr, _bUseEthernetAddress ); + _pSeq = pSeq; + } + } + return *_pSeq; +} + + +static void copy( Sequence< Type > & rDest, const Sequence< Type > & rSource, sal_Int32 nOffset ) +{ + Type * pDest = rDest.getArray(); + const Type * pSource = rSource.getConstArray(); + + for ( sal_Int32 nPos = rSource.getLength(); nPos--; ) + pDest[nOffset+ nPos] = pSource[nPos]; +} + + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Sequence< Type > & rAddTypes ) + : _aTypes( 1 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + copy( _aTypes, rAddTypes, 1 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Sequence< Type > & rAddTypes ) + : _aTypes( 2 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + copy( _aTypes, rAddTypes, 2 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Sequence< Type > & rAddTypes ) + : _aTypes( 3 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + copy( _aTypes, rAddTypes, 3 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Sequence< Type > & rAddTypes ) + : _aTypes( 4 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + copy( _aTypes, rAddTypes, 4 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Sequence< Type > & rAddTypes ) + : _aTypes( 5 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + copy( _aTypes, rAddTypes, 5 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Sequence< Type > & rAddTypes ) + : _aTypes( 6 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + copy( _aTypes, rAddTypes, 6 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Type & rType7, + const Sequence< Type > & rAddTypes ) + : _aTypes( 7 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + _aTypes[6] = rType7; + copy( _aTypes, rAddTypes, 7 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Type & rType7, + const Type & rType8, + const Sequence< Type > & rAddTypes ) + : _aTypes( 8 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + _aTypes[6] = rType7; + _aTypes[7] = rType8; + copy( _aTypes, rAddTypes, 8 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Type & rType7, + const Type & rType8, + const Type & rType9, + const Sequence< Type > & rAddTypes ) + : _aTypes( 9 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + _aTypes[6] = rType7; + _aTypes[7] = rType8; + _aTypes[8] = rType9; + copy( _aTypes, rAddTypes, 9 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Type & rType7, + const Type & rType8, + const Type & rType9, + const Type & rType10, + const Sequence< Type > & rAddTypes ) + : _aTypes( 10 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + _aTypes[6] = rType7; + _aTypes[7] = rType8; + _aTypes[8] = rType9; + _aTypes[9] = rType10; + copy( _aTypes, rAddTypes, 10 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Type & rType7, + const Type & rType8, + const Type & rType9, + const Type & rType10, + const Type & rType11, + const Sequence< Type > & rAddTypes ) + : _aTypes( 11 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + _aTypes[6] = rType7; + _aTypes[7] = rType8; + _aTypes[8] = rType9; + _aTypes[9] = rType10; + _aTypes[10] = rType11; + copy( _aTypes, rAddTypes, 11 ); +} + +OTypeCollection::OTypeCollection( + const Type & rType1, + const Type & rType2, + const Type & rType3, + const Type & rType4, + const Type & rType5, + const Type & rType6, + const Type & rType7, + const Type & rType8, + const Type & rType9, + const Type & rType10, + const Type & rType11, + const Type & rType12, + const Sequence< Type > & rAddTypes ) + : _aTypes( 12 + rAddTypes.getLength() ) +{ + _aTypes[0] = rType1; + _aTypes[1] = rType2; + _aTypes[2] = rType3; + _aTypes[3] = rType4; + _aTypes[4] = rType5; + _aTypes[5] = rType6; + _aTypes[6] = rType7; + _aTypes[7] = rType8; + _aTypes[8] = rType9; + _aTypes[9] = rType10; + _aTypes[10] = rType11; + _aTypes[11] = rType12; + copy( _aTypes, rAddTypes, 12 ); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/unourl.cxx b/cppuhelper/source/unourl.cxx new file mode 100644 index 000000000..8ee7e593a --- /dev/null +++ b/cppuhelper/source/unourl.cxx @@ -0,0 +1,266 @@ +/* -*- 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 <cppuhelper/unourl.hxx> + +#include <rtl/malformeduriexception.hxx> +#include <rtl/string.h> +#include <rtl/textenc.h> +#include <rtl/uri.h> +#include <rtl/uri.hxx> +#include <rtl/ustring.hxx> +#include <rtl/character.hxx> +#include <sal/types.h> + +#include <map> +#include <memory> + +using cppu::UnoUrl; +using cppu::UnoUrlDescriptor; + +class UnoUrlDescriptor::Impl +{ +public: + typedef std::map< OUString, OUString > Parameters; + + OUString m_aDescriptor; + OUString m_aName; + Parameters m_aParameters; + + /** @exception rtl::MalformedUriException + */ + explicit inline Impl(OUString const & m_aDescriptor); + + Impl * clone() const { return new Impl(*this); } +}; + +inline UnoUrlDescriptor::Impl::Impl(OUString const & rDescriptor) +{ + m_aDescriptor = rDescriptor; + enum State { STATE_NAME0, STATE_NAME, STATE_KEY0, STATE_KEY, STATE_VALUE }; + State eState = STATE_NAME0; + sal_Int32 nStart = 0; + OUString aKey; + for (sal_Int32 i = 0;; ++i) + { + bool bEnd = i == rDescriptor.getLength(); + sal_Unicode c = bEnd ? 0 : rDescriptor[i]; + switch (eState) + { + case STATE_NAME0: + if (bEnd || !rtl::isAsciiAlphanumeric(c)) + throw rtl::MalformedUriException( + "UNO URL contains bad descriptor name"); + nStart = i; + eState = STATE_NAME; + break; + + case STATE_NAME: + if (bEnd || c == 0x2C) // ',' + { + m_aName + = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase(); + eState = STATE_KEY0; + } + else if (!rtl::isAsciiAlphanumeric(c)) + throw rtl::MalformedUriException( + "UNO URL contains bad descriptor name"); + break; + + case STATE_KEY0: + if (bEnd || !rtl::isAsciiAlphanumeric(c)) + throw rtl::MalformedUriException( + "UNO URL contains bad parameter key"); + nStart = i; + eState = STATE_KEY; + break; + + case STATE_KEY: + if (c == 0x3D) // '=' + { + aKey = rDescriptor.copy(nStart, i - nStart).toAsciiLowerCase(); + nStart = i + 1; + eState = STATE_VALUE; + } + else if (bEnd || !rtl::isAsciiAlphanumeric(c)) + throw rtl::MalformedUriException( + "UNO URL contains bad parameter key"); + break; + + case STATE_VALUE: + if (bEnd || c == 0x2C) // ',' + { + if (!m_aParameters.emplace( + aKey, + rtl::Uri::decode(rDescriptor.copy(nStart, + i - nStart), + rtl_UriDecodeWithCharset, + RTL_TEXTENCODING_UTF8)).second) + throw rtl::MalformedUriException( + "UNO URL contains duplicated parameter"); + eState = STATE_KEY0; + } + break; + } + if (bEnd) + break; + } +} + +UnoUrlDescriptor::UnoUrlDescriptor(OUString const & rDescriptor): + m_pImpl(new Impl(rDescriptor)) +{} + +UnoUrlDescriptor::UnoUrlDescriptor(UnoUrlDescriptor const & rOther): + m_pImpl(rOther.m_pImpl->clone()) +{} + +UnoUrlDescriptor::~UnoUrlDescriptor() +{ + delete m_pImpl; +} + +UnoUrlDescriptor & UnoUrlDescriptor::operator =(UnoUrlDescriptor const & rOther) +{ + if (this != &rOther) + { + std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone()); + delete m_pImpl; + m_pImpl = newImpl.release(); + } + return *this; +} + +OUString const & UnoUrlDescriptor::getDescriptor() const +{ + return m_pImpl->m_aDescriptor; +} + +OUString const & UnoUrlDescriptor::getName() const +{ + return m_pImpl->m_aName; +} + +bool UnoUrlDescriptor::hasParameter(OUString const & rKey) const +{ + return m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase()) + != m_pImpl->m_aParameters.end(); +} + +OUString UnoUrlDescriptor::getParameter(OUString const & rKey) const +{ + Impl::Parameters::const_iterator + aIt(m_pImpl->m_aParameters.find(rKey.toAsciiLowerCase())); + return aIt == m_pImpl->m_aParameters.end() ? OUString() : aIt->second; +} + +class UnoUrl::Impl +{ +public: + UnoUrlDescriptor m_aConnection; + UnoUrlDescriptor m_aProtocol; + OUString m_aObjectName; + + Impl * clone() const { return new Impl(*this); } + + /** @exception rtl::MalformedUriException + */ + static inline Impl * create(OUString const & rUrl); + +private: + Impl(OUString const & rConnectionDescriptor, + OUString const & rProtocolDescriptor, + OUString const & rObjectName): + m_aConnection(rConnectionDescriptor), + m_aProtocol(rProtocolDescriptor), + m_aObjectName(rObjectName) + {} +}; + +inline UnoUrl::Impl * UnoUrl::Impl::create(OUString const & rUrl) +{ + if (!rUrl.startsWithIgnoreAsciiCase("uno:")) + throw rtl::MalformedUriException("UNO URL does not start with \"uno:\""); + sal_Int32 i = RTL_CONSTASCII_LENGTH("uno:"); + sal_Int32 j = rUrl.indexOf(';', i); + if (j < 0) + throw rtl::MalformedUriException("UNO URL has too few semicolons"); + OUString aConnection(rUrl.copy(i, j - i)); + i = j + 1; + j = rUrl.indexOf(0x3B, i); // ';' + if (j < 0) + throw rtl::MalformedUriException("UNO URL has too few semicolons"); + OUString aProtocol(rUrl.copy(i, j - i)); + i = j + 1; + if (i == rUrl.getLength()) + throw rtl::MalformedUriException("UNO URL contains empty ObjectName"); + for (j = i; j < rUrl.getLength(); ++j) + { + sal_Unicode c = rUrl[j]; + if (!rtl::isAsciiAlphanumeric(c) && c != 0x21 && c != 0x24 // '!', '$' + && c != 0x26 && c != 0x27 && c != 0x28 // '&', ''', '(' + && c != 0x29 && c != 0x2A && c != 0x2B // ')', '*', '+' + && c != 0x2C && c != 0x2D && c != 0x2E // ',', '-', '.' + && c != 0x2F && c != 0x3A && c != 0x3D // '/', ':', '=' + && c != 0x3F && c != 0x40 && c != 0x5F // '?', '@', '_' + && c != 0x7E) // '~' + throw rtl::MalformedUriException("UNO URL contains invalid ObjectName"); + } + return new Impl(aConnection, aProtocol, rUrl.copy(i)); +} + +UnoUrl::UnoUrl(OUString const & rUrl): m_pImpl(Impl::create(rUrl)) +{} + +UnoUrl::UnoUrl(UnoUrl const & rOther): m_pImpl(rOther.m_pImpl->clone()) +{} + +UnoUrl::~UnoUrl() +{ + delete m_pImpl; +} + +UnoUrl & UnoUrl::operator =(UnoUrl const & rOther) +{ + if (this != &rOther) + { + std::unique_ptr<Impl> newImpl(rOther.m_pImpl->clone()); + delete m_pImpl; + m_pImpl = newImpl.release(); + } + return *this; +} + +UnoUrlDescriptor const & UnoUrl::getConnection() const +{ + return m_pImpl->m_aConnection; +} + +UnoUrlDescriptor const & UnoUrl::getProtocol() const +{ + return m_pImpl->m_aProtocol; +} + +OUString const & UnoUrl::getObjectName() const +{ + return m_pImpl->m_aObjectName; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/weak.cxx b/cppuhelper/source/weak.cxx new file mode 100644 index 000000000..a11e52bbb --- /dev/null +++ b/cppuhelper/source/weak.cxx @@ -0,0 +1,530 @@ +/* -*- 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 <sal/log.hxx> + +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <cppuhelper/weakagg.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <cppuhelper/queryinterface.hxx> + +#include <com/sun/star/lang/DisposedException.hpp> + +#include <algorithm> +#include <vector> + +using namespace osl; +using namespace com::sun::star::uno; + +/** */ //for docpp +namespace cppu +{ + +// due to static Reflection destruction from usr, there must be a mutex leak (#73272#) +// this is used to lock all instances of OWeakConnectionPoint and OWeakRefListener as well as OWeakObject::m_pWeakConnectionPoint +static Mutex & getWeakMutex() +{ + static Mutex * s_pMutex = new Mutex(); + return *s_pMutex; +} + + +//-- OWeakConnectionPoint ---------------------------------------------------- + +class OWeakConnectionPoint: public XAdapter +{ +public: + /** + Hold the weak object without an acquire (only the pointer). + */ + explicit OWeakConnectionPoint( OWeakObject* pObj ) + : m_aRefCount( 0 ) + , m_pObject(pObj) + {} + + // noncopyable + OWeakConnectionPoint(const OWeakConnectionPoint&) = delete; + const OWeakConnectionPoint& operator=(const OWeakConnectionPoint&) = delete; + + // XInterface + Any SAL_CALL queryInterface( const Type & rType ) override; + void SAL_CALL acquire() throw() override; + void SAL_CALL release() throw() override; + + // XAdapter + css::uno::Reference< css::uno::XInterface > SAL_CALL queryAdapted() override; + void SAL_CALL addReference( const css::uno::Reference< css::uno::XReference >& xRef ) override; + void SAL_CALL removeReference( const css::uno::Reference< css::uno::XReference >& xRef ) override; + + /// Called from the weak object if the reference count goes to zero. + /// + /// @throws css::uno::RuntimeException + void dispose(); + +private: + virtual ~OWeakConnectionPoint() {} + + /// The reference counter. + oslInterlockedCount m_aRefCount; + /// The weak object + OWeakObject* m_pObject; + /// The container to hold the weak references + std::vector<Reference<XReference>> m_aReferences; +}; + +// XInterface +Any SAL_CALL OWeakConnectionPoint::queryInterface( const Type & rType ) +{ + return ::cppu::queryInterface( + rType, static_cast< XAdapter * >( this ), static_cast< XInterface * >( this ) ); +} + +// XInterface +void SAL_CALL OWeakConnectionPoint::acquire() throw() +{ + osl_atomic_increment( &m_aRefCount ); +} + +// XInterface +void SAL_CALL OWeakConnectionPoint::release() throw() +{ + if (! osl_atomic_decrement( &m_aRefCount )) + delete this; +} + +void OWeakConnectionPoint::dispose() +{ + std::vector<Reference<XReference>> aCopy; + { // only hold the mutex while we access the field + MutexGuard aGuard(getWeakMutex()); + // OWeakObject is not the only owner of this, so clear m_pObject + // so that queryAdapted() won't use it now that it's dead + m_pObject = nullptr; + // other code is going to call removeReference while we are doing this, so we need a + // copy, but since we are disposing and going away, we can just take the original data + aCopy.swap(m_aReferences); + } + Any ex; + for (const Reference<XReference> & i : aCopy ) + { + try + { + i->dispose(); + } + catch (css::lang::DisposedException &) {} + catch (RuntimeException &) + { + ex = cppu::getCaughtException(); + } + } + if (ex.hasValue()) + { + cppu::throwException(ex); + } +} + +// XInterface +Reference< XInterface > SAL_CALL OWeakConnectionPoint::queryAdapted() +{ + Reference< XInterface > ret; + + ClearableMutexGuard guard(getWeakMutex()); + + if (m_pObject) + { + oslInterlockedCount n = osl_atomic_increment( &m_pObject->m_refCount ); + + if (n > 1) + { + // The reference is incremented. The object cannot be destroyed. + // Release the guard at the earliest point. + guard.clear(); + // WeakObject has a (XInterface *) cast operator + ret = *m_pObject; + osl_atomic_decrement( &m_pObject->m_refCount ); + } + else + // Another thread wait in the dispose method at the guard + osl_atomic_decrement( &m_pObject->m_refCount ); + } + + return ret; +} + +// XInterface +void SAL_CALL OWeakConnectionPoint::addReference(const Reference< XReference >& rRef) +{ + MutexGuard aGuard(getWeakMutex()); + m_aReferences.push_back( rRef ); +} + +// XInterface +void SAL_CALL OWeakConnectionPoint::removeReference(const Reference< XReference >& rRef) +{ + MutexGuard aGuard(getWeakMutex()); + // Search from end because the thing that last added a ref is most likely to be the + // first to remove a ref. + // It's not really valid to compare the pointer directly, but it's faster. + auto it = std::find_if(m_aReferences.rbegin(), m_aReferences.rend(), + [&rRef](const Reference<XReference>& rxRef) { return rxRef.get() == rRef.get(); }); + if (it != m_aReferences.rend()) { + m_aReferences.erase( it.base()-1 ); + return; + } + // interface not found, use the correct compare method + it = std::find(m_aReferences.rbegin(), m_aReferences.rend(), rRef); + if ( it != m_aReferences.rend() ) + m_aReferences.erase( it.base()-1 ); +} + + +//-- OWeakObject ------------------------------------------------------- + + +#ifdef _MSC_VER +// Accidentally occurs in msvc mapfile = > had to be outlined. +OWeakObject::OWeakObject() + : m_refCount( 0 ), + m_pWeakConnectionPoint( nullptr ) +{ +} +#endif + +// XInterface +Any SAL_CALL OWeakObject::queryInterface( const Type & rType ) +{ + return ::cppu::queryInterface( + rType, + static_cast< XWeak * >( this ), static_cast< XInterface * >( this ) ); +} + +// XInterface +void SAL_CALL OWeakObject::acquire() throw() +{ + osl_atomic_increment( &m_refCount ); +} + +// XInterface +void SAL_CALL OWeakObject::release() throw() +{ + if (osl_atomic_decrement( &m_refCount ) == 0) { + // notify/clear all weak-refs before object's dtor is executed + // (which may check weak-refs to this object): + disposeWeakConnectionPoint(); + // destroy object: + delete this; + } +} + +void OWeakObject::disposeWeakConnectionPoint() +{ + OSL_PRECOND( m_refCount == 0, "OWeakObject::disposeWeakConnectionPoint: only to be called with a ref count of 0!" ); + if (m_pWeakConnectionPoint != nullptr) { + OWeakConnectionPoint * const p = m_pWeakConnectionPoint; + m_pWeakConnectionPoint = nullptr; + try { + p->dispose(); + } + catch (RuntimeException const& exc) { + SAL_WARN( "cppuhelper", exc ); + } + p->release(); + } +} + +OWeakObject::~OWeakObject() COVERITY_NOEXCEPT_FALSE +{ +} + +// XWeak +Reference< XAdapter > SAL_CALL OWeakObject::queryAdapter() +{ + if (!m_pWeakConnectionPoint) + { + // only acquire mutex if member is not created + MutexGuard aGuard( getWeakMutex() ); + if( !m_pWeakConnectionPoint ) + { + OWeakConnectionPoint * p = new OWeakConnectionPoint(this); + p->acquire(); + m_pWeakConnectionPoint = p; + } + } + + return m_pWeakConnectionPoint; +} + + +//-- OWeakAggObject ---------------------------------------------------- + +OWeakAggObject::~OWeakAggObject() +{ +} + +// XInterface +void OWeakAggObject::acquire() throw() +{ + Reference<XInterface > x( xDelegator ); + if (x.is()) + x->acquire(); + else + OWeakObject::acquire(); +} + +// XInterface +void OWeakAggObject::release() throw() +{ + Reference<XInterface > x( xDelegator ); + if (x.is()) + x->release(); + else + OWeakObject::release(); +} + +// XInterface +Any OWeakAggObject::queryInterface( const Type & rType ) +{ + Reference< XInterface > x( xDelegator ); // harden ref + return (x.is() ? x->queryInterface( rType ) : queryAggregation( rType )); +} + +// XAggregation +Any OWeakAggObject::queryAggregation( const Type & rType ) +{ + return ::cppu::queryInterface( + rType, + static_cast< XInterface * >( static_cast< OWeakObject * >( this ) ), + static_cast< XAggregation * >( this ), + static_cast< XWeak * >( this ) ); +} + +// XAggregation +void OWeakAggObject::setDelegator( const Reference<XInterface > & rDelegator ) +{ + xDelegator = rDelegator; +} + +} + +/** */ //for docpp +namespace com::sun::star::uno +{ + + +//-- OWeakRefListener ----------------------------------------------------- + +class OWeakRefListener final : public XReference +{ +public: + explicit OWeakRefListener(const Reference< XInterface >& xInt); + virtual ~OWeakRefListener(); + + // noncopyable + OWeakRefListener(const OWeakRefListener&) = delete; + const OWeakRefListener& operator=(const OWeakRefListener&) = delete; + + // XInterface + Any SAL_CALL queryInterface( const Type & rType ) override; + void SAL_CALL acquire() throw() override; + void SAL_CALL release() throw() override; + + // XReference + void SAL_CALL dispose() override; + + /// The reference counter. + oslInterlockedCount m_aRefCount; + /// The connection point of the weak object, guarded by getWeakMutex() + Reference< XAdapter > m_XWeakConnectionPoint; +}; + +OWeakRefListener::OWeakRefListener(const Reference< XInterface >& xInt) + : m_aRefCount( 1 ) +{ + try + { + Reference< XWeak > xWeak( Reference< XWeak >::query( xInt ) ); + + if (xWeak.is()) + { + m_XWeakConnectionPoint = xWeak->queryAdapter(); + + if (m_XWeakConnectionPoint.is()) + { + m_XWeakConnectionPoint->addReference(static_cast<XReference*>(this)); + } + } + } + catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected() + osl_atomic_decrement( &m_aRefCount ); +} + +OWeakRefListener::~OWeakRefListener() +{ + try + { + if (m_XWeakConnectionPoint.is()) + { + acquire(); // don't die again + m_XWeakConnectionPoint->removeReference(static_cast<XReference*>(this)); + } + } + catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected() +} + +// XInterface +Any SAL_CALL OWeakRefListener::queryInterface( const Type & rType ) +{ + return ::cppu::queryInterface( + rType, static_cast< XReference * >( this ), static_cast< XInterface * >( this ) ); +} + +// XInterface +void SAL_CALL OWeakRefListener::acquire() throw() +{ + osl_atomic_increment( &m_aRefCount ); +} + +// XInterface +void SAL_CALL OWeakRefListener::release() throw() +{ + if( ! osl_atomic_decrement( &m_aRefCount ) ) + delete this; +} + +void SAL_CALL OWeakRefListener::dispose() +{ + Reference< XAdapter > xAdp; + { + MutexGuard guard(cppu::getWeakMutex()); + if( m_XWeakConnectionPoint.is() ) + { + xAdp = m_XWeakConnectionPoint; + m_XWeakConnectionPoint.clear(); + } + } + + if( xAdp.is() ) + xAdp->removeReference(static_cast<XReference*>(this)); +} + + +//-- WeakReferenceHelper ---------------------------------------------------------- + +WeakReferenceHelper::WeakReferenceHelper(const Reference< XInterface >& xInt) + : m_pImpl( nullptr ) +{ + if (xInt.is()) + { + m_pImpl = new OWeakRefListener(xInt); + m_pImpl->acquire(); + } +} + +WeakReferenceHelper::WeakReferenceHelper(const WeakReferenceHelper& rWeakRef) + : m_pImpl( nullptr ) +{ + Reference< XInterface > xInt( rWeakRef.get() ); + if (xInt.is()) + { + m_pImpl = new OWeakRefListener(xInt); + m_pImpl->acquire(); + } +} + +void WeakReferenceHelper::clear() +{ + try + { + if (m_pImpl) + { + m_pImpl->dispose(); + m_pImpl->release(); + m_pImpl = nullptr; + } + } + catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected() +} + +WeakReferenceHelper& WeakReferenceHelper::operator=(const WeakReferenceHelper& rWeakRef) +{ + if (this == &rWeakRef) + { + return *this; + } + Reference< XInterface > xInt( rWeakRef.get() ); + return operator = ( xInt ); +} + +WeakReferenceHelper & WeakReferenceHelper::operator =( + WeakReferenceHelper && other) +{ + clear(); + std::swap(m_pImpl, other.m_pImpl); + return *this; +} + +WeakReferenceHelper & SAL_CALL +WeakReferenceHelper::operator= (const Reference< XInterface > & xInt) +{ + try + { + clear(); + if (xInt.is()) + { + m_pImpl = new OWeakRefListener(xInt); + m_pImpl->acquire(); + } + } + catch (RuntimeException &) { OSL_ASSERT( false ); } // assert here, but no unexpected() + return *this; +} + +WeakReferenceHelper::~WeakReferenceHelper() +{ + clear(); +} + +Reference< XInterface > WeakReferenceHelper::get() const +{ + try + { + Reference< XAdapter > xAdp; + { + // must lock to access m_XWeakConnectionPoint + MutexGuard guard(cppu::getWeakMutex()); + if( m_pImpl && m_pImpl->m_XWeakConnectionPoint.is() ) + xAdp = m_pImpl->m_XWeakConnectionPoint; + } + + if (xAdp.is()) + return xAdp->queryAdapted(); + } + catch (RuntimeException &) + { + OSL_ASSERT( false ); + } // assert here, but no unexpected() + + return Reference< XInterface >(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/unotypes/cppuhelper/detail/XExceptionThrower.idl b/cppuhelper/unotypes/cppuhelper/detail/XExceptionThrower.idl new file mode 100644 index 000000000..23baea7e5 --- /dev/null +++ b/cppuhelper/unotypes/cppuhelper/detail/XExceptionThrower.idl @@ -0,0 +1,41 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_cppuhelper_detail_XExceptionThrower_idl +#define INCLUDED_cppuhelper_detail_XExceptionThrower_idl + +#include <com/sun/star/uno/Exception.idl> +#include <com/sun/star/uno/XInterface.idl> + + +module cppuhelper { module detail { + +interface XExceptionThrower : com::sun::star::uno::XInterface +{ + void throwException( [in] any exc ) + raises (com::sun::star::uno::Exception); + void rethrowException() + raises (com::sun::star::uno::Exception); +}; + +}; }; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cpputools/Executable_sp2bv.mk b/cpputools/Executable_sp2bv.mk new file mode 100644 index 000000000..9ebbfaf3d --- /dev/null +++ b/cpputools/Executable_sp2bv.mk @@ -0,0 +1,26 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Executable_Executable,sp2bv)) + +$(eval $(call gb_Executable_use_api,sp2bv,\ + udkapi \ +)) + +$(eval $(call gb_Executable_use_libraries,sp2bv,\ + cppu \ + cppuhelper \ + sal \ +)) + +$(eval $(call gb_Executable_add_exception_objects,sp2bv,\ + cpputools/source/sp2bv/sp2bv \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/cpputools/Executable_uno.mk b/cpputools/Executable_uno.mk new file mode 100644 index 000000000..ba3b22fb6 --- /dev/null +++ b/cpputools/Executable_uno.mk @@ -0,0 +1,33 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Executable_Executable,uno)) + +$(eval $(call gb_Executable_use_internal_comprehensive_api,uno,\ + udkapi \ +)) + +$(eval $(call gb_Executable_use_libraries,uno,\ + cppu \ + cppuhelper \ + sal \ + salhelper \ +)) + +$(eval $(call gb_Executable_use_externals,uno,\ + libxml2 \ +)) + +$(eval $(call gb_Executable_add_exception_objects,uno,\ + cpputools/source/unoexe/unoexe \ +)) + +$(eval $(call gb_Executable_add_default_nativeres,uno)) + +# vim:set noet sw=4 ts=4: diff --git a/cpputools/Makefile b/cpputools/Makefile new file mode 100644 index 000000000..ccb1c85a0 --- /dev/null +++ b/cpputools/Makefile @@ -0,0 +1,7 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/cpputools/Module_cpputools.mk b/cpputools/Module_cpputools.mk new file mode 100644 index 000000000..5807e3c81 --- /dev/null +++ b/cpputools/Module_cpputools.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# 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/. +# + +$(eval $(call gb_Module_Module,cpputools)) + +ifneq (,$(filter DESKTOP,$(BUILD_TYPE))) + +$(eval $(call gb_Module_add_targets,cpputools,\ + Executable_sp2bv \ +)) + +$(eval $(call gb_Module_add_targets,cpputools,\ + Executable_uno \ +)) + +endif + +# vim:set noet sw=4 ts=4: diff --git a/cpputools/README b/cpputools/README new file mode 100644 index 000000000..9652827ca --- /dev/null +++ b/cpputools/README @@ -0,0 +1 @@ +Old way of doing component registration. Nowadays replaced by another stand-alone UI and tools called UNO package. diff --git a/cpputools/source/sp2bv/readme.txt b/cpputools/source/sp2bv/readme.txt new file mode 100644 index 000000000..f83b442c8 --- /dev/null +++ b/cpputools/source/sp2bv/readme.txt @@ -0,0 +1,8 @@ +This tool converts system paths into file urls and escapes it for use as +bootstrap variable. For example + +c:\program files\App$ +-> +file:///c:/program%20files/App$ +-> +file:///c:/program%20files/App\$ diff --git a/cpputools/source/sp2bv/sp2bv.cxx b/cpputools/source/sp2bv/sp2bv.cxx new file mode 100644 index 000000000..5af582002 --- /dev/null +++ b/cpputools/source/sp2bv/sp2bv.cxx @@ -0,0 +1,124 @@ +/* -*- 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <osl/thread.h> +#include <osl/file.h> +#include <rtl/ustring.hxx> +#include <rtl/ustrbuf.h> + +static bool hasOption(char const * szOption, int argc, char** argv); + + +#define HELP_TEXT \ +"SYNOPSIS \n\n" \ +"\tsp2bv [-h] [-?] string \n\n" \ +"DESCRIPTION\n\n" \ +"\tsp2bv stands for \"system path to bootstrap variable\"." \ +" First the system path is converted into a file URL. Then all " \ +"characters which have a special meaning in bootstrap variables, " \ +"such as \'$\' are escaped. The resulting string is written to " \ +"stdout and can be assigned to a bootstrap variable.\n" \ +"\n\n" \ +"OPTIONS \n\n" \ +"\tThe following options are supported: \n" \ +"-?\n " \ +"--help" \ +" Display help information.\n" + + +int main(int argc, char **argv) +{ + if( hasOption("--help",argc, argv) || hasOption("-h", argc, argv)) + { + fprintf(stdout, HELP_TEXT);// default + return 0; + } + + if (argc != 2) + { + fprintf(stdout, HELP_TEXT); + return -1; + } + + rtl_uString* pPath = nullptr; + rtl_string2UString( &pPath, argv[1], strlen(argv[1]), + osl_getThreadTextEncoding(),OSTRING_TO_OUSTRING_CVTFLAGS ); + + rtl_uString* pUrl = nullptr; + if (osl_getFileURLFromSystemPath(pPath, &pUrl) != osl_File_E_None) + return -1; +//escape the special characters + + sal_Unicode cEscapeChar = 0x5c; + rtl_uString* pBuffer = nullptr; + sal_Int32 nCapacity = 255; + rtl_uString_new_WithLength( &pBuffer, nCapacity ); + + const sal_Unicode* pCur = pUrl->buffer; + for (int i = 0; i != pUrl->length; i++) + { + switch( *pCur) + { + case '$': + rtl_uStringbuffer_insert( &pBuffer, &nCapacity, pBuffer->length, &cEscapeChar, 1); + rtl_uStringbuffer_insert( &pBuffer, &nCapacity, pBuffer->length, pCur, 1); + break; + case '{': + case '}': + case '\\': fprintf(stderr, "sp2vb: file URL contains invalid characters!\n"); + return -1; + default: + rtl_uStringbuffer_insert( &pBuffer, &nCapacity, pBuffer->length, pCur, 1); + } + pCur ++; + } +//convert back to byte string so that we can print it. + rtl_String* pBootVar = nullptr; + rtl_uString2String( &pBootVar, pBuffer->buffer, pBuffer->length, + osl_getThreadTextEncoding(), OUSTRING_TO_OSTRING_CVTFLAGS); + + fprintf(stdout, "%s", pBootVar->buffer); + fflush(stdout); + + rtl_uString_release(pBuffer); + rtl_uString_release(pPath); + rtl_uString_release(pUrl); + rtl_string_release(pBootVar); + return 0; +} + + +static bool hasOption(char const * szOption, int argc, char** argv) +{ + bool retVal = false; + for(int i= 1; i < argc; i++) + { + if( ! strcmp(argv[i], szOption)) + { + retVal = true; + break; + } + } + return retVal; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cpputools/source/unoexe/unoexe.cxx b/cpputools/source/unoexe/unoexe.cxx new file mode 100644 index 000000000..70a058039 --- /dev/null +++ b/cpputools/source/unoexe/unoexe.cxx @@ -0,0 +1,544 @@ +/* -*- 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 <stdio.h> + +#include <sal/main.h> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> +#include <osl/conditn.hxx> + +#include <rtl/process.h> +#include <rtl/string.h> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> + +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/lang/XMain.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/loader/XImplementationLoader.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/connection/Acceptor.hpp> +#include <com/sun/star/connection/XConnection.hpp> +#include <com/sun/star/bridge/XBridgeFactory.hpp> +#include <com/sun/star/bridge/XBridge.hpp> + +using namespace std; +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::loader; +using namespace com::sun::star::registry; +using namespace com::sun::star::connection; +using namespace com::sun::star::bridge; +using namespace com::sun::star::container; + +namespace unoexe +{ + +static bool s_quiet = false; + +static void out( const char * pText ) +{ + if (! s_quiet) + fprintf( stderr, "%s", pText ); +} + +static void out( const OUString & rText ) +{ + if (! s_quiet) + { + OString aText( OUStringToOString( rText, RTL_TEXTENCODING_ASCII_US ) ); + fprintf( stderr, "%s", aText.getStr() ); + } +} + +static const char arUsingText[] = +"\nusing:\n\n" +"uno [-c ComponentImplementationName -l LocationUrl | -s ServiceName]\n" +" [-u uno:(socket[,host=HostName][,port=nnn]|pipe[,name=PipeName]);<protocol>;Name\n" +" [--singleaccept] [--singleinstance]]\n" +" [--quiet]\n" +" [-- Argument1 Argument2 ...]\n"; + +/// @throws RuntimeException +static bool readOption( OUString * pValue, const char * pOpt, + sal_uInt32 * pnIndex, const OUString & aArg) +{ + const OUString dash("-"); + if(!aArg.startsWith(dash)) + return false; + + OUString aOpt = OUString::createFromAscii( pOpt ); + + if (aArg.getLength() < aOpt.getLength()) + return false; + + if (aOpt.equalsIgnoreAsciiCase( aArg.copy(1) )) + { + // take next argument + ++(*pnIndex); + + rtl_getAppCommandArg(*pnIndex, &pValue->pData); + if (*pnIndex >= rtl_getAppCommandArgCount() || pValue->copy(1) == dash) + { + throw RuntimeException( "incomplete option \"-" + aOpt + "\" given!" ); + } + SAL_INFO("cpputools.unoexe", "> identified option -" << pOpt << " = " << aArg); + ++(*pnIndex); + return true; + } + else if (aArg.indexOf(aOpt) == 1) + { + *pValue = aArg.copy(1 + aOpt.getLength()); + SAL_INFO("cpputools.unoexe", "> identified option -" << pOpt << " = " << aArg); + ++(*pnIndex); + + return true; + } + return false; +} + +static bool readOption( bool * pbOpt, const char * pOpt, + sal_uInt32 * pnIndex, const OUString & aArg) +{ + OUString aOpt = OUString::createFromAscii(pOpt); + + if(aArg.startsWith("--") && aOpt == aArg.copy(2)) + { + ++(*pnIndex); + *pbOpt = true; + SAL_INFO("cpputools.unoexe", "> identified option --" << pOpt); + return true; + } + return false; +} + +/// @throws Exception +template< class T > +static void createInstance( + Reference< T > & rxOut, + const Reference< XComponentContext > & xContext, + const OUString & rServiceName ) +{ + Reference< XMultiComponentFactory > xMgr( xContext->getServiceManager() ); + Reference< XInterface > x( xMgr->createInstanceWithContext( rServiceName, xContext ) ); + + if (! x.is()) + { + throw RuntimeException( "cannot get service instance \"" + rServiceName + "\"!" ); + } + + rxOut.set( x.get(), UNO_QUERY_THROW ); +} + +/// @throws Exception +static Reference< XInterface > loadComponent( + const Reference< XComponentContext > & xContext, + const OUString & rImplName, const OUString & rLocation ) +{ + // determine loader to be used + sal_Int32 nDot = rLocation.lastIndexOf( '.' ); + if (nDot <= 0 || nDot >= rLocation.getLength()) + { + throw RuntimeException( + "location \"" + rLocation + "\" has no extension! Cannot determine loader to be used!" ); + } + + Reference< XImplementationLoader > xLoader; + + OUString aExt( rLocation.copy( nDot +1 ) ); + + if (aExt == "dll" || aExt == "exe" || aExt == "dylib" || aExt == "so") + { + createInstance( + xLoader, xContext, "com.sun.star.loader.SharedLibrary" ); + } + else if (aExt == "jar" || aExt == "class") + { + createInstance( + xLoader, xContext, "com.sun.star.loader.Java" ); + } + else + { + throw RuntimeException( + "unknown extension of \"" + rLocation + "\"! No loader available!" ); + } + + Reference< XInterface > xInstance; + + // activate + Reference< XInterface > xFactory( xLoader->activate( + rImplName, OUString(), rLocation, Reference< XRegistryKey >() ) ); + if (xFactory.is()) + { + Reference< XSingleComponentFactory > xCFac( xFactory, UNO_QUERY ); + if (xCFac.is()) + { + xInstance = xCFac->createInstanceWithContext( xContext ); + } + else + { + Reference< XSingleServiceFactory > xSFac( xFactory, UNO_QUERY ); + if (xSFac.is()) + { + out( "\n> warning: ignoring context for implementation \"" ); + out( rImplName ); + out( "\"!" ); + xInstance = xSFac->createInstance(); + } + } + } + + if (! xInstance.is()) + { + throw RuntimeException( + "activating component \"" + rImplName + "\" from location \"" + rLocation + "\" failed!" ); + } + + return xInstance; +} + +namespace { + +class OInstanceProvider + : public WeakImplHelper< XInstanceProvider > +{ + Reference< XComponentContext > _xContext; + + Mutex _aSingleInstanceMutex; + Reference< XInterface > _xSingleInstance; + bool _bSingleInstance; + + OUString _aImplName; + OUString _aLocation; + OUString _aServiceName; + Sequence< Any > _aInitParams; + + OUString _aInstanceName; + + /// @throws Exception + inline Reference< XInterface > createInstance(); + +public: + OInstanceProvider( const Reference< XComponentContext > & xContext, + const OUString & rImplName, const OUString & rLocation, + const OUString & rServiceName, const Sequence< Any > & rInitParams, + bool bSingleInstance, const OUString & rInstanceName ) + : _xContext( xContext ) + , _bSingleInstance( bSingleInstance ) + , _aImplName( rImplName ) + , _aLocation( rLocation ) + , _aServiceName( rServiceName ) + , _aInitParams( rInitParams ) + , _aInstanceName( rInstanceName ) + {} + + // XInstanceProvider + virtual Reference< XInterface > SAL_CALL getInstance( const OUString & rName ) override; +}; + +} + +inline Reference< XInterface > OInstanceProvider::createInstance() +{ + Reference< XInterface > xRet; + if (!_aImplName.isEmpty()) // manually via loader + xRet = loadComponent( _xContext, _aImplName, _aLocation ); + else // via service manager + unoexe::createInstance( xRet, _xContext, _aServiceName ); + + // opt XInit + Reference< XInitialization > xInit( xRet, UNO_QUERY ); + if (xInit.is()) + xInit->initialize( _aInitParams ); + + return xRet; +} + +Reference< XInterface > OInstanceProvider::getInstance( const OUString & rName ) +{ + try + { + if (_aInstanceName == rName) + { + Reference< XInterface > xRet; + + if (_aImplName.isEmpty() && _aServiceName.isEmpty()) + { + OSL_ASSERT( rName == "uno.ComponentContext" ); + xRet = _xContext; + } + else if (_bSingleInstance) + { + if (! _xSingleInstance.is()) + { + MutexGuard aGuard( _aSingleInstanceMutex ); + if (! _xSingleInstance.is()) + { + _xSingleInstance = createInstance(); + } + } + xRet = _xSingleInstance; + } + else + { + xRet = createInstance(); + } + + return xRet; + } + } + catch (Exception & rExc) + { + out( "\n> error: " ); + out( rExc.Message ); + } + throw NoSuchElementException( + "no such element \"" + rName + "\"!" ); +} + +namespace { + +struct ODisposingListener : public WeakImplHelper< XEventListener > +{ + Condition cDisposed; + + // XEventListener + virtual void SAL_CALL disposing( const EventObject & rEvt ) override; + + static void waitFor( const Reference< XComponent > & xComp ); +}; + +} + +void ODisposingListener::disposing( const EventObject & ) +{ + cDisposed.set(); +} + +void ODisposingListener::waitFor( const Reference< XComponent > & xComp ) +{ + ODisposingListener * pListener = new ODisposingListener; + Reference< XEventListener > xListener( pListener ); + + xComp->addEventListener( xListener ); + pListener->cDisposed.wait(); +} + +} // namespace unoexe + +using namespace unoexe; + +SAL_IMPLEMENT_MAIN() +{ + sal_uInt32 nCount = rtl_getAppCommandArgCount(); + if (nCount == 0) + { + out( arUsingText ); + return 0; + } + + sal_Int32 nRet = 0; + Reference< XComponentContext > xContext; + + + try + { + OUString aImplName, aLocation, aServiceName, aUnoUrl; + Sequence< OUString > aParams; + bool bSingleAccept = false; + bool bSingleInstance = false; + + // read command line arguments + + sal_uInt32 nPos = 0; + // read up to arguments + while (nPos < nCount) + { + OUString arg; + + rtl_getAppCommandArg(nPos, &arg.pData); + + if (arg == "--") + { + ++nPos; + break; + } + + if (!(readOption( &aImplName, "c", &nPos, arg) || + readOption( &aLocation, "l", &nPos, arg) || + readOption( &aServiceName, "s", &nPos, arg) || + readOption( &aUnoUrl, "u", &nPos, arg) || + readOption( &s_quiet, "quiet", &nPos, arg) || + readOption( &bSingleAccept, "singleaccept", &nPos, arg) || + readOption( &bSingleInstance, "singleinstance", &nPos, arg))) + { + throw RuntimeException( + "unexpected argument \"" + arg + "\"" ); + } + } + + if (!(aImplName.isEmpty() || aServiceName.isEmpty())) + throw RuntimeException("give component exOR service name!" ); + if (aImplName.isEmpty() && aServiceName.isEmpty()) + { + if (! aUnoUrl.endsWithIgnoreAsciiCase( ";uno.ComponentContext" )) + throw RuntimeException( + "expected UNO-URL with instance name uno.ComponentContext!" ); + if (bSingleInstance) + throw RuntimeException( + "unexpected option --singleinstance!" ); + } + if (!aImplName.isEmpty() && aLocation.isEmpty()) + throw RuntimeException("give component location!" ); + if (!aServiceName.isEmpty() && !aLocation.isEmpty()) + out( "\n> warning: service name given, will ignore location!" ); + + // read component params + aParams.realloc( nCount - nPos ); + OUString * pParams = aParams.getArray(); + + sal_uInt32 nOffset = nPos; + for ( ; nPos < nCount; ++nPos ) + { + rtl_getAppCommandArg( nPos, &pParams[nPos -nOffset].pData ); + } + + xContext = defaultBootstrap_InitialComponentContext(); + + // accept, instantiate, etc. + + if (!aUnoUrl.isEmpty()) // accepting connections + { + if (aUnoUrl.getLength() < 10 || !aUnoUrl.startsWithIgnoreAsciiCase( "uno:" )) + { + throw RuntimeException("illegal uno url given!" ); + } + + sal_Int32 nIndex = 4; // skip initial "uno:" + bool bTooFewTokens {false}; + const OUString aConnectDescr{ aUnoUrl.getToken( 0, ';', nIndex ) }; // uno:CONNECTDESCR;iiop;InstanceName + if (nIndex<0) bTooFewTokens = true; + const OUString aUnoUrlToken{ aUnoUrl.getToken( 0, ';', nIndex ) }; + if (nIndex<0) bTooFewTokens = true; + const OUString aInstanceName{ aUnoUrl.getToken( 0, ';', nIndex ) }; + + // Exactly 3 tokens are required + if (bTooFewTokens || nIndex>0) + { + throw RuntimeException("illegal uno url given!" ); + } + + Reference< XAcceptor > xAcceptor = Acceptor::create(xContext); + + // init params + Sequence< Any > aInitParams( aParams.getLength() ); + const OUString * p = aParams.getConstArray(); + Any * pInitParams = aInitParams.getArray(); + for ( sal_Int32 i = aParams.getLength(); i--; ) + { + pInitParams[i] <<= p[i]; + } + + // instance provider + Reference< XInstanceProvider > xInstanceProvider( new OInstanceProvider( + xContext, aImplName, aLocation, aServiceName, aInitParams, + bSingleInstance, aInstanceName ) ); + + // coverity[loop_top] - not really an infinite loop, we can be instructed to exit via the connection + for (;;) + { + // accepting + out( "\n> accepting " ); + out( aConnectDescr ); + out( "..." ); + Reference< XConnection > xConnection( xAcceptor->accept( aConnectDescr ) ); + out( "connection established." ); + + Reference< XBridgeFactory > xBridgeFactory; + createInstance( + xBridgeFactory, xContext, + "com.sun.star.bridge.BridgeFactory" ); + + // bridge + Reference< XBridge > xBridge( xBridgeFactory->createBridge( + OUString(), aUnoUrlToken, + xConnection, xInstanceProvider ) ); + + if (bSingleAccept) + { + Reference< XComponent > xComp( xBridge, UNO_QUERY_THROW ); + ODisposingListener::waitFor( xComp ); + xComp->dispose(); + // explicitly dispose the remote bridge so that it joins + // on all spawned threads before process exit (see + // binaryurp/source/bridge.cxx for details) + break; + } + } + } + else // no uno url + { + Reference< XInterface > xInstance; + if (!aImplName.isEmpty()) // manually via loader + xInstance = loadComponent( xContext, aImplName, aLocation ); + else // via service manager + createInstance( xInstance, xContext, aServiceName ); + + // execution + Reference< XMain > xMain( xInstance, UNO_QUERY ); + if (xMain.is()) + { + nRet = xMain->run( aParams ); + } + else + { + Reference< XComponent > xComp( xInstance, UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); + throw RuntimeException( "component does not export interface \"com.sun.star.lang.XMain\"!" ); + } + } + } + catch (Exception & rExc) + { + out( "\n> error: " ); + out( rExc.Message ); + out( "\n> dying..." ); + nRet = 1; + } + + // cleanup + Reference< XComponent > xComp( xContext, UNO_QUERY ); + if (xComp.is()) + xComp->dispose(); + + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |