1 /*******************************************************************************
\r
2 * Copyright 2011 See AUTHORS file.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
15 ******************************************************************************/
17 package com.badlogic.gdx.jnigen;
\r
19 import java.io.File;
\r
20 import java.io.FileInputStream;
\r
21 import java.io.FileNotFoundException;
\r
22 import java.io.FileOutputStream;
\r
23 import java.io.IOException;
\r
24 import java.io.InputStream;
\r
25 import java.util.HashSet;
\r
26 import java.util.Set;
\r
27 import java.util.zip.CRC32;
\r
28 import java.util.zip.ZipEntry;
\r
29 import java.util.zip.ZipFile;
\r
31 /** Loads shared libraries from a natives jar file (desktop) or arm folders (Android). For desktop projects, have the natives jar
\r
32 * in the classpath, for Android projects put the shared libraries in the libs/armeabi and libs/armeabi-v7a folders.
\r
34 * See {@link AntScriptGenerator}.
\r
36 * @author mzechner */
\r
37 public class JniGenSharedLibraryLoader {
\r
38 private static Set<String> loadedLibraries = new HashSet<String>();
\r
39 private String nativesJar;
\r
41 public JniGenSharedLibraryLoader () {
\r
44 /** Fetches the natives from the given natives jar file. Used for testing a shared lib on the fly, see MyJniClass.
\r
45 * @param nativesJar */
\r
46 public JniGenSharedLibraryLoader (String nativesJar) {
\r
47 this.nativesJar = nativesJar;
\r
50 /** Returns a CRC of the remaining bytes in the stream. */
\r
51 public String crc (InputStream input) {
\r
52 if (input == null) return "" + System.nanoTime(); // fallback
\r
53 CRC32 crc = new CRC32();
\r
54 byte[] buffer = new byte[4096];
\r
57 int length = input.read(buffer);
\r
58 if (length == -1) break;
\r
59 crc.update(buffer, 0, length);
\r
61 } catch (Exception ex) {
\r
64 } catch (Exception ignored) {
\r
67 return Long.toString(crc.getValue());
\r
70 private boolean loadLibrary (String sharedLibName) {
\r
71 String path = extractLibrary(sharedLibName);
\r
72 if (path != null) System.load(path);
\r
73 return path != null;
\r
76 private String extractLibrary (String sharedLibName) {
\r
77 String srcCrc = crc(JniGenSharedLibraryLoader.class.getResourceAsStream("/" + sharedLibName));
\r
78 File nativesDir = new File(System.getProperty("java.io.tmpdir") + "/jnigen/" + srcCrc);
\r
79 File nativeFile = new File(nativesDir, sharedLibName);
\r
81 String extractedCrc = null;
\r
82 if (nativeFile.exists()) {
\r
84 extractedCrc = crc(new FileInputStream(nativeFile));
\r
85 } catch (FileNotFoundException ignored) {
\r
89 if(extractedCrc == null || !extractedCrc.equals(srcCrc)) {
\r
91 // Extract native from classpath to temp dir.
\r
92 InputStream input = null;
\r
93 if (nativesJar == null)
\r
94 input = JniGenSharedLibraryLoader.class.getResourceAsStream("/" + sharedLibName);
\r
96 input = getFromJar(nativesJar, sharedLibName);
\r
97 if (input == null) return null;
\r
98 nativesDir.mkdirs();
\r
99 FileOutputStream output = new FileOutputStream(nativeFile);
\r
100 byte[] buffer = new byte[4096];
\r
102 int length = input.read(buffer);
\r
103 if (length == -1) break;
\r
104 output.write(buffer, 0, length);
\r
108 } catch (IOException ex) {
\r
109 ex.printStackTrace();
\r
110 throw new RuntimeException(ex);
\r
113 return nativeFile.exists() ? nativeFile.getAbsolutePath() : null;
\r
116 private InputStream getFromJar (String jarFile, String sharedLibrary) throws IOException {
\r
117 ZipFile file = new ZipFile(nativesJar);
\r
118 ZipEntry entry = file.getEntry(sharedLibrary);
\r
119 return file.getInputStream(entry);
\r
122 /** Loads a shared library with the given name for the platform the application is running on. The name should not contain a
\r
123 * prefix (e.g. 'lib') or suffix (e.g. '.dll).
\r
124 * @param sharedLibName */
\r
125 public synchronized void load (String sharedLibName) {
\r
126 if (loadedLibraries.contains(sharedLibName)) return;
\r
128 boolean isWindows = System.getProperty("os.name").contains("Windows");
\r
129 boolean isLinux = System.getProperty("os.name").contains("Linux");
\r
130 boolean isMac = System.getProperty("os.name").contains("Mac");
\r
131 boolean isAndroid = false;
\r
132 boolean is64Bit = System.getProperty("os.arch").equals("amd64");
\r
133 String vm = System.getProperty("java.vm.name");
\r
134 if (vm != null && vm.contains("Dalvik")) {
\r
142 boolean loaded = false;
\r
145 loaded = loadLibrary(sharedLibName + ".dll");
\r
147 loaded = loadLibrary(sharedLibName + "64.dll");
\r
151 loaded = loadLibrary("lib" + sharedLibName + ".so");
\r
153 loaded = loadLibrary("lib" + sharedLibName + "64.so");
\r
156 loaded = loadLibrary("lib" + sharedLibName + ".dylib");
\r
159 System.loadLibrary(sharedLibName);
\r
162 if (loaded) loadedLibraries.add(sharedLibName);
\r