summaryrefslogtreecommitdiffstats
path: root/stoc
diff options
context:
space:
mode:
Diffstat (limited to 'stoc')
-rw-r--r--stoc/CppunitTest_stoc_dump.mk33
-rw-r--r--stoc/CppunitTest_stoc_uriproc.mk32
-rw-r--r--stoc/IwyuFilter_stoc.yaml47
-rw-r--r--stoc/Library_bootstrap.mk50
-rw-r--r--stoc/Library_introspection.mk29
-rw-r--r--stoc/Library_invocadapt.mk28
-rw-r--r--stoc/Library_invocation.mk28
-rw-r--r--stoc/Library_javaloader.mk30
-rw-r--r--stoc/Library_javavm.mk40
-rw-r--r--stoc/Library_namingservice.mk28
-rw-r--r--stoc/Library_proxyfac.mk26
-rw-r--r--stoc/Library_reflection.mk34
-rw-r--r--stoc/Library_stocservices.mk34
-rw-r--r--stoc/Makefile7
-rw-r--r--stoc/Module_stoc.mk37
-rw-r--r--stoc/README.md39
-rw-r--r--stoc/source/corereflection/base.hxx406
-rw-r--r--stoc/source/corereflection/crarray.cxx166
-rw-r--r--stoc/source/corereflection/crbase.cxx250
-rw-r--r--stoc/source/corereflection/crcomp.cxx310
-rw-r--r--stoc/source/corereflection/crefl.cxx333
-rw-r--r--stoc/source/corereflection/crenum.cxx158
-rw-r--r--stoc/source/corereflection/criface.cxx830
-rw-r--r--stoc/source/corereflection/dump.cxx358
-rw-r--r--stoc/source/corereflection/lrucache.hxx209
-rw-r--r--stoc/source/corereflection/reflection.component33
-rw-r--r--stoc/source/defaultregistry/defaultregistry.cxx1186
-rw-r--r--stoc/source/implementationregistration/implreg.cxx1580
-rw-r--r--stoc/source/implementationregistration/mergekeys.cxx177
-rw-r--r--stoc/source/implementationregistration/mergekeys.hxx46
-rw-r--r--stoc/source/inspect/introspection.component28
-rw-r--r--stoc/source/inspect/introspection.cxx2420
-rw-r--r--stoc/source/invocation/invocation.component26
-rw-r--r--stoc/source/invocation/invocation.cxx1091
-rw-r--r--stoc/source/invocation_adapterfactory/iafactory.cxx881
-rw-r--r--stoc/source/invocation_adapterfactory/invocadapt.component26
-rw-r--r--stoc/source/javaloader/javaloader.component28
-rw-r--r--stoc/source/javaloader/javaloader.cxx574
-rw-r--r--stoc/source/javavm/interact.cxx108
-rw-r--r--stoc/source/javavm/interact.hxx67
-rw-r--r--stoc/source/javavm/javavm.component28
-rw-r--r--stoc/source/javavm/javavm.cxx1416
-rw-r--r--stoc/source/javavm/javavm.hxx147
-rw-r--r--stoc/source/javavm/jvmargs.cxx32
-rw-r--r--stoc/source/javavm/jvmargs.hxx58
-rw-r--r--stoc/source/loader/dllcomponentloader.cxx152
-rw-r--r--stoc/source/namingservice/namingservice.component26
-rw-r--r--stoc/source/namingservice/namingservice.cxx123
-rw-r--r--stoc/source/proxy_factory/proxyfac.component26
-rw-r--r--stoc/source/proxy_factory/proxyfac.cxx411
-rw-r--r--stoc/source/security/access_controller.cxx863
-rw-r--r--stoc/source/security/file_policy.cxx494
-rw-r--r--stoc/source/security/lru_cache.h210
-rw-r--r--stoc/source/security/permissions.cxx601
-rw-r--r--stoc/source/security/permissions.h86
-rw-r--r--stoc/source/servicemanager/servicemanager.cxx1476
-rw-r--r--stoc/source/simpleregistry/simpleregistry.cxx932
-rw-r--r--stoc/source/typeconv/convert.cxx872
-rw-r--r--stoc/source/uriproc/ExternalUriReferenceTranslator.cxx187
-rw-r--r--stoc/source/uriproc/UriReference.cxx182
-rw-r--r--stoc/source/uriproc/UriReference.hxx112
-rw-r--r--stoc/source/uriproc/UriReferenceFactory.cxx701
-rw-r--r--stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx198
-rw-r--r--stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx385
-rw-r--r--stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx120
-rw-r--r--stoc/test/dump.cxx152
-rw-r--r--stoc/test/javavm/jvm_interaction/interactionhandler.cxx186
-rw-r--r--stoc/test/javavm/jvm_interaction/makefile.mk71
-rw-r--r--stoc/test/javavm/makefile.mk59
-rw-r--r--stoc/test/javavm/testapplet/TestApplet.html19
-rw-r--r--stoc/test/javavm/testapplet/TestApplet.java53
-rw-r--r--stoc/test/javavm/testapplet/makefile.mk43
-rw-r--r--stoc/test/javavm/testcomponent/TestComponent.java129
-rw-r--r--stoc/test/javavm/testcomponent/makefile.mk45
-rw-r--r--stoc/test/javavm/testcomponent/manifest1
-rw-r--r--stoc/test/javavm/testjavavm.cxx151
-rw-r--r--stoc/test/javavm/testjavavm.java30
-rw-r--r--stoc/test/language_binding.idl155
-rw-r--r--stoc/test/makefile.mk213
-rw-r--r--stoc/test/mergekeys_.cxx22
-rw-r--r--stoc/test/registry_tdprovider/makefile.mk54
-rw-r--r--stoc/test/registry_tdprovider/readme.txt4
-rw-r--r--stoc/test/registry_tdprovider/testregistrytdprovider.cxx798
-rw-r--r--stoc/test/registry_tdprovider/types.idl101
-rw-r--r--stoc/test/tdmanager/makefile.mk66
-rw-r--r--stoc/test/tdmanager/readme.txt4
-rw-r--r--stoc/test/tdmanager/testtdmanager.cxx332
-rw-r--r--stoc/test/tdmanager/types.idl37
-rw-r--r--stoc/test/tdmanager/types2_incomp.idl32
-rw-r--r--stoc/test/tdmanager/types3_incomp.idl27
-rw-r--r--stoc/test/tdmanager/types4_incomp.idl34
-rw-r--r--stoc/test/tdmanager/types5.idl37
-rw-r--r--stoc/test/tdmanager/types5_incomp.idl35
-rw-r--r--stoc/test/tdmanager/types6_incomp.idl35
-rw-r--r--stoc/test/testconv.cxx682
-rw-r--r--stoc/test/testcorefl.cxx377
-rw-r--r--stoc/test/testcorefl.idl93
-rw-r--r--stoc/test/testiadapter.cxx1051
-rw-r--r--stoc/test/testintrosp.cxx1203
-rw-r--r--stoc/test/testintrosp.idl187
-rw-r--r--stoc/test/testloader.cxx120
-rw-r--r--stoc/test/testproxyfac.cxx359
-rw-r--r--stoc/test/testregistry.cxx670
-rw-r--r--stoc/test/testsmgr.cxx88
-rw-r--r--stoc/test/testsmgr2.cxx109
-rw-r--r--stoc/test/testsmgr_cpnt.cxx302
-rw-r--r--stoc/test/testsmgr_cpnt.map25
-rw-r--r--stoc/test/uriproc/test_uriproc.cxx1420
-rw-r--r--stoc/unosdk.mk25
-rw-r--r--stoc/util/bootstrap.component56
-rw-r--r--stoc/util/stocservices.component45
111 files changed, 31388 insertions, 0 deletions
diff --git a/stoc/CppunitTest_stoc_dump.mk b/stoc/CppunitTest_stoc_dump.mk
new file mode 100644
index 0000000000..98f5fe7f8d
--- /dev/null
+++ b/stoc/CppunitTest_stoc_dump.mk
@@ -0,0 +1,33 @@
+# -*- 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,stoc_dump))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,stoc_dump, \
+ stoc/test/dump \
+))
+
+$(eval $(call gb_CppunitTest_use_internal_api,stoc_dump, \
+ cppu_qa_cppumaker_types \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,stoc_dump, \
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_CppunitTest_use_udk_api,stoc_dump))
+
+$(eval $(call gb_CppunitTest_use_ure,stoc_dump))
+
+$(call gb_CppunitTest_get_target,stoc_dump): \
+ UNO_TYPES += $(call gb_UnoApiTarget_get_target,cppu_qa_cppumaker_types)
+
+# vim: set noet sw=4 ts=4:
diff --git a/stoc/CppunitTest_stoc_uriproc.mk b/stoc/CppunitTest_stoc_uriproc.mk
new file mode 100644
index 0000000000..f754a02999
--- /dev/null
+++ b/stoc/CppunitTest_stoc_uriproc.mk
@@ -0,0 +1,32 @@
+# -*- 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,stoc_uriproc))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,stoc_uriproc, \
+ stoc/test/uriproc/test_uriproc \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,stoc_uriproc, \
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_CppunitTest_use_udk_api,stoc_uriproc))
+
+$(eval $(call gb_CppunitTest_use_ure,stoc_uriproc))
+
+# In a full build this is already covered indirectly by gb_CppunitTest_use_ure, but a module-only
+# build needs it (and instead using gb_CppunitTest_use_component would cause a "duplicate
+# implementation" DeploymentException):
+$(call gb_CppunitTest_get_target,stoc_uriproc): \
+ $(call gb_ComponentTarget_get_target,stoc/util/stocservices)
+
+# vim: set noet sw=4 ts=4:
diff --git a/stoc/IwyuFilter_stoc.yaml b/stoc/IwyuFilter_stoc.yaml
new file mode 100644
index 0000000000..5b046e4da1
--- /dev/null
+++ b/stoc/IwyuFilter_stoc.yaml
@@ -0,0 +1,47 @@
+---
+assumeFilename: stoc/source/javavm/javavm.cxx
+excludelist:
+ stoc/source/implementationregistration/mergekeys.hxx:
+ # Needed for css shortcut
+ - sal/types.h
+ stoc/source/javavm/interact.hxx:
+ # Base class needs complete type
+ - com/sun/star/task/XInteractionRequest.hpp
+ stoc/source/javavm/javavm.hxx:
+ # Base class needs complete type
+ - com/sun/star/container/XContainerListener.hpp
+ - com/sun/star/lang/XInitialization.hpp
+ - com/sun/star/java/XJavaThreadRegister_11.hpp
+ - com/sun/star/java/XJavaVM.hpp
+ - com/sun/star/lang/XServiceInfo.hpp
+ stoc/source/implementationregistration/mergekeys.cxx:
+ # Actually used
+ - com/sun/star/registry/XRegistryKey.hpp
+ stoc/source/corereflection/crefl.cxx:
+ # Safer to keep for use in cppu::UnoType template
+ - com/sun/star/reflection/XTypeDescription.hpp
+ stoc/source/corereflection/criface.cxx:
+ # Keep for platform-independent alloca.h abstraction
+ - sal/alloca.h
+ # Safer to keep for use in cppu::UnoType template
+ - com/sun/star/uno/RuntimeException.hpp
+ stoc/source/invocation_adapterfactory/iafactory.cxx:
+ # Safer to keep for use in cppu::UnoType template
+ - com/sun/star/script/XInvocation.hpp
+ # Complete type needed for uno_Interface
+ - uno/dispatcher.h
+ stoc/source/loader/dllcomponentloader.cxx:
+ # Needed for direct member access
+ - com/sun/star/lang/XMultiServiceFactory.hpp
+ stoc/source/security/permissions.cxx:
+ # Safer to keep for use in cppu::UnoType template
+ - com/sun/star/security/AllPermission.hpp
+ # Needed for __DIAGNOSE mode
+ - vector
+ - rtl/string.hxx
+ # Actually used
+ - com/sun/star/uno/Sequence.hxx
+ stoc/source/security/access_controller.cxx:
+ # Needed for __DIAGNOSE mode
+ - rtl/ustrbuf.hxx
+ - sal/log.hxx
diff --git a/stoc/Library_bootstrap.mk b/stoc/Library_bootstrap.mk
new file mode 100644
index 0000000000..62e2360581
--- /dev/null
+++ b/stoc/Library_bootstrap.mk
@@ -0,0 +1,50 @@
+# -*- 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,bootstrap))
+
+ifneq ($(debug),)
+
+$(eval $(call gb_Library_add_defs,bootstrap,\
+ $(if $(diag),\
+ $(if $(filter $(diag),cache full),-D__CACHE_DIAGNOSE) \
+ $(if $(filter-out $(diag),cache),-D__DIAGNOSE)) \
+))
+
+endif
+
+$(eval $(call gb_Library_use_external,bootstrap,boost_headers))
+
+$(eval $(call gb_Library_use_internal_bootstrap_api,bootstrap,\
+ udkapi \
+))
+
+$(eval $(call gb_Library_use_libraries,bootstrap,\
+ cppu \
+ cppuhelper \
+ reg \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_set_componentfile,bootstrap,stoc/util/bootstrap,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,bootstrap,\
+ stoc/source/defaultregistry/defaultregistry \
+ stoc/source/implementationregistration/implreg \
+ stoc/source/implementationregistration/mergekeys \
+ stoc/source/loader/dllcomponentloader \
+ stoc/source/security/access_controller \
+ stoc/source/security/file_policy \
+ stoc/source/security/permissions \
+ stoc/source/servicemanager/servicemanager \
+ stoc/source/simpleregistry/simpleregistry \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_introspection.mk b/stoc/Library_introspection.mk
new file mode 100644
index 0000000000..58ce9e404d
--- /dev/null
+++ b/stoc/Library_introspection.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_Library_Library,introspection))
+
+$(eval $(call gb_Library_use_external,introspection,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,introspection))
+
+$(eval $(call gb_Library_use_libraries,introspection,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_set_componentfile,introspection,stoc/source/inspect/introspection,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,introspection,\
+ stoc/source/inspect/introspection \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_invocadapt.mk b/stoc/Library_invocadapt.mk
new file mode 100644
index 0000000000..8166cfadcb
--- /dev/null
+++ b/stoc/Library_invocadapt.mk
@@ -0,0 +1,28 @@
+# -*- 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,invocadapt))
+
+$(eval $(call gb_Library_use_external,invocadapt,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,invocadapt))
+
+$(eval $(call gb_Library_use_libraries,invocadapt,\
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_set_componentfile,invocadapt,stoc/source/invocation_adapterfactory/invocadapt,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,invocadapt,\
+ stoc/source/invocation_adapterfactory/iafactory \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_invocation.mk b/stoc/Library_invocation.mk
new file mode 100644
index 0000000000..d62de01f41
--- /dev/null
+++ b/stoc/Library_invocation.mk
@@ -0,0 +1,28 @@
+# -*- 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,invocation))
+
+$(eval $(call gb_Library_use_external,invocation,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,invocation))
+
+$(eval $(call gb_Library_use_libraries,invocation,\
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_set_componentfile,invocation,stoc/source/invocation/invocation,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,invocation,\
+ stoc/source/invocation/invocation \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_javaloader.mk b/stoc/Library_javaloader.mk
new file mode 100644
index 0000000000..2fd3a491f8
--- /dev/null
+++ b/stoc/Library_javaloader.mk
@@ -0,0 +1,30 @@
+# -*- 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,javaloader))
+
+$(eval $(call gb_Library_use_external,javaloader,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,javaloader))
+
+$(eval $(call gb_Library_use_libraries,javaloader,\
+ cppu \
+ cppuhelper \
+ jvmaccess \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_set_componentfile,javaloader,stoc/source/javaloader/javaloader,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,javaloader,\
+ stoc/source/javaloader/javaloader \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_javavm.mk b/stoc/Library_javavm.mk
new file mode 100644
index 0000000000..adcb49691c
--- /dev/null
+++ b/stoc/Library_javavm.mk
@@ -0,0 +1,40 @@
+# -*- 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,javavm))
+
+$(eval $(call gb_Library_use_external,javavm,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,javavm))
+
+$(eval $(call gb_Library_use_libraries,javavm,\
+ cppu \
+ cppuhelper \
+ i18nlangtag \
+ jvmaccess \
+ jvmfwk \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_Library_set_componentfile,javavm,stoc/source/javavm/javavm,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,javavm,\
+ stoc/source/javavm/interact \
+ stoc/source/javavm/javavm \
+ stoc/source/javavm/jvmargs \
+))
+
+ifeq ($(OS),MACOSX)
+$(eval $(call gb_Library_use_system_darwin_frameworks,javavm,\
+ CoreFoundation \
+))
+endif
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_namingservice.mk b/stoc/Library_namingservice.mk
new file mode 100644
index 0000000000..6822635f00
--- /dev/null
+++ b/stoc/Library_namingservice.mk
@@ -0,0 +1,28 @@
+# -*- 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,namingservice))
+
+$(eval $(call gb_Library_use_external,namingservice,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,namingservice))
+
+$(eval $(call gb_Library_use_libraries,namingservice,\
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_set_componentfile,namingservice,stoc/source/namingservice/namingservice,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,namingservice,\
+ stoc/source/namingservice/namingservice \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_proxyfac.mk b/stoc/Library_proxyfac.mk
new file mode 100644
index 0000000000..9cd7be33a3
--- /dev/null
+++ b/stoc/Library_proxyfac.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_Library_Library,proxyfac))
+
+$(eval $(call gb_Library_use_udk_api,proxyfac))
+
+$(eval $(call gb_Library_use_libraries,proxyfac,\
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_set_componentfile,proxyfac,stoc/source/proxy_factory/proxyfac,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,proxyfac,\
+ stoc/source/proxy_factory/proxyfac \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_reflection.mk b/stoc/Library_reflection.mk
new file mode 100644
index 0000000000..083b237836
--- /dev/null
+++ b/stoc/Library_reflection.mk
@@ -0,0 +1,34 @@
+# -*- 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,reflection))
+
+$(eval $(call gb_Library_use_external,reflection,boost_headers))
+
+$(eval $(call gb_Library_use_udk_api,reflection))
+
+$(eval $(call gb_Library_use_libraries,reflection,\
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_set_componentfile,reflection,stoc/source/corereflection/reflection,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,reflection,\
+ stoc/source/corereflection/crarray \
+ stoc/source/corereflection/crbase \
+ stoc/source/corereflection/crcomp \
+ stoc/source/corereflection/crefl \
+ stoc/source/corereflection/crenum \
+ stoc/source/corereflection/criface \
+ stoc/source/corereflection/dump \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Library_stocservices.mk b/stoc/Library_stocservices.mk
new file mode 100644
index 0000000000..4d276129d8
--- /dev/null
+++ b/stoc/Library_stocservices.mk
@@ -0,0 +1,34 @@
+# -*- 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,stocservices))
+
+$(eval $(call gb_Library_use_udk_api,stocservices))
+
+$(eval $(call gb_Library_use_libraries,stocservices,\
+ cppu \
+ cppuhelper \
+ sal \
+))
+
+$(eval $(call gb_Library_use_external,stocservices,boost_headers))
+
+$(eval $(call gb_Library_set_componentfile,stocservices,stoc/util/stocservices,ure/services))
+
+$(eval $(call gb_Library_add_exception_objects,stocservices,\
+ stoc/source/typeconv/convert \
+ stoc/source/uriproc/ExternalUriReferenceTranslator \
+ stoc/source/uriproc/UriReference \
+ stoc/source/uriproc/UriReferenceFactory \
+ stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand \
+ stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript \
+ stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/Makefile b/stoc/Makefile
new file mode 100644
index 0000000000..ccb1c85a04
--- /dev/null
+++ b/stoc/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/stoc/Module_stoc.mk b/stoc/Module_stoc.mk
new file mode 100644
index 0000000000..e94e5be476
--- /dev/null
+++ b/stoc/Module_stoc.mk
@@ -0,0 +1,37 @@
+# -*- 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,stoc))
+
+$(eval $(call gb_Module_add_targets,stoc,\
+ Library_bootstrap \
+ Library_introspection \
+ Library_invocadapt \
+ Library_invocation \
+ Library_namingservice \
+ Library_proxyfac \
+ Library_reflection \
+ Library_stocservices \
+))
+
+ifeq ($(ENABLE_JAVA),TRUE)
+
+$(eval $(call gb_Module_add_targets,stoc,\
+ Library_javaloader \
+ Library_javavm \
+))
+
+endif
+
+$(eval $(call gb_Module_add_check_targets,stoc, \
+ CppunitTest_stoc_dump \
+ CppunitTest_stoc_uriproc \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/stoc/README.md b/stoc/README.md
new file mode 100644
index 0000000000..47fd36d20f
--- /dev/null
+++ b/stoc/README.md
@@ -0,0 +1,39 @@
+# Registries, Reflection, Introspection Implementation for UNO
+
+The UNO types and services bootstrapping code is very old, and concepts
+are tightly knit together. Whenever you want to change something you risk
+backwards incompatibility. The code causes mental pain, and whenever
+you need to touch it you want to run away screaming. One typically ends
+up doing minimally invasive changes. That way, you have a chance of
+surviving the process. But you also pile up guilt.
+
+At the heart of the matter there is the old binary "store" file structure
+and the `XRegistry` interface on top of it. At runtime, both all the UNO
+type information (scattered across a number of binary `.rdb` files) and
+all the UNO service information (scattered across a number of `.rdb` files
+that used to be binary but have been mostly changed to XML now) are
+represented by a single `XRegistry` instance each.
+
+The way the respective information is represented in the `XRegistry`
+interface simply corresponds to the way the information is stored in the
+binary `.rdb` files. Those files are designed for storage of hierarchically
+nested small blobs of information. Hence, for example information about
+a UNO interface type `com.sun.star.foo.XBar` is stored in a nested "folder"
+with path `com - sun - star - foo - XBar`, containing little blobs of
+information about the type's ancestors, its methods, etc. Similarly
+for information about instantiable services like `com.sun.star.baz.Boz`.
+
+As there are typically multiple `.rdb` files containing types resp.
+services (URE specific, LO specific, from extensions, ...), but they need
+to be represented by a single `XRegistry` instance, so "nested registries"
+were invented. They effectively form a linear list of chaining `XRegistry`
+instances together. Whenever a path needs to be looked up in the top-level
+registry, it effectively searches through the linear list of nested
+registries. All with the cumbersome UNO `XRegistry` interface between
+the individual parts. Horror.
+
+When the XML service `.rdb`s were introduced, we chickened out (see above
+for rationale) and put them behind an `XRegistry` facade, so that they
+would seamlessly integrate with the existing mess. We postponed
+systematic clean-up to the pie-in-the-sky days of LibreOffice 4 (or, "once we'll
+become incompatible with OpenOffice.org," as the phrase used to be back then)
diff --git a/stoc/source/corereflection/base.hxx b/stoc/source/corereflection/base.hxx
new file mode 100644
index 0000000000..03d844de3c
--- /dev/null
+++ b/stoc/source/corereflection/base.hxx
@@ -0,0 +1,406 @@
+/* -*- 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 .
+ */
+// #define TEST_LIST_CLASSES
+
+#ifndef INCLUDED_STOC_SOURCE_COREREFLECTION_BASE_HXX
+#define INCLUDED_STOC_SOURCE_COREREFLECTION_BASE_HXX
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <osl/mutex.hxx>
+#include <uno/mapping.hxx>
+#include <uno/dispatcher.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+
+#include "lrucache.hxx"
+
+#ifdef TEST_LIST_CLASSES
+#include <vector>
+#include <algorithm>
+#endif
+#include <unordered_map>
+#include <memory>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::reflection { class XIdlClass; }
+namespace com::sun::star::reflection { class XIdlField; }
+namespace com::sun::star::reflection { class XIdlMethod; }
+
+namespace stoc_corefl
+{
+
+#ifdef TEST_LIST_CLASSES
+extern std::vector<OUString> g_aClassNames;
+#endif
+
+
+::osl::Mutex & getMutexAccess();
+
+
+inline bool td_equals( typelib_TypeDescription * pTD, typelib_TypeDescriptionReference * pType )
+{
+ return (pTD->pWeakRef == pType ||
+ (pTD->pTypeName->length == pType->pTypeName->length &&
+ rtl_ustr_compare( pTD->pTypeName->buffer, pType->pTypeName->buffer ) == 0));
+}
+
+typedef std::unordered_map< OUString, css::uno::WeakReference< css::reflection::XIdlField > > OUString2Field;
+typedef std::unordered_map< OUString, css::uno::WeakReference< css::reflection::XIdlMethod > > OUString2Method;
+
+
+class IdlReflectionServiceImpl
+ : public ::cppu::WeakComponentImplHelper<
+ css::reflection::XIdlReflection,
+ css::container::XHierarchicalNameAccess,
+ css::lang::XServiceInfo>
+{
+ ::osl::Mutex _aComponentMutex;
+ css::uno::Reference< css::container::XHierarchicalNameAccess > _xTDMgr;
+
+ // caching
+ LRU_CacheAnyByOUString _aElements;
+
+ css::uno::Mapping _aCpp2Uno;
+ css::uno::Mapping _aUno2Cpp;
+
+ inline css::uno::Reference< css::reflection::XIdlClass > constructClass( typelib_TypeDescription * pTypeDescr );
+
+public:
+ /// @throws css::uno::RuntimeException
+ const css::uno::Mapping & getCpp2Uno();
+ /// @throws css::uno::RuntimeException
+ const css::uno::Mapping & getUno2Cpp();
+ /// @throws css::uno::RuntimeException
+ uno_Interface * mapToUno( const css::uno::Any & rObj, typelib_InterfaceTypeDescription * pTo );
+
+ // ctor/ dtor
+ explicit IdlReflectionServiceImpl( const css::uno::Reference< css::uno::XComponentContext > & xContext );
+ virtual ~IdlReflectionServiceImpl() override;
+
+ // WeakComponentImplHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XIdlReflection
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL forName( const OUString & rTypeName ) override;
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getType( const css::uno::Any & rObj ) override;
+
+ // XHierarchicalNameAccess
+ virtual css::uno::Any SAL_CALL getByHierarchicalName( const OUString & rName ) override;
+ virtual sal_Bool SAL_CALL hasByHierarchicalName( const OUString & rName ) override;
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::reflection::XIdlClass > forType( typelib_TypeDescription * pTypeDescr );
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::reflection::XIdlClass > forType( typelib_TypeDescriptionReference * pRef );
+};
+
+
+class IdlClassImpl
+ : public ::cppu::WeakImplHelper< css::reflection::XIdlClass >
+{
+ rtl::Reference<IdlReflectionServiceImpl>
+ m_xReflection;
+
+ OUString _aName;
+ css::uno::TypeClass _eTypeClass;
+
+ typelib_TypeDescription * _pTypeDescr;
+
+public:
+ typelib_TypeDescription * getTypeDescr() const
+ { return _pTypeDescr; }
+ IdlReflectionServiceImpl * getReflection() const
+ { return m_xReflection.get(); }
+
+ // Ctor
+ IdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ OUString aName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr );
+ virtual ~IdlClassImpl() override;
+
+ // XIdlClassImpl default implementation
+ virtual css::uno::TypeClass SAL_CALL getTypeClass() override;
+ virtual OUString SAL_CALL getName() override;
+ virtual sal_Bool SAL_CALL equals( const css::uno::Reference< css::reflection::XIdlClass >& xType ) override;
+
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual void SAL_CALL createObject( css::uno::Any & rObj ) override;
+
+ // def impl ????
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getClasses() override;
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getClass( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getInterfaces() override;
+
+ // structs, interfaces
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getSuperclasses() override;
+ // structs
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+ // interfaces
+ virtual css::uno::Uik SAL_CALL getUik() override;
+ virtual css::uno::Reference< css::reflection::XIdlMethod > SAL_CALL getMethod( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlMethod > > SAL_CALL getMethods() override;
+ // array
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getComponentType() override;
+ virtual css::uno::Reference< css::reflection::XIdlArray > SAL_CALL getArray() override;
+};
+
+
+class InterfaceIdlClassImpl
+ : public IdlClassImpl
+{
+ typedef std::pair< OUString, typelib_TypeDescription * > MemberInit;
+
+ css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > _xSuperClasses;
+
+ std::unique_ptr<MemberInit[]> _pSortedMemberInit; // first methods, then attributes
+ OUString2Field _aName2Field;
+ OUString2Method _aName2Method;
+ sal_Int32 _nMethods;
+ sal_Int32 _nAttributes;
+
+ void initMembers();
+
+public:
+ typelib_InterfaceTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_InterfaceTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor/ dtor
+ InterfaceIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ , _nMethods( 0 )
+ , _nAttributes( 0 )
+ {}
+ virtual ~InterfaceIdlClassImpl() override;
+
+ // IdlClassImpl modifications
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getSuperclasses() override;
+ virtual css::uno::Uik SAL_CALL getUik() override;
+ virtual css::uno::Reference< css::reflection::XIdlMethod > SAL_CALL getMethod( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlMethod > > SAL_CALL getMethods() override;
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+ virtual void SAL_CALL createObject( css::uno::Any & rObj ) override;
+};
+
+
+class CompoundIdlClassImpl
+ : public IdlClassImpl
+{
+ css::uno::Reference< css::reflection::XIdlClass >
+ _xSuperClass;
+ std::optional< css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > >
+ m_xFields;
+ OUString2Field _aName2Field;
+
+public:
+ typelib_CompoundTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_CompoundTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor/ dtor
+ CompoundIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ {}
+ virtual ~CompoundIdlClassImpl() override;
+
+ // IdlClassImpl modifications
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlClass > > SAL_CALL getSuperclasses() override;
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+};
+
+
+typedef cppu::ImplInheritanceHelper<IdlClassImpl, css::reflection::XIdlArray> ArrayIdlClassImpl_Base;
+class ArrayIdlClassImpl : public ArrayIdlClassImpl_Base
+{
+public:
+ typelib_IndirectTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_IndirectTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor
+ ArrayIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : ArrayIdlClassImpl_Base( pReflection, rName, eTypeClass, pTypeDescr )
+ {}
+
+ // IdlClassImpl modifications
+ virtual sal_Bool SAL_CALL isAssignableFrom( const css::uno::Reference< css::reflection::XIdlClass > & xType ) override;
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getComponentType() override;
+ virtual css::uno::Reference< css::reflection::XIdlArray > SAL_CALL getArray() override;
+
+ // XIdlArray
+ virtual void SAL_CALL realloc( css::uno::Any & rArray, sal_Int32 nLen ) override;
+ virtual sal_Int32 SAL_CALL getLen( const css::uno::Any & rArray ) override;
+ virtual css::uno::Any SAL_CALL get( const css::uno::Any & rArray, sal_Int32 nIndex ) override;
+ virtual void SAL_CALL set( css::uno::Any & rArray, sal_Int32 nIndex, const css::uno::Any & rNewValue ) override;
+};
+
+
+class EnumIdlClassImpl
+ : public IdlClassImpl
+{
+ std::optional< css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > > m_xFields;
+ OUString2Field _aName2Field;
+
+public:
+ typelib_EnumTypeDescription * getTypeDescr() const
+ { return reinterpret_cast<typelib_EnumTypeDescription *>(IdlClassImpl::getTypeDescr()); }
+
+ // ctor/ dtor
+ EnumIdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ const OUString & rName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : IdlClassImpl( pReflection, rName, eTypeClass, pTypeDescr )
+ {}
+ virtual ~EnumIdlClassImpl() override;
+
+ // IdlClassImpl modifications
+ virtual css::uno::Reference< css::reflection::XIdlField > SAL_CALL getField( const OUString & rName ) override;
+ virtual css::uno::Sequence< css::uno::Reference< css::reflection::XIdlField > > SAL_CALL getFields() override;
+ virtual void SAL_CALL createObject( css::uno::Any & rObj ) override;
+};
+
+
+class IdlMemberImpl
+ : public ::cppu::WeakImplHelper< css::reflection::XIdlMember >
+{
+ rtl::Reference<IdlReflectionServiceImpl>
+ m_xReflection;
+ OUString _aName;
+
+ typelib_TypeDescription * _pTypeDescr;
+ typelib_TypeDescription * _pDeclTypeDescr;
+
+protected:
+ css::uno::Reference< css::reflection::XIdlClass > _xDeclClass;
+
+public:
+ IdlReflectionServiceImpl * getReflection() const
+ { return m_xReflection.get(); }
+ typelib_TypeDescription * getTypeDescr() const
+ { return _pTypeDescr; }
+ typelib_TypeDescription * getDeclTypeDescr() const
+ { return _pDeclTypeDescr; }
+
+ // ctor/ dtor
+ IdlMemberImpl( IdlReflectionServiceImpl * pReflection, OUString aName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr );
+ virtual ~IdlMemberImpl() override;
+
+ // XIdlMember
+ virtual css::uno::Reference< css::reflection::XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+};
+
+
+// coerces to type descr pTo else queries for it: the interface pointer is returned via rDest
+// ## type to XidlClass coercion possible
+inline bool extract(
+ const css::uno::Any & rObj, typelib_InterfaceTypeDescription * pTo,
+ css::uno::Reference< css::uno::XInterface > & rDest,
+ IdlReflectionServiceImpl * pRefl )
+{
+ rDest.clear();
+ if (nullptr != pTo)
+ {
+ if (! rObj.hasValue())
+ return true;
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_INTERFACE)
+ {
+ return ::uno_type_assignData(
+ &rDest, pTo->aBase.pWeakRef,
+ const_cast< void * >( rObj.getValue() ), rObj.getValueTypeRef(),
+ reinterpret_cast< uno_QueryInterfaceFunc >(css::uno::cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(css::uno::cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release) );
+ }
+ else if (auto t = o3tl::tryAccess<css::uno::Type>(rObj))
+ {
+ rDest = pRefl->forType( t->getTypeLibType() );
+ return rDest.is();
+ }
+ }
+ return false;
+}
+
+inline bool coerce_assign(
+ void * pDest, typelib_TypeDescription * pTD, const css::uno::Any & rSource,
+ IdlReflectionServiceImpl * pRefl )
+{
+ if (pTD->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ css::uno::Reference< css::uno::XInterface > xVal;
+ if (extract( rSource, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD), xVal, pRefl ))
+ {
+ if (*static_cast<css::uno::XInterface **>(pDest))
+ (*static_cast<css::uno::XInterface **>(pDest))->release();
+ *static_cast<css::uno::XInterface **>(pDest) = xVal.get();
+ if (*static_cast<css::uno::XInterface **>(pDest))
+ (*static_cast<css::uno::XInterface **>(pDest))->acquire();
+ return true;
+ }
+ return false;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_ANY)
+ {
+ return uno_assignData(
+ pDest, pTD,
+ const_cast<css::uno::Any *>(&rSource), pTD,
+ reinterpret_cast< uno_QueryInterfaceFunc >(css::uno::cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(css::uno::cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release) );
+ }
+ else
+ {
+ return uno_type_assignData(
+ pDest, pTD->pWeakRef,
+ const_cast<void *>(rSource.getValue()), rSource.getValueTypeRef(),
+ reinterpret_cast< uno_QueryInterfaceFunc >(css::uno::cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(css::uno::cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(css::uno::cpp_release) );
+ }
+}
+
+}
+
+
+#endif // INCLUDED_STOC_SOURCE_COREREFLECTION_BASE_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crarray.cxx b/stoc/source/corereflection/crarray.cxx
new file mode 100644
index 0000000000..67be31e1ac
--- /dev/null
+++ b/stoc/source/corereflection/crarray.cxx
@@ -0,0 +1,166 @@
+/* -*- 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 <typelib/typedescription.h>
+#include <uno/data.h>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include "base.hxx"
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+// XIdlArray
+
+void ArrayIdlClassImpl::realloc( Any & rArray, sal_Int32 nLen )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ getXWeak(), 0 );
+ }
+ if (nLen < 0)
+ {
+ throw IllegalArgumentException(
+ "negative length given!",
+ getXWeak(), 1 );
+ }
+
+ uno_Sequence ** ppSeq = const_cast<uno_Sequence **>(static_cast<uno_Sequence * const *>(rArray.getValue()));
+ uno_sequence_realloc( ppSeq, &getTypeDescr()->aBase,
+ nLen,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ rArray.pData = ppSeq;
+}
+
+sal_Int32 ArrayIdlClassImpl::getLen( const Any & rArray )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ getXWeak(), 0 );
+ }
+
+ return (*static_cast<uno_Sequence * const *>(rArray.getValue()))->nElements;
+}
+
+Any ArrayIdlClassImpl::get( const Any & rArray, sal_Int32 nIndex )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ getXWeak(), 0 );
+ }
+
+ uno_Sequence * pSeq = *static_cast<uno_Sequence * const *>(rArray.getValue());
+ if (pSeq->nElements <= nIndex)
+ {
+ throw ArrayIndexOutOfBoundsException(
+ "illegal index given, index " + OUString::number(nIndex) + " is < " + OUString::number(pSeq->nElements),
+ getXWeak() );
+ }
+
+ Any aRet;
+ typelib_TypeDescription * pElemTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElemTypeDescr, getTypeDescr()->pType );
+ uno_any_destruct( &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_construct( &aRet, &pSeq->elements[nIndex * pElemTypeDescr->nSize],
+ pElemTypeDescr,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ TYPELIB_DANGER_RELEASE( pElemTypeDescr );
+ return aRet;
+}
+
+
+void ArrayIdlClassImpl::set( Any & rArray, sal_Int32 nIndex, const Any & rNewValue )
+{
+ TypeClass eTC = rArray.getValueTypeClass();
+ if (eTC != TypeClass_SEQUENCE)
+ {
+ throw IllegalArgumentException(
+ "expected sequence, but found " + rArray.getValueType().getTypeName(),
+ getXWeak(), 0 );
+ }
+
+ uno_Sequence * pSeq = *static_cast<uno_Sequence * const *>(rArray.getValue());
+ if (pSeq->nElements <= nIndex)
+ {
+ throw ArrayIndexOutOfBoundsException(
+ "illegal index given, index " + OUString::number(nIndex) + " is < " + OUString::number(pSeq->nElements),
+ getXWeak() );
+ }
+
+ uno_Sequence ** ppSeq = const_cast<uno_Sequence **>(static_cast<uno_Sequence * const *>(rArray.getValue()));
+ uno_sequence_reference2One(
+ ppSeq, &getTypeDescr()->aBase,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ rArray.pData = ppSeq;
+ pSeq = *ppSeq;
+
+ typelib_TypeDescription * pElemTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pElemTypeDescr, getTypeDescr()->pType );
+
+ if (! coerce_assign( &pSeq->elements[nIndex * pElemTypeDescr->nSize],
+ pElemTypeDescr, rNewValue, getReflection() ))
+ {
+ TYPELIB_DANGER_RELEASE( pElemTypeDescr );
+ throw IllegalArgumentException(
+ "sequence element is not assignable by given value!",
+ getXWeak(), 2 );
+ }
+ TYPELIB_DANGER_RELEASE( pElemTypeDescr );
+}
+
+// ArrayIdlClassImpl
+
+sal_Bool ArrayIdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ return (xType.is() &&
+ (equals( xType ) ||
+ (xType->getTypeClass() == getTypeClass() && // must be sequence|array
+ getComponentType()->isAssignableFrom( xType->getComponentType() ))));
+}
+
+Reference< XIdlClass > ArrayIdlClassImpl::getComponentType()
+{
+ return getReflection()->forType( getTypeDescr()->pType );
+}
+
+Reference< XIdlArray > ArrayIdlClassImpl::getArray()
+{
+ return this;
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crbase.cxx b/stoc/source/corereflection/crbase.cxx
new file mode 100644
index 0000000000..439ee5b222
--- /dev/null
+++ b/stoc/source/corereflection/crbase.cxx
@@ -0,0 +1,250 @@
+/* -*- 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/any2.h>
+
+#include <utility>
+
+#include "base.hxx"
+
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+#ifdef TEST_LIST_CLASSES
+ClassNameVector g_aClassNames;
+#endif
+
+
+::osl::Mutex & getMutexAccess()
+{
+ static osl::Mutex s_aMutex;
+
+ return s_aMutex;
+}
+
+
+IdlClassImpl::IdlClassImpl( IdlReflectionServiceImpl * pReflection,
+ OUString aName, typelib_TypeClass eTypeClass,
+ typelib_TypeDescription * pTypeDescr )
+ : m_xReflection( pReflection )
+ , _aName(std::move( aName ))
+ , _eTypeClass( static_cast<TypeClass>(eTypeClass) )
+ , _pTypeDescr( pTypeDescr )
+{
+ if (_pTypeDescr)
+ {
+ typelib_typedescription_acquire( _pTypeDescr );
+ if (! _pTypeDescr->bComplete)
+ typelib_typedescription_complete( &_pTypeDescr );
+ }
+
+#ifdef TEST_LIST_CLASSES
+ ClassNameVector::const_iterator iFind( std::find( g_aClassNames.begin(), g_aClassNames.end(), _aName ) );
+ OSL_ENSURE( iFind == g_aClassNames.end(), "### idl class already exists!" );
+ g_aClassNames.insert(g_aClassNames.begin(), _aName);
+#endif
+}
+
+IdlClassImpl::~IdlClassImpl()
+{
+ if (_pTypeDescr)
+ typelib_typedescription_release( _pTypeDescr );
+ m_xReflection.clear();
+
+#ifdef TEST_LIST_CLASSES
+ ClassNameVector::iterator iFind( std::find( g_aClassNames.begin(), g_aClassNames.end(), _aName ) );
+ OSL_ENSURE( iFind != g_aClassNames.end(), "### idl class does not exist!" );
+ g_aClassNames.erase( iFind );
+#endif
+}
+
+// XIdlClassImpl default implementation
+
+TypeClass IdlClassImpl::getTypeClass()
+{
+ return _eTypeClass;
+}
+
+OUString IdlClassImpl::getName()
+{
+ return _aName;
+}
+
+sal_Bool IdlClassImpl::equals( const Reference< XIdlClass >& xType )
+{
+ return (xType.is() &&
+ (xType->getTypeClass() == _eTypeClass) && (xType->getName() == _aName));
+}
+
+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, true, true, true, true, true, false },
+/* TypeClass_DOUBLE */ { false, false, true, true, true, true, true, true, true, true, true }
+};
+
+sal_Bool IdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ TypeClass eAssign = getTypeClass();
+ if (equals( xType ) || eAssign == TypeClass_ANY) // default shot
+ {
+ return true;
+ }
+ else
+ {
+ TypeClass eFrom = xType->getTypeClass();
+ if (eAssign > TypeClass_VOID && eAssign < TypeClass_STRING &&
+ eFrom > TypeClass_VOID && eFrom < TypeClass_STRING)
+ {
+ return s_aAssignableFromTab[static_cast<int>(eAssign)-1][static_cast<int>(eFrom)-1];
+ }
+ }
+ return false;
+}
+
+void IdlClassImpl::createObject( Any & rObj )
+{
+ rObj.clear();
+ uno_any_destruct( &rObj, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_construct( &rObj, nullptr, getTypeDescr(), nullptr );
+}
+
+// what TODO ????
+
+Sequence< Reference< XIdlClass > > IdlClassImpl::getClasses()
+{
+ OSL_FAIL( "### unexpected use!" );
+ return Sequence< Reference< XIdlClass > >();
+}
+
+Reference< XIdlClass > IdlClassImpl::getClass( const OUString & )
+{
+ OSL_FAIL( "### unexpected use!" );
+ return Reference< XIdlClass >();
+}
+
+Sequence< Reference< XIdlClass > > IdlClassImpl::getInterfaces()
+{
+// OSL_FAIL( "### unexpected use!" );
+ return Sequence< Reference< XIdlClass > >();
+}
+
+// structs, interfaces
+
+Sequence< Reference< XIdlClass > > IdlClassImpl::getSuperclasses()
+{
+ return Sequence< Reference< XIdlClass > >();
+}
+// structs
+
+Reference< XIdlField > IdlClassImpl::getField( const OUString & )
+{
+ return Reference< XIdlField >();
+}
+
+Sequence< Reference< XIdlField > > IdlClassImpl::getFields()
+{
+ return Sequence< Reference< XIdlField > >();
+}
+// interfaces
+
+Uik IdlClassImpl::getUik()
+{
+ return Uik();
+}
+
+Reference< XIdlMethod > IdlClassImpl::getMethod( const OUString & )
+{
+ return Reference< XIdlMethod >();
+}
+
+Sequence< Reference< XIdlMethod > > IdlClassImpl::getMethods()
+{
+ return Sequence< Reference< XIdlMethod > >();
+}
+// array
+
+Reference< XIdlClass > IdlClassImpl::getComponentType()
+{
+ return Reference< XIdlClass >();
+}
+
+Reference< XIdlArray > IdlClassImpl::getArray()
+{
+ return Reference< XIdlArray >();
+}
+
+
+IdlMemberImpl::IdlMemberImpl( IdlReflectionServiceImpl * pReflection, OUString aName,
+ typelib_TypeDescription * pTypeDescr,
+ typelib_TypeDescription * pDeclTypeDescr )
+ : m_xReflection( pReflection )
+ , _aName(std::move( aName ))
+ , _pTypeDescr( pTypeDescr )
+ , _pDeclTypeDescr( pDeclTypeDescr )
+{
+ typelib_typedescription_acquire( _pTypeDescr );
+ if (! _pTypeDescr->bComplete)
+ typelib_typedescription_complete( &_pTypeDescr );
+ typelib_typedescription_acquire( _pDeclTypeDescr );
+ if (! _pDeclTypeDescr->bComplete)
+ typelib_typedescription_complete( &_pDeclTypeDescr );
+}
+
+IdlMemberImpl::~IdlMemberImpl()
+{
+ typelib_typedescription_release( _pDeclTypeDescr );
+ typelib_typedescription_release( _pTypeDescr );
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlMemberImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ Reference< XIdlClass > xDeclClass( getReflection()->forType( getDeclTypeDescr() ) );
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ _xDeclClass = xDeclClass;
+ }
+ return _xDeclClass;
+}
+
+OUString IdlMemberImpl::getName()
+{
+ return _aName;
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crcomp.cxx b/stoc/source/corereflection/crcomp.cxx
new file mode 100644
index 0000000000..b1143e158b
--- /dev/null
+++ b/stoc/source/corereflection/crcomp.cxx
@@ -0,0 +1,310 @@
+/* -*- 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/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <com/sun/star/reflection/XIdlField.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/uno/TypeClass.hpp>
+
+#include "base.hxx"
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+namespace {
+
+typedef cppu::ImplInheritanceHelper<IdlMemberImpl, XIdlField, XIdlField2> IdlCompFieldImpl_Base;
+class IdlCompFieldImpl : public IdlCompFieldImpl_Base
+{
+ sal_Int32 _nOffset;
+
+public:
+ IdlCompFieldImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr,
+ sal_Int32 nOffset )
+ : IdlCompFieldImpl_Base( pReflection, rName, pTypeDescr, pDeclTypeDescr )
+ , _nOffset( nOffset )
+ {}
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlField
+ virtual Reference< XIdlClass > SAL_CALL getType() override;
+ virtual FieldAccessMode SAL_CALL getAccessMode() override;
+ virtual Any SAL_CALL get( const Any & rObj ) override;
+ virtual void SAL_CALL set( const Any & rObj, const Any & rValue ) override;
+ // XIdlField2: getType, getAccessMode and get are equal to XIdlField
+ virtual void SAL_CALL set( Any & rObj, const Any & rValue ) override;
+};
+
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlCompFieldImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ {
+ typelib_CompoundTypeDescription * pTD =
+ reinterpret_cast<typelib_CompoundTypeDescription *>(getDeclTypeDescr());
+ while (pTD)
+ {
+ typelib_TypeDescriptionReference ** ppTypeRefs = pTD->ppTypeRefs;
+ for ( sal_Int32 nPos = pTD->nMembers; nPos--; )
+ {
+ if (td_equals( getTypeDescr(), ppTypeRefs[nPos] ))
+ {
+ _xDeclClass = getReflection()->forType( &pTD->aBase );
+ return _xDeclClass;
+ }
+ }
+ pTD = pTD->pBaseTypeDescription;
+ }
+ }
+ }
+ return _xDeclClass;
+}
+
+OUString IdlCompFieldImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlField
+
+Reference< XIdlClass > IdlCompFieldImpl::getType()
+{
+ return getReflection()->forType( getTypeDescr() );
+}
+
+FieldAccessMode IdlCompFieldImpl::getAccessMode()
+{
+ return FieldAccessMode_READWRITE;
+}
+
+Any IdlCompFieldImpl::get( const Any & rObj )
+{
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_STRUCT ||
+ rObj.getValueTypeClass() == css::uno::TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pObjTD = nullptr;
+ TYPELIB_DANGER_GET( &pObjTD, rObj.getValueTypeRef() );
+
+ typelib_TypeDescription * pTD = pObjTD;
+ typelib_TypeDescription * pDeclTD = getDeclTypeDescr();
+ while (pTD && !typelib_typedescription_equals( pTD, pDeclTD ))
+ pTD = &reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+
+ OSL_ENSURE( pTD, "### illegal object type!" );
+ if (pTD)
+ {
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ Any aRet;
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_construct(
+ &aRet, const_cast<char *>(static_cast<char const *>(rObj.getValue()) + _nOffset), getTypeDescr(),
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ return aRet;
+ }
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ }
+ throw IllegalArgumentException(
+ "expected struct or exception, got " + rObj.getValueType().getTypeName(),
+ getXWeak(), 0 );
+}
+
+void IdlCompFieldImpl::set( const Any & rObj, const Any & rValue )
+{
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_STRUCT ||
+ rObj.getValueTypeClass() == css::uno::TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pObjTD = nullptr;
+ TYPELIB_DANGER_GET( &pObjTD, rObj.getValueTypeRef() );
+
+ typelib_TypeDescription * pTD = pObjTD;
+ typelib_TypeDescription * pDeclTD = getDeclTypeDescr();
+ while (pTD && !typelib_typedescription_equals( pTD, pDeclTD ))
+ pTD = &reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+
+ OSL_ENSURE( pTD, "### illegal object type!" );
+ if (pTD)
+ {
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ if (!coerce_assign( const_cast<char *>(static_cast<char const *>(rObj.getValue()) + _nOffset), getTypeDescr(), rValue, getReflection() ))
+ {
+ throw IllegalArgumentException(
+ "cannot assign value to destination",
+ getXWeak(), 1 );
+ }
+ return;
+ }
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ }
+ throw IllegalArgumentException(
+ "expected struct or exception, got " + rObj.getValueType().getTypeName(),
+ getXWeak(), 0 );
+}
+
+
+void IdlCompFieldImpl::set( Any & rObj, const Any & rValue )
+{
+ if (rObj.getValueTypeClass() == css::uno::TypeClass_STRUCT ||
+ rObj.getValueTypeClass() == css::uno::TypeClass_EXCEPTION)
+ {
+ typelib_TypeDescription * pObjTD = nullptr;
+ TYPELIB_DANGER_GET( &pObjTD, rObj.getValueTypeRef() );
+
+ typelib_TypeDescription * pTD = pObjTD;
+ typelib_TypeDescription * pDeclTD = getDeclTypeDescr();
+ while (pTD && !typelib_typedescription_equals( pTD, pDeclTD ))
+ pTD = &reinterpret_cast<typelib_CompoundTypeDescription *>(pTD)->pBaseTypeDescription->aBase;
+
+ OSL_ENSURE( pTD, "### illegal object type!" );
+ if (pTD)
+ {
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ if (!coerce_assign( const_cast<char *>(static_cast<char const *>(rObj.getValue()) + _nOffset), getTypeDescr(), rValue, getReflection() ))
+ {
+ throw IllegalArgumentException(
+ "cannot assign to destination",
+ getXWeak(), 1 );
+ }
+ return;
+ }
+ TYPELIB_DANGER_RELEASE( pObjTD );
+ }
+ throw IllegalArgumentException(
+ "expected struct or exception, got " + rObj.getValueType().getTypeName(),
+ getXWeak(), 0 );
+}
+
+
+CompoundIdlClassImpl::~CompoundIdlClassImpl()
+{
+}
+
+
+sal_Bool CompoundIdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ if (xType.is())
+ {
+ TypeClass eTC = xType->getTypeClass();
+ if (eTC == TypeClass_STRUCT || eTC == TypeClass_EXCEPTION)
+ {
+ if (equals( xType ))
+ return true;
+ else
+ {
+ const Sequence< Reference< XIdlClass > > & rSeq = xType->getSuperclasses();
+ if (rSeq.hasElements())
+ {
+ OSL_ENSURE( rSeq.getLength() == 1, "### unexpected len of super classes!" );
+ return isAssignableFrom( rSeq[0] );
+ }
+ }
+ }
+ }
+ return false;
+}
+
+Sequence< Reference< XIdlClass > > CompoundIdlClassImpl::getSuperclasses()
+{
+ if (! _xSuperClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xSuperClass.is())
+ {
+ typelib_CompoundTypeDescription * pCompTypeDescr = getTypeDescr()->pBaseTypeDescription;
+ if (pCompTypeDescr)
+ _xSuperClass = getReflection()->forType( &pCompTypeDescr->aBase );
+ }
+ }
+ if (_xSuperClass.is())
+ return Sequence< Reference< XIdlClass > >( &_xSuperClass, 1 );
+ else
+ return Sequence< Reference< XIdlClass > >();
+}
+
+Reference< XIdlField > CompoundIdlClassImpl::getField( const OUString & rName )
+{
+ if (! m_xFields)
+ getFields(); // init fields
+
+ const OUString2Field::const_iterator iFind( _aName2Field.find( rName ) );
+ if (iFind != _aName2Field.end())
+ return Reference< XIdlField >( (*iFind).second );
+ else
+ return Reference< XIdlField >();
+}
+
+Sequence< Reference< XIdlField > > CompoundIdlClassImpl::getFields()
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xFields)
+ {
+ sal_Int32 nAll = 0;
+ typelib_CompoundTypeDescription * pCompTypeDescr = getTypeDescr();
+ for ( ; pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ nAll += pCompTypeDescr->nMembers;
+
+ Sequence< Reference< XIdlField > > aFields( nAll );
+ Reference< XIdlField > * pSeq = aFields.getArray();
+
+ for ( pCompTypeDescr = getTypeDescr(); pCompTypeDescr;
+ pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ typelib_TypeDescriptionReference ** ppTypeRefs = pCompTypeDescr->ppTypeRefs;
+ rtl_uString ** ppNames = pCompTypeDescr->ppMemberNames;
+ sal_Int32 * pMemberOffsets = pCompTypeDescr->pMemberOffsets;
+
+ for ( sal_Int32 nPos = pCompTypeDescr->nMembers; nPos--; )
+ {
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, ppTypeRefs[nPos] );
+ OSL_ENSURE( pTD, "### cannot get field in struct!" );
+ if (pTD)
+ {
+ OUString aName( ppNames[nPos] );
+ _aName2Field[aName] = pSeq[--nAll] = new IdlCompFieldImpl(
+ getReflection(), aName, pTD, IdlClassImpl::getTypeDescr(), pMemberOffsets[nPos] );
+ TYPELIB_DANGER_RELEASE( pTD );
+ }
+ }
+ }
+
+ m_xFields = std::move( aFields );
+ }
+ return *m_xFields;
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crefl.cxx b/stoc/source/corereflection/crefl.cxx
new file mode 100644
index 0000000000..1f4562181a
--- /dev/null
+++ b/stoc/source/corereflection/crefl.cxx
@@ -0,0 +1,333 @@
+/* -*- 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/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/reflection/XConstantTypeDescription.hpp>
+#include <com/sun/star/reflection/XTypeDescription.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <o3tl/any.hxx>
+#include <uno/lbnames.h>
+#include "base.hxx"
+
+using namespace css;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::reflection;
+using namespace cppu;
+using namespace osl;
+
+namespace stoc_corefl
+{
+
+IdlReflectionServiceImpl::IdlReflectionServiceImpl(
+ const Reference< XComponentContext > & xContext )
+ : WeakComponentImplHelper( _aComponentMutex )
+{
+ xContext->getValueByName(
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager" ) >>= _xTDMgr;
+ OSL_ENSURE( _xTDMgr.is(), "### cannot get singleton \"TypeDescriptionManager\" from context!" );
+}
+
+IdlReflectionServiceImpl::~IdlReflectionServiceImpl() {}
+
+// XComponent
+
+void IdlReflectionServiceImpl::disposing()
+{
+ MutexGuard aGuard( _aComponentMutex );
+ _aElements.clear();
+#ifdef TEST_LIST_CLASSES
+ OSL_ENSURE( g_aClassNames.empty(), "### idl classes still alive!" );
+ for (auto const& className : g_aClassNames)
+ {
+ OUString aName(className);
+ }
+#endif
+}
+
+// XServiceInfo
+
+OUString IdlReflectionServiceImpl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.CoreReflection";
+}
+
+sal_Bool IdlReflectionServiceImpl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > IdlReflectionServiceImpl::getSupportedServiceNames()
+{
+ Sequence< OUString > seqNames { "com.sun.star.reflection.CoreReflection" };
+ return seqNames;
+}
+
+// XIdlReflection
+
+Reference< XIdlClass > IdlReflectionServiceImpl::getType( const Any & rObj )
+{
+ return (rObj.hasValue() ? forType( rObj.getValueTypeRef() ) : Reference< XIdlClass >());
+}
+
+
+inline Reference< XIdlClass > IdlReflectionServiceImpl::constructClass(
+ typelib_TypeDescription * pTypeDescr )
+{
+ OSL_ENSURE( pTypeDescr->eTypeClass != typelib_TypeClass_TYPEDEF, "### unexpected typedef!" );
+
+ switch (pTypeDescr->eTypeClass)
+ {
+ case typelib_TypeClass_VOID:
+ case typelib_TypeClass_CHAR:
+ case typelib_TypeClass_BOOLEAN:
+ case typelib_TypeClass_BYTE:
+ case typelib_TypeClass_SHORT:
+ case typelib_TypeClass_UNSIGNED_SHORT:
+ case typelib_TypeClass_LONG:
+ case typelib_TypeClass_UNSIGNED_LONG:
+ case typelib_TypeClass_HYPER:
+ case typelib_TypeClass_UNSIGNED_HYPER:
+ case typelib_TypeClass_FLOAT:
+ case typelib_TypeClass_DOUBLE:
+ case typelib_TypeClass_STRING:
+ case typelib_TypeClass_ANY:
+ return new IdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_ENUM:
+ return new EnumIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_STRUCT:
+ case typelib_TypeClass_EXCEPTION:
+ return new CompoundIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_SEQUENCE:
+ return new ArrayIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_INTERFACE:
+ return new InterfaceIdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ case typelib_TypeClass_TYPE:
+ return new IdlClassImpl( this, pTypeDescr->pTypeName, pTypeDescr->eTypeClass, pTypeDescr );
+
+ default:
+ SAL_INFO("stoc", "corereflection type unsupported: " << pTypeDescr->pTypeName);
+ return Reference< XIdlClass >();
+ }
+}
+
+Reference< XIdlClass > IdlReflectionServiceImpl::forName( const OUString & rTypeName )
+{
+ Reference< XIdlClass > xRet;
+ Any aAny( _aElements.getValue( rTypeName ) );
+
+ if (aAny.hasValue())
+ {
+ aAny >>= xRet;
+ }
+ else
+ {
+ // try to get _type_ by name
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescription_getByName( &pTD, rTypeName.pData );
+ if (pTD)
+ {
+ xRet = constructClass( pTD );
+ if (xRet.is())
+ _aElements.setValue( rTypeName, Any( xRet ) ); // update
+ typelib_typedescription_release( pTD );
+ }
+ }
+
+ return xRet;
+}
+
+// XHierarchicalNameAccess
+
+Any IdlReflectionServiceImpl::getByHierarchicalName( const OUString & rName )
+{
+ Any aRet( _aElements.getValue( rName ) );
+ if (! aRet.hasValue())
+ {
+ aRet = _xTDMgr->getByHierarchicalName( rName );
+ if (aRet.getValueTypeClass() == TypeClass_INTERFACE)
+ {
+ // type retrieved from tdmgr
+ OSL_ASSERT( (*o3tl::forceAccess<Reference<XInterface>>(aRet))->queryInterface(
+ cppu::UnoType<XTypeDescription>::get()).hasValue() );
+
+ css::uno::Reference< css::reflection::XConstantTypeDescription >
+ ctd;
+ if (aRet >>= ctd)
+ {
+ aRet = ctd->getConstantValue();
+ }
+ else
+ {
+ // if you are interested in a type then CALL forName()!!!
+ // this way is NOT recommended for types, because this method looks for constants first
+
+ // if td manager found some type, it will be in the cache (hopefully... we just got it)
+ // so the second retrieving via c typelib callback chain should succeed...
+
+ // try to get _type_ by name
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescription_getByName( &pTD, rName.pData );
+
+ aRet.clear(); // kick XTypeDescription interface
+
+ if (pTD)
+ {
+ Reference< XIdlClass > xIdlClass( constructClass( pTD ) );
+ aRet.setValue( &xIdlClass, cppu::UnoType<XIdlClass>::get());
+ typelib_typedescription_release( pTD );
+ }
+ }
+ }
+ // else is enum member(?)
+
+ // update
+ if (!aRet.hasValue())
+ throw container::NoSuchElementException( rName );
+
+ _aElements.setValue( rName, aRet );
+ }
+ return aRet;
+}
+
+sal_Bool IdlReflectionServiceImpl::hasByHierarchicalName( const OUString & rName )
+{
+ try
+ {
+ return getByHierarchicalName( rName ).hasValue();
+ }
+ catch (container::NoSuchElementException &)
+ {
+ }
+ return false;
+}
+
+
+Reference< XIdlClass > IdlReflectionServiceImpl::forType( typelib_TypeDescription * pTypeDescr )
+{
+ Reference< XIdlClass > xRet;
+ OUString aName( pTypeDescr->pTypeName );
+ Any aAny( _aElements.getValue( aName ) );
+
+ if (aAny.hasValue())
+ {
+ aAny >>= xRet;
+ }
+ else
+ {
+ xRet = constructClass( pTypeDescr );
+ if (xRet.is())
+ _aElements.setValue( aName, Any( xRet ) ); // update
+ }
+
+ return xRet;
+}
+
+Reference< XIdlClass > IdlReflectionServiceImpl::forType( typelib_TypeDescriptionReference * pRef )
+{
+ typelib_TypeDescription * pTD = nullptr;
+ TYPELIB_DANGER_GET( &pTD, pRef );
+ if (pTD)
+ {
+ Reference< XIdlClass > xRet = forType( pTD );
+ TYPELIB_DANGER_RELEASE( pTD );
+ return xRet;
+ }
+ throw RuntimeException(
+ "IdlReflectionServiceImpl::forType() failed!",
+ getXWeak() );
+}
+
+
+const Mapping & IdlReflectionServiceImpl::getCpp2Uno()
+{
+ if (! _aCpp2Uno.is())
+ {
+ MutexGuard aGuard( getMutexAccess() );
+ if (! _aCpp2Uno.is())
+ {
+ _aCpp2Uno = Mapping( CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO );
+ OSL_ENSURE( _aCpp2Uno.is(), "### cannot get c++ to uno mapping!" );
+ if (! _aCpp2Uno.is())
+ {
+ throw RuntimeException(
+ "cannot get c++ to uno mapping!",
+ getXWeak() );
+ }
+ }
+ }
+ return _aCpp2Uno;
+}
+
+const Mapping & IdlReflectionServiceImpl::getUno2Cpp()
+{
+ if (! _aUno2Cpp.is())
+ {
+ MutexGuard aGuard( getMutexAccess() );
+ if (! _aUno2Cpp.is())
+ {
+ _aUno2Cpp = Mapping( UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME );
+ OSL_ENSURE( _aUno2Cpp.is(), "### cannot get uno to c++ mapping!" );
+ if (! _aUno2Cpp.is())
+ {
+ throw RuntimeException(
+ "cannot get uno to c++ mapping!",
+ getXWeak() );
+ }
+ }
+ }
+ return _aUno2Cpp;
+}
+
+uno_Interface * IdlReflectionServiceImpl::mapToUno(
+ const Any & rObj, typelib_InterfaceTypeDescription * pTo )
+{
+ Reference< XInterface > xObj;
+ if (extract( rObj, pTo, xObj, this ))
+ return static_cast<uno_Interface *>(getCpp2Uno().mapInterface( xObj.get(), pTo ));
+
+ throw RuntimeException(
+ "illegal object given!",
+ getXWeak() );
+}
+
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_CoreReflection_get_implementation(
+ css::uno::XComponentContext * context,
+ css::uno::Sequence<css::uno::Any> const & arguments)
+{
+ SAL_WARN_IF(
+ arguments.hasElements(), "stoc", "unexpected singleton arguments");
+ return cppu::acquire(new stoc_corefl::IdlReflectionServiceImpl(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/crenum.cxx b/stoc/source/corereflection/crenum.cxx
new file mode 100644
index 0000000000..2cb07c9b5e
--- /dev/null
+++ b/stoc/source/corereflection/crenum.cxx
@@ -0,0 +1,158 @@
+/* -*- 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 "base.hxx"
+
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+#include <com/sun/star/reflection/XIdlField2.hpp>
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace stoc_corefl
+{
+
+namespace {
+
+typedef cppu::ImplInheritanceHelper<IdlMemberImpl, XIdlField, XIdlField2> IdlEnumFieldImpl_Base;
+class IdlEnumFieldImpl : public IdlEnumFieldImpl_Base
+{
+ sal_Int32 _nValue;
+
+public:
+ IdlEnumFieldImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, sal_Int32 nValue )
+ : IdlEnumFieldImpl_Base( pReflection, rName, pTypeDescr, pTypeDescr )
+ , _nValue( nValue )
+ {}
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlField
+ virtual Reference< XIdlClass > SAL_CALL getType() override;
+ virtual FieldAccessMode SAL_CALL getAccessMode() override;
+ virtual Any SAL_CALL get( const Any & rObj ) override;
+ virtual void SAL_CALL set( const Any & rObj, const Any & rValue ) override;
+ // XIdlField2: getType, getAccessMode and get are equal to XIdlField
+ virtual void SAL_CALL set( Any & rObj, const Any & rValue ) override;
+};
+
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlEnumFieldImpl::getDeclaringClass()
+{
+ return IdlMemberImpl::getDeclaringClass();
+}
+
+OUString IdlEnumFieldImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlField
+
+Reference< XIdlClass > IdlEnumFieldImpl::getType()
+{
+ return getDeclaringClass();
+}
+
+FieldAccessMode IdlEnumFieldImpl::getAccessMode()
+{
+ return FieldAccessMode_READONLY;
+}
+
+Any IdlEnumFieldImpl::get( const Any & )
+{
+ return Any( &_nValue, getTypeDescr() );
+}
+
+void IdlEnumFieldImpl::set( const Any &, const Any & )
+{
+ throw IllegalAccessException(
+ "cannot set enum field, it is constant",
+ getXWeak() );
+}
+
+void IdlEnumFieldImpl::set( Any &, const Any & )
+{
+ throw IllegalAccessException(
+ "cannot set enum field, it is constant",
+ getXWeak() );
+}
+
+
+EnumIdlClassImpl::~EnumIdlClassImpl()
+{
+}
+
+// IdlClassImpl modifications
+
+Reference< XIdlField > EnumIdlClassImpl::getField( const OUString & rName )
+{
+ if (! m_xFields)
+ getFields(); // init members
+
+ const OUString2Field::const_iterator iFind( _aName2Field.find( rName ) );
+ if (iFind != _aName2Field.end())
+ return (*iFind).second;
+ else
+ return Reference< XIdlField >();
+}
+
+Sequence< Reference< XIdlField > > EnumIdlClassImpl::getFields()
+{
+ if (! m_xFields)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xFields)
+ {
+ sal_Int32 nFields = getTypeDescr()->nEnumValues;
+ Sequence< Reference< XIdlField > > aFields( nFields );
+ Reference< XIdlField > * pSeq = aFields.getArray();
+
+ while (nFields--)
+ {
+ OUString aName( getTypeDescr()->ppEnumNames[nFields] );
+ _aName2Field[aName] = pSeq[nFields] = new IdlEnumFieldImpl(
+ getReflection(), aName, IdlClassImpl::getTypeDescr(), getTypeDescr()->pEnumValues[nFields] );
+ }
+
+ m_xFields = std::move( aFields );
+ }
+ }
+ return *m_xFields;
+}
+
+void EnumIdlClassImpl::createObject( Any & rObj )
+{
+ sal_Int32 eVal =
+ reinterpret_cast<typelib_EnumTypeDescription *>(IdlClassImpl::getTypeDescr())->nDefaultEnumValue;
+ rObj.setValue( &eVal, IdlClassImpl::getTypeDescr() );
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/criface.cxx b/stoc/source/corereflection/criface.cxx
new file mode 100644
index 0000000000..23d3d9bae2
--- /dev/null
+++ b/stoc/source/corereflection/criface.cxx
@@ -0,0 +1,830 @@
+/* -*- 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 <cstddef>
+#include <limits>
+
+#ifdef SAL_UNX
+#include <sal/alloca.h>
+#endif
+#include <o3tl/any.hxx>
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+
+#include "base.hxx"
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/typeprovider.hxx>
+
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::uno;
+
+namespace {
+
+std::size_t multipleOf16(std::size_t n) {
+ assert(n <= std::numeric_limits<std::size_t>::max() - 15);
+ return (n + 15) & ~std::size_t(15);
+}
+
+}
+
+namespace stoc_corefl
+{
+
+namespace {
+
+typedef cppu::ImplInheritanceHelper<IdlMemberImpl, XIdlField, XIdlField2> IdlAttributeFieldImpl_Base;
+class IdlAttributeFieldImpl : public IdlAttributeFieldImpl_Base
+{
+public:
+ typelib_InterfaceAttributeTypeDescription * getAttributeTypeDescr() const
+ { return reinterpret_cast<typelib_InterfaceAttributeTypeDescription *>(getTypeDescr()); }
+
+ IdlAttributeFieldImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr )
+ : IdlAttributeFieldImpl_Base( pReflection, rName, pTypeDescr, pDeclTypeDescr )
+ {}
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlField
+ virtual Reference< XIdlClass > SAL_CALL getType() override;
+ virtual FieldAccessMode SAL_CALL getAccessMode() override;
+ virtual Any SAL_CALL get( const Any & rObj ) override;
+ virtual void SAL_CALL set( const Any & rObj, const Any & rValue ) override;
+ // XIdlField2: getType, getAccessMode and get are equal to XIdlField
+ virtual void SAL_CALL set( Any & rObj, const Any & rValue ) override;
+
+private:
+ void checkException(
+ uno_Any * exception, Reference< XInterface > const & context) const;
+};
+
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlAttributeFieldImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ {
+ OUString aName(getAttributeTypeDescr()->aBase.aBase.pTypeName);
+ sal_Int32 i = aName.indexOf(':');
+ OSL_ASSERT(i >= 0);
+ _xDeclClass = getReflection()->forName(aName.copy(0, i));
+ }
+ }
+ return _xDeclClass;
+}
+
+OUString IdlAttributeFieldImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlField
+
+Reference< XIdlClass > IdlAttributeFieldImpl::getType()
+{
+ return getReflection()->forType(
+ getAttributeTypeDescr()->pAttributeTypeRef );
+}
+
+FieldAccessMode IdlAttributeFieldImpl::getAccessMode()
+{
+ return (getAttributeTypeDescr()->bReadOnly
+ ? FieldAccessMode_READONLY : FieldAccessMode_READWRITE);
+}
+
+Any IdlAttributeFieldImpl::get( const Any & rObj )
+{
+ uno_Interface * pUnoI = getReflection()->mapToUno(
+ rObj, reinterpret_cast<typelib_InterfaceTypeDescription *>(getDeclTypeDescr()) );
+ OSL_ENSURE( pUnoI, "### illegal destination object given!" );
+ if (pUnoI)
+ {
+ TypeDescription aTD( getAttributeTypeDescr()->pAttributeTypeRef );
+ typelib_TypeDescription * pTD = aTD.get();
+
+ uno_Any aExc;
+ uno_Any * pExc = &aExc;
+ void * pReturn = alloca( pTD->nSize );
+
+ (*pUnoI->pDispatcher)( pUnoI, getTypeDescr(), pReturn, nullptr, &pExc );
+ (*pUnoI->release)( pUnoI );
+
+ checkException(pExc, *o3tl::doAccess<Reference<XInterface>>(rObj));
+ Any aRet;
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_constructAndConvert( &aRet, pReturn, pTD, getReflection()->getUno2Cpp().get() );
+ uno_destructData( pReturn, pTD, nullptr );
+ return aRet;
+ }
+ throw IllegalArgumentException(
+ "illegal object given!",
+ getXWeak(), 0 );
+}
+
+void IdlAttributeFieldImpl::set( Any & rObj, const Any & rValue )
+{
+ if (getAttributeTypeDescr()->bReadOnly)
+ {
+ throw IllegalAccessException(
+ "cannot set readonly attribute!",
+ getXWeak() );
+ }
+
+ uno_Interface * pUnoI = getReflection()->mapToUno(
+ rObj, reinterpret_cast<typelib_InterfaceTypeDescription *>(getDeclTypeDescr()) );
+ OSL_ENSURE( pUnoI, "### illegal destination object given!" );
+ if (pUnoI)
+ {
+ TypeDescription aTD( getAttributeTypeDescr()->pAttributeTypeRef );
+ typelib_TypeDescription * pTD = aTD.get();
+
+ // construct uno value to be set
+ void * pArgs[1];
+ void * pArg = pArgs[0] = alloca( pTD->nSize );
+
+ bool bAssign;
+ if (pTD->eTypeClass == typelib_TypeClass_ANY)
+ {
+ uno_copyAndConvertData( pArg, const_cast< Any * >(&rValue),
+ pTD, getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (typelib_typedescriptionreference_equals( rValue.getValueTypeRef(), pTD->pWeakRef ))
+ {
+ uno_copyAndConvertData( pArg, const_cast< void * >(rValue.getValue()),
+ pTD, getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ Reference< XInterface > xObj;
+ bAssign = extract(
+ rValue, reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD), xObj,
+ getReflection() );
+ if (bAssign)
+ {
+ *static_cast<void **>(pArg) = getReflection()->getCpp2Uno().mapInterface(
+ xObj.get(), reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+ }
+ }
+ else
+ {
+ typelib_TypeDescription * pValueTD = nullptr;
+ TYPELIB_DANGER_GET( &pValueTD, rValue.getValueTypeRef() );
+ // construct temp uno val to do proper assignment: todo opt
+ void * pTemp = alloca( pValueTD->nSize );
+ uno_copyAndConvertData(
+ pTemp, const_cast<void *>(rValue.getValue()), pValueTD, getReflection()->getCpp2Uno().get() );
+ uno_constructData(
+ pArg, pTD );
+ // assignment does simple conversion
+ bAssign = uno_assignData(
+ pArg, pTD, pTemp, pValueTD, nullptr, nullptr, nullptr );
+ uno_destructData(
+ pTemp, pValueTD, nullptr );
+ TYPELIB_DANGER_RELEASE( pValueTD );
+ }
+
+ if (bAssign)
+ {
+ uno_Any aExc;
+ uno_Any * pExc = &aExc;
+ (*pUnoI->pDispatcher)( pUnoI, getTypeDescr(), nullptr, pArgs, &pExc );
+ (*pUnoI->release)( pUnoI );
+
+ uno_destructData( pArg, pTD, nullptr );
+ checkException(pExc, *o3tl::doAccess<Reference<XInterface>>(rObj));
+ return;
+ }
+ (*pUnoI->release)( pUnoI );
+
+ throw IllegalArgumentException(
+ "illegal value given!",
+ *o3tl::doAccess<Reference<XInterface>>(rObj), 1 );
+ }
+ throw IllegalArgumentException(
+ "illegal destination object given!",
+ getXWeak(), 0 );
+}
+
+void IdlAttributeFieldImpl::set( const Any & rObj, const Any & rValue )
+{
+ IdlAttributeFieldImpl::set( const_cast< Any & >( rObj ), rValue );
+}
+
+void IdlAttributeFieldImpl::checkException(
+ uno_Any * exception, Reference< XInterface > const & context) const
+{
+ if (exception == nullptr)
+ return;
+
+ Any e;
+ uno_any_destruct(&e, reinterpret_cast< uno_ReleaseFunc >(cpp_release));
+ uno_type_any_constructAndConvert(
+ &e, exception->pData, exception->pType,
+ getReflection()->getUno2Cpp().get());
+ uno_any_destruct(exception, nullptr);
+ if (!e.isExtractableTo(
+ cppu::UnoType<RuntimeException>::get()))
+ {
+ throw WrappedTargetRuntimeException(
+ "non-RuntimeException occurred when accessing an"
+ " interface type attribute",
+ context, e);
+ }
+ cppu::throwException(e);
+}
+
+namespace {
+
+typedef cppu::ImplInheritanceHelper<IdlMemberImpl, XIdlMethod> IdlInterfaceMethodImpl_Base;
+class IdlInterfaceMethodImpl : public IdlInterfaceMethodImpl_Base
+{
+ std::optional<Sequence< Reference< XIdlClass > >> m_xExceptionTypes;
+ std::optional<Sequence< Reference< XIdlClass > >> m_xParamTypes;
+ std::optional<Sequence< ParamInfo >> m_xParamInfos;
+
+public:
+ typelib_InterfaceMethodTypeDescription * getMethodTypeDescr() const
+ { return reinterpret_cast<typelib_InterfaceMethodTypeDescription *>(getTypeDescr()); }
+
+ IdlInterfaceMethodImpl( IdlReflectionServiceImpl * pReflection, const OUString & rName,
+ typelib_TypeDescription * pTypeDescr, typelib_TypeDescription * pDeclTypeDescr )
+ : IdlInterfaceMethodImpl_Base( pReflection, rName, pTypeDescr, pDeclTypeDescr )
+ {}
+
+ // XTypeProvider
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XIdlMember
+ virtual Reference< XIdlClass > SAL_CALL getDeclaringClass() override;
+ virtual OUString SAL_CALL getName() override;
+ // XIdlMethod
+ virtual Reference< XIdlClass > SAL_CALL getReturnType() override;
+ virtual Sequence< Reference< XIdlClass > > SAL_CALL getParameterTypes() override;
+ virtual Sequence< ParamInfo > SAL_CALL getParameterInfos() override;
+ virtual Sequence< Reference< XIdlClass > > SAL_CALL getExceptionTypes() override;
+ virtual MethodMode SAL_CALL getMode() override;
+ virtual Any SAL_CALL invoke( const Any & rObj, Sequence< Any > & rArgs ) override;
+};
+
+}
+
+// XTypeProvider
+
+Sequence< sal_Int8 > IdlInterfaceMethodImpl::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XIdlMember
+
+Reference< XIdlClass > IdlInterfaceMethodImpl::getDeclaringClass()
+{
+ if (! _xDeclClass.is())
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _xDeclClass.is())
+ {
+ OUString aName(getMethodTypeDescr()->aBase.aBase.pTypeName);
+ sal_Int32 i = aName.indexOf(':');
+ OSL_ASSERT(i >= 0);
+ _xDeclClass = getReflection()->forName(aName.copy(0, i));
+ }
+ }
+ return _xDeclClass;
+}
+
+OUString IdlInterfaceMethodImpl::getName()
+{
+ return IdlMemberImpl::getName();
+}
+
+// XIdlMethod
+
+Reference< XIdlClass > SAL_CALL IdlInterfaceMethodImpl::getReturnType()
+{
+ return getReflection()->forType( getMethodTypeDescr()->pReturnTypeRef );
+}
+
+Sequence< Reference< XIdlClass > > IdlInterfaceMethodImpl::getExceptionTypes()
+{
+ if (! m_xExceptionTypes)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xExceptionTypes)
+ {
+ sal_Int32 nExc = getMethodTypeDescr()->nExceptions;
+ Sequence< Reference< XIdlClass > > aTempExceptionTypes( nExc );
+ Reference< XIdlClass > * pExceptionTypes = aTempExceptionTypes.getArray();
+
+ typelib_TypeDescriptionReference ** ppExc =
+ getMethodTypeDescr()->ppExceptions;
+ IdlReflectionServiceImpl * pRefl = getReflection();
+
+ while (nExc--)
+ pExceptionTypes[nExc] = pRefl->forType( ppExc[nExc] );
+
+ m_xExceptionTypes = std::move(aTempExceptionTypes);
+ }
+ }
+ return *m_xExceptionTypes;
+}
+
+Sequence< Reference< XIdlClass > > IdlInterfaceMethodImpl::getParameterTypes()
+{
+ if (! m_xParamTypes)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xParamTypes)
+ {
+ sal_Int32 nParams = getMethodTypeDescr()->nParams;
+ Sequence< Reference< XIdlClass > > aTempParamTypes( nParams );
+ Reference< XIdlClass > * pParamTypes = aTempParamTypes.getArray();
+
+ typelib_MethodParameter * pTypelibParams =
+ getMethodTypeDescr()->pParams;
+ IdlReflectionServiceImpl * pRefl = getReflection();
+
+ while (nParams--)
+ pParamTypes[nParams] = pRefl->forType( pTypelibParams[nParams].pTypeRef );
+
+ m_xParamTypes = std::move(aTempParamTypes);
+ }
+ }
+ return *m_xParamTypes;
+}
+
+Sequence< ParamInfo > IdlInterfaceMethodImpl::getParameterInfos()
+{
+ if (! m_xParamInfos)
+ {
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! m_xParamInfos)
+ {
+ sal_Int32 nParams = getMethodTypeDescr()->nParams;
+ Sequence< ParamInfo > aTempParamInfos( nParams );
+ ParamInfo * pParamInfos = aTempParamInfos.getArray();
+
+ typelib_MethodParameter * pTypelibParams =
+ getMethodTypeDescr()->pParams;
+
+ if (m_xParamTypes) // use param types
+ {
+ const Reference< XIdlClass > * pParamTypes = m_xParamTypes->getConstArray();
+
+ while (nParams--)
+ {
+ const typelib_MethodParameter & rParam = pTypelibParams[nParams];
+ ParamInfo & rInfo = pParamInfos[nParams];
+ rInfo.aName = rParam.pName;
+ if (rParam.bIn)
+ rInfo.aMode = (rParam.bOut ? ParamMode_INOUT : ParamMode_IN);
+ else
+ rInfo.aMode = ParamMode_OUT;
+ rInfo.aType = pParamTypes[nParams];
+ }
+ }
+ else // make also param types sequence if not already initialized
+ {
+ Sequence< Reference< XIdlClass > > aTempParamTypes( nParams );
+ Reference< XIdlClass > * pParamTypes = aTempParamTypes.getArray();
+
+ IdlReflectionServiceImpl * pRefl = getReflection();
+
+ while (nParams--)
+ {
+ const typelib_MethodParameter & rParam = pTypelibParams[nParams];
+ ParamInfo & rInfo = pParamInfos[nParams];
+ rInfo.aName = rParam.pName;
+ if (rParam.bIn)
+ rInfo.aMode = (rParam.bOut ? ParamMode_INOUT : ParamMode_IN);
+ else
+ rInfo.aMode = ParamMode_OUT;
+ rInfo.aType = pParamTypes[nParams] = pRefl->forType( rParam.pTypeRef );
+ }
+
+ m_xParamTypes = std::move(aTempParamTypes);
+ }
+
+ m_xParamInfos = std::move(aTempParamInfos);
+ }
+ }
+ return *m_xParamInfos;
+}
+
+MethodMode SAL_CALL IdlInterfaceMethodImpl::getMode()
+{
+ return
+ getMethodTypeDescr()->bOneWay ? MethodMode_ONEWAY : MethodMode_TWOWAY;
+}
+
+Any SAL_CALL IdlInterfaceMethodImpl::invoke( const Any & rObj, Sequence< Any > & rArgs )
+{
+ if (auto ifc = o3tl::tryAccess<css::uno::Reference<css::uno::XInterface>>(
+ rObj))
+ {
+ // acquire()/ release()
+ if (rtl_ustr_ascii_compare( getTypeDescr()->pTypeName->buffer,
+ "com.sun.star.uno.XInterface::acquire" ) == 0)
+ {
+ (*ifc)->acquire();
+ return Any();
+ }
+ else if (rtl_ustr_ascii_compare( getTypeDescr()->pTypeName->buffer,
+ "com.sun.star.uno.XInterface::release" ) == 0)
+ {
+ (*ifc)->release();
+ return Any();
+ }
+ }
+
+ uno_Interface * pUnoI = getReflection()->mapToUno(
+ rObj, reinterpret_cast<typelib_InterfaceTypeDescription *>(getDeclTypeDescr()) );
+ OSL_ENSURE( pUnoI, "### illegal destination object given!" );
+ if (pUnoI)
+ {
+ sal_Int32 nParams = getMethodTypeDescr()->nParams;
+ if (rArgs.getLength() != nParams)
+ {
+ (*pUnoI->release)( pUnoI );
+ throw IllegalArgumentException(
+ "expected " + OUString::number(nParams) +
+ " arguments, got " + OUString::number(rArgs.getLength()),
+ *o3tl::doAccess<Reference<XInterface>>(rObj), 1 );
+ }
+
+ Any * pCppArgs = rArgs.getArray();
+ typelib_MethodParameter * pParams = getMethodTypeDescr()->pParams;
+ typelib_TypeDescription * pReturnType = nullptr;
+ TYPELIB_DANGER_GET(
+ &pReturnType, getMethodTypeDescr()->pReturnTypeRef );
+
+ // C/C++ ABIs typically assume that structs are padded at the end, and
+ // that those padding bytes may be written to (e.g., to write into the
+ // end of a "short" struct by writing the full contents of a "long"
+ // register); so create enough space here (assuming that no ABI requires
+ // padding larger than 16 byte boundaries):
+ void * pUnoReturn = (pReturnType->nSize == 0) ? nullptr : alloca( multipleOf16(pReturnType->nSize) );
+ void ** ppUnoArgs = static_cast<void **>(alloca( sizeof(void *) * nParams *2 ));
+ typelib_TypeDescription ** ppParamTypes = reinterpret_cast<typelib_TypeDescription **>(ppUnoArgs + nParams);
+
+ // convert arguments
+ for ( sal_Int32 nPos = 0; nPos < nParams; ++nPos )
+ {
+ ppParamTypes[nPos] = nullptr;
+ TYPELIB_DANGER_GET( ppParamTypes + nPos, pParams[nPos].pTypeRef );
+ typelib_TypeDescription * pTD = ppParamTypes[nPos];
+
+ ppUnoArgs[nPos] = alloca( pTD->nSize );
+ if (pParams[nPos].bIn)
+ {
+ bool bAssign;
+ if (typelib_typedescriptionreference_equals(
+ pCppArgs[nPos].getValueTypeRef(), pTD->pWeakRef ))
+ {
+ uno_type_copyAndConvertData(
+ ppUnoArgs[nPos], const_cast<void *>(pCppArgs[nPos].getValue()),
+ pCppArgs[nPos].getValueTypeRef(), getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_ANY)
+ {
+ uno_type_any_constructAndConvert(
+ static_cast<uno_Any *>(ppUnoArgs[nPos]), const_cast<void *>(pCppArgs[nPos].getValue()),
+ pCppArgs[nPos].getValueTypeRef(), getReflection()->getCpp2Uno().get() );
+ bAssign = true;
+ }
+ else if (pTD->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ Reference< XInterface > xDest;
+ bAssign = extract(
+ pCppArgs[nPos], reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD),
+ xDest, getReflection() );
+ if (bAssign)
+ {
+ *static_cast<void **>(ppUnoArgs[nPos]) = getReflection()->getCpp2Uno().mapInterface(
+ xDest.get(), reinterpret_cast<typelib_InterfaceTypeDescription *>(pTD) );
+ }
+ }
+ else
+ {
+ typelib_TypeDescription * pValueTD = nullptr;
+ TYPELIB_DANGER_GET( &pValueTD, pCppArgs[nPos].getValueTypeRef() );
+ // construct temp uno val to do proper assignment: todo opt
+ void * pTemp = alloca( pValueTD->nSize );
+ uno_copyAndConvertData(
+ pTemp, const_cast<void *>(pCppArgs[nPos].getValue()), pValueTD,
+ getReflection()->getCpp2Uno().get() );
+ uno_constructData(
+ ppUnoArgs[nPos], pTD );
+ // assignment does simple conversion
+ bAssign = uno_assignData(
+ ppUnoArgs[nPos], pTD, pTemp, pValueTD, nullptr, nullptr, nullptr );
+ uno_destructData(
+ pTemp, pValueTD, nullptr );
+ TYPELIB_DANGER_RELEASE( pValueTD );
+ }
+
+ if (! bAssign)
+ {
+ IllegalArgumentException aExc(
+ "cannot coerce argument type during corereflection call:"
+ "\narg no.: " + OUString::number(nPos)
+ + " expected: \"" + OUString::unacquired(&pTD->pTypeName)
+ + "\" actual: \"" + OUString::unacquired(&pCppArgs[nPos].getValueTypeRef()->pTypeName)
+ + "\"",
+ *o3tl::doAccess<Reference<XInterface>>(rObj), static_cast<sal_Int16>(nPos) );
+
+ // cleanup
+ while (nPos--)
+ {
+ if (pParams[nPos].bIn)
+ uno_destructData( ppUnoArgs[nPos], ppParamTypes[nPos], nullptr );
+ TYPELIB_DANGER_RELEASE( ppParamTypes[nPos] );
+ }
+ TYPELIB_DANGER_RELEASE( pReturnType );
+ (*pUnoI->release)( pUnoI );
+
+ throw aExc;
+ }
+ }
+ }
+
+ uno_Any aUnoExc;
+ uno_Any * pUnoExc = &aUnoExc;
+
+ (*pUnoI->pDispatcher)(
+ pUnoI, getTypeDescr(), pUnoReturn, ppUnoArgs, &pUnoExc );
+ (*pUnoI->release)( pUnoI );
+
+ Any aRet;
+ if (pUnoExc)
+ {
+ // cleanup
+ while (nParams--)
+ {
+ if (pParams[nParams].bIn)
+ uno_destructData( ppUnoArgs[nParams], ppParamTypes[nParams], nullptr );
+ TYPELIB_DANGER_RELEASE( ppParamTypes[nParams] );
+ }
+ TYPELIB_DANGER_RELEASE( pReturnType );
+
+ uno_any_destruct(&aRet,
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_type_copyAndConvertData(&aRet, pUnoExc, cppu::UnoType<Any>::get().getTypeLibType(),
+ getReflection()->getUno2Cpp().get() );
+ uno_any_destruct( pUnoExc, nullptr );
+ throw InvocationTargetException("exception occurred during invocation!",
+ *o3tl::doAccess<Reference<XInterface>>(rObj), aRet);
+ }
+ else
+ {
+ // reconvert arguments and cleanup
+ while (nParams--)
+ {
+ if (pParams[nParams].bOut) // write back
+ {
+ uno_any_destruct(
+ &pCppArgs[nParams],
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_constructAndConvert(
+ &pCppArgs[nParams], ppUnoArgs[nParams], ppParamTypes[nParams],
+ getReflection()->getUno2Cpp().get() );
+ }
+ uno_destructData( ppUnoArgs[nParams], ppParamTypes[nParams], nullptr );
+ TYPELIB_DANGER_RELEASE( ppParamTypes[nParams] );
+ }
+ uno_any_destruct(
+ &aRet, reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ uno_any_constructAndConvert(
+ &aRet, pUnoReturn, pReturnType,
+ getReflection()->getUno2Cpp().get() );
+ uno_destructData( pUnoReturn, pReturnType, nullptr );
+ TYPELIB_DANGER_RELEASE( pReturnType );
+ }
+ return aRet;
+ }
+ throw IllegalArgumentException(
+ "illegal destination object given!",
+ getXWeak(), 0 );
+}
+
+
+InterfaceIdlClassImpl::~InterfaceIdlClassImpl()
+{
+ for ( sal_Int32 nPos = _nMethods + _nAttributes; nPos--; )
+ typelib_typedescription_release( _pSortedMemberInit[nPos].second );
+}
+
+
+Sequence< Reference< XIdlClass > > InterfaceIdlClassImpl::getSuperclasses()
+{
+ ::osl::MutexGuard aGuard(getMutexAccess());
+ if (!_xSuperClasses.hasElements()) {
+ typelib_InterfaceTypeDescription * pType = getTypeDescr();
+ _xSuperClasses.realloc(pType->nBaseTypes);
+ auto pSuperClasses = _xSuperClasses.getArray();
+ for (sal_Int32 i = 0; i < pType->nBaseTypes; ++i) {
+ pSuperClasses[i] = getReflection()->forType(
+ &pType->ppBaseTypes[i]->aBase);
+ OSL_ASSERT(_xSuperClasses[i].is());
+ }
+ }
+ return _xSuperClasses;
+}
+
+void InterfaceIdlClassImpl::initMembers()
+{
+ sal_Int32 nAll = getTypeDescr()->nAllMembers;
+ std::unique_ptr<MemberInit[]> pSortedMemberInit(new MemberInit[nAll]);
+ typelib_TypeDescriptionReference ** ppAllMembers = getTypeDescr()->ppAllMembers;
+
+ for ( sal_Int32 nPos = 0; nPos < nAll; ++nPos )
+ {
+ sal_Int32 nIndex;
+ if (ppAllMembers[nPos]->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
+ {
+ // methods to front
+ nIndex = _nMethods;
+ ++_nMethods;
+ }
+ else
+ {
+ ++_nAttributes;
+ nIndex = (nAll - _nAttributes);
+ // attributes at the back
+ }
+
+ typelib_TypeDescription * pTD = nullptr;
+ typelib_typedescriptionreference_getDescription( &pTD, ppAllMembers[nPos] );
+ assert(pTD && "### cannot get type description!");
+ pSortedMemberInit[nIndex].first = reinterpret_cast<typelib_InterfaceMemberTypeDescription *>(pTD)->pMemberName;
+ pSortedMemberInit[nIndex].second = pTD;
+ }
+
+ _pSortedMemberInit = std::move(pSortedMemberInit);
+}
+
+sal_Bool InterfaceIdlClassImpl::isAssignableFrom( const Reference< XIdlClass > & xType )
+{
+ if (xType.is() && xType->getTypeClass() == TypeClass_INTERFACE)
+ {
+ if (equals( xType ))
+ return true;
+ else
+ {
+ const Sequence< Reference< XIdlClass > > & rSeq = xType->getSuperclasses();
+ if (std::any_of(rSeq.begin(), rSeq.end(),
+ [this](const Reference<XIdlClass>& rType){ return isAssignableFrom(rType); }))
+ return true;
+ }
+ }
+ return false;
+}
+
+Uik InterfaceIdlClassImpl::getUik()
+{
+ return Uik(0, 0, 0, 0, 0);
+ // Uiks are deprecated and this function must not be called
+}
+
+Sequence< Reference< XIdlMethod > > InterfaceIdlClassImpl::getMethods()
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ // create methods sequence
+ Sequence< Reference< XIdlMethod > > aRet( _nMethods );
+ Reference< XIdlMethod > * pRet = aRet.getArray();
+ for ( sal_Int32 nPos = _nMethods; nPos--; )
+ {
+
+ /*_aName2Method[_pSortedMemberInit[nPos].first] = */pRet[nPos] = new IdlInterfaceMethodImpl(
+ getReflection(), _pSortedMemberInit[nPos].first,
+ _pSortedMemberInit[nPos].second, IdlClassImpl::getTypeDescr() );
+ }
+ return aRet;
+}
+
+Sequence< Reference< XIdlField > > InterfaceIdlClassImpl::getFields()
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ // create fields sequence
+ Sequence< Reference< XIdlField > > aRet( _nAttributes );
+ Reference< XIdlField > * pRet = aRet.getArray();
+ for ( sal_Int32 nPos = _nAttributes; nPos--; )
+ {
+ /*_aName2Field[_pSortedMemberInit[_nMethods+nPos].first] = */pRet[_nAttributes-nPos-1] =
+ new IdlAttributeFieldImpl(
+ getReflection(), _pSortedMemberInit[_nMethods+nPos].first,
+ _pSortedMemberInit[_nMethods+nPos].second, IdlClassImpl::getTypeDescr() );
+ }
+ return aRet;
+}
+
+Reference< XIdlMethod > InterfaceIdlClassImpl::getMethod( const OUString & rName )
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ Reference< XIdlMethod > xRet;
+
+ // try weak map
+ const OUString2Method::const_iterator iFind( _aName2Method.find( rName ) );
+ if (iFind != _aName2Method.end())
+ xRet = (*iFind).second; // harden ref
+
+ if (! xRet.is())
+ {
+ for ( sal_Int32 nPos = _nMethods; nPos--; )
+ {
+ if (_pSortedMemberInit[nPos].first == rName)
+ {
+ _aName2Method[rName] = xRet = new IdlInterfaceMethodImpl(
+ getReflection(), rName,
+ _pSortedMemberInit[nPos].second, IdlClassImpl::getTypeDescr() );
+ break;
+ }
+ }
+ }
+ return xRet;
+}
+
+Reference< XIdlField > InterfaceIdlClassImpl::getField( const OUString & rName )
+{
+ ::osl::MutexGuard aGuard( getMutexAccess() );
+ if (! _pSortedMemberInit)
+ initMembers();
+
+ Reference< XIdlField > xRet;
+
+ // try weak map
+ const OUString2Field::const_iterator iFind( _aName2Field.find( rName ) );
+ if (iFind != _aName2Field.end())
+ xRet = (*iFind).second; // harden ref
+
+ if (! xRet.is())
+ {
+ for ( sal_Int32 nPos = _nAttributes; nPos--; )
+ {
+ if (_pSortedMemberInit[_nMethods+nPos].first == rName)
+ {
+ _aName2Field[rName] = xRet = new IdlAttributeFieldImpl(
+ getReflection(), rName,
+ _pSortedMemberInit[_nMethods+nPos].second, IdlClassImpl::getTypeDescr() );
+ break;
+ }
+ }
+ }
+ return xRet;
+}
+
+void InterfaceIdlClassImpl::createObject( Any & rObj )
+{
+ // interfaces cannot be constructed
+ rObj.clear();
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/dump.cxx b/stoc/source/corereflection/dump.cxx
new file mode 100644
index 0000000000..0905393db9
--- /dev/null
+++ b/stoc/source/corereflection/dump.cxx
@@ -0,0 +1,358 @@
+/* -*- 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 <bitset>
+
+#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/IllegalArgumentException.hpp>
+#include <com/sun/star/reflection/XConstantTypeDescription.hpp>
+#include <com/sun/star/reflection/XConstantsTypeDescription.hpp>
+#include <com/sun/star/reflection/XDump.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/Sequence.hxx>
+#include <com/sun/star/uno/Type.hxx>
+#include <com/sun/star/uno/TypeClass.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <config_typesizes.h>
+#include <cppu/unotype.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <o3tl/unreachable.hxx>
+#include <osl/mutex.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <typelib/typedescription.h>
+#include <typelib/typedescription.hxx>
+#include <uno/sequence2.h>
+
+namespace com::sun::star::uno
+{
+class XInterface;
+}
+
+namespace
+{
+template <typename T> OUString hex(T value, sal_Int32 width)
+{
+ OUStringBuffer buf(OUString::number(value, 16));
+ while (buf.getLength() < width)
+ {
+ buf.insert(0, '0');
+ }
+ return buf.makeStringAndClear();
+}
+
+css::uno::TypeDescription getTypeDescription(css::uno::Type const& type)
+{
+ typelib_TypeDescription* d = nullptr;
+ type.getDescription(&d);
+ return css::uno::TypeDescription(d);
+}
+
+OUString
+getIdentifier(css::uno::Reference<css::reflection::XConstantTypeDescription> const& constant)
+{
+ auto const n = constant->getName();
+ auto const i = n.lastIndexOf('.');
+ if (i == -1 || i == n.getLength() - 1)
+ {
+ throw css::uno::DeploymentException("bad constant name " + n);
+ }
+ return n.copy(i + 1);
+}
+
+OUString
+dumpBitset(css::uno::Sequence<css::uno::Reference<css::reflection::XConstantTypeDescription>> const&
+ constants,
+ sal_uInt64 value)
+{
+ OUStringBuffer buf;
+ auto a = value;
+ for (auto const& i : constants)
+ {
+ sal_uInt64 c;
+ if ((i->getConstantValue() >>= c) && std::bitset<64>{ c }.count() == 1 && (a & c) != 0)
+ {
+ if (!buf.isEmpty())
+ {
+ buf.append('+');
+ }
+ buf.append(getIdentifier(i));
+ a &= ~c;
+ }
+ }
+ return a == 0 && !buf.isEmpty() ? buf.makeStringAndClear() : OUString::number(value);
+}
+
+class Dump : public cppu::BaseMutex, public cppu::WeakComponentImplHelper<css::reflection::XDump>
+{
+public:
+ explicit Dump(css::uno::Reference<css::uno::XComponentContext> const& context)
+ : WeakComponentImplHelper(m_aMutex)
+ , manager_(context->getValueByName(
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager"),
+ css::uno::UNO_QUERY_THROW)
+ {
+ }
+
+ void SAL_CALL disposing() override
+ {
+ osl::MutexGuard g(m_aMutex);
+ manager_.clear();
+ }
+
+ OUString SAL_CALL dumpValue(css::uno::Any const& value) override
+ {
+ switch (value.getValueTypeClass())
+ {
+ case css::uno::TypeClass_VOID:
+ return "void";
+ case css::uno::TypeClass_BOOLEAN:
+ return OUString::boolean(value.get<bool>());
+ case css::uno::TypeClass_BYTE:
+ return OUString::number(value.get<sal_Int8>());
+ case css::uno::TypeClass_SHORT:
+ return OUString::number(value.get<sal_Int16>());
+ case css::uno::TypeClass_UNSIGNED_SHORT:
+ return OUString::number(value.get<sal_uInt16>());
+ case css::uno::TypeClass_LONG:
+ return OUString::number(value.get<sal_Int32>());
+ case css::uno::TypeClass_UNSIGNED_LONG:
+ return OUString::number(value.get<sal_uInt32>());
+ case css::uno::TypeClass_HYPER:
+ return OUString::number(value.get<sal_Int64>());
+ case css::uno::TypeClass_UNSIGNED_HYPER:
+ return OUString::number(value.get<sal_uInt64>());
+ case css::uno::TypeClass_FLOAT:
+ return OUString::number(value.get<float>());
+ case css::uno::TypeClass_DOUBLE:
+ return OUString::number(value.get<double>());
+ case css::uno::TypeClass_CHAR:
+ return "U+" + hex(value.get<sal_Unicode>(), 16);
+ case css::uno::TypeClass_STRING:
+ {
+ auto const s = value.get<OUString>();
+ OUStringBuffer buf;
+ for (sal_Int32 i = 0; i != s.getLength();)
+ {
+ auto const c = s.iterateCodePoints(&i);
+ if (c >= u8' ' && c <= u8'~')
+ {
+ if (c == u8'\"' || c == u8'\\')
+ {
+ buf.append('\\');
+ }
+ buf.append(char(c));
+ }
+ else if (c <= 0xFFFF)
+ {
+ buf.append("\\u" + hex(c, 4));
+ }
+ else
+ {
+ buf.append("\\U" + hex(c, 8));
+ }
+ }
+ return "\"" + buf + "\"";
+ }
+ case css::uno::TypeClass_TYPE:
+ return value.get<css::uno::Type>().getTypeName();
+ case css::uno::TypeClass_SEQUENCE:
+ {
+ css::uno::Type const t(reinterpret_cast<typelib_IndirectTypeDescription const*>(
+ getTypeDescription(value.getValueType()).get())
+ ->pType);
+ auto const n = getTypeDescription(t).get()->nSize;
+ auto const s = *static_cast<uno_Sequence* const*>(value.getValue());
+ OUStringBuffer buf;
+ for (sal_Int32 i = 0; i != s->nElements; ++i)
+ {
+ if (i != 0)
+ {
+ buf.append(", ");
+ }
+ css::uno::Any const e(s->elements + i * n, t);
+ buf.append(t == cppu::UnoType<css::uno::Any>::get() ? dumpAny(e)
+ : dumpValue(e));
+ }
+ return "[" + buf + "]";
+ }
+ case css::uno::TypeClass_ENUM:
+ {
+ auto const d = getTypeDescription(value.getValueType());
+ auto const ed = reinterpret_cast<typelib_EnumTypeDescription const*>(d.get());
+ auto const e = *static_cast<sal_Int32 const*>(value.getValue());
+ for (sal_Int32 i = 0; i != ed->nEnumValues; ++i)
+ {
+ if (ed->pEnumValues[i] == e)
+ {
+ return OUString(ed->ppEnumNames[i]);
+ }
+ }
+ return OUString::number(e);
+ }
+ case css::uno::TypeClass_STRUCT:
+ case css::uno::TypeClass_EXCEPTION:
+ {
+ auto const d = getTypeDescription(value.getValueType());
+ OUStringBuffer buf;
+ dumpCompoundType(reinterpret_cast<typelib_CompoundTypeDescription const*>(d.get()),
+ value.getValue(), &buf);
+ return "[" + buf + "]";
+ }
+ case css::uno::TypeClass_INTERFACE:
+ {
+ auto const p = *static_cast<void* const*>(value.getValue());
+ return p == nullptr ? OUString("null")
+ : OUString("0x"
+ + hex(reinterpret_cast<sal_uIntPtr>(p),
+ SAL_TYPES_SIZEOFPOINTER * 2));
+ }
+ default:
+ O3TL_UNREACHABLE;
+ }
+ }
+
+ OUString SAL_CALL dumpAny(css::uno::Any const& value) override
+ {
+ return "[" + value.getValueType().getTypeName() + ": " + dumpValue(value) + "]";
+ }
+
+ OUString SAL_CALL dumpConstant(OUString const& constantsGroup,
+ css::uno::Any const& value) override
+ {
+ css::uno::Reference<css::container::XHierarchicalNameAccess> manager;
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (rBHelper.bDisposed)
+ {
+ throw css::lang::DisposedException("css.reflection.Dumper");
+ }
+ manager = manager_;
+ }
+ css::uno::Reference<css::reflection::XConstantsTypeDescription> g;
+ try
+ {
+ manager_->getByHierarchicalName(constantsGroup) >>= g;
+ }
+ catch (css::container::NoSuchElementException)
+ {
+ }
+ if (!g.is())
+ {
+ throw css::lang::IllegalArgumentException("not a constants group: " + constantsGroup,
+ {}, 0);
+ }
+ auto const s = g->getConstants();
+ switch (value.getValueTypeClass())
+ {
+ case css::uno::TypeClass_BOOLEAN:
+ for (auto const& i : s)
+ {
+ if (i->getConstantValue() == value)
+ {
+ return getIdentifier(i);
+ }
+ }
+ return OUString::boolean(value.get<bool>());
+ case css::uno::TypeClass_BYTE:
+ case css::uno::TypeClass_SHORT:
+ case css::uno::TypeClass_LONG:
+ case css::uno::TypeClass_HYPER:
+ {
+ auto const v = value.get<sal_Int64>();
+ for (auto const& i : s)
+ {
+ sal_Int64 c;
+ if ((i->getConstantValue() >>= c) && c == v)
+ {
+ return getIdentifier(i);
+ }
+ }
+ return v >= 0 ? dumpBitset(s, v) : OUString::number(v);
+ }
+ case css::uno::TypeClass_UNSIGNED_SHORT:
+ case css::uno::TypeClass_UNSIGNED_LONG:
+ case css::uno::TypeClass_UNSIGNED_HYPER:
+ {
+ auto const v = value.get<sal_uInt64>();
+ for (auto const& i : s)
+ {
+ sal_uInt64 c;
+ if ((i->getConstantValue() >>= c) && c == v)
+ {
+ return getIdentifier(i);
+ }
+ }
+ return dumpBitset(s, v);
+ }
+ case css::uno::TypeClass_FLOAT:
+ case css::uno::TypeClass_DOUBLE:
+ {
+ auto const v = value.get<double>();
+ for (auto const& i : s)
+ {
+ double c;
+ if ((i->getConstantValue() >>= c) && c == v)
+ {
+ return getIdentifier(i);
+ }
+ }
+ return OUString::number(v);
+ }
+ default:
+ throw css::lang::IllegalArgumentException(
+ "not a numeric type: " + value.getValueTypeName(), {}, 1);
+ }
+ }
+
+private:
+ css::uno::Reference<css::container::XHierarchicalNameAccess> manager_;
+
+ void dumpCompoundType(typelib_CompoundTypeDescription const* description, void const* data,
+ OUStringBuffer* buffer)
+ {
+ if (auto base = description->pBaseTypeDescription)
+ {
+ dumpCompoundType(base, data, buffer);
+ }
+ for (sal_Int32 i = 0; i != description->nMembers; ++i)
+ {
+ if (!buffer->isEmpty())
+ {
+ buffer->append(", ");
+ }
+ buffer->append(OUString::unacquired(description->ppMemberNames + i) + ": ");
+ css::uno::Type t(description->ppTypeRefs[i]);
+ css::uno::Any const m(static_cast<char const*>(data) + description->pMemberOffsets[i],
+ t);
+ buffer->append(t == cppu::UnoType<css::uno::Any>::get() ? dumpAny(m) : dumpValue(m));
+ }
+ }
+};
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_stoc_Dump_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const& arguments)
+{
+ SAL_WARN_IF(arguments.hasElements(), "stoc", "unexpected singleton arguments");
+ return cppu::acquire(new Dump(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/stoc/source/corereflection/lrucache.hxx b/stoc/source/corereflection/lrucache.hxx
new file mode 100644
index 0000000000..d5eebe804f
--- /dev/null
+++ b/stoc/source/corereflection/lrucache.hxx
@@ -0,0 +1,209 @@
+/* -*- 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_STOC_SOURCE_COREREFLECTION_LRUCACHE_HXX
+#define INCLUDED_STOC_SOURCE_COREREFLECTION_LRUCACHE_HXX
+
+// __CACHE_DIAGNOSE forces cache size to 4 and works only for OUString keys
+// #define __CACHE_DIAGNOSE 1
+
+#include <rtl/ustring.hxx>
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+
+namespace com::sun::star::uno { class Any; }
+
+/** Implementation of a least recently used (lru) cache.
+ <br>
+*/
+template< class t_Key, class t_Val, class t_KeyHash >
+class LRU_Cache
+{
+ struct CacheEntry
+ {
+ t_Key aKey;
+ t_Val aVal;
+ CacheEntry * pPred;
+ CacheEntry * pSucc;
+ };
+ typedef std::unordered_map< t_Key, CacheEntry *, t_KeyHash > t_Key2Element;
+
+ mutable std::mutex _aCacheMutex;
+ sal_Int32 _nCachedElements;
+ t_Key2Element _aKey2Element;
+
+ std::unique_ptr<CacheEntry[]> _pBlock;
+ mutable CacheEntry * _pHead;
+ mutable CacheEntry * _pTail;
+ inline void toFront( CacheEntry * pEntry ) const;
+
+public:
+ /** Constructor:
+ <br>
+ @param nCachedElements number of elements to be cached; default param set to 128
+ */
+ explicit inline LRU_Cache();
+
+ /** Retrieves a value from the cache. Returns default constructed value,
+ if none was found.
+ <br>
+ @param rKey a key
+ @return value
+ */
+ inline t_Val getValue( const t_Key & rKey ) const;
+ /** Sets a value to be cached for given key.
+ <br>
+ @param rKey a key
+ @param rValue a value
+ */
+ inline void setValue( const t_Key & rKey, const t_Val & rValue );
+ /** Clears the cache, thus releasing all cached elements and keys.
+ <br>
+ */
+ inline void clear();
+};
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline LRU_Cache< t_Key, t_Val, t_KeyHash >::LRU_Cache()
+#ifdef __CACHE_DIAGNOSE
+ : _nCachedElements( 4 )
+#else
+ : _nCachedElements( 256 )
+#endif
+ , _pBlock( nullptr )
+ , _pHead( nullptr )
+ , _pTail( nullptr )
+{
+ _pBlock.reset(new CacheEntry[_nCachedElements]);
+ _pHead = _pBlock.get();
+ _pTail = _pBlock.get() + _nCachedElements - 1;
+ for (sal_Int32 nPos = _nCachedElements; nPos--;)
+ {
+ _pBlock[nPos].pPred = _pBlock.get() + nPos - 1;
+ _pBlock[nPos].pSucc = _pBlock.get() + nPos + 1;
+ }
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::toFront( CacheEntry * pEntry ) const
+{
+ if (pEntry != _pHead)
+ {
+ // cut out element
+ if (pEntry == _pTail)
+ {
+ _pTail = pEntry->pPred;
+ }
+ else
+ {
+ pEntry->pSucc->pPred = pEntry->pPred;
+ pEntry->pPred->pSucc = pEntry->pSucc;
+ }
+ // push to front
+ _pHead->pPred = pEntry;
+ pEntry->pSucc = _pHead;
+ _pHead = pEntry;
+ }
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline t_Val LRU_Cache< t_Key, t_Val, t_KeyHash >::getValue( const t_Key & rKey ) const
+{
+ std::scoped_lock aGuard( _aCacheMutex );
+ const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) );
+ if (iFind != _aKey2Element.end())
+ {
+ CacheEntry * pEntry = (*iFind).second;
+ toFront( pEntry );
+#ifdef __CACHE_DIAGNOSE
+ SAL_INFO("stoc.corerefl", "> retrieved element \"" );
+ SAL_INFO("stoc.corerefl", "" << pEntry->aKey);
+ SAL_INFO("stoc.corerefl", "\" from cache <" );
+#endif
+ return pEntry->aVal;
+ }
+ return t_Val();
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::setValue(
+ const t_Key & rKey, const t_Val & rValue )
+{
+ std::scoped_lock aGuard( _aCacheMutex );
+ if (_nCachedElements > 0)
+ {
+ const typename t_Key2Element::const_iterator iFind( _aKey2Element.find( rKey ) );
+
+ CacheEntry * pEntry;
+ if (iFind == _aKey2Element.end())
+ {
+ pEntry = _pTail; // erase last element
+#ifdef __CACHE_DIAGNOSE
+ if (pEntry->aKey.getLength())
+ {
+ SAL_INFO("stoc.corerefl", "> kicking element \"" );
+ SAL_INFO("stoc.corerefl", "" << pEntry->aKey);
+ SAL_INFO("stoc.corerefl", "\" from cache <" );
+ }
+#endif
+ _aKey2Element.erase( pEntry->aKey );
+ pEntry->aKey = rKey;
+ _aKey2Element[ rKey ] = pEntry;
+ }
+ else
+ {
+ pEntry = (*iFind).second;
+#ifdef __CACHE_DIAGNOSE
+ SAL_INFO("stoc.corerefl", "> replacing element \"" );
+ SAL_INFO("stoc.corerefl", "" << pEntry->aKey);
+ SAL_INFO("stoc.corerefl", "\" in cache <" );
+#endif
+ }
+ pEntry->aVal = rValue;
+ toFront( pEntry );
+ }
+}
+
+template< class t_Key, class t_Val, class t_KeyHash >
+inline void LRU_Cache< t_Key, t_Val, t_KeyHash >::clear()
+{
+ std::scoped_lock aGuard( _aCacheMutex );
+ _aKey2Element.clear();
+ for ( sal_Int32 nPos = _nCachedElements; nPos--; )
+ {
+ _pBlock[nPos].aKey = t_Key();
+ _pBlock[nPos].aVal = t_Val();
+ }
+ _nCachedElements = 0;
+#ifdef __CACHE_DIAGNOSE
+ SAL_INFO("stoc.corerefl", "> cleared cache <" );
+#endif
+}
+
+
+/** Template instance for OUString keys, Any values.<br>
+*/
+typedef LRU_Cache< OUString, css::uno::Any, OUStringHash >
+ LRU_CacheAnyByOUString;
+
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/corereflection/reflection.component b/stoc/source/corereflection/reflection.component
new file mode 100644
index 0000000000..0210c80904
--- /dev/null
+++ b/stoc/source/corereflection/reflection.component
@@ -0,0 +1,33 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.CoreReflection"
+ constructor="com_sun_star_comp_stoc_CoreReflection_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.reflection.CoreReflection"/>
+ <singleton name="com.sun.star.reflection.theCoreReflection"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.stoc.Dump"
+ constructor="com_sun_star_comp_stoc_Dump_get_implementation"
+ single-instance="true">
+ <singleton name="com.sun.star.reflection.Dump"/>
+ </implementation>
+</component>
diff --git a/stoc/source/defaultregistry/defaultregistry.cxx b/stoc/source/defaultregistry/defaultregistry.cxx
new file mode 100644
index 0000000000..815d7a6679
--- /dev/null
+++ b/stoc/source/defaultregistry/defaultregistry.cxx
@@ -0,0 +1,1186 @@
+/* -*- 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 <comphelper/sequence.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace css::uno;
+using namespace css::registry;
+using namespace css::lang;
+using namespace css::container;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+class NestedRegistryImpl : public WeakImplHelper < XSimpleRegistry, XInitialization, XServiceInfo, XEnumerationAccess >
+{
+public:
+ NestedRegistryImpl( );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override;
+
+ // XSimpleRegistry
+ virtual OUString SAL_CALL getURL() override;
+ virtual void SAL_CALL open( const OUString& rURL, sal_Bool bReadOnly, sal_Bool bCreate ) override;
+ virtual sal_Bool SAL_CALL isValid( ) override;
+ virtual void SAL_CALL close( ) override;
+ virtual void SAL_CALL destroy( ) override;
+ virtual Reference< XRegistryKey > SAL_CALL getRootKey( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL mergeKey( const OUString& aKeyName, const OUString& aUrl ) override;
+
+ // XEnumerationAccess
+ virtual Reference< XEnumeration > SAL_CALL createEnumeration( ) override;
+ virtual Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ friend class NestedKeyImpl;
+protected:
+ Mutex m_mutex;
+ sal_uInt32 m_state;
+ Reference<XSimpleRegistry> m_localReg;
+ Reference<XSimpleRegistry> m_defaultReg;
+
+};
+
+
+// class NestedKeyImpl the implementation of interface XRegistryKey
+
+class NestedKeyImpl : public WeakImplHelper< XRegistryKey >
+{
+public:
+ NestedKeyImpl( NestedRegistryImpl* pDefaultRegistry,
+ Reference<XRegistryKey>& localKey,
+ Reference<XRegistryKey>& defaultKey);
+
+ NestedKeyImpl( const OUString& aKeyName,
+ NestedKeyImpl* pKey);
+
+ // XRegistryKey
+ virtual OUString SAL_CALL getKeyName() override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual sal_Bool SAL_CALL isValid( ) override;
+ virtual RegistryKeyType SAL_CALL getKeyType( const OUString& rKeyName ) override;
+ virtual RegistryValueType SAL_CALL getValueType( ) override;
+ virtual sal_Int32 SAL_CALL getLongValue( ) override;
+ virtual void SAL_CALL setLongValue( sal_Int32 value ) override;
+ virtual Sequence< sal_Int32 > SAL_CALL getLongListValue( ) override;
+ virtual void SAL_CALL setLongListValue( const css::uno::Sequence< sal_Int32 >& seqValue ) override;
+ virtual OUString SAL_CALL getAsciiValue( ) override;
+ virtual void SAL_CALL setAsciiValue( const OUString& value ) override;
+ virtual Sequence< OUString > SAL_CALL getAsciiListValue( ) override;
+ virtual void SAL_CALL setAsciiListValue( const css::uno::Sequence< OUString >& seqValue ) override;
+ virtual OUString SAL_CALL getStringValue( ) override;
+ virtual void SAL_CALL setStringValue( const OUString& value ) override;
+ virtual Sequence< OUString > SAL_CALL getStringListValue( ) override;
+ virtual void SAL_CALL setStringListValue( const css::uno::Sequence< OUString >& seqValue ) override;
+ virtual Sequence< sal_Int8 > SAL_CALL getBinaryValue( ) override;
+ virtual void SAL_CALL setBinaryValue( const css::uno::Sequence< sal_Int8 >& value ) override;
+ virtual Reference< XRegistryKey > SAL_CALL openKey( const OUString& aKeyName ) override;
+ virtual Reference< XRegistryKey > SAL_CALL createKey( const OUString& aKeyName ) override;
+ virtual void SAL_CALL closeKey( ) override;
+ virtual void SAL_CALL deleteKey( const OUString& rKeyName ) override;
+ virtual Sequence< Reference< XRegistryKey > > SAL_CALL openKeys( ) override;
+ virtual Sequence< OUString > SAL_CALL getKeyNames( ) override;
+ virtual sal_Bool SAL_CALL createLink( const OUString& aLinkName, const OUString& aLinkTarget ) override;
+ virtual void SAL_CALL deleteLink( const OUString& rLinkName ) override;
+ virtual OUString SAL_CALL getLinkTarget( const OUString& rLinkName ) override;
+ virtual OUString SAL_CALL getResolvedName( const OUString& aKeyName ) override;
+
+protected:
+ void computeChanges();
+ OUString computeName(const OUString& name);
+
+ OUString m_name;
+ sal_uInt32 m_state;
+ rtl::Reference<NestedRegistryImpl> m_xRegistry;
+ Reference<XRegistryKey> m_localKey;
+ Reference<XRegistryKey> m_defaultKey;
+};
+
+
+NestedKeyImpl::NestedKeyImpl( NestedRegistryImpl* pDefaultRegistry,
+ Reference<XRegistryKey>& localKey,
+ Reference<XRegistryKey>& defaultKey )
+ : m_state(pDefaultRegistry->m_state), m_xRegistry(pDefaultRegistry), m_localKey(localKey), m_defaultKey(defaultKey)
+{
+ if (m_localKey.is())
+ {
+ m_name = m_localKey->getKeyName();
+ }
+ else if (m_defaultKey.is())
+ {
+ m_name = m_defaultKey->getKeyName();
+ }
+}
+
+
+NestedKeyImpl::NestedKeyImpl( const OUString& rKeyName,
+ NestedKeyImpl* pKey)
+ : m_xRegistry(pKey->m_xRegistry)
+{
+ if (pKey->m_localKey.is() && pKey->m_localKey->isValid())
+ {
+ m_localKey = pKey->m_localKey->openKey(rKeyName);
+ }
+ if (pKey->m_defaultKey.is() && pKey->m_defaultKey->isValid())
+ {
+ m_defaultKey = pKey->m_defaultKey->openKey(rKeyName);
+ }
+
+ if (m_localKey.is())
+ {
+ m_name = m_localKey->getKeyName();
+ }
+ else if (m_defaultKey.is())
+ {
+ m_name = m_defaultKey->getKeyName();
+ }
+
+ m_state = m_xRegistry->m_state;
+}
+
+void NestedKeyImpl::computeChanges()
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( m_state == m_xRegistry->m_state )
+ return;
+
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+
+ Reference<XRegistryKey> tmpKey = rootKey->openKey(m_name);
+
+ if ( tmpKey.is() )
+ {
+ m_localKey = rootKey->openKey(m_name);
+ }
+
+ m_state = m_xRegistry->m_state;
+}
+
+
+// NestedKey_Impl::computeName()
+
+OUString NestedKeyImpl::computeName(const OUString& name)
+{
+ OUString resLocalName, resDefaultName;
+
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ try
+ {
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ resLocalName = m_localKey->getResolvedName(name);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getResolvedName(name);
+ }
+
+ if ( !resLocalName.isEmpty() && m_xRegistry->m_defaultReg->isValid() )
+ {
+ Reference<XRegistryKey> localRoot(m_xRegistry->m_localReg->getRootKey());
+ Reference<XRegistryKey> defaultRoot(m_xRegistry->m_defaultReg->getRootKey());
+
+ resDefaultName = defaultRoot->getResolvedName(resLocalName);
+
+ sal_uInt32 count = 100;
+
+ while (resLocalName != resDefaultName && count > 0)
+ {
+ count--;
+
+ if (resLocalName.isEmpty() || resDefaultName.isEmpty())
+ throw InvalidRegistryException();
+
+ resLocalName = localRoot->getResolvedName(resDefaultName);
+ resDefaultName = defaultRoot->getResolvedName(resLocalName);
+ }
+ }
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return resLocalName;
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getKeyName()
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ return m_name;
+}
+
+
+sal_Bool SAL_CALL NestedKeyImpl::isReadOnly( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( !m_localKey.is() || !m_localKey->isValid() )
+ throw InvalidRegistryException();
+
+ return m_localKey->isReadOnly();
+}
+
+
+sal_Bool SAL_CALL NestedKeyImpl::isValid( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ return ((m_localKey.is() && m_localKey->isValid()) ||
+ (m_defaultKey.is() && m_defaultKey->isValid()) );
+}
+
+
+RegistryKeyType SAL_CALL NestedKeyImpl::getKeyType( const OUString& rKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getKeyType(rKeyName);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getKeyType(rKeyName);
+ }
+
+ return RegistryKeyType_KEY;
+}
+
+
+RegistryValueType SAL_CALL NestedKeyImpl::getValueType( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getValueType();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getValueType();
+ }
+
+ return RegistryValueType_NOT_DEFINED;
+}
+
+
+sal_Int32 SAL_CALL NestedKeyImpl::getLongValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getLongValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getLongValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setLongValue( sal_Int32 value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setLongValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setLongValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< sal_Int32 > SAL_CALL NestedKeyImpl::getLongListValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getLongListValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getLongListValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setLongListValue( const Sequence< sal_Int32 >& seqValue )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setLongListValue(seqValue);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setLongListValue(seqValue);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getAsciiValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getAsciiValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getAsciiValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setAsciiValue( const OUString& value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setAsciiValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setAsciiValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< OUString > SAL_CALL NestedKeyImpl::getAsciiListValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getAsciiListValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getAsciiListValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setAsciiListValue( const Sequence< OUString >& seqValue )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setAsciiListValue(seqValue);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setAsciiListValue(seqValue);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getStringValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getStringValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getStringValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setStringValue( const OUString& value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setStringValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setStringValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< OUString > SAL_CALL NestedKeyImpl::getStringListValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getStringListValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getStringListValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setStringListValue( const Sequence< OUString >& seqValue )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setStringListValue(seqValue);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setStringListValue(seqValue);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Sequence< sal_Int8 > SAL_CALL NestedKeyImpl::getBinaryValue( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ return m_localKey->getBinaryValue();
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ return m_defaultKey->getBinaryValue();
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::setBinaryValue( const Sequence< sal_Int8 >& value )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ computeChanges();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->setBinaryValue(value);
+ }
+ else if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+ m_localKey->setBinaryValue(value);
+ m_state = m_xRegistry->m_state++;
+ }
+ else
+ {
+ throw InvalidRegistryException();
+ }
+}
+
+
+Reference< XRegistryKey > SAL_CALL NestedKeyImpl::openKey( const OUString& aKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(aKeyName);
+
+ if ( resolvedName.isEmpty() )
+ throw InvalidRegistryException();
+
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ localKey = m_xRegistry->m_localReg->getRootKey()->openKey(resolvedName);
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
+ }
+
+ if ( localKey.is() || defaultKey.is() )
+ {
+ return new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey);
+ }
+ else
+ {
+ return Reference<XRegistryKey>();
+ }
+}
+
+
+Reference< XRegistryKey > SAL_CALL NestedKeyImpl::createKey( const OUString& aKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( (!m_localKey.is() && !m_defaultKey.is()) ||
+ (m_localKey.is() && m_localKey->isReadOnly()) )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(aKeyName);
+
+ if ( resolvedName.isEmpty() )
+ throw InvalidRegistryException();
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ localKey = m_xRegistry->m_localReg->getRootKey()->createKey(resolvedName);
+ if ( localKey.is() )
+ {
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
+ }
+
+ m_state = m_xRegistry->m_state++;
+
+ return new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey);
+ }
+ }
+ else
+ {
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+
+ localKey = m_xRegistry->m_localReg->getRootKey()->createKey(resolvedName);
+
+ if ( localKey.is() )
+ {
+ defaultKey = m_xRegistry->m_defaultReg->getRootKey()->openKey(resolvedName);
+
+ m_state = m_xRegistry->m_state++;
+
+ return new NestedKeyImpl(m_xRegistry.get(), localKey, defaultKey);
+ }
+ }
+ }
+
+ return Reference<XRegistryKey>();
+}
+
+
+void SAL_CALL NestedKeyImpl::closeKey( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ m_localKey->closeKey();
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ m_defaultKey->closeKey();
+ }
+}
+
+
+void SAL_CALL NestedKeyImpl::deleteKey( const OUString& rKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() || !m_localKey->isValid() ||
+ m_localKey->isReadOnly() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(rKeyName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ m_xRegistry->m_localReg->getRootKey()->deleteKey(resolvedName);
+}
+
+
+Sequence< Reference< XRegistryKey > > SAL_CALL NestedKeyImpl::openKeys( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ Sequence<OUString> localSeq, defaultSeq;
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ localSeq = m_localKey->getKeyNames();
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultSeq = m_defaultKey->getKeyNames();
+ }
+
+ std::vector< Reference<XRegistryKey> > retVec;
+ retVec.reserve(localSeq.getLength() + defaultSeq.getLength());
+
+ auto lKeyNameToRegKey = [this](const OUString& rName) -> Reference<XRegistryKey> {
+ sal_Int32 lastIndex = rName.lastIndexOf('/');
+ OUString name = rName.copy(lastIndex);
+ return new NestedKeyImpl(name, this);
+ };
+
+ for (const auto& rKeyName : std::as_const(localSeq))
+ retVec.push_back(lKeyNameToRegKey(rKeyName));
+
+ for (const auto& rKeyName : std::as_const(defaultSeq))
+ {
+ if ( comphelper::findValue(localSeq, rKeyName) == -1 )
+ {
+ retVec.push_back(lKeyNameToRegKey(rKeyName));
+ }
+ }
+
+ return comphelper::containerToSequence(retVec);
+}
+
+
+Sequence< OUString > SAL_CALL NestedKeyImpl::getKeyNames( )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ Sequence<OUString> localSeq, defaultSeq;
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ localSeq = m_localKey->getKeyNames();
+ }
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ defaultSeq = m_defaultKey->getKeyNames();
+ }
+
+ return comphelper::combineSequences(localSeq, defaultSeq);
+}
+
+
+sal_Bool SAL_CALL NestedKeyImpl::createLink( const OUString& aLinkName, const OUString& aLinkTarget )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+
+ bool isCreated = false;
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName;
+ sal_Int32 lastIndex = aLinkName.lastIndexOf('/');
+
+ if ( lastIndex > 0 )
+ {
+ OUString linkName = aLinkName.copy(0, lastIndex);
+
+ resolvedName = computeName(linkName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ resolvedName += aLinkName.subView(lastIndex);
+ }
+ else
+ {
+ if ( lastIndex == 0 )
+ resolvedName = m_name + aLinkName;
+ else
+ resolvedName = m_name + "/" + aLinkName;
+ }
+
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ isCreated = m_xRegistry->m_localReg->getRootKey()->createLink(resolvedName, aLinkTarget);
+ }
+ else
+ {
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ {
+ Reference<XRegistryKey> rootKey(m_xRegistry->m_localReg->getRootKey());
+ m_localKey = rootKey->createKey(m_name);
+
+ isCreated = m_xRegistry->m_localReg->getRootKey()->createLink(resolvedName, aLinkTarget);
+ }
+ }
+
+ if ( isCreated )
+ m_state = m_xRegistry->m_state++;
+
+ return isCreated;
+}
+
+
+void SAL_CALL NestedKeyImpl::deleteLink( const OUString& rLinkName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName;
+ sal_Int32 lastIndex = rLinkName.lastIndexOf('/');
+
+ if ( lastIndex > 0 )
+ {
+ OUString linkName = rLinkName.copy(0, lastIndex);
+
+ resolvedName = computeName(linkName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ resolvedName += rLinkName.subView(lastIndex);
+ }
+ else
+ {
+ if ( lastIndex == 0 )
+ resolvedName = m_name + rLinkName;
+ else
+ resolvedName = m_name + "/" + rLinkName;
+ }
+
+ if ( !m_localKey.is() || !m_localKey->isValid() ||
+ m_localKey->isReadOnly() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ m_xRegistry->m_localReg->getRootKey()->deleteLink(resolvedName);
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getLinkTarget( const OUString& rLinkName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName;
+ sal_Int32 lastIndex = rLinkName.lastIndexOf('/');
+
+ if ( lastIndex > 0 )
+ {
+ OUString linkName = rLinkName.copy(0, lastIndex);
+
+ resolvedName = computeName(linkName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ resolvedName += rLinkName.subView(lastIndex);
+ }
+ else
+ {
+ if ( lastIndex == 0 )
+ resolvedName = m_name + rLinkName;
+ else
+ resolvedName = m_name + "/" + rLinkName;
+ }
+
+ OUString linkTarget;
+ if ( m_localKey.is() && m_localKey->isValid() )
+ {
+ try
+ {
+ linkTarget = m_xRegistry->m_localReg->getRootKey()->getLinkTarget(resolvedName);
+ return linkTarget;
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+ }
+
+ if ( m_defaultKey.is() && m_defaultKey->isValid() )
+ linkTarget = m_xRegistry->m_defaultReg->getRootKey()->getLinkTarget(resolvedName);
+
+ return linkTarget;
+}
+
+
+OUString SAL_CALL NestedKeyImpl::getResolvedName( const OUString& aKeyName )
+{
+ Guard< Mutex > aGuard( m_xRegistry->m_mutex );
+ if ( !m_localKey.is() && !m_defaultKey.is() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ OUString resolvedName = computeName(aKeyName);
+
+ if ( resolvedName.isEmpty() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ return resolvedName;
+}
+
+
+// DefaultRegistry Implementation
+
+
+NestedRegistryImpl::NestedRegistryImpl( )
+ : m_state(0)
+{}
+
+class RegistryEnumueration : public WeakImplHelper< XEnumeration >
+{
+public:
+ RegistryEnumueration(
+ const Reference< XSimpleRegistry > &r1,
+ const Reference< XSimpleRegistry > &r2 )
+ : m_xReg1( r1 ) , m_xReg2( r2 )
+ {}
+public:
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override;
+ virtual Any SAL_CALL nextElement( ) override;
+
+private:
+ Reference< XSimpleRegistry > m_xReg1;
+ Reference< XSimpleRegistry > m_xReg2;
+};
+
+sal_Bool RegistryEnumueration::hasMoreElements( )
+{
+ return m_xReg1.is() || m_xReg2.is();
+}
+
+Any RegistryEnumueration::nextElement( )
+{
+ Any a;
+ if( m_xReg1.is() )
+ {
+ a <<= m_xReg1;
+ m_xReg1.clear();
+ }
+ else if( m_xReg2.is() )
+ {
+ a <<= m_xReg2;
+ m_xReg2.clear();
+ }
+ else
+ {
+ throw NoSuchElementException( "NestedRegistry: no nextElement() !" );
+ }
+ return a;
+}
+
+
+Reference< XEnumeration > NestedRegistryImpl::createEnumeration( )
+{
+ MutexGuard guard( m_mutex );
+ return new RegistryEnumueration( m_localReg, m_defaultReg );
+}
+
+Type NestedRegistryImpl::getElementType( )
+{
+ return cppu::UnoType<decltype(m_localReg)>::get();
+}
+
+sal_Bool SAL_CALL NestedRegistryImpl::hasElements( )
+{
+ MutexGuard guard( m_mutex );
+ return m_localReg.is() || m_defaultReg.is();
+}
+
+
+OUString SAL_CALL NestedRegistryImpl::getImplementationName( )
+{
+ return "com.sun.star.comp.stoc.NestedRegistry";
+}
+
+sal_Bool SAL_CALL NestedRegistryImpl::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence<OUString> SAL_CALL NestedRegistryImpl::getSupportedServiceNames( )
+{
+ Sequence< OUString > seqNames { "com.sun.star.registry.NestedRegistry" };
+ return seqNames;
+}
+
+
+void SAL_CALL NestedRegistryImpl::initialize( const Sequence< Any >& aArguments )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( (aArguments.getLength() == 2) &&
+ (aArguments[0].getValueType().getTypeClass() == TypeClass_INTERFACE) &&
+ (aArguments[1].getValueType().getTypeClass() == TypeClass_INTERFACE) )
+ {
+ aArguments[0] >>= m_localReg;
+ aArguments[1] >>= m_defaultReg;
+ if ( m_localReg == m_defaultReg )
+ m_defaultReg.clear();
+ }
+}
+
+
+OUString SAL_CALL NestedRegistryImpl::getURL()
+{
+ Guard< Mutex > aGuard( m_mutex );
+ try
+ {
+ if ( m_localReg.is() && m_localReg->isValid() )
+ return m_localReg->getURL();
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return OUString();
+}
+
+
+void SAL_CALL NestedRegistryImpl::open( const OUString&, sal_Bool, sal_Bool )
+{
+ throw InvalidRegistryException(
+ "the 'open' method is not specified for a nested registry" );
+}
+
+
+sal_Bool SAL_CALL NestedRegistryImpl::isValid( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ try
+ {
+ if ( (m_localReg.is() && m_localReg->isValid()) ||
+ (m_defaultReg.is() && m_defaultReg->isValid()) )
+ return true;
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return false;
+}
+
+
+void SAL_CALL NestedRegistryImpl::close( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( m_localReg.is() && m_localReg->isValid() )
+ {
+ m_localReg->close();
+ }
+ if ( m_defaultReg.is() && m_defaultReg->isValid() )
+ {
+ m_defaultReg->close();
+ }
+}
+
+
+void SAL_CALL NestedRegistryImpl::destroy( )
+{
+ throw InvalidRegistryException(
+ "the 'destroy' method is not specified for a nested registry" );
+}
+
+
+Reference< XRegistryKey > SAL_CALL NestedRegistryImpl::getRootKey( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ if ( !m_localReg.is() || !m_localReg->isValid() )
+ {
+ throw InvalidRegistryException();
+ }
+
+ Reference<XRegistryKey> localKey, defaultKey;
+
+ localKey = m_localReg->getRootKey();
+
+ if ( localKey.is() )
+ {
+ if ( m_defaultReg.is() && m_defaultReg->isValid() )
+ {
+ defaultKey = m_defaultReg->getRootKey();
+ }
+
+ return new NestedKeyImpl(this, localKey, defaultKey);
+ }
+
+ return Reference<XRegistryKey>();
+}
+
+
+sal_Bool SAL_CALL NestedRegistryImpl::isReadOnly( )
+{
+ Guard< Mutex > aGuard( m_mutex );
+ try
+ {
+ if ( m_localReg.is() && m_localReg->isValid() )
+ return m_localReg->isReadOnly();
+ }
+ catch(InvalidRegistryException& )
+ {
+ }
+
+ return false;
+}
+
+
+void SAL_CALL NestedRegistryImpl::mergeKey( const OUString&, const OUString& )
+{
+ throw css::uno::RuntimeException("css.registry.NestedRegistry::mergeKey: not implemented");
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_NestedRegistry_get_implementation(
+ SAL_UNUSED_PARAMETER css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new NestedRegistryImpl);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/implementationregistration/implreg.cxx b/stoc/source/implementationregistration/implreg.cxx
new file mode 100644
index 0000000000..ca8c6b2673
--- /dev/null
+++ b/stoc/source/implementationregistration/implreg.cxx
@@ -0,0 +1,1580 @@
+/* -*- 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 <string.h>
+#include <string_view>
+#include <vector>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/ustring.hxx>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/loader/XImplementationLoader.hpp>
+#include <com/sun/star/registry/XImplementationRegistration2.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/reflection/XServiceTypeDescription.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include "mergekeys.hxx"
+
+#if defined(_WIN32)
+#include <io.h>
+#endif
+
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::loader;
+using namespace css::beans;
+using namespace css::lang;
+using namespace css::registry;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+constexpr OUString slash_UNO_slash_REGISTRY_LINKS
+ = u"/UNO/REGISTRY_LINKS"_ustr;
+constexpr OUString slash_IMPLEMENTATIONS
+ = u"/IMPLEMENTATIONS"_ustr;
+constexpr OUString slash_UNO
+ = u"/UNO"_ustr;
+constexpr OUString slash_UNO_slash_SERVICES
+ = u"/UNO/SERVICES"_ustr;
+constexpr OUString slash_UNO_slash_SINGLETONS
+ = u"/UNO/SINGLETONS"_ustr;
+constexpr OUString slash_SERVICES
+ = u"/SERVICES/"_ustr;
+constexpr OUString slash_UNO_slash_LOCATION
+ = u"/UNO/LOCATION"_ustr;
+constexpr OUString slash_UNO_slash_ACTIVATOR
+ = u"/UNO/ACTIVATOR"_ustr;
+constexpr OUString colon_old
+ = u":old"_ustr;
+constexpr OUStringLiteral com_sun_star_registry_SimpleRegistry
+ = u"com.sun.star.registry.SimpleRegistry";
+constexpr OUString Registry
+ = u"Registry"_ustr;
+
+// static deleteAllLinkReferences()
+
+void deleteAllLinkReferences(const Reference < XSimpleRegistry >& xReg,
+ const Reference < XRegistryKey >& xSource)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ Reference < XRegistryKey > xKey = xSource->openKey(
+ slash_UNO_slash_REGISTRY_LINKS );
+
+ if (!(xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST)))
+ return;
+
+ const Sequence<OUString> linkNames = xKey->getAsciiListValue();
+
+ if (!linkNames.hasElements())
+ return;
+
+ OUString aLinkName;
+ OUString aLinkParent;
+ Reference < XRegistryKey > xLinkParent;
+ const sal_Unicode* pTmpName = nullptr;
+ const sal_Unicode* pShortName = nullptr;
+ sal_Int32 sEnd = 0;
+
+ for (const OUString& rLinkName : linkNames)
+ {
+ aLinkName = rLinkName;
+
+ pTmpName = aLinkName.getStr();
+
+ if (pTmpName[0] != L'/')
+ continue;
+
+ sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName = pTmpName+nIndex;
+
+ while (pShortName && pShortName[1] == L'%')
+ {
+ nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName += nIndex+2;
+ }
+
+ if (pShortName)
+ {
+ aLinkName = aLinkName.copy(0, pShortName - pTmpName);
+ }
+
+ xReg->getRootKey()->deleteLink(aLinkName);
+
+ sEnd = aLinkName.lastIndexOf( '/' );
+
+ aLinkParent = aLinkName.copy(0, sEnd);
+
+ while(!aLinkParent.isEmpty())
+ {
+ xLinkParent = xReg->getRootKey()->openKey(aLinkParent);
+
+ if (xLinkParent.is() && !xLinkParent->getKeyNames().hasElements())
+ {
+ aLinkName = aLinkParent;
+
+ xReg->getRootKey()->deleteKey(aLinkParent);
+
+ sEnd = aLinkName.lastIndexOf( '/' );
+
+ aLinkParent = aLinkName.copy(0, sEnd);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+}
+
+
+// static prepareLink
+
+void prepareLink( const Reference < XSimpleRegistry > & xDest,
+ const Reference < XRegistryKey > & xSource,
+ const OUString& link)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ OUString linkRefName = xSource->getKeyName();
+ OUString linkName(link);
+ bool isRelativ = false;
+
+ const sal_Unicode* pTmpName = link.getStr();
+ const sal_Unicode* pShortName;
+ sal_Int32 nIndex = rtl_ustr_indexOfChar( pTmpName, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName = pTmpName+nIndex;
+
+ if (pTmpName[0] != L'/')
+ isRelativ = true;
+
+ while (pShortName && pShortName[1] == L'%')
+ {
+ nIndex = rtl_ustr_indexOfChar( pShortName+2, '%' );
+ if ( nIndex == -1 )
+ pShortName = nullptr;
+ else
+ pShortName += nIndex+2;
+ }
+
+ if (pShortName)
+ {
+ linkRefName += link.subView(pShortName - pTmpName + 1);
+ linkName = link.copy(0, pShortName - pTmpName);
+ }
+
+ if (isRelativ)
+ xSource->createLink(linkName, linkRefName);
+ else
+ xDest->getRootKey()->createLink(linkName, linkRefName);
+}
+
+
+// static searchImplForLink
+
+OUString searchImplForLink(
+ const Reference < XRegistryKey > & xRootKey,
+ std::u16string_view linkName,
+ std::u16string_view implName )
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys( xKey->openKeys() );
+ OUString key_name( slash_UNO + linkName );
+
+ for (const Reference < XRegistryKey >& xImplKey : subKeys)
+ {
+ try
+ {
+ if (xImplKey->getKeyType( key_name ) == RegistryKeyType_LINK)
+ {
+ OUString oldImplName = xImplKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
+ if (implName != oldImplName)
+ {
+ return oldImplName;
+ }
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+ }
+ }
+
+ return OUString();
+}
+
+
+// static searchLinkTargetForImpl
+
+OUString searchLinkTargetForImpl(const Reference < XRegistryKey >& xRootKey,
+ std::u16string_view linkName,
+ const OUString& implName)
+{
+ Reference < XRegistryKey > xKey = xRootKey->openKey( slash_IMPLEMENTATIONS );
+
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys = xKey->openKeys();
+
+ OUString qualifiedLinkName( slash_UNO + linkName );
+
+ auto pSubKey = std::find_if(subKeys.begin(), subKeys.end(),
+ [&implName, &qualifiedLinkName](const Reference<XRegistryKey>& rSubKey) {
+ OUString tmpImplName = rSubKey->getKeyName().copy(strlen("/IMPLEMENTATIONS/"));
+ return tmpImplName == implName
+ && rSubKey->getKeyType( qualifiedLinkName ) == RegistryKeyType_LINK;
+ });
+ if (pSubKey != subKeys.end())
+ return (*pSubKey)->getLinkTarget( qualifiedLinkName );
+ }
+
+ return OUString();
+}
+
+
+// static createUniqueSubEntry
+
+void createUniqueSubEntry(const Reference < XRegistryKey > & xSuperKey,
+ const OUString& value)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ if (!xSuperKey.is())
+ return;
+
+ if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+
+ bool bReady = comphelper::findValue(implEntries, value) != -1;
+
+ if (bReady)
+ {
+ Sequence<OUString> implEntriesNew(length);
+ auto it = implEntriesNew.getArray();
+ *it = value;
+
+ std::copy_if(implEntries.begin(), implEntries.end(), std::next(it),
+ [&value](const OUString& rEntry) { return rEntry != value; });
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ } else
+ {
+ Sequence<OUString> implEntriesNew(length+1);
+ auto it = implEntriesNew.getArray();
+ *it = value;
+
+ std::copy(implEntries.begin(), implEntries.end(), std::next(it));
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ }
+ } else
+ {
+ Sequence<OUString> implEntriesNew { value };
+
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ }
+}
+
+
+// static deleteSubEntry
+
+bool deleteSubEntry(const Reference < XRegistryKey >& xSuperKey, const OUString& value)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ if (xSuperKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xSuperKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+ sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), value));
+ bool hasNoImplementations = false;
+
+ if (equals == length)
+ {
+ hasNoImplementations = true;
+ } else
+ {
+ Sequence<OUString> implEntriesNew(length - equals);
+
+ std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
+ [&value](const OUString& rEntry) { return rEntry != value; });
+ xSuperKey->setAsciiListValue(implEntriesNew);
+ }
+
+ if (hasNoImplementations)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// static prepareUserLink
+
+void prepareUserLink(const Reference < XSimpleRegistry >& xDest,
+ const OUString& linkName,
+ const OUString& linkTarget,
+ std::u16string_view implName)
+{
+ Reference < XRegistryKey > xRootKey = xDest->getRootKey();
+
+ if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
+ {
+ OUString oldImplName(searchImplForLink(xRootKey, linkName, implName));
+
+ if (!oldImplName.isEmpty())
+ {
+ createUniqueSubEntry(xDest->getRootKey()->createKey(
+ linkName + colon_old ), oldImplName);
+ }
+ }
+
+ if (xRootKey->isValid())
+ xRootKey->createLink(linkName, linkTarget);
+}
+
+
+// static deleteUserLink
+
+void deletePathIfPossible(const Reference < XRegistryKey >& xRootKey,
+ const OUString& path)
+{
+ try
+ {
+ Sequence<OUString> keyNames(xRootKey->openKey(path)->getKeyNames());
+
+ if (!keyNames.hasElements() &&
+ xRootKey->openKey(path)->getValueType() == RegistryValueType_NOT_DEFINED)
+ {
+ xRootKey->deleteKey(path);
+
+ OUString newPath = path.copy(0, path.lastIndexOf('/'));
+
+ if (newPath.getLength() > 1)
+ deletePathIfPossible(xRootKey, newPath);
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+}
+
+
+// static deleteUserLink
+
+void deleteUserLink(const Reference < XRegistryKey >& xRootKey,
+ const OUString& linkName,
+ std::u16string_view linkTarget,
+ const OUString& implName)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ bool bClean = false;
+
+ if (xRootKey->getKeyType(linkName) == RegistryKeyType_LINK)
+ {
+ OUString tmpTarget = xRootKey->getLinkTarget(linkName);
+
+ if (tmpTarget == linkTarget)
+ {
+ xRootKey->deleteLink(linkName);
+ }
+ }
+
+ Reference < XRegistryKey > xOldKey = xRootKey->openKey(
+ linkName + colon_old );
+ if (xOldKey.is())
+ {
+ if (xOldKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xOldKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+ sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
+ bool hasNoImplementations = false;
+
+ if (equals == length)
+ {
+ hasNoImplementations = true;
+ } else
+ {
+ OUString oldImpl;
+
+ if (length > equals + 1)
+ {
+ Sequence<OUString> implEntriesNew(length - equals - 1);
+ auto pNewArray = implEntriesNew.getArray();
+
+ sal_Int32 j = 0;
+ bool first = true;
+ for (sal_Int32 i = 0; i < length; i++)
+ {
+ if (implEntries[i] != implName)
+ {
+ if (first)
+ {
+ oldImpl = implEntries[i];
+ first = false;
+ } else
+ {
+ pNewArray[j++] = implEntries[i];
+ }
+ }
+ }
+
+ xOldKey->setAsciiListValue(implEntriesNew);
+ } else
+ {
+ oldImpl = implEntries[0];
+ OUString path(xOldKey->getKeyName());
+ xOldKey->closeKey();
+ xRootKey->deleteKey(path);
+ }
+
+ OUString oldTarget = searchLinkTargetForImpl(xRootKey, linkName, oldImpl);
+ if (!oldTarget.isEmpty())
+ {
+ xRootKey->createLink(linkName, oldTarget);
+ }
+ }
+
+ if (hasNoImplementations)
+ {
+ bClean = true;
+ OUString path(xOldKey->getKeyName());
+ xOldKey->closeKey();
+ xRootKey->deleteKey(path);
+ }
+ }
+ } else
+ {
+ bClean = true;
+ }
+
+ if (bClean)
+ {
+ OUString path = linkName.copy(0, linkName.lastIndexOf('/'));
+ deletePathIfPossible(xRootKey, path);
+ }
+}
+
+
+// static prepareUserKeys
+
+void prepareUserKeys(const Reference < XSimpleRegistry >& xDest,
+ const Reference < XRegistryKey >& xUnoKey,
+ const Reference < XRegistryKey >& xKey,
+ const OUString& implName,
+ bool bRegister)
+{
+ bool hasSubKeys = false;
+
+ Sequence<OUString> keyNames = xKey->getKeyNames();
+
+ OUString relativKey;
+ if (keyNames.hasElements())
+ relativKey = keyNames.getConstArray()[0].copy(xKey->getKeyName().getLength()+1);
+
+ if (keyNames.getLength() == 1 &&
+ xKey->getKeyType(relativKey) == RegistryKeyType_LINK)
+ {
+ hasSubKeys = true;
+
+ OUString linkTarget = xKey->getLinkTarget(relativKey);
+ OUString linkName(
+ OUString::Concat(xKey->getKeyName().subView(xUnoKey->getKeyName().getLength()))
+ + "/" + relativKey);
+
+ if (bRegister)
+ {
+ prepareUserLink(xDest, linkName, linkTarget, implName);
+ } else
+ {
+ deleteUserLink(xDest->getRootKey(), linkName, linkTarget, implName);
+ }
+ } else
+ {
+ const Sequence< Reference < XRegistryKey> > subKeys = xKey->openKeys();
+
+ if (subKeys.hasElements())
+ {
+ hasSubKeys = true;
+
+ for (const Reference < XRegistryKey > & rSubKey : subKeys)
+ {
+ prepareUserKeys(xDest, xUnoKey, rSubKey, implName, bRegister);
+ }
+ }
+ }
+
+ if (hasSubKeys)
+ return;
+
+ OUString keyName(xKey->getKeyName().copy(xUnoKey->getKeyName().getLength()));
+
+ Reference < XRegistryKey > xRootKey = xDest->getRootKey();
+ if (bRegister)
+ {
+ createUniqueSubEntry(xRootKey->createKey(keyName), implName);
+ }
+ else
+ {
+ Reference< XRegistryKey > rKey = xRootKey->openKey(keyName);
+ if( rKey.is() )
+ {
+ deleteSubEntry(rKey, implName);
+ xRootKey->deleteKey(keyName);
+ }
+
+ OUString path = keyName.copy(0, keyName.lastIndexOf('/'));
+ if( !path.isEmpty() )
+ {
+ deletePathIfPossible(xRootKey, path);
+ }
+ }
+}
+
+
+// static deleteAllImplementations
+
+void deleteAllImplementations( const Reference < XSimpleRegistry >& xReg,
+ const Reference < XRegistryKey >& xSource,
+ std::u16string_view locationUrl,
+ std::vector<OUString> & implNames)
+ // throw (InvalidRegistryException, RuntimeException)
+{
+ Sequence < Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ if (subKeys.hasElements())
+ {
+ bool hasLocationUrl = false;
+
+ for (const Reference < XRegistryKey> & xImplKey : std::as_const(subKeys))
+ {
+ Reference < XRegistryKey > xKey = xImplKey->openKey(
+ slash_UNO_slash_LOCATION );
+
+ if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCII))
+ {
+ if (xKey->getAsciiValue() == locationUrl)
+ {
+ hasLocationUrl = true;
+
+ OUString implName(xImplKey->getKeyName().copy(1));
+ sal_Int32 firstDot = implName.indexOf('/');
+
+ if (firstDot >= 0)
+ implName = implName.copy(firstDot + 1);
+
+ implNames.push_back(implName);
+
+ deleteAllLinkReferences(xReg, xImplKey);
+
+ xKey = xImplKey->openKey( slash_UNO );
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
+
+ for (const Reference < XRegistryKey > & rSubKey2 : subKeys2)
+ {
+ if (rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SERVICES ) &&
+ rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
+ rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_ACTIVATOR ) &&
+ rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ) &&
+ rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_LOCATION) )
+ {
+ prepareUserKeys(xReg, xKey, rSubKey2, implName, false);
+ }
+ }
+ }
+ }
+ }
+
+ if (hasLocationUrl)
+ {
+ hasLocationUrl = false;
+ OUString path(xImplKey->getKeyName());
+ xImplKey->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ }
+
+ subKeys = xSource->openKeys();
+ if (!subKeys.hasElements())
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ } else
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+}
+
+
+void delete_all_singleton_entries(
+ Reference < registry::XRegistryKey > const & xSingletons_section,
+ ::std::vector< OUString > const & impl_names )
+ // throw (InvalidRegistryException, RuntimeException)
+{
+ Sequence< Reference< registry::XRegistryKey > > singletons( xSingletons_section->openKeys() );
+ Reference< registry::XRegistryKey > const * subkeys = singletons.getConstArray();
+ for ( sal_Int32 nPos = singletons.getLength(); nPos--; )
+ {
+ Reference< registry::XRegistryKey > const & xSingleton = subkeys[ nPos ];
+ Reference< registry::XRegistryKey > xRegisteredImplNames(
+ xSingleton->openKey( "REGISTERED_BY" ) );
+ if (xRegisteredImplNames.is() && xRegisteredImplNames->isValid())
+ {
+ Sequence< OUString > registered_implnames;
+ try
+ {
+ registered_implnames = xRegisteredImplNames->getAsciiListValue();
+ }
+ catch (registry::InvalidValueException &)
+ {
+ }
+ auto aNonConstRange = asNonConstRange(registered_implnames);
+ sal_Int32 nOrigRegLength = registered_implnames.getLength();
+ sal_Int32 nNewLength = nOrigRegLength;
+ for ( sal_Int32 n = nOrigRegLength; n--; )
+ {
+ OUString const & registered_implname = registered_implnames[ n ];
+
+ for (auto const& impl_name : impl_names)
+ {
+ if (impl_name == registered_implname)
+ {
+ aNonConstRange[ n ] = registered_implnames[ nNewLength -1 ];
+ --nNewLength;
+ }
+ }
+ }
+
+ if (nNewLength != nOrigRegLength)
+ {
+ if (0 == nNewLength)
+ {
+ // remove whole entry
+ xRegisteredImplNames->closeKey();
+ xSingleton->deleteKey( "REGISTERED_BY" );
+ // registry key cannot provide its relative name, only absolute :(
+ OUString abs( xSingleton->getKeyName() );
+ xSingletons_section->deleteKey( abs.copy( abs.lastIndexOf( '/' ) +1 ) );
+ }
+ else
+ {
+ registered_implnames.realloc( nNewLength );
+ xRegisteredImplNames->setAsciiListValue( registered_implnames );
+ }
+ }
+ }
+ }
+}
+
+
+// static deleteAllServiceEntries
+
+void deleteAllServiceEntries( const Reference < XSimpleRegistry >& xReg,
+ const Reference < XRegistryKey >& xSource,
+ const OUString& implName)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ if (subKeys.hasElements())
+ {
+ bool hasNoImplementations = false;
+
+ for (const Reference < XRegistryKey > & xServiceKey : std::as_const(subKeys))
+ {
+ if (xServiceKey->getValueType() == RegistryValueType_ASCIILIST)
+ {
+ const Sequence<OUString> implEntries = xServiceKey->getAsciiListValue();
+ sal_Int32 length = implEntries.getLength();
+ sal_Int32 equals = static_cast<sal_Int32>(std::count(implEntries.begin(), implEntries.end(), implName));
+
+ if (equals == length)
+ {
+ hasNoImplementations = true;
+ } else
+ {
+ if (equals > 0)
+ {
+ Sequence<OUString> implEntriesNew(length-equals);
+
+ std::copy_if(implEntries.begin(), implEntries.end(), implEntriesNew.getArray(),
+ [&implName](const OUString& rEntry) { return rEntry != implName; });
+
+ xServiceKey->setAsciiListValue(implEntriesNew);
+ }
+ }
+ }
+
+ if (hasNoImplementations)
+ {
+ hasNoImplementations = false;
+ OUString path(xServiceKey->getKeyName());
+ xServiceKey->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ }
+
+ subKeys = xSource->openKeys();
+ if (!subKeys.hasElements())
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+ } else
+ {
+ OUString path(xSource->getKeyName());
+ xSource->closeKey();
+ xReg->getRootKey()->deleteKey(path);
+ }
+}
+
+
+bool is_supported_service(
+ OUString const & service_name,
+ Reference< reflection::XServiceTypeDescription > const & xService_td )
+{
+ if (xService_td->getName() == service_name)
+ return true;
+ const Sequence< Reference< reflection::XServiceTypeDescription > > seq(
+ xService_td->getMandatoryServices() );
+ return std::any_of(seq.begin(), seq.end(), [&service_name](const auto& rService) {
+ return is_supported_service( service_name, rService ); });
+}
+
+
+void insert_singletons(
+ Reference< registry::XSimpleRegistry > const & xDest,
+ Reference< registry::XRegistryKey > const & xImplKey,
+ Reference< XComponentContext > const & xContext )
+ // throw( registry::InvalidRegistryException, registry::CannotRegisterImplementationException, RuntimeException )
+{
+ // singletons
+ Reference< registry::XRegistryKey > xKey( xImplKey->openKey( "UNO/SINGLETONS" ) );
+ if (!(xKey.is() && xKey->isValid()))
+ return;
+
+ OUString implname( xImplKey->getKeyName().copy( sizeof ("/IMPLEMENTATIONS/") -1 ) );
+ // singleton entries
+ Sequence< Reference< registry::XRegistryKey > > xSingletons_section( xKey->openKeys() );
+ Reference< registry::XRegistryKey > const * p = xSingletons_section.getConstArray();
+ for ( sal_Int32 nPos = xSingletons_section.getLength(); nPos--; )
+ {
+ Reference< registry::XRegistryKey > const & xSingleton = p[ nPos ];
+ OUString singleton_name(
+ xSingleton->getKeyName().copy(
+ implname.getLength() + sizeof ("/IMPLEMENTATIONS//UNO/SINGLETONS/") -1 ) );
+ OUString service_name( xSingleton->getStringValue() );
+
+ OUString keyname( "/SINGLETONS/" + singleton_name );
+ Reference< registry::XRegistryKey > xKey2( xDest->getRootKey()->openKey( keyname ) );
+ if (xKey2.is() && xKey2->isValid())
+ {
+ try
+ {
+ OUString existing_name( xKey2->getStringValue() );
+ if ( existing_name != service_name )
+ {
+ Reference< container::XHierarchicalNameAccess > xTDMgr;
+ OUString the_tdmgr =
+ "/singletons/com.sun.star.reflection.theTypeDescriptionManager";
+ xContext->getValueByName( the_tdmgr ) >>= xTDMgr;
+ if (! xTDMgr.is())
+ {
+ throw RuntimeException( "cannot get singleton " + the_tdmgr );
+ }
+ try
+ {
+ Reference< reflection::XServiceTypeDescription > xExistingService_td;
+ xTDMgr->getByHierarchicalName( existing_name ) >>= xExistingService_td;
+ if (! xExistingService_td.is())
+ {
+ throw RuntimeException( "cannot get service type description: " + existing_name );
+ }
+
+ // everything's fine if existing service entry supports the one
+ // to be registered
+ if (! is_supported_service( service_name, xExistingService_td ))
+ {
+ throw registry::CannotRegisterImplementationException(
+ "existing singleton service (" + singleton_name + "=" + existing_name + ") "
+ " does not support given one: " + service_name);
+ }
+ }
+ catch (const container::NoSuchElementException & exc)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "cannot get service type description: " + exc.Message,
+ nullptr, anyEx );
+ }
+ }
+ }
+ catch (registry::InvalidValueException &)
+ {
+ // repair
+ xKey2->setStringValue( service_name );
+ }
+ }
+ else
+ {
+ // insert singleton entry
+ xKey2 = xDest->getRootKey()->createKey( keyname );
+ xKey2->setStringValue( service_name );
+ }
+
+ Reference< registry::XRegistryKey > xRegisteredImplNames(
+ xKey2->openKey( "REGISTERED_BY" ) );
+ if (!xRegisteredImplNames.is() || !xRegisteredImplNames->isValid())
+ {
+ // create
+ xRegisteredImplNames = xKey2->createKey( "REGISTERED_BY" );
+ }
+
+ Sequence< OUString > implnames;
+ try
+ {
+ implnames = xRegisteredImplNames->getAsciiListValue();
+ }
+ catch (registry::InvalidValueException &)
+ {
+ }
+ // check implname is already in
+ if (comphelper::findValue(implnames, implname) == -1)
+ {
+ // append and write back
+ implnames.realloc( implnames.getLength() +1 );
+ implnames.getArray()[ implnames.getLength() -1 ] = implname;
+ xRegisteredImplNames->setAsciiListValue( implnames );
+ }
+ }
+}
+
+
+// static prepareRegistry
+
+void prepareRegistry(
+ const Reference < XSimpleRegistry >& xDest,
+ const Reference < XRegistryKey >& xSource,
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ Reference< XComponentContext > const & xContext )
+ // throw ( InvalidRegistryException, CannotRegisterImplementationException, RuntimeException )
+{
+ const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ if (!subKeys.hasElements())
+ {
+ throw InvalidRegistryException(
+ "prepareRegistry(): source registry is empty" );
+ }
+
+ for (const Reference < XRegistryKey >& xImplKey : subKeys)
+ {
+ Reference < XRegistryKey > xKey = xImplKey->openKey(
+ slash_UNO_slash_SERVICES );
+
+ if (xKey.is())
+ {
+ // update entries in SERVICES section
+ const Sequence< Reference < XRegistryKey > > serviceKeys = xKey->openKeys();
+
+ OUString implName = xImplKey->getKeyName().copy(1);
+ sal_Int32 firstDot = implName.indexOf('/');
+
+ if (firstDot >= 0)
+ implName = implName.copy(firstDot + 1);
+
+ sal_Int32 offset = xKey->getKeyName().getLength() + 1;
+
+ for (const Reference < XRegistryKey >& rServiceKey : serviceKeys)
+ {
+ OUString serviceName = rServiceKey->getKeyName().copy(offset);
+
+ createUniqueSubEntry(
+ xDest->getRootKey()->createKey(
+ slash_SERVICES + serviceName ),
+ implName);
+ }
+
+ xKey = xImplKey->openKey( slash_UNO );
+ if (xKey.is())
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys2 = xKey->openKeys();
+
+ for (const Reference < XRegistryKey >& rSubKey2 : subKeys2)
+ {
+ if (rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SERVICES) &&
+ rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_REGISTRY_LINKS ) &&
+ rSubKey2->getKeyName() != Concat2View(xImplKey->getKeyName() + slash_UNO_slash_SINGLETONS ))
+ {
+ prepareUserKeys(xDest, xKey, rSubKey2, implName, true);
+ }
+ }
+ }
+ }
+
+ // update LOCATION entry
+ xKey = xImplKey->createKey( slash_UNO_slash_LOCATION );
+
+ if (xKey.is())
+ {
+ xKey->setAsciiValue(locationUrl);
+ }
+
+ // update ACTIVATOR entry
+ xKey = xImplKey->createKey( slash_UNO_slash_ACTIVATOR );
+
+ if (xKey.is())
+ {
+ xKey->setAsciiValue(implementationLoaderUrl);
+ }
+
+ xKey = xImplKey->openKey( slash_UNO_slash_SERVICES );
+
+ if (xKey.is() && (xKey->getValueType() == RegistryValueType_ASCIILIST))
+ {
+ // update link entries in REGISTRY_LINKS section
+ const Sequence<OUString> linkNames = xKey->getAsciiListValue();
+
+ for (const OUString& rLinkName : linkNames)
+ {
+ prepareLink(xDest, xImplKey, rLinkName);
+ }
+ }
+
+ insert_singletons( xDest, xImplKey, xContext );
+ }
+}
+
+
+void findImplementations( const Reference < XRegistryKey > & xSource,
+ std::vector<OUString>& implNames)
+{
+ bool isImplKey = false;
+
+ try
+ {
+ Reference < XRegistryKey > xKey = xSource->openKey(
+ slash_UNO_slash_SERVICES );
+
+ if (xKey.is() && xKey->getKeyNames().hasElements())
+ {
+ isImplKey = true;
+
+ OUString implName = xSource->getKeyName().copy(1).replace('/', '.');
+ sal_Int32 firstDot = implName.indexOf('.');
+
+ if (firstDot >= 0)
+ implName = implName.copy(firstDot + 1);
+
+ implNames.push_back(implName);
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+
+ if (isImplKey) return;
+
+ try
+ {
+ const Sequence< Reference < XRegistryKey > > subKeys = xSource->openKeys();
+
+ for (const Reference < XRegistryKey >& rSubKey : subKeys)
+ {
+ findImplementations(rSubKey, implNames);
+ }
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+}
+
+
+class ImplementationRegistration
+ : public WeakImplHelper< XImplementationRegistration2, XServiceInfo, XInitialization >
+{
+public:
+ explicit ImplementationRegistration( const Reference < XComponentContext > & rSMgr );
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XImplementationRegistration
+ virtual void SAL_CALL registerImplementation(
+ const OUString& implementationLoader,
+ const OUString& location,
+ const Reference < XSimpleRegistry > & xReg) override;
+
+ virtual sal_Bool SAL_CALL revokeImplementation(
+ const OUString& location,
+ const Reference < XSimpleRegistry >& xReg) override;
+
+ virtual Sequence< OUString > SAL_CALL getImplementations(
+ const OUString& implementationLoader,
+ const OUString& location) override;
+ virtual Sequence< OUString > SAL_CALL checkInstantiation(
+ const OUString& implementationName) override;
+
+ // XImplementationRegistration2
+ virtual void SAL_CALL registerImplementationWithLocation(
+ const OUString& implementationLoader,
+ const OUString& location,
+ const OUString& registeredLocation,
+ const Reference < XSimpleRegistry > & xReg) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize(
+ const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+private: // helper methods
+ void prepareRegister(
+ const OUString& implementationLoader,
+ const OUString& location,
+ const OUString& registeredLocation,
+ const Reference < XSimpleRegistry > & xReg);
+ // throw( CannotRegisterImplementationException, RuntimeException )
+
+ static void doRegister( const Reference < XMultiComponentFactory >& xSMgr,
+ const Reference < XComponentContext > &xCtx,
+ const Reference < XImplementationLoader >& xAct,
+ const Reference < XSimpleRegistry >& xDest,
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl);
+ /* throw ( InvalidRegistryException,
+ MergeConflictException,
+ CannotRegisterImplementationException, RuntimeException ) */
+
+ static void doRevoke( const Reference < XSimpleRegistry >& xDest,
+ std::u16string_view locationUrl );
+ // throw( InvalidRegistryException, RuntimeException )
+ Reference< XSimpleRegistry > getRegistryFromServiceManager() const;
+
+ static Reference< XSimpleRegistry > createTemporarySimpleRegistry(
+ const Reference< XMultiComponentFactory > &rSMgr,
+ const Reference < XComponentContext > & rCtx );
+
+private: // members
+ Reference < XMultiComponentFactory > m_xSMgr;
+ Reference < XComponentContext > m_xCtx;
+};
+
+
+// ImplementationRegistration()
+
+ImplementationRegistration::ImplementationRegistration( const Reference < XComponentContext > & xCtx )
+ : m_xSMgr( xCtx->getServiceManager() )
+ , m_xCtx( xCtx )
+{}
+
+// XServiceInfo
+OUString ImplementationRegistration::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.ImplementationRegistration";
+}
+
+// XServiceInfo
+sal_Bool ImplementationRegistration::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > ImplementationRegistration::getSupportedServiceNames()
+{
+ return { "com.sun.star.registry.ImplementationRegistration" };
+}
+
+Reference< XSimpleRegistry > ImplementationRegistration::getRegistryFromServiceManager() const
+{
+ Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
+ Reference < XSimpleRegistry > xRegistry;
+
+ if( xPropSet.is() ) {
+
+ try { // the implementation does not support XIntrospectionAccess !
+
+ Any aAny = xPropSet->getPropertyValue( Registry );
+
+ if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) {
+ aAny >>= xRegistry;
+ }
+ }
+ catch( UnknownPropertyException & ) {
+ // empty reference is error signal !
+ }
+ }
+
+ return xRegistry;
+}
+
+
+// XInitialization
+
+void ImplementationRegistration::initialize(
+ const css::uno::Sequence< css::uno::Any >& aArgs )
+{
+
+ if( aArgs.getLength() != 4 ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() expects 4 parameters, got " + OUString::number( aArgs.getLength() ),
+ Reference<XInterface > (), 0 );
+ }
+
+ Reference< XImplementationLoader > rLoader;
+ OUString loaderServiceName;
+ OUString locationUrl;
+ Reference< XSimpleRegistry > rReg;
+
+ // 1st argument : An instance of an implementation loader
+ if( aArgs.getConstArray()[0].getValueType().getTypeClass() == TypeClass_INTERFACE ) {
+ aArgs.getConstArray()[0] >>= rLoader;
+ }
+ if( !rLoader.is()) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid first parameter,"
+ "expected " + cppu::UnoType<decltype(rLoader)>::get().getTypeName() +
+ ", got " + aArgs.getConstArray()[0].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+
+ // 2nd argument : The service name of the loader. This name is written into the registry
+ if( aArgs.getConstArray()[1].getValueType().getTypeClass() == TypeClass_STRING ) {
+ aArgs.getConstArray()[1] >>= loaderServiceName;
+ }
+ if( loaderServiceName.isEmpty() ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid second parameter,"
+ "expected string, got " + aArgs.getConstArray()[1].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+
+ // 3rd argument : The file name of the dll, that contains the loader
+ if( aArgs.getConstArray()[2].getValueType().getTypeClass() == TypeClass_STRING ) {
+ aArgs.getConstArray()[2] >>= locationUrl;
+ }
+ if( locationUrl.isEmpty() ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid third parameter,"
+ "expected string, got " + aArgs.getConstArray()[2].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+
+ // 4th argument : The registry, the service should be written to
+ if( aArgs.getConstArray()[3].getValueType().getTypeClass() == TypeClass_INTERFACE ) {
+ aArgs.getConstArray()[3] >>= rReg;
+ }
+
+ if( !rReg.is() ) {
+ rReg = getRegistryFromServiceManager();
+ if( !rReg.is() ) {
+ throw IllegalArgumentException(
+ "ImplementationRegistration::initialize() invalid fourth parameter,"
+ "expected " + cppu::UnoType<decltype(rReg)>::get().getTypeName() +
+ ", got " + aArgs.getConstArray()[3].getValueTypeName(),
+ Reference< XInterface > (), 0 );
+ }
+ }
+
+ doRegister(m_xSMgr, m_xCtx, rLoader , rReg, loaderServiceName , locationUrl, locationUrl);
+}
+
+
+// virtual function registerImplementationWithLocation of XImplementationRegistration2
+
+void ImplementationRegistration::registerImplementationWithLocation(
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl,
+ const Reference < XSimpleRegistry > & xReg)
+{
+ prepareRegister(
+ implementationLoaderUrl, locationUrl, registeredLocationUrl, xReg);
+}
+
+// helper function
+void ImplementationRegistration::prepareRegister(
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl,
+ const Reference < XSimpleRegistry > & xReg)
+ // throw( CannotRegisterImplementationException, RuntimeException )
+{
+ OUString activatorName;
+
+ if (!implementationLoaderUrl.isEmpty())
+ {
+ activatorName = implementationLoaderUrl.getToken(0, ':');
+ } else
+ {
+ // check locationUrl to find out what kind of loader is needed
+ // set implLoaderUrl
+ }
+
+ if( !m_xSMgr.is() ) {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() "
+ "no componentcontext available to instantiate loader" );
+ }
+
+ try
+ {
+ Reference < XImplementationLoader > xAct(
+ m_xSMgr->createInstanceWithContext(activatorName, m_xCtx) , UNO_QUERY );
+ if (!xAct.is())
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() - The service "
+ + activatorName + " cannot be instantiated" );
+ }
+
+ Reference < XSimpleRegistry > xRegistry;
+
+ if (xReg.is())
+ {
+ // registry supplied by user
+ xRegistry = xReg;
+ }
+ else
+ {
+ xRegistry = getRegistryFromServiceManager();
+ }
+
+ if ( xRegistry.is())
+ {
+ doRegister(m_xSMgr, m_xCtx, xAct, xRegistry, implementationLoaderUrl,
+ locationUrl, registeredLocationUrl);
+ }
+
+ }
+ catch( CannotRegisterImplementationException & )
+ {
+ throw;
+ }
+ catch( const InvalidRegistryException & e )
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() "
+ "InvalidRegistryException during registration (" + e.Message + ")" );
+ }
+ catch( const MergeConflictException & e )
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::registerImplementation() "
+ "MergeConflictException during registration (" + e.Message + ")" );
+ }
+
+}
+
+
+// virtual function registerImplementation of XImplementationRegistration
+
+void ImplementationRegistration::registerImplementation(
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const Reference < XSimpleRegistry > & xReg)
+{
+ prepareRegister(implementationLoaderUrl, locationUrl, locationUrl, xReg);
+}
+
+
+// virtual function revokeImplementation of XImplementationRegistration
+
+sal_Bool ImplementationRegistration::revokeImplementation(const OUString& location,
+ const Reference < XSimpleRegistry >& xReg)
+{
+ bool ret = false;
+
+ Reference < XSimpleRegistry > xRegistry;
+
+ if (xReg.is()) {
+ xRegistry = xReg;
+ }
+ else {
+ Reference < XPropertySet > xPropSet( m_xSMgr, UNO_QUERY );
+ if( xPropSet.is() ) {
+ try {
+ Any aAny = xPropSet->getPropertyValue( Registry );
+
+ if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
+ {
+ aAny >>= xRegistry;
+ }
+ }
+ catch ( UnknownPropertyException & ) {
+ }
+ }
+ }
+
+ if (xRegistry.is())
+ {
+ try
+ {
+ doRevoke(xRegistry, location);
+ ret = true;
+ }
+ catch( InvalidRegistryException & )
+ {
+ // no way to transport the error, as no exception is specified and a runtime
+ // exception is not appropriate.
+ OSL_FAIL( "InvalidRegistryException during revokeImplementation" );
+ }
+ }
+
+ return ret;
+}
+
+
+// virtual function getImplementations of XImplementationRegistration
+
+Sequence< OUString > ImplementationRegistration::getImplementations(
+ const OUString & implementationLoaderUrl,
+ const OUString & locationUrl)
+{
+ OUString activatorName;
+
+ if (!implementationLoaderUrl.isEmpty())
+ {
+ activatorName = implementationLoaderUrl.getToken(0, ':');
+ } else
+ {
+ // check locationUrl to find out what kind of loader is needed
+ // set implementationLoaderUrl
+ }
+
+ if( m_xSMgr.is() ) {
+
+ Reference < XImplementationLoader > xAct(
+ m_xSMgr->createInstanceWithContext( activatorName, m_xCtx ), UNO_QUERY );
+
+ if (xAct.is())
+ {
+
+ Reference < XSimpleRegistry > xReg =
+ createTemporarySimpleRegistry( m_xSMgr, m_xCtx);
+
+ if (xReg.is())
+ {
+ try
+ {
+ xReg->open(OUString() /* in mem */, false, true);
+ Reference < XRegistryKey > xImpl;
+
+ { // only necessary for deleting the temporary variable of rootkey
+ xImpl = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
+ }
+ if (xAct->writeRegistryInfo(xImpl, implementationLoaderUrl, locationUrl))
+ {
+ std::vector<OUString> implNames;
+
+ findImplementations(xImpl, implNames);
+
+ if (!implNames.empty())
+ {
+ Sequence<OUString> seqImpl(comphelper::containerToSequence(implNames));
+ xImpl->closeKey();
+ return seqImpl;
+ }
+ }
+
+ xImpl->closeKey();
+ }
+ catch(MergeConflictException&)
+ {
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+ }
+ }
+ }
+
+ return Sequence<OUString>();
+}
+
+
+// virtual function checkInstantiation of XImplementationRegistration
+
+Sequence< OUString > ImplementationRegistration::checkInstantiation(const OUString&)
+{
+ OSL_FAIL( "ImplementationRegistration::checkInstantiation not implemented" );
+ return Sequence<OUString>();
+}
+
+
+// helper function doRegistration
+
+
+void ImplementationRegistration::doRevoke(
+ const Reference < XSimpleRegistry >& xDest,
+ std::u16string_view locationUrl)
+ // throw ( InvalidRegistryException, RuntimeException )
+{
+ if( !xDest.is() )
+ return;
+
+ std::vector<OUString> aNames;
+
+ Reference < XRegistryKey > xRootKey( xDest->getRootKey() );
+
+ Reference < XRegistryKey > xKey =
+ xRootKey->openKey( slash_IMPLEMENTATIONS );
+ if (xKey.is() && xKey->isValid())
+ {
+ deleteAllImplementations(xDest, xKey, locationUrl, aNames);
+ }
+
+ xKey = xRootKey->openKey( slash_SERVICES );
+ if (xKey.is())
+ {
+ for (auto const& name : aNames)
+ {
+ deleteAllServiceEntries(xDest, xKey, name);
+ }
+ }
+
+ xKey = xRootKey->openKey( "/SINGLETONS" );
+ if (xKey.is() && xKey->isValid())
+ {
+ delete_all_singleton_entries( xKey, aNames );
+ }
+
+ if (xRootKey.is())
+ xRootKey->closeKey();
+ if (xKey.is() && xKey->isValid() )
+ xKey->closeKey();
+}
+
+void ImplementationRegistration::doRegister(
+ const Reference< XMultiComponentFactory > & xSMgr,
+ const Reference< XComponentContext > &xCtx,
+ const Reference < XImplementationLoader > & xAct,
+ const Reference < XSimpleRegistry >& xDest,
+ const OUString& implementationLoaderUrl,
+ const OUString& locationUrl,
+ const OUString& registeredLocationUrl)
+ /* throw ( InvalidRegistryException,
+ MergeConflictException,
+ CannotRegisterImplementationException, RuntimeException ) */
+{
+ Reference < XSimpleRegistry > xReg =
+ createTemporarySimpleRegistry( xSMgr, xCtx );
+ Reference < XRegistryKey > xSourceKey;
+
+ if (!(xAct.is() && xReg.is() && xDest.is()))
+ return;
+
+ try
+ {
+ xReg->open(OUString() /* in mem */, false, true);
+
+ { // only necessary for deleting the temporary variable of rootkey
+ xSourceKey = xReg->getRootKey()->createKey( slash_IMPLEMENTATIONS );
+ }
+
+ bool bSuccess =
+ xAct->writeRegistryInfo(xSourceKey, implementationLoaderUrl, locationUrl);
+ if ( !bSuccess )
+ {
+ throw CannotRegisterImplementationException(
+ "ImplementationRegistration::doRegistration() component registration signaled failure" );
+ }
+
+ prepareRegistry(xDest, xSourceKey, implementationLoaderUrl, registeredLocationUrl, xCtx);
+
+ xSourceKey->closeKey();
+
+ xSourceKey = xReg->getRootKey();
+ Reference < XRegistryKey > xDestKey = xDest->getRootKey();
+ stoc_impreg::mergeKeys( xDestKey, xSourceKey );
+ xDestKey->closeKey();
+ xSourceKey->closeKey();
+
+
+ // Cleanup Source registry.
+ if ( xSourceKey->isValid() )
+ xSourceKey->closeKey();
+ }
+ catch(CannotRegisterImplementationException&)
+ {
+ if ( xSourceKey->isValid() )
+ xSourceKey->closeKey();
+ // and throw again
+ throw;
+ }
+}
+
+
+Reference< XSimpleRegistry > ImplementationRegistration::createTemporarySimpleRegistry(
+ const Reference< XMultiComponentFactory > &rSMgr,
+ const Reference < XComponentContext > & xCtx)
+{
+
+ Reference < XSimpleRegistry > xReg(
+ rSMgr->createInstanceWithContext(
+ com_sun_star_registry_SimpleRegistry, xCtx ),
+ UNO_QUERY);
+ OSL_ASSERT( xReg.is() );
+ return xReg;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_ImplementationRegistration_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ImplementationRegistration(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/implementationregistration/mergekeys.cxx b/stoc/source/implementationregistration/mergekeys.cxx
new file mode 100644
index 0000000000..dde219b9ad
--- /dev/null
+++ b/stoc/source/implementationregistration/mergekeys.cxx
@@ -0,0 +1,177 @@
+/* -*- 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 <utility>
+#include <vector>
+
+#include <osl/diagnose.h>
+
+#include <com/sun/star/registry/XRegistryKey.hpp>
+
+#include "mergekeys.hxx"
+
+using namespace ::osl;
+using namespace css::uno;
+using namespace ::com::sun::star;
+
+namespace stoc_impreg
+{
+
+namespace {
+
+struct Link
+{
+ OUString m_name;
+ OUString m_target;
+
+ Link( OUString name, OUString target )
+ : m_name(std::move( name ))
+ , m_target(std::move( target ))
+ {}
+};
+
+}
+
+typedef ::std::vector< Link > t_links;
+
+
+static void mergeKeys(
+ Reference< registry::XRegistryKey > const & xDest,
+ Reference< registry::XRegistryKey > const & xSource,
+ t_links & links )
+ // throw( registry::InvalidRegistryException, registry::MergeConflictException, RuntimeException )
+{
+ if (!xSource.is() || !xSource->isValid()) {
+ throw registry::InvalidRegistryException(
+ "source key is null or invalid!" );
+ }
+ if (!xDest.is() || !xDest->isValid()) {
+ throw registry::InvalidRegistryException(
+ "destination key is null or invalid!" );
+ }
+
+ // write value
+ switch (xSource->getValueType())
+ {
+ case registry::RegistryValueType_NOT_DEFINED:
+ break;
+ case registry::RegistryValueType_LONG:
+ xDest->setLongValue( xSource->getLongValue() );
+ break;
+ case registry::RegistryValueType_ASCII:
+ xDest->setAsciiValue( xSource->getAsciiValue() );
+ break;
+ case registry::RegistryValueType_STRING:
+ xDest->setStringValue( xSource->getStringValue() );
+ break;
+ case registry::RegistryValueType_BINARY:
+ xDest->setBinaryValue( xSource->getBinaryValue() );
+ break;
+ case registry::RegistryValueType_LONGLIST:
+ xDest->setLongListValue( xSource->getLongListValue() );
+ break;
+ case registry::RegistryValueType_ASCIILIST:
+ xDest->setAsciiListValue( xSource->getAsciiListValue() );
+ break;
+ case registry::RegistryValueType_STRINGLIST:
+ xDest->setStringListValue( xSource->getStringListValue() );
+ break;
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ // sub keys
+ Sequence< OUString > sourceKeys( xSource->getKeyNames() );
+ OUString const * pSourceKeys = sourceKeys.getConstArray();
+ for ( sal_Int32 nPos = sourceKeys.getLength(); nPos--; )
+ {
+ // key name
+ OUString name( pSourceKeys[ nPos ] );
+ sal_Int32 nSlash = name.lastIndexOf( '/' );
+ if (nSlash >= 0)
+ {
+ name = name.copy( nSlash +1 );
+ }
+
+ if (xSource->getKeyType( name ) == registry::RegistryKeyType_KEY)
+ {
+ // try to open existing dest key or create new one
+ Reference< registry::XRegistryKey > xDestKey( xDest->createKey( name ) );
+ Reference< registry::XRegistryKey > xSourceKey( xSource->openKey( name ) );
+ mergeKeys( xDestKey, xSourceKey, links );
+ xSourceKey->closeKey();
+ xDestKey->closeKey();
+ }
+ else // link
+ {
+ // remove existing key
+ Reference< registry::XRegistryKey > xDestKey( xDest->openKey( name ) );
+ if (xDestKey.is() && xDestKey->isValid()) // something to remove
+ {
+ xDestKey->closeKey();
+ if (xDest->getKeyType( name ) == registry::RegistryKeyType_LINK)
+ {
+ xDest->deleteLink( name );
+ }
+ else
+ {
+ xDest->deleteKey( name );
+ }
+ }
+
+ links.push_back( Link(
+ pSourceKeys[ nPos ], // abs path
+ xSource->getResolvedName( name ) // abs resolved name
+ ) );
+ }
+ }
+}
+
+
+void mergeKeys(
+ Reference< registry::XRegistryKey > const & xDest,
+ Reference< registry::XRegistryKey > const & xSource )
+ // throw( registry::InvalidRegistryException, registry::MergeConflictException, RuntimeException )
+{
+ if (!xDest.is() || !xDest->isValid()) {
+ throw registry::InvalidRegistryException(
+ "destination key is null or invalid!" );
+ }
+ if (xDest->isReadOnly())
+ {
+ throw registry::InvalidRegistryException(
+ "destination registry is read-only! cannot merge!" );
+ }
+
+ t_links links;
+ links.reserve( 16 );
+ mergeKeys( xDest, xSource, links );
+
+ for ( size_t nPos = links.size(); nPos--; )
+ {
+ Link const & r = links[ nPos ];
+ OSL_VERIFY( xDest->createLink( r.m_name, r.m_target ) );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/implementationregistration/mergekeys.hxx b/stoc/source/implementationregistration/mergekeys.hxx
new file mode 100644
index 0000000000..3f54e57124
--- /dev/null
+++ b/stoc/source/implementationregistration/mergekeys.hxx
@@ -0,0 +1,46 @@
+/* -*- 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_STOC_SOURCE_IMPLEMENTATIONREGISTRATION_MERGEKEYS_HXX
+#define INCLUDED_STOC_SOURCE_IMPLEMENTATIONREGISTRATION_MERGEKEYS_HXX
+
+#include <sal/config.h>
+#include <sal/types.h>
+
+namespace com::sun::star::registry {
+ class XRegistryKey;
+}
+namespace com::sun::star::uno { template <typename > class Reference; }
+
+namespace stoc_impreg {
+
+// throws css::registry::InvalidRegistryException,
+// css::registry::MergeConflictException,
+// css::uno::RuntimeException:
+void mergeKeys(
+ css::uno::Reference< css::registry::XRegistryKey >
+ const & xDest,
+ css::uno::Reference< css::registry::XRegistryKey >
+ const & xSource);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/inspect/introspection.component b/stoc/source/inspect/introspection.component
new file mode 100644
index 0000000000..84e121fad1
--- /dev/null
+++ b/stoc/source/inspect/introspection.component
@@ -0,0 +1,28 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.Introspection"
+ constructor="com_sun_star_comp_stoc_Introspection_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.beans.Introspection"/>
+ <singleton name="com.sun.star.beans.theIntrospection"/>
+ </implementation>
+</component>
diff --git a/stoc/source/inspect/introspection.cxx b/stoc/source/inspect/introspection.cxx
new file mode 100644
index 0000000000..eb06b66568
--- /dev/null
+++ b/stoc/source/inspect/introspection.cxx
@@ -0,0 +1,2420 @@
+/* -*- 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 <cstddef>
+#include <limits>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include <o3tl/any.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+#include <com/sun/star/lang/NoSuchMethodException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/reflection/XIdlClass.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <com/sun/star/beans/XIntrospection.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+#include <com/sun/star/beans/XExactName.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyConcept.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <unordered_map>
+#include <utility>
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::container;
+using namespace css::beans;
+using namespace css::beans::PropertyAttribute;
+using namespace css::beans::PropertyConcept;
+using namespace css::beans::MethodConcept;
+using namespace cppu;
+using namespace osl;
+
+namespace
+{
+
+typedef WeakImplHelper< XIntrospectionAccess, XMaterialHolder, XExactName,
+ XPropertySet, XFastPropertySet, XPropertySetInfo,
+ XNameContainer, XIndexContainer, XEnumerationAccess,
+ XIdlArray, XUnoTunnel > IntrospectionAccessHelper;
+
+
+// Special value for Method-Concept, to be able to mark "normal" functions
+#define MethodConcept_NORMAL_IMPL 0x80000000
+
+
+// Method to assert, if a class is derived from another class
+bool isDerivedFrom( const Reference<XIdlClass>& xToTestClass, const Reference<XIdlClass>& xDerivedFromClass )
+{
+ const Sequence< Reference<XIdlClass> > aClassesSeq = xToTestClass->getSuperclasses();
+
+ return std::any_of(aClassesSeq.begin(), aClassesSeq.end(),
+ [&xDerivedFromClass](const Reference<XIdlClass>& rxClass) {
+ return xDerivedFromClass->equals( rxClass )
+ || isDerivedFrom( rxClass, xDerivedFromClass );
+ });
+}
+
+
+// *** Classification of Properties (no enum, to be able to use Sequence) ***
+// Properties from a PropertySet-Interface
+#define MAP_PROPERTY_SET 0
+// Properties from Fields
+#define MAP_FIELD 1
+// Properties that get described with get/set methods
+#define MAP_GETSET 2
+// Properties with only a set method
+#define MAP_SETONLY 3
+
+
+// Increments by which the size of sequences get adjusted
+#define ARRAY_SIZE_STEP 20
+
+
+//*** IntrospectionAccessStatic_Impl ***
+
+// Equals to the old IntrospectionAccessImpl, forms now a static
+// part of the new Instance-related ImplIntrospectionAccess
+
+// Hashtable for the search of names
+typedef std::unordered_map
+<
+ OUString,
+ sal_Int32
+>
+IntrospectionNameMap;
+
+
+// Hashtable to assign exact names to the Lower-Case
+// converted names, for the support of XExactName
+typedef std::unordered_map
+<
+ OUString,
+ OUString
+>
+LowerToExactNameMap;
+
+
+class IntrospectionAccessStatic_Impl: public salhelper::SimpleReferenceObject
+{
+ friend class Implementation;
+ friend class ImplIntrospectionAccess;
+
+ // Holding CoreReflection
+ Reference< XIdlReflection > mxCoreReflection;
+
+ // InterfaceSequences, to save additional information in a property
+ // for example the Field at MAP_FIELD, the get/set-Methods at MAP_GETSET, et cetera
+ std::vector< Reference<XInterface> > aInterfaceSeq1;
+ std::vector< Reference<XInterface> > aInterfaceSeq2;
+
+ // Hashtables for names
+ IntrospectionNameMap maPropertyNameMap;
+ IntrospectionNameMap maMethodNameMap;
+ LowerToExactNameMap maLowerToExactNameMap;
+
+ // Vector of all Properties, also for delivering from getProperties()
+ std::vector<Property> maAllPropertySeq;
+
+ // Mapping of properties to Access-Types
+ std::vector<sal_Int16> maMapTypeSeq;
+
+ // Classification of found methods
+ std::vector<sal_Int32> maPropertyConceptSeq;
+
+ // Number of Properties
+ sal_Int32 mnPropCount;
+
+ // Number of Properties, which are assigned to particular concepts
+ //sal_Int32 mnDangerousPropCount;
+ sal_Int32 mnPropertySetPropCount;
+ sal_Int32 mnAttributePropCount;
+ sal_Int32 mnMethodPropCount;
+
+ // Flags which indicate if various interfaces are present
+ bool mbFastPropSet;
+ bool mbElementAccess;
+ bool mbNameAccess;
+ bool mbNameReplace;
+ bool mbNameContainer;
+ bool mbIndexAccess;
+ bool mbIndexReplace;
+ bool mbIndexContainer;
+ bool mbEnumerationAccess;
+ bool mbIdlArray;
+ bool mbUnoTunnel;
+
+ // Original handles of FastPropertySets
+ std::unique_ptr<sal_Int32[]> mpOrgPropertyHandleArray;
+
+ // MethodSequence, that accepts all methods
+ std::vector< Reference<XIdlMethod> > maAllMethodSeq;
+
+ // Classification of found methods
+ std::vector<sal_Int32> maMethodConceptSeq;
+
+ // Number of methods
+ sal_Int32 mnMethCount;
+
+ // Sequence of Listener, that can be registered
+ std::vector< Type > maSupportedListenerSeq;
+
+ // Helper-methods for adjusting sizes of Sequences
+ void checkPropertyArraysSize( sal_Int32 iNextIndex );
+ static void checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq, std::vector<Reference<XInterface>>& rInterfaceVec,
+ sal_Int32 iNextIndex );
+
+public:
+ explicit IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ );
+ sal_Int32 getPropertyIndex( const OUString& aPropertyName ) const;
+ sal_Int32 getMethodIndex( const OUString& aMethodName ) const;
+
+ // Methods of XIntrospectionAccess (OLD, now only Impl)
+ void setPropertyValue(const Any& obj, const OUString& aPropertyName, const Any& aValue) const;
+// void setPropertyValue(Any& obj, const OUString& aPropertyName, const Any& aValue) const;
+ Any getPropertyValue(const Any& obj, const OUString& aPropertyName) const;
+ void setPropertyValueByIndex(const Any& obj, sal_Int32 nIndex, const Any& aValue) const;
+// void setPropertyValueByIndex(Any& obj, sal_Int32 nIndex, const Any& aValue) const;
+ Any getPropertyValueByIndex(const Any& obj, sal_Int32 nIndex) const;
+
+ const std::vector<Property>& getProperties() const { return maAllPropertySeq; }
+ const std::vector< Reference<XIdlMethod> >& getMethods() const { return maAllMethodSeq; }
+ const std::vector< Type >& getSupportedListeners() const { return maSupportedListenerSeq; }
+ const std::vector<sal_Int32>& getPropertyConcepts() const { return maPropertyConceptSeq; }
+ const std::vector<sal_Int32>& getMethodConcepts() const { return maMethodConceptSeq; }
+};
+
+
+// Ctor
+IntrospectionAccessStatic_Impl::IntrospectionAccessStatic_Impl( Reference< XIdlReflection > const & xCoreReflection_ )
+ : mxCoreReflection( xCoreReflection_ )
+{
+ aInterfaceSeq1.resize( ARRAY_SIZE_STEP );
+ aInterfaceSeq2.resize( ARRAY_SIZE_STEP );
+
+ // Property-Data
+ maAllPropertySeq.resize( ARRAY_SIZE_STEP );
+ maMapTypeSeq.resize( ARRAY_SIZE_STEP );
+ maPropertyConceptSeq.resize( ARRAY_SIZE_STEP );
+
+ mbFastPropSet = false;
+ mbElementAccess = false;
+ mbNameAccess = false;
+ mbNameReplace = false;
+ mbNameContainer = false;
+ mbIndexAccess = false;
+ mbIndexReplace = false;
+ mbIndexContainer = false;
+ mbEnumerationAccess = false;
+ mbIdlArray = false;
+ mbUnoTunnel = false;
+
+ mpOrgPropertyHandleArray = nullptr;
+
+ mnPropCount = 0;
+ //mnDangerousPropCount = 0;
+ mnPropertySetPropCount = 0;
+ mnAttributePropCount = 0;
+ mnMethodPropCount = 0;
+
+ // Method-Data
+ mnMethCount = 0;
+}
+
+sal_Int32 IntrospectionAccessStatic_Impl::getPropertyIndex( const OUString& aPropertyName ) const
+{
+ auto aIt = maPropertyNameMap.find(aPropertyName);
+ if (aIt != maPropertyNameMap.end())
+ return aIt->second;
+
+ return -1;
+}
+
+sal_Int32 IntrospectionAccessStatic_Impl::getMethodIndex( const OUString& aMethodName ) const
+{
+ auto aIt = maMethodNameMap.find(aMethodName);
+ if (aIt != maMethodNameMap.end())
+ {
+ return aIt->second;
+ }
+
+ // #95159 Check if full qualified name matches
+ sal_Int32 nSearchFrom = aMethodName.getLength();
+ while( true )
+ {
+ // Strategy: Search back until the first '_' is found
+ sal_Int32 nFound = aMethodName.lastIndexOf( '_', nSearchFrom );
+ if( nFound == -1 )
+ break;
+
+ OUString aPureMethodName = aMethodName.copy( nFound + 1 );
+
+ aIt = maMethodNameMap.find( aPureMethodName );
+ if (aIt != maMethodNameMap.end())
+ {
+ // Check if it can be a type?
+ // Problem: Does not work if package names contain _ ?!
+ OUString aStr = aMethodName.copy( 0, nFound );
+ OUString aTypeName = aStr.replace( '_', '.' );
+ Reference< XIdlClass > xClass = mxCoreReflection->forName( aTypeName );
+ if( xClass.is() )
+ {
+ // If this is a valid class it could be the right method
+
+ // Could be the right method, type has to be checked
+ const sal_Int32 iHashResult = aIt->second;
+
+ const Reference<XIdlMethod> xMethod = maAllMethodSeq[iHashResult];
+
+ Reference< XIdlClass > xMethClass = xMethod->getDeclaringClass();
+ if( xClass->equals( xMethClass ) )
+ {
+ return iHashResult;
+ }
+ else
+ {
+ // Could also be another method with the same name
+ // Iterate over all methods
+ size_t nLen = maAllMethodSeq.size();
+ for (size_t i = 0; i < nLen; ++i)
+ {
+ const Reference<XIdlMethod> xMethod2 = maAllMethodSeq[ i ];
+ if( xMethod2->getName() == aPureMethodName )
+ {
+ Reference< XIdlClass > xMethClass2 = xMethod2->getDeclaringClass();
+
+ if( xClass->equals( xMethClass2 ) )
+ {
+ return i;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ nSearchFrom = nFound - 1;
+ if( nSearchFrom < 0 )
+ break;
+ }
+ return -1;
+}
+
+void IntrospectionAccessStatic_Impl::setPropertyValue( const Any& obj, const OUString& aPropertyName, const Any& aValue ) const
+//void IntrospectionAccessStatic_Impl::setPropertyValue( Any& obj, const OUString& aPropertyName, const Any& aValue ) const
+{
+ sal_Int32 i = getPropertyIndex( aPropertyName );
+ if( i == -1 )
+ throw UnknownPropertyException(aPropertyName);
+ setPropertyValueByIndex( obj, i, aValue );
+}
+
+void IntrospectionAccessStatic_Impl::setPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
+//void IntrospectionAccessStatic_Impl::setPropertyValueByIndex( Any& obj, sal_Int32 nSequenceIndex, const Any& aValue) const
+{
+ // Is the passed object something that fits?
+ Reference<XInterface> xInterface;
+ if( !(obj >>= xInterface) )
+ {
+ TypeClass eObjType = obj.getValueType().getTypeClass();
+ if( nSequenceIndex >= mnPropCount)
+ throw IllegalArgumentException(
+ "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), index > propertyCount, " +
+ OUString::number(nSequenceIndex) + " > " + OUString::number(mnPropCount),
+ Reference<XInterface>(), 0);
+ if( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION )
+ throw IllegalArgumentException(
+ "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), expected struct or exception, got" +
+ obj.getValueType().getTypeName(), Reference<XInterface>(), 0);
+ }
+
+ // Test flags
+ if( (maAllPropertySeq[ nSequenceIndex ].Attributes & READONLY) != 0 )
+ {
+ throw UnknownPropertyException(
+ "IntrospectionAccessStatic_Impl::setPropertyValueByIndex(), property at index " + OUString::number(nSequenceIndex) + " is readonly");
+ }
+
+ switch( maMapTypeSeq[ nSequenceIndex ] )
+ {
+ case MAP_PROPERTY_SET:
+ {
+ // Get Property
+ const Property& rProp = maAllPropertySeq[ nSequenceIndex ];
+
+ // Convert Interface-Parameter to the correct type
+ bool bUseCopy = false;
+ Any aRealValue;
+
+ if( auto valInterface = o3tl::tryAccess<
+ css::uno::Reference<css::uno::XInterface>>(aValue) )
+ {
+ Type aPropType = rProp.Type;
+ OUString aTypeName( aPropType.getTypeName() );
+ Reference< XIdlClass > xPropClass = mxCoreReflection->forName( aTypeName );
+ //Reference<XIdlClass> xPropClass = rProp.Type;
+ if( xPropClass.is() && xPropClass->getTypeClass() == TypeClass_INTERFACE )
+ {
+ if( valInterface->is() )
+ {
+ //Any queryInterface( const Type& rType );
+ aRealValue = (*valInterface)->queryInterface( aPropType );
+ if( aRealValue.hasValue() )
+ bUseCopy = true;
+ }
+ }
+ }
+
+ // Do we have a FastPropertySet and a valid Handle?
+ // CAUTION: At this point we exploit that the PropertySet
+ // gets queried at the beginning of the Introspection-Process.
+ sal_Int32 nOrgHandle;
+ if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
+ {
+ // Retrieve PropertySet-Interface
+ Reference<XFastPropertySet> xFastPropSet =
+ Reference<XFastPropertySet>::query( xInterface );
+ if( xFastPropSet.is() )
+ {
+ xFastPropSet->setFastPropertyValue( nOrgHandle, bUseCopy ? aRealValue : aValue );
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ }
+ }
+ // else take the normal one
+ else
+ {
+ // Retrieve PropertySet-Interface
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( xInterface );
+ if( xPropSet.is() )
+ {
+ xPropSet->setPropertyValue( rProp.Name, bUseCopy ? aRealValue : aValue );
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ }
+ }
+ }
+ break;
+
+ case MAP_FIELD:
+ {
+ Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
+ Reference<XIdlField2> xField2(xField, UNO_QUERY);
+ if( xField2.is() )
+ {
+ xField2->set( const_cast<Any&>(obj), aValue );
+ // IllegalArgumentException
+ // NullPointerException
+ } else
+ if( xField.is() )
+ {
+ xField->set( obj, aValue );
+ // IllegalArgumentException
+ // NullPointerException
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ }
+ }
+ break;
+
+ case MAP_GETSET:
+ case MAP_SETONLY:
+ {
+ // Fetch set method
+ Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq2[ nSequenceIndex ].get());
+ if( xMethod.is() )
+ {
+ Sequence<Any> args( 1 );
+ args.getArray()[0] = aValue;
+ xMethod->invoke( obj, args );
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ }
+ }
+ break;
+ }
+}
+
+Any IntrospectionAccessStatic_Impl::getPropertyValue( const Any& obj, const OUString& aPropertyName ) const
+{
+ sal_Int32 i = getPropertyIndex( aPropertyName );
+ if( i != -1 )
+ return getPropertyValueByIndex( obj, i );
+
+ throw UnknownPropertyException(aPropertyName);
+}
+
+Any IntrospectionAccessStatic_Impl::getPropertyValueByIndex(const Any& obj, sal_Int32 nSequenceIndex) const
+{
+ Any aRet;
+
+ // Is there anything suitable in the passed object?
+ Reference<XInterface> xInterface;
+ if( !(obj >>= xInterface) )
+ {
+ TypeClass eObjType = obj.getValueType().getTypeClass();
+ if( nSequenceIndex >= mnPropCount || ( eObjType != TypeClass_STRUCT && eObjType != TypeClass_EXCEPTION ) )
+ {
+ // throw IllegalArgumentException();
+ return aRet;
+ }
+ }
+
+ switch( maMapTypeSeq[ nSequenceIndex ] )
+ {
+ case MAP_PROPERTY_SET:
+ {
+ // Acquire property
+ const Property& rProp = maAllPropertySeq[ nSequenceIndex ];
+
+ // Do we have a FastPropertySet and a valid handle?
+ // NOTE: At this point is exploited that the PropertySet
+ // is queried at the beginning of introspection process.
+ sal_Int32 nOrgHandle;
+ if( mbFastPropSet && ( nOrgHandle = mpOrgPropertyHandleArray[ nSequenceIndex ] ) != -1 )
+ {
+ // Fetch the PropertySet interface
+ Reference<XFastPropertySet> xFastPropSet =
+ Reference<XFastPropertySet>::query( xInterface );
+ if( xFastPropSet.is() )
+ {
+ aRet = xFastPropSet->getFastPropertyValue( nOrgHandle);
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ return aRet;
+ }
+ }
+ // Otherwise use the normal one
+ else
+ {
+ // Fetch the PropertySet interface
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( xInterface );
+ if( xPropSet.is() )
+ {
+ aRet = xPropSet->getPropertyValue( rProp.Name );
+ }
+ else
+ {
+ // throw UnknownPropertyException
+ return aRet;
+ }
+ }
+ }
+ break;
+
+ case MAP_FIELD:
+ {
+ Reference<XIdlField> xField = static_cast<XIdlField*>(aInterfaceSeq1[ nSequenceIndex ].get());
+ if( xField.is() )
+ {
+ aRet = xField->get( obj );
+ // IllegalArgumentException
+ // NullPointerException
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ return aRet;
+ }
+ }
+ break;
+
+ case MAP_GETSET:
+ {
+ // Fetch get method
+ Reference<XIdlMethod> xMethod = static_cast<XIdlMethod*>(aInterfaceSeq1[ nSequenceIndex ].get());
+ if( xMethod.is() )
+ {
+ Sequence<Any> args;
+ aRet = xMethod->invoke( obj, args );
+ }
+ else
+ {
+ // throw IllegalArgumentException();
+ return aRet;
+ }
+ }
+ break;
+
+ case MAP_SETONLY:
+ // Get method does not exist
+ // throw WriteOnlyPropertyException();
+ return aRet;
+ }
+ return aRet;
+}
+
+
+// Helper method to adjust the size of the vectors
+void IntrospectionAccessStatic_Impl::checkPropertyArraysSize( sal_Int32 iNextIndex )
+{
+ sal_Int32 nLen = static_cast<sal_Int32>(maAllPropertySeq.size());
+ if( iNextIndex >= nLen )
+ {
+ maAllPropertySeq.resize( nLen + ARRAY_SIZE_STEP );
+ maMapTypeSeq.resize( nLen + ARRAY_SIZE_STEP );
+ maPropertyConceptSeq.resize( nLen + ARRAY_SIZE_STEP );
+ }
+}
+
+void IntrospectionAccessStatic_Impl::checkInterfaceArraySize( std::vector< Reference<XInterface> >& rSeq,
+ std::vector<Reference<XInterface>>& rInterfaceVec, sal_Int32 iNextIndex )
+{
+ sal_Int32 nLen = rSeq.size();
+ if( iNextIndex >= nLen )
+ {
+ // Synchronize new size with ARRAY_SIZE_STEP
+ sal_Int32 nMissingSize = iNextIndex - nLen + 1;
+ sal_Int32 nSteps = nMissingSize / ARRAY_SIZE_STEP + 1;
+ sal_Int32 nNewSize = nLen + nSteps * ARRAY_SIZE_STEP;
+
+ rSeq.resize( nNewSize );
+ rInterfaceVec = rSeq;
+ }
+}
+
+
+//*** ImplIntrospectionAccess ***
+
+
+// New Impl class as part of the introspection conversion to instance-bound
+// Introspection with property access via XPropertySet. The old class
+// ImplIntrospectionAccess lives on as IntrospectionAccessStatic_Impl
+class ImplIntrospectionAccess : public IntrospectionAccessHelper
+{
+ friend class Implementation;
+
+ // Object under examination
+ Any maInspectedObject;
+
+ // As interface
+ Reference<XInterface> mxIface;
+
+ // Static introspection data
+ rtl::Reference< IntrospectionAccessStatic_Impl > mpStaticImpl;
+
+ // Last Sequence that came with getProperties (optimization)
+ Sequence<Property> maLastPropertySeq;
+ sal_Int32 mnLastPropertyConcept;
+
+ // Last Sequence that came with getMethods (optimization)
+ Sequence<Reference<XIdlMethod> > maLastMethodSeq;
+ sal_Int32 mnLastMethodConcept;
+
+ // Guards the caching of queried interfaces
+ std::mutex m_aMutex;
+
+ // Original interfaces of the objects
+ Reference<XElementAccess> mxObjElementAccess;
+ Reference<XNameContainer> mxObjNameContainer;
+ Reference<XNameReplace> mxObjNameReplace;
+ Reference<XNameAccess> mxObjNameAccess;
+ Reference<XIndexContainer> mxObjIndexContainer;
+ Reference<XIndexReplace> mxObjIndexReplace;
+ Reference<XIndexAccess> mxObjIndexAccess;
+ Reference<XEnumerationAccess> mxObjEnumerationAccess;
+ Reference<XIdlArray> mxObjIdlArray;
+
+ Reference<XElementAccess> getXElementAccess();
+ Reference<XNameContainer> getXNameContainer();
+ Reference<XNameReplace> getXNameReplace();
+ Reference<XNameAccess> getXNameAccess();
+ Reference<XIndexContainer> getXIndexContainer();
+ Reference<XIndexReplace> getXIndexReplace();
+ Reference<XIndexAccess> getXIndexAccess();
+ Reference<XEnumerationAccess> getXEnumerationAccess();
+ Reference<XIdlArray> getXIdlArray();
+
+ void cacheXNameContainer();
+ void cacheXIndexContainer();
+
+public:
+ ImplIntrospectionAccess( Any obj, rtl::Reference< IntrospectionAccessStatic_Impl > pStaticImpl_ );
+
+ // Methods from XIntrospectionAccess
+ virtual sal_Int32 SAL_CALL getSuppliedMethodConcepts() override;
+ virtual sal_Int32 SAL_CALL getSuppliedPropertyConcepts() override;
+ virtual Property SAL_CALL getProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
+ virtual sal_Bool SAL_CALL hasProperty(const OUString& Name, sal_Int32 PropertyConcepts) override;
+ virtual Sequence< Property > SAL_CALL getProperties(sal_Int32 PropertyConcepts) override;
+ virtual Reference<XIdlMethod> SAL_CALL getMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
+ virtual sal_Bool SAL_CALL hasMethod(const OUString& Name, sal_Int32 MethodConcepts) override;
+ virtual Sequence< Reference<XIdlMethod> > SAL_CALL getMethods(sal_Int32 MethodConcepts) override;
+ virtual Sequence< Type > SAL_CALL getSupportedListeners() override;
+ using OWeakObject::queryAdapter;
+ virtual Reference<XInterface> SAL_CALL queryAdapter( const Type& rType ) override;
+
+ // Methods from XMaterialHolder
+ virtual Any SAL_CALL getMaterial() override;
+
+ // Methods from XExactName
+ virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) override;
+
+ // Methods from XInterface
+ virtual Any SAL_CALL queryInterface( const Type& rType ) override;
+ virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OWeakObject::release(); }
+
+ // Methods from XPropertySet
+ virtual Reference<XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue(const OUString& aPropertyName, const Any& aValue) override;
+ virtual Any SAL_CALL getPropertyValue(const OUString& aPropertyName) override;
+ virtual void SAL_CALL addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
+ virtual void SAL_CALL removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener) override;
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener) override;
+
+ // Methods from XFastPropertySet
+ virtual void SAL_CALL setFastPropertyValue(sal_Int32 nHandle, const Any& aValue) override;
+ virtual Any SAL_CALL getFastPropertyValue(sal_Int32 nHandle) override;
+
+ // Methods from XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties() override;
+ virtual Property SAL_CALL getPropertyByName(const OUString& Name) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName(const OUString& Name) override;
+
+ // Methods from XElementAccess
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // Methods from XNameAccess
+ virtual Any SAL_CALL getByName(const OUString& Name) override;
+ virtual Sequence< OUString > SAL_CALL getElementNames() override;
+ virtual sal_Bool SAL_CALL hasByName(const OUString& Name) override;
+
+ // Methods from XNameReplace
+ virtual void SAL_CALL replaceByName(const OUString& Name, const Any& Element) override;
+
+ // Methods from XNameContainer
+ virtual void SAL_CALL insertByName(const OUString& Name, const Any& Element) override;
+ virtual void SAL_CALL removeByName(const OUString& Name) override;
+
+ // Methods from XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual Any SAL_CALL getByIndex(sal_Int32 Index) override;
+
+ // Methods from XIndexReplace
+ virtual void SAL_CALL replaceByIndex(sal_Int32 Index, const Any& Element) override;
+
+ // Methods from XIndexContainer
+ virtual void SAL_CALL insertByIndex(sal_Int32 Index, const Any& Element) override;
+ virtual void SAL_CALL removeByIndex(sal_Int32 Index) override;
+
+ // Methods from XEnumerationAccess
+ virtual Reference<XEnumeration> SAL_CALL createEnumeration() override;
+
+ // Methods from XIdlArray
+ virtual void SAL_CALL realloc(Any& array, sal_Int32 length) override;
+ virtual sal_Int32 SAL_CALL getLen(const Any& array) override;
+ virtual Any SAL_CALL get(const Any& array, sal_Int32 index) override;
+ virtual void SAL_CALL set(Any& array, sal_Int32 index, const Any& value) override;
+
+ // Methods from XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const Sequence< sal_Int8 >& aIdentifier ) override;
+};
+
+ImplIntrospectionAccess::ImplIntrospectionAccess
+ ( Any obj, rtl::Reference< IntrospectionAccessStatic_Impl > pStaticImpl_ )
+ : maInspectedObject(std::move( obj )), mpStaticImpl(std::move( pStaticImpl_ )) ,
+ mnLastPropertyConcept(-1), mnLastMethodConcept(-1) //, maAdapter()
+{
+ // Save object as an interface if possible
+ maInspectedObject >>= mxIface;
+}
+
+Reference<XElementAccess> ImplIntrospectionAccess::getXElementAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjElementAccess.is() )
+ {
+ aGuard.unlock();
+ Reference<XElementAccess> xElementAccess( mxIface, UNO_QUERY );
+ aGuard.lock();
+ if( !mxObjElementAccess.is() )
+ mxObjElementAccess = xElementAccess;
+ }
+ return mxObjElementAccess;
+}
+
+void ImplIntrospectionAccess::cacheXNameContainer()
+{
+ Reference<XNameContainer> xNameContainer;
+ Reference<XNameReplace> xNameReplace;
+ Reference<XNameAccess> xNameAccess;
+ if (mpStaticImpl->mbNameContainer)
+ {
+ xNameContainer.set( mxIface, UNO_QUERY );
+ xNameReplace = xNameContainer;
+ xNameAccess = xNameContainer;
+ }
+ else if (mpStaticImpl->mbNameReplace)
+ {
+ xNameReplace.set( mxIface, UNO_QUERY );
+ xNameAccess = xNameReplace;
+ }
+ else if (mpStaticImpl->mbNameAccess)
+ {
+ xNameAccess.set( mxIface, UNO_QUERY );
+ }
+
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if( !mxObjNameContainer.is() )
+ mxObjNameContainer = xNameContainer;
+ if( !mxObjNameReplace.is() )
+ mxObjNameReplace = xNameReplace;
+ if( !mxObjNameAccess.is() )
+ mxObjNameAccess = xNameAccess;
+ }
+}
+
+Reference<XNameContainer> ImplIntrospectionAccess::getXNameContainer()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjNameContainer.is() )
+ {
+ aGuard.unlock();
+ cacheXNameContainer();
+ }
+ return mxObjNameContainer;
+}
+
+Reference<XNameReplace> ImplIntrospectionAccess::getXNameReplace()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjNameReplace.is() )
+ {
+ aGuard.unlock();
+ cacheXNameContainer();
+ }
+ return mxObjNameReplace;
+}
+
+Reference<XNameAccess> ImplIntrospectionAccess::getXNameAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjNameAccess.is() )
+ {
+ aGuard.unlock();
+ cacheXNameContainer();
+ }
+ return mxObjNameAccess;
+}
+
+void ImplIntrospectionAccess::cacheXIndexContainer()
+{
+ Reference<XIndexContainer> xIndexContainer;
+ Reference<XIndexReplace> xIndexReplace;
+ Reference<XIndexAccess> xIndexAccess;
+ if (mpStaticImpl->mbIndexContainer)
+ {
+ xIndexContainer.set( mxIface, UNO_QUERY );
+ xIndexReplace = xIndexContainer;
+ xIndexAccess = xIndexContainer;
+ }
+ else if (mpStaticImpl->mbIndexReplace)
+ {
+ xIndexReplace.set( mxIface, UNO_QUERY );
+ xIndexAccess = xIndexReplace;
+ }
+ else if (mpStaticImpl->mbIndexAccess)
+ {
+ xIndexAccess.set( mxIface, UNO_QUERY );
+ }
+
+ {
+ std::unique_lock aGuard( m_aMutex );
+ if( !mxObjIndexContainer.is() )
+ mxObjIndexContainer = xIndexContainer;
+ if( !mxObjIndexReplace.is() )
+ mxObjIndexReplace = xIndexReplace;
+ if( !mxObjIndexAccess.is() )
+ mxObjIndexAccess = xIndexAccess;
+ }
+}
+
+Reference<XIndexContainer> ImplIntrospectionAccess::getXIndexContainer()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIndexContainer.is() )
+ {
+ aGuard.unlock();
+ cacheXIndexContainer();
+ }
+ return mxObjIndexContainer;
+}
+
+Reference<XIndexReplace> ImplIntrospectionAccess::getXIndexReplace()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIndexReplace.is() )
+ {
+ aGuard.unlock();
+ cacheXIndexContainer();
+ }
+ return mxObjIndexReplace;
+}
+
+Reference<XIndexAccess> ImplIntrospectionAccess::getXIndexAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIndexAccess.is() )
+ {
+ aGuard.unlock();
+ cacheXIndexContainer();
+ }
+ return mxObjIndexAccess;
+}
+
+Reference<XEnumerationAccess> ImplIntrospectionAccess::getXEnumerationAccess()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjEnumerationAccess.is() )
+ {
+ aGuard.unlock();
+ Reference<XEnumerationAccess> xEnumerationAccess( mxIface, UNO_QUERY );
+ aGuard.lock();
+ if( !mxObjEnumerationAccess.is() )
+ mxObjEnumerationAccess = xEnumerationAccess;
+ }
+ return mxObjEnumerationAccess;
+}
+
+Reference<XIdlArray> ImplIntrospectionAccess::getXIdlArray()
+{
+ std::unique_lock aGuard( m_aMutex );
+
+ if( !mxObjIdlArray.is() )
+ {
+ aGuard.unlock();
+ Reference<XIdlArray> xIdlArray( mxIface, UNO_QUERY );
+ aGuard.lock();
+ if( !mxObjIdlArray.is() )
+ mxObjIdlArray = xIdlArray;
+ }
+ return mxObjIdlArray;
+}
+
+// Methods from XInterface
+Any SAL_CALL ImplIntrospectionAccess::queryInterface( const Type& rType )
+{
+ Any aRet( ::cppu::queryInterface(
+ rType,
+ static_cast< XIntrospectionAccess * >( this ),
+ static_cast< XMaterialHolder * >( this ),
+ static_cast< XExactName * >( this ),
+ static_cast< XPropertySet * >( this ),
+ static_cast< XFastPropertySet * >( this ),
+ static_cast< XPropertySetInfo * >( this ) ) );
+ if( !aRet.hasValue() )
+ aRet = OWeakObject::queryInterface( rType );
+
+ if( !aRet.hasValue() )
+ {
+ // Wrapper for the object interfaces
+ ( mpStaticImpl->mbElementAccess && (aRet = ::cppu::queryInterface
+ ( rType, static_cast< XElementAccess* >( static_cast< XNameAccess* >( this ) ) ) ).hasValue() )
+ || ( mpStaticImpl->mbNameAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XNameAccess* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbNameReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XNameReplace* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbNameContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XNameContainer* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIndexAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexAccess* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIndexReplace && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexReplace* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIndexContainer && (aRet = ::cppu::queryInterface( rType, static_cast< XIndexContainer* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbEnumerationAccess && (aRet = ::cppu::queryInterface( rType, static_cast< XEnumerationAccess* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbIdlArray && (aRet = ::cppu::queryInterface( rType, static_cast< XIdlArray* >( this ) ) ).hasValue() )
+ || ( mpStaticImpl->mbUnoTunnel && (aRet = ::cppu::queryInterface( rType, static_cast< XUnoTunnel* >( this ) ) ).hasValue() );
+ }
+ return aRet;
+}
+
+
+//*** Implementation of ImplIntrospectionAdapter ***
+
+
+// Methods from XPropertySet
+Reference<XPropertySetInfo> ImplIntrospectionAccess::getPropertySetInfo()
+{
+ return static_cast<XPropertySetInfo *>(this);
+}
+
+void ImplIntrospectionAccess::setPropertyValue(const OUString& aPropertyName, const Any& aValue)
+{
+ mpStaticImpl->setPropertyValue( maInspectedObject, aPropertyName, aValue );
+}
+
+Any ImplIntrospectionAccess::getPropertyValue(const OUString& aPropertyName)
+{
+ return mpStaticImpl->getPropertyValue( maInspectedObject, aPropertyName );
+}
+
+void ImplIntrospectionAccess::addPropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
+ if( xPropSet.is() )
+ xPropSet->addPropertyChangeListener(aPropertyName, aListener);
+ }
+}
+
+void ImplIntrospectionAccess::removePropertyChangeListener(const OUString& aPropertyName, const Reference<XPropertyChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
+ if( xPropSet.is() )
+ xPropSet->removePropertyChangeListener(aPropertyName, aListener);
+ }
+}
+
+void ImplIntrospectionAccess::addVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ //Reference<XPropertySet> xPropSet( mxIface, USR_QUERY );
+ if( xPropSet.is() )
+ xPropSet->addVetoableChangeListener(aPropertyName, aListener);
+ }
+}
+
+void ImplIntrospectionAccess::removeVetoableChangeListener(const OUString& aPropertyName, const Reference<XVetoableChangeListener>& aListener)
+{
+ if( mxIface.is() )
+ {
+ Reference<XPropertySet> xPropSet =
+ Reference<XPropertySet>::query( mxIface );
+ if( xPropSet.is() )
+ xPropSet->removeVetoableChangeListener(aPropertyName, aListener);
+ }
+}
+
+
+// Methods from XFastPropertySet
+void ImplIntrospectionAccess::setFastPropertyValue(sal_Int32, const Any&)
+{
+}
+
+Any ImplIntrospectionAccess::getFastPropertyValue(sal_Int32)
+{
+ return Any();
+}
+
+// Methods from XPropertySetInfo
+Sequence< Property > ImplIntrospectionAccess::getProperties()
+{
+ return comphelper::containerToSequence(mpStaticImpl->getProperties());
+}
+
+Property ImplIntrospectionAccess::getPropertyByName(const OUString& Name)
+{
+ return getProperty( Name, PropertyConcept::ALL );
+}
+
+sal_Bool ImplIntrospectionAccess::hasPropertyByName(const OUString& Name)
+{
+ return hasProperty( Name, PropertyConcept::ALL );
+}
+
+// Methods from XElementAccess
+Type ImplIntrospectionAccess::getElementType()
+{
+ return getXElementAccess()->getElementType();
+}
+
+sal_Bool ImplIntrospectionAccess::hasElements()
+{
+ return getXElementAccess()->hasElements();
+}
+
+// Methods from XNameAccess
+Any ImplIntrospectionAccess::getByName(const OUString& Name)
+{
+ return getXNameAccess()->getByName( Name );
+}
+
+Sequence< OUString > ImplIntrospectionAccess::getElementNames()
+{
+ return getXNameAccess()->getElementNames();
+}
+
+sal_Bool ImplIntrospectionAccess::hasByName(const OUString& Name)
+{
+ return getXNameAccess()->hasByName( Name );
+}
+
+// Methods from XNameContainer
+void ImplIntrospectionAccess::insertByName(const OUString& Name, const Any& Element)
+{
+ getXNameContainer()->insertByName( Name, Element );
+}
+
+void ImplIntrospectionAccess::replaceByName(const OUString& Name, const Any& Element)
+{
+ getXNameReplace()->replaceByName( Name, Element );
+}
+
+void ImplIntrospectionAccess::removeByName(const OUString& Name)
+{
+ getXNameContainer()->removeByName( Name );
+}
+
+// Methods from XIndexAccess
+// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const
+sal_Int32 ImplIntrospectionAccess::getCount()
+{
+ return getXIndexAccess()->getCount();
+}
+
+Any ImplIntrospectionAccess::getByIndex(sal_Int32 Index)
+{
+ return getXIndexAccess()->getByIndex( Index );
+}
+
+// Methods from XIndexContainer
+void ImplIntrospectionAccess::insertByIndex(sal_Int32 Index, const Any& Element)
+{
+ getXIndexContainer()->insertByIndex( Index, Element );
+}
+
+void ImplIntrospectionAccess::replaceByIndex(sal_Int32 Index, const Any& Element)
+{
+ getXIndexReplace()->replaceByIndex( Index, Element );
+}
+
+void ImplIntrospectionAccess::removeByIndex(sal_Int32 Index)
+{
+ getXIndexContainer()->removeByIndex( Index );
+}
+
+// Methods from XEnumerationAccess
+// Already in XNameAccess: virtual Reference<XIdlClass> getElementType() const;
+Reference<XEnumeration> ImplIntrospectionAccess::createEnumeration()
+{
+ return getXEnumerationAccess()->createEnumeration();
+}
+
+// Methods from XIdlArray
+void ImplIntrospectionAccess::realloc(Any& array, sal_Int32 length)
+{
+ getXIdlArray()->realloc( array, length );
+}
+
+sal_Int32 ImplIntrospectionAccess::getLen(const Any& array)
+{
+ return getXIdlArray()->getLen( array );
+}
+
+Any ImplIntrospectionAccess::get(const Any& array, sal_Int32 index)
+{
+ return getXIdlArray()->get( array, index );
+}
+
+void ImplIntrospectionAccess::set(Any& array, sal_Int32 index, const Any& value)
+{
+ getXIdlArray()->set( array, index, value );
+}
+
+// Methods from XUnoTunnel
+sal_Int64 ImplIntrospectionAccess::getSomething( const Sequence< sal_Int8 >& aIdentifier )
+{
+ if (Reference<XUnoTunnel> xUnoTunnel{ mxIface, css::uno::UNO_QUERY })
+ return xUnoTunnel->getSomething(aIdentifier);
+ return 0;
+}
+
+
+//*** Implementation of ImplIntrospectionAccess ***
+
+// Methods from XIntrospectionAccess
+sal_Int32 ImplIntrospectionAccess::getSuppliedMethodConcepts()
+{
+ return MethodConcept::DANGEROUS |
+ PROPERTY |
+ LISTENER |
+ ENUMERATION |
+ NAMECONTAINER |
+ INDEXCONTAINER;
+}
+
+sal_Int32 ImplIntrospectionAccess::getSuppliedPropertyConcepts()
+{
+ return PropertyConcept::DANGEROUS |
+ PROPERTYSET |
+ ATTRIBUTES |
+ METHODS;
+}
+
+Property ImplIntrospectionAccess::getProperty(const OUString& Name, sal_Int32 PropertyConcepts)
+{
+ Property aRet;
+ sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
+ bool bFound = false;
+ if( i != -1 )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
+ if( (PropertyConcepts & nConcept) != 0 )
+ {
+ aRet = mpStaticImpl->getProperties()[ i ];
+ bFound = true;
+ }
+ }
+ if( !bFound )
+ throw NoSuchElementException(Name);
+ return aRet;
+}
+
+sal_Bool ImplIntrospectionAccess::hasProperty(const OUString& Name, sal_Int32 PropertyConcepts)
+{
+ sal_Int32 i = mpStaticImpl->getPropertyIndex( Name );
+ bool bRet = false;
+ if( i != -1 )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getPropertyConcepts()[ i ];
+ if( (PropertyConcepts & nConcept) != 0 )
+ bRet = true;
+ }
+ return bRet;
+}
+
+Sequence< Property > ImplIntrospectionAccess::getProperties(sal_Int32 PropertyConcepts)
+{
+ // If all supported concepts are required, simply pass through the sequence
+ sal_Int32 nAllSupportedMask = PROPERTYSET |
+ ATTRIBUTES |
+ METHODS;
+ if( ( PropertyConcepts & nAllSupportedMask ) == nAllSupportedMask )
+ {
+ return comphelper::containerToSequence(mpStaticImpl->getProperties());
+ }
+
+ // Same sequence as last time?
+ if( mnLastPropertyConcept == PropertyConcepts )
+ {
+ return maLastPropertySeq;
+ }
+
+ // Number of properties to be delivered
+ sal_Int32 nCount = 0;
+
+ // There are currently no DANGEROUS properties
+ // if( PropertyConcepts & DANGEROUS )
+ // nCount += mpStaticImpl->mnDangerousPropCount;
+ if( PropertyConcepts & PROPERTYSET )
+ nCount += mpStaticImpl->mnPropertySetPropCount;
+ if( PropertyConcepts & ATTRIBUTES )
+ nCount += mpStaticImpl->mnAttributePropCount;
+ if( PropertyConcepts & METHODS )
+ nCount += mpStaticImpl->mnMethodPropCount;
+
+ // Realloc sequence according to the required number
+ maLastPropertySeq.realloc( nCount );
+ Property* pDestProps = maLastPropertySeq.getArray();
+
+ // Go through all the properties and apply according to the concept
+ const std::vector<Property>& rPropSeq = mpStaticImpl->getProperties();
+ const std::vector<sal_Int32>& rConcepts = mpStaticImpl->getPropertyConcepts();
+ sal_Int32 nLen = static_cast<sal_Int32>(rPropSeq.size());
+
+ sal_Int32 iDest = 0;
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ sal_Int32 nConcept = rConcepts[ i ];
+ if( nConcept & PropertyConcepts )
+ pDestProps[ iDest++ ] = rPropSeq[ i ];
+ }
+
+ // Remember PropertyConcept representing maLastPropertySeq
+ mnLastPropertyConcept = PropertyConcepts;
+
+ // Supply assembled Sequence
+ return maLastPropertySeq;
+}
+
+Reference<XIdlMethod> ImplIntrospectionAccess::getMethod(const OUString& Name, sal_Int32 MethodConcepts)
+{
+ Reference<XIdlMethod> xRet;
+ sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
+ if( i != -1 )
+ {
+
+ sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
+ if( (MethodConcepts & nConcept) != 0 )
+ {
+ xRet = mpStaticImpl->getMethods()[i];
+ }
+ }
+ if( !xRet.is() )
+ throw NoSuchMethodException(Name);
+ return xRet;
+}
+
+sal_Bool ImplIntrospectionAccess::hasMethod(const OUString& Name, sal_Int32 MethodConcepts)
+{
+ sal_Int32 i = mpStaticImpl->getMethodIndex( Name );
+ bool bRet = false;
+ if( i != -1 )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
+ if( (MethodConcepts & nConcept) != 0 )
+ bRet = true;
+ }
+ return bRet;
+}
+
+Sequence< Reference<XIdlMethod> > ImplIntrospectionAccess::getMethods(sal_Int32 MethodConcepts)
+{
+ // If all supported concepts are required, simply pass through the sequence
+ sal_Int32 nAllSupportedMask = MethodConcept::DANGEROUS |
+ PROPERTY |
+ LISTENER |
+ ENUMERATION |
+ NAMECONTAINER |
+ INDEXCONTAINER |
+ MethodConcept_NORMAL_IMPL;
+ if( ( MethodConcepts & nAllSupportedMask ) == nAllSupportedMask )
+ {
+ return comphelper::containerToSequence(mpStaticImpl->getMethods());
+ }
+
+ // Same sequence as last time?
+ if( mnLastMethodConcept == MethodConcepts )
+ {
+ return maLastMethodSeq;
+ }
+
+ // Get method sequences
+ const std::vector< Reference<XIdlMethod> >& aMethodSeq = mpStaticImpl->getMethods();
+ sal_Int32 nLen = static_cast<sal_Int32>(aMethodSeq.size());
+
+ // Realloc sequence according to the required number
+ // Unlike Properties, the number can not be determined by counters in
+ // inspect() beforehand, since methods can belong to several concepts
+ maLastMethodSeq.realloc( nLen );
+ Reference<XIdlMethod>* pDestMethods = maLastMethodSeq.getArray();
+
+ // Go through all the methods and apply according to the concept
+ sal_Int32 iDest = 0;
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ sal_Int32 nConcept = mpStaticImpl->getMethodConcepts()[ i ];
+ if( nConcept & MethodConcepts )
+ pDestMethods[ iDest++ ] = aMethodSeq[ i ];
+ }
+
+ // Bring to the correct length
+ maLastMethodSeq.realloc( iDest );
+
+ // Remember MethodConcept representing maLastMethodSeq
+ mnLastMethodConcept = MethodConcepts;
+
+ // Supply assembled Sequence
+ return maLastMethodSeq;
+}
+
+Sequence< Type > ImplIntrospectionAccess::getSupportedListeners()
+{
+ return comphelper::containerToSequence(mpStaticImpl->getSupportedListeners());
+}
+
+Reference<XInterface> SAL_CALL ImplIntrospectionAccess::queryAdapter( const Type& rType )
+{
+ Reference<XInterface> xRet;
+ if( rType == cppu::UnoType<XInterface>::get()
+ || rType == cppu::UnoType<XPropertySet>::get()
+ || rType == cppu::UnoType<XFastPropertySet>::get()
+ || rType == cppu::UnoType<XPropertySetInfo>::get()
+ || rType == cppu::UnoType<XElementAccess>::get()
+ || rType == cppu::UnoType<XNameAccess>::get()
+ || rType == cppu::UnoType<XNameReplace>::get()
+ || rType == cppu::UnoType<XNameContainer>::get()
+ || rType == cppu::UnoType<XIndexAccess>::get()
+ || rType == cppu::UnoType<XIndexReplace>::get()
+ || rType == cppu::UnoType<XIndexContainer>::get()
+ || rType == cppu::UnoType<XEnumerationAccess>::get()
+ || rType == cppu::UnoType<XIdlArray>::get()
+ || rType == cppu::UnoType<XUnoTunnel>::get() )
+ {
+ queryInterface( rType ) >>= xRet;
+ }
+ return xRet;
+}
+
+// Methods from XMaterialHolder
+Any ImplIntrospectionAccess::getMaterial()
+{
+ return maInspectedObject;
+}
+
+// Methods from XExactName
+OUString ImplIntrospectionAccess::getExactName( const OUString& rApproximateName )
+{
+ OUString aRetStr;
+ LowerToExactNameMap::iterator aIt =
+ mpStaticImpl->maLowerToExactNameMap.find( rApproximateName.toAsciiLowerCase() );
+ if (aIt != mpStaticImpl->maLowerToExactNameMap.end())
+ aRetStr = (*aIt).second;
+ return aRetStr;
+}
+
+struct TypeKey {
+ TypeKey(
+ css::uno::Reference<css::beans::XPropertySetInfo> theProperties,
+ std::vector<css::uno::Type> const & theTypes):
+ properties(std::move(theProperties))
+ {
+ //TODO: Could even sort the types lexicographically first, to increase
+ // the chance of matches between different implementations' getTypes(),
+ // but the old scheme of using getImplementationId() would have missed
+ // those matches, too:
+ OUStringBuffer b(static_cast<int>(theTypes.size() * 64));
+ for (const css::uno::Type& rType : theTypes) {
+ b.append(rType.getTypeName()
+ + "*"); // arbitrary delimiter not used by type grammar
+ }
+ types = b.makeStringAndClear();
+ }
+
+ css::uno::Reference<css::beans::XPropertySetInfo> properties;
+ OUString types;
+};
+
+struct TypeKeyLess {
+ bool operator ()(TypeKey const & key1, TypeKey const & key2) const {
+ if (key1.properties.get() < key2.properties.get()) {
+ return true;
+ }
+ if (key1.properties.get() > key2.properties.get()) {
+ return false;
+ }
+ return key1.types < key2.types;
+ }
+};
+
+template<typename Key, typename Less> class Cache {
+public:
+ rtl::Reference<IntrospectionAccessStatic_Impl> find(Key const & key) const {
+ typename Map::const_iterator i(map_.find(key));
+ if (i == map_.end()) {
+ return rtl::Reference<IntrospectionAccessStatic_Impl>();
+ } else {
+ if (i->second.hits < std::numeric_limits<unsigned>::max()) {
+ ++i->second.hits;
+ }
+ assert(i->second.access.is());
+ return i->second.access;
+ }
+ }
+
+ void insert(
+ Key const & key,
+ rtl::Reference<IntrospectionAccessStatic_Impl> const & access)
+ {
+ assert(access.is());
+ typename Map::size_type const MAX = 100;
+ assert(map_.size() <= MAX);
+ if (map_.size() == MAX) {
+ typename Map::iterator del = std::min_element(map_.begin(), map_.end(),
+ [](const typename Map::value_type& a, const typename Map::value_type& b) {
+ return a.second.hits < b.second.hits;
+ });
+ map_.erase(del);
+ }
+ bool ins = map_.emplace(key, Data(access)).second;
+ assert(ins); (void)ins;
+ }
+
+ void clear() { map_.clear(); }
+
+private:
+ struct Data {
+ explicit Data(
+ rtl::Reference<IntrospectionAccessStatic_Impl> theAccess):
+ access(std::move(theAccess)), hits(1)
+ {}
+
+ rtl::Reference<IntrospectionAccessStatic_Impl> access;
+ mutable unsigned hits;
+ };
+
+ typedef std::map<Key, Data, Less> Map;
+
+ Map map_;
+};
+
+typedef
+ cppu::WeakComponentImplHelper<
+ css::lang::XServiceInfo, css::beans::XIntrospection>
+ Implementation_Base;
+
+class Implementation: private cppu::BaseMutex, public Implementation_Base {
+public:
+ explicit Implementation(
+ css::uno::Reference<css::uno::XComponentContext> const & context):
+ Implementation_Base(m_aMutex),
+ reflection_(css::reflection::theCoreReflection::get(context))
+ {}
+
+private:
+ virtual void SAL_CALL disposing() override {
+ osl::MutexGuard g(m_aMutex);
+ reflection_.clear();
+ typeCache_.clear();
+ }
+
+ virtual OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.stoc.Introspection"; }
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ { return cppu::supportsService(this, ServiceName); }
+
+ virtual css::uno::Sequence<OUString> SAL_CALL
+ getSupportedServiceNames() override
+ {
+ Sequence<OUString> s { "com.sun.star.beans.Introspection" };
+ return s;
+ }
+
+ virtual css::uno::Reference<css::beans::XIntrospectionAccess> SAL_CALL
+ inspect(css::uno::Any const & aObject) override;
+
+ css::uno::Reference<css::reflection::XIdlReflection> reflection_;
+ Cache<TypeKey, TypeKeyLess> typeCache_;
+};
+
+css::uno::Reference<css::beans::XIntrospectionAccess> Implementation::inspect(
+ css::uno::Any const & aObject)
+{
+ css::uno::Reference<css::reflection::XIdlReflection> reflection;
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (rBHelper.bDisposed || rBHelper.bInDispose) {
+ throw css::lang::DisposedException(
+ getImplementationName(), getXWeak());
+ }
+ reflection = reflection_;
+ }
+ css::uno::Any aToInspectObj;
+ css::uno::Type t;
+ if (aObject >>= t) {
+ css::uno::Reference<css::reflection::XIdlClass> c(
+ reflection->forName(t.getTypeName()));
+ if (!c.is()) {
+ SAL_WARN("stoc", "cannot reflect type " << t.getTypeName());
+ return css::uno::Reference<css::beans::XIntrospectionAccess>();
+ }
+ aToInspectObj <<= c;
+ } else {
+ aToInspectObj = aObject;
+ }
+
+ // Examine object
+ TypeClass eType = aToInspectObj.getValueType().getTypeClass();
+ if( eType != TypeClass_INTERFACE && eType != TypeClass_STRUCT && eType != TypeClass_EXCEPTION )
+ return css::uno::Reference<css::beans::XIntrospectionAccess>();
+
+ if( auto x = o3tl::tryAccess<Reference<XInterface>>(aToInspectObj) )
+ {
+ if( !x->is() )
+ return css::uno::Reference<css::beans::XIntrospectionAccess>();
+ }
+
+ // Pointer to possibly needed new IntrospectionAccessStatic_Impl instance
+ rtl::Reference< IntrospectionAccessStatic_Impl > pAccess;
+
+ // Check: Is a matching access object already cached?
+ std::vector< Reference<XIdlClass> > SupportedClassSeq;
+ std::vector< Type > SupportedTypesSeq;
+ Reference<XTypeProvider> xTypeProvider;
+ Reference<XPropertySetInfo> xPropSetInfo;
+ Reference<XPropertySet> xPropSet;
+
+ // Look for interfaces XTypeProvider and PropertySet
+ if( eType == TypeClass_INTERFACE )
+ {
+ xTypeProvider.set( aToInspectObj, UNO_QUERY );
+ if( xTypeProvider.is() )
+ {
+ SupportedTypesSeq = comphelper::sequenceToContainer<std::vector<Type>>(xTypeProvider->getTypes());
+ } else {
+ SAL_WARN(
+ "stoc",
+ "object of type \"" << aToInspectObj.getValueTypeName()
+ << "\" lacks XTypeProvider");
+ SupportedTypesSeq = { aToInspectObj.getValueType() };
+ }
+ // Now try to get the PropertySetInfo
+ xPropSet.set( aToInspectObj, UNO_QUERY );
+ if( xPropSet.is() )
+ xPropSetInfo = xPropSet->getPropertySetInfo();
+
+ } else {
+ SupportedTypesSeq = { aToInspectObj.getValueType() };
+ }
+
+ {
+ osl::MutexGuard g(m_aMutex);
+ if (rBHelper.bDisposed || rBHelper.bInDispose) {
+ throw css::lang::DisposedException(
+ getImplementationName(), getXWeak());
+ }
+ TypeKey key(xPropSetInfo, SupportedTypesSeq);
+ pAccess = typeCache_.find(key);
+ if (pAccess.is()) {
+ return new ImplIntrospectionAccess(aToInspectObj, pAccess);
+ }
+ pAccess = new IntrospectionAccessStatic_Impl(reflection);
+ typeCache_.insert(key, pAccess);
+ }
+
+ // No access cached -> create new
+ std::vector<Property>& rAllPropArray = pAccess->maAllPropertySeq;
+ std::vector<Reference<XInterface>>& rInterfaces1 = pAccess->aInterfaceSeq1;
+ std::vector<Reference<XInterface>>& rInterfaces2 = pAccess->aInterfaceSeq2;
+ std::vector<sal_Int16>& rMapTypeArray = pAccess->maMapTypeSeq;
+ std::vector<sal_Int32>& rPropertyConceptArray = pAccess->maPropertyConceptSeq;
+
+ // References to important data from pAccess
+ sal_Int32& rPropCount = pAccess->mnPropCount;
+ IntrospectionNameMap& rPropNameMap = pAccess->maPropertyNameMap;
+ IntrospectionNameMap& rMethodNameMap = pAccess->maMethodNameMap;
+ LowerToExactNameMap& rLowerToExactNameMap = pAccess->maLowerToExactNameMap;
+
+
+ //*** Perform analysis ***
+
+ if( eType == TypeClass_INTERFACE )
+ {
+ size_t nTypeCount = SupportedTypesSeq.size();
+ if( nTypeCount )
+ {
+ SupportedClassSeq.resize( nTypeCount );
+
+ for( size_t i = 0 ; i < nTypeCount ; i++ )
+ SupportedClassSeq[i] = reflection->forName( SupportedTypesSeq[i].getTypeName() );
+ }
+
+ // First look for particular interfaces that are of particular
+ // importance to the introspection
+
+ // Is XPropertySet present?
+ if( xPropSet.is() && xPropSetInfo.is() )
+ {
+ // Is there also a FastPropertySet?
+ Reference<XFastPropertySet> xDummy( aToInspectObj, UNO_QUERY );
+ bool bFast = pAccess->mbFastPropSet = xDummy.is();
+
+ Sequence<Property> aPropSeq = xPropSetInfo->getProperties();
+ const Property* pProps = aPropSeq.getConstArray();
+ sal_Int32 nLen = aPropSeq.getLength();
+
+ // For a FastPropertySet we must remember the original handles
+ if( bFast )
+ pAccess->mpOrgPropertyHandleArray.reset( new sal_Int32[ nLen ] );
+
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ // Put property in its own list
+ pAccess->checkPropertyArraysSize( rPropCount );
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp = pProps[ i ];
+
+ if( bFast )
+ pAccess->mpOrgPropertyHandleArray[ i ] = rProp.Handle;
+
+ // Enter PropCount as a handle for its own FastPropertySet
+ rProp.Handle = rPropCount;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_PROPERTY_SET;
+ rPropertyConceptArray[ rPropCount ] = PROPERTYSET;
+ pAccess->mnPropertySetPropCount++;
+
+ // Enter name in hash table if not already known
+ OUString aPropName = rProp.Name;
+
+ // Do we already have the name?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if( aIt == rPropNameMap.end() )
+ {
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+ }
+ else
+ {
+ SAL_WARN( "stoc", "Introspection: Property \"" <<
+ aPropName << "\" found more than once in PropertySet" );
+ }
+
+ // Adjust count
+ rPropCount++;
+ }
+ }
+
+ // Indices in the export table
+ sal_Int32 iAllExportedMethod = 0;
+ sal_Int32 iAllSupportedListener = 0;
+
+ std::set<OUString> seen;
+
+ // Flag, whether XInterface methods should be recorded
+ // (this must be done only once, allowed initially)
+ bool bXInterfaceIsInvalid = false;
+
+ // Flag whether the XInterface methods have already been recorded. If
+ // sal_True, bXInterfaceIsInvalid is activated at the end of the interface
+ // loop, and XInterface methods are cut off thereafter.
+ bool bFoundXInterface = false;
+
+ size_t nClassCount = SupportedClassSeq.size();
+ for( size_t nIdx = 0 ; nIdx < nClassCount; nIdx++ )
+ {
+ Reference<XIdlClass> xImplClass2 = SupportedClassSeq[nIdx];
+ while( xImplClass2.is() )
+ {
+ // Fetch interfaces from the implementation
+ Sequence< Reference<XIdlClass> > aClassSeq = xImplClass2->getInterfaces();
+ sal_Int32 nIfaceCount = aClassSeq.getLength();
+
+ aClassSeq.realloc( nIfaceCount + 1 );
+ aClassSeq.getArray()[ nIfaceCount ] = xImplClass2;
+
+ for( const Reference<XIdlClass>& rxIfaceClass : std::as_const(aClassSeq) )
+ {
+ if (!seen.insert(rxIfaceClass->getName()).second) {
+ continue;
+ }
+
+ // 2. Register fields as properties
+
+ // Get fields
+ const Sequence< Reference<XIdlField> > fields = rxIfaceClass->getFields();
+
+ for( const Reference<XIdlField>& xField : fields )
+ {
+ Reference<XIdlClass> xPropType = xField->getType();
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Enter in own property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = xField->getName();
+ rProp.Handle = rPropCount;
+ Type aFieldType( xPropType->getTypeClass(), xPropType->getName() );
+ rProp.Type = aFieldType;
+ FieldAccessMode eAccessMode = xField->getAccessMode();
+ rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
+ eAccessMode == FieldAccessMode_CONST)
+ ? READONLY : 0;
+
+ // Enter name in hash table
+ OUString aPropName = rProp.Name;
+
+ // Do we have the name already?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if (aIt != rPropNameMap.end())
+ continue;
+
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember field
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
+ rInterfaces1, rPropCount );
+ rInterfaces1[ rPropCount ] = xField;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_FIELD;
+ rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
+ pAccess->mnAttributePropCount++;
+
+ // Adjust count
+ rPropCount++;
+ }
+
+
+ // 3. Methods
+
+ // Get and remember all methods
+ Sequence< Reference<XIdlMethod> > methods = rxIfaceClass->getMethods();
+ const Reference<XIdlMethod>* pSourceMethods = methods.getConstArray();
+ sal_Int32 nSourceMethodCount = methods.getLength();
+
+ // 3. a) Search get/set and listener methods
+
+ // Create field for information about the methods, so that methods which are not
+ // related to properties or listeners can easily be found later.
+ // New: initialise MethodConceptArray
+ enum MethodType
+ {
+ STANDARD_METHOD, // normal method, not related to properties or listeners
+ GETSET_METHOD, // belongs to a get/set property
+ ADD_LISTENER_METHOD, // add method of a listener interface
+ REMOVE_LISTENER_METHOD, // remove method of a listener interface
+ INVALID_METHOD // method whose class is not considered, e.g. XPropertySet
+ };
+ std::unique_ptr<MethodType[]> pMethodTypes( new MethodType[ nSourceMethodCount ] );
+ std::unique_ptr<sal_Int32[]> pLocalMethodConcepts( new sal_Int32[ nSourceMethodCount ] );
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ pMethodTypes[ i ] = STANDARD_METHOD;
+ pLocalMethodConcepts[ i ] = 0;
+ }
+
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
+ sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
+
+ // Fetch name
+ OUString aMethName = rxMethod_i->getName();
+
+ // Catalogue methods
+ // Filter all (?) methods of XInterface so e.g. acquire and release
+ // can not be called from scripting
+ OUString className(
+ rxMethod_i->getDeclaringClass()->getName());
+ if (className == "com.sun.star.uno.XInterface") {
+ bFoundXInterface = true;
+
+ if( bXInterfaceIsInvalid )
+ {
+ pMethodTypes[ i ] = INVALID_METHOD;
+ continue;
+ }
+ else
+ {
+ if( aMethName != "queryInterface" )
+ {
+ rMethodConcept_i |= MethodConcept::DANGEROUS;
+ continue;
+ }
+ }
+ } else if (className == "com.sun.star.uno.XAggregation")
+ {
+ if( aMethName == "setDelegator" )
+ {
+ rMethodConcept_i |= MethodConcept::DANGEROUS;
+ continue;
+ }
+ } else if (className
+ == "com.sun.star.container.XElementAccess")
+ {
+ rMethodConcept_i |= ( NAMECONTAINER |
+ INDEXCONTAINER |
+ ENUMERATION );
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XNameContainer")
+ {
+ rMethodConcept_i |= NAMECONTAINER;
+ pAccess->mbNameContainer = true;
+ pAccess->mbNameReplace = true;
+ pAccess->mbNameAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XNameReplace")
+ {
+ rMethodConcept_i |= NAMECONTAINER;
+ pAccess->mbNameReplace = true;
+ pAccess->mbNameAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XNameAccess")
+ {
+ rMethodConcept_i |= NAMECONTAINER;
+ pAccess->mbNameAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XIndexContainer")
+ {
+ rMethodConcept_i |= INDEXCONTAINER;
+ pAccess->mbIndexContainer = true;
+ pAccess->mbIndexReplace = true;
+ pAccess->mbIndexAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XIndexReplace")
+ {
+ rMethodConcept_i |= INDEXCONTAINER;
+ pAccess->mbIndexReplace = true;
+ pAccess->mbIndexAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XIndexAccess")
+ {
+ rMethodConcept_i |= INDEXCONTAINER;
+ pAccess->mbIndexAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.container.XEnumerationAccess")
+ {
+ rMethodConcept_i |= ENUMERATION;
+ pAccess->mbEnumerationAccess = true;
+ pAccess->mbElementAccess = true;
+ } else if (className
+ == "com.sun.star.reflection.XIdlArray")
+ {
+ pAccess->mbIdlArray = true;
+ } else if (className
+ == "com.sun.star.lang.XUnoTunnel")
+ {
+ pAccess->mbUnoTunnel = true;
+ }
+
+ // If the name is too short, it isn't anything
+ if( aMethName.getLength() <= 3 )
+ continue;
+
+ // Is it a get method?
+ OUString aPropName;
+ if( aMethName.startsWith("get", &aPropName) )
+ {
+ // Get methods must not have any parameters
+ Sequence< Reference<XIdlClass> > getParams = rxMethod_i->getParameterTypes();
+ if( getParams.hasElements() )
+ {
+ continue;
+ }
+
+ // Do we have the name already?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if (aIt != rPropNameMap.end())
+ {
+ /* TODO
+ SAL_INFO("stoc",(
+ String( "Introspection: Property \"" ) +
+ OOUStringToString( aPropName, CHARSET_SYSTEM ) +
+ String( "\" found more than once" ) );
+ */
+ continue;
+ }
+
+ // It is already at least a read-only property
+ rMethodConcept_i |= PROPERTY;
+
+ pMethodTypes[i] = GETSET_METHOD;
+ Reference<XIdlClass> xGetRetType = rxMethod_i->getReturnType();
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Write it in its property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = aPropName;
+ rProp.Handle = rPropCount;
+ rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
+ rProp.Attributes = READONLY;
+
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember get method
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
+ rInterfaces1, rPropCount );
+ rInterfaces1[ rPropCount ] = rxMethod_i;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_GETSET;
+ rPropertyConceptArray[ rPropCount ] = METHODS;
+ pAccess->mnMethodPropCount++;
+
+ // Search for matching set method
+ sal_Int32 k;
+ for( k = 0 ; k < nSourceMethodCount ; k++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
+
+ // Accept only methods that are not already assigned
+ if( k == i || pMethodTypes[k] != STANDARD_METHOD )
+ continue;
+
+ // Get name and evaluate
+ OUString aMethName2 = rxMethod_k->getName();
+ OUString aPropName2;
+ if (!(aMethName2.startsWith("set", &aPropName2)
+ && aPropName2 == aPropName))
+ continue;
+
+ // A set method must return void
+ Reference<XIdlClass> xSetRetType = rxMethod_k->getReturnType();
+ if( xSetRetType->getTypeClass() != TypeClass_VOID )
+ {
+ continue;
+ }
+
+ // A set method may only have one parameter
+ Sequence< Reference<XIdlClass> > setParams = rxMethod_k->getParameterTypes();
+ sal_Int32 nParamCount = setParams.getLength();
+ if( nParamCount != 1 )
+ {
+ continue;
+ }
+
+ // Next, the return type must correspond to the parameter type
+ const Reference<XIdlClass>* pParamArray2 = setParams.getConstArray();
+ Reference<XIdlClass> xParamType = pParamArray2[ 0 ];
+ if( xParamType->equals( xGetRetType ) )
+ {
+ pLocalMethodConcepts[ k ] = PROPERTY;
+
+ pMethodTypes[k] = GETSET_METHOD;
+
+ // Delete read-only flag again
+ rProp.Attributes &= ~READONLY;
+
+ // Remember set method
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq2,
+ rInterfaces2, rPropCount );
+ rInterfaces2[ rPropCount ] = rxMethod_k;
+ }
+ }
+
+ // Adjust count
+ rPropCount++;
+ }
+
+ // Is it an add listener method?
+ else if( aMethName.startsWith("add", &aPropName) )
+ {
+ // Does it end with "Listener"?
+ OUString aListenerName;
+ if( !aPropName.endsWith("Listener", &aListenerName) )
+ continue;
+
+ // TODO: More accurate tests could still be carried out here
+ // - Return type
+ // - Number and type of parameters
+
+
+ // Search for matching remove method, otherwise not applicable
+ sal_Int32 k;
+ for( k = 0 ; k < nSourceMethodCount ; k++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_k = pSourceMethods[k];
+
+ // Accept only methods that are not already assigned
+ if( k == i || pMethodTypes[k] != STANDARD_METHOD )
+ continue;
+
+ // Get name and evaluate
+ OUString aMethName2 = rxMethod_k->getName();
+ OUString aListenerName2;
+ if (!(aMethName2.startsWith(
+ "remove", &aPropName)
+ && aPropName.endsWith(
+ "Listener", &aListenerName2)
+ && aListenerName2 == aListenerName))
+ continue;
+
+ // TODO: More accurate tests could still be carried out here
+ // - Return type
+ // - Number and type of parameters
+
+
+ // Methods are recognised as a listener interface
+ rMethodConcept_i |= LISTENER;
+ pLocalMethodConcepts[ k ] |= LISTENER;
+
+ pMethodTypes[i] = ADD_LISTENER_METHOD;
+ pMethodTypes[k] = REMOVE_LISTENER_METHOD;
+ }
+ }
+ }
+
+
+ // A set method could still exist without a corresponding get method,
+ // this must be a write-only property
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod_i = pSourceMethods[i];
+
+ // Accept only methods that are not already assigned
+ if( pMethodTypes[i] != STANDARD_METHOD )
+ continue;
+
+ // Get name
+ OUString aMethName = rxMethod_i->getName();
+
+ // If the name is too short, it isn't anything
+ if( aMethName.getLength() <= 3 )
+ continue;
+
+ // Is it a set method without associated get method?
+ OUString aPropName;
+ if( aMethName.startsWith("set", &aPropName) )
+ {
+ // A set method must return void
+ Reference<XIdlClass> xSetRetType = rxMethod_i->getReturnType();
+ if( xSetRetType->getTypeClass() != TypeClass_VOID )
+ {
+ continue;
+ }
+
+ // A set method may only have one parameter
+ Sequence< Reference<XIdlClass> > setParams = rxMethod_i->getParameterTypes();
+ sal_Int32 nParamCount = setParams.getLength();
+ if( nParamCount != 1 )
+ {
+ continue;
+ }
+
+ // Do we have the name already?
+ IntrospectionNameMap::iterator aIt = rPropNameMap.find( aPropName );
+ if (aIt != rPropNameMap.end())
+ {
+ /* TODO:
+ SAL_INFO("stoc",(
+ String( "Introspection: Property \"" ) +
+ OOUStringToString( aPropName, CHARSET_SYSTEM ) +
+ String( "\" found more than once" ) );
+ */
+ continue;
+ }
+
+ // Now we know it's a write only property
+ pLocalMethodConcepts[ i ] = PROPERTY;
+
+ pMethodTypes[i] = GETSET_METHOD;
+ Reference<XIdlClass> xGetRetType = setParams.getConstArray()[0];
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Write it in its property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = aPropName;
+ rProp.Handle = rPropCount;
+ rProp.Type = Type( xGetRetType->getTypeClass(), xGetRetType->getName() );
+ rProp.Attributes = 0; // PROPERTY_WRITEONLY ???
+
+ // New entry in the hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember set method
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq2,
+ rInterfaces2, rPropCount );
+ rInterfaces2[ rPropCount ] = rxMethod_i;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_SETONLY;
+ rPropertyConceptArray[ rPropCount ] = METHODS;
+ pAccess->mnMethodPropCount++;
+
+ // Adjust count
+ rPropCount++;
+ }
+ }
+
+
+ // 4. Place methods in overall sequence
+
+ // How many methods in the method sequence
+ sal_Int32 nExportedMethodCount = 0;
+ sal_Int32 nSupportedListenerCount = 0;
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ if( pMethodTypes[ i ] != INVALID_METHOD )
+ {
+ nExportedMethodCount++;
+ }
+ if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
+ {
+ nSupportedListenerCount++;
+ }
+ }
+
+ // Enlarge sequences in the access object accordingly
+ pAccess->maAllMethodSeq.resize( nExportedMethodCount + iAllExportedMethod );
+ pAccess->maMethodConceptSeq.resize( nExportedMethodCount + iAllExportedMethod );
+ pAccess->maSupportedListenerSeq.resize( nSupportedListenerCount + iAllSupportedListener );
+
+ // Write in methods
+ for( sal_Int32 i = 0 ; i < nSourceMethodCount ; i++ )
+ {
+ if( pMethodTypes[ i ] != INVALID_METHOD )
+ {
+ // Address method
+ const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
+
+ // Enter name in hash table if not already known
+ OUString aMethName2 = rxMethod->getName();
+ IntrospectionNameMap::iterator aIt = rMethodNameMap.find( aMethName2 );
+ if( aIt == rMethodNameMap.end() )
+ {
+ // Enter
+ rMethodNameMap[ aMethName2 ] = iAllExportedMethod;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aMethName2.toAsciiLowerCase() ] = aMethName2;
+ }
+ else
+ {
+ sal_Int32 iHashResult = aIt->second;
+
+ Reference<XIdlMethod> xExistingMethod = pAccess->maAllMethodSeq[iHashResult];
+
+ Reference< XIdlClass > xExistingMethClass =
+ xExistingMethod->getDeclaringClass();
+ Reference< XIdlClass > xNewMethClass = rxMethod->getDeclaringClass();
+ if( xExistingMethClass->equals( xNewMethClass ) )
+ continue;
+ }
+
+ pAccess->maAllMethodSeq[iAllExportedMethod] = rxMethod;
+
+ // If a concept has been set, is the method "normal"?
+ sal_Int32& rMethodConcept_i = pLocalMethodConcepts[ i ];
+ if( !rMethodConcept_i )
+ rMethodConcept_i = MethodConcept_NORMAL_IMPL;
+ pAccess->maMethodConceptSeq[ iAllExportedMethod ] = rMethodConcept_i;
+ iAllExportedMethod++;
+ }
+ if( pMethodTypes[ i ] == ADD_LISTENER_METHOD )
+ {
+ // Determine class of listener
+ const Reference<XIdlMethod>& rxMethod = pSourceMethods[i];
+
+ // Enter void as default class
+ css::uno::Reference<css::reflection::XIdlClass>
+ xListenerClass(
+ reflection->forName(
+ cppu::UnoType<void>::get()
+ .getTypeName()));
+ // Old: Reference<XIdlClass> xListenerClass = Void_getReflection()->getIdlClass();
+
+ // Option 1: Search for parameters for a listener class
+ // Disadvantage: Superclasses should be searched recursively
+ const Sequence< Reference<XIdlClass> > aParams = rxMethod->getParameterTypes();
+
+ css::uno::Reference<css::reflection::XIdlClass>
+ xEventListenerClass(
+ reflection->forName(
+ cppu::UnoType<
+ css::lang::XEventListener>::get()
+ .getTypeName()));
+ // Old: Reference<XIdlClass> xEventListenerClass = XEventListener_getReflection()->getIdlClass();
+ auto pParam = std::find_if(aParams.begin(), aParams.end(),
+ [&xEventListenerClass](const Reference<XIdlClass>& rxClass) {
+ // Are we derived from a listener?
+ return rxClass->equals( xEventListenerClass )
+ || isDerivedFrom( rxClass, xEventListenerClass );
+ });
+ if (pParam != aParams.end())
+ {
+ xListenerClass = *pParam;
+ }
+
+ // Option 2: Unload the name of the method
+ // Disadvantage: Does not work with test listeners, where it does not exist
+ //aMethName = rxMethod->getName();
+ //aListenerName = aMethName.Copy( 3, aMethName.Len()-8-3 );
+ //Reference<XIdlClass> xListenerClass = reflection->forName( aListenerName );
+ Type aListenerType( TypeClass_INTERFACE, xListenerClass->getName() );
+ pAccess->maSupportedListenerSeq[ iAllSupportedListener ] = aListenerType;
+ iAllSupportedListener++;
+ }
+ }
+
+ // When there were XInterface methods in this run,
+ // ignore them in the future
+ if( bFoundXInterface )
+ bXInterfaceIsInvalid = true;
+ }
+
+ // Do superclasses exist? Then continue here
+ Sequence< Reference<XIdlClass> > aSuperClassSeq = xImplClass2->getSuperclasses();
+
+ // Currently only one superclass is considered
+ if( aSuperClassSeq.getLength() >= 1 )
+ {
+ xImplClass2 = aSuperClassSeq.getConstArray()[0];
+ OSL_ENSURE( xImplClass2.is(), "super class null" );
+ }
+ else
+ {
+ xImplClass2 = nullptr;
+ }
+ }
+ }
+
+ // Apply number of exported methods and adapt Sequences
+ // (can be different because duplicate methods are thrown
+ // out only after the determination of nExportedMethodCount)
+ sal_Int32& rMethCount = pAccess->mnMethCount;
+ rMethCount = iAllExportedMethod;
+ pAccess->maAllMethodSeq.resize( rMethCount );
+ pAccess->maMethodConceptSeq.resize( rMethCount );
+
+ // Resize the property sequences
+ pAccess->maAllPropertySeq.resize( rPropCount );
+ pAccess->maPropertyConceptSeq.resize( rPropCount );
+ pAccess->maMapTypeSeq.resize( rPropCount );
+ }
+ // Register struct fields as properties
+ else //if( eType == TypeClass_STRUCT )
+ {
+ // Is it an interface or a struct?
+ //Reference<XIdlClass> xClassRef = aToInspectObj.getReflection()->getIdlClass();
+ css::uno::Reference<css::reflection::XIdlClass> xClassRef(
+ reflection->forName(aToInspectObj.getValueTypeName()));
+ if( !xClassRef.is() )
+ {
+ SAL_WARN( "stoc", "Can't get XIdlClass from Reflection" );
+ return new ImplIntrospectionAccess(aToInspectObj, pAccess);
+ }
+
+ // Get fields
+ const Sequence< Reference<XIdlField> > fields = xClassRef->getFields();
+
+ for( const Reference<XIdlField>& xField : fields )
+ {
+ Reference<XIdlClass> xPropType = xField->getType();
+ OUString aPropName = xField->getName();
+
+ // Is the property sequence big enough?
+ pAccess->checkPropertyArraysSize( rPropCount );
+
+ // Write it in its property array
+ Property& rProp = rAllPropArray[ rPropCount ];
+ rProp.Name = aPropName;
+ rProp.Handle = rPropCount;
+ rProp.Type = Type( xPropType->getTypeClass(), xPropType->getName() );
+ FieldAccessMode eAccessMode = xField->getAccessMode();
+ rProp.Attributes = (eAccessMode == FieldAccessMode_READONLY ||
+ eAccessMode == FieldAccessMode_CONST)
+ ? READONLY : 0;
+
+ //FieldAccessMode eAccessMode = xField->getAccessMode();
+ //rProp.Attributes = (eAccessMode == FieldAccessMode::READONLY || eAccessMode == CONST)
+ //? PropertyAttribute::READONLY : 0;
+
+ // Write name in hash table
+ rPropNameMap[ aPropName ] = rPropCount;
+
+ // Maintain table for XExactName
+ rLowerToExactNameMap[ aPropName.toAsciiLowerCase() ] = aPropName;
+
+ // Remember field
+ IntrospectionAccessStatic_Impl::checkInterfaceArraySize( pAccess->aInterfaceSeq1,
+ rInterfaces1, rPropCount );
+ rInterfaces1[ rPropCount ] = xField;
+
+ // Remember type of property
+ rMapTypeArray[ rPropCount ] = MAP_FIELD;
+ rPropertyConceptArray[ rPropCount ] = ATTRIBUTES;
+ pAccess->mnAttributePropCount++;
+
+ // Adjust count
+ rPropCount++;
+ }
+ }
+
+ // Set property sequence to the correct length
+ pAccess->maAllPropertySeq.resize( pAccess->mnPropCount );
+
+ return new ImplIntrospectionAccess(aToInspectObj, pAccess);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_Introspection_get_implementation(
+ css::uno::XComponentContext * context,
+ css::uno::Sequence<css::uno::Any> const & arguments)
+{
+ SAL_WARN_IF(
+ arguments.hasElements(), "stoc", "unexpected singleton arguments");
+ return cppu::acquire(new Implementation(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/invocation/invocation.component b/stoc/source/invocation/invocation.component
new file mode 100644
index 0000000000..b5027a4d6d
--- /dev/null
+++ b/stoc/source/invocation/invocation.component
@@ -0,0 +1,26 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.Invocation"
+ constructor="stoc_InvocationService_get_implementation">
+ <service name="com.sun.star.script.Invocation"/>
+ </implementation>
+</component>
diff --git a/stoc/source/invocation/invocation.cxx b/stoc/source/invocation/invocation.cxx
new file mode 100644
index 0000000000..7da24b3ae0
--- /dev/null
+++ b/stoc/source/invocation/invocation.cxx
@@ -0,0 +1,1091 @@
+/* -*- 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 <comphelper/sequence.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/script/XInvocation2.hpp>
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/reflection/theCoreReflection.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/beans/XExactName.hpp>
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+#include <com/sun/star/beans/theIntrospection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/beans/PropertyConcept.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XTypeProvider.hpp>
+
+#include <memory>
+#include <vector>
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::script;
+using namespace css::reflection;
+using namespace css::beans;
+using namespace css::container;
+using namespace cppu;
+using namespace osl;
+
+namespace stoc_inv
+{
+
+
+// TODO: Implement centrally
+static Reference<XIdlClass> TypeToIdlClass( const Type& rType, const Reference< XIdlReflection > & xRefl )
+{
+ return xRefl->forName( rType.getTypeName() );
+}
+
+namespace {
+
+class Invocation_Impl
+ : public OWeakObject
+ , public XInvocation2
+ , public XNameContainer
+ , public XIndexContainer
+ , public XEnumerationAccess
+ , public XExactName
+ , public XMaterialHolder
+ , public XTypeProvider
+{
+public:
+ Invocation_Impl( const Any & rAdapted, const Reference<XTypeConverter> &,
+ const Reference<XIntrospection> &,
+ const Reference<XIdlReflection> &,
+ bool bFromOLE );
+
+ // XInterface
+ virtual Any SAL_CALL queryInterface( const Type & aType) override;
+ virtual void SAL_CALL acquire() noexcept override { OWeakObject::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OWeakObject::release(); }
+
+
+ // XTypeProvider
+ virtual Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XMaterialHolder
+ virtual Any SAL_CALL getMaterial() override;
+
+ // XInvocation
+ virtual Reference<XIntrospectionAccess> SAL_CALL getIntrospection() override;
+ virtual Any SAL_CALL invoke(const OUString& FunctionName, const Sequence< Any >& Params, Sequence< sal_Int16 >& OutParamIndex, Sequence< Any >& OutParam) override;
+ virtual void SAL_CALL setValue(const OUString& PropertyName, const Any& Value) override;
+ virtual Any SAL_CALL getValue(const OUString& PropertyName) override;
+ virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
+ virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
+
+ // XInvocation2
+ virtual Sequence< OUString > SAL_CALL getMemberNames( ) override;
+ virtual Sequence< InvocationInfo > SAL_CALL getInfo( ) override;
+ virtual InvocationInfo SAL_CALL getInfoForName( const OUString& aName, sal_Bool bExact ) override;
+
+ // All Access and Container methods are not thread safe
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override
+ { return _xElementAccess->getElementType(); }
+
+ virtual sal_Bool SAL_CALL hasElements() override
+ { return _xElementAccess->hasElements(); }
+
+ // XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& Name, const Any& Element ) override
+ { _xNameContainer->insertByName( Name, Element ); }
+
+ virtual void SAL_CALL removeByName( const OUString& Name ) override
+ { _xNameContainer->removeByName( Name ); }
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& Name, const Any& Element ) override
+ { _xNameReplace->replaceByName( Name, Element ); }
+
+ // XNameAccess
+ virtual Any SAL_CALL getByName( const OUString& Name ) override
+ { return _xNameAccess->getByName( Name ); }
+
+ virtual Sequence<OUString> SAL_CALL getElementNames() override
+ { return _xNameAccess->getElementNames(); }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& Name ) override
+ { return _xNameAccess->hasByName( Name ); }
+
+ // XIndexContainer
+ virtual void SAL_CALL insertByIndex( sal_Int32 Index, const Any& Element ) override
+ { _xIndexContainer->insertByIndex( Index, Element ); }
+
+ virtual void SAL_CALL removeByIndex( sal_Int32 Index ) override
+ { _xIndexContainer->removeByIndex( Index ); }
+
+ // XIndexReplace
+ virtual void SAL_CALL replaceByIndex( sal_Int32 Index, const Any& Element ) override
+ { _xIndexReplace->replaceByIndex( Index, Element ); }
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override
+ { return _xIndexAccess->getCount(); }
+
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index ) override
+ { return _xIndexAccess->getByIndex( Index ); }
+
+ // XEnumerationAccess
+ virtual Reference<XEnumeration> SAL_CALL createEnumeration() override
+ { return _xEnumerationAccess->createEnumeration(); }
+
+ // XExactName
+ virtual OUString SAL_CALL getExactName( const OUString& rApproximateName ) override;
+
+
+private:
+ void setMaterial( const Any& rMaterial );
+
+ void getInfoSequenceImpl( Sequence< OUString >* pStringSeq, Sequence< InvocationInfo >* pInfoSeq );
+ void fillInfoForNameAccess( InvocationInfo& rInfo, const OUString& aName );
+ static void fillInfoForProperty( InvocationInfo& rInfo, const Property& rProp );
+ static void fillInfoForMethod( InvocationInfo& rInfo, const Reference< XIdlMethod >& xMethod );
+
+ Reference<XTypeConverter> xTypeConverter;
+ Reference<XIntrospection> xIntrospection;
+ Reference<XIdlReflection> xCoreReflection;
+
+ Any _aMaterial;
+ // _xDirect and (_xIntrospectionAccess, xPropertySet) are exclusive
+ Reference<XInvocation> _xDirect;
+ Reference<XInvocation2> _xDirect2;
+ Reference<XPropertySet> _xPropertySet;
+ Reference<XIntrospectionAccess> _xIntrospectionAccess;
+
+ // supplied Interfaces
+ Reference<XNameContainer> _xNameContainer;
+ Reference<XNameReplace> _xNameReplace;
+ Reference<XNameAccess> _xNameAccess;
+ Reference<XIndexContainer> _xIndexContainer;
+ Reference<XIndexReplace> _xIndexReplace;
+ Reference<XIndexAccess> _xIndexAccess;
+ Reference<XEnumerationAccess> _xEnumerationAccess;
+ Reference<XElementAccess> _xElementAccess;
+
+
+ Reference<XExactName> _xENDirect, _xENIntrospection;
+
+ bool mbFromOLE;
+};
+
+}
+
+Invocation_Impl::Invocation_Impl
+(
+ const Any & rAdapted,
+ const Reference<XTypeConverter> & rTC,
+ const Reference<XIntrospection> & rI,
+ const Reference<XIdlReflection> & rCR,
+ bool bFromOLE
+)
+ : xTypeConverter( rTC )
+ , xIntrospection( rI )
+ , xCoreReflection( rCR )
+ , mbFromOLE( bFromOLE )
+{
+ setMaterial( rAdapted );
+}
+
+//### INTERFACE IMPLEMENTATIONS ####################################################################
+
+
+Any SAL_CALL Invocation_Impl::queryInterface( const Type & aType )
+{
+ // PropertySet implementation
+ Any a = ::cppu::queryInterface( aType,
+ static_cast< XInvocation* >(this),
+ static_cast< XMaterialHolder* >(this),
+ static_cast< XTypeProvider * >(this) );
+ if( a.hasValue() )
+ {
+ return a;
+ }
+
+ if( aType == cppu::UnoType<XExactName>::get())
+ {
+ // Invocation does not support XExactName, if direct object supports
+ // XInvocation, but not XExactName. Except when called from OLE Automation.
+ if (mbFromOLE ||
+ (_xDirect.is() && _xENDirect.is()) ||
+ (!_xDirect.is() && _xENIntrospection.is()))
+ {
+ return Any( Reference< XExactName >( static_cast< XExactName* >(this) ) );
+ }
+ }
+ else if ( aType == cppu::UnoType<XNameContainer>::get())
+ {
+ if( _xNameContainer.is() )
+ return Any( Reference< XNameContainer >( static_cast< XNameContainer* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XNameReplace>::get())
+ {
+ if( _xNameReplace.is() )
+ return Any( Reference< XNameReplace >( static_cast< XNameReplace* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XNameAccess>::get())
+ {
+ if( _xNameAccess.is() )
+ return Any( Reference< XNameAccess >( static_cast< XNameAccess* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XIndexContainer>::get())
+ {
+ if (_xIndexContainer.is())
+ return Any( Reference< XIndexContainer >( static_cast< XIndexContainer* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XIndexReplace>::get())
+ {
+ if (_xIndexReplace.is())
+ return Any( Reference< XIndexReplace >( static_cast< XIndexReplace* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XIndexAccess>::get())
+ {
+ if (_xIndexAccess.is())
+ return Any( Reference< XIndexAccess >( static_cast< XIndexAccess* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XEnumerationAccess>::get())
+ {
+ if (_xEnumerationAccess.is())
+ return Any( Reference< XEnumerationAccess >( static_cast< XEnumerationAccess* >(this) ) );
+ }
+ else if ( aType == cppu::UnoType<XElementAccess>::get())
+ {
+ if (_xElementAccess.is())
+ {
+ return Any( Reference< XElementAccess >(
+ static_cast< XElementAccess* >(static_cast< XNameContainer* >(this)) ) );
+ }
+ }
+ else if ( aType == cppu::UnoType<XInvocation2>::get())
+ {
+ // Invocation does not support XInvocation2, if direct object supports
+ // XInvocation, but not XInvocation2.
+ if ( mbFromOLE ||
+ ( _xDirect.is() && _xDirect2.is()) ||
+ (!_xDirect.is() && _xIntrospectionAccess.is() ) )
+ {
+ return Any( Reference< XInvocation2 >( static_cast< XInvocation2* >(this) ) );
+ }
+ }
+
+ return OWeakObject::queryInterface( aType );
+}
+
+
+Any Invocation_Impl::getMaterial()
+{
+ // AB, 12.2.1999 Make sure that the material is taken when possible
+ // from the direct Invocation of the Introspection, otherwise structs
+ // are not handled correctly
+ Reference<XMaterialHolder> xMaterialHolder;
+ if( _xDirect.is() )
+ {
+ xMaterialHolder.set( _xDirect, UNO_QUERY );
+ //_xDirect->queryInterface( XMaterialHolder::getSmartUik(), xMaterialHolder );
+ }
+ else if( _xIntrospectionAccess.is() )
+ {
+ xMaterialHolder.set( _xIntrospectionAccess, UNO_QUERY );
+ //_xIntrospectionAccess->queryInterface( XMaterialHolder::getSmartUik(), xMaterialHolder );
+ }
+ if( xMaterialHolder.is() )
+ {
+ return xMaterialHolder->getMaterial();
+ }
+ return _aMaterial;
+}
+
+
+void Invocation_Impl::setMaterial( const Any& rMaterial )
+{
+ // set the material first and only once
+ _aMaterial = rMaterial;
+
+ // First do this outside the guard
+ _xDirect.set( rMaterial, UNO_QUERY );
+
+ if( !mbFromOLE && _xDirect.is() )
+ {
+ // Consult object directly
+ _xElementAccess.set( _xDirect, UNO_QUERY );
+ _xEnumerationAccess.set( _xDirect, UNO_QUERY );
+ _xIndexAccess.set( _xDirect, UNO_QUERY );
+ _xIndexReplace.set( _xDirect, UNO_QUERY );
+ _xIndexContainer.set( _xDirect, UNO_QUERY );
+ _xNameAccess.set( _xDirect, UNO_QUERY );
+ _xNameReplace.set( _xDirect, UNO_QUERY );
+ _xNameContainer.set( _xDirect, UNO_QUERY );
+ _xENDirect.set( _xDirect, UNO_QUERY );
+ _xDirect2.set( _xDirect, UNO_QUERY );
+ }
+ else
+ {
+ // Make Invocation on the Introspection
+ if (xIntrospection.is())
+ {
+ _xIntrospectionAccess = xIntrospection->inspect( _aMaterial );
+ if( _xIntrospectionAccess.is() )
+ {
+ _xElementAccess.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XElementAccess>::get()), UNO_QUERY );
+
+ if( _xElementAccess.is() )
+ {
+ _xEnumerationAccess.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XEnumerationAccess>::get()), UNO_QUERY );
+
+ _xIndexAccess.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XIndexAccess>::get()), UNO_QUERY );
+
+ if( _xIndexAccess.is() )
+ {
+ _xIndexReplace.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XIndexReplace>::get()), UNO_QUERY );
+
+ _xIndexContainer.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XIndexContainer>::get()), UNO_QUERY );
+ }
+
+ _xNameAccess.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XNameAccess>::get()), UNO_QUERY );
+
+ if( _xNameAccess.is() )
+ {
+ _xNameReplace.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XNameReplace>::get()), UNO_QUERY );
+
+ _xNameContainer.set(
+ _xIntrospectionAccess->queryAdapter(
+ cppu::UnoType<XNameContainer>::get()), UNO_QUERY );
+ }
+ }
+
+ _xPropertySet.set( _xIntrospectionAccess->queryAdapter( cppu::UnoType<XPropertySet>::get()),
+ UNO_QUERY );
+
+ _xENIntrospection.set( _xIntrospectionAccess, UNO_QUERY );
+ }
+ }
+ }
+}
+
+
+OUString Invocation_Impl::getExactName( const OUString& rApproximateName )
+{
+ if (_xENDirect.is())
+ return _xENDirect->getExactName( rApproximateName );
+
+ OUString aRet;
+ if (_xENIntrospection.is())
+ aRet = _xENIntrospection->getExactName( rApproximateName );
+ return aRet;
+}
+
+
+Reference<XIntrospectionAccess> Invocation_Impl::getIntrospection()
+{
+ if( _xDirect.is() )
+ return _xDirect->getIntrospection();
+ else
+ return _xIntrospectionAccess;
+}
+
+
+sal_Bool Invocation_Impl::hasMethod( const OUString& Name )
+{
+ if (!mbFromOLE && _xDirect.is())
+ return _xDirect->hasMethod( Name );
+ if( _xIntrospectionAccess.is() )
+ return _xIntrospectionAccess->hasMethod( Name, MethodConcept::ALL ^ MethodConcept::DANGEROUS );
+ return false;
+}
+
+
+sal_Bool Invocation_Impl::hasProperty( const OUString& Name )
+{
+ if (_xDirect.is())
+ {
+ bool bRet = _xDirect->hasProperty( Name );
+ if (bRet || !mbFromOLE)
+ return bRet;
+ }
+ // PropertySet
+ if( _xIntrospectionAccess.is()
+ && _xIntrospectionAccess->hasProperty( Name, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) )
+ return true;
+ // NameAccess
+ if( _xNameAccess.is() )
+ return _xNameAccess->hasByName( Name );
+ return false;
+}
+
+
+Any Invocation_Impl::getValue( const OUString& PropertyName )
+{
+ try
+ {
+ if (_xDirect.is())
+ return _xDirect->getValue( PropertyName );
+ }
+ catch (Exception &)
+ {
+ if (!mbFromOLE)
+ throw;
+ }
+ try
+ {
+ // PropertySet
+ if( _xIntrospectionAccess.is() && _xPropertySet.is()
+ && _xIntrospectionAccess->hasProperty
+ ( PropertyName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) )
+ {
+ return _xPropertySet->getPropertyValue( PropertyName );
+ }
+ // NameAccess
+ if( _xNameAccess.is() && _xNameAccess->hasByName( PropertyName ) )
+ return _xNameAccess->getByName( PropertyName );
+ }
+ catch (UnknownPropertyException &)
+ {
+ throw;
+ }
+ catch (RuntimeException &)
+ {
+ throw;
+ }
+ catch (Exception &)
+ {
+ }
+
+ throw UnknownPropertyException( "cannot get value " + PropertyName );
+}
+
+
+void Invocation_Impl::setValue( const OUString& PropertyName, const Any& Value )
+{
+ try
+ {
+ if (_xDirect.is())
+ {
+ _xDirect->setValue( PropertyName, Value );
+ return;
+ }
+ }
+ catch (Exception &)
+ {
+ if (!mbFromOLE)
+ throw;
+ }
+ try
+ {
+ // Properties
+ if( _xIntrospectionAccess.is() && _xPropertySet.is()
+ && _xIntrospectionAccess->hasProperty(
+ PropertyName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) )
+ {
+ Property aProp = _xIntrospectionAccess->getProperty(
+ PropertyName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS );
+ Reference < XIdlClass > r = TypeToIdlClass( aProp.Type, xCoreReflection );
+ if( r->isAssignableFrom( TypeToIdlClass( Value.getValueType(), xCoreReflection ) ) )
+ _xPropertySet->setPropertyValue( PropertyName, Value );
+ else if( xTypeConverter.is() )
+ _xPropertySet->setPropertyValue(
+ PropertyName, xTypeConverter->convertTo( Value, aProp.Type ) );
+ else
+ throw RuntimeException( "no type converter service!" );
+ }
+ // NameContainer
+ else if( _xNameContainer.is() )
+ {
+ // Note: This misfeature deliberately not adapted to apply to objects which
+ // have XNameReplace but not XNameContainer
+ Any aConv;
+ Reference < XIdlClass > r =
+ TypeToIdlClass( _xNameContainer->getElementType(), xCoreReflection );
+ if( r->isAssignableFrom(TypeToIdlClass( Value.getValueType(), xCoreReflection ) ) )
+ aConv = Value;
+ else if( xTypeConverter.is() )
+ aConv = xTypeConverter->convertTo( Value, _xNameContainer->getElementType() );
+ else
+ throw RuntimeException( "no type converter service!" );
+
+ // Replace if present, otherwise insert
+ if (_xNameContainer->hasByName( PropertyName ))
+ _xNameContainer->replaceByName( PropertyName, aConv );
+ else
+ _xNameContainer->insertByName( PropertyName, aConv );
+ }
+ else
+ throw UnknownPropertyException( "no introspection nor name container!" );
+ }
+ catch (UnknownPropertyException &)
+ {
+ throw;
+ }
+ catch (CannotConvertException &)
+ {
+ throw;
+ }
+ catch (InvocationTargetException &)
+ {
+ throw;
+ }
+ catch (RuntimeException &)
+ {
+ throw;
+ }
+ catch (const Exception & exc)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw InvocationTargetException(
+ "exception occurred in setValue(): " + exc.Message,
+ Reference< XInterface >(), anyEx );
+ }
+}
+
+
+Any Invocation_Impl::invoke( const OUString& FunctionName, const Sequence<Any>& InParams,
+ Sequence<sal_Int16>& OutIndices, Sequence<Any>& OutParams )
+{
+ if (!mbFromOLE && _xDirect.is())
+ return _xDirect->invoke( FunctionName, InParams, OutIndices, OutParams );
+
+ if (_xIntrospectionAccess.is())
+ {
+ // throw NoSuchMethodException if not exist
+ Reference<XIdlMethod> xMethod = _xIntrospectionAccess->getMethod(
+ FunctionName, MethodConcept::ALL ^ MethodConcept::DANGEROUS );
+
+ // ParameterInfos
+ Sequence<ParamInfo> aFParams = xMethod->getParameterInfos();
+ const ParamInfo* pFParams = aFParams.getConstArray();
+ sal_Int32 nFParamsLen = aFParams.getLength();
+ if (nFParamsLen != InParams.getLength())
+ {
+ throw IllegalArgumentException(
+ "incorrect number of parameters passed invoking function " + FunctionName +
+ ": expected " + OUString::number(nFParamsLen) + ", got " + OUString::number(InParams.getLength()),
+ getXWeak(), sal_Int16(1) );
+ }
+
+ // IN Parameter
+ const Any* pInParams = InParams.getConstArray();
+
+ // Introspection Invoke Parameter
+ Sequence<Any> aInvokeParams( nFParamsLen );
+ Any* pInvokeParams = aInvokeParams.getArray();
+
+ // OUT Indices
+ OutIndices.realloc( nFParamsLen );
+ sal_Int16* pOutIndices = OutIndices.getArray();
+ sal_uInt32 nOutIndex = 0;
+
+ for ( sal_Int32 nPos = 0; nPos < nFParamsLen; ++nPos )
+ {
+ try
+ {
+ const ParamInfo& rFParam = pFParams[nPos];
+ const Reference<XIdlClass>& rDestType = rFParam.aType;
+
+ // is IN/INOUT parameter?
+ if (rFParam.aMode != ParamMode_OUT)
+ {
+ if (rDestType->isAssignableFrom( TypeToIdlClass( pInParams[nPos].getValueType(), xCoreReflection ) ))
+ {
+ pInvokeParams[nPos] = pInParams[nPos];
+ }
+ else if (xTypeConverter.is())
+ {
+ Type aDestType( rDestType->getTypeClass(), rDestType->getName() );
+ pInvokeParams[nPos] = xTypeConverter->convertTo( pInParams[nPos], aDestType );
+ }
+ else
+ {
+ throw CannotConvertException("invocation type mismatch!", *this, {}, 0, 0);
+ }
+ }
+
+ // is OUT/INOUT parameter?
+ if (rFParam.aMode != ParamMode_IN)
+ {
+ pOutIndices[nOutIndex] = static_cast<sal_Int16>(nPos);
+ if (rFParam.aMode == ParamMode_OUT)
+ rDestType->createObject( pInvokeParams[nPos] ); // default init
+ ++nOutIndex;
+ }
+ }
+ catch( CannotConvertException& rExc )
+ {
+ rExc.ArgumentIndex = nPos; // Add optional parameter index
+ throw;
+ }
+ }
+
+ // execute Method
+ Any aRet = xMethod->invoke( _aMaterial, aInvokeParams );
+
+ // OUT Params
+ OutIndices.realloc( nOutIndex );
+ OutParams.realloc( nOutIndex );
+
+ std::transform(std::cbegin(OutIndices), std::cend(OutIndices), OutParams.getArray(),
+ [&pInvokeParams](const sal_Int16 nIndex) -> Any { return pInvokeParams[nIndex]; });
+
+ return aRet;
+ }
+
+ throw RuntimeException("invocation lacking of introspection access!", *this);
+}
+
+namespace {
+
+// Struct to optimize sorting
+struct MemberItem
+{
+ OUString aName;
+
+ // Defines where the member comes from
+ enum class Mode { NameAccess, PropertySet, Method };
+ Mode eMode;
+
+ // Index to respective sequence
+ // (Index to NameAccess sequence for eMode==Mode::NameAccess etc.)
+ sal_Int32 nIndex;
+};
+
+}
+
+// Implementation of getting name or info
+// String sequence will be filled when pStringSeq != NULL
+// Info sequence will be filled when pInfoSeq != NULL
+void Invocation_Impl::getInfoSequenceImpl
+(
+ Sequence< OUString >* pStringSeq,
+ Sequence< InvocationInfo >* pInfoSeq
+)
+{
+ //Sequence< OUString > aStrSeq;
+ //if( !pStringSeq )
+ //pStringSeq = &aStrSeq;
+
+
+ // Get all needed sequences
+ Sequence<OUString> aNameAccessNames;
+ Sequence<Property> aPropertySeq;
+ Sequence< Reference< XIdlMethod > > aMethodSeq;
+
+ if( _xNameAccess.is() )
+ {
+ aNameAccessNames = _xNameAccess->getElementNames();
+ }
+
+ if( _xIntrospectionAccess.is() )
+ {
+ aPropertySeq = _xIntrospectionAccess->getProperties
+ ( PropertyConcept::ALL - PropertyConcept::DANGEROUS );
+
+ aMethodSeq = _xIntrospectionAccess->getMethods
+ ( MethodConcept::ALL - MethodConcept::DANGEROUS );
+ }
+
+ sal_Int32 nNameAccessCount = aNameAccessNames.getLength();
+ sal_Int32 nPropertyCount = aPropertySeq.getLength();
+ sal_Int32 nMethodCount = aMethodSeq.getLength();
+ sal_Int32 nTotalCount = nNameAccessCount + nPropertyCount + nMethodCount;
+
+ // Create and fill array of MemberItems
+ std::unique_ptr< MemberItem []> pItems( new MemberItem[ nTotalCount ] );
+ const OUString* pStrings = aNameAccessNames.getConstArray();
+ const Property* pProps = aPropertySeq.getConstArray();
+ const Reference< XIdlMethod >* pMethods = aMethodSeq.getConstArray();
+
+ // Fill array of MemberItems
+ sal_Int32 i, iTotal = 0;
+
+ // Name Access
+ for( i = 0 ; i < nNameAccessCount ; i++, iTotal++ )
+ {
+ MemberItem& rItem = pItems[ iTotal ];
+ rItem.aName = pStrings[ i ];
+ rItem.eMode = MemberItem::Mode::NameAccess;
+ rItem.nIndex = i;
+ }
+
+ // Property set
+ for( i = 0 ; i < nPropertyCount ; i++, iTotal++ )
+ {
+ MemberItem& rItem = pItems[ iTotal ];
+ rItem.aName = pProps[ i ].Name;
+ rItem.eMode = MemberItem::Mode::PropertySet;
+ rItem.nIndex = i;
+ }
+
+ // Methods
+ for( i = 0 ; i < nMethodCount ; i++, iTotal++ )
+ {
+ MemberItem& rItem = pItems[ iTotal ];
+ Reference< XIdlMethod > xMethod = pMethods[ i ];
+ rItem.aName = xMethod->getName();
+ rItem.eMode = MemberItem::Mode::Method;
+ rItem.nIndex = i;
+ }
+
+ // Setting up result sequences
+ OUString* pRetStrings = nullptr;
+ if( pStringSeq )
+ {
+ pStringSeq->realloc( nTotalCount );
+ pRetStrings = pStringSeq->getArray();
+ }
+
+ InvocationInfo* pRetInfos = nullptr;
+ if( pInfoSeq )
+ {
+ pInfoSeq->realloc( nTotalCount );
+ pRetInfos = pInfoSeq->getArray();
+ }
+
+ // Fill result sequences in the correct order of members
+ for( iTotal = 0 ; iTotal < nTotalCount ; iTotal++ )
+ {
+ MemberItem& rItem = pItems[ iTotal ];
+ if( pRetStrings )
+ {
+ pRetStrings[ iTotal ] = rItem.aName;
+ }
+
+ if( pRetInfos )
+ {
+ if( rItem.eMode == MemberItem::Mode::NameAccess )
+ {
+ fillInfoForNameAccess( pRetInfos[ iTotal ], rItem.aName );
+ }
+ else if( rItem.eMode == MemberItem::Mode::PropertySet )
+ {
+ fillInfoForProperty( pRetInfos[ iTotal ], pProps[ rItem.nIndex ] );
+ }
+ else if( rItem.eMode == MemberItem::Mode::Method )
+ {
+ fillInfoForMethod( pRetInfos[ iTotal ], pMethods[ rItem.nIndex ] );
+ }
+ }
+ }
+}
+
+// XInvocation2
+Sequence< OUString > SAL_CALL Invocation_Impl::getMemberNames( )
+{
+ if( _xDirect2.is() )
+ {
+ return _xDirect2->getMemberNames();
+ }
+ Sequence< OUString > aRetSeq;
+ getInfoSequenceImpl( &aRetSeq, nullptr );
+ return aRetSeq;
+}
+
+Sequence< InvocationInfo > SAL_CALL Invocation_Impl::getInfo( )
+{
+ if( _xDirect2.is() )
+ {
+ return _xDirect2->getInfo();
+ }
+ Sequence< InvocationInfo > aRetSeq;
+ getInfoSequenceImpl( nullptr, &aRetSeq );
+ return aRetSeq;
+}
+
+InvocationInfo SAL_CALL Invocation_Impl::getInfoForName( const OUString& aName, sal_Bool bExact )
+{
+ if( _xDirect2.is() )
+ {
+ return _xDirect2->getInfoForName( aName, bExact );
+ }
+
+ bool bFound = false;
+ OUString aExactName = aName;
+ InvocationInfo aRetInfo;
+
+ if( bExact )
+ aExactName = getExactName( aName );
+ if( !aExactName.isEmpty() )
+ {
+ if( _xIntrospectionAccess->hasMethod( aExactName, MethodConcept::ALL ^ MethodConcept::DANGEROUS ) )
+ {
+ Reference<XIdlMethod> xMethod = _xIntrospectionAccess->getMethod
+ ( aExactName, MethodConcept::ALL ^ MethodConcept::DANGEROUS );
+ fillInfoForMethod( aRetInfo, xMethod );
+ bFound = true;
+ }
+ else
+ {
+ if( _xIntrospectionAccess.is() && _xIntrospectionAccess->hasProperty
+ ( aExactName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS ) )
+ {
+ Property aProp = _xIntrospectionAccess->getProperty
+ ( aExactName, PropertyConcept::ALL ^ PropertyConcept::DANGEROUS );
+ fillInfoForProperty( aRetInfo, aProp );
+ bFound = true;
+ }
+ // NameAccess
+ else if( _xNameAccess.is() && _xNameAccess->hasByName( aExactName ) )
+ {
+ fillInfoForNameAccess( aRetInfo, aExactName );
+ bFound = true;
+ }
+ }
+ }
+ if( !bFound )
+ {
+ throw IllegalArgumentException(
+ "getExactName(), Unknown name " + aName,
+ getXWeak(), 0 );
+ }
+ return aRetInfo;
+}
+
+// Helper functions to fill InvocationInfo for XNameAccess
+void Invocation_Impl::fillInfoForNameAccess
+(
+ InvocationInfo& rInfo,
+ const OUString& aName
+)
+{
+ rInfo.aName = aName;
+ rInfo.eMemberType = MemberType_PROPERTY;
+ rInfo.PropertyAttribute = 0;
+ if( !_xNameContainer.is() )
+ {
+ rInfo.PropertyAttribute = PropertyAttribute::READONLY;
+ }
+ rInfo.aType = _xNameAccess->getElementType();
+}
+
+void Invocation_Impl::fillInfoForProperty
+(
+ InvocationInfo& rInfo,
+ const Property& rProp
+)
+{
+ rInfo.aName = rProp.Name;
+ rInfo.eMemberType = MemberType_PROPERTY;
+ rInfo.PropertyAttribute = rProp.Attributes;
+ rInfo.aType = rProp.Type;
+}
+
+void Invocation_Impl::fillInfoForMethod
+(
+ InvocationInfo& rInfo,
+ const Reference< XIdlMethod >& xMethod
+)
+{
+ rInfo.aName = xMethod->getName();
+ rInfo.eMemberType = MemberType_METHOD;
+ Reference< XIdlClass > xReturnClass = xMethod->getReturnType();
+ Type aReturnType( xReturnClass->getTypeClass(), xReturnClass->getName() );
+ rInfo.aType = aReturnType;
+ Sequence<ParamInfo> aParamInfos = xMethod->getParameterInfos();
+ sal_Int32 nParamCount = aParamInfos.getLength();
+ if( nParamCount <= 0 )
+ return;
+
+ const ParamInfo* pInfo = aParamInfos.getConstArray();
+
+ rInfo.aParamTypes.realloc( nParamCount );
+ Type* pParamTypes = rInfo.aParamTypes.getArray();
+ rInfo.aParamModes.realloc( nParamCount );
+ ParamMode* pParamModes = rInfo.aParamModes.getArray();
+
+ for( sal_Int32 i = 0 ; i < nParamCount ; i++ )
+ {
+ Reference< XIdlClass > xParamClass = pInfo[i].aType;
+ Type aParamType( xParamClass->getTypeClass(), xParamClass->getName() );
+ pParamTypes[ i ] = aParamType;
+ pParamModes[ i ] = pInfo[i].aMode;
+ }
+}
+
+
+// XTypeProvider
+Sequence< Type > SAL_CALL Invocation_Impl::getTypes()
+{
+ static Sequence<Type> s_types = [this]() {
+ std::vector<Type> tmp {
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XWeak>::get(),
+ cppu::UnoType<XInvocation>::get(),
+ cppu::UnoType<XMaterialHolder>::get() };
+
+ // Invocation does not support XExactName if direct object supports
+ // XInvocation, but not XExactName.
+ if ((_xDirect.is() && _xENDirect.is()) || (!_xDirect.is() && _xENIntrospection.is()))
+ tmp.push_back(cppu::UnoType<XExactName>::get());
+ if (_xNameContainer.is())
+ tmp.push_back(cppu::UnoType<XNameContainer>::get());
+ if (_xNameReplace.is())
+ tmp.push_back(cppu::UnoType<XNameReplace>::get());
+ if (_xNameAccess.is())
+ tmp.push_back(cppu::UnoType<XNameAccess>::get());
+ if (_xIndexContainer.is())
+ tmp.push_back(cppu::UnoType<XIndexContainer>::get());
+ if (_xIndexReplace.is())
+ tmp.push_back(cppu::UnoType<XIndexReplace>::get());
+ if (_xIndexAccess.is())
+ tmp.push_back(cppu::UnoType<XIndexAccess>::get());
+ if (_xEnumerationAccess.is())
+ tmp.push_back(cppu::UnoType<XEnumerationAccess>::get());
+ if (_xElementAccess.is())
+ tmp.push_back(cppu::UnoType<XElementAccess>::get());
+ // Invocation does not support XInvocation2, if direct object supports
+ // XInvocation, but not XInvocation2.
+ if ((_xDirect.is() && _xDirect2.is()) || (!_xDirect.is() && _xIntrospectionAccess.is()))
+ tmp.push_back(cppu::UnoType<XInvocation2>::get());
+
+ return comphelper::containerToSequence(tmp);
+ }();
+ return s_types;
+}
+
+Sequence< sal_Int8 > SAL_CALL Invocation_Impl::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+namespace {
+
+class InvocationService
+ : public WeakImplHelper< XSingleServiceFactory, XServiceInfo >
+{
+public:
+ explicit InvocationService( const Reference<XComponentContext> & xCtx );
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XSingleServiceFactory
+ Reference<XInterface> SAL_CALL createInstance() override;
+ Reference<XInterface> SAL_CALL createInstanceWithArguments(
+ const Sequence<Any>& rArguments ) override;
+private:
+ Reference<XComponentContext> mxCtx;
+ Reference<XMultiComponentFactory> mxSMgr;
+ Reference<XTypeConverter> xTypeConverter;
+ Reference<XIntrospection> xIntrospection;
+ Reference<XIdlReflection> xCoreReflection;
+};
+
+}
+
+InvocationService::InvocationService( const Reference<XComponentContext> & xCtx )
+ : mxCtx( xCtx )
+ , mxSMgr( xCtx->getServiceManager() )
+ , xCoreReflection( css::reflection::theCoreReflection::get(mxCtx) )
+{
+ xTypeConverter.set(
+ mxSMgr->createInstanceWithContext( "com.sun.star.script.Converter", xCtx ),
+ UNO_QUERY );
+ xIntrospection = theIntrospection::get(xCtx);
+}
+
+// XServiceInfo
+OUString InvocationService::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.Invocation";
+}
+
+// XServiceInfo
+sal_Bool InvocationService::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > InvocationService::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.Invocation" };
+}
+
+
+Reference<XInterface> InvocationService::createInstance()
+{
+ //TODO:throw( Exception("no default construction of invocation adapter possible!", *this) );
+ return Reference<XInterface>(); // dummy
+}
+
+
+Reference<XInterface> InvocationService::createInstanceWithArguments(
+ const Sequence<Any>& rArguments )
+{
+ if (rArguments.getLength() == 2)
+ {
+ OUString aArg1;
+ if ((rArguments[1] >>= aArg1) &&
+ aArg1 == "FromOLE")
+ {
+ return Reference< XInterface >
+ ( *new Invocation_Impl( *rArguments.getConstArray(),
+ xTypeConverter, xIntrospection, xCoreReflection, true ) );
+ }
+ }
+ if (rArguments.getLength() == 1)
+ {
+ return Reference< XInterface >
+ ( *new Invocation_Impl( *rArguments.getConstArray(),
+ xTypeConverter, xIntrospection, xCoreReflection, false ) );
+ }
+
+ //TODO:throw( Exception("no default construction of invocation adapter possible!", *this) );
+ return Reference<XInterface>();
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_InvocationService_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new InvocationService(context));
+}
+
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/invocation_adapterfactory/iafactory.cxx b/stoc/source/invocation_adapterfactory/iafactory.cxx
new file mode 100644
index 0000000000..b5b62db089
--- /dev/null
+++ b/stoc/source/invocation_adapterfactory/iafactory.cxx
@@ -0,0 +1,881 @@
+/* -*- 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 <osl/interlck.h>
+#include <osl/mutex.hxx>
+#include <o3tl/sorted_vector.hxx>
+#include <sal/log.hxx>
+
+#include <uno/dispatcher.h>
+#include <uno/data.h>
+#include <uno/any2.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/script/XInvocationAdapterFactory.hpp>
+#include <com/sun/star/script/XInvocationAdapterFactory2.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/reflection/InvocationTargetException.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <unordered_map>
+#include <vector>
+
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+namespace stoc_invadp
+{
+
+
+namespace {
+
+struct hash_ptr
+{
+ size_t operator() ( void * p ) const
+ { return reinterpret_cast<size_t>(p); }
+};
+
+}
+
+typedef o3tl::sorted_vector< void * > t_ptr_set;
+typedef std::unordered_map< void *, t_ptr_set, hash_ptr > t_ptr_map;
+
+namespace {
+
+class FactoryImpl
+ : public ::cppu::WeakImplHelper< lang::XServiceInfo,
+ script::XInvocationAdapterFactory,
+ script::XInvocationAdapterFactory2 >
+{
+public:
+ Mapping m_aUno2Cpp;
+ Mapping m_aCpp2Uno;
+ uno_Interface * m_pConverter;
+
+ typelib_TypeDescription * m_pInvokMethodTD;
+ typelib_TypeDescription * m_pSetValueTD;
+ typelib_TypeDescription * m_pGetValueTD;
+ typelib_TypeDescription * m_pAnySeqTD;
+ typelib_TypeDescription * m_pShortSeqTD;
+ typelib_TypeDescription * m_pConvertToTD;
+
+ Mutex m_mutex;
+ t_ptr_map m_receiver2adapters;
+
+ explicit FactoryImpl( Reference< XComponentContext > const & xContext );
+ virtual ~FactoryImpl() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XInvocationAdapterFactory
+ virtual Reference< XInterface > SAL_CALL createAdapter(
+ const Reference< script::XInvocation > & xReceiver, const Type & rType ) override;
+ // XInvocationAdapterFactory2
+ virtual Reference< XInterface > SAL_CALL createAdapter(
+ const Reference< script::XInvocation > & xReceiver,
+ const Sequence< Type > & rTypes ) override;
+};
+struct AdapterImpl;
+
+struct InterfaceAdapterImpl : public uno_Interface
+{
+ AdapterImpl * m_pAdapter;
+ typelib_InterfaceTypeDescription * m_pTypeDescr;
+};
+
+struct AdapterImpl
+{
+ oslInterlockedCount m_nRef;
+ FactoryImpl * m_pFactory;
+ void * m_key; // map key
+ uno_Interface * m_pReceiver; // XInvocation receiver
+
+ std::vector<InterfaceAdapterImpl> m_vInterfaces;
+
+ // XInvocation calls
+ void getValue(
+ const typelib_TypeDescription * pMemberType,
+ void * pReturn, uno_Any ** ppException );
+ void setValue(
+ const typelib_TypeDescription * pMemberType,
+ void * pArgs[], uno_Any ** ppException );
+ void invoke(
+ const typelib_TypeDescription * pMemberType,
+ void * pReturn, void * pArgs[], uno_Any ** ppException );
+
+ bool coerce_assign(
+ void * pDest, typelib_TypeDescriptionReference * pType,
+ uno_Any * pSource, uno_Any * pExc );
+ inline bool coerce_construct(
+ void * pDest, typelib_TypeDescriptionReference * pType,
+ uno_Any * pSource, uno_Any * pExc );
+
+ inline void acquire();
+ inline void release();
+ inline ~AdapterImpl();
+ inline AdapterImpl(
+ void * key, Reference< script::XInvocation > const & xReceiver,
+ const Sequence< Type > & rTypes,
+ FactoryImpl * pFactory );
+
+ // Copy assignment is forbidden and not implemented.
+ AdapterImpl (const AdapterImpl &) = delete;
+ AdapterImpl & operator= (const AdapterImpl &) = delete;
+};
+
+}
+
+inline AdapterImpl::~AdapterImpl()
+{
+ for ( size_t nPos = m_vInterfaces.size(); nPos--; )
+ {
+ ::typelib_typedescription_release(
+ &m_vInterfaces[ nPos ].m_pTypeDescr->aBase );
+ }
+
+ (*m_pReceiver->release)( m_pReceiver );
+ m_pFactory->release();
+}
+
+inline void AdapterImpl::acquire()
+{
+ osl_atomic_increment( &m_nRef );
+}
+
+inline void AdapterImpl::release()
+{
+ bool delete_this = false;
+ {
+ MutexGuard guard( m_pFactory->m_mutex );
+ if (! osl_atomic_decrement( &m_nRef ))
+ {
+ t_ptr_map::iterator iFind(
+ m_pFactory->m_receiver2adapters.find( m_key ) );
+ assert( m_pFactory->m_receiver2adapters.end() != iFind );
+ t_ptr_set & adapter_set = iFind->second;
+ if (adapter_set.erase( this ) != 1) {
+ OSL_ASSERT( false );
+ }
+ if (adapter_set.empty())
+ {
+ m_pFactory->m_receiver2adapters.erase( iFind );
+ }
+ delete_this = true;
+ }
+ }
+ if (delete_this)
+ delete this;
+}
+
+
+static void constructRuntimeException(
+ uno_Any * pExc, const OUString & rMsg )
+{
+ RuntimeException exc( rMsg );
+ // no conversion needed due to binary compatibility + no convertible type
+ ::uno_type_any_construct(
+ pExc, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), nullptr );
+}
+
+
+static bool type_equals(
+ typelib_TypeDescriptionReference * pType1,
+ typelib_TypeDescriptionReference * pType2 )
+{
+ return (pType1 == pType2 ||
+ (pType1->pTypeName->length == pType2->pTypeName->length &&
+ 0 == ::rtl_ustr_compare(
+ pType1->pTypeName->buffer, pType2->pTypeName->buffer )));
+}
+
+
+bool AdapterImpl::coerce_assign(
+ void * pDest, typelib_TypeDescriptionReference * pType, uno_Any * pSource,
+ uno_Any * pOutExc )
+{
+ if (typelib_TypeClass_ANY == pType->eTypeClass)
+ {
+ ::uno_type_any_assign(
+ static_cast<uno_Any *>(pDest), pSource->pData, pSource->pType, nullptr, nullptr );
+ return true;
+ }
+ if (::uno_type_assignData(
+ pDest, pType, pSource->pData, pSource->pType, nullptr, nullptr, nullptr ))
+ {
+ return true;
+ }
+ else // try type converter
+ {
+ uno_Any ret;
+ void * args[ 2 ];
+ args[ 0 ] = pSource;
+ args[ 1 ] = &pType;
+ uno_Any exc;
+ uno_Any * p_exc = &exc;
+
+ // converTo()
+ (*m_pFactory->m_pConverter->pDispatcher)(
+ m_pFactory->m_pConverter,
+ m_pFactory->m_pConvertToTD, &ret, args, &p_exc );
+
+ if (p_exc) // exception occurred
+ {
+ OSL_ASSERT(
+ p_exc->pType->eTypeClass == typelib_TypeClass_EXCEPTION );
+ if (typelib_typedescriptionreference_isAssignableFrom( cppu::UnoType<RuntimeException>::get().getTypeLibType(),
+ p_exc->pType ))
+ {
+ // is RuntimeException or derived: rethrow
+ uno_type_any_construct(
+ pOutExc, p_exc->pData, p_exc->pType, nullptr );
+ }
+ else
+ {
+ // set runtime exception
+ constructRuntimeException(
+ pOutExc, "type coercion failed: " +
+ static_cast< Exception const * >(
+ p_exc->pData )->Message );
+ }
+ ::uno_any_destruct( p_exc, nullptr );
+ // pOutExc constructed
+ return false;
+ }
+ else
+ {
+ bool succ = ::uno_type_assignData(
+ pDest, pType, ret.pData, ret.pType, nullptr, nullptr, nullptr );
+ ::uno_any_destruct( &ret, nullptr );
+ OSL_ENSURE(
+ succ, "### conversion succeeded, but assignment failed!?" );
+ if (! succ)
+ {
+ // set runtime exception
+ constructRuntimeException(
+ pOutExc,
+ "type coercion failed: "
+ "conversion succeeded, but assignment failed?!" );
+ }
+ return succ;
+ }
+ }
+}
+
+inline bool AdapterImpl::coerce_construct(
+ void * pDest, typelib_TypeDescriptionReference * pType, uno_Any * pSource,
+ uno_Any * pExc )
+{
+ if (typelib_TypeClass_ANY == pType->eTypeClass)
+ {
+ ::uno_type_copyData( pDest, pSource, pType, nullptr );
+ return true;
+ }
+ if (type_equals( pType, pSource->pType))
+ {
+ ::uno_type_copyData( pDest, pSource->pData, pType, nullptr );
+ return true;
+ }
+ ::uno_type_constructData( pDest, pType );
+ return coerce_assign( pDest, pType, pSource, pExc );
+}
+
+
+static void handleInvokExc( uno_Any * pDest, uno_Any * pSource )
+{
+ OUString const & name =
+ OUString::unacquired( &pSource->pType->pTypeName );
+
+ if ( name == "com.sun.star.reflection.InvocationTargetException" )
+ {
+ // unwrap invocation target exception
+ uno_Any * target_exc =
+ &static_cast< reflection::InvocationTargetException * >(
+ pSource->pData )->TargetException;
+ ::uno_type_any_construct(
+ pDest, target_exc->pData, target_exc->pType, nullptr );
+ }
+ else // all other exceptions are wrapped to RuntimeException
+ {
+ if (typelib_TypeClass_EXCEPTION == pSource->pType->eTypeClass)
+ {
+ constructRuntimeException(
+ pDest, static_cast<Exception const *>(pSource->pData)->Message );
+ }
+ else
+ {
+ constructRuntimeException(
+ pDest, "no exception has been thrown via invocation?!" );
+ }
+ }
+}
+
+void AdapterImpl::getValue(
+ const typelib_TypeDescription * pMemberType,
+ void * pReturn, uno_Any ** ppException )
+{
+ uno_Any aInvokRet;
+ void * pInvokArgs[1];
+ pInvokArgs[0] = const_cast<rtl_uString **>(
+ &reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->pMemberName);
+ uno_Any aInvokExc;
+ uno_Any * pInvokExc = &aInvokExc;
+
+ // getValue()
+ (*m_pReceiver->pDispatcher)(
+ m_pReceiver, m_pFactory->m_pGetValueTD,
+ &aInvokRet, pInvokArgs, &pInvokExc );
+
+ if (pInvokExc) // getValue() call exception
+ {
+ handleInvokExc( *ppException, pInvokExc );
+ ::uno_any_destruct( pInvokExc, nullptr ); // cleanup
+ }
+ else // invocation call succeeded
+ {
+ if (coerce_construct(
+ pReturn,
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
+ pMemberType)->pAttributeTypeRef,
+ &aInvokRet, *ppException ))
+ {
+ *ppException = nullptr; // no exceptions be thrown
+ }
+ ::uno_any_destruct( &aInvokRet, nullptr );
+ }
+}
+
+void AdapterImpl::setValue(
+ const typelib_TypeDescription * pMemberType,
+ void * pArgs[], uno_Any ** ppException )
+{
+ uno_Any aInvokVal;
+ ::uno_type_any_construct(
+ &aInvokVal, pArgs[0],
+ reinterpret_cast<typelib_InterfaceAttributeTypeDescription const *>(
+ pMemberType)->pAttributeTypeRef, nullptr );
+
+ void * pInvokArgs[2];
+ pInvokArgs[0] = const_cast<rtl_uString **>(
+ &reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->pMemberName);
+ pInvokArgs[1] = &aInvokVal;
+ uno_Any aInvokExc;
+ uno_Any * pInvokExc = &aInvokExc;
+
+ // setValue()
+ (*m_pReceiver->pDispatcher)(
+ m_pReceiver, m_pFactory->m_pSetValueTD, nullptr, pInvokArgs, &pInvokExc );
+
+ if (pInvokExc) // setValue() call exception
+ {
+ handleInvokExc( *ppException, pInvokExc );
+ ::uno_any_destruct( pInvokExc, nullptr ); // cleanup
+ }
+ else // invocation call succeeded
+ {
+ *ppException = nullptr; // no exceptions be thrown
+ }
+
+ ::uno_any_destruct( &aInvokVal, nullptr ); // cleanup
+}
+
+void AdapterImpl::invoke(
+ const typelib_TypeDescription * pMemberType,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ sal_Int32 nParams =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType)->nParams;
+ typelib_MethodParameter * pFormalParams =
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(pMemberType)->pParams;
+
+ // in params
+ uno_Sequence * pInParamsSeq = nullptr;
+ ::uno_sequence_construct(
+ &pInParamsSeq, m_pFactory->m_pAnySeqTD, nullptr, nParams, nullptr );
+ uno_Any * pInAnys = reinterpret_cast<uno_Any *>(pInParamsSeq->elements);
+ sal_Int32 nOutParams = 0;
+ sal_Int32 nPos;
+ for ( nPos = nParams; nPos--; )
+ {
+ typelib_MethodParameter const & rParam = pFormalParams[nPos];
+ if (rParam.bIn) // is in/inout param
+ {
+ ::uno_type_any_assign(
+ &pInAnys[nPos], pArgs[nPos], rParam.pTypeRef, nullptr, nullptr );
+ }
+ // else: pure out is empty any
+
+ if (rParam.bOut)
+ ++nOutParams;
+ }
+
+ // out params, out indices
+ uno_Sequence * pOutIndices;
+ uno_Sequence * pOutParams;
+ // return value
+ uno_Any aInvokRet;
+ // perform call
+ void * pInvokArgs[4];
+ pInvokArgs[0] = const_cast<rtl_uString **>(
+ &reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->pMemberName);
+ pInvokArgs[1] = &pInParamsSeq;
+ pInvokArgs[2] = &pOutIndices;
+ pInvokArgs[3] = &pOutParams;
+ uno_Any aInvokExc;
+ uno_Any * pInvokExc = &aInvokExc;
+
+ // invoke() call
+ (*m_pReceiver->pDispatcher)(
+ m_pReceiver, m_pFactory->m_pInvokMethodTD,
+ &aInvokRet, pInvokArgs, &pInvokExc );
+
+ if (pInvokExc)
+ {
+ handleInvokExc( *ppException, pInvokExc );
+ ::uno_any_destruct( pInvokExc, nullptr ); // cleanup
+ }
+ else // no invocation exception
+ {
+ // write changed out params
+ OSL_ENSURE(
+ pOutParams->nElements == nOutParams &&
+ pOutIndices->nElements == nOutParams,
+ "### out params lens differ!" );
+ if (pOutParams->nElements == nOutParams &&
+ pOutIndices->nElements == nOutParams)
+ {
+ sal_Int16 * pIndices = reinterpret_cast<sal_Int16 *>(pOutIndices->elements);
+ uno_Any * pOut = reinterpret_cast<uno_Any *>(pOutParams->elements);
+ for ( nPos = 0; nPos < nOutParams; ++nPos )
+ {
+ sal_Int32 nIndex = pIndices[nPos];
+ OSL_ENSURE( nIndex < nParams, "### illegal index!" );
+ typelib_MethodParameter const & rParam = pFormalParams[nIndex];
+ bool succ;
+ if (rParam.bIn) // is in/inout param
+ {
+ succ = coerce_assign(
+ pArgs[nIndex], rParam.pTypeRef, &pOut[nPos],
+ *ppException );
+ }
+ else // pure out
+ {
+ succ = coerce_construct(
+ pArgs[nIndex], rParam.pTypeRef, &pOut[nPos],
+ *ppException );
+ }
+ if (! succ) // cleanup of out params
+ {
+ for ( sal_Int32 n = 0; n <= nPos; ++n )
+ {
+ sal_Int32 nIndex2 = pIndices[n];
+ OSL_ENSURE( nIndex2 < nParams, "### illegal index!" );
+ typelib_MethodParameter const & rParam2 =
+ pFormalParams[nIndex2];
+ if (! rParam2.bIn) // is pure out param
+ {
+ ::uno_type_destructData(
+ pArgs[nIndex2], rParam2.pTypeRef, nullptr );
+ }
+ }
+ }
+ }
+ if (nPos == pOutIndices->nElements)
+ {
+ // out param copy ok; write return value
+ if (coerce_construct(
+ pReturn,
+ reinterpret_cast<typelib_InterfaceMethodTypeDescription const *>(
+ pMemberType)->pReturnTypeRef,
+ &aInvokRet, *ppException ))
+ {
+ *ppException = nullptr; // no exception
+ }
+ }
+ }
+ else
+ {
+ // set runtime exception
+ constructRuntimeException(
+ *ppException,
+ "out params lengths differ after invocation call!" );
+ }
+ // cleanup invok out params
+ ::uno_destructData( &pOutIndices, m_pFactory->m_pShortSeqTD, nullptr );
+ ::uno_destructData( &pOutParams, m_pFactory->m_pAnySeqTD, nullptr );
+ // cleanup invok return value
+ ::uno_any_destruct( &aInvokRet, nullptr );
+ }
+ // cleanup constructed in params
+ ::uno_destructData( &pInParamsSeq, m_pFactory->m_pAnySeqTD, nullptr );
+}
+
+extern "C"
+{
+
+static void adapter_acquire( uno_Interface * pUnoI )
+{
+ static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter->acquire();
+}
+
+static void adapter_release( uno_Interface * pUnoI )
+{
+ static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter->release();
+}
+
+static void adapter_dispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType,
+ void * pReturn, void * pArgs[], uno_Any ** ppException )
+{
+ // query to emulated interface
+ switch (reinterpret_cast<typelib_InterfaceMemberTypeDescription const *>(pMemberType)->nPosition)
+ {
+ case 0: // queryInterface()
+ {
+ AdapterImpl * that =
+ static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter;
+ *ppException = nullptr; // no exc
+ typelib_TypeDescriptionReference * pDemanded =
+ *static_cast<typelib_TypeDescriptionReference **>(pArgs[0]);
+ // pInterfaces[0] is XInterface
+ for ( size_t nPos = 0; nPos < that->m_vInterfaces.size(); ++nPos )
+ {
+ typelib_InterfaceTypeDescription * pTD =
+ that->m_vInterfaces[nPos].m_pTypeDescr;
+ while (pTD)
+ {
+ if (type_equals( pTD->aBase.pWeakRef, pDemanded ))
+ {
+ uno_Interface * pUnoI2 = &that->m_vInterfaces[nPos];
+ ::uno_any_construct(
+ static_cast<uno_Any *>(pReturn), &pUnoI2,
+ &pTD->aBase, nullptr );
+ return;
+ }
+ pTD = pTD->pBaseTypeDescription;
+ }
+ }
+ ::uno_any_construct( static_cast<uno_Any *>(pReturn), nullptr, nullptr, nullptr ); // clear()
+ break;
+ }
+ case 1: // acquire()
+ *ppException = nullptr; // no exc
+ adapter_acquire( pUnoI );
+ break;
+ case 2: // release()
+ *ppException = nullptr; // no exc
+ adapter_release( pUnoI );
+ break;
+
+ default:
+ {
+ AdapterImpl * that =
+ static_cast< InterfaceAdapterImpl * >( pUnoI )->m_pAdapter;
+ if (pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD)
+ {
+ that->invoke( pMemberType, pReturn, pArgs, ppException );
+ }
+ else // attribute
+ {
+ if (pReturn)
+ that->getValue( pMemberType, pReturn, ppException );
+ else
+ that->setValue( pMemberType, pArgs, ppException );
+ }
+ }
+ }
+}
+}
+
+AdapterImpl::AdapterImpl(
+ void * key, Reference< script::XInvocation > const & xReceiver,
+ const Sequence< Type > & rTypes,
+ FactoryImpl * pFactory )
+ : m_nRef( 1 ),
+ m_pFactory( pFactory ),
+ m_key( key ),
+ m_vInterfaces( rTypes.getLength() )
+{
+ // init adapters
+ const Type * pTypes = rTypes.getConstArray();
+ for ( sal_Int32 nPos = rTypes.getLength(); nPos--; )
+ {
+ InterfaceAdapterImpl * pInterface = &m_vInterfaces[nPos];
+ pInterface->acquire = adapter_acquire;
+ pInterface->release = adapter_release;
+ pInterface->pDispatcher = adapter_dispatch;
+ pInterface->m_pAdapter = this;
+ pInterface->m_pTypeDescr = nullptr;
+ pTypes[nPos].getDescription(
+ reinterpret_cast<typelib_TypeDescription **>(&pInterface->m_pTypeDescr) );
+ OSL_ASSERT( pInterface->m_pTypeDescr );
+ if (! pInterface->m_pTypeDescr)
+ {
+ for ( sal_Int32 n = 0; n < nPos; ++n )
+ {
+ ::typelib_typedescription_release(
+ &m_vInterfaces[ n ].m_pTypeDescr->aBase );
+ }
+ throw RuntimeException(
+ "cannot retrieve all interface type infos!" );
+ }
+ }
+
+ // map receiver
+ m_pReceiver = static_cast<uno_Interface *>(m_pFactory->m_aCpp2Uno.mapInterface(
+ xReceiver.get(), cppu::UnoType<decltype(xReceiver)>::get() ));
+ OSL_ASSERT( nullptr != m_pReceiver );
+ if (! m_pReceiver)
+ {
+ throw RuntimeException( "cannot map receiver!" );
+ }
+
+ m_pFactory->acquire();
+}
+
+
+FactoryImpl::FactoryImpl( Reference< XComponentContext > const & xContext )
+ : m_aUno2Cpp(Mapping( UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME )),
+ m_aCpp2Uno(Mapping( CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO)),
+ m_pInvokMethodTD( nullptr ),
+ m_pSetValueTD( nullptr ),
+ m_pGetValueTD( nullptr ),
+ m_pAnySeqTD( nullptr ),
+ m_pShortSeqTD( nullptr ),
+ m_pConvertToTD( nullptr )
+{
+ // C++/UNO bridge
+ OSL_ENSURE(
+ m_aUno2Cpp.is() && m_aCpp2Uno.is(), "### no uno / C++ mappings!" );
+
+ // type converter
+ Reference< script::XTypeConverter > xConverter(
+ xContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.script.Converter",
+ xContext ),
+ UNO_QUERY_THROW );
+ m_pConverter = static_cast<uno_Interface *>(m_aCpp2Uno.mapInterface(
+ xConverter.get(), cppu::UnoType<decltype(xConverter)>::get() ));
+ OSL_ASSERT( nullptr != m_pConverter );
+
+ // some type info:
+ // sequence< any >
+ Type const & rAnySeqType = cppu::UnoType<Sequence< Any >>::get();
+ rAnySeqType.getDescription( &m_pAnySeqTD );
+ // sequence< short >
+ const Type & rShortSeqType =
+ cppu::UnoType<Sequence< sal_Int16 >>::get();
+ rShortSeqType.getDescription( &m_pShortSeqTD );
+ // script.XInvocation
+ typelib_TypeDescription * pTD = nullptr;
+ const Type & rInvType = cppu::UnoType<script::XInvocation>::get();
+ TYPELIB_DANGER_GET( &pTD, rInvType.getTypeLibType() );
+ typelib_InterfaceTypeDescription * pITD;
+ pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD);
+ if( ! pITD->aBase.bComplete )
+ typelib_typedescription_complete( &pTD );
+ ::typelib_typedescriptionreference_getDescription(
+ &m_pInvokMethodTD, pITD->ppMembers[ 1 ] ); // invoke()
+ ::typelib_typedescriptionreference_getDescription(
+ &m_pSetValueTD, pITD->ppMembers[ 2 ] ); // setValue()
+ ::typelib_typedescriptionreference_getDescription(
+ &m_pGetValueTD, pITD->ppMembers[ 3 ] ); // getValue()
+ // script.XTypeConverter
+ const Type & rTCType =
+ cppu::UnoType<script::XTypeConverter>::get();
+ TYPELIB_DANGER_GET( &pTD, rTCType.getTypeLibType() );
+ pITD = reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD);
+ ::typelib_typedescriptionreference_getDescription(
+ &m_pConvertToTD, pITD->ppMembers[ 0 ] ); // convertTo()
+ TYPELIB_DANGER_RELEASE( pTD );
+
+ if (!m_pInvokMethodTD || !m_pSetValueTD || !m_pGetValueTD ||
+ !m_pConvertToTD ||
+ !m_pAnySeqTD || !m_pShortSeqTD)
+ {
+ throw RuntimeException( "missing type descriptions!" );
+ }
+}
+
+FactoryImpl::~FactoryImpl()
+{
+ ::typelib_typedescription_release( m_pInvokMethodTD );
+ ::typelib_typedescription_release( m_pSetValueTD );
+ ::typelib_typedescription_release( m_pGetValueTD );
+ ::typelib_typedescription_release( m_pAnySeqTD );
+ ::typelib_typedescription_release( m_pShortSeqTD );
+ ::typelib_typedescription_release( m_pConvertToTD );
+
+ (*m_pConverter->release)( m_pConverter );
+
+#if OSL_DEBUG_LEVEL > 0
+ assert(m_receiver2adapters.empty() && "still adapters out there!?");
+#endif
+}
+
+
+static AdapterImpl * lookup_adapter(
+ t_ptr_set ** pp_adapter_set,
+ t_ptr_map & map, void * key, Sequence< Type > const & rTypes )
+{
+ t_ptr_set & adapters_set = map[ key ];
+ *pp_adapter_set = &adapters_set;
+ if (adapters_set.empty())
+ return nullptr; // shortcut
+ // find matching adapter
+ Type const * pTypes = rTypes.getConstArray();
+ sal_Int32 nTypes = rTypes.getLength();
+ for (const auto& rpAdapter : adapters_set)
+ {
+ AdapterImpl * that = static_cast< AdapterImpl * >( rpAdapter );
+ // iterate through all types if that is a matching adapter
+ sal_Int32 nPosTypes;
+ for ( nPosTypes = nTypes; nPosTypes--; )
+ {
+ Type const & rType = pTypes[ nPosTypes ];
+ // find in adapter's type list
+ sal_Int32 nPos;
+ for ( nPos = that->m_vInterfaces.size(); nPos--; )
+ {
+ if (::typelib_typedescriptionreference_isAssignableFrom(
+ rType.getTypeLibType(),
+ that->m_vInterfaces[ nPos ].m_pTypeDescr->aBase.pWeakRef ))
+ {
+ // found
+ break;
+ }
+ }
+ if (nPos < 0) // type not found => next adapter
+ break;
+ }
+ if (nPosTypes < 0) // all types found
+ return that;
+ }
+ return nullptr;
+}
+
+// XInvocationAdapterFactory2 impl
+
+Reference< XInterface > FactoryImpl::createAdapter(
+ const Reference< script::XInvocation > & xReceiver,
+ const Sequence< Type > & rTypes )
+{
+ Reference< XInterface > xRet;
+ if (xReceiver.is() && rTypes.hasElements())
+ {
+ t_ptr_set * adapter_set;
+ AdapterImpl * that;
+ Reference< XInterface > xKey( xReceiver, UNO_QUERY );
+ {
+ ClearableMutexGuard guard( m_mutex );
+ that = lookup_adapter(
+ &adapter_set, m_receiver2adapters, xKey.get(), rTypes );
+ if (nullptr == that) // no entry
+ {
+ guard.clear();
+ // create adapter; already acquired: m_nRef == 1
+ AdapterImpl * pNew =
+ new AdapterImpl( xKey.get(), xReceiver, rTypes, this );
+ // lookup again
+ ClearableMutexGuard guard2( m_mutex );
+ that = lookup_adapter(
+ &adapter_set, m_receiver2adapters, xKey.get(), rTypes );
+ if (nullptr == that) // again no entry
+ {
+ std::pair< t_ptr_set::const_iterator, bool > i(adapter_set->insert(pNew));
+ SAL_WARN_IF(
+ !i.second, "stoc",
+ "set already contains " << *(i.first) << " != " << pNew);
+ that = pNew;
+ }
+ else
+ {
+ that->acquire();
+ guard2.clear();
+ delete pNew; // has never been inserted
+ }
+ }
+ else // found adapter
+ {
+ that->acquire();
+ }
+ }
+ // map one interface to C++
+ uno_Interface * pUnoI = that->m_vInterfaces.data();
+ m_aUno2Cpp.mapInterface(
+ reinterpret_cast<void **>(&xRet), pUnoI, cppu::UnoType<decltype(xRet)>::get() );
+ that->release();
+ OSL_ASSERT( xRet.is() );
+ if (! xRet.is())
+ {
+ throw RuntimeException( "mapping UNO to C++ failed!" );
+ }
+ }
+ return xRet;
+}
+// XInvocationAdapterFactory impl
+
+Reference< XInterface > FactoryImpl::createAdapter(
+ const Reference< script::XInvocation > & xReceiver, const Type & rType )
+{
+ return createAdapter( xReceiver, Sequence< Type >( &rType, 1 ) );
+}
+
+// XServiceInfo
+
+OUString FactoryImpl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.InvocationAdapterFactory";
+}
+
+sal_Bool FactoryImpl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > FactoryImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.InvocationAdapterFactory" };
+}
+
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_invocation_adapter_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new stoc_invadp::FactoryImpl(context));
+}
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/invocation_adapterfactory/invocadapt.component b/stoc/source/invocation_adapterfactory/invocadapt.component
new file mode 100644
index 0000000000..ec1723e22a
--- /dev/null
+++ b/stoc/source/invocation_adapterfactory/invocadapt.component
@@ -0,0 +1,26 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.InvocationAdapterFactory"
+ constructor="stoc_invocation_adapter_get_implementation" single-instance="true">
+ <service name="com.sun.star.script.InvocationAdapterFactory"/>
+ </implementation>
+</component>
diff --git a/stoc/source/javaloader/javaloader.component b/stoc/source/javaloader/javaloader.component
new file mode 100644
index 0000000000..e8d1533bac
--- /dev/null
+++ b/stoc/source/javaloader/javaloader.component
@@ -0,0 +1,28 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.JavaComponentLoader"
+ constructor="stoc_JavaComponentLoader_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.loader.Java"/>
+ <service name="com.sun.star.loader.Java2"/>
+ </implementation>
+</component>
diff --git a/stoc/source/javaloader/javaloader.cxx b/stoc/source/javaloader/javaloader.cxx
new file mode 100644
index 0000000000..e54ce9b2d7
--- /dev/null
+++ b/stoc/source/javaloader/javaloader.cxx
@@ -0,0 +1,574 @@
+/* -*- 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/process.h>
+#include <sal/log.hxx>
+
+#include <uno/environment.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+
+#ifdef LINUX
+#undef minor
+#undef major
+#endif
+
+#include <com/sun/star/java/XJavaVM.hpp>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <rtl/random.h>
+#include <rtl/ustrbuf.hxx>
+#include <osl/security.hxx>
+
+#include <cppuhelper/factory.hxx>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/bridge/UnoUrlResolver.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/loader/XImplementationLoader.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+
+// this one is header-only
+#include <comphelper/sequence.hxx>
+
+#include <mutex>
+#include <thread>
+#include <utility>
+
+namespace com::sun::star::registry { class XRegistryKey; }
+
+using namespace css::java;
+using namespace css::lang;
+using namespace css::loader;
+using namespace css::uno;
+using namespace css::registry;
+
+using namespace ::cppu;
+using namespace ::osl;
+
+namespace stoc_javaloader {
+
+namespace {
+
+// from desktop/source/deployment/misc/dp_misc.cxx
+OUString generateRandomPipeId()
+{
+ // compute some good pipe id:
+ static rtlRandomPool s_hPool = rtl_random_createPool();
+ if (s_hPool == nullptr)
+ throw RuntimeException( "cannot create random pool!?", nullptr );
+ sal_uInt8 bytes[ 32 ];
+ if (rtl_random_getBytes(
+ s_hPool, bytes, SAL_N_ELEMENTS(bytes) ) != rtl_Random_E_None) {
+ throw RuntimeException( "random pool error!?", nullptr );
+ }
+ OUStringBuffer buf;
+ for (unsigned char byte : bytes) {
+ buf.append( static_cast<sal_Int32>(byte), 0x10 );
+ }
+ return buf.makeStringAndClear();
+}
+
+// from desktop/source/deployment/registry/component/dp_component.cxx
+/** return a vector of bootstrap variables which have been provided
+ as command arguments.
+*/
+std::vector<OUString> getCmdBootstrapVariables()
+{
+ std::vector<OUString> ret;
+ sal_uInt32 count = osl_getCommandArgCount();
+ for (sal_uInt32 i = 0; i < count; i++)
+ {
+ OUString arg;
+ osl_getCommandArg(i, &arg.pData);
+ if (arg.startsWith("-env:"))
+ ret.push_back(arg);
+ }
+ return ret;
+}
+
+// from desktop/source/deployment/misc/dp_misc.cxx
+oslProcess raiseProcess(
+ OUString const & appURL, Sequence<OUString> const & args )
+{
+ ::osl::Security sec;
+ oslProcess hProcess = nullptr;
+ oslProcessError rc = osl_executeProcess(
+ appURL.pData,
+ reinterpret_cast<rtl_uString **>(
+ const_cast<OUString *>(args.getConstArray()) ),
+ args.getLength(),
+ osl_Process_DETACHED,
+ sec.getHandle(),
+ nullptr, // => current working dir
+ nullptr, 0, // => no env vars
+ &hProcess );
+
+ switch (rc) {
+ case osl_Process_E_None:
+ break;
+ case osl_Process_E_NotFound:
+ throw RuntimeException( "image not found!", nullptr );
+ case osl_Process_E_TimedOut:
+ throw RuntimeException( "timeout occurred!", nullptr );
+ case osl_Process_E_NoPermission:
+ throw RuntimeException( "permission denied!", nullptr );
+ case osl_Process_E_Unknown:
+ throw RuntimeException( "unknown error!", nullptr );
+ case osl_Process_E_InvalidError:
+ default:
+ throw RuntimeException( "unmapped error!", nullptr );
+ }
+
+ return hProcess;
+}
+
+// from desktop/source/deployment/registry/component/dp_component.cxx
+Reference<XComponentContext> raise_uno_process(
+ Reference<XComponentContext> const & xContext)
+{
+ OSL_ASSERT( xContext.is() );
+
+ OUString const url(css::util::theMacroExpander::get(xContext)->expandMacros("$URE_BIN_DIR/uno"));
+
+ const OUString connectStr = "uno:pipe,name=" + generateRandomPipeId() + ";urp;uno.ComponentContext";
+
+ // raise core UNO process to register/run a component,
+ // javavm service uses unorc next to executable to retrieve deployed
+ // jar typelibs
+
+ std::vector<OUString> args{
+#if OSL_DEBUG_LEVEL == 0
+ "--quiet",
+#endif
+ "--singleaccept",
+ "-u",
+ connectStr,
+ // don't inherit from unorc:
+ "-env:INIFILENAME=" };
+
+ //now add the bootstrap variables which were supplied on the command line
+ std::vector<OUString> bootvars = getCmdBootstrapVariables();
+ args.insert(args.end(), bootvars.begin(), bootvars.end());
+
+ oslProcess hProcess;
+ try {
+ hProcess = raiseProcess(url, comphelper::containerToSequence(args));
+ }
+ catch (...) {
+ OUStringBuffer sMsg = "error starting process: " + url;
+ for (const auto& arg : args) {
+ sMsg.append(" " + arg);
+ }
+ throw css::uno::RuntimeException(sMsg.makeStringAndClear());
+ }
+ try {
+ // from desktop/source/deployment/misc/dp_misc.cxx
+ Reference<css::bridge::XUnoUrlResolver> const xUnoUrlResolver(
+ css::bridge::UnoUrlResolver::create(xContext) );
+
+ for (int i = 0; i <= 40; ++i) // 20 seconds
+ {
+ try {
+ return Reference<XComponentContext>(
+ xUnoUrlResolver->resolve(connectStr),
+ UNO_QUERY_THROW );
+ }
+ catch (const css::connection::NoConnectException &) {
+ if (i < 40) {
+ std::this_thread::sleep_for( std::chrono::milliseconds(500) );
+ }
+ else throw;
+ }
+ }
+ return nullptr; // warning C4715
+ }
+ catch (...) {
+ // try to terminate process:
+ if ( osl_terminateProcess( hProcess ) != osl_Process_E_None )
+ {
+ OSL_ASSERT( false );
+ }
+ throw;
+ }
+}
+
+class JavaComponentLoader
+ : protected ::cppu::BaseMutex
+ , public WeakComponentImplHelper<XImplementationLoader, XServiceInfo>
+{
+ /** local context */
+ css::uno::Reference<XComponentContext> m_xComponentContext;
+
+ /** possible remote process' context (use depends on configuration).
+ note: lifetime must be effectively "static" as this JavaComponentLoader
+ has no control over the lifetime of the services created via this
+ context; hence JavaComponentLoader is a single-instance service.
+ */
+ css::uno::Reference<XComponentContext> m_xRemoteComponentContext;
+
+ /** Do not use m_javaLoader directly. Instead use getJavaLoader.
+ This is either an in-process loader implemented in Java,
+ or a remote instance of JavaComponentLoader running in uno process,
+ acting as a proxy.
+ */
+ css::uno::Reference<XImplementationLoader> m_javaLoader;
+ /** The returned Reference contains a null pointer if the office is not configured
+ to run java.
+
+ @exception css::uno::RuntimeException
+ If the Java implementation of the loader could not be obtained, for reasons other
+ then that java was not configured the RuntimeException is thrown.
+ */
+ const css::uno::Reference<XImplementationLoader> & getJavaLoader(OUString &);
+
+
+public:
+ /// @throws RuntimeException
+ explicit JavaComponentLoader(css::uno::Reference<XComponentContext> xCtx);
+
+public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // XImplementationLoader
+ virtual css::uno::Reference<XInterface> SAL_CALL activate(
+ const OUString& implementationName, const OUString& implementationLoaderUrl,
+ const OUString& locationUrl, const css::uno::Reference<XRegistryKey>& xKey) override;
+ virtual sal_Bool SAL_CALL writeRegistryInfo(
+ const css::uno::Reference<XRegistryKey>& xKey,
+ const OUString& implementationLoaderUrl, const OUString& locationUrl) override;
+};
+
+}
+
+void JavaComponentLoader::disposing()
+{
+ // Explicitly drop all remote refs to shut down the uno.bin process
+ // and particularly the connection to it, so that it can't do more calls
+ // during late shutdown.
+ m_javaLoader.clear();
+ if (m_xRemoteComponentContext.is()) {
+ Reference<XComponent> const xComp(m_xRemoteComponentContext, UNO_QUERY);
+ assert(xComp.is());
+ xComp->dispose();
+ m_xRemoteComponentContext.clear();
+ }
+}
+
+const css::uno::Reference<XImplementationLoader> & JavaComponentLoader::getJavaLoader(OUString & rRemoteArg)
+{
+ static std::mutex ourMutex;
+ std::unique_lock aGuard(ourMutex);
+
+ if (m_javaLoader.is())
+ return m_javaLoader;
+
+ // check if the JVM should be instantiated out-of-process
+ if (rRemoteArg.isEmpty()) {
+ if (!m_xRemoteComponentContext.is()) {
+ Reference<css::container::XHierarchicalNameAccess> const xConf(
+ m_xComponentContext->getServiceManager()->createInstanceWithArgumentsAndContext(
+ "com.sun.star.configuration.ReadOnlyAccess",
+ { Any(OUString("*")) }, // locale isn't relevant here
+ m_xComponentContext),
+ UNO_QUERY);
+
+ // configmgr is not part of URE, so may not exist!
+ if (xConf.is()) {
+ Any const value(xConf->getByHierarchicalName(
+ "org.openoffice.Office.Java/VirtualMachine/RunUnoComponentsOutOfProcess"));
+ bool b;
+ if ((value >>= b) && b) {
+ SAL_INFO("stoc.java", "JavaComponentLoader: starting uno process");
+ m_xRemoteComponentContext = raise_uno_process(m_xComponentContext);
+ }
+ }
+ }
+ if (m_xRemoteComponentContext.is()) {
+ SAL_INFO("stoc.java", "JavaComponentLoader: creating remote instance to start JVM in uno process");
+ // create JVM service in remote uno.bin process
+ Reference<XImplementationLoader> const xLoader(
+ m_xRemoteComponentContext->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.loader.Java2", m_xRemoteComponentContext),
+ UNO_QUERY_THROW);
+ assert(xLoader.is());
+ m_javaLoader = xLoader;
+ rRemoteArg = "remote";
+ SAL_INFO("stoc.java", "JavaComponentLoader: remote proxy instance created: " << m_javaLoader.get());
+ return m_javaLoader;
+ }
+ }
+
+ uno_Environment * pJava_environment = nullptr;
+ uno_Environment * pUno_environment = nullptr;
+ typelib_InterfaceTypeDescription * pType_XImplementationLoader = nullptr;
+
+ try {
+ // get a java vm, where we can create a loader
+ css::uno::Reference<XJavaVM> javaVM_xJavaVM(
+ m_xComponentContext->getValueByName(
+ ("/singletons/"
+ "com.sun.star.java.theJavaVirtualMachine")),
+ UNO_QUERY_THROW);
+
+ // Use the special protocol of XJavaVM.getJavaVM: If the passed in
+ // process ID has an extra 17th byte of value one, the returned any
+ // contains a pointer to a jvmaccess::UnoVirtualMachine, instead of the
+ // underlying JavaVM pointer:
+ Sequence<sal_Int8> processID(17);
+ rtl_getGlobalProcessId(reinterpret_cast<sal_uInt8 *>(processID.getArray()));
+ processID.getArray()[16] = 1;
+
+ // We get a non-refcounted pointer to a jvmaccess::UnoVirtualMachine
+ // from the XJavaVM service (the pointer is guaranteed to be valid
+ // as long as our reference to the XJavaVM service lasts), and
+ // convert the non-refcounted pointer into a refcounted one
+ // immediately:
+ static_assert(sizeof (sal_Int64)
+ >= sizeof (jvmaccess::UnoVirtualMachine *), "must be at least the same size");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::UnoVirtualMachine * >(nullptr));
+ javaVM_xJavaVM->getJavaVM(processID) >>= nPointer;
+ rtl::Reference< jvmaccess::UnoVirtualMachine > xVirtualMachine(
+ reinterpret_cast< jvmaccess::UnoVirtualMachine * >(nPointer));
+ if (!xVirtualMachine.is())
+ {
+ //throw RuntimeException(
+ // "javaloader error - JavaVirtualMachine service could not provide a VM",
+ // css::uno::Reference<XInterface>());
+ // We must not throw a RuntimeException, because this might end the applications.
+ // It is ok if java components
+ // are not working because the office can be installed without Java support.
+ SAL_WARN("stoc", "getJavaVM returned null");
+ return m_javaLoader; // null-ref
+ }
+
+ try
+ {
+ jvmaccess::VirtualMachine::AttachGuard aGuard2(
+ xVirtualMachine->getVirtualMachine());
+ JNIEnv * pJNIEnv = aGuard2.getEnvironment();
+
+ // instantiate the java JavaLoader
+ jclass jcClassLoader = pJNIEnv->FindClass("java/lang/ClassLoader");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not find class java/lang/ClassLoader");
+ jmethodID jmLoadClass = pJNIEnv->GetMethodID(
+ jcClassLoader, "loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not find method java/lang/ClassLoader.loadClass");
+ jvalue arg;
+ arg.l = pJNIEnv->NewStringUTF(
+ "com.sun.star.comp.loader.JavaLoader");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not create string");
+ jclass jcJavaLoader = static_cast< jclass >(
+ pJNIEnv->CallObjectMethodA(
+ static_cast< jobject >(xVirtualMachine->getClassLoader()),
+ jmLoadClass, &arg));
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - could not find class com/sun/star/comp/loader/JavaLoader");
+ jmethodID jmJavaLoader_init = pJNIEnv->GetMethodID(jcJavaLoader, "<init>", "()V");
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - instantiation of com.sun.star.comp.loader.JavaLoader failed");
+ jobject joJavaLoader = pJNIEnv->NewObject(jcJavaLoader, jmJavaLoader_init);
+ if(pJNIEnv->ExceptionOccurred())
+ throw RuntimeException(
+ "javaloader error - instantiation of com.sun.star.comp.loader.JavaLoader failed");
+
+ // map the java JavaLoader to this environment
+ OUString sJava("java");
+ uno_getEnvironment(&pJava_environment, sJava.pData,
+ xVirtualMachine.get());
+ if(!pJava_environment)
+ throw RuntimeException(
+ "javaloader error - no Java environment available");
+
+ // why is there no convenient constructor?
+ OUString sCppu_current_lb_name(CPPU_CURRENT_LANGUAGE_BINDING_NAME);
+ uno_getEnvironment(&pUno_environment, sCppu_current_lb_name.pData, nullptr);
+ if(!pUno_environment)
+ throw RuntimeException(
+ "javaloader error - no C++ environment available");
+
+ Mapping java_curr(pJava_environment, pUno_environment);
+ if(!java_curr.is())
+ throw RuntimeException(
+ "javaloader error - no mapping from java to C++ ");
+
+ // release java environment
+ pJava_environment->release(pJava_environment);
+ pJava_environment = nullptr;
+
+ // release uno environment
+ pUno_environment->release(pUno_environment);
+ pUno_environment = nullptr;
+
+ cppu::UnoType<XImplementationLoader>::get().
+ getDescription(reinterpret_cast<typelib_TypeDescription **>(&pType_XImplementationLoader));
+ if(!pType_XImplementationLoader)
+ throw RuntimeException(
+ "javaloader error - no type information for XImplementationLoader");
+
+ m_javaLoader.set(static_cast<XImplementationLoader *>(java_curr.mapInterface(joJavaLoader, pType_XImplementationLoader)));
+ pJNIEnv->DeleteLocalRef( joJavaLoader );
+ if(!m_javaLoader.is())
+ throw RuntimeException(
+ "javaloader error - mapping of java XImplementationLoader to c++ failed");
+
+ typelib_typedescription_release(reinterpret_cast<typelib_TypeDescription *>(pType_XImplementationLoader));
+ pType_XImplementationLoader = nullptr;
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException",
+ getXWeak(), anyEx );
+ }
+
+ // set the service manager at the javaloader
+ css::uno::Reference<XInitialization> javaLoader_XInitialization(m_javaLoader, UNO_QUERY_THROW);
+
+ Any any;
+ any <<= m_xComponentContext->getServiceManager();
+
+ javaLoader_XInitialization->initialize(Sequence<Any>(&any, 1));
+ }
+ catch(RuntimeException &) {
+ if(pJava_environment)
+ pJava_environment->release(pJava_environment);
+
+ if(pUno_environment)
+ pUno_environment->release(pUno_environment);
+
+ if(pType_XImplementationLoader)
+ typelib_typedescription_release(
+ reinterpret_cast<typelib_TypeDescription *>(pType_XImplementationLoader));
+ throw;
+ }
+ SAL_INFO("stoc", "javaloader.cxx: mapped javaloader - 0x" << m_javaLoader.get());
+ return m_javaLoader;
+}
+
+JavaComponentLoader::JavaComponentLoader(css::uno::Reference<XComponentContext> xCtx)
+ : WeakComponentImplHelper(m_aMutex)
+ , m_xComponentContext(std::move(xCtx))
+{
+
+}
+
+// XServiceInfo
+OUString SAL_CALL JavaComponentLoader::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.JavaComponentLoader";
+}
+
+sal_Bool SAL_CALL JavaComponentLoader::supportsService(const OUString & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence<OUString> SAL_CALL JavaComponentLoader::getSupportedServiceNames()
+{
+ return { "com.sun.star.loader.Java", "com.sun.star.loader.Java2" };
+}
+
+
+// XImplementationLoader
+sal_Bool SAL_CALL JavaComponentLoader::writeRegistryInfo(
+ const css::uno::Reference<XRegistryKey> & xKey, const OUString & blabla,
+ const OUString & rLibName)
+{
+ OUString remoteArg(blabla);
+ const css::uno::Reference<XImplementationLoader> & loader = getJavaLoader(remoteArg);
+ if (!loader.is())
+ throw CannotRegisterImplementationException("Could not create Java implementation loader");
+ return loader->writeRegistryInfo(xKey, remoteArg, rLibName);
+}
+
+css::uno::Reference<XInterface> SAL_CALL JavaComponentLoader::activate(
+ const OUString & rImplName, const OUString & blabla, const OUString & rLibName,
+ const css::uno::Reference<XRegistryKey> & xKey)
+{
+ OUString remoteArg(blabla);
+ if (rImplName.isEmpty() && blabla.isEmpty() && rLibName.isEmpty())
+ {
+ // preload JVM was requested
+ (void)getJavaLoader(remoteArg);
+ return css::uno::Reference<XInterface>();
+ }
+
+ const css::uno::Reference<XImplementationLoader> & loader = getJavaLoader(remoteArg);
+ if (!loader.is())
+ throw CannotActivateFactoryException("Could not create Java implementation loader");
+ return loader->activate(rImplName, remoteArg, rLibName, xKey);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_JavaComponentLoader_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
+{
+ try {
+ return cppu::acquire(new JavaComponentLoader(context));
+ }
+ catch(const RuntimeException & runtimeException) {
+ SAL_INFO(
+ "stoc",
+ "could not init javaloader due to " << runtimeException);
+ throw;
+ }
+}
+
+} //end namespace
+
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/interact.cxx b/stoc/source/javavm/interact.cxx
new file mode 100644
index 0000000000..49f223383a
--- /dev/null
+++ b/stoc/source/javavm/interact.cxx
@@ -0,0 +1,108 @@
+/* -*- 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 "interact.hxx"
+
+#include <com/sun/star/task/XInteractionAbort.hpp>
+#include <com/sun/star/task/XInteractionRetry.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <mutex>
+#include <utility>
+
+namespace com::sun::star::task { class XInteractionContinuation; }
+
+using stoc_javavm::InteractionRequest;
+
+namespace {
+
+class AbortContinuation:
+ public cppu::WeakImplHelper<css::task::XInteractionAbort>
+{
+public:
+ AbortContinuation() {}
+ AbortContinuation(const AbortContinuation&) = delete;
+ AbortContinuation& operator=(const AbortContinuation&)= delete;
+
+ virtual void SAL_CALL select() override {}
+
+private:
+ virtual ~AbortContinuation() override {}
+};
+
+}
+
+class InteractionRequest::RetryContinuation:
+ public cppu::WeakImplHelper<css::task::XInteractionRetry>
+{
+public:
+ RetryContinuation(): m_bSelected(false) {}
+ RetryContinuation(const RetryContinuation&) = delete;
+ RetryContinuation& operator=(const RetryContinuation&) = delete;
+
+ virtual void SAL_CALL select() override;
+
+ bool isSelected() const;
+
+private:
+ virtual ~RetryContinuation() override {}
+
+ mutable std::mutex m_aMutex;
+ bool m_bSelected;
+};
+
+void SAL_CALL InteractionRequest::RetryContinuation::select()
+{
+ std::scoped_lock aGuard(m_aMutex);
+ m_bSelected = true;
+}
+
+bool InteractionRequest::RetryContinuation::isSelected() const
+{
+ std::scoped_lock aGuard(m_aMutex);
+ return m_bSelected;
+}
+
+InteractionRequest::InteractionRequest(css::uno::Any aRequest):
+ m_aRequest(std::move(aRequest))
+{
+ m_xRetryContinuation = new RetryContinuation;
+ m_aContinuations = { new AbortContinuation, m_xRetryContinuation };
+}
+
+css::uno::Any SAL_CALL InteractionRequest::getRequest()
+{
+ return m_aRequest;
+}
+
+css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > >
+SAL_CALL InteractionRequest::getContinuations()
+{
+ return m_aContinuations;
+}
+
+bool InteractionRequest::retry() const
+{
+ return m_xRetryContinuation.is() && m_xRetryContinuation->isSelected();
+}
+
+InteractionRequest::~InteractionRequest()
+{}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/interact.hxx b/stoc/source/javavm/interact.hxx
new file mode 100644
index 0000000000..42fa373a33
--- /dev/null
+++ b/stoc/source/javavm/interact.hxx
@@ -0,0 +1,67 @@
+/* -*- 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_STOC_SOURCE_JAVAVM_INTERACT_HXX
+#define INCLUDED_STOC_SOURCE_JAVAVM_INTERACT_HXX
+
+#include <com/sun/star/task/XInteractionRequest.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star::task {
+ class XInteractionContinuation;
+}
+
+namespace stoc_javavm {
+
+class InteractionRequest:
+ public cppu::WeakImplHelper< css::task::XInteractionRequest >
+{
+public:
+ explicit InteractionRequest(css::uno::Any aRequest);
+
+ virtual css::uno::Any SAL_CALL getRequest() override;
+
+ virtual css::uno::Sequence< css::uno::Reference<
+ css::task::XInteractionContinuation > > SAL_CALL
+ getContinuations() override;
+
+ bool retry() const;
+
+private:
+ class RetryContinuation;
+
+ InteractionRequest(InteractionRequest const &) = delete;
+ void operator =(const InteractionRequest&) = delete;
+
+ virtual ~InteractionRequest() override;
+
+ css::uno::Any m_aRequest;
+ css::uno::Sequence< css::uno::Reference<
+ css::task::XInteractionContinuation > > m_aContinuations;
+ rtl::Reference< RetryContinuation > m_xRetryContinuation;
+};
+
+}
+
+#endif // INCLUDED_STOC_SOURCE_JAVAVM_INTERACT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/javavm.component b/stoc/source/javavm/javavm.component
new file mode 100644
index 0000000000..71379052b8
--- /dev/null
+++ b/stoc/source/javavm/javavm.component
@@ -0,0 +1,28 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.JavaVirtualMachine"
+ constructor="stoc_JavaVM_get_implementation"
+ single-instance="true">
+ <service name="com.sun.star.java.JavaVirtualMachine"/>
+ <singleton name="com.sun.star.java.theJavaVirtualMachine"/>
+ </implementation>
+</component>
diff --git a/stoc/source/javavm/javavm.cxx b/stoc/source/javavm/javavm.cxx
new file mode 100644
index 0000000000..a1fedd1d2d
--- /dev/null
+++ b/stoc/source/javavm/javavm.cxx
@@ -0,0 +1,1416 @@
+/* -*- 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 "javavm.hxx"
+
+#include "interact.hxx"
+#include "jvmargs.hxx"
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/java/JavaNotFoundException.hpp>
+#include <com/sun/star/java/InvalidJavaSettingsException.hpp>
+#include <com/sun/star/java/RestartRequiredException.hpp>
+#include <com/sun/star/java/JavaDisabledException.hpp>
+#include <com/sun/star/java/JavaVMCreationFailureException.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#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/XComponentContext.hpp>
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/util/theMacroExpander.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <jvmaccess/classpath.hxx>
+#include <jvmaccess/unovirtualmachine.hxx>
+#include <jvmaccess/virtualmachine.hxx>
+#include <rtl/process.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <sal/log.hxx>
+#include <uno/current_context.hxx>
+#include <jvmfwk/framework.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <jni.h>
+
+#include <stack>
+#include <string.h>
+#include <time.h>
+#include <memory>
+#include <utility>
+#include <vector>
+
+// Properties of the javavm can be put
+// as a comma separated list in this
+// environment variable
+#ifdef UNIX
+#define TIMEZONE "MEZ"
+#else
+#define TIMEZONE "MET"
+#endif
+
+#ifdef MACOSX
+#include <premac.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <postmac.h>
+#endif
+
+/* Within this implementation of the com.sun.star.java.JavaVirtualMachine
+ * service and com.sun.star.java.theJavaVirtualMachine singleton, the method
+ * com.sun.star.java.XJavaVM.getJavaVM relies on the following:
+ * 1 The string "$URE_INTERNAL_JAVA_DIR/" is expanded via the
+ * com.sun.star.util.theMacroExpander singleton into an internal (see the
+ * com.sun.star.uri.ExternalUriReferenceTranslator service), hierarchical URI
+ * reference relative to which the URE JAR files can be addressed.
+ * 2 The string "$URE_INTERNAL_JAVA_CLASSPATH" is either not expandable via the
+ * com.sun.star.util.theMacroExpander singleton
+ * (com.sun.star.lang.IllegalArgumentException), or is expanded via the
+ * com.sun.star.util.theMacroExpander singleton into a list of zero or more
+ * internal (see the com.sun.star.uri.ExternalUriReferenceTranslator service)
+ * URIs, where any space characters (U+0020) are ignored (and, in particular,
+ * separate adjacent URIs).
+ * If either of these requirements is not met, getJavaVM raises a
+ * com.sun.star.uno.RuntimeException.
+ */
+
+using stoc_javavm::JavaVirtualMachine;
+
+namespace {
+
+
+class NoJavaIniException: public css::uno::Exception
+{
+};
+
+typedef std::stack< jvmaccess::VirtualMachine::AttachGuard * > GuardStack;
+
+extern "C" {
+
+static void destroyAttachGuards(void * pData)
+{
+ GuardStack * pStack = static_cast< GuardStack * >(pData);
+ if (pStack != nullptr)
+ {
+ while (!pStack->empty())
+ {
+ delete pStack->top();
+ pStack->pop();
+ }
+ delete pStack;
+ }
+}
+
+}
+
+bool askForRetry(css::uno::Any const & rException)
+{
+ if (comphelper::IsContextFlagActive("DontEnableJava"))
+ return false;
+
+ css::uno::Reference< css::uno::XCurrentContext > xContext(
+ css::uno::getCurrentContext());
+ if (xContext.is())
+ {
+ css::uno::Reference< css::task::XInteractionHandler > xHandler;
+ xContext->getValueByName("java-vm.interaction-handler")
+ >>= xHandler;
+ if (xHandler.is())
+ {
+ rtl::Reference< stoc_javavm::InteractionRequest > xRequest(
+ new stoc_javavm::InteractionRequest(rException));
+ xHandler->handle(xRequest);
+ return xRequest->retry();
+ }
+ }
+ return false;
+}
+
+// Only gets the properties if the "Proxy Server" entry in the option dialog is
+// set to manual (i.e. not to none)
+/// @throws css::uno::Exception
+void getINetPropsFromConfig(stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx )
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry = xSMgr->createInstanceWithContext(
+ "com.sun.star.configuration.ConfigurationRegistry",
+ xCtx );
+ if(!xConfRegistry.is()) throw css::uno::RuntimeException("javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open("org.openoffice.Inet", true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey = xConfRegistry_simple->getRootKey();
+
+// if ooInetProxyType is not 0 then read the settings
+ css::uno::Reference<css::registry::XRegistryKey> proxyEnable= xRegistryRootKey->openKey("Settings/ooInetProxyType");
+ if( proxyEnable.is() && 0 != proxyEnable->getLongValue())
+ {
+ // read http proxy name
+ css::uno::Reference<css::registry::XRegistryKey> httpProxy_name = xRegistryRootKey->openKey("Settings/ooInetHTTPProxyName");
+ if(httpProxy_name.is() && !httpProxy_name->getStringValue().isEmpty()) {
+ OUString httpHost = "http.proxyHost=" + httpProxy_name->getStringValue();
+
+ // read http proxy port
+ css::uno::Reference<css::registry::XRegistryKey> httpProxy_port = xRegistryRootKey->openKey("Settings/ooInetHTTPProxyPort");
+ if(httpProxy_port.is() && httpProxy_port->getLongValue()) {
+ OUString httpPort = "http.proxyPort=" + OUString::number(httpProxy_port->getLongValue());
+
+ pjvm->pushProp(httpHost);
+ pjvm->pushProp(httpPort);
+ }
+ }
+
+ // read https proxy name
+ css::uno::Reference<css::registry::XRegistryKey> httpsProxy_name = xRegistryRootKey->openKey("Settings/ooInetHTTPSProxyName");
+ if(httpsProxy_name.is() && !httpsProxy_name->getStringValue().isEmpty()) {
+ OUString httpsHost = "https.proxyHost=" + httpsProxy_name->getStringValue();
+
+ // read https proxy port
+ css::uno::Reference<css::registry::XRegistryKey> httpsProxy_port = xRegistryRootKey->openKey("Settings/ooInetHTTPSProxyPort");
+ if(httpsProxy_port.is() && httpsProxy_port->getLongValue()) {
+ OUString httpsPort = "https.proxyPort=" + OUString::number(httpsProxy_port->getLongValue());
+
+ pjvm->pushProp(httpsHost);
+ pjvm->pushProp(httpsPort);
+ }
+ }
+
+ // read nonProxyHosts
+ css::uno::Reference<css::registry::XRegistryKey> nonProxies_name = xRegistryRootKey->openKey("Settings/ooInetNoProxy");
+ if(nonProxies_name.is() && !nonProxies_name->getStringValue().isEmpty()) {
+ OUString value = nonProxies_name->getStringValue();
+ // replace the separator ";" by "|"
+ value = value.replace(';', '|');
+
+ OUString httpNonProxyHosts = "http.nonProxyHosts=" + value;
+
+ pjvm->pushProp(httpNonProxyHosts);
+ }
+ }
+ xConfRegistry_simple->close();
+}
+
+/// @throws css::uno::Exception
+void getDefaultLocaleFromConfig(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx )
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry =
+ xSMgr->createInstanceWithContext( "com.sun.star.configuration.ConfigurationRegistry", xCtx );
+ if(!xConfRegistry.is())
+ throw css::uno::RuntimeException(
+ "javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(
+ xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open("org.openoffice.Setup", true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey = xConfRegistry_simple->getRootKey();
+
+ // Since 1.7 Java knows DISPLAY and FORMAT locales, which match our UI and
+ // system locale. See
+ // http://hg.openjdk.java.net/jdk8u/jdk8u-dev/jdk/file/569b1b644416/src/share/classes/java/util/Locale.java
+ // https://docs.oracle.com/javase/tutorial/i18n/locale/scope.html
+ // https://docs.oracle.com/javase/7/docs/api/java/util/Locale.html
+
+ // Read UI language/locale.
+ css::uno::Reference<css::registry::XRegistryKey> xUILocale = xRegistryRootKey->openKey("L10N/ooLocale");
+ if(xUILocale.is() && !xUILocale->getStringValue().isEmpty()) {
+ LanguageTag aLanguageTag( xUILocale->getStringValue());
+ OUString language;
+ OUString script;
+ OUString country;
+ // Java knows nothing but plain old ISO codes, unless Locale.Builder or
+ // Locale.forLanguageTag() are used, or non-standardized variant field
+ // content which we ignore.
+ aLanguageTag.getIsoLanguageScriptCountry( language, script, country);
+
+ if(!language.isEmpty()) {
+ OUString prop = "user.language=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ // As of Java 7 also script is supported.
+ if(!script.isEmpty()) {
+ OUString prop = "user.script=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country=" + country;
+ pjvm->pushProp(prop);
+ }
+
+ // Java 7 DISPLAY category is our UI language/locale.
+ if(!language.isEmpty()) {
+ OUString prop = "user.language.display=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ if(!script.isEmpty()) {
+ OUString prop = "user.script.display=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country.display=" + country;
+ pjvm->pushProp(prop);
+ }
+ }
+
+ // Read system locale.
+ css::uno::Reference<css::registry::XRegistryKey> xLocale = xRegistryRootKey->openKey("L10N/ooSetupSystemLocale");
+ if(xLocale.is() && !xLocale->getStringValue().isEmpty()) {
+ LanguageTag aLanguageTag( xLocale->getStringValue());
+ OUString language;
+ OUString script;
+ OUString country;
+ // Java knows nothing but plain old ISO codes, unless Locale.Builder or
+ // Locale.forLanguageTag() are used, or non-standardized variant field
+ // content which we ignore.
+ aLanguageTag.getIsoLanguageScriptCountry( language, script, country);
+
+ // Java 7 FORMAT category is our system locale.
+ if(!language.isEmpty()) {
+ OUString prop = "user.language.format=" + language;
+ pjvm->pushProp(prop);
+ }
+
+ if(!script.isEmpty()) {
+ OUString prop = "user.script.format=" + script;
+ pjvm->pushProp(prop);
+ }
+
+ if(!country.isEmpty()) {
+ OUString prop = "user.country.format=" + country;
+ pjvm->pushProp(prop);
+ }
+ }
+
+ xConfRegistry_simple->close();
+}
+
+/// @throws css::uno::Exception
+void getJavaPropsFromSafetySettings(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext> &xCtx)
+{
+ css::uno::Reference<css::uno::XInterface> xConfRegistry =
+ xSMgr->createInstanceWithContext(
+ "com.sun.star.configuration.ConfigurationRegistry",
+ xCtx);
+ if(!xConfRegistry.is())
+ throw css::uno::RuntimeException(
+ "javavm.cxx: couldn't get ConfigurationRegistry", nullptr);
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xConfRegistry_simple(
+ xConfRegistry, css::uno::UNO_QUERY_THROW);
+ xConfRegistry_simple->open(
+ "org.openoffice.Office.Java",
+ true, false);
+ css::uno::Reference<css::registry::XRegistryKey> xRegistryRootKey =
+ xConfRegistry_simple->getRootKey();
+
+ if (xRegistryRootKey.is())
+ {
+ css::uno::Reference<css::registry::XRegistryKey> key_NetAccess= xRegistryRootKey->openKey("VirtualMachine/NetAccess");
+ if (key_NetAccess.is())
+ {
+ sal_Int32 val= key_NetAccess->getLongValue();
+ OUString sVal;
+ switch( val)
+ {
+ case 0: sVal = "host";
+ break;
+ case 1: sVal = "unrestricted";
+ break;
+ case 3: sVal = "none";
+ break;
+ }
+ OUString sProperty = "appletviewer.security.mode=" + sVal;
+ pjvm->pushProp(sProperty);
+ }
+ css::uno::Reference<css::registry::XRegistryKey> key_CheckSecurity= xRegistryRootKey->openKey(
+ "VirtualMachine/Security");
+ if( key_CheckSecurity.is())
+ {
+ bool val = static_cast<bool>(key_CheckSecurity->getLongValue());
+ OUString sProperty("stardiv.security.disableSecurity=");
+ if( val)
+ sProperty += "false";
+ else
+ sProperty += "true";
+ pjvm->pushProp( sProperty);
+ }
+ }
+ xConfRegistry_simple->close();
+}
+
+void setTimeZone(stoc_javavm::JVM * pjvm) noexcept {
+ /* A Bug in the Java function
+ ** struct Hjava_util_Properties * java_lang_System_initProperties(
+ ** struct Hjava_lang_System *this,
+ ** struct Hjava_util_Properties *props);
+ ** This function doesn't detect MEZ, MET or "W. Europe Standard Time"
+ */
+ struct tm *tmData;
+ time_t clock = time(nullptr);
+ tzset();
+ tmData = localtime(&clock);
+#ifdef MACOSX
+ char * p = tmData->tm_zone;
+#elif defined(_MSC_VER)
+ char * p = _tzname[0];
+ (void)tmData;
+#else
+ char * p = tzname[0];
+ (void)tmData;
+#endif
+
+ if (!strcmp(TIMEZONE, p))
+ pjvm->pushProp("user.timezone=ECT");
+}
+
+/// @throws css::uno::Exception
+void initVMConfiguration(
+ stoc_javavm::JVM * pjvm,
+ const css::uno::Reference<css::lang::XMultiComponentFactory> & xSMgr,
+ const css::uno::Reference<css::uno::XComponentContext > &xCtx)
+{
+ stoc_javavm::JVM jvm;
+ try {
+ getINetPropsFromConfig(&jvm, xSMgr, xCtx);
+ }
+ catch(const css::uno::Exception & exception) {
+ SAL_INFO("stoc", "can not get INETProps because of " << exception);
+ }
+
+ try {
+ getDefaultLocaleFromConfig(&jvm, xSMgr,xCtx);
+ }
+ catch(const css::uno::Exception & exception) {
+ SAL_INFO("stoc", "can not get locale because of " << exception);
+ }
+
+ try
+ {
+ getJavaPropsFromSafetySettings(&jvm, xSMgr, xCtx);
+ }
+ catch(const css::uno::Exception & exception) {
+ SAL_INFO("stoc", "couldn't get safety settings because of " << exception);
+ }
+
+ *pjvm= jvm;
+
+ // rhbz#1285356, native look will be gtk2, which crashes
+ // when gtk3 is already loaded. Until there is a solution
+ // java-side force look and feel to something that doesn't
+ // crash when we are using gtk3
+ if (getenv("STOC_FORCE_SYSTEM_LAF"))
+ pjvm->pushProp("swing.systemlaf=javax.swing.plaf.metal.MetalLookAndFeel");
+
+ setTimeZone(pjvm);
+}
+
+class DetachCurrentThread {
+public:
+ explicit DetachCurrentThread(JavaVM * jvm): m_jvm(jvm) {}
+
+ ~DetachCurrentThread() {
+#ifdef MACOSX
+ // tdf#101376 don't detach thread if it is the main thread on macOS
+ // On macOS, many AWT classes do their work on the main thread
+ // deep in native methods in the java.awt.* classes. The problem
+ // is that Oracle's and OpenJDK's JVMs don't bracket their
+ // "perform on main thread" native calls with "attach/detach
+ // current thread" calls to the JVM.
+ if (CFRunLoopGetCurrent() != CFRunLoopGetMain())
+#endif
+ if (m_jvm->DetachCurrentThread() != 0) {
+ OSL_ASSERT(false);
+ }
+ }
+
+ DetachCurrentThread(const DetachCurrentThread&) = delete;
+ DetachCurrentThread& operator=(const DetachCurrentThread&) = delete;
+
+private:
+ JavaVM * m_jvm;
+};
+
+}
+
+JavaVirtualMachine::JavaVirtualMachine(
+ css::uno::Reference< css::uno::XComponentContext > xContext):
+ WeakComponentImplHelper(m_aMutex),
+ m_xContext(std::move(xContext)),
+ m_bDisposed(false),
+ m_pJavaVm(nullptr),
+ m_aAttachGuards(destroyAttachGuards) // TODO check for validity
+{}
+
+void SAL_CALL
+JavaVirtualMachine::initialize(css::uno::Sequence< css::uno::Any > const &
+ rArguments)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", getXWeak());
+ if (m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "bad call to initialize",
+ getXWeak());
+ css::beans::NamedValue val;
+ if (rArguments.getLength() == 1 && (rArguments[0] >>= val) && val.Name == "UnoVirtualMachine" )
+ {
+ OSL_ENSURE(
+ sizeof (sal_Int64) >= sizeof (jvmaccess::UnoVirtualMachine *),
+ "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::UnoVirtualMachine * >(nullptr));
+ val.Value >>= nPointer;
+ m_xUnoVirtualMachine =
+ reinterpret_cast< jvmaccess::UnoVirtualMachine * >(nPointer);
+ } else {
+ OSL_ENSURE(
+ sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *),
+ "Pointer cannot be represented as sal_Int64");
+ sal_Int64 nPointer = reinterpret_cast< sal_Int64 >(
+ static_cast< jvmaccess::VirtualMachine * >(nullptr));
+ if (rArguments.getLength() == 1)
+ rArguments[0] >>= nPointer;
+ rtl::Reference< jvmaccess::VirtualMachine > vm(
+ reinterpret_cast< jvmaccess::VirtualMachine * >(nPointer));
+ if (vm.is()) {
+ try {
+ m_xUnoVirtualMachine = new jvmaccess::UnoVirtualMachine(vm, nullptr);
+ } catch (jvmaccess::UnoVirtualMachine::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::UnoVirtualMachine::CreationException",
+ getXWeak(), anyEx );
+ }
+ }
+ }
+ if (!m_xUnoVirtualMachine.is()) {
+ throw css::lang::IllegalArgumentException(
+ "sequence of exactly one any containing either (a) a"
+ " com.sun.star.beans.NamedValue with Name"
+ " \"UnoVirtualMachine\" and Value a hyper representing a"
+ " non-null pointer to a jvmaccess:UnoVirtualMachine, or (b)"
+ " a hyper representing a non-null pointer to a"
+ " jvmaccess::VirtualMachine required",
+ getXWeak(), 0);
+ }
+ m_xVirtualMachine = m_xUnoVirtualMachine->getVirtualMachine();
+}
+
+OUString SAL_CALL JavaVirtualMachine::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.JavaVirtualMachine";
+}
+
+sal_Bool SAL_CALL
+JavaVirtualMachine::supportsService(OUString const & rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL
+JavaVirtualMachine::getSupportedServiceNames()
+{
+ return { "com.sun.star.java.JavaVirtualMachine" };
+}
+
+css::uno::Any SAL_CALL
+JavaVirtualMachine::getJavaVM(css::uno::Sequence< sal_Int8 > const & rProcessId)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", getXWeak());
+ css::uno::Sequence< sal_Int8 > aId(16);
+ rtl_getGlobalProcessId(reinterpret_cast< sal_uInt8 * >(aId.getArray()));
+ enum ReturnType {
+ RETURN_JAVAVM, RETURN_VIRTUALMACHINE, RETURN_UNOVIRTUALMACHINE };
+ ReturnType returnType =
+ rProcessId.getLength() == 17 && rProcessId[16] == 0
+ ? RETURN_VIRTUALMACHINE
+ : rProcessId.getLength() == 17 && rProcessId[16] == 1
+ ? RETURN_UNOVIRTUALMACHINE
+ : RETURN_JAVAVM;
+ css::uno::Sequence< sal_Int8 > aProcessId(rProcessId);
+ if (returnType != RETURN_JAVAVM)
+ aProcessId.realloc(16);
+ if (aId != aProcessId)
+ return css::uno::Any();
+
+ std::unique_ptr<JavaInfo> info;
+ while (!m_xVirtualMachine.is()) // retry until successful
+ {
+ stoc_javavm::JVM aJvm;
+ initVMConfiguration(&aJvm, m_xContext->getServiceManager(),
+ m_xContext);
+ const std::vector<OUString> & props = aJvm.getProperties();
+ std::vector<OUString> options;
+ options.reserve(props.size());
+ for (auto const& i : props)
+ {
+ options.push_back(i.startsWith("-") ? i : "-D" + i);
+ }
+
+ JNIEnv * pMainThreadEnv = nullptr;
+ javaFrameworkError errcode;
+
+ if (getenv("STOC_FORCE_NO_JRE"))
+ errcode = JFW_E_NO_SELECT;
+ else
+ errcode = jfw_startVM(info.get(), options, & m_pJavaVm,
+ & pMainThreadEnv);
+
+ bool bStarted = false;
+ switch (errcode)
+ {
+ case JFW_E_NONE: bStarted = true; break;
+ case JFW_E_NO_SELECT:
+ {
+ // No Java configured. We silently run the Java configuration
+ info.reset();
+ javaFrameworkError errFind;
+ if (getenv("STOC_FORCE_NO_JRE"))
+ errFind = JFW_E_NO_JAVA_FOUND;
+ else
+ errFind = jfw_findAndSelectJRE(&info);
+ if (errFind == JFW_E_NONE)
+ {
+ continue;
+ }
+ else if (errFind == JFW_E_NO_JAVA_FOUND)
+ {
+
+ //Warning MessageBox:
+ //%PRODUCTNAME requires a Java runtime environment (JRE) to perform this task.
+ //Please install a JRE and restart %PRODUCTNAME.
+ css::java::JavaNotFoundException exc(
+ "JavaVirtualMachine::getJavaVM failed because"
+ " No suitable JRE found!",
+ getXWeak());
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ else
+ {
+ //An unexpected error occurred
+ throw css::uno::RuntimeException(
+ "[JavaVirtualMachine]:An unexpected error occurred"
+ " while searching for a Java, " + OUString::number(errFind), nullptr);
+ }
+ }
+ case JFW_E_INVALID_SETTINGS:
+ {
+ //Warning MessageBox:
+ // The %PRODUCTNAME configuration has been changed. Under Tools
+ // - Options - %PRODUCTNAME - Java, select the Java runtime environment
+ // you want to have used by %PRODUCTNAME.
+ css::java::InvalidJavaSettingsException exc(
+ "JavaVirtualMachine::getJavaVM failed because"
+ " Java settings have changed!",
+ getXWeak());
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ case JFW_E_JAVA_DISABLED:
+ {
+ //QueryBox:
+ //%PRODUCTNAME requires a Java runtime environment (JRE) to perform
+ //this task. However, use of a JRE has been disabled. Do you want to
+ //enable the use of a JRE now?
+ css::java::JavaDisabledException exc(
+ "JavaVirtualMachine::getJavaVM failed because Java is disabled!",
+ getXWeak());
+ if( ! askForRetry(css::uno::Any(exc)))
+ return css::uno::Any();
+ continue;
+ }
+ case JFW_E_VM_CREATION_FAILED:
+ {
+ //If the creation failed because the JRE has been uninstalled then
+ //we search another one. As long as there is a javaldx, we should
+ //never come into this situation. javaldx checks always if the JRE
+ //still exist.
+ std::unique_ptr<JavaInfo> aJavaInfo;
+ if (JFW_E_NONE == jfw_getSelectedJRE(&aJavaInfo))
+ {
+ bool bExist = false;
+ if (JFW_E_NONE == jfw_existJRE(aJavaInfo.get(), &bExist))
+ {
+ if (!bExist
+ && ! (aJavaInfo->nRequirements & JFW_REQUIRE_NEEDRESTART))
+ {
+ info.reset();
+ javaFrameworkError errFind = jfw_findAndSelectJRE(
+ &info);
+ if (errFind == JFW_E_NONE)
+ {
+ continue;
+ }
+ }
+ }
+ }
+
+ //Error: %PRODUCTNAME requires a Java
+ //runtime environment (JRE) to perform this task. The selected JRE
+ //is defective. Please select another version or install a new JRE
+ //and select it under Tools - Options - %PRODUCTNAME - Java.
+ css::java::JavaVMCreationFailureException exc(
+ "JavaVirtualMachine::getJavaVM failed because Java is defective!",
+ getXWeak(), 0);
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ case JFW_E_RUNNING_JVM:
+ {
+ //This service should make sure that we do not start java twice.
+ OSL_ASSERT(false);
+ break;
+ }
+ case JFW_E_NEED_RESTART:
+ {
+ //Error:
+ //For the selected Java runtime environment to work properly,
+ //%PRODUCTNAME must be restarted. Please restart %PRODUCTNAME now.
+ css::java::RestartRequiredException exc(
+ "JavaVirtualMachine::getJavaVM failed because "
+ "Office must be restarted before Java can be used!",
+ getXWeak());
+ askForRetry(css::uno::Any(exc));
+ return css::uno::Any();
+ }
+ default:
+ //RuntimeException: error is somewhere in the java framework.
+ //An unexpected error occurred
+ throw css::uno::RuntimeException(
+ "[JavaVirtualMachine]:An unexpected error occurred"
+ " while starting Java!", nullptr);
+ }
+
+ if (bStarted)
+ {
+ {
+ DetachCurrentThread detach(m_pJavaVm);
+ // necessary to make debugging work; this thread will be
+ // suspended when the destructor of detach returns
+ m_xVirtualMachine = new jvmaccess::VirtualMachine(
+ m_pJavaVm, JNI_VERSION_1_2, true, pMainThreadEnv);
+ setUpUnoVirtualMachine(pMainThreadEnv);
+ }
+ // Listen for changes in the configuration (e.g. proxy settings):
+ // TODO this is done too late; changes to the configuration done
+ // after the above call to initVMConfiguration are lost
+ registerConfigChangesListener();
+
+ break;
+ }
+ }
+ if (!m_xUnoVirtualMachine.is()) {
+ try {
+ jvmaccess::VirtualMachine::AttachGuard guard(m_xVirtualMachine);
+ setUpUnoVirtualMachine(guard.getEnvironment());
+ } catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException occurred",
+ getXWeak(), anyEx );
+ }
+ }
+ switch (returnType) {
+ default: // RETURN_JAVAVM
+ if (m_pJavaVm == nullptr) {
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine service was initialized in a way"
+ " that the requested JavaVM pointer is not available",
+ getXWeak());
+ }
+ return css::uno::Any(reinterpret_cast< sal_IntPtr >(m_pJavaVm));
+ case RETURN_VIRTUALMACHINE:
+ OSL_ASSERT(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *));
+ return css::uno::Any(
+ reinterpret_cast< sal_Int64 >(
+ m_xUnoVirtualMachine->getVirtualMachine().get()));
+ case RETURN_UNOVIRTUALMACHINE:
+ OSL_ASSERT(sizeof (sal_Int64) >= sizeof (jvmaccess::VirtualMachine *));
+ return css::uno::Any(
+ reinterpret_cast< sal_Int64 >(m_xUnoVirtualMachine.get()));
+ }
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isVMStarted()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), getXWeak());
+ return m_xUnoVirtualMachine.is();
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isVMEnabled()
+{
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), getXWeak());
+ }
+// stoc_javavm::JVM aJvm;
+// initVMConfiguration(&aJvm, m_xContext->getServiceManager(), m_xContext);
+// return aJvm.isEnabled();
+ //ToDo
+ bool bEnabled = false;
+ if (jfw_getEnabled( & bEnabled) != JFW_E_NONE)
+ throw css::uno::RuntimeException();
+ return bEnabled;
+}
+
+sal_Bool SAL_CALL JavaVirtualMachine::isThreadAttached()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ OUString(), getXWeak());
+ // TODO isThreadAttached only returns true if the thread was attached via
+ // registerThread:
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ return pStack != nullptr && !pStack->empty();
+}
+
+void SAL_CALL JavaVirtualMachine::registerThread()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", getXWeak());
+ if (!m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::registerThread: null VirtualMachine",
+ getXWeak());
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ if (pStack == nullptr)
+ {
+ pStack = new GuardStack;
+ m_aAttachGuards.setData(pStack);
+ }
+ try
+ {
+ pStack->push(
+ new jvmaccess::VirtualMachine::AttachGuard(
+ m_xUnoVirtualMachine->getVirtualMachine()));
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "JavaVirtualMachine::registerThread: jvmaccess::"
+ "VirtualMachine::AttachGuard::CreationException",
+ getXWeak(), anyEx );
+ }
+}
+
+void SAL_CALL JavaVirtualMachine::revokeThread()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_bDisposed)
+ throw css::lang::DisposedException(
+ "", getXWeak());
+ if (!m_xUnoVirtualMachine.is())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::revokeThread: null VirtualMachine",
+ getXWeak());
+ GuardStack * pStack
+ = static_cast< GuardStack * >(m_aAttachGuards.getData());
+ if (pStack == nullptr || pStack->empty())
+ throw css::uno::RuntimeException(
+ "JavaVirtualMachine::revokeThread: no matching registerThread",
+ getXWeak());
+ delete pStack->top();
+ pStack->pop();
+}
+
+void SAL_CALL
+JavaVirtualMachine::disposing(css::lang::EventObject const & rSource)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ if (rSource.Source == m_xInetConfiguration)
+ m_xInetConfiguration.clear();
+ if (rSource.Source == m_xJavaConfiguration)
+ m_xJavaConfiguration.clear();
+}
+
+void SAL_CALL JavaVirtualMachine::elementInserted(
+ css::container::ContainerEvent const &)
+{}
+
+void SAL_CALL JavaVirtualMachine::elementRemoved(
+ css::container::ContainerEvent const &)
+{}
+
+// If a user changes the setting, for example for proxy settings, then this
+// function will be called from the configuration manager. Even if the .xml
+// file does not contain an entry yet and that entry has to be inserted, this
+// function will be called. We call java.lang.System.setProperty for the new
+// values.
+void SAL_CALL JavaVirtualMachine::elementReplaced(
+ css::container::ContainerEvent const & rEvent)
+{
+ // TODO Using the new value stored in rEvent is wrong here. If two threads
+ // receive different elementReplaced calls in quick succession, it is
+ // unspecified which changes the JVM's system properties last. A correct
+ // solution must atomically (i.e., protected by a mutex) read the latest
+ // value from the configuration and set it as a system property at the JVM.
+
+ OUString aAccessor;
+ rEvent.Accessor >>= aAccessor;
+ OUString aPropertyName;
+ OUString aPropertyValue;
+ bool bSecurityChanged = false;
+ if ( aAccessor == "ooInetProxyType" )
+ {
+ // Proxy none, manually
+ sal_Int32 value = 0;
+ rEvent.Element >>= value;
+ setINetSettingsInVM(value != 0);
+ return;
+ }
+ else if ( aAccessor == "ooInetHTTPProxyName" )
+ {
+ aPropertyName = "http.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetHTTPProxyPort" )
+ {
+ aPropertyName = "http.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetHTTPSProxyName" )
+ {
+ aPropertyName = "https.proxyHost";
+ rEvent.Element >>= aPropertyValue;
+ }
+ else if ( aAccessor == "ooInetHTTPSProxyPort" )
+ {
+ aPropertyName = "https.proxyPort";
+ sal_Int32 n = 0;
+ rEvent.Element >>= n;
+ aPropertyValue = OUString::number(n);
+ }
+ else if ( aAccessor == "ooInetNoProxy" )
+ {
+ aPropertyName = "http.nonProxyHosts";
+ rEvent.Element >>= aPropertyValue;
+ aPropertyValue = aPropertyValue.replace(';', '|');
+ }
+ else if ( aAccessor == "NetAccess" )
+ {
+ aPropertyName = "appletviewer.security.mode";
+ sal_Int32 n = 0;
+ if (rEvent.Element >>= n)
+ switch (n)
+ {
+ case 0:
+ aPropertyValue = "host";
+ break;
+ case 1:
+ aPropertyValue = "unrestricted";
+ break;
+ case 3:
+ aPropertyValue = "none";
+ break;
+ }
+ else
+ return;
+ bSecurityChanged = true;
+ }
+ else if ( aAccessor == "Security" )
+ {
+ aPropertyName = "stardiv.security.disableSecurity";
+ bool b;
+ if (rEvent.Element >>= b)
+ if (b)
+ aPropertyValue = "false";
+ else
+ aPropertyValue = "true";
+ else
+ return;
+ bSecurityChanged = true;
+ }
+ else
+ return;
+
+ rtl::Reference< jvmaccess::VirtualMachine > xVirtualMachine;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if (m_xUnoVirtualMachine.is()) {
+ xVirtualMachine = m_xUnoVirtualMachine->getVirtualMachine();
+ }
+ }
+ if (!xVirtualMachine.is())
+ return;
+
+ try
+ {
+ jvmaccess::VirtualMachine::AttachGuard aAttachGuard(
+ xVirtualMachine);
+ JNIEnv * pJNIEnv = aAttachGuard.getEnvironment();
+
+ // call java.lang.System.setProperty
+ // String setProperty( String key, String value)
+ jclass jcSystem= pJNIEnv->FindClass("java/lang/System");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/lang/System", nullptr);
+ jmethodID jmSetProps= pJNIEnv->GetStaticMethodID( jcSystem, "setProperty","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.setProperty", nullptr);
+
+ jstring jsPropName= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyName.getStr()), aPropertyName.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+
+ // remove the property if it does not have a value ( user left the dialog field empty)
+ // or if the port is set to 0
+ aPropertyValue= aPropertyValue.trim();
+ if( aPropertyValue.isEmpty() ||
+ ((aPropertyName == "http.proxyPort" /*|| aPropertyName == "socksProxyPort"*/) && aPropertyValue == "0")
+ )
+ {
+ // call java.lang.System.getProperties
+ jmethodID jmGetProps= pJNIEnv->GetStaticMethodID( jcSystem, "getProperties","()Ljava/util/Properties;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getProperties", nullptr);
+ jobject joProperties= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetProps);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.getProperties", nullptr);
+ // call java.util.Properties.remove
+ jclass jcProperties= pJNIEnv->FindClass("java/util/Properties");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/util/Properties", nullptr);
+ jmethodID jmRemove= pJNIEnv->GetMethodID( jcProperties, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.util.Properties.remove", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsPropName);
+ }
+ else
+ {
+ // Change the Value of the property
+ jstring jsPropValue= pJNIEnv->NewString( reinterpret_cast<jchar const *>(aPropertyValue.getStr()), aPropertyValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsPropName, jsPropValue);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+
+ // If the settings for Security and NetAccess changed then we have to notify the SandboxSecurity
+ // SecurityManager
+ // call System.getSecurityManager()
+ if (bSecurityChanged)
+ {
+ jmethodID jmGetSecur= pJNIEnv->GetStaticMethodID( jcSystem,"getSecurityManager","()Ljava/lang/SecurityManager;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getSecurityManager", nullptr);
+ jobject joSecur= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetSecur);
+ if (joSecur != nullptr)
+ {
+ // Make sure the SecurityManager is our SandboxSecurity
+ // FindClass("com.sun.star.lib.sandbox.SandboxSecurityManager" only worked at the first time
+ // this code was executed. Maybe it is a security feature. However, all attempts to debug the
+ // SandboxSecurity class (maybe the VM invokes checkPackageAccess) failed.
+// jclass jcSandboxSec= pJNIEnv->FindClass("com.sun.star.lib.sandbox.SandboxSecurity");
+// if(pJNIEnv->ExceptionOccurred()) throw RuntimeException("JNI:FindClass com.sun.star.lib.sandbox.SandboxSecurity");
+// jboolean bIsSand= pJNIEnv->IsInstanceOf( joSecur, jcSandboxSec);
+ // The SecurityManagers class Name must be com.sun.star.lib.sandbox.SandboxSecurity
+ jclass jcSec= pJNIEnv->GetObjectClass( joSecur);
+ jclass jcClass= pJNIEnv->FindClass("java/lang/Class");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java.lang.Class", nullptr);
+ jmethodID jmName= pJNIEnv->GetMethodID( jcClass,"getName","()Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.lang.Class.getName", nullptr);
+ jstring jsClass= static_cast<jstring>(pJNIEnv->CallObjectMethod( jcSec, jmName));
+ const jchar* jcharName= pJNIEnv->GetStringChars( jsClass, nullptr);
+ OUString sName(reinterpret_cast<sal_Unicode const *>(jcharName));
+ bool bIsSandbox;
+ bIsSandbox = sName == "com.sun.star.lib.sandbox.SandboxSecurity";
+ pJNIEnv->ReleaseStringChars( jsClass, jcharName);
+
+ if (bIsSandbox)
+ {
+ // call SandboxSecurity.reset
+ jmethodID jmReset= pJNIEnv->GetMethodID( jcSec,"reset","()V");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID com.sun.star.lib.sandbox.SandboxSecurity.reset", nullptr);
+ pJNIEnv->CallVoidMethod( joSecur, jmReset);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallVoidMethod com.sun.star.lib.sandbox.SandboxSecurity.reset", nullptr);
+ }
+ }
+ }
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::VirtualMachine::AttachGuard::CreationException",
+ getXWeak(), anyEx );
+ }
+}
+
+JavaVirtualMachine::~JavaVirtualMachine()
+{
+ if (m_xInetConfiguration.is())
+ // We should never get here, but just in case...
+ try
+ {
+ m_xInetConfiguration->removeContainerListener(this);
+ }
+ catch (css::uno::Exception &)
+ {
+ OSL_FAIL("com.sun.star.uno.Exception caught");
+ }
+ if (m_xJavaConfiguration.is())
+ // We should never get here, but just in case...
+ try
+ {
+ m_xJavaConfiguration->removeContainerListener(this);
+ }
+ catch (css::uno::Exception &)
+ {
+ OSL_FAIL("com.sun.star.uno.Exception caught");
+ }
+}
+
+void SAL_CALL JavaVirtualMachine::disposing()
+{
+ css::uno::Reference< css::container::XContainer > xContainer1;
+ css::uno::Reference< css::container::XContainer > xContainer2;
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ m_bDisposed = true;
+ xContainer1 = m_xInetConfiguration;
+ m_xInetConfiguration.clear();
+ xContainer2 = m_xJavaConfiguration;
+ m_xJavaConfiguration.clear();
+ }
+ if (xContainer1.is())
+ xContainer1->removeContainerListener(this);
+ if (xContainer2.is())
+ xContainer2->removeContainerListener(this);
+}
+
+/*We listen to changes in the configuration. For example, the user changes the proxy
+ settings in the options dialog (menu tools). Then we are notified of this change and
+ if the java vm is already running we change the properties (System.lang.System.setProperties)
+ through JNI.
+ To receive notifications this class implements XContainerListener.
+*/
+void JavaVirtualMachine::registerConfigChangesListener()
+{
+ try
+ {
+ css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
+ m_xContext->getValueByName(
+ "/singletons/com.sun.star.configuration.theDefaultProvider"),
+ css::uno::UNO_QUERY);
+
+ if (xConfigProvider.is())
+ {
+ // We register this instance as listener to changes in org.openoffice.Inet/Settings
+ // arguments for ConfigurationAccess
+ css::uno::Sequence<css::uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", css::uno::Any(OUString("org.openoffice.Inet/Settings"))},
+ {"depth", css::uno::Any(sal_Int32(-1))}
+ }));
+ m_xInetConfiguration.set(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments),
+ css::uno::UNO_QUERY);
+
+ if (m_xInetConfiguration.is())
+ m_xInetConfiguration->addContainerListener(this);
+
+ // now register as listener to changes in org.openoffice.Java/VirtualMachine
+ css::uno::Sequence<css::uno::Any> aArguments2(comphelper::InitAnyPropertySequence(
+ {
+ {"nodepath", css::uno::Any(OUString("org.openoffice.Office.Java/VirtualMachine"))},
+ {"depth", css::uno::Any(sal_Int32(-1))} // depth: -1 means unlimited
+ }));
+ m_xJavaConfiguration.set(
+ xConfigProvider->createInstanceWithArguments(
+ "com.sun.star.configuration.ConfigurationAccess",
+ aArguments2),
+ css::uno::UNO_QUERY);
+
+ if (m_xJavaConfiguration.is())
+ m_xJavaConfiguration->addContainerListener(this);
+ }
+ }catch(const css::uno::Exception & e)
+ {
+ SAL_INFO("stoc", "could not set up listener for Configuration because of >" << e << "<");
+ }
+}
+
+// param true: all Inet setting are set as Java Properties on a live VM.
+// false: the Java net properties are set to empty value.
+void JavaVirtualMachine::setINetSettingsInVM(bool set_reset)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ try
+ {
+ if (m_xUnoVirtualMachine.is())
+ {
+ jvmaccess::VirtualMachine::AttachGuard aAttachGuard(
+ m_xUnoVirtualMachine->getVirtualMachine());
+ JNIEnv * pJNIEnv = aAttachGuard.getEnvironment();
+
+ // The Java Properties
+ OUString sHttpProxyHost("http.proxyHost");
+ OUString sHttpProxyPort("http.proxyPort");
+ OUString sHttpNonProxyHosts("http.nonProxyHosts");
+
+ // create Java Properties as JNI strings
+ jstring jsHttpProxyHost= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpProxyHost.getStr()), sHttpProxyHost.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpProxyPort= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpProxyPort.getStr()), sHttpProxyPort.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ jstring jsHttpNonProxyHosts= pJNIEnv->NewString( reinterpret_cast<jchar const *>(sHttpNonProxyHosts.getStr()), sHttpNonProxyHosts.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+
+ // prepare java.lang.System.setProperty
+ jclass jcSystem= pJNIEnv->FindClass("java/lang/System");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/lang/System", nullptr);
+ jmethodID jmSetProps= pJNIEnv->GetStaticMethodID( jcSystem, "setProperty","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.setProperty", nullptr);
+
+ // call java.lang.System.getProperties
+ jmethodID jmGetProps= pJNIEnv->GetStaticMethodID( jcSystem, "getProperties","()Ljava/util/Properties;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetStaticMethodID java.lang.System.getProperties", nullptr);
+ jobject joProperties= pJNIEnv->CallStaticObjectMethod( jcSystem, jmGetProps);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.getProperties", nullptr);
+ // prepare java.util.Properties.remove
+ jclass jcProperties= pJNIEnv->FindClass("java/util/Properties");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:FindClass java/util/Properties", nullptr);
+
+ if (set_reset)
+ {
+ // Set all network properties with the VM
+ JVM jvm;
+ getINetPropsFromConfig( &jvm, m_xContext->getServiceManager(), m_xContext);
+ const ::std::vector< OUString> & Props = jvm.getProperties();
+
+ for( auto& prop : Props)
+ {
+ sal_Int32 index= prop.indexOf( '=');
+ std::u16string_view propName= prop.subView( 0, index);
+ OUString propValue= prop.copy( index + 1);
+
+ if (propName == sHttpProxyHost)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpProxyHost, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpProxyPort)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpProxyPort, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ else if( propName == sHttpNonProxyHosts)
+ {
+ jstring jsVal= pJNIEnv->NewString( reinterpret_cast<jchar const *>(propValue.getStr()), propValue.getLength());
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:NewString", nullptr);
+ pJNIEnv->CallStaticObjectMethod( jcSystem, jmSetProps, jsHttpNonProxyHosts, jsVal);
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:CallStaticObjectMethod java.lang.System.setProperty", nullptr);
+ }
+ }
+ }
+ else
+ {
+ // call java.util.Properties.remove
+ jmethodID jmRemove= pJNIEnv->GetMethodID( jcProperties, "remove", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ if(pJNIEnv->ExceptionOccurred()) throw css::uno::RuntimeException("JNI:GetMethodID java.util.Property.remove", nullptr);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpProxyHost);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpProxyPort);
+ pJNIEnv->CallObjectMethod( joProperties, jmRemove, jsHttpNonProxyHosts);
+ }
+ }
+ }
+ catch (css::uno::RuntimeException &)
+ {
+ OSL_FAIL("RuntimeException");
+ }
+ catch (jvmaccess::VirtualMachine::AttachGuard::CreationException &)
+ {
+ OSL_FAIL("jvmaccess::VirtualMachine::AttachGuard::CreationException");
+ }
+}
+
+void JavaVirtualMachine::setUpUnoVirtualMachine(JNIEnv * environment) {
+ css::uno::Reference< css::util::XMacroExpander > exp = css::util::theMacroExpander::get(m_xContext);
+ OUString baseUrl;
+ try {
+ baseUrl = exp->expandMacros("$URE_INTERNAL_JAVA_DIR/");
+ } catch (css::lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "css::lang::IllegalArgumentException",
+ getXWeak(), anyEx );
+ }
+ OUString classPath;
+ try {
+ classPath = exp->expandMacros("$URE_INTERNAL_JAVA_CLASSPATH");
+ } catch (css::lang::IllegalArgumentException &) {}
+ jclass class_URLClassLoader = environment->FindClass(
+ "java/net/URLClassLoader");
+ if (class_URLClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URLClassLoader = environment->GetMethodID(
+ class_URLClassLoader, "<init>", "([Ljava/net/URL;)V");
+ if (ctor_URLClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jclass class_URL = environment->FindClass("java/net/URL");
+ if (class_URL == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URL_1 = environment->GetMethodID(
+ class_URL, "<init>", "(Ljava/lang/String;)V");
+ if (ctor_URL_1 == nullptr) {
+ handleJniException(environment);
+ }
+ jvalue args[3];
+ args[0].l = environment->NewString(
+ reinterpret_cast< jchar const * >(baseUrl.getStr()),
+ static_cast< jsize >(baseUrl.getLength()));
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jobject base = environment->NewObjectA(class_URL, ctor_URL_1, args);
+ if (base == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_URL_2 = environment->GetMethodID(
+ class_URL, "<init>", "(Ljava/net/URL;Ljava/lang/String;)V");
+ if (ctor_URL_2 == nullptr) {
+ handleJniException(environment);
+ }
+ jobjectArray classpath = jvmaccess::ClassPath::translateToUrls(
+ m_xContext, environment, classPath);
+ if (classpath == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = base;
+ args[1].l = environment->NewStringUTF("unoloader.jar");
+ if (args[1].l == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewObjectA(class_URL, ctor_URL_2, args);
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewObjectArray(1, class_URL, args[0].l);
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jobject cl1 = environment->NewObjectA(
+ class_URLClassLoader, ctor_URLClassLoader, args);
+ if (cl1 == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID method_loadClass = environment->GetMethodID(
+ class_URLClassLoader, "loadClass",
+ "(Ljava/lang/String;)Ljava/lang/Class;");
+ if (method_loadClass == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = environment->NewStringUTF(
+ "com.sun.star.lib.unoloader.UnoClassLoader");
+ if (args[0].l == nullptr) {
+ handleJniException(environment);
+ }
+ jclass class_UnoClassLoader = static_cast< jclass >(
+ environment->CallObjectMethodA(cl1, method_loadClass, args));
+ if (class_UnoClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ jmethodID ctor_UnoClassLoader = environment->GetMethodID(
+ class_UnoClassLoader, "<init>",
+ "(Ljava/net/URL;[Ljava/net/URL;Ljava/lang/ClassLoader;)V");
+ if (ctor_UnoClassLoader == nullptr) {
+ handleJniException(environment);
+ }
+ args[0].l = base;
+ args[1].l = classpath;
+ args[2].l = cl1;
+ jobject cl2 = environment->NewObjectA(
+ class_UnoClassLoader, ctor_UnoClassLoader, args);
+ if (cl2 == nullptr) {
+ handleJniException(environment);
+ }
+ try {
+ m_xUnoVirtualMachine = new jvmaccess::UnoVirtualMachine(
+ m_xVirtualMachine, cl2);
+ } catch (jvmaccess::UnoVirtualMachine::CreationException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "jvmaccess::UnoVirtualMachine::CreationException",
+ getXWeak(), anyEx );
+ }
+}
+
+void JavaVirtualMachine::handleJniException(JNIEnv * environment) {
+#if defined DBG_UTIL
+ environment->ExceptionDescribe();
+#else
+ environment->ExceptionClear();
+#endif
+ throw css::uno::RuntimeException(
+ "JNI exception occurred",
+ getXWeak());
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_JavaVM_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new JavaVirtualMachine(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/javavm.hxx b/stoc/source/javavm/javavm.hxx
new file mode 100644
index 0000000000..b4f79d1f9f
--- /dev/null
+++ b/stoc/source/javavm/javavm.hxx
@@ -0,0 +1,147 @@
+/* -*- 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_STOC_SOURCE_JAVAVM_JAVAVM_HXX
+#define INCLUDED_STOC_SOURCE_JAVAVM_JAVAVM_HXX
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/java/XJavaThreadRegister_11.hpp>
+#include <com/sun/star/java/XJavaVM.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/thread.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star {
+ namespace container { class XContainer; }
+ namespace uno { class XComponentContext; }
+}
+namespace jvmaccess {
+ class UnoVirtualMachine;
+ class VirtualMachine;
+}
+
+namespace stoc_javavm {
+
+class JavaVirtualMachine:
+ private cppu::BaseMutex,
+ public cppu::WeakComponentImplHelper<
+ css::lang::XInitialization, css::lang::XServiceInfo, css::java::XJavaVM,
+ css::java::XJavaThreadRegister_11, css::container::XContainerListener>
+{
+public:
+ explicit JavaVirtualMachine(
+ css::uno::Reference<
+ css::uno::XComponentContext > xContext);
+
+ // XInitialization
+ virtual void SAL_CALL
+ initialize(css::uno::Sequence< css::uno::Any > const &
+ rArguments) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+
+ virtual sal_Bool SAL_CALL
+ supportsService(OUString const & rServiceName) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // XJavaVM
+ virtual css::uno::Any SAL_CALL
+ getJavaVM(css::uno::Sequence< sal_Int8 > const & rProcessId) override;
+
+ virtual sal_Bool SAL_CALL isVMStarted() override;
+
+ virtual sal_Bool SAL_CALL isVMEnabled() override;
+
+ // XJavaThreadRegister_11
+ virtual sal_Bool SAL_CALL isThreadAttached() override;
+
+ virtual void SAL_CALL registerThread() override;
+
+ virtual void SAL_CALL revokeThread() override;
+
+ // XContainerListener
+ virtual void SAL_CALL
+ disposing(css::lang::EventObject const & rSource) override;
+
+ virtual void SAL_CALL
+ elementInserted(css::container::ContainerEvent const & rEvent) override;
+
+ virtual void SAL_CALL
+ elementRemoved(css::container::ContainerEvent const & rEvent) override;
+
+ virtual void SAL_CALL
+ elementReplaced(css::container::ContainerEvent const & rEvent) override;
+
+private:
+ JavaVirtualMachine(JavaVirtualMachine const &) = delete;
+ void operator =(const JavaVirtualMachine&) = delete;
+
+ virtual ~JavaVirtualMachine() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ void registerConfigChangesListener();
+
+ void setINetSettingsInVM(bool set_reset);
+
+ void setUpUnoVirtualMachine(JNIEnv * environment);
+
+ void handleJniException(JNIEnv * environment);
+
+ css::uno::Reference< css::uno::XComponentContext >
+ m_xContext;
+
+ // the following are controlled by BaseMutex::m_aMutex:
+ bool m_bDisposed;
+ rtl::Reference< jvmaccess::VirtualMachine > m_xVirtualMachine;
+ rtl::Reference< jvmaccess::UnoVirtualMachine > m_xUnoVirtualMachine;
+ JavaVM * m_pJavaVm;
+ // If the first creation of Java failed and this flag is set then the
+ // next call to getJavaVM throws a RuntimException. This is useful when
+ // the second attempt to create Java might cause a crash.
+ css::uno::Reference< css::container::XContainer >
+ m_xInetConfiguration;
+ css::uno::Reference< css::container::XContainer >
+ m_xJavaConfiguration; // for Java settings
+
+ osl::ThreadData m_aAttachGuards;
+};
+
+}
+
+#endif // INCLUDED_STOC_SOURCE_JAVAVM_JAVAVM_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/jvmargs.cxx b/stoc/source/javavm/jvmargs.cxx
new file mode 100644
index 0000000000..f98f22ec0c
--- /dev/null
+++ b/stoc/source/javavm/jvmargs.cxx
@@ -0,0 +1,32 @@
+/* -*- 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 "jvmargs.hxx"
+#include <rtl/ustring.hxx>
+
+namespace stoc_javavm
+{
+JVM::JVM() noexcept //: _enabled(sal_False)
+{
+}
+
+void JVM::pushProp(const OUString& property) { _props.push_back(property); }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/javavm/jvmargs.hxx b/stoc/source/javavm/jvmargs.hxx
new file mode 100644
index 0000000000..adc41ffa15
--- /dev/null
+++ b/stoc/source/javavm/jvmargs.hxx
@@ -0,0 +1,58 @@
+/* -*- 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_STOC_SOURCE_JAVAVM_JVMARGS_HXX
+#define INCLUDED_STOC_SOURCE_JAVAVM_JVMARGS_HXX
+
+
+#include <vector>
+#include <rtl/ustring.hxx>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-attributes"
+#endif
+#include <jni.h>
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+extern "C" {
+ typedef jint JNICALL JNI_InitArgs_Type(void *);
+ typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
+
+}
+
+namespace stoc_javavm {
+
+ class JVM {
+ ::std::vector<OUString> _props;
+
+ public:
+ JVM() noexcept;
+
+ void pushProp(const OUString & uString);
+ const ::std::vector< OUString> & getProperties() const { return _props;}
+ };
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/loader/dllcomponentloader.cxx b/stoc/source/loader/dllcomponentloader.cxx
new file mode 100644
index 0000000000..43f20ad0a5
--- /dev/null
+++ b/stoc/source/loader/dllcomponentloader.cxx
@@ -0,0 +1,152 @@
+/* -*- 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 <rtl/ustring.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/shlib.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/bootstrap.hxx>
+
+#include <com/sun/star/loader/XImplementationLoader.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace com::sun::star::registry { class XRegistryKey; }
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::loader;
+using namespace css::lang;
+using namespace css::registry;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+class DllComponentLoader
+ : public WeakImplHelper< XImplementationLoader,
+ XInitialization,
+ XServiceInfo >
+{
+public:
+ explicit DllComponentLoader( const Reference<XComponentContext> & xCtx );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // XImplementationLoader
+ virtual Reference<XInterface> SAL_CALL activate( const OUString& implementationName, const OUString& implementationLoaderUrl, const OUString& locationUrl, const Reference<XRegistryKey>& xKey ) override;
+ virtual sal_Bool SAL_CALL writeRegistryInfo( const Reference<XRegistryKey>& xKey, const OUString& implementationLoaderUrl, const OUString& locationUrl ) override;
+
+private:
+ Reference<XMultiServiceFactory> m_xSMgr;
+};
+
+
+DllComponentLoader::DllComponentLoader( const Reference<XComponentContext> & xCtx )
+{
+ m_xSMgr.set( xCtx->getServiceManager(), UNO_QUERY );
+}
+
+OUString SAL_CALL DllComponentLoader::getImplementationName( )
+{
+ return "com.sun.star.comp.stoc.DLLComponentLoader";
+}
+
+sal_Bool SAL_CALL DllComponentLoader::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+Sequence<OUString> SAL_CALL DllComponentLoader::getSupportedServiceNames( )
+{
+ return { "com.sun.star.loader.SharedLibrary" };
+}
+
+
+void DllComponentLoader::initialize( const css::uno::Sequence< css::uno::Any >& )
+{
+ OSL_FAIL( "dllcomponentloader::initialize should not be called !" );
+// if( aArgs.getLength() != 1 )
+// {
+// throw IllegalArgumentException();
+// }
+
+// Reference< XMultiServiceFactory > rServiceManager;
+
+// if( aArgs.getConstArray()[0].getValueType().getTypeClass() == TypeClass_INTERFACE )
+// {
+// aArgs.getConstArray()[0] >>= rServiceManager;
+// }
+
+// if( !rServiceManager.is() )
+// {
+// throw IllegalArgumentException();
+// }
+
+// m_xSMgr = rServiceManager;
+}
+
+
+Reference<XInterface> SAL_CALL DllComponentLoader::activate(
+ const OUString & rImplName, const OUString &, const OUString & rLibName,
+ const Reference< XRegistryKey > & )
+{
+ return loadSharedLibComponentFactory(
+ cppu::bootstrap_expandUri(rLibName), OUString(), rImplName, m_xSMgr,
+ css::uno::Reference<css::registry::XRegistryKey>());
+}
+
+
+sal_Bool SAL_CALL DllComponentLoader::writeRegistryInfo(
+ const Reference< XRegistryKey > & xKey, const OUString &, const OUString & rLibName )
+{
+#ifdef DISABLE_DYNLOADING
+ (void) xKey;
+ (void) rLibName;
+ OSL_FAIL( "DllComponentLoader::writeRegistryInfo() should not be called I think?" );
+ return sal_False;
+#else
+ writeSharedLibComponentInfo(
+ cppu::bootstrap_expandUri(rLibName), OUString(), m_xSMgr, xKey );
+ return true;
+#endif
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_DLLComponentLoader_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new DllComponentLoader(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/namingservice/namingservice.component b/stoc/source/namingservice/namingservice.component
new file mode 100644
index 0000000000..3ba192e866
--- /dev/null
+++ b/stoc/source/namingservice/namingservice.component
@@ -0,0 +1,26 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.NamingService"
+ constructor="stoc_NamingService_Impl_get_implementation">
+ <service name="com.sun.star.uno.NamingService"/>
+ </implementation>
+</component>
diff --git a/stoc/source/namingservice/namingservice.cxx b/stoc/source/namingservice/namingservice.cxx
new file mode 100644
index 0000000000..acabb7370c
--- /dev/null
+++ b/stoc/source/namingservice/namingservice.cxx
@@ -0,0 +1,123 @@
+/* -*- 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/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/uno/XNamingService.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <mutex>
+#include <unordered_map>
+
+using namespace cppu;
+using namespace osl;
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::registry;
+
+
+namespace stoc_namingservice
+{
+
+typedef std::unordered_map< OUString, Reference<XInterface > > HashMap_OWString_Interface;
+
+namespace {
+
+class NamingService_Impl
+ : public WeakImplHelper < XServiceInfo, XNamingService >
+{
+ std::mutex aMutex;
+ HashMap_OWString_Interface aMap;
+public:
+ NamingService_Impl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override;
+ virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override;
+ virtual void SAL_CALL revokeObject( const OUString& Name ) override;
+};
+
+}
+
+
+
+NamingService_Impl::NamingService_Impl() {}
+
+// XServiceInfo
+OUString NamingService_Impl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.NamingService";
+}
+
+// XServiceInfo
+sal_Bool NamingService_Impl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > NamingService_Impl::getSupportedServiceNames()
+{
+ return { "com.sun.star.uno.NamingService" };
+}
+
+// XServiceInfo
+Reference< XInterface > NamingService_Impl::getRegisteredObject( const OUString& Name )
+{
+ std::scoped_lock aGuard( aMutex );
+ Reference< XInterface > xRet;
+ HashMap_OWString_Interface::iterator aIt = aMap.find( Name );
+ if( aIt != aMap.end() )
+ xRet = (*aIt).second;
+ return xRet;
+}
+
+// XServiceInfo
+void NamingService_Impl::registerObject( const OUString& Name, const Reference< XInterface >& Object )
+{
+ std::scoped_lock aGuard( aMutex );
+ aMap[ Name ] = Object;
+}
+
+// XServiceInfo
+void NamingService_Impl::revokeObject( const OUString& Name )
+{
+ std::scoped_lock aGuard( aMutex );
+ aMap.erase( Name );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_NamingService_Impl_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new stoc_namingservice::NamingService_Impl());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/proxy_factory/proxyfac.component b/stoc/source/proxy_factory/proxyfac.component
new file mode 100644
index 0000000000..b069f88dff
--- /dev/null
+++ b/stoc/source/proxy_factory/proxyfac.component
@@ -0,0 +1,26 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.reflection.ProxyFactory"
+ constructor="stoc_FactoryImpl_get_implementation" single-instance="true">
+ <service name="com.sun.star.reflection.ProxyFactory"/>
+ </implementation>
+</component>
diff --git a/stoc/source/proxy_factory/proxyfac.cxx b/stoc/source/proxy_factory/proxyfac.cxx
new file mode 100644
index 0000000000..6745d0163c
--- /dev/null
+++ b/stoc/source/proxy_factory/proxyfac.cxx
@@ -0,0 +1,411 @@
+/* -*- 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 <osl/interlck.h>
+#include <rtl/ref.hxx>
+#include <uno/dispatcher.hxx>
+#include <uno/data.h>
+#include <uno/lbnames.h>
+#include <uno/mapping.hxx>
+#include <uno/environment.hxx>
+#include <typelib/typedescription.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/weakagg.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <utility>
+
+
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+
+namespace
+{
+
+struct FactoryImpl : public ::cppu::WeakImplHelper< lang::XServiceInfo,
+ reflection::XProxyFactory >
+{
+ Environment m_uno_env;
+ Environment m_cpp_env;
+ Mapping m_uno2cpp;
+ Mapping m_cpp2uno;
+
+ UnoInterfaceReference binuno_queryInterface(
+ UnoInterfaceReference const & unoI,
+ typelib_InterfaceTypeDescription * pTypeDescr );
+
+ FactoryImpl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString & rServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XProxyFactory
+ virtual Reference< XAggregation > SAL_CALL createProxy(
+ Reference< XInterface > const & xTarget ) override;
+};
+
+
+UnoInterfaceReference FactoryImpl::binuno_queryInterface(
+ UnoInterfaceReference const & unoI,
+ typelib_InterfaceTypeDescription * pTypeDescr )
+{
+ // init queryInterface() td
+ static typelib_TypeDescription* s_pQITD = []() {
+ typelib_TypeDescription* pTXInterfaceDescr = nullptr;
+ TYPELIB_DANGER_GET(&pTXInterfaceDescr, cppu::UnoType<XInterface>::get().getTypeLibType());
+ typelib_TypeDescription* pQITD = nullptr;
+ typelib_typedescriptionreference_getDescription(
+ &pQITD, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTXInterfaceDescr)
+ ->ppAllMembers[0]);
+ TYPELIB_DANGER_RELEASE(pTXInterfaceDescr);
+ return pQITD;
+ }();
+
+ void * args[ 1 ];
+ args[ 0 ] = &reinterpret_cast< typelib_TypeDescription * >(
+ pTypeDescr )->pWeakRef;
+ uno_Any ret_val, exc_space;
+ uno_Any * exc = &exc_space;
+
+ unoI.dispatch( s_pQITD, &ret_val, args, &exc );
+
+ if (exc == nullptr)
+ {
+ UnoInterfaceReference ret;
+ if (ret_val.pType->eTypeClass == typelib_TypeClass_INTERFACE)
+ {
+ ret.set( *static_cast< uno_Interface ** >(ret_val.pData),
+ SAL_NO_ACQUIRE );
+ typelib_typedescriptionreference_release( ret_val.pType );
+ }
+ else
+ {
+ uno_any_destruct( &ret_val, nullptr );
+ }
+ return ret;
+ }
+ else
+ {
+ // exception occurred:
+ OSL_ENSURE(
+ typelib_typedescriptionreference_isAssignableFrom( cppu::UnoType<RuntimeException>::get().getTypeLibType(),
+ exc->pType ),
+ "### RuntimeException expected!" );
+ Any cpp_exc;
+ uno_type_copyAndConvertData(
+ &cpp_exc, exc, cppu::UnoType<decltype(cpp_exc)>::get().getTypeLibType(),
+ m_uno2cpp.get() );
+ uno_any_destruct( exc, nullptr );
+ ::cppu::throwException( cpp_exc );
+ OSL_ASSERT( false ); // way of no return
+ return UnoInterfaceReference(); // for dummy
+ }
+}
+
+
+struct ProxyRoot : public ::cppu::OWeakAggObject
+{
+ // XAggregation
+ virtual Any SAL_CALL queryAggregation( Type const & rType ) override;
+
+ ProxyRoot( ::rtl::Reference< FactoryImpl > factory,
+ Reference< XInterface > const & xTarget );
+
+ ::rtl::Reference< FactoryImpl > m_factory;
+
+private:
+ UnoInterfaceReference m_target;
+};
+
+
+struct binuno_Proxy : public uno_Interface
+{
+ oslInterlockedCount m_nRefCount;
+ ::rtl::Reference< ProxyRoot > m_root;
+ UnoInterfaceReference m_target;
+ OUString m_oid;
+ TypeDescription m_typeDescr;
+
+ binuno_Proxy(
+ ::rtl::Reference< ProxyRoot > root,
+ UnoInterfaceReference target,
+ OUString oid, TypeDescription typeDescr );
+};
+
+extern "C"
+{
+
+
+static void binuno_proxy_free(
+ uno_ExtEnvironment * pEnv, void * pProxy )
+{
+ binuno_Proxy * proxy = static_cast< binuno_Proxy * >(
+ static_cast< uno_Interface * >( pProxy ) );
+ OSL_ASSERT( proxy->m_root->m_factory->m_uno_env.get()->pExtEnv == pEnv );
+ delete proxy;
+}
+
+
+static void binuno_proxy_acquire( uno_Interface * pUnoI )
+{
+ binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
+ if (osl_atomic_increment( &that->m_nRefCount ) != 1)
+ return;
+
+ // rebirth of zombie
+ uno_ExtEnvironment * uno_env =
+ that->m_root->m_factory->m_uno_env.get()->pExtEnv;
+ OSL_ASSERT( uno_env != nullptr );
+ (*uno_env->registerProxyInterface)(
+ uno_env, reinterpret_cast< void ** >( &pUnoI ), binuno_proxy_free,
+ that->m_oid.pData,
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ that->m_typeDescr.get() ) );
+ OSL_ASSERT( that == static_cast< binuno_Proxy * >( pUnoI ) );
+}
+
+
+static void binuno_proxy_release( uno_Interface * pUnoI )
+{
+ binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
+ if (osl_atomic_decrement( &that->m_nRefCount ) == 0)
+ {
+ uno_ExtEnvironment * uno_env =
+ that->m_root->m_factory->m_uno_env.get()->pExtEnv;
+ OSL_ASSERT( uno_env != nullptr );
+ (*uno_env->revokeInterface)( uno_env, pUnoI );
+ }
+}
+
+
+static void binuno_proxy_dispatch(
+ uno_Interface * pUnoI, const typelib_TypeDescription * pMemberType,
+ void * pReturn, void * pArgs [], uno_Any ** ppException )
+{
+ binuno_Proxy * that = static_cast< binuno_Proxy * >( pUnoI );
+ switch (reinterpret_cast< typelib_InterfaceMemberTypeDescription const * >(
+ pMemberType )->nPosition)
+ {
+ case 0: // queryInterface()
+ {
+ try
+ {
+ Type const & rType =
+ *static_cast< Type const * >( pArgs[ 0 ] );
+ Any ret( that->m_root->queryInterface( rType ) );
+ uno_type_copyAndConvertData(
+ pReturn, &ret, cppu::UnoType<decltype(ret)>::get().getTypeLibType(),
+ that->m_root->m_factory->m_cpp2uno.get() );
+ *ppException = nullptr; // no exc
+ }
+ catch (RuntimeException &)
+ {
+ Any exc( ::cppu::getCaughtException() );
+ uno_type_any_constructAndConvert(
+ *ppException, const_cast< void * >(exc.getValue()),
+ exc.getValueTypeRef(),
+ that->m_root->m_factory->m_cpp2uno.get() );
+ }
+ break;
+ }
+ case 1: // acquire()
+ binuno_proxy_acquire( pUnoI );
+ *ppException = nullptr; // no exc
+ break;
+ case 2: // release()
+ binuno_proxy_release( pUnoI );
+ *ppException = nullptr; // no exc
+ break;
+ default:
+ that->m_target.dispatch( pMemberType, pReturn, pArgs, ppException );
+ break;
+ }
+}
+
+}
+
+
+binuno_Proxy::binuno_Proxy(
+ ::rtl::Reference< ProxyRoot > root,
+ UnoInterfaceReference target,
+ OUString oid, TypeDescription typeDescr )
+ : m_nRefCount( 1 ),
+ m_root(std::move( root )),
+ m_target(std::move( target )),
+ m_oid(std::move( oid )),
+ m_typeDescr(std::move( typeDescr ))
+{
+ uno_Interface::acquire = binuno_proxy_acquire;
+ uno_Interface::release = binuno_proxy_release;
+ uno_Interface::pDispatcher = binuno_proxy_dispatch;
+}
+
+ProxyRoot::ProxyRoot(
+ ::rtl::Reference< FactoryImpl > factory,
+ Reference< XInterface > const & xTarget )
+ : m_factory(std::move( factory ))
+{
+ m_factory->m_cpp2uno.mapInterface(
+ reinterpret_cast< void ** >( &m_target.m_pUnoI ), xTarget.get(),
+ cppu::UnoType<decltype(xTarget)>::get() );
+ OSL_ENSURE( m_target.is(), "### mapping interface failed!" );
+}
+
+
+Any ProxyRoot::queryAggregation( Type const & rType )
+{
+ Any ret( OWeakAggObject::queryAggregation( rType ) );
+ if (! ret.hasValue())
+ {
+ typelib_TypeDescription * pTypeDescr = nullptr;
+ TYPELIB_DANGER_GET( &pTypeDescr, rType.getTypeLibType() );
+ try
+ {
+ Reference< XInterface > xProxy;
+ uno_ExtEnvironment * cpp_env = m_factory->m_cpp_env.get()->pExtEnv;
+ OSL_ASSERT( cpp_env != nullptr );
+
+ // mind a new delegator, calculate current root:
+ Reference< XInterface > xRoot(
+ static_cast< OWeakObject * >(this), UNO_QUERY_THROW );
+ OUString oid;
+ (*cpp_env->getObjectIdentifier)( cpp_env, &oid.pData, xRoot.get() );
+ OSL_ASSERT( !oid.isEmpty() );
+
+ (*cpp_env->getRegisteredInterface)(
+ cpp_env, reinterpret_cast< void ** >( &xProxy ),
+ oid.pData, reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(pTypeDescr) );
+ if (! xProxy.is())
+ {
+ // perform query on target:
+ UnoInterfaceReference proxy_target(
+ m_factory->binuno_queryInterface(
+ m_target, reinterpret_cast<
+ typelib_InterfaceTypeDescription * >(pTypeDescr) ) );
+ if (proxy_target.is())
+ {
+ // ensure root's object entries:
+ UnoInterfaceReference root;
+ m_factory->m_cpp2uno.mapInterface(
+ reinterpret_cast< void ** >( &root.m_pUnoI ),
+ xRoot.get(), cppu::UnoType<decltype(xRoot)>::get() );
+
+ UnoInterfaceReference proxy(
+ // ref count initially 1:
+ new binuno_Proxy( this, proxy_target, oid, pTypeDescr ),
+ SAL_NO_ACQUIRE );
+ uno_ExtEnvironment * uno_env =
+ m_factory->m_uno_env.get()->pExtEnv;
+ OSL_ASSERT( uno_env != nullptr );
+ (*uno_env->registerProxyInterface)(
+ uno_env, reinterpret_cast< void ** >( &proxy.m_pUnoI ),
+ binuno_proxy_free, oid.pData,
+ reinterpret_cast< typelib_InterfaceTypeDescription * >(
+ pTypeDescr ) );
+
+ m_factory->m_uno2cpp.mapInterface(
+ reinterpret_cast< void ** >( &xProxy ),
+ proxy.get(), pTypeDescr );
+ }
+ }
+ if (xProxy.is())
+ ret.setValue( &xProxy, pTypeDescr );
+ }
+ catch (...) // finally
+ {
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ throw;
+ }
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+ }
+ return ret;
+}
+
+
+FactoryImpl::FactoryImpl()
+{
+ OUString uno = UNO_LB_UNO;
+ OUString cpp = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+
+ uno_getEnvironment(
+ reinterpret_cast< uno_Environment ** >( &m_uno_env ), uno.pData, nullptr );
+ OSL_ENSURE( m_uno_env.is(), "### cannot get binary uno env!" );
+
+ uno_getEnvironment(
+ reinterpret_cast< uno_Environment ** >( &m_cpp_env ), cpp.pData, nullptr );
+ OSL_ENSURE( m_cpp_env.is(), "### cannot get C++ uno env!" );
+
+ uno_getMapping(
+ reinterpret_cast< uno_Mapping ** >( &m_uno2cpp ),
+ m_uno_env.get(), m_cpp_env.get(), nullptr );
+ OSL_ENSURE( m_uno2cpp.is(), "### cannot get bridge uno <-> C++!" );
+
+ uno_getMapping(
+ reinterpret_cast< uno_Mapping ** >( &m_cpp2uno ),
+ m_cpp_env.get(), m_uno_env.get(), nullptr );
+ OSL_ENSURE( m_cpp2uno.is(), "### cannot get bridge C++ <-> uno!" );
+}
+
+// XProxyFactory
+
+Reference< XAggregation > FactoryImpl::createProxy(
+ Reference< XInterface > const & xTarget )
+{
+ return new ProxyRoot( this, xTarget );
+}
+
+// XServiceInfo
+
+OUString FactoryImpl::getImplementationName()
+{
+ return "com.sun.star.comp.reflection.ProxyFactory";
+}
+
+sal_Bool FactoryImpl::supportsService( const OUString & rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+Sequence< OUString > FactoryImpl::getSupportedServiceNames()
+{
+ return { "com.sun.star.reflection.ProxyFactory" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+stoc_FactoryImpl_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new FactoryImpl);
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/access_controller.cxx b/stoc/source/security/access_controller.cxx
new file mode 100644
index 0000000000..1359e529c7
--- /dev/null
+++ b/stoc/source/security/access_controller.cxx
@@ -0,0 +1,863 @@
+/* -*- 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 <utility>
+#include <vector>
+
+#include <osl/diagnose.h>
+#include <osl/mutex.hxx>
+#include <osl/thread.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include <uno/current_context.h>
+#include <uno/lbnames.h>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/uno/DeploymentException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/security/XAccessController.hpp>
+#include <com/sun/star/security/XPolicy.hpp>
+
+#include "lru_cache.h"
+#include "permissions.h"
+
+#include <memory>
+
+constexpr OUString SERVICE_NAME = u"com.sun.star.security.AccessController"_ustr;
+constexpr OUStringLiteral USER_CREDS = u"access-control.user-credentials.id";
+
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace css::uno;
+using namespace stoc_sec;
+
+namespace {
+
+// static stuff initialized when loading lib
+OUString s_envType = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
+constexpr OUString s_acRestriction = u"access-control.restriction"_ustr;
+
+
+/** ac context intersects permissions of two ac contexts
+*/
+class acc_Intersection
+ : public WeakImplHelper< security::XAccessControlContext >
+{
+ Reference< security::XAccessControlContext > m_x1, m_x2;
+
+ acc_Intersection(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+public:
+ static Reference< security::XAccessControlContext > create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+};
+
+acc_Intersection::acc_Intersection(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ : m_x1( x1 )
+ , m_x2( x2 )
+{}
+
+Reference< security::XAccessControlContext > acc_Intersection::create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+{
+ if (! x1.is())
+ return x2;
+ if (! x2.is())
+ return x1;
+ return new acc_Intersection( x1, x2 );
+}
+
+void acc_Intersection::checkPermission(
+ Any const & perm )
+{
+ m_x1->checkPermission( perm );
+ m_x2->checkPermission( perm );
+}
+
+/** ac context unifies permissions of two ac contexts
+*/
+class acc_Union
+ : public WeakImplHelper< security::XAccessControlContext >
+{
+ Reference< security::XAccessControlContext > m_x1, m_x2;
+
+ acc_Union(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+public:
+ static Reference< security::XAccessControlContext > create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 );
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+};
+
+acc_Union::acc_Union(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+ : m_x1( x1 )
+ , m_x2( x2 )
+{}
+
+Reference< security::XAccessControlContext > acc_Union::create(
+ Reference< security::XAccessControlContext > const & x1,
+ Reference< security::XAccessControlContext > const & x2 )
+{
+ if (! x1.is())
+ return Reference< security::XAccessControlContext >(); // unrestricted
+ if (! x2.is())
+ return Reference< security::XAccessControlContext >(); // unrestricted
+ return new acc_Union( x1, x2 );
+}
+
+void acc_Union::checkPermission(
+ Any const & perm )
+{
+ try
+ {
+ m_x1->checkPermission( perm );
+ }
+ catch (security::AccessControlException &)
+ {
+ m_x2->checkPermission( perm );
+ }
+}
+
+/** ac context doing permission checks on static permissions
+*/
+class acc_Policy
+ : public WeakImplHelper< security::XAccessControlContext >
+{
+ PermissionCollection m_permissions;
+
+public:
+ explicit acc_Policy(
+ PermissionCollection permissions )
+ : m_permissions(std::move( permissions ))
+ {}
+
+ // XAccessControlContext impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+};
+
+void acc_Policy::checkPermission(
+ Any const & perm )
+{
+ m_permissions.checkPermission( perm );
+}
+
+/** current context overriding dynamic ac restriction
+*/
+class acc_CurrentContext
+ : public WeakImplHelper< XCurrentContext >
+{
+ Reference< XCurrentContext > m_xDelegate;
+ Any m_restriction;
+
+public:
+ acc_CurrentContext(
+ Reference< XCurrentContext > const & xDelegate,
+ Reference< security::XAccessControlContext > const & xRestriction );
+
+ // XCurrentContext impl
+ virtual Any SAL_CALL getValueByName( OUString const & name ) override;
+};
+
+acc_CurrentContext::acc_CurrentContext(
+ Reference< XCurrentContext > const & xDelegate,
+ Reference< security::XAccessControlContext > const & xRestriction )
+ : m_xDelegate( xDelegate )
+{
+ if (xRestriction.is())
+ {
+ m_restriction <<= xRestriction;
+ }
+ // return empty any otherwise on getValueByName(), not null interface
+}
+
+Any acc_CurrentContext::getValueByName( OUString const & name )
+{
+ if (name == s_acRestriction)
+ {
+ return m_restriction;
+ }
+ else if (m_xDelegate.is())
+ {
+ return m_xDelegate->getValueByName( name );
+ }
+ else
+ {
+ return Any();
+ }
+}
+
+
+Reference< security::XAccessControlContext > getDynamicRestriction(
+ Reference< XCurrentContext > const & xContext )
+{
+ if (xContext.is())
+ {
+ Any acc(xContext->getValueByName(s_acRestriction));
+ if (typelib_TypeClass_INTERFACE == acc.pType->eTypeClass)
+ {
+ // avoid ref-counting
+ OUString const & typeName =
+ OUString::unacquired( &acc.pType->pTypeName );
+ if ( typeName == "com.sun.star.security.XAccessControlContext" )
+ {
+ return Reference< security::XAccessControlContext >(
+ *static_cast< security::XAccessControlContext ** >( acc.pData ) );
+ }
+ else // try to query
+ {
+ return Reference< security::XAccessControlContext >::query(
+ *static_cast< XInterface ** >( acc.pData ) );
+ }
+ }
+ }
+ return Reference< security::XAccessControlContext >();
+}
+
+class cc_reset
+{
+ void * m_cc;
+public:
+ explicit cc_reset( void * cc )
+ : m_cc( cc ) {}
+ ~cc_reset()
+ { ::uno_setCurrentContext( m_cc, s_envType.pData, nullptr ); }
+};
+
+typedef WeakComponentImplHelper<
+ security::XAccessController, lang::XServiceInfo, lang::XInitialization > t_helper;
+
+
+class AccessController
+ : public cppu::BaseMutex
+ , public t_helper
+{
+ Reference< XComponentContext > m_xComponentContext;
+
+ Reference< security::XPolicy > m_xPolicy;
+ Reference< security::XPolicy > const & getPolicy();
+
+ // mode
+ enum class Mode { Off, On, DynamicOnly, SingleUser, SingleDefaultUser };
+ Mode m_mode;
+
+ PermissionCollection m_defaultPermissions;
+ // for single-user mode
+ PermissionCollection m_singleUserPermissions;
+ OUString m_singleUserId;
+ bool m_defaultPerm_init;
+ bool m_singleUser_init;
+ // for multi-user mode
+ lru_cache< OUString, PermissionCollection, OUStringHash, std::equal_to< OUString > >
+ m_user2permissions;
+
+ ThreadData m_rec;
+ typedef std::vector< std::pair< OUString, Any > > t_rec_vec;
+ void clearPostPoned();
+ void checkAndClearPostPoned();
+
+ PermissionCollection getEffectivePermissions(
+ Reference< XCurrentContext > const & xContext,
+ Any const & demanded_perm );
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ explicit AccessController( Reference< XComponentContext > const & xComponentContext );
+
+ // XInitialization impl
+ virtual void SAL_CALL initialize(
+ Sequence< Any > const & arguments ) override;
+
+ // XAccessController impl
+ virtual void SAL_CALL checkPermission(
+ Any const & perm ) override;
+ virtual Any SAL_CALL doRestricted(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction ) override;
+ virtual Any SAL_CALL doPrivileged(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction ) override;
+ virtual Reference< security::XAccessControlContext > SAL_CALL getContext() 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;
+};
+
+AccessController::AccessController( Reference< XComponentContext > const & xComponentContext )
+ : t_helper( m_aMutex )
+ , m_xComponentContext( xComponentContext )
+ , m_mode( Mode::On ) // default
+ , m_defaultPerm_init( false )
+ , m_singleUser_init( false )
+ , m_rec( nullptr )
+{
+ // The .../mode value had originally been set in
+ // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
+ // to something other than "off" depending on various UNO_AC* bootstrap
+ // variables that are no longer supported, so this is mostly dead code now:
+ OUString mode;
+ if (m_xComponentContext->getValueByName( "/services/" + SERVICE_NAME + "/mode" ) >>= mode)
+ {
+ if ( mode == "off" )
+ {
+ m_mode = Mode::Off;
+ }
+ else if ( mode == "on" )
+ {
+ m_mode = Mode::On;
+ }
+ else if ( mode == "dynamic-only" )
+ {
+ m_mode = Mode::DynamicOnly;
+ }
+ else if ( mode == "single-user" )
+ {
+ m_xComponentContext->getValueByName(
+ "/services/" + SERVICE_NAME + "/single-user-id" ) >>= m_singleUserId;
+ if (m_singleUserId.isEmpty())
+ {
+ throw RuntimeException(
+ "expected a user id in component context entry "
+ "\"/services/" + SERVICE_NAME + "/single-user-id\"!",
+ getXWeak() );
+ }
+ m_mode = Mode::SingleUser;
+ }
+ else if ( mode == "single-default-user" )
+ {
+ m_mode = Mode::SingleDefaultUser;
+ }
+ }
+
+ // switch on caching for Mode::DynamicOnly and Mode::On (shareable multi-user process)
+ if (Mode::On != m_mode && Mode::DynamicOnly != m_mode)
+ return;
+
+ sal_Int32 cacheSize = 0; // multi-user cache size
+ if (! (m_xComponentContext->getValueByName(
+ "/services/" + SERVICE_NAME + "/user-cache-size" ) >>= cacheSize))
+ {
+ cacheSize = 128; // reasonable default?
+ }
+#ifdef __CACHE_DIAGNOSE
+ cacheSize = 2;
+#endif
+ m_user2permissions.setSize( cacheSize );
+}
+
+void AccessController::disposing()
+{
+ m_mode = Mode::Off; // avoid checks from now on xxx todo review/ better Mode::DynamicOnly?
+ m_xPolicy.clear();
+ m_xComponentContext.clear();
+}
+
+// XInitialization impl
+
+void AccessController::initialize(
+ Sequence< Any > const & arguments )
+{
+ // xxx todo: review for forking
+ // portal forking hack: re-initialize for another user-id
+ if (Mode::SingleUser != m_mode) // only if in single-user mode
+ {
+ throw RuntimeException(
+ "invalid call: ac must be in \"single-user\" mode!", getXWeak() );
+ }
+ OUString userId;
+ arguments[ 0 ] >>= userId;
+ if ( userId.isEmpty() )
+ {
+ throw RuntimeException(
+ "expected a user-id as first argument!", getXWeak() );
+ }
+ // assured that no sync is necessary: no check happens at this forking time
+ m_singleUserId = userId;
+ m_singleUser_init = false;
+}
+
+
+Reference< security::XPolicy > const & AccessController::getPolicy()
+{
+ // get policy singleton
+ if (! m_xPolicy.is())
+ {
+ Reference< security::XPolicy > xPolicy;
+ m_xComponentContext->getValueByName(
+ "/singletons/com.sun.star.security.thePolicy" ) >>= xPolicy;
+ if (!xPolicy.is())
+ {
+ throw SecurityException(
+ "cannot get policy singleton!", getXWeak() );
+ }
+
+ MutexGuard guard( m_aMutex );
+ if (! m_xPolicy.is())
+ {
+ m_xPolicy = xPolicy;
+ }
+ }
+ return m_xPolicy;
+}
+
+#ifdef __DIAGNOSE
+static void dumpPermissions(
+ PermissionCollection const & collection, OUString const & userId = OUString() )
+{
+ OUStringBuffer buf( 48 );
+ if (!userId.isEmpty())
+ {
+ buf.append( "> dumping permissions of user \"" );
+ buf.append( userId );
+ buf.append( "\":" );
+ }
+ else
+ {
+ buf.append( "> dumping default permissions:" );
+ }
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+ Sequence< OUString > permissions( collection.toStrings() );
+ OUString const * p = permissions.getConstArray();
+ for ( sal_Int32 nPos = 0; nPos < permissions.getLength(); ++nPos )
+ {
+ SAL_INFO("stoc", p[ nPos ] );
+ }
+ SAL_INFO("stoc", "> permission dump done" );
+}
+#endif
+
+
+void AccessController::clearPostPoned()
+{
+ delete static_cast< t_rec_vec * >( m_rec.getData() );
+ m_rec.setData( nullptr );
+}
+
+void AccessController::checkAndClearPostPoned()
+{
+ // check postponed permissions
+ std::unique_ptr< t_rec_vec > rec( static_cast< t_rec_vec * >( m_rec.getData() ) );
+ m_rec.setData( nullptr ); // takeover ownership
+ OSL_ASSERT(rec);
+ if (!rec)
+ return;
+
+ t_rec_vec const& vec = *rec;
+ switch (m_mode)
+ {
+ case Mode::SingleUser:
+ {
+ OSL_ASSERT( m_singleUser_init );
+ for (const auto & p : vec)
+ {
+ OSL_ASSERT( m_singleUserId == p.first );
+ m_singleUserPermissions.checkPermission( p.second );
+ }
+ break;
+ }
+ case Mode::SingleDefaultUser:
+ {
+ OSL_ASSERT( m_defaultPerm_init );
+ for (const auto & p : vec)
+ {
+ OSL_ASSERT( p.first.isEmpty() ); // default-user
+ m_defaultPermissions.checkPermission( p.second );
+ }
+ break;
+ }
+ case Mode::On:
+ {
+ for (const auto & p : vec)
+ {
+ PermissionCollection const * pPermissions;
+ // lookup policy for user
+ {
+ MutexGuard guard( m_aMutex );
+ pPermissions = m_user2permissions.lookup( p.first );
+ }
+ OSL_ASSERT( pPermissions );
+ if (pPermissions)
+ {
+ pPermissions->checkPermission( p.second );
+ }
+ }
+ break;
+ }
+ default:
+ OSL_FAIL( "### this should never be called in this ac mode!" );
+ break;
+ }
+}
+
+/** this is the only function calling the policy singleton and thus has to take care
+ of recurring calls!
+
+ @param demanded_perm (if not empty) is the demanded permission of a checkPermission() call
+ which will be postponed for recurring calls
+*/
+PermissionCollection AccessController::getEffectivePermissions(
+ Reference< XCurrentContext > const & xContext,
+ Any const & demanded_perm )
+{
+ OUString userId;
+
+ switch (m_mode)
+ {
+ case Mode::SingleUser:
+ {
+ if (m_singleUser_init)
+ return m_singleUserPermissions;
+ userId = m_singleUserId;
+ break;
+ }
+ case Mode::SingleDefaultUser:
+ {
+ if (m_defaultPerm_init)
+ return m_defaultPermissions;
+ break;
+ }
+ case Mode::On:
+ {
+ if (xContext.is())
+ {
+ xContext->getValueByName( USER_CREDS ) >>= userId;
+ }
+ if ( userId.isEmpty() )
+ {
+ throw SecurityException(
+ "cannot determine current user in multi-user ac!", getXWeak() );
+ }
+
+ // lookup policy for user
+ MutexGuard guard( m_aMutex );
+ PermissionCollection const * pPermissions = m_user2permissions.lookup( userId );
+ if (pPermissions)
+ return *pPermissions;
+ break;
+ }
+ default:
+ OSL_FAIL( "### this should never be called in this ac mode!" );
+ return PermissionCollection();
+ }
+
+ // call on policy
+ // iff this is a recurring call for the default user, then grant all permissions
+ t_rec_vec * rec = static_cast< t_rec_vec * >( m_rec.getData() );
+ if (rec) // tls entry exists => this is recursive call
+ {
+ if (demanded_perm.hasValue())
+ {
+ // enqueue
+ rec->push_back( std::pair< OUString, Any >( userId, demanded_perm ) );
+ }
+#ifdef __DIAGNOSE
+ SAL_INFO("stoc", "> info: recurring call of user: " << userId );
+#endif
+ return PermissionCollection( new AllPermission() );
+ }
+ else // no tls
+ {
+ rec = new t_rec_vec;
+ m_rec.setData( rec );
+ }
+
+ try // calls on API
+ {
+ // init default permissions
+ if (! m_defaultPerm_init)
+ {
+ PermissionCollection defaultPermissions(
+ getPolicy()->getDefaultPermissions() );
+ // assign
+ MutexGuard guard( m_aMutex );
+ if (! m_defaultPerm_init)
+ {
+ m_defaultPermissions = defaultPermissions;
+ m_defaultPerm_init = true;
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( m_defaultPermissions );
+#endif
+ }
+
+ PermissionCollection ret;
+
+ // init user permissions
+ switch (m_mode)
+ {
+ case Mode::SingleUser:
+ {
+ ret = PermissionCollection(
+ getPolicy()->getPermissions( userId ), m_defaultPermissions );
+ {
+ // assign
+ MutexGuard guard( m_aMutex );
+ if (m_singleUser_init)
+ {
+ ret = m_singleUserPermissions;
+ }
+ else
+ {
+ m_singleUserPermissions = ret;
+ m_singleUser_init = true;
+ }
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( ret, userId );
+#endif
+ break;
+ }
+ case Mode::SingleDefaultUser:
+ {
+ ret = m_defaultPermissions;
+ break;
+ }
+ case Mode::On:
+ {
+ ret = PermissionCollection(
+ getPolicy()->getPermissions( userId ), m_defaultPermissions );
+ {
+ // cache
+ MutexGuard guard( m_aMutex );
+ m_user2permissions.set( userId, ret );
+ }
+#ifdef __DIAGNOSE
+ dumpPermissions( ret, userId );
+#endif
+ break;
+ }
+ default:
+ break;
+ }
+
+ // check postponed
+ checkAndClearPostPoned();
+ return ret;
+ }
+ catch (const security::AccessControlException & exc) // wrapped into DeploymentException
+ {
+ clearPostPoned(); // safety: exception could have happened before checking postponed?
+ throw DeploymentException( "deployment error (AccessControlException occurred): " + exc.Message, exc.Context );
+ }
+ catch (RuntimeException &)
+ {
+ // don't check postponed, just cleanup
+ clearPostPoned();
+ delete static_cast< t_rec_vec * >( m_rec.getData() );
+ m_rec.setData( nullptr );
+ throw;
+ }
+ catch (Exception &)
+ {
+ // check postponed permissions first
+ // => AccessControlExceptions are errors, user exceptions not!
+ checkAndClearPostPoned();
+ throw;
+ }
+ catch (...)
+ {
+ // don't check postponed, just cleanup
+ clearPostPoned();
+ throw;
+ }
+}
+
+// XAccessController impl
+
+void AccessController::checkPermission(
+ Any const & perm )
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "checkPermission() call on disposed AccessController!", getXWeak() );
+ }
+
+ if (Mode::Off == m_mode)
+ return;
+
+ // first dynamic check of ac contexts
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+ Reference< security::XAccessControlContext > xACC( getDynamicRestriction( xContext ) );
+ if (xACC.is())
+ {
+ xACC->checkPermission( perm );
+ }
+
+ if (Mode::DynamicOnly == m_mode)
+ return;
+
+ // then static check
+ getEffectivePermissions( xContext, perm ).checkPermission( perm );
+}
+
+Any AccessController::doRestricted(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "doRestricted() call on disposed AccessController!", getXWeak() );
+ }
+
+ if (Mode::Off == m_mode) // optimize this way, because no dynamic check will be performed
+ return xAction->run();
+
+ if (xRestriction.is())
+ {
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+
+ // override restriction
+ Reference< XCurrentContext > xNewContext(
+ new acc_CurrentContext( xContext, acc_Intersection::create(
+ xRestriction, getDynamicRestriction( xContext ) ) ) );
+ ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
+ cc_reset reset( xContext.get() );
+ return xAction->run();
+ }
+ else
+ {
+ return xAction->run();
+ }
+}
+
+Any AccessController::doPrivileged(
+ Reference< security::XAction > const & xAction,
+ Reference< security::XAccessControlContext > const & xRestriction )
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "doPrivileged() call on disposed AccessController!", getXWeak() );
+ }
+
+ if (Mode::Off == m_mode) // no dynamic check will be performed
+ {
+ return xAction->run();
+ }
+
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+
+ Reference< security::XAccessControlContext > xOldRestr(
+ getDynamicRestriction( xContext ) );
+
+ if (xOldRestr.is()) // previous restriction
+ {
+ // override restriction
+ Reference< XCurrentContext > xNewContext(
+ new acc_CurrentContext( xContext, acc_Union::create( xRestriction, xOldRestr ) ) );
+ ::uno_setCurrentContext( xNewContext.get(), s_envType.pData, nullptr );
+ cc_reset reset( xContext.get() );
+ return xAction->run();
+ }
+ else // no previous restriction => never current restriction
+ {
+ return xAction->run();
+ }
+}
+
+Reference< security::XAccessControlContext > AccessController::getContext()
+{
+ if (rBHelper.bDisposed)
+ {
+ throw lang::DisposedException(
+ "getContext() call on disposed AccessController!", getXWeak() );
+ }
+
+ if (Mode::Off == m_mode) // optimize this way, because no dynamic check will be performed
+ {
+ return new acc_Policy( PermissionCollection( new AllPermission() ) );
+ }
+
+ Reference< XCurrentContext > xContext;
+ ::uno_getCurrentContext( reinterpret_cast<void **>(&xContext), s_envType.pData, nullptr );
+
+ return acc_Intersection::create(
+ getDynamicRestriction( xContext ),
+ new acc_Policy( getEffectivePermissions( xContext, Any() ) ) );
+}
+
+// XServiceInfo impl
+
+OUString AccessController::getImplementationName()
+{
+ return "com.sun.star.security.comp.stoc.AccessController";
+}
+
+sal_Bool AccessController::supportsService( OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+Sequence< OUString > AccessController::getSupportedServiceNames()
+{
+ Sequence<OUString> aSNS { SERVICE_NAME };
+ return aSNS;
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_security_comp_stoc_AccessController_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new AccessController(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/file_policy.cxx b/stoc/source/security/file_policy.cxx
new file mode 100644
index 0000000000..63d0c6156e
--- /dev/null
+++ b/stoc/source/security/file_policy.cxx
@@ -0,0 +1,494 @@
+/* -*- 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 <osl/file.h>
+#include <rtl/byteseq.hxx>
+#include <rtl/ustrbuf.hxx>
+
+#include <cppuhelper/access_control.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/security/XPolicy.hpp>
+#include <com/sun/star/security/AllPermission.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>
+
+#include <string_view>
+#include <unordered_map>
+#include <utility>
+
+constexpr OUString IMPL_NAME = u"com.sun.star.security.comp.stoc.FilePolicy"_ustr;
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+namespace {
+
+typedef WeakComponentImplHelper< security::XPolicy, lang::XServiceInfo > t_helper;
+
+
+class FilePolicy
+ : public cppu::BaseMutex
+ , public t_helper
+{
+ Reference< XComponentContext > m_xComponentContext;
+ AccessControl m_ac;
+
+ Sequence< Any > m_defaultPermissions;
+ typedef std::unordered_map< OUString, Sequence< Any > > t_permissions;
+ t_permissions m_userPermissions;
+ bool m_init;
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ explicit FilePolicy( Reference< XComponentContext > const & xComponentContext );
+
+ // XPolicy impl
+ virtual Sequence< Any > SAL_CALL getPermissions(
+ OUString const & userId ) override;
+ virtual Sequence< Any > SAL_CALL getDefaultPermissions() override;
+ virtual void SAL_CALL refresh() 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;
+};
+
+FilePolicy::FilePolicy( Reference< XComponentContext > const & xComponentContext )
+ : t_helper( m_aMutex )
+ , m_xComponentContext( xComponentContext )
+ , m_ac( xComponentContext )
+ , m_init( false )
+{}
+
+void FilePolicy::disposing()
+{
+ m_userPermissions.clear();
+ m_defaultPermissions = Sequence< Any >();
+ m_xComponentContext.clear();
+}
+
+
+Sequence< Any > FilePolicy::getPermissions(
+ OUString const & userId )
+{
+ if (! m_init)
+ {
+ refresh();
+ m_init = true;
+ }
+
+ MutexGuard guard( m_aMutex );
+ t_permissions::iterator iFind( m_userPermissions.find( userId ) );
+ if (m_userPermissions.end() == iFind)
+ {
+ return Sequence< Any >();
+ }
+ else
+ {
+ return iFind->second;
+ }
+}
+
+Sequence< Any > FilePolicy::getDefaultPermissions()
+{
+ if (! m_init)
+ {
+ refresh();
+ m_init = true;
+ }
+
+ MutexGuard guard( m_aMutex );
+ return m_defaultPermissions;
+}
+
+
+class PolicyReader
+{
+ OUString m_fileName;
+ oslFileHandle m_file;
+
+ sal_Int32 m_linepos;
+ rtl::ByteSequence m_line;
+ sal_Int32 m_pos;
+ sal_Unicode m_back;
+
+ sal_Unicode get();
+ void back( sal_Unicode c )
+ { m_back = c; }
+
+ static bool isWhiteSpace( sal_Unicode c )
+ { return (' ' == c || '\t' == c || '\n' == c || '\r' == c); }
+ void skipWhiteSpace();
+
+ static bool isCharToken( sal_Unicode c )
+ { return (';' == c || ',' == c || '{' == c || '}' == c); }
+
+public:
+ PolicyReader( OUString file, AccessControl & ac );
+ ~PolicyReader();
+
+ void error( std::u16string_view msg );
+
+ OUString getToken();
+ OUString assureToken();
+ OUString getQuotedToken();
+ OUString assureQuotedToken();
+ void assureToken( sal_Unicode token );
+};
+
+void PolicyReader::assureToken( sal_Unicode token )
+{
+ skipWhiteSpace();
+ sal_Unicode c = get();
+ if (c == token)
+ return;
+ OUString msg = "expected >" + OUStringChar(c) + "<!";
+ error( msg );
+}
+
+OUString PolicyReader::assureQuotedToken()
+{
+ OUString token( getQuotedToken() );
+ if (token.isEmpty())
+ error( u"unexpected end of file!" );
+ return token;
+}
+
+OUString PolicyReader::getQuotedToken()
+{
+ skipWhiteSpace();
+ OUStringBuffer buf( 32 );
+ sal_Unicode c = get();
+ if ('\"' != c)
+ error( u"expected quoting >\"< character!" );
+ c = get();
+ while ('\0' != c && '\"' != c)
+ {
+ buf.append( c );
+ c = get();
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString PolicyReader::assureToken()
+{
+ OUString token( getToken() );
+ if ( token.isEmpty())
+ error( u"unexpected end of file!" );
+ return token;
+}
+
+OUString PolicyReader::getToken()
+{
+ skipWhiteSpace();
+ sal_Unicode c = get();
+ if (isCharToken( c ))
+ return OUString( &c, 1 );
+ OUStringBuffer buf( 32 );
+ while ('\0' != c && !isCharToken( c ) && !isWhiteSpace( c ))
+ {
+ buf.append( c );
+ c = get();
+ }
+ back( c );
+ return buf.makeStringAndClear();
+}
+
+void PolicyReader::skipWhiteSpace()
+{
+ sal_Unicode c;
+ do
+ {
+ c = get();
+ }
+ while (isWhiteSpace( c )); // seeking next non-whitespace char
+
+ if ('/' == c) // C/C++ like comment
+ {
+ c = get();
+ if ('/' == c) // C++ like comment
+ {
+ do
+ {
+ c = get();
+ }
+ while ('\n' != c && '\0' != c); // seek eol/eof
+ skipWhiteSpace(); // cont skip on next line
+ }
+ else if ('*' == c) // C like comment
+ {
+ bool fini = true;
+ do
+ {
+ c = get();
+ if ('*' == c)
+ {
+ c = get();
+ fini = ('/' == c || '\0' == c);
+ }
+ else
+ {
+ fini = ('\0' == c);
+ }
+ }
+ while (! fini);
+ skipWhiteSpace(); // cont skip on next line
+ }
+ else
+ {
+ error( u"expected C/C++ like comment!" );
+ }
+ }
+ else if ('#' == c) // script like comment
+ {
+ do
+ {
+ c = get();
+ }
+ while ('\n' != c && '\0' != c); // seek eol/eof
+ skipWhiteSpace(); // cont skip on next line
+ }
+
+ else // is token char
+ {
+ back( c );
+ }
+}
+
+sal_Unicode PolicyReader::get()
+{
+ if ('\0' != m_back) // one char push back possible
+ {
+ sal_Unicode c = m_back;
+ m_back = '\0';
+ return c;
+ }
+ else if (m_pos == m_line.getLength()) // provide newline as whitespace
+ {
+ ++m_pos;
+ return '\n';
+ }
+ else if (m_pos > m_line.getLength()) // read new line
+ {
+ sal_Bool eof;
+ oslFileError rc = ::osl_isEndOfFile( m_file, &eof );
+ if (osl_File_E_None != rc)
+ error( u"checking eof failed!" );
+ if (eof)
+ return '\0';
+
+ rc = ::osl_readLine( m_file, reinterpret_cast< sal_Sequence ** >( &m_line ) );
+ if (osl_File_E_None != rc)
+ error( u"read line failed!" );
+ ++m_linepos;
+ if (! m_line.getLength()) // empty line read
+ {
+ m_pos = 1; // read new line next time
+ return '\n';
+ }
+ m_pos = 0;
+ }
+ return (m_line.getConstArray()[ m_pos++ ]);
+}
+
+void PolicyReader::error( std::u16string_view msg )
+{
+ throw RuntimeException(
+ "error processing file \"" + m_fileName +
+ "\" [line " + OUString::number(m_linepos) +
+ ", column " + OUString::number(m_pos) +
+ "] " + msg);
+}
+
+PolicyReader::PolicyReader( OUString fileName, AccessControl & ac )
+ : m_fileName(std::move( fileName ))
+ , m_linepos( 0 )
+ , m_pos( 1 ) // force readline
+ , m_back( '\0' )
+{
+ ac.checkFilePermission( m_fileName, "read" );
+ if (osl_File_E_None != ::osl_openFile( m_fileName.pData, &m_file, osl_File_OpenFlag_Read ))
+ {
+ throw RuntimeException( "cannot open file \"" + m_fileName + "\"!" );
+ }
+}
+
+PolicyReader::~PolicyReader()
+{
+ if ( ::osl_closeFile( m_file ) != osl_File_E_None ) {
+ OSL_ASSERT( false );
+ }
+}
+
+constexpr OUStringLiteral s_grant = u"grant";
+constexpr OUStringLiteral s_user = u"user";
+constexpr OUStringLiteral s_permission = u"permission";
+constexpr OUStringLiteral s_openBrace = u"{";
+constexpr OUStringLiteral s_closingBrace = u"}";
+
+constexpr OUStringLiteral s_filePermission = u"com.sun.star.io.FilePermission";
+constexpr OUStringLiteral s_socketPermission = u"com.sun.star.connection.SocketPermission";
+constexpr OUStringLiteral s_runtimePermission = u"com.sun.star.security.RuntimePermission";
+constexpr OUStringLiteral s_allPermission = u"com.sun.star.security.AllPermission";
+
+
+void FilePolicy::refresh()
+{
+ // read out file (the .../file-name value had originally been set in
+ // cppu::add_access_control_entries (cppuhelper/source/servicefactory.cxx)
+ // depending on various UNO_AC* bootstrap variables that are no longer
+ // supported, so this is effectively dead code):
+ OUString fileName;
+ m_xComponentContext->getValueByName(
+ "/implementations/" + IMPL_NAME + "/file-name" ) >>= fileName;
+ if ( fileName.isEmpty() )
+ {
+ throw RuntimeException(
+ "name of policy file unknown!",
+ getXWeak() );
+ }
+
+ PolicyReader reader( fileName, m_ac );
+
+ // fill these two
+ Sequence< Any > defaultPermissions;
+ t_permissions userPermissions;
+
+ OUString token( reader.getToken() );
+ while (!token.isEmpty())
+ {
+ if ( token != s_grant )
+ reader.error( u"expected >grant< token!" );
+ OUString userId;
+ token = reader.assureToken();
+ if ( token == s_user ) // next token is user-id
+ {
+ userId = reader.assureQuotedToken();
+ token = reader.assureToken();
+ }
+ if ( token != s_openBrace )
+ reader.error( u"expected opening brace >{<!" );
+ token = reader.assureToken();
+ // permissions list
+ while ( token != s_closingBrace )
+ {
+ if ( token != s_permission )
+ reader.error( u"expected >permission< or closing brace >}<!" );
+
+ token = reader.assureToken(); // permission type
+ Any perm;
+ if ( token == s_filePermission ) // FilePermission
+ {
+ OUString url( reader.assureQuotedToken() );
+ reader.assureToken( ',' );
+ OUString actions( reader.assureQuotedToken() );
+ perm <<= io::FilePermission( url, actions );
+ }
+ else if ( token == s_socketPermission ) // SocketPermission
+ {
+ OUString host( reader.assureQuotedToken() );
+ reader.assureToken( ',' );
+ OUString actions( reader.assureQuotedToken() );
+ perm <<= connection::SocketPermission( host, actions );
+ }
+ else if ( token == s_runtimePermission ) // RuntimePermission
+ {
+ OUString name( reader.assureQuotedToken() );
+ perm <<= security::RuntimePermission( name );
+ }
+ else if ( token == s_allPermission ) // AllPermission
+ {
+ perm <<= security::AllPermission();
+ }
+ else
+ {
+ reader.error( u"expected permission type!" );
+ }
+
+ reader.assureToken( ';' );
+
+ // insert
+ if (!userId.isEmpty())
+ {
+ Sequence< Any > perms( userPermissions[ userId ] );
+ sal_Int32 len = perms.getLength();
+ perms.realloc( len +1 );
+ perms.getArray()[ len ] = perm;
+ userPermissions[ userId ] = perms;
+ }
+ else
+ {
+ sal_Int32 len = defaultPermissions.getLength();
+ defaultPermissions.realloc( len +1 );
+ defaultPermissions.getArray()[ len ] = perm;
+ }
+
+ token = reader.assureToken(); // next permissions token
+ }
+
+ reader.assureToken( ';' ); // semi
+ token = reader.getToken(); // next grant token
+ }
+
+ // assign new ones
+ MutexGuard guard( m_aMutex );
+ m_defaultPermissions = defaultPermissions;
+ m_userPermissions = userPermissions;
+}
+
+
+OUString FilePolicy::getImplementationName()
+{
+ return IMPL_NAME;
+}
+
+sal_Bool FilePolicy::supportsService( OUString const & serviceName )
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+Sequence< OUString > FilePolicy::getSupportedServiceNames()
+{
+ return { "com.sun.star.security.Policy" };
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_security_comp_stoc_FilePolicy_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new FilePolicy(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/lru_cache.h b/stoc/source/security/lru_cache.h
new file mode 100644
index 0000000000..402b41d587
--- /dev/null
+++ b/stoc/source/security/lru_cache.h
@@ -0,0 +1,210 @@
+/* -*- 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_STOC_SOURCE_SECURITY_LRU_CACHE_H
+#define INCLUDED_STOC_SOURCE_SECURITY_LRU_CACHE_H
+
+#include <memory>
+#include <unordered_map>
+
+// __CACHE_DIAGNOSE works only for OUString keys
+#ifdef __CACHE_DIAGNOSE
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/string.hxx>
+#include <sal/log.hxx>
+#endif
+
+
+namespace stoc_sec
+{
+
+/** Implementation of a least recently used (lru) cache.
+*/
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+class lru_cache
+{
+ struct Entry
+ {
+ t_key m_key;
+ t_val m_val;
+ Entry * m_pred;
+ Entry * m_succ;
+ };
+ typedef std::unordered_map< t_key, Entry *, t_hashKey, t_equalKey > t_key2element;
+ t_key2element m_key2element;
+ ::std::size_t m_size;
+
+ std::unique_ptr<Entry[]> m_block;
+ mutable Entry * m_head;
+ mutable Entry * m_tail;
+ inline void toFront( Entry * entry ) const;
+
+public:
+ /** Default Ctor. Does not cache.
+ */
+ inline lru_cache();
+
+ /** Retrieves a pointer to value in cache. Returns 0, if none was found.
+
+ @param key a key
+ @return pointer to value or 0
+ */
+ inline t_val const * lookup( t_key const & key ) const;
+
+ /** Sets a value to be cached for given key.
+
+ @param key a key
+ @param val a value
+ */
+ inline void set( t_key const & key, t_val const & val );
+
+ /** Sets the number of elements to be cached. This will clear previous entries.
+
+ @param cacheSize number of elements to be cached
+ */
+ inline void setSize( ::std::size_t size );
+};
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline void lru_cache< t_key, t_val, t_hashKey, t_equalKey >::setSize(
+ ::std::size_t size )
+{
+ m_key2element.clear();
+ m_block.reset();
+ m_size = size;
+
+ if (0 < m_size)
+ {
+ m_block.reset( new Entry[ m_size ] );
+ m_head = m_block.get();
+ m_tail = m_block.get() + m_size -1;
+ for ( ::std::size_t nPos = m_size; nPos--; )
+ {
+ m_block[ nPos ].m_pred = m_block.get() + nPos -1;
+ m_block[ nPos ].m_succ = m_block.get() + nPos +1;
+ }
+ }
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline lru_cache< t_key, t_val, t_hashKey, t_equalKey >::lru_cache()
+ : m_size( 0 )
+ , m_block( nullptr )
+ , m_head( nullptr )
+ , m_tail( nullptr )
+{
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline void lru_cache< t_key, t_val, t_hashKey, t_equalKey >::toFront(
+ Entry * entry ) const
+{
+ if (entry != m_head)
+ {
+ // cut out element
+ if (entry == m_tail)
+ {
+ m_tail = entry->m_pred;
+ }
+ else
+ {
+ entry->m_succ->m_pred = entry->m_pred;
+ entry->m_pred->m_succ = entry->m_succ;
+ }
+ // push to front
+ m_head->m_pred = entry;
+ entry->m_succ = m_head;
+ m_head = entry;
+ }
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline t_val const * lru_cache< t_key, t_val, t_hashKey, t_equalKey >::lookup(
+ t_key const & key ) const
+{
+ if (0 < m_size)
+ {
+ typename t_key2element::const_iterator const iFind( m_key2element.find( key ) );
+ if (iFind != m_key2element.end())
+ {
+ Entry * entry = iFind->second;
+ toFront( entry );
+#ifdef __CACHE_DIAGNOSE
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( "> retrieved element \"" );
+ buf.append( entry->m_key );
+ buf.appendAscii( "\" from cache" );
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+#endif
+ return &entry->m_val;
+ }
+ }
+ return nullptr;
+}
+
+template< typename t_key, typename t_val, typename t_hashKey, typename t_equalKey >
+inline void lru_cache< t_key, t_val, t_hashKey, t_equalKey >::set(
+ t_key const & key, t_val const & val )
+{
+ if (0 < m_size)
+ {
+ typename t_key2element::const_iterator const iFind( m_key2element.find( key ) );
+
+ Entry * entry;
+ if (iFind == m_key2element.end())
+ {
+ entry = m_tail; // erase last element
+#ifdef __CACHE_DIAGNOSE
+ if (entry->m_key.getLength())
+ {
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( "> kicking element \"" );
+ buf.append( entry->m_key );
+ buf.appendAscii( "\" from cache" );
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+ }
+#endif
+ m_key2element.erase( entry->m_key );
+ entry->m_key = key;
+ ::std::pair< typename t_key2element::iterator, bool > insertion(
+ m_key2element.emplace( key, entry ) );
+ OSL_ENSURE( insertion.second, "### inserting new cache entry failed?!" );
+ }
+ else
+ {
+ entry = iFind->second;
+#ifdef __CACHE_DIAGNOSE
+ OUStringBuffer buf( 48 );
+ buf.appendAscii( "> replacing element \"" );
+ buf.append( entry->m_key );
+ buf.appendAscii( "\" in cache" );
+ SAL_INFO("stoc", buf.makeStringAndClear() );
+#endif
+ }
+ entry->m_val = val;
+ toFront( entry );
+ }
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/permissions.cxx b/stoc/source/security/permissions.cxx
new file mode 100644
index 0000000000..48a1f907f0
--- /dev/null
+++ b/stoc/source/security/permissions.cxx
@@ -0,0 +1,601 @@
+/* -*- 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 <vector>
+
+#include <osl/process.h>
+#include <osl/socket.hxx>
+#include <osl/mutex.hxx>
+
+#include <rtl/string.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <com/sun/star/security/RuntimePermission.hpp>
+#include <com/sun/star/security/AllPermission.hpp>
+#include <com/sun/star/io/FilePermission.hpp>
+#include <com/sun/star/connection/SocketPermission.hpp>
+#include <com/sun/star/security/AccessControlException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "permissions.h"
+
+using namespace ::osl;
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+namespace stoc_sec
+{
+
+
+static sal_Int32 makeMask(
+ OUString const & items, char const * const * strings )
+{
+ sal_Int32 mask = 0;
+
+ sal_Int32 n = 0;
+ do
+ {
+ OUString item( o3tl::trim(o3tl::getToken(items, 0, ',', n )) );
+ if ( item.isEmpty())
+ continue;
+ sal_Int32 nPos = 0;
+ while (strings[ nPos ])
+ {
+ if (item.equalsAscii( strings[ nPos ] ))
+ {
+ mask |= (0x80000000 >> nPos);
+ break;
+ }
+ ++nPos;
+ }
+#if OSL_DEBUG_LEVEL > 0
+ if (! strings[ nPos ])
+ {
+ SAL_WARN("stoc", "ignoring unknown socket action: " << item );
+ }
+#endif
+ }
+ while (n >= 0); // all items
+ return mask;
+}
+
+static OUString makeStrings(
+ sal_Int32 mask, char const * const * strings )
+{
+ OUStringBuffer buf( 48 );
+ while (mask)
+ {
+ if (0x80000000 & mask)
+ {
+ buf.appendAscii( *strings );
+ if ((mask << 1) != 0) // more items following
+ buf.append( ',' );
+ }
+ mask = (mask << 1);
+ ++strings;
+ }
+ return buf.makeStringAndClear();
+}
+
+namespace {
+
+class SocketPermission : public Permission
+{
+ static char const * s_actions [];
+ sal_Int32 m_actions;
+
+ OUString m_host;
+ sal_Int32 m_lowerPort;
+ sal_Int32 m_upperPort;
+ mutable OUString m_ip;
+ mutable bool m_resolveErr;
+ mutable bool m_resolvedHost;
+ bool m_wildCardHost;
+
+ inline bool resolveHost() const;
+
+public:
+ SocketPermission(
+ connection::SocketPermission const & perm,
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() );
+ virtual bool implies( Permission const & perm ) const override;
+ virtual OUString toString() const override;
+};
+
+}
+
+char const * SocketPermission::s_actions [] = { "accept", "connect", "listen", "resolve", nullptr };
+
+SocketPermission::SocketPermission(
+ connection::SocketPermission const & perm,
+ ::rtl::Reference< Permission > const & next )
+ : Permission( SOCKET, next )
+ , m_actions( makeMask( perm.Actions, s_actions ) )
+ , m_host( perm.Host )
+ , m_lowerPort( 0 )
+ , m_upperPort( 65535 )
+ , m_resolveErr( false )
+ , m_resolvedHost( false )
+ , m_wildCardHost( !perm.Host.isEmpty() && '*' == perm.Host.pData->buffer[ 0 ] )
+{
+ if (0xe0000000 & m_actions) // if any (except resolve) is given => resolve implied
+ m_actions |= 0x10000000;
+
+ // separate host from portrange
+ sal_Int32 colon = m_host.indexOf( ':' );
+ if (colon < 0) // port [range] not given
+ return;
+
+ sal_Int32 minus = m_host.indexOf( '-', colon +1 );
+ if (minus < 0)
+ {
+ m_lowerPort = m_upperPort = o3tl::toInt32(m_host.subView( colon +1 ));
+ }
+ else if (minus == (colon +1)) // -N
+ {
+ m_upperPort = o3tl::toInt32(m_host.subView( minus +1 ));
+ }
+ else if (minus == (m_host.getLength() -1)) // N-
+ {
+ m_lowerPort = o3tl::toInt32(m_host.subView( colon +1, m_host.getLength() -1 -colon -1 ));
+ }
+ else // A-B
+ {
+ m_lowerPort = o3tl::toInt32(m_host.subView( colon +1, minus - colon -1 ));
+ m_upperPort = o3tl::toInt32(m_host.subView( minus +1 ));
+ }
+ m_host = m_host.copy( 0, colon );
+}
+
+inline bool SocketPermission::resolveHost() const
+{
+ if (m_resolveErr)
+ return false;
+
+ if (! m_resolvedHost)
+ {
+ // dns lookup
+ SocketAddr addr;
+ SocketAddr::resolveHostname( m_host, addr );
+ OUString ip;
+ m_resolveErr = (::osl_Socket_Ok != ::osl_getDottedInetAddrOfSocketAddr(
+ addr.getHandle(), &ip.pData ));
+ if (m_resolveErr)
+ return false;
+
+ MutexGuard guard( Mutex::getGlobalMutex() );
+ if (! m_resolvedHost)
+ {
+ m_ip = ip;
+ m_resolvedHost = true;
+ }
+ }
+ return m_resolvedHost;
+}
+
+bool SocketPermission::implies( Permission const & perm ) const
+{
+ // check type
+ if (SOCKET != perm.m_type)
+ return false;
+ SocketPermission const & demanded = static_cast< SocketPermission const & >( perm );
+
+ // check actions
+ if ((m_actions & demanded.m_actions) != demanded.m_actions)
+ return false;
+
+ // check ports
+ if (demanded.m_lowerPort < m_lowerPort)
+ return false;
+ if (demanded.m_upperPort > m_upperPort)
+ return false;
+
+ // quick check host (DNS names: RFC 1034/1035)
+ if (m_host.equalsIgnoreAsciiCase( demanded.m_host ))
+ return true;
+ // check for host wildcards
+ if (m_wildCardHost)
+ {
+ OUString const & demanded_host = demanded.m_host;
+ if (demanded_host.getLength() <= m_host.getLength())
+ return false;
+ sal_Int32 len = m_host.getLength() -1; // skip star
+ return (0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ demanded_host.getStr() + demanded_host.getLength() - len, len,
+ m_host.pData->buffer + 1, len ));
+ }
+ if (demanded.m_wildCardHost)
+ return false;
+
+ // compare IP addresses
+ if (! resolveHost())
+ return false;
+ if (! demanded.resolveHost())
+ return false;
+ return m_ip == demanded.m_ip;
+}
+
+OUString SocketPermission::toString() const
+{
+ OUStringBuffer buf( 48 );
+ // host
+ buf.append( "com.sun.star.connection.SocketPermission (host=\""
+ + m_host );
+ if (m_resolvedHost)
+ {
+ buf.append( "[" + m_ip + "]" );
+ }
+ // port
+ if (0 != m_lowerPort || 65535 != m_upperPort)
+ {
+ buf.append( ':' );
+ if (m_lowerPort > 0)
+ buf.append( m_lowerPort );
+ if (m_upperPort > m_lowerPort)
+ {
+ buf.append( '-' );
+ if (m_upperPort < 65535)
+ buf.append( m_upperPort );
+ }
+ }
+ // actions
+ buf.append( "\", actions=\""
+ + makeStrings( m_actions, s_actions )
+ + "\")" );
+ return buf.makeStringAndClear();
+}
+
+namespace {
+
+class FilePermission : public Permission
+{
+ static char const * s_actions [];
+ sal_Int32 m_actions;
+
+ OUString m_url;
+ bool m_allFiles;
+
+public:
+ FilePermission(
+ io::FilePermission const & perm,
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() );
+ virtual bool implies( Permission const & perm ) const override;
+ virtual OUString toString() const override;
+};
+
+}
+
+char const * FilePermission::s_actions [] = { "read", "write", "execute", "delete", nullptr };
+
+static OUString const & getWorkingDir()
+{
+ static OUString s_workingDir = []() {
+ OUString workingDir;
+ ::osl_getProcessWorkingDir(&workingDir.pData);
+ return workingDir;
+ }();
+ return s_workingDir;
+}
+
+FilePermission::FilePermission(
+ io::FilePermission const & perm,
+ ::rtl::Reference< Permission > const & next )
+ : Permission( FILE, next )
+ , m_actions( makeMask( perm.Actions, s_actions ) )
+ , m_url( perm.URL )
+ , m_allFiles( perm.URL == "<<ALL FILES>>" )
+{
+ if ( m_allFiles)
+ return;
+
+ if ( m_url == "*" )
+ {
+ m_url = getWorkingDir() + "/*";
+ }
+ else if ( m_url == "-" )
+ {
+ m_url = getWorkingDir() + "/-";
+ }
+ else if (!m_url.startsWith("file:///"))
+ {
+ // relative path
+ OUString out;
+ oslFileError rc = ::osl_getAbsoluteFileURL(
+ getWorkingDir().pData, perm.URL.pData, &out.pData );
+ m_url = (osl_File_E_None == rc ? out : perm.URL); // fallback
+ }
+#ifdef _WIN32
+ // correct win drive letters
+ if (9 < m_url.getLength() && '|' == m_url[ 9 ]) // file:///X|
+ {
+ constexpr OUStringLiteral s_colon = u":";
+ // common case in API is a ':' (sal), so convert '|' to ':'
+ m_url = m_url.replaceAt( 9, 1, s_colon );
+ }
+#endif
+}
+
+bool FilePermission::implies( Permission const & perm ) const
+{
+ // check type
+ if (FILE != perm.m_type)
+ return false;
+ FilePermission const & demanded = static_cast< FilePermission const & >( perm );
+
+ // check actions
+ if ((m_actions & demanded.m_actions) != demanded.m_actions)
+ return false;
+
+ // check url
+ if (m_allFiles)
+ return true;
+ if (demanded.m_allFiles)
+ return false;
+
+#ifdef _WIN32
+ if (m_url.equalsIgnoreAsciiCase( demanded.m_url ))
+ return true;
+#else
+ if (m_url == demanded.m_url )
+ return true;
+#endif
+ if (m_url.getLength() > demanded.m_url.getLength())
+ return false;
+ // check /- wildcard: all files and recursive in that path
+ if (m_url.endsWith("/-"))
+ {
+ // demanded url must start with granted path (including path trailing path sep)
+ sal_Int32 len = m_url.getLength() -1;
+#ifdef _WIN32
+ return (0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len ));
+#else
+ return (0 == ::rtl_ustr_reverseCompare_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len ));
+#endif
+ }
+ // check /* wildcard: all files in that path (not recursive!)
+ if (m_url.endsWith("/*"))
+ {
+ // demanded url must start with granted path (including path trailing path sep)
+ sal_Int32 len = m_url.getLength() -1;
+#ifdef _WIN32
+ return ((0 == ::rtl_ustr_compareIgnoreAsciiCase_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len )) &&
+ (0 > demanded.m_url.indexOf( '/', len ))); // in addition, no deeper paths
+#else
+ return ((0 == ::rtl_ustr_reverseCompare_WithLength(
+ demanded.m_url.pData->buffer, len, m_url.pData->buffer, len )) &&
+ (0 > demanded.m_url.indexOf( '/', len ))); // in addition, no deeper paths
+#endif
+ }
+ return false;
+}
+
+OUString FilePermission::toString() const
+{
+ return
+ // url
+ "com.sun.star.io.FilePermission (url=\"" + m_url
+ // actions
+ + "\", actions=\"" + makeStrings( m_actions, s_actions ) + "\")";
+}
+
+namespace {
+
+class RuntimePermission : public Permission
+{
+ OUString m_name;
+
+public:
+ RuntimePermission(
+ security::RuntimePermission const & perm,
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() )
+ : Permission( RUNTIME, next )
+ , m_name( perm.Name )
+ {}
+ virtual bool implies( Permission const & perm ) const override;
+ virtual OUString toString() const override;
+};
+
+}
+
+bool RuntimePermission::implies( Permission const & perm ) const
+{
+ // check type
+ if (RUNTIME != perm.m_type)
+ return false;
+ RuntimePermission const & demanded = static_cast< RuntimePermission const & >( perm );
+
+ // check name
+ return m_name == demanded.m_name;
+}
+
+OUString RuntimePermission::toString() const
+{
+ return "com.sun.star.security.RuntimePermission (name=\"" +
+ m_name + "\")";
+}
+
+
+bool AllPermission::implies( Permission const & ) const
+{
+ return true;
+}
+
+OUString AllPermission::toString() const
+{
+ return "com.sun.star.security.AllPermission";
+}
+
+
+PermissionCollection::PermissionCollection(
+ Sequence< Any > const & permissions, PermissionCollection const & addition )
+ : m_head( addition.m_head )
+{
+ Any const * perms = permissions.getConstArray();
+ for ( sal_Int32 nPos = permissions.getLength(); nPos--; )
+ {
+ Any const & perm = perms[ nPos ];
+ Type const & perm_type = perm.getValueType();
+
+ // supported permission types
+ if (perm_type.equals( cppu::UnoType<io::FilePermission>::get()))
+ {
+ m_head = new FilePermission(
+ *static_cast< io::FilePermission const * >( perm.pData ), m_head );
+ }
+ else if (perm_type.equals( cppu::UnoType<connection::SocketPermission>::get()))
+ {
+ m_head = new SocketPermission(
+ *static_cast< connection::SocketPermission const * >( perm.pData ), m_head );
+ }
+ else if (perm_type.equals( cppu::UnoType<security::RuntimePermission>::get()))
+ {
+ m_head = new RuntimePermission(
+ *static_cast< security::RuntimePermission const * >( perm.pData ), m_head );
+ }
+ else if (perm_type.equals( cppu::UnoType<security::AllPermission>::get()))
+ {
+ m_head = new AllPermission( m_head );
+ }
+ else
+ {
+ throw RuntimeException( "checking for unsupported permission type: " + perm_type.getTypeName() );
+ }
+ }
+}
+#ifdef __DIAGNOSE
+
+Sequence< OUString > PermissionCollection::toStrings() const
+{
+ std::vector< OUString > strings;
+ strings.reserve( 8 );
+ for ( Permission * perm = m_head.get(); perm; perm = perm->m_next.get() )
+ {
+ strings.push_back( perm->toString() );
+ }
+ return Sequence< OUString >( strings.data(), strings.size() );
+}
+#endif
+
+static bool implies(
+ ::rtl::Reference< Permission > const & head, Permission const & demanded )
+{
+ for ( Permission * perm = head.get(); perm; perm = perm->m_next.get() )
+ {
+ if (perm->implies( demanded ))
+ return true;
+ }
+ return false;
+}
+
+#ifdef __DIAGNOSE
+
+static void demanded_diag(
+ Permission const & perm )
+{
+ OUStringBuffer buf( 48 );
+ buf.append( "demanding " );
+ buf.append( perm.toString() );
+ buf.append( " => ok." );
+ OString str(
+ OUStringToOString( buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US ) );
+ SAL_INFO("stoc",( "%s", str.getStr() );
+}
+#endif
+
+static void throwAccessControlException(
+ Permission const & perm, Any const & demanded_perm )
+{
+ throw security::AccessControlException(
+ "access denied: " + perm.toString(),
+ Reference< XInterface >(), demanded_perm );
+}
+
+void PermissionCollection::checkPermission( Any const & perm ) const
+{
+ Type const & demanded_type = perm.getValueType();
+
+ // supported permission types
+ // stack object of SimpleReferenceObject are ok, as long as they are not
+ // assigned to a ::rtl::Reference<> (=> delete this)
+ if (demanded_type.equals( cppu::UnoType<io::FilePermission>::get()))
+ {
+ FilePermission demanded(
+ *static_cast< io::FilePermission const * >( perm.pData ) );
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else if (demanded_type.equals( cppu::UnoType<connection::SocketPermission>::get()))
+ {
+ SocketPermission demanded(
+ *static_cast< connection::SocketPermission const * >( perm.pData ) );
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else if (demanded_type.equals( cppu::UnoType<security::RuntimePermission>::get()))
+ {
+ RuntimePermission demanded(
+ *static_cast< security::RuntimePermission const * >( perm.pData ) );
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else if (demanded_type.equals( cppu::UnoType<security::AllPermission>::get()))
+ {
+ AllPermission demanded;
+ if (implies( m_head, demanded ))
+ {
+#ifdef __DIAGNOSE
+ demanded_diag( demanded );
+#endif
+ return;
+ }
+ throwAccessControlException( demanded, perm );
+ }
+ else
+ {
+ throw RuntimeException( "checking for unsupported permission type: " + demanded_type.getTypeName() );
+ }
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/security/permissions.h b/stoc/source/security/permissions.h
new file mode 100644
index 0000000000..99c5584635
--- /dev/null
+++ b/stoc/source/security/permissions.h
@@ -0,0 +1,86 @@
+/* -*- 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_STOC_SOURCE_SECURITY_PERMISSIONS_H
+#define INCLUDED_STOC_SOURCE_SECURITY_PERMISSIONS_H
+
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+#include <utility>
+
+namespace com::sun::star::uno { class Any; }
+namespace com::sun::star::uno { template <class E> class Sequence; }
+
+namespace stoc_sec
+{
+
+class Permission : public ::salhelper::SimpleReferenceObject
+{
+public:
+ ::rtl::Reference< Permission > m_next;
+ // mode
+ enum t_type { ALL, RUNTIME, SOCKET, FILE } m_type;
+
+ Permission(
+ t_type type,
+ ::rtl::Reference< Permission > next )
+ : m_next(std::move( next ))
+ , m_type( type )
+ {}
+
+ virtual bool implies( Permission const & perm ) const = 0;
+ virtual OUString toString() const = 0;
+};
+
+class AllPermission : public Permission
+{
+public:
+ explicit AllPermission(
+ ::rtl::Reference< Permission > const & next = ::rtl::Reference< Permission >() )
+ : Permission( ALL, next )
+ {}
+
+ virtual bool implies( Permission const & ) const override;
+ virtual OUString toString() const override;
+};
+
+
+class PermissionCollection
+{
+ ::rtl::Reference< Permission > m_head;
+public:
+ PermissionCollection()
+ {}
+ explicit PermissionCollection( ::rtl::Reference< Permission > single )
+ : m_head(std::move( single ))
+ {}
+ PermissionCollection(
+ css::uno::Sequence< css::uno::Any > const & permissions,
+ PermissionCollection const & addition = PermissionCollection() );
+#ifdef __DIAGNOSE
+ css::uno::Sequence< OUString > toStrings() const;
+#endif
+ void checkPermission( css::uno::Any const & perm ) const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/servicemanager/servicemanager.cxx b/stoc/source/servicemanager/servicemanager.cxx
new file mode 100644
index 0000000000..c61e23cf85
--- /dev/null
+++ b/stoc/source/servicemanager/servicemanager.cxx
@@ -0,0 +1,1476 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <osl/mutex.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#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/XEventListener.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/container/XSet.hpp>
+#include <com/sun/star/container/XElementAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <iterator>
+#include <mutex>
+#include <string_view>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::beans;
+using namespace css::registry;
+using namespace css::lang;
+using namespace css::container;
+using namespace cppu;
+using namespace osl;
+
+namespace {
+
+Sequence< OUString > retrieveAsciiValueList(
+ const Reference< XSimpleRegistry > &xReg, const OUString &keyName )
+{
+ Reference< XEnumerationAccess > xAccess( xReg, UNO_QUERY );
+ Sequence< OUString > seq;
+ if( xAccess.is() )
+ {
+ Reference< XEnumeration > xEnum = xAccess->createEnumeration();
+ while( xEnum.is() && xEnum->hasMoreElements() )
+ {
+ Reference< XSimpleRegistry > xTempReg;
+ xEnum->nextElement() >>= xTempReg;
+ if( xTempReg.is() )
+ {
+ const Sequence< OUString > seq2 = retrieveAsciiValueList( xTempReg, keyName );
+
+ if( seq2.hasElements() )
+ {
+ sal_Int32 n1Len = seq.getLength();
+ sal_Int32 n2Len = seq2.getLength();
+
+ seq.realloc( n1Len + n2Len );
+ std::copy(seq2.begin(), seq2.end(), std::next(seq.getArray(), n1Len));
+ }
+ }
+ }
+ }
+ else if( xReg.is () )
+ {
+ try
+ {
+ Reference< XRegistryKey > rRootKey = xReg->getRootKey();
+ if( rRootKey.is() )
+ {
+ Reference<XRegistryKey > xKey = rRootKey->openKey(keyName);
+ if( xKey.is() )
+ {
+ seq = xKey->getAsciiListValue();
+ }
+ }
+ }
+ catch( InvalidRegistryException & )
+ {
+ }
+ catch (InvalidValueException &)
+ {
+ }
+ }
+ return seq;
+}
+
+/*****************************************************************************
+ Enumeration by ServiceName
+*****************************************************************************/
+
+typedef std::unordered_set< Reference<XInterface > > HashSet_Ref;
+
+
+class ServiceEnumeration_Impl : public WeakImplHelper< XEnumeration >
+{
+public:
+ explicit ServiceEnumeration_Impl( const Sequence< Reference<XInterface > > & rFactories )
+ : aFactories( rFactories )
+ , nIt( 0 )
+ {}
+
+ // XEnumeration
+ sal_Bool SAL_CALL hasMoreElements() override;
+ Any SAL_CALL nextElement() override;
+private:
+ std::mutex aMutex;
+ Sequence< Reference<XInterface > > aFactories;
+ sal_Int32 nIt;
+};
+
+// XEnumeration
+sal_Bool ServiceEnumeration_Impl::hasMoreElements()
+{
+ std::scoped_lock aGuard( aMutex );
+ return nIt != aFactories.getLength();
+}
+
+// XEnumeration
+Any ServiceEnumeration_Impl::nextElement()
+{
+ std::scoped_lock aGuard( aMutex );
+ if( nIt == aFactories.getLength() )
+ throw NoSuchElementException("no more elements");
+
+ return Any( &aFactories.getConstArray()[nIt++], cppu::UnoType<XInterface>::get());
+}
+
+
+class PropertySetInfo_Impl : public WeakImplHelper< beans::XPropertySetInfo >
+{
+ Sequence< beans::Property > m_properties;
+
+public:
+ explicit PropertySetInfo_Impl( Sequence< beans::Property > const & properties )
+ : m_properties( properties )
+ {}
+
+ // XPropertySetInfo impl
+ virtual Sequence< beans::Property > SAL_CALL getProperties() override;
+ virtual beans::Property SAL_CALL getPropertyByName( OUString const & name ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( OUString const & name ) override;
+};
+
+Sequence< beans::Property > PropertySetInfo_Impl::getProperties()
+{
+ return m_properties;
+}
+
+beans::Property PropertySetInfo_Impl::getPropertyByName( OUString const & name )
+{
+ beans::Property const * p = m_properties.getConstArray();
+ for ( sal_Int32 nPos = m_properties.getLength(); nPos--; )
+ {
+ if (p[ nPos ].Name == name)
+ return p[ nPos ];
+ }
+ throw beans::UnknownPropertyException(
+ "unknown property: " + name );
+}
+
+sal_Bool PropertySetInfo_Impl::hasPropertyByName( OUString const & name )
+{
+ return std::any_of(std::cbegin(m_properties), std::cend(m_properties),
+ [&name](const beans::Property& rProp) { return rProp.Name == name; });
+}
+
+
+/*****************************************************************************
+ Enumeration by implementation
+*****************************************************************************/
+class ImplementationEnumeration_Impl : public WeakImplHelper< XEnumeration >
+{
+public:
+ explicit ImplementationEnumeration_Impl( HashSet_Ref xImplementationMap )
+ : aImplementationMap(std::move( xImplementationMap ))
+ , aIt( aImplementationMap.begin() )
+ {}
+
+ // XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual Any SAL_CALL nextElement() override;
+
+private:
+ std::mutex aMutex;
+ HashSet_Ref aImplementationMap;
+ HashSet_Ref::iterator aIt;
+};
+
+// XEnumeration
+sal_Bool ImplementationEnumeration_Impl::hasMoreElements()
+{
+ std::scoped_lock aGuard( aMutex );
+ return aIt != aImplementationMap.end();
+}
+
+// XEnumeration
+Any ImplementationEnumeration_Impl::nextElement()
+{
+ std::scoped_lock aGuard( aMutex );
+ if( aIt == aImplementationMap.end() )
+ throw NoSuchElementException("no more elements");
+
+ Any ret( &(*aIt), cppu::UnoType<XInterface>::get());
+ ++aIt;
+ return ret;
+}
+
+/*****************************************************************************
+ Hash tables
+*****************************************************************************/
+typedef std::unordered_set
+<
+ OUString
+> HashSet_OWString;
+
+typedef std::unordered_multimap
+<
+ OUString,
+ Reference<XInterface >
+> HashMultimap_OWString_Interface;
+
+typedef std::unordered_map
+<
+ OUString,
+ Reference<XInterface >
+> HashMap_OWString_Interface;
+
+/*****************************************************************************
+ class OServiceManager_Listener
+*****************************************************************************/
+class OServiceManager_Listener : public WeakImplHelper< XEventListener >
+{
+private:
+ WeakReference<XSet > xSMgr;
+
+public:
+ explicit OServiceManager_Listener( const Reference<XSet > & rSMgr )
+ : xSMgr( rSMgr )
+ {}
+
+ // XEventListener
+ virtual void SAL_CALL disposing(const EventObject & rEvt ) override;
+};
+
+void OServiceManager_Listener::disposing(const EventObject & rEvt )
+{
+ Reference<XSet > x( xSMgr );
+ if( !x.is() )
+ return;
+
+ try
+ {
+ x->remove( Any( &rEvt.Source, cppu::UnoType<XInterface>::get()) );
+ }
+ catch( const IllegalArgumentException & )
+ {
+ OSL_FAIL( "IllegalArgumentException caught" );
+ }
+ catch( const NoSuchElementException & )
+ {
+ OSL_FAIL( "NoSuchElementException caught" );
+ }
+}
+
+
+/*****************************************************************************
+ class OServiceManager
+*****************************************************************************/
+
+typedef WeakComponentImplHelper<
+ lang::XMultiServiceFactory, lang::XMultiComponentFactory, lang::XServiceInfo,
+ lang::XInitialization,
+ container::XSet, container::XContentEnumerationAccess,
+ beans::XPropertySet > t_OServiceManager_impl;
+
+class OServiceManager
+ : public cppu::BaseMutex
+ , public t_OServiceManager_impl
+{
+public:
+ explicit OServiceManager( Reference< XComponentContext > const & xContext );
+
+ // XInitialization
+ void SAL_CALL initialize( Sequence< Any > const & args ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XMultiComponentFactory
+ virtual Reference< XInterface > SAL_CALL createInstanceWithContext(
+ OUString const & rServiceSpecifier, Reference< XComponentContext > const & xContext ) override;
+ virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
+ OUString const & rServiceSpecifier,
+ Sequence< Any > const & rArguments,
+ Reference< XComponentContext > const & xContext ) override;
+// virtual Sequence< OUString > SAL_CALL getAvailableServiceNames()
+// throw (RuntimeException);
+
+ // XMultiServiceFactory
+ virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() override;
+ virtual Reference<XInterface > SAL_CALL createInstance(const OUString &) override;
+ virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const OUString &, const Sequence<Any >& Arguments) override;
+
+ // The same as the getAvailableServiceNames, but only unique names
+ Sequence< OUString > getUniqueAvailableServiceNames(
+ HashSet_OWString & aNameSet );
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ // XEnumerationAccess
+ virtual Reference<XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XSet
+ virtual sal_Bool SAL_CALL has( const Any & Element ) override;
+ virtual void SAL_CALL insert( const Any & Element ) override;
+ virtual void SAL_CALL remove( const Any & Element ) override;
+
+ // XContentEnumerationAccess
+ //Sequence< OUString > getAvailableServiceNames() throw( (Exception) );
+ virtual Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose() override;
+
+ // XPropertySet
+ Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override;
+ Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+ void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override;
+ void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override;
+ void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override;
+ void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override;
+
+protected:
+ bool is_disposed() const;
+ void check_undisposed() const;
+ virtual void SAL_CALL disposing() override;
+
+ bool haveFactoryWithThisImplementation(const OUString& aImplName);
+
+ virtual Sequence< Reference< XInterface > > queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & xContext );
+
+ Reference< XComponentContext > m_xContext;
+
+ Reference< beans::XPropertySetInfo > m_xPropertyInfo;
+
+ // factories which have been loaded and not inserted( by XSet::insert)
+ // are remembered by this set.
+ HashSet_Ref m_SetLoadedFactories;
+private:
+
+ Reference<XEventListener > getFactoryListener();
+
+
+ HashMultimap_OWString_Interface m_ServiceMap;
+ HashSet_Ref m_ImplementationMap;
+ HashMap_OWString_Interface m_ImplementationNameMap;
+ Reference<XEventListener > xFactoryListener;
+ bool m_bInDisposing;
+};
+
+
+bool OServiceManager::is_disposed() const
+{
+ // ought to be guarded by m_mutex:
+ return (m_bInDisposing || rBHelper.bDisposed);
+}
+
+
+void OServiceManager::check_undisposed() const
+{
+ if (is_disposed())
+ {
+ throw lang::DisposedException(
+ "service manager instance has already been disposed!",
+ const_cast<OServiceManager *>(this)->getXWeak() );
+ }
+}
+
+
+typedef WeakComponentImplHelper<
+ lang::XMultiServiceFactory, lang::XMultiComponentFactory, lang::XServiceInfo,
+ container::XSet, container::XContentEnumerationAccess,
+ beans::XPropertySet > t_OServiceManagerWrapper_impl;
+
+class OServiceManagerWrapper : public cppu::BaseMutex, public t_OServiceManagerWrapper_impl
+{
+ Reference< XComponentContext > m_xContext;
+ Reference< XMultiComponentFactory > m_root;
+ Reference< XMultiComponentFactory > const & getRoot() const
+ {
+ if (! m_root.is())
+ {
+ throw lang::DisposedException(
+ "service manager instance has already been disposed!" );
+ }
+ return m_root;
+ }
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+public:
+ explicit OServiceManagerWrapper(
+ Reference< XComponentContext > const & xContext );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override
+ { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->getImplementationName(); }
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override
+ { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->supportsService( ServiceName ); }
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override
+ { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->getSupportedServiceNames(); }
+
+ // XMultiComponentFactory
+ virtual Reference< XInterface > SAL_CALL createInstanceWithContext(
+ OUString const & rServiceSpecifier, Reference< XComponentContext > const & xContext ) override
+ { return getRoot()->createInstanceWithContext( rServiceSpecifier, xContext ); }
+ virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext(
+ OUString const & rServiceSpecifier,
+ Sequence< Any > const & rArguments,
+ Reference< XComponentContext > const & xContext ) override
+ { return getRoot()->createInstanceWithArgumentsAndContext( rServiceSpecifier, rArguments, xContext ); }
+// virtual Sequence< OUString > SAL_CALL getAvailableServiceNames()
+// throw (RuntimeException);
+
+ // XMultiServiceFactory
+ virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() override
+ { return getRoot()->getAvailableServiceNames(); }
+ virtual Reference<XInterface > SAL_CALL createInstance(const OUString & name) override
+ { return getRoot()->createInstanceWithContext( name, m_xContext ); }
+ virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const OUString & name, const Sequence<Any >& Arguments) override
+ { return getRoot()->createInstanceWithArgumentsAndContext( name, Arguments, m_xContext ); }
+
+ // XElementAccess
+ virtual Type SAL_CALL getElementType() override
+ { return Reference< XElementAccess >(getRoot(), UNO_QUERY_THROW)->getElementType(); }
+ virtual sal_Bool SAL_CALL hasElements() override
+ { return Reference< XElementAccess >(getRoot(), UNO_QUERY_THROW)->hasElements(); }
+
+ // XEnumerationAccess
+ virtual Reference<XEnumeration > SAL_CALL createEnumeration() override
+ { return Reference< XEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createEnumeration(); }
+
+ // XSet
+ virtual sal_Bool SAL_CALL has( const Any & Element ) override
+ { return Reference< XSet >(getRoot(), UNO_QUERY_THROW)->has( Element ); }
+ virtual void SAL_CALL insert( const Any & Element ) override
+ { Reference< XSet >(getRoot(), UNO_QUERY_THROW)->insert( Element ); }
+ virtual void SAL_CALL remove( const Any & Element ) override
+ { Reference< XSet >(getRoot(), UNO_QUERY_THROW)->remove( Element ); }
+
+ // XContentEnumerationAccess
+ //Sequence< OUString > getAvailableServiceNames() throw( (Exception) );
+ virtual Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override
+ { return Reference< XContentEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createContentEnumeration( aServiceName ); }
+
+ // XPropertySet
+ Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override
+ { return Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->getPropertySetInfo(); }
+
+ void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override;
+ Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+
+ void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addPropertyChangeListener( PropertyName, aListener ); }
+ void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removePropertyChangeListener( PropertyName, aListener ); }
+ void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addVetoableChangeListener( PropertyName, aListener ); }
+ void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override
+ { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removeVetoableChangeListener( PropertyName, aListener ); }
+};
+
+void SAL_CALL OServiceManagerWrapper::setPropertyValue(
+ const OUString& PropertyName, const Any& aValue )
+{
+ if ( PropertyName == "DefaultContext" )
+ {
+ Reference< XComponentContext > xContext;
+ if (!(aValue >>= xContext))
+ {
+ throw IllegalArgumentException(
+ "no XComponentContext given!",
+ getXWeak(), 1 );
+ }
+
+ MutexGuard aGuard( m_aMutex );
+ m_xContext = xContext;
+
+ }
+ else
+ {
+ Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->setPropertyValue( PropertyName, aValue );
+ }
+}
+
+Any SAL_CALL OServiceManagerWrapper::getPropertyValue(
+ const OUString& PropertyName )
+{
+ if ( PropertyName == "DefaultContext" )
+ {
+ MutexGuard aGuard( m_aMutex );
+ if( m_xContext.is() )
+ return Any( m_xContext );
+ else
+ return Any();
+ }
+ else
+ {
+ return Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->getPropertyValue( PropertyName );
+ }
+}
+
+void OServiceManagerWrapper::disposing()
+{
+ m_xContext.clear();
+
+// no m_root->dispose(), because every context disposes its service manager...
+ m_root.clear();
+}
+
+OServiceManagerWrapper::OServiceManagerWrapper(
+ Reference< XComponentContext > const & xContext )
+ : t_OServiceManagerWrapper_impl( m_aMutex )
+ , m_xContext( xContext )
+ , m_root( xContext->getServiceManager() )
+{
+ if (! m_root.is())
+ {
+ throw RuntimeException(
+ "no service manager to wrap" );
+ }
+}
+
+
+/**
+ * Create a ServiceManager
+ */
+OServiceManager::OServiceManager( Reference< XComponentContext > const & xContext )
+ : t_OServiceManager_impl( m_aMutex )
+ , m_xContext( xContext )
+ , m_bInDisposing( false )
+{}
+
+// XComponent
+void OServiceManager::dispose()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ return;
+ t_OServiceManager_impl::dispose();
+}
+
+void OServiceManager::disposing()
+{
+ // dispose all factories
+ HashSet_Ref aImpls;
+ {
+ MutexGuard aGuard( m_aMutex );
+ m_bInDisposing = true;
+ aImpls = m_ImplementationMap;
+ }
+ for( const auto& rxImpl : aImpls )
+ {
+ try
+ {
+ Reference<XComponent > xComp( Reference<XComponent >::query( rxImpl ) );
+ if( xComp.is() )
+ xComp->dispose();
+ }
+ catch (const RuntimeException & exc)
+ {
+ SAL_INFO("stoc", "RuntimeException occurred upon disposing factory: " << exc);
+ }
+ }
+
+ // dispose
+ HashSet_Ref aImplMap;
+ {
+ MutexGuard aGuard( m_aMutex );
+ // erase all members
+ m_ServiceMap = HashMultimap_OWString_Interface();
+ aImplMap = m_ImplementationMap;
+ m_ImplementationMap = HashSet_Ref();
+ m_ImplementationNameMap = HashMap_OWString_Interface();
+ m_SetLoadedFactories= HashSet_Ref();
+ }
+
+ m_xContext.clear();
+
+ // not only the Event should hold the object
+ OSL_ASSERT( m_refCount != 1 );
+}
+
+// XPropertySet
+Reference<XPropertySetInfo > OServiceManager::getPropertySetInfo()
+{
+ check_undisposed();
+ if (! m_xPropertyInfo.is())
+ {
+ Sequence< beans::Property > seq{ beans::Property(
+ "DefaultContext", -1, cppu::UnoType<decltype(m_xContext)>::get(), 0 ) };
+ Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) );
+
+ MutexGuard aGuard( m_aMutex );
+ if (! m_xPropertyInfo.is())
+ {
+ m_xPropertyInfo = xInfo;
+ }
+ }
+ return m_xPropertyInfo;
+}
+
+void OServiceManager::setPropertyValue(
+ const OUString& PropertyName, const Any& aValue )
+{
+ check_undisposed();
+ if ( PropertyName != "DefaultContext" )
+ {
+ throw UnknownPropertyException(
+ "unknown property " + PropertyName,
+ getXWeak() );
+ }
+
+ Reference< XComponentContext > xContext;
+ if (!(aValue >>= xContext))
+ {
+ throw IllegalArgumentException(
+ "no XComponentContext given!",
+ getXWeak(), 1 );
+ }
+
+ MutexGuard aGuard( m_aMutex );
+ m_xContext = xContext;
+}
+
+Any OServiceManager::getPropertyValue(const OUString& PropertyName)
+{
+ check_undisposed();
+ if ( PropertyName == "DefaultContext" )
+ {
+ MutexGuard aGuard( m_aMutex );
+ if( m_xContext.is() )
+ return Any( m_xContext );
+ else
+ return Any();
+ }
+ else
+ {
+ UnknownPropertyException except("ServiceManager : unknown property " + PropertyName, {});
+ throw except;
+ }
+}
+
+void OServiceManager::addPropertyChangeListener(
+ const OUString&, const Reference<XPropertyChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+void OServiceManager::removePropertyChangeListener(
+ const OUString&, const Reference<XPropertyChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+void OServiceManager::addVetoableChangeListener(
+ const OUString&, const Reference<XVetoableChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+void OServiceManager::removeVetoableChangeListener(
+ const OUString&, const Reference<XVetoableChangeListener >&)
+{
+ check_undisposed();
+ throw UnknownPropertyException("unsupported");
+}
+
+// OServiceManager
+Reference<XEventListener > OServiceManager::getFactoryListener()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ if( !xFactoryListener.is() )
+ xFactoryListener = new OServiceManager_Listener( this );
+ return xFactoryListener;
+}
+
+// XMultiServiceFactory, XContentEnumeration
+Sequence< OUString > OServiceManager::getUniqueAvailableServiceNames(
+ HashSet_OWString & aNameSet )
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ for( const auto& rEntry : m_ServiceMap )
+ aNameSet.insert( rEntry.first );
+
+ /* do not return the implementation names
+ HashMap_OWString_Interface m_ImplementationNameMap;
+ HashMap_OWString_Interface::iterator aIt = m_ImplementationNameMap.begin();
+ while( aIt != m_ImplementationNameMap.end() )
+ aNameSet.insert( (*aIt++).first );
+ */
+
+ return comphelper::containerToSequence(aNameSet);
+}
+
+// XMultiComponentFactory
+Reference< XInterface > OServiceManager::createInstanceWithContext(
+ OUString const & rServiceSpecifier,
+ Reference< XComponentContext > const & xContext )
+{
+ check_undisposed();
+#if OSL_DEBUG_LEVEL > 0
+ Reference< beans::XPropertySet > xProps( xContext->getServiceManager(), UNO_QUERY );
+ OSL_ASSERT( xProps.is() );
+ if (xProps.is())
+ {
+ Reference< XComponentContext > xDefContext;
+ xProps->getPropertyValue( "DefaultContext" ) >>= xDefContext;
+ OSL_ENSURE(
+ xContext == xDefContext,
+ "### default context of service manager singleton differs from context holding it!" );
+ }
+#endif
+
+ const Sequence< Reference< XInterface > > factories(
+ queryServiceFactories( rServiceSpecifier, xContext ) );
+ for ( Reference< XInterface > const & xFactory : factories )
+ {
+ try
+ {
+ if (xFactory.is())
+ {
+ Reference< XSingleComponentFactory > xFac( xFactory, UNO_QUERY );
+ if (xFac.is())
+ {
+ return xFac->createInstanceWithContext( xContext );
+ }
+ else
+ {
+ Reference< XSingleServiceFactory > xFac2( xFactory, UNO_QUERY );
+ if (xFac2.is())
+ {
+ SAL_INFO("stoc", "ignoring given context raising service " << rServiceSpecifier << "!!!");
+ return xFac2->createInstance();
+ }
+ }
+ }
+ }
+ catch (const lang::DisposedException & exc)
+ {
+ SAL_INFO("stoc", "DisposedException occurred: " << exc);
+ }
+ }
+
+ return Reference< XInterface >();
+}
+// XMultiComponentFactory
+Reference< XInterface > OServiceManager::createInstanceWithArgumentsAndContext(
+ OUString const & rServiceSpecifier,
+ Sequence< Any > const & rArguments,
+ Reference< XComponentContext > const & xContext )
+{
+ check_undisposed();
+#if OSL_DEBUG_LEVEL > 0
+ Reference< beans::XPropertySet > xProps( xContext->getServiceManager(), UNO_QUERY );
+ OSL_ASSERT( xProps.is() );
+ if (xProps.is())
+ {
+ Reference< XComponentContext > xDefContext;
+ xProps->getPropertyValue( "DefaultContext" ) >>= xDefContext;
+ OSL_ENSURE(
+ xContext == xDefContext,
+ "### default context of service manager singleton differs from context holding it!" );
+ }
+#endif
+
+ const Sequence< Reference< XInterface > > factories(
+ queryServiceFactories( rServiceSpecifier, xContext ) );
+ for ( Reference< XInterface > const & xFactory : factories )
+ {
+ try
+ {
+ if (xFactory.is())
+ {
+ Reference< XSingleComponentFactory > xFac( xFactory, UNO_QUERY );
+ if (xFac.is())
+ {
+ return xFac->createInstanceWithArgumentsAndContext( rArguments, xContext );
+ }
+ else
+ {
+ Reference< XSingleServiceFactory > xFac2( xFactory, UNO_QUERY );
+ if (xFac2.is())
+ {
+ SAL_INFO("stoc", "ignoring given context raising service " << rServiceSpecifier << "!!!");
+ return xFac2->createInstanceWithArguments( rArguments );
+ }
+ }
+ }
+ }
+ catch (const lang::DisposedException & exc)
+ {
+ SAL_INFO("stoc", "DisposedException occurred: " << exc);
+ }
+ }
+
+ return Reference< XInterface >();
+}
+
+// XMultiServiceFactory, XMultiComponentFactory, XContentEnumeration
+Sequence< OUString > OServiceManager::getAvailableServiceNames()
+{
+ check_undisposed();
+ // all names
+ HashSet_OWString aNameSet;
+ return getUniqueAvailableServiceNames( aNameSet );
+}
+
+// XMultipleServiceFactory
+Reference<XInterface > OServiceManager::createInstance(
+ const OUString& rServiceSpecifier )
+{
+ return createInstanceWithContext(
+ rServiceSpecifier, m_xContext );
+}
+
+// XMultipleServiceFactory
+Reference<XInterface > OServiceManager::createInstanceWithArguments(
+ const OUString& rServiceSpecifier,
+ const Sequence<Any >& rArguments )
+{
+ return createInstanceWithArgumentsAndContext(
+ rServiceSpecifier, rArguments, m_xContext );
+}
+
+// XInitialization
+void OServiceManager::initialize( Sequence< Any > const & )
+{
+ check_undisposed();
+ OSL_FAIL( "not impl!" );
+}
+
+// XServiceInfo
+OUString OServiceManager::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.OServiceManager";
+}
+
+// XServiceInfo
+sal_Bool OServiceManager::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > OServiceManager::getSupportedServiceNames()
+{
+ return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" };
+}
+
+
+Sequence< Reference< XInterface > > OServiceManager::queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & )
+{
+ Sequence< Reference< XInterface > > ret;
+
+ MutexGuard aGuard( m_aMutex );
+ ::std::pair<
+ HashMultimap_OWString_Interface::iterator,
+ HashMultimap_OWString_Interface::iterator> p(
+ m_ServiceMap.equal_range( aServiceName ) );
+
+ if (p.first == p.second) // no factories
+ {
+ // no service found, look for an implementation
+ HashMap_OWString_Interface::iterator aIt = m_ImplementationNameMap.find( aServiceName );
+ if( aIt != m_ImplementationNameMap.end() )
+ {
+ Reference< XInterface > const & x = aIt->second;
+ // an implementation found
+ ret = Sequence< Reference< XInterface > >( &x, 1 );
+ }
+ }
+ else
+ {
+ ::std::vector< Reference< XInterface > > vec;
+ vec.reserve( 4 );
+ while (p.first != p.second)
+ {
+ vec.push_back( p.first->second );
+ ++p.first;
+ }
+ ret = Sequence< Reference< XInterface > >( vec.data(), vec.size() );
+ }
+
+ return ret;
+}
+
+// XContentEnumerationAccess
+Reference<XEnumeration > OServiceManager::createContentEnumeration(
+ const OUString& aServiceName )
+{
+ check_undisposed();
+ Sequence< Reference< XInterface > > factories(
+ OServiceManager::queryServiceFactories( aServiceName, m_xContext ) );
+ if (factories.hasElements())
+ return new ServiceEnumeration_Impl( factories );
+ else
+ return Reference< XEnumeration >();
+}
+
+// XEnumeration
+Reference<XEnumeration > OServiceManager::createEnumeration()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ return new ImplementationEnumeration_Impl( m_ImplementationMap );
+}
+
+// XElementAccess
+Type OServiceManager::getElementType()
+{
+ check_undisposed();
+ return cppu::UnoType<XInterface>::get();
+}
+
+// XElementAccess
+sal_Bool OServiceManager::hasElements()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ return !m_ImplementationMap.empty();
+}
+
+// XSet
+sal_Bool OServiceManager::has( const Any & Element )
+{
+ check_undisposed();
+ if( Element.getValueTypeClass() == TypeClass_INTERFACE )
+ {
+ Reference<XInterface > xEle( Element, UNO_QUERY_THROW );
+ MutexGuard aGuard( m_aMutex );
+ return m_ImplementationMap.find( xEle ) !=
+ m_ImplementationMap.end();
+ }
+ else if (auto implName = o3tl::tryAccess<OUString>(Element))
+ {
+ MutexGuard aGuard( m_aMutex );
+ return m_ImplementationNameMap.find( *implName ) !=
+ m_ImplementationNameMap.end();
+ }
+ return false;
+}
+
+// XSet
+void OServiceManager::insert( const Any & Element )
+{
+ check_undisposed();
+ if( Element.getValueTypeClass() != TypeClass_INTERFACE )
+ {
+ throw IllegalArgumentException(
+ "exception interface, got " + Element.getValueType().getTypeName(),
+ Reference< XInterface >(), 0 );
+ }
+ Reference<XInterface > xEle( Element, UNO_QUERY_THROW );
+
+ {
+ MutexGuard aGuard( m_aMutex );
+ HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle );
+ if( aIt != m_ImplementationMap.end() )
+ {
+ throw ElementExistException( "element already exists!" );
+ }
+
+ // put into the implementation hashmap
+ m_ImplementationMap.insert( xEle );
+
+ // put into the implementation name hashmap
+ Reference<XServiceInfo > xInfo( Reference<XServiceInfo >::query( xEle ) );
+ if( xInfo.is() )
+ {
+ OUString aImplName = xInfo->getImplementationName();
+ if( !aImplName.isEmpty() )
+ m_ImplementationNameMap[ aImplName ] = xEle;
+
+ //put into the service map
+ const Sequence< OUString > aServiceNames = xInfo->getSupportedServiceNames();
+ for( const OUString& rServiceName : aServiceNames )
+ {
+ m_ServiceMap.emplace(
+ rServiceName, *o3tl::doAccess<Reference<XInterface>>(Element) );
+ }
+ }
+ }
+ // add the disposing listener to the factory
+ Reference<XComponent > xComp( Reference<XComponent >::query( xEle ) );
+ if( xComp.is() )
+ xComp->addEventListener( getFactoryListener() );
+}
+
+// helper function
+bool OServiceManager::haveFactoryWithThisImplementation(const OUString& aImplName)
+{
+ return ( m_ImplementationNameMap.find(aImplName) != m_ImplementationNameMap.end());
+}
+
+// XSet
+void OServiceManager::remove( const Any & Element )
+{
+ if (is_disposed())
+ return;
+
+ Reference<XInterface > xEle;
+ if (Element.getValueTypeClass() == TypeClass_INTERFACE)
+ {
+ xEle.set( Element, UNO_QUERY_THROW );
+ }
+ else if (auto implName = o3tl::tryAccess<OUString>(Element))
+ {
+ MutexGuard aGuard( m_aMutex );
+ HashMap_OWString_Interface::const_iterator const iFind(
+ m_ImplementationNameMap.find( *implName ) );
+ if (iFind == m_ImplementationNameMap.end())
+ {
+ throw NoSuchElementException(
+ "element is not in: " + *implName,
+ getXWeak() );
+ }
+ xEle = iFind->second;
+ }
+ else
+ {
+ throw IllegalArgumentException(
+ "expected interface or string, got " + Element.getValueType().getTypeName(),
+ Reference< XInterface >(), 0 );
+ }
+
+ // remove the disposing listener from the factory
+ Reference<XComponent > xComp( Reference<XComponent >::query( xEle ) );
+ if( xComp.is() )
+ xComp->removeEventListener( getFactoryListener() );
+
+ MutexGuard aGuard( m_aMutex );
+ HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle );
+ if( aIt == m_ImplementationMap.end() )
+ {
+ throw NoSuchElementException(
+ "element not found",
+ getXWeak() );
+ }
+ //First remove all factories which have been loaded by ORegistryServiceManager.
+ m_SetLoadedFactories.erase( *aIt);
+ //Remove from the implementation map. It contains all factories of m_SetLoadedFactories
+ //which have been added directly through XSet, that is not via ORegistryServiceManager
+ m_ImplementationMap.erase( aIt );
+
+ // remove from the implementation name hashmap
+ Reference<XServiceInfo > xInfo( Reference<XServiceInfo >::query( xEle ) );
+ if( xInfo.is() )
+ {
+ OUString aImplName = xInfo->getImplementationName();
+ if( !aImplName.isEmpty() )
+ m_ImplementationNameMap.erase( aImplName );
+ }
+
+ //remove from the service map
+ Reference<XServiceInfo > xSF( Reference<XServiceInfo >::query( xEle ) );
+ if( !xSF.is() )
+ return;
+
+ const Sequence< OUString > aServiceNames = xSF->getSupportedServiceNames();
+ for( const OUString& rServiceName : aServiceNames )
+ {
+ std::pair<HashMultimap_OWString_Interface::iterator, HashMultimap_OWString_Interface::iterator> p =
+ m_ServiceMap.equal_range( rServiceName );
+
+ while( p.first != p.second )
+ {
+ if( xEle == (*p.first).second )
+ {
+ m_ServiceMap.erase( p.first );
+ break;
+ }
+ ++p.first;
+ }
+ }
+}
+
+/*****************************************************************************
+ class ORegistryServiceManager
+*****************************************************************************/
+class ORegistryServiceManager : public OServiceManager
+{
+public:
+ explicit ORegistryServiceManager( Reference< XComponentContext > const & xContext );
+
+ // XInitialization
+ void SAL_CALL initialize(const Sequence< Any >& Arguments) override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.stoc.ORegistryServiceManager"; }
+
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XMultiServiceFactory
+ Sequence< OUString > SAL_CALL getAvailableServiceNames() override;
+
+ // XContentEnumerationAccess
+ //Sequence< OUString > getAvailableServiceNames() throw( (Exception) );
+ Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override;
+
+ // XComponent
+ void SAL_CALL dispose() override;
+
+ // OServiceManager
+ Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ Any SAL_CALL getPropertyValue(const OUString& PropertyName) override;
+
+protected:
+ //OServiceManager
+ Sequence< Reference< XInterface > > queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & xContext ) override;
+private:
+ Reference<XRegistryKey > getRootKey();
+ Reference<XInterface > loadWithImplementationName(
+ const OUString & rImplName, Reference< XComponentContext > const & xContext );
+ Sequence<OUString> getFromServiceName(std::u16string_view serviceName) const;
+ Reference<XInterface > loadWithServiceName(
+ std::u16string_view rImplName, Reference< XComponentContext > const & xContext );
+ void fillAllNamesFromRegistry( HashSet_OWString & );
+
+ bool m_searchedRegistry;
+ Reference<XSimpleRegistry > m_xRegistry; // readonly property Registry
+ Reference<XRegistryKey > m_xRootKey;
+
+#if OSL_DEBUG_LEVEL > 0
+ bool m_init;
+#endif
+};
+
+/**
+ * Create a ServiceManager
+ */
+ORegistryServiceManager::ORegistryServiceManager( Reference< XComponentContext > const & xContext )
+ : OServiceManager( xContext )
+ , m_searchedRegistry(false)
+#if OSL_DEBUG_LEVEL > 0
+ , m_init( false )
+#endif
+{
+}
+
+// XComponent
+void ORegistryServiceManager::dispose()
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ return;
+ OServiceManager::dispose();
+ // dispose
+ MutexGuard aGuard( m_aMutex );
+ // erase all members
+ m_xRegistry.clear();
+ m_xRootKey.clear();
+}
+
+/**
+ * Return the root key of the registry. The Default registry service is ordered
+ * if no registry is set.
+ */
+//Reference<XServiceProvider > create_DefaultRegistry_ServiceProvider();
+
+Reference<XRegistryKey > ORegistryServiceManager::getRootKey()
+{
+ if( !m_xRootKey.is() )
+ {
+ MutexGuard aGuard( m_aMutex );
+ // DefaultRegistry suchen !!!!
+ if( !m_xRegistry.is() && !m_searchedRegistry )
+ {
+ // NB. we only search this once
+ m_searchedRegistry = true;
+
+ m_xRegistry.set(
+ createInstanceWithContext(
+ "com.sun.star.registry.DefaultRegistry",
+ m_xContext ),
+ UNO_QUERY );
+ }
+ if( m_xRegistry.is() && !m_xRootKey.is() )
+ m_xRootKey = m_xRegistry->getRootKey();
+ }
+
+ return m_xRootKey;
+}
+
+/**
+ * Create a service provider from the registry with an implementation name
+ */
+Reference<XInterface > ORegistryServiceManager::loadWithImplementationName(
+ const OUString& name, Reference< XComponentContext > const & xContext )
+{
+ Reference<XInterface > ret;
+
+ Reference<XRegistryKey > xRootKey = getRootKey();
+ if( !xRootKey.is() )
+ return ret;
+
+ try
+ {
+ OUString implementationName = "/IMPLEMENTATIONS/" + name;
+ Reference<XRegistryKey > xImpKey = m_xRootKey->openKey(implementationName);
+
+ if( xImpKey.is() )
+ {
+ Reference< lang::XMultiServiceFactory > xMgr;
+ if (xContext.is())
+ xMgr.set( xContext->getServiceManager(), UNO_QUERY_THROW );
+ else
+ xMgr.set( this );
+ ret = createSingleRegistryFactory( xMgr, name, xImpKey );
+ insert( Any( ret ) );
+ // Remember this factory as loaded in contrast to inserted ( XSet::insert)
+ // factories. Those loaded factories in this set are candidates for being
+ // released on an unloading notification.
+ m_SetLoadedFactories.insert( ret);
+ }
+ }
+ catch (InvalidRegistryException &)
+ {
+ }
+
+ return ret;
+}
+
+/**
+ * Return all implementation out of the registry.
+ */
+Sequence<OUString> ORegistryServiceManager::getFromServiceName(
+ std::u16string_view serviceName ) const
+{
+ OUString buf = OUString::Concat("/SERVICES/") + serviceName;
+ return retrieveAsciiValueList( m_xRegistry, buf );
+}
+
+/**
+ * Create a service provider from the registry
+ */
+Reference<XInterface > ORegistryServiceManager::loadWithServiceName(
+ std::u16string_view serviceName, Reference< XComponentContext > const & xContext )
+{
+ const Sequence<OUString> implEntries = getFromServiceName( serviceName );
+ for (const auto& rEntry : implEntries)
+ {
+ Reference< XInterface > x( loadWithImplementationName( rEntry, xContext ) );
+ if (x.is())
+ return x;
+ }
+
+ return Reference<XInterface >();
+}
+
+/**
+ * Return a sequence of all service names from the registry.
+ */
+void ORegistryServiceManager::fillAllNamesFromRegistry( HashSet_OWString & rSet )
+{
+ Reference<XRegistryKey > xRootKey = getRootKey();
+ if( !xRootKey.is() )
+ return;
+
+ try
+ {
+ Reference<XRegistryKey > xServicesKey = xRootKey->openKey( "SERVICES" );
+ // root + /Services + /
+ if( xServicesKey.is() )
+ {
+ sal_Int32 nPrefix = xServicesKey->getKeyName().getLength() +1;
+ const Sequence<Reference<XRegistryKey > > aKeys = xServicesKey->openKeys();
+ std::transform(aKeys.begin(), aKeys.end(), std::inserter(rSet, rSet.end()),
+ [nPrefix](const Reference<XRegistryKey>& rKey) -> OUString {
+ return rKey->getKeyName().copy( nPrefix ); });
+ }
+ }
+ catch (InvalidRegistryException &)
+ {
+ }
+}
+
+// XInitialization
+void ORegistryServiceManager::initialize(const Sequence< Any >& Arguments)
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ if (Arguments.hasElements())
+ {
+ m_xRootKey.clear();
+ Arguments[ 0 ] >>= m_xRegistry;
+ }
+#if OSL_DEBUG_LEVEL > 0
+ // to find all bootstrapping processes to be fixed...
+ OSL_ENSURE( !m_init, "### second init of service manager instance!" );
+ m_init = true;
+#endif
+}
+
+// XMultiServiceFactory, XContentEnumeration
+Sequence< OUString > ORegistryServiceManager::getAvailableServiceNames()
+{
+ check_undisposed();
+ MutexGuard aGuard( m_aMutex );
+ // all names
+ HashSet_OWString aNameSet;
+
+ // all names from the registry
+ fillAllNamesFromRegistry( aNameSet );
+
+ return OServiceManager::getUniqueAvailableServiceNames( aNameSet );
+}
+
+// XServiceInfo
+Sequence< OUString > ORegistryServiceManager::getSupportedServiceNames()
+{
+ return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.RegistryServiceManager" };
+}
+
+
+// OServiceManager
+Sequence< Reference< XInterface > > ORegistryServiceManager::queryServiceFactories(
+ const OUString& aServiceName, Reference< XComponentContext > const & xContext )
+{
+ Sequence< Reference< XInterface > > ret(
+ OServiceManager::queryServiceFactories( aServiceName, xContext ) );
+ if (ret.hasElements())
+ {
+ return ret;
+ }
+ else
+ {
+ MutexGuard aGuard( m_aMutex );
+ Reference< XInterface > x( loadWithServiceName( aServiceName, xContext ) );
+ if (! x.is())
+ x = loadWithImplementationName( aServiceName, xContext );
+ return Sequence< Reference< XInterface > >( &x, 1 );
+ }
+}
+
+// XContentEnumerationAccess
+Reference<XEnumeration > ORegistryServiceManager::createContentEnumeration(
+ const OUString& aServiceName )
+{
+ check_undisposed();
+ MutexGuard aGuard(m_aMutex);
+ // get all implementation names registered under this service name from the registry
+ const Sequence<OUString> aImpls = getFromServiceName( aServiceName );
+ // load and insert all factories specified by the registry
+ for( const OUString& aImplName : aImpls )
+ {
+ if ( !haveFactoryWithThisImplementation(aImplName) )
+ {
+ loadWithImplementationName( aImplName, m_xContext );
+ }
+ }
+ // call the superclass to enumerate all contents
+ return OServiceManager::createContentEnumeration( aServiceName );
+}
+
+// OServiceManager
+Reference<XPropertySetInfo > ORegistryServiceManager::getPropertySetInfo()
+{
+ check_undisposed();
+ if (! m_xPropertyInfo.is())
+ {
+ Sequence< beans::Property > seq{
+ beans::Property("DefaultContext", -1, cppu::UnoType<decltype(m_xContext)>::get(), 0),
+ beans::Property("Registry", -1, cppu::UnoType<decltype(m_xRegistry)>::get(),
+ beans::PropertyAttribute::READONLY)
+ };
+ Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) );
+
+ MutexGuard aGuard( m_aMutex );
+ if (! m_xPropertyInfo.is())
+ {
+ m_xPropertyInfo = xInfo;
+ }
+ }
+ return m_xPropertyInfo;
+}
+
+Any ORegistryServiceManager::getPropertyValue(const OUString& PropertyName)
+{
+ check_undisposed();
+ if ( PropertyName == "Registry" )
+ {
+ MutexGuard aGuard( m_aMutex );
+ if( m_xRegistry.is() )
+ return Any( m_xRegistry );
+ else
+ return Any();
+ }
+ return OServiceManager::getPropertyValue( PropertyName );
+}
+
+} // namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_OServiceManager_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new OServiceManager(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_ORegistryServiceManager_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ORegistryServiceManager(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_OServiceManagerWrapper_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new OServiceManagerWrapper(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/simpleregistry/simpleregistry.cxx b/stoc/source/simpleregistry/simpleregistry.cxx
new file mode 100644
index 0000000000..f793aa56db
--- /dev/null
+++ b/stoc/source/simpleregistry/simpleregistry.cxx
@@ -0,0 +1,932 @@
+/* -*- 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 <mutex>
+#include <optional>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/registry/InvalidRegistryException.hpp>
+#include <com/sun/star/registry/InvalidValueException.hpp>
+#include <com/sun/star/registry/RegistryKeyType.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/RuntimeException.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <registry/registry.hxx>
+#include <registry/regtype.h>
+#include <rtl/ref.hxx>
+#include <rtl/string.h>
+#include <rtl/string.hxx>
+#include <rtl/textcvt.h>
+#include <rtl/textenc.h>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace {
+
+class SimpleRegistry:
+ public cppu::WeakImplHelper<
+ css::registry::XSimpleRegistry, css::lang::XServiceInfo >
+{
+public:
+ SimpleRegistry(): registry_(Registry()) {}
+
+ ~SimpleRegistry() {
+ std::scoped_lock guard(mutex_);
+ registry_.reset();
+ }
+
+ std::mutex mutex_;
+
+private:
+ virtual OUString SAL_CALL getURL() override;
+
+ virtual void SAL_CALL open(
+ OUString const & rURL, sal_Bool bReadOnly, sal_Bool bCreate) override;
+
+ virtual sal_Bool SAL_CALL isValid() override;
+
+ virtual void SAL_CALL close() override;
+
+ virtual void SAL_CALL destroy() override;
+
+ virtual css::uno::Reference< css::registry::XRegistryKey > SAL_CALL
+ getRootKey() override;
+
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+
+ virtual void SAL_CALL mergeKey(
+ OUString const & aKeyName, OUString const & aUrl) override;
+
+ virtual OUString SAL_CALL getImplementationName() override
+ { return "com.sun.star.comp.stoc.SimpleRegistry"; }
+
+ virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override
+ { return cppu::supportsService(this, ServiceName); }
+
+ virtual css::uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override
+ {
+ css::uno::Sequence< OUString > names { "com.sun.star.registry.SimpleRegistry" };
+ return names;
+ }
+
+ std::optional<Registry> registry_;
+};
+
+class Key: public cppu::WeakImplHelper< css::registry::XRegistryKey > {
+public:
+ Key(
+ rtl::Reference< SimpleRegistry > registry,
+ RegistryKey const & key):
+ registry_(std::move(registry)), key_(key) {}
+
+ ~Key() {
+ std::scoped_lock guard(registry_->mutex_);
+ key_.reset();
+ }
+
+private:
+ virtual OUString SAL_CALL getKeyName() override;
+
+ virtual sal_Bool SAL_CALL isReadOnly() override;
+
+ virtual sal_Bool SAL_CALL isValid() override;
+
+ virtual css::registry::RegistryKeyType SAL_CALL getKeyType(
+ OUString const & rKeyName) override;
+
+ virtual css::registry::RegistryValueType SAL_CALL getValueType() override;
+
+ virtual sal_Int32 SAL_CALL getLongValue() override;
+
+ virtual void SAL_CALL setLongValue(sal_Int32 value) override;
+
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getLongListValue() override;
+
+ virtual void SAL_CALL setLongListValue(
+ css::uno::Sequence< sal_Int32 > const & seqValue) override;
+
+ virtual OUString SAL_CALL getAsciiValue() override;
+
+ virtual void SAL_CALL setAsciiValue(OUString const & value) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getAsciiListValue() override;
+
+ virtual void SAL_CALL setAsciiListValue(
+ css::uno::Sequence< OUString > const & seqValue) override;
+
+ virtual OUString SAL_CALL getStringValue() override;
+
+ virtual void SAL_CALL setStringValue(OUString const & value) override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getStringListValue() override;
+
+ virtual void SAL_CALL setStringListValue(
+ css::uno::Sequence< OUString > const & seqValue) override;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBinaryValue() override;
+
+ virtual void SAL_CALL setBinaryValue(
+ css::uno::Sequence< sal_Int8 > const & value) override;
+
+ virtual css::uno::Reference< css::registry::XRegistryKey > SAL_CALL openKey(
+ OUString const & aKeyName) override;
+
+ virtual css::uno::Reference< css::registry::XRegistryKey > SAL_CALL
+ createKey(OUString const & aKeyName) override;
+
+ virtual void SAL_CALL closeKey() override;
+
+ virtual void SAL_CALL deleteKey(OUString const & rKeyName) override;
+
+ virtual
+ css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > >
+ SAL_CALL openKeys() override;
+
+ virtual css::uno::Sequence< OUString > SAL_CALL getKeyNames() override;
+
+ virtual sal_Bool SAL_CALL createLink(
+ OUString const & aLinkName, OUString const & aLinkTarget) override;
+
+ virtual void SAL_CALL deleteLink(OUString const & rLinkName) override;
+
+ virtual OUString SAL_CALL getLinkTarget(OUString const & rLinkName) override;
+
+ virtual OUString SAL_CALL getResolvedName(OUString const & aKeyName) override;
+
+ rtl::Reference< SimpleRegistry > registry_;
+ std::optional<RegistryKey> key_;
+};
+
+OUString Key::getKeyName() {
+ std::scoped_lock guard(registry_->mutex_);
+ return key_->getName();
+}
+
+sal_Bool Key::isReadOnly()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ return key_->isReadOnly();
+}
+
+sal_Bool Key::isValid() {
+ std::scoped_lock guard(registry_->mutex_);
+ return key_->isValid();
+}
+
+css::registry::RegistryKeyType Key::getKeyType(OUString const & )
+{
+ return css::registry::RegistryKeyType_KEY;
+}
+
+css::registry::RegistryValueType Key::getValueType()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_->getValueInfo(OUString(), &type, &size);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::INVALID_VALUE:
+ type = RegValueType::NOT_DEFINED;
+ break;
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getValueType:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ switch (type) {
+ default:
+ std::abort(); // this cannot happen
+ // pseudo-fall-through to avoid warnings on MSC
+ case RegValueType::NOT_DEFINED:
+ return css::registry::RegistryValueType_NOT_DEFINED;
+ case RegValueType::LONG:
+ return css::registry::RegistryValueType_LONG;
+ case RegValueType::STRING:
+ return css::registry::RegistryValueType_ASCII;
+ case RegValueType::UNICODE:
+ return css::registry::RegistryValueType_STRING;
+ case RegValueType::BINARY:
+ return css::registry::RegistryValueType_BINARY;
+ case RegValueType::LONGLIST:
+ return css::registry::RegistryValueType_LONGLIST;
+ case RegValueType::STRINGLIST:
+ return css::registry::RegistryValueType_ASCIILIST;
+ case RegValueType::UNICODELIST:
+ return css::registry::RegistryValueType_STRINGLIST;
+ }
+}
+
+sal_Int32 Key::getLongValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ sal_Int32 value;
+ RegError err = key_->getValue(OUString(), &value);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getLongValue:"
+ " underlying RegistryKey::getValue() = RegError::INVALID_VALUE",
+ getXWeak());
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getLongValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ return value;
+}
+
+void Key::setLongValue(sal_Int32 value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_->setValue(
+ OUString(), RegValueType::LONG, &value, sizeof (sal_Int32));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setLongValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Sequence< sal_Int32 > Key::getLongListValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryValueList< sal_Int32 > list;
+ RegError err = key_->getLongListValue(OUString(), list);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::VALUE_NOT_EXISTS:
+ return css::uno::Sequence< sal_Int32 >();
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getLongListValue:"
+ " underlying RegistryKey::getLongListValue() ="
+ " RegError::INVALID_VALUE",
+ getXWeak());
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getLongListValue:"
+ " underlying RegistryKey::getLongListValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getLongListValue:"
+ " underlying RegistryKey::getLongListValue() too large",
+ getXWeak());
+ }
+ css::uno::Sequence< sal_Int32 > value(static_cast< sal_Int32 >(n));
+ auto aValueRange = asNonConstRange(value);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aValueRange[static_cast< sal_Int32 >(i)] = list.getElement(i);
+ }
+ return value;
+}
+
+void Key::setLongListValue(css::uno::Sequence< sal_Int32 > const & seqValue)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_->setLongListValue(
+ OUString(), seqValue.getConstArray(), static_cast< sal_uInt32 >(seqValue.getLength()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setLongListValue:"
+ " underlying RegistryKey::setLongListValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+OUString Key::getAsciiValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_->getValueInfo(OUString(), &type, &size);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ if (type != RegValueType::STRING) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey type = " + OUString::number(static_cast<int>(type)),
+ getXWeak());
+ }
+ // size contains terminating null (error in underlying registry.cxx):
+ if (size == 0) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey size 0 cannot happen due to"
+ " design error",
+ getXWeak());
+ }
+ if (size > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey size too large",
+ getXWeak());
+ }
+ std::vector< char > list(size);
+ err = key_->getValue(OUString(), list.data());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ if (list[size - 1] != '\0') {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey value must be null-terminated due"
+ " to design error",
+ getXWeak());
+ }
+ OUString value;
+ if (!rtl_convertStringToUString(
+ &value.pData, list.data(),
+ static_cast< sal_Int32 >(size - 1), RTL_TEXTENCODING_UTF8,
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getAsciiValue:"
+ " underlying RegistryKey not UTF-8",
+ getXWeak());
+ }
+ return value;
+}
+
+void Key::setAsciiValue(OUString const & value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ OString utf8;
+ if (!value.convertToString(
+ &utf8, RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ throw css::uno::RuntimeException(
+ "com.sun.star.registry.SimpleRegistry key setAsciiValue:"
+ " value not UTF-16",
+ getXWeak());
+ }
+ RegError err = key_->setValue(
+ OUString(), RegValueType::STRING,
+ const_cast< char * >(utf8.getStr()), utf8.getLength() + 1);
+ // +1 for terminating null (error in underlying registry.cxx)
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setAsciiValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Sequence< OUString > Key::getAsciiListValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryValueList< char * > list;
+ RegError err = key_->getStringListValue(OUString(), list);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::VALUE_NOT_EXISTS:
+ return css::uno::Sequence< OUString >();
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying"
+ " RegistryKey::getStringListValue() = RegError::INVALID_VALUE",
+ getXWeak());
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying"
+ " RegistryKey::getStringListValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying"
+ " RegistryKey::getStringListValue() too large",
+ getXWeak());
+ }
+ css::uno::Sequence< OUString > value(static_cast< sal_Int32 >(n));
+ auto aValueRange = asNonConstRange(value);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ char * el = list.getElement(i);
+ sal_Int32 size = rtl_str_getLength(el);
+ if (!rtl_convertStringToUString(
+ &aValueRange[static_cast< sal_Int32 >(i)].pData, el, size,
+ RTL_TEXTENCODING_UTF8,
+ (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
+ RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
+ {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getAsciiListValue: underlying RegistryKey not"
+ " UTF-8",
+ getXWeak());
+ }
+ }
+ return value;
+}
+
+void Key::setAsciiListValue(
+ css::uno::Sequence< OUString > const & seqValue)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ std::vector< OString > list;
+ for (const auto& rValue : seqValue) {
+ OString utf8;
+ if (!rValue.convertToString(
+ &utf8, RTL_TEXTENCODING_UTF8,
+ (RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
+ {
+ throw css::uno::RuntimeException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " setAsciiListValue: value not UTF-16",
+ getXWeak());
+ }
+ list.push_back(utf8);
+ }
+ std::vector< char * > list2;
+ for (const auto& rItem : list)
+ {
+ list2.push_back(const_cast< char * >(rItem.getStr()));
+ }
+ RegError err = key_->setStringListValue(
+ OUString(), list2.data(), static_cast< sal_uInt32 >(list2.size()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " setAsciiListValue: underlying"
+ " RegistryKey::setStringListValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+OUString Key::getStringValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_->getValueInfo(OUString(), &type, &size);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ if (type != RegValueType::UNICODE) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey type = " + OUString::number(static_cast<int>(type)),
+ getXWeak());
+ }
+ // size contains terminating null and is *2 (error in underlying
+ // registry.cxx):
+ if (size == 0 || (size & 1) == 1) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey size 0 or odd cannot happen due to"
+ " design error",
+ getXWeak());
+ }
+ if (size > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey size too large",
+ getXWeak());
+ }
+ std::vector< sal_Unicode > list(size);
+ err = key_->getValue(OUString(), list.data());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ if (list[size/2 - 1] != 0) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getStringValue:"
+ " underlying RegistryKey value must be null-terminated due"
+ " to design error",
+ getXWeak());
+ }
+ return OUString(list.data(), static_cast< sal_Int32 >(size/2 - 1));
+}
+
+void Key::setStringValue(OUString const & value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_->setValue(
+ OUString(), RegValueType::UNICODE,
+ const_cast< sal_Unicode * >(value.getStr()),
+ (value.getLength() + 1) * sizeof (sal_Unicode));
+ // +1 for terminating null (error in underlying registry.cxx)
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setStringValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Sequence< OUString > Key::getStringListValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryValueList< sal_Unicode * > list;
+ RegError err = key_->getUnicodeListValue(OUString(), list);
+ switch (err) {
+ case RegError::NO_ERROR:
+ break;
+ case RegError::VALUE_NOT_EXISTS:
+ return css::uno::Sequence< OUString >();
+ case RegError::INVALID_VALUE:
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getStringListValue: underlying"
+ " RegistryKey::getUnicodeListValue() = RegError::INVALID_VALUE",
+ getXWeak());
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getStringListValue: underlying"
+ " RegistryKey::getUnicodeListValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " getStringListValue: underlying"
+ " RegistryKey::getUnicodeListValue() too large",
+ getXWeak());
+ }
+ css::uno::Sequence< OUString > value(static_cast< sal_Int32 >(n));
+ auto aValueRange = asNonConstRange(value);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aValueRange[static_cast< sal_Int32 >(i)] = list.getElement(i);
+ }
+ return value;
+}
+
+void Key::setStringListValue(
+ css::uno::Sequence< OUString > const & seqValue)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ std::vector< sal_Unicode * > list;
+ list.reserve(seqValue.getLength());
+ std::transform(seqValue.begin(), seqValue.end(), std::back_inserter(list),
+ [](const OUString& rValue) -> sal_Unicode* { return const_cast<sal_Unicode*>(rValue.getStr()); });
+ RegError err = key_->setUnicodeListValue(
+ OUString(), list.data(), static_cast< sal_uInt32 >(list.size()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key"
+ " setStringListValue: underlying"
+ " RegistryKey::setUnicodeListValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Sequence< sal_Int8 > Key::getBinaryValue()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegValueType type;
+ sal_uInt32 size;
+ RegError err = key_->getValueInfo(OUString(), &type, &size);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey::getValueInfo() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ if (type != RegValueType::BINARY) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey type = " + OUString::number(static_cast<int>(type)),
+ getXWeak());
+ }
+ if (size > SAL_MAX_INT32) {
+ throw css::registry::InvalidValueException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey size too large",
+ getXWeak());
+ }
+ css::uno::Sequence< sal_Int8 > value(static_cast< sal_Int32 >(size));
+ err = key_->getValue(OUString(), value.getArray());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getBinaryValue:"
+ " underlying RegistryKey::getValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ return value;
+}
+
+void Key::setBinaryValue(css::uno::Sequence< sal_Int8 > const & value)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_->setValue(
+ OUString(), RegValueType::BINARY,
+ const_cast< sal_Int8 * >(value.getConstArray()),
+ static_cast< sal_uInt32 >(value.getLength()));
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key setBinaryValue:"
+ " underlying RegistryKey::setValue() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Reference< css::registry::XRegistryKey > Key::openKey(
+ OUString const & aKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKey key;
+ RegError err = key_->openKey(aKeyName, key);
+ switch (err) {
+ case RegError::NO_ERROR:
+ return new Key(registry_, key);
+ case RegError::KEY_NOT_EXISTS:
+ return css::uno::Reference< css::registry::XRegistryKey >();
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key openKey:"
+ " underlying RegistryKey::openKey() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Reference< css::registry::XRegistryKey > Key::createKey(
+ OUString const & aKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKey key;
+ RegError err = key_->createKey(aKeyName, key);
+ switch (err) {
+ case RegError::NO_ERROR:
+ return new Key(registry_, key);
+ case RegError::INVALID_KEYNAME:
+ return css::uno::Reference< css::registry::XRegistryKey >();
+ default:
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key createKey:"
+ " underlying RegistryKey::createKey() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+void Key::closeKey()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_->closeKey();
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key closeKey:"
+ " underlying RegistryKey::closeKey() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+void Key::deleteKey(OUString const & rKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegError err = key_->deleteKey(rKeyName);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key deleteKey:"
+ " underlying RegistryKey::deleteKey() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > >
+Key::openKeys()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKeyArray list;
+ RegError err = key_->openSubKeys(OUString(), list);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key openKeys:"
+ " underlying RegistryKey::openSubKeys() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getKeyNames:"
+ " underlying RegistryKey::getKeyNames() too large",
+ getXWeak());
+ }
+ css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > >
+ keys(static_cast< sal_Int32 >(n));
+ auto aKeysRange = asNonConstRange(keys);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aKeysRange[static_cast< sal_Int32 >(i)] = new Key(
+ registry_, list.getElement(i));
+ }
+ return keys;
+}
+
+css::uno::Sequence< OUString > Key::getKeyNames()
+{
+ std::scoped_lock guard(registry_->mutex_);
+ RegistryKeyNames list;
+ RegError err = key_->getKeyNames(OUString(), list);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getKeyNames:"
+ " underlying RegistryKey::getKeyNames() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ sal_uInt32 n = list.getLength();
+ if (n > SAL_MAX_INT32) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getKeyNames:"
+ " underlying RegistryKey::getKeyNames() too large",
+ getXWeak());
+ }
+ css::uno::Sequence< OUString > names(static_cast< sal_Int32 >(n));
+ auto aNamesRange = asNonConstRange(names);
+ for (sal_uInt32 i = 0; i < n; ++i) {
+ aNamesRange[static_cast< sal_Int32 >(i)] = list.getElement(i);
+ }
+ return names;
+}
+
+sal_Bool Key::createLink(
+ OUString const & /*aLinkName*/, OUString const & /*aLinkTarget*/)
+{
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key createLink: links are no longer supported",
+ getXWeak());
+}
+
+void Key::deleteLink(OUString const & /*rLinkName*/)
+{
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key deleteLink: links are no longer supported",
+ getXWeak());
+}
+
+OUString Key::getLinkTarget(OUString const & /*rLinkName*/)
+{
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getLinkTarget: links are no longer supported",
+ getXWeak());
+}
+
+OUString Key::getResolvedName(OUString const & aKeyName)
+{
+ std::scoped_lock guard(registry_->mutex_);
+ OUString resolved;
+ RegError err = key_->getResolvedKeyName(aKeyName, resolved);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry key getResolvedName:"
+ " underlying RegistryKey::getResolvedName() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ return resolved;
+}
+
+OUString SimpleRegistry::getURL() {
+ std::scoped_lock guard(mutex_);
+ return registry_->getName();
+}
+
+void SimpleRegistry::open(
+ OUString const & rURL, sal_Bool bReadOnly, sal_Bool bCreate)
+{
+ std::scoped_lock guard(mutex_);
+ RegError err = (rURL.isEmpty() && bCreate)
+ ? RegError::REGISTRY_NOT_EXISTS
+ : registry_->open(rURL, bReadOnly ? RegAccessMode::READONLY : RegAccessMode::READWRITE);
+ if (err == RegError::REGISTRY_NOT_EXISTS && bCreate) {
+ err = registry_->create(rURL);
+ }
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.open(" + rURL +
+ "): underlying Registry::open/create() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+sal_Bool SimpleRegistry::isValid() {
+ std::scoped_lock guard(mutex_);
+ return registry_->isValid();
+}
+
+void SimpleRegistry::close()
+{
+ std::scoped_lock guard(mutex_);
+ RegError err = registry_->close();
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.close:"
+ " underlying Registry::close() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+void SimpleRegistry::destroy()
+{
+ std::scoped_lock guard(mutex_);
+ RegError err = registry_->destroy(OUString());
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.destroy:"
+ " underlying Registry::destroy() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+}
+
+css::uno::Reference< css::registry::XRegistryKey > SimpleRegistry::getRootKey()
+{
+ std::scoped_lock guard(mutex_);
+ RegistryKey root;
+ RegError err = registry_->openRootKey(root);
+ if (err != RegError::NO_ERROR) {
+ throw css::registry::InvalidRegistryException(
+ "com.sun.star.registry.SimpleRegistry.getRootKey:"
+ " underlying Registry::getRootKey() = " + OUString::number(static_cast<int>(err)),
+ getXWeak());
+ }
+ return new Key(this, root);
+}
+
+sal_Bool SimpleRegistry::isReadOnly()
+{
+ std::scoped_lock guard(mutex_);
+ return registry_->isReadOnly();
+}
+
+void SimpleRegistry::mergeKey(
+ OUString const &, OUString const &)
+{
+ throw css::uno::RuntimeException("css.registry.SimpleRegistry::mergeKey: not implemented");
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_stoc_SimpleRegistry_get_implementation(
+ SAL_UNUSED_PARAMETER css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new SimpleRegistry);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/typeconv/convert.cxx b/stoc/source/typeconv/convert.cxx
new file mode 100644
index 0000000000..c3cd1b9997
--- /dev/null
+++ b/stoc/source/typeconv/convert.cxx
@@ -0,0 +1,872 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <o3tl/underlyingenumvalue.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <typelib/typedescription.hxx>
+#include <uno/data.h>
+
+#ifdef _WIN32
+#include <cmath>
+#else
+#include <math.h>
+#endif
+#include <float.h>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/CannotConvertException.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/script/FailReason.hpp>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::script;
+using namespace cppu;
+using namespace osl;
+
+namespace stoc_tcv
+{
+
+static double round( double aVal )
+{
+ bool bPos = (aVal >= 0.0);
+ aVal = ::fabs( aVal );
+ double aUpper = ::ceil( aVal );
+
+ aVal = ((aUpper-aVal) <= 0.5) ? aUpper : (aUpper - 1.0);
+ return (bPos ? aVal : -aVal);
+}
+
+
+static bool getNumericValue( double & rfVal, std::u16string_view rStr )
+{
+ double fRet = o3tl::toDouble(rStr);
+ if (fRet == 0.0)
+ {
+ size_t nLen = rStr.size();
+ if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
+ {
+ rfVal = 0.0;
+ return true;
+ }
+
+ std::u16string_view trim( o3tl::trim(rStr) );
+
+ // try hex
+ size_t nX = trim.find( 'x' );
+ if (nX == std::u16string_view::npos)
+ nX = trim.find( 'X' );
+
+ if (nX > 0 && nX != std::u16string_view::npos && trim[nX-1] == '0') // 0x
+ {
+ bool bNeg = false;
+ switch (nX)
+ {
+ case 2: // (+|-)0x...
+ if (trim[0] == '-')
+ bNeg = true;
+ else if (trim[0] != '+')
+ return false;
+ break;
+ case 1: // 0x...
+ break;
+ default:
+ return false;
+ }
+
+ OUString aHexRest( trim.substr( nX+1 ) );
+ sal_uInt64 nRet = aHexRest.toUInt64( 16 );
+
+ if (nRet == 0)
+ {
+ for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
+ {
+ if (aHexRest[nPos] != '0')
+ return false;
+ }
+ }
+
+ rfVal = (bNeg ? -static_cast<double>(nRet) : static_cast<double>(nRet));
+ return true;
+ }
+
+ nLen = trim.size();
+ size_t nPos = 0;
+
+ // skip +/-
+ if (nLen && (trim[0] == '-' || trim[0] == '+'))
+ ++nPos;
+
+ while (nPos < nLen) // skip leading zeros
+ {
+ if (trim[nPos] != '0')
+ {
+ if (trim[nPos] != '.')
+ return false;
+ ++nPos;
+ while (nPos < nLen) // skip trailing zeros
+ {
+ if (trim[nPos] != '0')
+ return false;
+ ++nPos;
+ }
+ break;
+ }
+ ++nPos;
+ }
+ }
+ rfVal = fRet;
+ return true;
+}
+
+
+static bool getHyperValue( sal_Int64 & rnVal, std::u16string_view rStr )
+{
+ size_t nLen = rStr.size();
+ if (!nLen || (nLen == 1 && rStr[0] == '0')) // common case
+ {
+ rnVal = 0;
+ return true;
+ }
+
+ std::u16string_view trim( o3tl::trim(rStr) );
+
+ // try hex
+ size_t nX = trim.find( 'x' );
+ if (nX == std::u16string_view::npos)
+ nX = trim.find( 'X' );
+
+ if (nX != std::u16string_view::npos)
+ {
+ if (nX > 0 && trim[nX-1] == '0') // 0x
+ {
+ bool bNeg = false;
+ switch (nX)
+ {
+ case 2: // (+|-)0x...
+ if (trim[0] == '-')
+ bNeg = true;
+ else if (trim[0] != '+')
+ return false;
+ break;
+ case 1: // 0x...
+ break;
+ default:
+ return false;
+ }
+
+ OUString aHexRest( trim.substr( nX+1 ) );
+ sal_uInt64 nRet = aHexRest.toUInt64( 16 );
+
+ if (nRet == 0)
+ {
+ for ( sal_Int32 nPos = aHexRest.getLength(); nPos--; )
+ {
+ if (aHexRest[nPos] != '0')
+ return false;
+ }
+ }
+
+ rnVal = (bNeg ? -static_cast<sal_Int64>(nRet) : nRet);
+ return true;
+ }
+ return false;
+ }
+
+ double fVal;
+ if (getNumericValue( fVal, rStr ) &&
+ fVal >= double(SAL_MIN_INT64) &&
+ fVal <= double(SAL_MAX_UINT64))
+ {
+ rnVal = static_cast<sal_Int64>(round( fVal ));
+ return true;
+ }
+ return false;
+}
+
+namespace {
+
+class TypeConverter_Impl : public WeakImplHelper< XTypeConverter, XServiceInfo >
+{
+ // ...misc helpers...
+ /// @throws CannotConvertException
+ static sal_Int64 toHyper(
+ const Any& rAny, sal_Int64 min, sal_uInt64 max = SAL_MAX_UINT64 );
+ /// @throws CannotConvertException
+ static double toDouble( const Any& rAny, double min = -DBL_MAX, double max = DBL_MAX );
+
+public:
+ TypeConverter_Impl();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // XTypeConverter
+ virtual Any SAL_CALL convertTo( const Any& aFrom, const Type& DestinationType ) override;
+ virtual Any SAL_CALL convertToSimpleType( const Any& aFrom, TypeClass aDestinationType ) override;
+};
+
+}
+
+TypeConverter_Impl::TypeConverter_Impl() {}
+
+// XServiceInfo
+OUString TypeConverter_Impl::getImplementationName()
+{
+ return "com.sun.star.comp.stoc.TypeConverter";
+}
+
+// XServiceInfo
+sal_Bool TypeConverter_Impl::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+// XServiceInfo
+Sequence< OUString > TypeConverter_Impl::getSupportedServiceNames()
+{
+ return { "com.sun.star.script.Converter" };
+}
+
+
+sal_Int64 TypeConverter_Impl::toHyper( const Any& rAny, sal_Int64 min, sal_uInt64 max )
+{
+ sal_Int64 nRet;
+ TypeClass aDestinationClass = rAny.getValueTypeClass();
+
+ switch (aDestinationClass)
+ {
+ // ENUM
+ case TypeClass_ENUM:
+ nRet = *static_cast<sal_Int32 const *>(rAny.getValue());
+ break;
+ // BOOL
+ case TypeClass_BOOLEAN:
+ nRet = *o3tl::forceAccess<bool>(rAny) ? 1 : 0;
+ break;
+ // CHAR, BYTE
+ case TypeClass_CHAR:
+ nRet = *o3tl::forceAccess<sal_Unicode>(rAny);
+ break;
+ case TypeClass_BYTE:
+ nRet = *o3tl::forceAccess<sal_Int8>(rAny);
+ break;
+ // SHORT
+ case TypeClass_SHORT:
+ nRet = *o3tl::forceAccess<sal_Int16>(rAny);
+ break;
+ // UNSIGNED SHORT
+ case TypeClass_UNSIGNED_SHORT:
+ nRet = *o3tl::forceAccess<sal_uInt16>(rAny);
+ break;
+ // LONG
+ case TypeClass_LONG:
+ nRet = *o3tl::forceAccess<sal_Int32>(rAny);
+ break;
+ // UNSIGNED LONG
+ case TypeClass_UNSIGNED_LONG:
+ nRet = *o3tl::forceAccess<sal_uInt32>(rAny);
+ break;
+ // HYPER
+ case TypeClass_HYPER:
+ nRet = *o3tl::forceAccess<sal_Int64>(rAny);
+ break;
+ // UNSIGNED HYPER
+ case TypeClass_UNSIGNED_HYPER:
+ {
+ auto const n = *o3tl::forceAccess<sal_uInt64>(rAny);
+ if ((min < 0 || n >= o3tl::make_unsigned(min)) && // lower bound
+ n <= max) // upper bound
+ {
+ return static_cast<sal_Int64>(n);
+ }
+ throw CannotConvertException(
+ "UNSIGNED HYPER out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ // FLOAT, DOUBLE
+ case TypeClass_FLOAT:
+ {
+ double fVal = round( *o3tl::forceAccess<float>(rAny) );
+ if (fVal >= min && fVal <= max)
+ {
+ nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
+ return nRet;
+ }
+ throw CannotConvertException(
+ "FLOAT out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+ case TypeClass_DOUBLE:
+ {
+ double fVal = round( *o3tl::forceAccess<double>(rAny) );
+ if (fVal >= min && fVal <= max)
+ {
+ nRet = (fVal >= 0.0 ? static_cast<sal_Int64>(static_cast<sal_uInt64>(fVal)) : static_cast<sal_Int64>(fVal));
+ return nRet;
+ }
+ throw CannotConvertException(
+ "DOUBLE out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ // STRING
+ case TypeClass_STRING:
+ {
+ sal_Int64 nVal = SAL_CONST_INT64(0);
+ if (! getHyperValue( nVal, *o3tl::forceAccess<OUString>(rAny) ))
+ {
+ throw CannotConvertException(
+ "invalid STRING value!",
+ Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
+ }
+ nRet = nVal;
+ if (nVal >= min && (nVal < 0 || o3tl::make_unsigned(nVal) <= max))
+ return nRet;
+ throw CannotConvertException(
+ "STRING value out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+ }
+
+ default:
+ throw CannotConvertException(
+ "Type " + OUString::number(o3tl::to_underlying(aDestinationClass)) + " is not supported!",
+ Reference<XInterface>(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
+ }
+
+ if (nRet >= min && (nRet < 0 || o3tl::make_unsigned(nRet) <= max))
+ return nRet;
+ throw CannotConvertException(
+ "VALUE is out of range!",
+ Reference<XInterface>(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+}
+
+
+double TypeConverter_Impl::toDouble( const Any& rAny, double min, double max )
+{
+ double fRet;
+ TypeClass aDestinationClass = rAny.getValueTypeClass();
+
+ switch (aDestinationClass)
+ {
+ // ENUM
+ case TypeClass_ENUM:
+ fRet = *static_cast<sal_Int32 const *>(rAny.getValue());
+ break;
+ // BOOL
+ case TypeClass_BOOLEAN:
+ fRet = *o3tl::forceAccess<bool>(rAny) ? 1.0 : 0.0;
+ break;
+ // CHAR, BYTE
+ case TypeClass_CHAR:
+ fRet = *o3tl::forceAccess<sal_Unicode>(rAny);
+ break;
+ case TypeClass_BYTE:
+ fRet = *o3tl::forceAccess<sal_Int8>(rAny);
+ break;
+ // SHORT
+ case TypeClass_SHORT:
+ fRet = *o3tl::forceAccess<sal_Int16>(rAny);
+ break;
+ // UNSIGNED SHORT
+ case TypeClass_UNSIGNED_SHORT:
+ fRet = *o3tl::forceAccess<sal_uInt16>(rAny);
+ break;
+ // LONG
+ case TypeClass_LONG:
+ fRet = *o3tl::forceAccess<sal_Int32>(rAny);
+ break;
+ // UNSIGNED LONG
+ case TypeClass_UNSIGNED_LONG:
+ fRet = *o3tl::forceAccess<sal_uInt32>(rAny);
+ break;
+ // HYPER
+ case TypeClass_HYPER:
+ fRet = static_cast<double>(*o3tl::forceAccess<sal_Int64>(rAny));
+ break;
+ // UNSIGNED HYPER
+ case TypeClass_UNSIGNED_HYPER:
+ fRet = static_cast<double>(*o3tl::forceAccess<sal_uInt64>(rAny));
+ break;
+ // FLOAT, DOUBLE
+ case TypeClass_FLOAT:
+ fRet = *o3tl::forceAccess<float>(rAny);
+ break;
+ case TypeClass_DOUBLE:
+ fRet = *o3tl::forceAccess<double>(rAny);
+ break;
+
+ // STRING
+ case TypeClass_STRING:
+ {
+ if (! getNumericValue( fRet, *o3tl::forceAccess<OUString>(rAny) ))
+ {
+ throw CannotConvertException(
+ "invalid STRING value!",
+ Reference<XInterface>(), aDestinationClass, FailReason::IS_NOT_NUMBER, 0 );
+ }
+ break;
+ }
+
+ default:
+ throw CannotConvertException(
+ "Type " + OUString::number(o3tl::to_underlying(aDestinationClass)) + " is not supported!",
+ Reference< XInterface >(), aDestinationClass, FailReason::TYPE_NOT_SUPPORTED, 0 );
+ }
+
+ if (fRet >= min && fRet <= max)
+ return fRet;
+ throw CannotConvertException(
+ "VALUE is out of range!",
+ Reference< XInterface >(), aDestinationClass, FailReason::OUT_OF_RANGE, 0 );
+}
+
+
+Any SAL_CALL TypeConverter_Impl::convertTo( const Any& rVal, const Type& aDestType )
+{
+ const Type& aSourceType = rVal.getValueType();
+ if (aSourceType == aDestType)
+ return rVal;
+
+ TypeClass aSourceClass = aSourceType.getTypeClass();
+ TypeClass aDestinationClass = aDestType.getTypeClass();
+
+ Any aRet;
+
+ // convert to...
+ switch (aDestinationClass)
+ {
+ // --- to VOID ------------------------------------------------------------------------------
+ case TypeClass_VOID:
+ return Any();
+ // --- to ANY -------------------------------------------------------------------------------
+ case TypeClass_ANY:
+ return rVal;
+
+ // --- to STRUCT, EXCEPTION ----------------------------------------------------------
+ case TypeClass_STRUCT:
+ case TypeClass_EXCEPTION:
+ {
+ // same types or destination type is derived source type?
+ TypeDescription aSourceTD( aSourceType );
+ TypeDescription aDestTD( aDestType );
+ if (!typelib_typedescription_isAssignableFrom( aDestTD.get(), aSourceTD.get() ))
+ {
+ throw CannotConvertException(
+ "value is not of same or derived type!",
+ Reference< XInterface >(), aDestinationClass,
+ FailReason::SOURCE_IS_NO_DERIVED_TYPE, 0 );
+ }
+ aRet.setValue( rVal.getValue(), aDestTD.get() ); // evtl. .uP.cAsT.
+ break;
+ }
+ // --- to INTERFACE -------------------------------------------------------------------------
+ case TypeClass_INTERFACE:
+ {
+ if (! rVal.hasValue())
+ {
+ // void -> interface (null)
+ void * null_ref = nullptr;
+ // coverity[var_deref_model : FALSE] - null_ref will not be derefed in this case
+ aRet.setValue( &null_ref, aDestType );
+ break;
+ }
+
+ auto ifc = o3tl::tryAccess<css::uno::Reference<css::uno::XInterface>>(
+ rVal);
+ if (!ifc || !ifc->is())
+ {
+ throw CannotConvertException(
+ "value is not interface",
+ Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
+ }
+ aRet = (*ifc)->queryInterface(aDestType );
+ if (! aRet.hasValue())
+ {
+ throw CannotConvertException(
+ "value does not implement " + aDestType.getTypeName(),
+ Reference< XInterface >(), aDestinationClass, FailReason::NO_SUCH_INTERFACE, 0 );
+ }
+ break;
+ }
+ // --- to SEQUENCE --------------------------------------------------------------------------
+ case TypeClass_SEQUENCE:
+ {
+ if (aSourceClass==TypeClass_SEQUENCE)
+ {
+ if( aSourceType == aDestType )
+ return rVal;
+
+ TypeDescription aSourceTD( aSourceType );
+ TypeDescription aDestTD( aDestType );
+ // For a sequence type notation "[]...", SequenceTypeDescription in
+ // cppuhelper/source/typemanager.cxx resolves the "..." component type notation part
+ // only lazily, so it could happen here that bad user input (e.g., "[]" or "[]foo" from
+ // a Basic script CreateUnoValue call) leads to a bad but as-of-yet undetected
+ // aDestType, so check it here; this is less likely an issue for the non-sequence type
+ // classes, whose notation is not resolved lazily based on their syntax:
+ if (!aDestTD.is()) {
+ throw css::lang::IllegalArgumentException(
+ "Bad XTypeConverter::convertTo destination " + aDestType.getTypeName(),
+ getXWeak(), 1);
+ }
+ typelib_TypeDescription * pSourceElementTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pSourceElementTD,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(aSourceTD.get())->pType );
+ typelib_TypeDescription * pDestElementTD = nullptr;
+ TYPELIB_DANGER_GET(
+ &pDestElementTD,
+ reinterpret_cast<typelib_IndirectTypeDescription *>(aDestTD.get())->pType );
+
+ sal_uInt32 nPos = (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->nElements;
+ uno_Sequence * pRet = nullptr;
+ uno_sequence_construct(
+ &pRet, aDestTD.get(), nullptr, nPos,
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire) );
+ aRet.setValue( &pRet, aDestTD.get() );
+ uno_destructData(
+ &pRet, aDestTD.get(),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) );
+ // decr ref count
+
+ char * pDestElements = (*static_cast<uno_Sequence * const *>(aRet.getValue()))->elements;
+ const char * pSourceElements =
+ (*static_cast<const uno_Sequence * const *>(rVal.getValue()))->elements;
+
+ while (nPos--)
+ {
+ char * pDestPos = pDestElements + (nPos * pDestElementTD->nSize);
+ const char * pSourcePos = pSourceElements + (nPos * pSourceElementTD->nSize);
+
+ Any aElement(
+ convertTo( Any( pSourcePos, pSourceElementTD ), pDestElementTD->pWeakRef ) );
+
+ if (!uno_assignData(
+ pDestPos, pDestElementTD,
+ (pDestElementTD->eTypeClass == typelib_TypeClass_ANY
+ ? &aElement
+ : const_cast< void * >( aElement.getValue() )),
+ pDestElementTD,
+ reinterpret_cast< uno_QueryInterfaceFunc >(
+ cpp_queryInterface),
+ reinterpret_cast< uno_AcquireFunc >(cpp_acquire),
+ reinterpret_cast< uno_ReleaseFunc >(cpp_release) ))
+ {
+ OSL_ASSERT( false );
+ }
+ }
+ TYPELIB_DANGER_RELEASE( pDestElementTD );
+ TYPELIB_DANGER_RELEASE( pSourceElementTD );
+ }
+ break;
+ }
+ // --- to ENUM ------------------------------------------------------------------------------
+ case TypeClass_ENUM:
+ {
+ TypeDescription aEnumTD( aDestType );
+ aEnumTD.makeComplete();
+ sal_Int32 nPos = -1;
+
+ if (aSourceClass==TypeClass_STRING)
+ {
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (o3tl::forceAccess<OUString>(rVal)->equalsIgnoreAsciiCase(
+ OUString::unacquired(&reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]) ))
+ break;
+ }
+ }
+ else if (aSourceClass!=TypeClass_ENUM && // exclude some unwanted types for toHyper()
+ aSourceClass!=TypeClass_BOOLEAN &&
+ aSourceClass!=TypeClass_CHAR)
+ {
+ sal_Int32 nEnumValue = static_cast<sal_Int32>(toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ));
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
+ break;
+ }
+ }
+
+ if (nPos < 0)
+ {
+ throw CannotConvertException(
+ "value cannot be converted to demanded ENUM!",
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
+ }
+
+ aRet.setValue(
+ &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos],
+ aEnumTD.get() );
+
+ break;
+ }
+
+ default:
+ // else simple type conversion possible?
+ try
+ {
+ aRet = convertToSimpleType( rVal, aDestinationClass );
+ }
+ catch (IllegalArgumentException &)
+ {
+ // ...FailReason::INVALID is thrown
+ }
+ }
+
+ if (aRet.hasValue())
+ return aRet;
+
+ throw CannotConvertException(
+ "conversion not possible!",
+ Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
+}
+
+
+Any TypeConverter_Impl::convertToSimpleType( const Any& rVal, TypeClass aDestinationClass )
+{
+ switch (aDestinationClass)
+ {
+ // only simple Conversion of _simple_ types
+ case TypeClass_VOID:
+ case TypeClass_BOOLEAN:
+ case TypeClass_BYTE:
+ case TypeClass_SHORT:
+ case TypeClass_UNSIGNED_SHORT:
+ case TypeClass_LONG:
+ case TypeClass_UNSIGNED_LONG:
+ case TypeClass_HYPER:
+ case TypeClass_UNSIGNED_HYPER:
+ case TypeClass_FLOAT:
+ case TypeClass_DOUBLE:
+ case TypeClass_CHAR:
+ case TypeClass_STRING:
+ case TypeClass_ANY:
+ break;
+
+ default:
+ throw IllegalArgumentException(
+ "destination type is not simple!",
+ Reference< XInterface >(), sal_Int16(1) );
+ }
+
+ const Type& aSourceType = rVal.getValueType();
+ TypeClass aSourceClass = aSourceType.getTypeClass();
+ if (aDestinationClass == aSourceClass)
+ return rVal;
+
+ Any aRet;
+
+ // Convert to...
+ switch (aDestinationClass)
+ {
+ // --- to VOID ------------------------------------------------------------------------------
+ case TypeClass_VOID:
+ return Any();
+
+ // --- to ANY -------------------------------------------------------------------------------
+ case TypeClass_ANY:
+ return rVal;
+
+ // --- to BOOL ------------------------------------------------------------------------------
+ case TypeClass_BOOLEAN:
+ switch (aSourceClass)
+ {
+ default:
+ aRet <<= (toDouble( rVal ) != 0.0);
+ break;
+ case TypeClass_ENUM: // exclude enums
+ break;
+
+ case TypeClass_STRING:
+ {
+ const OUString & aStr = *o3tl::forceAccess<OUString>(rVal);
+ if ( aStr == "0" || aStr.equalsIgnoreAsciiCase( "false" ))
+ {
+ aRet <<= false;
+ }
+ else if ( aStr == "1" || aStr.equalsIgnoreAsciiCase( "true" ))
+ {
+ aRet <<= true;
+ }
+ else
+ {
+ throw CannotConvertException(
+ "STRING has no boolean value, " + aStr,
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_BOOL, 0 );
+ }
+ }
+ }
+ break;
+
+ // --- to CHAR, BYTE ------------------------------------------------------------------------
+ case TypeClass_CHAR:
+ {
+ if (aSourceClass==TypeClass_STRING)
+ {
+ auto const s = o3tl::forceAccess<OUString>(rVal);
+ if (s->getLength() == 1) // single char
+ aRet <<= (*s)[0];
+ }
+ else if (aSourceClass!=TypeClass_ENUM && // exclude enums, chars
+ aSourceClass!=TypeClass_CHAR)
+ {
+ aRet <<= sal_Unicode(toHyper( rVal, 0, 0xffff )); // range
+ }
+ break;
+ }
+ case TypeClass_BYTE:
+ aRet <<= static_cast<sal_Int8>( toHyper( rVal, -sal_Int64(0x80), 0x7f ) );
+ break;
+
+ // --- to SHORT, UNSIGNED SHORT -------------------------------------------------------------
+ case TypeClass_SHORT:
+ aRet <<= static_cast<sal_Int16>( toHyper( rVal, -sal_Int64(0x8000), 0x7fff ) );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ aRet <<= static_cast<sal_uInt16>( toHyper( rVal, 0, 0xffff ) );
+ break;
+
+ // --- to LONG, UNSIGNED LONG ---------------------------------------------------------------
+ case TypeClass_LONG:
+ aRet <<= static_cast<sal_Int32>( toHyper( rVal, -sal_Int64(0x80000000), 0x7fffffff ) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ aRet <<= static_cast<sal_uInt32>( toHyper( rVal, 0, 0xffffffff ) );
+ break;
+
+ // --- to HYPER, UNSIGNED HYPER--------------------------------------------
+ case TypeClass_HYPER:
+ aRet <<= toHyper( rVal, SAL_MIN_INT64, SAL_MAX_INT64 );
+ break;
+ case TypeClass_UNSIGNED_HYPER:
+ aRet <<= static_cast<sal_uInt64>( toHyper( rVal, 0 ) );
+ break;
+
+ // --- to FLOAT, DOUBLE ---------------------------------------------------------------------
+ case TypeClass_FLOAT:
+ aRet <<= static_cast<float>( toDouble( rVal, -FLT_MAX, FLT_MAX ) );
+ break;
+ case TypeClass_DOUBLE:
+ aRet <<= toDouble( rVal, -DBL_MAX, DBL_MAX );
+ break;
+
+ // --- to STRING ----------------------------------------------------------------------------
+ case TypeClass_STRING:
+ switch (aSourceClass)
+ {
+ case TypeClass_ENUM:
+ {
+ TypeDescription aEnumTD( aSourceType );
+ aEnumTD.makeComplete();
+ sal_Int32 nPos;
+ sal_Int32 nEnumValue = *static_cast<sal_Int32 const *>(rVal.getValue());
+ for ( nPos = reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->nEnumValues; nPos--; )
+ {
+ if (nEnumValue == reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->pEnumValues[nPos])
+ break;
+ }
+ if (nPos < 0)
+ {
+ throw CannotConvertException(
+ "value is not ENUM!",
+ Reference< XInterface >(), aDestinationClass, FailReason::IS_NOT_ENUM, 0 );
+ }
+
+ aRet <<= OUString::unacquired(
+ &reinterpret_cast<typelib_EnumTypeDescription *>(aEnumTD.get())->ppEnumNames[nPos]);
+
+ break;
+ }
+
+ case TypeClass_BOOLEAN:
+ aRet <<= *o3tl::forceAccess<bool>(rVal) ?
+ OUString("true") :
+ OUString("false");
+ break;
+ case TypeClass_CHAR:
+ aRet <<= OUString(*o3tl::forceAccess<sal_Unicode>(rVal));
+ break;
+
+ case TypeClass_BYTE:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int8>(rVal) );
+ break;
+ case TypeClass_SHORT:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int16>(rVal) );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt16>(rVal) );
+ break;
+ case TypeClass_LONG:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int32>(rVal) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_uInt32>(rVal) );
+ break;
+ case TypeClass_HYPER:
+ aRet <<= OUString::number( *o3tl::forceAccess<sal_Int64>(rVal) );
+ break;
+// case TypeClass_UNSIGNED_HYPER:
+// aRet <<= OUString::valueOf( (sal_Int64)*(sal_uInt64 const *)rVal.getValue() );
+// break;
+ // handle unsigned hyper like double
+
+ default:
+ aRet <<= OUString::number( toDouble( rVal ) );
+ }
+ break;
+
+ default:
+ OSL_ASSERT(false);
+ break;
+ }
+
+ if (aRet.hasValue())
+ return aRet;
+
+ throw CannotConvertException(
+ "conversion not possible!",
+ Reference< XInterface >(), aDestinationClass, FailReason::INVALID, 0 );
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_stoc_TypeConverter_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new stoc_tcv::TypeConverter_Impl());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx
new file mode 100644
index 0000000000..b9e2ca4e99
--- /dev/null
+++ b/stoc/source/uriproc/ExternalUriReferenceTranslator.cxx
@@ -0,0 +1,187 @@
+/* -*- 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/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <osl/thread.h>
+#include <rtl/string.h>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class XInterface; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace {
+
+class Translator:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XExternalUriReferenceTranslator>
+{
+public:
+ Translator() {}
+
+ Translator(const Translator&) = delete;
+ Translator& operator=(const Translator&) = delete;
+
+ 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 OUString SAL_CALL
+ translateToInternal(OUString const & externalUriReference) override;
+
+ virtual OUString SAL_CALL
+ translateToExternal(OUString const & internalUriReference) override;
+
+private:
+ virtual ~Translator() override {}
+};
+
+OUString Translator::getImplementationName()
+{
+ return "com.sun.star.comp.uri.ExternalUriReferenceTranslator";
+}
+
+sal_Bool Translator::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Translator::getSupportedServiceNames()
+{
+ css::uno::Sequence< OUString > s { "com.sun.star.uri.ExternalUriReferenceTranslator" };
+ return s;
+}
+
+OUString Translator::translateToInternal(
+ OUString const & externalUriReference)
+{
+ if (!externalUriReference.matchIgnoreAsciiCase("file:/"))
+ {
+ return externalUriReference;
+ }
+ sal_Int32 i = RTL_CONSTASCII_LENGTH("file:");
+ OUStringBuffer buf(128);
+ buf.append(externalUriReference.subView(0, i));
+ // Some environments (e.g., Java) produce illegal file URLs without an
+ // authority part; treat them as having an empty authority part:
+ if (!externalUriReference.match("//", i))
+ {
+ buf.append("//");
+ }
+ rtl_TextEncoding encoding = osl_getThreadTextEncoding();
+ for (bool path = true;;) {
+ sal_Int32 j = i;
+ while (j != externalUriReference.getLength()
+ && externalUriReference[j] != '#'
+ && (!path || externalUriReference[j] != '/'))
+ {
+ ++j;
+ }
+ if (j != i) {
+ OUString seg(
+ rtl::Uri::encode(
+ rtl::Uri::decode(
+ externalUriReference.copy(i, j - i),
+ rtl_UriDecodeStrict, encoding),
+ rtl_UriCharClassPchar, rtl_UriEncodeStrict,
+ RTL_TEXTENCODING_UTF8));
+ if (seg.isEmpty()) {
+ return OUString();
+ }
+ buf.append(seg);
+ }
+ if (j == externalUriReference.getLength()) {
+ break;
+ }
+ buf.append(externalUriReference[j]);
+ path = externalUriReference[j] == '/';
+ i = j + 1;
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString Translator::translateToExternal(
+ OUString const & internalUriReference)
+{
+ if (!internalUriReference.matchIgnoreAsciiCase("file://"))
+ {
+ return internalUriReference;
+ }
+ sal_Int32 i = RTL_CONSTASCII_LENGTH("file://");
+ OUStringBuffer buf(128);
+ buf.append(internalUriReference.subView(0, i));
+ rtl_TextEncoding encoding = osl_getThreadTextEncoding();
+ for (bool path = true;;) {
+ sal_Int32 j = i;
+ while (j != internalUriReference.getLength()
+ && internalUriReference[j] != '#'
+ && (!path || internalUriReference[j] != '/'))
+ {
+ ++j;
+ }
+ if (j != i) {
+ // Use rtl_UriDecodeToIuri -> rtl_UriEncodeStrictKeepEscapes instead
+ // of rtl_UriDecodeStrict -> rtl_UriEncodeStrict, so that spurious
+ // non--UTF-8 octets like "%FE" are copied verbatim:
+ OUString seg(
+ rtl::Uri::encode(
+ rtl::Uri::decode(
+ internalUriReference.copy(i, j - i),
+ rtl_UriDecodeToIuri, RTL_TEXTENCODING_UTF8),
+ rtl_UriCharClassPchar, rtl_UriEncodeStrictKeepEscapes,
+ encoding));
+ if (seg.isEmpty()) {
+ return OUString();
+ }
+ buf.append(seg);
+ }
+ if (j == internalUriReference.getLength()) {
+ break;
+ }
+ buf.append(internalUriReference[j]);
+ path = internalUriReference[j] == '/';
+ i = j + 1;
+ }
+ return buf.makeStringAndClear();
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_ExternalUriReferenceTranslator_get_implementation(css::uno::XComponentContext* ,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new Translator);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriReference.cxx b/stoc/source/uriproc/UriReference.cxx
new file mode 100644
index 0000000000..fc27201414
--- /dev/null
+++ b/stoc/source/uriproc/UriReference.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 <sal/config.h>
+
+#include <cassert>
+
+#include "UriReference.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <utility>
+#include <sal/types.h>
+
+using stoc::uriproc::UriReference;
+
+UriReference::UriReference(
+ OUString scheme, bool bHasAuthority,
+ OUString const & authority, OUString path,
+ bool bHasQuery, OUString const & query):
+ m_path(std::move(path)),
+ m_scheme(std::move(scheme)),
+ m_authority(authority),
+ m_query(query),
+ m_hasAuthority(bHasAuthority),
+ m_hasQuery(bHasQuery),
+ m_hasFragment(false)
+{
+ assert(authority.isEmpty() || bHasAuthority);
+ assert(query.isEmpty() || bHasQuery);
+}
+
+UriReference::~UriReference() {}
+
+OUString UriReference::getUriReference()
+{
+ std::lock_guard g(m_mutex);
+ OUStringBuffer buf(128);
+ if (!m_scheme.isEmpty()) {
+ buf.append(m_scheme + ":");
+ }
+ appendSchemeSpecificPart(buf);
+ if (m_hasFragment) {
+ buf.append("#" + m_fragment);
+ }
+ return buf.makeStringAndClear();
+}
+
+bool UriReference::isAbsolute() const {
+ return !m_scheme.isEmpty();
+}
+
+
+OUString UriReference::getSchemeSpecificPart()
+{
+ std::lock_guard g(m_mutex);
+ OUStringBuffer buf;
+ appendSchemeSpecificPart(buf);
+ return buf.makeStringAndClear();
+}
+
+bool UriReference::isHierarchical() {
+ std::lock_guard g(m_mutex);
+ return m_scheme.isEmpty() || m_hasAuthority || m_path.startsWith("/");
+}
+
+bool UriReference::hasAuthority() const {
+ return m_hasAuthority;
+}
+
+const OUString& UriReference::getAuthority() const {
+ return m_authority;
+}
+
+OUString UriReference::getPath() {
+ std::lock_guard g(m_mutex);
+ return m_path;
+}
+
+bool UriReference::hasRelativePath() {
+ std::lock_guard g(m_mutex);
+ return !m_hasAuthority
+ && (m_path.isEmpty() || m_path[0] != '/');
+}
+
+sal_Int32 UriReference::getPathSegmentCount()
+{
+ std::lock_guard g(m_mutex);
+ if (m_path.isEmpty()) {
+ return 0;
+ } else {
+ sal_Int32 n = m_path[0] == '/' ? 0 : 1;
+ for (sal_Int32 i = 0;; ++i) {
+ i = m_path.indexOf('/', i);
+ if (i < 0) {
+ break;
+ }
+ ++n;
+ }
+ return n;
+ }
+}
+
+OUString UriReference::getPathSegment(sal_Int32 index)
+{
+ std::lock_guard g(m_mutex);
+ if (!m_path.isEmpty() && index >= 0) {
+ for (sal_Int32 i = m_path[0] == '/' ? 1 : 0;; ++i) {
+ if (index-- == 0) {
+ sal_Int32 j = m_path.indexOf('/', i);
+ return j < 0 ? m_path.copy(i) : m_path.copy(i, j - i);
+ }
+ i = m_path.indexOf('/', i);
+ if (i < 0) {
+ break;
+ }
+ }
+ }
+ return OUString();
+}
+
+bool UriReference::hasQuery() const {
+ return m_hasQuery;
+}
+
+const OUString& UriReference::getQuery() const {
+ return m_query;
+}
+
+bool UriReference::hasFragment() {
+ std::lock_guard g(m_mutex);
+ return m_hasFragment;
+}
+
+OUString UriReference::getFragment() {
+ std::lock_guard g(m_mutex);
+ return m_fragment;
+}
+
+void UriReference::setFragment(OUString const & fragment)
+{
+ std::lock_guard g(m_mutex);
+ m_hasFragment = true;
+ m_fragment = fragment;
+}
+
+void UriReference::clearFragment() {
+ std::lock_guard g(m_mutex);
+ m_hasFragment = false;
+ m_fragment.clear();
+}
+
+void UriReference::appendSchemeSpecificPart(OUStringBuffer & buffer) const
+{
+ if (m_hasAuthority) {
+ buffer.append("//");
+ buffer.append(m_authority);
+ }
+ buffer.append(m_path);
+ if (m_hasQuery) {
+ buffer.append('?');
+ buffer.append(m_query);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriReference.hxx b/stoc/source/uriproc/UriReference.hxx
new file mode 100644
index 0000000000..1b373f56a7
--- /dev/null
+++ b/stoc/source/uriproc/UriReference.hxx
@@ -0,0 +1,112 @@
+/* -*- 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_STOC_SOURCE_URIPROC_URIREFERENCE_HXX
+#define INCLUDED_STOC_SOURCE_URIPROC_URIREFERENCE_HXX
+
+#include <mutex>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <rtl/ustrbuf.hxx>
+
+namespace stoc::uriproc {
+
+class UriReference {
+public:
+ UriReference(
+ OUString scheme, bool hasAuthority,
+ OUString const & authority, OUString path,
+ bool hasQuery, OUString const & query);
+
+ ~UriReference();
+
+ /// @throws css::uno::RuntimeException
+ OUString getUriReference();
+
+ /// @throws css::uno::RuntimeException
+ bool isAbsolute() const;
+
+ /// @throws css::uno::RuntimeException
+ const OUString& getScheme() const { return m_scheme;}
+
+ /// @throws css::uno::RuntimeException
+ OUString getSchemeSpecificPart();
+
+ /// @throws css::uno::RuntimeException
+ bool isHierarchical();
+
+ /// @throws css::uno::RuntimeException
+ bool hasAuthority() const;
+
+ /// @throws css::uno::RuntimeException
+ const OUString& getAuthority() const;
+
+ /// @throws css::uno::RuntimeException
+ OUString getPath();
+
+ /// @throws css::uno::RuntimeException
+ bool hasRelativePath();
+
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getPathSegmentCount();
+
+ /// @throws css::uno::RuntimeException
+ OUString getPathSegment(sal_Int32 index);
+
+ /// @throws css::uno::RuntimeException
+ bool hasQuery() const;
+
+ /// @throws css::uno::RuntimeException
+ const OUString& getQuery() const;
+
+ /// @throws css::uno::RuntimeException
+ bool hasFragment();
+
+ /// @throws css::uno::RuntimeException
+ OUString getFragment();
+
+ /// @throws css::uno::RuntimeException
+ void setFragment(OUString const & fragment);
+
+ /// @throws css::uno::RuntimeException
+ void clearFragment();
+
+ std::mutex m_mutex;
+ OUString m_path;
+
+private:
+ UriReference(UriReference const &) = delete;
+ void operator =(UriReference const &) = delete;
+
+ void appendSchemeSpecificPart(OUStringBuffer & buffer) const;
+
+ OUString m_scheme;
+ OUString m_authority;
+ OUString m_query;
+ OUString m_fragment;
+ bool m_hasAuthority;
+ bool m_hasQuery;
+ bool m_hasFragment;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriReferenceFactory.cxx b/stoc/source/uriproc/UriReferenceFactory.cxx
new file mode 100644
index 0000000000..2573917713
--- /dev/null
+++ b/stoc/source/uriproc/UriReferenceFactory.cxx
@@ -0,0 +1,701 @@
+/* -*- 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 <cstddef>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#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/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <com/sun/star/uri/RelativeUriExcessParentSegments.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+#include <com/sun/star/uri/XUriSchemeParser.hpp>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/character.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include "UriReference.hxx"
+
+namespace {
+
+bool equalIgnoreEscapeCase(std::u16string_view s1, std::u16string_view s2) {
+ if (s1.size() == s2.size()) {
+ for (size_t i = 0; i < s1.size();) {
+ if (s1[i] == '%' && s2[i] == '%' && s1.size() - i > 2
+ && rtl::isAsciiHexDigit(s1[i + 1])
+ && rtl::isAsciiHexDigit(s1[i + 2])
+ && rtl::isAsciiHexDigit(s2[i + 1])
+ && rtl::isAsciiHexDigit(s2[i + 2])
+ && rtl::compareIgnoreAsciiCase(s1[i + 1], s2[i + 1]) == 0
+ && rtl::compareIgnoreAsciiCase(s1[i + 2], s2[i + 2]) == 0)
+ {
+ i += 3;
+ } else if (s1[i] != s2[i]) {
+ return false;
+ } else {
+ ++i;
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+sal_Int32 parseScheme(std::u16string_view uriReference) {
+ if (uriReference.size() >= 2 && rtl::isAsciiAlpha(uriReference[0])) {
+ for (size_t i = 0; i < uriReference.size(); ++i) {
+ sal_Unicode c = uriReference[i];
+ if (c == ':') {
+ return i;
+ } else if (!rtl::isAsciiAlpha(c) && !rtl::isAsciiDigit(c)
+ && c != '+' && c != '-' && c != '.')
+ {
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+class UriReference:
+ public cppu::WeakImplHelper<css::uri::XUriReference>
+{
+public:
+ UriReference(
+ OUString const & scheme, bool bHasAuthority,
+ OUString const & authority, OUString const & path,
+ bool bHasQuery, OUString const & query):
+ m_base(
+ scheme, bHasAuthority, authority, path, bHasQuery,
+ query)
+ {}
+
+ UriReference(const UriReference&) = delete;
+ UriReference& operator=(const UriReference&) = delete;
+
+ virtual OUString SAL_CALL getUriReference() override
+ { return m_base.getUriReference(); }
+
+ virtual sal_Bool SAL_CALL isAbsolute() override
+ { return m_base.isAbsolute(); }
+
+ virtual OUString SAL_CALL getScheme() override
+ { return m_base.getScheme(); }
+
+ virtual OUString SAL_CALL getSchemeSpecificPart() override
+ { return m_base.getSchemeSpecificPart(); }
+
+ virtual sal_Bool SAL_CALL isHierarchical() override
+ { return m_base.isHierarchical(); }
+
+ virtual sal_Bool SAL_CALL hasAuthority() override
+ { return m_base.hasAuthority(); }
+
+ virtual OUString SAL_CALL getAuthority() override
+ { return m_base.getAuthority(); }
+
+ virtual OUString SAL_CALL getPath() override
+ { return m_base.getPath(); }
+
+ virtual sal_Bool SAL_CALL hasRelativePath() override
+ { return m_base.hasRelativePath(); }
+
+ virtual sal_Int32 SAL_CALL getPathSegmentCount() override
+ { return m_base.getPathSegmentCount(); }
+
+ virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
+ { return m_base.getPathSegment(index); }
+
+ virtual sal_Bool SAL_CALL hasQuery() override
+ { return m_base.hasQuery(); }
+
+ virtual OUString SAL_CALL getQuery() override
+ { return m_base.getQuery(); }
+
+ virtual sal_Bool SAL_CALL hasFragment() override
+ { return m_base.hasFragment(); }
+
+ virtual OUString SAL_CALL getFragment() override
+ { return m_base.getFragment(); }
+
+ virtual void SAL_CALL setFragment(OUString const & fragment) override
+ { m_base.setFragment(fragment); }
+
+ virtual void SAL_CALL clearFragment() override
+ { m_base.clearFragment(); }
+
+private:
+ virtual ~UriReference() override {}
+
+ stoc::uriproc::UriReference m_base;
+};
+
+css::uno::Reference< css::uri::XUriReference > parseGeneric(
+ OUString const & scheme, OUString const & schemeSpecificPart)
+{
+ sal_Int32 len = schemeSpecificPart.getLength();
+ sal_Int32 i = 0;
+ bool hasAuthority = false;
+ OUString authority;
+ if (len - i >= 2 && schemeSpecificPart[i] == '/'
+ && schemeSpecificPart[i + 1] == '/')
+ {
+ i += 2;
+ sal_Int32 n = i;
+ while (i < len && schemeSpecificPart[i] != '/'
+ && schemeSpecificPart[i] != '?') {
+ ++i;
+ }
+ hasAuthority = true;
+ authority = schemeSpecificPart.copy(n, i - n);
+ }
+ sal_Int32 n = i;
+ i = schemeSpecificPart.indexOf('?', i);
+ if (i == -1) {
+ i = len;
+ }
+ OUString path = schemeSpecificPart.copy(n, i - n);
+ bool hasQuery = false;
+ OUString query;
+ if (i != len) {
+ hasQuery = true;
+ query = schemeSpecificPart.copy(i + 1);
+ }
+ return new UriReference(
+ scheme, hasAuthority, authority, path, hasQuery, query);
+}
+
+struct Segment {
+ bool leadingSlash;
+ bool excessParent;
+ std::u16string_view segment;
+
+ Segment(bool theLeadingSlash, bool theExcessParent, std::u16string_view theSegment):
+ leadingSlash(theLeadingSlash), excessParent(theExcessParent), segment(theSegment) {}
+};
+
+std::pair<std::vector<Segment>, bool> processSegments(
+ std::u16string_view first, std::u16string_view second, bool processSpecialSegments)
+{
+ std::vector<Segment> segments;
+ bool processed = false;
+ std::u16string_view const * half = &first;
+ // later checks for `half == &first` and `half == &second` rely on the fact that `first` and
+ // `second` are passed by value, in case a caller passes the same object for both arguments
+ std::size_t index = 0;
+ bool slash = false;
+ if (index == half->length()) {
+ half = &second;
+ index = 0;
+ }
+ if (index != half->length()) {
+ if ((*half)[index] == u'/') {
+ slash = true;
+ ++index;
+ }
+ for (;;) {
+ if (index == half->length() && half == &first) {
+ half = &second;
+ index = 0;
+ }
+ if (index == half->length()) {
+ if (slash) {
+ segments.emplace_back(true, false, std::u16string_view());
+ }
+ break;
+ }
+ auto const n = std::min(half->find(u'/', index), half->length());
+ auto const leadingSlash = slash;
+ auto const segment = half->substr(index, n - index);
+ auto const process = processSpecialSegments || half == &second;
+ index = n;
+ slash = false;
+ if (index == half->length() && half == &first) {
+ half = &second;
+ index = 0;
+ }
+ if (index != half->length() && (*half)[index] == u'/') {
+ slash = true;
+ ++index;
+ }
+ if (process) {
+ if (segment == u".") {
+ slash = leadingSlash;
+ processed = true;
+ continue;
+ } else if (segment == u"..") {
+ if (segments.empty() || segments.back().excessParent) {
+ segments.emplace_back(leadingSlash, true, segment);
+ } else {
+ if (leadingSlash) {
+ segments.pop_back();
+ }
+ slash = leadingSlash;
+ }
+ processed = true;
+ continue;
+ }
+ }
+ segments.emplace_back(leadingSlash, false, segment);
+ }
+ }
+ return {segments, processed};
+}
+
+class Factory:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XUriReferenceFactory>
+{
+public:
+ explicit Factory(
+ css::uno::Reference< css::uno::XComponentContext > context):
+ m_context(std::move(context)) {}
+
+ Factory(const Factory&) = delete;
+ Factory& operator=(const Factory&) = delete;
+
+ 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::uri::XUriReference > SAL_CALL
+ parse(OUString const & uriReference) override;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ makeAbsolute(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool processAdditionalSpecialSegments,
+ css::uri::RelativeUriExcessParentSegments excessParentSegments) override;
+
+ virtual css::uno::Reference< css::uri::XUriReference > SAL_CALL
+ makeRelative(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool preferAuthorityOverRelativePath,
+ sal_Bool preferAbsoluteOverRelativePath,
+ sal_Bool encodeRetainedSpecialSegments) override;
+
+private:
+ virtual ~Factory() override {}
+
+ css::uno::Reference< css::uri::XUriReference > clone(
+ css::uno::Reference< css::uri::XUriReference > const & uriReference)
+ { return parse(uriReference->getUriReference()); }
+
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+};
+
+OUString Factory::getImplementationName()
+{
+ return "com.sun.star.comp.uri.UriReferenceFactory";
+}
+
+sal_Bool Factory::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
+{
+ css::uno::Sequence< OUString > s { "com.sun.star.uri.UriReferenceFactory" };
+ return s;
+}
+
+css::uno::Reference< css::uri::XUriReference > Factory::parse(
+ OUString const & uriReference)
+{
+ sal_Int32 fragment = uriReference.indexOf('#');
+ if (fragment == -1) {
+ fragment = uriReference.getLength();
+ }
+ OUString scheme;
+ OUString schemeSpecificPart;
+ OUString serviceName;
+ sal_Int32 n = parseScheme(uriReference);
+ assert(n < fragment);
+ if (n >= 0) {
+ scheme = uriReference.copy(0, n);
+ schemeSpecificPart = uriReference.copy(n + 1, fragment - (n + 1));
+ OUStringBuffer buf(128);
+ buf.append("com.sun.star.uri.UriSchemeParser_");
+ for (sal_Int32 i = 0; i < scheme.getLength(); ++i) {
+ sal_Unicode c = scheme[i];
+ if (rtl::isAsciiUpperCase(c)) {
+ buf.append(static_cast<sal_Unicode>(rtl::toAsciiLowerCase(c)));
+ } else if (c == '+') {
+ buf.append("PLUS");
+ } else if (c == '-') {
+ buf.append("HYPHEN");
+ } else if (c == '.') {
+ buf.append("DOT");
+ } else {
+ assert(rtl::isAsciiLowerCase(c) || rtl::isAsciiDigit(c));
+ buf.append(c);
+ }
+ }
+ serviceName = buf.makeStringAndClear();
+ } else {
+ schemeSpecificPart = uriReference.copy(0, fragment);
+ }
+ css::uno::Reference< css::uri::XUriSchemeParser > parser;
+ if (!serviceName.isEmpty()) {
+ css::uno::Reference< css::lang::XMultiComponentFactory > factory(
+ m_context->getServiceManager());
+ if (factory.is()) {
+ css::uno::Reference< css::uno::XInterface > service;
+ try {
+ service = factory->createInstanceWithContext(
+ serviceName, m_context);
+ } catch (css::uno::RuntimeException &) {
+ throw;
+ } catch (const css::uno::Exception &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException(
+ "creating service " + serviceName,
+ getXWeak(),
+ anyEx);
+ }
+ if (service.is()) {
+ parser.set( service, css::uno::UNO_QUERY_THROW);
+ }
+ }
+ }
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ parser.is()
+ ? parser->parse(scheme, schemeSpecificPart)
+ : parseGeneric(scheme, schemeSpecificPart));
+ if (uriRef.is() && fragment != uriReference.getLength()) {
+ uriRef->setFragment(uriReference.copy(fragment + 1));
+ }
+ return uriRef;
+}
+
+css::uno::Reference< css::uri::XUriReference > Factory::makeAbsolute(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool processAdditionalSpecialSegments,
+ css::uri::RelativeUriExcessParentSegments excessParentSegments)
+{
+ if (!baseUriReference.is() || !baseUriReference->isAbsolute()
+ || !uriReference.is()) {
+ return nullptr;
+ } else if (uriReference->isAbsolute()) {
+ if (processAdditionalSpecialSegments) {
+ auto const path = uriReference->getPath();
+ auto [segments, proc] = processSegments(path, {}, true);
+ if (proc) {
+ OUStringBuffer abs(uriReference->getScheme() + ":");
+ if (uriReference->hasAuthority()) {
+ abs.append("//" + uriReference->getAuthority());
+ }
+ for (auto const & i : segments)
+ {
+ if (i.excessParent) {
+ switch (excessParentSegments) {
+ case css::uri::RelativeUriExcessParentSegments_ERROR:
+ return nullptr;
+
+ case css::uri::RelativeUriExcessParentSegments_RETAIN:
+ assert(i.segment == u"..");
+ break;
+
+ case css::uri::RelativeUriExcessParentSegments_REMOVE:
+ continue;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (i.leadingSlash) {
+ abs.append('/');
+ }
+ abs.append(i.segment);
+ }
+ if (uriReference->hasQuery()) {
+ abs.append("?" + uriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ abs.append("#" + uriReference->getFragment());
+ }
+ return parse(abs.makeStringAndClear());
+ }
+ }
+ return clone(uriReference);
+ } else if (!uriReference->hasAuthority()
+ && uriReference->getPath().isEmpty()) {
+ OUStringBuffer abs(baseUriReference->getScheme() + ":");
+ if (baseUriReference->hasAuthority()) {
+ abs.append("//" + baseUriReference->getAuthority());
+ }
+ abs.append(baseUriReference->getPath());
+ if (uriReference->hasQuery()) {
+ abs.append("?" + uriReference->getQuery());
+ } else if (baseUriReference->hasQuery()) {
+ abs.append("?" + baseUriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ abs.append("#" + uriReference->getFragment());
+ }
+ return parse(abs.makeStringAndClear());
+ } else {
+ OUStringBuffer abs(128);
+ abs.append(baseUriReference->getScheme() + ":");
+ if (uriReference->hasAuthority()) {
+ abs.append("//" + uriReference->getAuthority());
+ } else if (baseUriReference->hasAuthority()) {
+ abs.append("//" + baseUriReference->getAuthority());
+ }
+ if (uriReference->hasRelativePath()) {
+ auto path1 = baseUriReference->getPath();
+ if (path1.isEmpty()) {
+ if (baseUriReference->hasAuthority()) {
+ path1 = "/";
+ }
+ } else {
+ path1 = path1.copy(0, path1.lastIndexOf('/') + 1);
+ }
+ auto const path2 = uriReference->getPath();
+ auto [segments, _] = processSegments(path1, path2, processAdditionalSpecialSegments);
+ (void)_;
+ for (auto const & i : segments)
+ {
+ if (i.excessParent) {
+ switch (excessParentSegments) {
+ case css::uri::RelativeUriExcessParentSegments_ERROR:
+ return nullptr;
+
+ case css::uri::RelativeUriExcessParentSegments_RETAIN:
+ assert(i.segment == u"..");
+ break;
+
+ case css::uri::RelativeUriExcessParentSegments_REMOVE:
+ continue;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (i.leadingSlash) {
+ abs.append('/');
+ }
+ abs.append(i.segment);
+ }
+ } else {
+ bool processed = false;
+ if (processAdditionalSpecialSegments) {
+ auto const path = uriReference->getPath();
+ auto [segments, proc] = processSegments(path, {}, true);
+ if (proc) {
+ for (auto const & i : segments)
+ {
+ if (i.excessParent) {
+ switch (excessParentSegments) {
+ case css::uri::RelativeUriExcessParentSegments_ERROR:
+ return nullptr;
+
+ case css::uri::RelativeUriExcessParentSegments_RETAIN:
+ assert(i.segment == u"..");
+ break;
+
+ case css::uri::RelativeUriExcessParentSegments_REMOVE:
+ continue;
+
+ default:
+ assert(false);
+ break;
+ }
+ }
+ if (i.leadingSlash) {
+ abs.append('/');
+ }
+ abs.append(i.segment);
+ }
+ processed = true;
+ }
+ }
+ if (!processed) {
+ abs.append(uriReference->getPath());
+ }
+ }
+ if (uriReference->hasQuery()) {
+ abs.append("?" + uriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ abs.append("#" + uriReference->getFragment());
+ }
+ return parse(abs.makeStringAndClear());
+ }
+}
+
+css::uno::Reference< css::uri::XUriReference > Factory::makeRelative(
+ css::uno::Reference< css::uri::XUriReference > const & baseUriReference,
+ css::uno::Reference< css::uri::XUriReference > const & uriReference,
+ sal_Bool preferAuthorityOverRelativePath,
+ sal_Bool preferAbsoluteOverRelativePath,
+ sal_Bool encodeRetainedSpecialSegments)
+{
+ if (!baseUriReference.is() || !baseUriReference->isAbsolute()
+ || !uriReference.is()) {
+ return nullptr;
+ } else if (!uriReference->isAbsolute() || uriReference->hasRelativePath()
+ || !baseUriReference->getScheme().equalsIgnoreAsciiCase(
+ uriReference->getScheme())) {
+ return clone(uriReference);
+ } else {
+ OUStringBuffer rel(128);
+ bool omitQuery = false;
+ if ((baseUriReference->hasAuthority() != uriReference->hasAuthority())
+ || !equalIgnoreEscapeCase(
+ baseUriReference->getAuthority(),
+ uriReference->getAuthority()))
+ {
+ if (uriReference->hasAuthority()) {
+ rel.append("//" + uriReference->getAuthority());
+ }
+ rel.append(uriReference->getPath());
+ } else if ((equalIgnoreEscapeCase(
+ baseUriReference->getPath(), uriReference->getPath())
+ || (baseUriReference->getPath() == "/"
+ && uriReference->getPath().isEmpty()))
+ && baseUriReference->hasQuery() == uriReference->hasQuery()
+ && equalIgnoreEscapeCase(
+ baseUriReference->getQuery(), uriReference->getQuery()))
+ {
+ omitQuery = true;
+ } else {
+ sal_Int32 count1 = std::max< sal_Int32 >(
+ baseUriReference->getPathSegmentCount(), 1);
+ sal_Int32 count2 = std::max< sal_Int32 >(
+ uriReference->getPathSegmentCount(), 1);
+ sal_Int32 i = 0;
+ for (; i < std::min(count1, count2) - 1; ++i) {
+ if (!equalIgnoreEscapeCase(
+ baseUriReference->getPathSegment(i),
+ uriReference->getPathSegment(i)))
+ {
+ break;
+ }
+ }
+ if (i == 0
+ && (preferAbsoluteOverRelativePath || uriReference->hasQuery())
+ && (preferAuthorityOverRelativePath
+ || !uriReference->getPath().startsWith("//")))
+ {
+ if (uriReference->getPath().isEmpty()) {
+ if (!baseUriReference->getPath().isEmpty()
+ && baseUriReference->getPath() != "/")
+ {
+ rel.append('/');
+ }
+ } else if (uriReference->getPath() == "/") {
+ if (baseUriReference->getPath().isEmpty()
+ || baseUriReference->getPath() != "/")
+ {
+ rel.append('/');
+ }
+ } else {
+ if (uriReference->getPath().startsWith("//")) {
+ assert(uriReference->hasAuthority());
+ rel.append("//" + uriReference->getAuthority());
+ }
+ rel.append(uriReference->getPath());
+ }
+ } else {
+ bool segments = false;
+ for (sal_Int32 j = i; j < count1 - 1; ++j) {
+ if (segments) {
+ rel.append('/');
+ }
+ rel.append("..");
+ segments = true;
+ }
+ if (i < count2 - 1
+ || (!uriReference->getPathSegment(count2 - 1).isEmpty()))
+ {
+ if (!segments
+ && (uriReference->getPathSegment(i).isEmpty()
+ || (parseScheme(uriReference->getPathSegment(i))
+ >= 0)))
+ {
+ rel.append('.');
+ segments = true;
+ }
+ for (; i < count2; ++i) {
+ if (segments) {
+ rel.append('/');
+ }
+ OUString s(uriReference->getPathSegment(i));
+ if (encodeRetainedSpecialSegments && s == ".") {
+ rel.append("%2E");
+ } else if (encodeRetainedSpecialSegments && s == "..") {
+ rel.append("%2E%2E");
+ } else {
+ rel.append(s);
+ }
+ segments = true;
+ }
+ }
+ }
+ }
+ if (!omitQuery && uriReference->hasQuery()) {
+ rel.append("?" + uriReference->getQuery());
+ }
+ if (uriReference->hasFragment()) {
+ rel.append("#" + uriReference->getFragment());
+ }
+ return parse(rel.makeStringAndClear());
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_UriReferenceFactory_get_implementation(css::uno::XComponentContext* rxContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new Factory(rxContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx
new file mode 100644
index 0000000000..dde6fcb060
--- /dev/null
+++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTexpand.cxx
@@ -0,0 +1,198 @@
+/* -*- 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/lang/XServiceInfo.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/uri/XUriSchemeParser.hpp>
+#include <com/sun/star/uri/XVndSunStarExpandUrlReference.hpp>
+#include <com/sun/star/util/XMacroExpander.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include "UriReference.hxx"
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::uno { class XInterface; }
+namespace com::sun::star::uri { class XUriReference; }
+
+namespace {
+
+bool parseSchemeSpecificPart(OUString const & part) {
+ // Liberally accepts both an empty opaque_part and an opaque_part that
+ // starts with a non-escaped "/":
+ return part.isEmpty()
+ || (!::rtl::Uri::decode(part, ::rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8).isEmpty());
+}
+
+class UrlReference:
+ public ::cppu::WeakImplHelper<css::uri::XVndSunStarExpandUrlReference>
+{
+public:
+ UrlReference(OUString const & scheme, OUString const & path):
+ base_(
+ scheme, false, OUString(), path, false,
+ OUString())
+ {}
+
+ UrlReference(const UrlReference&) = delete;
+ UrlReference& operator=(const UrlReference&) = delete;
+
+ virtual OUString SAL_CALL getUriReference() override
+ { return base_.getUriReference(); }
+
+ virtual sal_Bool SAL_CALL isAbsolute() override
+ { return base_.isAbsolute(); }
+
+ virtual OUString SAL_CALL getScheme() override
+ { return base_.getScheme(); }
+
+ virtual OUString SAL_CALL getSchemeSpecificPart() override
+ { return base_.getSchemeSpecificPart(); }
+
+ virtual sal_Bool SAL_CALL isHierarchical() override
+ { return base_.isHierarchical(); }
+
+ virtual sal_Bool SAL_CALL hasAuthority() override
+ { return base_.hasAuthority(); }
+
+ virtual OUString SAL_CALL getAuthority() override
+ { return base_.getAuthority(); }
+
+ virtual OUString SAL_CALL getPath() override
+ { return base_.getPath(); }
+
+ virtual sal_Bool SAL_CALL hasRelativePath() override
+ { return base_.hasRelativePath(); }
+
+ virtual ::sal_Int32 SAL_CALL getPathSegmentCount() override
+ { return base_.getPathSegmentCount(); }
+
+ virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
+ { return base_.getPathSegment(index); }
+
+ virtual sal_Bool SAL_CALL hasQuery() override
+ { return base_.hasQuery(); }
+
+ virtual OUString SAL_CALL getQuery() override
+ { return base_.getQuery(); }
+
+ virtual sal_Bool SAL_CALL hasFragment() override
+ { return base_.hasFragment(); }
+
+ virtual OUString SAL_CALL getFragment() override
+ { return base_.getFragment(); }
+
+ virtual void SAL_CALL setFragment(OUString const & fragment) override
+ { base_.setFragment(fragment); }
+
+ virtual void SAL_CALL clearFragment() override
+ { base_.clearFragment(); }
+
+ virtual OUString SAL_CALL expand(
+ css::uno::Reference< css::util::XMacroExpander > const & expander) override;
+
+private:
+ virtual ~UrlReference() override {}
+
+ stoc::uriproc::UriReference base_;
+};
+
+OUString UrlReference::expand(
+ css::uno::Reference< css::util::XMacroExpander > const & expander)
+{
+ if (!expander.is()) {
+ throw css::uno::RuntimeException("null expander passed to XVndSunStarExpandUrl.expand");
+ }
+ return expander->expandMacros(
+ ::rtl::Uri::decode(
+ getPath(), ::rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8));
+}
+
+class Parser:
+ public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XUriSchemeParser>
+{
+public:
+ Parser() {}
+
+ Parser(const Parser&) = delete;
+ Parser& operator=(const Parser&) = delete;
+
+ 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::uri::XUriReference > SAL_CALL
+ parse(
+ OUString const & scheme,
+ OUString const & schemeSpecificPart) override;
+
+private:
+ virtual ~Parser() override {}
+};
+
+OUString Parser::getImplementationName()
+{
+ return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand";
+}
+
+sal_Bool Parser::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
+{
+ return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand" };
+}
+
+css::uno::Reference< css::uri::XUriReference > Parser::parse(
+ OUString const & scheme, OUString const & schemeSpecificPart)
+{
+ if (!parseSchemeSpecificPart(schemeSpecificPart)) {
+ return css::uno::Reference< css::uri::XUriReference >();
+ }
+ return new UrlReference(scheme, schemeSpecificPart);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTexpand_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ //TODO: single instance
+ return ::cppu::acquire(new Parser());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.cxx
new file mode 100644
index 0000000000..1f53351693
--- /dev/null
+++ b/stoc/source/uriproc/UriSchemeParser_vndDOTsunDOTstarDOTscript.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 "UriReference.hxx"
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/uri/XUriSchemeParser.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/character.hxx>
+#include <rtl/uri.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <o3tl/safeint.hxx>
+
+#include <string_view>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::uno { class XInterface; }
+namespace com::sun::star::uri { class XUriReference; }
+
+namespace {
+
+int getHexWeight(sal_Unicode c) {
+ return c >= '0' && c <= '9' ? static_cast< int >(c - '0')
+ : c >= 'A' && c <= 'F' ? static_cast< int >(c - 'A' + 10)
+ : c >= 'a' && c <= 'f' ? static_cast< int >(c - 'a' + 10)
+ : -1;
+}
+
+int parseEscaped(std::u16string_view part, sal_Int32 * index) {
+ if (part.size() - *index < 3 || part[*index] != '%') {
+ return -1;
+ }
+ int n1 = getHexWeight(part[*index + 1]);
+ int n2 = getHexWeight(part[*index + 2]);
+ if (n1 < 0 || n2 < 0) {
+ return -1;
+ }
+ *index += 3;
+ return (n1 << 4) | n2;
+}
+
+OUString parsePart(
+ std::u16string_view part, bool namePart, sal_Int32 * index)
+{
+ OUStringBuffer buf(64);
+ while (o3tl::make_unsigned(*index) < part.size()) {
+ sal_Unicode c = part[*index];
+ if (namePart ? c == '?' : c == '&' || c == '=') {
+ break;
+ } else if (c == '%') {
+ sal_Int32 i = *index;
+ int n = parseEscaped(part, &i);
+ if (n >= 0 && n <= 0x7F) {
+ buf.append(static_cast< sal_Unicode >(n));
+ } else if (n >= 0xC0 && n <= 0xFC) {
+ sal_Int32 encoded;
+ int shift;
+ sal_Int32 min;
+ if (n <= 0xDF) {
+ encoded = (n & 0x1F) << 6;
+ shift = 0;
+ min = 0x80;
+ } else if (n <= 0xEF) {
+ encoded = (n & 0x0F) << 12;
+ shift = 6;
+ min = 0x800;
+ } else if (n <= 0xF7) {
+ encoded = (n & 0x07) << 18;
+ shift = 12;
+ min = 0x10000;
+ } else if (n <= 0xFB) {
+ encoded = (n & 0x03) << 24;
+ shift = 18;
+ min = 0x200000;
+ } else {
+ encoded = 0;
+ shift = 24;
+ min = 0x4000000;
+ }
+ bool utf8 = true;
+ for (; shift >= 0; shift -= 6) {
+ n = parseEscaped(part, &i);
+ if (n < 0x80 || n > 0xBF) {
+ utf8 = false;
+ break;
+ }
+ encoded |= (n & 0x3F) << shift;
+ }
+ if (!utf8 || !rtl::isUnicodeScalarValue(encoded)
+ || encoded < min)
+ {
+ break;
+ }
+ buf.appendUtf32(encoded);
+ } else {
+ break;
+ }
+ *index = i;
+ } else {
+ buf.append(c);
+ ++*index;
+ }
+ }
+ return buf.makeStringAndClear();
+}
+
+OUString encodeNameOrParamFragment(OUString const & fragment) {
+ static constexpr auto nameOrParamFragment = rtl::createUriCharClass(
+ u8"!$'()*+,-.0123456789:;@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz~");
+ return rtl::Uri::encode(
+ fragment, nameOrParamFragment.data(), rtl_UriEncodeIgnoreEscapes,
+ RTL_TEXTENCODING_UTF8);
+}
+
+bool parseSchemeSpecificPart(std::u16string_view part) {
+ size_t len = part.size();
+ sal_Int32 i = 0;
+ if (parsePart(part, true, &i).isEmpty() || part[0] == '/') {
+ return false;
+ }
+ if (o3tl::make_unsigned(i) == len) {
+ return true;
+ }
+ for (;;) {
+ ++i; // skip '?' or '&'
+ if (parsePart(part, false, &i).isEmpty() || o3tl::make_unsigned(i) == len
+ || part[i] != '=')
+ {
+ return false;
+ }
+ ++i;
+ parsePart(part, false, &i);
+ if (o3tl::make_unsigned(i) == len) {
+ return true;
+ }
+ if (part[i] != '&') {
+ return false;
+ }
+ }
+}
+
+class UrlReference:
+ public cppu::WeakImplHelper<css::uri::XVndSunStarScriptUrlReference>
+{
+public:
+ UrlReference(OUString const & scheme, OUString const & path):
+ m_base(
+ scheme, false, OUString(), path, false, OUString())
+ {}
+
+ UrlReference(const UrlReference&) = delete;
+ UrlReference& operator=(const UrlReference&) = delete;
+
+ virtual OUString SAL_CALL getUriReference() override
+ { return m_base.getUriReference(); }
+
+ virtual sal_Bool SAL_CALL isAbsolute() override
+ { return m_base.isAbsolute(); }
+
+ virtual OUString SAL_CALL getScheme() override
+ { return m_base.getScheme(); }
+
+ virtual OUString SAL_CALL getSchemeSpecificPart() override
+ { return m_base.getSchemeSpecificPart(); }
+
+ virtual sal_Bool SAL_CALL isHierarchical() override
+ { return m_base.isHierarchical(); }
+
+ virtual sal_Bool SAL_CALL hasAuthority() override
+ { return m_base.hasAuthority(); }
+
+ virtual OUString SAL_CALL getAuthority() override
+ { return m_base.getAuthority(); }
+
+ virtual OUString SAL_CALL getPath() override
+ { return m_base.getPath(); }
+
+ virtual sal_Bool SAL_CALL hasRelativePath() override
+ { return m_base.hasRelativePath(); }
+
+ virtual sal_Int32 SAL_CALL getPathSegmentCount() override
+ { return m_base.getPathSegmentCount(); }
+
+ virtual OUString SAL_CALL getPathSegment(sal_Int32 index) override
+ { return m_base.getPathSegment(index); }
+
+ virtual sal_Bool SAL_CALL hasQuery() override
+ { return m_base.hasQuery(); }
+
+ virtual OUString SAL_CALL getQuery() override
+ { return m_base.getQuery(); }
+
+ virtual sal_Bool SAL_CALL hasFragment() override
+ { return m_base.hasFragment(); }
+
+ virtual OUString SAL_CALL getFragment() override
+ { return m_base.getFragment(); }
+
+ virtual void SAL_CALL setFragment(OUString const & fragment) override
+ { m_base.setFragment(fragment); }
+
+ virtual void SAL_CALL clearFragment() override
+ { m_base.clearFragment(); }
+
+ virtual OUString SAL_CALL getName() override;
+
+ virtual void SAL_CALL setName(OUString const & name) override;
+
+ virtual sal_Bool SAL_CALL hasParameter(OUString const & key) override;
+
+ virtual OUString SAL_CALL getParameter(OUString const & key) override;
+
+ virtual void SAL_CALL setParameter(OUString const & key, OUString const & value) override;
+
+private:
+ virtual ~UrlReference() override {}
+
+ sal_Int32 findParameter(std::u16string_view key) const;
+
+ stoc::uriproc::UriReference m_base;
+};
+
+OUString UrlReference::getName() {
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = 0;
+ return parsePart(m_base.m_path, true, &i);
+}
+
+void SAL_CALL UrlReference::setName(OUString const & name)
+{
+ if (name.isEmpty())
+ throw css::lang::IllegalArgumentException(
+ OUString(), *this, 1);
+
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = 0;
+ parsePart(m_base.m_path, true, &i);
+
+ m_base.m_path = encodeNameOrParamFragment(name) + m_base.m_path.subView(i);
+}
+
+sal_Bool UrlReference::hasParameter(OUString const & key)
+{
+ std::lock_guard g(m_base.m_mutex);
+ return findParameter(key) >= 0;
+}
+
+OUString UrlReference::getParameter(OUString const & key)
+{
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = findParameter(key);
+ return i >= 0 ? parsePart(m_base.m_path, false, &i) : OUString();
+}
+
+void UrlReference::setParameter(OUString const & key, OUString const & value)
+{
+ if (key.isEmpty())
+ throw css::lang::IllegalArgumentException(
+ OUString(), *this, 1);
+
+ std::lock_guard g(m_base.m_mutex);
+ sal_Int32 i = findParameter(key);
+ bool bExistent = ( i>=0 );
+ if (!bExistent) {
+ i = m_base.m_path.getLength();
+ }
+
+ OUStringBuffer newPath(128);
+ newPath.append(m_base.m_path.subView(0, i));
+ if (!bExistent) {
+ newPath.append( m_base.m_path.indexOf('?') < 0 ? '?' : '&' );
+ newPath.append(encodeNameOrParamFragment(key) + "=");
+ }
+ newPath.append(encodeNameOrParamFragment(value));
+ if (bExistent) {
+ /*oldValue = */
+ parsePart(m_base.m_path, false, &i); // skip key
+ newPath.append(m_base.m_path.subView(i));
+ }
+
+ m_base.m_path = newPath.makeStringAndClear();
+}
+
+sal_Int32 UrlReference::findParameter(std::u16string_view key) const {
+ sal_Int32 i = 0;
+ parsePart(m_base.m_path, true, &i); // skip name
+ for (;;) {
+ if (i == m_base.m_path.getLength()) {
+ return -1;
+ }
+ ++i; // skip '?' or '&'
+ OUString k = parsePart(m_base.m_path, false, &i);
+ ++i; // skip '='
+ if (k == key) {
+ return i;
+ }
+ parsePart(m_base.m_path, false, &i); // skip value
+ }
+}
+
+class Parser:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XUriSchemeParser>
+{
+public:
+ Parser() {}
+
+ Parser(const Parser&) = delete;
+ Parser& operator=(const Parser&) = delete;
+
+ 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::uri::XUriReference > SAL_CALL
+ parse(
+ OUString const & scheme, OUString const & schemeSpecificPart) override;
+
+private:
+ virtual ~Parser() override {}
+};
+
+OUString Parser::getImplementationName()
+{
+ return "com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript";
+}
+
+sal_Bool Parser::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Parser::getSupportedServiceNames()
+{
+ return { "com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript" };
+}
+
+css::uno::Reference< css::uri::XUriReference >
+Parser::parse(
+ OUString const & scheme, OUString const & schemeSpecificPart)
+{
+ if (!parseSchemeSpecificPart(schemeSpecificPart)) {
+ return nullptr;
+ }
+ return new UrlReference(scheme, schemeSpecificPart);
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation(css::uno::XComponentContext*,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ //TODO: single instance
+ return ::cppu::acquire(new Parser());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx
new file mode 100644
index 0000000000..7520c460f1
--- /dev/null
+++ b/stoc/source/uriproc/VndSunStarPkgUrlReferenceFactory.cxx
@@ -0,0 +1,120 @@
+/* -*- 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/lang/XServiceInfo.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/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/textenc.h>
+#include <rtl/uri.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustring.hxx>
+#include <utility>
+#include <sal/types.h>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::uno { class XInterface; }
+
+namespace {
+
+class Factory:
+ public cppu::WeakImplHelper<
+ css::lang::XServiceInfo, css::uri::XVndSunStarPkgUrlReferenceFactory>
+{
+public:
+ explicit Factory(
+ css::uno::Reference< css::uno::XComponentContext > context):
+ m_context(std::move(context)) {}
+
+ Factory(const Factory&) = delete;
+ Factory& operator=(const Factory&) = delete;
+
+ 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::uri::XUriReference > SAL_CALL
+ createVndSunStarPkgUrlReference(
+ css::uno::Reference< css::uri::XUriReference > const & authority) override;
+
+private:
+ virtual ~Factory() override {}
+
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+};
+
+OUString Factory::getImplementationName()
+{
+ return "com.sun.star.comp.uri.VndSunStarPkgUrlReferenceFactory";
+}
+
+sal_Bool Factory::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > Factory::getSupportedServiceNames()
+{
+ css::uno::Sequence< OUString > s { "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory" };
+ return s;
+}
+
+css::uno::Reference< css::uri::XUriReference >
+Factory::createVndSunStarPkgUrlReference(
+ css::uno::Reference< css::uri::XUriReference > const & authority)
+{
+ if (!authority.is()) {
+ throw css::uno::RuntimeException(
+ "null authority passed to"
+ " XVndSunStarPkgUrlReferenceFactory.createVndSunStarPkgUrlReference");
+ }
+ if (authority->isAbsolute() && !authority->hasFragment()) {
+ OUString buf =
+ "vnd.sun.star.pkg://" +
+ rtl::Uri::encode(
+ authority->getUriReference(), rtl_UriCharClassRegName,
+ rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8);
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ css::uri::UriReferenceFactory::create(m_context)->parse(
+ buf));
+ return uriRef;
+ } else {
+ return css::uno::Reference< css::uri::XUriReference >();
+ }
+}
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_uri_VndSunStarPkgUrlReferenceFactory_get_implementation(css::uno::XComponentContext* rxContext,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return ::cppu::acquire(new Factory(rxContext));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/dump.cxx b/stoc/test/dump.cxx
new file mode 100644
index 0000000000..798e05acc2
--- /dev/null
+++ b/stoc/test/dump.cxx
@@ -0,0 +1,152 @@
+/* -*- 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 <com/sun/star/beans/PropertyChangeEvent.hpp>
+#include <com/sun/star/reflection/Dump.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/TypeClass.hpp>
+#include <cppuhelper/bootstrap.hxx>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <test/codemaker/cppumaker/ByteBits.hpp>
+#include <test/codemaker/cppumaker/Constants.hpp>
+#include <test/codemaker/cppumaker/ShortBits.hpp>
+#include <test/codemaker/cppumaker/UnsignedHyperBits.hpp>
+
+namespace
+{
+class Dump : public CppUnit::TestFixture
+{
+public:
+ void setUp() override
+ {
+ dump_ = css::reflection::Dump::get(cppu::defaultBootstrap_InitialComponentContext());
+ }
+
+ void testSequence()
+ {
+ CPPUNIT_ASSERT_EQUAL(OUString("[]"),
+ dump_->dumpValue(css::uno::Any(css::uno::Sequence<sal_Int32>{})));
+ CPPUNIT_ASSERT_EQUAL(OUString("[1]"),
+ dump_->dumpValue(css::uno::Any(css::uno::Sequence<sal_Int32>{ 1 })));
+ CPPUNIT_ASSERT_EQUAL(OUString("[1, 2, 3]"), dump_->dumpValue(css::uno::Any(
+ css::uno::Sequence<sal_Int32>{ 1, 2, 3 })));
+ CPPUNIT_ASSERT_EQUAL(OUString("[[long: 1], [string: \"2\"], [[]long: [1, 2]]]"),
+ (dump_->dumpValue(css::uno::Any(css::uno::Sequence<css::uno::Any>{
+ css::uno::Any(sal_Int32(1)), css::uno::Any(OUString("2")),
+ css::uno::Any(css::uno::Sequence<sal_Int32>{ 1, 2 }) }))));
+ }
+
+ void testEnum()
+ {
+ CPPUNIT_ASSERT_EQUAL(OUString("ENUM"),
+ dump_->dumpValue(css::uno::Any(css::uno::TypeClass_ENUM)));
+ CPPUNIT_ASSERT_EQUAL(OUString("-1"),
+ dump_->dumpValue(css::uno::Any(css::uno::TypeClass(-1))));
+ CPPUNIT_ASSERT_EQUAL(OUString("12345"),
+ dump_->dumpValue(css::uno::Any(css::uno::TypeClass(12345))));
+ }
+
+ void testStruct()
+ {
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("[Source: null, PropertyName: \"test\", Further: false, PropertyHandle: 3, "
+ "OldValue: [void: void], NewValue: [long: 5]]"),
+ dump_->dumpValue(css::uno::Any(css::beans::PropertyChangeEvent(
+ {}, "test", false, 3, {}, css::uno::Any(sal_Int32(5))))));
+ }
+
+ void testConstantsGroup()
+ {
+ CPPUNIT_ASSERT_EQUAL(OUString("byteMin"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(sal_Int8(-128))));
+ CPPUNIT_ASSERT_EQUAL(OUString("byteMax"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(sal_Int8(127))));
+ CPPUNIT_ASSERT_EQUAL(OUString("longMin"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(sal_Int32(-2147483648))));
+ CPPUNIT_ASSERT_EQUAL(OUString("longMax"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(sal_Int32(2147483647))));
+ CPPUNIT_ASSERT_EQUAL(OUString("hyperMin"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(SAL_MIN_INT64)));
+ CPPUNIT_ASSERT_EQUAL(OUString("hyperMax"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(SAL_MAX_INT64)));
+ CPPUNIT_ASSERT_EQUAL(OUString("17"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(sal_Int32(17))));
+ CPPUNIT_ASSERT_EQUAL(OUString("2147483646"),
+ dump_->dumpConstant("test.codemaker.cppumaker.Constants",
+ css::uno::Any(sal_Int32(2147483646))));
+
+ CPPUNIT_ASSERT_EQUAL(OUString("0"), dump_->dumpConstant("test.codemaker.cppumaker.ByteBits",
+ css::uno::Any(sal_Int8(0))));
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("BIT0+BIT2"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ByteBits", css::uno::Any(sal_Int8(5))));
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("BIT4"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ByteBits", css::uno::Any(sal_Int8(16))));
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("BIT0+BIT4"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ByteBits", css::uno::Any(sal_Int8(17))));
+ CPPUNIT_ASSERT_EQUAL(OUString("BIT7"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ByteBits",
+ css::uno::Any(sal_Int8(-128))));
+ CPPUNIT_ASSERT_EQUAL(
+ OUString("ALL"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ByteBits", css::uno::Any(sal_Int8(-1))));
+
+ CPPUNIT_ASSERT_EQUAL(OUString("BIT7"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ShortBits",
+ css::uno::Any(sal_Int16(128))));
+ CPPUNIT_ASSERT_EQUAL(OUString("ALL"),
+ dump_->dumpConstant("test.codemaker.cppumaker.ShortBits",
+ css::uno::Any(sal_Int16(-1))));
+
+ CPPUNIT_ASSERT_EQUAL(OUString("BIT63"),
+ dump_->dumpConstant("test.codemaker.cppumaker.UnsignedHyperBits",
+ css::uno::Any(sal_uInt64(9223372036854775808u))));
+ CPPUNIT_ASSERT_EQUAL(OUString("BIT0+BIT62"),
+ dump_->dumpConstant("test.codemaker.cppumaker.UnsignedHyperBits",
+ css::uno::Any(sal_uInt64(4611686018427387905))));
+ CPPUNIT_ASSERT_EQUAL(OUString("BIT0+BIT63"),
+ dump_->dumpConstant("test.codemaker.cppumaker.UnsignedHyperBits",
+ css::uno::Any(sal_uInt64(9223372036854775809u))));
+ CPPUNIT_ASSERT_EQUAL(OUString("ALL"),
+ dump_->dumpConstant("test.codemaker.cppumaker.UnsignedHyperBits",
+ css::uno::Any(SAL_MAX_UINT64)));
+ }
+
+ CPPUNIT_TEST_SUITE(Dump);
+ CPPUNIT_TEST(testSequence);
+ CPPUNIT_TEST(testEnum);
+ CPPUNIT_TEST(testStruct);
+ CPPUNIT_TEST(testConstantsGroup);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ css::uno::Reference<css::reflection::XDump> dump_;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Dump);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/stoc/test/javavm/jvm_interaction/interactionhandler.cxx b/stoc/test/javavm/jvm_interaction/interactionhandler.cxx
new file mode 100644
index 0000000000..f1c4baf863
--- /dev/null
+++ b/stoc/test/javavm/jvm_interaction/interactionhandler.cxx
@@ -0,0 +1,186 @@
+/* -*- 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 <jni.h>
+
+#include <stdio.h>
+#include <sal/main.h>
+#include <rtl/process.h>
+
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include <osl/thread.h>
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/java/XJavaVM.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+#include <com/sun/star/java/XJavaThreadRegister_11.hpp>
+
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/task/XInteractionRequest.hpp>
+#include <com/sun/star/task/XInteractionContinuation.hpp>
+#include <com/sun/star/task/XInteractionAbort.hpp>
+#include <com/sun/star/task/XInteractionRetry.hpp>
+#include <com/sun/star/java/JavaNotConfiguredException.hpp>
+#include <com/sun/star/java/MissingJavaRuntimeException.hpp>
+#include <com/sun/star/java/JavaDisabledException.hpp>
+#include <com/sun/star/java/JavaVMCreationFailureException.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <uno/current_context.hxx>
+
+using namespace cppu;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::registry;
+using namespace css::java;
+using namespace css::task;
+
+
+#define INTERACTION_HANDLER_NAME "java-vm.interaction-handler"
+
+class Context: public WeakImplHelper<XCurrentContext>
+{
+ virtual Any SAL_CALL getValueByName( const OUString& Name ) throw (RuntimeException);
+};
+
+class InteractionHandler: public WeakImplHelper<XInteractionHandler>
+{
+ virtual void SAL_CALL handle( const Reference< XInteractionRequest >& Request )
+ throw (RuntimeException);
+};
+
+Any SAL_CALL Context::getValueByName( const OUString& Name) throw (RuntimeException)
+{
+ Any retVal;
+ if( Name.equals( INTERACTION_HANDLER_NAME))
+ {
+ Reference<XInteractionHandler> handler(new InteractionHandler());
+ retVal <<= handler;
+ }
+ return retVal;
+}
+
+void SAL_CALL InteractionHandler::handle( const Reference< XInteractionRequest >& Request )
+ throw (RuntimeException)
+{
+ Any anyExc= Request->getRequest();
+ Sequence<Reference< XInteractionContinuation> >seqCont= Request->getContinuations();
+
+ Reference<XInteractionAbort> abort;
+ Reference<XInteractionRetry> retry;
+
+ for (sal_Int32 i= 0; i < seqCont.getLength(); i++)
+ {
+ abort.set( seqCont[i], UNO_QUERY );
+ if(abort.is())
+ break;
+ }
+ for (sal_Int32 i= 0; i < seqCont.getLength(); i++)
+ {
+ retry.set( seqCont[i], UNO_QUERY );
+ if(retry.is())
+ break;
+ }
+
+ static int cRetry= 0;
+
+ if( cRetry++ == 5)
+ {
+ if( abort.is())
+ abort->select();
+ return;
+ }
+ if( retry.is())
+ retry->select();
+}
+
+sal_Bool test1(const Reference< XMultiServiceFactory > & xMgr )
+{
+ sal_Bool retVal= sal_True;
+ setCurrentContext(Reference<XCurrentContext>(new Context());
+
+ OUString sVMService("com.sun.star.java.JavaVirtualMachine");
+ Reference<XInterface> xXInt= xMgr->createInstance(sVMService);
+ if( ! xXInt.is())
+ return sal_False;
+ Reference<XJavaVM> xVM( xXInt, UNO_QUERY);
+ if( ! xVM.is())
+ return sal_False;
+
+
+ sal_Int8 arId[16];
+ rtl_getGlobalProcessId((sal_uInt8*) arId);
+
+ Any anyVM;
+ try
+ {
+ anyVM = xVM->getJavaVM( Sequence<sal_Int8>(arId, 16));
+ }
+ catch (const JavaNotConfiguredException& e)
+ {
+ OString msg= OUStringToOString(e.Message, osl_getThreadTextEncoding());
+ printf("JavaNotConfiguredException: %s\n", msg.getStr());
+ }
+ catch (const JavaVMCreationFailureException& e)
+ {
+ OString msg= OUStringToOString(e.Message, osl_getThreadTextEncoding());
+ printf("JavaVMCreationFailureException: %s\n", msg.getStr());
+ }
+ catch (const MissingJavaRuntimeException& e)
+ {
+ OString msg= OUStringToOString(e.Message, osl_getThreadTextEncoding());
+ printf("MissingJavaRuntimeException: %s\n", msg.getStr());
+ }
+ catch (const JavaDisabledException& e)
+ {
+ OString msg= OUStringToOString(e.Message, osl_getThreadTextEncoding());
+ printf("JavaDisabledException: %s\n", msg.getStr());
+ }
+ catch (const RuntimeException & e)
+ {
+ OString msg= OUStringToOString(e.Message, osl_getThreadTextEncoding());
+ printf("###RuntimeException: %s\n", msg.getStr());
+ retVal= sal_False;
+ }
+ return retVal;
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ Reference<XSimpleRegistry> xreg= createSimpleRegistry();
+ xreg->open( OUString("applicat.rdb"),
+ sal_False, sal_False );
+
+ Reference< XComponentContext > context= bootstrap_InitialComponentContext(xreg);
+ Reference<XMultiComponentFactory> fac= context->getServiceManager();
+ Reference<XMultiServiceFactory> xMgr( fac, UNO_QUERY);
+
+ sal_Bool bSucc = test1(xMgr);
+ Reference< XComponent > xCompContext( context, UNO_QUERY );
+ xCompContext->dispose();
+ return (bSucc ? 0 : -1);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/javavm/jvm_interaction/makefile.mk b/stoc/test/javavm/jvm_interaction/makefile.mk
new file mode 100644
index 0000000000..c9c1084a52
--- /dev/null
+++ b/stoc/test/javavm/jvm_interaction/makefile.mk
@@ -0,0 +1,71 @@
+#
+# 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 .
+#
+PRJ=..$/..$/..
+TARGET= jvminteraction
+PRJNAME= stoc
+TARGET6= $(TARGET)
+TARGETTYPE= CUI
+LIBTARGET= NO
+ENABLE_EXCEPTIONS=TRUE
+
+UNOUCRDEP= $(SOLARBINDIR)$/udkapi.rdb
+UNOUCRRDB= $(SOLARBINDIR)$/udkapi.rdb
+UNOUCROUT= $(OUT)$/inc$
+INCPRE+= $(OUT)$/inc$
+
+
+
+# --- Settings -----------------------------------------------------
+.INCLUDE : settings.mk
+
+# --- Application 6 - testjavavm ------------------------------------
+
+UNOTYPES= com.sun.star.lang.XMultiComponentFactory \
+ com.sun.star.uno.XWeak \
+ com.sun.star.java.XJavaVM \
+ com.sun.star.java.XJavaThreadRegister_11 \
+ com.sun.star.java.JavaNotConfiguredException \
+ com.sun.star.java.MissingJavaRuntimeException \
+ com.sun.star.java.JavaDisabledException \
+ com.sun.star.java.JavaVMCreationFailureException \
+ com.sun.star.registry.XSimpleRegistry \
+ com.sun.star.lang.XComponent \
+ com.sun.star.registry.XImplementationRegistration \
+ com.sun.star.lang.XSingleServiceFactory \
+ com.sun.star.uno.TypeClass \
+ com.sun.star.lang.XMultiServiceFactory \
+ com.sun.star.uno.XCurrentContext \
+ com.sun.star.task.XInteractionHandler \
+ com.sun.star.task.XInteractionRequest \
+ com.sun.star.task.XInteractionContinuation \
+ com.sun.star.task.XInteractionAbort \
+ com.sun.star.task.XInteractionRetry \
+
+
+APP6TARGET= $(TARGET6)
+APP6OBJS = $(OBJ)$/interactionhandler.obj
+APP6STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(SALLIB)
+
+# --- Target ------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/stoc/test/javavm/makefile.mk b/stoc/test/javavm/makefile.mk
new file mode 100644
index 0000000000..eb0ffb7619
--- /dev/null
+++ b/stoc/test/javavm/makefile.mk
@@ -0,0 +1,59 @@
+#
+# 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 .
+#
+PRJ=..$/..
+TARGET= testjavavm
+PRJNAME= stoc
+TARGET6= testjavavm
+TARGETTYPE= CUI
+LIBTARGET= NO
+ENABLE_EXCEPTIONS=TRUE
+
+UNOUCRDEP= $(SOLARBINDIR)$/udkapi.rdb
+UNOUCRRDB= $(SOLARBINDIR)$/udkapi.rdb
+UNOUCROUT= $(OUT)$/inc$
+INCPRE+= $(OUT)$/inc$
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- Application 6 - testjavavm ------------------------------------
+
+UNOTYPES= com.sun.star.lang.XMultiComponentFactory \
+ com.sun.star.uno.XWeak \
+ com.sun.star.java.XJavaVM \
+ com.sun.star.java.XJavaThreadRegister_11 \
+ com.sun.star.registry.XSimpleRegistry \
+ com.sun.star.lang.XComponent \
+ com.sun.star.registry.XImplementationRegistration \
+ com.sun.star.lang.XSingleServiceFactory \
+ com.sun.star.uno.TypeClass \
+ com.sun.star.lang.XMultiServiceFactory
+
+APP6TARGET= $(TARGET6)
+APP6OBJS = $(OBJ)$/testjavavm.obj
+APP6STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(SALLIB)
+
+# --- Target ------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/stoc/test/javavm/testapplet/TestApplet.html b/stoc/test/javavm/testapplet/TestApplet.html
new file mode 100644
index 0000000000..e83d2ffe7d
--- /dev/null
+++ b/stoc/test/javavm/testapplet/TestApplet.html
@@ -0,0 +1,19 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252">
+ <TITLE>A Clock (1.1)</TITLE>
+ <META NAME="GENERATOR" CONTENT="StarOffice 6.0 (Win32)">
+ <META NAME="CREATED" CONTENT="20011119;12262427">
+ <META NAME="CHANGED" CONTENT="16010101;0">
+</HEAD>
+<BODY LANG="de-DE">
+<H1>TestApplet</H1>
+<HR>
+<P>
+<APPLET CODE="TestApplet.class" ALIGN=BOTTOM WIDTH=170 HEIGHT=150>
+</APPLET>
+</P>
+
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/stoc/test/javavm/testapplet/TestApplet.java b/stoc/test/javavm/testapplet/TestApplet.java
new file mode 100644
index 0000000000..e271f4dd1f
--- /dev/null
+++ b/stoc/test/javavm/testapplet/TestApplet.java
@@ -0,0 +1,53 @@
+/*
+ * 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 .
+ */
+
+import java.awt.Color;
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.MalformedURLException;
+
+public class TestApplet extends java.applet.Applet {
+
+ /** Initialization method that will be called after the applet is loaded
+ * into the browser.
+ */
+ @Override
+ public void init () {
+ setBackground( Color.green);
+ resize( 300, 300);
+
+ // Security tests.
+ File f= new File("d:\\temp\\javasecurity.txt");
+ try {
+ f.createNewFile();
+
+ // local connection
+ URL url= new URL("http://localhost:8080/index.html");
+ url.openStream();
+ // remote connection
+ url= new URL("http://www.w3.org/index.html");
+ url.openStream();
+ }catch( MalformedURLException mue) {
+ }catch( IOException e) {
+ String s= e.getMessage();
+ System.out.println(s);
+ }
+
+ }
+}
diff --git a/stoc/test/javavm/testapplet/makefile.mk b/stoc/test/javavm/testapplet/makefile.mk
new file mode 100644
index 0000000000..c2b5a2001f
--- /dev/null
+++ b/stoc/test/javavm/testapplet/makefile.mk
@@ -0,0 +1,43 @@
+#
+# 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 .
+#
+
+PRJ=..$/..$/..
+
+PRJNAME = testapplet
+PACKAGE =
+TARGET = TestApplet
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# Files --------------------------------------------------------
+
+JARFILES = ridl.jar jurt.jar unoil.jar
+
+JAVAFILES= $(subst,$(CLASSDIR)$/$(PACKAGE)$/, $(subst,.class,.java $(JAVACLASSFILES)))
+
+
+JAVACLASSFILES= \
+ $(CLASSDIR)$/$(PACKAGE)$/TestApplet.class
+
+JARCLASSDIRS= .
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/stoc/test/javavm/testcomponent/TestComponent.java b/stoc/test/javavm/testcomponent/TestComponent.java
new file mode 100644
index 0000000000..d976323c5f
--- /dev/null
+++ b/stoc/test/javavm/testcomponent/TestComponent.java
@@ -0,0 +1,129 @@
+/*
+ * 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 .
+ */
+
+import com.sun.star.comp.loader.FactoryHelper;
+import com.sun.star.lang.*;
+import com.sun.star.uno.*;
+import com.sun.star.registry.XRegistryKey;
+import java.io.*;
+import java.net.*;
+
+
+/** This component implements XTypeProvider for use with StarBasic.
+ * The XServiceInfo is implemented to have an interface in which we can put some
+ * code just for the sake of debugging.
+ *
+ * To debug with JPDA (jdk 1.3), put these lines in the java.ini within the [Java] section:
+ * -Xdebug
+ * -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y
+ *
+ * When the Virtual Machine service is instantiated it will block until the debugger
+ * attaches to it on port 8000. You can chose a different port. You attach to the VM using
+ * jdb by
+ *
+ * jdb -connect com.sun.jdi.SocketAttach:hostname=myhost,port=8000
+ *
+ * myhost is the hostname where the VM is running.
+*/
+public class TestComponent implements XServiceInfo, XTypeProvider
+{
+ public static final String __serviceName="JavaTestComponent";
+
+ // XTypeProvider
+ public com.sun.star.uno.Type[] getTypes( )
+ {
+ Type[] retValue= new Type[2];
+ retValue[0]= new Type( XServiceInfo.class);
+ retValue[1]= new Type( XTypeProvider.class);
+ return retValue;
+ }
+ // XTypeProvider
+ public byte[] getImplementationId( )
+ {
+ return new byte[0];
+ }
+
+
+ // XServiceName
+ public String getImplementationName( )
+ {
+ // the functions are for debugging
+
+ // Test security settings
+ File f= new File("c:/temp/javasecurity.txt");
+ try {
+ f.createNewFile();
+
+ // local connection
+ URL url= new URL("http://localhost:8080/index.html");
+ url.openStream();
+ // remote connection
+ url= new URL("http://www.w3.org/index.html");
+ url.openStream();
+ }catch( MalformedURLException mue) {
+ }catch( IOException e) {
+ String s= e.getMessage();
+ System.out.println(s);
+ }
+
+ return __serviceName;
+ }
+ // XServiceName
+ public boolean supportsService( /*IN*/String ServiceName )
+ {
+
+ return false;
+ }
+
+ //XServiceName
+ public String[] getSupportedServiceNames( )
+ {
+ String[] retValue= new String[0];
+ return retValue;
+ }
+
+ public static XSingleServiceFactory __getServiceFactory(String implName,
+ XMultiServiceFactory multiFactory,
+ XRegistryKey regKey)
+ {
+ XSingleServiceFactory xSingleServiceFactory = null;
+
+ if (implName.equals( TestComponent.class.getName()) )
+ xSingleServiceFactory = FactoryHelper.getServiceFactory( TestComponent.class,
+ TestComponent.__serviceName,
+ multiFactory,
+ regKey);
+
+ return xSingleServiceFactory;
+ }
+
+ /**
+ * Writes the service information into the given registry key.
+ * This method is called by the <code>JavaLoader</code>
+ * <p>
+ * @return returns true if the operation succeeded
+ * @param regKey the registryKey
+ * @see com.sun.star.comp.loader.JavaLoader
+ */
+ public static boolean __writeRegistryServiceInfo(XRegistryKey regKey)
+ {
+ return FactoryHelper.writeRegistryServiceInfo( TestComponent.class.getName(),
+ TestComponent.__serviceName, regKey);
+ }
+
+}
diff --git a/stoc/test/javavm/testcomponent/makefile.mk b/stoc/test/javavm/testcomponent/makefile.mk
new file mode 100644
index 0000000000..89ae042adc
--- /dev/null
+++ b/stoc/test/javavm/testcomponent/makefile.mk
@@ -0,0 +1,45 @@
+#
+# 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 .
+#
+
+PRJ=..$/..$/..
+
+PRJNAME = testcomponent
+PACKAGE =
+TARGET = JavaTestComponent
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# Files --------------------------------------------------------
+
+JARFILES = ridl.jar jurt.jar unoil.jar
+
+CUSTOMMANIFESTFILE= manifest
+
+JARTARGET = $(TARGET).jar
+
+JAVAFILES= \
+ TestComponent.java
+
+
+JAVACLASSFILES = $(foreach,i,$(JAVAFILES) $(CLASSDIR)$/$(PACKAGE)$/$(i:b).class)
+
+# --- Targets ------------------------------------------------------
+
+.INCLUDE : target.mk
diff --git a/stoc/test/javavm/testcomponent/manifest b/stoc/test/javavm/testcomponent/manifest
new file mode 100644
index 0000000000..1763d7bb95
--- /dev/null
+++ b/stoc/test/javavm/testcomponent/manifest
@@ -0,0 +1 @@
+RegistrationClassName: TestComponent
diff --git a/stoc/test/javavm/testjavavm.cxx b/stoc/test/javavm/testjavavm.cxx
new file mode 100644
index 0000000000..0e243f62d3
--- /dev/null
+++ b/stoc/test/javavm/testjavavm.cxx
@@ -0,0 +1,151 @@
+/* -*- 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 <jni.h>
+
+#include <stdio.h>
+#include <sal/main.h>
+#include <sal/log.hxx>
+#include <rtl/process.h>
+
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/bootstrap.hxx>
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <com/sun/star/java/XJavaVM.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+#include <com/sun/star/java/XJavaThreadRegister_11.hpp>
+
+using namespace cppu;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::registry;
+using namespace css::java;
+
+
+sal_Bool testJavaVM(const Reference< XMultiServiceFactory > & xMgr )
+{
+
+ OUString sVMService("com.sun.star.java.JavaVirtualMachine");
+ Reference<XInterface> xXInt= xMgr->createInstance(sVMService);
+ if( ! xXInt.is())
+ return sal_False;
+ Reference<XJavaVM> xVM( xXInt, UNO_QUERY);
+ if( ! xVM.is())
+ return sal_False;
+ Reference<XJavaThreadRegister_11> xreg11(xVM, UNO_QUERY);
+ if( ! xreg11.is())
+ return sal_False;
+
+
+ sal_Int8 arId[16];
+ rtl_getGlobalProcessId((sal_uInt8*) arId);
+ Any anyVM = xVM->getJavaVM( Sequence<sal_Int8>(arId, 16));
+ if ( ! anyVM.hasValue())
+ {
+ OSL_FAIL("could not get Java VM");
+ return sal_False;
+ }
+
+ sal_Bool b= xreg11->isThreadAttached();
+ xreg11->registerThread();
+ b= xreg11->isThreadAttached();
+ xreg11->revokeThread();
+ b= xreg11->isThreadAttached();
+
+
+ b= xVM->isVMEnabled();
+ b= xVM->isVMStarted();
+
+
+ b= xVM->isVMEnabled();
+ b= xVM->isVMStarted();
+
+
+ JavaVM* _jvm= *(JavaVM**) anyVM.getValue();
+ JNIEnv *p_env;
+ if( _jvm->AttachCurrentThread((void**) &p_env, 0))
+ return sal_False;
+
+ jclass cls = p_env->FindClass( "TestJavaVM");
+ if (cls == 0) {
+ SAL_WARN("stoc", "Can't find Prog class");
+ exit(1);
+ }
+
+ jmethodID id = p_env->GetStaticMethodID( cls, "getInt", "()I");
+ if( id)
+ {
+ p_env->CallStaticIntMethod(cls, id);
+ }
+
+ if( p_env->ExceptionOccurred()){
+ p_env->ExceptionDescribe();
+ p_env->ExceptionClear();
+ }
+
+
+ _jvm->DetachCurrentThread();
+ return sal_True;
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ Reference<XSimpleRegistry> xreg= createSimpleRegistry();
+ xreg->open( OUString("applicat.rdb"),
+ sal_False, sal_False );
+
+ Reference< XComponentContext > context= bootstrap_InitialComponentContext(xreg);
+ Reference<XMultiComponentFactory> fac= context->getServiceManager();
+ Reference<XMultiServiceFactory> xMgr( fac, UNO_QUERY);
+
+ sal_Bool bSucc = sal_False;
+ try
+ {
+ OUString sImplReg(
+ "com.sun.star.registry.ImplementationRegistration");
+ Reference<css::registry::XImplementationRegistration> xImplReg(
+ xMgr->createInstance( sImplReg ), UNO_QUERY );
+ OSL_ENSURE( xImplReg.is(), "### no impl reg!" );
+
+
+ OUString sLibLoader("com.sun.star.loader.SharedLibrary");
+ OUString sJenLib( "javavm.uno" SAL_DLLEXTENSION );
+ xImplReg->registerImplementation(
+ sLibLoader, sJenLib, Reference< XSimpleRegistry >() );
+
+ bSucc = testJavaVM( xMgr );
+ }
+ catch (const Exception & rExc)
+ {
+ DBG_UNHANDLED_EXCEPTION("stoc", "### exception occurred: " << rExc );
+ }
+
+ Reference< XComponent > xCompContext( context, UNO_QUERY );
+ xCompContext->dispose();
+ printf("javavm %s", bSucc ? "succeeded" : "failed");
+ return (bSucc ? 0 : -1);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/javavm/testjavavm.java b/stoc/test/javavm/testjavavm.java
new file mode 100644
index 0000000000..9309843b08
--- /dev/null
+++ b/stoc/test/javavm/testjavavm.java
@@ -0,0 +1,30 @@
+/*
+ * 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 .
+ */
+
+class TestJavaVM
+{
+ public static int getInt()
+ {
+ return 100;
+ }
+
+ public static void main( String args[])
+ {
+ System.out.println("Hello World");
+ }
+}
diff --git a/stoc/test/language_binding.idl b/stoc/test/language_binding.idl
new file mode 100644
index 0000000000..db568f077d
--- /dev/null
+++ b/stoc/test/language_binding.idl
@@ -0,0 +1,155 @@
+/* -*- 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 .
+ */
+
+module test
+{
+
+enum TestEnum
+{
+ TEST,
+ ONE,
+ TWO,
+ CHECK,
+ LOLA,
+ PALOO,
+ ZA
+};
+
+/**
+ * simple c++ types
+ */
+struct TestSimple
+{
+ boolean Bool;
+ char Char;
+ byte Byte;
+ short Short;
+ unsigned short UShort;
+ long Long;
+ unsigned long ULong;
+ hyper Hyper;
+ unsigned hyper UHyper;
+ float Float;
+ double Double;
+ test::TestEnum Enum;
+};
+/**
+ * complex c++ types
+ */
+struct TestElement : test::TestSimple
+{
+ string String;
+ com::sun::star::uno::XInterface Interface;
+ any Any;
+};
+struct TestDataElements : test::TestElement
+{
+ sequence<test::TestElement > Sequence;
+};
+
+typedef TestDataElements TestData;
+
+/** Monster test interface to test language binding calls. */
+interface XLBTestBase : com::sun::star::uno::XInterface
+{
+ /**
+ * in parameter test, tests by calls reference also (complex types)
+ */
+ void setValues( [in] boolean bBool, [in] char cChar, [in] byte nByte,
+ [in] short nShort, [in] unsigned short nUShort,
+ [in] long nLong, [in] unsigned long nULong,
+ [in] hyper nHyper, [in] unsigned hyper nUHyper,
+ [in] float fFloat, [in] double fDouble,
+ [in] test::TestEnum eEnum, [in] string aString,
+ [in] com::sun::star::uno::XInterface xInterface, [in] any aAny,
+ [in] sequence<test::TestElement > aSequence,
+ [in] test::TestData aStruct );
+ /**
+ * inout parameter test
+ */
+ test::TestData setValues2( [inout] boolean bBool, [inout] char cChar, [inout] byte nByte,
+ [inout] short nShort, [inout] unsigned short nUShort,
+ [inout] long nLong, [inout] unsigned long nULong,
+ [inout] hyper nHyper, [inout] unsigned hyper nUHyper,
+ [inout] float fFloat, [inout] double fDouble,
+ [inout] test::TestEnum eEnum, [inout] string aString,
+ [inout] com::sun::star::uno::XInterface xInterface, [inout] any aAny,
+ [inout] sequence<test::TestElement > aSequence,
+ [inout] test::TestData aStruct );
+
+ /**
+ * out parameter test
+ */
+ test::TestData getValues( [out] boolean bBool, [out] char cChar, [out] byte nByte,
+ [out] short nShort, [out] unsigned short nUShort,
+ [out] long nLong, [out] unsigned long nULong,
+ [out] hyper nHyper, [out] unsigned hyper nUHyper,
+ [out] float fFloat, [out] double fDouble,
+ [out] test::TestEnum eEnum, [out] string aString,
+ [out] com::sun::star::uno::XInterface xInterface, [out] any aAny,
+ [out] sequence<test::TestElement > aSequence,
+ [out] test::TestData aStruct );
+
+ [attribute] boolean Bool;
+ [attribute] byte Byte;
+ [attribute] char Char;
+ [attribute] short Short;
+ [attribute] unsigned short UShort;
+ [attribute] long Long;
+ [attribute] unsigned long ULong;
+ [attribute] hyper Hyper;
+ [attribute] unsigned hyper UHyper;
+ [attribute] float Float;
+ [attribute] double Double;
+ [attribute] test::TestEnum Enum;
+ [attribute] string String;
+ [attribute] com::sun::star::uno::XInterface Interface;
+ [attribute] any Any;
+ [attribute] sequence<test::TestElement > Sequence;
+ [attribute] test::TestData Struct;
+};
+
+
+/** Inheriting from monster; adds raiseException(). */
+interface XLanguageBindingTest : test::XLBTestBase
+{
+ /**
+ * params are there only for dummy, to test if all temp out params will be released.
+ */
+ test::TestData raiseException( [out] boolean bBool, [out] char cChar, [out] byte nByte,
+ [out] short nShort, [out] unsigned short nUShort,
+ [out] long nLong, [out] unsigned long nULong,
+ [out] hyper nHyper, [out] unsigned hyper nUHyper,
+ [out] float fFloat, [out] double fDouble,
+ [out] test::TestEnum eEnum, [out] string aString,
+ [out] com::sun::star::uno::XInterface xInterface, [out] any aAny,
+ [out] sequence<test::TestElement > aSequence,
+ [out] test::TestData aStruct )
+ raises( com::sun::star::lang::IllegalArgumentException );
+
+ /**
+ * raises runtime exception
+ */
+ [attribute] long RuntimeException;
+};
+
+}; // test
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/makefile.mk b/stoc/test/makefile.mk
new file mode 100644
index 0000000000..97c5950a35
--- /dev/null
+++ b/stoc/test/makefile.mk
@@ -0,0 +1,213 @@
+#
+# 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 .
+#
+
+PRJ=..
+
+PRJNAME=stoc
+TARGET=stoc
+TARGET1=testloader
+TARGET2=testregistry
+TARGET3=testsmgr
+TARGET4=testcorefl
+TARGET5=testinvocation
+TARGET6=testintrosp
+TARGET7=testconv
+TARGET8=testproxyfac
+TARGET9=testsmgr2
+TARGETTYPE=CUI
+
+ENABLE_EXCEPTIONS=TRUE
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : settings.mk
+
+# --- smgr component -----------------------------------------------
+SHL1OBJS= \
+ $(OBJ)$/testsmgr_cpnt.obj
+
+SHL1STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(SALLIB)
+
+SHL1TARGET=testsmgr_component
+SHL1DEPN=
+SHL1IMPLIB=i$(SHL1TARGET)
+SHL1DEF=$(MISC)$/$(SHL1TARGET).def
+DEF1NAME=$(SHL1TARGET)
+SHL1VERSIONMAP=testsmgr_cpnt.map
+
+# --- Application 1 ------------------------------------------------
+APP1TARGET= $(TARGET1)
+APP1OBJS= $(OBJ)$/testloader.obj
+
+APP1STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(SALLIB)
+
+# --- Application 2 ------------------------------------------------
+APP2TARGET= $(TARGET2)
+APP2OBJS= $(OBJ)$/testregistry.obj $(OBJ)$/mergekeys_.obj
+
+APP2STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(REGLIB) \
+ $(SALLIB)
+
+# --- Application 3 - testsmgr main ------------------------------------
+APP3TARGET= $(TARGET3)
+APP3OBJS = $(OBJ)$/testsmgr.obj
+APP3STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(REGLIB) \
+ $(SALLIB)
+
+.IF "$(OS)"!="WNT"
+APP3STDLIBS+= -l$(SHL1TARGET)
+.ENDIF
+.IF "$(OS)"=="WNT"
+APP3STDLIBS+= i$(SHL1TARGET).lib
+.ENDIF
+
+# --- Application 4 - testcorefl main ------------------------------------
+APP4TARGET= $(TARGET4)
+APP4OBJS = $(OBJ)$/testcorefl.obj
+APP4STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALLIB)
+
+# --- Application 5 - testinvocation main ------------------------------------
+APP5TARGET= $(TARGET5)
+APP5OBJS = $(OBJ)$/testiadapter.obj
+APP5STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALLIB)
+
+# --- Application 6 - testitrosp main ------------------------------------
+APP6TARGET= $(TARGET6)
+APP6OBJS = $(OBJ)$/testintrosp.obj
+APP6STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALHELPERLIB) \
+ $(SALLIB)
+
+# --- Application 7 - testconv main ------------------------------------
+APP7TARGET= $(TARGET7)
+APP7OBJS = $(OBJ)$/testconv.obj
+APP7STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALLIB)
+
+# --- Application 8 - testproxyfac main ------------------------------------
+APP8TARGET= $(TARGET8)
+APP8OBJS = $(OBJ)$/testproxyfac.obj
+APP8STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALLIB)
+
+# --- Application 9 - testproxyfac main ------------------------------------
+APP9TARGET= $(TARGET9)
+APP9OBJS = $(OBJ)$/testsmgr2.obj
+APP9STDLIBS= \
+ $(CPPULIB) \
+ $(CPPUHELPERLIB) \
+ $(SALLIB)
+
+
+ALLIDLFILES:= testcorefl.idl language_binding.idl testintrosp.idl
+
+
+# --- Target ------------------------------------------------
+
+.IF "$(depend)" == ""
+ALL : $(MISC)$/test_types_generated.flag \
+ $(BIN)$/test1.rdb \
+ $(BIN)$/test2.rdb \
+ ALLTAR
+.ELSE
+ALL: ALLDEP
+.ENDIF
+
+.INCLUDE : target.mk
+
+CPPUMAKERFLAGS =
+.IF "$(COM)" == "MSC"
+CPPUMAKERFLAGS = -L
+.ENDIF
+
+FACTORYTYPES:= -T com.sun.star.lang.XSingleComponentFactory \
+ -T com.sun.star.uno.XComponentContext \
+ -T com.sun.star.uno.XWeak \
+ -T com.sun.star.container.XEnumeration \
+ -T com.sun.star.lang.XComponent \
+ -T com.sun.star.registry.XSimpleRegistry \
+ -T com.sun.star.lang.XInitialization \
+ -T com.sun.star.lang.XMultiServiceFactory\
+ -T com.sun.star.loader.XImplementationLoader \
+ -T com.sun.star.registry.XImplementationRegistration \
+ -T com.sun.star.container.XSet \
+ -T com.sun.star.lang.XSingleServiceFactory\
+ -T com.sun.star.lang.XServiceInfo \
+ -T com.sun.star.container.XContentEnumerationAccess \
+ -T com.sun.star.container.XEnumeration
+
+TESTCOREFL:=ModuleC;ModuleC.XInterfaceA;ModuleC.XInterfaceB;ModuleA.XInterface1;com.sun.star.reflection.XIdlReflection;com.sun.star.reflection.XIdlField;com.sun.star.reflection.XIdlArray;com.sun.star.reflection.XIdlMethod;com.sun.star.reflection.XIdlClass;com.sun.star.beans.XPropertySet;com.sun.star.lang.XComponent;com.sun.star.container.XHierarchicalNameAccess;com.sun.star.reflection.XIdlField2;com.sun.star.lang.DisposedException
+TESTIADAPTER:=com.sun.star.beans.XIntrospection;com.sun.star.beans.MethodConcept;com.sun.star.beans.XExactName;com.sun.star.lang.XTypeProvider;com.sun.star.uno.XAggregation;com.sun.star.script.XInvocationAdapterFactory;com.sun.star.script.XInvocationAdapterFactory2;com.sun.star.script.XInvocation;com.sun.star.lang.XMultiServiceFactory;com.sun.star.registry.XSimpleRegistry;com.sun.star.lang.XInitialization;test.XLanguageBindingTest
+TESTINTROSP:=ModuleA;ModuleA.XIntroTest;com.sun.star.beans.XPropertySet;com.sun.star.container.XIndexAccess;com.sun.star.container.XNameAccess;com.sun.star.beans.PropertyAttribute;com.sun.star.beans.PropertyConcept
+TESTCONV:=com.sun.star.script.XTypeConverter
+TESTPROXYFAC:=com.sun.star.reflection.XProxyFactory
+TESTSECURITY:=com.sun.star.security.AllPermission;com.sun.star.security.XPolicy;com.sun.star.security.XAccessController;com.sun.star.io.FilePermission;com.sun.star.connection.SocketPermission;com.sun.star.uno.XCurrentContext
+
+$(BIN)$/test1.rdb: $(SHL1TARGETN)
+.IF "$(OS)"!="WNT"
+ cp $(SHL1TARGETN) $(BIN)
+.ENDIF
+ cd $(BIN) && regcomp -register -r test1.rdb -c $(SHL1TARGET)
+
+$(BIN)$/test2.rdb:
+ cd $(BIN) && regcomp -register -r test2.rdb -c remotebridge.uno$(DLLPOST)
+
+$(BIN)$/stoctest.rdb: $(ALLIDLFILES)
+ idlc -I$(PRJ) -I$(SOLARIDLDIR) -O$(BIN) $?
+ regmerge $@ /UCR $(BIN)$/{$(?:f:s/.idl/.urd/)}
+ regmerge $@ / $(SOLARBINDIR)$/udkapi.rdb
+ regcomp -register -r $@ -c reflection.uno$(DLLPOST)
+ touch $@
+
+$(MISC)$/test_types_generated.flag : $(BIN)$/stoctest.rdb makefile.mk
+ -rm -f $(MISC)$/test_types_generated.flag
+ cppumaker $(CPPUMAKERFLAGS) -BUCR -O$(UNOUCROUT) $(FACTORYTYPES) -T"$(TESTIADAPTER)" $(BIN)$/stoctest.rdb
+ cppumaker $(CPPUMAKERFLAGS) -BUCR -O$(UNOUCROUT) -T"$(TESTCOREFL)" $(BIN)$/stoctest.rdb
+ cppumaker $(CPPUMAKERFLAGS) -BUCR -O$(UNOUCROUT) -T"$(TESTINTROSP)" $(BIN)$/stoctest.rdb
+ cppumaker $(CPPUMAKERFLAGS) -BUCR -O$(UNOUCROUT) -T"$(TESTCONV)" $(BIN)$/stoctest.rdb
+ cppumaker $(CPPUMAKERFLAGS) -BUCR -O$(UNOUCROUT) -T"$(TESTPROXYFAC)" $(BIN)$/stoctest.rdb
+ cppumaker $(CPPUMAKERFLAGS) -BUCR -O$(UNOUCROUT) -T"$(TESTSECURITY)" $(BIN)$/stoctest.rdb
+ touch $(MISC)$/test_types_generated.flag
diff --git a/stoc/test/mergekeys_.cxx b/stoc/test/mergekeys_.cxx
new file mode 100644
index 0000000000..079e12670a
--- /dev/null
+++ b/stoc/test/mergekeys_.cxx
@@ -0,0 +1,22 @@
+/* -*- 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 "../source/implementationregistration/mergekeys.cxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/registry_tdprovider/makefile.mk b/stoc/test/registry_tdprovider/makefile.mk
new file mode 100644
index 0000000000..35a7851173
--- /dev/null
+++ b/stoc/test/registry_tdprovider/makefile.mk
@@ -0,0 +1,54 @@
+#
+# 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 .
+#
+
+PRJ := ..$/..
+PRJNAME := stoc
+
+TARGET := test_registry_tdprovider
+
+ENABLE_EXCEPTIONS := TRUE
+
+.INCLUDE: settings.mk
+
+DLLPRE = # no leading "lib" on .so files
+
+SLOFILES = $(SLO)$/testregistrytdprovider.obj
+
+SHL1TARGET = $(ENFORCEDSHLPREFIX)testregistrytdprovider.uno
+SHL1OBJS = $(SLOFILES)
+SHL1VERSIONMAP = $(SOLARENV)/src/component.map
+SHL1STDLIBS = $(CPPULIB) $(CPPUHELPERLIB) $(SALLIB)
+SHL1IMPLIB = itestregistrytdprovider
+DEF1NAME = $(SHL1TARGET)
+
+.INCLUDE: target.mk
+
+ALLTAR: test
+
+$(MISC)$/$(TARGET)$/all.rdb: types.idl
+ - rm $@
+ - $(MKDIR) $(MISC)$/$(TARGET)
+ idlc -O$(MISC)$/$(TARGET) -I$(SOLARIDLDIR) -C -cid -we $<
+ regmerge $@ /UCR $(MISC)$/$(TARGET)$/types.urd
+ regmerge $@ / $(SOLARBINDIR)$/types.rdb
+
+$(SLOFILES): $(MISC)$/$(TARGET)$/all.rdb
+
+test .PHONY: $(SHL1TARGETN) $(MISC)$/$(TARGET)$/all.rdb
+ uno -c test.registrytdprovider.impl -l $(subst,$/,/ $(SHL1TARGETN)) \
+ -ro $(subst,$/,/ $(MISC)$/$(TARGET)$/all.rdb)
diff --git a/stoc/test/registry_tdprovider/readme.txt b/stoc/test/registry_tdprovider/readme.txt
new file mode 100644
index 0000000000..9267df8582
--- /dev/null
+++ b/stoc/test/registry_tdprovider/readme.txt
@@ -0,0 +1,4 @@
+This test uses the delivered regtypeprov.uno dynamic library, not the local one.
+(It might work to fix this, changing the test from a UNO component started from
+the uno executable to a stand-alone application that bootstraps UNO in a special
+way.)
diff --git a/stoc/test/registry_tdprovider/testregistrytdprovider.cxx b/stoc/test/registry_tdprovider/testregistrytdprovider.cxx
new file mode 100644
index 0000000000..46e3d0998b
--- /dev/null
+++ b/stoc/test/registry_tdprovider/testregistrytdprovider.cxx
@@ -0,0 +1,798 @@
+/* -*- 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/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/lang/XMain.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/reflection/XCompoundTypeDescription.hpp>
+#include <com/sun/star/reflection/XInterfaceAttributeTypeDescription2.hpp>
+#include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
+#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp>
+#include <com/sun/star/reflection/XInterfaceTypeDescription2.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/registry/InvalidRegistryException.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#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/TypeClass.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/textenc.h>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <uno/environment.h>
+
+#include /*MSVC trouble: <cstdlib>*/ <stdlib.h>
+#include <iostream>
+#include <ostream>
+
+namespace {
+
+class Service: public cppu::WeakImplHelper< css::lang::XMain > {
+public:
+ virtual sal_Int32 SAL_CALL
+ run(css::uno::Sequence< OUString > const & arguments)
+ throw (css::uno::RuntimeException);
+
+ static OUString getImplementationName();
+
+ static css::uno::Sequence< OUString > getSupportedServiceNames();
+
+ static css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & context)
+ throw (css::uno::Exception);
+
+private:
+ explicit Service(
+ css::uno::Reference< css::uno::XComponentContext > const & context):
+ m_context(context)
+ {}
+
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+};
+
+}
+
+namespace {
+
+std::ostream & operator <<(std::ostream & out, OUString const & value) {
+ return out << OUStringToOString(value, RTL_TEXTENCODING_UTF8).getStr();
+}
+
+void assertTrue(bool argument) {
+ if (!argument) {
+ std::cerr
+ << "assertTrue(" << argument << ") failed" << std::endl;
+ /*MSVC trouble: std::*/abort();
+ }
+}
+
+void assertFalse(bool argument) {
+ if (argument) {
+ std::cerr
+ << "assertFalse(" << argument << ") failed" << std::endl;
+ /*MSVC trouble: std::*/abort();
+ }
+}
+
+template< typename T > void assertEqual(T const & value, T const & argument) {
+ if (argument != value) {
+ std::cerr
+ << "assertEqual(" << value << ", " << argument << ") failed"
+ << std::endl;
+ /*MSVC trouble: std::*/abort();
+ }
+}
+
+}
+
+sal_Int32 Service::run(css::uno::Sequence< OUString > const &)
+ throw (css::uno::RuntimeException)
+{
+ css::uno::Reference< css::lang::XMultiComponentFactory > factory(
+ m_context->getServiceManager());
+ assertTrue(factory.is());
+ css::uno::Sequence< css::uno::Any > args(1);
+ args[0] = css::uno::Reference< css::beans::XPropertySet >(
+ factory, css::uno::UNO_QUERY_THROW)->getPropertyValue(
+ OUString("Registry"));
+ css::uno::Reference< css::container::XHierarchicalNameAccess > provider(
+ factory->createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.stoc.RegistryTypeDescriptionProvider",
+ args, m_context),
+ css::uno::UNO_QUERY_THROW);
+
+ // The following assumes that interface members are sorted by increasing
+ // values of XInterfaceMemberTypeDescription.getPosition, the exceptions
+ // of interface attributes and interface methods, the constructors of
+ // services, and the exceptions of service constructors are sorted as given
+ // in the UNOIDL source code:
+
+ assertEqual< bool >(
+ false,
+ provider->hasByHierarchicalName(
+ OUString( "[][]boolean")));
+ assertEqual< bool >(
+ false,
+ provider->hasByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct3<boolean,boolean>")));
+ assertEqual< bool >(
+ false,
+ provider->hasByHierarchicalName(
+ OUString( "com.sun.star.uno.XComponentContext::getValueByName")));
+
+ css::uno::Reference< css::reflection::XCompoundTypeDescription > exception;
+ exception.set(
+ provider->getByHierarchicalName(
+ OUString( "com.sun.star.uno.Exception")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_EXCEPTION, exception->getTypeClass());
+ assertEqual( OUString( "com.sun.star.uno.Exception"),
+ exception->getName());
+ assertFalse(exception->getBaseType().is());
+ exception.set(
+ provider->getByHierarchicalName(
+ OUString( "com.sun.star.uno.RuntimeException")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_EXCEPTION, exception->getTypeClass());
+ assertEqual( OUString( "com.sun.star.uno.RuntimeException"),
+ exception->getName());
+ assertEqual( OUString( "com.sun.star.uno.Exception"),
+ exception->getBaseType()->getName());
+
+ css::uno::Reference< css::reflection::XStructTypeDescription > structure;
+
+ structure.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct2")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_STRUCT, structure->getTypeClass());
+ assertEqual( OUString( "test.registrytdprovider.Struct2"),
+ structure->getName());
+ assertFalse(structure->getBaseType().is());
+ assertEqual< sal_Int32 >(1, structure->getMemberTypes().getLength());
+ assertEqual(
+ OUString( "test.registrytdprovider.Struct1"),
+ structure->getMemberTypes()[0]->getName());
+ assertEqual< sal_Int32 >(1, structure->getMemberNames().getLength());
+ assertEqual(
+ OUString("s1"),
+ structure->getMemberNames()[0]);
+ assertEqual< sal_Int32 >(0, structure->getTypeParameters().getLength());
+ assertEqual< sal_Int32 >(0, structure->getTypeArguments().getLength());
+
+ structure.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct3")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_STRUCT, structure->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.Struct3"),
+ structure->getName());
+ assertFalse(structure->getBaseType().is());
+ assertEqual< sal_Int32 >(1, structure->getMemberTypes().getLength());
+ assertEqual(
+ css::uno::TypeClass_UNKNOWN,
+ structure->getMemberTypes()[0]->getTypeClass());
+ assertEqual(
+ OUString("U"),
+ structure->getMemberTypes()[0]->getName());
+ assertEqual< sal_Int32 >(1, structure->getMemberNames().getLength());
+ assertEqual(
+ OUString("s2"),
+ structure->getMemberNames()[0]);
+ assertEqual< sal_Int32 >(2, structure->getTypeParameters().getLength());
+ assertEqual(
+ OUString("T"),
+ structure->getTypeParameters()[0]);
+ assertEqual(
+ OUString("U"),
+ structure->getTypeParameters()[1]);
+ assertEqual< sal_Int32 >(0, structure->getTypeArguments().getLength());
+
+ structure.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct4")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_STRUCT, structure->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.Struct4"),
+ structure->getName());
+ assertEqual(
+ OUString( "test.registrytdprovider.Struct2"),
+ structure->getBaseType()->getName());
+ assertEqual< sal_Int32 >(1, structure->getMemberTypes().getLength());
+ assertEqual(
+ OUString( "test.registrytdprovider.Struct3<"
+ "test.registrytdprovider.Struct2,"
+ "test.registrytdprovider.Struct3<boolean,any>>"),
+ structure->getMemberTypes()[0]->getName());
+ assertEqual< sal_Int32 >(1, structure->getMemberNames().getLength());
+ assertEqual(
+ OUString("s2"),
+ structure->getMemberNames()[0]);
+ assertEqual< sal_Int32 >(0, structure->getTypeParameters().getLength());
+ assertEqual< sal_Int32 >(0, structure->getTypeArguments().getLength());
+
+ css::uno::Reference< css::reflection::XInterfaceTypeDescription2 >
+ interface;
+
+ interface.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.XTest1")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_INTERFACE, interface->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest1"),
+ interface->getName());
+ css::uno::Sequence<
+ css::uno::Reference< css::reflection::XTypeDescription > > bases(
+ interface->getBaseTypes());
+ assertEqual< sal_Int32 >(1, bases.getLength());
+ assertEqual(
+ OUString( "com.sun.star.uno.XInterface"),
+ bases[0]->getName());
+ css::uno::Sequence<
+ css::uno::Reference< css::reflection::XTypeDescription > >
+ optionalBases(interface->getOptionalBaseTypes());
+ assertEqual< sal_Int32 >(1, optionalBases.getLength());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.XBase"),
+ optionalBases[0]->getName());
+ css::uno::Sequence<
+ css::uno::Reference<
+ css::reflection::XInterfaceMemberTypeDescription > > members(
+ interface->getMembers());
+ assertEqual< sal_Int32 >(5, members.getLength());
+
+ css::uno::Reference< css::reflection::XInterfaceAttributeTypeDescription2 >
+ attribute;
+ css::uno::Sequence<
+ css::uno::Reference< css::reflection::XCompoundTypeDescription > >
+ getExceptions;
+ css::uno::Sequence<
+ css::uno::Reference< css::reflection::XCompoundTypeDescription > >
+ setExceptions;
+ css::uno::Reference< css::reflection::XInterfaceMethodTypeDescription >
+ method;
+
+ attribute.set( members[0], css::uno::UNO_QUERY_THROW);
+ assertEqual(
+ css::uno::TypeClass_INTERFACE_ATTRIBUTE, attribute->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest1::a1"),
+ attribute->getName());
+ assertEqual(
+ OUString("a1"),
+ attribute->getMemberName());
+ assertEqual< sal_Int32 >(3, attribute->getPosition());
+ assertEqual< bool >(false, attribute->isReadOnly());
+ assertEqual(
+ OUString("short"),
+ attribute->getType()->getName());
+ assertEqual< bool >(true, attribute->isBound());
+ getExceptions = attribute->getGetExceptions();
+ assertEqual< sal_Int32 >(0, getExceptions.getLength());
+ setExceptions = attribute->getSetExceptions();
+ assertEqual< sal_Int32 >(0, setExceptions.getLength());
+
+ attribute.set( members[1], css::uno::UNO_QUERY_THROW);
+ assertEqual(
+ css::uno::TypeClass_INTERFACE_ATTRIBUTE, attribute->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest1::a2"),
+ attribute->getName());
+ assertEqual(
+ OUString("a2"),
+ attribute->getMemberName());
+ assertEqual< sal_Int32 >(4, attribute->getPosition());
+ assertEqual< bool >(false, attribute->isReadOnly());
+ assertEqual(
+ OUString("long"),
+ attribute->getType()->getName());
+ assertEqual< bool >(false, attribute->isBound());
+ getExceptions = attribute->getGetExceptions();
+ assertEqual< sal_Int32 >(2, getExceptions.getLength());
+ assertEqual(
+ OUString( "com.sun.star.lang.WrappedTargetException"),
+ getExceptions[0]->getName());
+ assertEqual(
+ OUString( "com.sun.star.uno.RuntimeException"),
+ getExceptions[1]->getName());
+ setExceptions = attribute->getSetExceptions();
+ assertEqual< sal_Int32 >(2, setExceptions.getLength());
+ assertEqual(
+ OUString( "com.sun.star.uno.Exception"),
+ setExceptions[0]->getName());
+ assertEqual(
+ OUString( "com.sun.star.lang.WrappedTargetException"),
+ setExceptions[1]->getName());
+
+ attribute.set( members[2], css::uno::UNO_QUERY_THROW);
+ assertEqual(
+ css::uno::TypeClass_INTERFACE_ATTRIBUTE, attribute->getTypeClass());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.XTest1::a3"),
+ attribute->getName());
+ assertEqual(
+ OUString("a3"),
+ attribute->getMemberName());
+ assertEqual< sal_Int32 >(5, attribute->getPosition());
+ assertEqual< bool >(true, attribute->isReadOnly());
+ assertEqual(
+ OUString("hyper"),
+ attribute->getType()->getName());
+ assertEqual< bool >(true, attribute->isBound());
+ getExceptions = attribute->getGetExceptions();
+ assertEqual< sal_Int32 >(1, getExceptions.getLength());
+ assertEqual(
+ OUString( "com.sun.star.lang.WrappedTargetException"),
+ getExceptions[0]->getName());
+ setExceptions = attribute->getSetExceptions();
+ assertEqual< sal_Int32 >(0, setExceptions.getLength());
+
+ method.set( members[3], css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_INTERFACE_METHOD, method->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest1::f1"),
+ method->getName());
+ assertEqual(
+ OUString("f1"),
+ method->getMemberName());
+ assertEqual< sal_Int32 >(6, method->getPosition());
+ assertEqual< bool >(false, method->isOneway());
+ assertEqual< sal_Int32 >(1, method->getParameters().getLength());
+ assertEqual(
+ OUString("p"),
+ method->getParameters()[0]->getName());
+ assertEqual(
+ OUString("any"),
+ method->getParameters()[0]->getType()->getName());
+ assertEqual< bool >(false, method->getParameters()[0]->isIn());
+ assertEqual< bool >(true, method->getParameters()[0]->isOut());
+ assertEqual< sal_Int32 >(0, method->getParameters()[0]->getPosition());
+ assertEqual< sal_Int32 >(1, method->getExceptions().getLength());
+ assertEqual(
+ OUString( "com.sun.star.uno.RuntimeException"),
+ method->getExceptions()[0]->getName());
+
+ method.set( members[4], css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_INTERFACE_METHOD, method->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest1::f2"),
+ method->getName());
+ assertEqual(
+ OUString("f2"),
+ method->getMemberName());
+ assertEqual< sal_Int32 >(7, method->getPosition());
+ assertEqual< bool >(true, method->isOneway());
+ assertEqual< sal_Int32 >(0, method->getParameters().getLength());
+ assertEqual< sal_Int32 >(0, method->getExceptions().getLength());
+
+ interface.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.XTest2")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_INTERFACE, interface->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest2"),
+ interface->getName());
+ assertEqual< sal_Int32 >(1, interface->getBaseTypes().getLength());
+ assertEqual(
+ OUString( "test.registrytdprovider.Typedef2"),
+ interface->getBaseTypes()[0]->getName());
+ assertEqual< sal_Int32 >(0, interface->getOptionalBaseTypes().getLength());
+ assertEqual< sal_Int32 >(0, interface->getMembers().getLength());
+
+ css::uno::Reference< css::reflection::XServiceTypeDescription2 > service;
+
+ service.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Service1")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SERVICE, service->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.Service1"),
+ service->getName());
+ assertEqual< sal_Int32 >(0, service->getMandatoryServices().getLength());
+ assertEqual< sal_Int32 >(0, service->getOptionalServices().getLength());
+ assertEqual< sal_Int32 >(0, service->getMandatoryInterfaces().getLength());
+ assertEqual< sal_Int32 >(0, service->getOptionalInterfaces().getLength());
+ assertEqual< bool >(true, service->isSingleInterfaceBased());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.XTest1"),
+ service->getInterface()->getName());
+ assertEqual< sal_Int32 >(2, service->getConstructors().getLength());
+ assertEqual(
+ OUString("c1"),
+ service->getConstructors()[0]->getName());
+ assertEqual< sal_Int32 >(
+ 0, service->getConstructors()[0]->getParameters().getLength());
+ assertEqual< sal_Int32 >(
+ 0, service->getConstructors()[0]->getExceptions().getLength());
+ assertEqual(
+ OUString("c2"),
+ service->getConstructors()[1]->getName());
+ assertEqual< sal_Int32 >(
+ 1, service->getConstructors()[1]->getParameters().getLength());
+ assertEqual(
+ OUString("p"),
+ service->getConstructors()[1]->getParameters()[0]->getName());
+ assertEqual(
+ OUString("any"),
+ (service->getConstructors()[1]->getParameters()[0]->getType()->
+ getName()));
+ assertEqual< bool >(
+ true, service->getConstructors()[1]->getParameters()[0]->isIn());
+ assertEqual< bool >(
+ false, service->getConstructors()[1]->getParameters()[0]->isOut());
+ assertEqual< sal_Int32 >(
+ 0, service->getConstructors()[1]->getParameters()[0]->getPosition());
+ assertEqual< bool >(
+ true,
+ service->getConstructors()[1]->getParameters()[0]->isRestParameter());
+ assertEqual< sal_Int32 >(
+ 1, service->getConstructors()[1]->getExceptions().getLength());
+ assertEqual(
+ OUString( "com.sun.star.uno.RuntimeException"),
+ service->getConstructors()[1]->getExceptions()[0]->getName());
+
+ service.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Service2")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SERVICE, service->getTypeClass());
+ assertEqual(
+ OUString( "test.registrytdprovider.Service2"),
+ service->getName());
+ assertEqual< sal_Int32 >(0, service->getMandatoryServices().getLength());
+ assertEqual< sal_Int32 >(0, service->getOptionalServices().getLength());
+ assertEqual< sal_Int32 >(1, service->getMandatoryInterfaces().getLength());
+ assertEqual(
+ OUString( "test.registrytdprovider.XTest1"),
+ service->getMandatoryInterfaces()[0]->getName());
+ assertEqual< sal_Int32 >(1, service->getOptionalInterfaces().getLength());
+ assertEqual(
+ OUString( "test.registrytdprovider.XBase"),
+ service->getOptionalInterfaces()[0]->getName());
+ assertEqual< bool >(false, service->isSingleInterfaceBased());
+ assertFalse(service->getInterface().is());
+ assertEqual< sal_Int32 >(0, service->getConstructors().getLength());
+
+ service.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Service3")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SERVICE, service->getTypeClass());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Service3"),
+ service->getName());
+ assertEqual< sal_Int32 >(0, service->getMandatoryServices().getLength());
+ assertEqual< sal_Int32 >(0, service->getOptionalServices().getLength());
+ assertEqual< sal_Int32 >(0, service->getMandatoryInterfaces().getLength());
+ assertEqual< sal_Int32 >(0, service->getOptionalInterfaces().getLength());
+ assertEqual< bool >(true, service->isSingleInterfaceBased());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Typedef2"),
+ service->getInterface()->getName());
+ assertEqual< sal_Int32 >(0, service->getConstructors().getLength());
+
+ css::uno::Reference< css::reflection::XSingletonTypeDescription2 >
+ singleton;
+
+ singleton.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Singleton1")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SINGLETON, singleton->getTypeClass());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Singleton1"),
+ singleton->getName());
+ assertFalse(singleton->getService().is());
+ assertEqual< bool >(true, singleton->isInterfaceBased());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.XTest1"),
+ singleton->getInterface()->getName());
+
+ singleton.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Singleton2")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SINGLETON, singleton->getTypeClass());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Singleton2"),
+ singleton->getName());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Service1"),
+ singleton->getService()->getName());
+ assertEqual< bool >(false, singleton->isInterfaceBased());
+ assertFalse(singleton->getInterface().is());
+
+ singleton.set(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Singleton3")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SINGLETON, singleton->getTypeClass());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Singleton3"),
+ singleton->getName());
+ assertFalse(singleton->getService().is());
+ assertEqual< bool >(true, singleton->isInterfaceBased());
+ assertEqual(
+ OUString(
+ "test.registrytdprovider.Typedef2"),
+ singleton->getInterface()->getName());
+
+ css::uno::Reference< css::reflection::XPublished > published;
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Enum1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Enum2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct3")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XStructTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct3")),
+ css::uno::UNO_QUERY_THROW)->getMemberTypes()[0],
+ css::uno::UNO_QUERY);
+ assertFalse(published.is());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Struct3a")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Exception1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Exception2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.XTest1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.XTest2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Typedef1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Typedef2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ //TODO: check constants test.registrytdprovider.Const1 (published),
+ // test.registrytdprovider.Const2 (unpublished), and
+ // test.registrytdprovider.Consts1.C (no XPublished), which are not
+ // accessible via provider->getByHierarchicalName (see #i31428)
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Consts1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Consts2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertFalse(published.is());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Service1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Service2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Singleton2")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertTrue(published->isPublished());
+ published.set(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ provider->getByHierarchicalName(
+ OUString( "test.registrytdprovider.Singleton1")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY);
+ assertTrue(published.is());
+ assertFalse(published->isPublished());
+
+ return 0;
+}
+
+OUString Service::getImplementationName() {
+ return OUString("test.registrytdprovider.impl");
+}
+
+css::uno::Sequence< OUString > Service::getSupportedServiceNames() {
+ return css::uno::Sequence< OUString >();
+}
+
+css::uno::Reference< css::uno::XInterface > Service::createInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & context)
+ throw (css::uno::Exception)
+{
+ return cppu::getXWeak(new Service(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(char const * implName,
+ void * serviceManager, void *) {
+ void * p = 0;
+ if (serviceManager != 0) {
+ css::uno::Reference< css::lang::XSingleComponentFactory > f;
+ if (Service::getImplementationName().equalsAscii(implName)) {
+ f = cppu::createSingleComponentFactory(
+ &Service::createInstance, Service::getImplementationName(),
+ Service::getSupportedServiceNames());
+ }
+ if (f.is()) {
+ f->acquire();
+ p = f.get();
+ }
+ }
+ return p;
+}
+
+namespace {
+
+bool writeInfo(void * registryKey, OUString const & implementationName,
+ css::uno::Sequence< OUString > const & serviceNames) {
+ OUString keyName = "/" + implementationName + "/UNO/SERVICES";
+ css::uno::Reference< css::registry::XRegistryKey > key;
+ try {
+ key = static_cast< css::registry::XRegistryKey * >(registryKey)->
+ createKey(keyName);
+ } catch (css::registry::InvalidRegistryException &) {}
+ if (!key.is()) {
+ return false;
+ }
+ bool success = true;
+ for (auto const& rServiceName : serviceNames) {
+ try {
+ key->createKey(rServiceName);
+ } catch (css::registry::InvalidRegistryException &) {
+ success = false;
+ break;
+ }
+ }
+ return success;
+}
+
+}
+
+extern "C" sal_Bool SAL_CALL component_writeInfo(void *, void * registryKey) {
+ return registryKey
+ && writeInfo(registryKey, Service::getImplementationName(),
+ Service::getSupportedServiceNames());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/registry_tdprovider/types.idl b/stoc/test/registry_tdprovider/types.idl
new file mode 100644
index 0000000000..7d37e23221
--- /dev/null
+++ b/stoc/test/registry_tdprovider/types.idl
@@ -0,0 +1,101 @@
+/* -*- 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 .
+ */
+
+module test { module registrytdprovider {
+
+published enum Enum1 { E1 };
+
+enum Enum2 { E1 };
+
+published struct Struct1 { long s1; };
+
+struct Struct2 { Struct1 s1; };
+
+published struct Struct3<T, U> { U s2; };
+
+struct Struct3a<T, U> { U s2; };
+
+struct Struct4: Struct2 { Struct3< Struct2, Struct3< boolean, any > > s2; };
+
+published exception Exception1: com::sun::star::uno::Exception {};
+
+exception Exception2: com::sun::star::uno::Exception {};
+
+published interface XBase {};
+
+published typedef XBase Typedef1;
+
+typedef Typedef1 Typedef2;
+
+published interface XTest1 {
+ [optional] interface XBase;
+
+ void f1([out] any p) raises (com::sun::star::uno::RuntimeException);
+
+ void f2();
+
+ [attribute, bound] short a1;
+
+ [attribute] long a2 {
+ get raises
+ (com::sun::star::lang::WrappedTargetException,
+ com::sun::star::uno::RuntimeException);
+ set raises
+ (com::sun::star::uno::Exception,
+ com::sun::star::lang::WrappedTargetException);
+ };
+
+ [attribute, readonly, bound] hyper a3 {
+ get raises (com::sun::star::lang::WrappedTargetException);
+ };
+};
+
+interface XTest2: Typedef2 {};
+
+published service Service1: XTest1 {
+ c1();
+
+ c2([in] any... p) raises (com::sun::star::uno::RuntimeException);
+};
+
+service Service2 {
+ [optional] interface XBase;
+
+ interface XTest1;
+};
+
+service Service3: Typedef2 {};
+
+singleton Singleton1: XTest1;
+
+published singleton Singleton2 { service Service1; };
+
+singleton Singleton3: Typedef2;
+
+published const long Const1 = 0;
+
+const long Const2 = 0;
+
+published constants Consts1 { const long C = 0; };
+
+constants Consts2 { const long C = 0; };
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/makefile.mk b/stoc/test/tdmanager/makefile.mk
new file mode 100644
index 0000000000..47cc135ba7
--- /dev/null
+++ b/stoc/test/tdmanager/makefile.mk
@@ -0,0 +1,66 @@
+#
+# 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 .
+#
+
+PRJ := ..$/..
+PRJNAME := stoc
+
+TARGET := test_tdmanager
+
+ENABLE_EXCEPTIONS := TRUE
+
+.INCLUDE: settings.mk
+
+DLLPRE = # no leading "lib" on .so files
+
+SLOFILES = $(SLO)$/testtdmanager.obj
+
+SHL1TARGET = $(ENFORCEDSHLPREFIX)testtdmanager.uno
+SHL1OBJS = $(SLOFILES)
+SHL1VERSIONMAP = $(SOLARENV)/src/component.map
+SHL1STDLIBS = $(CPPULIB) $(CPPUHELPERLIB) $(SALLIB)
+SHL1IMPLIB = itesttdmanager
+DEF1NAME = $(SHL1TARGET)
+
+.INCLUDE: target.mk
+
+ALLTAR: test
+
+$(MISC)$/$(TARGET)$/%.rdb : %.idl
+ - rm $@
+ - $(MKDIR) $(MISC)$/$(TARGET)
+ idlc -O$(MISC)$/$(TARGET) -I$(SOLARIDLDIR) -C -cid -we $<
+ regmerge $@ /UCR $(subst,.rdb,.urd $@)
+
+IDL_FILES = \
+ types.idl \
+ types2_incomp.idl \
+ types3_incomp.idl \
+ types4_incomp.idl \
+ types5_incomp.idl \
+ types5.idl \
+ types6_incomp.idl
+
+RDB_FILES = $(foreach,i,$(subst,.idl,.rdb $(IDL_FILES)) $(MISC)$/$(TARGET)$/$i)
+
+$(SLOFILES): $(RDB_FILES)
+
+test .PHONY: $(SHL1TARGETN) $(RDB_FILES)
+ uno -c test.tdmanager.impl -l $(subst,$/,/ $(SHL1TARGETN)) \
+ -ro $(subst,$/,/ $(SOLARBINDIR)$/udkapi_doc.rdb) \
+ -- $(subst,$/,/ $(SOLARBINDIR)$/types_doc.rdb) \
+ $(subst,$/,/ $(RDB_FILES))
diff --git a/stoc/test/tdmanager/readme.txt b/stoc/test/tdmanager/readme.txt
new file mode 100644
index 0000000000..f497720496
--- /dev/null
+++ b/stoc/test/tdmanager/readme.txt
@@ -0,0 +1,4 @@
+This test uses the delivered typemgr.uno dynamic library, not the local one.
+(It might work to fix this, changing the test from a UNO component started from
+the uno executable to a stand-alone application that bootstraps UNO in a special
+way.)
diff --git a/stoc/test/tdmanager/testtdmanager.cxx b/stoc/test/tdmanager/testtdmanager.cxx
new file mode 100644
index 0000000000..7c9971d6aa
--- /dev/null
+++ b/stoc/test/tdmanager/testtdmanager.cxx
@@ -0,0 +1,332 @@
+/* -*- 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/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/container/XSet.hpp>
+#include <com/sun/star/lang/XMain.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/reflection/XIndirectTypeDescription.hpp>
+#include <com/sun/star/reflection/XInterfaceMethodTypeDescription.hpp>
+#include <com/sun/star/reflection/XPublished.hpp>
+#include <com/sun/star/reflection/XStructTypeDescription.hpp>
+#include <com/sun/star/reflection/XTypeDescription.hpp>
+#include <com/sun/star/registry/InvalidRegistryException.hpp>
+#include <com/sun/star/registry/XRegistryKey.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#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/TypeClass.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uno/XInterface.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weak.hxx>
+#include <osl/file.h>
+#include <osl/thread.h>
+#include <rtl/textenc.h>
+#include <rtl/ustring.h>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <uno/environment.h>
+
+#include /*MSVC trouble: <cstdlib>*/ <stdlib.h>
+#include <iostream>
+#include <ostream>
+
+namespace {
+
+class Service: public cppu::WeakImplHelper< css::lang::XMain > {
+public:
+ virtual sal_Int32 SAL_CALL
+ run(css::uno::Sequence< OUString > const & arguments)
+ throw (css::uno::RuntimeException);
+
+ static OUString getImplementationName();
+
+ static css::uno::Sequence< OUString > getSupportedServiceNames();
+
+ static css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & context)
+ throw (css::uno::Exception);
+
+private:
+ explicit Service(
+ css::uno::Reference< css::uno::XComponentContext > const & context):
+ m_context(context)
+ {}
+
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+};
+
+}
+
+namespace {
+
+std::ostream & operator <<(std::ostream & out, OUString const & value) {
+ return out << OUStringToOString(value, RTL_TEXTENCODING_UTF8).getStr();
+}
+
+void assertTrue(bool argument) {
+ if (!argument) {
+ std::cerr
+ << "assertTrue(" << argument << ") failed" << std::endl;
+ /*MSVC trouble: std::*/abort();
+ }
+}
+
+void assertFalse(bool argument) {
+ if (argument) {
+ std::cerr
+ << "assertFalse(" << argument << ") failed" << std::endl;
+ /*MSVC trouble: std::*/abort();
+ }
+}
+
+template< typename T > void assertEqual(T const & value, T const & argument) {
+ if (argument != value) {
+ std::cerr
+ << "assertEqual(" << value << ", " << argument << ") failed"
+ << std::endl;
+ /*MSVC trouble: std::*/abort();
+ }
+}
+
+}
+
+sal_Int32 Service::run(css::uno::Sequence< OUString > const & arguments)
+ throw (css::uno::RuntimeException)
+{
+ css::uno::Reference< css::lang::XMultiComponentFactory > factory(
+ m_context->getServiceManager());
+ assertTrue(factory.is());
+ css::uno::Reference< css::container::XHierarchicalNameAccess > manager(
+ m_context->getValueByName(
+ OUString(
+ "/singletons/"
+ "com.sun.star.reflection.theTypeDescriptionManager")),
+ css::uno::UNO_QUERY_THROW);
+
+
+ // test: add cmd line rdbs to manager
+
+
+ OSL_ASSERT( arguments.getLength() > 0 );
+ css::uno::Reference<css::container::XSet> xSet(
+ manager, css::uno::UNO_QUERY_THROW );
+ for ( sal_Int32 argPos = 0; argPos < arguments.getLength(); ++argPos ) {
+ OUString url;
+ OSL_VERIFY( osl_File_E_None == osl_getFileURLFromSystemPath(
+ arguments[argPos].pData, &url.pData ) );
+ bool supposedToBeCompatible = ! url.endsWithIgnoreAsciiCase("_incomp.rdb");
+
+ css::uno::Reference<css::registry::XSimpleRegistry> xReg(
+ m_context->getServiceManager()->createInstanceWithContext(
+ "com.sun.star.registry.SimpleRegistry",
+ m_context ), css::uno::UNO_QUERY_THROW );
+ xReg->open( url, true /* read-only */, false /* ! create */ );
+ css::uno::Any arg( css::uno::makeAny(xReg) );
+ css::uno::Reference<css::container::XHierarchicalNameAccess> xTDprov(
+ m_context->getServiceManager()->
+ createInstanceWithArgumentsAndContext(
+ "com.sun.star.comp.stoc.RegistryTypeDescriptionProvider",
+ css::uno::Sequence<css::uno::Any>( &arg, 1 ), m_context ),
+ css::uno::UNO_QUERY_THROW );
+ try {
+ xSet->insert( css::uno::makeAny(xTDprov) );
+ if (! supposedToBeCompatible)
+ std::cerr << "current rdb file: " <<
+ OUStringToOString(
+ url, osl_getThreadTextEncoding()).getStr() << std::endl;
+ assertTrue(supposedToBeCompatible);
+ } catch (css::lang::IllegalArgumentException &) {
+ if (supposedToBeCompatible)
+ throw;
+ assertFalse(supposedToBeCompatible);
+ }
+ }
+
+ /
+
+ css::uno::Reference< css::reflection::XIndirectTypeDescription > sequence(
+ manager->getByHierarchicalName(
+ OUString("[][]boolean")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_SEQUENCE, sequence->getTypeClass());
+ assertEqual(
+ OUString("[][]boolean"),
+ sequence->getName());
+ assertEqual(
+ OUString("[]boolean"),
+ sequence->getReferencedType()->getName());
+
+ css::uno::Reference< css::reflection::XStructTypeDescription > structure(
+ manager->getByHierarchicalName(
+ OUString( "test.tdmanager.Struct<boolean,test.tdmanager.Struct<"
+ "any,com.sun.star.uno.XInterface>>")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_STRUCT, structure->getTypeClass());
+ assertEqual(
+ OUString( "test.tdmanager.Struct<boolean,test.tdmanager.Struct<"
+ "any,com.sun.star.uno.XInterface>>"),
+ structure->getName());
+ assertEqual< bool >(false, structure->getBaseType().is());
+ assertEqual< sal_Int32 >(1, structure->getMemberTypes().getLength());
+ assertEqual(
+ OUString( "test.tdmanager.Struct<any,com.sun.star.uno.XInterface>"),
+ structure->getMemberTypes()[0]->getName());
+ assertEqual< sal_Int32 >(1, structure->getMemberNames().getLength());
+ assertEqual(
+ OUString("s"),
+ structure->getMemberNames()[0]);
+ assertEqual< sal_Int32 >(0, structure->getTypeParameters().getLength());
+ assertEqual< sal_Int32 >(2, structure->getTypeArguments().getLength());
+ assertEqual(
+ OUString("boolean"),
+ structure->getTypeArguments()[0]->getName());
+ assertEqual(
+ OUString( "test.tdmanager.Struct<any,com.sun.star.uno.XInterface>"),
+ structure->getTypeArguments()[1]->getName());
+
+ css::uno::Reference< css::reflection::XInterfaceMethodTypeDescription >
+ method(
+ manager->getByHierarchicalName(
+ OUString( "com.sun.star.uno.XComponentContext::getValueByName")),
+ css::uno::UNO_QUERY_THROW);
+ assertEqual(css::uno::TypeClass_INTERFACE_METHOD, method->getTypeClass());
+ assertEqual(
+ OUString( "com.sun.star.uno.XComponentContext::getValueByName"),
+ method->getName());
+ assertEqual(
+ OUString("getValueByName"),
+ method->getMemberName());
+ assertEqual< sal_Int32 >(3, method->getPosition());
+ assertEqual(
+ OUString("any"),
+ method->getReturnType()->getName());
+ assertEqual< bool >(false, method->isOneway());
+ assertEqual< sal_Int32 >(1, method->getParameters().getLength());
+ assertEqual(
+ OUString("Name"),
+ method->getParameters()[0]->getName());
+ assertEqual(
+ OUString("string"),
+ method->getParameters()[0]->getType()->getName());
+ assertEqual< bool >(true, method->getParameters()[0]->isIn());
+ assertEqual< bool >(false, method->getParameters()[0]->isOut());
+ assertEqual< sal_Int32 >(0, method->getParameters()[0]->getPosition());
+ assertEqual< sal_Int32 >(0, method->getExceptions().getLength());
+
+ assertFalse(
+ css::uno::Reference< css::reflection::XPublished >(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ manager->getByHierarchicalName(
+ OUString("[]boolean")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY).is());
+ assertFalse(
+ css::uno::Reference< css::reflection::XPublished >(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ manager->getByHierarchicalName(
+ OUString( "com.sun.star.beans.XIntroTest::ObjectName")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY).is());
+ assertFalse(
+ css::uno::Reference< css::reflection::XPublished >(
+ css::uno::Reference< css::reflection::XTypeDescription >(
+ manager->getByHierarchicalName(
+ OUString( "com.sun.star.beans.XIntroTest::writeln")),
+ css::uno::UNO_QUERY_THROW),
+ css::uno::UNO_QUERY).is());
+ //TODO: check that the reflection of a property of an accumulation-based
+ // service does not support XPublished
+
+ return 0;
+}
+
+OUString Service::getImplementationName() {
+ return OUString("test.tdmanager.impl");
+}
+
+css::uno::Sequence< OUString > Service::getSupportedServiceNames() {
+ return css::uno::Sequence< OUString >();
+}
+
+css::uno::Reference< css::uno::XInterface > Service::createInstance(
+ css::uno::Reference< css::uno::XComponentContext > const & context)
+ throw (css::uno::Exception)
+{
+ return cppu::getXWeak(new Service(context));
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(char const * implName,
+ void * serviceManager, void *) {
+ void * p = 0;
+ if (serviceManager != 0) {
+ css::uno::Reference< css::lang::XSingleComponentFactory > f;
+ if (Service::getImplementationName().equalsAscii(implName)) {
+ f = cppu::createSingleComponentFactory(
+ &Service::createInstance, Service::getImplementationName(),
+ Service::getSupportedServiceNames());
+ }
+ if (f.is()) {
+ f->acquire();
+ p = f.get();
+ }
+ }
+ return p;
+}
+
+namespace {
+
+bool writeInfo(void * registryKey, OUString const & implementationName,
+ css::uno::Sequence< OUString > const & serviceNames) {
+ OUString keyName = "/" + implementationName + "/UNO/SERVICES";
+ css::uno::Reference< css::registry::XRegistryKey > key;
+ try {
+ key = static_cast< css::registry::XRegistryKey * >(registryKey)->
+ createKey(keyName);
+ } catch (css::registry::InvalidRegistryException &) {}
+ if (!key.is()) {
+ return false;
+ }
+ bool success = true;
+ for (sal_Int32 i = 0; i < serviceNames.getLength(); ++i) {
+ try {
+ key->createKey(serviceNames[i]);
+ } catch (css::registry::InvalidRegistryException &) {
+ success = false;
+ break;
+ }
+ }
+ return success;
+}
+
+}
+
+extern "C" sal_Bool SAL_CALL component_writeInfo(void *, void * registryKey) {
+ return registryKey
+ && writeInfo(registryKey, Service::getImplementationName(),
+ Service::getSupportedServiceNames());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types.idl b/stoc/test/tdmanager/types.idl
new file mode 100644
index 0000000000..612ad1bac4
--- /dev/null
+++ b/stoc/test/tdmanager/types.idl
@@ -0,0 +1,37 @@
+/* -*- 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 .
+ */
+
+module test { module tdmanager {
+
+struct Struct<T, U> { U s; };
+
+published interface XAnother {
+ void f();
+};
+
+service MyService {
+ [optional] interface XAnother;
+ [property, optional] boolean b;
+};
+
+const long CCC = 5;
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types2_incomp.idl b/stoc/test/tdmanager/types2_incomp.idl
new file mode 100644
index 0000000000..cb3b0e02c0
--- /dev/null
+++ b/stoc/test/tdmanager/types2_incomp.idl
@@ -0,0 +1,32 @@
+/* -*- 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 .
+ */
+
+module com { module sun { module star { module text {
+
+typedef long XTextField;
+
+}; }; }; };
+
+module test { module tdmanager {
+
+const long CCC = 6;
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types3_incomp.idl b/stoc/test/tdmanager/types3_incomp.idl
new file mode 100644
index 0000000000..cb2603f6ff
--- /dev/null
+++ b/stoc/test/tdmanager/types3_incomp.idl
@@ -0,0 +1,27 @@
+/* -*- 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 .
+ */
+
+module test { module tdmanager {
+
+// added member:
+struct Struct<T, U> { U s; long n; };
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types4_incomp.idl b/stoc/test/tdmanager/types4_incomp.idl
new file mode 100644
index 0000000000..6711673ba9
--- /dev/null
+++ b/stoc/test/tdmanager/types4_incomp.idl
@@ -0,0 +1,34 @@
+/* -*- 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 .
+ */
+
+module test { module tdmanager {
+
+published interface XAnother {
+ // wrong name:
+ void f2();
+};
+
+service MyService {
+ [optional] interface XAnother;
+ [property, optional] boolean b;
+};
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types5.idl b/stoc/test/tdmanager/types5.idl
new file mode 100644
index 0000000000..21eda7d389
--- /dev/null
+++ b/stoc/test/tdmanager/types5.idl
@@ -0,0 +1,37 @@
+/* -*- 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 .
+ */
+
+module test { module tdmanager {
+
+published interface XAnother {
+ void f();
+};
+
+service MyService {
+ [optional] interface XAnother;
+ // correct order:
+ [property, optional] boolean b;
+ [property, optional] boolean b2;
+};
+
+const long CCC = 5;
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types5_incomp.idl b/stoc/test/tdmanager/types5_incomp.idl
new file mode 100644
index 0000000000..8f3b5f83c1
--- /dev/null
+++ b/stoc/test/tdmanager/types5_incomp.idl
@@ -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 .
+ */
+
+module test { module tdmanager {
+
+published interface XAnother {
+ void f();
+};
+
+service MyService {
+ [optional] interface XAnother;
+ // wrong order:
+ [property, optional] boolean b2;
+ [property, optional] boolean b;
+};
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/tdmanager/types6_incomp.idl b/stoc/test/tdmanager/types6_incomp.idl
new file mode 100644
index 0000000000..898c9b3d2b
--- /dev/null
+++ b/stoc/test/tdmanager/types6_incomp.idl
@@ -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 .
+ */
+
+module test { module tdmanager {
+
+published interface XAnother {
+ void f();
+};
+
+service MyService {
+ // made non-optional:
+ interface XAnother;
+ [property, optional] boolean b;
+ [property, optional] boolean b2;
+};
+
+}; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testconv.cxx b/stoc/test/testconv.cxx
new file mode 100644
index 0000000000..5549779db1
--- /dev/null
+++ b/stoc/test/testconv.cxx
@@ -0,0 +1,682 @@
+/* -*- 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/main.h>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <cppuhelper/servicefactory.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/reflection/FieldAccessMode.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+
+#include <cmath>
+#include <float.h>
+#include <stdio.h>
+
+
+using namespace cppu;
+using namespace osl;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::script;
+using namespace css::reflection;
+using namespace css::registry;
+
+
+const double MIN_DOUBLE = -DBL_MAX;
+const double MAX_DOUBLE = DBL_MAX;
+const double MIN_FLOAT = -FLT_MAX;
+const double MAX_FLOAT = FLT_MAX;
+
+
+static void printValue( const Any & rVal )
+{
+ // print value
+ OString aStr( OUStringToOString( rVal.getValueType().getTypeName(), RTL_TEXTENCODING_ISO_8859_1 ) );
+ printf( "(%s)", aStr.getStr() );
+
+ switch (rVal.getValueTypeClass())
+ {
+ case TypeClass_VOID:
+ printf( "void" );
+ break;
+ case TypeClass_ANY:
+ if (rVal.hasValue())
+ printValue( *(Any *)rVal.getValue() );
+ break;
+ case TypeClass_BOOLEAN:
+ printf( "%s", (*(sal_Bool *)rVal.getValue() ? "true" : "false") );
+ break;
+ case TypeClass_CHAR:
+ {
+ char ar[2];
+ ar[0] = (char)*(sal_Unicode *)rVal.getValue();
+ ar[1] = 0;
+ printf( "%s", ar );
+ break;
+ }
+ case TypeClass_BYTE:
+ printf( "%x", (int)*(sal_Int8 *)rVal.getValue() );
+ break;
+ case TypeClass_SHORT:
+ printf( "%x", *(sal_Int16 *)rVal.getValue() );
+ break;
+ case TypeClass_UNSIGNED_SHORT:
+ printf( "%x", *(sal_uInt16 *)rVal.getValue() );
+ break;
+ case TypeClass_LONG:
+ printf( "%lx", static_cast<long>(*(sal_Int32 *)rVal.getValue()) );
+ break;
+ case TypeClass_UNSIGNED_LONG:
+ printf( "%lx", static_cast<unsigned long>(*(sal_uInt32 *)rVal.getValue()) );
+ break;
+ case TypeClass_HYPER:
+ printf( "%lx", (long)*(sal_Int64 *)rVal.getValue() );
+ break;
+ case TypeClass_UNSIGNED_HYPER:
+ printf( "%lx", (unsigned long)*(sal_uInt64 *)rVal.getValue() );
+ break;
+ case TypeClass_FLOAT:
+ printf( "%f", *(float *)rVal.getValue() );
+ break;
+ case TypeClass_DOUBLE:
+ printf( "%g", *(double *)rVal.getValue() );
+ break;
+ case TypeClass_STRING:
+ {
+ OString aStr2( OUStringToOString( *(OUString *)rVal.getValue(), RTL_TEXTENCODING_ISO_8859_1 ) );
+ printf( aStr2.getStr() );
+ break;
+ }
+ case TypeClass_ENUM:
+ {
+ typelib_EnumTypeDescription * pEnumTD = 0;
+ TYPELIB_DANGER_GET( (typelib_TypeDescription **)&pEnumTD, rVal.getValueTypeRef() );
+
+ for ( sal_Int32 nPos = pEnumTD->nEnumValues; nPos--; )
+ {
+ if (pEnumTD->pEnumValues[nPos] == *(int *)rVal.getValue())
+ {
+ printf( OUStringToOString(pEnumTD->ppEnumNames[nPos]->buffer, RTL_TEXTENCODING_ASCII_US).getStr() );
+ TYPELIB_DANGER_RELEASE( (typelib_TypeDescription *)pEnumTD );
+ return;
+ }
+ }
+ TYPELIB_DANGER_RELEASE( (typelib_TypeDescription *)pEnumTD );
+ printf( ">ENUM not found!<" );
+ break;
+ }
+ case TypeClass_SEQUENCE:
+ {
+ uno_Sequence * pSeq = *(uno_Sequence **)rVal.getValue();
+ typelib_TypeDescription * pSeqTD = 0;
+ TYPELIB_DANGER_GET( &pSeqTD, rVal.getValueTypeRef() );
+ typelib_TypeDescription * pElemTD = 0;
+ TYPELIB_DANGER_GET( &pElemTD, ((typelib_IndirectTypeDescription *)pSeqTD)->pType );
+
+ sal_Int32 nLen = pSeq->nElements;
+ if (nLen)
+ {
+ printf( "{ " );
+ for ( sal_Int32 nPos = 0; nPos < nLen; ++nPos )
+ {
+ printValue( Any( ((char *)pSeq->elements) + (nPos * pElemTD->nSize), pElemTD ) );
+ if (nPos < (nLen-1))
+ printf( ", " );
+ }
+ printf( " }" );
+ }
+
+ TYPELIB_DANGER_RELEASE( pElemTD );
+ TYPELIB_DANGER_RELEASE( pSeqTD );
+ break;
+ }
+
+ default:
+ printf( ">not printable<" );
+ break;
+ }
+}
+
+static Reference< XTypeConverter > s_xConverter;
+
+
+static sal_Bool convertTo( const Type & rDestType, const Any & rVal, sal_Bool bExpectSuccess )
+{
+ sal_Bool bCanConvert = sal_False;
+ Any aRet;
+
+ OString aExcMsg;
+
+ try
+ {
+ aRet = s_xConverter->convertTo( rVal, rDestType );
+ bCanConvert = sal_True;
+ }
+ catch (const Exception & rExc)
+ {
+ aExcMsg = OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US );
+ }
+
+ if (bExpectSuccess && !bCanConvert)
+ {
+ printf( "# conversion of " );
+ printValue( rVal );
+ printf( " to " );
+ printf( OUStringToOString(rDestType.getTypeName(), RTL_TEXTENCODING_ASCII_US).getStr() );
+ printf( " failed, but success was expected! [" );
+ printf( aExcMsg.getStr() );
+ printf( "]\n" );
+ aRet = s_xConverter->convertTo( rVal, rDestType );
+#if OSL_DEBUG_LEVEL > 0
+ // for debugging, to trace again
+ try
+ {
+ aRet = s_xConverter->convertTo( rVal, rDestType );
+ }
+ catch (Exception &)
+ {
+ }
+#endif
+ return sal_False;
+ }
+ if (!bExpectSuccess && bCanConvert)
+ {
+ printf( "# conversion of " );
+ printValue( rVal );
+ printf( " to " );
+ printValue( aRet );
+ printf( " was successful, but was not expected to be!\n" );
+#if OSL_DEBUG_LEVEL > 0
+ // for debugging, to trace again
+ aRet = s_xConverter->convertTo( rVal, rDestType );
+#endif
+ return sal_False;
+ }
+
+#ifdef __RECONVERSION_OUTPUT__
+//= re-conversion output =
+ if (bCanConvert)
+ {
+ // re convert to original type
+ sal_Bool bReConvert = sal_False;
+ Any aRet2;
+
+ try
+ {
+ aRet2 = s_xConverter->convertTo( aRet, rVal.getValueType() );
+ bReConvert = sal_True;
+ }
+ catch (const Exception & rExc)
+ {
+ aExcMsg = OUStringToOString( rExc.Message, RTL_TEXTENCODING_ISO_8859_1 );
+ }
+
+ if (bReConvert)
+ {
+ if (rVal != aRet2)
+ {
+ printf( "# re-conversion of " );
+ printValue( rVal );
+ printf( " to " );
+ printValue( aRet );
+ printf( " to " );
+ printValue( aRet2 );
+ printf( ": first and last do not match!\n" );
+ }
+ }
+ else
+ {
+ printf( "# re-conversion of " );
+ printValue( aRet );
+ printf( " to " );
+ printf( rVal.getValueType().getTypeName().getStr() );
+ printf( " failed! [" );
+ printf( aExcMsg.getStr() );
+ printf( "]\n" );
+ }
+ }
+#endif
+
+ return sal_True;
+}
+
+
+typedef struct _ConvBlock
+{
+ Any _value;
+ sal_Bool _toString, _toDouble, _toFloat;
+ sal_Bool _toUINT32, _toINT32, _toUINT16, _toINT16, _toBYTE, _toBOOL, _toChar;
+ sal_Bool _toTypeClass, _toSeqINT16, _toSeqAny;
+
+ _ConvBlock()
+ {
+ }
+ _ConvBlock( const Any & rValue_,
+ sal_Bool toString_, sal_Bool toDouble_, sal_Bool toFloat_,
+ sal_Bool toUINT32_, sal_Bool toINT32_, sal_Bool toUINT16_, sal_Bool toINT16_,
+ sal_Bool toBYTE_, sal_Bool toBOOL_, sal_Bool toChar_,
+ sal_Bool toTypeClass_, sal_Bool toSeqINT16_, sal_Bool toSeqAny_ )
+ : _value( rValue_ )
+ , _toString( toString_ ), _toDouble( toDouble_ ), _toFloat( toFloat_ )
+ , _toUINT32( toUINT32_ ), _toINT32( toINT32_ ), _toUINT16( toUINT16_ ), _toINT16( toINT16_ )
+ , _toBYTE( toBYTE_ ), _toBOOL( toBOOL_ ), _toChar( toChar_ )
+ , _toTypeClass( toTypeClass_ ), _toSeqINT16( toSeqINT16_ ), _toSeqAny( toSeqAny_ )
+ {
+ }
+} ConvBlock;
+
+
+static sal_Int32 initBlocks( ConvBlock * pTestBlocks )
+{
+ Any aVal;
+
+ sal_uInt32 nElems = 0;
+
+ // ==BYTE==
+ aVal <<= OUString("0xff");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("255");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_Int8)0xffu;
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("0x80");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("128");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_Int8)( 0x80u );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("0x7f");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("127");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_Int8)( 0x7f );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("5");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 );
+ aVal <<= OUString("+5");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_Int8)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("-5");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int8)( -5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("256");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==UINT16==
+ aVal <<= OUString("65535");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("0xffff");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt16)( 0xffff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("32768");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt16)( 0x8000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("32767");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("0x7fff");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt16)( 0x7fff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("256");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("0x100");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt16)( 0x100 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_uInt16)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_uInt16)( -5 ); // is 0xfffb
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==INT16==
+ aVal <<= (sal_Int16)( -1 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int16)( -0x8000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int16)( 0x7fff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int16)( 0x100 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int16)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int16)( -5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==UINT32==
+ aVal <<= OUString("+4294967295");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("4294967295");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("0xffffffff");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt32)( 0xffffffff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("-2147483648");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("-0x80000000");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_uInt32)( 0x80000000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("2147483647");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("0x7fffffff");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt32)( 0x7fffffff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("65536");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= OUString("0x10000");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt32)( 0x10000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_uInt32)( 0x8000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_uInt32)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("0xfffffffb");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (sal_uInt32)( -5 ); // is 0xfffffffb
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==INT32==
+ aVal <<= (sal_Int32)( 0xffffffff ); // is -1
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int32)( 0x80000000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int32)( 0x7fffffff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int32)( 0x10000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int32)( -0x8001 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int32)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (sal_Int32)( -5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==FLOAT==
+ aVal <<= OUString("-3.4e+38");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (float)( MIN_FLOAT );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("+3.4e+38");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (float)( MAX_FLOAT );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("9e-20");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ aVal <<= (float)( 9e-20 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("+.7071067811865");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ aVal <<= (float)( M_SQRT1_2 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("3.14159265359");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ aVal <<= (float)( M_PI );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (float)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==DOUBLE==
+ aVal <<= OUString("-1.7976931348623155e+308");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (double)( MIN_DOUBLE );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("1.7976931348623155e+308");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (double)( MAX_DOUBLE );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( MIN_FLOAT );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( MAX_FLOAT );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( -((double)0x80000000) );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( -((double)0x80000001) );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( 0x7fffffff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( 0x80000000 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( 0xffffffff );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("0x100000000");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
+ aVal <<= (double)( SAL_CONST_INT64(0x100000000) );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= (double)( 5 );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==CHAR==
+ sal_Unicode c = 'A';
+ aVal.setValue( &c, cppu::UnoType<cppu::UnoCharType>::get() );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("A");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==BOOL==
+ aVal <<= OUString("0");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("1");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("False");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("true");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+
+ sal_Bool bTmp = sal_True;
+ aVal.setValue( &bTmp, cppu::UnoType<bool>::get() );
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==ZERO STRINGS==
+ aVal <<= OUString();
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("-");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("-0");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==TYPECLASS ENUM==
+ aVal <<= OUString("eNuM");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal <<= OUString("DOUBLE");
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ int e = 1;
+ aVal.setValue( &e, cppu::UnoType<TypeClass>::get());
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ aVal.setValue( &e, cppu::UnoType<FieldAccessMode>::get());
+ pTestBlocks[nElems++] = ConvBlock( aVal, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==SEQ of INT==
+ Sequence< sal_Int32 > aINT32Seq( 3 ), aINT32Seq2( 3 );
+ sal_Int32 * pINT32Seq = aINT32Seq.getArray();
+ pINT32Seq[0] = -32768;
+ pINT32Seq[1] = 0;
+ pINT32Seq[2] = 32767;
+ aVal <<= aINT32Seq;
+ pTestBlocks[nElems++] = ConvBlock( aVal, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ pINT32Seq = aINT32Seq2.getArray();
+ pINT32Seq[0] = -32768;
+ pINT32Seq[1] = -32769;
+ pINT32Seq[2] = 32767;
+ aVal <<= aINT32Seq2;
+ pTestBlocks[nElems++] = ConvBlock( aVal, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ // ==SEQ of ANY==
+ Sequence< Any > aAnySeq( 2 ), aAnySeq2( 2 );
+ Any * pAnySeq = aAnySeq.getArray();
+ pAnySeq[0] = makeAny( aINT32Seq );
+ pAnySeq[1] = makeAny( OUString("lala") );
+ aVal <<= aAnySeq;
+ pTestBlocks[nElems++] = ConvBlock( aVal, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ pAnySeq = aAnySeq2.getArray();
+ pAnySeq[0] <<= (sal_Int32)4711;
+ pAnySeq[1] <<= OUString("0815");
+ aVal <<= aAnySeq2;
+ pTestBlocks[nElems++] = ConvBlock( aVal, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 );
+ // st,do,fl,u3,i3,u1,i1,by,bo,ch,tc,si,sa
+ return nElems;
+}
+
+
+static void test_Conversion( const Reference< XMultiServiceFactory > & xMgr )
+{
+ printf( "test_Conversion(): start...\n" );
+
+ Reference< XTypeConverter > xConverter( xMgr->createInstance( "com.sun.star.script.Converter" ), UNO_QUERY );
+
+ ConvBlock * pTestBlocks = new ConvBlock[256];
+ sal_Int32 nPos = initBlocks( pTestBlocks );
+
+ s_xConverter = xConverter;
+ while (nPos--)
+ {
+ const ConvBlock& rBlock = pTestBlocks[nPos];
+ const Any & rVal = rBlock._value;
+
+ convertTo( cppu::UnoType<OUString>::get(), rVal, rBlock._toString );
+ convertTo( cppu::UnoType<float>::get(), rVal, rBlock._toFloat );
+ convertTo( cppu::UnoType<double>::get(), rVal, rBlock._toDouble );
+ convertTo( cppu::UnoType<sal_uInt32>::get(), rVal, rBlock._toUINT32 );
+ convertTo( cppu::UnoType<sal_Int32>::get(), rVal, rBlock._toINT32 );
+ convertTo( cppu::UnoType<cppu::UnoUnsignedShortType>::get(), rVal, rBlock._toUINT16 );
+ convertTo( cppu::UnoType<sal_Int16>::get(), rVal, rBlock._toINT16 );
+ convertTo( cppu::UnoType<sal_Int8>::get(), rVal, rBlock._toBYTE );
+ convertTo( cppu::UnoType<bool>::get(), rVal, rBlock._toBOOL );
+ convertTo( cppu::UnoType<cppu::UnoCharType>::get(), rVal, rBlock._toChar );
+ convertTo( cppu::UnoType<TypeClass>::get(), rVal, rBlock._toTypeClass );
+ convertTo( cppu::UnoType<Sequence< sal_Int16 >>::get(), rVal, rBlock._toSeqINT16 );
+ convertTo( cppu::UnoType<Sequence< Any >>::get(), rVal, rBlock._toSeqAny );
+
+ convertTo( cppu::UnoType<void>::get(), rVal, sal_True ); // anything converts to void
+ }
+ s_xConverter.clear();
+
+ delete [] pTestBlocks;
+
+ Any aRet;
+ aRet = xConverter->convertTo( Any( &xMgr, cppu::UnoType<XMultiServiceFactory>::get()),
+ cppu::UnoType<XServiceInfo>::get());
+ aRet = xConverter->convertTo( aRet, cppu::UnoType<XMultiServiceFactory>::get());
+ aRet = xConverter->convertTo( aRet, cppu::UnoType<XServiceInfo>::get());
+ aRet <<= SAL_CONST_INT64(0x7fffffffffffffff);
+ aRet = xConverter->convertTo( aRet, cppu::UnoType<sal_uInt64>::get());
+ OSL_ASSERT( *(const sal_uInt64 *)aRet.getValue() == SAL_CONST_UINT64(0x7fffffffffffffff) );
+ aRet <<= SAL_CONST_UINT64(0xffffffffffffffff);
+ aRet = xConverter->convertTo( aRet, cppu::UnoType<sal_uInt64>::get());
+ OSL_ASSERT( *(const sal_uInt64 *)aRet.getValue() == SAL_CONST_UINT64(0xffffffffffffffff) );
+ aRet <<= SAL_CONST_INT64(-1);
+ aRet = xConverter->convertTo( aRet, cppu::UnoType<sal_Int8>::get());
+ OSL_ASSERT( *(const sal_Int8 *)aRet.getValue() == (-1) );
+ printf( "test_Conversion(): end.\n" );
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ Reference< XMultiServiceFactory > xMgr( createRegistryServiceFactory( OUString("stoctest.rdb") ) );
+
+ try
+ {
+ Reference< XImplementationRegistration > xImplReg(
+ xMgr->createInstance("com.sun.star.registry.ImplementationRegistration"), UNO_QUERY );
+ OSL_ENSURE( xImplReg.is(), "### no impl reg!" );
+
+ OUString aLibName("stocservices.uno" SAL_DLLEXTENSION );
+ xImplReg->registerImplementation(
+ OUString("com.sun.star.loader.SharedLibrary"),
+ aLibName, Reference< XSimpleRegistry >() );
+
+ test_Conversion( xMgr );
+ }
+ catch (const Exception & rExc)
+ {
+ DBG_UNHANDLED_EXCEPTION("stoc", "### exception occurred: " << rExc );
+ }
+
+ Reference< XComponent >( xMgr, UNO_QUERY )->dispose();
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testcorefl.cxx b/stoc/test/testcorefl.cxx
new file mode 100644
index 0000000000..cd873670b7
--- /dev/null
+++ b/stoc/test/testcorefl.cxx
@@ -0,0 +1,377 @@
+/* -*- 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 <sal/main.h>
+#include <osl/diagnose.h>
+
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/weak.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <ModuleA/XInterface1.hpp>
+#include <ModuleC/XInterfaceA.hpp>
+#include <ModuleC/XInterfaceB.hpp>
+#include <ModuleC/ModuleC.hpp>
+
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/reflection/XIdlField2.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+
+#include <rtl/ustrbuf.hxx>
+
+#include <stdio.h>
+
+using namespace cppu;
+using namespace osl;
+using namespace ModuleA;
+using namespace ModuleB;
+using namespace ModuleC;
+using namespace ModuleA::ModuleB;
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::registry;
+using namespace css::reflection;
+using namespace css::container;
+
+
+class OInterfaceA : public WeakImplHelper< XInterfaceA >
+{
+public:
+
+ virtual void SAL_CALL methodA() throw (RuntimeException)
+ {}
+
+ virtual void SAL_CALL methodB(sal_Int16 /*aShort*/) throw (RuntimeException)
+ {}
+ virtual Sequence< StructB > SAL_CALL methodC(const StructC& /*aStructC*/, StructA& /*aStructA*/) throw (RuntimeException)
+ { return Sequence< StructB >(); }
+};
+
+
+static inline bool uik_equals( const Uik & rUik1, const Uik & rUik2 )
+{
+ return (rUik1.m_Data1 == rUik2.m_Data1 &&
+ rUik1.m_Data2 == rUik2.m_Data2 &&
+ rUik1.m_Data3 == rUik2.m_Data3 &&
+ rUik1.m_Data4 == rUik2.m_Data4 &&
+ rUik1.m_Data5 == rUik2.m_Data5);
+}
+
+static sal_Bool test_corefl( const Reference< XIdlReflection > & xRefl )
+{
+ Reference< XIdlClass > xClass;
+ Reference< XHierarchicalNameAccess > xHNameAccess( xRefl, UNO_QUERY );
+ OSL_ENSURE(xHNameAccess.is(), "### cannot get XHierarchicalNameAccess!" );
+
+ OSL_ENSURE(xRefl->forName("ModuleA.StructA")->getName() == "ModuleA.StructA", "test_RegCoreReflection(): error 2b");
+ OSL_ENSURE(xRefl->forName("ModuleA.ExceptionB")->getTypeClass() == TypeClass_EXCEPTION, "test_RegCoreReflection(): error 2c");
+ OSL_ENSURE(xRefl->forName("ModuleA.ModuleB.EnumA").is(), "test_RegCoreReflection(): error 2e");
+
+
+ OSL_ENSURE(*(const sal_Bool *)xHNameAccess->getByHierarchicalName(OUString("ModuleC.aConstBoolean")).getValue() == aConstBoolean, "test_RegCoreReflection(): error 4c");
+ OSL_ENSURE(*(const sal_Int8 *)xHNameAccess->getByHierarchicalName(OUString("ModuleC.aConstByte")).getValue() == aConstByte, "test_RegCoreReflection(): error 4e");
+ OSL_ENSURE(xHNameAccess->getByHierarchicalName(OUString("ModuleC.aConstShort")) == aConstShort, "test_RegCoreReflection(): error 4g");
+ OSL_ENSURE(xHNameAccess->getByHierarchicalName(OUString("ModuleC.aConstUShort")) == aConstUShort, "test_RegCoreReflection(): error 4i");
+ OSL_ENSURE(xHNameAccess->getByHierarchicalName(OUString("ModuleC.aConstLong")) == aConstLong, "test_RegCoreReflection(): error 4k");
+ OSL_ENSURE(xHNameAccess->getByHierarchicalName(OUString("ModuleC.aConstULong")) == aConstULong, "test_RegCoreReflection(): error 4m");
+
+ // Enums
+
+ xClass = xRefl->forName("ModuleA.ModuleB.EnumA");
+
+ OSL_ENSURE(xClass.is(), "test_RegCoreReflection(): error 5");
+
+ Sequence<Reference< XIdlField > > fields = xClass->getFields();
+
+ OSL_ENSURE(
+ (fields.getLength() == 3) &&
+ (fields.getArray()[0]->getName() == "VAL_1" ) &&
+ (*(EnumA*)fields.getArray()[0]->get(Any()).getValue() == EnumA_VAL_1) &&
+ (fields.getArray()[1]->getName() == "VAL_2" ) &&
+ (*(EnumA*)fields.getArray()[1]->get(Any()).getValue() == EnumA_VAL_2) &&
+ (fields.getArray()[2]->getName() == "VAL_3" ) &&
+ (*(EnumA*)fields.getArray()[2]->get(Any()).getValue() == EnumA_VAL_3),
+ "test_RegCoreReflection(): error 6");
+
+
+ // Interface
+
+ Reference< XIdlClass > xA = xRefl->forName("ModuleC.XInterfaceB");
+
+ xClass = xRefl->forName("ModuleC.XInterfaceB");
+
+ OSL_ENSURE(xClass == xA, "test_RegCoreReflection(): error 7");
+ OSL_ENSURE(xClass.is(), "test_RegCoreReflection(): error 7a");
+
+ typelib_TypeDescription * pTD = 0;
+ OUString aModuleName( "ModuleC.XInterfaceB" );
+ typelib_typedescription_getByName( &pTD, aModuleName.pData );
+ OSL_ENSURE( pTD, "### cannot get typedescription for ModuleC.XInterfaceB!" );
+
+ OSL_ENSURE( uik_equals( *(Uik *)&((typelib_InterfaceTypeDescription *)pTD)->aUik,
+ xClass->getUik() ),
+ "test_RegCoreReflection(): error 8" );
+ typelib_typedescription_release( pTD );
+
+ OSL_ENSURE(xClass->getSuperclasses().getLength() == 1, "test_RegCoreReflection(): error 9");
+ OSL_ENSURE(xClass->getSuperclasses().getArray()[0]->getName() == "ModuleC.XInterfaceA", "test_RegCoreReflection(): error 10");
+ OSL_ENSURE(xClass->getMethods().getLength() == 7, "test_RegCoreReflection(): error 11");
+ OSL_ENSURE(xA->getMethods().getLength() == 7, "test_RegCoreReflection(): error 11a");
+ OSL_ENSURE(xClass->getMethods().getArray()[3]->getName() == "methodA", "test_RegCoreReflection(): 12");
+ OSL_ENSURE(xClass->getMethods().getArray()[3]->getReturnType()->getTypeClass() == TypeClass_VOID, "test_RegCoreReflection(): error 13");
+ OSL_ENSURE(xClass->getMethods().getArray()[3]->getParameterTypes().getLength() == 0, "test_RegCoreReflection(): error 14");
+ OSL_ENSURE(xClass->getMethods().getArray()[3]->getExceptionTypes().getLength() == 0, "test_RegCoreReflection(): error 15");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getName() == "methodB", "test_RegCoreReflection(): error 16");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getMode() == MethodMode_ONEWAY, "test_RegCoreReflection(): error 16a");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getReturnType()->getTypeClass() == TypeClass_VOID, "test_RegCoreReflection(): error 16");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getParameterTypes().getLength() == 1, "test_RegCoreReflection(): error 17");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getParameterTypes().getArray()[0]->getTypeClass() == TypeClass_SHORT, "test_RegCoreReflection(): error 18");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getParameterInfos().getArray()[0].aName == "aShort", "test_RegCoreReflection(): error 18a");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getParameterInfos().getArray()[0].aType == xRefl->forName("short"), "test_RegCoreReflection(): error 18b");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getParameterInfos().getArray()[0].aMode == ParamMode_IN, "test_RegCoreReflection(): error 18c");
+ OSL_ENSURE(xClass->getMethods().getArray()[4]->getExceptionTypes().getLength() == 0, "test_RegCoreReflection(): error 19");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getName() == "methodC", "test_RegCoreReflection(): error 20");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getMode() == MethodMode_TWOWAY, "test_RegCoreReflection(): error 20a");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getReturnType()->getTypeClass() == TypeClass_SEQUENCE, "test_RegCoreReflection(): error 21");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getReturnType()->getComponentType()->getTypeClass() == TypeClass_STRUCT, "test_RegCoreReflection(): error 22");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getReturnType()->getComponentType()->getName() == "ModuleA.StructB", "test_RegCoreReflection(): error 23");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getParameterTypes().getLength() == 2, "test_RegCoreReflection(): error 24");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getParameterTypes().getArray()[0]->getTypeClass() == TypeClass_STRUCT, "test_RegCoreReflection(): error 25");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getParameterTypes().getArray()[0]->getName() == "ModuleA.StructC", "test_RegCoreReflection(): error 26");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getParameterTypes().getArray()[1]->getTypeClass() == TypeClass_STRUCT, "test_RegCoreReflection(): error 27");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getParameterTypes().getArray()[1]->getName() == "ModuleA.StructA", "test_RegCoreReflection(): error 28");
+ OSL_ENSURE(xClass->getMethods().getArray()[5]->getExceptionTypes().getLength() == 0, "test_RegCoreReflection(): error 29");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getName() == "methodD", "test_RegCoreReflection(): error 30");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getReturnType()->getTypeClass() == TypeClass_INTERFACE, "test_RegCoreReflection(): error 31");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getReturnType()->getName() == "ModuleC.XInterfaceA", "test_RegCoreReflection(): error 32");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getParameterTypes().getLength() == 1, "test_RegCoreReflection(): error 33");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getParameterTypes().getArray()[0]->getTypeClass() == TypeClass_ENUM, "test_RegCoreReflection(): error 34");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getParameterTypes().getArray()[0]->getName() == "ModuleA.ModuleB.EnumA", "test_RegCoreReflection(): error 35");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getLength() == 3, "test_RegCoreReflection(): error 36");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[0]->getTypeClass() == TypeClass_EXCEPTION, "test_RegCoreReflection(): error 37");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[0]->getName() == "ModuleA.ExceptionA", "test_RegCoreReflection(): error 38");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[1]->getTypeClass() == TypeClass_EXCEPTION, "test_RegCoreReflection(): error 38");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[1]->getName() == "ModuleA.ExceptionB", "test_RegCoreReflection(): error 39");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getTypeClass() == TypeClass_EXCEPTION, "test_RegCoreReflection(): error 40");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getName() == "ModuleA.ExceptionC", "test_RegCoreReflection(): error 41");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getLength() == 3, "test_RegCoreReflection(): error 42");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getArray()[0]->getType()->getTypeClass() == TypeClass_BOOLEAN, "test_RegCoreReflection(): error 43");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getArray()[0]->getType()->getName() == "boolean", "test_RegCoreReflection(): error 43a");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getArray()[1]->getType()->getTypeClass() == TypeClass_STRUCT, "test_RegCoreReflection(): error 44");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getArray()[1]->getType()->getName() == "ModuleA.StructC", "test_RegCoreReflection(): error 45");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getArray()[2]->getType()->getTypeClass() == TypeClass_INTERFACE, "test_RegCoreReflection(): error 46");
+ OSL_ENSURE(xClass->getMethods().getArray()[6]->getExceptionTypes().getArray()[2]->getFields().getArray()[2]->getType()->getName() == "ModuleA.XInterface1", "test_RegCoreReflection(): error 47");
+
+ // SequenceReflections
+
+ OSL_ENSURE(xRefl->forName("[]ModuleA.StructA")->getTypeClass() == TypeClass_SEQUENCE, "test_RegCoreReflection(): error 48");
+ OSL_ENSURE(xRefl->forName("[]ModuleA.StructA")->getComponentType().is(), "test_RegCoreReflection(): error 49");
+ OSL_ENSURE(xRefl->forName("[][]ModuleA.StructA")->getComponentType()->getComponentType()->getName() == "ModuleA.StructA", "test_RegCoreReflection(): error 50");
+ OSL_ENSURE(xRefl->forName("[]com.sun.star.uno.XInterface") == xRefl->forName("ModuleA.StructC")->getField(OUString("aInterfaceSeq"))->getType(), "test_RegCoreReflection(): error 51");
+
+ StructC aStructC;
+ aStructC.aLong = aConstLong;
+ aStructC.aShort = aConstShort;
+ aStructC.aFloat = aConstFloat;
+ aStructC.aDouble = aConstDouble;
+ aStructC.aInterfaceSeq = Sequence<Reference<XInterface > >();
+
+ Any aAny;
+
+ xRefl->forName("ModuleA.StructC")->getField(OUString("aInterfaceSeq"))->getType()->createObject(aAny);
+
+ OSL_ENSURE(aAny.getValueType() == cppu::UnoType<Sequence<Reference< XInterface > >>::get(), "test_RegCoreReflection(): error 51a");
+
+ Any aStructAny(&aStructC, cppu::UnoType<StructC>::get());
+
+ sal_Int32 nLong = aConstLong * 2;
+ aAny.setValue( &nLong, cppu::UnoType<sal_Int32>::get());
+
+ OSL_ENSURE(*(sal_Int32*)xRefl->forName("ModuleA.StructA")->getField(OUString( "aLong" ))->get(
+ Any(&aStructC, cppu::UnoType<StructC>::get())).getValue() == aConstLong, "test_RegCoreReflection(): error 52");
+ OSL_ENSURE(xRefl->forName("ModuleA.StructA")->getField(OUString( "aLong" ))->getAccessMode() == FieldAccessMode_READWRITE, "test_RegCoreReflection(): error 52a");
+ Reference< XIdlField2 > rField ( xRefl->forName("ModuleA.StructC")->getField(OUString( "aLong" )) , UNO_QUERY );
+ rField->set(aStructAny, aAny);
+ OSL_ENSURE(*(sal_Int32*)xRefl->forName("ModuleA.StructB")->getField(OUString( "aLong" ))->get(aStructAny).getValue() == *(sal_Int32*)aAny.getValue(), "test_RegCoreReflection(): error 53");
+
+ xRefl->forName("[]ModuleA.StructA")->createObject(aAny);
+
+ OSL_ENSURE( aAny.getValueTypeName() == "[]ModuleA.StructA", "test_RegCoreReflection(): error 54" );
+ xRefl->forName("[][]ModuleA.StructA")->createObject(aAny);
+
+ OSL_ENSURE( aAny.getValueTypeName() == "[][]ModuleA.StructA", "test_RegCoreReflection(): error 56" );
+
+ OSL_ENSURE(xRefl->forName("[][][]unsigned long")->getComponentType()->getComponentType()->getComponentType()->getTypeClass() == TypeClass_UNSIGNED_LONG, "test_RegCoreReflection(): error 62");
+
+ try
+ {
+ SAL_WARN( "stoc", "case 1" );
+ Any bla = xRefl->forName("ModuleA.StructC")->getField(OUString("aString"))->get(Any());
+ OSL_ENSURE(sal_False, "test_RegCoreReflection(): error 63");
+ return sal_False;
+ }
+ catch (IllegalArgumentException &)
+ {
+ }
+
+ try
+ {
+ SAL_WARN( "stoc", "case 2" );
+ Any blup;
+ blup <<= aStructC;
+ Any gulp;
+ rField.set( xRefl->forName("ModuleA.StructC")->getField(OUString("aString")) , UNO_QUERY);
+ rField->set( blup, gulp);
+ OSL_ENSURE(sal_False, "test_RegCoreReflection(): error 64");
+ return sal_False;
+ }
+ catch (IllegalArgumentException &)
+ {
+ }
+
+ try
+ {
+ SAL_WARN( "stoc", "case 3" );
+ Any gulp;
+ gulp <<= 3.14f;
+ Any blup;
+ blup <<= aStructC;
+ rField.set( xRefl->forName("ModuleA.StructC")->getField(OUString("aString")) , UNO_QUERY);
+ xRefl->forName("ModuleA.StructC")->getField(OUString("aString"))->set(blup, gulp);
+ OSL_ENSURE(sal_False, "test_RegCoreReflection(): error 65");
+ return sal_False;
+ }
+ catch (IllegalArgumentException &)
+ {
+ }
+
+ Any gulp;
+ gulp <<= OUString("Test");
+ Any blup;
+ blup <<= aStructC;
+ xRefl->forName("ModuleA.StructC")->getField(OUString("aString"))->set(blup, gulp);
+
+ Reference< XInterfaceA > xAI = new OInterfaceA();
+
+ try
+ {
+ Sequence< Any > params;
+ SAL_WARN( "stoc", "case 4" );
+
+ Any a;
+ a <<= xAI;
+ Any bla = xRefl->forName("ModuleC.XInterfaceA")->getMethod(OUString("methodC"))->invoke(a, params);
+ OSL_ENSURE(sal_False, "test_RegCoreReflection(): error 66");
+ return sal_False;
+ }
+ catch (IllegalArgumentException &)
+ {
+ }
+
+ StructA aStructA;
+
+ {
+ Sequence< Any > params(2);
+
+ params.getArray()[0].setValue(&aStructC, cppu::UnoType<StructC>::get());
+ params.getArray()[1].setValue(&aStructC, cppu::UnoType<StructC>::get());
+
+ Any a;
+ a <<= xAI;
+ Any bla = xRefl->forName("ModuleC.XInterfaceA")->getMethod(OUString("methodC"))->invoke(a, params);
+ }
+ try
+ {
+ Sequence< Any > params(2);
+
+ params.getArray()[0].setValue(&aStructA, cppu::UnoType<StructA>::get());
+ params.getArray()[1].setValue(&aStructA, cppu::UnoType<StructA>::get());
+
+ Any a;
+ a <<= xAI;
+ Any bla = xRefl->forName("ModuleC.XInterfaceA")->getMethod(OUString("methodC"))->invoke(a, params);
+ OSL_ENSURE(sal_False, "test_RegCoreReflection(): error 67");
+ return sal_False;
+ }
+ catch (IllegalArgumentException &)
+ {
+ }
+
+ Sequence< Any > params(2);
+
+ params.getArray()[0].setValue(&aStructC, cppu::UnoType<StructC>::get());
+ params.getArray()[1].setValue(&aStructA, cppu::UnoType<StructA>::get());
+
+ Any a;
+ a <<= xAI;
+ bool result = (xRefl->forName("ModuleC.XInterfaceA")->getMethod(OUString("methodC"))->invoke(a, params).getValueType()
+ == cppu::UnoType<Sequence<StructB>>::get()); (void)result;
+ OSL_ENSURE(result, "test_RegCoreReflection(): error 68");
+
+ return sal_True;
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ sal_Bool bSucc = sal_False;
+ try
+ {
+ OUString aLibName( "reflection.uno" SAL_DLLEXTENSION );
+
+ Reference< XMultiServiceFactory > xMgr(
+ createRegistryServiceFactory(
+ OUString( "stoctest.rdb" ) ) );
+ Reference< XComponentContext > xContext;
+ Reference< beans::XPropertySet > xProps( xMgr, UNO_QUERY );
+ OSL_ASSERT( xProps.is() );
+ xProps->getPropertyValue(
+ OUString( "DefaultContext" ) ) >>=
+ xContext;
+ OSL_ASSERT( xContext.is() );
+
+ Reference< XIdlReflection > xRefl;
+ xContext->getValueByName(
+ OUString( "/singletons/com.sun.star.reflection.theCoreReflection") )
+ >>= xRefl;
+ OSL_ENSURE(
+ xRefl.is(), "### CoreReflection singleton not accessible!?" );
+
+ bSucc = test_corefl( xRefl );
+
+ Reference< XComponent >( xContext, UNO_QUERY )->dispose();
+ }
+ catch (const Exception & rExc)
+ {
+ DBG_UNHANDLED_EXCEPTION("stoc", "### exception occurred: " << rExc );
+ }
+
+ printf( "testcorefl %s !\n", (bSucc ? "succeeded" : "failed") );
+ return (bSucc ? 0 : -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testcorefl.idl b/stoc/test/testcorefl.idl
new file mode 100644
index 0000000000..c345b725bb
--- /dev/null
+++ b/stoc/test/testcorefl.idl
@@ -0,0 +1,93 @@
+/* -*- 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 .
+ */
+
+module ModuleA
+{
+ exception ExceptionA
+ {
+ boolean aBoolean;
+ };
+
+ struct StructA
+ {
+ long aLong;
+ short aShort;
+ };
+
+ struct StructB : StructA
+ {
+ double aDouble;
+ float aFloat;
+ };
+
+ struct StructC : StructB
+ {
+ string aString;
+ sequence<com::sun::star::uno::XInterface> aInterfaceSeq;
+ };
+
+ exception ExceptionB : ExceptionA
+ {
+ StructC aStructC;
+ };
+
+ interface XInterface1 : com::sun::star::uno::XInterface
+ {
+ };
+
+ exception ExceptionC : ExceptionB
+ {
+ XInterface1 aInterface1;
+ };
+
+ module ModuleB
+ {
+ enum EnumA { VAL_1, VAL_2, VAL_3 = 17};
+ };
+
+};
+
+module ModuleC
+{
+ const boolean aConstBoolean = True;
+ const byte aConstByte = 0;
+ const short aConstShort = -1;
+ const unsigned short aConstUShort = 1;
+ const long aConstLong = -2;
+ const unsigned long aConstULong = 2;
+ const float aConstFloat = 3.14;
+ const double aConstDouble = 3.14e-10;
+
+
+ interface XInterfaceA : com::sun::star::uno::XInterface
+ {
+ void methodA();
+ void methodB([in] short aShort);
+ sequence<ModuleA::StructB> methodC([in] ModuleA::StructC aStructC, [inout] ModuleA::StructA aStructA);
+ };
+
+ interface XInterfaceB : XInterfaceA
+ {
+ [attribute] string aString;
+
+ XInterfaceA methodD([in] ModuleA::ModuleB::EnumA aEnumA) raises (ModuleA::ExceptionA, ModuleA::ExceptionB, ModuleA::ExceptionC);
+ };
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testiadapter.cxx b/stoc/test/testiadapter.cxx
new file mode 100644
index 0000000000..ca5afc4029
--- /dev/null
+++ b/stoc/test/testiadapter.cxx
@@ -0,0 +1,1051 @@
+/* -*- 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 <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/weak.hxx>
+
+#include <test/XLanguageBindingTest.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/script/XInvocationAdapterFactory.hpp>
+#include <com/sun/star/script/XInvocationAdapterFactory2.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cmath>
+
+
+using namespace test;
+using namespace cppu;
+using namespace osl;
+using namespace css::uno;
+using namespace css::script;
+using namespace css::beans;
+using namespace css::lang;
+using namespace css::reflection;
+using namespace css::registry;
+
+
+sal_Bool equals( const test::TestElement & rData1, const test::TestElement & rData2 )
+{
+ OSL_ENSURE( rData1.Bool == rData2.Bool, "### bool does not match!" );
+ OSL_ENSURE( rData1.Char == rData2.Char, "### char does not match!" );
+ OSL_ENSURE( rData1.Byte == rData2.Byte, "### byte does not match!" );
+ OSL_ENSURE( rData1.Short == rData2.Short, "### short does not match!" );
+ OSL_ENSURE( rData1.UShort == rData2.UShort, "### unsigned short does not match!" );
+ OSL_ENSURE( rData1.Long == rData2.Long, "### long does not match!" );
+ OSL_ENSURE( rData1.ULong == rData2.ULong, "### unsigned long does not match!" );
+ OSL_ENSURE( rData1.Hyper == rData2.Hyper, "### hyper does not match!" );
+ OSL_ENSURE( rData1.UHyper == rData2.UHyper, "### unsigned hyper does not match!" );
+ OSL_ENSURE( rData1.Float == rData2.Float, "### float does not match!" );
+ OSL_ENSURE( rData1.Double == rData2.Double, "### double does not match!" );
+ OSL_ENSURE( rData1.Enum == rData2.Enum, "### enum does not match!" );
+ OSL_ENSURE( rData1.String == rData2.String, "### string does not match!" );
+ OSL_ENSURE( rData1.Interface == rData2.Interface, "### interface does not match!" );
+ OSL_ENSURE( rData1.Any == rData2.Any, "### any does not match!" );
+
+ return (rData1.Bool == rData2.Bool &&
+ rData1.Char == rData2.Char &&
+ rData1.Byte == rData2.Byte &&
+ rData1.Short == rData2.Short &&
+ rData1.UShort == rData2.UShort &&
+ rData1.Long == rData2.Long &&
+ rData1.ULong == rData2.ULong &&
+ rData1.Hyper == rData2.Hyper &&
+ rData1.UHyper == rData2.UHyper &&
+ rData1.Float == rData2.Float &&
+ rData1.Double == rData2.Double &&
+ rData1.Enum == rData2.Enum &&
+ rData1.String == rData2.String &&
+ rData1.Interface == rData2.Interface &&
+ rData1.Any == rData2.Any);
+}
+
+sal_Bool equals( const test::TestData & rData1, const test::TestData & rData2 )
+{
+ sal_Int32 nLen;
+
+ if ((rData1.Sequence == rData2.Sequence) &&
+ equals( (const test::TestElement &)rData1, (const test::TestElement &)rData2 ) &&
+ (nLen = rData1.Sequence.getLength()) == rData2.Sequence.getLength())
+ {
+ // once again by hand sequence ==
+ const test::TestElement * pElements1 = rData1.Sequence.getConstArray();
+ const test::TestElement * pElements2 = rData2.Sequence.getConstArray();
+ for ( ; nLen--; )
+ {
+ if (! equals( pElements1[nLen], pElements2[nLen] ))
+ {
+ OSL_FAIL( "### sequence element did not match!" );
+ return sal_False;
+ }
+ }
+ return sal_True;
+ }
+ return sal_False;
+}
+
+void assign( test::TestElement & rData,
+ sal_Bool bBool, sal_Unicode cChar, sal_Int8 nByte,
+ sal_Int16 nShort, sal_uInt16 nUShort,
+ sal_Int32 nLong, sal_uInt32 nULong,
+ sal_Int64 nHyper, sal_uInt64 nUHyper,
+ float fFloat, double fDouble,
+ test::TestEnum eEnum, const OUString& rStr,
+ const css::uno::Reference< css::uno::XInterface >& xTest,
+ const css::uno::Any& rAny )
+{
+ rData.Bool = bBool;
+ rData.Char = cChar;
+ rData.Byte = nByte;
+ rData.Short = nShort;
+ rData.UShort = nUShort;
+ rData.Long = nLong;
+ rData.ULong = nULong;
+ rData.Hyper = nHyper;
+ rData.UHyper = nUHyper;
+ rData.Float = fFloat;
+ rData.Double = fDouble;
+ rData.Enum = eEnum;
+ rData.String = rStr;
+ rData.Interface = xTest;
+ rData.Any = rAny;
+}
+
+void assign( test::TestData & rData,
+ sal_Bool bBool, sal_Unicode cChar, sal_Int8 nByte,
+ sal_Int16 nShort, sal_uInt16 nUShort,
+ sal_Int32 nLong, sal_uInt32 nULong,
+ sal_Int64 nHyper, sal_uInt64 nUHyper,
+ float fFloat, double fDouble,
+ test::TestEnum eEnum, const OUString& rStr,
+ const css::uno::Reference< css::uno::XInterface >& xTest,
+ const css::uno::Any& rAny,
+ const css::uno::Sequence< test::TestElement >& rSequence )
+{
+ assign( (test::TestElement &)rData,
+ bBool, cChar, nByte, nShort, nUShort, nLong, nULong, nHyper, nUHyper, fFloat, fDouble,
+ eEnum, rStr, xTest, rAny );
+ rData.Sequence = rSequence;
+}
+
+
+class Test_Impl : public WeakImplHelper< XLanguageBindingTest >
+{
+ test::TestData _aData, _aStructData;
+
+public:
+ virtual ~Test_Impl()
+ { SAL_INFO("stoc", "> scalar Test_Impl dtor <" ); }
+
+ // XLBTestBase
+ virtual void SAL_CALL setValues( sal_Bool bBool, sal_Unicode cChar, sal_Int8 nByte,
+ sal_Int16 nShort, sal_uInt16 nUShort,
+ sal_Int32 nLong, sal_uInt32 nULong,
+ sal_Int64 nHyper, sal_uInt64 nUHyper,
+ float fFloat, double fDouble,
+ test::TestEnum eEnum, const OUString& rStr,
+ const css::uno::Reference< css::uno::XInterface >& xTest,
+ const css::uno::Any& rAny,
+ const css::uno::Sequence<test::TestElement >& rSequence,
+ const test::TestData& rStruct )
+ throw(css::uno::RuntimeException);
+
+ virtual test::TestData SAL_CALL setValues2( sal_Bool& bBool, sal_Unicode& cChar, sal_Int8& nByte,
+ sal_Int16& nShort, sal_uInt16& nUShort,
+ sal_Int32& nLong, sal_uInt32& nULong,
+ sal_Int64& nHyper, sal_uInt64& nUHyper,
+ float& fFloat, double& fDouble,
+ test::TestEnum& eEnum, OUString& rStr,
+ css::uno::Reference< css::uno::XInterface >& xTest,
+ css::uno::Any& rAny,
+ css::uno::Sequence<test::TestElement >& rSequence,
+ test::TestData& rStruct )
+ throw(css::uno::RuntimeException);
+
+ virtual test::TestData SAL_CALL getValues( sal_Bool& bBool, sal_Unicode& cChar, sal_Int8& nByte,
+ sal_Int16& nShort, sal_uInt16& nUShort,
+ sal_Int32& nLong, sal_uInt32& nULong,
+ sal_Int64& nHyper, sal_uInt64& nUHyper,
+ float& fFloat, double& fDouble,
+ test::TestEnum& eEnum, OUString& rStr,
+ css::uno::Reference< css::uno::XInterface >& xTest,
+ css::uno::Any& rAny,
+ css::uno::Sequence< test::TestElement >& rSequence,
+ test::TestData& rStruct )
+ throw(css::uno::RuntimeException);
+
+ virtual sal_Bool SAL_CALL getBool() throw(css::uno::RuntimeException)
+ { return _aData.Bool; }
+ virtual sal_Int8 SAL_CALL getByte() throw(css::uno::RuntimeException)
+ { return _aData.Byte; }
+ virtual sal_Unicode SAL_CALL getChar() throw(css::uno::RuntimeException)
+ { return _aData.Char; }
+ virtual sal_Int16 SAL_CALL getShort() throw(css::uno::RuntimeException)
+ { return _aData.Short; }
+ virtual sal_uInt16 SAL_CALL getUShort() throw(css::uno::RuntimeException)
+ { return _aData.UShort; }
+ virtual sal_Int32 SAL_CALL getLong() throw(css::uno::RuntimeException)
+ { return _aData.Long; }
+ virtual sal_uInt32 SAL_CALL getULong() throw(css::uno::RuntimeException)
+ { return _aData.ULong; }
+ virtual sal_Int64 SAL_CALL getHyper() throw(css::uno::RuntimeException)
+ { return _aData.Hyper; }
+ virtual sal_uInt64 SAL_CALL getUHyper() throw(css::uno::RuntimeException)
+ { return _aData.UHyper; }
+ virtual float SAL_CALL getFloat() throw(css::uno::RuntimeException)
+ { return _aData.Float; }
+ virtual double SAL_CALL getDouble() throw(css::uno::RuntimeException)
+ { return _aData.Double; }
+ virtual test::TestEnum SAL_CALL getEnum() throw(css::uno::RuntimeException)
+ { return _aData.Enum; }
+ virtual OUString SAL_CALL getString() throw(css::uno::RuntimeException)
+ { return _aData.String; }
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getInterface( ) throw(css::uno::RuntimeException)
+ { return _aData.Interface; }
+ virtual css::uno::Any SAL_CALL getAny() throw(css::uno::RuntimeException)
+ { return _aData.Any; }
+ virtual css::uno::Sequence< test::TestElement > SAL_CALL getSequence() throw(css::uno::RuntimeException)
+ { return _aData.Sequence; }
+ virtual test::TestData SAL_CALL getStruct() throw(css::uno::RuntimeException)
+ { return _aStructData; }
+
+ virtual void SAL_CALL setBool( sal_Bool _bool ) throw(css::uno::RuntimeException)
+ { _aData.Bool = _bool; }
+ virtual void SAL_CALL setByte( sal_Int8 _byte ) throw(css::uno::RuntimeException)
+ { _aData.Byte = _byte; }
+ virtual void SAL_CALL setChar( sal_Unicode _char ) throw(css::uno::RuntimeException)
+ { _aData.Char = _char; }
+ virtual void SAL_CALL setShort( sal_Int16 _short ) throw(css::uno::RuntimeException)
+ { _aData.Short = _short; }
+ virtual void SAL_CALL setUShort( sal_uInt16 _ushort ) throw(css::uno::RuntimeException)
+ { _aData.UShort = _ushort; }
+ virtual void SAL_CALL setLong( sal_Int32 _long ) throw(css::uno::RuntimeException)
+ { _aData.Long = _long; }
+ virtual void SAL_CALL setULong( sal_uInt32 _ulong ) throw(css::uno::RuntimeException)
+ { _aData.ULong = _ulong; }
+ virtual void SAL_CALL setHyper( sal_Int64 _hyper ) throw(css::uno::RuntimeException)
+ { _aData.Hyper = _hyper; }
+ virtual void SAL_CALL setUHyper( sal_uInt64 _uhyper ) throw(css::uno::RuntimeException)
+ { _aData.UHyper = _uhyper; }
+ virtual void SAL_CALL setFloat( float _float ) throw(css::uno::RuntimeException)
+ { _aData.Float = _float; }
+ virtual void SAL_CALL setDouble( double _double ) throw(css::uno::RuntimeException)
+ { _aData.Double = _double; }
+ virtual void SAL_CALL setEnum( test::TestEnum _enum ) throw(css::uno::RuntimeException)
+ { _aData.Enum = _enum; }
+ virtual void SAL_CALL setString( const OUString& _string ) throw(css::uno::RuntimeException)
+ { _aData.String = _string; }
+ virtual void SAL_CALL setInterface( const css::uno::Reference< css::uno::XInterface >& _interface ) throw(css::uno::RuntimeException)
+ { _aData.Interface = _interface; }
+ virtual void SAL_CALL setAny( const css::uno::Any& _any ) throw(css::uno::RuntimeException)
+ { _aData.Any = _any; }
+ virtual void SAL_CALL setSequence( const css::uno::Sequence<test::TestElement >& _sequence ) throw(css::uno::RuntimeException)
+ { _aData.Sequence = _sequence; }
+ virtual void SAL_CALL setStruct( const test::TestData& _struct ) throw(css::uno::RuntimeException)
+ { _aStructData = _struct; }
+
+ // XLanguageBindingTest
+ virtual test::TestData SAL_CALL raiseException( sal_Bool& bBool, sal_Unicode& cChar, sal_Int8& nByte, sal_Int16& nShort, sal_uInt16& nUShort, sal_Int32& nLong, sal_uInt32& nULong, sal_Int64& nHyper, sal_uInt64& nUHyper, float& fFloat, double& fDouble, test::TestEnum& eEnum, OUString& aString, css::uno::Reference< css::uno::XInterface >& xInterface, css::uno::Any& aAny, css::uno::Sequence<test::TestElement >& aSequence,test::TestData& aStruct )
+ throw(css::lang::IllegalArgumentException, css::uno::RuntimeException);
+
+ virtual sal_Int32 SAL_CALL getRuntimeException() throw(css::uno::RuntimeException);
+ virtual void SAL_CALL setRuntimeException( sal_Int32 _runtimeexception ) throw(css::uno::RuntimeException);
+};
+
+class XLB_Invocation : public WeakImplHelper< XInvocation >
+{
+ Reference< XLanguageBindingTest > _xLBT;
+
+public:
+ XLB_Invocation( const Reference< XMultiServiceFactory > & /*xMgr*/,
+ const Reference< XLanguageBindingTest > & xLBT )
+ : _xLBT( xLBT )
+ {}
+
+ // XInvocation
+ virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection() throw(css::uno::RuntimeException)
+ { return Reference< XIntrospectionAccess >(); }
+ virtual Any SAL_CALL invoke( const OUString & rFunctionName,
+ const Sequence< Any > & rParams,
+ Sequence< sal_Int16 > & rOutParamIndex,
+ Sequence< Any > & rOutParam ) throw(css::lang::IllegalArgumentException, css::script::CannotConvertException, css::reflection::InvocationTargetException, css::uno::RuntimeException);
+ virtual void SAL_CALL setValue( const OUString & rPropertyName, const Any & rValue ) throw(css::beans::UnknownPropertyException, css::script::CannotConvertException, css::reflection::InvocationTargetException, css::uno::RuntimeException);
+ virtual Any SAL_CALL getValue( const OUString & rPropertyName ) throw(css::beans::UnknownPropertyException, css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL hasMethod( const OUString & rName ) throw(css::uno::RuntimeException);
+ virtual sal_Bool SAL_CALL hasProperty( const OUString & rName ) throw(css::uno::RuntimeException);
+};
+
+Any XLB_Invocation::invoke( const OUString & rFunctionName,
+ const Sequence< Any > & rParams,
+ Sequence< sal_Int16 > & rOutParamIndex,
+ Sequence< Any > & rOutParam )
+ throw(css::lang::IllegalArgumentException, css::script::CannotConvertException, css::reflection::InvocationTargetException, css::uno::RuntimeException)
+{
+ bool bImplementedMethod = true;
+
+ Any aRet;
+
+ OSL_ASSERT( rOutParam.getLength() == 0 );
+ OSL_ASSERT( rOutParamIndex.getLength() == 0 );
+
+ try
+ {
+ sal_Bool aBool;
+ sal_Unicode aChar;
+ sal_Int8 nByte;
+ sal_Int16 nShort;
+ sal_uInt16 nUShort;
+ sal_Int32 nLong;
+ sal_uInt32 nULong;
+ sal_Int64 nHyper;
+ sal_uInt64 nUHyper;
+ float fFloat = 0.0;
+ double fDouble = 0.0;
+ TestEnum eEnum;
+ OUString aString;
+ Reference< XInterface > xInterface;
+ Any aAny;
+ Sequence< TestElement > aSeq;
+ TestData aData;
+
+ if ( rFunctionName == "setValues" )
+ {
+ OSL_ASSERT( rParams.getLength() == 17 );
+ aBool = *(sal_Bool *)rParams[0].getValue();
+ aChar = *(sal_Unicode *)rParams[1].getValue();
+ rParams[2] >>= nByte;
+ rParams[3] >>= nShort;
+ rParams[4] >>= nUShort;
+ rParams[5] >>= nLong;
+ rParams[6] >>= nULong;
+ rParams[7] >>= nHyper;
+ rParams[8] >>= nUHyper;
+ rParams[9] >>= fFloat;
+ rParams[10] >>= fDouble;
+ rParams[11] >>= eEnum;
+ rParams[12] >>= aString;
+ rParams[13] >>= xInterface;
+ rParams[14] >>= aAny;
+ rParams[15] >>= aSeq;
+ rParams[16] >>= aData;
+
+ _xLBT->setValues( aBool, aChar, nByte, nShort, nUShort, nLong, nULong,
+ nHyper, nUHyper, fFloat, fDouble, eEnum, aString, xInterface,
+ aAny, aSeq, aData );
+
+ rOutParamIndex.realloc( 0 );
+ rOutParam.realloc( 0 );
+ }
+ else if ( rFunctionName == "setValues2" )
+ {
+ aBool = *(sal_Bool *)rParams[0].getValue();
+ aChar = *(sal_Unicode *)rParams[1].getValue();
+ rParams[2] >>= nByte;
+ rParams[3] >>= nShort;
+ rParams[4] >>= nUShort;
+ rParams[5] >>= nLong;
+ rParams[6] >>= nULong;
+ rParams[7] >>= nHyper;
+ rParams[8] >>= nUHyper;
+ rParams[9] >>= fFloat;
+ rParams[10] >>= fDouble;
+ rParams[11] >>= eEnum;
+ rParams[12] >>= aString;
+ rParams[13] >>= xInterface;
+ rParams[14] >>= aAny;
+ rParams[15] >>= aSeq;
+ rParams[16] >>= aData;
+
+ aRet <<= _xLBT->setValues2( aBool, aChar, nByte, nShort, nUShort, nLong, nULong,
+ nHyper, nUHyper, fFloat, fDouble, eEnum, aString, xInterface,
+ aAny, aSeq, aData );
+
+ rOutParamIndex.realloc( 17 );
+ rOutParamIndex[0] = 0;
+ rOutParamIndex[1] = 1;
+ rOutParamIndex[2] = 2;
+ rOutParamIndex[3] = 3;
+ rOutParamIndex[4] = 4;
+ rOutParamIndex[5] = 5;
+ rOutParamIndex[6] = 6;
+ rOutParamIndex[7] = 7;
+ rOutParamIndex[8] = 8;
+ rOutParamIndex[9] = 9;
+ rOutParamIndex[10] = 10;
+ rOutParamIndex[11] = 11;
+ rOutParamIndex[12] = 12;
+ rOutParamIndex[13] = 13;
+ rOutParamIndex[14] = 14;
+ rOutParamIndex[15] = 15;
+ rOutParamIndex[16] = 16;
+
+ rOutParam.realloc( 17 );
+ rOutParam[0].setValue( &aBool, cppu::UnoType<bool>::get() );
+ rOutParam[1].setValue( &aChar, cppu::UnoType<cppu::UnoCharType>::get() );
+ rOutParam[2] <<= nByte;
+ rOutParam[3] <<= nShort;
+ rOutParam[4] <<= nUShort;
+ rOutParam[5] <<= nLong;
+ rOutParam[6] <<= nULong;
+ rOutParam[7] <<= nHyper;
+ rOutParam[8] <<= nUHyper;
+ rOutParam[9] <<= fFloat;
+ rOutParam[10] <<= fDouble;
+ rOutParam[11] <<= eEnum;
+ rOutParam[12] <<= aString;
+ rOutParam[13] <<= xInterface;
+ rOutParam[14] <<= aAny;
+ rOutParam[15] <<= aSeq;
+ rOutParam[16] <<= aData;
+ }
+ else if ( rFunctionName == "getValues" )
+ {
+ aRet <<= _xLBT->getValues( aBool, aChar, nByte, nShort, nUShort, nLong, nULong,
+ nHyper, nUHyper, fFloat, fDouble, eEnum, aString, xInterface,
+ aAny, aSeq, aData );
+
+ rOutParamIndex.realloc( 17 );
+ rOutParamIndex[0] = 0;
+ rOutParamIndex[1] = 1;
+ rOutParamIndex[2] = 2;
+ rOutParamIndex[3] = 3;
+ rOutParamIndex[4] = 4;
+ rOutParamIndex[5] = 5;
+ rOutParamIndex[6] = 6;
+ rOutParamIndex[7] = 7;
+ rOutParamIndex[8] = 8;
+ rOutParamIndex[9] = 9;
+ rOutParamIndex[10] = 10;
+ rOutParamIndex[11] = 11;
+ rOutParamIndex[12] = 12;
+ rOutParamIndex[13] = 13;
+ rOutParamIndex[14] = 14;
+ rOutParamIndex[15] = 15;
+ rOutParamIndex[16] = 16;
+
+ rOutParam.realloc( 17 );
+ rOutParam[0].setValue( &aBool, cppu::UnoType<bool>::get() );
+ rOutParam[1].setValue( &aChar, cppu::UnoType<cppu::UnoCharType>::get() );
+ rOutParam[2] <<= nByte;
+ rOutParam[3] <<= nShort;
+ rOutParam[4] <<= nUShort;
+ rOutParam[5] <<= nLong;
+ rOutParam[6] <<= nULong;
+ rOutParam[7] <<= nHyper;
+ rOutParam[8] <<= nUHyper;
+ rOutParam[9] <<= fFloat;
+ rOutParam[10] <<= fDouble;
+ rOutParam[11] <<= eEnum;
+ rOutParam[12] <<= aString;
+ rOutParam[13] <<= xInterface;
+ rOutParam[14] <<= aAny;
+ rOutParam[15] <<= aSeq;
+ rOutParam[16] <<= aData;
+ }
+ else if ( rFunctionName == "raiseException" )
+ {
+ aRet <<= _xLBT->raiseException( aBool, aChar, nByte, nShort, nUShort, nLong, nULong,
+ nHyper, nUHyper, fFloat, fDouble, eEnum, aString, xInterface,
+ aAny, aSeq, aData );
+
+ rOutParamIndex.realloc( 17 );
+ rOutParamIndex[0] = 0;
+ rOutParamIndex[1] = 1;
+ rOutParamIndex[2] = 2;
+ rOutParamIndex[3] = 3;
+ rOutParamIndex[4] = 4;
+ rOutParamIndex[5] = 5;
+ rOutParamIndex[6] = 6;
+ rOutParamIndex[7] = 7;
+ rOutParamIndex[8] = 8;
+ rOutParamIndex[9] = 9;
+ rOutParamIndex[10] = 10;
+ rOutParamIndex[11] = 11;
+ rOutParamIndex[12] = 12;
+ rOutParamIndex[13] = 13;
+ rOutParamIndex[14] = 14;
+ rOutParamIndex[15] = 15;
+ rOutParamIndex[16] = 16;
+
+ rOutParam.realloc( 17 );
+ rOutParam[0].setValue( &aBool, cppu::UnoType<bool>::get() );
+ rOutParam[1].setValue( &aChar, cppu::UnoType<cppu::UnoCharType>::get() );
+ rOutParam[2] <<= nByte;
+ rOutParam[3] <<= nShort;
+ rOutParam[4] <<= nUShort;
+ rOutParam[5] <<= nLong;
+ rOutParam[6] <<= nULong;
+ rOutParam[7] <<= nHyper;
+ rOutParam[8] <<= nUHyper;
+ rOutParam[9] <<= fFloat;
+ rOutParam[10] <<= fDouble;
+ rOutParam[11] <<= eEnum;
+ rOutParam[12] <<= aString;
+ rOutParam[13] <<= xInterface;
+ rOutParam[14] <<= aAny;
+ rOutParam[15] <<= aSeq;
+ rOutParam[16] <<= aData;
+ }
+ else
+ {
+ bImplementedMethod = false;
+ }
+ }
+ catch (const IllegalArgumentException & rExc)
+ {
+ // thrown by raiseException() call
+ InvocationTargetException aExc;
+ aExc.TargetException <<= rExc;
+ throw aExc;
+ }
+ catch (Exception &)
+ {
+ OSL_FAIL( "### unexpected exception caught!" );
+ throw;
+ }
+
+ if (! bImplementedMethod)
+ {
+ throw IllegalArgumentException(
+ OUString( "not an implemented method!" ),
+ (OWeakObject *)this, 0 );
+ }
+
+ return aRet;
+}
+
+void XLB_Invocation::setValue( const OUString & rName, const Any & rValue )
+ throw(css::beans::UnknownPropertyException, css::script::CannotConvertException, css::reflection::InvocationTargetException, css::uno::RuntimeException)
+{
+ if ( rName == "Bool" )
+ _xLBT->setBool( *(const sal_Bool *)rValue.getValue() );
+ else if ( rName == "Byte" )
+ _xLBT->setByte( *(const sal_Int8 *)rValue.getValue() );
+ else if ( rName == "Char" )
+ _xLBT->setChar( *(const sal_Unicode *)rValue.getValue() );
+ else if ( rName == "Short" )
+ _xLBT->setShort( *(const sal_Int16 *)rValue.getValue() );
+ else if ( rName == "UShort" )
+ _xLBT->setUShort( *(const sal_uInt16 *)rValue.getValue() );
+ else if ( rName == "Long" )
+ _xLBT->setLong( *(const sal_Int32 *)rValue.getValue() );
+ else if ( rName == "ULong" )
+ _xLBT->setULong( *(const sal_uInt32 *)rValue.getValue() );
+ else if ( rName == "Hyper" )
+ _xLBT->setHyper( *(const sal_Int64 *)rValue.getValue() );
+ else if ( rName == "UHyper" )
+ _xLBT->setUHyper( *(const sal_uInt64 *)rValue.getValue() );
+ else if ( rName == "Float" )
+ _xLBT->setFloat( *(const float *)rValue.getValue() );
+ else if ( rName == "Double" )
+ _xLBT->setDouble( *(const double *)rValue.getValue() );
+ else if ( rName == "Enum" )
+ _xLBT->setEnum( *(const TestEnum *)rValue.getValue() );
+ else if ( rName == "String" )
+ _xLBT->setString( *(const OUString *)rValue.getValue() );
+ else if ( rName == "Interface" )
+ _xLBT->setInterface( *(const Reference< XInterface > *)rValue.getValue() );
+ else if ( rName == "Any" )
+ _xLBT->setAny( rValue );
+ else if ( rName == "Sequence" )
+ _xLBT->setSequence( *(const Sequence< TestElement > *)rValue.getValue() );
+ else if ( rName == "Struct" )
+ _xLBT->setStruct( *(const TestData *)rValue.getValue() );
+ else if ( rName == "RuntimeException" )
+ _xLBT->setRuntimeException( *(const sal_Int32 *)rValue.getValue() );
+}
+
+Any XLB_Invocation::getValue( const OUString & rName )
+ throw(css::beans::UnknownPropertyException, css::uno::RuntimeException)
+{
+ Any aRet;
+ if ( rName == "Bool" )
+ {
+ sal_Bool aBool = _xLBT->getBool();
+ aRet.setValue( &aBool, cppu::UnoType<bool>::get() );
+ }
+ else if ( rName == "Byte" )
+ aRet <<= _xLBT->getByte();
+ else if ( rName == "Char" )
+ {
+ sal_Unicode aChar = _xLBT->getChar();
+ aRet.setValue( &aChar, cppu::UnoType<cppu::UnoCharType>::get() );
+ }
+ else if ( rName == "Short" )
+ aRet <<= _xLBT->getShort();
+ else if ( rName == "UShort" )
+ aRet <<= _xLBT->getUShort();
+ else if ( rName == "Long" )
+ aRet <<= _xLBT->getLong();
+ else if ( rName == "ULong" )
+ aRet <<= _xLBT->getULong();
+ else if ( rName == "Hyper" )
+ aRet <<= _xLBT->getHyper();
+ else if ( rName == "UHyper" )
+ aRet <<= _xLBT->getUHyper();
+ else if ( rName == "Float" )
+ aRet <<= _xLBT->getFloat();
+ else if ( rName == "Double" )
+ aRet <<= _xLBT->getDouble();
+ else if ( rName == "Enum" )
+ aRet <<= _xLBT->getEnum();
+ else if ( rName == "String" )
+ aRet <<= _xLBT->getString();
+ else if ( rName == "Interface" )
+ aRet <<= _xLBT->getInterface();
+ else if ( rName == "Any" )
+ aRet <<= _xLBT->getAny();
+ else if ( rName == "Sequence" )
+ aRet <<= _xLBT->getSequence();
+ else if ( rName == "Struct" )
+ aRet <<= _xLBT->getStruct();
+ else if ( rName == "RuntimeException" )
+ aRet <<= _xLBT->getRuntimeException();
+ return aRet;
+}
+
+sal_Bool XLB_Invocation::hasMethod( const OUString & rName )
+ throw(css::uno::RuntimeException)
+{
+ return (rName == "raiseException" ||
+ rName == "getValues" ||
+ rName == "setValues2" ||
+ rName == "setValues" ||
+ rName == "acquire" ||
+ rName == "release" ||
+ rName == "queryInterface" );
+}
+
+sal_Bool XLB_Invocation::hasProperty( const OUString & rName )
+ throw(css::uno::RuntimeException)
+{
+ return (rName == "Bool" ||
+ rName == "Byte" ||
+ rName == "Char" ||
+ rName == "Short" ||
+ rName == "UShort" ||
+ rName == "Long" ||
+ rName == "ULong" ||
+ rName == "Hyper" ||
+ rName == "UHyper" ||
+ rName == "Float" ||
+ rName == "Double" ||
+ rName == "Enum" ||
+ rName == "String" ||
+ rName == "Interface" ||
+ rName == "Any" ||
+ rName == "Sequence" ||
+ rName == "Struct" ||
+ rName == "RuntimeException" );
+}
+
+
+void Test_Impl::setValues( sal_Bool bBool, sal_Unicode cChar, sal_Int8 nByte,
+ sal_Int16 nShort, sal_uInt16 nUShort,
+ sal_Int32 nLong, sal_uInt32 nULong,
+ sal_Int64 nHyper, sal_uInt64 nUHyper,
+ float fFloat, double fDouble,
+ test::TestEnum eEnum, const OUString& rStr,
+ const css::uno::Reference< css::uno::XInterface >& xTest,
+ const css::uno::Any& rAny,
+ const css::uno::Sequence<test::TestElement >& rSequence,
+ const test::TestData& rStruct )
+ throw(css::uno::RuntimeException)
+{
+ assign( _aData,
+ bBool, cChar, nByte, nShort, nUShort, nLong, nULong, nHyper, nUHyper, fFloat, fDouble,
+ eEnum, rStr, xTest, rAny, rSequence );
+ _aStructData = rStruct;
+}
+
+test::TestData Test_Impl::setValues2( sal_Bool& bBool, sal_Unicode& cChar, sal_Int8& nByte,
+ sal_Int16& nShort, sal_uInt16& nUShort,
+ sal_Int32& nLong, sal_uInt32& nULong,
+ sal_Int64& nHyper, sal_uInt64& nUHyper,
+ float& fFloat, double& fDouble,
+ test::TestEnum& eEnum, OUString& rStr,
+ css::uno::Reference< css::uno::XInterface >& xTest,
+ css::uno::Any& rAny,
+ css::uno::Sequence<test::TestElement >& rSequence,
+ test::TestData& rStruct )
+ throw(css::uno::RuntimeException)
+{
+ assign( _aData,
+ bBool, cChar, nByte, nShort, nUShort, nLong, nULong, nHyper, nUHyper, fFloat, fDouble,
+ eEnum, rStr, xTest, rAny, rSequence );
+ _aStructData = rStruct;
+ return _aStructData;
+}
+
+test::TestData Test_Impl::getValues( sal_Bool& bBool, sal_Unicode& cChar, sal_Int8& nByte,
+ sal_Int16& nShort, sal_uInt16& nUShort,
+ sal_Int32& nLong, sal_uInt32& nULong,
+ sal_Int64& nHyper, sal_uInt64& nUHyper,
+ float& fFloat, double& fDouble,
+ test::TestEnum& eEnum, OUString& rStr,
+ css::uno::Reference< css::uno::XInterface >& xTest,
+ css::uno::Any& rAny,
+ css::uno::Sequence<test::TestElement >& rSequence,
+ test::TestData& rStruct )
+ throw(css::uno::RuntimeException)
+{
+ bBool = _aData.Bool;
+ cChar = _aData.Char;
+ nByte = _aData.Byte;
+ nShort = _aData.Short;
+ nUShort = _aData.UShort;
+ nLong = _aData.Long;
+ nULong = _aData.ULong;
+ nHyper = _aData.Hyper;
+ nUHyper = _aData.UHyper;
+ fFloat = _aData.Float;
+ fDouble = _aData.Double;
+ eEnum = _aData.Enum;
+ rStr = _aData.String;
+ xTest = _aData.Interface;
+ rAny = _aData.Any;
+ rSequence = _aData.Sequence;
+ rStruct = _aStructData;
+ return _aStructData;
+}
+
+
+sal_Bool performTest( const Reference<XLanguageBindingTest > & xLBT )
+{
+ OSL_ENSURE( xLBT.is(), "### no test interface!" );
+ if (xLBT.is())
+ {
+ // this data is never ever granted access to by calls other than equals(), assign()!
+ test::TestData aData; // test against this data
+
+ Reference<XInterface > xI( *new OWeakObject() );
+
+ assign( (test::TestElement &)aData,
+ sal_True, '@', 17, 0x1234, 0xfedc, 0x12345678, 0xfedcba98,
+ SAL_CONST_INT64(0x123456789abcdef0),
+ SAL_CONST_UINT64(0xfedcba9876543210),
+ (float)17.03125, M_PI, TestEnum_LOLA, OUString("dumdidum"), xI,
+ Any( &xI, cppu::UnoType<XInterface>::get()) );
+
+ OSL_ENSURE( aData.Any == xI, "### unexpected any!" );
+ OSL_ENSURE( !(aData.Any != xI), "### unexpected any!" );
+
+ aData.Sequence = Sequence<test::TestElement >( (const test::TestElement *)&aData, 1 );
+ // aData complete
+
+
+ // this is a manually copy of aData for first setting...
+ test::TestData aSetData;
+
+ assign( (test::TestElement &)aSetData,
+ aData.Bool, aData.Char, aData.Byte, aData.Short, aData.UShort,
+ aData.Long, aData.ULong, aData.Hyper, aData.UHyper, aData.Float, aData.Double,
+ aData.Enum, aData.String, xI,
+ Any( &xI, cppu::UnoType<XInterface>::get()) );
+
+ aSetData.Sequence = Sequence<test::TestElement >( (const test::TestElement *)&aSetData, 1 );
+
+ xLBT->setValues(
+ aSetData.Bool, aSetData.Char, aSetData.Byte, aSetData.Short, aSetData.UShort,
+ aSetData.Long, aSetData.ULong, aSetData.Hyper, aSetData.UHyper, aSetData.Float, aSetData.Double,
+ aSetData.Enum, aSetData.String, aSetData.Interface, aSetData.Any, aSetData.Sequence, aSetData );
+
+ {
+ test::TestData aRet, aRet2;
+ xLBT->getValues(
+ aRet.Bool, aRet.Char, aRet.Byte, aRet.Short, aRet.UShort,
+ aRet.Long, aRet.ULong, aRet.Hyper, aRet.UHyper, aRet.Float, aRet.Double,
+ aRet.Enum, aRet.String, aRet.Interface, aRet.Any, aRet.Sequence, aRet2 );
+
+ OSL_ASSERT( equals( aData, aRet ) && equals( aData, aRet2 ) );
+
+ // set last retrieved values
+ test::TestData aSV2ret = xLBT->setValues2(
+ aRet.Bool, aRet.Char, aRet.Byte, aRet.Short, aRet.UShort,
+ aRet.Long, aRet.ULong, aRet.Hyper, aRet.UHyper, aRet.Float, aRet.Double,
+ aRet.Enum, aRet.String, aRet.Interface, aRet.Any, aRet.Sequence, aRet2 );
+
+ OSL_ASSERT( equals( aData, aSV2ret ) && equals( aData, aRet2 ) );
+ }
+ {
+ test::TestData aRet, aRet2;
+ test::TestData aGVret = xLBT->getValues(
+ aRet.Bool, aRet.Char, aRet.Byte, aRet.Short, aRet.UShort,
+ aRet.Long, aRet.ULong, aRet.Hyper, aRet.UHyper, aRet.Float, aRet.Double,
+ aRet.Enum, aRet.String, aRet.Interface, aRet.Any, aRet.Sequence, aRet2 );
+
+ OSL_ASSERT( equals( aData, aRet ) && equals( aData, aRet2 ) && equals( aData, aGVret ) );
+
+ // set last retrieved values
+ xLBT->setBool( aRet.Bool );
+ xLBT->setChar( aRet.Char );
+ xLBT->setByte( aRet.Byte );
+ xLBT->setShort( aRet.Short );
+ xLBT->setUShort( aRet.UShort );
+ xLBT->setLong( aRet.Long );
+ xLBT->setULong( aRet.ULong );
+ xLBT->setHyper( aRet.Hyper );
+ xLBT->setUHyper( aRet.UHyper );
+ xLBT->setFloat( aRet.Float );
+ xLBT->setDouble( aRet.Double );
+ xLBT->setEnum( aRet.Enum );
+ xLBT->setString( aRet.String );
+ xLBT->setInterface( aRet.Interface );
+ xLBT->setAny( aRet.Any );
+ xLBT->setSequence( aRet.Sequence );
+ xLBT->setStruct( aRet2 );
+ }
+ {
+ test::TestData aRet, aRet2;
+ aRet.Hyper = xLBT->getHyper();
+ aRet.UHyper = xLBT->getUHyper();
+ aRet.Float = xLBT->getFloat();
+ aRet.Double = xLBT->getDouble();
+ aRet.Byte = xLBT->getByte();
+ aRet.Char = xLBT->getChar();
+ aRet.Bool = xLBT->getBool();
+ aRet.Short = xLBT->getShort();
+ aRet.UShort = xLBT->getUShort();
+ aRet.Long = xLBT->getLong();
+ aRet.ULong = xLBT->getULong();
+ aRet.Enum = xLBT->getEnum();
+ aRet.String = xLBT->getString();
+ aRet.Interface = xLBT->getInterface();
+ aRet.Any = xLBT->getAny();
+ aRet.Sequence = xLBT->getSequence();
+ aRet2 = xLBT->getStruct();
+
+ return (equals( aData, aRet ) && equals( aData, aRet2 ));
+ }
+ }
+ return sal_False;
+}
+
+
+test::TestData Test_Impl::raiseException( sal_Bool& /*bBool*/, sal_Unicode& /*cChar*/, sal_Int8& /*nByte*/, sal_Int16& /*nShort*/, sal_uInt16& /*nUShort*/, sal_Int32& /*nLong*/, sal_uInt32& /*nULong*/, sal_Int64& /*nHyper*/, sal_uInt64& /*nUHyper*/, float& /*fFloat*/, double& /*fDouble*/, test::TestEnum& /*eEnum*/, OUString& /*aString*/, css::uno::Reference< css::uno::XInterface >& /*xInterface*/, css::uno::Any& /*aAny*/, css::uno::Sequence< test::TestElement >& /*aSequence*/, test::TestData& /*aStruct*/ )
+ throw(css::lang::IllegalArgumentException, css::uno::RuntimeException)
+{
+ IllegalArgumentException aExc;
+ aExc.ArgumentPosition = 5;
+ aExc.Message = "dum dum dum I dance around the circle...";
+ aExc.Context = *this;
+ throw aExc;
+}
+
+sal_Int32 Test_Impl::getRuntimeException() throw(css::uno::RuntimeException)
+{
+ RuntimeException aExc;
+ aExc.Message = "dum dum dum I dance around the circle...";
+ aExc.Context = *this;
+ throw aExc;
+}
+
+void Test_Impl::setRuntimeException( sal_Int32 /*_runtimeexception*/ ) throw(css::uno::RuntimeException)
+{
+ RuntimeException aExc;
+ aExc.Message = "dum dum dum I dance around the circle...";
+ aExc.Context = *this;
+ throw aExc;
+}
+
+
+sal_Bool raiseException( const Reference<XLanguageBindingTest > & xLBT )
+{
+ try
+ {
+ try
+ {
+ try
+ {
+ test::TestData aRet, aRet2;
+ xLBT->raiseException(
+ aRet.Bool, aRet.Char, aRet.Byte, aRet.Short, aRet.UShort,
+ aRet.Long, aRet.ULong, aRet.Hyper, aRet.UHyper, aRet.Float, aRet.Double,
+ aRet.Enum, aRet.String, aRet.Interface, aRet.Any, aRet.Sequence, aRet2 );
+ return sal_False;
+ }
+ catch (const IllegalArgumentException &aExc)
+ {
+ OSL_ENSURE( aExc.ArgumentPosition == 5 &&
+ aExc.Message.startsWith("dum dum dum I dance around the circle..."),
+ "### unexpected exception content!" );
+
+ Reference<XLanguageBindingTest > xLBT2(
+ Reference<XLanguageBindingTest >::query( aExc.Context ) );
+
+ OSL_ENSURE( xLBT2.is(), "### unexpected source of exception!" );
+ if (xLBT2.is())
+ xLBT2->getRuntimeException();
+ else
+ return sal_False;
+ }
+ }
+ catch (const RuntimeException & rExc)
+ {
+ OSL_ENSURE( rExc.Message.startsWith("dum dum dum I dance around the circle..."),
+ "### unexpected exception content!" );
+
+ Reference<XLanguageBindingTest > xLBT2(
+ Reference<XLanguageBindingTest >::query( rExc.Context ) );
+
+ OSL_ENSURE( xLBT2.is(), "### unexpected source of exception!" );
+ if (xLBT2.is())
+ xLBT2->setRuntimeException( 0xcafebabe );
+ else
+ return sal_False;
+ }
+ }
+ catch (const Exception & aExc)
+ {
+ OSL_ENSURE( aExc.Message.startsWith("dum dum dum I dance around the circle..."),
+ "### unexpected exception content!" );
+ return aExc.Message.startsWith("dum dum dum I dance around the circle...");
+ }
+ return sal_False;
+}
+
+
+static sal_Bool test_adapter( const Reference< XMultiServiceFactory > & xMgr )
+{
+ Reference< XInvocationAdapterFactory > xAdapFac(
+ xMgr->createInstance("com.sun.star.script.InvocationAdapterFactory"), UNO_QUERY );
+ Reference< XInvocationAdapterFactory2 > xAdapFac2( xAdapFac, UNO_QUERY_THROW );
+
+ Reference< XLanguageBindingTest > xOriginal( (XLanguageBindingTest *)new Test_Impl() );
+ Reference< XInvocation > xInvok( new XLB_Invocation( xMgr, xOriginal ) );
+ Reference< XLanguageBindingTest > xLBT( xAdapFac->createAdapter(
+ xInvok, cppu::UnoType<XLanguageBindingTest>::get()), UNO_QUERY );
+ Reference< XLanguageBindingTest > xLBT2(
+ xAdapFac->createAdapter(
+ xInvok, cppu::UnoType<XLanguageBindingTest>::get()), UNO_QUERY );
+ if (xLBT != xLBT2)
+ return sal_False;
+ Reference< XInterface > xLBT3(
+ xAdapFac->createAdapter(
+ xInvok, cppu::UnoType<XInterface>::get()), UNO_QUERY );
+ if (xLBT != xLBT3)
+ return sal_False;
+ Type ar[ 2 ] = {
+ cppu::UnoType<XLBTestBase>::get(),
+ cppu::UnoType<XInterface>::get()};
+ Reference< XInterface > xLBT4(
+ xAdapFac2->createAdapter( xInvok, Sequence< Type >( ar, 2 ) ), UNO_QUERY );
+ if (xLBT != xLBT4)
+ return sal_False;
+ Reference< XSimpleRegistry > xInvalidAdapter(
+ xAdapFac->createAdapter(
+ xInvok, cppu::UnoType<XSimpleRegistry>::get()), UNO_QUERY );
+ if (xLBT == xInvalidAdapter)
+ return sal_False;
+
+ try
+ {
+ xInvalidAdapter->isValid();
+ return sal_False;
+ }
+ catch (RuntimeException &)
+ {
+ }
+
+ return (performTest( xLBT ) && raiseException( xLBT ));
+}
+
+static sal_Bool test_invocation( const Reference< XMultiServiceFactory > & xMgr )
+{
+ Reference< XInvocationAdapterFactory > xAdapFac(
+ xMgr->createInstance("com.sun.star.script.InvocationAdapterFactory"), UNO_QUERY );
+ Reference< XSingleServiceFactory > xInvocFac(
+ xMgr->createInstance("com.sun.star.script.Invocation"), UNO_QUERY );
+
+ Reference< XLanguageBindingTest > xOriginal( (XLanguageBindingTest *)new Test_Impl() );
+ Any aOriginal( &xOriginal, cppu::UnoType<decltype(xOriginal)>::get() );
+ Reference< XInvocation > xInvok(
+ xInvocFac->createInstanceWithArguments( Sequence< Any >( &aOriginal, 1 ) ), UNO_QUERY );
+
+ Reference< XLanguageBindingTest > xLBT( xAdapFac->createAdapter(
+ xInvok, cppu::UnoType<XLanguageBindingTest>::get()), UNO_QUERY );
+
+ return (performTest( xLBT ) && raiseException( xLBT ));
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ Reference< XMultiServiceFactory > xMgr( createRegistryServiceFactory(
+ OUString( "stoctest.rdb" ) ) );
+
+ try
+ {
+ Reference< XImplementationRegistration > xImplReg(
+ xMgr->createInstance( "com.sun.star.registry.ImplementationRegistration" ),
+ UNO_QUERY );
+ OSL_ENSURE( xImplReg.is(), "### no impl reg!" );
+
+ xImplReg->registerImplementation(
+ OUString("com.sun.star.loader.SharedLibrary"),
+ OUString("invocadapt.uno" SAL_DLLEXTENSION),
+ Reference< XSimpleRegistry >() );
+ xImplReg->registerImplementation(
+ OUString("com.sun.star.loader.SharedLibrary"),
+ OUString("stocservices.uno" SAL_DLLEXTENSION),
+ Reference< XSimpleRegistry >() );
+ xImplReg->registerImplementation(
+ OUString("com.sun.star.loader.SharedLibrary"),
+ OUString("invocation.uno" SAL_DLLEXTENSION),
+ Reference< XSimpleRegistry >() );
+ xImplReg->registerImplementation(
+ OUString("com.sun.star.loader.SharedLibrary"),
+ OUString("reflection.uno" SAL_DLLEXTENSION),
+ Reference< XSimpleRegistry >() );
+ xImplReg->registerImplementation(
+ OUString("com.sun.star.loader.SharedLibrary"),
+ OUString("introspection.uno" SAL_DLLEXTENSION),
+ Reference< XSimpleRegistry >() );
+
+ if (test_adapter( xMgr ))
+ {
+ fprintf( stderr, "> test_iadapter() succeeded.\n" );
+ if (test_invocation( xMgr ))
+ {
+ fprintf( stderr, "> test_invocation() succeeded.\n" );
+ }
+ }
+ }
+ catch (const Exception & rExc)
+ {
+ fprintf( stderr, "> exception occurred: " );
+ OString aMsg( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
+ fprintf( stderr, "%s\n", aMsg.getStr() );
+ }
+
+ Reference< XComponent >( xMgr, UNO_QUERY )->dispose();
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testintrosp.cxx b/stoc/test/testintrosp.cxx
new file mode 100644
index 0000000000..0b56c8564e
--- /dev/null
+++ b/stoc/test/testintrosp.cxx
@@ -0,0 +1,1203 @@
+/* -*- 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/main.h>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <osl/diagnose.h>
+
+#include <ModuleA/XIntroTest.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XIntrospection.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyConcept.hpp>
+#include <com/sun/star/beans/MethodConcept.hpp>
+#include <com/sun/star/beans/XExactName.hpp>
+#include <com/sun/star/container/XElementAccess.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/reflection/XIdlReflection.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+
+#include <stdio.h>
+#include <string.h>
+#include <cmath>
+
+using namespace cppu;
+using namespace ModuleA;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::beans;
+using namespace css::registry;
+using namespace css::reflection;
+using namespace css::container;
+using namespace css::beans::PropertyAttribute;
+
+
+#define DEFAULT_INDEX_ACCESS_COUNT 10
+#define DEFAULT_NAME_ACCESS_COUNT 5
+
+// Auxiliary function, in order to get from one type XIdlClass
+Reference<XIdlClass> TypeToIdlClass( const Type& rType, const Reference< XMultiServiceFactory > & xMgr )
+{
+ static Reference< XIdlReflection > xRefl;
+
+ // register void as default class
+ Reference<XIdlClass> xRetClass;
+ typelib_TypeDescription * pTD = 0;
+ rType.getDescription( &pTD );
+ if( pTD )
+ {
+ OUString sOWName( pTD->pTypeName );
+ if( !xRefl.is() )
+ {
+ xRefl.set( xMgr->createInstance( "com.sun.star.reflection.CoreReflection" ), UNO_QUERY );
+ OSL_ENSURE( xRefl.is(), "### no corereflection!" );
+ }
+ xRetClass = xRefl->forName( sOWName );
+ }
+ return xRetClass;
+}
+
+
+// Helper function to convert Any to UString
+// TODO: This code could be moved to a more central place.
+// Currently it's used only for simple data types.
+
+OUString AnyToString( const Any& aValue, sal_Bool bIncludeType, const Reference< XMultiServiceFactory > & xMgr )
+{
+ Type aValType = aValue.getValueType();
+ TypeClass eType = aValType.getTypeClass();
+ char pBuffer[50];
+
+ OUString aRetStr;
+ switch( eType )
+ {
+ case TypeClass_TYPE: aRetStr = "TYPE TYPE"; break;
+ case TypeClass_INTERFACE: aRetStr = "TYPE INTERFACE"; break;
+ case TypeClass_SERVICE: aRetStr = "TYPE SERVICE"; break;
+ case TypeClass_STRUCT: aRetStr = "TYPE STRUCT"; break;
+ case TypeClass_TYPEDEF: aRetStr = "TYPE TYPEDEF"; break;
+ case TypeClass_ENUM: aRetStr = "TYPE ENUM"; break;
+ case TypeClass_EXCEPTION: aRetStr = "TYPE EXCEPTION"; break;
+ case TypeClass_SEQUENCE: aRetStr = "TYPE SEQUENCE"; break;
+ case TypeClass_VOID: aRetStr = "TYPE void"; break;
+ case TypeClass_ANY: aRetStr = "TYPE any"; break;
+ case TypeClass_UNKNOWN: aRetStr = "TYPE unknown"; break;
+ case TypeClass_BOOLEAN:
+ {
+ sal_Bool b = *(sal_Bool*)aValue.getValue();
+ aRetStr = OUString::valueOf( b );
+ break;
+ }
+ case TypeClass_CHAR:
+ {
+ sal_Unicode c = *(sal_Unicode*)aValue.getValue();
+ aRetStr = OUString::valueOf( c );
+ break;
+ }
+ case TypeClass_STRING:
+ {
+ aValue >>= aRetStr;
+ break;
+ }
+ case TypeClass_FLOAT:
+ {
+ float f(0.0);
+ aValue >>= f;
+ snprintf( pBuffer, sizeof( pBuffer ), "%f", f );
+ aRetStr = OUString( pBuffer, strlen( pBuffer ), RTL_TEXTENCODING_ASCII_US );
+ break;
+ }
+ case TypeClass_DOUBLE:
+ {
+ double d(0.0);
+ aValue >>= d;
+ snprintf( pBuffer, sizeof( pBuffer ), "%f", d );
+ aRetStr = OUString( pBuffer, strlen( pBuffer ), RTL_TEXTENCODING_ASCII_US );
+ break;
+ }
+ case TypeClass_BYTE:
+ {
+ sal_Int8 n(0);
+ aValue >>= n;
+ aRetStr = OUString::valueOf( (sal_Int32) n );
+ break;
+ }
+ case TypeClass_SHORT:
+ {
+ sal_Int16 n(0);
+ aValue >>= n;
+ aRetStr = OUString::valueOf( (sal_Int32) n );
+ break;
+ }
+ case TypeClass_LONG:
+ {
+ sal_Int32 n(0);
+ aValue >>= n;
+ aRetStr = OUString::valueOf( n );
+ break;
+ }
+ default: ;
+ }
+
+ if( bIncludeType )
+ {
+ Reference< XIdlClass > xIdlClass = TypeToIdlClass( aValType, xMgr );
+ aRetStr += " (Typ: " + xIdlClass->getName() + ")";
+ }
+ return aRetStr;
+}
+
+// XPropertySetInfo for test class
+
+class ImplPropertySetInfo : public WeakImplHelper< XPropertySetInfo >
+{
+ friend class ImplIntroTest;
+
+ Reference< XMultiServiceFactory > mxMgr;
+
+public:
+ explicit ImplPropertySetInfo( const Reference< XMultiServiceFactory > & xMgr )
+ : mxMgr( xMgr ) {}
+
+ // Methods of XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties( )
+ throw(RuntimeException);
+ virtual Property SAL_CALL getPropertyByName( const OUString& aName )
+ throw(UnknownPropertyException, RuntimeException);
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name )
+ throw(RuntimeException);
+};
+
+
+Sequence< Property > ImplPropertySetInfo::getProperties()
+ throw( RuntimeException )
+{
+ static Sequence<Property> * pSeq = NULL;
+
+ if( !pSeq )
+ {
+ // Create information for the properties "Width", "Height" and "Name"
+ pSeq = new Sequence<Property>( 3 );
+ Property * pAry = pSeq->getArray();
+
+ pAry[0].Name = "Factor";
+ pAry[0].Handle = -1;
+ pAry[0].Type = cppu::UnoType<double>::get();
+ pAry[0].Attributes = BOUND | TRANSIENT;
+
+ pAry[1].Name = "MyCount";
+ pAry[1].Handle = -1;
+ pAry[1].Type = cppu::UnoType<sal_Int32>::get();
+ pAry[1].Attributes = BOUND | TRANSIENT;
+
+ pAry[2].Name = "Info";
+ pAry[2].Handle = -1;
+ pAry[2].Type = cppu::UnoType<OUString>::get();
+ pAry[2].Attributes = TRANSIENT;
+ }
+ // Return information about all three properties
+ return *pSeq;
+}
+
+Property ImplPropertySetInfo::getPropertyByName(const OUString& Name)
+ throw( UnknownPropertyException, RuntimeException )
+{
+ Sequence<Property> aSeq = getProperties();
+ const Property * pAry = aSeq.getConstArray();
+
+ for( sal_Int32 i = aSeq.getLength(); i--; )
+ {
+ if( pAry[i].Name == Name )
+ return pAry[i];
+ }
+ // Property unknown, also return empty ones
+ return Property();
+}
+
+sal_Bool ImplPropertySetInfo::hasPropertyByName(const OUString& Name)
+ throw( RuntimeException )
+{
+ Sequence<Property> aSeq = getProperties();
+ const Property * pAry = aSeq.getConstArray();
+
+ for( sal_Int32 i = aSeq.getLength(); i--; )
+ {
+ if( pAry[i].Name == Name )
+ return sal_True;
+ }
+ // Property unknown, also return empty ones
+ return sal_False;
+}
+
+
+class ImplIntroTest : public WeakImplHelper< XIntroTest, XPropertySet, XNameAccess, XIndexAccess >
+{
+ Reference< XMultiServiceFactory > mxMgr;
+
+ friend class ImplPropertySetInfo;
+
+ // Properties for the PropertySet
+ Any aAnyArray[10];
+
+ Reference< XPropertySetInfo > m_xMyInfo;
+
+ OUString m_ObjectName;
+
+ sal_Int16 m_nMarkusAge;
+ sal_Int16 m_nMarkusChildrenCount;
+
+ long m_lDroenk;
+ sal_Int16 m_nBla;
+ sal_Int16 m_nBlub;
+ sal_Int16 m_nGulp;
+ sal_Int16 m_nLaber;
+ TypeClass eTypeClass;
+ Sequence< OUString > aStringSeq;
+ Sequence< Sequence< Sequence< sal_Int16 > > > aMultSeq;
+ Reference< XIntroTest > m_xIntroTest;
+
+ // Data for NameAccess
+ Reference< XIntroTest >* pNameAccessTab;
+
+ // Data for IndexAccess
+ Reference< XIntroTest >* pIndexAccessTab;
+ sal_Int16 iIndexAccessCount;
+
+ // struct properties
+ Property m_aFirstStruct;
+ PropertyValue m_aSecondStruct;
+
+ // remember listener (one listener per property)
+ Reference< XPropertyChangeListener > aPropChangeListener;
+ OUString aPropChangeListenerStr;
+ Reference< XVetoableChangeListener > aVetoPropChangeListener;
+ OUString aVetoPropChangeListenerStr;
+
+ void Init();
+
+public:
+ explicit ImplIntroTest( const Reference< XMultiServiceFactory > & xMgr )
+ : mxMgr( xMgr )
+ {
+ Init();
+ }
+
+ // despite virtual inline, to simplify coding (testing only)
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo( )
+ throw(RuntimeException);
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+ throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException);
+ virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException);
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*xListener*/ )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+ {}
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< XPropertyChangeListener >& /*aListener*/ )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+ {}
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+ {}
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener >& /*aListener*/ )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+ {}
+
+ // XIntroTest methods
+ // Attributes
+ virtual OUString SAL_CALL getObjectName() throw(RuntimeException)
+ { return m_ObjectName; }
+ virtual void SAL_CALL setObjectName( const OUString& _objectname ) throw(RuntimeException)
+ { m_ObjectName = _objectname; }
+ virtual OUString SAL_CALL getFirstName()
+ throw(RuntimeException);
+ virtual OUString SAL_CALL getLastName() throw(RuntimeException)
+ { return OUString("Meyer"); }
+ virtual sal_Int16 SAL_CALL getAge() throw(RuntimeException)
+ { return m_nMarkusAge; }
+ virtual sal_Int16 SAL_CALL getChildrenCount() throw(RuntimeException)
+ { return m_nMarkusChildrenCount; }
+ virtual void SAL_CALL setChildrenCount( sal_Int16 _childrencount ) throw(RuntimeException)
+ { m_nMarkusChildrenCount = _childrencount; }
+ virtual Property SAL_CALL getFirstStruct() throw(RuntimeException)
+ { return m_aFirstStruct; }
+ virtual void SAL_CALL setFirstStruct( const Property& _firststruct ) throw(RuntimeException)
+ { m_aFirstStruct = _firststruct; }
+ virtual PropertyValue SAL_CALL getSecondStruct() throw(RuntimeException)
+ { return m_aSecondStruct; }
+ virtual void SAL_CALL setSecondStruct( const PropertyValue& _secondstruct ) throw(RuntimeException)
+ { m_aSecondStruct = _secondstruct; }
+
+ // Methods
+ virtual void SAL_CALL writeln( const OUString& Text )
+ throw(RuntimeException);
+ virtual sal_Int32 SAL_CALL getDroenk( ) throw(RuntimeException)
+ { return m_lDroenk; }
+ virtual Reference< ::ModuleA::XIntroTest > SAL_CALL getIntroTest( ) throw(RuntimeException);
+ virtual sal_Int32 SAL_CALL getUps( sal_Int32 l ) throw(RuntimeException)
+ { return 2*l; }
+ virtual void SAL_CALL setDroenk( sal_Int32 l ) throw(RuntimeException)
+ { m_lDroenk = l; }
+ virtual sal_Int16 SAL_CALL getBla( ) throw(RuntimeException)
+ { return m_nBla; }
+ virtual void SAL_CALL setBla( sal_Int32 n ) throw(RuntimeException)
+ { m_nBla = (sal_Int16)n; }
+ virtual sal_Int16 SAL_CALL getBlub( ) throw(RuntimeException)
+ { return m_nBlub; }
+ virtual void SAL_CALL setBlub( sal_Int16 n ) throw(RuntimeException)
+ { m_nBlub = n; }
+ virtual sal_Int16 SAL_CALL getGulp( ) throw(RuntimeException)
+ { return m_nGulp; }
+ virtual sal_Int16 SAL_CALL setGulp( sal_Int16 n ) throw(RuntimeException)
+ { m_nGulp = n; return 1; }
+ virtual TypeClass SAL_CALL getTypeClass( sal_Int16 /*n*/ ) throw(RuntimeException)
+ { return eTypeClass; }
+ virtual void SAL_CALL setTypeClass( TypeClass t, double /*d1*/, double /*d2*/ ) throw(RuntimeException)
+ { eTypeClass = t; }
+ virtual Sequence< OUString > SAL_CALL getStrings( ) throw(RuntimeException)
+ { return aStringSeq; }
+ virtual void SAL_CALL setStrings( const Sequence< OUString >& Strings ) throw(RuntimeException)
+ { aStringSeq = Strings; }
+ virtual void SAL_CALL setStringsPerMethod( const Sequence< OUString >& Strings, sal_Int16 /*n*/ ) throw(RuntimeException)
+ { aStringSeq = Strings; }
+ virtual Sequence< Sequence< Sequence< sal_Int16 > > > SAL_CALL getMultiSequence( ) throw(RuntimeException)
+ { return aMultSeq; }
+ virtual void SAL_CALL setMultiSequence( const Sequence< Sequence< Sequence< sal_Int16 > > >& Seq ) throw(RuntimeException)
+ { aMultSeq = Seq; }
+ virtual void SAL_CALL addPropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
+ throw(RuntimeException);
+ virtual void SAL_CALL removePropertiesChangeListener( const Reference< XPropertiesChangeListener >& Listener )
+ throw(RuntimeException);
+
+
+ // Methods of XElementAccess
+ virtual Type SAL_CALL getElementType( )
+ throw(RuntimeException);
+ virtual sal_Bool SAL_CALL hasElements( )
+ throw(RuntimeException);
+
+ // XNameAccess methods
+ // Methods
+ virtual Any SAL_CALL getByName( const OUString& aName )
+ throw(NoSuchElementException, WrappedTargetException, RuntimeException);
+ virtual Sequence< OUString > SAL_CALL getElementNames( )
+ throw(RuntimeException);
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName )
+ throw(RuntimeException);
+
+ // XIndexAccess methods
+ // Methods
+ virtual sal_Int32 SAL_CALL getCount( )
+ throw(RuntimeException);
+ virtual Any SAL_CALL getByIndex( sal_Int32 Index )
+ throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException);
+};
+
+void ImplIntroTest::Init()
+{
+ // set unique name
+ static sal_Int32 nObjCount = 0;
+ OUString aName( "IntroTest-Obj Nr. " );
+ aName += OUString::valueOf( nObjCount );
+ setObjectName( aName );
+
+ // initialize properties
+ aAnyArray[0] <<= 3.14;
+ aAnyArray[1] <<= (sal_Int32)42;
+ aAnyArray[2] <<= OUString( "Hallo" );
+
+ // fetch PropertySetInfo once for internal use
+ m_xMyInfo = getPropertySetInfo();
+ m_xMyInfo->acquire(); // otherwise it could crash at shutdown
+
+ m_nMarkusAge = 33;
+ m_nMarkusChildrenCount = 2;
+
+ m_lDroenk = 314;
+ m_nBla = 42;
+ m_nBlub = 111;
+ m_nGulp = 99;
+ m_nLaber = 1;
+ eTypeClass = TypeClass_INTERFACE;
+
+ // string sequence initialization
+ aStringSeq.realloc( 3 );
+ aStringSeq[ 0 ] = "String 0";
+ aStringSeq[ 1 ] = "String 1";
+ aStringSeq[ 2 ] = "String 2";
+
+ // structs initialization
+ m_aFirstStruct.Name = "FirstStruct-Name";
+ m_aFirstStruct.Handle = 77777;
+ //XIdlClassRef Type;
+ m_aFirstStruct.Attributes = -222;
+
+ //XInterfaceRef Source;
+ Any Value;
+ Value <<= M_E;
+ m_aSecondStruct.Value = Value;
+ //XIdlClassRef ListenerType;
+ m_aSecondStruct.State = PropertyState_DIRECT_VALUE;
+
+ // IndexAccess
+ iIndexAccessCount = DEFAULT_INDEX_ACCESS_COUNT;
+ pIndexAccessTab = NULL;
+ pNameAccessTab = NULL;
+}
+
+Reference< XPropertySetInfo > ImplIntroTest::getPropertySetInfo()
+ throw(RuntimeException)
+{
+ static ImplPropertySetInfo aInfo( mxMgr );
+ // All objects have the same Properties, so
+ // the Info is the same for all
+ return &aInfo;
+}
+
+void ImplIntroTest::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+ throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException)
+{
+ if( aPropChangeListener.is() && aPropertyName == aPropChangeListenerStr )
+ {
+ PropertyChangeEvent aEvt;
+ aEvt.Source = (OWeakObject*)this;
+ aEvt.PropertyName = aPropertyName;
+ aEvt.PropertyHandle = 0;
+ aPropChangeListener->propertyChange( aEvt );
+ }
+ if( aVetoPropChangeListener.is() && aPropertyName == aVetoPropChangeListenerStr )
+ {
+ PropertyChangeEvent aEvt;
+ aEvt.Source = (OWeakObject*)this;
+ aEvt.PropertyName = aVetoPropChangeListenerStr;
+ aEvt.PropertyHandle = 0;
+ aVetoPropChangeListener->vetoableChange( aEvt );
+ }
+
+ Sequence<Property> aPropSeq = m_xMyInfo->getProperties();
+ sal_Int32 nLen = aPropSeq.getLength();
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ Property aProp = aPropSeq.getArray()[ i ];
+ if( aProp.Name == aPropertyName )
+ aAnyArray[i] = aValue;
+ }
+}
+
+Any ImplIntroTest::getPropertyValue( const OUString& PropertyName )
+ throw(UnknownPropertyException, WrappedTargetException, RuntimeException)
+{
+ Sequence<Property> aPropSeq = m_xMyInfo->getProperties();
+ sal_Int32 nLen = aPropSeq.getLength();
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ Property aProp = aPropSeq.getArray()[ i ];
+ if( aProp.Name == PropertyName )
+ return aAnyArray[i];
+ }
+ return Any();
+}
+
+OUString ImplIntroTest::getFirstName()
+ throw(RuntimeException)
+{
+ return OUString("Markus");
+}
+
+void ImplIntroTest::writeln( const OUString& Text )
+ throw(RuntimeException)
+{
+ OString aStr( Text.getStr(), Text.getLength(), RTL_TEXTENCODING_ASCII_US );
+
+ printf( "%s", aStr.getStr() );
+}
+
+Reference< XIntroTest > ImplIntroTest::getIntroTest()
+ throw(RuntimeException)
+{
+ if( !m_xIntroTest.is() )
+ m_xIntroTest = new ImplIntroTest( mxMgr );
+ return m_xIntroTest;
+}
+
+// Methods of XElementAccess
+Type ImplIntroTest::getElementType( )
+ throw(RuntimeException)
+{
+ // TODO
+ Type aRetType;
+ return aRetType;
+}
+
+sal_Bool ImplIntroTest::hasElements( )
+ throw(RuntimeException)
+{
+ return sal_True;
+}
+
+// XNameAccess methods
+sal_Int32 getIndexForName( const OUString& ItemName )
+{
+ OUString aLeftStr = ItemName.copy( 0, 4 );
+ if( aLeftStr == "Item" )
+ {
+ // TODO
+ OUString aNumStr = ItemName.copy( 4 );
+ }
+ return -1;
+}
+
+
+Any ImplIntroTest::getByName( const OUString& aName )
+ throw(NoSuchElementException, WrappedTargetException, RuntimeException)
+{
+ Any aRetAny;
+
+ if( !pNameAccessTab )
+ pNameAccessTab = new Reference< XIntroTest >[ DEFAULT_NAME_ACCESS_COUNT ];
+
+ sal_Int32 iIndex = getIndexForName( aName );
+ if( iIndex != -1 )
+ {
+ if( !pNameAccessTab[iIndex].is() )
+ {
+ ImplIntroTest* p = new ImplIntroTest( mxMgr );
+ OUString aName2( "IntroTest by Name-Access, Index = " );
+ aName2 += OUString::valueOf( iIndex );
+ p->setObjectName( aName2 );
+ pNameAccessTab[iIndex] = p;
+ }
+
+ Reference< XIntroTest > xRet = pNameAccessTab[iIndex];
+ aRetAny = makeAny( xRet );
+ }
+ return aRetAny;
+}
+
+Sequence< OUString > ImplIntroTest::getElementNames( )
+ throw(RuntimeException)
+{
+ Sequence<OUString> aStrSeq( DEFAULT_NAME_ACCESS_COUNT );
+ OUString* pStr = aStrSeq.getArray();
+ for( sal_Int32 i = 0 ; i < DEFAULT_NAME_ACCESS_COUNT ; i++ )
+ {
+ OUString aName( "Item" );
+ aName += OUString::valueOf( i );
+ pStr[i] = aName;
+ }
+ return aStrSeq;
+}
+
+sal_Bool ImplIntroTest::hasByName( const OUString& aName )
+ throw(RuntimeException)
+{
+ return ( getIndexForName( aName ) != -1 );
+}
+
+// XIndexAccess methods
+sal_Int32 ImplIntroTest::getCount( )
+ throw(RuntimeException)
+{
+ return iIndexAccessCount;
+}
+
+Any ImplIntroTest::getByIndex( sal_Int32 Index )
+ throw(IndexOutOfBoundsException, WrappedTargetException, RuntimeException)
+{
+ Any aRetAny;
+
+ if( !pIndexAccessTab )
+ pIndexAccessTab = new Reference< XIntroTest >[ iIndexAccessCount ];
+
+ if( Index < iIndexAccessCount )
+ {
+ if( !pNameAccessTab[Index].is() )
+ {
+ ImplIntroTest* p = new ImplIntroTest( mxMgr );
+ OUString aName( "IntroTest by Index-Access, Index = " );
+ aName += OUString::valueOf( Index );
+ p->setObjectName( aName );
+ pIndexAccessTab[Index] = p;
+ }
+ Reference< XIntroTest > xRet = pIndexAccessTab[Index];
+ aRetAny = makeAny( xRet );
+ }
+ return aRetAny;
+}
+
+void ImplIntroTest::addPropertiesChangeListener( const Sequence< OUString >& /*PropertyNames*/,
+ const Reference< XPropertiesChangeListener >& /*Listener*/ )
+ throw(RuntimeException)
+{
+}
+
+void ImplIntroTest::removePropertiesChangeListener
+( const Reference< XPropertiesChangeListener >& /*Listener*/ )
+ throw(RuntimeException)
+{
+}
+
+
+struct DefItem
+{
+ char const * pName;
+ sal_Int32 nConcept;
+};
+
+// special value for method concept, to mark "normal" functions
+#define MethodConcept_NORMAL_IMPL 0x80000000
+
+
+// return test object
+Any getIntrospectionTestObject( const Reference< XMultiServiceFactory > & xMgr )
+{
+ Any aObjAny;
+ Reference< XIntroTest > xTestObj = new ImplIntroTest( xMgr );
+ aObjAny.setValue( &xTestObj, cppu::UnoType<XIntroTest>::get());
+ return aObjAny;
+}
+
+static sal_Bool test_introsp( Reference< XMultiServiceFactory > xMgr,
+ Reference< XIdlReflection > /*xRefl*/, Reference< XIntrospection > xIntrospection )
+{
+ DefItem pPropertyDefs[] =
+ {
+ { "Factor", PropertyConcept::PROPERTYSET },
+ { "MyCount", PropertyConcept::PROPERTYSET },
+ { "Info", PropertyConcept::PROPERTYSET },
+ { "ObjectName", PropertyConcept::ATTRIBUTES },
+ { "FirstName", PropertyConcept::ATTRIBUTES },
+ { "LastName", PropertyConcept::ATTRIBUTES },
+ { "Age", PropertyConcept::ATTRIBUTES },
+ { "ChildrenCount", PropertyConcept::ATTRIBUTES },
+ { "FirstStruct", PropertyConcept::ATTRIBUTES },
+ { "SecondStruct", PropertyConcept::ATTRIBUTES },
+ { "Droenk", PropertyConcept::METHODS },
+ { "IntroTest", PropertyConcept::METHODS },
+ { "Bla", PropertyConcept::METHODS },
+ { "Blub", PropertyConcept::METHODS },
+ { "Gulp", PropertyConcept::METHODS },
+ { "Strings", PropertyConcept::METHODS },
+ { "MultiSequence", PropertyConcept::METHODS },
+ { "PropertySetInfo", PropertyConcept::METHODS },
+ { "ElementType", PropertyConcept::METHODS },
+ { "ElementNames", PropertyConcept::METHODS },
+ { "Count", PropertyConcept::METHODS },
+ { "Types", PropertyConcept::METHODS },
+ { "ImplementationId", PropertyConcept::METHODS },
+ { NULL, 0 }
+ };
+
+ char const * pDemandedPropVals[] =
+ {
+ "3.140000",
+ "42",
+ "Hallo",
+ "IntroTest-Obj Nr. 0",
+ "Markus",
+ "Meyer",
+ "33",
+ "2",
+ "TYPE STRUCT",
+ "TYPE STRUCT",
+ "314",
+ "TYPE INTERFACE",
+ "42",
+ "111",
+ "99",
+ "TYPE SEQUENCE",
+ "TYPE SEQUENCE",
+ "TYPE INTERFACE",
+ "TYPE TYPE",
+ "TYPE SEQUENCE",
+ "10",
+ "TYPE SEQUENCE",
+ "TYPE SEQUENCE",
+ };
+
+ char const * pDemandedModifiedPropVals[] =
+ {
+ "4.140000",
+ "43",
+ "Hallo (Modified!)",
+ "IntroTest-Obj Nr. 0 (Modified!)",
+ "Markus",
+ "Meyer",
+ "33",
+ "3",
+ "Value has not been modified",
+ "Value has not been modified",
+ "315",
+ "Value has not been modified",
+ "42",
+ "112",
+ "99",
+ "Value has not been modified",
+ "Value has not been modified",
+ "Value has not been modified",
+ "Value has not been modified",
+ "Value has not been modified",
+ "10",
+ "Value has not been modified",
+ "Value has not been modified",
+ };
+
+ char const * pDemandedPropTypes[] =
+ {
+ "double",
+ "long",
+ "string",
+ "string",
+ "string",
+ "string",
+ "short",
+ "short",
+ "com.sun.star.beans.Property",
+ "com.sun.star.beans.PropertyValue",
+ "long",
+ "ModuleA.XIntroTest",
+ "short",
+ "short",
+ "short",
+ "[]string",
+ "[][][]short",
+ "com.sun.star.beans.XPropertySetInfo",
+ "type",
+ "[]string",
+ "long",
+ "[]type",
+ "[]byte",
+ };
+
+ DefItem pMethodDefs[] =
+ {
+ { "queryInterface", MethodConcept_NORMAL_IMPL },
+ { "acquire", MethodConcept::DANGEROUS },
+ { "release", MethodConcept::DANGEROUS },
+ { "writeln", MethodConcept_NORMAL_IMPL },
+ { "getDroenk", MethodConcept::PROPERTY },
+ { "getIntroTest", MethodConcept::PROPERTY },
+ { "getUps", MethodConcept_NORMAL_IMPL },
+ { "setDroenk", MethodConcept::PROPERTY },
+ { "getBla", MethodConcept::PROPERTY },
+ { "setBla", MethodConcept_NORMAL_IMPL },
+ { "getBlub", MethodConcept::PROPERTY },
+ { "setBlub", MethodConcept::PROPERTY },
+ { "getGulp", MethodConcept::PROPERTY },
+ { "setGulp", MethodConcept_NORMAL_IMPL },
+ { "getTypeClass", MethodConcept_NORMAL_IMPL },
+ { "setTypeClass", MethodConcept_NORMAL_IMPL },
+ { "getStrings", MethodConcept::PROPERTY },
+ { "setStrings", MethodConcept::PROPERTY },
+ { "setStringsPerMethod", MethodConcept_NORMAL_IMPL },
+ { "getMultiSequence", MethodConcept::PROPERTY },
+ { "setMultiSequence", MethodConcept::PROPERTY },
+ { "addPropertiesChangeListener", MethodConcept::LISTENER },
+ { "removePropertiesChangeListener", MethodConcept::LISTENER },
+ { "getPropertySetInfo", MethodConcept::PROPERTY },
+ { "setPropertyValue", MethodConcept_NORMAL_IMPL },
+ { "getPropertyValue", MethodConcept_NORMAL_IMPL },
+ { "addPropertyChangeListener", MethodConcept::LISTENER },
+ { "removePropertyChangeListener", MethodConcept::LISTENER },
+ { "addVetoableChangeListener", MethodConcept::LISTENER },
+ { "removeVetoableChangeListener", MethodConcept::LISTENER },
+ { "getElementType", MethodConcept::PROPERTY | MethodConcept::NAMECONTAINER| MethodConcept::INDEXCONTAINER | MethodConcept::ENUMERATION },
+ { "hasElements", MethodConcept::NAMECONTAINER | MethodConcept::INDEXCONTAINER | MethodConcept::ENUMERATION },
+ { "getByName", MethodConcept::NAMECONTAINER },
+ { "getElementNames", MethodConcept::PROPERTY | MethodConcept::NAMECONTAINER },
+ { "hasByName", MethodConcept::NAMECONTAINER },
+ { "getCount", MethodConcept::PROPERTY | MethodConcept::INDEXCONTAINER },
+ { "getByIndex", MethodConcept::INDEXCONTAINER },
+ { "getTypes", MethodConcept::PROPERTY },
+ { "getImplementationId", MethodConcept::PROPERTY },
+ { "queryAdapter", MethodConcept_NORMAL_IMPL },
+ { NULL, 0 }
+ };
+
+ OString aErrorStr;
+
+
+ // create test object
+ Any aObjAny = getIntrospectionTestObject( xMgr );
+
+ // inspect introspection service
+ xIntrospection->inspect( aObjAny );
+ xIntrospection->inspect( aObjAny );
+ Reference< XIntrospectionAccess > xAccess = xIntrospection->inspect( aObjAny );
+ OSL_ENSURE( xAccess.is(), "introspection failed, no XIntrospectionAccess returned" );
+ if( !xAccess.is() )
+ return sal_False;
+
+ // check result of introspection
+
+ // determine XPropertySet-UIK
+ Type aType = cppu::UnoType<XPropertySet>::get();
+
+ Reference< XInterface > xPropSetIface = xAccess->queryAdapter( aType );
+ Reference< XPropertySet > xPropSet( xPropSetIface, UNO_QUERY );
+ OSL_ENSURE( xPropSet.is(), "Could not get XPropertySet by queryAdapter()" );
+
+ // XExactName
+ Reference< XExactName > xExactName( xAccess, UNO_QUERY );
+ OSL_ENSURE( xExactName.is(), "Introspection doesn't support ExactName" );
+
+ // loop over all concept combinations
+ for( sal_Int32 nConcepts = 0 ; nConcepts < 16 ; nConcepts++ )
+ {
+ // how many properties should this be
+ sal_Int32 nDemandedPropCount = 0;
+ sal_Int32 iList = 0;
+ while( pPropertyDefs[ iList ].pName )
+ {
+ if( pPropertyDefs[ iList ].nConcept & nConcepts )
+ nDemandedPropCount++;
+ iList++;
+ }
+
+ if( xPropSet.is() )
+ {
+ Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
+ Sequence<Property> aRetSeq = xAccess->getProperties( nConcepts );
+
+ sal_Int32 nLen = aRetSeq.getLength();
+
+ aErrorStr = "Expected to find "
+ + OString::valueOf( nDemandedPropCount )
+ + " properties but found "
+ + OString::valueOf( nLen );
+ OSL_ENSURE( nLen == nDemandedPropCount, aErrorStr.getStr() );
+
+ const Property* pProps = aRetSeq.getConstArray();
+ Any aPropVal;
+ sal_Int32 i;
+ iList = 0;
+ for( i = 0 ; i < nLen ; i++ )
+ {
+ const Property aProp = pProps[ i ];
+
+ // search for next suitable method in the list
+ while( pPropertyDefs[ iList ].pName )
+ {
+ if( pPropertyDefs[ iList ].nConcept & nConcepts )
+ break;
+ iList++;
+ }
+ sal_Int32 iDemanded = iList;
+ iList++;
+
+ OUString aPropName = aProp.Name;
+ OString aNameStr( aPropName.getStr(), aPropName.getLength(), RTL_TEXTENCODING_ASCII_US );
+
+ OString aDemandedName = pPropertyDefs[ iDemanded ].pName;
+ aErrorStr = "Expected property \""
+ + aDemandedName
+ + "\", found \""
+ + aNameStr
+ + "\"";
+ OSL_ENSURE( aNameStr == aDemandedName, aErrorStr.getStr() );
+
+ Type aPropType = aProp.Type;
+ OString aTypeNameStr( OUStringToOString(aPropType.getTypeName(), RTL_TEXTENCODING_ASCII_US) );
+ OString aDemandedTypeNameStr = pDemandedPropTypes[ iDemanded ];
+ aErrorStr = "Property \""
+ + aDemandedName
+ + "\", expected type >"
+ + aDemandedTypeNameStr
+ + "< found type >"
+ + aTypeNameStr
+ + "<";
+ OSL_ENSURE( aTypeNameStr == aDemandedTypeNameStr, aErrorStr.getStr() );
+
+ // read and report value of property
+ aPropVal = xPropSet->getPropertyValue( aPropName );
+
+ OString aValStr = OUStringToOString( AnyToString( aPropVal, sal_False, xMgr ), RTL_TEXTENCODING_ASCII_US );
+ OString aDemandedValStr = pDemandedPropVals[ iDemanded ];
+ aErrorStr = "Property \""
+ + aDemandedName
+ + "\", expected val >"
+ + aDemandedValStr
+ + "< found val >"
+ + aValStr
+ + "<";
+ OSL_ENSURE( aValStr == aDemandedValStr, aErrorStr.getStr() );
+
+ // check value and modify it according to its type
+ TypeClass eType = aPropVal.getValueType().getTypeClass();
+ Any aNewVal;
+ sal_Bool bModify = sal_True;
+ switch( eType )
+ {
+ case TypeClass_STRING:
+ {
+ OUString aStr;
+ aPropVal >>= aStr;
+ aStr += " (Modified!)";
+ aNewVal <<= aStr;
+ break;
+ }
+ case TypeClass_DOUBLE:
+ {
+ double d(0.0);
+ aPropVal >>= d;
+ aNewVal <<= d + 1.0;
+ break;
+ }
+ case TypeClass_SHORT:
+ {
+ sal_Int16 n(0);
+ aPropVal >>= n;
+ aNewVal <<= sal_Int16( n + 1 );
+ break;
+ }
+ case TypeClass_LONG:
+ {
+ sal_Int32 n(0);
+ aPropVal >>= n;
+ aNewVal <<= sal_Int32( n + 1 );
+ break;
+ }
+ default:
+ bModify = sal_False;
+ break;
+ }
+
+ // modify only in the last iteration
+ if( nConcepts == 15 )
+ {
+ // check XExactName, switch everything to upper case
+ // (introspection uses lower case)
+ OUString aUpperUStr = aPropName.toAsciiUpperCase();
+ OUString aExactName = xExactName->getExactName( aUpperUStr );
+ if( aExactName != aPropName )
+ {
+ aErrorStr = "Property \""
+ + OUStringToOString( aPropName, RTL_TEXTENCODING_ASCII_US )
+ + "\", not found as \""
+ + OUStringToOString(aUpperUStr, RTL_TEXTENCODING_ASCII_US )
+ + "\" using XExactName";
+ OSL_ENSURE( sal_False, aErrorStr.getStr() );
+ }
+ }
+ else
+ {
+ bModify = sal_False;
+ }
+
+ // set new value, then read and return value
+ if( bModify )
+ {
+ // catch UnknownPropertyException for ReadOnly properties
+ try
+ {
+ xPropSet->setPropertyValue( aPropName, aNewVal );
+ }
+ catch(const UnknownPropertyException &)
+ {
+ }
+
+ aPropVal = xPropSet->getPropertyValue( aPropName );
+
+ OUString aStr = AnyToString( aPropVal, sal_False, xMgr );
+ OString aModifiedValStr = OUStringToOString( aStr, RTL_TEXTENCODING_ASCII_US );
+ OString aDemandedModifiedValStr = pDemandedModifiedPropVals[ i ];
+ aErrorStr = "Property \""
+ + aDemandedName
+ + "\", expected modified val >"
+ + aDemandedModifiedValStr
+ + "< found val >"
+ + aModifiedValStr
+ + "<";
+ OSL_ENSURE( aModifiedValStr == aDemandedModifiedValStr, aErrorStr.getStr() );
+ }
+
+ // check whether all properties can be found individually
+ aErrorStr = "property \""
+ + aDemandedName
+ + "\" not found with hasProperty()";
+ OUString aWDemandedName = OStringToOUString(aDemandedName, RTL_TEXTENCODING_ASCII_US );
+ sal_Bool bProperty = xAccess->hasProperty( aWDemandedName, nConcepts );
+ OSL_ENSURE( bProperty, aErrorStr.getStr() );
+
+ aErrorStr = "property \""
+ + aDemandedName
+ + "\" not equal to same Property in sequence returned by getProperties()";
+ try
+ {
+ Property aGetProp = xAccess->getProperty( aWDemandedName, nConcepts );
+ }
+ catch (const RuntimeException &)
+ {
+ aErrorStr = "property \""
+ + aDemandedName
+ + "\", exception was thrown when trying getProperty()";
+ OSL_ENSURE( sal_False, aErrorStr.getStr() );
+ }
+
+ }
+ }
+ }
+
+ // loop over all concept combinations
+ for( sal_Int32 nConcepts = 0 ; nConcepts < 128 ; nConcepts++ )
+ {
+ // The 2^6th bit stands for "the rest"
+ sal_Int32 nRealConcepts = nConcepts;
+ if( nConcepts & 0x40 )
+ nRealConcepts |= (0xFFFFFFFF - 0x3F);
+
+ // Count the number of methods there should be
+ sal_Int32 nDemandedMethCount = 0;
+ sal_Int32 iList = 0;
+ while( pMethodDefs[ iList ].pName )
+ {
+ if( pMethodDefs[ iList ].nConcept & nRealConcepts )
+ nDemandedMethCount++;
+ iList++;
+ }
+
+ // Output the method array.
+ Sequence< Reference< XIdlMethod > > aMethodSeq = xAccess->getMethods( nRealConcepts );
+ sal_Int32 nLen = aMethodSeq.getLength();
+
+ aErrorStr = "Expected to find "
+ + OString::valueOf( nDemandedMethCount )
+ + " methods but found "
+ + OString::valueOf( nLen );
+ OSL_ENSURE( nLen == nDemandedMethCount, aErrorStr.getStr() );
+
+ const Reference< XIdlMethod >* pMethods = aMethodSeq.getConstArray();
+ sal_Int32 i;
+ iList = 0;
+
+ for( i = 0 ; i < nLen ; i++ )
+ {
+ const Reference< XIdlMethod >& rxMethod = pMethods[i];
+
+ OUString aMethName = rxMethod->getName();
+ OString aNameStr = OUStringToOString(aMethName, RTL_TEXTENCODING_ASCII_US );
+
+ // locate the next matching method in the list.
+ while( pMethodDefs[ iList ].pName )
+ {
+ if( pMethodDefs[ iList ].nConcept & nRealConcepts )
+ break;
+ iList++;
+ }
+ OString aDemandedName = pMethodDefs[ iList ].pName;
+ iList++;
+
+ aErrorStr = "Expected method \""
+ + aDemandedName
+ + "\", found \""
+ + aNameStr
+ + "\"";
+ OSL_ENSURE( aNameStr == aDemandedName, aErrorStr.getStr() );
+
+ // Check that the method is really there with hasMethod.
+ aErrorStr = "method \""
+ + aDemandedName
+ + "\" not found with hasMethod()";
+ OUString aWDemandedName = OStringToOUString(aDemandedName, RTL_TEXTENCODING_ASCII_US );
+ sal_Bool bMethod = xAccess->hasMethod( aWDemandedName, nRealConcepts );
+ OSL_ENSURE( bMethod, aErrorStr.getStr() );
+
+ aErrorStr = "method \""
+ + aDemandedName
+ + "\" not equal to same method in sequence returned by getMethods()";
+ try
+ {
+ Reference< XIdlMethod > xGetMethod = xAccess->getMethod( aWDemandedName, nRealConcepts );
+ OSL_ENSURE( xGetMethod == rxMethod , aErrorStr.getStr() );
+ }
+ catch (const RuntimeException &)
+ {
+ aErrorStr = "method \""
+ + aDemandedName
+ + "\", exception was thrown when trying getMethod()";
+ OSL_ENSURE( sal_False, aErrorStr.getStr() );
+ }
+ }
+ }
+
+ // print listener class
+ Sequence< Type > aClassSeq = xAccess->getSupportedListeners();
+ sal_Int32 nLen = aClassSeq.getLength();
+
+ const Type* pListeners = aClassSeq.getConstArray();
+ for( sal_Int32 i = 0 ; i < nLen ; i++ )
+ {
+ const Type& aListenerType = pListeners[i];
+ OUString aListenerClassName = aListenerType.getTypeName();
+ }
+
+ return sal_True;
+}
+
+
+SAL_IMPLEMENT_MAIN()
+{
+ Reference< XMultiServiceFactory > xMgr( createRegistryServiceFactory( OUString("stoctest.rdb") ) );
+
+ sal_Bool bSucc = sal_False;
+ try
+ {
+ Reference< XImplementationRegistration > xImplReg(
+ xMgr->createInstance("com.sun.star.registry.ImplementationRegistration"), UNO_QUERY );
+ OSL_ENSURE( xImplReg.is(), "### no impl reg!" );
+
+ // Register services
+ OUString libName( "reflection.uno" SAL_DLLEXTENSION );
+ fprintf(stderr, "1\n" );
+ xImplReg->registerImplementation(OUString("com.sun.star.loader.SharedLibrary"),
+ libName, Reference< XSimpleRegistry >() );
+ fprintf(stderr, "2\n" );
+ Reference< XIdlReflection > xRefl( xMgr->createInstance("com.sun.star.reflection.CoreReflection"), UNO_QUERY );
+ OSL_ENSURE( xRefl.is(), "### no corereflection!" );
+
+ // Introspection
+ libName = OUString( "introspection.uno" SAL_DLLEXTENSION);
+ fprintf(stderr, "3\n" );
+ xImplReg->registerImplementation(OUString("com.sun.star.loader.SharedLibrary"),
+ libName, Reference< XSimpleRegistry >() );
+ fprintf(stderr, "4\n" );
+ Reference< XIntrospection > xIntrosp( xMgr->createInstance("com.sun.star.beans.Introspection"), UNO_QUERY );
+ OSL_ENSURE( xRefl.is(), "### no corereflection!" );
+
+ fprintf(stderr, "before test_introsp\n" );
+ bSucc = test_introsp( xMgr, xRefl, xIntrosp );
+ fprintf(stderr, "after test_introsp\n" );
+ }
+ catch (const Exception & rExc)
+ {
+ DBG_UNHANDLED_EXCEPTION("stoc", "### exception occurred: " << rExc );
+ }
+
+ Reference< XComponent >( xMgr, UNO_QUERY )->dispose();
+
+ printf( "testintrosp %s !\n", (bSucc ? "succeeded" : "failed") );
+ return (bSucc ? 0 : -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testintrosp.idl b/stoc/test/testintrosp.idl
new file mode 100644
index 0000000000..fbb53ffb7e
--- /dev/null
+++ b/stoc/test/testintrosp.idl
@@ -0,0 +1,187 @@
+/* -*- 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 .
+ */
+
+module ModuleA
+{
+//module com { module sun { module star { module beans {
+
+//interface XPropertyChangeListener;
+//interface XPropertiesChangeListener;
+
+
+/** This is a test interface for introspection.
+
+ <p>IMPORTANT: FOR TEST ONLY!
+
+ <p>The following interface is just for testing purposes. It will not
+ stay in the product. It is only used as an exportable test class,
+ i.e. for BASIC integration.
+
+ @deprecated
+*/
+interface XIntroTest: com::sun::star::uno::XInterface
+{
+
+ /** contains the ID-String of the implementation.
+ */
+ [attribute] string ObjectName;
+
+
+ /** contains the first name of a person.
+ */
+ [readonly, attribute] string FirstName;
+
+
+ /** contains the last name of a person.
+ */
+ [readonly, attribute] string LastName;
+
+
+ /** contains the age of a person.
+ */
+ [readonly, attribute] short Age;
+
+
+ /** contains the number of children person has.
+ */
+ [attribute] short ChildrenCount;
+
+
+ /** contains a struct of type Property.
+ */
+ [attribute] com::sun::star::beans::Property FirstStruct;
+
+
+ /** contains a struct of type PropertyValue.
+ */
+ [attribute] com::sun::star::beans::PropertyValue SecondStruct;
+
+
+ /** output method
+ */
+ void writeln( [in] string Text );
+
+
+ /** ...
+ */
+ long getDroenk();
+
+
+ /** get further introspection test objects
+ */
+ XIntroTest getIntroTest();
+ //com::sun::star::beans::XIntroTest getIntroTest();
+
+
+ /** !!! No property, because parameter exists
+ */
+ long getUps( [in] long l );
+
+
+ /** ...
+ */
+ void setDroenk( [in] long l );
+
+
+ /** ...
+ */
+ short getBla();
+
+
+ /** !!! Not the set method for property Bla, because param type != return type.
+ */
+ void setBla( [in] long n );
+
+
+ /** ...
+ */
+ short getBlub();
+
+
+ /** ...
+ */
+ void setBlub( [in] short n );
+
+
+ /** ...
+ */
+ short getGulp();
+
+
+ /** !!! Not the set method for property Gulp, because return type != void.
+ */
+ short setGulp( [in] short n );
+
+
+ /** ...
+ */
+ com::sun::star::uno::TypeClass getTypeClass( [in] short n );
+
+
+ /** ...
+ */
+ void setTypeClass( [in] com::sun::star::uno::TypeClass t,
+ [in] double d1,
+ [in] double d2 );
+
+
+ /**
+ */
+ sequence<string> getStrings();
+
+
+ /** ...
+ */
+ void setStrings( [in] sequence<string> Strings );
+
+
+ /** ...
+ */
+ void setStringsPerMethod( [in] sequence<string> Strings,
+ [in] short n );
+
+
+ /**
+ */
+ sequence< sequence< sequence< short > > > getMultiSequence();
+
+
+ /** ...
+ */
+ void setMultiSequence( [in] sequence< sequence< sequence< short > > > Seq );
+
+
+ /**Add a PropertiesChangeListener
+ */
+ void addPropertiesChangeListener( [in] sequence< string > PropertyNames,
+ [in] com::sun::star::beans::XPropertiesChangeListener Listener );
+
+
+ /**Remove a PropertiesChangeListener
+ */
+ void removePropertiesChangeListener( [in] com::sun::star::beans::XPropertiesChangeListener Listener );
+
+};
+
+
+
+};
+//}; }; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testloader.cxx b/stoc/test/testloader.cxx
new file mode 100644
index 0000000000..beb77e7d96
--- /dev/null
+++ b/stoc/test/testloader.cxx
@@ -0,0 +1,120 @@
+/* -*- 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 <osl/module.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/loader/XImplementationLoader.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/factory.hxx>
+
+#if defined ( UNX )
+#include <limits.h>
+#define _MAX_PATH PATH_MAX
+#endif
+
+using namespace css::uno;
+using namespace css::loader;
+using namespace css::lang;
+using namespace osl;
+using namespace cppu;
+
+
+class EmptyComponentContext : public WeakImplHelper< XComponentContext >
+{
+public:
+ virtual Any SAL_CALL getValueByName( const OUString& /*Name*/ )
+ throw (RuntimeException)
+ {
+ return Any();
+ }
+ virtual Reference< XMultiComponentFactory > SAL_CALL getServiceManager( )
+ throw (RuntimeException)
+ {
+ return Reference< XMultiComponentFactory > ();
+ }
+
+};
+
+
+SAL_IMPLEMENT_MAIN()
+{
+ Reference<XInterface> xIFace;
+
+ Module module;
+
+ OUString dllName(
+ "bootstrap.uno" SAL_DLLEXTENSION );
+
+ if (module.load(dllName))
+ {
+ // try to get provider from module
+ component_getFactoryFunc pCompFactoryFunc = (component_getFactoryFunc)
+ module.getFunctionSymbol( OUString(COMPONENT_GETFACTORY) );
+
+ if (pCompFactoryFunc)
+ {
+ XSingleServiceFactory * pRet = (XSingleServiceFactory *)(*pCompFactoryFunc)(
+ "com.sun.star.comp.stoc.DLLComponentLoader", 0, 0 );
+ if (pRet)
+ {
+ xIFace = pRet;
+ pRet->release();
+ }
+ }
+ }
+
+ OSL_ENSURE( xIFace.is(), "testloader error1");
+
+ Reference<XSingleComponentFactory> xFactory( Reference<XSingleComponentFactory>::query(xIFace) );
+
+ OSL_ENSURE( xFactory.is(), "testloader error2");
+
+ Reference<XInterface> xLoader = xFactory->createInstanceWithContext( new EmptyComponentContext );
+
+ OSL_ENSURE( xLoader.is(), "testloader error3");
+
+ Reference<XServiceInfo> xServInfo( Reference<XServiceInfo>::query(xLoader) );
+
+ OSL_ENSURE( xServInfo.is(), "testloader error4");
+
+ OSL_ENSURE( xServInfo->getImplementationName() == "com.sun.star.comp.stoc.DLLComponentLoader", "testloader error5");
+ OSL_ENSURE( xServInfo->supportsService("com.sun.star.loader.SharedLibrary"), "testloader error6");
+ OSL_ENSURE( xServInfo->getSupportedServiceNames().getLength() == 1, "testloader error7");
+
+ xIFace.clear();
+ xFactory.clear();
+ xLoader.clear();
+ xServInfo.clear();
+
+ printf("Test Dll ComponentLoader, OK!\n");
+
+ return 0;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testproxyfac.cxx b/stoc/test/testproxyfac.cxx
new file mode 100644
index 0000000000..befc67ae8e
--- /dev/null
+++ b/stoc/test/testproxyfac.cxx
@@ -0,0 +1,359 @@
+/* -*- 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/main.h>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <rtl/alloc.h>
+#include <uno/environment.hxx>
+#include <uno/lbnames.h>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/XCurrentContext.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/reflection/XProxyFactory.hpp>
+
+#include <stdio.h>
+
+
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::com::sun::star;
+using namespace css::uno;
+
+
+typedef WeakImplHelper< lang::XServiceInfo,
+ XCurrentContext,
+ reflection::XProxyFactory > t_impl;
+
+
+class TargetObject : public t_impl
+{
+public:
+ static int s_obj;
+
+ virtual ~TargetObject() {
+ --s_obj;
+ SAL_INFO("stoc", "~TargetObject()" );
+ }
+ TargetObject()
+ { ++s_obj; }
+
+ Any SAL_CALL queryInterface( Type const & type )
+ throw (RuntimeException);
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() throw (RuntimeException)
+ { return OUString("target"); }
+ virtual sal_Bool SAL_CALL supportsService( const OUString & /*rServiceName*/ )
+ throw (RuntimeException)
+ { return sal_False; }
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
+ throw (RuntimeException)
+ { return Sequence< OUString >(); }
+ // XProxyFactory
+ virtual Reference< XAggregation > SAL_CALL createProxy(
+ const Reference< XInterface > & xTarget ) throw (RuntimeException)
+ { return Reference< XAggregation >( xTarget, UNO_QUERY ); }
+ // XCurrentContext
+ virtual Any SAL_CALL getValueByName( OUString const & name )
+ throw (RuntimeException)
+ { return makeAny( name ); }
+};
+
+
+Any TargetObject::queryInterface( Type const & type )
+ throw (RuntimeException)
+{
+ Any ret( t_impl::queryInterface( type ) );
+ if (ret.hasValue())
+ return ret;
+ throw lang::DisposedException(
+ OUString( "my test exception" ),
+ getXWeak() );
+}
+
+int TargetObject::s_obj = 0;
+
+
+class TestMaster : public WeakImplHelper< lang::XServiceInfo >
+{
+ Reference< XAggregation > m_xProxyTarget;
+ Reference<lang::XServiceInfo> m_xOtherProxyTargetBeforeSetDelegator;
+
+ inline TestMaster() { ++s_obj; }
+public:
+ static int s_obj;
+ static Reference< XInterface > create(
+ Reference< reflection::XProxyFactory > const & xProxyFac );
+ static Reference< XInterface > create(
+ Reference< XInterface > const & xTarget,
+ Reference< reflection::XProxyFactory > const & xProxyFac );
+
+ virtual ~TestMaster() {
+ --s_obj;
+ SAL_INFO("stoc", "~TestMaster()" );
+ }
+
+ virtual Any SAL_CALL queryInterface( const Type & rType )
+ throw (RuntimeException)
+ {
+ Any aRet(
+ WeakImplHelper< lang::XServiceInfo >::queryInterface( rType ) );
+ if (aRet.hasValue())
+ return aRet;
+ return m_xProxyTarget->queryAggregation( rType );
+ }
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() throw (RuntimeException)
+ { return OUString("master"); }
+ virtual sal_Bool SAL_CALL supportsService( const OUString & /*rServiceName*/ )
+ throw (RuntimeException)
+ { return sal_False; }
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames()
+ throw (RuntimeException)
+ { return Sequence< OUString >(); }
+};
+
+int TestMaster::s_obj = 0;
+
+
+Reference< XInterface > TestMaster::create(
+ Reference< XInterface > const & xTarget,
+ Reference< reflection::XProxyFactory > const & xProxyFac )
+{
+ TestMaster * that = new TestMaster;
+ Reference< XInterface > xRet( getXWeak( that ) );
+ {
+ Reference< XAggregation > xAgg( xProxyFac->createProxy( xTarget ) );
+ // ownership take over
+ that->m_xProxyTarget.set( xAgg, UNO_QUERY_THROW );
+ that->m_xOtherProxyTargetBeforeSetDelegator.set(
+ that->m_xProxyTarget, UNO_QUERY );
+ }
+ that->m_xProxyTarget->setDelegator( xRet );
+ return xRet;
+}
+
+Reference< XInterface > TestMaster::create(
+ Reference< reflection::XProxyFactory > const & xProxyFac )
+{
+ return create(
+ getXWeak( new TargetObject ), xProxyFac );
+}
+
+
+static void test_proxyfac_(
+ Reference< XInterface > const & xMaster, OUString const & test,
+ Reference< reflection::XProxyFactory > const & /*xProxyFac*/ )
+{
+ (void)test;
+ Reference< lang::XServiceInfo > xMaster_XServiceInfo(
+ xMaster, UNO_QUERY_THROW );
+ OSL_ASSERT( xMaster_XServiceInfo->getImplementationName().equals( test ) );
+
+ Reference< reflection::XProxyFactory > xTarget( xMaster, UNO_QUERY_THROW );
+ Reference< XCurrentContext > xTarget_XCurrentContext(
+ xTarget, UNO_QUERY_THROW );
+ Reference< XCurrentContext > xMaster_XCurrentContext(
+ xMaster, UNO_QUERY_THROW );
+
+ OSL_ASSERT(
+ xTarget_XCurrentContext->getValueByName( test ) == makeAny( test ) );
+ OSL_ASSERT(
+ xMaster_XCurrentContext->getValueByName( test ) == makeAny( test ) );
+
+ Reference< XAggregation > xFakeAgg( xTarget->createProxy( xTarget ) );
+ if (xFakeAgg.is())
+ {
+ OSL_ASSERT( xTarget == xFakeAgg );
+ OSL_ASSERT( xMaster == xFakeAgg );
+ }
+
+ Reference< lang::XServiceInfo > xTarget_XServiceInfo(
+ xTarget, UNO_QUERY_THROW );
+ OSL_ASSERT( xTarget_XServiceInfo->getImplementationName().equals( test ) );
+ Reference< lang::XServiceInfo > xTarget_XServiceInfo2(
+ xTarget, UNO_QUERY_THROW );
+ OSL_ASSERT( xTarget_XServiceInfo2.get() == xTarget_XServiceInfo.get() );
+
+ OSL_ASSERT( xTarget == xTarget_XCurrentContext );
+ OSL_ASSERT( xTarget_XCurrentContext == xMaster );
+ OSL_ASSERT(
+ xTarget_XCurrentContext.get() == xMaster_XCurrentContext.get() );
+ OSL_ASSERT( xTarget_XCurrentContext == xMaster );
+ OSL_ASSERT( xTarget == xMaster );
+ OSL_ASSERT( xTarget_XServiceInfo.get() == xMaster_XServiceInfo.get() );
+ OSL_ASSERT( xTarget_XServiceInfo == xMaster );
+ OSL_ASSERT( xMaster_XServiceInfo == xMaster );
+
+ try
+ {
+ Reference< registry::XRegistryKey >(
+ xMaster, UNO_QUERY_THROW );
+ }
+ catch (const lang::DisposedException & exc)
+ {
+ if ( exc.Message != "my test exception" )
+ throw;
+ }
+}
+
+static void test_proxyfac(
+ Reference< XInterface > const & xMaster, OUString const & test,
+ Reference< reflection::XProxyFactory > const & xProxyFac )
+{
+ test_proxyfac_( xMaster, test, xProxyFac );
+ // proxy the proxy...
+ Reference< XInterface > xNew( TestMaster::create( xMaster, xProxyFac ) );
+ test_proxyfac_(
+ xNew, OUString( "master" ), xProxyFac );
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ bool success = true;
+
+ Environment cpp_env;
+ OUString cpp( CPPU_CURRENT_LANGUAGE_BINDING_NAME );
+ uno_getEnvironment(
+ reinterpret_cast< uno_Environment ** >( &cpp_env ),
+ cpp.pData, 0 );
+ OSL_ENSURE( cpp_env.is(), "### cannot get C++ uno env!" );
+
+ {
+ Reference< lang::XMultiServiceFactory > xMgr(
+ createRegistryServiceFactory(
+ OUString( "stoctest.rdb" ) ) );
+
+ try
+ {
+ Reference< registry::XImplementationRegistration > xImplReg(
+ xMgr->createInstance( "com.sun.star.registry.ImplementationRegistration" ),
+ UNO_QUERY );
+ OSL_ENSURE( xImplReg.is(), "### no impl reg!" );
+
+ OUString aLibName(
+ "proxyfac.uno" SAL_DLLEXTENSION );
+ xImplReg->registerImplementation(
+ OUString( "com.sun.star.loader.SharedLibrary" ),
+ aLibName, Reference< registry::XSimpleRegistry >() );
+
+ Reference< reflection::XProxyFactory > xProxyFac(
+ xMgr->createInstance("com.sun.star.reflection.ProxyFactory"),
+ UNO_QUERY_THROW );
+
+ Reference< XAggregation > x(
+ xProxyFac->createProxy(
+ getXWeak( new TargetObject ) ) );
+ // no call
+
+ {
+ Reference< XInterface > xMaster( TestMaster::create( xProxyFac ) );
+ test_proxyfac(
+ xMaster,
+ OUString( "master" ),
+ xProxyFac );
+ }
+ {
+ Reference< XInterface > xMaster( TestMaster::create( xProxyFac ) );
+ // no call
+ }
+
+ {
+ Reference< XInterface > xMaster( TestMaster::create( xProxyFac ) );
+ Reference< reflection::XProxyFactory > xSlave_lives_alone(
+ xMaster, UNO_QUERY_THROW );
+ xMaster.clear();
+ test_proxyfac(
+ xSlave_lives_alone,
+ OUString( "master" ),
+ xProxyFac );
+ uno_dumpEnvironment( stdout, cpp_env.get(), 0 );
+ }
+ {
+ Reference< XInterface > xMaster( TestMaster::create( xProxyFac ) );
+ Reference< reflection::XProxyFactory > xSlave_lives_alone(
+ xMaster, UNO_QUERY_THROW );
+ // no call
+ }
+
+ test_proxyfac(
+ xProxyFac->createProxy(
+ getXWeak( new TargetObject ) ),
+ OUString( "target" ),
+ xProxyFac );
+ uno_dumpEnvironment( stdout, cpp_env.get(), 0 );
+ }
+ catch (const Exception & rExc)
+ {
+ (void)rExc;
+ OSL_ENSURE(
+ ! __FILE__,
+ OUStringToOString(
+ rExc.Message, RTL_TEXTENCODING_ASCII_US ).getStr() );
+ success = false;
+ }
+
+
+ Reference< lang::XComponent > xComp;
+ Reference< beans::XPropertySet >(
+ xMgr, UNO_QUERY_THROW )->getPropertyValue(
+ OUString( "DefaultContext" ) )
+ >>= xComp;
+ xComp->dispose();
+ }
+
+ if (TestMaster::s_obj != 0)
+ fprintf( stderr, "TestMaster objects: %d\n", TestMaster::s_obj );
+ if (TargetObject::s_obj != 0)
+ fprintf( stderr, "TargetObject objects: %d\n", TargetObject::s_obj );
+
+ uno_dumpEnvironment( stdout, cpp_env.get(), 0 );
+ void ** ppInterfaces;
+ sal_Int32 len;
+ uno_ExtEnvironment * env = cpp_env.get()->pExtEnv;
+ (*env->getRegisteredInterfaces)(
+ env, &ppInterfaces, &len, rtl_allocateMemory );
+ if (len != 0)
+ fprintf( stderr, "%d registered C++ interfaces left!\n", len );
+
+ success &= (TestMaster::s_obj == 0 &&
+ TargetObject::s_obj == 0 &&
+ len == 0);
+ if (success)
+ {
+ printf( "testproxyfac succeeded.\n" );
+ return 0;
+ }
+ else
+ {
+ fprintf( stderr, "testproxyfac failed!\n" );
+ return 1;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testregistry.cxx b/stoc/test/testregistry.cxx
new file mode 100644
index 0000000000..ef0d0a91d5
--- /dev/null
+++ b/stoc/test/testregistry.cxx
@@ -0,0 +1,670 @@
+/* -*- 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 <sal/main.h>
+#include <osl/module.hxx>
+#include <osl/diagnose.h>
+#include <osl/process.h>
+#include <registry/registry.hxx>
+
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/bootstrap.hxx>
+#include <cppuhelper/servicefactory.hxx>
+
+#include <com/sun/star/lang/XComponent.hpp>
+
+#if defined ( UNX )
+#include <limits.h>
+#define _MAX_PATH PATH_MAX
+#endif
+
+using namespace com::sun::star;
+using namespace css::uno;
+using namespace css::registry;
+using namespace css::lang;
+using namespace css::beans;
+using namespace osl;
+
+
+namespace stoc_impreg
+{
+void SAL_CALL mergeKeys(
+Reference< registry::XRegistryKey > const & xDest,
+Reference< registry::XRegistryKey > const & xSource );
+}
+static void mergeKeys(
+Reference< registry::XSimpleRegistry > const & xDest,
+OUString const & rBaseNode,
+OUString const & rURL )
+{
+Reference< registry::XRegistryKey > xDestRoot( xDest->getRootKey() );
+Reference< registry::XRegistryKey > xDestKey;
+if (rBaseNode.getLength())
+{
+xDestKey = xDestRoot->createKey( rBaseNode );
+xDestRoot->closeKey();
+}
+else
+{
+xDestKey = xDestRoot;
+}
+Reference< registry::XSimpleRegistry > xSimReg( ::cppu::createSimpleRegistry() );
+xSimReg->open( rURL, sal_True, sal_False );
+OSL_ASSERT( xSimReg->isValid() );
+Reference< registry::XRegistryKey > xSourceKey( xSimReg->getRootKey() );
+::stoc_impreg::mergeKeys( xDestKey, xSourceKey );
+xSourceKey->closeKey();
+xSimReg->close();
+xDestKey->closeKey();
+}
+
+
+OString userRegEnv("STAR_USER_REGISTRY=");
+
+OUString getExePath()
+{
+OUString exe;
+OSL_VERIFY( osl_getExecutableFile( &exe.pData ) == osl_Process_E_None);
+#if defined(_WIN32)
+exe = exe.copy(0, exe.getLength() - 16);
+#else
+exe = exe.copy(0, exe.getLength() - 12);
+#endif
+return exe;
+}
+
+void setStarUserRegistry()
+{
+Registry *myRegistry = new Registry();
+
+RegistryKey rootKey, rKey, rKey2;
+
+OUString userReg = getExePath();
+userReg += "user.rdb";
+if(myRegistry->open(userReg, RegAccessMode::READWRITE))
+{
+OSL_VERIFY(!myRegistry->create(userReg));
+}
+
+OSL_VERIFY(!myRegistry->close());
+delete myRegistry;
+
+userRegEnv += OUStringToOString(userReg, RTL_TEXTENCODING_ASCII_US);
+ putenv((char *)userRegEnv.getStr());
+}
+
+void setLinkInDefaultRegistry(const OUString& linkName, const OUString& linkTarget)
+{
+ Registry *myRegistry = new Registry();
+
+ RegistryKey rootKey;
+
+ OUString appReg = getExePath();
+ appReg += "stoctest.rdb";
+
+ OSL_VERIFY(!myRegistry->open(appReg, RegAccessMode::READWRITE));
+ OSL_VERIFY(!myRegistry->openRootKey(rootKey));
+
+ OSL_VERIFY(!rootKey.createLink(linkName, linkTarget));
+
+ OSL_VERIFY(!rootKey.closeKey());
+ OSL_VERIFY(!myRegistry->close());
+
+ delete myRegistry;
+}
+
+
+void test_SimpleRegistry(
+ OUString const & testreg,
+ OUString const & testreg2,
+ bool bMergeDifferently = true )
+{
+ Reference<XInterface> xIFace;
+ Module module;
+
+ OUString dllName(
+ "simplereg.uno" SAL_DLLEXTENSION );
+
+ if (module.load(dllName))
+ {
+ // try to get provider from module
+ component_getFactoryFunc pCompFactoryFunc = (component_getFactoryFunc)
+ module.getFunctionSymbol( OUString(COMPONENT_GETFACTORY) );
+
+ if (pCompFactoryFunc)
+ {
+ XSingleServiceFactory * pRet = (XSingleServiceFactory *)
+ (*pCompFactoryFunc)(
+ "com.sun.star.comp.stoc.SimpleRegistry", 0, 0 );
+ if (pRet)
+ {
+ xIFace = pRet;
+ pRet->release();
+ }
+ }
+ }
+
+ OSL_ENSURE( xIFace.is(), "test_SimpleRegistry error1");
+
+ Reference<XSingleServiceFactory> xFactory( Reference<XSingleServiceFactory>::query(xIFace) );
+ xIFace.clear();
+
+ OSL_ENSURE( xFactory.is(), "testloader error11");
+
+ Reference<XInterface> xIFace2 = xFactory->createInstance();
+ xFactory.clear();
+
+ OSL_ENSURE( xIFace2.is(), "testloader error12");
+
+ Reference<XServiceInfo> xServInfo( Reference<XServiceInfo>::query(xIFace2) );
+
+ OSL_ENSURE( xServInfo.is(), "test_SimpleRegistry error2");
+
+ OSL_ENSURE( xServInfo->getImplementationName() == "com.sun.star.comp.stoc.SimpleRegistry", "test_SimpleRegistry error3");
+ OSL_ENSURE( xServInfo->supportsService("com.sun.star.registry.SimpleRegistry"), "test_SimpleRegistry error4");
+ OSL_ENSURE( xServInfo->getSupportedServiceNames().getLength() == 1, "test_SimpleRegistry error5");
+ xServInfo.clear();
+
+ Reference<XSimpleRegistry> xReg( Reference<XSimpleRegistry>::query(xIFace2) );
+ xIFace2.clear();
+
+ OSL_ENSURE( xReg.is(), "test_SimpleRegistry error6");
+
+ try
+ {
+ xReg->open(testreg, sal_False, sal_True);
+
+ OSL_ENSURE( xReg->isValid() != sal_False, "test_SimpleRegistry error 7" );
+ OSL_ENSURE( xReg->isReadOnly() == sal_False, "test_SimpleRegistry error 8" );
+
+ Reference<XRegistryKey> xRootKey(xReg->getRootKey());
+ OSL_ENSURE( xRootKey->isValid(), "test_SimpleRegistry error 9" );
+
+ Reference<XRegistryKey> xKey = xRootKey->createKey(OUString( "FirstKey" ));
+
+ Reference<XRegistryKey> xSubKey = xKey->createKey(OUString( "FirstSubKey" ));
+ xSubKey->setLongValue(123456789);
+
+ xSubKey = xKey->createKey(OUString( "SecondSubKey" ));
+ xSubKey->setAsciiValue(OUString( "I'm an ascii value" ));
+
+ xSubKey = xKey->createKey(OUString( "ThirdSubKey" ));
+ xSubKey->setStringValue(OUString( "I'm a Unicode value" ));
+
+ xSubKey = xKey->createKey(OUString( "FourthSubKey" ));
+ Sequence<sal_Int8> aSeq((sal_Int8*)"I'm a binary value", 25);
+ xSubKey->setBinaryValue(aSeq);
+
+ Sequence<OUString> seqNames = xKey->getKeyNames();
+ Sequence< Reference<XRegistryKey> > seqKeys = xKey->openKeys();
+
+ OUString name;
+ for (sal_Int32 i=0; i < seqNames.getLength(); i++)
+ {
+ name = seqNames.getArray()[i];
+ xSubKey = seqKeys.getArray()[i];
+
+ if (name == "/FirstKey/FirstSubKey" )
+ {
+ OSL_ENSURE( xSubKey->getLongValue() == 123456789,
+ "test_SimpleRegistry error 10" );
+ } else
+ if (name == "/FirstKey/SecondSubKey" )
+ {
+ OSL_ENSURE( xSubKey->getAsciiValue() == "I'm an ascii value",
+ "test_SimpleRegistry error 11" );
+ } else
+ if (name == "/FirstKey/ThirdSubKey" )
+ {
+ OSL_ENSURE( xSubKey->getStringValue() == "I'm a Unicode value",
+ "test_SimpleRegistry error 12" );
+ } else
+ if (name == "/FirstKey/FourthSubKey" )
+ {
+ Sequence<sal_Int8> seqByte = xSubKey->getBinaryValue();
+ OSL_ENSURE(!strcmp(((const char*)seqByte.getArray()), "I'm a binary value"),
+ "test_SimpleRegistry error 13" );
+ }
+
+ seqKeys.getArray()[i]->closeKey();
+ }
+
+ xKey->closeKey();
+
+ xRootKey->deleteKey(OUString( "FirstKey" ));
+ xRootKey->createKey(OUString( "SecondFirstKey" ));
+
+ xKey = xRootKey->createKey(OUString( "SecondKey" ));
+ sal_Int32 pLongs[3] = {123, 456, 789};
+ Sequence<sal_Int32> seqLongs(pLongs, 3);
+ xKey->setLongListValue(seqLongs);
+
+ Sequence<sal_Int32> seqLongs2;
+ seqLongs2 = xKey->getLongListValue();
+ OSL_ENSURE( seqLongs.getLength() == 3, "test_SimpleRegistry error 14" );
+ OSL_ENSURE( seqLongs.getArray()[0] == 123, "test_SimpleRegistry error 15" );
+ OSL_ENSURE( seqLongs.getArray()[1] == 456, "test_SimpleRegistry error 16" );
+ OSL_ENSURE( seqLongs.getArray()[2] == 789, "test_SimpleRegistry error 17" );
+
+
+ xKey = xRootKey->createKey(OUString( "ThirdKey" ));
+ OUString pAscii[3];
+ pAscii[0] = "Hello";
+ pAscii[1] = "here I";
+ pAscii[2] = "come";
+
+ Sequence<OUString> seqAscii(pAscii, 3);
+ xKey->setAsciiListValue(seqAscii);
+
+ Sequence<OUString> seqAscii2;
+ seqAscii2 = xKey->getAsciiListValue();
+ OSL_ENSURE( seqAscii2.getLength() == 3, "test_SimpleRegistry error 18" );
+ OSL_ENSURE( seqAscii2.getArray()[0] == "Hello", "test_SimpleRegistry error 19");
+ OSL_ENSURE( seqAscii2.getArray()[1] == "here I", "test_SimpleRegistry error 20");
+ OSL_ENSURE( seqAscii2.getArray()[2] == "come", "test_SimpleRegistry error 21");
+
+ xKey = xRootKey->createKey(OUString( "FourthKey" ));
+ OUString pUnicode[3];
+ pUnicode[0] = "Hello";
+ pUnicode[1] = "here I";
+ pUnicode[2] = "come as unicode";
+
+ Sequence<OUString> seqUnicode(pUnicode, 3);
+ xKey->setStringListValue(seqUnicode);
+
+ Sequence<OUString> seqUnicode2;
+ seqUnicode2 = xKey->getStringListValue();
+ OSL_ENSURE( seqUnicode2.getLength() == 3, "test_SimpleRegistry error 22" );
+ OSL_ENSURE( seqUnicode2.getArray()[0] == "Hello", "test_SimpleRegistry error 23");
+ OSL_ENSURE( seqUnicode2.getArray()[1] == "here I", "test_SimpleRegistry error 24");
+ OSL_ENSURE( seqUnicode2.getArray()[2] == "come as unicode", "test_SimpleRegistry error 25");
+
+
+ xReg->open(testreg2, sal_False, sal_True);
+ OSL_ENSURE( xReg->isValid() != sal_False, "test_SimpleRegistry error 25" );
+ xRootKey = xReg->getRootKey();
+ xKey = xRootKey->createKey(OUString( "ThirdKey/FirstSubKey/WithSubSubKey" ));
+ xKey->closeKey();
+ OSL_VERIFY(
+ xRootKey->createLink(
+ OUString( "LinkTest" ),
+ OUString( "/ThirdKey/FirstSubKey/WithSubSubKey" )) );
+ xRootKey->closeKey();
+ xReg->close();
+
+ xReg->open(testreg, sal_False, sal_False);
+ OSL_ENSURE( xReg->isValid() != sal_False, "test_SimpleRegistry error 26" );
+
+ if (bMergeDifferently)
+ {
+ mergeKeys(
+ xReg,
+ OUString(),
+ testreg2 );
+ }
+ else
+ {
+ xReg->mergeKey(OUString(), testreg2);
+ }
+
+ xRootKey = xReg->getRootKey();
+ xKey = xRootKey->openKey("LinkTest");
+ OSL_ENSURE( xKey.is() && xKey->isValid() && xKey->getKeyName() == "/ThirdKey/FirstSubKey/WithSubSubKey", "test_SimpleRegistry error 1213" );
+ xKey->closeKey();
+ OSL_ENSURE(
+ xRootKey->getKeyType( OUString( "LinkTest" ) ) ==
+ registry::RegistryKeyType_LINK,
+ "test_SimpleRegistry error 1214" );
+
+ xKey = xRootKey->openKey("FirstKey/SecondSubKey");
+ OSL_ENSURE( !xKey.is(), "test_SimpleRegistry error 27" );
+
+ // Test Links
+ xKey = xRootKey->createKey(OUString( "FifthKey" ));
+ xKey->createLink(OUString( "MyFirstLink" ),
+ OUString( "/ThirdKey/FirstSubKey" ));
+
+ xKey = xRootKey->openKey("/FifthKey/MyFirstLink");
+ OSL_ENSURE( xKey->isValid(), "test_SimpleRegistry error 27" );
+ OSL_ENSURE( xKey->getKeyName() == "/ThirdKey/FirstSubKey", "test_SimpleRegistry error 28" );
+
+ xKey->createLink(OUString( "/WithSubSubKey/MyFourthLink" ),
+ OUString( "/FourthKey/MySecondLink" ));
+
+ OSL_ENSURE( xKey->getLinkTarget(OUString( "/WithSubSubKey/MyFourthLink" ))
+ == "/FourthKey/MySecondLink", "test_SimpleRegistry error 29" );
+
+ try
+ {
+ OSL_ENSURE( xKey->getResolvedName(OUString( "/WithSubSubKey/MyFourthLink/BlaBlaBla" ))
+ == "/FourthKey/MySecondLink/BlaBlaBla", "test_SimpleRegistry error 30" );
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+
+ xRootKey->createLink(OUString( "/FourthKey/MySecondLink" ),
+ OUString( "/SixthKey/MyThirdLink" ));
+ xKey = xRootKey->createKey(OUString( "SixthKey" ));
+ xKey->createLink(OUString( "MyThirdLink" ),
+ OUString( "/FourthKey/MySecondLink" ));
+
+ xKey = xRootKey->createKey(OUString( "/SixthKey/SixthSubKey" ));
+
+ try
+ {
+ xRootKey->openKey("/FifthKey/MyFirstLink/WithSubSubKey/MyFourthLink");
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+
+ OSL_ENSURE( xRootKey->getLinkTarget(OUString( "/FifthKey/MyFirstLink/WithSubSubKey/MyFourthLink" ))
+ == "/FourthKey/MySecondLink", "test_SimpleRegistry error 31" );
+
+ xRootKey->deleteLink(OUString( "/FifthKey/MyFirstLink/WithSubSubKey/MyFourthLink" ));
+
+ xRootKey->createLink(OUString( "/FourthKey/MySecondLink" ),
+ OUString( "/ThirdKey/FirstSubKey/WithSubSubKey" ));
+
+ xKey = xRootKey->openKey("SixthKey");
+ seqNames = xKey->getKeyNames();
+ seqKeys = xKey->openKeys();
+
+ OSL_ENSURE( seqNames.getArray()[0] == "/SixthKey/SixthSubKey",
+ "test_SimpleRegistry error 32" );
+ OSL_ENSURE( seqNames.getArray()[1] == "/SixthKey/MyThirdLink",
+ "test_SimpleRegistry error 33" );
+
+ OSL_ENSURE( seqKeys.getArray()[0]->getKeyName() == "/SixthKey/SixthSubKey",
+ "test_SimpleRegistry error 34" );
+ OSL_ENSURE( seqKeys.getArray()[1]->getKeyName() == "/ThirdKey/FirstSubKey/WithSubSubKey",
+ "test_SimpleRegistry error 35" );
+
+ xRootKey->deleteLink(OUString( "/FourthKey/MySecondLink" ));
+ xRootKey->closeKey();
+ }
+ catch(InvalidRegistryException&)
+ {
+ OSL_ENSURE(0, "exception InvalidRegistryExcption raised while doing test_SimpleRegistry");
+ }
+ catch(InvalidValueException&)
+ {
+ OSL_ENSURE(0, "exception InvalidValueExcption raised while doing test_SimpleRegistry()");
+ }
+
+ xReg.clear();
+
+ printf("Test SimpleRegistry, OK!\n");
+}
+
+
+void test_DefaultRegistry(
+ OUString const & testreg,
+ OUString const & testreg2,
+ bool bMergeDifferently = false )
+{
+ // Test NestedRegistry
+ OUString exePath( getExePath() );
+ OUString userRdb(exePath);
+ OUString applicatRdb(exePath);
+
+ userRdb += "user.rdb";
+ applicatRdb += "stoctest.rdb";
+
+ Reference < XMultiServiceFactory > rSMgr = ::cppu::createRegistryServiceFactory( userRdb, applicatRdb, sal_False, OUString());
+ //OUString("//./e:/src596/stoc/wntmsci3/bin") );
+
+ Reference< XPropertySet > xPropSet( rSMgr, UNO_QUERY);
+ OSL_ENSURE( xPropSet.is(), "test_DefaultRegistry error0");
+
+ Any aPropertyAny( xPropSet->getPropertyValue("Registry") );
+ OSL_ENSURE( aPropertyAny.hasValue(), "test_DefaultRegistry error1");
+
+ Reference<XSimpleRegistry> xReg;
+ aPropertyAny >>= xReg;
+ OSL_ENSURE( xReg.is(), "test_DefaultRegistry error1a");
+
+ Reference<XServiceInfo> xServInfo( Reference<XServiceInfo>::query(xReg) );
+
+ OSL_ENSURE( xServInfo.is(), "test_DefaultRegistry error2");
+
+ OSL_ENSURE( xServInfo->getImplementationName() == "com.sun.star.comp.stoc.NestedRegistry", "test_DefaultRegistry error3");
+ OSL_ENSURE( xServInfo->supportsService("com.sun.star.registry.NestedRegistry"), "test_DefaultRegistry error4");
+ OSL_ENSURE( xServInfo->getSupportedServiceNames().getLength() == 1, "test_DefaultRegistry error5");
+ xServInfo.clear();
+
+ OSL_ENSURE( xReg.is(), "test_DefaultRegistry error6");
+
+ try
+ {
+ Reference<XRegistryKey> xRootKey(xReg->getRootKey());
+
+ Reference<XRegistryKey> xKey = xRootKey->openKey("/UCR/com/sun/star/registry/XSimpleRegistry");
+
+ OSL_ENSURE( xKey->getKeyName() == "/UCR/com/sun/star/registry/XSimpleRegistry",
+ "test_DefaultRegistry error 7" );
+
+ if (bMergeDifferently)
+ {
+ mergeKeys(
+ xReg,
+ OUString( "Test" ),
+ testreg );
+ }
+ else
+ {
+ xReg->mergeKey(OUString( "Test" ), testreg );
+ }
+
+ xKey = xRootKey->openKey("Test/ThirdKey/FirstSubKey/WithSubSubKey");
+ if (xKey.is())
+ xKey->setLongValue(123456789);
+
+ xKey = xRootKey->openKey("Test/ThirdKey/FirstSubKey");
+ if (xKey.is())
+ {
+ xKey->createKey(OUString( "SecondSubSubKey" ));
+
+ Sequence<OUString> seqNames = xKey->getKeyNames();
+
+ OSL_ENSURE( seqNames.getLength() == 2, "test_DefaultRegistry error 8" );
+ }
+
+ xKey = xRootKey->openKey("/Test/ThirdKey");
+ if (xKey.is())
+ {
+ RegistryValueType valueType = xKey->getValueType();
+ OSL_ENSURE( valueType == RegistryValueType_ASCIILIST, "test_DefaultRegistry error 9" );
+
+ Sequence<OUString> seqValue = xKey->getAsciiListValue();
+
+ OSL_ENSURE( seqValue.getLength() == 3, "test_DefaultRegistry error 10" );
+ OSL_ENSURE( seqValue.getArray()[0] == "Hello",
+ "test_DefaultRegistry error 11" );
+ OSL_ENSURE( seqValue.getArray()[1] == "here I",
+ "test_DefaultRegistry error 12" );
+ OSL_ENSURE( seqValue.getArray()[2] == "come",
+ "test_DefaultRegistry error 13" );
+
+ xKey->setLongListValue({ 1234, 4567, 7890 });
+
+ Sequence<sal_Int32> seqLongValue = xKey->getLongListValue();
+
+ OSL_ENSURE( seqLongValue.getLength() == 3, "test_DefaultRegistry error 14" );
+ OSL_ENSURE( seqLongValue.getArray()[0] == 1234, "test_DefaultRegistry error 15" );
+ OSL_ENSURE( seqLongValue.getArray()[1] == 4567, "test_DefaultRegistry error 16" );
+ OSL_ENSURE( seqLongValue.getArray()[2] == 7890, "test_DefaultRegistry error 17" );
+ }
+
+ // Test Links
+ xKey = xRootKey->createKey(OUString( "/Test/FifthKey" ));
+ xKey->createLink(OUString( "MyFirstLink" ),
+ OUString( "/Test/ThirdKey/FirstSubKey" ));
+
+ xKey = xRootKey->openKey("/Test/FifthKey/MyFirstLink");
+ OSL_ENSURE( xKey->isValid(), "test_DefaultRegistry error 18" );
+ OSL_ENSURE( xKey->getKeyName() == "/Test/ThirdKey/FirstSubKey",
+ "test_DefaultRegistry error 19" );
+
+ xKey->createLink(OUString( "/WithSubSubKey/MyFourthLink" ),
+ OUString( "/Test/FourthKey/MySecondLink" ));
+
+ OSL_ENSURE( xKey->getLinkTarget(OUString( "/WithSubSubKey/MyFourthLink" ))
+ == "/Test/FourthKey/MySecondLink",
+ "test_DefaultRegistry error 20" );
+
+ try
+ {
+ OSL_ENSURE( xKey->getResolvedName(OUString( "/WithSubSubKey/MyFourthLink/BlaBlaBla" ))
+ == "/Test/FourthKey/MySecondLink/BlaBlaBla",
+ "test_DefaultRegistry error 21" );
+ }
+ catch(InvalidRegistryException&)
+ {
+ }
+
+ xRootKey->createLink(OUString( "/Test/FourthKey/MySecondLink" ),
+ OUString( "/Test/SixthKey/MyThirdLink" ));
+ xKey = xRootKey->createKey(OUString( "/Test/SixthKey" ));
+ xKey->createLink(OUString( "MyThirdLink" ),
+ OUString( "/Test/FourthKey/MySecondLink" ));
+
+ try
+ {
+ xRootKey->openKey("/Test/FifthKey/MyFirstLink/WithSubSubKey/MyFourthLink");
+ }
+ catch(InvalidRegistryException&)
+ {
+ printf("test InvalidRegistryExcption OK!\n");
+ }
+
+ OSL_ENSURE( xRootKey->getLinkTarget(OUString( "/Test/FifthKey/MyFirstLink/WithSubSubKey/MyFourthLink" ))
+ == "/Test/FourthKey/MySecondLink",
+ "test_DefaultRegistry error 22" );
+
+ xRootKey->deleteLink(OUString( "/Test/FifthKey/MyFirstLink/WithSubSubKey/MyFourthLink" ));
+
+ xKey = xRootKey->openKey("/Test/DefaultLink/SecondSubSubKey");
+ if (xKey.is())
+ {
+ OSL_ENSURE( xKey->getKeyName() == "/Test/ThirdKey/FirstSubKey/SecondSubSubKey", "test_DefaultRegistry error 23" );
+ }
+ xKey = xRootKey->createKey(OUString( "/Test/DefaultLink/ThirdSubSubKey" ));
+ if (xKey.is())
+ {
+ OSL_ENSURE( xKey->getKeyName() == "/Test/ThirdKey/FirstSubKey/ThirdSubSubKey",
+ "test_DefaultRegistry error 24" );
+ }
+
+ xKey = xRootKey->openKey("Test");
+ OSL_ENSURE( xKey->isValid(), "test_DefaultRegistry error 25" );
+
+ xRootKey->deleteKey(OUString( "Test" ));
+
+ if (bMergeDifferently)
+ {
+ mergeKeys(
+ xReg,
+ OUString( "AllFromTestreg2" ),
+ testreg2);
+ }
+ else
+ {
+ xReg->mergeKey(OUString( "AllFromTestreg2" ),
+ testreg2);
+ }
+
+ xKey = xRootKey->openKey("/AllFromTestreg2/ThirdKey/FirstSubKey");
+ if (xKey.is())
+ {
+ xRootKey->deleteKey(OUString( "/AllFromTestreg2" ));
+ }
+
+ }
+ catch(InvalidRegistryException&)
+ {
+ OSL_ENSURE(0, "exception InvalidRegistryExcption raised while doing test_DefaultRegistry");
+ }
+ catch(InvalidValueException&)
+ {
+ OSL_ENSURE(0, "exception InvalidValueExcption raised while doing test_DefaultRegistry()");
+ }
+ try
+ {
+ xReg->close();
+ }
+ catch(const InvalidRegistryException& e)
+ {
+ (void)e;
+ OSL_ENSURE(0, OUStringToOString(e.Message,RTL_TEXTENCODING_ASCII_US).getStr());
+ }
+
+
+ xReg.clear();
+
+ // shutdown
+ Reference< css::lang::XComponent > xComp( rSMgr, UNO_QUERY );
+ OSL_ENSURE( xComp.is(), "### service manager has to implement XComponent!" );
+ xComp->dispose();
+
+ printf("Test DefaultRegistry, OK!\n");
+}
+
+
+SAL_IMPLEMENT_MAIN()
+{
+// setStarUserRegistry();
+ setLinkInDefaultRegistry(OUString("/Test/DefaultLink"),
+ OUString("/Test/FifthKey/MyFirstLink"));
+
+ OUString reg1( "testreg1.rdb" );
+ OUString reg2( "testreg2.rdb" );
+ OUString areg1( "atestreg1.rdb" );
+ OUString areg2( "atestreg2.rdb" );
+
+ test_SimpleRegistry( reg1, reg2 );
+ test_DefaultRegistry( reg1, reg2 );
+ test_SimpleRegistry( areg1, areg2, true ); // use different merge
+ test_DefaultRegistry( areg1, areg2, true );
+
+ Reference< XSimpleRegistry > xSimReg( ::cppu::createSimpleRegistry() );
+ xSimReg->open( reg1, sal_False, sal_True );
+ xSimReg->destroy();
+ xSimReg->open( reg2, sal_False, sal_True );
+ xSimReg->destroy();
+ xSimReg->open( areg1, sal_False, sal_True );
+ xSimReg->destroy();
+ xSimReg->open( areg2, sal_False, sal_True );
+ xSimReg->destroy();
+ return 0;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testsmgr.cxx b/stoc/test/testsmgr.cxx
new file mode 100644
index 0000000000..a8243386e2
--- /dev/null
+++ b/stoc/test/testsmgr.cxx
@@ -0,0 +1,88 @@
+/* -*- 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 <osl/process.h>
+#include <registry/registry.hxx>
+#include <uno/mapping.hxx>
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+extern "C" void SAL_CALL test_ServiceManager();
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+OString userRegEnv("STAR_USER_REGISTRY=");
+
+OUString getExePath()
+{
+ OUString exe;
+
+ OSL_VERIFY(osl_getExecutableFile(&exe.pData) == osl_Process_E_None);
+
+#if defined(_WIN32)
+ exe = exe.copy(0, exe.getLength() - 16);
+#else
+ exe = exe.copy(0, exe.getLength() - 12);
+#endif
+ return exe;
+}
+
+void setStarUserRegistry()
+{
+ Registry* myRegistry = new Registry();
+
+ RegistryKey rootKey, rKey, rKey2;
+
+ OUString userReg = getExePath();
+ userReg += "user.rdb";
+ if (myRegistry->open(userReg, RegAccessMode::READWRITE))
+ {
+ OSL_VERIFY(!myRegistry->create(userReg));
+ }
+
+ OSL_VERIFY(!myRegistry->close());
+ delete myRegistry;
+
+ userRegEnv += OUStringToOString(userReg, RTL_TEXTENCODING_ASCII_US);
+ putenv((char*)userRegEnv.getStr());
+}
+
+SAL_IMPLEMENT_MAIN()
+{
+ printf("ServiceManagerTest : \r");
+ setStarUserRegistry();
+ fflush(stdout);
+ test_ServiceManager();
+
+ printf("ServiceManagerTest : OK\n");
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testsmgr2.cxx b/stoc/test/testsmgr2.cxx
new file mode 100644
index 0000000000..2e40c0444d
--- /dev/null
+++ b/stoc/test/testsmgr2.cxx
@@ -0,0 +1,109 @@
+/* -*- 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 <cppuhelper/bootstrap.hxx>
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::cppu;
+using namespace css::uno;
+using namespace css::lang;
+using namespace css::container;
+using namespace css::registry;
+
+SAL_IMPLEMENT_MAIN()
+{
+ try
+ {
+
+ Reference< XSimpleRegistry > r1 = createSimpleRegistry();
+ Reference< XSimpleRegistry > r2 = createSimpleRegistry();
+ r1->open( OUString( "test1.rdb" ), sal_True, sal_False );
+ r2->open( OUString( "test2.rdb" ), sal_True, sal_False );
+ Reference< XSimpleRegistry > r = createNestedRegistry( );
+ Reference< XInitialization > rInit( r, UNO_QUERY );
+ Sequence< Any > seq( 2 );
+ seq[0] <<= r1;
+ seq[1] <<= r2;
+ rInit->initialize( seq );
+
+ Reference< XComponentContext > rComp = bootstrap_InitialComponentContext( r );
+
+ Reference< XContentEnumerationAccess > xCtAccess( rComp->getServiceManager(), UNO_QUERY );
+
+ Reference< XEnumeration > rEnum =
+ xCtAccess->createContentEnumeration( OUString( "com.sun.star.bridge.Bridge" ) );
+
+ sal_Int32 n = 0;
+ while( rEnum->hasMoreElements() )
+ {
+ Reference< XServiceInfo > r3;
+ rEnum->nextElement() >>= r3;
+ OString o = OUStringToOString( r3->getImplementationName() , RTL_TEXTENCODING_ASCII_US );
+ printf( "%s\n" , o.getStr() );
+ Sequence< OUString > seq2 = r3->getSupportedServiceNames();
+ for( int i = 0 ;i < seq2.getLength() ; i ++ )
+ {
+ o = OUStringToOString( seq2[i] , RTL_TEXTENCODING_ASCII_US );
+ printf( " %s\n" , o.getStr() );
+ }
+ n ++;
+ }
+ // there are two services in two registries !
+ OSL_ASSERT( 2 == n );
+ if( 2 == n )
+ {
+ printf( "test passed\n" );
+ }
+
+ Reference< XComponent > xComp( rComp, UNO_QUERY );
+ xComp->dispose();
+ try
+ {
+ xCtAccess->createContentEnumeration(
+ OUString( "blabla" ) );
+ }
+ catch (DisposedException &)
+ {
+ printf( "already disposed results in DisposedException: ok.\n" );
+ return 0;
+ }
+ fprintf( stderr, "missing DisposedException!\n" );
+ return 1;
+ }
+ catch ( const Exception & e )
+ {
+ OString o = OUStringToOString( e.Message , RTL_TEXTENCODING_ASCII_US );
+ printf( "%s\n" , o.getStr() );
+ OSL_ASSERT( 0 );
+ return 1;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testsmgr_cpnt.cxx b/stoc/test/testsmgr_cpnt.cxx
new file mode 100644
index 0000000000..0adc74f874
--- /dev/null
+++ b/stoc/test/testsmgr_cpnt.cxx
@@ -0,0 +1,302 @@
+/* -*- 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/alloc.h>
+#include <osl/security.h>
+#include <osl/thread.h>
+#include <osl/mutex.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weak.hxx>
+#include <uno/mapping.hxx>
+
+
+#include <cppuhelper/factory.hxx>
+#include <cppuhelper/servicefactory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <registry/registry.hxx>
+
+#include <com/sun/star/registry/XSimpleRegistry.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/registry/XImplementationRegistration.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+
+#include <stdio.h>
+
+#if defined ( UNX )
+#include <limits.h>
+#define _MAX_PATH PATH_MAX
+#endif
+
+
+#define IMPLEMENTATION_NAME "com.sun.star.DummyService.V10"
+#define SERVICE_NAME "com.sun.star.ts.TestManagerImpl"
+
+
+using namespace css::uno;
+using namespace css::registry;
+using namespace css::lang;
+using namespace css::container;
+using namespace osl;
+using namespace cppu;
+
+
+Reference<XMultiServiceFactory> getProcessServiceManager()
+{
+ static Reference<XMultiServiceFactory> s_x(
+ createRegistryServiceFactory(OUString("stoctest.rdb"), sal_False));
+ return s_x;
+}
+
+Reference< XMultiServiceFactory > createRegistryServiceManager( const OUString& registryName )
+{
+ return createRegistryServiceFactory( registryName );
+}
+
+
+/**********************************
+* The service, that is used to test the Service manager
+*
+*
+*
+*************************************/
+static sal_uInt32 nInstanceCount = 0;
+class Test_Manager_Impl : public WeakImplHelper< XServiceInfo >
+{
+public:
+ Test_Manager_Impl(){ nInstanceCount++;}
+ ~Test_Manager_Impl();
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() throw();
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw();
+ Sequence< OUString > SAL_CALL getSupportedServiceNames() throw();
+ static Sequence< OUString > SAL_CALL getSupportedServiceNames_Static() throw();
+
+private:
+// static XIdlClassRef getStaticIdlClass();
+};
+
+Test_Manager_Impl::~Test_Manager_Impl()
+{
+ nInstanceCount--;
+}
+
+
+// old, is no longer needed by the new Mimic
+Reference< XInterface > SAL_CALL Test_Manager_Impl_CreateInstance_Impl()
+{
+ return (OWeakObject *)new Test_Manager_Impl();
+}
+
+
+// Test_Manager_Impl_CreateInstance()
+
+Reference < XInterface > SAL_CALL Test_Manager_Impl_CreateInstance(
+ const Reference< XMultiServiceFactory > & /*rSMgr*/ ) throw (Exception)
+{
+ Reference < XInterface > xService = (XWeak *)(OWeakObject *)new Test_Manager_Impl( );
+
+ return xService;
+}
+
+
+// Test_Manager_Impl::getImplementationName
+
+OUString Test_Manager_Impl::getImplementationName() throw()
+{
+ return OUString(IMPLEMENTATION_NAME);
+}
+
+// Test_Manager_Impl::supportsService
+sal_Bool Test_Manager_Impl::supportsService( const OUString& ServiceName ) throw()
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+
+// Test_Manager_Impl::getSupportedServiceNames
+
+Sequence< OUString > Test_Manager_Impl::getSupportedServiceNames() throw ()
+{
+ return getSupportedServiceNames_Static();
+}
+
+
+// Test_Manager_Impl::getSupportedServiceNames_Static
+
+Sequence< OUString > Test_Manager_Impl::getSupportedServiceNames_Static() throw ()
+{
+ return { SERVICE_NAME, "com.sun.star.bridge.Bridge" };
+}
+
+
+/****
+*
+*
+* This routine performs the test of the process service manager ( getProcessServiceManager is called )
+*
+*
+*
+****/
+
+extern "C" void SAL_CALL test_ServiceManager()
+{
+#if ! defined SAL_DLLPREFIX
+#define SAL_DLLPREFIX ""
+#endif
+ OUString atUModule2 = SAL_DLLPREFIX "testsmgr_component" SAL_DLLEXTENSION ;
+
+ // expand shared library name
+ OString atModule2( OUStringToOString(atUModule2, RTL_TEXTENCODING_ASCII_US) );
+
+ // get the process servicemanager
+ Reference <XMultiServiceFactory> xSMgr = getProcessServiceManager();
+
+ OSL_ENSURE( xSMgr.is() , "query on XServiceManager failed" );
+
+ Reference<XContentEnumerationAccess> xContEnum(xSMgr, UNO_QUERY);
+ OSL_ENSURE( xContEnum.is() , "query on XContentEnumerationAccess failed" );
+ Reference<XEnumeration > xEnum(xContEnum->createContentEnumeration(OUString("com.sun.star.registry.SimpleRegistry")));
+ OSL_ENSURE( xEnum.is() , "createContentEnumeration failed" );
+ sal_Int32 nLen = 0;
+ while( xEnum->hasMoreElements() )
+ {
+ nLen++;
+ xEnum->nextElement();
+ }
+ OSL_ENSURE( nLen == 1, "more than one implementation for SimpleRegistry" );
+
+ Reference<XEnumerationAccess> xImplEnum(xSMgr, UNO_QUERY);
+ OSL_ENSURE( xImplEnum.is() , "query on XEnumeration failed" );
+ xEnum.set(xImplEnum->createEnumeration());
+ OSL_ENSURE( xEnum.is() , "createEnumeration failed" );
+ nLen = 0;
+ while( xEnum->hasMoreElements() )
+ {
+ nLen++;
+ Reference< XServiceInfo > sf( xEnum->nextElement(), UNO_QUERY );
+ OString str( OUStringToOString( sf->getImplementationName(), RTL_TEXTENCODING_ASCII_US ) );
+ ::fprintf( stderr, "> implementation name: %s\n", str.getStr() );
+ }
+ OSL_ENSURE( nLen == 8, "more than 6 factories" );
+
+ // try to get an instance for an unknown service
+ OSL_VERIFY( !xSMgr->createInstance("bla.blup.Q").is() );
+
+
+ // First test : register service via the internal function of the component itself
+
+ {
+ Reference< XImplementationRegistration >
+ xInst( xSMgr->createInstance("com.sun.star.registry.ImplementationRegistration"), UNO_QUERY );
+ OSL_ENSURE( xInst.is(), "no ImplementationRegistration" );
+
+ try {
+ // register the services via writeComponentRegInfo (see at end of this file)
+ xInst->registerImplementation(OUString("com.sun.star.loader.SharedLibrary"), atUModule2, Reference< XSimpleRegistry >() );
+ }
+ catch(const CannotRegisterImplementationException &) {
+ OSL_ENSURE( 0, "register implementation failed" );
+ }
+
+ // getImplementations() check
+ Sequence<OUString> seqImpl = xInst->getImplementations(OUString("com.sun.star.loader.SharedLibrary"), atUModule2);
+ OSL_ENSURE( seqImpl.getLength() == 1, "count of implementations is wrong" );
+ OSL_ENSURE( seqImpl.getConstArray()[0] == "com.sun.star.DummyService.V10", "implementation name is not equal" );
+
+
+ // tests, if a service provider can be instantiated.
+
+ Reference< XInterface > xIFace(xSMgr->createInstance("com.sun.star.ts.TestManagerImpl"));
+ OSL_ENSURE( xIFace.is(), "loadable service not found" );
+
+ // remove the service
+ OSL_VERIFY( xInst->revokeImplementation(atUModule2, Reference< XSimpleRegistry > ()) );
+ }
+
+ Reference<XComponent> xComp(xSMgr, UNO_QUERY);
+ xComp->dispose();
+
+ xComp.clear();
+ xSMgr.clear();
+}
+
+
+extern "C"
+{
+
+sal_Bool SAL_CALL component_writeInfo(
+ void * /*pServiceManager*/, void * pRegistryKey )
+{
+ if (pRegistryKey)
+ {
+ try
+ {
+ Reference< XRegistryKey > xNewKey(
+ reinterpret_cast< XRegistryKey * >( pRegistryKey )->createKey(
+ OUString( "/" IMPLEMENTATION_NAME "/UNO/SERVICES" ) ) );
+
+ const Sequence< OUString > & rSNL =
+ Test_Manager_Impl::getSupportedServiceNames_Static();
+ const OUString * pArray = rSNL.getConstArray();
+ for ( sal_Int32 nPos = rSNL.getLength(); nPos--; )
+ xNewKey->createKey( pArray[nPos] );
+
+ return sal_True;
+ }
+ catch (InvalidRegistryException &)
+ {
+ OSL_FAIL( "### InvalidRegistryException!" );
+ }
+ }
+ return sal_False;
+}
+
+SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(
+ const char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
+{
+ void * pRet = 0;
+
+ if (rtl_str_compare( pImplName, IMPLEMENTATION_NAME ) == 0)
+ {
+ Reference< XSingleServiceFactory > xFactory( createSingleFactory(
+ reinterpret_cast< XMultiServiceFactory * >( pServiceManager ),
+ OUString( IMPLEMENTATION_NAME ),
+ Test_Manager_Impl_CreateInstance,
+ Test_Manager_Impl::getSupportedServiceNames_Static() ) );
+
+ if (xFactory.is())
+ {
+ xFactory->acquire();
+ pRet = xFactory.get();
+ }
+ }
+
+ return pRet;
+}
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/test/testsmgr_cpnt.map b/stoc/test/testsmgr_cpnt.map
new file mode 100644
index 0000000000..0bd933d7e8
--- /dev/null
+++ b/stoc/test/testsmgr_cpnt.map
@@ -0,0 +1,25 @@
+#
+# 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:
+ component_writeInfo;
+ component_getFactory;
+ test_ServiceManager;
+ local:
+ *;
+};
diff --git a/stoc/test/uriproc/test_uriproc.cxx b/stoc/test/uriproc/test_uriproc.cxx
new file mode 100644
index 0000000000..aa96e6a86b
--- /dev/null
+++ b/stoc/test/uriproc/test_uriproc.cxx
@@ -0,0 +1,1420 @@
+/* -*- 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/lang/XComponent.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/uri/ExternalUriReferenceTranslator.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/uri/VndSunStarPkgUrlReferenceFactory.hpp>
+#include <com/sun/star/uri/XExternalUriReferenceTranslator.hpp>
+#include <com/sun/star/uri/XUriReference.hpp>
+#include <com/sun/star/uri/XUriReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarExpandUrlReference.hpp>
+#include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
+#include <com/sun/star/uri/XVndSunStarScriptUrlReference.hpp>
+#include <com/sun/star/util/XMacroExpander.hpp>
+#include <cppuhelper/bootstrap.hxx>
+#include <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+#include <rtl/string.hxx>
+#include <rtl/textenc.h>
+#include <rtl/uri.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <sal/macros.h>
+
+namespace {
+
+#define TEST_ASSERT_EQUAL(token1, token2, token3, expected, actual) \
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( \
+ createTestAssertEqualMessage( \
+ token1, token2, token3, #expected, #actual, expected, actual). \
+ getStr(), \
+ (expected), (actual))
+
+template< typename T > void append(
+ OUStringBuffer & buffer, T const & value)
+{
+ buffer.append(value);
+}
+
+template<> void append(OUStringBuffer & buffer, bool const & value) {
+ buffer.append(value);
+}
+
+template<> void append(OUStringBuffer & buffer, std::size_t const & value)
+{
+ buffer.append(static_cast< sal_Int32 >(value));
+}
+
+template<> void append(OUStringBuffer & buffer, char const * const & value)
+{
+ buffer.appendAscii(value);
+}
+
+template< typename T1, typename T2, typename T3, typename T4 >
+OString createTestAssertEqualMessage(
+ char const * token1, T1 const & token2, T2 const & token3,
+ char const * expectedExpr, char const * actualExpr, T3 const & expected,
+ T4 const & actual)
+{
+ OUStringBuffer buf(512);
+ buf.appendAscii(token1);
+ buf.append('|');
+ append(buf, token2);
+ buf.append('|');
+ append(buf, token3);
+ buf.append(": TEST_ASSERT_EQUAL(");
+ buf.appendAscii(expectedExpr);
+ buf.append(", ");
+ buf.appendAscii(actualExpr);
+ buf.append("): <");
+ append(buf, expected);
+ buf.append("> != <");
+ append(buf, actual);
+ buf.append('>');
+ return OUStringToOString(
+ buf.makeStringAndClear(), RTL_TEXTENCODING_ASCII_US);
+}
+
+class Test: public CppUnit::TestFixture {
+public:
+ virtual void setUp();
+
+ virtual void tearDown();
+
+ void testParse();
+
+ void testMakeAbsolute();
+
+ void testMakeRelative();
+
+ void testVndSunStarExpand();
+
+ void testVndSunStarScript();
+
+ void testTranslator();
+
+ void testPkgUrlFactory();
+
+ CPPUNIT_TEST_SUITE(Test);
+ CPPUNIT_TEST(testParse);
+ CPPUNIT_TEST(testMakeAbsolute);
+ CPPUNIT_TEST(testMakeRelative);
+ CPPUNIT_TEST(testVndSunStarExpand);
+ CPPUNIT_TEST(testVndSunStarScript);
+ CPPUNIT_TEST(testTranslator);
+ CPPUNIT_TEST(testPkgUrlFactory);
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+ css::uno::Reference< css::uno::XComponentContext > m_context;
+ css::uno::Reference< css::uri::XUriReferenceFactory > m_uriFactory;
+};
+
+void Test::setUp() {
+ m_context = cppu::defaultBootstrap_InitialComponentContext();
+ m_uriFactory = css::uri::UriReferenceFactory::create(m_context);
+}
+
+void Test::tearDown() {
+ m_uriFactory.clear();
+ css::uno::Reference< css::lang::XComponent >(
+ m_context, css::uno::UNO_QUERY_THROW)->dispose();
+}
+
+void Test::testParse() {
+ struct Data {
+ char const * uriReference;
+ char const * scheme;
+ char const * schemeSpecificPart;
+ bool isHierarchical;
+ char const * authority;
+ char const * path;
+ bool hasRelativePath;
+ sal_Int32 pathSegmentCount;
+ char const * pathSegment0;
+ char const * pathSegment1;
+ char const * pathSegment2;
+ char const * pathSegment3;
+ char const * pathSegment4;
+ char const * query;
+ char const * fragment;
+ };
+ Data data[] = {
+ { "", nullptr, "", true, nullptr,
+ "", true, 0, "", "", "", "", "", nullptr, nullptr },
+ { "scheme:", "scheme", "", false, nullptr,
+ "", true, 0, "", "", "", "", "", nullptr, nullptr },
+ { "scheme:/", "scheme", "/", true, nullptr,
+ "/", false, 1, "", "", "", "", "", nullptr, nullptr },
+ { "scheme://", "scheme", "//", true, "",
+ "", false, 0, "", "", "", "", "", nullptr, nullptr },
+ { "scheme:///", "scheme", "///", true, "",
+ "/", false, 1, "", "", "", "", "", nullptr, nullptr },
+ { "scheme:////", "scheme", "////", true, "",
+ "//", false, 2, "", "", "", "", "", nullptr, nullptr },
+ { "scheme:////", "scheme", "////", true, "",
+ "//", false, 2, "", "", "", "", "", nullptr, nullptr },
+ { "scheme:#", "scheme", "", false, nullptr,
+ "", true, 0, "", "", "", "", "", nullptr, "" },
+ { "scheme:?", "scheme", "?", false, nullptr,
+ "", true, 0, "", "", "", "", "", "", nullptr },
+ { "/", nullptr, "/", true, nullptr,
+ "/", false, 1, "", "", "", "", "", nullptr, nullptr },
+ { "//", nullptr, "//", true, "",
+ "", false, 0, "", "", "", "", "", nullptr, nullptr },
+ { "///", nullptr, "///", true, "",
+ "/", false, 1, "", "", "", "", "", nullptr, nullptr },
+ { "////", nullptr, "////", true, "",
+ "//", false, 2, "", "", "", "", "", nullptr, nullptr } };
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].uriReference)));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference, data[i].schemeSpecificPart != nullptr,
+ uriRef.is());
+ if (uriRef.is()) {
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].uriReference),
+ uriRef->getUriReference());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].scheme != nullptr, bool(uriRef->isAbsolute()));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(
+ data[i].scheme == nullptr ? "" : data[i].scheme),
+ uriRef->getScheme());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].schemeSpecificPart),
+ uriRef->getSchemeSpecificPart());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].isHierarchical,
+ static_cast< bool >(uriRef->isHierarchical()));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].authority != nullptr, bool(uriRef->hasAuthority()));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(
+ data[i].authority == nullptr ? "" : data[i].authority),
+ uriRef->getAuthority());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].path),
+ uriRef->getPath());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].hasRelativePath,
+ static_cast< bool >(uriRef->hasRelativePath()));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].pathSegmentCount, uriRef->getPathSegmentCount());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString(), uriRef->getPathSegment(-1));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].pathSegment0),
+ uriRef->getPathSegment(0));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].pathSegment1),
+ uriRef->getPathSegment(1));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].pathSegment2),
+ uriRef->getPathSegment(2));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].pathSegment3),
+ uriRef->getPathSegment(3));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].pathSegment4),
+ uriRef->getPathSegment(4));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString(), uriRef->getPathSegment(5));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].query != nullptr, bool(uriRef->hasQuery()));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(
+ data[i].query == nullptr ? "" : data[i].query),
+ uriRef->getQuery());
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ data[i].fragment != nullptr, bool(uriRef->hasFragment()));
+ TEST_ASSERT_EQUAL(
+ "testParse", i, data[i].uriReference,
+ OUString::createFromAscii(
+ data[i].fragment == nullptr ? "" : data[i].fragment),
+ uriRef->getFragment());
+ }
+ }
+}
+
+void Test::testMakeAbsolute() {
+ struct Data {
+ char const * baseUriReference;
+ char const * uriReference;
+ bool processSpecialBaseSegments;
+ css::uri::RelativeUriExcessParentSegments excessParentSegments;
+ char const * absolute;
+ };
+ Data data[] = {
+ // The following tests are taken from RFC 3986, Section 5.4:
+ { "http://a/b/c/d;p?q", "g:h", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "g:h" },
+ { "http://a/b/c/d;p?q", "g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/g" },
+ { "http://a/b/c/d;p?q", "./g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/g" },
+ { "http://a/b/c/d;p?q", "g/", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/g/" },
+ { "http://a/b/c/d;p?q", "/g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/g" },
+ { "http://a/b/c/d;p?q", "//g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://g" },
+ { "http://a/b/c/d;p?q", "?y", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/d;p?y" },
+ { "http://a/b/c/d;p?q", "g?y", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g?y" },
+ { "http://a/b/c/d;p?q", "#s", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/d;p?q#s" },
+ { "http://a/b/c/d;p?q", "g#s", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g#s" },
+ { "http://a/b/c/d;p?q", "g?y#s", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g?y#s" },
+ { "http://a/b/c/d;p?q", ";x", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/;x" },
+ { "http://a/b/c/d;p?q", "g;x", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g;x" },
+ { "http://a/b/c/d;p?q", "g;x?y#s", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g;x?y#s" },
+ { "http://a/b/c/d;p?q", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/d;p?q" },
+ { "http://a/b/c/d;p?q", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/" },
+ { "http://a/b/c/d;p?q", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/" },
+ { "http://a/b/c/d;p?q", "..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/" },
+ { "http://a/b/c/d;p?q", "../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/" },
+ { "http://a/b/c/d;p?q", "../g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/g" },
+ { "http://a/b/c/d;p?q", "../..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/" },
+ { "http://a/b/c/d;p?q", "../../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/" },
+ { "http://a/b/c/d;p?q", "../../g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/g" },
+ { "http://a/b/c/d;p?q", "../../../g", true,
+ css::uri::RelativeUriExcessParentSegments_ERROR, nullptr },
+ { "http://a/b/c/d;p?q", "../../../g", true,
+ css::uri::RelativeUriExcessParentSegments_RETAIN, "http://a/../g" },
+ { "http://a/b/c/d;p?q", "../../../g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/g" },
+ { "http://a/b/c/d;p?q", "../../../../g", true,
+ css::uri::RelativeUriExcessParentSegments_ERROR, nullptr },
+ { "http://a/b/c/d;p?q", "../../../../g", true,
+ css::uri::RelativeUriExcessParentSegments_RETAIN,
+ "http://a/../../g" },
+ { "http://a/b/c/d;p?q", "../../../../g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/g" },
+ { "http://a/b/c/d;p?q", "/./g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/g" },
+ { "http://a/b/c/d;p?q", "/../g", true,
+ css::uri::RelativeUriExcessParentSegments_ERROR, nullptr },
+ { "http://a/b/c/d;p?q", "/../g", true,
+ css::uri::RelativeUriExcessParentSegments_RETAIN, "http://a/../g" },
+ { "http://a/b/c/d;p?q", "/../g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/g" },
+ { "http://a/b/c/d;p?q", "g.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/g." },
+ { "http://a/b/c/d;p?q", ".g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/.g" },
+ { "http://a/b/c/d;p?q", "g..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g.." },
+ { "http://a/b/c/d;p?q", "..g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/..g" },
+ { "http://a/b/c/d;p?q", "./../g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/g" },
+ { "http://a/b/c/d;p?q", "./g/.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/g/" },
+ { "http://a/b/c/d;p?q", "g/./h", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g/h" },
+ { "http://a/b/c/d;p?q", "g/../h", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/h" },
+ { "http://a/b/c/d;p?q", "g;x=1/./y", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g;x=1/y" },
+ { "http://a/b/c/d;p?q", "g;x=1/../y", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http://a/b/c/y" },
+ { "http://a/b/c/d;p?q", "g?y/./x", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g?y/./x" },
+ { "http://a/b/c/d;p?q", "g?y/../x", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g?y/../x" },
+ { "http://a/b/c/d;p?q", "g#s/./x", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g#s/./x" },
+ { "http://a/b/c/d;p?q", "g#s/../x", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "http://a/b/c/g#s/../x" },
+ { "http://a/b/c/d;p?q", "http:g", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "http:g" },
+
+ { "scheme:", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+
+ { "scheme://a", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a" },
+ { "scheme://a", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+
+ { "scheme://a/", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+
+ { "scheme://a/b", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b" },
+ { "scheme://a/b", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+ { "scheme://a/b", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/" },
+
+ { "scheme://a/b/", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+ { "scheme://a/b/", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a/b/" },
+
+ { "scheme:a", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a" },
+ { "scheme:a", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:a", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:a", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:a", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:a", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:" },
+ { "scheme:a", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:a", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+
+ { "scheme:a/", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+
+ { "scheme:a/b", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b" },
+ { "scheme:a/b", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+ { "scheme:a/b", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/" },
+
+ { "scheme:a/b/", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+ { "scheme:a/b/", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:a/b/" },
+
+ { "scheme:/a", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a" },
+ { "scheme:/a", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+ { "scheme:/a", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/" },
+
+ { "scheme:/a/", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+
+ { "scheme:/a/b", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b" },
+ { "scheme:/a/b", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+ { "scheme:/a/b", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/" },
+
+ { "scheme:/a/b/", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", ".", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/../", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./././x/..", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./x/../.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./x/.././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "././x/.././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "././x/../././", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+ { "scheme:/a/b/", "./././x/../././.", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme:/a/b/" },
+
+ { "scheme://a#s", "", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a" },
+ { "scheme://a", "?q", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a?q" },
+ { "scheme://a#s", "?q", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a?q" },
+ { "scheme://a", "#s", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a#s" },
+ { "scheme://a#s1", "#s2", true,
+ css::uri::RelativeUriExcessParentSegments_REMOVE, "scheme://a#s2" },
+
+ { "schema://a", "schema://b/c/../d", true, css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "schema://b/d" },
+
+ // Per RFC 3986 Section 5.2.1 "Pre-parse the Base URI", "Normalization of the base URI
+ // [...; esp. dot-segment removal per Section 6.2.2.3 "Path Segment Normalization"] is
+ // optional" (and not done by our implementation), so if the relative URI has no scheme and
+ // no authority and an empty path, the Base URI's path is used unmodified per Section 5.2.2
+ // "Transform References" and thus still contains dot-segments:
+ { "scheme:/a/../b/c", "", true, css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "scheme:/a/../b/c" },
+ { "scheme:/a/../b/c", "d", true, css::uri::RelativeUriExcessParentSegments_REMOVE,
+ "scheme:/b/d" } };
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ css::uno::Reference< css::uri::XUriReference > baseUriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].baseUriReference)));
+ TEST_ASSERT_EQUAL("testMakeAbsolute", i, data[i].baseUriReference, true, baseUriRef.is());
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].uriReference)));
+ TEST_ASSERT_EQUAL("testMakeAbsolute", i, data[i].uriReference, true, uriRef.is());
+ css::uno::Reference< css::uri::XUriReference > absolute(
+ m_uriFactory->makeAbsolute(
+ baseUriRef, uriRef, data[i].processSpecialBaseSegments,
+ data[i].excessParentSegments));
+ TEST_ASSERT_EQUAL(
+ "testMakeAbsolute", i, data[i].uriReference,
+ data[i].absolute != nullptr, absolute.is());
+ if (absolute.is()) {
+ TEST_ASSERT_EQUAL(
+ "testMakeAbsolute", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].absolute),
+ absolute->getUriReference());
+ }
+ // For those test cases that conform to RFC 3986, check that the behavior matches
+ // rtl::Uri::convertRelToAbs:
+ if (data[i].processSpecialBaseSegments
+ && data[i].excessParentSegments == css::uri::RelativeUriExcessParentSegments_REMOVE)
+ {
+ try {
+ auto const absolute2 = rtl::Uri::convertRelToAbs(
+ OUString::createFromAscii(data[i].baseUriReference),
+ OUString::createFromAscii(data[i].uriReference));
+ TEST_ASSERT_EQUAL(
+ "testMakeAbsolute", i, data[i].uriReference, true, data[i].absolute != nullptr);
+ TEST_ASSERT_EQUAL(
+ "testMakeAbsolute", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].absolute), absolute2);
+ } catch (rtl::MalformedUriException &) {
+ TEST_ASSERT_EQUAL(
+ "testMakeAbsolute", i, data[i].uriReference, true, data[i].absolute == nullptr);
+ }
+ }
+ }
+}
+
+void Test::testMakeRelative() {
+ struct Data {
+ char const * baseUriReference;
+ char const * uriReference;
+ bool preferAuthorityOverRelativePath;
+ bool preferAbsoluteOverRelativePath;
+ bool encodeRetainedSpecialSegments;
+ char const * relative;
+ char const * absolute;
+ };
+ Data data[] = {
+ { "scheme1://a/b/c", "scheme2://a/b/c?q#s", true, true, false,
+ "scheme2://a/b/c?q#s", nullptr },
+ { "scheme://a/b/c", "scheme:a/b/c?q#s", true, true, false,
+ "scheme:a/b/c?q#s", nullptr },
+ { "scheme://a/b/c", "", true, true, false, "", "scheme://a/b/c" },
+ { "scheme://a/b/c", "//d/e/f", true, true, false, "//d/e/f",
+ "scheme://d/e/f" },
+ { "scheme://a/b/c", "./e?q#s", true, true, false, "./e?q#s",
+ "scheme://a/b/e?q#s" },
+ { "scheme://a/b", "scheme://a?q", true, true, false, "/?q",
+ "scheme://a/?q" },
+ { "scheme://a/b", "scheme://a?q", true, false, false, "/?q",
+ "scheme://a/?q" },
+ { "scheme://a", "scheme://a?q", true, true, false, "?q", nullptr },
+ { "scheme://a/", "scheme://a?q", true, true, false, "?q",
+ "scheme://a/?q" },
+ { "scheme://a", "scheme://a/?q", true, true, false, "/?q",
+ nullptr },
+ { "scheme://a/", "scheme://a/?q", true, true, false, "?q",
+ nullptr },
+ { "scheme://a?q", "scheme://a?q", true, true, false, "", nullptr },
+ { "scheme://a/?q", "scheme://a?q", true, true, false, "",
+ "scheme://a/?q" },
+ { "scheme://a?q", "scheme://a/?q", true, true, false, "/?q",
+ nullptr },
+ { "scheme://a/?q", "scheme://a/?q", true, true, false, "", nullptr },
+ { "scheme://a/b/c/d", "scheme://a//", true, true, false, "//a//", nullptr },
+ { "scheme://a/b/c/d", "scheme://a//", false, true, false, "../..//",
+ nullptr },
+ { "scheme://a/b/c/d", "scheme://a//", true, false, false, "../..//",
+ nullptr },
+ { "scheme://a/b/c/d", "scheme://a//", false, false, false, "../..//",
+ nullptr },
+ { "scheme://a/b/c/d", "scheme://a/e", true, true, false, "/e", nullptr },
+ { "scheme://a/b/c/d", "scheme://a/e", true, false, false, "../../e",
+ nullptr },
+ { "scheme://a/b/c/d/e", "scheme://a/b/f", true, true, false, "../../f",
+ nullptr },
+ { "scheme://a/b/c/d/e", "scheme://a/b", true, true, false, "/b", nullptr },
+ { "scheme://a/b/c/d/e", "scheme://a/b", true, false, false,
+ "../../../b", nullptr },
+ { "scheme://a/b/c/d/e", "scheme://a/b/", true, true, false, "../..",
+ nullptr },
+ { "scheme://a/b/c/d/e", "scheme://a/b/c", true, true, false, "../../c",
+ nullptr },
+ { "scheme://a/b/c/d/e", "scheme://a/b/c/", true, true, false, "..", nullptr },
+ { "scheme://a/b/", "scheme://a/b/c/d", true, true, false, "c/d", nullptr },
+ { "scheme://a/b/", "scheme://a/b/c/d/", true, true, false, "c/d/", nullptr },
+ { "scheme://a/b/c", "scheme://a/b//", true, true, false, ".//", nullptr },
+ { "scheme://a/b/c", "scheme://a/b//d", true, true, false, ".//d", nullptr },
+ { "scheme://a/b/c", "scheme://a/b//d//", true, true, false, ".//d//",
+ nullptr },
+ { "scheme://a/b/c", "scheme://a/b/d+:", true, true, false, "./d+:", nullptr },
+ { "scheme://a/b/c", "scheme://a/b/+d:", true, true, false, "+d:", nullptr },
+ { "scheme://a/b/c", "scheme://a/b/d#e:f", true, true, false, "d#e:f",
+ nullptr },
+ { "scheme://a/b/c/", "scheme://a/b/../d/.e/.", true, true, false,
+ "../../d/.e/.",
+ "scheme://a/d/.e/" },
+ { "scheme://a/b/c/", "scheme://a/b/../d/.e/.", true, true, true,
+ "../%2E%2E/d/.e/%2E", "scheme://a/b/%2E%2E/d/.e/%2E" },
+ { "scheme://auth/a/b", "scheme://auth//c/d", true, true, false,
+ "//auth//c/d", nullptr },
+ { "scheme://auth/a/b", "scheme://auth//c/d", false, true, false,
+ "..//c/d", nullptr },
+ { "scheme://auth/a/b", "scheme://auth/c/d", true, true, false, "/c/d",
+ nullptr },
+ { "scheme://auth/a/b", "scheme://auth/c/d", true, false, false,
+ "../c/d", nullptr },
+ { "scheme:a/b/c", "scheme://d/e/f", true, true, false, "//d/e/f", nullptr },
+ { "scheme:/a/b/c", "scheme://d/e/f", true, true, false, "//d/e/f", nullptr },
+ { "scheme:a/b/c", "scheme:/d/e/f", true, true, false, "/d/e/f", nullptr },
+ { "scheme:/a/b/c", "scheme:/d/e/f", true, true, false, "/d/e/f", nullptr },
+ { "scheme:a/b/c", "scheme:d/e/f", true, true, false, "scheme:d/e/f", nullptr },
+ { "scheme:/a/b/c", "scheme:d/e/f", true, true, false, "scheme:d/e/f", nullptr } };
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ css::uno::Reference< css::uri::XUriReference > baseUriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].baseUriReference)));
+ TEST_ASSERT_EQUAL("testMakeRelative", i, data[i].baseUriReference, true, baseUriRef.is());
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].uriReference)));
+ TEST_ASSERT_EQUAL("testMakeRelative", i, data[i].uriReference, true, uriRef.is());
+ css::uno::Reference< css::uri::XUriReference > relative(
+ m_uriFactory->makeRelative(
+ baseUriRef, uriRef, data[i].preferAuthorityOverRelativePath,
+ data[i].preferAbsoluteOverRelativePath,
+ data[i].encodeRetainedSpecialSegments));
+ TEST_ASSERT_EQUAL(
+ "testMakeRelative", i, data[i].uriReference,
+ data[i].relative != nullptr, relative.is());
+ if (relative.is()) {
+ TEST_ASSERT_EQUAL(
+ "testMakeRelative", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].relative),
+ relative->getUriReference());
+ css::uno::Reference< css::uri::XUriReference > absolute(
+ m_uriFactory->makeAbsolute(
+ baseUriRef, relative, true,
+ css::uri::RelativeUriExcessParentSegments_ERROR));
+ TEST_ASSERT_EQUAL("testMakeRelative", i, data[i].uriReference, true, absolute.is());
+ TEST_ASSERT_EQUAL(
+ "testMakeRelative", i, data[i].uriReference,
+ OUString::createFromAscii(
+ data[i].absolute == nullptr
+ ? data[i].uriReference : data[i].absolute),
+ absolute->getUriReference());
+ }
+ }
+}
+
+void Test::testVndSunStarExpand() {
+ struct Data {
+ char const * uriReference;
+ char const * expanded;
+ };
+ Data data[] = {
+ { "vnd.sun.star.expand:", "" }, // liberally accepted
+ { "vnd.sun.star.expand:/", "/" }, // liberally accepted
+ { "vnd.sun.star.expand:%80", nullptr },
+ { "vnd.sun.star.expand:%5C$%5C%24%5C%5C", "$$\\" } };
+ css::uno::Reference< css::util::XMacroExpander > expander(
+ m_context->getValueByName(
+ "/singletons/com.sun.star.util.theMacroExpander"),
+ css::uno::UNO_QUERY_THROW);
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].uriReference)));
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarExpand", i, data[i].uriReference,
+ data[i].expanded != nullptr, uriRef.is());
+ if (uriRef.is()) {
+ css::uno::Reference< css::uri::XVndSunStarExpandUrlReference >
+ expandUrl(uriRef, css::uno::UNO_QUERY_THROW);
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarExpand", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].expanded),
+ expandUrl->expand(expander));
+ }
+ }
+}
+
+void Test::testVndSunStarScript() {
+ struct Parameter {
+ char const * key;
+ char const * value;
+ };
+ std::size_t const parameterCount = 3;
+ struct Data {
+ char const * uriReference;
+ char const * name;
+ const bool normalized;
+ Parameter parameters[parameterCount];
+ };
+ Data data[] = {
+ { "vnd.sun.star.script:", nullptr, false, {} },
+ { "vnd.sun.star.script:/", nullptr, false, {} },
+ { "vnd.sun.star.script:/abc/def?ghi=jkl&mno=pqr", nullptr, false, {} },
+ { "vnd.sun.star.script:abc%3fdef/ghi", "abc?def/ghi", false, {} },
+ { "vnd.sun.star.script:name?a", nullptr, false, {} },
+ { "vnd.sun.star.script:name?a=", "name", true, { { "a", "" }, { "A", nullptr } } },
+ { "vnd.sun.star.script:name?a=&", nullptr, true, {} },
+ { "vnd.sun.star.script:name?key1=&%26=%3D&key1=hello", "name", true,
+ { { "key1", "" }, { "key2", nullptr }, { "&", "=" } } } };
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].uriReference)));
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript", i, data[i].uriReference, data[i].name != nullptr,
+ uriRef.is());
+ if (uriRef.is()) {
+ css::uno::Reference< css::uri::XVndSunStarScriptUrlReference >
+ scriptUrl(uriRef, css::uno::UNO_QUERY_THROW);
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].uriReference),
+ scriptUrl->getUriReference());
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript", i, data[i].uriReference,
+ OUString::createFromAscii(data[i].name),
+ scriptUrl->getName());
+ OUString originalReference(uriRef->getUriReference());
+ for (std::size_t j = 0; j < parameterCount; ++j) {
+ if (data[i].parameters[j].key != nullptr) {
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript",
+ static_cast< double >(i)
+ + static_cast< double >(j) / 10.0,
+ data[i].uriReference,
+ data[i].parameters[j].value != nullptr,
+ bool(
+ scriptUrl->hasParameter(
+ OUString::createFromAscii(
+ data[i].parameters[j].key))));
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript",
+ static_cast< double >(i)
+ + static_cast< double >(j) / 10.0,
+ data[i].uriReference,
+ OUString::createFromAscii(
+ data[i].parameters[j].value),
+ scriptUrl->getParameter(
+ OUString::createFromAscii(
+ data[i].parameters[j].key)));
+
+ // setting the parameter to its original value should not change
+ // the overall uri reference (provided it was normalized before)
+ if ( data[i].normalized ) {
+ if ( scriptUrl->hasParameter(OUString::createFromAscii(
+ data[i].parameters[j].key)) ) {
+ scriptUrl->setParameter(
+ OUString::createFromAscii(
+ data[i].parameters[j].key),
+ scriptUrl->getParameter(
+ OUString::createFromAscii(
+ data[i].parameters[j].key)));
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript",
+ static_cast< double >(i)
+ + static_cast< double >(j) / 10.0,
+ OUString("setParameter"),
+ originalReference,
+ uriRef->getUriReference());
+ }
+ }
+ }
+ }
+ if ( data[i].normalized ) {
+ scriptUrl->setName(scriptUrl->getName());
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript",
+ i,
+ OUString("setName"),
+ originalReference,
+ uriRef->getUriReference());
+ }
+ }
+ }
+
+ css::uno::Reference< css::uri::XUriReference > uriRef(
+ m_uriFactory->parse(
+ "vnd.sun.star.script:Hello?location=Library.Module"),
+ css::uno::UNO_SET_THROW);
+ css::uno::Reference< css::uri::XVndSunStarScriptUrlReference >
+ scriptUrl(uriRef, css::uno::UNO_QUERY_THROW);
+
+ scriptUrl->setParameter(
+ "location",
+ "foo");
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript", sal_Int32(10), sal_Int32(1),
+ OUString("vnd.sun.star.script:Hello?location=foo"),
+ uriRef->getUriReference());
+
+ scriptUrl->setParameter(
+ "language",
+ "StarBasic");
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript", sal_Int32(10), sal_Int32(2),
+ OUString("vnd.sun.star.script:Hello?location=foo&language=StarBasic"),
+ uriRef->getUriReference());
+
+
+ bool caughtExpected = false;
+ try {
+ scriptUrl->setName(OUString());
+ }
+ catch( const css::lang::IllegalArgumentException& ) {
+ caughtExpected = true;
+ }
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript",
+ OUString("illegal arguments"),
+ OUString("name"),
+ true,
+ caughtExpected);
+
+ caughtExpected = false;
+ try {
+ scriptUrl->setParameter(
+ OUString(),
+ "non-empty");
+ }
+ catch( const css::lang::IllegalArgumentException& ) {
+ caughtExpected = true;
+ }
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarScript",
+ OUString("illegal arguments"),
+ OUString("parameter"),
+ true,
+ caughtExpected);
+}
+
+void Test::testTranslator() {
+ struct Data {
+ char const * externalUriReference;
+ char const * internalUriReference;
+ bool toInternal;
+ };
+ Data data[] = {
+ { "", "", true },
+ { "#fragment", "#fragment", true },
+ { "segment/segment?query#fragment", "segment/segment?query#fragment",
+ true },
+ { "/segment/segment?query#fragment", "/segment/segment?query#fragment",
+ true },
+ { "//authority/segment?query#fragment",
+ "//authority/segment?query#fragment", true },
+ { "foo:bar#fragment", "foo:bar#fragment", true },
+ { "file:///abc/def", "file:///abc/def", true },
+ { "file:///abc/%FEef", "file:///abc/%feef", false },
+ { "file:///abc/%80%80ef", "file:///abc/%80%80ef", false },
+ { "file:///abc/%ED%A0%80%ED%B0%80ef",
+ "file:///abc/%ED%A0%80%ED%B0%80ef", false },
+ { "file:///abc/%25.ef", "file:///abc/%.ef", false },
+ { "file:///abc/%25ef", "file:///abc/%25ef", true } };
+ css::uno::Reference< css::uri::XExternalUriReferenceTranslator >
+ translator(css::uri::ExternalUriReferenceTranslator::create(m_context));
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ if (data[i].toInternal) {
+ TEST_ASSERT_EQUAL(
+ "testTranslator, translateToInternal", i,
+ data[i].externalUriReference,
+ OUString::createFromAscii(data[i].internalUriReference),
+ translator->translateToInternal(
+ OUString::createFromAscii(
+ data[i].externalUriReference)));
+ }
+ TEST_ASSERT_EQUAL(
+ "testTranslator, translateToExternal", i,
+ data[i].internalUriReference,
+ OUString::createFromAscii(data[i].externalUriReference),
+ translator->translateToExternal(
+ OUString::createFromAscii(data[i].internalUriReference)));
+ }
+}
+
+void Test::testPkgUrlFactory() {
+ struct Data {
+ char const * authority;
+ char const * result;
+ };
+ Data data[] = {
+ { "a/b/c", nullptr },
+ { "file:///#foo", nullptr },
+ { "file:///a%25b%2fc/d~e&f@g?h",
+ "vnd.sun.star.pkg://file:%2F%2F%2Fa%2525b%252fc%2Fd~e&f@g%3Fh" } };
+ css::uno::Reference< css::uri::XVndSunStarPkgUrlReferenceFactory > factory(
+ css::uri::VndSunStarPkgUrlReferenceFactory::create(m_context));
+ for (std::size_t i = 0; i < SAL_N_ELEMENTS(data); ++i) {
+ css::uno::Reference< css::uri::XUriReference > url(
+ factory->createVndSunStarPkgUrlReference(
+ m_uriFactory->parse(
+ OUString::createFromAscii(data[i].authority))));
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarPkgFactory", i, data[i].authority,
+ data[i].result != nullptr, url.is());
+ if (data[i].result != nullptr) {
+ TEST_ASSERT_EQUAL(
+ "testVndSunStarPkgFactory", i, data[i].authority,
+ OUString::createFromAscii(data[i].result),
+ url->getUriReference());
+ }
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(Test);
+
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/stoc/unosdk.mk b/stoc/unosdk.mk
new file mode 100644
index 0000000000..b28206536e
--- /dev/null
+++ b/stoc/unosdk.mk
@@ -0,0 +1,25 @@
+#
+# 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 .
+#
+
+PPATH=inc
+
+FILES= \
+ $(PPATH)\stoc\component.hxx
+
+unosdk: $(FILES)
+ docpp -H -m -f -u -d ..\..\doc\stoc $(FILES)
diff --git a/stoc/util/bootstrap.component b/stoc/util/bootstrap.component
new file mode 100644
index 0000000000..b6d5a7b810
--- /dev/null
+++ b/stoc/util/bootstrap.component
@@ -0,0 +1,56 @@
+<?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@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.DLLComponentLoader"
+ constructor="com_sun_star_comp_stoc_DLLComponentLoader_get_implementation">
+ <service name="com.sun.star.loader.SharedLibrary"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.stoc.ImplementationRegistration"
+ constructor="com_sun_star_comp_stoc_ImplementationRegistration_get_implementation">
+ <service name="com.sun.star.registry.ImplementationRegistration"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.stoc.NestedRegistry"
+ constructor="com_sun_star_comp_stoc_NestedRegistry_get_implementation">
+ <service name="com.sun.star.registry.NestedRegistry"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.stoc.ORegistryServiceManager"
+ constructor="com_sun_star_comp_stoc_ORegistryServiceManager_get_implementation">
+ <service name="com.sun.star.lang.RegistryServiceManager"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.stoc.OServiceManager"
+ constructor="com_sun_star_comp_stoc_OServiceManager_get_implementation">
+ <service name="com.sun.star.lang.ServiceManager"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.stoc.OServiceManagerWrapper"
+ constructor="com_sun_star_comp_stoc_OServiceManagerWrapper_get_implementation"/>
+ <implementation name="com.sun.star.comp.stoc.SimpleRegistry"
+ constructor="com_sun_star_comp_stoc_SimpleRegistry_get_implementation">
+ <service name="com.sun.star.registry.SimpleRegistry"/>
+ </implementation>
+ <implementation name="com.sun.star.security.comp.stoc.AccessController"
+ constructor="com_sun_star_security_comp_stoc_AccessController_get_implementation">
+ <service name="com.sun.star.security.AccessController"/>
+ </implementation>
+ <implementation name="com.sun.star.security.comp.stoc.FilePolicy"
+ constructor="com_sun_star_security_comp_stoc_FilePolicy_get_implementation">
+ <service name="com.sun.star.security.Policy"/>
+ </implementation>
+</component>
diff --git a/stoc/util/stocservices.component b/stoc/util/stocservices.component
new file mode 100644
index 0000000000..bbb113f0d8
--- /dev/null
+++ b/stoc/util/stocservices.component
@@ -0,0 +1,45 @@
+<?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@" xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.stoc.TypeConverter"
+ constructor="com_sun_star_comp_stoc_TypeConverter_get_implementation">
+ <service name="com.sun.star.script.Converter"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.uri.ExternalUriReferenceTranslator"
+ constructor="com_sun_star_comp_uri_ExternalUriReferenceTranslator_get_implementation">
+ <service name="com.sun.star.uri.ExternalUriReferenceTranslator"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.uri.UriReferenceFactory"
+ constructor="com_sun_star_comp_uri_UriReferenceFactory_get_implementation">
+ <service name="com.sun.star.uri.UriReferenceFactory"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand"
+ constructor="com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTexpand_get_implementation">
+ <service name="com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTexpand"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript"
+ constructor="com_sun_star_comp_uri_UriSchemeParser_vndDOTsunDOTstarDOTscript_get_implementation">
+ <service name="com.sun.star.uri.UriSchemeParser_vndDOTsunDOTstarDOTscript"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.uri.VndSunStarPkgUrlReferenceFactory"
+ constructor="com_sun_star_comp_uri_VndSunStarPkgUrlReferenceFactory_get_implementation">
+ <service name="com.sun.star.uri.VndSunStarPkgUrlReferenceFactory"/>
+ </implementation>
+</component>