001package com.github.sarxos.webcam.ds.civil;
002
003import java.io.File;
004import java.io.FileNotFoundException;
005import java.io.FileOutputStream;
006import java.io.IOException;
007import java.io.InputStream;
008import java.io.OutputStream;
009
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013
014public 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}