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    }