View Javadoc

1   /*
2   	Copyright (c) 2009 Olivier Chafik, All Rights Reserved
3   	
4   	This file is part of JNAerator (http://jnaerator.googlecode.com/).
5   	
6   	JNAerator is free software: you can redistribute it and/or modify
7   	it under the terms of the GNU Lesser General Public License as published by
8   	the Free Software Foundation, either version 3 of the License, or
9   	(at your option) any later version.
10  	
11  	JNAerator is distributed in the hope that it will be useful,
12  	but WITHOUT ANY WARRANTY; without even the implied warranty of
13  	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  	GNU Lesser General Public License for more details.
15  	
16  	You should have received a copy of the GNU Lesser General Public License
17  	along with JNAerator.  If not, see <http://www.gnu.org/licenses/>.
18  */
19  package com.ochafik.lang.jnaerator.runtime;
20  
21  import java.io.File;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.OutputStream;
26  import java.net.URL;
27  import java.net.URLConnection;
28  import java.net.URLDecoder;
29  import java.util.ArrayList;
30  import java.util.Iterator;
31  import java.util.List;
32  
33  import com.ochafik.net.URLUtils;
34  import com.sun.jna.Platform;
35  
36  /**
37   * @see http://landonf.bikemonkey.org/static/soylatte/
38   * @author ochafik
39   *
40   */
41  public class LibraryExtractor {
42  	public static String getCurrentOSAndArchString() {
43  		String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
44  
45  		if (os.equals("Mac OS X")) {
46  			os = "darwin";
47  			arch = "fat";
48  			//arch = Platform.is64Bit() ? "64" : "32";
49  		} else if (os.startsWith("Windows")) {
50  			return "win" + (Platform.is64Bit() ? "64" : "32");
51  		} else if (os.matches("SunOS|Solaris"))
52  			os = "solaris";
53  		
54  		return os + "-" + arch;
55  	}
56  	public static String getLibraryPath(String libraryName, boolean extractAllLibraries, Class<?> cl) {
57  		try {
58  			String customPath = System.getProperty("library." + libraryName);
59  			if (customPath == null)
60  				customPath = System.getenv(libraryName.toUpperCase() + "_LIBRARY");
61  			if (customPath != null) {
62  				File f = new File(customPath);
63  				if (!f.exists())
64  					System.err.println("Library file '" + customPath + "' does not exist !");
65  				else
66  					return f.getAbsolutePath();
67  			}
68  			//ClassLoader cl = LibraryExtractor.class.getClassLoader();
69  			String prefix = "(?i)" + (Platform.isWindows() || Platform.isWindowsCE() ? "" : "lib") + libraryName + "[^A-Za-z_].*";
70  			String libsuffix = "(?i).*\\.(so|dll|dylib|jnilib)";
71  			String othersuffix = "(?i).*\\.(pdb)";
72  			
73  			URL sourceURL = null;
74  			List<URL> otherURLs = new ArrayList<URL>();
75  			
76  
77  			String arch = getCurrentOSAndArchString();
78  			//System.out.println("libURL = " + libURL);
79  			List<URL> list = URLUtils.listFiles(URLUtils.getResource(cl, "libraries/" + arch), null);
80  			if (list.isEmpty()) {
81  				for (URL u : URLUtils.listFiles(URLUtils.getResource(cl, "libraries"), null)) {
82  					String f = u.getFile();
83  					int i = f.lastIndexOf('/');
84  					if (i >= 0)
85  						f = f.substring(i + 1);
86  					if (arch.startsWith(f)) {
87  						list = URLUtils.listFiles(u, null);
88  						break;
89  					}
90  				}
91  				
92  			}
93  			for (File f : new File(".").listFiles())
94  				if (f.isFile())
95  					list.add(f.toURI().toURL());
96  			
97  			for (URL url : list) {
98  				String fileName = new File(url.toString()).getName();
99  				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 }