|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
* This file is part of libbluray
|
|
Packit |
5e46da |
* Copyright (C) 2010 William Hahne
|
|
Packit |
5e46da |
* Copyright (C) 2012 Petri Hintukainen <phintuka@users.sourceforge.net>
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is free software; you can redistribute it and/or
|
|
Packit |
5e46da |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License as published by the Free Software Foundation; either
|
|
Packit |
5e46da |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
5e46da |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
5e46da |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
5e46da |
* Lesser General Public License for more details.s
|
|
Packit |
5e46da |
*
|
|
Packit |
5e46da |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
5e46da |
* License along with this library. If not, see
|
|
Packit |
5e46da |
* <http://www.gnu.org/licenses/>.
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if HAVE_CONFIG_H
|
|
Packit |
5e46da |
#include "config.h"
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "bdj.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "native/register_native.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include "file/file.h"
|
|
Packit |
5e46da |
#include "file/dirs.h"
|
|
Packit |
5e46da |
#include "file/dl.h"
|
|
Packit |
5e46da |
#include "util/strutl.h"
|
|
Packit |
5e46da |
#include "util/macro.h"
|
|
Packit |
5e46da |
#include "util/logging.h"
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#include <jni.h>
|
|
Packit |
5e46da |
#include <stdio.h>
|
|
Packit |
5e46da |
#include <stdlib.h>
|
|
Packit |
5e46da |
#include <string.h>
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef __APPLE__
|
|
Packit |
5e46da |
#include <sys/types.h>
|
|
Packit |
5e46da |
#include <sys/wait.h>
|
|
Packit |
5e46da |
#include <limits.h>
|
|
Packit |
5e46da |
#include <unistd.h>
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef _WIN32
|
|
Packit |
5e46da |
#include <windows.h>
|
|
Packit |
5e46da |
#include <winreg.h>
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef HAVE_BDJ_J2ME
|
|
Packit |
5e46da |
#define BDJ_JARFILE "libbluray-j2me-" VERSION ".jar"
|
|
Packit |
5e46da |
#else
|
|
Packit |
5e46da |
#define BDJ_JARFILE "libbluray-j2se-" VERSION ".jar"
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
struct bdjava_s {
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
void *h_libjli;
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
void *h_libjvm;
|
|
Packit |
5e46da |
JavaVM *jvm;
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
typedef jint (JNICALL * fptr_JNI_CreateJavaVM) (JavaVM **pvm, void **penv,void *args);
|
|
Packit |
5e46da |
typedef jint (JNICALL * fptr_JNI_GetCreatedJavaVMs) (JavaVM **vmBuf, jsize bufLen, jsize *nVMs);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(_WIN32) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
static void *_load_dll(const wchar_t *lib_path, const wchar_t *dll_search_path)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
void *result;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
typedef PVOID(WINAPI *AddDllDirectoryF) (PCWSTR);
|
|
Packit |
5e46da |
typedef BOOL(WINAPI *RemoveDllDirectoryF)(PVOID);
|
|
Packit |
5e46da |
AddDllDirectoryF pAddDllDirectory;
|
|
Packit |
5e46da |
RemoveDllDirectoryF pRemoveDllDirectory;
|
|
Packit |
5e46da |
pAddDllDirectory = (AddDllDirectoryF)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "AddDllDirectory");
|
|
Packit |
5e46da |
pRemoveDllDirectory = (RemoveDllDirectoryF)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "RemoveDllDirectory");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pAddDllDirectory && pRemoveDllDirectory) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
result = LoadLibraryExW(lib_path, NULL,
|
|
Packit |
5e46da |
LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!result) {
|
|
Packit |
5e46da |
PVOID cookie = pAddDllDirectory(dll_search_path);
|
|
Packit |
5e46da |
result = LoadLibraryExW(lib_path, NULL,
|
|
Packit |
5e46da |
LOAD_LIBRARY_SEARCH_SYSTEM32 |
|
|
Packit |
5e46da |
LOAD_LIBRARY_SEARCH_USER_DIRS);
|
|
Packit |
5e46da |
pRemoveDllDirectory(cookie);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
result = LoadLibraryW(lib_path);
|
|
Packit |
5e46da |
if (!result) {
|
|
Packit |
5e46da |
SetDllDirectoryW(dll_search_path);
|
|
Packit |
5e46da |
result = LoadLibraryW(lib_path);
|
|
Packit |
5e46da |
SetDllDirectoryW(L"");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(_WIN32) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
static void *_load_jvm_win32(const char **p_java_home)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
static char java_home[256] = "";
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
wchar_t buf_loc[4096] = L"SOFTWARE\\JavaSoft\\Java Runtime Environment\\";
|
|
Packit |
5e46da |
wchar_t buf_vers[128];
|
|
Packit |
5e46da |
wchar_t java_path[4096] = L"";
|
|
Packit |
5e46da |
char strbuf[256];
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
LONG r;
|
|
Packit |
5e46da |
DWORD lType;
|
|
Packit |
5e46da |
DWORD dSize = sizeof(buf_vers);
|
|
Packit |
5e46da |
HKEY hkey;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf_loc, 0, KEY_READ, &hkey);
|
|
Packit |
5e46da |
if (r != ERROR_SUCCESS) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening registry key SOFTWARE\\JavaSoft\\Java Runtime Environment\\\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
r = RegQueryValueExW(hkey, L"CurrentVersion", NULL, &lType, (LPBYTE)buf_vers, &dSize);
|
|
Packit |
5e46da |
RegCloseKey(hkey);
|
|
Packit |
5e46da |
if (r != ERROR_SUCCESS) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "CurrentVersion registry value not found\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (debug_mask & DBG_BDJ) {
|
|
Packit |
5e46da |
if (!WideCharToMultiByte(CP_UTF8, 0, buf_vers, -1, strbuf, sizeof(strbuf), NULL, NULL)) {
|
|
Packit |
5e46da |
strbuf[0] = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "JRE version: %s\n", strbuf);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
wcscat(buf_loc, buf_vers);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dSize = sizeof(buf_loc);
|
|
Packit |
5e46da |
r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, buf_loc, 0, KEY_READ, &hkey);
|
|
Packit |
5e46da |
if (r != ERROR_SUCCESS) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error opening JRE version-specific registry key\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
r = RegQueryValueExW(hkey, L"JavaHome", NULL, &lType, (LPBYTE)buf_loc, &dSize);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (r == ERROR_SUCCESS) {
|
|
Packit |
5e46da |
/* do not fail even if not found */
|
|
Packit |
5e46da |
if (WideCharToMultiByte(CP_UTF8, 0, buf_loc, -1, java_home, sizeof(java_home), NULL, NULL)) {
|
|
Packit |
5e46da |
*p_java_home = java_home;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "JavaHome: %s\n", java_home);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
wcscat(java_path, buf_loc);
|
|
Packit |
5e46da |
wcscat(java_path, L"\\bin");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
dSize = sizeof(buf_loc);
|
|
Packit |
5e46da |
r = RegQueryValueExW(hkey, L"RuntimeLib", NULL, &lType, (LPBYTE)buf_loc, &dSize);
|
|
Packit |
5e46da |
RegCloseKey(hkey);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (r != ERROR_SUCCESS) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "RuntimeLib registry value not found\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void *result = _load_dll(buf_loc, java_path);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!WideCharToMultiByte(CP_UTF8, 0, buf_loc, -1, strbuf, sizeof(strbuf), NULL, NULL)) {
|
|
Packit |
5e46da |
strbuf[0] = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (!result) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "can't open library '%s'\n", strbuf);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Using JRE library %s\n", strbuf);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef _WIN32
|
|
Packit |
5e46da |
static inline char *_utf8_to_cp(const char *utf8)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
|
|
Packit |
5e46da |
if (wlen <= 0) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
wchar_t *wide = (wchar_t *)malloc(wlen * sizeof(wchar_t));
|
|
Packit |
5e46da |
if (!wide) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
if (!MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wide, wlen)) {
|
|
Packit |
5e46da |
X_FREE(wide);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
size_t len = WideCharToMultiByte(CP_ACP, 0, wide, -1, NULL, 0, NULL, NULL);
|
|
Packit |
5e46da |
if (len <= 0) {
|
|
Packit |
5e46da |
X_FREE(wide);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
char *out = (char *)malloc(len);
|
|
Packit |
5e46da |
if (out != NULL) {
|
|
Packit |
5e46da |
if (!WideCharToMultiByte(CP_ACP, 0, wide, -1, out, len, NULL, NULL)) {
|
|
Packit |
5e46da |
X_FREE(out);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(wide);
|
|
Packit |
5e46da |
return out;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef __APPLE__
|
|
Packit |
5e46da |
// The current official JRE is installed by Oracle's Java Applet internet plugin:
|
|
Packit |
5e46da |
#define MACOS_JRE_HOME "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home"
|
|
Packit |
5e46da |
static const char *jre_plugin_path = MACOS_JRE_HOME;
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#define MACOS_JAVA_HOME "/usr/libexec/java_home"
|
|
Packit |
5e46da |
static char *_java_home_macos()
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
static char result[PATH_MAX] = "";
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (result[0])
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
pid_t java_home_pid;
|
|
Packit |
5e46da |
int fd[2], exitcode;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (pipe(fd)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "unable to set up pipes\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
switch (java_home_pid = vfork())
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
case -1:
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "vfork failed\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
case 0:
|
|
Packit |
5e46da |
if (dup2(fd[1], STDOUT_FILENO) == -1) {
|
|
Packit |
5e46da |
_exit(-1);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
close(fd[1]);
|
|
Packit |
5e46da |
close(fd[0]);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
execl(MACOS_JAVA_HOME, MACOS_JAVA_HOME);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
_exit(-1);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
default:
|
|
Packit |
5e46da |
close(fd[1]);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (int len = 0; ;) {
|
|
Packit |
5e46da |
int n = read(fd[0], result + len, sizeof result - len);
|
|
Packit |
5e46da |
if (n <= 0)
|
|
Packit |
5e46da |
break;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
len += n;
|
|
Packit |
5e46da |
result[len-1] = '\0';
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
waitpid(java_home_pid, &exitcode, 0);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (result[0] == '\0' || exitcode) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT,
|
|
Packit |
5e46da |
"Unable to read path from " MACOS_JAVA_HOME "\n");
|
|
Packit |
5e46da |
result[0] = '\0';
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "macos java home: '%s'\n", result );
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#undef MACOS_JAVA_HOME
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void *_jvm_dlopen(const char *java_home, const char *jvm_dir, const char *jvm_lib)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (java_home) {
|
|
Packit |
5e46da |
char *path = str_printf("%s" DIR_SEP "%s" DIR_SEP "%s", java_home, jvm_dir, jvm_lib);
|
|
Packit |
5e46da |
if (!path) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Opening %s ...\n", path);
|
|
Packit |
5e46da |
void *h = dl_dlopen(path, NULL);
|
|
Packit |
5e46da |
X_FREE(path);
|
|
Packit |
5e46da |
return h;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Opening %s ...\n", jvm_lib);
|
|
Packit |
5e46da |
return dl_dlopen(jvm_lib, NULL);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void *_jvm_dlopen_a(const char *java_home,
|
|
Packit |
5e46da |
const char * const *jvm_dir, unsigned num_jvm_dir,
|
|
Packit |
5e46da |
const char *jvm_lib)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
unsigned ii;
|
|
Packit |
5e46da |
void *dll = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
for (ii = 0; !dll && ii < num_jvm_dir; ii++) {
|
|
Packit |
5e46da |
dll = _jvm_dlopen(java_home, jvm_dir[ii], jvm_lib);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return dll;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
static void *_load_jli_macos()
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
const char *java_home = NULL;
|
|
Packit |
5e46da |
static const char jli_dir[] = "jre/lib/jli";
|
|
Packit |
5e46da |
static const char jli_lib[] = "libjli";
|
|
Packit |
5e46da |
void *handle;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* JAVA_HOME set, use it */
|
|
Packit |
5e46da |
java_home = getenv("JAVA_HOME");
|
|
Packit |
5e46da |
if (java_home) {
|
|
Packit |
5e46da |
return _jvm_dlopen(java_home, jli_dir, jli_lib);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
java_home = _java_home_macos();
|
|
Packit |
5e46da |
if (java_home) {
|
|
Packit |
5e46da |
handle = _jvm_dlopen(java_home, jli_dir, jli_lib);
|
|
Packit |
5e46da |
if (handle) {
|
|
Packit |
5e46da |
return handle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
// check if the JRE is installed:
|
|
Packit |
5e46da |
return _jvm_dlopen(jre_plugin_path, "lib/jli", jli_lib);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static void *_load_jvm(const char **p_java_home)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
#ifdef HAVE_BDJ_J2ME
|
|
Packit |
5e46da |
# ifdef _WIN32
|
|
Packit |
5e46da |
static const char * const jvm_path[] = {NULL, JDK_HOME};
|
|
Packit |
5e46da |
static const char * const jvm_dir[] = {"bin"};
|
|
Packit |
5e46da |
static const char jvm_lib[] = "cvmi";
|
|
Packit |
5e46da |
# else
|
|
Packit |
5e46da |
static const char * const jvm_path[] = {NULL, JDK_HOME, "/opt/PhoneME"};
|
|
Packit |
5e46da |
static const char * const jvm_dir[] = {"bin"};
|
|
Packit |
5e46da |
static const char jvm_lib[] = "libcvm";
|
|
Packit |
5e46da |
# endif
|
|
Packit |
5e46da |
#else /* HAVE_BDJ_J2ME */
|
|
Packit |
5e46da |
# ifdef _WIN32
|
|
Packit |
5e46da |
static const char * const jvm_path[] = {NULL, JDK_HOME};
|
|
Packit |
5e46da |
static const char * const jvm_dir[] = {"jre\\bin\\server",
|
|
Packit |
5e46da |
"bin\\server",
|
|
Packit |
5e46da |
"jre\\bin\\client",
|
|
Packit |
5e46da |
"bin\\client",
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
static const char jvm_lib[] = "jvm";
|
|
Packit |
5e46da |
# else
|
|
Packit |
5e46da |
# ifdef __APPLE__
|
|
Packit |
5e46da |
static const char * const jvm_path[] = {NULL, JDK_HOME, MACOS_JRE_HOME};
|
|
Packit |
5e46da |
static const char * const jvm_dir[] = {"jre/lib/server",
|
|
Packit |
5e46da |
"lib/server"};
|
|
Packit |
5e46da |
# else
|
|
Packit |
5e46da |
static const char * const jvm_path[] = {NULL,
|
|
Packit |
5e46da |
JDK_HOME,
|
|
Packit |
5e46da |
"/usr/lib/jvm/default-java",
|
|
Packit |
5e46da |
"/usr/lib/jvm/default",
|
|
Packit |
5e46da |
"/usr/lib/jvm/",
|
|
Packit |
5e46da |
"/etc/java-config-2/current-system-vm",
|
|
Packit |
5e46da |
"/usr/lib/jvm/java-7-openjdk",
|
|
Packit |
5e46da |
"/usr/lib/jvm/java-8-openjdk",
|
|
Packit |
5e46da |
"/usr/lib/jvm/java-6-openjdk",
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
static const char * const jvm_dir[] = {"jre/lib/" JAVA_ARCH "/server"};
|
|
Packit |
5e46da |
# endif
|
|
Packit |
5e46da |
static const char jvm_lib[] = "libjvm";
|
|
Packit |
5e46da |
# endif
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
const unsigned num_jvm_dir = sizeof(jvm_dir) / sizeof(jvm_dir[0]);
|
|
Packit |
5e46da |
const unsigned num_jvm_path = sizeof(jvm_path) / sizeof(jvm_path[0]);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
const char *java_home = NULL;
|
|
Packit |
5e46da |
unsigned path_ind;
|
|
Packit |
5e46da |
void *handle = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* JAVA_HOME set, use it */
|
|
Packit |
5e46da |
java_home = getenv("JAVA_HOME");
|
|
Packit |
5e46da |
if (java_home) {
|
|
Packit |
5e46da |
*p_java_home = java_home;
|
|
Packit |
5e46da |
return _jvm_dlopen_a(java_home, jvm_dir, num_jvm_dir, jvm_lib);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(_WIN32) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
handle = _load_jvm_win32(p_java_home);
|
|
Packit |
5e46da |
if (handle) {
|
|
Packit |
5e46da |
return handle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
java_home = _java_home_macos();
|
|
Packit |
5e46da |
if (java_home) {
|
|
Packit |
5e46da |
handle = _jvm_dlopen_a(java_home, jvm_dir, num_jvm_dir, jvm_lib);
|
|
Packit |
5e46da |
if (handle) {
|
|
Packit |
5e46da |
*p_java_home = java_home;
|
|
Packit |
5e46da |
return handle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
// check if the JRE is installed:
|
|
Packit |
5e46da |
handle = _jvm_dlopen(jre_plugin_path, "lib/server", jvm_lib);
|
|
Packit |
5e46da |
if (handle) {
|
|
Packit |
5e46da |
*p_java_home = jre_plugin_path;
|
|
Packit |
5e46da |
return handle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "JAVA_HOME not set, trying default locations\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* try our pre-defined locations */
|
|
Packit |
5e46da |
for (path_ind = 0; !handle && path_ind < num_jvm_path; path_ind++) {
|
|
Packit |
5e46da |
*p_java_home = jvm_path[path_ind];
|
|
Packit |
5e46da |
handle = _jvm_dlopen_a(jvm_path[path_ind], jvm_dir, num_jvm_dir, jvm_lib);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!*p_java_home) {
|
|
Packit |
5e46da |
*p_java_home = dl_get_path();
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return handle;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _can_read_file(const char *fn)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_FILE_H *fp;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!fn) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
fp = file_open(fn, "rb");
|
|
Packit |
5e46da |
if (fp) {
|
|
Packit |
5e46da |
uint8_t b;
|
|
Packit |
5e46da |
int result = (int)file_read(fp, &b, 1);
|
|
Packit |
5e46da |
file_close(fp);
|
|
Packit |
5e46da |
if (result == 1) {
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Error reading %s\n", fn);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void bdj_storage_cleanup(BDJ_STORAGE *p)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
X_FREE(p->cache_root);
|
|
Packit |
5e46da |
X_FREE(p->persistent_root);
|
|
Packit |
5e46da |
X_FREE(p->classpath);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static const char *_find_libbluray_jar(BDJ_STORAGE *storage)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
// pre-defined search paths for libbluray.jar
|
|
Packit |
5e46da |
static const char * const jar_paths[] = {
|
|
Packit |
5e46da |
#ifndef _WIN32
|
|
Packit |
5e46da |
"/usr/share/java/" BDJ_JARFILE,
|
|
Packit |
5e46da |
"/usr/share/libbluray/lib/" BDJ_JARFILE,
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
BDJ_JARFILE,
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
unsigned i;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (storage->classpath) {
|
|
Packit |
5e46da |
return storage->classpath;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// check if overriding the classpath
|
|
Packit |
5e46da |
const char *classpath = getenv("LIBBLURAY_CP");
|
|
Packit |
5e46da |
if (classpath) {
|
|
Packit |
5e46da |
size_t cp_len = strlen(classpath);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// directory or file ?
|
|
Packit |
5e46da |
if (cp_len > 0 && (classpath[cp_len - 1] == '/' || classpath[cp_len - 1] == '\\')) {
|
|
Packit |
5e46da |
storage->classpath = str_printf("%s%s", classpath, BDJ_JARFILE);
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
storage->classpath = str_dup(classpath);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!storage->classpath) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_can_read_file(storage->classpath)) {
|
|
Packit |
5e46da |
return storage->classpath;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(storage->classpath);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "invalid LIBBLURAY_CP %s\n", classpath);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "LIBBLURAY_CP not set, searching for "BDJ_JARFILE" ...\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// check directory where libbluray.so was loaded from
|
|
Packit |
5e46da |
const char *lib_path = dl_get_path();
|
|
Packit |
5e46da |
if (lib_path) {
|
|
Packit |
5e46da |
char *cp = str_printf("%s" BDJ_JARFILE, lib_path);
|
|
Packit |
5e46da |
if (!cp) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Checking %s ...\n", cp);
|
|
Packit |
5e46da |
if (_can_read_file(cp)) {
|
|
Packit |
5e46da |
storage->classpath = cp;
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "using %s\n", cp);
|
|
Packit |
5e46da |
return cp;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(cp);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// check pre-defined directories
|
|
Packit |
5e46da |
for (i = 0; i < sizeof(jar_paths) / sizeof(jar_paths[0]); i++) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Checking %s ...\n", jar_paths[i]);
|
|
Packit |
5e46da |
if (_can_read_file(jar_paths[i])) {
|
|
Packit |
5e46da |
storage->classpath = str_dup(jar_paths[i]);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "using %s\n", storage->classpath);
|
|
Packit |
5e46da |
return storage->classpath;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, BDJ_JARFILE" not found.\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static const char *_bdj_persistent_root(BDJ_STORAGE *storage)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
const char *root;
|
|
Packit |
5e46da |
char *data_home;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (storage->no_persistent_storage) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!storage->persistent_root) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
root = getenv("LIBBLURAY_PERSISTENT_ROOT");
|
|
Packit |
5e46da |
if (root) {
|
|
Packit |
5e46da |
return root;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
data_home = file_get_data_home();
|
|
Packit |
5e46da |
if (data_home) {
|
|
Packit |
5e46da |
storage->persistent_root = str_printf("%s" DIR_SEP "bluray" DIR_SEP "dvb.persistent.root" DIR_SEP, data_home);
|
|
Packit |
5e46da |
X_FREE(data_home);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "LIBBLURAY_PERSISTENT_ROOT not set, using %s\n", storage->persistent_root);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!storage->persistent_root) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "WARNING: BD-J persistent root not set\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return storage->persistent_root;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static const char *_bdj_buda_root(BDJ_STORAGE *storage)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
const char *root;
|
|
Packit |
5e46da |
char *cache_home;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (storage->no_persistent_storage) {
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!storage->cache_root) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
root = getenv("LIBBLURAY_CACHE_ROOT");
|
|
Packit |
5e46da |
if (root) {
|
|
Packit |
5e46da |
return root;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
cache_home = file_get_cache_home();
|
|
Packit |
5e46da |
if (cache_home) {
|
|
Packit |
5e46da |
storage->cache_root = str_printf("%s" DIR_SEP "bluray" DIR_SEP "bluray.bindingunit.root" DIR_SEP, cache_home);
|
|
Packit |
5e46da |
X_FREE(cache_home);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "LIBBLURAY_CACHE_ROOT not set, using %s\n", storage->cache_root);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!storage->cache_root) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "WARNING: BD-J cache root not set\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return storage->cache_root;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _get_method(JNIEnv *env, jclass *cls, jmethodID *method_id,
|
|
Packit |
5e46da |
const char *class_name, const char *method_name, const char *method_sig)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
*method_id = NULL;
|
|
Packit |
5e46da |
*cls = (*env)->FindClass(env, class_name);
|
|
Packit |
5e46da |
if (!*cls) {
|
|
Packit |
5e46da |
(*env)->ExceptionDescribe(env);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to locate class %s\n", class_name);
|
|
Packit |
5e46da |
(*env)->ExceptionClear(env);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*method_id = (*env)->GetStaticMethodID(env, *cls, method_name, method_sig);
|
|
Packit |
5e46da |
if (!*method_id) {
|
|
Packit |
5e46da |
(*env)->ExceptionDescribe(env);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to locate class %s method %s %s\n",
|
|
Packit |
5e46da |
class_name, method_name, method_sig);
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, *cls);
|
|
Packit |
5e46da |
*cls = NULL;
|
|
Packit |
5e46da |
(*env)->ExceptionClear(env);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _bdj_init(JNIEnv *env, struct bluray *bd, const char *disc_root, const char *bdj_disc_id,
|
|
Packit |
5e46da |
BDJ_STORAGE *storage)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
if (!bdj_register_native_methods(env)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Couldn't register native methods.\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// initialize class org.videolan.Libbluray
|
|
Packit |
5e46da |
jclass init_class;
|
|
Packit |
5e46da |
jmethodID init_id;
|
|
Packit |
5e46da |
if (!_get_method(env, &init_class, &init_id,
|
|
Packit |
5e46da |
"org/videolan/Libbluray", "init",
|
|
Packit |
5e46da |
"(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) {
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
const char *disc_id = (bdj_disc_id && bdj_disc_id[0]) ? bdj_disc_id : "00000000000000000000000000000000";
|
|
Packit |
5e46da |
jlong param_bdjava_ptr = (jlong)(intptr_t) bd;
|
|
Packit |
5e46da |
jstring param_disc_id = (*env)->NewStringUTF(env, disc_id);
|
|
Packit |
5e46da |
jstring param_disc_root = (*env)->NewStringUTF(env, disc_root);
|
|
Packit |
5e46da |
jstring param_persistent_root = (*env)->NewStringUTF(env, _bdj_persistent_root(storage));
|
|
Packit |
5e46da |
jstring param_buda_root = (*env)->NewStringUTF(env, _bdj_buda_root(storage));
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
(*env)->CallStaticVoidMethod(env, init_class, init_id,
|
|
Packit |
5e46da |
param_bdjava_ptr, param_disc_id, param_disc_root,
|
|
Packit |
5e46da |
param_persistent_root, param_buda_root);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, init_class);
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, param_disc_id);
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, param_disc_root);
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, param_persistent_root);
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, param_buda_root);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((*env)->ExceptionOccurred(env)) {
|
|
Packit |
5e46da |
(*env)->ExceptionDescribe(env);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to initialize BD-J (uncaught exception)\n");
|
|
Packit |
5e46da |
(*env)->ExceptionClear(env);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int bdj_jvm_available(BDJ_STORAGE *storage)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
const char *java_home;
|
|
Packit |
5e46da |
void* jvm_lib = _load_jvm(&java_home);
|
|
Packit |
5e46da |
if (!jvm_lib) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "BD-J check: Failed to load JVM library\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
dl_dlclose(jvm_lib);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!_find_libbluray_jar(storage)) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "BD-J check: Failed to load libbluray.jar\n");
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "BD-J check: OK\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 2;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _find_jvm(void *jvm_lib, JNIEnv **env, JavaVM **jvm)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
fptr_JNI_GetCreatedJavaVMs JNI_GetCreatedJavaVMs_fp;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*(void **)(&JNI_GetCreatedJavaVMs_fp) = dl_dlsym(jvm_lib, "JNI_GetCreatedJavaVMs");
|
|
Packit |
5e46da |
if (JNI_GetCreatedJavaVMs_fp == NULL) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Couldn't find symbol JNI_GetCreatedJavaVMs.\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
jsize nVMs = 0;
|
|
Packit |
5e46da |
JavaVM* javavm = NULL;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int result = JNI_GetCreatedJavaVMs_fp(&javavm, 1, &nVMs);
|
|
Packit |
5e46da |
if (result == JNI_OK && nVMs > 0) {
|
|
Packit |
5e46da |
*jvm = javavm;
|
|
Packit |
5e46da |
(**jvm)->AttachCurrentThread(*jvm, (void**)env, NULL);
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
static int _create_jvm(void *jvm_lib, const char *java_home, const char *jar_file,
|
|
Packit |
5e46da |
JNIEnv **env, JavaVM **jvm)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
(void)java_home; /* used only with J2ME */
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
fptr_JNI_CreateJavaVM JNI_CreateJavaVM_fp;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
*(void **)(&JNI_CreateJavaVM_fp) = dl_dlsym(jvm_lib, "JNI_CreateJavaVM");
|
|
Packit |
5e46da |
if (JNI_CreateJavaVM_fp == NULL) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Couldn't find symbol JNI_CreateJavaVM.\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
JavaVMOption* option = calloc(1, sizeof(JavaVMOption) * 20);
|
|
Packit |
5e46da |
if (!option) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_CRIT, "out of memory\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int n = 0;
|
|
Packit |
5e46da |
JavaVMInitArgs args;
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-Dawt.toolkit=java.awt.BDToolkit");
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-Djava.awt.graphicsenv=java.awt.BDGraphicsEnvironment");
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-Djavax.accessibility.assistive_technologies= ");
|
|
Packit |
5e46da |
option[n++].optionString = str_printf("-Xbootclasspath/p:%s", jar_file);
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-Xms256M");
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-Xmx256M");
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-Xss2048k");
|
|
Packit |
5e46da |
#ifdef HAVE_BDJ_J2ME
|
|
Packit |
5e46da |
option[n++].optionString = str_printf("-Djava.home=%s", java_home);
|
|
Packit |
5e46da |
option[n++].optionString = str_printf("-Xbootclasspath/a:%s/lib/xmlparser.jar", java_home);
|
|
Packit |
5e46da |
option[n++].optionString = str_dup ("-XfullShutdown");
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* JVM debug options */
|
|
Packit |
5e46da |
if (getenv("BDJ_JVM_DEBUG")) {
|
|
Packit |
5e46da |
option[n++].optionString = str_dup("-ea");
|
|
Packit |
5e46da |
//option[n++].optionString = str_dup("-verbose");
|
|
Packit |
5e46da |
//option[n++].optionString = str_dup("-verbose:class,gc,jni");
|
|
Packit |
5e46da |
option[n++].optionString = str_dup("-Xdebug");
|
|
Packit |
5e46da |
option[n++].optionString = str_dup("-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef HAVE_BDJ_J2ME
|
|
Packit |
5e46da |
/*
|
|
Packit |
5e46da |
see: http://docs.oracle.com/javame/config/cdc/cdc-opt-impl/ojmeec/1.0/runtime/html/cvm.htm#CACBHBJB
|
|
Packit |
5e46da |
trace method execution: BDJ_JVM_TRACE=0x0002
|
|
Packit |
5e46da |
trace exceptions: BDJ_JVM_TRACE=0x4000
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
if (getenv("BDJ_JVM_TRACE")) {
|
|
Packit |
5e46da |
option[n++].optionString = str_printf("-Xtrace:%s", getenv("BDJ_JVM_TRACE"));
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
args.version = JNI_VERSION_1_4;
|
|
Packit |
5e46da |
args.nOptions = n;
|
|
Packit |
5e46da |
args.options = option;
|
|
Packit |
5e46da |
args.ignoreUnrecognized = JNI_FALSE; // don't ignore unrecognized options
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#ifdef _WIN32
|
|
Packit |
5e46da |
/* ... in windows, JVM options are not UTF8 but current system code page ... */
|
|
Packit |
5e46da |
/* luckily, most BD-J options can be passed in as java strings later. But, not class path. */
|
|
Packit |
5e46da |
int ii;
|
|
Packit |
5e46da |
for (ii = 0; ii < n; ii++) {
|
|
Packit |
5e46da |
char *tmp = _utf8_to_cp(option[ii].optionString);
|
|
Packit |
5e46da |
if (tmp) {
|
|
Packit |
5e46da |
X_FREE(option[ii].optionString);
|
|
Packit |
5e46da |
option[ii].optionString = tmp;
|
|
Packit |
5e46da |
} else {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to convert %s\n", option[ii].optionString);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int result = JNI_CreateJavaVM_fp(jvm, (void**) env, &args);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
while (--n >= 0) {
|
|
Packit |
5e46da |
X_FREE(option[n].optionString);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
X_FREE(option);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (result != JNI_OK || !*env) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to create new Java VM. JNI_CreateJavaVM result: %d\n", result);
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDJAVA* bdj_open(const char *path, struct bluray *bd,
|
|
Packit |
5e46da |
const char *bdj_disc_id, BDJ_STORAGE *storage)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "bdj_open()\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
const char *jar_file = _find_libbluray_jar(storage);
|
|
Packit |
5e46da |
if (!jar_file) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "BD-J start failed: " BDJ_JARFILE " not found.\n");
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
/* On macOS we need to load libjli to workaround a bug where the wrong
|
|
Packit |
5e46da |
* version would be used: https://bugs.openjdk.java.net/browse/JDK-7131356
|
|
Packit |
5e46da |
*/
|
|
Packit |
5e46da |
void* jli_lib = _load_jli_macos();
|
|
Packit |
5e46da |
if (!jli_lib) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Wasn't able to load JLI\n");
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
// first load the jvm using dlopen
|
|
Packit |
5e46da |
const char *java_home = NULL;
|
|
Packit |
5e46da |
void* jvm_lib = _load_jvm(&java_home);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!jvm_lib) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Wasn't able to load JVM\n");
|
|
Packit |
5e46da |
return 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BDJAVA* bdjava = calloc(1, sizeof(BDJAVA));
|
|
Packit |
5e46da |
if (!bdjava) {
|
|
Packit |
5e46da |
dl_dlclose(jvm_lib);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
JNIEnv* env = NULL;
|
|
Packit |
5e46da |
JavaVM *jvm = NULL;
|
|
Packit |
5e46da |
if (!_find_jvm(jvm_lib, &env, &jvm) &&
|
|
Packit |
5e46da |
!_create_jvm(jvm_lib, java_home, jar_file, &env, &jvm)) {
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(bdjava);
|
|
Packit |
5e46da |
dl_dlclose(jvm_lib);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
bdjava->h_libjli = jli_lib;
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
bdjava->h_libjvm = jvm_lib;
|
|
Packit |
5e46da |
bdjava->jvm = jvm;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (debug_mask & DBG_JNI) {
|
|
Packit |
5e46da |
int version = (int)(*env)->GetVersion(env);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "Java version: %d.%d\n", version >> 16, version & 0xffff);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!_bdj_init(env, bd, path, bdj_disc_id, storage)) {
|
|
Packit |
5e46da |
bdj_close(bdjava);
|
|
Packit |
5e46da |
return NULL;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* detach java main thread (CreateJavaVM attachs calling thread to JVM) */
|
|
Packit |
5e46da |
(*bdjava->jvm)->DetachCurrentThread(bdjava->jvm);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return bdjava;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
void bdj_close(BDJAVA *bdjava)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
JNIEnv *env;
|
|
Packit |
5e46da |
int attach = 0;
|
|
Packit |
5e46da |
jclass shutdown_class;
|
|
Packit |
5e46da |
jmethodID shutdown_id;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bdjava) {
|
|
Packit |
5e46da |
return;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "bdj_close()\n");
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bdjava->jvm) {
|
|
Packit |
5e46da |
if ((*bdjava->jvm)->GetEnv(bdjava->jvm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) {
|
|
Packit |
5e46da |
(*bdjava->jvm)->AttachCurrentThread(bdjava->jvm, (void**)&env, NULL);
|
|
Packit |
5e46da |
attach = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_get_method(env, &shutdown_class, &shutdown_id,
|
|
Packit |
5e46da |
"org/videolan/Libbluray", "shutdown", "()V")) {
|
|
Packit |
5e46da |
(*env)->CallStaticVoidMethod(env, shutdown_class, shutdown_id);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((*env)->ExceptionOccurred(env)) {
|
|
Packit |
5e46da |
(*env)->ExceptionDescribe(env);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "Failed to shutdown BD-J (uncaught exception)\n");
|
|
Packit |
5e46da |
(*env)->ExceptionClear(env);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, shutdown_class);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
bdj_unregister_native_methods(env);
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (attach) {
|
|
Packit |
5e46da |
(*bdjava->jvm)->DetachCurrentThread(bdjava->jvm);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (bdjava->h_libjvm) {
|
|
Packit |
5e46da |
dl_dlclose(bdjava->h_libjvm);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
#if defined(__APPLE__) && !defined(HAVE_BDJ_J2ME)
|
|
Packit |
5e46da |
if (bdjava->h_libjli) {
|
|
Packit |
5e46da |
dl_dlclose(bdjava->h_libjli);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
#endif
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
X_FREE(bdjava);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
int bdj_process_event(BDJAVA *bdjava, unsigned ev, unsigned param)
|
|
Packit |
5e46da |
{
|
|
Packit |
5e46da |
static const char * const ev_name[] = {
|
|
Packit |
5e46da |
/* 0 */ "NONE",
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* 1 */ "START",
|
|
Packit |
5e46da |
/* 2 */ "STOP",
|
|
Packit |
5e46da |
/* 3 */ "PSR102",
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* 4 */ "PLAYLIST",
|
|
Packit |
5e46da |
/* 5 */ "PLAYITEM",
|
|
Packit |
5e46da |
/* 6 */ "CHAPTER",
|
|
Packit |
5e46da |
/* 7 */ "MARK",
|
|
Packit |
5e46da |
/* 8 */ "PTS",
|
|
Packit |
5e46da |
/* 9 */ "END_OF_PLAYLIST",
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* 10 */ "SEEK",
|
|
Packit |
5e46da |
/* 11 */ "RATE",
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* 12 */ "ANGLE",
|
|
Packit |
5e46da |
/* 13 */ "AUDIO_STREAM",
|
|
Packit |
5e46da |
/* 14 */ "SUBTITLE",
|
|
Packit |
5e46da |
/* 15 */ "SECONDARY_STREAM",
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
/* 16 */ "VK_KEY",
|
|
Packit |
5e46da |
/* 17 */ "UO_MASKED",
|
|
Packit |
5e46da |
/* 18 */ "MOUSE",
|
|
Packit |
5e46da |
};
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
JNIEnv* env;
|
|
Packit |
5e46da |
int attach = 0;
|
|
Packit |
5e46da |
jclass event_class;
|
|
Packit |
5e46da |
jmethodID event_id;
|
|
Packit |
5e46da |
int result = -1;
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (!bdjava) {
|
|
Packit |
5e46da |
return -1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (ev > BDJ_EVENT_LAST) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "bdj_process_event(%d,%d): unknown event\n", ev, param);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
// Disable too verbose logging (PTS)
|
|
Packit |
5e46da |
else if (ev != BDJ_EVENT_PTS) {
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ, "bdj_process_event(%s,%d)\n", ev_name[ev], param);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((*bdjava->jvm)->GetEnv(bdjava->jvm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) {
|
|
Packit |
5e46da |
(*bdjava->jvm)->AttachCurrentThread(bdjava->jvm, (void**)&env, NULL);
|
|
Packit |
5e46da |
attach = 1;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (_get_method(env, &event_class, &event_id,
|
|
Packit |
5e46da |
"org/videolan/Libbluray", "processEvent", "(II)Z")) {
|
|
Packit |
5e46da |
if ((*env)->CallStaticBooleanMethod(env, event_class, event_id, (jint)ev, (jint)param)) {
|
|
Packit |
5e46da |
result = 0;
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if ((*env)->ExceptionOccurred(env)) {
|
|
Packit |
5e46da |
(*env)->ExceptionDescribe(env);
|
|
Packit |
5e46da |
BD_DEBUG(DBG_BDJ | DBG_CRIT, "bdj_process_event(%u,%u) failed (uncaught exception)\n", ev, param);
|
|
Packit |
5e46da |
(*env)->ExceptionClear(env);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
(*env)->DeleteLocalRef(env, event_class);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
if (attach) {
|
|
Packit |
5e46da |
(*bdjava->jvm)->DetachCurrentThread(bdjava->jvm);
|
|
Packit |
5e46da |
}
|
|
Packit |
5e46da |
|
|
Packit |
5e46da |
return result;
|
|
Packit |
5e46da |
}
|