diff src/name/blackcap/exifwasher/exiv2/Initialize.kt @ 0:db63d01a23c6

JNI calls and test case (finally!) seem to work.
author David Barts <n5jrn@me.com>
date Tue, 31 Mar 2020 13:24:48 -0700
parents
children 42277ce58ace
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/name/blackcap/exifwasher/exiv2/Initialize.kt	Tue Mar 31 13:24:48 2020 -0700
@@ -0,0 +1,81 @@
+/*
+ * Logic common to initializing all external (JNI) classes goes here.
+ */
+package name.blackcap.exifwasher.exiv2
+
+import java.io.File
+import java.io.FileOutputStream
+import java.io.IOException
+import java.util.jar.JarEntry
+import java.util.jar.JarFile
+import name.blackcap.exifwasher.LF_DIR
+import name.blackcap.exifwasher.OS
+
+object Initialize {
+    private var initialized = false
+
+    public fun libraries() {
+        /* no-op if already initialized */
+        if (initialized) {
+            return
+        }
+
+        /* use the appropriate binary for the system we're on */
+        val subdir = when(OS.type) {
+            OS.UNIX -> "linux"
+            OS.MAC -> "mac"
+            OS.WINDOWS -> "windows"
+            OS.OTHER -> throw RuntimeException("unsupported OS!")
+        }
+        val ext = when(OS.type) {
+            OS.UNIX -> "so"
+            OS.MAC -> "dylib"
+            OS.WINDOWS -> "dll"
+            OS.OTHER -> throw RuntimeException("unsupported OS!")
+        }
+
+        /* extract to scratch files, if needed, then load */
+        val klass = Initialize::class.java
+        var myJar = JarFile(File(klass.getProtectionDomain().getCodeSource().getLocation().toURI()))
+        for (base in arrayOf("libexiv2", "libjni")) {
+            val eBase = "${base}.${ext}"
+            val sPath = "name/blackcap/exifwasher/binaries/${subdir}/${eBase}"
+            val source = myJar.getJarEntry(sPath)
+            if (source == null) {
+                die("${sPath} not found in jar")
+            }
+            val target = File(LF_DIR, eBase)
+            val tPath = target.toString()
+            try {
+                if (!target.exists() || target.lastModified() < source.getTime()) {
+                    myJar.getInputStream(source).use { sfp ->
+                        FileOutputStream(target).use { tfp ->
+                            sfp.copyTo(tfp)
+                        }
+                    }
+                    target.setExecutable(true)
+                    target.setLastModified(source.getTime())
+                }
+            } catch (e: IOException) {
+                val message = e.message ?: "I/O error"
+                die("unable to create ${tPath}: ${message}")
+            }
+            try {
+                println("loading: ${tPath}")  /* debug */
+                System.load(tPath)
+            } catch (e: UnsatisfiedLinkError) {
+                val message = e.message ?: "unsatisfied link"
+                die("unable to link ${tPath}: ${message}")
+            }
+        }
+
+        initialized = true
+        System.err.println("libraries loaded")  /* debug */
+    }
+
+    private fun die(message: String) {
+        /* should open a dialog */
+        System.err.println(message)
+        System.exit(1)
+    }
+}