diff --git a/build.xml b/build.xml index 095da4bab5..70575132f8 100644 --- a/build.xml +++ b/build.xml @@ -526,11 +526,11 @@ + + - - - + diff --git a/native/Makefile b/native/Makefile index 72dfe8a650..406abef669 100644 --- a/native/Makefile +++ b/native/Makefile @@ -60,6 +60,7 @@ endif LIBRARY=$(BUILD)/$(LIBPFX)jnidispatch$(JNISFX) TESTLIB=$(BUILD)/$(LIBPFX)testlib$(LIBSFX) TESTLIB2=$(BUILD)/$(LIBPFX)testlib2$(LIBSFX) +TESTLIBJAR=$(BUILD)/$(LIBPFX)testlibjar$(LIBSFX) # Reasonable defaults based on GCC LIBPFX=lib @@ -296,7 +297,7 @@ else $(CC) $(CFLAGS) -c $< $(COUT) endif -all: $(LIBRARY) $(TESTLIB) $(TESTLIB2) +all: $(LIBRARY) $(TESTLIB) $(TESTLIB2) $(TESTLIBJAR) install: mkdir $(INSTALLDIR) @@ -321,6 +322,9 @@ endif $(TESTLIB2): $(BUILD)/testlib2.o $(LD) $(LDFLAGS) $< $(TESTDEP) +$(TESTLIBJAR): $(BUILD)/testlibjar.o + $(LD) $(LDFLAGS) $< $(LIBS) + ifneq ($(DYNAMIC_LIBFFI),true) $(FFI_LIB): @mkdir -p $(FFI_BUILD) diff --git a/src/com/sun/jna/NativeLibrary.java b/src/com/sun/jna/NativeLibrary.java index 8b4031222b..0fe07a6585 100644 --- a/src/com/sun/jna/NativeLibrary.java +++ b/src/com/sun/jna/NativeLibrary.java @@ -15,7 +15,10 @@ package com.sun.jna; import java.io.File; +import java.io.FileOutputStream; import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; import java.lang.ref.WeakReference; import java.lang.ref.Reference; import java.lang.reflect.Method; @@ -165,6 +168,17 @@ else if (Platform.isWindows()) { try { handle = Native.open(libraryPath); } catch(UnsatisfiedLinkError e2) { e = e2; } } + // As a last resort, try to extract the library from the JAR + if (handle == 0) { + final String embeddedLib = getEmbeddedLibraryPathFromJar(mapLibraryName(libraryName)); + if (embeddedLib != null) + { + try { + handle = Native.open(embeddedLib); + } + catch (UnsatisfiedLinkError e2) { e = e2; } + } + } if (handle == 0) { throw new UnsatisfiedLinkError("Unable to load library '" + libraryName + "': " + e.getMessage()); @@ -172,6 +186,62 @@ else if (Platform.isWindows()) { } return new NativeLibrary(libraryName, libraryPath, handle, options); } + + private static String getEmbeddedLibraryPathFromJar(String libraryName) + { + // Do not extract the library from JAR if jna.nounpack=true + if (Boolean.getBoolean("jna.nounpack")) { + return null; + } + final String libraryPath = System.getProperty("os.name") + "-" + System.getProperty("os.arch") + "/"; + File libFile; + try + { + libFile = extractEmbeddedLibraryResource(libraryPath, libraryName); + } + catch (IOException e) + { + return null; + } + if (libFile == null) + { + return null; + } + else + { + return libFile.getAbsolutePath(); + } + } + + private static File extractEmbeddedLibraryResource(String libraryPath, String libraryName) throws IOException { + final InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(libraryPath + libraryName); + if (is == null) { + return null; + } + FileOutputStream fos = null; + File lib = null; + try { + // Suffix is required on windows, or library fails to load + // Let Java pick the suffix, except on windows, to avoid + // problems with Web Start. + File dir = Native.getTempDir(); + lib = File.createTempFile(libraryName, Platform.isWindows()?".dll":null, dir); + lib.deleteOnExit(); + fos = new FileOutputStream(lib); + int count; + byte[] buf = new byte[1024]; + while ((count = is.read(buf, 0, buf.length)) > 0) { + fos.write(buf, 0, count); + } + } + finally { + try { is.close(); } catch(IOException e) { } + if (fos != null) { + try { fos.close(); } catch(IOException e) { } + } + } + return lib; + } private String getLibraryName(String libraryName) { String simplified = libraryName; diff --git a/test/com/sun/jna/NativeLibraryTest.java b/test/com/sun/jna/NativeLibraryTest.java index 60e73eb833..189f0c0dbe 100644 --- a/test/com/sun/jna/NativeLibraryTest.java +++ b/test/com/sun/jna/NativeLibraryTest.java @@ -17,6 +17,7 @@ import java.util.Arrays; import java.util.List; +import junit.framework.Assert; import junit.framework.TestCase; public class NativeLibraryTest extends TestCase { @@ -190,6 +191,18 @@ public void testGetProcess() { // Access a common C library function process.getFunction("printf"); } + + public static interface TestLibraryInJar extends Library { + int test(); + } + + /** + * Tests that we can load a library which is embedded in the test JAR. + */ + public void testEmbeddedLibrary() { + TestLibraryInJar lib = (TestLibraryInJar)Native.loadLibrary("testlibjar", TestLibraryInJar.class); + Assert.assertEquals(0, lib.test()); + } public static void main(String[] args) { junit.textui.TestRunner.run(NativeLibraryTest.class);