OSDN Git Service

82fdec521c901d5336c5aa753c5061e948b200a2
[mikumikustudio/MikuMikuStudio.git] / engine / src / desktop / com / jme3 / system / Natives.java
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.system;
33
34 import java.io.File;
35 import java.io.FileNotFoundException;
36 import java.io.FileOutputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.OutputStream;
40 import java.net.MalformedURLException;
41 import java.net.URL;
42 import java.net.URLConnection;
43 import java.util.logging.Level;
44 import java.util.logging.Logger;
45
46 /**
47  * Helper class for extracting the natives (dll, so) from the jars.
48  * This class should only be used internally.
49  */
50 public class Natives {
51
52     private static final Logger logger = Logger.getLogger(Natives.class.getName());
53     private static final byte[] buf = new byte[1024];
54     private static File workingDir = new File("").getAbsoluteFile();
55  
56     public static void setExtractionDir(String name) {
57         workingDir = new File(name).getAbsoluteFile();
58     }
59
60     protected static void extractNativeLib(String sysName, String name) throws IOException {
61         extractNativeLib(sysName, name, false, true);
62     }
63
64     protected static void extractNativeLib(String sysName, String name, boolean load) throws IOException {
65         extractNativeLib(sysName, name, load, true);
66     }
67     
68     protected static void extractNativeLib(String sysName, String name, boolean load, boolean warning) throws IOException {
69         String fullname = System.mapLibraryName(name);
70
71         String path = "native/" + sysName + "/" + fullname;
72         URL url = Thread.currentThread().getContextClassLoader().getResource(path);
73         
74         if (url == null) {
75             if (sysName.equals("macosx")) {
76                 fullname = fullname.replace(".dylib", ".jnilib");
77                 String path2 = "native/" + sysName + "/" + fullname;
78                 // logger.warning("retry "+path2);
79                 url = Thread.currentThread().getContextClassLoader().getResource(path2);
80                 if (url == null) {
81                     if (!warning) {
82                         logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}",
83                                 new String[]{sysName, fullname});
84                     }
85                     return;
86                 }
87             } else {
88                 if (!warning) {
89                     logger.log(Level.WARNING, "Cannot locate native library: {0}/{1}",
90                             new String[]{sysName, fullname});
91                 }
92                 return;
93             }
94         }
95         
96         URLConnection conn = url.openConnection();
97         InputStream in = conn.getInputStream();
98         File targetFile = new File(workingDir, fullname);
99         // logger.info("targetFile = "+targetFile.getPath());
100         if (targetFile.exists()){
101             // OK, compare last modified date of this file to 
102             // file in jar
103             long targetLastModified = targetFile.lastModified();
104             long sourceLastModified = conn.getLastModified();
105             
106             // Allow ~1 second range for OSes that only support low precision
107             if (targetLastModified + 1000 > sourceLastModified){
108                 logger.log(Level.FINE, "Not copying library {0}. Latest already extracted.", fullname);
109                 // return;
110             }
111         }
112         try {
113             OutputStream out = new FileOutputStream(targetFile);
114             int len;
115             while ((len = in.read(buf)) > 0) {
116                 out.write(buf, 0, len);
117             }
118             in.close();
119             out.close();
120             
121             // NOTE: On OSes that support "Date Created" property, 
122             // this will cause the last modified date to be lower than
123             // date created which makes no sense
124             targetFile.setLastModified(conn.getLastModified());
125         } catch (FileNotFoundException ex) {
126             if (ex.getMessage().contains("used by another process")) {
127                 return;
128             }
129
130             throw ex;
131         } finally {
132             if (load) {
133                 logger.log(Level.INFO, "Load native library {0}", targetFile.getAbsolutePath());
134                 System.load(targetFile.getAbsolutePath());
135             }
136         }
137         logger.log(Level.FINE, "Copied {0} to {1}", new Object[]{fullname, targetFile});
138     }
139
140     private static String getExtractionDir() {
141         URL temp = Natives.class.getResource("");
142         if (temp != null) {
143             StringBuilder sb = new StringBuilder(temp.toString());
144             if (sb.indexOf("jar:") == 0) {
145                 sb.delete(0, 4);
146                 sb.delete(sb.indexOf("!"), sb.length());
147                 sb.delete(sb.lastIndexOf("/") + 1, sb.length());
148             }
149             try {
150                 return new URL(sb.toString()).toString();
151             } catch (MalformedURLException ex) {
152                 return null;
153             }
154         }
155         return null;
156     }
157     
158     protected static boolean isUsingNativeBullet(){
159         try {
160             Class clazz = Class.forName("com.jme3.bullet.util.NativeMeshUtil");
161             return clazz != null;
162         } catch (ClassNotFoundException ex) {
163             return false;
164         }
165     }
166
167     protected static void extractNativeLibs(Platform platform, AppSettings settings) throws IOException {
168         String renderer = settings.getRenderer();
169         String audioRenderer = settings.getAudioRenderer();
170         boolean needLWJGL = false;
171         boolean needOAL = false;
172         boolean needJInput = false;
173         boolean needNativeBullet = isUsingNativeBullet();
174         if (renderer != null) {
175             if (renderer.startsWith("LWJGL")) {
176                 needLWJGL = true;
177             }
178         }
179         if (audioRenderer != null) {
180             if (audioRenderer.equals("LWJGL")) {
181                 needLWJGL = true;
182                 needOAL = true;
183             }
184         }
185         needJInput = settings.useJoysticks();
186
187         if (needLWJGL) {
188             logger.log(Level.INFO, "Extraction Directory #1: {0}", getExtractionDir());
189             logger.log(Level.INFO, "Extraction Directory #2: {0}", workingDir.toString());
190 //            logger.log(Level.INFO, "Extraction Directory #3: {0}", System.getProperty("user.dir"));
191             // LWJGL supports this feature where
192             // it can load libraries from this path.
193             // This is a fallback method in case the OS doesn't load
194             // native libraries from the working directory (e.g Linux).
195             System.setProperty("org.lwjgl.librarypath", workingDir.toString());
196         }
197
198         switch (platform) {
199             case Windows64:
200                 if (needLWJGL) {
201                     extractNativeLib("windows", "lwjgl64");
202                 }
203                 if (needOAL) {
204                     extractNativeLib("windows", "OpenAL64");
205                 }
206                 if (needJInput) {
207                     extractNativeLib("windows", "jinput-dx8_64");
208                     extractNativeLib("windows", "jinput-raw_64");
209                 }
210                 if (needNativeBullet) {
211                     extractNativeLib("windows", "bulletjme64", true, false);
212                 }
213                 break;
214             case Windows32:
215                 if (needLWJGL) {
216                     extractNativeLib("windows", "lwjgl");
217                 }
218                 if (needOAL) {
219                     extractNativeLib("windows", "OpenAL32");
220                 }
221                 if (needJInput) {
222                     extractNativeLib("windows", "jinput-dx8");
223                     extractNativeLib("windows", "jinput-raw");
224                 }
225                 if (needNativeBullet) {
226                     extractNativeLib("windows", "bulletjme", true, false);
227                 }
228                 break;
229             case Linux64:
230                 if (needLWJGL) {
231                     extractNativeLib("linux", "lwjgl64");
232                 }
233                 if (needJInput) {
234                     extractNativeLib("linux", "jinput-linux64");
235                 }
236                 if (needOAL) {
237                     extractNativeLib("linux", "openal64");
238                 }
239                 if (needNativeBullet) {
240                     extractNativeLib("linux", "bulletjme64", true, false);
241                 }
242                 break;
243             case Linux32:
244                 if (needLWJGL) {
245                     extractNativeLib("linux", "lwjgl");
246                 }
247                 if (needJInput) {
248                     extractNativeLib("linux", "jinput-linux");
249                 }
250                 if (needOAL) {
251                     extractNativeLib("linux", "openal");
252                 }
253                 if (needNativeBullet) {
254                     extractNativeLib("linux", "bulletjme", true, false);
255                 }
256                 break;
257             case SolarisAMD64:
258                 if (needLWJGL) {
259                     extractNativeLib("solaris", "lwjgl64");
260                 }
261 //                if (needJInput) {
262 //                    extractNativeLib("solaris", "jinput-linux64");
263 //                }
264                 if (needOAL) {
265                     extractNativeLib("solaris", "openal64");
266                 }
267                 if (needNativeBullet) {
268                     extractNativeLib("solaris", "bulletjme64", true, false);
269                 }
270                 break;
271             case SolarisX86:
272                 if (needLWJGL) {
273                     extractNativeLib("solaris", "lwjgl");
274                 }
275 //                if (needJInput) {
276 //                    extractNativeLib("solaris", "jinput-linux");
277 //                }
278                 if (needOAL) {
279                     extractNativeLib("solaris", "openal");
280                 }
281                 if (needNativeBullet) {
282                     extractNativeLib("solaris", "bulletjme", true, false);
283                 }
284                 break;
285             case MacOSX_PPC32:
286             case MacOSX32:
287             case MacOSX_PPC64:
288             case MacOSX64:
289                 if (needLWJGL) {
290                     extractNativeLib("macosx", "lwjgl");
291                 }
292                 if (needOAL)
293                     extractNativeLib("macosx", "openal");
294                 if (needJInput) {
295                     extractNativeLib("macosx", "jinput-osx");
296                 }
297                 if (needNativeBullet) {
298                     extractNativeLib("macosx", "bulletjme", true, false);
299                 }
300                 break;
301         }
302     }
303 }