summaryrefslogtreecommitdiffstats
path: root/jvmfwk/plugins/sunmajor
diff options
context:
space:
mode:
Diffstat (limited to '')
-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
17 files changed, 3709 insertions, 0 deletions
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: */