001    package com.github.sarxos.webcam.ds.civil;
002    
003    import java.io.File;
004    import java.io.FileNotFoundException;
005    import java.io.FileOutputStream;
006    import java.io.IOException;
007    import java.io.InputStream;
008    import java.io.OutputStream;
009    
010    import org.slf4j.Logger;
011    import org.slf4j.LoggerFactory;
012    
013    
014    public class LtiCivilLoader {
015    
016            private static final Logger LOG = LoggerFactory.getLogger(LtiCivilLoader.class);
017    
018            /**
019             * Will be called until JVM shutdown.
020             * 
021             * @author Bartosz Firyn (SarXos)
022             */
023            private static class Deleter extends Thread {
024    
025                    private File file = null;
026    
027                    public Deleter(File file) {
028                            super("lti-civil-binary-deleter");
029                            this.file = file;
030                    }
031    
032                    @Override
033                    public void run() {
034                            super.run();
035                            if (file.exists()) {
036                                    if (!file.delete()) {
037                                            LOG.warn(String.format("JVM was not able to remove file %s", file));
038                                    }
039                            }
040                    }
041            }
042    
043            /**
044             * Copy bytes from a large (over 2GB) InputStream to an OutputStream.
045             * 
046             * @param input the InputStream to read from
047             * @param output the OutputStream to write to
048             * @return the number of bytes copied
049             * @throws NullPointerException if the input or output is null
050             * @throws IOException if an I/O error occurs
051             */
052            public static long copy(InputStream input, OutputStream output) throws IOException {
053                    byte[] buffer = new byte[1024 * 4];
054                    long count = 0;
055                    int n = 0;
056                    while (-1 != (n = input.read(buffer))) {
057                            output.write(buffer, 0, n);
058                            count += n;
059                    }
060                    return count;
061            }
062    
063            public static void load(String lib) {
064                    LOG.info("Loading native library: " + lib);
065                    try {
066                            System.loadLibrary(lib);
067                            LOG.info("DLL has been loaded from memory: " + lib);
068                    } catch (UnsatisfiedLinkError e) {
069                            try {
070                                    load("webcam-capture-lib-" + System.currentTimeMillis(), lib);
071                            } catch (Exception e2) {
072                                    LOG.error("Exception when loading DLL library", e2);
073                                    throw new RuntimeException(e2);
074                            }
075                    }
076            }
077    
078            public static void load(String path, String name) {
079    
080                    String libroot = "/META-INF/lib";
081                    String libpath = null;
082                    String libfile = null;
083    
084                    boolean arch64 = System.getProperty("os.arch").indexOf("64") != -1;
085                    boolean linux = System.getProperty("os.name").toLowerCase().indexOf("linux") != -1;
086    
087                    if (linux) {
088                            if (arch64) {
089                                    libpath = libroot + "/linux64/";
090                                    libfile = "lib" + name + ".so";
091                            } else {
092                                    libpath = libroot + "/linux32/";
093                                    libfile = "lib" + name + ".so";
094                            }
095                    } else {
096                            libpath = libroot + "/win32/";
097                            libfile = name + ".dll";
098                    }
099    
100                    File parent = new File(System.getProperty("java.io.tmpdir") + "/" + path);
101                    if (!parent.exists()) {
102                            if (!parent.mkdirs()) {
103                                    throw new RuntimeException("Cannot create directory: " + parent.getAbsolutePath());
104                            }
105                    }
106    
107                    File file = new File(parent, libfile);
108                    if (!file.exists()) {
109    
110                            boolean created = false;
111                            try {
112                                    created = file.createNewFile();
113                            } catch (IOException e) {
114                                    throw new RuntimeException("Not able to create file: " + file, e);
115                            }
116                            if (!created) {
117                                    throw new RuntimeException("File cannot be created: " + file);
118                            }
119    
120                            Runtime.getRuntime().addShutdownHook(new Deleter(file));
121                    }
122    
123                    String resource = libpath + libfile;
124    
125                    InputStream in = LtiCivilDriver.class.getResourceAsStream(resource);
126                    if (in == null) {
127                            throw new RuntimeException("Resource not found: " + resource);
128                    }
129    
130                    FileOutputStream fos = null;
131    
132                    try {
133                            fos = new FileOutputStream(file);
134                            copy(in, fos);
135                    } catch (FileNotFoundException e) {
136                            throw new RuntimeException("File not found " + file, e);
137                    } catch (IOException e) {
138                            throw new RuntimeException("IO exception", e);
139                    } finally {
140                            if (in != null) {
141                                    try {
142                                            in.close();
143                                    } catch (IOException e) {
144                                            throw new RuntimeException("Cannot close input stream", e);
145                                    }
146                            }
147                            if (fos != null) {
148                                    try {
149                                            fos.close();
150                                    } catch (IOException e) {
151                                            throw new RuntimeException("Cannot close file output stream", e);
152                                    }
153                            }
154                    }
155    
156                    try {
157                            System.load(file.getAbsolutePath());
158                    } catch (UnsatisfiedLinkError e) {
159                            throw new RuntimeException("Library file cannot be loaded: " + file, e);
160                    }
161            }
162    }