PageRenderTime 67ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/sun/jna/Native.java

http://github.com/twall/jna
Java | 2414 lines | 1410 code | 203 blank | 801 comment | 337 complexity | 8c7944b63e7c7813d66fcf2b4782f8df MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0
  1. /* Copyright (c) 2007-2015 Timothy Wall, 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. import java.awt.Component;
  26. import java.awt.GraphicsEnvironment;
  27. import java.awt.HeadlessException;
  28. import java.awt.Window;
  29. import java.io.File;
  30. import java.io.FileOutputStream;
  31. import java.io.FilenameFilter;
  32. import java.io.IOException;
  33. import java.io.InputStream;
  34. import java.io.UnsupportedEncodingException;
  35. import java.lang.ref.Reference;
  36. import java.lang.ref.WeakReference;
  37. import java.lang.reflect.Array;
  38. import java.lang.reflect.Field;
  39. import java.lang.reflect.InvocationHandler;
  40. import java.lang.reflect.Method;
  41. import java.lang.reflect.Modifier;
  42. import java.lang.reflect.Proxy;
  43. import java.net.URI;
  44. import java.net.URISyntaxException;
  45. import java.net.URL;
  46. import java.net.URLClassLoader;
  47. import java.nio.Buffer;
  48. import java.nio.ByteBuffer;
  49. import java.nio.charset.Charset;
  50. import java.nio.charset.IllegalCharsetNameException;
  51. import java.nio.charset.UnsupportedCharsetException;
  52. import java.security.AccessController;
  53. import java.security.PrivilegedAction;
  54. import java.util.ArrayList;
  55. import java.util.Arrays;
  56. import java.util.Collections;
  57. import java.util.HashMap;
  58. import java.util.List;
  59. import java.util.Map;
  60. import java.util.StringTokenizer;
  61. import java.util.WeakHashMap;
  62. import com.sun.jna.Callback.UncaughtExceptionHandler;
  63. import com.sun.jna.Structure.FFIType;
  64. import java.util.logging.Level;
  65. import java.util.logging.Logger;
  66. /** Provides generation of invocation plumbing for a defined native
  67. * library interface. Also provides various utilities for native operations.
  68. * <p>
  69. * {@link #getTypeMapper} and {@link #getStructureAlignment} are provided
  70. * to avoid having to explicitly pass these parameters to {@link Structure}s,
  71. * which would require every {@link Structure} which requires custom mapping
  72. * or alignment to define a constructor and pass parameters to the superclass.
  73. * To avoid lots of boilerplate, the base {@link Structure} constructor
  74. * figures out these properties based on its enclosing interface.<p>
  75. * <a name=library_loading></a>
  76. * <h2>Library Loading</h2>
  77. * <p>When JNA classes are loaded, the native shared library (jnidispatch) is
  78. * loaded as well. An attempt is made to load it from the any paths defined
  79. * in <code>jna.boot.library.path</code> (if defined), then the system library
  80. * path using {@link System#loadLibrary}, unless <code>jna.nosys=true</code>.
  81. * If not found, the appropriate library will be extracted from the class path
  82. * (into a temporary directory if found within a jar file) and loaded from
  83. * there, unless <code>jna.noclasspath=true</code>. If your system has
  84. * additional security constraints regarding execution or load of files
  85. * (SELinux, for example), you should probably install the native library in
  86. * an accessible location and configure your system accordingly, rather than
  87. * relying on JNA to extract the library from its own jar file.</p>
  88. * <p>To avoid the automatic unpacking (in situations where you want to force a
  89. * failure if the JNA native library is not properly installed on the system),
  90. * set the system property <code>jna.nounpack=true</code>.
  91. * </p>
  92. * <p>While this class and its corresponding native library are loaded, the
  93. * system property <code>jna.loaded</code> will be set. The property will be
  94. * cleared when native support has been unloaded (i.e. the Native class and
  95. * its underlying native support has been GC'd).</p>
  96. * <p>NOTE: all native functions are provided within this class to ensure that
  97. * all other JNA-provided classes and objects are GC'd and/or
  98. * finalized/disposed before this class is disposed and/or removed from
  99. * memory (most notably Memory and any other class which by default frees its
  100. * resources in a finalizer).</p>
  101. * <a name=native_library_loading></a>
  102. * <h2>Native Library Loading</h2>
  103. * Native libraries loaded via {@link #load(Class)} may be found in
  104. * <a href="NativeLibrary.html#library_search_paths">several locations</a>.
  105. * @see Library
  106. * @author Todd Fast, todd.fast@sun.com
  107. * @author twall@users.sf.net
  108. */
  109. public final class Native implements Version {
  110. private static final Logger LOG = Logger.getLogger(Native.class.getName());
  111. public static final Charset DEFAULT_CHARSET;
  112. public static final String DEFAULT_ENCODING;
  113. static {
  114. // JNA used the defaultCharset to determine which encoding to use when
  115. // converting strings to native char*. The defaultCharset is set from
  116. // the system property file.encoding. Up to JDK 17 its value defaulted
  117. // to the system default encoding. From JDK 18 onwards its default value
  118. // changed to UTF-8.
  119. // JDK 18+ exposes the native encoding as the new system property
  120. // native.encoding, prior versions don't have that property and will
  121. // report NULL for it.
  122. // The algorithm is simple: If native.encoding is set, it will be used
  123. // else the original implementation of Charset#defaultCharset is used
  124. String nativeEncoding = System.getProperty("native.encoding");
  125. Charset nativeCharset = null;
  126. if (nativeEncoding != null) {
  127. try {
  128. nativeCharset = Charset.forName(nativeEncoding);
  129. } catch (Exception ex) {
  130. LOG.log(Level.WARNING, "Failed to get charset for native.encoding value : '" + nativeEncoding + "'", ex);
  131. }
  132. }
  133. if (nativeCharset == null) {
  134. nativeCharset = Charset.defaultCharset();
  135. }
  136. DEFAULT_CHARSET = nativeCharset;
  137. DEFAULT_ENCODING = nativeCharset.name();
  138. }
  139. public static final boolean DEBUG_LOAD = Boolean.getBoolean("jna.debug_load");
  140. public static final boolean DEBUG_JNA_LOAD = Boolean.getBoolean("jna.debug_load.jna");
  141. private final static Level DEBUG_JNA_LOAD_LEVEL = DEBUG_JNA_LOAD ? Level.INFO : Level.FINE;
  142. // Used by tests, do not remove
  143. static String jnidispatchPath = null;
  144. private static final Map<Class<?>, Map<String, Object>> typeOptions = Collections.synchronizedMap(new WeakHashMap<Class<?>, Map<String, Object>>());
  145. private static final Map<Class<?>, Reference<?>> libraries = Collections.synchronizedMap(new WeakHashMap<Class<?>, Reference<?>>());
  146. private static final String _OPTION_ENCLOSING_LIBRARY = "enclosing-library";
  147. private static final UncaughtExceptionHandler DEFAULT_HANDLER =
  148. new UncaughtExceptionHandler() {
  149. @Override
  150. public void uncaughtException(Callback c, Throwable e) {
  151. LOG.log(Level.WARNING, "JNA: Callback " + c + " threw the following exception", e);
  152. }
  153. };
  154. private static UncaughtExceptionHandler callbackExceptionHandler = DEFAULT_HANDLER;
  155. /** The size of a native pointer (<code>void*</code>) on the current
  156. * platform, in bytes.
  157. */
  158. public static final int POINTER_SIZE;
  159. /** Size of a native <code>long</code> type, in bytes. */
  160. public static final int LONG_SIZE;
  161. /** Size of a native <code>wchar_t</code> type, in bytes. */
  162. public static final int WCHAR_SIZE;
  163. /** Size of a native <code>size_t</code> type, in bytes. */
  164. public static final int SIZE_T_SIZE;
  165. /** Size of a native <code>bool</code> type (C99 and later), in bytes. */
  166. public static final int BOOL_SIZE;
  167. /** Size of a native <code>long double</code> type (C99 and later), in bytes. */
  168. public static final int LONG_DOUBLE_SIZE;
  169. private static final int TYPE_VOIDP = 0;
  170. private static final int TYPE_LONG = 1;
  171. private static final int TYPE_WCHAR_T = 2;
  172. private static final int TYPE_SIZE_T = 3;
  173. private static final int TYPE_BOOL = 4;
  174. private static final int TYPE_LONG_DOUBLE = 5;
  175. static final int MAX_ALIGNMENT;
  176. static final int MAX_PADDING;
  177. /**
  178. * Version string must have the structure <major>.<minor>.<revision>
  179. * a bugfix change in the native code increments revision, the minor is
  180. * incremented for backwards compatible changes and the major version
  181. * is changed for backwards incompatbile changes.
  182. *
  183. * @param expectedVersion
  184. * @param nativeVersion
  185. * @return true if nativeVersion describes a version compatible to expectedVersion
  186. */
  187. static boolean isCompatibleVersion(String expectedVersion, String nativeVersion) {
  188. String[] expectedVersionParts = expectedVersion.split("\\.");
  189. String[] nativeVersionParts = nativeVersion.split("\\.");
  190. if(expectedVersionParts.length < 3 || nativeVersionParts.length < 3) {
  191. return false;
  192. }
  193. int expectedMajor = Integer.parseInt(expectedVersionParts[0]);
  194. int nativeMajor = Integer.parseInt(nativeVersionParts[0]);
  195. int expectedMinor = Integer.parseInt(expectedVersionParts[1]);
  196. int nativeMinor = Integer.parseInt(nativeVersionParts[1]);
  197. if(expectedMajor != nativeMajor) {
  198. return false;
  199. }
  200. if(expectedMinor > nativeMinor) {
  201. return false;
  202. }
  203. return true;
  204. }
  205. static {
  206. loadNativeDispatchLibrary();
  207. if (! isCompatibleVersion(VERSION_NATIVE, getNativeVersion())) {
  208. String LS = System.getProperty("line.separator");
  209. throw new Error(LS + LS
  210. + "There is an incompatible JNA native library installed on this system" + LS
  211. + "Expected: " + VERSION_NATIVE + LS
  212. + "Found: " + getNativeVersion() + LS
  213. + (jnidispatchPath != null
  214. ? "(at " + jnidispatchPath + ")" : System.getProperty("java.library.path"))
  215. + "." + LS
  216. + "To resolve this issue you may do one of the following:" + LS
  217. + " - remove or uninstall the offending library" + LS
  218. + " - set the system property jna.nosys=true" + LS
  219. + " - set jna.boot.library.path to include the path to the version of the " + LS
  220. + " jnidispatch library included with the JNA jar file you are using" + LS);
  221. }
  222. POINTER_SIZE = sizeof(TYPE_VOIDP);
  223. LONG_SIZE = sizeof(TYPE_LONG);
  224. WCHAR_SIZE = sizeof(TYPE_WCHAR_T);
  225. SIZE_T_SIZE = sizeof(TYPE_SIZE_T);
  226. BOOL_SIZE = sizeof(TYPE_BOOL);
  227. LONG_DOUBLE_SIZE = sizeof(TYPE_LONG_DOUBLE);
  228. // Perform initialization of other JNA classes until *after*
  229. // initializing the above final fields
  230. initIDs();
  231. if (Boolean.getBoolean("jna.protected")) {
  232. setProtected(true);
  233. }
  234. MAX_ALIGNMENT = Platform.isSPARC() || Platform.isWindows()
  235. || (Platform.isLinux() && (Platform.isARM() || Platform.isPPC() || Platform.isMIPS()))
  236. || Platform.isAIX()
  237. || (Platform.isAndroid() && !Platform.isIntel())
  238. ? 8 : LONG_SIZE;
  239. MAX_PADDING = (Platform.isMac() && Platform.isPPC()) ? 8 : MAX_ALIGNMENT;
  240. System.setProperty("jna.loaded", "true");
  241. }
  242. /** Force a dispose when the Native class is GC'd. */
  243. private static final Object finalizer = new Object() {
  244. @Override
  245. protected void finalize() throws Throwable {
  246. dispose();
  247. super.finalize();
  248. }
  249. };
  250. /** Properly dispose of JNA functionality.
  251. Called when this class is finalized and also from JNI when
  252. JNA's native shared library is unloaded.
  253. */
  254. private static void dispose() {
  255. CallbackReference.disposeAll();
  256. Memory.disposeAll();
  257. NativeLibrary.disposeAll();
  258. unregisterAll();
  259. jnidispatchPath = null;
  260. System.setProperty("jna.loaded", "false");
  261. }
  262. /** Remove any automatically unpacked native library.
  263. This will fail on windows, which disallows removal of any file that is
  264. still in use, so an alternative is required in that case. Mark
  265. the file that could not be deleted, and attempt to delete any
  266. temporaries on next startup.
  267. Do NOT force the class loader to unload the native library, since
  268. that introduces issues with cleaning up any extant JNA bits
  269. (e.g. Memory) which may still need use of the library before shutdown.
  270. */
  271. static boolean deleteLibrary(File lib) {
  272. if (lib.delete()) {
  273. return true;
  274. }
  275. // Couldn't delete it, mark for later deletion
  276. markTemporaryFile(lib);
  277. return false;
  278. }
  279. private Native() { }
  280. private static native void initIDs();
  281. /** Set whether native memory accesses are protected from invalid
  282. * accesses. This should only be set true when testing or debugging,
  283. * and should not be considered reliable or robust for applications
  284. * where JNA native calls are occurring on multiple threads.
  285. * Protected mode will be automatically set if the
  286. * system property <code>jna.protected</code> has a value of "true"
  287. * when the JNA library is first loaded.<p>
  288. * If not supported by the underlying platform, this setting will
  289. * have no effect.<p>
  290. * NOTE: On platforms which support signals (non-Windows), JNA uses
  291. * signals to trap errors. This may interfere with the JVM's own use of
  292. * signals. When protected mode is enabled, you should make use of the
  293. * jsig library, if available (see <a href="http://download.oracle.com/javase/6/docs/technotes/guides/vm/signal-chaining.html">Signal Chaining</a>).
  294. * In short, set the environment variable <code>LD_PRELOAD</code> to the
  295. * path to <code>libjsig.so</code> in your JRE lib directory
  296. * (usually ${java.home}/lib/${os.arch}/libjsig.so) before launching your
  297. * Java application.
  298. */
  299. public static synchronized native void setProtected(boolean enable);
  300. /** Returns whether protection is enabled. Check the result of this method
  301. * after calling {@link #setProtected setProtected(true)} to determine
  302. * if this platform supports protecting memory accesses.
  303. */
  304. public static synchronized native boolean isProtected();
  305. /** Utility method to get the native window ID for a Java {@link Window}
  306. * as a <code>long</code> value.
  307. * This method is primarily for X11-based systems, which use an opaque
  308. * <code>XID</code> (usually <code>long int</code>) to identify windows.
  309. * @throws HeadlessException if the current VM is running headless
  310. */
  311. public static long getWindowID(Window w) throws HeadlessException {
  312. return AWT.getWindowID(w);
  313. }
  314. /** Utility method to get the native window ID for a heavyweight Java
  315. * {@link Component} as a <code>long</code> value.
  316. * This method is primarily for X11-based systems, which use an opaque
  317. * <code>XID</code> (usually <code>long int</code>) to identify windows.
  318. * @throws HeadlessException if the current VM is running headless
  319. */
  320. public static long getComponentID(Component c) throws HeadlessException {
  321. return AWT.getComponentID(c);
  322. }
  323. /** Utility method to get the native window pointer for a Java
  324. * {@link Window} as a {@link Pointer} value. This method is primarily for
  325. * w32, which uses the <code>HANDLE</code> type (actually
  326. * <code>void *</code>) to identify windows.
  327. * @throws HeadlessException if the current VM is running headless
  328. */
  329. public static Pointer getWindowPointer(Window w) throws HeadlessException {
  330. return new Pointer(AWT.getWindowID(w));
  331. }
  332. /** Utility method to get the native window pointer for a heavyweight Java
  333. * {@link Component} as a {@link Pointer} value. This method is primarily
  334. * for w32, which uses the <code>HWND</code> type (actually
  335. * <code>void *</code>) to identify windows.
  336. * @throws HeadlessException if the current VM is running headless
  337. */
  338. public static Pointer getComponentPointer(Component c) throws HeadlessException {
  339. return new Pointer(AWT.getComponentID(c));
  340. }
  341. static native long getWindowHandle0(Component c);
  342. /** Convert a direct {@link Buffer} into a {@link Pointer}.
  343. * @throws IllegalArgumentException if the buffer is not direct.
  344. */
  345. public static Pointer getDirectBufferPointer(Buffer b) {
  346. long peer = _getDirectBufferPointer(b);
  347. return peer == 0 ? null : new Pointer(peer);
  348. }
  349. private static native long _getDirectBufferPointer(Buffer b);
  350. /**
  351. * Gets the charset belonging to the given {@code encoding}.
  352. * @param encoding The encoding - if {@code null} then the default platform
  353. * encoding is used.
  354. * @return The charset belonging to the given {@code encoding} or the platform default.
  355. * Never {@code null}.
  356. */
  357. private static Charset getCharset(String encoding) {
  358. Charset charset = null;
  359. if (encoding != null) {
  360. try {
  361. charset = Charset.forName(encoding);
  362. }
  363. catch(IllegalCharsetNameException e) {
  364. LOG.log(Level.WARNING, "JNA Warning: Encoding ''{0}'' is unsupported ({1})",
  365. new Object[]{encoding, e.getMessage()});
  366. }
  367. catch(UnsupportedCharsetException e) {
  368. LOG.log(Level.WARNING, "JNA Warning: Encoding ''{0}'' is unsupported ({1})",
  369. new Object[]{encoding, e.getMessage()});
  370. }
  371. }
  372. if (charset == null) {
  373. LOG.log(Level.WARNING, "JNA Warning: Using fallback encoding {0}", Native.DEFAULT_CHARSET);
  374. charset = Native.DEFAULT_CHARSET;
  375. }
  376. return charset;
  377. }
  378. /**
  379. * Obtain a Java String from the given native byte array. If there is
  380. * no NUL terminator, the String will comprise the entire array. The
  381. * encoding is obtained from {@link #getDefaultStringEncoding()}.
  382. *
  383. * @param buf The buffer containing the encoded bytes
  384. * @see #toString(byte[], String)
  385. */
  386. public static String toString(byte[] buf) {
  387. return toString(buf, getDefaultStringEncoding());
  388. }
  389. /**
  390. * Obtain a Java String from the given native byte array, using the given
  391. * encoding. If there is no NUL terminator, the String will comprise the
  392. * entire array.
  393. *
  394. * <p><strong>Usage note</strong>: This function assumes, that {@code buf}
  395. * holds a {@code char} array. This means only single-byte encodings are
  396. * supported.</p>
  397. *
  398. * @param buf The buffer containing the encoded bytes. Must not be {@code null}.
  399. * @param encoding The encoding name - if {@code null} then the platform
  400. * default encoding will be used
  401. */
  402. public static String toString(byte[] buf, String encoding) {
  403. return Native.toString(buf, Native.getCharset(encoding));
  404. }
  405. /**
  406. * Obtain a Java String from the given native byte array, using the given
  407. * encoding. If there is no NUL terminator, the String will comprise the
  408. * entire array.
  409. *
  410. * <p><strong>Usage note</strong>: This function assumes, that {@code buf}
  411. * holds a {@code char} array. This means only single-byte encodings are
  412. * supported.</p>
  413. *
  414. * @param buf The buffer containing the encoded bytes. Must not be {@code null}.
  415. * @param charset The charset to decode {@code buf}. Must not be {@code null}.
  416. */
  417. public static String toString(byte[] buf, Charset charset) {
  418. int len = buf.length;
  419. // find out the effective length
  420. for (int index = 0; index < len; index++) {
  421. if (buf[index] == 0) {
  422. len = index;
  423. break;
  424. }
  425. }
  426. if (len == 0) {
  427. return "";
  428. }
  429. return new String(buf, 0, len, charset);
  430. }
  431. /**
  432. * Obtain a Java String from the given native wchar_t array. If there is
  433. * no NUL terminator, the String will comprise the entire array.
  434. *
  435. * @param buf The buffer containing the characters
  436. */
  437. public static String toString(char[] buf) {
  438. int len = buf.length;
  439. for (int index = 0; index < len; index++) {
  440. if (buf[index] == '\0') {
  441. len = index;
  442. break;
  443. }
  444. }
  445. if (len == 0) {
  446. return "";
  447. } else {
  448. return new String(buf, 0, len);
  449. }
  450. }
  451. /**
  452. * Converts a &quot;list&quot; of strings each null terminated
  453. * into a {@link List} of {@link String} values. The end of the
  454. * list is signaled by an extra NULL value at the end or by the
  455. * end of the buffer.
  456. * @param buf The buffer containing the strings
  457. * @return A {@link List} of all the strings in the buffer
  458. * @see #toStringList(char[], int, int)
  459. */
  460. public static List<String> toStringList(char[] buf) {
  461. return toStringList(buf, 0, buf.length);
  462. }
  463. /**
  464. * Converts a &quot;list&quot; of strings each null terminated
  465. * into a {@link List} of {@link String} values. The end of the
  466. * list is signaled by an extra NULL value at the end or by the
  467. * end of the data.
  468. * @param buf The buffer containing the strings
  469. * @param offset Offset to start parsing
  470. * @param len The total characters to parse
  471. * @return A {@link List} of all the strings in the buffer
  472. */
  473. public static List<String> toStringList(char[] buf, int offset, int len) {
  474. List<String> list = new ArrayList<String>();
  475. int lastPos = offset;
  476. int maxPos = offset + len;
  477. for (int curPos = offset; curPos < maxPos; curPos++) {
  478. if (buf[curPos] != '\0') {
  479. continue;
  480. }
  481. // check if found the extra null terminator
  482. if (lastPos == curPos) {
  483. return list;
  484. }
  485. String value = new String(buf, lastPos, curPos - lastPos);
  486. list.add(value);
  487. lastPos = curPos + 1; // skip the '\0'
  488. }
  489. // This point is reached if there is no double null terminator
  490. if (lastPos < maxPos) {
  491. String value = new String(buf, lastPos, maxPos - lastPos);
  492. list.add(value);
  493. }
  494. return list;
  495. }
  496. /** Map a library interface to the current process, providing
  497. * the explicit interface class.
  498. * Native libraries loaded via this method may be found in
  499. * <a href="NativeLibrary.html#library_search_paths">several locations</a>.
  500. * @param <T> Type of expected wrapper
  501. * @param interfaceClass The implementation wrapper interface
  502. * @return an instance of the requested interface, mapped to the current
  503. * process.
  504. * @throws UnsatisfiedLinkError if the library cannot be found or
  505. * dependent libraries are missing.
  506. */
  507. public static <T extends Library> T load(Class<T> interfaceClass) {
  508. return load(null, interfaceClass);
  509. }
  510. /** Map a library interface to the current process, providing
  511. * the explicit interface class. Any options provided for the library are
  512. * cached and associated with the library and any of its defined
  513. * structures and/or functions.
  514. * Native libraries loaded via this method may be found in
  515. * <a href="NativeLibrary.html#library_search_paths">several locations</a>.
  516. * @param <T> Type of expected wrapper
  517. * @param interfaceClass The implementation wrapper interface
  518. * @param options Map of library options
  519. * @return an instance of the requested interface, mapped to the current
  520. * process.
  521. * @throws UnsatisfiedLinkError if the library cannot be found or
  522. * dependent libraries are missing.
  523. * @see #load(String, Class, Map)
  524. */
  525. public static <T extends Library> T load(Class<T> interfaceClass, Map<String, ?> options) {
  526. return load(null, interfaceClass, options);
  527. }
  528. /** Map a library interface to the given shared library, providing
  529. * the explicit interface class.
  530. * If <code>name</code> is null, attempts to map onto the current process.
  531. * Native libraries loaded via this method may be found in
  532. * <a href="NativeLibrary.html#library_search_paths">several locations</a>.
  533. * @param <T> Type of expected wrapper
  534. * @param name Library base name
  535. * @param interfaceClass The implementation wrapper interface
  536. * @return an instance of the requested interface, mapped to the indicated
  537. * native library.
  538. * @throws UnsatisfiedLinkError if the library cannot be found or
  539. * dependent libraries are missing.
  540. * @see #load(String, Class, Map)
  541. */
  542. public static <T extends Library> T load(String name, Class<T> interfaceClass) {
  543. return load(name, interfaceClass, Collections.<String, Object>emptyMap());
  544. }
  545. /** Load a library interface from the given shared library, providing
  546. * the explicit interface class and a map of options for the library.
  547. * If no library options are detected the map is interpreted as a map
  548. * of Java method names to native function names.<p>
  549. * If <code>name</code> is null, attempts to map onto the current process.
  550. * Native libraries loaded via this method may be found in
  551. * <a href="NativeLibrary.html#library_search_paths">several locations</a>.
  552. * @param <T> Type of expected wrapper
  553. * @param name Library base name
  554. * @param interfaceClass The implementation wrapper interface
  555. * @param options Map of library options
  556. * @return an instance of the requested interface, mapped to the indicated
  557. * native library.
  558. * @throws UnsatisfiedLinkError if the library cannot be found or
  559. * dependent libraries are missing.
  560. */
  561. public static <T extends Library> T load(String name, Class<T> interfaceClass, Map<String, ?> options) {
  562. if (!Library.class.isAssignableFrom(interfaceClass)) {
  563. // Maybe still possible if the caller is not using generics?
  564. throw new IllegalArgumentException("Interface (" + interfaceClass.getSimpleName() + ")"
  565. + " of library=" + name + " does not extend " + Library.class.getSimpleName());
  566. }
  567. Library.Handler handler = new Library.Handler(name, interfaceClass, options);
  568. ClassLoader loader = interfaceClass.getClassLoader();
  569. Object proxy = Proxy.newProxyInstance(loader, new Class[] {interfaceClass}, handler);
  570. cacheOptions(interfaceClass, options, proxy);
  571. return interfaceClass.cast(proxy);
  572. }
  573. /**
  574. * Provided for improved compatibility between JNA 4.X and 5.X
  575. *
  576. * @see Native#load(java.lang.Class)
  577. */
  578. @Deprecated
  579. public static <T> T loadLibrary(Class<T> interfaceClass) {
  580. return loadLibrary(null, interfaceClass);
  581. }
  582. /**
  583. * Provided for improved compatibility between JNA 4.X and 5.X
  584. *
  585. * @see Native#load(java.lang.Class, java.util.Map)
  586. */
  587. @Deprecated
  588. public static <T> T loadLibrary(Class<T> interfaceClass, Map<String, ?> options) {
  589. return loadLibrary(null, interfaceClass, options);
  590. }
  591. /**
  592. * Provided for improved compatibility between JNA 4.X and 5.X
  593. *
  594. * @see Native#load(java.lang.String, java.lang.Class)
  595. */
  596. @Deprecated
  597. public static <T> T loadLibrary(String name, Class<T> interfaceClass) {
  598. return loadLibrary(name, interfaceClass, Collections.<String, Object>emptyMap());
  599. }
  600. /**
  601. * Provided for improved compatibility between JNA 4.X and 5.X
  602. *
  603. * @see Native#load(java.lang.String, java.lang.Class, java.util.Map)
  604. */
  605. @Deprecated
  606. public static <T> T loadLibrary(String name, Class<T> interfaceClass, Map<String, ?> options) {
  607. if (!Library.class.isAssignableFrom(interfaceClass)) {
  608. // Maybe still possible if the caller is not using generics?
  609. throw new IllegalArgumentException("Interface (" + interfaceClass.getSimpleName() + ")"
  610. + " of library=" + name + " does not extend " + Library.class.getSimpleName());
  611. }
  612. Library.Handler handler = new Library.Handler(name, interfaceClass, options);
  613. ClassLoader loader = interfaceClass.getClassLoader();
  614. Object proxy = Proxy.newProxyInstance(loader, new Class[] {interfaceClass}, handler);
  615. cacheOptions(interfaceClass, options, proxy);
  616. return interfaceClass.cast(proxy);
  617. }
  618. /** Attempts to force initialization of an instance of the library interface
  619. * by loading a public static field of the requisite type.
  620. * Returns whether an instance variable was instantiated.
  621. * Expects that lock on libraries is already held
  622. */
  623. private static void loadLibraryInstance(Class<?> cls) {
  624. if (cls != null && !libraries.containsKey(cls)) {
  625. try {
  626. Field[] fields = cls.getFields();
  627. for (int i=0;i < fields.length;i++) {
  628. Field field = fields[i];
  629. if (field.getType() == cls
  630. && Modifier.isStatic(field.getModifiers())) {
  631. // Ensure the field gets initialized by reading it
  632. field.setAccessible(true); // interface might be private
  633. libraries.put(cls, new WeakReference<Object>(field.get(null)));
  634. break;
  635. }
  636. }
  637. }
  638. catch (Exception e) {
  639. throw new IllegalArgumentException("Could not access instance of "
  640. + cls + " (" + e + ")");
  641. }
  642. }
  643. }
  644. /**
  645. * Find the library interface corresponding to the given class. Checks
  646. * all ancestor classes and interfaces for a declaring class which
  647. * implements {@link Library}.
  648. * @param cls The given class
  649. * @return The enclosing class
  650. */
  651. static Class<?> findEnclosingLibraryClass(Class<?> cls) {
  652. if (cls == null) {
  653. return null;
  654. }
  655. // Check for direct-mapped libraries, which won't necessarily
  656. // implement com.sun.jna.Library.
  657. Map<String, ?> libOptions = typeOptions.get(cls);
  658. if (libOptions != null) {
  659. Class<?> enclosingClass = (Class<?>)libOptions.get(_OPTION_ENCLOSING_LIBRARY);
  660. if (enclosingClass != null) {
  661. return enclosingClass;
  662. }
  663. return cls;
  664. }
  665. if (Library.class.isAssignableFrom(cls)) {
  666. return cls;
  667. }
  668. if (Callback.class.isAssignableFrom(cls)) {
  669. cls = CallbackReference.findCallbackClass(cls);
  670. }
  671. Class<?> declaring = cls.getDeclaringClass();
  672. Class<?> fromDeclaring = findEnclosingLibraryClass(declaring);
  673. if (fromDeclaring != null) {
  674. return fromDeclaring;
  675. }
  676. return findEnclosingLibraryClass(cls.getSuperclass());
  677. }
  678. /** Return the preferred native library configuration options for the given
  679. * class. First attempts to load any field of the interface type within
  680. * the interface mapping, then checks the cache for any specified library
  681. * options. If none found, a set of library options will be generated
  682. * from the fields (by order of precedence) <code>OPTIONS</code> (a {@link
  683. * Map}), <code>TYPE_MAPPER</code> (a {@link TypeMapper}),
  684. * <code>STRUCTURE_ALIGNMENT</code> (an {@link Integer}), and
  685. * <code>STRING_ENCODING</code> (a {@link String}).
  686. *
  687. * @param type The type class
  688. * @return The options map
  689. */
  690. public static Map<String, Object> getLibraryOptions(Class<?> type) {
  691. Map<String, Object> libraryOptions;
  692. // cached already ?
  693. libraryOptions = typeOptions.get(type);
  694. if (libraryOptions != null) {
  695. return libraryOptions;
  696. }
  697. Class<?> mappingClass = findEnclosingLibraryClass(type);
  698. if (mappingClass != null) {
  699. loadLibraryInstance(mappingClass);
  700. } else {
  701. mappingClass = type;
  702. }
  703. libraryOptions = typeOptions.get(mappingClass);
  704. if (libraryOptions != null) {
  705. typeOptions.put(type, libraryOptions); // cache for next time
  706. return libraryOptions;
  707. }
  708. try {
  709. Field field = mappingClass.getField("OPTIONS");
  710. field.setAccessible(true);
  711. libraryOptions = (Map<String, Object>) field.get(null);
  712. if (libraryOptions == null) {
  713. throw new IllegalStateException("Null options field");
  714. }
  715. } catch (NoSuchFieldException e) {
  716. libraryOptions = Collections.<String, Object>emptyMap();
  717. } catch (Exception e) {
  718. throw new IllegalArgumentException("OPTIONS must be a public field of type java.util.Map (" + e + "): " + mappingClass);
  719. }
  720. // Make a clone of the original options
  721. libraryOptions = new HashMap<String, Object>(libraryOptions);
  722. if (!libraryOptions.containsKey(Library.OPTION_TYPE_MAPPER)) {
  723. libraryOptions.put(Library.OPTION_TYPE_MAPPER, lookupField(mappingClass, "TYPE_MAPPER", TypeMapper.class));
  724. }
  725. if (!libraryOptions.containsKey(Library.OPTION_STRUCTURE_ALIGNMENT)) {
  726. libraryOptions.put(Library.OPTION_STRUCTURE_ALIGNMENT, lookupField(mappingClass, "STRUCTURE_ALIGNMENT", Integer.class));
  727. }
  728. if (!libraryOptions.containsKey(Library.OPTION_STRING_ENCODING)) {
  729. libraryOptions.put(Library.OPTION_STRING_ENCODING, lookupField(mappingClass, "STRING_ENCODING", String.class));
  730. }
  731. libraryOptions = cacheOptions(mappingClass, libraryOptions, null);
  732. // Store the original lookup class, if different from the mapping class
  733. if (type != mappingClass) {
  734. typeOptions.put(type, libraryOptions);
  735. }
  736. return libraryOptions;
  737. }
  738. private static Object lookupField(Class<?> mappingClass, String fieldName, Class<?> resultClass) {
  739. try {
  740. Field field = mappingClass.getField(fieldName);
  741. field.setAccessible(true);
  742. return field.get(null);
  743. }
  744. catch (NoSuchFieldException e) {
  745. return null;
  746. }
  747. catch (Exception e) {
  748. throw new IllegalArgumentException(fieldName + " must be a public field of type "
  749. + resultClass.getName() + " ("
  750. + e + "): " + mappingClass);
  751. }
  752. }
  753. /** Return the preferred {@link TypeMapper} for the given native interface.
  754. * See {@link com.sun.jna.Library#OPTION_TYPE_MAPPER}.
  755. */
  756. public static TypeMapper getTypeMapper(Class<?> cls) {
  757. Map<String, ?> options = getLibraryOptions(cls);
  758. return (TypeMapper) options.get(Library.OPTION_TYPE_MAPPER);
  759. }
  760. /**
  761. * @param cls The native interface type
  762. * @return The preferred string encoding for the given native interface.
  763. * If there is no setting, defaults to the {@link #getDefaultStringEncoding()}.
  764. * @see com.sun.jna.Library#OPTION_STRING_ENCODING
  765. */
  766. public static String getStringEncoding(Class<?> cls) {
  767. Map<String, ?> options = getLibraryOptions(cls);
  768. String encoding = (String) options.get(Library.OPTION_STRING_ENCODING);
  769. return encoding != null ? encoding : getDefaultStringEncoding();
  770. }
  771. /**
  772. * @return The default string encoding. Returns the value of the system
  773. * property <code>jna.encoding</code> or {@link Native#DEFAULT_ENCODING}.
  774. */
  775. public static String getDefaultStringEncoding() {
  776. return System.getProperty("jna.encoding", DEFAULT_ENCODING);
  777. }
  778. /**
  779. * @param cls The native interface type
  780. * @return The preferred structure alignment for the given native interface.
  781. * @see com.sun.jna.Library#OPTION_STRUCTURE_ALIGNMENT
  782. */
  783. public static int getStructureAlignment(Class<?> cls) {
  784. Integer alignment = (Integer)getLibraryOptions(cls).get(Library.OPTION_STRUCTURE_ALIGNMENT);
  785. return alignment == null ? Structure.ALIGN_DEFAULT : alignment;
  786. }
  787. /**
  788. * @param s The input string
  789. * @return A byte array corresponding to the given String. The encoding
  790. * used is obtained from {@link #getDefaultStringEncoding()}.
  791. */
  792. static byte[] getBytes(String s) {
  793. return getBytes(s, getDefaultStringEncoding());
  794. }
  795. /**
  796. * @param s The string. Must not be {@code null}.
  797. * @param encoding The encoding - if {@code null} then the default platform
  798. * encoding is used
  799. * @return A byte array corresponding to the given String, using the given
  800. * encoding. If the encoding is not found default to the platform native
  801. * encoding.
  802. */
  803. static byte[] getBytes(String s, String encoding) {
  804. return Native.getBytes(s, Native.getCharset(encoding));
  805. }
  806. /**
  807. * @param s The string. Must not be {@code null}.
  808. * @param charset The charset used to encode {@code s}. Must not be {@code null}.
  809. * @return A byte array corresponding to the given String, using the given
  810. * charset.
  811. */
  812. static byte[] getBytes(String s, Charset charset) {
  813. return s.getBytes(charset);
  814. }
  815. /**
  816. * @param s The string
  817. * @return A NUL-terminated byte buffer equivalent to the given String,
  818. * using the encoding returned by {@link #getDefaultStringEncoding()}.
  819. * @see #toByteArray(String, String)
  820. */
  821. public static byte[] toByteArray(String s) {
  822. return toByteArray(s, getDefaultStringEncoding());
  823. }
  824. /**
  825. * @param s The string. Must not be {@code null}.
  826. * @param encoding The encoding - if {@code null} then the default platform
  827. * encoding is used
  828. * @return A NUL-terminated byte buffer equivalent to the given String,
  829. * using the given encoding.
  830. * @see #getBytes(String, String)
  831. */
  832. public static byte[] toByteArray(String s, String encoding) {
  833. return Native.toByteArray(s, Native.getCharset(encoding));
  834. }
  835. /**
  836. * @param s The string. Must not be {@code null}.
  837. * @param charset The charset used to encode {@code s}. Must not be {@code null}.
  838. * @return A NUL-terminated byte buffer equivalent to the given String,
  839. * using the given charset.
  840. * @see #getBytes(String, String)
  841. */
  842. public static byte[] toByteArray(String s, Charset charset) {
  843. byte[] bytes = Native.getBytes(s, charset);
  844. byte[] buf = new byte[bytes.length+1];
  845. System.arraycopy(bytes, 0, buf, 0, bytes.length);
  846. return buf;
  847. }
  848. /**
  849. * @param s The string
  850. * @return A NUL-terminated wide character buffer equivalent to the given string.
  851. */
  852. public static char[] toCharArray(String s) {
  853. char[] chars = s.toCharArray();
  854. char[] buf = new char[chars.length+1];
  855. System.arraycopy(chars, 0, buf, 0, chars.length);
  856. return buf;
  857. }
  858. /**
  859. * Loads the JNA stub library.
  860. * First tries jna.boot.library.path, then the system path, then from the
  861. * jar file.
  862. */
  863. private static void loadNativeDispatchLibrary() {
  864. if (!Boolean.getBoolean("jna.nounpack")) {
  865. try {
  866. removeTemporaryFiles();
  867. }
  868. catch(IOException e) {
  869. LOG.log(Level.WARNING, "JNA Warning: IOException removing temporary files", e);
  870. }
  871. }
  872. String libName = System.getProperty("jna.boot.library.name", "jnidispatch");
  873. String bootPath = System.getProperty("jna.boot.library.path");
  874. if (bootPath != null) {
  875. // String.split not available in 1.4
  876. StringTokenizer dirs = new StringTokenizer(bootPath, File.pathSeparator);
  877. while (dirs.hasMoreTokens()) {
  878. String dir = dirs.nextToken();
  879. File file = new File(new File(dir), System.mapLibraryName(libName).replace(".dylib", ".jnilib"));
  880. String path = file.getAbsolutePath();
  881. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Looking in {0}", path);
  882. if (file.exists()) {
  883. try {
  884. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Trying {0}", path);
  885. System.setProperty("jnidispatch.path", path);
  886. System.load(path);
  887. jnidispatchPath = path;
  888. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Found jnidispatch at {0}", path);
  889. return;
  890. } catch (UnsatisfiedLinkError ex) {
  891. // Not a problem if already loaded in anoteher class loader
  892. // Unfortunately we can't distinguish the difference...
  893. //System.out.println("File found at " + file + " but not loadable: " + ex.getMessage());
  894. }
  895. }
  896. if (Platform.isMac()) {
  897. String orig, ext;
  898. if (path.endsWith("dylib")) {
  899. orig = "dylib";
  900. ext = "jnilib";
  901. } else {
  902. orig = "jnilib";
  903. ext = "dylib";
  904. }
  905. path = path.substring(0, path.lastIndexOf(orig)) + ext;
  906. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Looking in {0}", path);
  907. if (new File(path).exists()) {
  908. try {
  909. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Trying {0}", path);
  910. System.setProperty("jnidispatch.path", path);
  911. System.load(path);
  912. jnidispatchPath = path;
  913. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Found jnidispatch at {0}", path);
  914. return;
  915. } catch (UnsatisfiedLinkError ex) {
  916. LOG.log(Level.WARNING, "File found at " + path + " but not loadable: " + ex.getMessage(), ex);
  917. }
  918. }
  919. }
  920. }
  921. }
  922. String jnaNosys = System.getProperty("jna.nosys", "true");
  923. if ((!Boolean.parseBoolean(jnaNosys)) || Platform.isAndroid()) {
  924. try {
  925. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Trying (via loadLibrary) {0}", libName);
  926. System.loadLibrary(libName);
  927. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Found jnidispatch on system path");
  928. return;
  929. }
  930. catch(UnsatisfiedLinkError e) {
  931. }
  932. }
  933. if (!Boolean.getBoolean("jna.noclasspath")) {
  934. loadNativeDispatchLibraryFromClasspath();
  935. }
  936. else {
  937. throw new UnsatisfiedLinkError("Unable to locate JNA native support library");
  938. }
  939. }
  940. static final String JNA_TMPLIB_PREFIX = "jna";
  941. /**
  942. * Attempts to load the native library resource from the filesystem,
  943. * extracting the JNA stub library from jna.jar if not already available.
  944. */
  945. private static void loadNativeDispatchLibraryFromClasspath() {
  946. try {
  947. String mappedName = System.mapLibraryName("jnidispatch").replace(".dylib", ".jnilib");
  948. if(Platform.isAIX()) {
  949. // OpenJDK is reported to map to .so -- this works around the
  950. // difference between J9 and OpenJDK
  951. mappedName = "libjnidispatch.a";
  952. }
  953. String libName = "/com/sun/jna/" + Platform.RESOURCE_PREFIX + "/" + mappedName;
  954. File lib = extractFromResourcePath(libName, Native.class.getClassLoader());
  955. if (lib == null) {
  956. if (lib == null) {
  957. throw new UnsatisfiedLinkError("Could not find JNA native support");
  958. }
  959. }
  960. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Trying {0}", lib.getAbsolutePath());
  961. System.setProperty("jnidispatch.path", lib.getAbsolutePath());
  962. System.load(lib.getAbsolutePath());
  963. jnidispatchPath = lib.getAbsolutePath();
  964. LOG.log(DEBUG_JNA_LOAD_LEVEL, "Found jnidispatch at {0}", jnidispatchPath);
  965. // Attempt to delete immediately once jnidispatch is successfully
  966. // loaded. This avoids the complexity of trying to do so on "exit",
  967. // which point can vary under different circumstances (native
  968. // compilation, dynamically loaded modules, normal application, etc).
  969. if (isUnpacked(lib)
  970. && !Boolean.getBoolean("jnidispatch.preserve")) {
  971. deleteLibrary(lib);
  972. }
  973. }
  974. catch(IOException e) {
  975. throw new UnsatisfiedLinkError(e.getMessage());
  976. }
  977. }
  978. /** Identify temporary files unpacked from classpath jar files. */
  979. static boolean isUnpacked(File file) {
  980. return file.getName().startsWith(JNA_TMPLIB_PREFIX);
  981. }
  982. /** Attempt to extract a native library from the current resource path,
  983. * using the current thread context class loader.
  984. * @param name Base name of native library to extract. May also be an
  985. * absolute resource path (i.e. starts with "/"), in which case the
  986. * no transformations of the library name are performed. If only the base
  987. * name is given, the resource path is attempted both with and without
  988. * {@link Platform#RESOURCE_PREFIX}, after mapping the library name via
  989. * {@link NativeLibrary#mapSharedLibraryName(String)}.
  990. * @return File indicating extracted resource on disk
  991. * @throws IOException if resource not found
  992. */
  993. public static File extractFromResourcePath(String name) throws IOException {
  994. return extractFromResourcePath(name, null);
  995. }
  996. /** Attempt to extract a native library from the resource path using the
  997. * given class loader.
  998. * @param name Base name of native library to extract. May also be an
  999. * absolute resource path (i.e. starts with "/"), in which case the
  1000. * no transformations of the library name are performed. If only the base
  1001. * name is given, the resource path is attempted both with and without
  1002. * {@link Platform#RESOURCE_PREFIX}, after mapping the library name via
  1003. * {@link NativeLibrary#mapSharedLibraryName(String)}.
  1004. * @param loader Class loader to use to load resources
  1005. * @return File indicating extracted resource on disk
  1006. * @throws IOException if resource not found
  1007. */
  1008. public static File extractFromResourcePath(String name, ClassLoader loader) throws IOException {
  1009. final Level DEBUG = (DEBUG_LOAD
  1010. || (DEBUG_JNA_LOAD && name.contains("jnidispatch"))) ? Level.INFO : Level.FINE;
  1011. if (loader == null) {
  1012. loader = Thread.currentThread().getContextClassLoader();
  1013. // Context class loader is not guaranteed to be set
  1014. if (loader == null) {
  1015. loader = Native.class.getClassLoader();
  1016. }
  1017. }
  1018. LOG.log(DEBUG, "Looking in classpath from {0} for {1}", new Object[]{loader, name});
  1019. String libname = name.startsWith("/") ? name : NativeLibrary.mapSharedLibraryName(name);
  1020. String resourcePath = name.startsWith("/") ? name : Platform.RESOURCE_PREFIX + "/" + libname;
  1021. if (resourcePath.startsWith("/")) {
  1022. resourcePath = resourcePath.substring(1);
  1023. }
  1024. URL url = loader.getResource(resourcePath);
  1025. if (url == null) {
  1026. if (resourcePath.startsWith(Platform.RESOURCE_PREFIX)) {
  1027. // Fallback for legacy darwin behaviour: darwin was in the past
  1028. // special cased in that all architectures were mapped to the same
  1029. // prefix and it was expected, that a fat binary was present at that
  1030. // point, that contained all architectures.
  1031. if(Platform.RESOURCE_PREFIX.startsWith("darwin")) {
  1032. url = loader.getResource("darwin/" + resourcePath.substring(Platform.RESOURCE_PREFIX.length() + 1));
  1033. }
  1034. if (url == null) {
  1035. // If not found with the standard resource prefix, try without it
  1036. url = loader.getResource(libname);
  1037. }
  1038. } else if (resourcePath.startsWith("com/sun/jna/" + Platform.RESOURCE_PREFIX + "/")) {
  1039. // Fallback for legacy darwin behaviour: darwin was in the past
  1040. // special cased in that all architectures were mapped to the same
  1041. // prefix and it was expected, that a fat binary was present at that
  1042. // point, that contained all architectures.
  1043. if(Platform.RESOURCE_PREFIX.startsWith("com/sun/jna/darwin")) {
  1044. url = loader.getResource("com/sun/jna/darwin" + resourcePath.substring(("com/sun/jna/" + Platform.RESOURCE_PREFIX).length() + 1));
  1045. }
  1046. if (url == null) {
  1047. // If not found with the standard resource prefix, try without it
  1048. url = loader.getResource(libname);
  1049. }
  1050. }
  1051. }
  1052. if (url == null) {
  1053. String path = System.getProperty("java.class.path");
  1054. if (loader instanceof URLClassLoader) {
  1055. path = Arrays.asList(((URLClassLoader)loader).getURLs()).toString();
  1056. }
  1057. throw new IOException("Native library (" + resourcePath + ") not found in resource path (" + path + ")");
  1058. }
  1059. LOG.log(DEBUG, "Found library resource at {0}", url);
  1060. File lib = null;
  1061. if (url.getProtocol().toLowerCase().equals("file")) {
  1062. try {
  1063. lib = new File(new URI(url.toString()));
  1064. }
  1065. catch(URISyntaxException e) {
  1066. lib = new File(url.getPath());
  1067. }
  1068. LOG.log(DEBUG, "Looking in {0}", lib.getAbsolutePath());
  1069. if (!lib.exists()) {
  1070. throw new IOException("File URL " + url + " could not be properly decoded");
  1071. }
  1072. }
  1073. else if (!Boolean.getBoolean("jna.nounpack")) {
  1074. InputStream is = url.openStream();
  1075. if (is == null) {
  1076. throw new IOException("Can't obtain InputStream for " + resourcePath);
  1077. }
  1078. FileOutputStream fos = null;
  1079. try {
  1080. // Suffix is required on windows, or library fails to load
  1081. // Let Java pick the suffix, except on windows, to avoid
  1082. // problems with Web Start.
  1083. File dir = getTempDir();
  1084. lib = File.createTempFile(JNA_TMPLIB_PREFIX, Platform.isWindows()?".dll":null, dir);
  1085. if (!Boolean.getBoolean("jnidispatch.preserve")) {
  1086. lib.deleteOnExit();
  1087. }
  1088. LOG.log(DEBUG, "Extracting library to {0}", lib.getAbsolutePath());
  1089. fos = new FileOutputStream(lib);
  1090. int count;
  1091. byte[] buf = new byte[1024];
  1092. while ((count = is.read(buf, 0, buf.length)) > 0) {
  1093. fos.write(buf, 0, count);
  1094. }
  1095. }
  1096. catch(IOException e) {
  1097. throw new IOException("Failed to create temporary file for " + name + " library: " + e.getMessage());
  1098. }
  1099. finally {
  1100. try { is.close(); } catch(IOException e) { }
  1101. if (fos != null) {
  1102. try { fos.close(); } catch(IOException e) { }
  1103. }
  1104. }
  1105. }
  1106. return lib;
  1107. }
  1108. /**
  1109. * Initialize field and method IDs for native methods of this class.
  1110. * Returns the size of a native pointer.
  1111. **/
  1112. private static native int sizeof(int type);
  1113. private static native String getNativeVersion();
  1114. private static native String getAPIChecksum();
  1115. /** Retrieve last error set by the OS. This corresponds to
  1116. * <code>GetLastError()</code> on Windows, and <code>errno</code> on
  1117. * most other platforms. The value is preserved per-thread, but whether
  1118. * the original value is per-thread depends on the underlying OS.
  1119. * <p>
  1120. * An alternative method of obtaining the last error result is
  1121. * to declare your mapped method to throw {@link LastErrorException}
  1122. * instead. If a method's signature includes a throw of {@link
  1123. * LastErrorException}, the last error will be set to zero before the
  1124. * native call and a {@link LastErrorException} will be raised if the last
  1125. * error value is non-zero after the call, regardless of the actual
  1126. * returned value from the native function.</p>
  1127. */
  1128. public static native int getLastError();
  1129. /** Set the OS last error code. The value will be saved on a per-thread
  1130. * basis.
  1131. */
  1132. public static native void setLastError(int code);
  1133. /**
  1134. * Returns a synchronized (thread-safe) library backed by the specified
  1135. * library. This wrapping will prevent simultaneous invocations of any
  1136. * functions mapped to a given {@link NativeLibrary}. Note that the
  1137. * native library may still be sensitive to being called from different
  1138. * threads.
  1139. * <p>
  1140. * @param library the library to be "wrapped" in a synchronized library.
  1141. * @return a synchronized view of the specified library.
  1142. */
  1143. public static Library synchronizedLibrary(final Library library) {
  1144. Class<?> cls = library.getClass();
  1145. if (!Proxy.isProxyClass(cls)) {
  1146. throw new IllegalArgumentException("Library must be a proxy class");
  1147. }
  1148. InvocationHandler ih = Proxy.getInvocationHandler(library);
  1149. if (!(ih instanceof Library.Handler)) {
  1150. throw new IllegalArgumentException("Unrecognized proxy handler: " + ih);
  1151. }
  1152. final Library.Handler handler = (Library.Handler)ih;
  1153. InvocationHandler newHandler = new InvocationHandler() {
  1154. @Override
  1155. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  1156. synchronized(handler.getNativeLibrary()) {
  1157. return handler.invoke(library, method, args);
  1158. }
  1159. }
  1160. };
  1161. return (Library)Proxy.newProxyInstance(cls.getClassLoader(),
  1162. cls.getInterfaces(),
  1163. newHandler);
  1164. }
  1165. /** If running web start, determine the location of a given native
  1166. * library. This value may be used to properly set
  1167. * <code>jna.library.path</code> so that JNA can load libraries identified
  1168. * by the &lt;nativelib&gt; tag in the JNLP configuration file. Returns
  1169. * <code>null</code> if the Web Start native library cache location can not
  1170. * be determined. Note that the path returned may be different for any
  1171. * given library name.
  1172. * <p>
  1173. * Use <code>System.getProperty("javawebstart.version")</code> to detect
  1174. * whether your code is running under Web Start.
  1175. * @throws UnsatisfiedLinkError if the library can't be found by the
  1176. * Web Start class loader, which usually means it wasn't included as
  1177. * a <code>&lt;nativelib&gt;</code> resource in the JNLP file.
  1178. * @return null if unable to query the web start loader.
  1179. */
  1180. public static String getWebStartLibraryPath(final String libName) {
  1181. if (System.getProperty("javawebstart.version") == null)
  1182. return null;
  1183. try {
  1184. final ClassLoader cl = Native.class.getClassLoader();
  1185. Method m = AccessController.doPrivileged(new PrivilegedAction<Method>() {
  1186. @Override
  1187. public Method run() {
  1188. try {
  1189. Method m = ClassLoader.class.getDeclaredMethod("findLibrary", new Class[] { String.class });
  1190. m.setAccessible(true);
  1191. return m;
  1192. }
  1193. catch(Exception e) {
  1194. return null;
  1195. }
  1196. }
  1197. });
  1198. String libpath = (String)m.invoke(cl, new Object[] { libName });
  1199. if (libpath != null) {
  1200. return new File(libpath).getParent();
  1201. }
  1202. return null;
  1203. }
  1204. catch (Exception e) {
  1205. return null;
  1206. }
  1207. }
  1208. /** Perform cleanup of automatically unpacked native shared library.
  1209. */
  1210. static void markTemporaryFile(File file) {
  1211. // If we can't force an unload/delete, flag the file for later
  1212. // deletion
  1213. try {
  1214. File marker = new File(file.getParentFile(), file.getName() + ".x");
  1215. marker.createNewFile();
  1216. }
  1217. catch(IOException e) { e.printStackTrace(); }
  1218. }
  1219. /** Obtain a directory suitable for writing JNA-specific temporary files.
  1220. Override with <code>jna.tmpdir</code>
  1221. */
  1222. static File getTempDir() throws IOException {
  1223. File jnatmp;
  1224. String prop = System.getProperty("jna.tmpdir");
  1225. if (prop != null) {
  1226. jnatmp = new File(prop);
  1227. jnatmp.mkdirs();
  1228. }
  1229. else {
  1230. File tmp = new File(System.getProperty("java.io.tmpdir"));
  1231. if(Platform.isMac()) {
  1232. // https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
  1233. jnatmp = new File(System.getProperty("user.home"), "Library/Caches/JNA/temp");
  1234. } else if (Platform.isLinux() || Platform.isSolaris() || Platform.isAIX() || Platform.isFreeBSD() || Platform.isNetBSD() || Platform.isOpenBSD() || Platform.iskFreeBSD()) {
  1235. // https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
  1236. // The XDG_CACHE_DIR is expected to be per user
  1237. String xdgCacheEnvironment = System.getenv("XDG_CACHE_HOME");
  1238. File xdgCacheFile;
  1239. if(xdgCacheEnvironment == null || xdgCacheEnvironment.trim().isEmpty()) {
  1240. xdgCacheFile = new File(System.getProperty("user.home"), ".cache");
  1241. } else {
  1242. xdgCacheFile = new File(xdgCacheEnvironment);
  1243. }
  1244. jnatmp = new File(xdgCacheFile, "JNA/temp");
  1245. } else {
  1246. // Loading DLLs via System.load() under a directory with a unicode
  1247. // name will fail on windows, so use a hash code of the user's
  1248. // name in case the user's name contains non-ASCII characters
  1249. jnatmp = new File(tmp, "jna-" + System.getProperty("user.name").hashCode());
  1250. }
  1251. jnatmp.mkdirs();
  1252. if (!jnatmp.exists() || !jnatmp.canWrite()) {
  1253. jnatmp = tmp;
  1254. }
  1255. }
  1256. if (!jnatmp.exists()) {
  1257. throw new IOException("JNA temporary directory '" + jnatmp + "' does not exist");
  1258. }
  1259. if (!jnatmp.canWrite()) {
  1260. throw new IOException("JNA temporary directory '" + jnatmp + "' is not writable");
  1261. }
  1262. return jnatmp;
  1263. }
  1264. /** Remove all marked temporary files in the given directory. */
  1265. static void removeTemporaryFiles() throws IOException {
  1266. File dir = getTempDir();
  1267. FilenameFilter filter = new FilenameFilter() {
  1268. @Override
  1269. public boolean accept(File dir, String name) {
  1270. return name.endsWith(".x") && name.startsWith(JNA_TMPLIB_PREFIX);
  1271. }
  1272. };
  1273. File[] files = dir.listFiles(filter);
  1274. for (int i=0;files != null && i < files.length;i++) {
  1275. File marker = files[i];
  1276. String name = marker.getName();
  1277. name = name.substring(0, name.length()-2);
  1278. File target = new File(marker.getParentFile(), name);
  1279. if (!target.exists() || target.delete()) {
  1280. marker.delete();
  1281. }
  1282. }
  1283. }
  1284. /**
  1285. * @param type The Java class for which the native size is to be determined
  1286. * @param value an instance of said class (if available)
  1287. * @return the native size of the given class, in bytes.
  1288. * For use with arrays.
  1289. */
  1290. public static int getNativeSize(Class<?> type, Object value) {
  1291. if (type.isArray()) {
  1292. int len = Array.getLength(value);
  1293. if (len > 0) {
  1294. Object o = Array.get(value, 0);
  1295. return len * getNativeSize(type.getComponentType(), o);
  1296. }
  1297. // Don't process zero-length arrays
  1298. throw new IllegalArgumentException("Arrays of length zero not allowed: " + type);
  1299. }
  1300. if (Structure.class.isAssignableFrom(type)
  1301. && !Structure.ByReference.class.isAssignableFrom(type)) {
  1302. return Structure.size((Class<Structure>) type, (Structure)value);
  1303. }
  1304. try {
  1305. return getNativeSize(type);
  1306. }
  1307. catch(IllegalArgumentException e) {
  1308. throw new IllegalArgumentException("The type \"" + type.getName()
  1309. + "\" is not supported: "
  1310. + e.getMessage());
  1311. }
  1312. }
  1313. /**
  1314. * Returns the native size for a given Java class. Structures are
  1315. * assumed to be <code>struct</code> pointers unless they implement
  1316. * {@link Structure.ByValue}.
  1317. *
  1318. * @param cls The Java class
  1319. * @return The native size for the class
  1320. */
  1321. public static int getNativeSize(Class<?> cls) {
  1322. if (NativeMapped.class.isAssignableFrom(cls)) {
  1323. cls = NativeMappedConverter.getInstance(cls).nativeType();
  1324. }
  1325. // boolean defaults to 32 bit integer if not otherwise mapped
  1326. if (cls == boolean.class || cls == Boolean.class) return 4;
  1327. if (cls == byte.class || cls == Byte.class) return 1;
  1328. if (cls == short.class || cls == Short.class) return 2;
  1329. if (cls == char.class || cls == Character.class) return WCHAR_SIZE;
  1330. if (cls == int.class || cls == Integer.class) return 4;
  1331. if (cls == long.class || cls == Long.class) return 8;
  1332. if (cls == float.class || cls == Float.class) return 4;
  1333. if (cls == double.class || cls == Double.class) return 8;
  1334. if (Structure.class.isAssignableFrom(cls)) {
  1335. if (Structure.ByValue.class.isAssignableFrom(cls)) {
  1336. return Structure.size((Class<? extends Structure>) cls);
  1337. }
  1338. return POINTER_SIZE;
  1339. }
  1340. if (Pointer.class.isAssignableFrom(cls)
  1341. || (Platform.HAS_BUFFERS && Buffers.isBuffer(cls))
  1342. || Callback.class.isAssignableFrom(cls)
  1343. || String.class == cls
  1344. || WString.class == cls) {
  1345. return POINTER_SIZE;
  1346. }
  1347. throw new IllegalArgumentException("Native size for type \"" + cls.getName()
  1348. + "\" is unknown");
  1349. }
  1350. /**
  1351. * @param cls The Java class
  1352. * @return {@code true} whether the given class is supported as a native argument type.
  1353. */
  1354. public static boolean isSupportedNativeType(Class<?> cls) {
  1355. if (Structure.class.isAssignableFrom(cls)) {
  1356. return true;
  1357. }
  1358. try {
  1359. return getNativeSize(cls) != 0;
  1360. }
  1361. catch(IllegalArgumentException e) {
  1362. return false;
  1363. }
  1364. }
  1365. /**
  1366. * Set the default handler invoked when a callback throws an uncaught
  1367. * exception. If the given handler is <code>null</code>, the default
  1368. * handler will be reinstated.
  1369. *
  1370. * @param eh The default handler
  1371. */
  1372. public static void setCallbackExceptionHandler(UncaughtExceptionHandler eh) {
  1373. callbackExceptionHandler = eh == null ? DEFAULT_HANDLER : eh;
  1374. }
  1375. /** @return the current handler for callback uncaught exceptions. */
  1376. public static UncaughtExceptionHandler getCallbackExceptionHandler() {
  1377. return callbackExceptionHandler;
  1378. }
  1379. /**
  1380. * When called from a class static initializer, maps all native methods
  1381. * found within that class to native libraries via the JNA raw calling
  1382. * interface.
  1383. * @param libName library name to which functions should be bound
  1384. */
  1385. public static void register(String libName) {
  1386. register(findDirectMappedClass(getCallingClass()), libName);
  1387. }
  1388. /**
  1389. * When called from a class static initializer, maps all native methods
  1390. * found within that class to native libraries via the JNA raw calling
  1391. * interface.
  1392. * @param lib native library to which functions should be bound
  1393. */
  1394. public static void register(NativeLibrary lib) {
  1395. register(findDirectMappedClass(getCallingClass()), lib);
  1396. }
  1397. /** Find the nearest enclosing class with native methods. */
  1398. static Class<?> findDirectMappedClass(Class<?> cls) {
  1399. Method[] methods = cls.getDeclaredMethods();
  1400. for (Method m : methods) {
  1401. if ((m.getModifiers() & Modifier.NATIVE) != 0) {
  1402. return cls;
  1403. }
  1404. }
  1405. int idx = cls.getName().lastIndexOf("$");
  1406. if (idx != -1) {
  1407. String name = cls.getName().substring(0, idx);
  1408. try {
  1409. return findDirectMappedClass(Class.forName(name, true, cls.getClassLoader()));
  1410. } catch(ClassNotFoundException e) {
  1411. // ignored
  1412. }
  1413. }
  1414. throw new IllegalArgumentException("Can't determine class with native methods from the current context (" + cls + ")");
  1415. }
  1416. /** Try to determine the class context in which a {@link #register(String)} call
  1417. was made.
  1418. */
  1419. static Class<?> getCallingClass() {
  1420. Class<?>[] context = new SecurityManager() {
  1421. @Override
  1422. public Class<?>[] getClassContext() {
  1423. return super.getClassContext();
  1424. }
  1425. }.getClassContext();
  1426. if (context == null) {
  1427. throw new IllegalStateException("The SecurityManager implementation on this platform is broken; you must explicitly provide the class to register");
  1428. }
  1429. if (context.length < 4) {
  1430. throw new IllegalStateException("This method must be called from the static initializer of a class");
  1431. }
  1432. return context[3];
  1433. }
  1434. /**
  1435. * Set a thread initializer for the given callback.
  1436. * @param cb The callback to invoke
  1437. * @param initializer The thread initializer indicates desired thread configuration when the
  1438. * given Callback is invoked on a native thread not yet attached to the VM.
  1439. */
  1440. public static void setCallbackThreadInitializer(Callback cb, CallbackThreadInitializer initializer) {
  1441. CallbackReference.setCallbackThreadInitializer(cb, initializer);
  1442. }
  1443. private static final Map<Class<?>, long[]> registeredClasses = new WeakHashMap<Class<?>, long[]>();
  1444. private static final Map<Class<?>, NativeLibrary> registeredLibraries = new WeakHashMap<Class<?>, NativeLibrary>();
  1445. private static void unregisterAll() {
  1446. synchronized(registeredClasses) {
  1447. for (Map.Entry<Class<?>, long[]> e : registeredClasses.entrySet()) {
  1448. unregister(e.getKey(), e.getValue());
  1449. }
  1450. registeredClasses.clear();
  1451. }
  1452. }
  1453. /** Remove all native mappings for the calling class.
  1454. Should only be called if the class is no longer referenced and about
  1455. to be garbage collected.
  1456. */
  1457. public static void unregister() {
  1458. unregister(findDirectMappedClass(getCallingClass()));
  1459. }
  1460. /** Remove all native mappings for the given class.
  1461. Should only be called if the class is no longer referenced and about
  1462. to be garbage collected.
  1463. */
  1464. public static void unregister(Class<?> cls) {
  1465. synchronized(registeredClasses) {
  1466. long[] handles = registeredClasses.get(cls);
  1467. if (handles != null) {
  1468. unregister(cls, handles);
  1469. registeredClasses.remove(cls);
  1470. registeredLibraries.remove(cls);
  1471. }
  1472. }
  1473. }
  1474. /**
  1475. * @param cls The type {@link Class}
  1476. * @return whether the given class's native components are registered.
  1477. */
  1478. public static boolean registered(Class<?> cls) {
  1479. synchronized(registeredClasses) {
  1480. return registeredClasses.containsKey(cls);
  1481. }
  1482. }
  1483. /* Unregister the native methods for the given class. */
  1484. private static native void unregister(Class<?> cls, long[] handles);
  1485. static String getSignature(Class<?> cls) {
  1486. if (cls.isArray()) {
  1487. return "[" + getSignature(cls.getComponentType());
  1488. }
  1489. if (cls.isPrimitive()) {
  1490. if (cls == void.class) return "V";
  1491. if (cls == boolean.class) return "Z";
  1492. if (cls == byte.class) return "B";
  1493. if (cls == short.class) return "S";
  1494. if (cls == char.class) return "C";
  1495. if (cls == int.class) return "I";
  1496. if (cls == long.class) return "J";
  1497. if (cls == float.class) return "F";
  1498. if (cls == double.class) return "D";
  1499. }
  1500. return "L" + replace(".", "/", cls.getName()) + ";";
  1501. }
  1502. // No String.replace available in 1.4
  1503. static String replace(String s1, String s2, String str) {
  1504. StringBuilder buf = new StringBuilder();
  1505. while (true) {
  1506. int idx = str.indexOf(s1);
  1507. if (idx == -1) {
  1508. buf.append(str);
  1509. break;
  1510. }
  1511. else {
  1512. buf.append(str.substring(0, idx));
  1513. buf.append(s2);
  1514. str = str.substring(idx + s1.length());
  1515. }
  1516. }
  1517. return buf.toString();
  1518. }
  1519. /** Indicates whether the callback has an initializer. */
  1520. static final int CB_HAS_INITIALIZER = 1;
  1521. private static final int CVT_UNSUPPORTED = -1;
  1522. private static final int CVT_DEFAULT = 0;
  1523. private static final int CVT_POINTER = 1;
  1524. private static final int CVT_STRING = 2;
  1525. private static final int CVT_STRUCTURE = 3;
  1526. private static final int CVT_STRUCTURE_BYVAL = 4;
  1527. private static final int CVT_BUFFER = 5;
  1528. private static final int CVT_ARRAY_BYTE = 6;
  1529. private static final int CVT_ARRAY_SHORT = 7;
  1530. private static final int CVT_ARRAY_CHAR = 8;
  1531. private static final int CVT_ARRAY_INT = 9;
  1532. private static final int CVT_ARRAY_LONG = 10;
  1533. private static final int CVT_ARRAY_FLOAT = 11;
  1534. private static final int CVT_ARRAY_DOUBLE = 12;
  1535. private static final int CVT_ARRAY_BOOLEAN = 13;
  1536. private static final int CVT_BOOLEAN = 14;
  1537. private static final int CVT_CALLBACK = 15;
  1538. private static final int CVT_FLOAT = 16;
  1539. private static final int CVT_NATIVE_MAPPED = 17;
  1540. private static final int CVT_NATIVE_MAPPED_STRING = 18;
  1541. private static final int CVT_NATIVE_MAPPED_WSTRING = 19;
  1542. private static final int CVT_WSTRING = 20;
  1543. private static final int CVT_INTEGER_TYPE = 21;
  1544. private static final int CVT_POINTER_TYPE = 22;
  1545. private static final int CVT_TYPE_MAPPER = 23;
  1546. private static final int CVT_TYPE_MAPPER_STRING = 24;
  1547. private static final int CVT_TYPE_MAPPER_WSTRING = 25;
  1548. private static final int CVT_OBJECT = 26;
  1549. private static final int CVT_JNIENV = 27;
  1550. private static final int CVT_SHORT = 28;
  1551. private static final int CVT_BYTE = 29;
  1552. private static int getConversion(Class<?> type, TypeMapper mapper, boolean allowObjects) {
  1553. if (type == Void.class) type = void.class;
  1554. if (mapper != null) {
  1555. FromNativeConverter fromNative = mapper.getFromNativeConverter(type);
  1556. ToNativeConverter toNative = mapper.getToNativeConverter(type);
  1557. if (fromNative != null) {
  1558. Class<?> nativeType = fromNative.nativeType();
  1559. if (nativeType == String.class) {
  1560. return CVT_TYPE_MAPPER_STRING;
  1561. }
  1562. if (nativeType == WString.class) {
  1563. return CVT_TYPE_MAPPER_WSTRING;
  1564. }
  1565. return CVT_TYPE_MAPPER;
  1566. }
  1567. if (toNative != null) {
  1568. Class<?> nativeType = toNative.nativeType();
  1569. if (nativeType == String.class) {
  1570. return CVT_TYPE_MAPPER_STRING;
  1571. }
  1572. if (nativeType == WString.class) {
  1573. return CVT_TYPE_MAPPER_WSTRING;
  1574. }
  1575. return CVT_TYPE_MAPPER;
  1576. }
  1577. }
  1578. if (Pointer.class.isAssignableFrom(type)) {
  1579. return CVT_POINTER;
  1580. }
  1581. if (String.class == type) {
  1582. return CVT_STRING;
  1583. }
  1584. if (WString.class.isAssignableFrom(type)) {
  1585. return CVT_WSTRING;
  1586. }
  1587. if (Platform.HAS_BUFFERS && Buffers.isBuffer(type)) {
  1588. return CVT_BUFFER;
  1589. }
  1590. if (Structure.class.isAssignableFrom(type)) {
  1591. if (Structure.ByValue.class.isAssignableFrom(type)) {
  1592. return CVT_STRUCTURE_BYVAL;
  1593. }
  1594. return CVT_STRUCTURE;
  1595. }
  1596. if (type.isArray()) {
  1597. switch(type.getName().charAt(1)) {
  1598. case 'Z': return CVT_ARRAY_BOOLEAN;
  1599. case 'B': return CVT_ARRAY_BYTE;
  1600. case 'S': return CVT_ARRAY_SHORT;
  1601. case 'C': return CVT_ARRAY_CHAR;
  1602. case 'I': return CVT_ARRAY_INT;
  1603. case 'J': return CVT_ARRAY_LONG;
  1604. case 'F': return CVT_ARRAY_FLOAT;
  1605. case 'D': return CVT_ARRAY_DOUBLE;
  1606. default: break;
  1607. }
  1608. }
  1609. if (type.isPrimitive()) {
  1610. return type == boolean.class ? CVT_BOOLEAN : CVT_DEFAULT;
  1611. }
  1612. if (Callback.class.isAssignableFrom(type)) {
  1613. return CVT_CALLBACK;
  1614. }
  1615. if (IntegerType.class.isAssignableFrom(type)) {
  1616. return CVT_INTEGER_TYPE;
  1617. }
  1618. if (PointerType.class.isAssignableFrom(type)) {
  1619. return CVT_POINTER_TYPE;
  1620. }
  1621. if (NativeMapped.class.isAssignableFrom(type)) {
  1622. Class<?> nativeType = NativeMappedConverter.getInstance(type).nativeType();
  1623. if (nativeType == String.class) {
  1624. return CVT_NATIVE_MAPPED_STRING;
  1625. }
  1626. if (nativeType == WString.class) {
  1627. return CVT_NATIVE_MAPPED_WSTRING;
  1628. }
  1629. return CVT_NATIVE_MAPPED;
  1630. }
  1631. if (JNIEnv.class == type) {
  1632. return CVT_JNIENV;
  1633. }
  1634. return allowObjects ? CVT_OBJECT : CVT_UNSUPPORTED;
  1635. }
  1636. /**
  1637. * When called from a class static initializer, maps all native methods
  1638. * found within that class to native libraries via the JNA raw calling
  1639. * interface. Uses the class loader of the given class to search for the
  1640. * native library in the resource path if it is not found in the system
  1641. * library load path or <code>jna.library.path</code>.
  1642. * @param cls Class with native methods to register
  1643. * @param libName name of or path to native library to which functions
  1644. * should be bound
  1645. */
  1646. public static void register(Class<?> cls, String libName) {
  1647. NativeLibrary library =
  1648. NativeLibrary.getInstance(libName, Collections.singletonMap(Library.OPTION_CLASSLOADER, cls.getClassLoader()));
  1649. register(cls, library);
  1650. }
  1651. /** When called from a class static initializer, maps all native methods
  1652. * found within that class to native libraries via the JNA raw calling
  1653. * interface.
  1654. * @param cls Class with native methods to register
  1655. * @param lib library to which functions should be bound
  1656. */
  1657. // TODO: derive options from annotations (per-class or per-method)
  1658. // options: read parameter type mapping (long/native long),
  1659. // method name, library name, call conv
  1660. public static void register(Class<?> cls, NativeLibrary lib) {
  1661. Method[] methods = cls.getDeclaredMethods();
  1662. List<Method> mlist = new ArrayList<Method>();
  1663. Map<String, ?> options = lib.getOptions();
  1664. TypeMapper mapper = (TypeMapper) options.get(Library.OPTION_TYPE_MAPPER);
  1665. boolean allowObjects = Boolean.TRUE.equals(options.get(Library.OPTION_ALLOW_OBJECTS));
  1666. options = cacheOptions(cls, options, null);
  1667. for (Method m : methods) {
  1668. if ((m.getModifiers() & Modifier.NATIVE) != 0) {
  1669. mlist.add(m);
  1670. }
  1671. }
  1672. long[] handles = new long[mlist.size()];
  1673. for (int i=0;i < handles.length;i++) {
  1674. Method method = mlist.get(i);
  1675. String sig = "(";
  1676. Class<?> rclass = method.getReturnType();
  1677. long rtype, closure_rtype;
  1678. Class<?>[] ptypes = method.getParameterTypes();
  1679. long[] atypes = new long[ptypes.length];
  1680. long[] closure_atypes = new long[ptypes.length];
  1681. int[] cvt = new int[ptypes.length];
  1682. ToNativeConverter[] toNative = new ToNativeConverter[ptypes.length];
  1683. FromNativeConverter fromNative = null;
  1684. int rcvt = getConversion(rclass, mapper, allowObjects);
  1685. boolean throwLastError = false;
  1686. switch (rcvt) {
  1687. case CVT_UNSUPPORTED:
  1688. throw new IllegalArgumentException(rclass + " is not a supported return type (in method " + method.getName() + " in " + cls + ")");
  1689. case CVT_TYPE_MAPPER:
  1690. case CVT_TYPE_MAPPER_STRING:
  1691. case CVT_TYPE_MAPPER_WSTRING:
  1692. fromNative = mapper.getFromNativeConverter(rclass);
  1693. // FFIType.get() always looks up the native type for any given
  1694. // class, so if we actually have conversion into a Java
  1695. // object, make sure we use the proper type information
  1696. closure_rtype = FFIType.get(rclass.isPrimitive() ? rclass : Pointer.class).getPointer().peer;
  1697. rtype = FFIType.get(fromNative.nativeType()).getPointer().peer;
  1698. break;
  1699. case CVT_NATIVE_MAPPED:
  1700. case CVT_NATIVE_MAPPED_STRING:
  1701. case CVT_NATIVE_MAPPED_WSTRING:
  1702. case CVT_INTEGER_TYPE:
  1703. case CVT_POINTER_TYPE:
  1704. closure_rtype = FFIType.get(Pointer.class).getPointer().peer;
  1705. rtype = FFIType.get(NativeMappedConverter.getInstance(rclass).nativeType()).getPointer().peer;
  1706. break;
  1707. case CVT_STRUCTURE:
  1708. case CVT_OBJECT:
  1709. closure_rtype = rtype = FFIType.get(Pointer.class).getPointer().peer;
  1710. break;
  1711. case CVT_STRUCTURE_BYVAL:
  1712. closure_rtype = FFIType.get(Pointer.class).getPointer().peer;
  1713. rtype = FFIType.get(rclass).getPointer().peer;
  1714. break;
  1715. default:
  1716. closure_rtype = rtype = FFIType.get(rclass).getPointer().peer;
  1717. }
  1718. for (int t=0;t < ptypes.length;t++) {
  1719. Class<?> type = ptypes[t];
  1720. sig += getSignature(type);
  1721. int conversionType = getConversion(type, mapper, allowObjects);
  1722. cvt[t] = conversionType;
  1723. if (conversionType == CVT_UNSUPPORTED) {
  1724. throw new IllegalArgumentException(type + " is not a supported argument type (in method " + method.getName() + " in " + cls + ")");
  1725. }
  1726. if ((conversionType == CVT_NATIVE_MAPPED)
  1727. || (conversionType == CVT_NATIVE_MAPPED_STRING)
  1728. || (conversionType == CVT_NATIVE_MAPPED_WSTRING)
  1729. || (conversionType == CVT_INTEGER_TYPE)) {
  1730. type = NativeMappedConverter.getInstance(type).nativeType();
  1731. } else if ((conversionType == CVT_TYPE_MAPPER)
  1732. || (conversionType == CVT_TYPE_MAPPER_STRING)
  1733. || (conversionType == CVT_TYPE_MAPPER_WSTRING)) {
  1734. toNative[t] = mapper.getToNativeConverter(type);
  1735. }
  1736. // Determine the type that will be passed to the native
  1737. // function, as well as the type to be passed
  1738. // from Java initially
  1739. switch(conversionType) {
  1740. case CVT_STRUCTURE_BYVAL:
  1741. case CVT_INTEGER_TYPE:
  1742. case CVT_POINTER_TYPE:
  1743. case CVT_NATIVE_MAPPED:
  1744. case CVT_NATIVE_MAPPED_STRING:
  1745. case CVT_NATIVE_MAPPED_WSTRING:
  1746. atypes[t] = FFIType.get(type).getPointer().peer;
  1747. closure_atypes[t] = FFIType.get(Pointer.class).getPointer().peer;
  1748. break;
  1749. case CVT_TYPE_MAPPER:
  1750. case CVT_TYPE_MAPPER_STRING:
  1751. case CVT_TYPE_MAPPER_WSTRING:
  1752. closure_atypes[t] = FFIType.get(type.isPrimitive() ? type : Pointer.class).getPointer().peer;
  1753. atypes[t] = FFIType.get(toNative[t].nativeType()).getPointer().peer;
  1754. break;
  1755. case CVT_DEFAULT:
  1756. closure_atypes[t] = atypes[t] = FFIType.get(type).getPointer().peer;
  1757. break;
  1758. default:
  1759. closure_atypes[t] = atypes[t] = FFIType.get(Pointer.class).getPointer().peer;
  1760. }
  1761. }
  1762. sig += ")";
  1763. sig += getSignature(rclass);
  1764. Class<?>[] etypes = method.getExceptionTypes();
  1765. for (int e=0;e < etypes.length;e++) {
  1766. if (LastErrorException.class.isAssignableFrom(etypes[e])) {
  1767. throwLastError = true;
  1768. break;
  1769. }
  1770. }
  1771. Function f = lib.getFunction(method.getName(), method);
  1772. try {
  1773. handles[i] = registerMethod(cls, method.getName(),
  1774. sig, cvt,
  1775. closure_atypes, atypes, rcvt,
  1776. closure_rtype, rtype,
  1777. method,
  1778. f.peer, f.getCallingConvention(),
  1779. throwLastError,
  1780. toNative, fromNative,
  1781. f.encoding);
  1782. } catch(NoSuchMethodError e) {
  1783. throw new UnsatisfiedLinkError("No method " + method.getName() + " with signature " + sig + " in " + cls);
  1784. }
  1785. }
  1786. synchronized(registeredClasses) {
  1787. registeredClasses.put(cls, handles);
  1788. registeredLibraries.put(cls, lib);
  1789. }
  1790. }
  1791. /* Take note of options used for a given library mapping, to facilitate
  1792. * looking them up later.
  1793. */
  1794. private static Map<String, Object> cacheOptions(Class<?> cls, Map<String, ?> options, Object proxy) {
  1795. Map<String, Object> libOptions = new HashMap<String, Object>(options);
  1796. libOptions.put(_OPTION_ENCLOSING_LIBRARY, cls);
  1797. typeOptions.put(cls, libOptions);
  1798. if (proxy != null) {
  1799. libraries.put(cls, new WeakReference<Object>(proxy));
  1800. }
  1801. // If it's a direct mapping, AND implements a Library interface,
  1802. // cache the library interface as well, so that any nested
  1803. // classes get the appropriate associated options
  1804. if (!cls.isInterface()
  1805. && Library.class.isAssignableFrom(cls)) {
  1806. Class<?> ifaces[] = cls.getInterfaces();
  1807. for (Class<?> ifc : ifaces) {
  1808. if (Library.class.isAssignableFrom(ifc)) {
  1809. cacheOptions(ifc, libOptions, proxy);
  1810. break;
  1811. }
  1812. }
  1813. }
  1814. return libOptions;
  1815. }
  1816. private static native long registerMethod(Class<?> cls,
  1817. String name,
  1818. String signature,
  1819. int[] conversions,
  1820. long[] closure_arg_types,
  1821. long[] arg_types,
  1822. int rconversion,
  1823. long closure_rtype,
  1824. long rtype,
  1825. Method method,
  1826. long fptr,
  1827. int callingConvention,
  1828. boolean throwLastError,
  1829. ToNativeConverter[] toNative,
  1830. FromNativeConverter fromNative,
  1831. String encoding);
  1832. // Called from native code
  1833. private static NativeMapped fromNative(Class<?> cls, Object value) {
  1834. // NOTE: technically should be CallbackParameterContext
  1835. return (NativeMapped)NativeMappedConverter.getInstance(cls).fromNative(value, new FromNativeContext(cls));
  1836. }
  1837. // Called from native code
  1838. private static NativeMapped fromNative(Method m, Object value) {
  1839. Class<?> cls = m.getReturnType();
  1840. return (NativeMapped)NativeMappedConverter.getInstance(cls).fromNative(value, new MethodResultContext(cls, null, null, m));
  1841. }
  1842. // Called from native code
  1843. private static Class<?> nativeType(Class<?> cls) {
  1844. return NativeMappedConverter.getInstance(cls).nativeType();
  1845. }
  1846. // Called from native code
  1847. private static Object toNative(ToNativeConverter cvt, Object o) {
  1848. // NOTE: technically should be either CallbackResultContext or
  1849. // FunctionParameterContext
  1850. return cvt.toNative(o, new ToNativeContext());
  1851. }
  1852. // Called from native code
  1853. private static Object fromNative(FromNativeConverter cvt, Object o, Method m) {
  1854. return cvt.fromNative(o, new MethodResultContext(m.getReturnType(), null, null, m));
  1855. }
  1856. /** Create a new cif structure. */
  1857. public static native long ffi_prep_cif(int abi, int nargs, long ffi_return_type, long ffi_types);
  1858. /** Make an FFI function call. */
  1859. public static native void ffi_call(long cif, long fptr, long resp, long args);
  1860. public static native long ffi_prep_closure(long cif, ffi_callback cb);
  1861. public static native void ffi_free_closure(long closure);
  1862. /** Returns the size (calculated by libffi) of the given type. */
  1863. static native int initialize_ffi_type(long type_info);
  1864. public interface ffi_callback {
  1865. void invoke(long cif, long resp, long argp);
  1866. }
  1867. /** Prints JNA library details to the console. */
  1868. public static void main(String[] args) {
  1869. final String DEFAULT_TITLE = "Java Native Access (JNA)";
  1870. final String DEFAULT_VERSION = VERSION;
  1871. final String DEFAULT_BUILD = VERSION + " (package information missing)";
  1872. Package pkg = Native.class.getPackage();
  1873. String title = pkg != null
  1874. ? pkg.getSpecificationTitle() : DEFAULT_TITLE;
  1875. if (title == null) title = DEFAULT_TITLE;
  1876. String version = pkg != null
  1877. ? pkg.getSpecificationVersion() : DEFAULT_VERSION;
  1878. if (version == null) version = DEFAULT_VERSION;
  1879. title += " API Version " + version;
  1880. System.out.println(title);
  1881. version = pkg != null
  1882. ? pkg.getImplementationVersion() : DEFAULT_BUILD;
  1883. if (version == null) version = DEFAULT_BUILD;
  1884. System.out.println("Version: " + version);
  1885. System.out.println(" Native: " + getNativeVersion() + " ("
  1886. + getAPIChecksum() + ")");
  1887. System.out.println(" Prefix: " + Platform.RESOURCE_PREFIX);
  1888. }
  1889. /** Free the given callback trampoline. */
  1890. static synchronized native void freeNativeCallback(long ptr);
  1891. /** Use direct mapping for callback. */
  1892. static final int CB_OPTION_DIRECT = 1;
  1893. /** Return a DLL-resident fucntion pointer. */
  1894. static final int CB_OPTION_IN_DLL = 2;
  1895. /** Create a native trampoline to delegate execution to the Java callback.
  1896. */
  1897. static synchronized native long createNativeCallback(Callback callback,
  1898. Method method,
  1899. Class<?>[] parameterTypes,
  1900. Class<?> returnType,
  1901. int callingConvention,
  1902. int flags,
  1903. String encoding);
  1904. /**
  1905. * Call the native function.
  1906. *
  1907. * @param function Present to prevent the GC to collect the Function object
  1908. * prematurely
  1909. * @param fp function pointer
  1910. * @param callFlags calling convention to be used
  1911. * @param args Arguments to pass to the native function
  1912. *
  1913. * @return The value returned by the target native function
  1914. */
  1915. static native int invokeInt(Function function, long fp, int callFlags, Object[] args);
  1916. /**
  1917. * Call the native function.
  1918. *
  1919. * @param function Present to prevent the GC to collect the Function object
  1920. * prematurely
  1921. * @param fp function pointer
  1922. * @param callFlags calling convention to be used
  1923. * @param args Arguments to pass to the native function
  1924. *
  1925. * @return The value returned by the target native function
  1926. */
  1927. static native long invokeLong(Function function, long fp, int callFlags, Object[] args);
  1928. /**
  1929. * Call the native function.
  1930. *
  1931. * @param function Present to prevent the GC to collect the Function object
  1932. * prematurely
  1933. * @param fp function pointer
  1934. * @param callFlags calling convention to be used
  1935. * @param args Arguments to pass to the native function
  1936. */
  1937. static native void invokeVoid(Function function, long fp, int callFlags, Object[] args);
  1938. /**
  1939. * Call the native function.
  1940. *
  1941. * @param function Present to prevent the GC to collect the Function object
  1942. * prematurely
  1943. * @param fp function pointer
  1944. * @param callFlags calling convention to be used
  1945. * @param args Arguments to pass to the native function
  1946. *
  1947. * @return The value returned by the target native function
  1948. */
  1949. static native float invokeFloat(Function function, long fp, int callFlags, Object[] args);
  1950. /**
  1951. * Call the native function.
  1952. *
  1953. * @param function Present to prevent the GC to collect the Function object
  1954. * prematurely
  1955. * @param fp function pointer
  1956. * @param callFlags calling convention to be used
  1957. * @param args Arguments to pass to the native function
  1958. *
  1959. * @return The value returned by the target native function
  1960. */
  1961. static native double invokeDouble(Function function, long fp, int callFlags, Object[] args);
  1962. /**
  1963. * Call the native function.
  1964. *
  1965. * @param function Present to prevent the GC to collect the Function object
  1966. * prematurely
  1967. * @param fp function pointer
  1968. * @param callFlags calling convention to be used
  1969. * @param args Arguments to pass to the native function
  1970. *
  1971. * @return The value returned by the target native function
  1972. */
  1973. static native long invokePointer(Function function, long fp, int callFlags, Object[] args);
  1974. /**
  1975. * Call the native function, returning a struct by value.
  1976. *
  1977. * @param function Present to prevent the GC to collect the Function object
  1978. * prematurely
  1979. * @param fp function pointer
  1980. * @param callFlags calling convention to be used
  1981. * @param args Arguments to pass to the native function
  1982. * @param memory Memory for pre-allocated structure to hold the result
  1983. * @param typeInfo Native type information for the Structure
  1984. */
  1985. private static native void invokeStructure(Function function, long fp, int callFlags,
  1986. Object[] args, long memory,
  1987. long type_info);
  1988. /**
  1989. * Call the native function, returning a struct by value.
  1990. *
  1991. * @param function Present to prevent the GC to collect the Function object
  1992. * prematurely
  1993. * @param fp function pointer
  1994. * @param callFlags calling convention to be used
  1995. * @param args Arguments to pass to the native function
  1996. *
  1997. * @return the passed-in Structure
  1998. */
  1999. static Structure invokeStructure(Function function, long fp, int callFlags, Object[] args,
  2000. Structure s) {
  2001. invokeStructure(function, fp, callFlags, args, s.getPointer().peer,
  2002. s.getTypeInfo().peer);
  2003. return s;
  2004. }
  2005. /**
  2006. * Call the native function, returning a Java <code>Object</code>.
  2007. *
  2008. * @param function Present to prevent the GC to collect the Function object
  2009. * prematurely
  2010. * @param fp function pointer
  2011. * @param callFlags calling convention to be used
  2012. * @param args Arguments to pass to the native function
  2013. *
  2014. * @return The returned Java <code>Object</code>
  2015. */
  2016. static native Object invokeObject(Function function, long fp, int callFlags, Object[] args);
  2017. /** Open the requested native library with default options. */
  2018. static long open(String name) {
  2019. return open(name, -1);
  2020. }
  2021. /** Open the requested native library with the specified platform-specific
  2022. * otions.
  2023. */
  2024. static native long open(String name, int flags);
  2025. /** Close the given native library. */
  2026. static native void close(long handle);
  2027. static native long findSymbol(long handle, String name);
  2028. /*
  2029. ============================================================================
  2030. The first argument of the following read, write, get<Type> and set<Type>
  2031. function is present to protect it from the GC.
  2032. Although on the native side only the baseaddr and offset are used to access
  2033. the memory, the Pointer argument must not be removed. This is the usecase:
  2034. --------------------------------------
  2035. Memory pointer = <init>;
  2036. <do something and work on Memory>
  2037. String result = pointer.getWideString(0)
  2038. <do nothing more with Memory>
  2039. --------------------------------------
  2040. In getWideString the pointer address is resolved and is passed to native. If
  2041. the Memory object itself is not passed to native, the GC can collect the
  2042. object at that point as it is not used anymore and the finalizers could run.
  2043. The would introduce a race between the native call and the GC running the
  2044. finalizers. The finalizers free the allocated memory, which results in
  2045. a SEGFAULT.
  2046. Passing only the Pointer object and loading the peer value via JNI was not
  2047. implemented, as in microbenchmarks it showed large impact. Passing the
  2048. Pointer object instead of the peer and offset value to getInt resulted in
  2049. a performance of 70% of the unmodified source.
  2050. ============================================================================
  2051. */
  2052. static native long indexOf(Pointer pointer, long baseaddr, long offset, byte value);
  2053. static native void read(Pointer pointer, long baseaddr, long offset, byte[] buf, int index, int length);
  2054. static native void read(Pointer pointer, long baseaddr, long offset, short[] buf, int index, int length);
  2055. static native void read(Pointer pointer, long baseaddr, long offset, char[] buf, int index, int length);
  2056. static native void read(Pointer pointer, long baseaddr, long offset, int[] buf, int index, int length);
  2057. static native void read(Pointer pointer, long baseaddr, long offset, long[] buf, int index, int length);
  2058. static native void read(Pointer pointer, long baseaddr, long offset, float[] buf, int index, int length);
  2059. static native void read(Pointer pointer, long baseaddr, long offset, double[] buf, int index, int length);
  2060. static native void write(Pointer pointer, long baseaddr, long offset, byte[] buf, int index, int length);
  2061. static native void write(Pointer pointer, long baseaddr, long offset, short[] buf, int index, int length);
  2062. static native void write(Pointer pointer, long baseaddr, long offset, char[] buf, int index, int length);
  2063. static native void write(Pointer pointer, long baseaddr, long offset, int[] buf, int index, int length);
  2064. static native void write(Pointer pointer, long baseaddr, long offset, long[] buf, int index, int length);
  2065. static native void write(Pointer pointer, long baseaddr, long offset, float[] buf, int index, int length);
  2066. static native void write(Pointer pointer, long baseaddr, long offset, double[] buf, int index, int length);
  2067. static native byte getByte(Pointer pointer, long baseaddr, long offset);
  2068. static native char getChar(Pointer pointer, long baseaddr, long offset);
  2069. static native short getShort(Pointer pointer, long baseaddr, long offset);
  2070. static native int getInt(Pointer pointer, long baseaddr, long offset);
  2071. static native long getLong(Pointer pointer, long baseaddr, long offset);
  2072. static native float getFloat(Pointer pointer, long baseaddr, long offset);
  2073. static native double getDouble(Pointer pointer, long baseaddr, long offset);
  2074. static Pointer getPointer(long addr) {
  2075. long peer = _getPointer(addr);
  2076. return peer == 0 ? null : new Pointer(peer);
  2077. }
  2078. private static native long _getPointer(long addr);
  2079. static native String getWideString(Pointer pointer, long baseaddr, long offset);
  2080. static String getString(Pointer pointer, long offset) {
  2081. return getString(pointer, offset, getDefaultStringEncoding());
  2082. }
  2083. static String getString(Pointer pointer, long offset, String encoding) {
  2084. byte[] data = getStringBytes(pointer, pointer.peer, offset);
  2085. if (encoding != null) {
  2086. try {
  2087. return new String(data, encoding);
  2088. }
  2089. catch(UnsupportedEncodingException e) {
  2090. }
  2091. }
  2092. return new String(data);
  2093. }
  2094. static native byte[] getStringBytes(Pointer pointer, long baseaddr, long offset);
  2095. static native void setMemory(Pointer pointer, long baseaddr, long offset, long length, byte value);
  2096. static native void setByte(Pointer pointer, long baseaddr, long offset, byte value);
  2097. static native void setShort(Pointer pointer, long baseaddr, long offset, short value);
  2098. static native void setChar(Pointer pointer, long baseaddr, long offset, char value);
  2099. static native void setInt(Pointer pointer, long baseaddr, long offset, int value);
  2100. static native void setLong(Pointer pointer, long baseaddr, long offset, long value);
  2101. static native void setFloat(Pointer pointer, long baseaddr, long offset, float value);
  2102. static native void setDouble(Pointer pointer, long baseaddr, long offset, double value);
  2103. static native void setPointer(Pointer pointer, long baseaddr, long offset, long value);
  2104. static native void setWideString(Pointer pointer, long baseaddr, long offset, String value);
  2105. static native ByteBuffer getDirectByteBuffer(Pointer pointer, long addr, long offset, long length);
  2106. /**
  2107. * Call the real native malloc
  2108. * @param size size of the memory to be allocated
  2109. * @return native address of the allocated memory block; zero if the
  2110. * allocation failed.
  2111. */
  2112. public static native long malloc(long size);
  2113. /**
  2114. * Call the real native free
  2115. * @param ptr native address to be freed; a value of zero has no effect,
  2116. * passing an already-freed pointer will cause pain.
  2117. */
  2118. public static native void free(long ptr);
  2119. private static final ThreadLocal<Memory> nativeThreadTerminationFlag =
  2120. new ThreadLocal<Memory>() {
  2121. @Override
  2122. protected Memory initialValue() {
  2123. Memory m = new Memory(4);
  2124. m.clear();
  2125. return m;
  2126. }
  2127. };
  2128. private static final Map<Thread, Pointer> nativeThreads = Collections.synchronizedMap(new WeakHashMap<Thread, Pointer>());
  2129. /** <p>Indicate whether the JVM should detach the current native thread when
  2130. the current Java code finishes execution. Generally this is used to
  2131. avoid detaching native threads when it is known that a given thread
  2132. will be relatively long-lived and call back to Java code frequently.
  2133. </p>
  2134. This call is lightweight; it only results in an additional JNI
  2135. crossing if the desired state changes from its last setting.
  2136. @throws IllegalStateException if {@link #detach detach(true)} is
  2137. called on a thread created by the JVM.
  2138. */
  2139. public static void detach(boolean detach) {
  2140. Thread thread = Thread.currentThread();
  2141. if (detach) {
  2142. // If a CallbackThreadInitializer was used to avoid detach,
  2143. // we won't have put that thread into the nativeThreads map.
  2144. // Performance is not as critical in that case, and since
  2145. // detach is the default behavior, force an update of the detach
  2146. // state every time. Clear the termination flag, since it's not
  2147. // needed when the native thread is detached normally.
  2148. nativeThreads.remove(thread);
  2149. Pointer p = nativeThreadTerminationFlag.get();
  2150. setDetachState(true, 0);
  2151. }
  2152. else {
  2153. if (!nativeThreads.containsKey(thread)) {
  2154. Pointer p = nativeThreadTerminationFlag.get();
  2155. nativeThreads.put(thread, p);
  2156. setDetachState(false, p.peer);
  2157. }
  2158. }
  2159. }
  2160. static Pointer getTerminationFlag(Thread t) {
  2161. return nativeThreads.get(t);
  2162. }
  2163. private static native void setDetachState(boolean detach, long terminationFlag);
  2164. private static class Buffers {
  2165. static boolean isBuffer(Class<?> cls) {
  2166. return Buffer.class.isAssignableFrom(cls);
  2167. }
  2168. }
  2169. /** Provides separation of JAWT functionality for the sake of J2ME
  2170. * ports which do not include AWT support.
  2171. */
  2172. private static class AWT {
  2173. static long getWindowID(Window w) throws HeadlessException {
  2174. return getComponentID(w);
  2175. }
  2176. // Declaring the argument as Object rather than Component avoids class not
  2177. // found errors on phoneME foundation profile.
  2178. static long getComponentID(Object o) throws HeadlessException {
  2179. if (GraphicsEnvironment.isHeadless()) {
  2180. throw new HeadlessException("No native windows when headless");
  2181. }
  2182. Component c = (Component)o;
  2183. if (c.isLightweight()) {
  2184. throw new IllegalArgumentException("Component must be heavyweight");
  2185. }
  2186. if (!c.isDisplayable())
  2187. throw new IllegalStateException("Component must be displayable");
  2188. // On X11 VMs prior to 1.5, the window must be visible
  2189. if (Platform.isX11()
  2190. && System.getProperty("java.version").startsWith("1.4")) {
  2191. if (!c.isVisible()) {
  2192. throw new IllegalStateException("Component must be visible");
  2193. }
  2194. }
  2195. // By this point, we're certain that Toolkit.loadLibraries() has
  2196. // been called, thus avoiding AWT/JAWT link errors
  2197. // (see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6539705).
  2198. return Native.getWindowHandle0(c);
  2199. }
  2200. }
  2201. }