Skip to content

Commit db1b553

Browse files
Merge pull request #1490 from korlibs/feature/direct.mapping.custom.symbol.provider
Adds support for a custom SymbolProvider in NativeLibrary & Library
2 parents 9e7160e + 5a6a9f2 commit db1b553

5 files changed

Lines changed: 169 additions & 2 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Features
1212
* [#1471](https://github.com/java-native-access/jna/pull/1471): Add `c.s.j.p.win32.Advapi32Util#isCurrentProcessElevated` and associated Types - [@dbwiddis](https://github.com/dbwiddis).
1313
* [#1474](https://github.com/java-native-access/jna/pull/1474): Add `c.s.j.p.win32.WbemCli#IWbemClassObject.IWbemQualifierSet`, `IWbemServices.GetObject`, `IWbemContext.SetValue` and associated methods - [@rchateauneu](https://github.com/rchateauneu).
1414
* [#1482](https://github.com/java-native-access/jna/pull/1482): Add multilingual support of `Kernel32Util.formatMessage` - [@overpathz](https://github.com/overpathz).
15+
* [#1490](https://github.com/java-native-access/jna/pull/1490): Adds support for a custom `SymbolProvider` in `NativeLibrary` & `Library` - [@soywiz](https://github.com/soywiz).
1516

1617
Bug Fixes
1718
---------

src/com/sun/jna/Library.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public interface Library {
114114
*/
115115
String OPTION_CLASSLOADER = "classloader";
116116

117+
/**
118+
* Supports a custom symbol provider for the NativeLibrary (see {@link SymbolProvider})
119+
*/
120+
String OPTION_SYMBOL_PROVIDER = "symbol-provider";
121+
117122
static class Handler implements InvocationHandler {
118123

119124
static final Method OBJECT_TOSTRING;

src/com/sun/jna/NativeLibrary.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,20 @@
8787
public class NativeLibrary implements Closeable {
8888

8989
private static final Logger LOG = Logger.getLogger(NativeLibrary.class.getName());
90-
private final static Level DEBUG_LOAD_LEVEL = DEBUG_LOAD ? Level.INFO : Level.FINE;
90+
private static final Level DEBUG_LOAD_LEVEL = DEBUG_LOAD ? Level.INFO : Level.FINE;
91+
private static final SymbolProvider NATIVE_SYMBOL_PROVIDER = new SymbolProvider() {
92+
@Override
93+
public long getSymbolAddress(long handle, String name, SymbolProvider parent) {
94+
return Native.findSymbol(handle, name);
95+
}
96+
};
9197

9298
private Cleaner.Cleanable cleanable;
9399
private long handle;
94100
private final String libraryName;
95101
private final String libraryPath;
96102
private final Map<String, Function> functions = new HashMap<String, Function>();
103+
private final SymbolProvider symbolProvider;
97104
final int callFlags;
98105
private String encoding;
99106
final Map<String, ?> options;
@@ -123,6 +130,13 @@ private NativeLibrary(String libraryName, String libraryPath, long handle, Map<S
123130
this.callFlags = callingConvention;
124131
this.options = options;
125132
this.encoding = (String)options.get(Library.OPTION_STRING_ENCODING);
133+
SymbolProvider optionSymbolProvider = (SymbolProvider)options.get(Library.OPTION_SYMBOL_PROVIDER);
134+
if (optionSymbolProvider == null) {
135+
this.symbolProvider = NATIVE_SYMBOL_PROVIDER;
136+
} else {
137+
this.symbolProvider = optionSymbolProvider;
138+
}
139+
126140
if (this.encoding == null) {
127141
this.encoding = Native.getDefaultStringEncoding();
128142
}
@@ -636,7 +650,7 @@ long getSymbolAddress(String name) {
636650
if (handle == 0) {
637651
throw new UnsatisfiedLinkError("Library has been unloaded");
638652
}
639-
return Native.findSymbol(handle, name);
653+
return this.symbolProvider.getSymbolAddress(handle, name, NATIVE_SYMBOL_PROVIDER);
640654
}
641655

642656
@Override
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* Copyright (c) 2022 Carlos Ballesteros, All Rights Reserved
2+
*
3+
* The contents of this file is dual-licensed under 2
4+
* alternative Open Source/Free licenses: LGPL 2.1 or later and
5+
* Apache License 2.0. (starting with JNA version 4.0.0).
6+
*
7+
* You can freely decide which license you want to apply to
8+
* the project.
9+
*
10+
* You may obtain a copy of the LGPL License at:
11+
*
12+
* http://www.gnu.org/licenses/licenses.html
13+
*
14+
* A copy is also included in the downloadable source code package
15+
* containing JNA, in file "LGPL2.1".
16+
*
17+
* You may obtain a copy of the Apache License at:
18+
*
19+
* http://www.apache.org/licenses/
20+
*
21+
* A copy is also included in the downloadable source code package
22+
* containing JNA, in file "AL2.0".
23+
*/
24+
package com.sun.jna;
25+
26+
/**
27+
* Interface to define a custom symbol provider.
28+
*
29+
* This can be used for method hooking, or special
30+
* classes like direct mapping the Win32 OpenGL.
31+
*/
32+
public interface SymbolProvider {
33+
/**
34+
* Gets the address of a symbol by its name and the handle of the library.
35+
*
36+
* @param handle Handle of the original library
37+
* @param name Name of the symbol to load
38+
* @param parent Parent symbol provider
39+
*
40+
* @return Address of the symbol, typically a function.
41+
*/
42+
long getSymbolAddress(long handle, String name, SymbolProvider parent);
43+
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/* Copyright (c) 2022 Carlos Ballesteros, All Rights Reserved
2+
*
3+
* The contents of this file is dual-licensed under 2
4+
* alternative Open Source/Free licenses: LGPL 2.1 or later and
5+
* Apache License 2.0. (starting with JNA version 4.0.0).
6+
*
7+
* You can freely decide which license you want to apply to
8+
* the project.
9+
*
10+
* You may obtain a copy of the LGPL License at:
11+
*
12+
* http://www.gnu.org/licenses/licenses.html
13+
*
14+
* A copy is also included in the downloadable source code package
15+
* containing JNA, in file "LGPL2.1".
16+
*
17+
* You may obtain a copy of the Apache License at:
18+
*
19+
* http://www.apache.org/licenses/
20+
*
21+
* A copy is also included in the downloadable source code package
22+
* containing JNA, in file "AL2.0".
23+
*/
24+
package com.sun.jna;
25+
26+
import junit.framework.TestCase;
27+
28+
import java.util.Collections;
29+
30+
public class NativeCustomSymbolProviderTest extends TestCase implements Paths {
31+
public static void main(java.lang.String[] argList) {
32+
junit.textui.TestRunner.run(NativeCustomSymbolProviderTest.class);
33+
}
34+
35+
interface MathInterfaceWithSymbolProvider extends Library {
36+
37+
double sin(double x);
38+
double cos(double x);
39+
40+
}
41+
42+
static class MathLibraryWithSymbolProvider {
43+
44+
public static native double sin(double x);
45+
public static native double cos(double x);
46+
47+
static {
48+
Native.register(MathLibraryWithSymbolProvider.class, NativeLibrary.getInstance(Platform.MATH_LIBRARY_NAME, Collections.singletonMap(
49+
Library.OPTION_SYMBOL_PROVIDER,
50+
new SymbolProvider() {
51+
@Override
52+
public long getSymbolAddress(long handle, String name, SymbolProvider parent) {
53+
if (name.equals("sin")) {
54+
return parent.getSymbolAddress(handle, "cos", null);
55+
} else {
56+
return parent.getSymbolAddress(handle, "sin", null);
57+
}
58+
}
59+
}
60+
)));
61+
}
62+
}
63+
64+
MathInterfaceWithSymbolProvider lib;
65+
MathInterfaceWithSymbolProvider libCustom;
66+
67+
@Override
68+
protected void setUp() {
69+
lib = Native.load(Platform.MATH_LIBRARY_NAME, MathInterfaceWithSymbolProvider.class);
70+
libCustom = Native.load(
71+
Platform.MATH_LIBRARY_NAME,
72+
MathInterfaceWithSymbolProvider.class, Collections.singletonMap(
73+
Library.OPTION_SYMBOL_PROVIDER,
74+
new SymbolProvider() {
75+
@Override
76+
public long getSymbolAddress(long handle, String name, SymbolProvider parent) {
77+
if (name.equals("sin")) {
78+
return parent.getSymbolAddress(handle, "cos", null);
79+
} else {
80+
return parent.getSymbolAddress(handle, "sin", null);
81+
}
82+
}
83+
}
84+
)
85+
);
86+
}
87+
88+
@Override
89+
protected void tearDown() {
90+
lib = null;
91+
libCustom = null;
92+
}
93+
94+
95+
public void testDirectMappingSymbolProvider() {
96+
assertEquals(lib.cos(0.0), MathLibraryWithSymbolProvider.sin(0.0));
97+
assertEquals(lib.sin(0.0), MathLibraryWithSymbolProvider.cos(0.0));
98+
}
99+
100+
public void testInterfaceCustomSymbolProvider() {
101+
assertEquals(lib.cos(0.0), libCustom.sin(0.0));
102+
assertEquals(lib.sin(0.0), libCustom.cos(0.0));
103+
}
104+
}

0 commit comments

Comments
 (0)