001 /*
002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003
004 This file is part of JNAerator (http://jnaerator.googlecode.com/).
005
006 JNAerator is free software: you can redistribute it and/or modify
007 it under the terms of the GNU Lesser General Public License as published by
008 the Free Software Foundation, either version 3 of the License, or
009 (at your option) any later version.
010
011 JNAerator is distributed in the hope that it will be useful,
012 but WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 GNU Lesser General Public License for more details.
015
016 You should have received a copy of the GNU Lesser General Public License
017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
018 */
019 package com.ochafik.lang.jnaerator.runtime;
020
021 import java.io.File;
022 import java.io.FileOutputStream;
023 import java.io.IOException;
024 import java.io.InputStream;
025 import java.io.OutputStream;
026 import java.net.URL;
027 import java.net.URLConnection;
028 import java.net.URLDecoder;
029 import java.util.ArrayList;
030 import java.util.Iterator;
031 import java.util.List;
032
033 import com.ochafik.net.URLUtils;
034 import com.sun.jna.Platform;
035
036 /**
037 * @see http://landonf.bikemonkey.org/static/soylatte/
038 * @author ochafik
039 *
040 */
041 public class LibraryExtractor {
042 public static String getCurrentOSAndArchString() {
043 String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
044
045 if (os.equals("Mac OS X")) {
046 os = "darwin";
047 arch = "fat";
048 //arch = Platform.is64Bit() ? "64" : "32";
049 } else if (os.startsWith("Windows")) {
050 return "win" + (Platform.is64Bit() ? "64" : "32");
051 } else if (os.matches("SunOS|Solaris"))
052 os = "solaris";
053
054 return os + "-" + arch;
055 }
056 public static String getLibraryPath(String libraryName, boolean extractAllLibraries, Class<?> cl) {
057 try {
058 String customPath = System.getProperty("library." + libraryName);
059 if (customPath == null)
060 customPath = System.getenv(libraryName.toUpperCase() + "_LIBRARY");
061 if (customPath != null) {
062 File f = new File(customPath);
063 if (!f.exists())
064 System.err.println("Library file '" + customPath + "' does not exist !");
065 else
066 return f.getAbsolutePath();
067 }
068 //ClassLoader cl = LibraryExtractor.class.getClassLoader();
069 String prefix = "(?i)" + (Platform.isWindows() || Platform.isWindowsCE() ? "" : "lib") + libraryName + "[^A-Za-z_].*";
070 String libsuffix = "(?i).*\\.(so|dll|dylib|jnilib)";
071 String othersuffix = "(?i).*\\.(pdb)";
072
073 URL sourceURL = null;
074 List<URL> otherURLs = new ArrayList<URL>();
075
076
077 String arch = getCurrentOSAndArchString();
078 //System.out.println("libURL = " + libURL);
079 List<URL> list = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/" + arch), null);
080 if (list.isEmpty()) {
081 for (URL u : URLUtils.listFiles(URLUtils.getResource(cl, "libraries"), null)) {
082 String f = u.getFile();
083 int i = f.lastIndexOf('/');
084 if (i >= 0)
085 f = f.substring(i + 1);
086 if (arch.startsWith(f)) {
087 list = URLUtils.listFiles(u, null);
088 break;
089 }
090 }
091
092 }
093 for (File f : new File(".").listFiles())
094 if (f.isFile())
095 list.add(f.toURI().toURL());
096
097 for (URL url : list) {
098 String fileName = new File(url.toString()).getName();
099 boolean pref = fileName.matches(prefix), suff = fileName.matches(libsuffix);
100 if (pref && suff)
101 sourceURL = url;
102 else if (suff || fileName.matches(othersuffix))
103 otherURLs.add(url);
104 }
105 List<File> files = new ArrayList<File>();
106 if (extractAllLibraries) {
107 for (URL url : otherURLs)
108 files.add(extract(url));
109 }
110
111 if (sourceURL == null)
112 return libraryName;
113 else {
114 File file = extract(sourceURL);
115 files.add(file);
116
117 int lastSize;
118 do {
119 lastSize = files.size();
120 for (Iterator<File> it = files.iterator(); it.hasNext();) {
121 File f = it.next();
122 if (!f.getName().matches(libsuffix))
123 continue;
124
125 try {
126 System.load(f.toString());
127 it.remove();
128 } catch (Throwable ex) {
129 System.err.println("Loading " + f.getName() + " failed (" + ex + ")");
130 }
131 }
132 } while (files.size() < lastSize);
133
134 return file.getCanonicalPath();
135 }
136 } catch (Throwable ex) {
137 System.err.println("ERROR: Failed to extract library " + libraryName);
138 ex.printStackTrace();
139 return libraryName;
140 }
141 }
142 private static File extract(URL url) throws IOException {
143 File localFile;
144 if ("file".equals(url.getProtocol()))
145 localFile = new File(URLDecoder.decode(url.getFile(), "UTF-8"));
146 else {
147 File f = new File(System.getProperty("user.home"));
148 f = new File(f, ".jnaerator");
149 f = new File(f, "extractedLibraries");
150 if (!f.exists())
151 f.mkdirs();
152
153 localFile = new File(f, new File(url.getFile()).getName());
154 URLConnection c = url.openConnection();
155 if (localFile.exists() && localFile.lastModified() > c.getLastModified()) {
156 c.getInputStream().close();
157 } else {
158 System.out.println("Extracting " + url);
159 InputStream in = c.getInputStream();
160 OutputStream out = new FileOutputStream(localFile);
161 int len;
162 byte[] b = new byte[1024];
163 while ((len = in.read(b)) > 0)
164 out.write(b, 0, len);
165 out.close();
166 in.close();
167 }
168 }
169 return localFile;
170 }
171 public static void loadLibrary(String libraryName, boolean extractAllLibraries, Class<?> cl) {
172 System.loadLibrary(getLibraryPath(libraryName, extractAllLibraries, cl));
173 }
174 }