Skip to content

Commit

Permalink
Adds support for a custom SymbolProvider in NativeLibrary
Browse files Browse the repository at this point in the history
  • Loading branch information
soywiz committed Dec 10, 2022
1 parent 49d80ee commit d3198b2
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/com/sun/jna/Library.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ public interface Library {
*/
String OPTION_CLASSLOADER = "classloader";

/**
* Supports a custom symbol provider for the NativeLibrary (see {@link SymbolProvider})
*/
String OPTION_SYMBOL_PROVIDER = "symbol-provider";

static class Handler implements InvocationHandler {

static final Method OBJECT_TOSTRING;
Expand Down
19 changes: 18 additions & 1 deletion src/com/sun/jna/NativeLibrary.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ public class NativeLibrary implements Closeable {
private final Map<String, Function> functions = new HashMap<String, Function>();
final int callFlags;
private String encoding;
private SymbolProvider symbolProvider;
private SymbolProvider defaultSymbolProvider;
final Map<String, ?> options;

private static final Map<String, Reference<NativeLibrary>> libraries = new HashMap<String, Reference<NativeLibrary>>();
Expand Down Expand Up @@ -123,6 +125,17 @@ private NativeLibrary(String libraryName, String libraryPath, long handle, Map<S
this.callFlags = callingConvention;
this.options = options;
this.encoding = (String)options.get(Library.OPTION_STRING_ENCODING);
this.symbolProvider = (SymbolProvider)options.get(Library.OPTION_SYMBOL_PROVIDER);
if (this.symbolProvider != null) {
//noinspection Convert2Lambda
defaultSymbolProvider = new SymbolProvider() {
@Override
public long getSymbolAddress(long handle, String name, SymbolProvider parent) {
return Native.findSymbol(handle, name);
}
};
}

if (this.encoding == null) {
this.encoding = Native.getDefaultStringEncoding();
}
Expand Down Expand Up @@ -636,7 +649,11 @@ long getSymbolAddress(String name) {
if (handle == 0) {
throw new UnsatisfiedLinkError("Library has been unloaded");
}
return Native.findSymbol(handle, name);
if (symbolProvider != null) {
return symbolProvider.getSymbolAddress(handle, name, defaultSymbolProvider);
} else {
return Native.findSymbol(handle, name);
}
}

@Override
Expand Down
43 changes: 43 additions & 0 deletions src/com/sun/jna/SymbolProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* Copyright (c) 2022 Carlos Ballesteros, All Rights Reserved
*
* The contents of this file is dual-licensed under 2
* alternative Open Source/Free licenses: LGPL 2.1 or later and
* Apache License 2.0. (starting with JNA version 4.0.0).
*
* You can freely decide which license you want to apply to
* the project.
*
* You may obtain a copy of the LGPL License at:
*
* http://www.gnu.org/licenses/licenses.html
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "LGPL2.1".
*
* You may obtain a copy of the Apache License at:
*
* http://www.apache.org/licenses/
*
* A copy is also included in the downloadable source code package
* containing JNA, in file "AL2.0".
*/
package com.sun.jna;

/**
* Interface to define a custom symbol provider.
*
* This can be used for method hooking, or special
* classes like direct mapping the Win32 OpenGL.
*/
public interface SymbolProvider {
/**
* Gets the address of a symbol by its name and the handle of the library.
*
* @param handle Handle of the original library
* @param name Name of the symbol to load
* @param parent Parent symbol provider
*
* @return Address of the symbol, typically a function.
*/
long getSymbolAddress(long handle, String name, SymbolProvider parent);
}
28 changes: 28 additions & 0 deletions test/com/sun/jna/DirectTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,36 @@ public static void main(java.lang.String[] argList) {

static class MathLibrary {

public static native double sin(double x);
public static native double cos(double x);

static {
Native.register(Platform.MATH_LIBRARY_NAME);
}
}

static class MathLibraryWithSymbolProvider {

public static native double sin(double x);
public static native double cos(double x);

static {
Native.register(MathLibraryWithSymbolProvider.class, NativeLibrary.getInstance(Platform.MATH_LIBRARY_NAME, Collections.singletonMap(
Library.OPTION_SYMBOL_PROVIDER,
new SymbolProvider() {
@Override
public long getSymbolAddress(long handle, String name, SymbolProvider parent) {
if (name.equals("sin")) {
return parent.getSymbolAddress(handle, "cos", null);
} else {
return parent.getSymbolAddress(handle, "sin", null);
}
}
}
)));
}
}

interface MathInterface extends Library {
double cos(double x);
}
Expand Down Expand Up @@ -299,6 +322,11 @@ public String getFunctionName(NativeLibrary lib, Method method) {
}
}

public void testDirectMappingSymbolProvider() {
assertEquals(MathLibrary.cos(0.0), MathLibraryWithSymbolProvider.sin(0.0));
assertEquals(MathLibrary.sin(0.0), MathLibraryWithSymbolProvider.cos(0.0));
}

public static class PointerNativeMapped implements NativeMapped {
String nativeMethodName;
@Override
Expand Down

0 comments on commit d3198b2

Please sign in to comment.