All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.jnigen.JniGenSharedLibraryLoader Maven / Gradle / Ivy

There is a newer version: 2.5.2
Show newest version
/*******************************************************************************
 * Copyright 2011 See AUTHORS file.
 * 
 * Licensed 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
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/

package com.badlogic.gdx.jnigen;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/** Loads shared libraries from a natives jar file (desktop) or arm folders (Android). For desktop projects, have the natives jar
 * in the classpath, for Android projects put the shared libraries in the libs/armeabi and libs/armeabi-v7a folders.
 * 
 * See {@link AntScriptGenerator}.
 * 
 * @author mzechner */
public class JniGenSharedLibraryLoader {
	private static Set loadedLibraries = new HashSet();
	private String nativesJar;
	private SharedLibraryFinder libraryFinder;

	private ZipFile nativesZip = null;

	public JniGenSharedLibraryLoader () {
	}

	/** Fetches the natives from the given natives jar file. Used for testing a shared lib on the fly, see MyJniClass.
	 * @param nativesJar */
	public JniGenSharedLibraryLoader (String nativesJar) {
		this.nativesJar = nativesJar;
	}

	/** Fetches the natives from the given natives jar file. Used for testing a shared lib on the fly, see MyJniClass.
	 * @param nativesJar
	 * @param libraryFinder A custom libraryfinder, which enables the use of different dynamic libs naming. */
	public JniGenSharedLibraryLoader (String nativesJar, SharedLibraryFinder libraryFinder) {
		this.nativesJar = nativesJar;
		this.libraryFinder = libraryFinder;
		if (nativesJar != null) {
			try {
				nativesZip = new ZipFile(nativesJar);
			} catch (IOException e) {
				nativesZip = null;
			}
		}
	}

	/** Setting a SharedLibraryFinder enables you to load libraries according to a nondefault natives jar layout or library names.
	 * @param libraryFinder */
	public void setSharedLibraryFinder (SharedLibraryFinder libraryFinder) {
		this.libraryFinder = libraryFinder;
		if (nativesJar != null) {
			try {
				nativesZip = new ZipFile(nativesJar);
			} catch (IOException e) {
				nativesZip = null;
			}
		}
	}

	/** Returns a CRC of the remaining bytes in the stream. */
	public String crc (InputStream input) {
		if (input == null) return "" + System.nanoTime(); // fallback
		CRC32 crc = new CRC32();
		byte[] buffer = new byte[4096];
		try {
			while (true) {
				int length = input.read(buffer);
				if (length == -1) break;
				crc.update(buffer, 0, length);
			}
		} catch (Exception ex) {
			try {
				input.close();
			} catch (Exception ignored) {
			}
		}
		return Long.toString(crc.getValue());
	}

	private boolean loadLibrary (String sharedLibName) {
		if (sharedLibName == null) return false;

		String path = extractLibrary(sharedLibName);
		if (path != null) System.load(path);
		return path != null;
	}

	private String extractLibrary (String sharedLibName) {
		String srcCrc = crc(JniGenSharedLibraryLoader.class.getResourceAsStream("/" + sharedLibName));
		File nativesDir = new File(System.getProperty("java.io.tmpdir") + "/jnigen/" + srcCrc);
		File nativeFile = new File(nativesDir, sharedLibName);

		String extractedCrc = null;
		if (nativeFile.exists()) {
			try {
				extractedCrc = crc(new FileInputStream(nativeFile));
			} catch (FileNotFoundException ignored) {
			}
		}

		if (extractedCrc == null || !extractedCrc.equals(srcCrc)) {
			try {
				// Extract native from classpath to temp dir.
				InputStream input = null;
				if (nativesJar == null)
					input = JniGenSharedLibraryLoader.class.getResourceAsStream("/" + sharedLibName);
				else
					input = getFromJar(nativesJar, sharedLibName);
				if (input == null) return null;
				nativeFile.getParentFile().mkdirs();
				FileOutputStream output = new FileOutputStream(nativeFile);
				byte[] buffer = new byte[4096];
				while (true) {
					int length = input.read(buffer);
					if (length == -1) break;
					output.write(buffer, 0, length);
				}
				input.close();
				output.close();
			} catch (IOException ex) {
				ex.printStackTrace();
				throw new RuntimeException(ex);
			}
		}
		return nativeFile.exists() ? nativeFile.getAbsolutePath() : null;
	}

	private InputStream getFromJar (String jarFile, String sharedLibrary) throws IOException {
		ZipFile file = new ZipFile(nativesJar);
		ZipEntry entry = file.getEntry(sharedLibrary);
		return file.getInputStream(entry);
	}

	/** Loads a shared library with the given name for the platform the application is running on. The name should not contain a
	 * prefix (e.g. 'lib') or suffix (e.g. '.dll).
	 * @param sharedLibName */
	public synchronized void load (String sharedLibName) {
		if (loadedLibraries.contains(sharedLibName)) return;

		boolean isWindows = System.getProperty("os.name").contains("Windows");
		boolean isLinux = System.getProperty("os.name").contains("Linux");
		boolean isMac = System.getProperty("os.name").contains("Mac");
		boolean isAndroid = false;
		boolean is64Bit = System.getProperty("os.arch").equals("amd64") || System.getProperty("os.arch").equals("x86_64");
		boolean isArm = System.getProperty("os.arch").equals("arm");

		String vm = System.getProperty("java.vm.name");
		if (vm != null && vm.contains("Dalvik")) {
			isAndroid = true;
			isWindows = false;
			isLinux = false;
			isMac = false;
			is64Bit = false;
		}

		boolean loaded = false;
		if (isWindows) {
			if (libraryFinder != null)
				loaded = loadLibrary(libraryFinder.getSharedLibraryNameWindows(sharedLibName, is64Bit, nativesZip));
			else if (!is64Bit)
				loaded = loadLibrary(sharedLibName + ".dll");
			else
				loaded = loadLibrary(sharedLibName + "64.dll");
		}
		if (isLinux) {
			if (libraryFinder != null)
				loaded = loadLibrary(libraryFinder.getSharedLibraryNameLinux(sharedLibName, is64Bit, isArm, nativesZip));
			else if (!is64Bit) {
				if (isArm)
					loaded = loadLibrary("lib" + sharedLibName + "Arm.so");
				else
					loaded = loadLibrary("lib" + sharedLibName + ".so");
			} else {
				if (isArm)
					loaded = loadLibrary("lib" + sharedLibName + "Arm64.so");
				else
					loaded = loadLibrary("lib" + sharedLibName + "64.so");
			}
		}
		if (isMac) {
			if (libraryFinder != null)
				loaded = loadLibrary(libraryFinder.getSharedLibraryNameMac(sharedLibName, is64Bit, nativesZip));
			else if (!is64Bit)
				loaded = loadLibrary("lib" + sharedLibName + ".dylib");
			else
				loaded = loadLibrary("lib" + sharedLibName + "64.dylib");
		}
		if (isAndroid) {
			if (libraryFinder != null)
				System.loadLibrary(libraryFinder.getSharedLibraryNameAndroid(sharedLibName, nativesZip));
			else
				System.loadLibrary(sharedLibName);
			loaded = true;
		}
		if (loaded) loadedLibraries.add(sharedLibName);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy