diff options
Diffstat (limited to 'engine/src/desktop/com/jme3/system/Natives.java')
-rw-r--r-- | engine/src/desktop/com/jme3/system/Natives.java | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/engine/src/desktop/com/jme3/system/Natives.java b/engine/src/desktop/com/jme3/system/Natives.java new file mode 100644 index 0000000..979c606 --- /dev/null +++ b/engine/src/desktop/com/jme3/system/Natives.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jme3.system; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Helper class for extracting the natives (dll, so) from the jars. + * This class should only be used internally. + */ +public final class Natives { + + private static final Logger logger = Logger.getLogger(Natives.class.getName()); + private static final byte[] buf = new byte[1024]; + private static File extractionDirOverride = null; + private static File extractionDir = null; + + public static void setExtractionDir(String name) { + extractionDirOverride = new File(name).getAbsoluteFile(); + } + + public static File getExtractionDir() { + if (extractionDirOverride != null) { + return extractionDirOverride; + } + if (extractionDir == null) { + File workingFolder = new File("").getAbsoluteFile(); + if (!workingFolder.canWrite()) { + setStorageExtractionDir(); + } else { + try { + File file = new File(workingFolder.getAbsolutePath() + File.separator + ".jmetestwrite"); + file.createNewFile(); + file.delete(); + extractionDir = workingFolder; + } catch (Exception e) { + setStorageExtractionDir(); + } + } + } + return extractionDir; + } + + private static void setStorageExtractionDir() { + logger.log(Level.WARNING, "Working directory is not writable. Using home directory instead."); + extractionDir = new File(JmeSystem.getStorageFolder(), + "natives_" + Integer.toHexString(computeNativesHash())); + if (!extractionDir.exists()) { + extractionDir.mkdir(); + } + } + + private static int computeNativesHash() { + try { + String classpath = System.getProperty("java.class.path"); + URL url = Thread.currentThread().getContextClassLoader().getResource("com/jme3/system/Natives.class"); + + StringBuilder sb = new StringBuilder(url.toString()); + if (sb.indexOf("jar:") == 0) { + sb.delete(0, 4); + sb.delete(sb.indexOf("!"), sb.length()); + sb.delete(sb.lastIndexOf("/") + 1, sb.length()); + } + try { + url = new URL(sb.toString()); + } catch (MalformedURLException ex) { + throw new UnsupportedOperationException(ex); + } + + URLConnection conn = url.openConnection(); + int hash = classpath.hashCode() ^ (int) conn.getLastModified(); + return hash; + } catch (IOException ex) { + throw new UnsupportedOperationException(ex); + } + } + + public static void extractNativeLib(String sysName, String name) throws IOException { + extractNativeLib(sysName, name, false, true); + } + + public static void extractNativeLib(String sysName, String name, boolean load) throws IOException { + extractNativeLib(sysName, name, load, true); + } + + public static void extractNativeLib(String sysName, String name, boolean load, boolean warning) throws IOException { + String fullname = System.mapLibraryName(name); + + String path = "native/" + sysName + "/" + fullname; + URL url = Thread.currentThread().getContextClassLoader().getResource(path); + + if (url == null) { + if (!warning) { + logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}", + new String[]{sysName, fullname}); + } + return; + } + + URLConnection conn = url.openConnection(); + InputStream in = conn.getInputStream(); + File targetFile = new File(getExtractionDir(), fullname); + OutputStream out = null; + try { + if (targetFile.exists()) { + // OK, compare last modified date of this file to + // file in jar + long targetLastModified = targetFile.lastModified(); + long sourceLastModified = conn.getLastModified(); + + // Allow ~1 second range for OSes that only support low precision + if (targetLastModified + 1000 > sourceLastModified) { + logger.log(Level.FINE, "Not copying library {0}. Latest already extracted.", fullname); + return; + } + } + + out = new FileOutputStream(targetFile); + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + in = null; + out.close(); + out = null; + + // NOTE: On OSes that support "Date Created" property, + // this will cause the last modified date to be lower than + // date created which makes no sense + targetFile.setLastModified(conn.getLastModified()); + } catch (FileNotFoundException ex) { + if (ex.getMessage().contains("used by another process")) { + return; + } + + throw ex; + } finally { + if (load) { + System.load(targetFile.getAbsolutePath()); + } + if(in != null){ + in.close(); + } + if(out != null){ + out.close(); + } + } + logger.log(Level.FINE, "Copied {0} to {1}", new Object[]{fullname, targetFile}); + } + + protected static boolean isUsingNativeBullet() { + try { + Class clazz = Class.forName("com.jme3.bullet.util.NativeMeshUtil"); + return clazz != null; + } catch (ClassNotFoundException ex) { + return false; + } + } + + public static void extractNativeLibs(Platform platform, AppSettings settings) throws IOException { + String renderer = settings.getRenderer(); + String audioRenderer = settings.getAudioRenderer(); + boolean needLWJGL = false; + boolean needOAL = false; + boolean needJInput = false; + boolean needNativeBullet = isUsingNativeBullet(); + + if (renderer != null) { + if (renderer.startsWith("LWJGL")) { + needLWJGL = true; + } + } + if (audioRenderer != null) { + if (audioRenderer.equals("LWJGL")) { + needLWJGL = true; + needOAL = true; + } + } + needJInput = settings.useJoysticks(); + + String libraryPath = getExtractionDir().toString(); + if (needLWJGL) { + logger.log(Level.INFO, "Extraction Directory: {0}", getExtractionDir().toString()); + + // LWJGL supports this feature where + // it can load libraries from this path. + System.setProperty("org.lwjgl.librarypath", libraryPath); + } + if (needJInput) { + // AND Luckily enough JInput supports the same feature. + System.setProperty("net.java.games.input.librarypath", libraryPath); + } + + switch (platform) { + case Windows64: + if (needLWJGL) { + extractNativeLib("windows", "lwjgl64"); + } + if (needOAL) { + extractNativeLib("windows", "OpenAL64"); + } + if (needJInput) { + extractNativeLib("windows", "jinput-dx8_64"); + extractNativeLib("windows", "jinput-raw_64"); + } + if (needNativeBullet) { + extractNativeLib("windows", "bulletjme64", true, false); + } + break; + case Windows32: + if (needLWJGL) { + extractNativeLib("windows", "lwjgl"); + } + if (needOAL) { + extractNativeLib("windows", "OpenAL32"); + } + if (needJInput) { + extractNativeLib("windows", "jinput-dx8"); + extractNativeLib("windows", "jinput-raw"); + } + if (needNativeBullet) { + extractNativeLib("windows", "bulletjme", true, false); + } + break; + case Linux64: + if (needLWJGL) { + extractNativeLib("linux", "lwjgl64"); + } + if (needJInput) { + extractNativeLib("linux", "jinput-linux64"); + } + if (needOAL) { + extractNativeLib("linux", "openal64"); + } + if (needNativeBullet) { + extractNativeLib("linux", "bulletjme64", true, false); + } + break; + case Linux32: + if (needLWJGL) { + extractNativeLib("linux", "lwjgl"); + } + if (needJInput) { + extractNativeLib("linux", "jinput-linux"); + } + if (needOAL) { + extractNativeLib("linux", "openal"); + } + if (needNativeBullet) { + extractNativeLib("linux", "bulletjme", true, false); + } + break; + case MacOSX_PPC32: + case MacOSX32: + case MacOSX_PPC64: + case MacOSX64: + if (needLWJGL) { + extractNativeLib("macosx", "lwjgl"); + } +// if (needOAL) +// extractNativeLib("macosx", "openal"); + if (needJInput) { + extractNativeLib("macosx", "jinput-osx"); + } + if (needNativeBullet) { + extractNativeLib("macosx", "bulletjme", true, false); + } + break; + } + } +} |