summaryrefslogtreecommitdiffstats
path: root/jvmfwk
diff options
context:
space:
mode:
Diffstat (limited to 'jvmfwk')
-rw-r--r--jvmfwk/CppunitTest_jvmfwk_sunversion.mk40
-rw-r--r--jvmfwk/CustomTarget_jreproperties.mk23
-rw-r--r--jvmfwk/CustomTarget_jvmfwk_jvmfwk3_ini.mk38
-rw-r--r--jvmfwk/Executable_javaldx.mk21
-rw-r--r--jvmfwk/IwyuFilter_jvmfwk.yaml36
-rw-r--r--jvmfwk/Library_jvmfwk.mk87
-rw-r--r--jvmfwk/Makefile14
-rw-r--r--jvmfwk/Module_jvmfwk.mk37
-rw-r--r--jvmfwk/Package_jreproperties.mk14
-rw-r--r--jvmfwk/Package_jvmfwk_jvmfwk3_ini.mk16
-rw-r--r--jvmfwk/Package_rcfiles.mk30
-rw-r--r--jvmfwk/README.md20
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors.xsd61
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors_freebsd.xml32
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors_linux.xml44
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors_macosx.xml38
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors_macosx_aarch64.xml11
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors_unx.xml29
-rw-r--r--jvmfwk/distributions/OpenOfficeorg/javavendors_wnt.xml38
-rw-r--r--jvmfwk/inc/elements.hxx329
-rw-r--r--jvmfwk/inc/fwkbase.hxx130
-rw-r--r--jvmfwk/inc/fwkutil.hxx77
-rw-r--r--jvmfwk/inc/libxmlutil.hxx101
-rw-r--r--jvmfwk/inc/vendorbase.hxx182
-rw-r--r--jvmfwk/inc/vendorplugin.hxx245
-rw-r--r--jvmfwk/plugins/sunmajor/javaenvsetup/javaldx.cxx160
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/JREProperties.java62
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/diagnostics.h35
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/otherjre.cxx115
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/otherjre.hxx43
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx900
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/sunjre.cxx116
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/sunjre.hxx42
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/sunversion.cxx303
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/sunversion.hxx115
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/util.cxx1281
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/util.hxx116
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.hxx14
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.mm109
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/vendorbase.cxx197
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/vendorlist.cxx52
-rw-r--r--jvmfwk/plugins/sunmajor/pluginlib/vendorlist.hxx49
-rw-r--r--jvmfwk/qa/unit/sunversion.cxx128
-rw-r--r--jvmfwk/source/elements.cxx971
-rw-r--r--jvmfwk/source/framework.cxx749
-rw-r--r--jvmfwk/source/framework.hxx41
-rw-r--r--jvmfwk/source/fwkbase.cxx524
-rw-r--r--jvmfwk/source/fwkutil.cxx194
-rw-r--r--jvmfwk/source/javasettings.xsd70
-rw-r--r--jvmfwk/source/javasettings_template.xml52
-rw-r--r--jvmfwk/source/libxmlutil.cxx136
51 files changed, 8267 insertions, 0 deletions
diff --git a/jvmfwk/CppunitTest_jvmfwk_sunversion.mk b/jvmfwk/CppunitTest_jvmfwk_sunversion.mk
new file mode 100644
index 000000000..8aa6a2c68
--- /dev/null
+++ b/jvmfwk/CppunitTest_jvmfwk_sunversion.mk
@@ -0,0 +1,40 @@
+# -*- 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,jvmfwk_sunversion))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,jvmfwk_sunversion, \
+ jvmfwk/qa/unit/sunversion \
+))
+
+$(eval $(call gb_CppunitTest_set_include,jvmfwk_sunversion, \
+ $$(INCLUDE) \
+ -I$(SRCDIR) \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,jvmfwk_sunversion, \
+ libxml2 \
+))
+
+$(eval $(call gb_CppunitTest_use_libraries,jvmfwk_sunversion, \
+ sal \
+ salhelper \
+))
+
+$(eval $(call gb_CppunitTest_use_library_objects,jvmfwk_sunversion, \
+ jvmfwk \
+))
+
+ifeq ($(OS),MACOSX)
+$(eval $(call gb_CppunitTest_use_system_darwin_frameworks,jvmfwk_sunversion, \
+ Foundation \
+))
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/jvmfwk/CustomTarget_jreproperties.mk b/jvmfwk/CustomTarget_jreproperties.mk
new file mode 100644
index 000000000..da509dbff
--- /dev/null
+++ b/jvmfwk/CustomTarget_jreproperties.mk
@@ -0,0 +1,23 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,jvmfwk/jreproperties))
+
+$(call gb_CustomTarget_get_target,jvmfwk/jreproperties) : $(call gb_CustomTarget_get_workdir,jvmfwk/jreproperties)/JREProperties.class
+
+$(call gb_CustomTarget_get_workdir,jvmfwk/jreproperties)/JREProperties.class : \
+ $(SRCDIR)/jvmfwk/plugins/sunmajor/pluginlib/JREProperties.java \
+ | $(call gb_CustomTarget_get_workdir,jvmfwk/jreproperties)/.dir
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),JCS,1)
+ $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),JCS)
+ $(call gb_Helper_abbreviate_dirs, \
+ cd $(dir $@) && $(call gb_JavaClassSet_JAVACCOMMAND,$(JAVA_TARGET_VER)) $(gb_JavaClassSet_JAVACDEBUG) -d $(dir $@) $^)
+ $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),JCS)
+
+# vim:set shiftwidth=4 tabstop=4 noexpandtab:
diff --git a/jvmfwk/CustomTarget_jvmfwk_jvmfwk3_ini.mk b/jvmfwk/CustomTarget_jvmfwk_jvmfwk3_ini.mk
new file mode 100644
index 000000000..bd9621fd2
--- /dev/null
+++ b/jvmfwk/CustomTarget_jvmfwk_jvmfwk3_ini.mk
@@ -0,0 +1,38 @@
+# -*- 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/.
+#
+# 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 .
+#
+
+$(eval $(call gb_CustomTarget_CustomTarget,jvmfwk/jvmfwk3_ini))
+
+$(eval $(call gb_CustomTarget_register_targets,jvmfwk/jvmfwk3_ini, \
+ $(call gb_Helper_get_rcfile,jvmfwk3) \
+))
+
+$(call gb_CustomTarget_get_workdir,jvmfwk/jvmfwk3_ini)/$(call gb_Helper_get_rcfile,jvmfwk3): \
+ $(SRCDIR)/jvmfwk/CustomTarget_jvmfwk_jvmfwk3_ini.mk
+ $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),ECH,1)
+ $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),ECH)
+ ( printf '[Bootstrap]\n' && \
+ printf 'UNO_JAVA_JFW_VENDOR_SETTINGS=$(if $(filter MACOSX,$(OS)),$${ORIGIN}/../share/misc/,$${ORIGIN}/)javavendors.xml\n' && \
+ printf 'UNO_JAVA_JFW_SHARED_DATA=$${URE_OVERRIDE_JAVA_JFW_SHARED_DATA}\n' && \
+ printf 'UNO_JAVA_JFW_USER_DATA=$${URE_OVERRIDE_JAVA_JFW_USER_DATA}\n' && \
+ printf 'UNO_JAVA_JFW_CLASSPATH_URLS=$${URE_MORE_JAVA_CLASSPATH_URLS}\n' \
+ ) > $@
+ $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),ECH)
+
+# vim: set noet sw=4 ts=4:
diff --git a/jvmfwk/Executable_javaldx.mk b/jvmfwk/Executable_javaldx.mk
new file mode 100644
index 000000000..ab5ae8abe
--- /dev/null
+++ b/jvmfwk/Executable_javaldx.mk
@@ -0,0 +1,21 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Executable_Executable,javaldx))
+
+$(eval $(call gb_Executable_use_libraries,javaldx,\
+ jvmfwk \
+ sal \
+))
+
+$(eval $(call gb_Executable_add_exception_objects,javaldx,\
+ jvmfwk/plugins/sunmajor/javaenvsetup/javaldx \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/jvmfwk/IwyuFilter_jvmfwk.yaml b/jvmfwk/IwyuFilter_jvmfwk.yaml
new file mode 100644
index 000000000..bfca82b3d
--- /dev/null
+++ b/jvmfwk/IwyuFilter_jvmfwk.yaml
@@ -0,0 +1,36 @@
+---
+assumeFilename: jvmfwk/source/fwkbase.cxx
+excludelist:
+ jvmfwk/inc/fwkutil.hxx:
+ # Needed on MACOSX
+ - config_folders.h
+ # Don't replace with URE impl. detail
+ - rtl/byteseq.hxx
+ jvmfwk/inc/vendorbase.hxx:
+ # OSL_BIGENDIAN is being checked
+ - osl/endian.h
+ jvmfwk/source/framework.cxx:
+ # Don't replace with URE impl. detail
+ - osl/thread.hxx
+ jvmfwk/source/fwkbase.cxx:
+ # Don't replace with URE impl. detail
+ - osl/thread.hxx
+ jvmfwk/source/fwkutil.cxx:
+ # Needed on WIN32
+ - sal/log.hxx
+ jvmfwk/plugins/sunmajor/javaenvsetup/javaldx.cxx:
+ # Don't replace with URE impl. detail
+ - rtl/byteseq.hxx
+ jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx:
+ # Needed on WIN32
+ - o3tl/char16_t2wchar_t.hxx
+ - string_view
+ # Don't replace with URE impl. detail
+ - osl/thread.hxx
+ # Don't replace with bits/types, needed for sig_atomic_t
+ - signal.h
+ jvmfwk/plugins/sunmajor/pluginlib/util.cxx:
+ # Needed on MACOSX
+ - config_folders.h
+ # Don't replace with URE impl. detail
+ - osl/module.hxx
diff --git a/jvmfwk/Library_jvmfwk.mk b/jvmfwk/Library_jvmfwk.mk
new file mode 100644
index 000000000..64a6b9d8e
--- /dev/null
+++ b/jvmfwk/Library_jvmfwk.mk
@@ -0,0 +1,87 @@
+# -*- 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,jvmfwk))
+
+$(eval $(call gb_Library_add_defs,jvmfwk,\
+ -DJVMFWK_DLLIMPLEMENTATION \
+))
+
+ifneq ($(JVM_ONE_PATH_CHECK),)
+$(eval $(call gb_Library_add_defs,jvmfwk,\
+ -DJVM_ONE_PATH_CHECK=\"$(JVM_ONE_PATH_CHECK)\" \
+))
+endif
+
+$(eval $(call gb_Library_set_include,jvmfwk,\
+ -I$(SRCDIR)/jvmfwk/inc \
+ $$(INCLUDE) \
+))
+
+$(eval $(call gb_Library_use_api,jvmfwk,\
+ udkapi \
+))
+
+$(eval $(call gb_Library_use_libraries,jvmfwk,\
+ cppu \
+ cppuhelper \
+ sal \
+ salhelper \
+))
+
+ifeq ($(OS),ANDROID)
+$(eval $(call gb_Library_use_libraries,jvmfwk,\
+ lo-bootstrap \
+))
+endif
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Library_use_system_win32_libs,jvmfwk,\
+ advapi32 \
+))
+endif
+
+$(eval $(call gb_Library_use_externals,jvmfwk,\
+ boost_headers \
+ libxml2 \
+ valgrind \
+))
+
+ifeq ($(OS),MACOSX)
+$(eval $(call gb_Library_add_cxxflags,jvmfwk,\
+ $(gb_OBJCXXFLAGS) \
+))
+
+ifeq ($(CPUNAME),X86_64)
+$(eval $(call gb_Library_add_objcxxobjects,jvmfwk,\
+ jvmfwk/plugins/sunmajor/pluginlib/util_cocoa \
+))
+endif
+
+$(eval $(call gb_Library_add_libs,jvmfwk,\
+ -framework Foundation \
+))
+endif
+
+$(eval $(call gb_Library_add_exception_objects,jvmfwk,\
+ jvmfwk/plugins/sunmajor/pluginlib/otherjre \
+ jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin \
+ jvmfwk/plugins/sunmajor/pluginlib/sunjre \
+ jvmfwk/plugins/sunmajor/pluginlib/sunversion \
+ jvmfwk/plugins/sunmajor/pluginlib/util \
+ jvmfwk/plugins/sunmajor/pluginlib/vendorbase \
+ jvmfwk/plugins/sunmajor/pluginlib/vendorlist \
+ jvmfwk/source/elements \
+ jvmfwk/source/framework \
+ jvmfwk/source/fwkbase \
+ jvmfwk/source/fwkutil \
+ jvmfwk/source/libxmlutil \
+))
+
+# vim:set noet sw=4 ts=4:
diff --git a/jvmfwk/Makefile b/jvmfwk/Makefile
new file mode 100644
index 000000000..0997e6284
--- /dev/null
+++ b/jvmfwk/Makefile
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST))))
+
+include $(module_directory)/../solenv/gbuild/partial_build.mk
+
+# vim: set noet sw=4 ts=4:
diff --git a/jvmfwk/Module_jvmfwk.mk b/jvmfwk/Module_jvmfwk.mk
new file mode 100644
index 000000000..802daed57
--- /dev/null
+++ b/jvmfwk/Module_jvmfwk.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,jvmfwk))
+
+ifeq ($(ENABLE_JAVA),TRUE)
+
+$(eval $(call gb_Module_add_targets,jvmfwk,\
+ CustomTarget_jreproperties \
+ CustomTarget_jvmfwk_jvmfwk3_ini \
+ Library_jvmfwk \
+ Package_jreproperties \
+ Package_jvmfwk_jvmfwk3_ini \
+ Package_rcfiles \
+))
+
+ifneq (,$(filter-out MACOSX WNT,$(OS)))
+ifneq (,$(filter DESKTOP,$(BUILD_TYPE)))
+$(eval $(call gb_Module_add_targets,jvmfwk,\
+ Executable_javaldx \
+))
+endif
+endif
+
+$(eval $(call gb_Module_add_check_targets,jvmfwk, \
+ CppunitTest_jvmfwk_sunversion \
+))
+
+endif
+
+# vim:set noet sw=4 ts=4:
diff --git a/jvmfwk/Package_jreproperties.mk b/jvmfwk/Package_jreproperties.mk
new file mode 100644
index 000000000..cd12402c6
--- /dev/null
+++ b/jvmfwk/Package_jreproperties.mk
@@ -0,0 +1,14 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Package_Package,jvmfwk_jreproperties,$(call gb_CustomTarget_get_workdir,jvmfwk/jreproperties)))
+
+$(eval $(call gb_Package_add_file,jvmfwk_jreproperties,$(if $(filter MACOSX,$(OS)),$(LIBO_URE_SHARE_JAVA_FOLDER),$(LIBO_URE_LIB_FOLDER))/JREProperties.class,JREProperties.class))
+
+# vim:set noet sw=4 ts=4:
diff --git a/jvmfwk/Package_jvmfwk_jvmfwk3_ini.mk b/jvmfwk/Package_jvmfwk_jvmfwk3_ini.mk
new file mode 100644
index 000000000..51a933cea
--- /dev/null
+++ b/jvmfwk/Package_jvmfwk_jvmfwk3_ini.mk
@@ -0,0 +1,16 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_Package_Package,jvmfwk_jvmfwk3_ini,$(call gb_CustomTarget_get_workdir,jvmfwk/jvmfwk3_ini)))
+
+$(eval $(call gb_Package_add_files,jvmfwk_jvmfwk3_ini,$(LIBO_URE_ETC_FOLDER), \
+ $(call gb_Helper_get_rcfile,jvmfwk3) \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/jvmfwk/Package_rcfiles.mk b/jvmfwk/Package_rcfiles.mk
new file mode 100644
index 000000000..e7010b970
--- /dev/null
+++ b/jvmfwk/Package_rcfiles.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_Package_Package,jvmfwk_javavendors,$(SRCDIR)/jvmfwk))
+
+ifeq ($(OS),WNT)
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_wnt.xml))
+else ifeq ($(OS),FREEBSD)
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_freebsd.xml))
+else ifeq ($(OS),MACOSX)
+ifeq ($(CPUNAME),AARCH64)
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_macosx_aarch64.xml))
+else
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_macosx.xml))
+endif
+else ifeq ($(OS),LINUX)
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_linux.xml))
+else ifeq ($(OS),AIX)
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_linux.xml))
+else
+$(eval $(call gb_Package_add_file,jvmfwk_javavendors,$(LIBO_URE_MISC_FOLDER)/javavendors.xml,distributions/OpenOfficeorg/javavendors_unx.xml))
+endif
+
+# vim:set noet sw=4 ts=4:
diff --git a/jvmfwk/README.md b/jvmfwk/README.md
new file mode 100644
index 000000000..3f99d9dba
--- /dev/null
+++ b/jvmfwk/README.md
@@ -0,0 +1,20 @@
+# JVM Framework Wrappers
+
+Wrappers so you can use all the Java Runtime Environments with their slightly incompatible APIs with more ease.
+
+Used to use an over-engineered "plugin" mechanism although there was only one
+"plugin", called "sunmajor", that handles all possible JREs.
+
+IMPORTANT: The `<updated>` element in `vmfwk/distributions/OpenOfficeorg/javavendors_*.xml` files
+should only be updated for incompatible changes, not for compatible ones. As stated in the commit
+message of <https://gerrit.libreoffice.org/#/c/69730/> in LibreOffice gerrit:
+
+javavendors\_\*.xml &lt;updated\> should not have been updated...
+
+Changing `<updated>` causes `jfw_startVM` and `jfw_getSelectedJRE` (both
+`jvmfwk/source/framework.cxx`) to fail with `JFW_E_INVALID_SETTINGS`, which in turn causes functionality
+that requires a JVM to issue a GUI error dialog stating that the user must select a new JRE in the
+Options dialog. While that behavior makes sense if a JRE was selected that would no longer be
+supported by the modified `javavendors_*.xml`, it is just annoying if an already selected JRE is still
+supported. And a compatible change to `javavendors_*.xml` implies that an already selected JRE will
+still be supported."
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors.xsd b/jvmfwk/distributions/OpenOfficeorg/javavendors.xsd
new file mode 100644
index 000000000..fbc643f71
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors.xsd
@@ -0,0 +1,61 @@
+<?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 .
+-->
+<schema targetNamespace="http://openoffice.org/2004/java/framework/1.0"
+ xmlns:jf="http://openoffice.org/2004/java/framework/1.0"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+ <element name="javaSelection" type="jf:JavaSelectionType">
+ <unique name="dummy3">
+ <selector xpath="jf:vendorInfos/jf:vendor"/>
+ <field xpath="@name"/>
+ </unique>
+ </element>
+
+ <complexType name="JavaSelectionType">
+ <sequence>
+ <element name="updated" type="date"/>
+ <element name="vendorInfos" type="jf:VendorInfoType"/>
+ </sequence>
+ </complexType>
+
+
+ <complexType name="VendorInfoType">
+ <sequence>
+ <element name="vendor" type="jf:VendorType" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+
+ <complexType name="VendorType">
+ <sequence>
+ <element name="minVersion" type="string" minOccurs="0"/>
+ <element name="maxVersion" type="string" minOccurs="0"/>
+ <element name="excludeVersions" minOccurs="0">
+ <complexType>
+ <sequence>
+ <element name="version" type="string" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ </complexType>
+ </element>
+ </sequence>
+ <attribute name="name" use="required" type="string"/>
+ </complexType>
+
+
+
+</schema>
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors_freebsd.xml b/jvmfwk/distributions/OpenOfficeorg/javavendors_freebsd.xml
new file mode 100644
index 000000000..b7776db58
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors_freebsd.xml
@@ -0,0 +1,32 @@
+<?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 .
+ -->
+<javaSelection xmlns="http://openoffice.org/2004/java/framework/1.0">
+ <updated>2019-07-26</updated>
+ <vendorInfos>
+ <vendor name="Oracle Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Sun Microsystems Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="The FreeBSD Foundation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ </vendorInfos>
+</javaSelection>
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors_linux.xml b/jvmfwk/distributions/OpenOfficeorg/javavendors_linux.xml
new file mode 100644
index 000000000..09fcf3733
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors_linux.xml
@@ -0,0 +1,44 @@
+<?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 .
+ -->
+<javaSelection xmlns="http://openoffice.org/2004/java/framework/1.0">
+ <updated>2019-07-26</updated>
+ <vendorInfos>
+ <vendor name="Sun Microsystems Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Oracle Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="IBM Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Blackdown Java-Linux Team">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="BEA Systems, Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Azul Systems, Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Amazon.com Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ </vendorInfos>
+</javaSelection>
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors_macosx.xml b/jvmfwk/distributions/OpenOfficeorg/javavendors_macosx.xml
new file mode 100644
index 000000000..a10e366f5
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors_macosx.xml
@@ -0,0 +1,38 @@
+<?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 .
+ -->
+<javaSelection xmlns="http://openoffice.org/2004/java/framework/1.0">
+ <updated>2019-07-26</updated>
+ <vendorInfos>
+ <vendor name="Oracle Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Apple Computer, Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Apple Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Azul Systems, Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Amazon.com Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ </vendorInfos>
+</javaSelection>
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors_macosx_aarch64.xml b/jvmfwk/distributions/OpenOfficeorg/javavendors_macosx_aarch64.xml
new file mode 100644
index 000000000..329030ccb
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors_macosx_aarch64.xml
@@ -0,0 +1,11 @@
+<?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/.
+ -->
+<javaSelection xmlns="http://openoffice.org/2004/java/framework/1.0">
+ <updated>2021-10-19</updated>
+</javaSelection>
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors_unx.xml b/jvmfwk/distributions/OpenOfficeorg/javavendors_unx.xml
new file mode 100644
index 000000000..9eab9d832
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors_unx.xml
@@ -0,0 +1,29 @@
+<?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 .
+ -->
+<javaSelection xmlns="http://openoffice.org/2004/java/framework/1.0">
+ <updated>2019-07-26</updated>
+ <vendorInfos>
+ <vendor name="Oracle Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Sun Microsystems Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ </vendorInfos>
+</javaSelection>
diff --git a/jvmfwk/distributions/OpenOfficeorg/javavendors_wnt.xml b/jvmfwk/distributions/OpenOfficeorg/javavendors_wnt.xml
new file mode 100644
index 000000000..d37db0a16
--- /dev/null
+++ b/jvmfwk/distributions/OpenOfficeorg/javavendors_wnt.xml
@@ -0,0 +1,38 @@
+<?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 .
+ -->
+<javaSelection xmlns="http://openoffice.org/2004/java/framework/1.0">
+ <updated>2019-07-26</updated>
+ <vendorInfos>
+ <vendor name="Oracle Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Sun Microsystems Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="IBM Corporation">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Azul Systems, Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ <vendor name="Amazon.com Inc.">
+ <minVersion>1.8.0</minVersion>
+ </vendor>
+ </vendorInfos>
+</javaSelection>
diff --git a/jvmfwk/inc/elements.hxx b/jvmfwk/inc/elements.hxx
new file mode 100644
index 000000000..3fde096c4
--- /dev/null
+++ b/jvmfwk/inc/elements.hxx
@@ -0,0 +1,329 @@
+/* -*- 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_JVMFWK_SOURCE_ELEMENTS_HXX
+#define INCLUDED_JVMFWK_SOURCE_ELEMENTS_HXX
+
+#include <sal/config.h>
+
+#include <memory>
+#include <vector>
+#include "fwkutil.hxx"
+#include <rtl/ustring.hxx>
+#include <rtl/byteseq.hxx>
+#include <libxml/parser.h>
+#include <optional>
+
+struct JavaInfo;
+
+#define NS_JAVA_FRAMEWORK "http://openoffice.org/2004/java/framework/1.0"
+#define NS_SCHEMA_INSTANCE "http://www.w3.org/2001/XMLSchema-instance"
+
+namespace jfw
+{
+/** gets the value of the updated element from the javavendors.xml.
+ */
+OString getElementUpdated();
+
+/** create the child elements within the root structure for each platform.
+
+ @param bNeedsSave
+ [out]If true then the respective structure of elements was added and the
+ document needs to be saved.
+ */
+void createSettingsStructure(xmlDoc* document, bool* bNeedsSave);
+
+/** represents the settings saved in the /java/javaInfo element.
+ It is used within class NodeJava which determines the settings
+ file.
+*/
+class CNodeJavaInfo
+{
+public:
+ CNodeJavaInfo();
+
+ /** if true, then javaInfo is empty. When writeToNode is called
+ then all child elements are deleted.
+ */
+ bool m_bEmptyNode;
+ /** Contains the value of the <updated> element of
+ the javavendors.xml after loadFromNode was called.
+ It is not used, when the javaInfo node is written.
+ see writeToNode
+ */
+ OString sAttrVendorUpdate;
+ /** contains the nil value of the /java/javaInfo@xsi:nil attribute.
+ Default is true;
+ */
+ bool bNil;
+ /** contains the value of the /java/javaInfo@autoSelect attribute.
+ Default is true. If it is false then the user has modified the JRE
+ selection by actively choosing a JRE from the options dialog. That is,
+ the function jfw_setSelectedJRE was called. Contrary, the function
+ jfw_findAndSelectJRE sets the attribute to true.
+ */
+ bool bAutoSelect;
+ OUString sVendor;
+ OUString sLocation;
+ OUString sVersion;
+ sal_uInt64 nRequirements;
+ ::rtl::ByteSequence arVendorData;
+
+ /** reads the node /java/javaInfo.
+ If javaInfo@xsi:nil = true then member bNil is set to true
+ and no further elements are read.
+ */
+ void loadFromNode(xmlDoc* pDoc, xmlNode* pJavaInfo);
+ /** The attribute nil will be set to false. The function gets the value
+ javaSettings/updated from the javavendors.xml and writes it to
+ javaInfo@vendorUpdate in javasettings.xml
+ */
+ void writeToNode(xmlDoc* pDoc, xmlNode* pJavaInfo) const;
+
+ /** returns NULL if javaInfo is nil.
+ */
+ std::unique_ptr<JavaInfo> makeJavaInfo() const;
+};
+
+/** this class represents the java settings based on a particular
+ settings file.
+
+ Which settings file is used is determined by the value passed into the
+ constructor and the values of the bootstrap parameters
+ UNO_JAVA_JFW_USER_DATA and UNO_JAVA_JFW_SHARED_DATA.
+
+ The method load reads the data from the settings file.
+ The method write stores the data into the settings file.
+ */
+class NodeJava
+{
+public:
+ enum Layer
+ {
+ USER,
+ SHARED
+ };
+
+private:
+ /** creates settings file and fills it with default values.
+
+ When this function is called then it creates the
+ settings file at the position determined by the bootstrap parameters
+ (UNO_JAVA_JFW_USER_DATA, UNO_JAVA_JFW_SHARED_DATA) and m_layer, unless
+ the file already exists (see createSettingsDocument).
+
+ @return
+ JFW_E_CONFIG_READWRITE
+ */
+ bool prepareSettingsDocument() const;
+
+ /** helper function for prepareSettingsDocument.
+ */
+ bool createSettingsDocument() const;
+
+ /** returns the system path to the data file which is to be used. The value
+ depends on the member m_layer and the bootstrap parameters
+ UNO_JAVA_JFW_USER_DATA and UNO_JAVA_JFW_SHARED_DATA.
+ */
+ OString getSettingsPath() const;
+
+ /** returns the file URL to the data file which is to be used. See getSettingsPath.
+ */
+ OUString getSettingsURL() const;
+
+ /** Verifies if the respective settings file exist.
+ */
+ static jfw::FileStatus checkSettingsFileStatus(OUString const& sURL);
+
+ /** Determines the layer for which the instance the loads and writes the
+ data.
+ */
+ Layer m_layer;
+
+ /** User configurable option. /java/enabled
+ If /java/enabled@xsi:nil == true then the value will be uninitialized
+ after a call to load().
+ */
+ std::optional<sal_Bool> m_enabled;
+
+ /** User configurable option. /java/userClassPath
+ If /java/userClassPath@xsi:nil == true then the value is uninitialized
+ after a call to load().
+ */
+ std::optional<OUString> m_userClassPath;
+ /** User configurable option. /java/javaInfo
+ If /java/javaInfo@xsi:nil == true then the value is uninitialized
+ after a call to load.
+ */
+ std::optional<CNodeJavaInfo> m_javaInfo;
+ /** User configurable option. /java/vmParameters
+ If /java/vmParameters@xsi:nil == true then the value is uninitialized
+ after a call to load.
+ */
+ std::optional<::std::vector<OUString>> m_vmParameters;
+ /** User configurable option. /java/jreLocations
+ If /java/jreLocations@xsi:nil == true then the value is uninitialized
+ after a call to load.
+ */
+ std::optional<::std::vector<OUString>> m_JRELocations;
+
+public:
+ explicit NodeJava(Layer theLayer);
+
+ /** sets m_enabled.
+ /java/enabled@xsi:nil will be set to false when write is called.
+ */
+ void setEnabled(bool bEnabled);
+
+ /** sets m_sUserClassPath. See setEnabled.
+ */
+ void setUserClassPath(const OUString& sClassPath);
+
+ /** sets m_aInfo. See setEnabled.
+ @param bAutoSelect
+ true- called by jfw_setSelectedJRE
+ false called by jfw_findAndSelectJRE
+ */
+ void setJavaInfo(const JavaInfo* pInfo, bool bAutoSelect);
+
+ /** sets the /java/vmParameters/param elements.
+ When this method all previous values are removed and replaced
+ by those in arParameters.
+ /java/vmParameters@xsi:nil will be set to true when write() is
+ called.
+ */
+ void setVmParameters(std::vector<OUString> const& arParameters);
+
+ /** adds a location to the already existing locations.
+ Note: call load() before, then add the location and then call write().
+ */
+ void addJRELocation(OUString const& sLocation);
+
+ /** writes the data to user settings.
+ */
+ void write() const;
+
+ /** load the values of the settings file.
+ */
+ void load();
+
+ /** returns the value of the element /java/enabled
+ */
+ const std::optional<sal_Bool>& getEnabled() const { return m_enabled; }
+ /** returns the value of the element /java/userClassPath.
+ */
+ const std::optional<OUString>& getUserClassPath() const { return m_userClassPath; }
+
+ /** returns the value of the element /java/javaInfo.
+ */
+ const std::optional<CNodeJavaInfo>& getJavaInfo() const { return m_javaInfo; }
+
+ /** returns the parameters from the element /java/vmParameters/param.
+ */
+ const std::optional<::std::vector<OUString>>& getVmParameters() const { return m_vmParameters; }
+
+ /** returns the parameters from the element /java/jreLocations/location.
+ */
+ const std::optional<::std::vector<OUString>>& getJRELocations() const { return m_JRELocations; }
+};
+
+/** merges the settings for shared, user and installation during construction.
+ The class uses a simple merge mechanism for the javasettings.xml files in share and
+ user. The following elements completely overwrite the corresponding elements
+ from share:
+ /java/enabled
+ /java/userClassPath
+ /java/vmParameters
+ /java/jreLocations
+ /java/javaInfo
+
+ In case of an installation, the shared and user settings are completely
+ disregarded.
+
+ The locations of the different settings files is obtained through the
+ bootstrap variables:
+ UNO_JAVA_JFW_USER_DATA
+ UNO_JAVA_JFW_SHARED_DATA
+
+ The class also determines useful default values for settings which have not been made.
+*/
+class MergedSettings final
+{
+private:
+ MergedSettings& operator=(MergedSettings const&) = delete;
+ MergedSettings(MergedSettings const&) = delete;
+
+ void merge(const NodeJava& share, const NodeJava& user);
+
+ bool m_bEnabled;
+
+ OUString m_sClassPath;
+
+ ::std::vector<OUString> m_vmParams;
+
+ ::std::vector<OUString> m_JRELocations;
+
+ CNodeJavaInfo m_javaInfo;
+
+public:
+ MergedSettings();
+ ~MergedSettings();
+
+ /** the default is true.
+ */
+ bool getEnabled() const { return m_bEnabled; }
+
+ const OUString& getUserClassPath() const { return m_sClassPath; }
+
+ ::std::vector<OString> getVmParametersUtf8() const;
+ /** returns a JavaInfo structure representing the node
+ /java/javaInfo. Every time a new JavaInfo structure is created
+ which needs to be freed by the caller.
+ If both, user and share settings are nil, then NULL is returned.
+ */
+ std::unique_ptr<JavaInfo> createJavaInfo() const;
+
+ /** returns the value of the attribute /java/javaInfo[@vendorUpdate].
+ */
+ OString const& getJavaInfoAttrVendorUpdate() const { return m_javaInfo.sAttrVendorUpdate; }
+
+#ifdef _WIN32
+ /** returns the javaInfo@autoSelect attribute.
+ Before calling this function loadFromSettings must be called.
+ It uses the javaInfo@autoSelect attribute to determine
+ the return value;
+ */
+ bool getJavaInfoAttrAutoSelect() const;
+#endif
+
+ void getVmParametersArray(std::vector<OUString>* parParameters) const;
+
+ const ::std::vector<OUString>& getJRELocations() const { return m_JRELocations; }
+};
+
+struct VersionInfo
+{
+ ::std::vector<OUString> vecExcludeVersions;
+ OUString sMinVersion;
+ OUString sMaxVersion;
+};
+
+} //end namespace
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/inc/fwkbase.hxx b/jvmfwk/inc/fwkbase.hxx
new file mode 100644
index 000000000..61c3fa500
--- /dev/null
+++ b/jvmfwk/inc/fwkbase.hxx
@@ -0,0 +1,130 @@
+/* -*- 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_JVMFWK_INC_FWKBASE_HXX
+#define INCLUDED_JVMFWK_INC_FWKBASE_HXX
+
+#include <sal/config.h>
+
+#include <string_view>
+#include <vector>
+
+#include <rtl/ustring.hxx>
+#include "libxmlutil.hxx"
+
+namespace jfw
+{
+struct VersionInfo;
+
+class VendorSettings
+{
+ CXmlDocPtr m_xmlDocVendorSettings;
+ CXPathContextPtr m_xmlPathContextVendorSettings;
+
+public:
+ VendorSettings();
+
+ VersionInfo getVersionInformation(std::u16string_view sVendor) const;
+};
+
+/* The class offers functions to retrieve verified bootstrap parameters.
+ */
+namespace BootParams
+{
+/* Gets the file URL to the JRE which has been determined by the
+ bootstrap parameter UNO_JAVA_JFW_JREHOME or UNO_JAVA_JFW_ENV_JREHOME.
+
+ In direct mode either of them must be set. If not an exception is thrown.
+*/
+OUString getJREHome();
+
+::std::vector<OString> getVMParameters();
+
+OUString getUserData();
+
+OUString getSharedData();
+
+/* returns the file URL to the vendor settings xml file.
+ */
+OUString getVendorSettings();
+
+/* User the parameter UNO_JAVA_JFW_CLASSPATH and UNO_JAVA_JFW_ENV_CLASSPATH
+ to compose a classpath
+ */
+OString getClasspath();
+
+OUString getClasspathUrls();
+
+} //end namespace
+
+enum JFW_MODE
+{
+ JFW_MODE_APPLICATION,
+
+ JFW_MODE_DIRECT
+};
+
+JFW_MODE getMode();
+
+/** creates the -Djava.class.path option with the complete classpath, including
+ the paths which are set by UNO_JAVA_JFW_CLASSPATH_URLS.
+ */
+OString makeClassPathOption(std::u16string_view sUserClassPath);
+
+OString getSettingsPath(const OUString& sURL);
+
+/** Get the system path to the javasettings.xml
+ Converts the URL returned from getUserSettingsURL to a
+ Systempath. An empty string is returned if the file
+ does not exist.
+ @throws FrameworkException
+ */
+OString getUserSettingsPath();
+
+/** Returns the system path of the share settings file.
+ Returns a valid string or throws an exception.
+ @throws FrameworkException
+ */
+OString getSharedSettingsPath();
+
+/* returns a valid string or throws an exception.
+ @throws FrameworkException
+ */
+OString getVendorSettingsPath();
+
+/** Called from writeJavaInfoData. It sets the process identifier. When
+java is to be started, then the current id is compared to the one set by
+this function. If they are identical then the Java was selected in the
+same process. If that Java needs a prepared environment, such as a
+LD_LIBRARY_PATH, then it must not be started in this process.
+*/
+void setJavaSelected();
+
+/** Determines if the currently selected Java was set in this process.
+
+ @see setProcessId()
+ */
+bool wasJavaSelectedInSameProcess();
+/* Only for application mode.
+ */
+OUString getApplicationClassPath();
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/inc/fwkutil.hxx b/jvmfwk/inc/fwkutil.hxx
new file mode 100644
index 000000000..76d437ae7
--- /dev/null
+++ b/jvmfwk/inc/fwkutil.hxx
@@ -0,0 +1,77 @@
+/* -*- 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_JVMFWK_SOURCE_FWKUTIL_HXX
+#define INCLUDED_JVMFWK_SOURCE_FWKUTIL_HXX
+
+#include <config_folders.h>
+
+#include <sal/config.h>
+#include <rtl/bootstrap.hxx>
+#include <rtl/byteseq.hxx>
+#include <osl/mutex.hxx>
+
+namespace osl { class Mutex; }
+
+namespace jfw
+{
+
+/** Returns the file URL of the directory where the framework library
+ (this library) resides.
+*/
+OUString getLibraryLocation();
+
+/** provides a bootstrap class which already knows the values from the
+ jvmfkwrc file.
+*/
+const rtl::Bootstrap * Bootstrap();
+
+osl::Mutex& FwkMutex();
+
+rtl::ByteSequence encodeBase16(const rtl::ByteSequence& rawData);
+rtl::ByteSequence decodeBase16(const rtl::ByteSequence& data);
+
+OUString getDirFromFile(std::u16string_view usFilePath);
+
+enum FileStatus
+{
+ FILE_OK,
+ FILE_DOES_NOT_EXIST,
+ FILE_INVALID
+};
+
+/** checks if the URL is a file.
+
+ If it is a link to a file than
+ it is resolved. Assuming that the argument
+ represents a relative URL then FILE_INVALID
+ is returned.
+
+
+ @return
+ one of the values of FileStatus.
+
+ @exception
+ Errors occurred during determining if the file exists
+ */
+FileStatus checkFileURL(const OUString & path);
+
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/inc/libxmlutil.hxx b/jvmfwk/inc/libxmlutil.hxx
new file mode 100644
index 000000000..2599cff50
--- /dev/null
+++ b/jvmfwk/inc/libxmlutil.hxx
@@ -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 .
+ */
+#ifndef INCLUDED_JVMFWK_INC_LIBXMLUTIL_HXX
+#define INCLUDED_JVMFWK_INC_LIBXMLUTIL_HXX
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <rtl/ustring.hxx>
+
+namespace jfw
+{
+class CXPathObjectPtr
+{
+ xmlXPathObject* _object;
+ CXPathObjectPtr& operator=(const CXPathObjectPtr&) = delete;
+ CXPathObjectPtr(const CXPathObjectPtr&) = delete;
+
+public:
+ CXPathObjectPtr();
+ CXPathObjectPtr(xmlXPathObject*);
+ ~CXPathObjectPtr();
+ /** Takes ownership of xmlXPathObject
+ */
+ CXPathObjectPtr& operator=(xmlXPathObject* pObj);
+ xmlXPathObject* operator->() { return _object; }
+ operator xmlXPathObject*() const { return _object; }
+};
+
+class CXPathContextPtr
+{
+ xmlXPathContext* _object;
+
+ CXPathContextPtr(const jfw::CXPathContextPtr&) = delete;
+ CXPathContextPtr& operator=(const CXPathContextPtr&) = delete;
+
+public:
+ CXPathContextPtr();
+ CXPathContextPtr(xmlXPathContextPtr aContext);
+ CXPathContextPtr& operator=(xmlXPathContextPtr pObj);
+ ~CXPathContextPtr();
+ operator xmlXPathContext*() const { return _object; }
+};
+
+class CXmlDocPtr
+{
+ xmlDoc* _object;
+
+ CXmlDocPtr(const CXmlDocPtr&) = delete;
+
+public:
+ CXmlDocPtr& operator=(const CXmlDocPtr&);
+ CXmlDocPtr();
+ CXmlDocPtr(xmlDoc* aDoc);
+ /** Takes ownership of xmlDoc
+ */
+ CXmlDocPtr& operator=(xmlDoc* pObj);
+ ~CXmlDocPtr();
+ operator xmlDoc*() const { return _object; }
+};
+
+class CXmlCharPtr
+{
+ xmlChar* _object;
+
+ CXmlCharPtr(const CXmlCharPtr&) = delete;
+ CXmlCharPtr& operator=(const CXmlCharPtr&) = delete;
+
+public:
+ CXmlCharPtr();
+ CXmlCharPtr(xmlChar* aDoc);
+ explicit CXmlCharPtr(std::u16string_view);
+ ~CXmlCharPtr();
+ CXmlCharPtr& operator=(xmlChar* pObj);
+ operator xmlChar*() const { return _object; }
+ operator OUString();
+ operator OString() { return reinterpret_cast<char*>(_object); }
+};
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/inc/vendorbase.hxx b/jvmfwk/inc/vendorbase.hxx
new file mode 100644
index 000000000..779fc8f7a
--- /dev/null
+++ b/jvmfwk/inc/vendorbase.hxx
@@ -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 .
+ */
+
+#ifndef INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_VENDORBASE_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_VENDORBASE_HXX
+
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+#include <osl/endian.h>
+#include <salhelper/simplereferenceobject.hxx>
+#include <vector>
+
+namespace jfw_plugin
+{
+//Used by subclasses of VendorBase to build paths to Java runtime
+#if defined(JAVA_ARCH)
+#define JFW_PLUGIN_ARCH JAVA_ARCH
+#elif defined SPARC64
+#define JFW_PLUGIN_ARCH "sparcv9"
+#elif defined SPARC
+#define JFW_PLUGIN_ARCH "sparc"
+#elif defined X86_64
+#define JFW_PLUGIN_ARCH "amd64"
+#elif defined ARM64
+#define JFW_PLUGIN_ARCH "arm64"
+#elif defined INTEL
+#define JFW_PLUGIN_ARCH "i386"
+#elif defined POWERPC64
+#define JFW_PLUGIN_ARCH "ppc64"
+#elif defined POWERPC
+#define JFW_PLUGIN_ARCH "ppc"
+#elif defined MIPS
+#ifdef OSL_BIGENDIAN
+#define JFW_PLUGIN_ARCH "mips"
+#else
+/* FIXME: do JDKs have some JDK-specific define? This is for
+OpenJDK at least, but probably not true for Lemotes JDK */
+#define JFW_PLUGIN_ARCH "mipsel"
+#endif
+#elif defined MIPS64
+#ifdef OSL_BIGENDIAN
+#define JFW_PLUGIN_ARCH "mips64"
+#else
+#define JFW_PLUGIN_ARCH "mips64el"
+#endif
+#elif defined S390X
+#define JFW_PLUGIN_ARCH "s390x"
+#elif defined S390
+#define JFW_PLUGIN_ARCH "s390"
+#elif defined ARM
+#define JFW_PLUGIN_ARCH "arm"
+#elif defined IA64
+#define JFW_PLUGIN_ARCH "ia64"
+#elif defined M68K
+#define JFW_PLUGIN_ARCH "m68k"
+#elif defined HPPA
+#define JFW_PLUGIN_ARCH "parisc"
+#elif defined AXP
+#define JFW_PLUGIN_ARCH "alpha"
+#elif defined AARCH64
+#define JFW_PLUGIN_ARCH "aarch64"
+#else // SPARC, INTEL, POWERPC, MIPS, MIPS64, ARM, IA64, M68K, HPPA, ALPHA
+#error unknown platform
+#endif // SPARC, INTEL, POWERPC, MIPS, MIPS64, ARM, IA64, M68K, HPPA, ALPHA
+
+class MalformedVersionException final : public std::exception
+{
+public:
+ virtual ~MalformedVersionException() override;
+};
+
+class VendorBase : public salhelper::SimpleReferenceObject
+{
+public:
+ VendorBase();
+ /* static char const* const * getJavaExePaths(int* size);
+
+ returns relative paths to the java executable as
+ file URLs.
+
+ For example "bin/java.exe". You need
+ to implement this function in a derived class, if
+ the paths differ. this implementation provides for
+ Windows "bin/java.exe" and for Unix "bin/java".
+ The paths are relative file URLs. That is, they always
+ contain '/' even on windows. The paths are relative
+ to the installation directory of a JRE.
+
+
+ The signature of this function must correspond to
+ getJavaExePaths_func.
+ */
+
+ /* static rtl::Reference<VendorBase> createInstance();
+
+ creates an instance of this class. MUST be overridden
+ in a derived class.
+ ####################################################
+ OVERRIDE in derived class
+ ###################################################
+ @param
+ Key - value pairs of the system properties of the JRE.
+ */
+
+ const OUString& getVendor() const;
+ const OUString& getVersion() const;
+ const OUString& getHome() const;
+ const OUString& getRuntimeLibrary() const;
+ const OUString& getLibraryPath() const;
+ bool isValidArch() const;
+ /* determines if prior to running java something has to be done,
+ like setting the LD_LIBRARY_PATH. This implementation checks
+ if an LD_LIBRARY_PATH (getLD_LIBRARY_PATH) needs to be set and
+ if so, needsRestart returns true.
+ */
+ bool needsRestart() const;
+
+ /* compares versions of this vendor. MUST be overridden
+ in a derived class.
+ ####################################################
+ OVERRIDE in derived class
+ ###################################################
+ @return
+ 0 this.version == sSecond
+ 1 this.version > sSecond
+ -1 this.version < sSEcond
+
+ @throw
+ MalformedVersionException if the version string was not recognized.
+ */
+ virtual int compareVersions(const OUString& sSecond) const = 0;
+
+protected:
+ /* called automatically on the instance created by createInstance.
+
+ @return
+ true - the object could completely initialize.
+ false - the object could not completely initialize. In this case
+ it will be discarded by the caller.
+ */
+ bool initialize(const std::vector<std::pair<OUString, OUString>>& props);
+
+ /* returns relative file URLs to the runtime library.
+ For example "/bin/client/jvm.dll"
+ */
+ virtual char const* const* getRuntimePaths(int* size) = 0;
+
+ virtual char const* const* getLibraryPaths(int* size) = 0;
+
+ OUString m_sVendor;
+ OUString m_sVersion;
+ OUString m_sHome;
+ OUString m_sRuntimeLibrary;
+ OUString m_sLD_LIBRARY_PATH;
+ OUString m_sArch;
+
+ typedef rtl::Reference<VendorBase> (*createInstance_func)();
+ friend rtl::Reference<VendorBase>
+ createInstance(createInstance_func pFunc,
+ const std::vector<std::pair<OUString, OUString>>& properties);
+};
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/inc/vendorplugin.hxx b/jvmfwk/inc/vendorplugin.hxx
new file mode 100644
index 000000000..4c24903ba
--- /dev/null
+++ b/jvmfwk/inc/vendorplugin.hxx
@@ -0,0 +1,245 @@
+/* -*- 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 .
+ */
+
+/** @HTML */
+#ifndef INCLUDED_JVMFWK_INC_VENDORPLUGIN_HXX
+#define INCLUDED_JVMFWK_INC_VENDORPLUGIN_HXX
+
+#include <rtl/ustring.hxx>
+#include <jni.h>
+
+#include <memory>
+#include <vector>
+
+namespace jfw_plugin { class VendorBase; }
+namespace rtl { template <class reference_type> class Reference; }
+
+struct JavaInfo;
+
+namespace jfw { class VendorSettings; }
+
+/**
+ @file
+ <p>
+ This API shall be implemented if one wants to support a Java Runtime
+ Environment (JRE) of a particular vendor. Because there is currently no
+ specification which rules the structure and location of JRE installations
+ and the format of version strings it is not possible to supply a general
+ implementation for all possible vendors. If an application determines exactly
+ what version a JRE must have then it relies on certain features and bug
+ fixes of that version. Because a version 1.4.2_1 from vendor X may contain
+ different fixes as the same version from vendor Y it is important to see
+ version and vendor as one entity. One without the other does not guarantee
+ the existence of a particular set of features or bug fixes. An implementation
+ of this API may support multiple vendors. </p>
+ */
+
+enum class javaPluginError
+{
+ NONE,
+ Error,
+ InvalidArg,
+ WrongVersionFormat,
+ FailedVersion,
+ NoJre,
+ WrongArch,
+ VmCreationFailed
+};
+
+
+/** obtains information about installations of Java Runtime Environments (JREs).
+
+ <p>The function gathers information about available JREs. Only information
+ about those JREs which match the version requirements are returned. These
+ requirements are specified by the parameter <code>vendorSettings</code>.
+ </p>
+ <p>
+ The JavaInfo structures returned in <code>parJavaInfo</code> should be ordered
+ according to their version. The one, representing a JRE with the highest
+ version should be the first in the array. </p>
+ @param parJavaInfo
+ [out] if the function runs successfully then <code>parJavaInfo</code> contains
+ on return a vector of pointers to <code>JavaInfo</code> objects.
+
+ @return
+ javaPluginError::NONE the function ran successfully.</br>
+ javaPluginError::Error an error occurred during execution.</br>
+ javaPluginError::WrongVersionFormat the version strings in
+ <code>vendorSettings</code> are not recognized as valid
+ version strings.
+ */
+javaPluginError jfw_plugin_getAllJavaInfos(
+ bool checkJavaHomeAndPath,
+ jfw::VendorSettings const & vendorSettings,
+ std::vector<std::unique_ptr<JavaInfo>> * parJavaInfo,
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos);
+
+/** obtains information for a JRE at a given location.
+
+ <p>If the given location belongs to a JRE
+ and the JRE has a version which meets the requirements as
+ specified by <code>vendorSettings</code> then
+ this function shall return a JavaInfo object for this JRE.</p>
+
+ @param sLocation
+ [in] a file URL to the directory of the JRE.
+ @param ppInfo
+ [out] if the function runs successfully then <code>ppInfo</code> contains
+ on return a pointer to a <code>JavaInfo</code> object.
+
+ @return
+ javaPluginError::NONE the function ran successfully.</br>
+ javaPluginError::Error an error occurred during execution.</br>
+ javaPluginError::InvalidArg an argument was not valid. For example, sLocation
+ is an empty string.</br>
+ javaPluginError::FailedVersion there is a JRE at the given location but it does not
+ meet the version requirements.
+ javaPluginError::NoJre no JRE could be detected at the given location.
+ */
+javaPluginError jfw_plugin_getJavaInfoByPath(
+ OUString const& sLocation,
+ jfw::VendorSettings const & vendorSettings,
+ std::unique_ptr<JavaInfo> * ppInfo);
+
+
+/** obtains information for a JRE referenced by the JAVA_HOME environment variable.
+
+ <p>If the JAVA_HOME environment variable is set and points to a JRE that
+ matches the requirements given by vendorSettings (i.e.
+ the version requirements, if any, for the vendor are met),
+ then this function shall return a JavaInfo object for this JRE.</p>
+
+ @param ppInfo
+ [out] if the JAVA_HOME environment variable is set and points to a suitable
+ JRE, then <code>ppInfo</code> contains
+ on return a pointer to its <code>JavaInfo</code> object.
+
+ @return
+ javaPluginError::NONE the function ran successfully.</br>
+ javaPluginError::NoJre no suitable JRE could be detected at the given location. However, that
+ does not mean necessarily that there is no JRE. There could be a JRE but
+ it does not
+ meet the version requirements.
+ */
+javaPluginError jfw_plugin_getJavaInfoFromJavaHome(
+ jfw::VendorSettings const & vendorSettings,
+ std::unique_ptr<JavaInfo> * ppInfo,
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos);
+
+
+/** obtains information about installations of Java Runtime Environments (JREs)
+ whose executable is in the PATH.
+
+ <p>The function gathers information about available JREs which are on the PATH
+ (PATH environment variable) and meet the version requirements given by
+ <code>vendorSettings</code> (i.e.
+ the version requirements, if any, for the vendor are met).
+ </p>
+ <p>
+ The JavaInfo structures returned in <code>vecJavaInfosFromPath</code> should be ordered
+ according to their occurrence in the PATH. The one that is the first one on the PATH
+ is also the first element in the vector.</p>
+ @param vecJavaInfosFromPath
+ [out] if the function runs successfully then <code>vecJavaInfosFromPath</code>
+ contains on return a vector of pointers to <code>JavaInfo</code> objects.
+ On return of this function, <code>vecJavaInfosFromPath</code> references
+ a newly created vector rather than the same vector as before with
+ the <code>JavaInfo</code> objects inserted into the existing vector.
+
+ @return
+ javaPluginError::NONE the function ran successfully and at least one JRE
+ that meets the requirements was found.</br>
+ javaPluginError::NoJre no JavaInfo that meets the version criteria was found
+ when inspecting the PATH
+ */
+
+javaPluginError jfw_plugin_getJavaInfosFromPath(
+ jfw::VendorSettings const & vendorSettings,
+ std::vector<std::unique_ptr<JavaInfo>> & vecJavaInfosFromPath,
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos);
+
+/** starts a Java Virtual Machine.
+
+ <p>The caller should provide all essential JavaVMOptions, such as the
+ class path (-Djava.class.path=xxx). It is assumed that the caller
+ knows what JRE is used. Hence the implementation does not need to check
+ the options for validity. If a user configured the application to
+ use specific options, such as -X..., then it is in his responsibility to
+ ensure that the application works properly. The function may add or modify
+ properties. For example, it may add to the class path property.
+ <p>
+ The function must ensure, that the VM does not abort the process
+ during instantiation.</p>
+ <p>
+ The function receives a <code>JavaInfo</code> object that was created
+ by the functions <code>jfw_plugin_getJavaInfoByPath</code> or
+ <code>jfw_plugin_getAllJavaInfos</code> from the same library. This can be
+ guaranteed if an application uses exactly one library for one vendor.
+ Therefore the functions which create the <code>JavaInfo</code> can store all
+ necessary information which are needed for starting the VM into that
+ structure. </p>
+
+ @param pInfo
+ [in] the JavaInfo object with information about the JRE.
+ @param arOptions
+ [in] the options which are passed into the JNI_CreateJavaVM function.
+ Can be NULL.
+ @param nSizeOptions
+ [in] the number of elements in <code>arOptions</code>.
+ @param ppVM
+ [out] the JavaVM pointer of the created VM.
+ @param ppEnv
+ [out] the JNIEnv pointer of the created VM.
+
+ @return
+ javaPluginError::NONE the function ran successfully.</br>
+ javaPluginError::Error an error occurred during execution.</br>
+ JFW_PLUGIN_E_VM_CREATION_FAILED a VM could not be created. The error was caused
+ by the JRE.
+ */
+javaPluginError jfw_plugin_startJavaVirtualMachine(
+ const JavaInfo *pInfo,
+ const JavaVMOption *arOptions,
+ sal_Int32 nSizeOptions,
+ JavaVM ** ppVM,
+ JNIEnv ** ppEnv);
+
+
+/** checks if the installation of the jre still exists.
+
+ This function checks if the JRE described by pInfo still
+ exists. The check must be very quick because it is called by javaldx
+ (Linux, Solaris) at start up.
+
+ @param pInfo
+ [in] the JavaInfo object with information about the JRE.
+ @param pp_exist
+ [out] the parameter is set to either sal_True or sal_False. The value is
+ only valid if the function returns JFW_E_NONE.
+
+ @return
+ javaPluginError::NONE the function ran successfully.</br>
+ javaPluginError::Error an error occurred during execution.</br>
+ javaPluginError::InvalidArg pInfo contains invalid data</br>
+ */
+javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, bool *exist);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/javaenvsetup/javaldx.cxx b/jvmfwk/plugins/sunmajor/javaenvsetup/javaldx.cxx
new file mode 100644
index 000000000..9a39f2131
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/javaenvsetup/javaldx.cxx
@@ -0,0 +1,160 @@
+/* -*- 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 <memory>
+
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <sal/main.h>
+#include <sal/types.h>
+#include <osl/thread.h>
+#include <rtl/ustring.hxx>
+#include <rtl/byteseq.hxx>
+#include <jvmfwk/framework.hxx>
+#include <o3tl/string_view.hxx>
+
+
+static bool hasOption(char const * szOption, int argc, char** argv);
+static OString getLD_LIBRARY_PATH(const rtl::ByteSequence & vendorData);
+static bool findAndSelect(std::unique_ptr<JavaInfo>*);
+
+#define HELP_TEXT \
+"\njavaldx is necessary to make Java work on some UNIX platforms." \
+"It prints a string to std out that consists of directories which " \
+"have to be included into the LD_LIBRARY_PATH variable.The setting of " \
+"the variable usually occurs in a shell script that runs javaldx.\n" \
+"The directories are from the chosen java installation. \n" \
+"Options are: \n"\
+"--help or -h\n"
+
+SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv)
+{
+ try
+ {
+ if( hasOption("--help",argc, argv) || hasOption("-h", argc, argv))
+ {
+ fprintf(stdout, HELP_TEXT);// default
+ return 0;
+ }
+ bool bEnabled = false;
+ javaFrameworkError errcode = jfw_getEnabled( & bEnabled);
+ if (errcode == JFW_E_NONE && !bEnabled)
+ {
+ //Do not do any preparation because that may only slow startup time.
+ fprintf(stdout, "\n");
+ return 0;
+ }
+ else if (errcode != JFW_E_NONE && errcode != JFW_E_DIRECT_MODE)
+ {
+ fprintf(stderr,"javaldx failed!\n");
+ return -1;
+ }
+
+ std::unique_ptr<JavaInfo> aInfo;
+ errcode = jfw_getSelectedJRE(&aInfo);
+
+ if (errcode != JFW_E_NONE && errcode != JFW_E_INVALID_SETTINGS)
+ {
+ fprintf(stderr,"javaldx failed!\n");
+ return -1;
+ }
+
+ if (!aInfo)
+ {
+ if (!findAndSelect(&aInfo))
+ return -1;
+ }
+ else
+ {
+ //check if the JRE was not uninstalled
+ bool bExist = false;
+ errcode = jfw_existJRE(aInfo.get(), &bExist);
+ if (errcode == JFW_E_NONE)
+ {
+ if (!bExist && !findAndSelect(&aInfo))
+ return -1;
+ }
+ else
+ {
+ fprintf(stderr, "javaldx: Could not determine if JRE still exist\n");
+ return -1;
+ }
+ }
+
+ OString sPaths = getLD_LIBRARY_PATH(aInfo->arVendorData);
+ fprintf(stdout, "%s\n", sPaths.getStr());
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << "javaldx failed! " << e.what() << std::endl;
+ return -1;
+ }
+
+ return 0;
+}
+
+OString getLD_LIBRARY_PATH(const rtl::ByteSequence & vendorData)
+{
+ const sal_Unicode* chars = reinterpret_cast<sal_Unicode const *>(vendorData.getConstArray());
+ sal_Int32 len = vendorData.getLength();
+ OUString sData(chars, len / 2);
+ //the runtime lib is on the first line
+ sal_Int32 index = 0;
+ std::u16string_view aToken = o3tl::getToken(sData, 1, '\n', index);
+
+ OString paths =
+ OUStringToOString(aToken, osl_getThreadTextEncoding());
+ return paths;
+}
+
+static bool hasOption(char const * szOption, int argc, char** argv)
+{
+ bool retVal= false;
+ for(int i= 1; i < argc; i++)
+ {
+ if( ! strcmp(argv[i], szOption))
+ {
+ retVal= true;
+ break;
+ }
+ }
+ return retVal;
+}
+
+static bool findAndSelect(std::unique_ptr<JavaInfo> * ppInfo)
+{
+ javaFrameworkError errcode = jfw_findAndSelectJRE(ppInfo);
+ if (errcode == JFW_E_NO_JAVA_FOUND)
+ {
+ fprintf(stderr,"javaldx: Could not find a Java Runtime Environment!\n");
+ return false;
+ }
+ else if (errcode != JFW_E_NONE && errcode != JFW_E_DIRECT_MODE)
+ {
+ fprintf(stderr,"javaldx failed!\n");
+ return false;
+ }
+ return true;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/JREProperties.java b/jvmfwk/plugins/sunmajor/pluginlib/JREProperties.java
new file mode 100644
index 000000000..0d3503af3
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/JREProperties.java
@@ -0,0 +1,62 @@
+/*
+ * 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.util.*;
+
+/** This class prints out the system properties.
+
+ We cannot print the strings directly because of encoding issues. Since
+ about 1.3.1 one can start java with the option -Dfile.encoding=UTF-8, but
+ unfortunately this works only with later update - versions (for example,
+ 1.3.1_07). Therefore we use this scheme. The property string has this form:
+ name=value
+
+ Every character is cast to an integer which value is printed, followed by a
+ space. If all characters of the string are printed, then a new line is printed.
+*/
+public class JREProperties
+{
+ public static void main(String[] args)
+ {
+ try
+ {
+ Properties p = System.getProperties();
+ Enumeration e = p.propertyNames();
+ while (e.hasMoreElements()) {
+ String sProp = (String) e.nextElement();
+ String sCompleteProp = sProp + "=" + p.getProperty(sProp);
+ char[] arChars = new char[sCompleteProp.length()];
+ sCompleteProp.getChars(0, sCompleteProp.length(), arChars, 0);
+ for (int c = 0; c < arChars.length; c++) {
+ System.out.print(String.valueOf((int) arChars[c]));
+ System.out.print(" ");
+ }
+ System.out.print("\n");
+ }
+ }
+ catch(Exception e)
+ {
+ System.err.println(e);
+ }
+
+ System.exit(0);
+ }
+
+
+
+}
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/diagnostics.h b/jvmfwk/plugins/sunmajor/pluginlib/diagnostics.h
new file mode 100644
index 000000000..599c40438
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/diagnostics.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_DIAGNOSTICS_H
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_DIAGNOSTICS_H
+
+#include <sal/config.h>
+
+#include <sal/log.hxx>
+
+#define JFW_ENSURE(c, m) SAL_WARN_IF(!(c), "jfw", m)
+
+#define JFW_TRACE0(m) SAL_INFO("jfw.level1", m)
+
+#define JFW_TRACE2(m) SAL_INFO("jfw.level2", m)
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/otherjre.cxx b/jvmfwk/plugins/sunmajor/pluginlib/otherjre.cxx
new file mode 100644
index 000000000..528af9498
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/otherjre.cxx
@@ -0,0 +1,115 @@
+/* -*- 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 "otherjre.hxx"
+
+using ::rtl::Reference;
+namespace jfw_plugin
+{
+
+Reference<VendorBase> OtherInfo::createInstance()
+{
+ return new OtherInfo;
+}
+
+
+char const* const* OtherInfo::getJavaExePaths(int * size)
+{
+ static char const * ar[] = {
+#if defined(_WIN32)
+ "bin/java.exe",
+ "jre/bin/java.exe"
+#elif defined UNX
+ "bin/java",
+ "jre/bin/java"
+#endif
+ };
+ *size = SAL_N_ELEMENTS (ar);
+ return ar;
+}
+
+char const* const* OtherInfo::getRuntimePaths(int * size)
+{
+ static char const* ar[]= {
+#if defined(_WIN32)
+ "/bin/client/jvm.dll",
+ "/bin/hotspot/jvm.dll",
+ "/bin/classic/jvm.dll",
+ "/bin/jrockit/jvm.dll",
+ // Needed by IBM Semeru Runtime, which is an OpenJDK (so should actually use SunInfo) with a
+ // java.vendor of "IBM Corporation", so using OtherInfo here (cf. gVendorMap in
+ // jvmfwk/plugins/sunmajor/pluginlib/vendorlist.cxx):
+ "/bin/server/jvm.dll"
+#elif defined UNX
+#ifdef MACOSX
+ "/../../../../../Frameworks/JavaVM.framework/JavaVM" //as of 1.6.0_22
+#else
+ "/lib/" JFW_PLUGIN_ARCH "/client/libjvm.so", // for Blackdown PPC
+ "/lib/" JFW_PLUGIN_ARCH "/server/libjvm.so", // for Blackdown AMD64
+ "/lib/" JFW_PLUGIN_ARCH "/classic/libjvm.so", // for Blackdown PPC
+ "/lib/" JFW_PLUGIN_ARCH "/jrockit/libjvm.so", // for Java of BEA Systems
+ "/bin/classic/libjvm.so", // fallback for older for IBM Java
+ "/jre/bin/classic/libjvm.so" // fallback for older for IBM Java
+#endif
+#endif
+
+ };
+ *size = SAL_N_ELEMENTS(ar);
+ return ar;
+}
+
+char const* const* OtherInfo::getLibraryPaths(int* size)
+{
+
+#if defined(UNX) && !defined(MACOSX)
+ //mac version does not have a ld library path anymore
+ static char const * ar[] = {
+ "/bin",
+ "/jre/bin",
+ "/bin/classic",
+ "/jre/bin/classic",
+ "/lib/" JFW_PLUGIN_ARCH "/client",
+ "/lib/" JFW_PLUGIN_ARCH "/server",
+ "/lib/" JFW_PLUGIN_ARCH "/classic",
+ "/lib/" JFW_PLUGIN_ARCH "/jrockit",
+ "/lib/" JFW_PLUGIN_ARCH "/native_threads",
+ ("/lib/" JFW_PLUGIN_ARCH)
+ };
+
+ *size = SAL_N_ELEMENTS(ar);
+ return ar;
+#else
+ *size = 0;
+ return nullptr;
+#endif
+}
+
+int OtherInfo::compareVersions(const OUString& /*sSecond*/) const
+{
+ //Need to provide an own algorithm for comparing version.
+ //Because this function returns always 0, which means the version of
+ //this JRE and the provided version "sSecond" are equal, one cannot put
+ //any excludeVersion entries in the javavendors.xml file.
+ return 0;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/otherjre.hxx b/jvmfwk/plugins/sunmajor/pluginlib/otherjre.hxx
new file mode 100644
index 000000000..f722234ef
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/otherjre.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_OTHERJRE_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_OTHERJRE_HXX
+
+#include <vendorbase.hxx>
+
+namespace jfw_plugin
+{
+/* Do not forget to put this class in the vendor map in vendorlist.cxx
+ */
+class OtherInfo : public VendorBase
+{
+public:
+ static char const* const* getJavaExePaths(int* size);
+
+ static rtl::Reference<VendorBase> createInstance();
+
+ virtual char const* const* getRuntimePaths(int* size) override;
+ virtual char const* const* getLibraryPaths(int* size) override;
+ virtual int compareVersions(const OUString& sSecond) const override;
+};
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx b/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx
new file mode 100644
index 000000000..03c38c1de
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/sunjavaplugin.cxx
@@ -0,0 +1,900 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#ifdef _WIN32
+# include <sys/stat.h>
+# if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+#endif
+
+#ifdef ANDROID
+# include <dlfcn.h>
+#endif
+
+#include <string.h>
+
+#include <cstddef>
+#include <cassert>
+#include <memory>
+#include <string_view>
+#include <utility>
+#include <vector>
+
+#include <config_options.h>
+#include <osl/diagnose.h>
+#include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <osl/module.hxx>
+#include <osl/mutex.hxx>
+#include <osl/process.h>
+#include <osl/thread.hxx>
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+#include <o3tl/char16_t2wchar_t.hxx>
+#include <setjmp.h>
+#include <signal.h>
+
+#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/byteseq.hxx>
+#include <fwkbase.hxx>
+#include <elements.hxx>
+#include <vendorbase.hxx>
+#include <vendorplugin.hxx>
+#include <jvmfwk/framework.hxx>
+#include "util.hxx"
+#include "sunversion.hxx"
+#include "diagnostics.h"
+
+#if defined MACOSX && defined __x86_64__
+#include "util_cocoa.hxx"
+#endif
+
+#ifdef ANDROID
+#include <osl/detail/android-bootstrap.h>
+#else
+#if !ENABLE_RUNTIME_OPTIMIZATIONS
+#define FORCE_INTERPRETED 1
+#elif defined HAVE_VALGRIND_HEADERS
+#include <valgrind/valgrind.h>
+#define FORCE_INTERPRETED RUNNING_ON_VALGRIND
+#else
+#define FORCE_INTERPRETED 0
+#endif
+#endif
+
+#if defined LINUX && (defined X86 || defined X86_64)
+#include <sys/resource.h>
+#endif
+
+using namespace osl;
+using namespace jfw_plugin;
+
+
+namespace {
+
+#if defined(UNX) && !defined(ANDROID)
+OString getPluginJarPath(
+ std::u16string_view sVendor,
+ std::u16string_view sLocation,
+ std::u16string_view sVersion)
+{
+ OString ret;
+ OUString sName1("javaplugin.jar");
+ OUString sName2("plugin.jar");
+ OUString sPath;
+ if ( sVendor == u"Sun Microsystems Inc." )
+ {
+ SunVersion ver142("1.4.2-ea");
+ SunVersion ver150("1.5.0-ea");
+ SunVersion ver(sVersion);
+ OSL_ASSERT(ver142 && ver150 && ver);
+
+ OUString sName;
+ if (ver < ver142)
+ {
+ sName = sName1;
+ }
+ else if (ver < ver150)
+ {//this will cause ea, beta etc. to have plugin.jar in path.
+ //but this does not harm. 1.5.0-beta < 1.5.0
+ sName = sName2;
+ }
+ if (!sName.isEmpty())
+ {
+ sName = OUString::Concat(sLocation) + "/lib/" + sName;
+ OSL_VERIFY(
+ osl_getSystemPathFromFileURL(sName.pData, & sPath.pData)
+ == osl_File_E_None);
+ }
+ }
+ else
+ {
+ OUString sName(OUString::Concat(sLocation) + "/lib/" + sName1);
+ OUString sPath1;
+ OUString sPath2;
+ if (osl_getSystemPathFromFileURL(sName.pData, & sPath1.pData)
+ == osl_File_E_None)
+ {
+ sName = OUString::Concat(sLocation) + "/lib/" + sName2;
+ if (osl_getSystemPathFromFileURL(sName.pData, & sPath2.pData)
+ == osl_File_E_None)
+ {
+ sPath = sPath1 + OUStringChar(SAL_PATHSEPARATOR) + sPath2;
+ }
+ }
+ OSL_ASSERT(!sPath.isEmpty());
+ }
+ ret = OUStringToOString(sPath, osl_getThreadTextEncoding());
+
+ return ret;
+}
+#endif // UNX
+
+
+std::unique_ptr<JavaInfo> createJavaInfo(
+ const rtl::Reference<VendorBase> & info)
+{
+ OUStringBuffer buf(1024);
+ buf.append(info->getRuntimeLibrary());
+ if (!info->getLibraryPath().isEmpty())
+ {
+ buf.append("\n");
+ buf.append(info->getLibraryPath());
+ buf.append("\n");
+ }
+ OUString sVendorData = buf.makeStringAndClear();
+ return std::unique_ptr<JavaInfo>(
+ new JavaInfo{
+ info->getVendor(), info->getHome(), info->getVersion(),
+ sal_uInt64(info->needsRestart() ? JFW_REQUIRE_NEEDRESTART : 0),
+ rtl::ByteSequence(
+ reinterpret_cast<sal_Int8*>(sVendorData.pData->buffer),
+ sVendorData.getLength() * sizeof(sal_Unicode))});
+}
+
+OUString getRuntimeLib(const rtl::ByteSequence & data)
+{
+ const sal_Unicode* chars = reinterpret_cast<sal_Unicode const *>(data.getConstArray());
+ sal_Int32 len = data.getLength();
+ OUString sData(chars, len / 2);
+ //the runtime lib is on the first line
+ sal_Int32 index = 0;
+ OUString aToken = sData.getToken( 0, '\n', index);
+
+ return aToken;
+}
+
+jmp_buf jmp_jvm_abort;
+sig_atomic_t g_bInGetJavaVM = 0;
+
+extern "C" void JNICALL abort_handler()
+{
+ // If we are within JNI_CreateJavaVM then we jump back into getJavaVM
+ if( g_bInGetJavaVM != 0 )
+ {
+ SAL_WARN("jfw", "JavaVM: JNI_CreateJavaVM called os::abort(), caught by abort_handler");
+ longjmp( jmp_jvm_abort, 0);
+ }
+}
+
+typedef jint JNICALL JNI_CreateVM_Type(JavaVM **, JNIEnv **, void *);
+
+#ifndef ANDROID
+int createJvm(
+ JNI_CreateVM_Type * pCreateJavaVM, JavaVM ** pJavaVM, JNIEnv ** ppEnv, JavaVMInitArgs * vm_args)
+{
+ /* We set a global flag which is used by the abort handler in order to
+ determine whether it is should use longjmp to get back into this function.
+ That is, the abort handler determines if it is on the same stack as this function
+ and then jumps back into this function.
+ */
+ g_bInGetJavaVM = 1;
+ jint err;
+ memset( jmp_jvm_abort, 0, sizeof(jmp_jvm_abort));
+ /* If the setjmp return value is not "0" then this point was reached by a longjmp in the
+ abort_handler, which was called indirectly by JNI_CreateVM.
+ */
+ if( setjmp( jmp_jvm_abort ) == 0)
+ {
+ //returns negative number on failure
+ err= pCreateJavaVM(pJavaVM, ppEnv, vm_args);
+ g_bInGetJavaVM = 0;
+ }
+ else
+ // set err to a positive number, so as or recognize that an abort (longjmp)
+ //occurred
+ err= 1;
+ return err;
+}
+#endif
+
+/** helper function to check Java version requirements
+
+ This function checks if the Java version of the given VendorBase
+ meets the given Java version requirements.
+
+ @param aVendorInfo
+ [in] the object to be inspected whether it meets the version requirements
+ @param sMinVersion
+ [in] represents the minimum version of a JRE. The string can be empty.
+ @param sMaxVersion
+ [in] represents the maximum version of a JRE. The string can be empty.
+ @param arExcludeList
+ [in] contains a list of &quot;bad&quot; versions. JREs which have one of these
+ versions must not be returned by this function.
+
+ @return
+ javaPluginError::NONE the function ran successfully and the version requirements are met
+ javaPluginError::FailedVersion at least one of the version requirements (minVersion,
+ maxVersion, excludeVersions) was violated
+ javaPluginError::WrongVersionFormat the version strings in
+ <code>sMinVersion,sMaxVersion,arExcludeList</code> are not recognized as valid
+ version strings.
+
+ */
+javaPluginError checkJavaVersionRequirements(
+ rtl::Reference<VendorBase> const & aVendorInfo,
+ OUString const& sMinVersion,
+ OUString const& sMaxVersion,
+ std::vector<OUString> const & arExcludeList)
+{
+ if (!aVendorInfo->isValidArch())
+ {
+ return javaPluginError::WrongArch;
+ }
+ if (!sMinVersion.isEmpty())
+ {
+ try
+ {
+ if (aVendorInfo->compareVersions(sMinVersion) < 0)
+ return javaPluginError::FailedVersion;
+ }
+ catch (MalformedVersionException&)
+ {
+ //The minVersion was not recognized as valid for this vendor.
+ JFW_ENSURE(
+ false,
+ "[Java framework]sunjavaplugin does not know version: "
+ + sMinVersion + " for vendor: " + aVendorInfo->getVendor()
+ + " .Check minimum Version." );
+ return javaPluginError::WrongVersionFormat;
+ }
+ }
+
+ if (!sMaxVersion.isEmpty())
+ {
+ try
+ {
+ if (aVendorInfo->compareVersions(sMaxVersion) > 0)
+ return javaPluginError::FailedVersion;
+ }
+ catch (MalformedVersionException&)
+ {
+ //The maxVersion was not recognized as valid for this vendor.
+ JFW_ENSURE(
+ false,
+ "[Java framework]sunjavaplugin does not know version: "
+ + sMaxVersion + " for vendor: " + aVendorInfo->getVendor()
+ + " .Check maximum Version." );
+ return javaPluginError::WrongVersionFormat;
+ }
+ }
+
+ for (auto const & sExVer: arExcludeList) {
+ try
+ {
+ if (aVendorInfo->compareVersions(sExVer) == 0)
+ return javaPluginError::FailedVersion;
+ }
+ catch (MalformedVersionException&)
+ {
+ //The excluded version was not recognized as valid for this vendor.
+ JFW_ENSURE(
+ false,
+ "[Java framework]sunjavaplugin does not know version: "
+ + sExVer + " for vendor: " + aVendorInfo->getVendor()
+ + " .Check excluded versions." );
+ return javaPluginError::WrongVersionFormat;
+ }
+ }
+
+ return javaPluginError::NONE;
+}
+
+}
+
+javaPluginError jfw_plugin_getAllJavaInfos(
+ bool checkJavaHomeAndPath,
+ jfw::VendorSettings const & vendorSettings,
+ std::vector<std::unique_ptr<JavaInfo>>* parJavaInfo,
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos)
+{
+ assert(parJavaInfo);
+
+ //Find all JREs
+ std::vector<rtl::Reference<VendorBase> > vecInfos =
+ addAllJREInfos(checkJavaHomeAndPath, infos);
+ std::vector<rtl::Reference<VendorBase> > vecVerifiedInfos;
+
+ for (auto const& vecInfo : vecInfos)
+ {
+ auto const versionInfo = vendorSettings.getVersionInformation(vecInfo->getVendor());
+ javaPluginError err = checkJavaVersionRequirements(
+ vecInfo, versionInfo.sMinVersion, versionInfo.sMaxVersion, versionInfo.vecExcludeVersions);
+
+ if (err == javaPluginError::FailedVersion || err == javaPluginError::WrongArch)
+ continue;
+ else if (err == javaPluginError::WrongVersionFormat)
+ return err;
+
+ vecVerifiedInfos.push_back(vecInfo);
+ }
+ //Now vecVerifiedInfos contains all those JREs which meet the version requirements
+ //Transfer them into the array that is passed out.
+ parJavaInfo->clear();
+ for (auto const& vecVerifiedInfo : vecVerifiedInfos)
+ {
+ parJavaInfo->push_back(createJavaInfo(vecVerifiedInfo));
+ }
+
+ return javaPluginError::NONE;
+}
+
+javaPluginError jfw_plugin_getJavaInfoByPath(
+ OUString const& sPath,
+ jfw::VendorSettings const & vendorSettings,
+ std::unique_ptr<JavaInfo> * ppInfo)
+{
+ assert(ppInfo != nullptr);
+ OSL_ASSERT(!sPath.isEmpty());
+ if (sPath.isEmpty())
+ return javaPluginError::InvalidArg;
+
+ rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(sPath);
+ if (!aVendorInfo.is())
+ return javaPluginError::NoJre;
+
+ //Check if the detected JRE matches the version requirements
+ javaPluginError errorcode = javaPluginError::NONE;
+ auto const versionInfo = vendorSettings.getVersionInformation(aVendorInfo->getVendor());
+ errorcode = checkJavaVersionRequirements(
+ aVendorInfo, versionInfo.sMinVersion, versionInfo.sMaxVersion, versionInfo.vecExcludeVersions);
+
+ if (errorcode == javaPluginError::NONE)
+ *ppInfo = createJavaInfo(aVendorInfo);
+
+ return errorcode;
+}
+
+javaPluginError jfw_plugin_getJavaInfoFromJavaHome(
+ jfw::VendorSettings const & vendorSettings,
+ std::unique_ptr<JavaInfo> * ppInfo,
+ std::vector<rtl::Reference<VendorBase>> & infos)
+{
+ assert(ppInfo);
+
+ std::vector<rtl::Reference<VendorBase>> infoJavaHome;
+ addJavaInfoFromJavaHome(infos, infoJavaHome);
+
+ if (infoJavaHome.empty())
+ return javaPluginError::NoJre;
+ assert(infoJavaHome.size() == 1);
+
+ //Check if the detected JRE matches the version requirements
+ auto const versionInfo = vendorSettings.getVersionInformation(infoJavaHome[0]->getVendor());
+ if (checkJavaVersionRequirements(
+ infoJavaHome[0],
+ versionInfo.sMinVersion,
+ versionInfo.sMaxVersion,
+ versionInfo.vecExcludeVersions)
+ == javaPluginError::NONE)
+ {
+ *ppInfo = createJavaInfo(infoJavaHome[0]);
+ return javaPluginError::NONE;
+ }
+
+ return javaPluginError::NoJre;
+}
+
+javaPluginError jfw_plugin_getJavaInfosFromPath(
+ jfw::VendorSettings const & vendorSettings,
+ std::vector<std::unique_ptr<JavaInfo>> & javaInfosFromPath,
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> & infos)
+{
+ // find JREs from PATH
+ std::vector<rtl::Reference<VendorBase>> vecInfosFromPath;
+ addJavaInfosFromPath(infos, vecInfosFromPath);
+
+ std::vector<std::unique_ptr<JavaInfo>> vecVerifiedInfos;
+
+ // copy infos of JREs that meet version requirements to vecVerifiedInfos
+ for (auto const& infosFromPath : vecInfosFromPath)
+ {
+ auto const versionInfo = vendorSettings.getVersionInformation(infosFromPath->getVendor());
+ if (checkJavaVersionRequirements(
+ infosFromPath,
+ versionInfo.sMinVersion,
+ versionInfo.sMaxVersion,
+ versionInfo.vecExcludeVersions)
+ == javaPluginError::NONE)
+ {
+ vecVerifiedInfos.push_back(createJavaInfo(infosFromPath));
+ }
+ }
+
+ if (vecVerifiedInfos.empty())
+ return javaPluginError::NoJre;
+
+ javaInfosFromPath = std::move(vecVerifiedInfos);
+
+ return javaPluginError::NONE;
+}
+
+
+#if defined(_WIN32)
+
+// Load msvcr71.dll using an explicit full path from where it is
+// present as bundled with the JRE. In case it is not found where we
+// think it should be, do nothing, and just let the implicit loading
+// that happens when loading the JVM take care of it.
+
+static void load_msvcr(std::u16string_view jvm_dll, std::u16string_view msvcr)
+{
+ // First check if msvcr71.dll is in the same folder as jvm.dll. It
+ // normally isn't, at least up to 1.6.0_22, but who knows if it
+ // might be in the future.
+ std::size_t slash = jvm_dll.rfind('\\');
+
+ if (slash == std::u16string_view::npos)
+ {
+ // Huh, weird path to jvm.dll. Oh well.
+ SAL_WARN("jfw", "JVM pathname <" << OUString(jvm_dll) << "> w/o backslash");
+ return;
+ }
+
+ if (LoadLibraryW(
+ o3tl::toW(OUString(OUString::Concat(jvm_dll.substr(0, slash+1)) + msvcr).getStr())))
+ return;
+
+ // Then check if msvcr71.dll is in the parent folder of where
+ // jvm.dll is. That is currently (1.6.0_22) as far as I know the
+ // normal case.
+ slash = jvm_dll.rfind('\\', slash);
+
+ if (slash == std::u16string_view::npos)
+ return;
+
+ (void)LoadLibraryW(
+ o3tl::toW(OUString(OUString::Concat(jvm_dll.substr(0, slash+1)) + msvcr).getStr()));
+}
+
+// Check if the jvm DLL imports msvcr71.dll, and in that case try
+// loading it explicitly. In case something goes wrong, do nothing,
+// and just let the implicit loading try to take care of it.
+static void do_msvcr_magic(OUString const &jvm_dll)
+{
+ struct stat st;
+
+ OUString Module;
+ osl::FileBase::RC nError = osl::FileBase::getSystemPathFromFileURL(
+ jvm_dll, Module);
+
+ if ( osl::FileBase::E_None != nError )
+ {
+ SAL_WARN(
+ "jfw", "getSystemPathFromFileURL(" << jvm_dll << "): " << +nError);
+ return;
+ }
+
+ FILE *f = _wfopen(o3tl::toW(Module.getStr()), L"rb");
+
+ if (!f)
+ {
+ SAL_WARN("jfw", "_wfopen(" << Module << ") failed");
+ return;
+ }
+
+ if (fstat(fileno(f), &st) == -1)
+ {
+ SAL_WARN("jfw", "fstat(" << Module << ") failed");
+ fclose(f);
+ return;
+ }
+
+ PIMAGE_DOS_HEADER dos_hdr = static_cast<PIMAGE_DOS_HEADER>(malloc(st.st_size));
+ assert(dos_hdr);
+ if (fread(dos_hdr, st.st_size, 1, f) != 1 ||
+ memcmp(dos_hdr, "MZ", 2) != 0 ||
+ dos_hdr->e_lfanew < 0 ||
+ dos_hdr->e_lfanew > static_cast<LONG>(st.st_size - sizeof(IMAGE_NT_HEADERS)))
+ {
+ SAL_WARN("jfw", "analyzing <" << Module << "> failed");
+ free(dos_hdr);
+ fclose(f);
+ return;
+ }
+
+ fclose(f);
+
+ IMAGE_NT_HEADERS *nt_hdr = reinterpret_cast<IMAGE_NT_HEADERS *>(reinterpret_cast<char *>(dos_hdr) + dos_hdr->e_lfanew);
+
+ DWORD importsVA = nt_hdr->OptionalHeader
+ .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
+ // first determine Virtual-to-File-address mapping for the section
+ // that contains the import directory
+ IMAGE_SECTION_HEADER *sections = IMAGE_FIRST_SECTION(nt_hdr);
+ ptrdiff_t VAtoPhys = -1;
+ for (int i = 0; i < nt_hdr->FileHeader.NumberOfSections; ++i)
+ {
+ if (sections->VirtualAddress <= importsVA &&
+ importsVA < sections->VirtualAddress + sections->SizeOfRawData)
+ {
+ VAtoPhys = static_cast<size_t>(sections->PointerToRawData) - static_cast<size_t>(sections->VirtualAddress);
+ break;
+ }
+ ++sections;
+ }
+ if (-1 == VAtoPhys) // not found?
+ {
+ SAL_WARN("jfw", "analyzing <" << Module << "> failed");
+ free(dos_hdr);
+ return;
+ }
+ IMAGE_IMPORT_DESCRIPTOR *imports =
+ reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(reinterpret_cast<char *>(dos_hdr) + importsVA + VAtoPhys);
+
+ while (imports <= reinterpret_cast<IMAGE_IMPORT_DESCRIPTOR *>(reinterpret_cast<char *>(dos_hdr) + st.st_size - sizeof (IMAGE_IMPORT_DESCRIPTOR)) &&
+ imports->Name != 0 &&
+ imports->Name + VAtoPhys < static_cast<DWORD>(st.st_size))
+ {
+ static std::u16string_view msvcrts[] =
+ {
+ u"msvcr71.dll",
+ u"msvcr100.dll"
+ };
+ char const* importName = reinterpret_cast<char *>(dos_hdr) + imports->Name + VAtoPhys;
+ sal_Int32 importNameLen = rtl_str_getLength(importName);
+ for (size_t i = 0; i < SAL_N_ELEMENTS(msvcrts); ++i)
+ {
+ if (0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLengths(
+ msvcrts[i].data(), msvcrts[i].size(),
+ importName, importNameLen))
+ {
+ load_msvcr(Module, msvcrts[i]);
+ free(dos_hdr);
+ return;
+ }
+ }
+ imports++;
+ }
+
+ free(dos_hdr);
+}
+
+#endif
+
+/** starts a Java Virtual Machine.
+ <p>
+ The function shall ensure, that the VM does not abort the process
+ during instantiation.
+ </p>
+ */
+javaPluginError jfw_plugin_startJavaVirtualMachine(
+ const JavaInfo *pInfo,
+ const JavaVMOption* arOptions,
+ sal_Int32 cOptions,
+ JavaVM ** ppVm,
+ JNIEnv ** ppEnv)
+{
+ static osl::Mutex aPluginMutex;
+ assert(pInfo != nullptr);
+ assert(ppVm != nullptr);
+ assert(ppEnv != nullptr);
+ osl::MutexGuard guard(aPluginMutex);
+ javaPluginError errorcode = javaPluginError::NONE;
+#ifdef MACOSX
+ rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath( pInfo->sLocation );
+ if ( !aVendorInfo.is() || aVendorInfo->compareVersions( pInfo->sVersion ) < 0 )
+ return javaPluginError::VmCreationFailed;
+#endif
+ OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
+#if defined MACOSX && defined __x86_64__
+ if ( !JvmfwkUtil_isLoadableJVM( sRuntimeLib ) )
+ return javaPluginError::VmCreationFailed;
+#endif
+ JFW_TRACE2("Using Java runtime library: " << sRuntimeLib);
+
+#ifndef ANDROID
+ // On linux we load jvm with RTLD_GLOBAL. This is necessary for debugging, because
+ // libjdwp.so need a symbol (fork1) from libjvm which it only gets if the jvm is loaded
+ // with RTLD_GLOBAL. On Solaris libjdwp.so is correctly linked with libjvm.so
+ osl::Module moduleRt;
+#if defined(LINUX)
+ if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_NOW))
+#elif defined MACOSX
+ // Must be SAL_LOADMODULE_GLOBAL when e.g. specifying a
+ // -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000 option to
+ // JDK 1.8.0_121 at least, as JNI_CreateJavaVM -> Threads::create_vm ->
+ // JvmtiExport::post_vm_initialized -> cbEarlyVMInit -> initialize ->
+ // util_initialize -> sun.misc.VMSupport.getAgentProperties ->
+ // Java_sun_misc_VMSupport_initAgentProperties ->
+ // JDK_FindJvmEntry("JVM_INitAgentProperties") ->
+ // dlsym(RTLD_DEFAULT, "JVM_INitAgentProperties"):
+ if (!moduleRt.load(sRuntimeLib, SAL_LOADMODULE_GLOBAL))
+#else
+#if defined(_WIN32)
+ do_msvcr_magic(sRuntimeLib);
+#endif
+ if (!moduleRt.load(sRuntimeLib))
+#endif
+ {
+ JFW_ENSURE(false,
+ "[Java framework]sunjavaplugin" SAL_DLLEXTENSION
+ " could not load Java runtime library: \n"
+ + sRuntimeLib + "\n");
+ JFW_TRACE0("Could not load Java runtime library: " << sRuntimeLib);
+ return javaPluginError::VmCreationFailed;
+ }
+
+#if defined UNX && !defined MACOSX
+ //Setting the JAVA_HOME is needed for awt
+ OUString sPathLocation;
+ osl::FileBase::getSystemPathFromFileURL(pInfo->sLocation, sPathLocation);
+ osl_setEnvironment(OUString("JAVA_HOME").pData, sPathLocation.pData);
+#endif
+
+ OUString sSymbolCreateJava("JNI_CreateJavaVM");
+
+ JNI_CreateVM_Type * pCreateJavaVM =
+ reinterpret_cast<JNI_CreateVM_Type *>(moduleRt.getFunctionSymbol(sSymbolCreateJava));
+ if (!pCreateJavaVM)
+ {
+ OSL_ASSERT(false);
+ OString sLib = OUStringToOString(
+ sRuntimeLib, osl_getThreadTextEncoding());
+ OString sSymbol = OUStringToOString(
+ sSymbolCreateJava, osl_getThreadTextEncoding());
+ SAL_WARN("jfw", "Java runtime library: " << sLib << " does not export symbol " << sSymbol);
+ return javaPluginError::VmCreationFailed;
+ }
+ moduleRt.release();
+
+ // Valgrind typically emits many false errors when executing JIT'ed JVM
+ // code, so force the JVM into interpreted mode:
+ bool addForceInterpreted = FORCE_INTERPRETED > 0;
+
+ // Some testing with Java 1.4 showed that JavaVMOption.optionString has to
+ // be encoded with the system encoding (i.e., osl_getThreadTextEncoding):
+ JavaVMInitArgs vm_args;
+
+ struct Option {
+ Option(OString const & theOptionString, void * theExtraInfo):
+ optionString(theOptionString), extraInfo(theExtraInfo)
+ {}
+
+ OString optionString;
+ void * extraInfo;
+ };
+ std::vector<Option> options;
+
+ // We set an abort handler which is called when the VM calls _exit during
+ // JNI_CreateJavaVM. This happens when the LD_LIBRARY_PATH does not contain
+ // all some directories of the Java installation. This is necessary for
+ // all versions below 1.5.1
+ options.emplace_back("abort", reinterpret_cast<void*>(abort_handler));
+ bool hasStackSize = false;
+#ifdef UNX
+ // Until java 1.5 we need to put a plugin.jar or javaplugin.jar (<1.4.2)
+ // in the class path in order to have applet support:
+ OString sAddPath = getPluginJarPath(pInfo->sVendor, pInfo->sLocation,pInfo->sVersion);
+#endif
+ for (int i = 0; i < cOptions; i++)
+ {
+ OString opt(arOptions[i].optionString);
+#ifdef UNX
+ if (opt.startsWith("-Djava.class.path="))
+ {
+ if (!sAddPath.isEmpty())
+ {
+ opt += OStringChar(SAL_PATHSEPARATOR) + sAddPath;
+ sAddPath.clear();
+ }
+ }
+#endif
+ if (opt == "-Xint") {
+ addForceInterpreted = false;
+ }
+ if (opt.startsWith("-Xss")) {
+ hasStackSize = true;
+ }
+ options.emplace_back(opt, arOptions[i].extraInfo);
+ }
+ if (addForceInterpreted) {
+ options.emplace_back("-Xint", nullptr);
+ }
+ if (!hasStackSize) {
+#if defined LINUX && (defined X86 || defined X86_64)
+ // At least OpenJDK 1.8.0's os::workaround_expand_exec_shield_cs_limit
+ // (hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp) can mmap an rwx
+ // page into the area that the main stack can grow down to according to
+ // "ulimit -s", as os::init_2's (hotspot/src/os/linux/vm/os_linux.cpp)
+ // call to
+ //
+ // Linux::capture_initial_stack(JavaThread::stack_size_at_create());
+ //
+ // caps _initial_thread_stack_size at threadStackSizeInBytes ,i.e.,
+ // -Xss, which appears to default to only 327680, whereas "ulimit -s"
+ // defaults to 8192 * 1024 at least on Fedora 20; so attempt to pass in
+ // a useful -Xss argument:
+ rlimit l;
+ if (getrlimit(RLIMIT_STACK, &l) == 0) {
+ if (l.rlim_cur == RLIM_INFINITY) {
+ SAL_INFO("jfw", "RLIMIT_STACK RLIM_INFINITY -> 8192K");
+ l.rlim_cur = 8192 * 1024;
+ } else if (l.rlim_cur > 512 * 1024 * 1024) {
+ SAL_INFO(
+ "jfw", "huge RLIMIT_STACK " << l.rlim_cur << " -> 8192K");
+ l.rlim_cur = 8192 * 1024;
+ }
+ options.emplace_back("-Xss" + OString::number(l.rlim_cur), nullptr);
+ } else {
+ int e = errno;
+ SAL_WARN("jfw", "getrlimit(RLIMIT_STACK) failed with errno " << e);
+ }
+#endif
+ }
+#ifdef UNX
+ if (!sAddPath.isEmpty()) {
+ options.emplace_back("-Djava.class.path=" + sAddPath, nullptr);
+ }
+#endif
+
+ std::unique_ptr<JavaVMOption[]> sarOptions(new JavaVMOption[options.size()]);
+ for (std::vector<Option>::size_type i = 0; i != options.size(); ++i) {
+ SAL_INFO(
+ "jfw",
+ "VM option \"" << options[i].optionString << "\" "
+ << options[i].extraInfo);
+ sarOptions[i].optionString = const_cast<char *>(
+ options[i].optionString.getStr());
+ sarOptions[i].extraInfo = options[i].extraInfo;
+ }
+
+#ifdef MACOSX
+ vm_args.version= JNI_VERSION_1_4; // issue 88987
+#else
+ vm_args.version= JNI_VERSION_1_2;
+#endif
+ vm_args.options= sarOptions.get();
+ vm_args.nOptions= options.size(); //TODO overflow
+ vm_args.ignoreUnrecognized= JNI_TRUE;
+
+ JavaVM * pJavaVM = nullptr;
+ jint err = createJvm(pCreateJavaVM, &pJavaVM, ppEnv, &vm_args);
+
+ if(err != 0)
+ {
+ if( err < 0)
+ {
+ SAL_WARN("jfw", "Can not create Java Virtual Machine, " << err);
+ errorcode = javaPluginError::VmCreationFailed;
+ }
+ else if( err > 0)
+ {
+ SAL_WARN("jfw", "Can not create JavaVirtualMachine, abort handler was called");
+ errorcode = javaPluginError::VmCreationFailed;
+ }
+ }
+ else
+ {
+ *ppVm = pJavaVM;
+ JFW_TRACE2("JVM created");
+ }
+#else
+ (void) arOptions;
+ (void) cOptions;
+ (void) ppEnv;
+ // On Android we always have a Java VM as we only expect this code
+ // to be run in an Android app anyway.
+ *ppVm = lo_get_javavm();
+#endif
+
+ return errorcode;
+}
+
+javaPluginError jfw_plugin_existJRE(const JavaInfo *pInfo, bool *exist)
+{
+ assert(pInfo != nullptr);
+ assert(exist != nullptr);
+
+ javaPluginError ret = javaPluginError::NONE;
+ OUString sLocation(pInfo->sLocation);
+
+ if (sLocation.isEmpty())
+ return javaPluginError::InvalidArg;
+ ::osl::DirectoryItem item;
+ ::osl::File::RC rc_item = ::osl::DirectoryItem::get(sLocation, item);
+ if (::osl::File::E_None == rc_item)
+ {
+ *exist = true;
+ }
+ else if (::osl::File::E_NOENT == rc_item)
+ {
+ *exist = false;
+ }
+ else
+ {
+ ret = javaPluginError::Error;
+ }
+ //We can have the situation that the JavaVM runtime library is not
+ //contained within JAVA_HOME. Then the check for JAVA_HOME would return
+ //true although the runtime library may not be loadable.
+ //Or the JAVA_HOME directory of a deinstalled JRE left behind.
+ if (ret == javaPluginError::NONE && *exist)
+ {
+ OUString sRuntimeLib = getRuntimeLib(pInfo->arVendorData);
+ JFW_TRACE2("Checking existence of Java runtime library");
+
+ ::osl::DirectoryItem itemRt;
+ ::osl::File::RC rc_itemRt = ::osl::DirectoryItem::get(sRuntimeLib, itemRt);
+ if (::osl::File::E_None == rc_itemRt)
+ {
+ *exist = true;
+ JFW_TRACE2("Java runtime library exist: " << sRuntimeLib);
+
+ // Check version
+ rtl::Reference<VendorBase> aVendorInfo = getJREInfoByPath(sLocation);
+ if (!aVendorInfo.is())
+ {
+ *exist = false;
+ JFW_TRACE2("JRE or supported vendor not accessible at location: " << sLocation);
+ }
+ else if(pInfo->sVersion!=aVendorInfo->getVersion())
+ {
+ *exist = false;
+ JFW_TRACE2("Mismatch between version number in libreoffice settings and installed JRE: " << pInfo->sVersion <<" != " << aVendorInfo->getVersion());
+ }
+ }
+ else if (::osl::File::E_NOENT == rc_itemRt)
+ {
+ *exist = false;
+ JFW_TRACE2("Java runtime library does not exist: " << sRuntimeLib);
+ }
+ else
+ {
+ ret = javaPluginError::Error;
+ JFW_TRACE2("Error while looking for Java runtime library: " << sRuntimeLib);
+ }
+ }
+ return ret;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunjre.cxx b/jvmfwk/plugins/sunmajor/pluginlib/sunjre.cxx
new file mode 100644
index 000000000..a0f8cbee1
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/sunjre.cxx
@@ -0,0 +1,116 @@
+/* -*- 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 "sunjre.hxx"
+#include "sunversion.hxx"
+#include "diagnostics.h"
+
+namespace jfw_plugin
+{
+
+rtl::Reference<VendorBase> SunInfo::createInstance()
+{
+ return new SunInfo;
+}
+
+char const* const* SunInfo::getJavaExePaths(int * size)
+{
+ static char const * ar[] = {
+#if defined(_WIN32)
+ "java.exe",
+ "bin/java.exe",
+ "jre/bin/java.exe"
+#elif defined UNX
+ "java",
+ "bin/java",
+ "jre/bin/java"
+#endif
+ };
+ *size = SAL_N_ELEMENTS(ar);
+ return ar;
+}
+
+char const* const* SunInfo::getRuntimePaths(int * size)
+{
+ static char const* ar[]= {
+#if defined(_WIN32)
+ "/bin/client/jvm.dll",
+ "/bin/hotspot/jvm.dll",
+ "/bin/classic/jvm.dll",
+ "/bin/jrockit/jvm.dll",
+ // The 64-bit JRE has the jvm in bin/server
+ "/bin/server/jvm.dll"
+#elif defined MACOSX
+ // Oracle Java 7, under /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home
+ "/lib/server/libjvm.dylib",
+ "/lib/jli/libjli.dylib"
+#elif defined UNX
+ "/lib/" JFW_PLUGIN_ARCH "/client/libjvm.so",
+ "/lib/" JFW_PLUGIN_ARCH "/server/libjvm.so",
+ "/lib/" JFW_PLUGIN_ARCH "/classic/libjvm.so",
+ "/lib/" JFW_PLUGIN_ARCH "/jrockit/libjvm.so",
+ "/lib/server/libjvm.so"
+#endif
+ };
+ *size = SAL_N_ELEMENTS(ar);
+ return ar;
+}
+
+char const* const* SunInfo::getLibraryPaths(int* size)
+{
+#if defined UNX && !defined MACOSX
+ static char const * ar[] = {
+ "/lib/" JFW_PLUGIN_ARCH "/client",
+ "/lib/" JFW_PLUGIN_ARCH "/server",
+ "/lib/" JFW_PLUGIN_ARCH "/native_threads",
+ ("/lib/" JFW_PLUGIN_ARCH)
+ };
+ *size = SAL_N_ELEMENTS(ar);
+ return ar;
+#else
+ *size = 0;
+ return nullptr;
+#endif
+}
+
+int SunInfo::compareVersions(const OUString& sSecond) const
+{
+ OUString sFirst = getVersion();
+
+ SunVersion version1(sFirst);
+ JFW_ENSURE(version1, "[Java framework] sunjavaplugin" SAL_DLLEXTENSION
+ " does not know the version: "
+ + sFirst + " as valid for a SUN/Oracle JRE.");
+ SunVersion version2(sSecond);
+ if ( ! version2)
+ throw MalformedVersionException();
+
+ if (version1 == version2)
+ return 0;
+ if (version1 > version2)
+ return 1;
+ else
+ return -1;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunjre.hxx b/jvmfwk/plugins/sunmajor/pluginlib/sunjre.hxx
new file mode 100644
index 000000000..773f40080
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/sunjre.hxx
@@ -0,0 +1,42 @@
+/* -*- 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_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_SUNJRE_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_SUNJRE_HXX
+
+#include <vendorbase.hxx>
+
+namespace jfw_plugin
+{
+class SunInfo : public VendorBase
+{
+public:
+ static char const* const* getJavaExePaths(int* size);
+
+ static rtl::Reference<VendorBase> createInstance();
+
+ virtual char const* const* getRuntimePaths(int* size) override;
+ virtual char const* const* getLibraryPaths(int* size) override;
+
+ virtual int compareVersions(const OUString& sSecond) const override;
+};
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunversion.cxx b/jvmfwk/plugins/sunmajor/pluginlib/sunversion.cxx
new file mode 100644
index 000000000..16a1e14f3
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/sunversion.cxx
@@ -0,0 +1,303 @@
+/* -*- 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 "sunversion.hxx"
+#include <osl/thread.h>
+#include <rtl/character.hxx>
+#include <rtl/ustring.hxx>
+#include <string.h>
+namespace jfw_plugin { //stoc_javadetect
+
+
+SunVersion::SunVersion(std::u16string_view usVer):
+ m_nUpdateSpecial(0), m_preRelease(Rel_NONE)
+{
+ OString sVersion= OUStringToOString(usVer, osl_getThreadTextEncoding());
+ m_bValid = init(sVersion.getStr());
+}
+SunVersion::SunVersion(const char * szVer):
+ m_nUpdateSpecial(0), m_preRelease(Rel_NONE)
+{
+ m_bValid = init(szVer);
+}
+
+
+/**Format major.minor.maintenance_update
+ */
+bool SunVersion::init(const char *szVersion)
+{
+ if (!szVersion || szVersion[0] == '\0')
+ return false;
+
+ //first get the major,minor,maintenance
+ const char * pLast = szVersion;
+ const char * pCur = szVersion;
+ //pEnd point to the position after the last character
+ const char * pEnd = szVersion + strlen(szVersion);
+ // 0 = major, 1 = minor, 2 = maintenance, 3 = update
+ int nPart = 0;
+ // position within part beginning with 0
+ int nPartPos = 0;
+ char buf[128];
+
+ //char must me a number 0 - 999 and no leading
+ while (true)
+ {
+ if (pCur < pEnd && rtl::isAsciiDigit(static_cast<unsigned char>(*pCur)))
+ {
+ pCur ++;
+ nPartPos ++;
+ }
+ //if correct separator then form integer
+ else if (
+ (nPartPos != 0) // prevents: ".4.1", "..1", part must start with digit
+ && (
+ //separators after maintenance (1.4.1_01, 1.4.1-beta, or 1.4.1)
+ (pCur == pEnd || *pCur == '_' || *pCur == '-')
+ ||
+ //separators between major-minor and minor-maintenance (or fourth segment)
+ (nPart < 3 && *pCur == '.') )
+ && (
+ //prevent 1.4.0. 1.4.0-
+ pCur + 1 != pEnd
+ || rtl::isAsciiDigit(static_cast<unsigned char>(*pCur))) )
+ {
+ bool afterMaint = pCur == pEnd || *pCur == '_' || *pCur == '-';
+
+ int len = pCur - pLast;
+ if (len >= 127)
+ return false;
+
+ strncpy(buf, pLast, len);
+ buf[len] = 0;
+ pCur ++;
+ pLast = pCur;
+
+ m_arVersionParts[nPart] = atoi(buf);
+
+ if (afterMaint)
+ nPart = 2;
+ nPart ++;
+ nPartPos = 0;
+ if (nPart == 3)
+ break;
+
+ //check next character
+ if (! ( (pCur < pEnd)
+ && ( (nPart < 3)
+ && rtl::isAsciiDigit(
+ static_cast<unsigned char>(*pCur)))))
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ if (pCur >= pEnd)
+ return true;
+ //We have now 1.4.1. This can be followed by _01 (or a fourth segment .1), -beta, etc.
+ // _01 (update) According to docu must not be followed by any other
+ //characters, but on Solaris 9 we have a 1.4.1_01a!!
+ if (* (pCur - 1) == '_' || *(pCur - 1) == '.')
+ {// _01, _02
+ // update is the last part _01, _01a, part 0 is the digits parts and 1 the trailing alpha
+ while (true)
+ {
+ if (pCur <= pEnd)
+ {
+ if ( ! rtl::isAsciiDigit(static_cast<unsigned char>(*pCur)))
+ {
+ //1.8.0_102-, 1.8.0_01a,
+ size_t len = pCur - pLast;
+ if (len > sizeof(buf) - 1)
+ return false;
+ //we've got the update: 01, 02 etc
+ strncpy(buf, pLast, len);
+ buf[len] = 0;
+ m_arVersionParts[nPart] = atoi(buf);
+ if (pCur == pEnd)
+ {
+ break;
+ }
+ if (*pCur == 'a' && (pCur + 1) == pEnd)
+ {
+ //check if it s followed by a simple "a" (not specified)
+ m_nUpdateSpecial = *pCur;
+ break;
+ }
+ else if (*pCur == '-' && pCur < pEnd)
+ {
+ //check 1.5.0_01-ea
+ PreRelease pr = getPreRelease(++pCur);
+ if (pr == Rel_NONE)
+ return false;
+ //just ignore -ea because its no official release
+ break;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ if (pCur < pEnd)
+ pCur ++;
+ else
+ break;
+ }
+ }
+ }
+ // 1.4.1-ea
+ else if (*(pCur - 1) == '-')
+ {
+ m_preRelease = getPreRelease(pCur);
+ if (m_preRelease == Rel_NONE)
+ return false;
+#if defined(FREEBSD)
+ if (m_preRelease == Rel_FreeBSD)
+ {
+ pCur++; //eliminate 'p'
+ if (pCur < pEnd
+ && rtl::isAsciiDigit(static_cast<unsigned char>(*pCur)))
+ pCur ++;
+ int len = pCur - pLast -1; //eliminate 'p'
+ if (len >= 127)
+ return false;
+ strncpy(buf, (pLast+1), len); //eliminate 'p'
+ buf[len] = 0;
+ m_nUpdateSpecial = atoi(buf)+100; //hack for FBSD #i56953#
+ return true;
+ }
+#endif
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+}
+
+SunVersion::PreRelease SunVersion::getPreRelease(const char *szRelease)
+{
+ if (szRelease == nullptr)
+ return Rel_NONE;
+ if( ! strcmp(szRelease,"internal"))
+ return Rel_INTERNAL;
+ else if( ! strcmp(szRelease,"ea"))
+ return Rel_EA;
+ else if( ! strcmp(szRelease,"ea1"))
+ return Rel_EA1;
+ else if( ! strcmp(szRelease,"ea2"))
+ return Rel_EA2;
+ else if( ! strcmp(szRelease,"ea3"))
+ return Rel_EA3;
+ else if ( ! strcmp(szRelease,"beta"))
+ return Rel_BETA;
+ else if ( ! strcmp(szRelease,"beta1"))
+ return Rel_BETA1;
+ else if ( ! strcmp(szRelease,"beta2"))
+ return Rel_BETA2;
+ else if ( ! strcmp(szRelease,"beta3"))
+ return Rel_BETA3;
+ else if (! strcmp(szRelease, "rc"))
+ return Rel_RC;
+ else if (! strcmp(szRelease, "rc1"))
+ return Rel_RC1;
+ else if (! strcmp(szRelease, "rc2"))
+ return Rel_RC2;
+ else if (! strcmp(szRelease, "rc3"))
+ return Rel_RC3;
+#if defined (FREEBSD)
+ else if (! strncmp(szRelease, "p", 1))
+ return Rel_FreeBSD;
+#endif
+ else
+ return Rel_NONE;
+}
+
+/* Examples:
+ a) 1.0 < 1.1
+ b) 1.0 < 1.0.0
+ c) 1.0 < 1.0_00
+
+ returns false if both values are equal
+*/
+bool SunVersion::operator > (const SunVersion& ver) const
+{
+ if( &ver == this)
+ return false;
+
+ //compare major.minor.maintenance
+ for( int i= 0; i < 4; i ++)
+ {
+ // 1.4 > 1.3
+ if(m_arVersionParts[i] > ver.m_arVersionParts[i])
+ {
+ return true;
+ }
+ else if (m_arVersionParts[i] < ver.m_arVersionParts[i])
+ {
+ return false;
+ }
+ }
+ //major.minor.maintenance_update are equal. Test for a trailing char
+ if (m_nUpdateSpecial > ver.m_nUpdateSpecial)
+ {
+ return true;
+ }
+
+ //Until here the versions are equal
+ //compare pre -release values
+ if ((m_preRelease == Rel_NONE && ver.m_preRelease == Rel_NONE)
+ ||
+ (m_preRelease != Rel_NONE && ver.m_preRelease == Rel_NONE))
+ return false;
+ else if (m_preRelease == Rel_NONE && ver.m_preRelease != Rel_NONE)
+ return true;
+ else if (m_preRelease > ver.m_preRelease)
+ return true;
+
+ return false;
+}
+
+bool SunVersion::operator < (const SunVersion& ver) const
+{
+ return (! operator > (ver)) && (! operator == (ver));
+}
+
+bool SunVersion::operator == (const SunVersion& ver) const
+{
+ bool bRet= true;
+ for(int i= 0; i < 4; i++)
+ {
+ if( m_arVersionParts[i] != ver.m_arVersionParts[i])
+ {
+ bRet= false;
+ break;
+ }
+ }
+ bRet = m_nUpdateSpecial == ver.m_nUpdateSpecial && bRet;
+ bRet = m_preRelease == ver.m_preRelease && bRet;
+ return bRet;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/sunversion.hxx b/jvmfwk/plugins/sunmajor/pluginlib/sunversion.hxx
new file mode 100644
index 000000000..58173b74f
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/sunversion.hxx
@@ -0,0 +1,115 @@
+/* -*- 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_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_SUNVERSION_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_SUNVERSION_HXX
+
+#include <sal/config.h>
+
+#include <string_view>
+
+namespace jfw_plugin
+{
+/* SunVersion is used to compare java versions based on a string, as taken
+ from the registry. The strings look like "1.3", "1.3.1", "1.3.1_02" etc.
+ Versions such as "1.4.1_01a" are allowed although this is not specified.
+ 1.4.1_01 < 1.4.1_01a < 1.4.1_01b < 1.4.1_02
+ Pre - release versions, such as 1.4.1-ea, 1.4.1-beta, 1.4.1-rc are recognized,
+ but are treated as minor to release versions:
+ 1.4.0 > 1.4.2-beta
+ Pre releases relate this way
+ 1.4.1-ea < 1.4.1-beta < 1.4.1-rc1
+
+ This class supports also a FreeBSD Java. This is currently necessary because
+ it also has the vendor string "Sun Microsystems Inc.".
+
+ An object acts as holder for the version string. That string may be present
+ even if the version could not be parsed. Then the version may not be compatible
+ to a SUN Java version.
+
+ An invalid object, that is, operator bool returns false, will always be
+ the lower version in a comparison. If two invalid objects are compared
+ then they are considered equal.
+
+ To test if the version is ok, that is this object can be compared to others,
+ use the bool conversion operator.
+ */
+class SunVersion final
+{
+ enum PreRelease
+ {
+ Rel_NONE,
+ Rel_INTERNAL,
+ Rel_EA,
+ Rel_EA1,
+ Rel_EA2,
+ Rel_EA3,
+ Rel_BETA,
+ Rel_BETA1,
+ Rel_BETA2,
+ Rel_BETA3,
+ Rel_RC,
+ Rel_RC1,
+ Rel_RC2,
+ Rel_RC3
+#if defined(FREEBSD)
+ ,
+ Rel_FreeBSD
+#endif
+ };
+
+ //contains major,minor,micro,update
+ int m_arVersionParts[4] = {};
+ // The update can be followed by a char, e.g. 1.4.1_01a
+ char m_nUpdateSpecial;
+
+ PreRelease m_preRelease;
+
+public:
+ explicit SunVersion(const char* szVer);
+ explicit SunVersion(std::u16string_view usVer);
+
+ /**
+ Pre-release versions are taken into account.
+ 1.5.0-beta > 1.5.0-ea > 1.4.2
+ */
+ bool operator>(const SunVersion& ver) const;
+ bool operator<(const SunVersion& ver) const;
+ bool operator==(const SunVersion& ver) const;
+
+ /** Test if the version is compatible tu SUN's versioning scheme
+ */
+ operator bool() { return m_bValid; }
+
+private:
+ bool init(const char* szVer);
+
+ bool m_bValid;
+
+ /* Determines if a string constitutes a pre release. For example, if
+ "ea" is passed then Rel_EA is returned. If the string is no pre release
+ then Rel_NONE is returned.
+ */
+ static PreRelease getPreRelease(const char* szRel);
+};
+}
+
+#endif // INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_SUNVERSION_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util.cxx b/jvmfwk/plugins/sunmajor/pluginlib/util.cxx
new file mode 100644
index 000000000..6eb96d731
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/util.cxx
@@ -0,0 +1,1281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_folders.h>
+
+#include "util.hxx"
+
+#include <osl/process.h>
+#include <osl/file.hxx>
+#include <osl/module.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <salhelper/linkhelper.hxx>
+#include <salhelper/thread.hxx>
+#include <o3tl/string_view.hxx>
+#include <memory>
+#include <utility>
+#include <algorithm>
+#include <map>
+#include <string_view>
+
+#if defined(_WIN32)
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#endif
+#include <string.h>
+
+#include "sunjre.hxx"
+#include "vendorlist.hxx"
+#include "diagnostics.h"
+#if defined MACOSX && defined __x86_64__
+#include "util_cocoa.hxx"
+#endif
+
+using namespace osl;
+
+using ::rtl::Reference;
+
+#ifdef _WIN32
+#define HKEY_SUN_JRE L"Software\\JavaSoft\\Java Runtime Environment"
+#define HKEY_SUN_SDK L"Software\\JavaSoft\\Java Development Kit"
+#endif
+
+#if defined( UNX ) && !defined( MACOSX )
+namespace {
+char const *g_arJavaNames[] = {
+ "",
+ "j2re",
+ "j2se",
+ "j2sdk",
+ "jdk",
+ "jre",
+ "java"
+};
+
+/* These are directory names which could contain multiple java installations.
+ */
+char const *g_arCollectDirs[] = {
+ "",
+#ifndef JVM_ONE_PATH_CHECK
+ "j2re/",
+ "j2se/",
+ "j2sdk/",
+ "jdk/",
+ "jre/",
+ "java/",
+#endif
+ "jvm/"
+};
+
+/* These are directories in which a java installation is
+ looked for.
+*/
+char const *g_arSearchPaths[] = {
+#ifndef JVM_ONE_PATH_CHECK
+ "",
+ "usr/",
+ "usr/local/",
+#ifdef X86_64
+ "usr/lib64/",
+#endif
+ "usr/lib/",
+ "usr/bin/"
+#else
+ JVM_ONE_PATH_CHECK
+#endif
+};
+}
+#endif // UNX && !MACOSX
+
+namespace jfw_plugin
+{
+#if defined(_WIN32)
+static bool getSDKInfoFromRegistry(std::vector<OUString> & vecHome);
+static bool getJREInfoFromRegistry(std::vector<OUString>& vecJavaHome);
+#endif
+
+static bool decodeOutput(std::string_view s, OUString* out);
+
+
+namespace
+{
+
+bool addJREInfo(
+ rtl::Reference<VendorBase> const & info,
+ std::vector<rtl::Reference<VendorBase>> & infos)
+{
+ if (std::none_of(infos.begin(), infos.end(), InfoFindSame(info->getHome()))) {
+ infos.push_back(info);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool getAndAddJREInfoByPath(
+ const OUString& path,
+ std::vector<rtl::Reference<VendorBase> > & allInfos,
+ std::vector<rtl::Reference<VendorBase> > & addedInfos)
+{
+ rtl::Reference<VendorBase> aInfo = getJREInfoByPath(path);
+ if (aInfo.is()) {
+ if (addJREInfo(aInfo, allInfos)) {
+ addedInfos.push_back(aInfo);
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+}
+
+namespace {
+
+class FileHandleGuard
+{
+public:
+ explicit FileHandleGuard(oslFileHandle & rHandle):
+ m_rHandle(rHandle) {}
+
+ inline ~FileHandleGuard();
+
+ FileHandleGuard(const FileHandleGuard&) = delete;
+ FileHandleGuard& operator=(const FileHandleGuard&) = delete;
+
+ oslFileHandle & getHandle() { return m_rHandle; }
+
+private:
+ oslFileHandle & m_rHandle;
+};
+
+}
+
+inline FileHandleGuard::~FileHandleGuard()
+{
+ if (m_rHandle != nullptr)
+ {
+ if (osl_closeFile(m_rHandle) != osl_File_E_None)
+ {
+ OSL_FAIL("unexpected situation");
+ }
+ }
+}
+
+namespace {
+
+class FileHandleReader
+{
+public:
+ enum Result
+ {
+ RESULT_OK,
+ RESULT_EOF,
+ RESULT_ERROR
+ };
+
+ explicit FileHandleReader(oslFileHandle & rHandle):
+ m_aGuard(rHandle), m_nSize(0), m_nIndex(0), m_bLf(false) {}
+
+ Result readLine(OString * pLine);
+
+private:
+ enum { BUFFER_SIZE = 1024 };
+
+ char m_aBuffer[BUFFER_SIZE];
+ FileHandleGuard m_aGuard;
+ int m_nSize;
+ int m_nIndex;
+ bool m_bLf;
+};
+
+}
+
+FileHandleReader::Result
+FileHandleReader::readLine(OString * pLine)
+{
+ OSL_ENSURE(pLine, "specification violation");
+
+ for (bool bEof = true;; bEof = false)
+ {
+ if (m_nIndex == m_nSize)
+ {
+ sal_uInt64 nRead = 0;
+ switch (osl_readFile(
+ m_aGuard.getHandle(), m_aBuffer, sizeof(m_aBuffer), &nRead))
+ {
+ case osl_File_E_PIPE: //HACK! for windows
+ nRead = 0;
+ [[fallthrough]];
+ case osl_File_E_None:
+ if (nRead == 0)
+ {
+ m_bLf = false;
+ return bEof ? RESULT_EOF : RESULT_OK;
+ }
+ m_nIndex = 0;
+ m_nSize = static_cast< int >(nRead);
+ break;
+ case osl_File_E_INTR:
+ continue;
+
+ default:
+ return RESULT_ERROR;
+ }
+ }
+
+ if (m_bLf && m_aBuffer[m_nIndex] == 0x0A)
+ ++m_nIndex;
+ m_bLf = false;
+
+ int nStart = m_nIndex;
+ while (m_nIndex != m_nSize)
+ switch (m_aBuffer[m_nIndex++])
+ {
+ case 0x0D:
+ m_bLf = true;
+ [[fallthrough]];
+ case 0x0A:
+ *pLine += std::string_view(m_aBuffer + nStart,
+ m_nIndex - 1 - nStart);
+ //TODO! check for overflow, and not very efficient
+ return RESULT_OK;
+ }
+
+ *pLine += std::string_view(m_aBuffer + nStart, m_nIndex - nStart);
+ //TODO! check for overflow, and not very efficient
+ }
+}
+
+namespace {
+
+class AsynchReader: public salhelper::Thread
+{
+ size_t m_nDataSize;
+ std::unique_ptr<char[]> m_arData;
+
+ FileHandleGuard m_aGuard;
+
+ virtual ~AsynchReader() override {}
+
+ void execute() override;
+public:
+
+ explicit AsynchReader(oslFileHandle & rHandle);
+
+ /** only call this function after this thread has finished.
+
+ That is, call join on this instance and then call getData.
+
+ */
+ OString getData();
+};
+
+}
+
+AsynchReader::AsynchReader(oslFileHandle & rHandle):
+ Thread("jvmfwkAsyncReader"), m_nDataSize(0),
+ m_aGuard(rHandle)
+{
+}
+
+OString AsynchReader::getData()
+{
+ return OString(m_arData.get(), m_nDataSize);
+}
+
+void AsynchReader::execute()
+{
+ const sal_uInt64 BUFFER_SIZE = 4096;
+ char aBuffer[BUFFER_SIZE];
+ while (true)
+ {
+ sal_uInt64 nRead;
+ //the function blocks until something could be read or the pipe closed.
+ switch (osl_readFile(
+ m_aGuard.getHandle(), aBuffer, BUFFER_SIZE, &nRead))
+ {
+ case osl_File_E_PIPE: //HACK! for windows
+ nRead = 0;
+ [[fallthrough]];
+ case osl_File_E_None:
+ break;
+ default:
+ return;
+ }
+
+ if (nRead == 0)
+ {
+ break;
+ }
+ else if (nRead <= BUFFER_SIZE)
+ {
+ //Save the data we have in m_arData into a temporary array
+ std::unique_ptr<char[]> arTmp( new char[m_nDataSize]);
+ if (m_nDataSize != 0) {
+ memcpy(arTmp.get(), m_arData.get(), m_nDataSize);
+ }
+ //Enlarge m_arData to hold the newly read data
+ m_arData.reset(new char[static_cast<size_t>(m_nDataSize + nRead)]);
+ //Copy back the data that was already in m_arData
+ memcpy(m_arData.get(), arTmp.get(), m_nDataSize);
+ //Add the newly read data to m_arData
+ memcpy(m_arData.get() + m_nDataSize, aBuffer, static_cast<size_t>(nRead));
+ m_nDataSize += static_cast<size_t>(nRead);
+ }
+ }
+}
+
+bool getJavaProps(const OUString & exePath,
+#ifdef JVM_ONE_PATH_CHECK
+ const OUString & homePath,
+#endif
+ std::vector<std::pair<OUString, OUString> >& props,
+ bool * bProcessRun)
+{
+ bool ret = false;
+
+ OSL_ASSERT(!exePath.isEmpty());
+ OUString usStartDir;
+ //We need to set the CLASSPATH in case the office is started from
+ //a different directory. The JREProperties.class is expected to reside
+ //next to the plugin, except on macOS where it is in ../Resources/java relative
+ //to the plugin.
+ OUString sThisLib;
+ if (!osl_getModuleURLFromAddress(reinterpret_cast<void *>(&getJavaProps),
+ & sThisLib.pData))
+ {
+ return false;
+ }
+ sThisLib = getDirFromFile(sThisLib);
+ OUString sClassPath;
+ if (osl_getSystemPathFromFileURL(sThisLib.pData, & sClassPath.pData)
+ != osl_File_E_None)
+ {
+ return false;
+ }
+
+#ifdef MACOSX
+#if defined __x86_64__
+ if (!JvmfwkUtil_isLoadableJVM(exePath))
+ return false;
+#endif
+ if (sClassPath.endsWith("/"))
+ sClassPath += "../Resources/java/";
+ else
+ sClassPath += "/../Resources/java";
+#endif
+
+ //prepare the arguments
+ sal_Int32 const cArgs = 3;
+ OUString arg1 = "-classpath";// + sClassPath;
+ OUString arg2 = sClassPath;
+ OUString arg3("JREProperties");
+ rtl_uString *args[cArgs] = {arg1.pData, arg2.pData, arg3.pData};
+
+ oslProcess javaProcess= nullptr;
+ oslFileHandle fileOut= nullptr;
+ oslFileHandle fileErr= nullptr;
+
+ FileHandleReader stdoutReader(fileOut);
+ rtl::Reference< AsynchReader > stderrReader(new AsynchReader(fileErr));
+
+ JFW_TRACE2("Executing: " + exePath);
+ oslProcessError procErr =
+ osl_executeProcess_WithRedirectedIO( exePath.pData,//usExe.pData,
+ args,
+ cArgs, //sal_uInt32 nArguments,
+ osl_Process_HIDDEN, //oslProcessOption Options,
+ nullptr, //oslSecurity Security,
+ usStartDir.pData,//usStartDir.pData,//usWorkDir.pData, //rtl_uString *strWorkDir,
+ nullptr, //rtl_uString *strEnvironment[],
+ 0, // sal_uInt32 nEnvironmentVars,
+ &javaProcess, //oslProcess *pProcess,
+ nullptr,//oslFileHandle *pChildInputWrite,
+ &fileOut,//oslFileHandle *pChildOutputRead,
+ &fileErr);//oslFileHandle *pChildErrorRead);
+
+ if( procErr != osl_Process_E_None)
+ {
+ JFW_TRACE2("Execution failed");
+ *bProcessRun = false;
+ SAL_WARN("jfw",
+ "osl_executeProcess failed (" << ret << "): \"" << exePath << "\"");
+ return ret;
+ }
+ else
+ {
+ JFW_TRACE2("Java executed successfully");
+ *bProcessRun = true;
+ }
+
+ //Start asynchronous reading (different thread) of error stream
+ stderrReader->launch();
+
+ //Use this thread to read output stream
+ FileHandleReader::Result rs = FileHandleReader::RESULT_OK;
+ JFW_TRACE2("Properties found:");
+ while (true)
+ {
+ OString aLine;
+ rs = stdoutReader.readLine( & aLine);
+ if (rs != FileHandleReader::RESULT_OK)
+ break;
+ OUString sLine;
+ if (!decodeOutput(aLine, &sLine))
+ continue;
+ JFW_TRACE2(" \"" << sLine << "\"");
+ sLine = sLine.trim();
+ if (sLine.isEmpty())
+ continue;
+ //The JREProperties class writes key value pairs, separated by '='
+ sal_Int32 index = sLine.indexOf('=');
+ OSL_ASSERT(index != -1);
+ OUString sKey = sLine.copy(0, index);
+ OUString sVal = sLine.copy(index + 1);
+
+#ifdef JVM_ONE_PATH_CHECK
+ //replace absolute path by linux distro link
+ OUString sHomeProperty("java.home");
+ if(sHomeProperty.equals(sKey))
+ {
+ sVal = homePath + "/jre";
+ }
+#endif
+
+ props.emplace_back(sKey, sVal);
+ }
+
+ if (rs != FileHandleReader::RESULT_ERROR && !props.empty())
+ ret = true;
+
+ //process error stream data
+ stderrReader->join();
+ JFW_TRACE2("Java wrote to stderr:\" "
+ << stderrReader->getData() << " \"");
+
+ TimeValue waitMax= {5 ,0};
+ procErr = osl_joinProcessWithTimeout(javaProcess, &waitMax);
+ OSL_ASSERT(procErr == osl_Process_E_None);
+ osl_freeProcessHandle(javaProcess);
+ return ret;
+}
+
+/* converts the properties printed by JREProperties.class into
+ readable strings. The strings are encoded as integer values separated
+ by spaces.
+ */
+bool decodeOutput(std::string_view s, OUString* out)
+{
+ OSL_ASSERT(out != nullptr);
+ OUStringBuffer buff(512);
+ sal_Int32 nIndex = 0;
+ do
+ {
+ std::string_view aToken = o3tl::getToken(s, 0, ' ', nIndex );
+ if (!aToken.empty())
+ {
+ for (size_t i = 0; i < aToken.size(); ++i)
+ {
+ if (aToken[i] < '0' || aToken[i] > '9')
+ return false;
+ }
+ sal_Unicode value = static_cast<sal_Unicode>(o3tl::toInt32(aToken));
+ buff.append(value);
+ }
+ } while (nIndex >= 0);
+
+ *out = buff.makeStringAndClear();
+ return true;
+}
+
+
+#if defined(_WIN32)
+
+static bool getJavaInfoFromRegistry(const wchar_t* szRegKey,
+ std::vector<OUString>& vecJavaHome)
+{
+ HKEY hRoot;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, szRegKey, 0, KEY_ENUMERATE_SUB_KEYS, &hRoot)
+ == ERROR_SUCCESS)
+ {
+ DWORD dwIndex = 0;
+ const DWORD BUFFSIZE = 1024;
+ wchar_t bufVersion[BUFFSIZE];
+ FILETIME fileTime;
+ DWORD nNameLen = sizeof(bufVersion);
+
+ // Iterate over all subkeys of HKEY_LOCAL_MACHINE\Software\JavaSoft\Java Runtime Environment
+ while (RegEnumKeyExW(hRoot, dwIndex, bufVersion, &nNameLen, nullptr, nullptr, nullptr, &fileTime) != ERROR_NO_MORE_ITEMS)
+ {
+ HKEY hKey;
+ // Open a Java Runtime Environment sub key, e.g. "1.4.0"
+ if (RegOpenKeyExW(hRoot, bufVersion, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+ {
+ DWORD dwType;
+ DWORD dwTmpPathLen= 0;
+ // Get the path to the JavaHome every JRE entry
+ // Find out how long the string for JavaHome is and allocate memory to hold the path
+ if( RegQueryValueExW(hKey, L"JavaHome", nullptr, &dwType, nullptr, &dwTmpPathLen)== ERROR_SUCCESS)
+ {
+ unsigned char* szTmpPath= static_cast<unsigned char *>(malloc(dwTmpPathLen+sizeof(sal_Unicode)));
+ // According to https://msdn.microsoft.com/en-us/ms724911, the application should ensure
+ // that the string is properly terminated before using it
+ for (DWORD i = 0; i < sizeof(sal_Unicode); ++i)
+ szTmpPath[dwTmpPathLen + i] = 0;
+ // Get the path for the runtime lib
+ if(RegQueryValueExW(hKey, L"JavaHome", nullptr, &dwType, szTmpPath, &dwTmpPathLen) == ERROR_SUCCESS)
+ {
+ // There can be several version entries referring with the same JavaHome,e.g 1.4 and 1.4.1
+ OUString usHome(reinterpret_cast<sal_Unicode*>(szTmpPath));
+ // check if there is already an entry with the same JavaHomeruntime lib
+ // if so, we use the one with the more accurate version
+ OUString usHomeUrl;
+ if (osl_getFileURLFromSystemPath(usHome.pData, & usHomeUrl.pData) ==
+ osl_File_E_None)
+ {
+ bool bAppend= true;
+ //iterate over the vector with java home strings
+ for (auto const& javaHome : vecJavaHome)
+ {
+ if(usHomeUrl.equals(javaHome))
+ {
+ bAppend= false;
+ break;
+ }
+ }
+ // Save the home dir
+ if(bAppend)
+ {
+ vecJavaHome.push_back(usHomeUrl);
+ }
+ }
+ }
+ free( szTmpPath);
+ RegCloseKey(hKey);
+ }
+ }
+ dwIndex ++;
+ nNameLen = BUFFSIZE;
+ }
+ RegCloseKey(hRoot);
+ }
+ return true;
+}
+
+
+bool getSDKInfoFromRegistry(std::vector<OUString> & vecHome)
+{
+ return getJavaInfoFromRegistry(HKEY_SUN_SDK, vecHome);
+}
+
+bool getJREInfoFromRegistry(std::vector<OUString>& vecJavaHome)
+{
+ return getJavaInfoFromRegistry(HKEY_SUN_JRE, vecJavaHome);
+}
+
+static void addJavaInfoFromWinReg(
+ std::vector<rtl::Reference<VendorBase> > & allInfos,
+ std::vector<rtl::Reference<VendorBase> > & addedInfos)
+{
+ // Get Java s from registry
+ std::vector<OUString> vecJavaHome;
+ if(getSDKInfoFromRegistry(vecJavaHome))
+ {
+ // create impl objects
+ for (auto const& javaHome : vecJavaHome)
+ {
+ getAndAddJREInfoByPath(javaHome, allInfos, addedInfos);
+ }
+ }
+
+ vecJavaHome.clear();
+ if(getJREInfoFromRegistry(vecJavaHome))
+ {
+ for (auto const& javaHome : vecJavaHome)
+ {
+ getAndAddJREInfoByPath(javaHome, allInfos, addedInfos);
+ }
+ }
+
+ vecJavaHome.clear();
+ if (getJavaInfoFromRegistry(L"Software\\JavaSoft\\JDK", vecJavaHome)) {
+ for (auto const & javaHome: vecJavaHome) {
+ getAndAddJREInfoByPath(javaHome, allInfos, addedInfos);
+ }
+ }
+
+ vecJavaHome.clear();
+ if (getJavaInfoFromRegistry(L"Software\\JavaSoft\\JRE", vecJavaHome)) {
+ for (auto const & javaHome: vecJavaHome) {
+ getAndAddJREInfoByPath(javaHome, allInfos, addedInfos);
+ }
+ }
+}
+
+#endif // _WIN32
+
+void bubbleSortVersion(std::vector<rtl::Reference<VendorBase> >& vec)
+{
+ if(vec.empty())
+ return;
+ int size= vec.size() - 1;
+ int cIter= 0;
+ // sort for version
+ for(int i= 0; i < size; i++)
+ {
+ for(int j= size; j > 0 + cIter; j--)
+ {
+ rtl::Reference<VendorBase>& cur= vec.at(j);
+ rtl::Reference<VendorBase>& next= vec.at(j-1);
+
+ int nCmp = 0;
+ // comparing invalid SunVersion s is possible, they will be less than a
+ // valid version
+
+ //check if version of current is recognized, by comparing it with itself
+ try
+ {
+ (void)cur->compareVersions(cur->getVersion());
+ }
+ catch (MalformedVersionException &)
+ {
+ nCmp = -1; // current < next
+ }
+ //The version of cur is valid, now compare with the second version
+ if (nCmp == 0)
+ {
+ try
+ {
+ nCmp = cur->compareVersions(next->getVersion());
+ }
+ catch (MalformedVersionException & )
+ {
+ //The second version is invalid, therefore it regards less.
+ nCmp = 1;
+ }
+ }
+ if(nCmp == 1) // cur > next
+ {
+ std::swap(cur, next);
+ }
+ }
+ ++cIter;
+ }
+}
+
+
+void addJREInfoFromBinPath(
+ const OUString& path, std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos)
+{
+ // file:///c:/jre/bin
+ //map: jre/bin/java.exe
+
+ for ( sal_Int32 pos = 0;
+ gVendorMap[pos].sVendorName != nullptr; ++pos )
+ {
+ std::vector<OUString> vecPaths;
+ getJavaExePaths_func pFunc = gVendorMap[pos].getJavaFunc;
+
+ int size = 0;
+ char const* const* arExePaths = (*pFunc)(&size);
+ vecPaths = getVectorFromCharArray(arExePaths, size);
+
+ //make sure argument path does not end with '/'
+ OUString sBinPath = path;
+ if (path.endsWith("/"))
+ sBinPath = path.copy(0, path.getLength() - 1);
+
+ for (auto const& looppath : vecPaths)
+ {
+ //the map contains e.g. jre/bin/java.exe
+ //get the directory where the executable is contained
+ OUString sHome;
+ sal_Int32 index = looppath.lastIndexOf('/');
+ if (index == -1)
+ {
+ //map contained only : "java.exe, then the argument
+ //path is already the home directory
+ sHome = sBinPath;
+ }
+ else
+ {
+ // jre/bin/jre -> jre/bin
+ OUString sMapPath = looppath.copy(0, index);
+ index = sBinPath.lastIndexOf(sMapPath);
+ if (index != -1
+ && (index + sMapPath.getLength() == sBinPath.getLength())
+ && sBinPath[index - 1] == '/')
+ {
+ sHome = sBinPath.copy(index - 1);
+ }
+ }
+ if (!sHome.isEmpty()
+ && getAndAddJREInfoByPath(path, allInfos, addedInfos))
+ {
+ return;
+ }
+ }
+ }
+}
+
+std::vector<Reference<VendorBase> > addAllJREInfos(
+ bool checkJavaHomeAndPath,
+ std::vector<rtl::Reference<VendorBase>> & allInfos)
+{
+ std::vector<Reference<VendorBase> > addedInfos;
+
+#if defined(_WIN32)
+ // Get Javas from the registry
+ addJavaInfoFromWinReg(allInfos, addedInfos);
+#endif // _WIN32
+
+ if (checkJavaHomeAndPath) {
+ addJavaInfoFromJavaHome(allInfos, addedInfos);
+ //this function should be called after addJavaInfosDirScan.
+ //Otherwise in SDKs Java may be started twice
+ addJavaInfosFromPath(allInfos, addedInfos);
+ }
+
+#ifdef UNX
+ addJavaInfosDirScan(allInfos, addedInfos);
+#endif
+
+ bubbleSortVersion(addedInfos);
+ return addedInfos;
+}
+
+
+std::vector<OUString> getVectorFromCharArray(char const * const * ar, int size)
+{
+ std::vector<OUString> vec;
+ for( int i = 0; i < size; i++)
+ {
+ OUString s(ar[i], strlen(ar[i]), RTL_TEXTENCODING_UTF8);
+ vec.push_back(s);
+ }
+ return vec;
+}
+
+/** Checks if the path is a directory. Links are resolved.
+ In case of an error the returned string has the length 0.
+ Otherwise the returned string is the "resolved" file URL.
+ */
+static OUString resolveDirPath(const OUString & path)
+{
+ OUString ret;
+ salhelper::LinkResolver aResolver(osl_FileStatus_Mask_Type |
+ osl_FileStatus_Mask_FileURL);
+ if (aResolver.fetchFileStatus(path) == osl::FileBase::E_None)
+ {
+ //check if this is a directory
+ if (aResolver.m_aStatus.getFileType() == FileStatus::Directory)
+ {
+#ifndef JVM_ONE_PATH_CHECK
+ ret = aResolver.m_aStatus.getFileURL();
+#else
+ ret = path;
+#endif
+ }
+ }
+ return ret;
+}
+/** Checks if the path is a file. If it is a link to a file than
+ it is resolved.
+ */
+static OUString resolveFilePath(const OUString & path)
+{
+ OUString ret;
+ salhelper::LinkResolver aResolver(osl_FileStatus_Mask_Type |
+ osl_FileStatus_Mask_FileURL);
+ if (aResolver.fetchFileStatus(path) == osl::FileBase::E_None)
+ {
+ //check if this is a file
+ if (aResolver.m_aStatus.getFileType() == FileStatus::Regular)
+ {
+#ifndef JVM_ONE_PATH_CHECK
+ ret = aResolver.m_aStatus.getFileURL();
+#else
+ ret = path;
+#endif
+ }
+ }
+ return ret;
+}
+
+rtl::Reference<VendorBase> getJREInfoByPath(
+ const OUString& path)
+{
+ rtl::Reference<VendorBase> ret;
+ static std::vector<OUString> vecBadPaths;
+
+ static std::map<OUString, rtl::Reference<VendorBase> > mapJREs;
+ OUString sFilePath;
+ std::vector<std::pair<OUString, OUString> > props;
+
+ OUString sResolvedDir = resolveDirPath(path);
+ // If this path is invalid then there is no chance to find a JRE here
+ if (sResolvedDir.isEmpty())
+ {
+ return nullptr;
+ }
+
+ //check if the directory path is good, that is a JRE was already recognized.
+ //Then we need not detect it again
+ //For example, a sun JDK contains <jdk>/bin/java and <jdk>/jre/bin/java.
+ //When <jdk>/bin/java has been found then we need not find <jdk>/jre/bin/java.
+ //Otherwise we would execute java two times for every JDK found.
+ auto entry2 = find_if(mapJREs.cbegin(), mapJREs.cend(),
+ SameOrSubDirJREMap(sResolvedDir));
+ if (entry2 != mapJREs.end())
+ {
+ JFW_TRACE2("JRE found again (detected before): " << sResolvedDir);
+ return entry2->second;
+ }
+
+ for ( sal_Int32 pos = 0;
+ gVendorMap[pos].sVendorName != nullptr; ++pos )
+ {
+ std::vector<OUString> vecPaths;
+ getJavaExePaths_func pFunc = gVendorMap[pos].getJavaFunc;
+
+ int size = 0;
+ char const* const* arExePaths = (*pFunc)(&size);
+ vecPaths = getVectorFromCharArray(arExePaths, size);
+
+ bool bBreak = false;
+ for (auto const& looppath : vecPaths)
+ {
+ //if the path is a link, then resolve it
+ //check if the executable exists at all
+
+ //path can be only "file:///". Then do not append a '/'
+ //sizeof counts the terminating 0
+ OUString sFullPath;
+ if (path.getLength() == sizeof("file:///") - 1)
+ sFullPath = sResolvedDir + looppath;
+ else
+ sFullPath = sResolvedDir + "/" + looppath;
+
+ sFilePath = resolveFilePath(sFullPath);
+
+ if (sFilePath.isEmpty())
+ {
+ //The file path (to java exe) is not valid
+ auto ifull = find(vecBadPaths.cbegin(), vecBadPaths.cend(), sFullPath);
+ if (ifull == vecBadPaths.cend())
+ {
+ vecBadPaths.push_back(sFullPath);
+ }
+ continue;
+ }
+
+ auto ifile = find(vecBadPaths.cbegin(), vecBadPaths.cend(), sFilePath);
+ if (ifile != vecBadPaths.cend())
+ {
+ continue;
+ }
+
+ auto entry = mapJREs.find(sFilePath);
+ if (entry != mapJREs.end())
+ {
+ JFW_TRACE2("JRE found again (detected before): " << sFilePath);
+
+ return entry->second;
+ }
+
+ bool bProcessRun= false;
+ if (!getJavaProps(sFilePath,
+#ifdef JVM_ONE_PATH_CHECK
+ sResolvedDir,
+#endif
+ props, & bProcessRun))
+ {
+ //The java executable could not be run or the system properties
+ //could not be retrieved. We can assume that this java is corrupt.
+ vecBadPaths.push_back(sFilePath);
+ //If there was a java executable, that could be run but we did not get
+ //the system properties, then we also assume that the whole Java installation
+ //does not work. In a jdk there are two executables. One in jdk/bin and the other
+ //in jdk/jre/bin. We do not search any further, because we assume that if one java
+ //does not work then the other does not work as well. This saves us to run java
+ //again which is quite costly.
+ if (bProcessRun)
+ {
+ // 1.3.1 special treatment: jdk/bin/java and /jdk/jre/bin/java are links to
+ //a script, named .java_wrapper. The script starts jdk/bin/sparc/native_threads/java
+ //or jdk/jre/bin/sparc/native_threads/java. The script uses the name with which it was
+ //invoked to build the path to the executable. It we start the script directly as .java_wrapper
+ //then it tries to start a jdk/.../native_threads/.java_wrapper. Therefore the link, which
+ //is named java, must be used to start the script.
+ getJavaProps(sFullPath,
+#ifdef JVM_ONE_PATH_CHECK
+ sResolvedDir,
+#endif
+ props, & bProcessRun);
+ // Either we found a working 1.3.1
+ // Or the java is broken. In both cases we stop searching under this "root" directory
+ bBreak = true;
+ break;
+ }
+ //sFilePath is no working java executable. We continue with another possible
+ //path.
+ else
+ {
+ continue;
+ }
+ }
+ //sFilePath is a java and we could get the system properties. We proceed with this
+ //java.
+ else
+ {
+ bBreak = true;
+ break;
+ }
+ }
+ if (bBreak)
+ break;
+ }
+
+ if (props.empty())
+ {
+ return rtl::Reference<VendorBase>();
+ }
+
+ //find java.vendor property
+ OUString sVendorName;
+
+ for (auto const& prop : props)
+ {
+ if (prop.first == "java.vendor")
+ {
+ sVendorName = prop.second;
+ break;
+ }
+ }
+
+ auto knownVendor = false;
+ if (!sVendorName.isEmpty())
+ {
+ //find the creator func for the respective vendor name
+ for ( sal_Int32 c = 0;
+ gVendorMap[c].sVendorName != nullptr; ++c )
+ {
+ OUString sNameMap(gVendorMap[c].sVendorName, strlen(gVendorMap[c].sVendorName),
+ RTL_TEXTENCODING_ASCII_US);
+ if (sNameMap == sVendorName)
+ {
+ ret = createInstance(gVendorMap[c].createFunc, props);
+ knownVendor = true;
+ break;
+ }
+ }
+ }
+ // For unknown vendors, try SunInfo as fallback:
+ if (!knownVendor)
+ {
+ ret = createInstance(SunInfo::createInstance, props);
+ }
+ if (!ret.is())
+ {
+ vecBadPaths.push_back(sFilePath);
+ }
+ else
+ {
+ JFW_TRACE2("Found JRE: " << sResolvedDir << " at: " << path);
+
+ mapJREs.emplace(sResolvedDir, ret);
+ mapJREs.emplace(sFilePath, ret);
+ }
+
+ return ret;
+}
+
+Reference<VendorBase> createInstance(createInstance_func pFunc,
+ const std::vector<std::pair<OUString, OUString> >& properties)
+{
+
+ Reference<VendorBase> aBase = (*pFunc)();
+ if (aBase.is())
+ {
+ if (!aBase->initialize(properties))
+ aBase = nullptr;
+ }
+ return aBase;
+}
+
+inline OUString getDirFromFile(std::u16string_view usFilePath)
+{
+ size_t index = usFilePath.rfind('/');
+ return OUString(usFilePath.substr(0, index));
+}
+
+void addJavaInfosFromPath(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos)
+{
+#if !defined JVM_ONE_PATH_CHECK
+// Get Java from PATH environment variable
+ char *szPath= getenv("PATH");
+ if(!szPath)
+ return;
+
+ OUString usAllPath(szPath, strlen(szPath), osl_getThreadTextEncoding());
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString usToken( usAllPath.getToken( 0, SAL_PATHSEPARATOR, nIndex ) );
+ OUString usTokenUrl;
+ if(File::getFileURLFromSystemPath(usToken, usTokenUrl) == File::E_None)
+ {
+ if(!usTokenUrl.isEmpty())
+ {
+ OUString usBin;
+ if(usTokenUrl == ".")
+ {
+ OUString usWorkDirUrl;
+ if(osl_Process_E_None == osl_getProcessWorkingDir(&usWorkDirUrl.pData))
+ usBin= usWorkDirUrl;
+ }
+ else if(usTokenUrl == "..")
+ {
+ OUString usWorkDir;
+ if(osl_Process_E_None == osl_getProcessWorkingDir(&usWorkDir.pData))
+ usBin= getDirFromFile(usWorkDir);
+ }
+ else
+ {
+ usBin = usTokenUrl;
+ }
+ if(!usBin.isEmpty())
+ {
+ addJREInfoFromBinPath(usBin, allInfos, addedInfos);
+ }
+ }
+ }
+ }
+ while ( nIndex >= 0 );
+#endif
+}
+
+
+void addJavaInfoFromJavaHome(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos)
+{
+#if !defined JVM_ONE_PATH_CHECK
+ // Get Java from JAVA_HOME environment
+
+ // Note that on macOS is it not normal at all to have a JAVA_HOME environment
+ // variable. We set it in our build environment for build-time programs, though,
+ // so it is set when running unit tests that involve Java functionality. (Which affects
+ // at least CppunitTest_dbaccess_dialog_save, too, and not only the JunitTest ones.)
+ char *szJavaHome= getenv("JAVA_HOME");
+ if(szJavaHome)
+ {
+ OUString sHome(szJavaHome, strlen(szJavaHome), osl_getThreadTextEncoding());
+ OUString sHomeUrl;
+ if(File::getFileURLFromSystemPath(sHome, sHomeUrl) == File::E_None)
+ {
+ getAndAddJREInfoByPath(sHomeUrl, allInfos, addedInfos);
+ }
+ }
+#endif
+}
+
+bool makeDriveLetterSame(OUString * fileURL)
+{
+ bool ret = false;
+ DirectoryItem item;
+ if (DirectoryItem::get(*fileURL, item) == File::E_None)
+ {
+ FileStatus status(osl_FileStatus_Mask_FileURL);
+ if (item.getFileStatus(status) == File::E_None)
+ {
+ *fileURL = status.getFileURL();
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+#ifdef UNX
+#ifdef __sun
+
+void addJavaInfosDirScan(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos)
+{
+ JFW_TRACE2("Checking /usr/jdk/latest");
+ getAndAddJREInfoByPath("file:////usr/jdk/latest", allInfos, addedInfos);
+}
+
+#else
+void addJavaInfosDirScan(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos)
+{
+#ifdef MACOSX
+ // Ignore all but Oracle's JDK as loading Apple's Java and Oracle's JRE
+ // will cause macOS's JavaVM framework to display a dialog and invoke
+ // exit() when loaded via JNI on macOS 10.10
+ Directory aDir("file:///Library/Java/JavaVirtualMachines");
+ if (aDir.open() == File::E_None)
+ {
+ DirectoryItem aItem;
+ while (aDir.getNextItem(aItem) == File::E_None)
+ {
+ FileStatus aStatus(osl_FileStatus_Mask_FileURL);
+ if (aItem.getFileStatus(aStatus) == File::E_None)
+ {
+ OUString aItemURL( aStatus.getFileURL() );
+ if (aItemURL.getLength())
+ {
+ aItemURL += "/Contents/Home";
+ if (DirectoryItem::get(aItemURL, aItem) == File::E_None)
+ getAndAddJREInfoByPath(aItemURL, allInfos, addedInfos);
+ }
+ }
+ }
+ aDir.close();
+ }
+#else // MACOSX
+ OUString excMessage = "[Java framework] sunjavaplugin: "
+ "Error in function addJavaInfosDirScan in util.cxx.";
+ int cJavaNames= SAL_N_ELEMENTS(g_arJavaNames);
+ std::unique_ptr<OUString[]> sarJavaNames(new OUString[cJavaNames]);
+ OUString *arNames = sarJavaNames.get();
+ for(int i= 0; i < cJavaNames; i++)
+ arNames[i] = OUString(g_arJavaNames[i], strlen(g_arJavaNames[i]),
+ RTL_TEXTENCODING_UTF8);
+
+ int cSearchPaths= SAL_N_ELEMENTS(g_arSearchPaths);
+ std::unique_ptr<OUString[]> sarPathNames(new OUString[cSearchPaths]);
+ OUString *arPaths = sarPathNames.get();
+ for(int c = 0; c < cSearchPaths; c++)
+ arPaths[c] = OUString(g_arSearchPaths[c], strlen(g_arSearchPaths[c]),
+ RTL_TEXTENCODING_UTF8);
+
+ int cCollectDirs = SAL_N_ELEMENTS(g_arCollectDirs);
+ std::unique_ptr<OUString[]> sarCollectDirs(new OUString[cCollectDirs]);
+ OUString *arCollectDirs = sarCollectDirs.get();
+ for(int d = 0; d < cCollectDirs; d++)
+ arCollectDirs[d] = OUString(g_arCollectDirs[d], strlen(g_arCollectDirs[d]),
+ RTL_TEXTENCODING_UTF8);
+
+
+ for( int ii = 0; ii < cSearchPaths; ii ++)
+ {
+ OUString usDir1("file:///" + arPaths[ii]);
+ DirectoryItem item;
+ if(DirectoryItem::get(usDir1, item) == File::E_None)
+ {
+ for(int j= 0; j < cCollectDirs; j++)
+ {
+ OUString usDir2(usDir1 + arCollectDirs[j]);
+ // prevent that we scan the whole /usr, /usr/lib, etc directories
+ if (!arCollectDirs[j].isEmpty())
+ {
+ //usr/java/xxx
+ //Examining every subdirectory
+ Directory aCollectionDir(usDir2);
+
+ Directory::RC openErr = aCollectionDir.open();
+ switch (openErr)
+ {
+ case File::E_None:
+ break;
+ case File::E_NOENT:
+ case File::E_NOTDIR:
+ continue;
+ case File::E_ACCES:
+ JFW_TRACE2("Could not read directory " << usDir2 << " because of missing access rights");
+ continue;
+ default:
+ JFW_TRACE2("Could not read directory " << usDir2 << ". Osl file error: " << openErr);
+ continue;
+ }
+
+ DirectoryItem curIt;
+ File::RC errNext = File::E_None;
+ while( (errNext = aCollectionDir.getNextItem(curIt)) == File::E_None)
+ {
+ FileStatus aStatus(osl_FileStatus_Mask_FileURL);
+ File::RC errStatus = File::E_None;
+ if ((errStatus = curIt.getFileStatus(aStatus)) != File::E_None)
+ {
+ JFW_TRACE2(excMessage + "getFileStatus failed with error " << errStatus);
+ continue;
+ }
+ JFW_TRACE2("Checking if directory: " << aStatus.getFileURL() << " is a Java");
+
+ getAndAddJREInfoByPath(
+ aStatus.getFileURL(), allInfos, addedInfos);
+ }
+
+ JFW_ENSURE(errNext == File::E_None || errNext == File::E_NOENT,
+ "[Java framework] sunjavaplugin: "
+ "Error while iterating over contents of "
+ + usDir2 + ". Osl file error: "
+ + OUString::number(openErr));
+ }
+ else
+ {
+ //usr/java
+ //When we look directly into a dir like /usr, /usr/lib, etc. then we only
+ //look for certain java directories, such as jre, jdk, etc. We do not want
+ //to examine the whole directory because of performance reasons.
+ DirectoryItem item2;
+ if(DirectoryItem::get(usDir2, item2) == File::E_None)
+ {
+ for( int k= 0; k < cJavaNames; k++)
+ {
+ // /usr/java/j2re1.4.0
+ OUString usDir3(usDir2 + arNames[k]);
+
+ DirectoryItem item3;
+ if(DirectoryItem::get(usDir3, item3) == File::E_None)
+ {
+ //remove trailing '/'
+ sal_Int32 islash = usDir3.lastIndexOf('/');
+ if (islash == usDir3.getLength() - 1
+ && (islash
+ > RTL_CONSTASCII_LENGTH("file://")))
+ usDir3 = usDir3.copy(0, islash);
+ getAndAddJREInfoByPath(
+ usDir3, allInfos, addedInfos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif // MACOSX
+}
+#endif // ifdef __sun
+#endif // ifdef UNX
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util.hxx b/jvmfwk/plugins/sunmajor/pluginlib/util.hxx
new file mode 100644
index 000000000..9ba005583
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/util.hxx
@@ -0,0 +1,116 @@
+/* -*- 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_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_UTIL_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_UTIL_HXX
+
+#include <rtl/ustring.hxx>
+#include <vector>
+#include <vendorbase.hxx>
+
+namespace jfw_plugin
+{
+
+std::vector<OUString> getVectorFromCharArray(char const * const * ar, int size);
+
+/* The function uses the relative paths, such as "bin/java.exe" and the provided
+ path to derive the home directory. The home directory is then used as
+ argument to getJREInfoByPath. For example usBinDir is
+ file:///c:/j2sdk/jre/bin then file:///c:/j2sdk/jre would be derived.
+ */
+void addJREInfoFromBinPath(
+ const OUString& path,
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos);
+inline OUString getDirFromFile(std::u16string_view usFilePath);
+void addJavaInfosFromPath(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos);
+
+/* Returns a VendorBase object if JAVA_HOME environment variable points
+ to a JRE.
+ */
+void addJavaInfoFromJavaHome(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos);
+
+void addJavaInfosDirScan(
+ std::vector<rtl::Reference<VendorBase>> & allInfos,
+ std::vector<rtl::Reference<VendorBase>> & addedInfos);
+
+bool makeDriveLetterSame(OUString * fileURL);
+
+
+/* for std::find_if
+ Used to find a JavaInfo::Impl object in a std::vector<Impl*> which has a member usJavaHome
+ as the specified string in the constructor.
+*/
+struct InfoFindSame
+{
+ OUString sJava;
+ explicit InfoFindSame(const OUString& sJavaHome):sJava(sJavaHome){}
+
+ bool operator () (const rtl::Reference<VendorBase> & aVendorInfo)
+ {
+ return aVendorInfo->getHome() == sJava;
+ }
+};
+
+struct SameOrSubDirJREMap
+{
+ OUString s1;
+ explicit SameOrSubDirJREMap(const OUString& s):s1(s){
+ }
+
+ bool operator () (const std::pair<const OUString, rtl::Reference<VendorBase> > & s2)
+ {
+ if (s1 == s2.first)
+ return true;
+ OUString sSub = s2.first + "/";
+ if (s1.match(sSub))
+ return true;
+ return false;
+ }
+};
+
+
+/* Creates a VendorBase object if a JRE could be found at the specified path.
+
+ This depends if there is a JRE at all and if it is from a vendor that
+ is supported by this plugin.
+ */
+rtl::Reference<VendorBase> getJREInfoByPath(const OUString& path);
+
+std::vector<rtl::Reference<VendorBase> > addAllJREInfos(
+ bool checkJavaHomeAndPath, std::vector<rtl::Reference<VendorBase>> & infos);
+
+bool getJavaProps(
+ const OUString & exePath,
+#ifdef JVM_ONE_PATH_CHECK
+ const OUString & homePath,
+#endif
+ std::vector<std::pair<OUString, OUString> >& props,
+ bool * bProcessRun);
+
+void bubbleSortVersion(std::vector<rtl::Reference<VendorBase> >& vec);
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.hxx b/jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.hxx
new file mode 100644
index 000000000..ae43cee91
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.hxx
@@ -0,0 +1,14 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#ifndef INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_UTIL_COCOA_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_UTIL_COCOA_HXX
+
+#include <sal/config.h>
+
+#include <rtl/ustring.hxx>
+
+bool JvmfwkUtil_isLoadableJVM(OUString const& aURL);
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.mm b/jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.mm
new file mode 100644
index 000000000..8c745f8d9
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/util_cocoa.mm
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+
+#include <rtl/ustring.hxx>
+
+#include <premac.h>
+#import <Foundation/Foundation.h>
+#include <postmac.h>
+
+#import "util_cocoa.hxx"
+
+using namespace rtl;
+
+bool JvmfwkUtil_isLoadableJVM( OUString const & aURL )
+{
+ bool bRet = false;
+
+ if ( aURL.getLength() )
+ {
+ NSAutoreleasePool *pPool = [[NSAutoreleasePool alloc] init];
+
+ NSString *pString = [NSString stringWithCharacters:reinterpret_cast<unichar const *>(aURL.getStr()) length:aURL.getLength()];
+ if ( pString )
+ {
+ // Ignore all but Oracle's JDK as loading Apple's Java and Oracle's
+ // JRE will cause macOS's JavaVM framework to display a dialog and
+ // invoke exit() when loaded via JNI on macOS 10.10
+ NSURL *pURL = [NSURL URLWithString:pString];
+ if ( pURL )
+ pURL = [pURL filePathURL];
+ if ( pURL )
+ pURL = [pURL URLByStandardizingPath];
+ if ( pURL )
+ pURL = [pURL URLByResolvingSymlinksInPath];
+
+ while ( pURL )
+ {
+ // Check if this is a valid bundle
+ NSNumber *pDir = nil;
+ NSURL *pContentsURL = [pURL URLByAppendingPathComponent:@"Contents"];
+ if ( pContentsURL && [pContentsURL getResourceValue:&pDir forKey:NSURLIsDirectoryKey error:nil] && pDir && [pDir boolValue] )
+ {
+ NSBundle *pBundle = [NSBundle bundleWithURL:pURL];
+ if ( pBundle )
+ {
+ // Make sure that this bundle's Info.plist has the
+ // proper JVM keys to supports loading via JNI. If
+ // this bundle is a valid JVM and these keys
+ // are missing, loading the JVM will cause macOS's
+ // JavaVM framework to display a dialog and invoke
+ // exit() when loaded via JNI on macOS 10.10.
+ NSDictionary *pInfo = [pBundle infoDictionary];
+ if ( pInfo )
+ {
+ NSDictionary *pJavaVM = [pInfo objectForKey:@"JavaVM"];
+ if ( pJavaVM && [pJavaVM isKindOfClass:[NSDictionary class]] )
+ {
+ NSArray *pJVMCapabilities = [pJavaVM objectForKey:@"JVMCapabilities"];
+ if ( pJVMCapabilities )
+ {
+ if ( [pJVMCapabilities indexOfObjectIdenticalTo:@"JNI"] == NSNotFound )
+ {
+ if ( [pJVMCapabilities isKindOfClass:[NSMutableArray class]] )
+ {
+ [static_cast<NSMutableArray *>(pJVMCapabilities) addObject:@"JNI"];
+ bRet = true;
+ }
+ else if ( [pJavaVM isKindOfClass:[NSMutableDictionary class]] )
+ {
+ NSMutableArray *pNewJVMCapabilities = [NSMutableArray arrayWithCapacity:[pJVMCapabilities count] + 1];
+ if ( pNewJVMCapabilities )
+ {
+ [pNewJVMCapabilities addObject:@"JNI"];
+ [static_cast<NSMutableDictionary *>(pJavaVM) setObject:pNewJVMCapabilities forKey:@"JVMCapabilities"];
+ bRet = true;
+ }
+ }
+ }
+ else
+ {
+ bRet = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ NSURL *pOldURL = pURL;
+ pURL = [pURL URLByDeletingLastPathComponent];
+ if ( pURL )
+ {
+ pURL = [pURL URLByStandardizingPath];
+ if ( pURL )
+ {
+ pURL = [pURL URLByResolvingSymlinksInPath];
+ if ( pURL && [pURL isEqual:pOldURL] )
+ pURL = nil;
+ }
+ }
+ }
+ }
+
+ [pPool release];
+ }
+
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/vendorbase.cxx b/jvmfwk/plugins/sunmajor/pluginlib/vendorbase.cxx
new file mode 100644
index 000000000..f4cf14a9a
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/vendorbase.cxx
@@ -0,0 +1,197 @@
+/* -*- 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/file.hxx>
+
+#include <vendorbase.hxx>
+#include "util.hxx"
+
+using namespace osl;
+
+
+namespace jfw_plugin
+{
+
+MalformedVersionException::~MalformedVersionException() = default;
+
+VendorBase::VendorBase()
+{
+}
+
+bool VendorBase::initialize(const std::vector<std::pair<OUString, OUString> >& props)
+{
+ //get java.vendor, java.version, java.home
+ //from system properties
+
+ bool bVersion = false;
+ bool bVendor = false;
+ bool bHome = false;
+ bool bArch = false;
+
+ for (auto const& prop : props)
+ {
+ if(! bVendor && prop.first == "java.vendor")
+ {
+ m_sVendor = prop.second;
+ bVendor = true;
+ }
+ else if (!bVersion && prop.first == "java.version")
+ {
+ m_sVersion = prop.second;
+ bVersion = true;
+ }
+ else if (!bHome && prop.first == "java.home")
+ {
+#ifndef JVM_ONE_PATH_CHECK
+ OUString fileURL;
+ if (osl_getFileURLFromSystemPath(prop.second.pData,& fileURL.pData) ==
+ osl_File_E_None)
+ {
+ //make sure that the drive letter have all the same case
+ //otherwise file:///c:/jre and file:///C:/jre produce two
+ //different objects!!!
+ if (makeDriveLetterSame( & fileURL))
+ {
+ m_sHome = fileURL;
+ bHome = true;
+ }
+ }
+#else
+ m_sHome = prop.second;
+ bHome = true;
+#endif
+ }
+ else if (!bArch && prop.first == "os.arch")
+ {
+ m_sArch = prop.second;
+ bArch = true;
+ }
+ if (bVendor && bVersion && bHome && bArch) {
+ break;
+ }
+ }
+ if (!bVersion || !bVendor || !bHome || !bArch)
+ return false;
+
+ // init m_sRuntimeLibrary
+ OSL_ASSERT(!m_sHome.isEmpty());
+ //call virtual function to get the possible paths to the runtime library.
+
+ int size = 0;
+ char const* const* arRtPaths = getRuntimePaths( & size);
+ std::vector<OUString> libpaths = getVectorFromCharArray(arRtPaths, size);
+
+ bool bRt = false;
+ for (auto const& libpath : libpaths)
+ {
+ //Construct an absolute path to the possible runtime
+ OUString usRt= m_sHome + libpath;
+ DirectoryItem item;
+ if(DirectoryItem::get(usRt, item) == File::E_None)
+ {
+ //found runtime lib
+ m_sRuntimeLibrary = usRt;
+ bRt = true;
+ break;
+ }
+ }
+ if (!bRt)
+ return false;
+
+ // init m_sLD_LIBRARY_PATH
+ OSL_ASSERT(!m_sHome.isEmpty());
+ size = 0;
+ char const * const * arLDPaths = getLibraryPaths( & size);
+ std::vector<OUString> ld_paths = getVectorFromCharArray(arLDPaths, size);
+
+ bool bLdPath = true;
+ int c = 0;
+ for (auto const& ld_path : ld_paths)
+ {
+ OUString usAbsUrl= m_sHome + ld_path;
+ // convert to system path
+ OUString usSysPath;
+ if(File::getSystemPathFromFileURL(usAbsUrl, usSysPath) == File::E_None)
+ {
+
+ if(c > 0)
+ m_sLD_LIBRARY_PATH+= OUStringChar(SAL_PATHSEPARATOR);
+ m_sLD_LIBRARY_PATH+= usSysPath;
+ }
+ else
+ {
+ bLdPath = false;
+ break;
+ }
+ ++c;
+ }
+ return bLdPath;
+}
+
+const OUString & VendorBase::getVendor() const
+{
+ return m_sVendor;
+}
+const OUString & VendorBase::getVersion() const
+{
+ return m_sVersion;
+}
+
+const OUString & VendorBase::getHome() const
+{
+ return m_sHome;
+}
+
+const OUString & VendorBase::getLibraryPath() const
+{
+ return m_sLD_LIBRARY_PATH;
+}
+
+const OUString & VendorBase::getRuntimeLibrary() const
+{
+ return m_sRuntimeLibrary;
+}
+
+bool VendorBase::isValidArch() const
+{
+ // Warning: These values come from the "os.arch" property.
+ // It is not defined what the exact values are.
+ // Oracle JRE 8 has "x86" and "amd64", the others were found at http://lopica.sourceforge.net/os.html .
+ // There might still be missing some options; we need to extend the check once we find out.
+#if defined _WIN64 || (defined MACOSX && defined __x86_64__)
+ return m_sArch == "amd64" || m_sArch == "x86_64";
+#elif defined _WIN32
+ return m_sArch == "x86" || m_sArch == "i386" || m_sArch == "i686";
+#elif defined MACOSX && defined __aarch64__
+ return m_sArch == "aarch64";
+#else
+ (void)this;
+ return true;
+#endif
+}
+
+bool VendorBase::needsRestart() const
+{
+ return !getLibraryPath().isEmpty();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/vendorlist.cxx b/jvmfwk/plugins/sunmajor/pluginlib/vendorlist.cxx
new file mode 100644
index 000000000..96cc05167
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/vendorlist.cxx
@@ -0,0 +1,52 @@
+/* -*- 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 "vendorlist.hxx"
+#include "sunjre.hxx"
+#include "otherjre.hxx"
+
+namespace jfw_plugin
+{
+
+/* Note: The vendor strings must be UTF-8. For example, if
+ the string contains an umlaut then it must be expressed
+ by "\xXX\xXX"
+ */
+VendorSupportMapEntry const gVendorMap[] ={
+// For macOS, don't bother with implementations that aren't relevant (or have never existed)
+#ifdef MACOSX
+ VENDOR_MAP_ENTRY<OtherInfo>("Apple Inc."),
+ VENDOR_MAP_ENTRY<OtherInfo>("Apple Computer, Inc."),
+#endif
+ VENDOR_MAP_ENTRY<SunInfo>("Sun Microsystems Inc."),
+ VENDOR_MAP_ENTRY<SunInfo>("Oracle Corporation"),
+ VENDOR_MAP_ENTRY<SunInfo>("Amazon.com Inc."),
+ VENDOR_MAP_ENTRY<SunInfo>("Azul Systems, Inc."),
+#ifndef MACOSX
+ VENDOR_MAP_ENTRY<OtherInfo>("IBM Corporation"),
+ VENDOR_MAP_ENTRY<OtherInfo>("Blackdown Java-Linux Team"),
+ VENDOR_MAP_ENTRY<OtherInfo>("BEA Systems, Inc."),
+ VENDOR_MAP_ENTRY<OtherInfo>("The FreeBSD Foundation"),
+#endif
+ {nullptr, nullptr, nullptr} };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/plugins/sunmajor/pluginlib/vendorlist.hxx b/jvmfwk/plugins/sunmajor/pluginlib/vendorlist.hxx
new file mode 100644
index 000000000..e10958d24
--- /dev/null
+++ b/jvmfwk/plugins/sunmajor/pluginlib/vendorlist.hxx
@@ -0,0 +1,49 @@
+/* -*- 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_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_VENDORLIST_HXX
+#define INCLUDED_JVMFWK_PLUGINS_SUNMAJOR_PLUGINLIB_VENDORLIST_HXX
+
+#include <rtl/ref.hxx>
+
+namespace jfw_plugin { class VendorBase; }
+
+namespace jfw_plugin
+{
+
+typedef char const * const * (* getJavaExePaths_func)(int*);
+typedef rtl::Reference<VendorBase> (* createInstance_func) ();
+
+struct VendorSupportMapEntry
+{
+ char const * sVendorName;
+ getJavaExePaths_func getJavaFunc;
+ createInstance_func createFunc;
+};
+
+extern VendorSupportMapEntry const gVendorMap[];
+
+template<typename y> constexpr VendorSupportMapEntry VENDOR_MAP_ENTRY(char const * x) {
+ return {x, & y::getJavaExePaths, & y::createInstance};
+}
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/qa/unit/sunversion.cxx b/jvmfwk/qa/unit/sunversion.cxx
new file mode 100644
index 000000000..a717dc438
--- /dev/null
+++ b/jvmfwk/qa/unit/sunversion.cxx
@@ -0,0 +1,128 @@
+/* -*- 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/.
+ *
+ * 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 <cppunit/TestAssert.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/plugin/TestPlugIn.h>
+
+#include <rtl/string.hxx>
+#include <sal/types.h>
+
+#include <jvmfwk/plugins/sunmajor/pluginlib/sunversion.hxx>
+
+namespace
+{
+class TestSunVersion : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE(TestSunVersion);
+ CPPUNIT_TEST(testSunVersion);
+ CPPUNIT_TEST_SUITE_END();
+
+ void testSunVersion();
+};
+
+void TestSunVersion::testSunVersion()
+{
+ static char const * versions[] = {"1.4.0", "1.4.1", "1.0.0", "10.0.0", "10.10.0",
+ "10.2.2", "10.10.0", "10.10.10", "111.0.999",
+ "1.4.1_01", "9.90.99_09", "1.4.1_99",
+ "1.4.1_00a",
+ "1.4.1-ea", "1.4.1-beta", "1.4.1-rc1",
+ "1.5.0_01-ea", "1.5.0_01-rc2",
+ "10.0", "10.10", "1.5.0_010"};
+ static char const * badVersions[] = {".4.0", "..1", "", "10.10.0.", "10.10.0-", "10.10.0.",
+ "10.2-2", "10_10.0", "10..10", "a.0.999",
+ "1.4b.1_01", "9.90.-99_09", "1.4.1_99-",
+ "1.4.1_00a2", "1.4.0_z01z", "1.4.1__99A",
+ "1.4.1-1ea", "1.5.0._01-", "1.5.0_01-eac"};
+ static char const * orderedVer[] = { "1.3.1-ea", "1.3.1-beta", "1.3.1-rc1",
+ "1.3.1", "1.3.1_00a", "1.3.1_01", "1.3.1_01a",
+ "1.3.2", "1.4.0", "1.5.0_01-ea", "2.0.0"};
+
+ int num = SAL_N_ELEMENTS (versions);
+ int numBad = SAL_N_ELEMENTS (badVersions);
+ int numOrdered = SAL_N_ELEMENTS (orderedVer);
+ //parsing test (positive)
+ for (int i = 0; i < num; i++)
+ {
+ jfw_plugin::SunVersion ver(versions[i]);
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("SunVersion(\"") + versions[i] + "\") good").getStr(), ver);
+ }
+ //Parsing test (negative)
+ for ( int i = 0; i < numBad; i++)
+ {
+ jfw_plugin::SunVersion ver(badVersions[i]);
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("SunVersion(\"") + badVersions[i] + "\") bad").getStr(), !ver);
+ }
+
+ // Ordering test
+ int j = 0;
+ for (int i = 0; i < numOrdered; i ++)
+ {
+ jfw_plugin::SunVersion curVer(orderedVer[i]);
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("SunVersion(\"") + orderedVer[i] + "\") good").getStr(),
+ curVer);
+ for (j = 0; j < numOrdered; j++)
+ {
+ jfw_plugin::SunVersion compVer(orderedVer[j]);
+ if (i < j)
+ {
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("\"") + orderedVer[i] + "\" < \"" + orderedVer[j])
+ .getStr(),
+ curVer < compVer);
+ }
+ else if ( i == j)
+ {
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("\"") + orderedVer[i] + "\" == \"" + orderedVer[j])
+ .getStr(),
+ curVer.operator ==(compVer));
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("not \"") + orderedVer[i] + "\" > \"" + orderedVer[j])
+ .getStr(),
+ ! (curVer > compVer));
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("not \"") + orderedVer[i] + "\" < \"" + orderedVer[j])
+ .getStr(),
+ ! (curVer < compVer));
+ }
+ else if (i > j)
+ {
+ CPPUNIT_ASSERT_MESSAGE(
+ OString(OString::Concat("\"") + orderedVer[i] + "\" > \"" + orderedVer[j])
+ .getStr(),
+ curVer > compVer);
+ }
+ }
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(TestSunVersion);
+}
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/jvmfwk/source/elements.cxx b/jvmfwk/source/elements.cxx
new file mode 100644
index 000000000..c48f942ef
--- /dev/null
+++ b/jvmfwk/source/elements.cxx
@@ -0,0 +1,971 @@
+/* -*- 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 <cassert>
+#include <memory>
+
+#include <elements.hxx>
+#include <osl/mutex.hxx>
+#include <osl/file.hxx>
+#include <fwkutil.hxx>
+#include <fwkbase.hxx>
+#include "framework.hxx"
+#include <libxmlutil.hxx>
+#include <algorithm>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <optional>
+#include <string.h>
+
+// For backwards compatibility, the nRequirements flag word is
+// read/written as potentially signed hexadecimal number (though that has no
+// practical relevance given that it has only one flag with value 0x01
+// defined).
+
+using namespace osl;
+namespace jfw
+{
+
+static OString getElement(OString const & docPath,
+ xmlChar const * pathExpression)
+{
+ //Prepare the xml document and context
+ OSL_ASSERT(!docPath.isEmpty());
+ jfw::CXmlDocPtr doc(xmlParseFile(docPath.getStr()));
+ if (doc == nullptr)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Error in function getElement (elements.cxx)");
+
+ jfw::CXPathContextPtr context(xmlXPathNewContext(doc));
+ if (xmlXPathRegisterNs(context, reinterpret_cast<xmlChar const *>("jf"),
+ reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)) == -1)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Error in function getElement (elements.cxx)");
+
+ CXPathObjectPtr pathObj = xmlXPathEvalExpression(pathExpression, context);
+ OString sValue;
+ if (xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
+ {
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Error in function getElement (elements.cxx)");
+ }
+ sValue = reinterpret_cast<char*>(pathObj->nodesetval->nodeTab[0]->content);
+ return sValue;
+}
+
+OString getElementUpdated()
+{
+ return getElement(jfw::getVendorSettingsPath(),
+ reinterpret_cast<xmlChar const *>("/jf:javaSelection/jf:updated/text()"));
+}
+
+void createSettingsStructure(xmlDoc * document, bool * bNeedsSave)
+{
+ OString sExcMsg("[Java framework] Error in function createSettingsStructure "
+ "(elements.cxx).");
+ xmlNode * root = xmlDocGetRootElement(document);
+ if (root == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ bool bFound = false;
+ xmlNode * cur = root->children;
+ while (cur != nullptr)
+ {
+ if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("enabled")) == 0)
+ {
+ bFound = true;
+ break;
+ }
+ cur = cur->next;
+ }
+ if (bFound)
+ {
+ *bNeedsSave = false;
+ return;
+ }
+ //We will modify this document
+ *bNeedsSave = true;
+ // Now we create the child elements ------------------
+ //Get xsi:nil namespace
+ xmlNs* nsXsi = xmlSearchNsByHref(
+ document, root, reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+
+ //<enabled xsi:nil="true"
+ xmlNode * nodeEn = xmlNewTextChild(
+ root, nullptr, reinterpret_cast<xmlChar const *>("enabled"), reinterpret_cast<xmlChar const *>(""));
+ if (nodeEn == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlSetNsProp(nodeEn, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
+ //add a new line
+ xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(root, nodeCrLf);
+
+ //<userClassPath xsi:nil="true">
+ xmlNode * nodeUs = xmlNewTextChild(
+ root, nullptr, reinterpret_cast<xmlChar const *>("userClassPath"), reinterpret_cast<xmlChar const *>(""));
+ if (nodeUs == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlSetNsProp(nodeUs, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
+ //add a new line
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(root, nodeCrLf);
+
+ //<vmParameters xsi:nil="true">
+ xmlNode * nodeVm = xmlNewTextChild(
+ root, nullptr, reinterpret_cast<xmlChar const *>("vmParameters"), reinterpret_cast<xmlChar const *>(""));
+ if (nodeVm == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlSetNsProp(nodeVm, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
+ //add a new line
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(root, nodeCrLf);
+
+ //<jreLocations xsi:nil="true">
+ xmlNode * nodeJre = xmlNewTextChild(
+ root, nullptr, reinterpret_cast<xmlChar const *>("jreLocations"), reinterpret_cast<xmlChar const *>(""));
+ if (nodeJre == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlSetNsProp(nodeJre, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
+ //add a new line
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(root, nodeCrLf);
+
+ //<javaInfo xsi:nil="true">
+ xmlNode * nodeJava = xmlNewTextChild(
+ root, nullptr, reinterpret_cast<xmlChar const *>("javaInfo"), reinterpret_cast<xmlChar const *>(""));
+ if (nodeJava == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlSetNsProp(nodeJava, nsXsi, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>("true"));
+ //add a new line
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(root, nodeCrLf);
+}
+
+NodeJava::NodeJava(Layer layer):
+ m_layer(layer)
+{
+ //This class reads and write to files which should only be done in
+ //application mode
+ if (getMode() == JFW_MODE_DIRECT)
+ throw FrameworkException(
+ JFW_E_DIRECT_MODE,
+ "[Java framework] Trying to access settings files in direct mode.");
+}
+
+
+void NodeJava::load()
+{
+ const OString sExcMsg("[Java framework] Error in function NodeJava::load"
+ "(elements.cxx).");
+ if (SHARED == m_layer)
+ {
+ //we do not support yet to write into the shared installation
+
+ //check if shared settings exist at all.
+ OUString sURL(BootParams::getSharedData());
+ jfw::FileStatus s = sURL.isEmpty()
+ ? FILE_DOES_NOT_EXIST : checkFileURL(sURL);
+ if (s == FILE_INVALID)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Invalid file for shared Java settings.");
+ else if (s == FILE_DOES_NOT_EXIST)
+ //Writing shared data is not supported yet.
+ return;
+ }
+ else if (USER == m_layer)
+ {
+ if (!prepareSettingsDocument())
+ {
+ SAL_INFO("jfw.level1", "no path to load user settings document from");
+ return;
+ }
+ }
+ else
+ {
+ OSL_FAIL("[Java framework] Unknown enum used.");
+ }
+
+
+ //Read the user elements
+ OString sSettingsPath = getSettingsPath();
+ //There must not be a share settings file
+ CXmlDocPtr docUser(xmlParseFile(sSettingsPath.getStr()));
+ if (docUser == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ xmlNode * cur = xmlDocGetRootElement(docUser);
+ if (cur == nullptr || cur->children == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ CXmlCharPtr sNil;
+ cur = cur->children;
+ while (cur != nullptr)
+ {
+ if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("enabled")) == 0)
+ {
+ //only overwrite share settings if xsi:nil="false"
+ sNil = xmlGetNsProp(
+ cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+ if (sNil == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
+ {
+ CXmlCharPtr sEnabled( xmlNodeListGetString(
+ docUser, cur->children, 1));
+ if (xmlStrcmp(sEnabled, reinterpret_cast<xmlChar const *>("true")) == 0)
+ m_enabled = std::optional<sal_Bool>(true);
+ else if (xmlStrcmp(sEnabled, reinterpret_cast<xmlChar const *>("false")) == 0)
+ m_enabled = std::optional<sal_Bool>(false);
+ }
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("userClassPath")) == 0)
+ {
+ sNil = xmlGetNsProp(
+ cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+ if (sNil == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
+ {
+ CXmlCharPtr sUser(xmlNodeListGetString(
+ docUser, cur->children, 1));
+ m_userClassPath = std::optional<OUString>(OUString(sUser));
+ }
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("javaInfo")) == 0)
+ {
+ sNil = xmlGetNsProp(
+ cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+ if (sNil == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
+ {
+ if (! m_javaInfo)
+ m_javaInfo = std::optional<CNodeJavaInfo>(CNodeJavaInfo());
+ m_javaInfo->loadFromNode(docUser, cur);
+ }
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vmParameters")) == 0)
+ {
+ sNil = xmlGetNsProp(
+ cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+ if (sNil == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
+ {
+ if ( ! m_vmParameters)
+ m_vmParameters = std::optional<std::vector<OUString> >(
+ std::vector<OUString> ());
+
+ xmlNode * pOpt = cur->children;
+ while (pOpt != nullptr)
+ {
+ if (xmlStrcmp(pOpt->name, reinterpret_cast<xmlChar const *>("param")) == 0)
+ {
+ CXmlCharPtr sOpt = xmlNodeListGetString(
+ docUser, pOpt->children, 1);
+ m_vmParameters->push_back(sOpt);
+ }
+ pOpt = pOpt->next;
+ }
+ }
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("jreLocations")) == 0)
+ {
+ sNil = xmlGetNsProp(
+ cur, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+ if (sNil == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
+ {
+ if (! m_JRELocations)
+ m_JRELocations = std::optional<std::vector<OUString> >(
+ std::vector<OUString>());
+
+ xmlNode * pLoc = cur->children;
+ while (pLoc != nullptr)
+ {
+ if (xmlStrcmp(pLoc->name, reinterpret_cast<xmlChar const *>("location")) == 0)
+ {
+ CXmlCharPtr sLoc = xmlNodeListGetString(
+ docUser, pLoc->children, 1);
+ m_JRELocations->push_back(sLoc);
+ }
+ pLoc = pLoc->next;
+ }
+ }
+ }
+ cur = cur->next;
+ }
+}
+
+OString NodeJava::getSettingsPath() const
+{
+ OString ret;
+ switch (m_layer)
+ {
+ case USER: ret = getUserSettingsPath(); break;
+ case SHARED: ret = getSharedSettingsPath(); break;
+ default:
+ OSL_FAIL("[Java framework] NodeJava::getSettingsPath()");
+ }
+ return ret;
+}
+
+OUString NodeJava::getSettingsURL() const
+{
+ OUString ret;
+ switch (m_layer)
+ {
+ case USER: ret = BootParams::getUserData(); break;
+ case SHARED: ret = BootParams::getSharedData(); break;
+ default:
+ OSL_FAIL("[Java framework] NodeJava::getSettingsURL()");
+ }
+ return ret;
+}
+
+bool NodeJava::prepareSettingsDocument() const
+{
+ OString sExcMsg(
+ "[Java framework] Error in function prepareSettingsDocument"
+ " (elements.cxx).");
+ if (!createSettingsDocument())
+ {
+ return false;
+ }
+ OString sSettings = getSettingsPath();
+ CXmlDocPtr doc(xmlParseFile(sSettings.getStr()));
+ if (!doc)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ bool bNeedsSave = false;
+ createSettingsStructure(doc, & bNeedsSave);
+ if (bNeedsSave)
+ {
+ if (xmlSaveFormatFileEnc(
+ sSettings.getStr(), doc,"UTF-8", 1) == -1)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ }
+ return true;
+}
+
+void NodeJava::write() const
+{
+ OString sExcMsg("[Java framework] Error in function NodeJava::writeSettings "
+ "(elements.cxx).");
+ CXmlDocPtr docUser;
+ CXPathContextPtr contextUser;
+ CXPathObjectPtr pathObj;
+
+ if (!prepareSettingsDocument())
+ {
+ SAL_INFO("jfw.level1", "no path to write settings document to");
+ return;
+ }
+
+ //Read the user elements
+ OString sSettingsPath = getSettingsPath();
+ docUser = xmlParseFile(sSettingsPath.getStr());
+ if (docUser == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ contextUser = xmlXPathNewContext(docUser);
+ if (xmlXPathRegisterNs(contextUser, reinterpret_cast<xmlChar const *>("jf"),
+ reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK)) == -1)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ xmlNode * root = xmlDocGetRootElement(docUser);
+ //Get xsi:nil namespace
+ xmlNs* nsXsi = xmlSearchNsByHref(docUser,
+ root,
+ reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+
+ //set the <enabled> element
+ //The element must exist
+ if (m_enabled)
+ {
+ pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:enabled"),
+ contextUser);
+ if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ xmlNode * nodeEnabled = pathObj->nodesetval->nodeTab[0];
+ xmlSetNsProp(nodeEnabled,
+ nsXsi,
+ reinterpret_cast<xmlChar const *>("nil"),
+ reinterpret_cast<xmlChar const *>("false"));
+
+ if (m_enabled == std::optional<sal_Bool>(true))
+ xmlNodeSetContent(nodeEnabled,reinterpret_cast<xmlChar const *>("true"));
+ else
+ xmlNodeSetContent(nodeEnabled,reinterpret_cast<xmlChar const *>("false"));
+ }
+
+ //set the <userClassPath> element
+ //The element must exist
+ if (m_userClassPath)
+ {
+ pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:userClassPath"),
+ contextUser);
+ if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ xmlNode * nodeEnabled = pathObj->nodesetval->nodeTab[0];
+ xmlSetNsProp(nodeEnabled, nsXsi, reinterpret_cast<xmlChar const *>("nil"),reinterpret_cast<xmlChar const *>("false"));
+ xmlNodeSetContent(nodeEnabled,static_cast<xmlChar*>(CXmlCharPtr(*m_userClassPath)));
+ }
+
+ //set <javaInfo> element
+ if (m_javaInfo)
+ {
+ pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:javaInfo"),
+ contextUser);
+ if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ m_javaInfo->writeToNode(
+ docUser, pathObj->nodesetval->nodeTab[0]);
+ }
+
+ //set <vmParameters> element
+ if (m_vmParameters)
+ {
+ pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:vmParameters"),
+ contextUser);
+ if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlNode* vmParameters = pathObj->nodesetval->nodeTab[0];
+ //set xsi:nil = false;
+ xmlSetNsProp(vmParameters, nsXsi,reinterpret_cast<xmlChar const *>("nil"),
+ reinterpret_cast<xmlChar const *>("false"));
+
+ //remove option elements
+ xmlNode* cur = vmParameters->children;
+ while (cur != nullptr)
+ {
+ xmlNode* lastNode = cur;
+ cur = cur->next;
+ xmlUnlinkNode(lastNode);
+ xmlFreeNode(lastNode);
+ }
+ //add a new line after <vmParameters>
+ if (!m_vmParameters->empty())
+ {
+ xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(vmParameters, nodeCrLf);
+ }
+
+ for (auto const & vmParameter : *m_vmParameters)
+ {
+ xmlNewTextChild(vmParameters, nullptr, reinterpret_cast<xmlChar const *>("param"),
+ CXmlCharPtr(vmParameter));
+ //add a new line
+ xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(vmParameters, nodeCrLf);
+ }
+ }
+
+ //set <jreLocations> element
+ if (m_JRELocations)
+ {
+ pathObj = xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>("/jf:java/jf:jreLocations"),
+ contextUser);
+ if ( ! pathObj || xmlXPathNodeSetIsEmpty(pathObj->nodesetval))
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlNode* jreLocationsNode = pathObj->nodesetval->nodeTab[0];
+ //set xsi:nil = false;
+ xmlSetNsProp(jreLocationsNode, nsXsi,reinterpret_cast<xmlChar const *>("nil"),
+ reinterpret_cast<xmlChar const *>("false"));
+
+ //remove option elements
+ xmlNode* cur = jreLocationsNode->children;
+ while (cur != nullptr)
+ {
+ xmlNode* lastNode = cur;
+ cur = cur->next;
+ xmlUnlinkNode(lastNode);
+ xmlFreeNode(lastNode);
+ }
+ //add a new line after <vmParameters>
+ if (!m_JRELocations->empty())
+ {
+ xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(jreLocationsNode, nodeCrLf);
+ }
+
+ for (auto const & JRELocation : *m_JRELocations)
+ {
+ xmlNewTextChild(jreLocationsNode, nullptr, reinterpret_cast<xmlChar const *>("location"),
+ CXmlCharPtr(JRELocation));
+ //add a new line
+ xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(jreLocationsNode, nodeCrLf);
+ }
+ }
+
+ if (xmlSaveFormatFile(sSettingsPath.getStr(), docUser, 1) == -1)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+}
+
+void NodeJava::setEnabled(bool bEnabled)
+{
+ m_enabled = std::optional<sal_Bool>(bEnabled);
+}
+
+
+void NodeJava::setUserClassPath(const OUString & sClassPath)
+{
+ m_userClassPath = std::optional<OUString>(sClassPath);
+}
+
+void NodeJava::setJavaInfo(const JavaInfo * pInfo, bool bAutoSelect)
+{
+ if (!m_javaInfo)
+ m_javaInfo = std::optional<CNodeJavaInfo>(CNodeJavaInfo());
+ m_javaInfo->bAutoSelect = bAutoSelect;
+ m_javaInfo->bNil = false;
+
+ if (pInfo != nullptr)
+ {
+ m_javaInfo->m_bEmptyNode = false;
+ m_javaInfo->sVendor = pInfo->sVendor;
+ m_javaInfo->sLocation = pInfo->sLocation;
+ m_javaInfo->sVersion = pInfo->sVersion;
+ m_javaInfo->nRequirements = pInfo->nRequirements;
+ m_javaInfo->arVendorData = pInfo->arVendorData;
+ }
+ else
+ {
+ m_javaInfo->m_bEmptyNode = true;
+ m_javaInfo->sVendor.clear();
+ m_javaInfo->sLocation.clear();
+ m_javaInfo->sVersion.clear();
+ m_javaInfo->nRequirements = 0;
+ m_javaInfo->arVendorData = rtl::ByteSequence();
+ }
+}
+
+void NodeJava::setVmParameters(std::vector<OUString> const & arOptions)
+{
+ m_vmParameters = std::optional<std::vector<OUString> >(arOptions);
+}
+
+void NodeJava::addJRELocation(OUString const & sLocation)
+{
+ if (!m_JRELocations)
+ m_JRELocations = std::optional<std::vector<OUString> >(
+ std::vector<OUString> ());
+ //only add the path if not already present
+ std::vector<OUString>::const_iterator it =
+ std::find(m_JRELocations->begin(), m_JRELocations->end(), sLocation);
+ if (it == m_JRELocations->end())
+ m_JRELocations->push_back(sLocation);
+}
+
+jfw::FileStatus NodeJava::checkSettingsFileStatus(OUString const & sURL)
+{
+ jfw::FileStatus ret = FILE_DOES_NOT_EXIST;
+
+ //check the file time
+ ::osl::DirectoryItem item;
+ File::RC rc = ::osl::DirectoryItem::get(sURL, item);
+ if (File::E_None == rc)
+ {
+ ::osl::FileStatus stat(osl_FileStatus_Mask_Validate);
+ File::RC rc_stat = item.getFileStatus(stat);
+ if (File::E_None == rc_stat)
+ {
+ ret = FILE_OK;
+ }
+ else if (File::E_NOENT == rc_stat)
+ {
+ ret = FILE_DOES_NOT_EXIST;
+ }
+ else
+ {
+ ret = FILE_INVALID;
+ }
+ }
+ else if(File::E_NOENT == rc)
+ {
+ ret = FILE_DOES_NOT_EXIST;
+ }
+ else
+ {
+ ret = FILE_INVALID;
+ }
+ return ret;
+}
+
+bool NodeJava::createSettingsDocument() const
+{
+ const OUString sURL = getSettingsURL();
+ if (sURL.isEmpty())
+ {
+ return false;
+ }
+ //make sure there is a user directory
+ OString sExcMsg("[Java framework] Error in function createSettingsDocument "
+ "(elements.cxx).");
+ // check if javasettings.xml already exist
+ if (FILE_OK == checkSettingsFileStatus(sURL))
+ return true;
+
+ //make sure that the directories are created in case they do not exist
+ FileBase::RC rcFile = Directory::createPath(getDirFromFile(sURL));
+ if (rcFile != FileBase::E_EXIST && rcFile != FileBase::E_None)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ //javasettings.xml does not exist yet
+ CXmlDocPtr doc(xmlNewDoc(reinterpret_cast<xmlChar const *>("1.0")));
+ if (! doc)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ //Create the root element and name spaces
+ xmlNodePtr root = xmlNewDocNode(
+ doc, nullptr, reinterpret_cast<xmlChar const *>("java"), reinterpret_cast<xmlChar const *>("\n"));
+
+ if (root == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ if (xmlNewNs(root, reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK),nullptr) == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ if (xmlNewNs(root,reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE),reinterpret_cast<xmlChar const *>("xsi")) == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ xmlDocSetRootElement(doc, root);
+
+ //Create a comment
+ xmlNodePtr com = xmlNewComment(
+ reinterpret_cast<xmlChar const *>("This is a generated file. Do not alter this file!"));
+ if (com == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ if (xmlAddPrevSibling(root, com) == nullptr)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ const OString path = getSettingsPath();
+ if (xmlSaveFormatFileEnc(path.getStr(), doc,"UTF-8", 1) == -1)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ return true;
+}
+
+
+CNodeJavaInfo::CNodeJavaInfo() :
+ m_bEmptyNode(false), bNil(true), bAutoSelect(true),
+ nRequirements(0)
+{
+}
+
+void CNodeJavaInfo::loadFromNode(xmlDoc * pDoc, xmlNode * pJavaInfo)
+{
+ OString sExcMsg("[Java framework] Error in function NodeJavaInfo::loadFromNode "
+ "(elements.cxx).");
+
+ OSL_ASSERT(pJavaInfo && pDoc);
+ if (pJavaInfo->children == nullptr)
+ return;
+ //Get the xsi:nil attribute;
+ CXmlCharPtr sNil = xmlGetNsProp(
+ pJavaInfo, reinterpret_cast<xmlChar const *>("nil"), reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+ if ( ! sNil)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("true")) == 0)
+ bNil = true;
+ else if (xmlStrcmp(sNil, reinterpret_cast<xmlChar const *>("false")) == 0)
+ bNil = false;
+ else
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ if (bNil)
+ return;
+
+ //Get javaInfo@manuallySelected attribute
+ CXmlCharPtr sAutoSelect = xmlGetProp(
+ pJavaInfo, reinterpret_cast<xmlChar const *>("autoSelect"));
+ if ( ! sAutoSelect)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ if (xmlStrcmp(sAutoSelect, reinterpret_cast<xmlChar const *>("true")) == 0)
+ bAutoSelect = true;
+ else if (xmlStrcmp(sAutoSelect, reinterpret_cast<xmlChar const *>("false")) == 0)
+ bAutoSelect = false;
+ else
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+
+ xmlNode * cur = pJavaInfo->children;
+
+ while (cur != nullptr)
+ {
+ if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vendor")) == 0)
+ {
+ CXmlCharPtr xmlVendor = xmlNodeListGetString(
+ pDoc, cur->children, 1);
+ if (! xmlVendor)
+ return;
+ sVendor = xmlVendor;
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("location")) == 0)
+ {
+ CXmlCharPtr xmlLocation = xmlNodeListGetString(
+ pDoc, cur->children, 1);
+ sLocation = xmlLocation;
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("version")) == 0)
+ {
+ CXmlCharPtr xmlVersion = xmlNodeListGetString(
+ pDoc, cur->children, 1);
+ sVersion = xmlVersion;
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("requirements")) == 0)
+ {
+ CXmlCharPtr xmlRequire = xmlNodeListGetString(
+ pDoc, cur->children, 1);
+ OUString sRequire = xmlRequire;
+ nRequirements = sRequire.toInt64(16);
+#ifdef MACOSX
+ //javaldx is not used anymore in the mac build. In case the Java
+ //corresponding to the saved settings does not exist anymore the
+ //javavm services will look for an existing Java after creation of
+ //the JVM failed. See stoc/source/javavm/javavm.cxx. Only if
+ //nRequirements does not have the flag JFW_REQUIRE_NEEDRESTART the
+ //jvm of the new selected JRE will be started. Old settings (before
+ //OOo 3.3) still contain the flag which can be safely ignored.
+ nRequirements &= ~JFW_REQUIRE_NEEDRESTART;
+#endif
+ }
+ else if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("vendorData")) == 0)
+ {
+ CXmlCharPtr xmlData = xmlNodeListGetString(
+ pDoc, cur->children, 1);
+ xmlChar* _data = static_cast<xmlChar*>(xmlData);
+ if (_data)
+ {
+ rtl::ByteSequence seq(reinterpret_cast<sal_Int8*>(_data), strlen(reinterpret_cast<char*>(_data)));
+ arVendorData = decodeBase16(seq);
+ }
+ }
+ cur = cur->next;
+ }
+
+ if (sVendor.isEmpty())
+ m_bEmptyNode = true;
+ //Get the javainfo attributes
+ CXmlCharPtr sVendorUpdate = xmlGetProp(pJavaInfo,
+ reinterpret_cast<xmlChar const *>("vendorUpdate"));
+ if ( ! sVendorUpdate)
+ throw FrameworkException(JFW_E_ERROR, sExcMsg);
+ sAttrVendorUpdate = sVendorUpdate;
+}
+
+
+void CNodeJavaInfo::writeToNode(xmlDoc* pDoc,
+ xmlNode* pJavaInfoNode) const
+
+{
+ OSL_ASSERT(pJavaInfoNode && pDoc);
+ //write the attribute vendorSettings
+
+ //javaInfo@vendorUpdate
+ //creates the attribute if necessary
+ OString sUpdated = getElementUpdated();
+
+ xmlSetProp(pJavaInfoNode, reinterpret_cast<xmlChar const *>("vendorUpdate"),
+ reinterpret_cast<xmlChar const *>(sUpdated.getStr()));
+
+ //javaInfo@autoSelect
+ xmlSetProp(pJavaInfoNode, reinterpret_cast<xmlChar const *>("autoSelect"),
+ reinterpret_cast<xmlChar const *>(bAutoSelect ? "true" : "false"));
+
+ //Set xsi:nil in javaInfo element to false
+ //the xmlNs pointer must not be destroyed
+ xmlNs* nsXsi = xmlSearchNsByHref(pDoc,
+ pJavaInfoNode,
+ reinterpret_cast<xmlChar const *>(NS_SCHEMA_INSTANCE));
+
+ xmlSetNsProp(pJavaInfoNode,
+ nsXsi,
+ reinterpret_cast<xmlChar const *>("nil"),
+ reinterpret_cast<xmlChar const *>("false"));
+
+ //Delete the children of JavaInfo
+ xmlNode* cur = pJavaInfoNode->children;
+ while (cur != nullptr)
+ {
+ xmlNode* lastNode = cur;
+ cur = cur->next;
+ xmlUnlinkNode(lastNode);
+ xmlFreeNode(lastNode);
+ }
+
+ //If the JavaInfo was set with an empty value,
+ //then we are done.
+ if (m_bEmptyNode)
+ return;
+
+ //add a new line after <javaInfo>
+ xmlNode * nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+
+ //Create the vendor element
+ xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("vendor"),
+ CXmlCharPtr(sVendor));
+ //add a new line for better readability
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+
+ //Create the location element
+ xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("location"),
+ CXmlCharPtr(sLocation));
+ //add a new line for better readability
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+
+ //Create the version element
+ xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("version"),
+ CXmlCharPtr(sVersion));
+ //add a new line for better readability
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+
+ //Create the features element, for backwards compatibility (it used to support one flag
+ // JFW_FEATURE_ACCESSBRIDGE = 0x01, but is ignored and always written as zero now)
+ xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("features"),
+ reinterpret_cast<xmlChar const *>("0"));
+ //add a new line for better readability
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+
+
+ //Create the requirements element
+ OUString sRequirements = OUString::number(
+ nRequirements, 16);
+ xmlNewTextChild(pJavaInfoNode, nullptr, reinterpret_cast<xmlChar const *>("requirements"),
+ CXmlCharPtr(sRequirements));
+ //add a new line for better readability
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+
+
+ //Create the vendorData element
+ rtl::ByteSequence data = encodeBase16(arVendorData);
+ xmlNode* dataNode = xmlNewChild(pJavaInfoNode, nullptr,
+ reinterpret_cast<xmlChar const *>("vendorData"),
+ reinterpret_cast<xmlChar const *>(""));
+ xmlNodeSetContentLen(dataNode,
+ reinterpret_cast<xmlChar*>(data.getArray()), data.getLength());
+ //add a new line for better readability
+ nodeCrLf = xmlNewText(reinterpret_cast<xmlChar const *>("\n"));
+ xmlAddChild(pJavaInfoNode, nodeCrLf);
+}
+
+std::unique_ptr<JavaInfo> CNodeJavaInfo::makeJavaInfo() const
+{
+ if (bNil || m_bEmptyNode)
+ return std::unique_ptr<JavaInfo>();
+ return std::unique_ptr<JavaInfo>(
+ new JavaInfo{
+ sVendor, sLocation, sVersion, nRequirements,
+ arVendorData});
+}
+
+
+MergedSettings::MergedSettings():
+ m_bEnabled(false)
+{
+ NodeJava settings(NodeJava::USER);
+ settings.load();
+ NodeJava sharedSettings(NodeJava::SHARED);
+ sharedSettings.load();
+ merge(sharedSettings, settings);
+}
+
+MergedSettings::~MergedSettings()
+{
+}
+
+void MergedSettings::merge(const NodeJava & share, const NodeJava & user)
+{
+ if (user.getEnabled())
+ m_bEnabled = * user.getEnabled();
+ else if (share.getEnabled())
+ m_bEnabled = * share.getEnabled();
+ else
+ m_bEnabled = true;
+
+ if (user.getUserClassPath())
+ m_sClassPath = * user.getUserClassPath();
+ else if (share.getUserClassPath())
+ m_sClassPath = * share.getUserClassPath();
+
+ if (user.getJavaInfo())
+ m_javaInfo = * user.getJavaInfo();
+ else if (share.getJavaInfo())
+ m_javaInfo = * share.getJavaInfo();
+
+ if (user.getVmParameters())
+ m_vmParams = * user.getVmParameters();
+ else if (share.getVmParameters())
+ m_vmParams = * share.getVmParameters();
+
+ if (user.getJRELocations())
+ m_JRELocations = * user.getJRELocations();
+ else if (share.getJRELocations())
+ m_JRELocations = * share.getJRELocations();
+}
+
+
+::std::vector< OString> MergedSettings::getVmParametersUtf8() const
+{
+ ::std::vector< OString> ret;
+ for (auto const & vmParam : m_vmParams)
+ {
+ ret.push_back( OUStringToOString(vmParam, RTL_TEXTENCODING_UTF8));
+ }
+ return ret;
+}
+
+
+std::unique_ptr<JavaInfo> MergedSettings::createJavaInfo() const
+{
+ return m_javaInfo.makeJavaInfo();
+}
+#ifdef _WIN32
+bool MergedSettings::getJavaInfoAttrAutoSelect() const
+{
+ return m_javaInfo.bAutoSelect;
+}
+#endif
+void MergedSettings::getVmParametersArray(std::vector<OUString> * parParams)
+ const
+{
+ assert(parParams != nullptr);
+ osl::MutexGuard guard(FwkMutex());
+
+ *parParams = m_vmParams;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/source/framework.cxx b/jvmfwk/source/framework.cxx
new file mode 100644
index 000000000..8aa85082b
--- /dev/null
+++ b/jvmfwk/source/framework.cxx
@@ -0,0 +1,749 @@
+/* -*- 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 <cassert>
+#include <memory>
+
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/diagnose.h>
+#ifdef _WIN32
+#include <osl/file.hxx>
+#include <osl/process.h>
+#endif
+#include <osl/thread.hxx>
+#include <jvmfwk/framework.hxx>
+#include <vendorbase.hxx>
+#include <vendorplugin.hxx>
+#include <vector>
+#include <algorithm>
+#include "framework.hxx"
+#include <fwkutil.hxx>
+#include <elements.hxx>
+#include <fwkbase.hxx>
+
+namespace {
+
+bool g_bEnabledSwitchedOn = false;
+
+JavaVM * g_pJavaVM = nullptr;
+
+bool areEqualJavaInfo(
+ JavaInfo const * pInfoA,JavaInfo const * pInfoB)
+{
+ return jfw_areEqualJavaInfo(pInfoA, pInfoB);
+}
+
+}
+
+javaFrameworkError jfw_findAllJREs(std::vector<std::unique_ptr<JavaInfo>> *pparInfo)
+{
+ assert(pparInfo != nullptr);
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+
+ jfw::VendorSettings aVendorSettings;
+ std::vector<std::unique_ptr<JavaInfo>> vecInfo;
+
+ //Use all plug-in libraries to get Java installations.
+ std::vector<std::unique_ptr<JavaInfo>> arInfos;
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> infos;
+ javaPluginError plerr = jfw_plugin_getAllJavaInfos(
+ true,
+ aVendorSettings,
+ & arInfos,
+ infos);
+
+ if (plerr != javaPluginError::NONE)
+ return JFW_E_ERROR;
+
+ for (auto & j: arInfos)
+ vecInfo.push_back(std::move(j));
+
+ // direct mode disregards Java settings, so only retrieve
+ // JREs from settings when application mode is used
+ if (jfw::getMode() == jfw::JFW_MODE_APPLICATION)
+ {
+ //get the list of paths to jre locations which have been
+ //added manually
+ const jfw::MergedSettings settings;
+ const std::vector<OUString> vecJRELocations =
+ settings.getJRELocations();
+ //Check if any plugin can detect JREs at the location
+ // of the paths added by jfw_addJRELocation
+ //Check every manually added location
+ for (auto const & ii: vecJRELocations)
+ {
+ std::unique_ptr<JavaInfo> aInfo;
+ plerr = jfw_plugin_getJavaInfoByPath(
+ ii,
+ aVendorSettings,
+ &aInfo);
+ if (plerr == javaPluginError::NoJre)
+ continue;
+ if (plerr == javaPluginError::FailedVersion)
+ continue;
+ if (plerr == javaPluginError::WrongArch)
+ continue;
+ else if (plerr != javaPluginError::NONE)
+ return JFW_E_ERROR;
+
+ // Was this JRE already added?
+ if (std::none_of(
+ vecInfo.begin(), vecInfo.end(),
+ [&aInfo](std::unique_ptr<JavaInfo> const & info) {
+ return areEqualJavaInfo(
+ info.get(), aInfo.get());
+ }))
+ {
+ vecInfo.push_back(std::move(aInfo));
+ }
+ }
+ }
+
+ *pparInfo = std::move(vecInfo);
+
+ return JFW_E_NONE;
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ SAL_WARN( "jfw", e.message);
+ return e.errorCode;
+ }
+}
+
+javaFrameworkError jfw_startVM(
+ JavaInfo const * pInfo, std::vector<OUString> const & arOptions,
+ JavaVM ** ppVM, JNIEnv ** ppEnv)
+{
+ assert(ppVM != nullptr);
+ javaFrameworkError errcode = JFW_E_NONE;
+
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+
+ //We keep this pointer so we can determine if a VM has already
+ //been created.
+ if (g_pJavaVM != nullptr)
+ return JFW_E_RUNNING_JVM;
+
+ std::vector<OString> vmParams;
+ OString sUserClassPath;
+ std::unique_ptr<JavaInfo> aInfo;
+ if (pInfo == nullptr)
+ {
+ jfw::JFW_MODE mode = jfw::getMode();
+ if (mode == jfw::JFW_MODE_APPLICATION)
+ {
+ const jfw::MergedSettings settings;
+ if (!settings.getEnabled())
+ return JFW_E_JAVA_DISABLED;
+ aInfo = settings.createJavaInfo();
+ //check if a Java has ever been selected
+ if (!aInfo)
+ return JFW_E_NO_SELECT;
+
+ //check if the javavendors.xml has changed after a Java was selected
+ OString sVendorUpdate = jfw::getElementUpdated();
+
+ if (sVendorUpdate != settings.getJavaInfoAttrVendorUpdate())
+ return JFW_E_INVALID_SETTINGS;
+
+ //check if JAVA is disabled
+ //If Java is enabled, but it was disabled when this process was started
+ // then no preparational work, such as setting the LD_LIBRARY_PATH, was
+ //done. Therefore if a JRE needs it, it must not be started.
+ if (g_bEnabledSwitchedOn &&
+ (aInfo->nRequirements & JFW_REQUIRE_NEEDRESTART))
+ return JFW_E_NEED_RESTART;
+
+ //Check if the selected Java was set in this process. If so it
+ //must not have the requirements flag JFW_REQUIRE_NEEDRESTART
+ if ((aInfo->nRequirements & JFW_REQUIRE_NEEDRESTART)
+ && jfw::wasJavaSelectedInSameProcess())
+ return JFW_E_NEED_RESTART;
+
+ vmParams = settings.getVmParametersUtf8();
+ sUserClassPath = jfw::makeClassPathOption(settings.getUserClassPath());
+ } // end mode FWK_MODE_OFFICE
+ else if (mode == jfw::JFW_MODE_DIRECT)
+ {
+ errcode = jfw_getSelectedJRE(&aInfo);
+ if (errcode != JFW_E_NONE)
+ return errcode;
+ //In direct mode the options are specified by bootstrap variables
+ //of the form UNO_JAVA_JFW_PARAMETER_1 .. UNO_JAVA_JFW_PARAMETER_n
+ vmParams = jfw::BootParams::getVMParameters();
+ auto const cp = jfw::BootParams::getClasspath();
+ if (!cp.isEmpty())
+ {
+ sUserClassPath =
+ "-Djava.class.path=" + cp;
+ }
+ }
+ else
+ OSL_ASSERT(false);
+ pInfo = aInfo.get();
+ }
+ assert(pInfo != nullptr);
+
+#ifdef _WIN32
+ // Alternative JREs (AdoptOpenJDK, Azul Zulu) are missing the bin/ folder in
+ // java.library.path. Somehow setting java.library.path accordingly doesn't work,
+ // but the PATH gets picked up, so add it there.
+ // Without this hack, some features don't work in alternative JREs.
+ OUString sPATH;
+ osl_getEnvironment(OUString("PATH").pData, &sPATH.pData);
+ OUString sJRELocation;
+ osl::FileBase::getSystemPathFromFileURL(pInfo->sLocation + "/bin", sJRELocation);
+ if (sPATH.isEmpty())
+ sPATH = sJRELocation;
+ else
+ sPATH = sJRELocation + OUStringChar(SAL_PATHSEPARATOR) + sPATH;
+ osl_setEnvironment(OUString("PATH").pData, sPATH.pData);
+#endif // _WIN32
+
+ // create JavaVMOptions array that is passed to the plugin
+ // it contains the classpath and all options set in the
+ //options dialog
+ std::unique_ptr<JavaVMOption[]> sarJOptions(
+ new JavaVMOption[
+ arOptions.size() + (sUserClassPath.isEmpty() ? 1 : 2) + vmParams.size()]);
+ JavaVMOption * arOpt = sarJOptions.get();
+ if (! arOpt)
+ return JFW_E_ERROR;
+
+ //The first argument is the classpath
+ int index = 0;
+ if (!sUserClassPath.isEmpty()) {
+ arOpt[index].optionString= const_cast<char*>(sUserClassPath.getStr());
+ arOpt[index].extraInfo = nullptr;
+ ++index;
+ }
+ // Set a flag that this JVM has been created via the JNI Invocation API
+ // (used, for example, by UNO remote bridges to share a common thread pool
+ // factory among Java and native bridge implementations):
+ arOpt[index].optionString = const_cast<char *>("-Dorg.openoffice.native=");
+ arOpt[index].extraInfo = nullptr;
+ ++index;
+
+ //add the options set by options dialog
+ for (auto const & vmParam : vmParams)
+ {
+ arOpt[index].optionString = const_cast<char*>(vmParam.getStr());
+ arOpt[index].extraInfo = nullptr;
+ index ++;
+ }
+ //add all options of the arOptions argument
+ std::vector<OString> convertedOptions;
+ for (auto const & ii: arOptions)
+ {
+ OString conv = OUStringToOString(ii, osl_getThreadTextEncoding());
+ convertedOptions.push_back(conv);
+ // keep conv.getStr() alive until after the call to
+ // jfw_plugin_startJavaVirtualMachine below
+ arOpt[index].optionString = const_cast<char *>(conv.getStr());
+ arOpt[index].extraInfo = nullptr;
+ index++;
+ }
+
+ //start Java
+ JavaVM *pVm = nullptr;
+ SAL_INFO("jfw", "Starting Java");
+ javaPluginError plerr = jfw_plugin_startJavaVirtualMachine(pInfo, arOpt, index, & pVm, ppEnv);
+ if (plerr == javaPluginError::VmCreationFailed)
+ {
+ errcode = JFW_E_VM_CREATION_FAILED;
+ }
+ else if (plerr != javaPluginError::NONE )
+ {
+ errcode = JFW_E_ERROR;
+ }
+ else
+ {
+ g_pJavaVM = pVm;
+ *ppVM = pVm;
+ }
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message);
+ }
+
+ return errcode;
+}
+
+/** We do not use here jfw_findAllJREs and then check if a JavaInfo
+ meets the requirements, because that means using all plug-ins, which
+ may take quite a while. The implementation first inspects JAVA_HOME and
+ PATH environment variables. If no suitable JavaInfo is found there, it
+ inspects all JavaInfos found by the jfw_plugin_get* functions.
+ */
+javaFrameworkError jfw_findAndSelectJRE(std::unique_ptr<JavaInfo> *pInfo)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ std::unique_ptr<JavaInfo> aCurrentInfo;
+
+
+ // 'bInfoFound' indicates whether a Java installation has been found
+ bool bInfoFound = false;
+
+ // get list of vendors for Java installations
+ jfw::VendorSettings aVendorSettings;
+
+ std::vector<rtl::Reference<jfw_plugin::VendorBase>> infos;
+
+ // first inspect Java installation that the JAVA_HOME
+ // environment variable points to (if it is set)
+ if (jfw_plugin_getJavaInfoFromJavaHome(
+ aVendorSettings, &aCurrentInfo, infos)
+ == javaPluginError::NONE)
+ {
+ bInfoFound = true;
+ }
+
+ // if no Java installation was detected by using JAVA_HOME,
+ // query PATH for Java installations
+ if (!bInfoFound)
+ {
+ std::vector<std::unique_ptr<JavaInfo>> vecJavaInfosFromPath;
+ if (jfw_plugin_getJavaInfosFromPath(
+ aVendorSettings, vecJavaInfosFromPath, infos)
+ == javaPluginError::NONE)
+ {
+ assert(!vecJavaInfosFromPath.empty());
+ aCurrentInfo = std::move(vecJavaInfosFromPath[0]);
+ bInfoFound = true;
+ }
+ }
+
+
+ // if no suitable Java installation has been found yet:
+ // first use jfw_plugin_getAllJavaInfos to find a suitable Java installation,
+ // then try paths that have been added manually
+ if (!bInfoFound)
+ {
+ //get all installations
+ std::vector<std::unique_ptr<JavaInfo>> arInfos;
+ javaPluginError plerr = jfw_plugin_getAllJavaInfos(
+ false,
+ aVendorSettings,
+ & arInfos,
+ infos);
+
+ if (plerr == javaPluginError::NONE && !arInfos.empty())
+ {
+ aCurrentInfo = std::move(arInfos[0]);
+ }
+
+ if (!aCurrentInfo)
+ {//The plug-ins did not find a suitable Java. Now try the paths which have been
+ //added manually.
+ //get the list of paths to jre locations which have been added manually
+ const jfw::MergedSettings settings;
+ //node.loadFromSettings();
+ const std::vector<OUString> & vecJRELocations =
+ settings.getJRELocations();
+ //use all plug-ins to determine the JavaInfo objects
+ for (auto const & JRELocation : vecJRELocations)
+ {
+ std::unique_ptr<JavaInfo> aInfo;
+ javaPluginError err = jfw_plugin_getJavaInfoByPath(
+ JRELocation,
+ aVendorSettings,
+ &aInfo);
+ if (err == javaPluginError::NoJre)
+ continue;
+ if (err == javaPluginError::FailedVersion)
+ continue;
+ else if (err !=javaPluginError::NONE)
+ return JFW_E_ERROR;
+
+ if (aInfo)
+ {
+ aCurrentInfo = std::move(aInfo);
+ break;
+ }
+ }//end iterate over paths
+ }
+ }
+ if (aCurrentInfo)
+ {
+ jfw::NodeJava javaNode(jfw::NodeJava::USER);
+ javaNode.setJavaInfo(aCurrentInfo.get(),true);
+ javaNode.write();
+ //remember that this JRE was selected in this process
+ jfw::setJavaSelected();
+
+ if (pInfo !=nullptr)
+ {
+ *pInfo = std::move(aCurrentInfo);
+ }
+ }
+ else
+ {
+ errcode = JFW_E_NO_JAVA_FOUND;
+ }
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+
+ return errcode;
+}
+
+bool jfw_areEqualJavaInfo(JavaInfo const * pInfoA,JavaInfo const * pInfoB)
+{
+ if (pInfoA == pInfoB)
+ return true;
+ if (pInfoA == nullptr || pInfoB == nullptr)
+ return false;
+ if (pInfoA->sVendor == pInfoB->sVendor
+ && pInfoA->sLocation == pInfoB->sLocation
+ && pInfoA->sVersion == pInfoB->sVersion
+ && pInfoA->nRequirements == pInfoB->nRequirements
+ && pInfoA->arVendorData == pInfoB->arVendorData)
+ {
+ return true;
+ }
+ return false;
+}
+
+javaFrameworkError jfw_getSelectedJRE(std::unique_ptr<JavaInfo> *ppInfo)
+{
+ assert(ppInfo != nullptr);
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ {
+ if ((errcode = jfw_getJavaInfoByPath(
+ jfw::BootParams::getJREHome(), ppInfo))
+ != JFW_E_NONE)
+ throw jfw::FrameworkException(
+ JFW_E_CONFIGURATION,
+ "[Java framework] The JRE specified by the bootstrap "
+ "variable UNO_JAVA_JFW_JREHOME or UNO_JAVA_JFW_ENV_JREHOME "
+ " could not be recognized. Check the values and make sure that you "
+ "use a plug-in library that can recognize that JRE.");
+
+ return JFW_E_NONE;
+ }
+
+ const jfw::MergedSettings settings;
+ *ppInfo = settings.createJavaInfo();
+ if (!*ppInfo)
+ {
+ return JFW_E_NONE;
+ }
+ //If the javavendors.xml has changed, then the current selected
+ //Java is not valid anymore
+ // /java/javaInfo/@vendorUpdate != javaSelection/updated (javavendors.xml)
+ OString sUpdated = jfw::getElementUpdated();
+
+ if (sUpdated != settings.getJavaInfoAttrVendorUpdate())
+ {
+ ppInfo->reset();
+ return JFW_E_INVALID_SETTINGS;
+ }
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+
+bool jfw_isVMRunning()
+{
+ osl::MutexGuard guard(jfw::FwkMutex());
+ return g_pJavaVM != nullptr;
+}
+
+javaFrameworkError jfw_getJavaInfoByPath(OUString const & pPath, std::unique_ptr<JavaInfo> *ppInfo)
+{
+ assert(ppInfo != nullptr);
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+
+ jfw::VendorSettings aVendorSettings;
+
+ //ask all plugins if this is a JRE.
+ //If so check if it meets the version requirements.
+ //Only if it does return a JavaInfo
+ javaPluginError plerr = jfw_plugin_getJavaInfoByPath(
+ pPath,
+ aVendorSettings,
+ ppInfo);
+
+ if(plerr == javaPluginError::FailedVersion)
+ {//found JRE but it has the wrong version
+ ppInfo->reset();
+ errcode = JFW_E_FAILED_VERSION;
+ }
+ OSL_ASSERT(plerr == javaPluginError::NONE || plerr == javaPluginError::NoJre);
+ if (!*ppInfo && errcode != JFW_E_FAILED_VERSION)
+ errcode = JFW_E_NOT_RECOGNIZED;
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+
+ return errcode;
+}
+
+
+javaFrameworkError jfw_setSelectedJRE(JavaInfo const *pInfo)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ //check if pInfo is the selected JRE
+ std::unique_ptr<JavaInfo> currentInfo;
+ errcode = jfw_getSelectedJRE( & currentInfo);
+ if (errcode != JFW_E_NONE && errcode != JFW_E_INVALID_SETTINGS)
+ return errcode;
+
+ if (!jfw_areEqualJavaInfo(currentInfo.get(), pInfo))
+ {
+ jfw::NodeJava node(jfw::NodeJava::USER);
+ node.setJavaInfo(pInfo, false);
+ node.write();
+ //remember that the JRE was selected in this process
+ jfw::setJavaSelected();
+ }
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+javaFrameworkError jfw_setEnabled(bool bEnabled)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+
+ if (!g_bEnabledSwitchedOn && bEnabled)
+ {
+ //When the process started then Enabled was false.
+ //This is first time enabled is set to true.
+ //That means, no preparational work has been done, such as setting the
+ //LD_LIBRARY_PATH, etc.
+
+ //check if Enabled is false;
+ const jfw::MergedSettings settings;
+ if (!settings.getEnabled())
+ g_bEnabledSwitchedOn = true;
+ }
+ jfw::NodeJava node(jfw::NodeJava::USER);
+ node.setEnabled(bEnabled);
+ node.write();
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+
+javaFrameworkError jfw_getEnabled(bool *pbEnabled)
+{
+ assert(pbEnabled != nullptr);
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ osl::MutexGuard guard(jfw::FwkMutex());
+ jfw::MergedSettings settings;
+ *pbEnabled = settings.getEnabled();
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+
+
+javaFrameworkError jfw_setVMParameters(std::vector<OUString> const & arOptions)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ jfw::NodeJava node(jfw::NodeJava::USER);
+ node.setVmParameters(arOptions);
+ node.write();
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+
+ return errcode;
+}
+
+javaFrameworkError jfw_getVMParameters(std::vector<OUString> * parOptions)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+
+ const jfw::MergedSettings settings;
+ settings.getVmParametersArray(parOptions);
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+
+javaFrameworkError jfw_setUserClassPath(OUString const & pCp)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ jfw::NodeJava node(jfw::NodeJava::USER);
+ node.setUserClassPath(pCp);
+ node.write();
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+
+javaFrameworkError jfw_getUserClassPath(OUString * ppCP)
+{
+ assert(ppCP != nullptr);
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ const jfw::MergedSettings settings;
+ *ppCP = settings.getUserClassPath();
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+ return errcode;
+}
+
+javaFrameworkError jfw_addJRELocation(OUString const & sLocation)
+{
+ javaFrameworkError errcode = JFW_E_NONE;
+ try
+ {
+ osl::MutexGuard guard(jfw::FwkMutex());
+ if (jfw::getMode() == jfw::JFW_MODE_DIRECT)
+ return JFW_E_DIRECT_MODE;
+ jfw::NodeJava node(jfw::NodeJava::USER);
+ node.load();
+ node.addJRELocation(sLocation);
+ node.write();
+ }
+ catch (const jfw::FrameworkException& e)
+ {
+ errcode = e.errorCode;
+ SAL_WARN( "jfw", e.message );
+ }
+
+ return errcode;
+
+}
+
+javaFrameworkError jfw_existJRE(const JavaInfo *pInfo, bool *exist)
+{
+ javaPluginError plerr = jfw_plugin_existJRE(pInfo, exist);
+
+ javaFrameworkError ret = JFW_E_NONE;
+ switch (plerr)
+ {
+ case javaPluginError::NONE:
+ ret = JFW_E_NONE;
+ break;
+ case javaPluginError::Error:
+ ret = JFW_E_ERROR;
+ break;
+ default:
+ ret = JFW_E_ERROR;
+ }
+ return ret;
+}
+
+void jfw_lock()
+{
+ jfw::FwkMutex().acquire();
+}
+
+void jfw_unlock()
+{
+ jfw::FwkMutex().release();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/source/framework.hxx b/jvmfwk/source/framework.hxx
new file mode 100644
index 000000000..39bda148b
--- /dev/null
+++ b/jvmfwk/source/framework.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_JVMFWK_SOURCE_FRAMEWORK_HXX
+#define INCLUDED_JVMFWK_SOURCE_FRAMEWORK_HXX
+
+#include <jvmfwk/framework.hxx>
+
+namespace jfw
+{
+
+class FrameworkException : public std::exception
+{
+public:
+
+ FrameworkException(javaFrameworkError err, const OString& msg):
+ errorCode(err), message(msg)
+ {
+ }
+ javaFrameworkError errorCode;
+ OString message;
+};
+}
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/source/fwkbase.cxx b/jvmfwk/source/fwkbase.cxx
new file mode 100644
index 000000000..225437011
--- /dev/null
+++ b/jvmfwk/source/fwkbase.cxx
@@ -0,0 +1,524 @@
+/* -*- 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/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <libxml/xpathInternals.h>
+#include <osl/file.hxx>
+#include <osl/thread.hxx>
+#include <o3tl/string_view.hxx>
+#include "framework.hxx"
+#include <fwkutil.hxx>
+#include <elements.hxx>
+#include <fwkbase.hxx>
+
+using namespace osl;
+
+
+#define UNO_JAVA_JFW_PARAMETER "UNO_JAVA_JFW_PARAMETER_"
+#define UNO_JAVA_JFW_JREHOME "UNO_JAVA_JFW_JREHOME"
+#define UNO_JAVA_JFW_ENV_JREHOME "UNO_JAVA_JFW_ENV_JREHOME"
+#define UNO_JAVA_JFW_CLASSPATH "UNO_JAVA_JFW_CLASSPATH"
+#define UNO_JAVA_JFW_ENV_CLASSPATH "UNO_JAVA_JFW_ENV_CLASSPATH"
+#define UNO_JAVA_JFW_CLASSPATH_URLS "UNO_JAVA_JFW_CLASSPATH_URLS"
+#define UNO_JAVA_JFW_VENDOR_SETTINGS "UNO_JAVA_JFW_VENDOR_SETTINGS"
+
+namespace jfw
+{
+static bool g_bJavaSet = false;
+
+namespace {
+
+#if defined _WIN32
+ // The paths are used in libxml. On Windows, it takes UTF-8 paths.
+constexpr rtl_TextEncoding PathEncoding() { return RTL_TEXTENCODING_UTF8; }
+#else
+rtl_TextEncoding PathEncoding() { return osl_getThreadTextEncoding(); }
+#endif
+
+OString getVendorSettingsPath(OUString const & sURL)
+{
+ if (sURL.isEmpty())
+ return OString();
+ OUString sSystemPathSettings;
+ if (osl_getSystemPathFromFileURL(sURL.pData,
+ & sSystemPathSettings.pData) != osl_File_E_None)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Error in function getVendorSettingsPath (fwkbase.cxx) ");
+ OString osSystemPathSettings = OUStringToOString(sSystemPathSettings, PathEncoding());
+ return osSystemPathSettings;
+}
+
+OUString getParam(OUString const & name)
+{
+ OUString retVal;
+ bool b = Bootstrap()->getFrom(name, retVal);
+ SAL_INFO(
+ "jfw",
+ "Using bootstrap parameter " << name << " = \"" << retVal << "\""
+ << (b ? "" : " (undefined)"));
+ return retVal;
+}
+
+OUString getParamFirstUrl(OUString const & name)
+{
+ // Some parameters can consist of multiple URLs (separated by space
+ // characters, although trim() harmlessly also removes other white-space),
+ // of which only the first is used:
+ return getParam(name).trim().getToken(0, ' ');
+}
+
+}//blind namespace
+
+
+VendorSettings::VendorSettings()
+{
+ OUString xmlDocVendorSettingsFileUrl(BootParams::getVendorSettings());
+ //Prepare the xml document and context
+ OString sSettingsPath = getVendorSettingsPath(xmlDocVendorSettingsFileUrl);
+ if (sSettingsPath.isEmpty())
+ {
+ OString sMsg("[Java framework] A vendor settings file was not specified."
+ "Check the bootstrap parameter " UNO_JAVA_JFW_VENDOR_SETTINGS ".");
+ SAL_WARN( "jfw", sMsg );
+ throw FrameworkException(JFW_E_CONFIGURATION, sMsg);
+ }
+ if (sSettingsPath.isEmpty())
+ return;
+
+ m_xmlDocVendorSettings = xmlParseFile(sSettingsPath.getStr());
+ if (m_xmlDocVendorSettings == nullptr)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ OString::Concat("[Java framework] Error while parsing file: ")
+ + sSettingsPath + ".");
+
+ m_xmlPathContextVendorSettings = xmlXPathNewContext(m_xmlDocVendorSettings);
+ int res = xmlXPathRegisterNs(
+ m_xmlPathContextVendorSettings, reinterpret_cast<xmlChar const *>("jf"),
+ reinterpret_cast<xmlChar const *>(NS_JAVA_FRAMEWORK));
+ if (res == -1)
+ throw FrameworkException(JFW_E_ERROR,
+ "[Java framework] Error in constructor VendorSettings::VendorSettings() (fwkbase.cxx)");
+}
+
+VersionInfo VendorSettings::getVersionInformation(std::u16string_view sVendor) const
+{
+ OSL_ASSERT(!sVendor.empty());
+ OString osVendor = OUStringToOString(sVendor, RTL_TEXTENCODING_UTF8);
+ CXPathObjectPtr pathObject = xmlXPathEvalExpression(
+ reinterpret_cast<xmlChar const *>(
+ OString(
+ "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" + osVendor
+ + "\"]/jf:minVersion").getStr()),
+ m_xmlPathContextVendorSettings);
+ if (xmlXPathNodeSetIsEmpty(pathObject->nodesetval))
+ {
+ return {
+ {},
+#if defined MACOSX && defined __aarch64__
+ "17",
+#else
+ "1.8.0",
+#endif
+ ""};
+ }
+
+ VersionInfo aVersionInfo;
+ //Get minVersion
+ OString sExpression =
+ "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" +
+ osVendor + "\"]/jf:minVersion";
+
+ CXPathObjectPtr xPathObjectMin =
+ xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>(sExpression.getStr()),
+ m_xmlPathContextVendorSettings);
+ if (xmlXPathNodeSetIsEmpty(xPathObjectMin->nodesetval))
+ {
+ aVersionInfo.sMinVersion.clear();
+ }
+ else
+ {
+ CXmlCharPtr sVersion = xmlNodeListGetString(
+ m_xmlDocVendorSettings,
+ xPathObjectMin->nodesetval->nodeTab[0]->xmlChildrenNode, 1);
+ OString osVersion(sVersion);
+ aVersionInfo.sMinVersion = OStringToOUString(
+ osVersion, RTL_TEXTENCODING_UTF8);
+ }
+
+ //Get maxVersion
+ sExpression = "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" +
+ osVendor + "\"]/jf:maxVersion";
+ CXPathObjectPtr xPathObjectMax = xmlXPathEvalExpression(
+ reinterpret_cast<xmlChar const *>(sExpression.getStr()),
+ m_xmlPathContextVendorSettings);
+ if (xmlXPathNodeSetIsEmpty(xPathObjectMax->nodesetval))
+ {
+ aVersionInfo.sMaxVersion.clear();
+ }
+ else
+ {
+ CXmlCharPtr sVersion = xmlNodeListGetString(
+ m_xmlDocVendorSettings,
+ xPathObjectMax->nodesetval->nodeTab[0]->xmlChildrenNode, 1);
+ OString osVersion(sVersion);
+ aVersionInfo.sMaxVersion = OStringToOUString(
+ osVersion, RTL_TEXTENCODING_UTF8);
+ }
+
+ //Get excludeVersions
+ sExpression = "/jf:javaSelection/jf:vendorInfos/jf:vendor[@name=\"" +
+ osVendor + "\"]/jf:excludeVersions/jf:version";
+ CXPathObjectPtr xPathObjectVersions =
+ xmlXPathEvalExpression(reinterpret_cast<xmlChar const *>(sExpression.getStr()),
+ m_xmlPathContextVendorSettings);
+ if (!xmlXPathNodeSetIsEmpty(xPathObjectVersions->nodesetval))
+ {
+ xmlNode* cur = xPathObjectVersions->nodesetval->nodeTab[0];
+ while (cur != nullptr)
+ {
+ if (cur->type == XML_ELEMENT_NODE )
+ {
+ if (xmlStrcmp(cur->name, reinterpret_cast<xmlChar const *>("version")) == 0)
+ {
+ CXmlCharPtr sVersion = xmlNodeListGetString(
+ m_xmlDocVendorSettings, cur->xmlChildrenNode, 1);
+ OString osVersion(sVersion);
+ OUString usVersion = OStringToOUString(
+ osVersion, RTL_TEXTENCODING_UTF8);
+ aVersionInfo.vecExcludeVersions.push_back(usVersion);
+ }
+ }
+ cur = cur->next;
+ }
+ }
+ return aVersionInfo;
+}
+
+::std::vector<OString> BootParams::getVMParameters()
+{
+ ::std::vector<OString> vecParams;
+
+ for (sal_Int32 i = 1; ; i++)
+ {
+ OUString sName = UNO_JAVA_JFW_PARAMETER + OUString::number(i);
+ OUString sValue;
+ if (Bootstrap()->getFrom(sName, sValue))
+ {
+ OString sParam =
+ OUStringToOString(sValue, osl_getThreadTextEncoding());
+ vecParams.push_back(sParam);
+ SAL_INFO(
+ "jfw.level2",
+ "Using bootstrap parameter " << sName << " = " << sParam);
+ }
+ else
+ break;
+ }
+ return vecParams;
+}
+
+OUString BootParams::getUserData()
+{
+ return getParamFirstUrl("UNO_JAVA_JFW_USER_DATA");
+}
+
+OUString BootParams::getSharedData()
+{
+ return getParamFirstUrl("UNO_JAVA_JFW_SHARED_DATA");
+}
+
+OString BootParams::getClasspath()
+{
+ OString sClassPath;
+ OUString sCP;
+ if (Bootstrap()->getFrom( UNO_JAVA_JFW_CLASSPATH, sCP ))
+ {
+ sClassPath = OUStringToOString(sCP, PathEncoding());
+ SAL_INFO(
+ "jfw.level2",
+ "Using bootstrap parameter " UNO_JAVA_JFW_CLASSPATH " = "
+ << sClassPath);
+ }
+
+ OUString sEnvCP;
+ if (Bootstrap()->getFrom( UNO_JAVA_JFW_ENV_CLASSPATH, sEnvCP ))
+ {
+ char * pCp = getenv("CLASSPATH");
+ if (pCp)
+ {
+ sClassPath += OStringChar(SAL_PATHSEPARATOR) + pCp;
+ }
+ SAL_INFO(
+ "jfw.level2",
+ "Using bootstrap parameter " UNO_JAVA_JFW_ENV_CLASSPATH
+ " and class path is: " << (pCp ? pCp : ""));
+ }
+
+ return sClassPath;
+}
+
+OUString BootParams::getVendorSettings()
+{
+ OUString sVendor;
+ if (Bootstrap()->getFrom(UNO_JAVA_JFW_VENDOR_SETTINGS, sVendor))
+ {
+ //check the value of the bootstrap variable
+ jfw::FileStatus s = checkFileURL(sVendor);
+ if (s != FILE_OK)
+ {
+ //This bootstrap parameter can contain a relative URL
+ OUString sAbsoluteUrl;
+ OUString sBaseDir = getLibraryLocation();
+ if (File::getAbsoluteFileURL(sBaseDir, sVendor, sAbsoluteUrl)
+ != File::E_None)
+ throw FrameworkException(
+ JFW_E_CONFIGURATION,
+ "[Java framework] Invalid value for bootstrap variable: "
+ UNO_JAVA_JFW_VENDOR_SETTINGS);
+ sVendor = sAbsoluteUrl;
+ s = checkFileURL(sVendor);
+ if (s == jfw::FILE_INVALID || s == jfw::FILE_DOES_NOT_EXIST)
+ {
+ throw FrameworkException(
+ JFW_E_CONFIGURATION,
+ "[Java framework] Invalid value for bootstrap variable: "
+ UNO_JAVA_JFW_VENDOR_SETTINGS);
+ }
+ }
+ SAL_INFO(
+ "jfw.level2",
+ "Using bootstrap parameter " UNO_JAVA_JFW_VENDOR_SETTINGS " = "
+ << sVendor);
+ }
+ return sVendor;
+}
+
+OUString BootParams::getJREHome()
+{
+ OUString sJRE;
+ OUString sEnvJRE;
+ bool bJRE = Bootstrap()->getFrom(UNO_JAVA_JFW_JREHOME, sJRE);
+ bool bEnvJRE = Bootstrap()->getFrom(UNO_JAVA_JFW_ENV_JREHOME, sEnvJRE);
+
+ if (bJRE && bEnvJRE)
+ {
+ throw FrameworkException(
+ JFW_E_CONFIGURATION,
+ "[Java framework] Both bootstrap parameter "
+ UNO_JAVA_JFW_JREHOME" and "
+ UNO_JAVA_JFW_ENV_JREHOME" are set. However only one of them can be set."
+ "Check bootstrap parameters: environment variables, command line "
+ "arguments, rc/ini files for executable and java framework library.");
+ }
+ else if (bEnvJRE)
+ {
+ const char * pJRE = getenv("JAVA_HOME");
+ if (pJRE == nullptr)
+ {
+ throw FrameworkException(
+ JFW_E_CONFIGURATION,
+ "[Java framework] Both bootstrap parameter "
+ UNO_JAVA_JFW_ENV_JREHOME" is set, but the environment variable "
+ "JAVA_HOME is not set.");
+ }
+ OString osJRE(pJRE);
+ OUString usJRE = OStringToOUString(osJRE, osl_getThreadTextEncoding());
+ if (File::getFileURLFromSystemPath(usJRE, sJRE) != File::E_None)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Error in function BootParams::getJREHome() "
+ "(fwkbase.cxx).");
+ SAL_INFO(
+ "jfw.level2",
+ "Using bootstrap parameter " UNO_JAVA_JFW_ENV_JREHOME
+ " with JAVA_HOME = " << pJRE);
+ }
+ else if (getMode() == JFW_MODE_DIRECT && !bJRE)
+ {
+ throw FrameworkException(
+ JFW_E_CONFIGURATION,
+ "[Java framework] The bootstrap parameter "
+ UNO_JAVA_JFW_ENV_JREHOME" or " UNO_JAVA_JFW_JREHOME
+ " must be set in direct mode.");
+ }
+
+ SAL_INFO_IF(
+ bJRE, "jfw.level2",
+ "Using bootstrap parameter " UNO_JAVA_JFW_JREHOME " = " << sJRE);
+ return sJRE;
+}
+
+OUString BootParams::getClasspathUrls()
+{
+ OUString sParams;
+ Bootstrap()->getFrom( UNO_JAVA_JFW_CLASSPATH_URLS, sParams);
+ SAL_INFO(
+ "jfw.level2",
+ "Using bootstrap parameter " UNO_JAVA_JFW_CLASSPATH_URLS " = "
+ << sParams);
+ return sParams;
+}
+
+JFW_MODE getMode()
+{
+ static bool g_bMode = false;
+ static JFW_MODE g_mode = JFW_MODE_APPLICATION;
+
+ if (!g_bMode)
+ {
+ //check if either of the "direct mode" bootstrap variables is set
+ bool bDirectMode = true;
+ OUString sValue;
+ const rtl::Bootstrap * aBoot = Bootstrap();
+ if (!aBoot->getFrom(UNO_JAVA_JFW_JREHOME, sValue))
+ {
+ if (!aBoot->getFrom(UNO_JAVA_JFW_ENV_JREHOME, sValue))
+ {
+ if (!aBoot->getFrom(UNO_JAVA_JFW_CLASSPATH, sValue))
+ {
+ if (!aBoot->getFrom(UNO_JAVA_JFW_ENV_CLASSPATH, sValue))
+ {
+ OUString sParams = UNO_JAVA_JFW_PARAMETER +
+ OUString::number(1);
+ if (!aBoot->getFrom(sParams, sValue))
+ {
+ bDirectMode = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (bDirectMode)
+ g_mode = JFW_MODE_DIRECT;
+ else
+ g_mode = JFW_MODE_APPLICATION;
+ g_bMode = true;
+ }
+
+ return g_mode;
+}
+
+OUString getApplicationClassPath()
+{
+ OSL_ASSERT(getMode() == JFW_MODE_APPLICATION);
+ OUString sParams = BootParams::getClasspathUrls();
+ if (sParams.isEmpty())
+ return OUString();
+
+ OUStringBuffer buf;
+ sal_Int32 index = 0;
+ do
+ {
+ OUString token( o3tl::trim(o3tl::getToken(sParams, 0, ' ', index )) );
+ if (!token.isEmpty())
+ {
+ OUString systemPathElement;
+ oslFileError rc = osl_getSystemPathFromFileURL(
+ token.pData, &systemPathElement.pData );
+ OSL_ASSERT( rc == osl_File_E_None );
+ if (rc == osl_File_E_None && !systemPathElement.isEmpty())
+ {
+ if (buf.getLength() > 0)
+ buf.append( SAL_PATHSEPARATOR );
+ buf.append( systemPathElement );
+ }
+ }
+ }
+ while (index >= 0);
+ return buf.makeStringAndClear();
+}
+
+OString makeClassPathOption(std::u16string_view sUserClassPath)
+{
+ //Compose the class path
+ OString sPaths;
+ OUStringBuffer sBufCP(4096);
+
+ // append all user selected jars to the class path
+ if (!sUserClassPath.empty())
+ sBufCP.append(sUserClassPath);
+
+ //append all jar libraries and components to the class path
+ OUString sAppCP = getApplicationClassPath();
+ if (!sAppCP.isEmpty())
+ {
+ if (!sUserClassPath.empty())
+ {
+ sBufCP.append(SAL_PATHSEPARATOR);
+ }
+ sBufCP.append(sAppCP);
+ }
+
+ sPaths = OUStringToOString(sBufCP.makeStringAndClear(), PathEncoding());
+ if (sPaths.isEmpty()) {
+ return "";
+ }
+
+ OString sOptionClassPath = "-Djava.class.path=" + sPaths;
+ return sOptionClassPath;
+}
+
+OString getUserSettingsPath()
+{
+ return getSettingsPath(BootParams::getUserData());
+}
+
+OString getSharedSettingsPath()
+{
+ return getSettingsPath(BootParams::getSharedData());
+}
+
+OString getSettingsPath( const OUString & sURL)
+{
+ if (sURL.isEmpty())
+ return OString();
+ OUString sPath;
+ if (osl_getSystemPathFromFileURL(sURL.pData,
+ & sPath.pData) != osl_File_E_None)
+ throw FrameworkException(
+ JFW_E_ERROR,
+ "[Java framework] Error in function ::getSettingsPath (fwkbase.cxx).");
+ return OUStringToOString(sPath, PathEncoding());
+}
+
+OString getVendorSettingsPath()
+{
+ return getVendorSettingsPath(BootParams::getVendorSettings());
+}
+
+void setJavaSelected()
+{
+ g_bJavaSet = true;
+}
+
+bool wasJavaSelectedInSameProcess()
+{
+ //g_setJavaProcId not set means no Java selected
+ return g_bJavaSet;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/source/fwkutil.cxx b/jvmfwk/source/fwkutil.cxx
new file mode 100644
index 000000000..89cb2e541
--- /dev/null
+++ b/jvmfwk/source/fwkutil.cxx
@@ -0,0 +1,194 @@
+/* -*- 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 .
+ */
+
+
+#if defined(_WIN32)
+#if !defined WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#include <algorithm>
+#endif
+
+#include <osl/module.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/file.hxx>
+#include <sal/log.hxx>
+
+#include "framework.hxx"
+#include <fwkutil.hxx>
+#include <memory>
+
+using namespace osl;
+
+
+namespace jfw
+{
+
+/** provides a bootstrap class which already knows the values from the
+ jvmfkwrc file.
+*/
+const rtl::Bootstrap* Bootstrap()
+{
+ static const rtl::Bootstrap* SINGLETON = []()
+ {
+ OUString sIni = getLibraryLocation() +
+#ifdef MACOSX
+ // For some reason the jvmfwk3rc file is traditionally in
+ // LIBO_URE_ETC_FOLDER
+ "/../" LIBO_URE_ETC_FOLDER
+#endif
+ SAL_CONFIGFILE("/jvmfwk3");
+ ::rtl::Bootstrap * bootstrap = new ::rtl::Bootstrap(sIni);
+ SAL_INFO("jfw.level2", "Using configuration file " << sIni);
+ return bootstrap;
+ }();
+ return SINGLETON;
+};
+
+osl::Mutex& FwkMutex()
+{
+ static osl::Mutex SINGLETON;
+ return SINGLETON;
+}
+
+
+rtl::ByteSequence encodeBase16(const rtl::ByteSequence& rawData)
+{
+ static const char EncodingTable[] =
+ {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ sal_Int32 lenRaw = rawData.getLength();
+ std::unique_ptr<char[]> pBuf(new char[lenRaw * 2]);
+ const sal_Int8* arRaw = rawData.getConstArray();
+
+ char* pCurBuf = pBuf.get();
+ for (int i = 0; i < lenRaw; i++)
+ {
+ unsigned char curChar = arRaw[i];
+ curChar >>= 4;
+
+ *pCurBuf = EncodingTable[curChar];
+ pCurBuf++;
+
+ curChar = arRaw[i];
+ curChar &= 0x0F;
+
+ *pCurBuf = EncodingTable[curChar];
+ pCurBuf++;
+ }
+
+ rtl::ByteSequence ret(reinterpret_cast<sal_Int8*>(pBuf.get()), lenRaw * 2);
+ return ret;
+}
+
+rtl::ByteSequence decodeBase16(const rtl::ByteSequence& data)
+{
+ static const char decodingTable[] =
+ {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
+ sal_Int32 lenData = data.getLength();
+ sal_Int32 lenBuf = lenData / 2; //always divisible by two
+ std::unique_ptr<unsigned char[]> pBuf(new unsigned char[lenBuf]);
+ const sal_Int8* pData = data.getConstArray();
+ for (sal_Int32 i = 0; i < lenBuf; i++)
+ {
+ sal_Int8 curChar = *pData++;
+ //find the index of the first 4bits
+ // TODO What happens if text is not valid Hex characters?
+ unsigned char nibble = 0;
+ for (unsigned char j = 0; j < 16; j++)
+ {
+ if (curChar == decodingTable[j])
+ {
+ nibble = j;
+ break;
+ }
+ }
+ nibble <<= 4;
+ curChar = *pData++;
+ //find the index for the next 4bits
+ for (unsigned char j = 0; j < 16; j++)
+ {
+ if (curChar == decodingTable[j])
+ {
+ nibble |= j;
+ break;
+ }
+ }
+ pBuf[i] = nibble;
+ }
+ rtl::ByteSequence ret(reinterpret_cast<sal_Int8*>(pBuf.get()), lenBuf );
+ return ret;
+}
+
+OUString getDirFromFile(std::u16string_view usFilePath)
+{
+ size_t index = usFilePath.rfind('/');
+ return OUString(usFilePath.substr(0, index));
+}
+
+OUString getLibraryLocation()
+{
+ OUString libraryFileUrl;
+
+ if (!osl::Module::getUrlFromAddress(
+ reinterpret_cast< oslGenericFunction >(getLibraryLocation),
+ libraryFileUrl))
+ throw FrameworkException(JFW_E_ERROR,
+ "[Java framework] Error in function getLibraryLocation (fwkutil.cxx).");
+
+ return getDirFromFile(libraryFileUrl);
+}
+
+jfw::FileStatus checkFileURL(const OUString & sURL)
+{
+ jfw::FileStatus ret = jfw::FILE_OK;
+ DirectoryItem item;
+ File::RC rc_item = DirectoryItem::get(sURL, item);
+ if (File::E_None == rc_item)
+ {
+ osl::FileStatus status(osl_FileStatus_Mask_Validate);
+
+ File::RC rc_stat = item.getFileStatus(status);
+ if (File::E_None == rc_stat)
+ {
+ ret = FILE_OK;
+ }
+ else if (File::E_NOENT == rc_stat)
+ {
+ ret = FILE_DOES_NOT_EXIST;
+ }
+ else
+ {
+ ret = FILE_INVALID;
+ }
+ }
+ else if (File::E_NOENT == rc_item)
+ {
+ ret = FILE_DOES_NOT_EXIST;
+ }
+ else
+ {
+ ret = FILE_INVALID;
+ }
+ return ret;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/jvmfwk/source/javasettings.xsd b/jvmfwk/source/javasettings.xsd
new file mode 100644
index 000000000..e0ccbd47e
--- /dev/null
+++ b/jvmfwk/source/javasettings.xsd
@@ -0,0 +1,70 @@
+<?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 .
+-->
+
+<!--
+ Document : javasettings.xsd
+ Created on : 25. März 2004, 16:16
+ Author : jl97489
+ Description:
+ Purpose of XML Schema document follows.
+-->
+
+<schema targetNamespace="http://openoffice.org/2004/java/framework/1.0"
+ xmlns:jf="http://openoffice.org/2004/java/framework/1.0"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ elementFormDefault="qualified">
+
+<element name="java">
+ <complexType>
+ <sequence>
+ <element name="enabled" nillable="true" default="true" type="boolean"/>
+ <element name="userClassPath" nillable="true" type="string"/>
+ <element name="vmParameters" nillable="true" type="jf:vmParametersType"/>
+ <element name="jreLocations" nillable="true" type="jf:jreLocationsType"/>
+ <element name="javaInfo" nillable="true" type="jf:javaInfoType"/>
+ </sequence>
+ </complexType>
+
+</element>
+
+<complexType name="javaInfoType">
+ <sequence>
+ <element name="vendor" type="string"/>
+ <element name="location" type="string"/>
+ <element name="version" type="string"/>
+ <element name="features" default="0" type="unsignedLong"/>
+ <element name="requirements" default="0" type="unsignedLong"/>
+ <element name="vendorData" type="base64Binary"/>
+ </sequence>
+ <attribute name="vendorUpdate" type="date"/>
+</complexType>
+
+<complexType name="vmParametersType">
+ <sequence>
+ <element name="param" minOccurs="0" maxOccurs="unbounded" type="string"/>
+ </sequence>
+</complexType>
+
+<complexType name="jreLocationsType">
+ <sequence>
+ <element name="location" minOccurs="0" maxOccurs="unbounded" type="string"/>
+ </sequence>
+</complexType>
+
+</schema>
diff --git a/jvmfwk/source/javasettings_template.xml b/jvmfwk/source/javasettings_template.xml
new file mode 100644
index 000000000..c73404c69
--- /dev/null
+++ b/jvmfwk/source/javasettings_template.xml
@@ -0,0 +1,52 @@
+<?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 .
+-->
+
+<!--
+This file shows what elements the javasettings_platform.xml can contain.
+The children of javaInfo are only created when a JRE is selected. The children of
+vmParameters are only created when parameters are added and the children of
+jreLocations are only created when the paths are added.
+See CNodeJava::loadFromSettings and CNodeJava::writeSettings for details.
+When extending the javavendors.xml then use the schema to verify it.
+-->
+
+<java xmlns='http://openoffice.org/2004/java/framework/1.0'
+ xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
+ xsi:schemaLocation='http://openoffice.org/2004/java/framework/1.0 file:/D:/cws-jl6/jvmfwk/source/javasettings.xsd'>
+ <classesDirectory>program/classes</classesDirectory>
+ <enabled xsi:nil="true"></enabled>
+ <userClassPath xsi:nil="true"></userClassPath>
+ <vmParameters xsi:nil="true"/>
+ <!--param>-Xdebug</param-->
+ <!--</vmParameters>-->
+ <jreLocations xsi:nil="true"/>
+ <!--location></location-->
+ <!--</jreLocations>-->
+ <javaInfo xsi:nil="true"/>
+ <!--javaInfo vendorUpdate="2004-03-27" xsi:nil="false"-->
+ <!--vendor></vendor>
+ <location></location>
+ <version></version>
+ <features></features>
+ <requirements></requirements>
+ <vendorData></vendorData>
+ </javaInfo-->
+ </java>
+
+
diff --git a/jvmfwk/source/libxmlutil.cxx b/jvmfwk/source/libxmlutil.cxx
new file mode 100644
index 000000000..f83e14143
--- /dev/null
+++ b/jvmfwk/source/libxmlutil.cxx
@@ -0,0 +1,136 @@
+/* -*- 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 <libxmlutil.hxx>
+
+namespace jfw
+{
+
+CXPathObjectPtr::CXPathObjectPtr():_object(nullptr)
+{
+}
+CXPathObjectPtr::CXPathObjectPtr(xmlXPathObject* pObj):_object(pObj)
+{
+}
+CXPathObjectPtr::~CXPathObjectPtr()
+{
+ xmlXPathFreeObject(_object);
+}
+CXPathObjectPtr & CXPathObjectPtr::operator = (xmlXPathObject* pObj)
+{
+ if (_object == pObj)
+ return *this;
+
+ xmlXPathFreeObject(_object);
+ _object = pObj;
+ return *this;
+}
+
+CXPathContextPtr::CXPathContextPtr(xmlXPathContextPtr aContext)
+ : _object(aContext)
+{
+}
+
+CXPathContextPtr::CXPathContextPtr():_object(nullptr)
+{
+}
+
+CXPathContextPtr::~CXPathContextPtr()
+{
+ xmlXPathFreeContext(_object);
+}
+
+CXPathContextPtr & CXPathContextPtr::operator = (xmlXPathContextPtr pObj)
+{
+ if (_object == pObj)
+ return *this;
+ xmlXPathFreeContext(_object);
+ _object = pObj;
+ return *this;
+}
+
+
+CXmlDocPtr::CXmlDocPtr(xmlDoc* aDoc)
+ : _object(aDoc)
+{
+}
+
+CXmlDocPtr::CXmlDocPtr():_object(nullptr)
+{
+}
+
+CXmlDocPtr::~CXmlDocPtr()
+{
+ xmlFreeDoc(_object);
+}
+CXmlDocPtr & CXmlDocPtr::operator = (xmlDoc* pObj)
+{
+ if (_object == pObj)
+ return *this;
+ xmlFreeDoc(_object);
+ _object = pObj;
+ return *this;
+}
+
+
+CXmlCharPtr::CXmlCharPtr(xmlChar * aChar)
+ : _object(aChar)
+{
+}
+
+CXmlCharPtr::CXmlCharPtr(std::u16string_view s):
+ _object(nullptr)
+{
+ OString o = OUStringToOString(s, RTL_TEXTENCODING_UTF8);
+ _object = xmlCharStrdup(o.getStr());
+}
+CXmlCharPtr::CXmlCharPtr():_object(nullptr)
+{
+}
+
+CXmlCharPtr::~CXmlCharPtr()
+{
+ xmlFree(_object);
+}
+
+CXmlCharPtr & CXmlCharPtr::operator = (xmlChar* pObj)
+{
+ if (pObj == _object)
+ return *this;
+ xmlFree(_object);
+ _object = pObj;
+ return *this;
+}
+
+
+CXmlCharPtr::operator OUString()
+{
+ OUString ret;
+ if (_object != nullptr)
+ {
+ OString aOStr(reinterpret_cast<char*>(_object));
+ ret = OStringToOUString(aOStr, RTL_TEXTENCODING_UTF8);
+ }
+ return ret;
+}
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */