Project: JNA
Revision: 639
Author: twalljava
Date: 13 Aug 2008 10:17:40
Changes:allow String[] as callback argument/return
Files:modified: /trunk/jnalib/src/com/sun/jna/Pointer.java (
try)
modified: /trunk/jnalib/src/com/sun/jna/StringArray.java (
try)
modified: /trunk/jnalib/release-notes.html (
try)
modified: /trunk/jnalib/test/com/sun/jna/CallbacksTest.java (
try)
modified: /trunk/jnalib/src/com/sun/jna/overview.html (
try)
modified: /trunk/jnalib/native/testlib.c (
try)
modified: /trunk/jnalib/src/com/sun/jna/CallbackReference.java (
try)
Diff:
| ... | ...@@ -13,6 +13,8 @@ |
| 13 | 13 | import java.io.UnsupportedEncodingException; |
| 14 | 14 | import java.nio.ByteBuffer; |
| 15 | 15 | import java.nio.ByteOrder; |
| 16 | import java.util.ArrayList; |
| 17 | import java.util.List; |
| 16 | 18 | |
| 17 | 19 | /** |
| 18 | 20 | * An abstraction for a native pointer data type. A Pointer instance |
| ... | ...@@ -603,12 +605,53 @@ |
| 603 | 605 | return buf; |
| 604 | 606 | } |
| 605 | 607 | |
| 608 | /** Returns an array of {@link Pointer}. The array length is |
| 609 | * determined by a NULL-valued terminating element. |
| 610 | */ |
| 611 | public Pointer[] getPointerArray(long base) { |
| 612 | List array = new ArrayList(); |
| 613 | int offset = 0; |
| 614 | Pointer p = getPointer(base); |
| 615 | while (p != null) { |
| 616 | array.add(p); |
| 617 | offset += Pointer.SIZE; |
| 618 | p = getPointer(base + offset); |
| 619 | } |
| 620 | return (Pointer[])array.toArray(new Pointer[array.size()]); |
| 621 | } |
| 622 | |
| 623 | /** Returns an array of {@link Pointer} of the requested size. */ |
| 606 | 624 | public Pointer[] getPointerArray(long offset, int arraySize) { |
| 607 | 625 | Pointer[] buf = new Pointer[arraySize]; |
| 608 | 626 | read(offset, buf, 0, arraySize); |
| 609 | 627 | return buf; |
| 610 | 628 | } |
| 611 | 629 | |
| 630 | /** Returns an array of <code>String</code> based on a native array |
| 631 | * of <code>char *</code>. The array length is determined by a |
| 632 | * NULL-valued terminating element. |
| 633 | */ |
| 634 | public String[] getStringArray(long base) { |
| 635 | return getStringArray(base, false); |
| 636 | } |
| 637 | |
| 638 | /** Returns an array of <code>String</code> based on a native array |
| 639 | * of <code>char*</code> or <code>wchar_t*</code> based on the |
| 640 | * <code>wide</code> parameter. The array length is determined by a |
| 641 | * NULL-valued terminating element. |
| 642 | */ |
| 643 | public String[] getStringArray(long base, boolean wide) { |
| 644 | List strings = new ArrayList(); |
| 645 | int offset = 0; |
| 646 | Pointer p = getPointer(base); |
| 647 | while (p != null) { |
| 648 | strings.add(p.getString(0, wide)); |
| 649 | offset += SIZE; |
| 650 | p = getPointer(base + offset); |
| 651 | } |
| 652 | return (String[])strings.toArray(new String[strings.size()]); |
| 653 | } |
| 654 | |
| 612 | 655 | ////////////////////////////////////////////////////////////////////////// |
| 613 | 656 | // Java type write methods |
| 614 | 657 | ////////////////////////////////////////////////////////////////////////// |
| ... | ...@@ -1,3 +1,15 @@ |
| 1 | /* Copyright (c) 2007-2008 Timothy Wall, All Rights Reserved |
| 2 | * |
| 3 | * This library is free software; you can redistribute it and/or |
| 4 | * modify it under the terms of the GNU Lesser General Public |
| 5 | * License as published by the Free Software Foundation; either |
| 6 | * version 2.1 of the License, or (at your option) any later version. |
| 7 | * <p/> |
| 8 | * This library is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 11 | * Lesser General Public License for more details. |
| 12 | */ |
| 1 | 13 | package com.sun.jna; |
| 2 | 14 | |
| 3 | 15 | import java.util.ArrayList; |
| ... | ...@@ -43,8 +55,13 @@ |
| 43 | 55 | public void read() { |
| 44 | 56 | boolean returnWide = original instanceof WString[]; |
| 45 | 57 | for (int si=0;si < original.length;si++) { |
| 46 | | String s = getPointer(si * Pointer.SIZE).getString(0, wide); |
| 47 | | original[si] = returnWide ? new WString(s) : (Object)s; |
| 58 | Pointer p = getPointer(si * Pointer.SIZE); |
| 59 | Object s = null; |
| 60 | if (p != null) { |
| 61 | s = p.getString(0, wide); |
| 62 | if (returnWide) s = new WString((String)s); |
| 63 | } |
| 64 | original[si] = s; |
| 48 | 65 | } |
| 49 | 66 | } |
| 50 | 67 | } |
| 51 | 68 | \ No newline at end of file |
| ... | ...@@ -4,6 +4,7 @@ |
| 4 | 4 | <ul>
|
| 5 | 5 | <li>Allow explicit declaration of field order for VMs which have an unpredictable field order.
|
| 6 | 6 | <li>Check for w32 libraries with a "lib" prefix in addition to normal lookup.
|
| 7 | <li>Allow String[]/WString[] as callback argument/return value (assume NULL-terminated array).
|
| 7 | 8 | <li>Add Solaris8 compatibility to sunos-sparc build (Corey Puffalt).
|
| 8 | 9 | <li>Look up libraries using web start library path, if appropriate (Corey Puffalt).
|
| 9 | 10 | <li>Use constants to return integer boolean values.
|
| ... | ...@@ -16,6 +17,7 @@ |
| 16 | 17 | <li>Avoid transparent window events always dragging window bug on OSX.
|
| 17 | 18 | <li>Fix division by zero error calculating structure size on OSX/ppc.
|
| 18 | 19 | <li>Avoid overwriting initialized NativeMapped Structure fields when calculating structure size.
|
| 20 | <li>Fix NPE reading back into StringArray.
|
| 19 | 21 | </ul>
|
| 20 | 22 | <h2>Release 3.0.4</h2>
|
| 21 | 23 | <b>Features</b><br>
|
| ... | ...@@ -1,4 +1,4 @@ |
| 1 | | /* Copyright (c) 2007 Timothy Wall, All Rights Reserved |
| 1 | /* Copyright (c) 2007-2008 Timothy Wall, All Rights Reserved |
| 2 | 2 | * |
| 3 | 3 | * This library is free software; you can redistribute it and/or |
| 4 | 4 | * modify it under the terms of the GNU Lesser General Public |
| ... | ...@@ -94,6 +94,10 @@ |
| 94 | 94 | interface CopyArgToByReference extends Callback { |
| 95 | 95 | int callback(int arg, IntByReference result); |
| 96 | 96 | } |
| 97 | interface StringArrayCallback extends Callback { |
| 98 | String[] callback(String[] arg); |
| 99 | } |
| 100 | Pointer callStringArrayCallback(StringArrayCallback c, String[] arg); |
| 97 | 101 | int callCallbackWithByReferenceArgument(CopyArgToByReference cb, int arg, IntByReference result); |
| 98 | 102 | TestStructure.ByValue callCallbackWithStructByValue(TestStructure.TestCallback callback, TestStructure.ByValue cbstruct); |
| 99 | 103 | interface CbCallback extends Callback { |
| ... | ...@@ -406,6 +410,24 @@ |
| 406 | 410 | assertEquals("Wrong wide string return", VALUE, value); |
| 407 | 411 | } |
| 408 | 412 | |
| 413 | public void testCallStringArrayCallback() { |
| 414 | final boolean[] called = {false}; |
| 415 | final String[][] cbargs = { null }; |
| 416 | TestLibrary.StringArrayCallback cb = new TestLibrary.StringArrayCallback() { |
| 417 | public String[] callback(String[] arg) { |
| 418 | called[0] = true; |
| 419 | cbargs[0] = arg; |
| 420 | return arg; |
| 421 | } |
| 422 | }; |
| 423 | final String[] VALUE = { "value", null }; |
| 424 | Pointer value = lib.callStringArrayCallback(cb, VALUE); |
| 425 | assertTrue("Callback not called", called[0]); |
| 426 | assertEquals("Wrong callback argument 1", VALUE[0], cbargs[0][0]); |
| 427 | String[] result = value.getStringArray(0); |
| 428 | assertEquals("Wrong String return", VALUE[0], result[0]); |
| 429 | } |
| 430 | |
| 409 | 431 | public void testCallCallbackWithByReferenceArgument() { |
| 410 | 432 | final boolean[] called = {false}; |
| 411 | 433 | TestLibrary.CopyArgToByReference cb = new TestLibrary.CopyArgToByReference() { |
| ... | ...@@ -115,6 +115,8 @@ |
| 115 | 115 | <tr><td colspan=3>In addition to the above types, which are supported at the native layer, the JNA Java library automatically handles the following types. All but <code>NativeMapped</code> and <code>NativeLong</code> are converted to {@link com.sun.jna.Pointer} before being passed to the native layer.</td></tr> |
| 116 | 116 | <tr><td>{@link java.lang.String}</td><td>char*</td><td>NUL-terminated array (native encoding or <code>jna.encoding</code>)</td> |
| 117 | 117 | <tr><td>{@link com.sun.jna.WString}</td><td>wchar_t*</td><td>NUL-terminated array (unicode)</td> |
| 118 | <tr><td>{@link java.lang.String String[]}</td><td>char**</td><td>NULL-terminated array of C strings</td> |
| 119 | <tr><td>{@link com.sun.jna.WString WString[]}</td><td>wchar_t**</td><td>NULL-terminated array of wide C strings</td> |
| 118 | 120 | <tr><td>{@link com.sun.jna.Structure}</td><td>struct*<br>struct</td><td>pointer to struct (argument or return) ({@link com.sun.jna.Structure.ByReference or explicitly})<br>struct by value (member of struct) ({@link com.sun.jna.Structure.ByValue or explicitly})</td> |
| 119 | 121 | <tr><td>{@link com.sun.jna.Union}</td><td>union</td><td>same as <code>Structure</code></td> |
| 120 | 122 | <tr><td>{@link com.sun.jna.Structure Structure[]}</td><td>struct[]</td><td>array of structs, contiguous in memory</td> |
| ... | ...@@ -198,6 +200,7 @@ |
| 198 | 200 | <code>jna.encoding</code> is set to a valid encoding. This property may be |
| 199 | 201 | set to "UTF8", for example, to ensure all native strings use that encoding. |
| 200 | 202 | <p> |
| 203 | Arrays of <code>String</code> passed to native code (either as a function argument or callback return value) will be converted into a NULL-terminated array of <code>char*</code> (or <code>wchar_t*</code> in the case of an array of <code>WString</code>. |
| 201 | 204 | |
| 202 | 205 | <a name="wide-strings"></a> |
| 203 | 206 | <h3>Wide Strings</h3> |
| ... | ...@@ -227,6 +230,9 @@ |
| 227 | 230 | <em>must</em> be "callback", and the arguments and return value follow the |
| 228 | 231 | same rules as for a direct function invocation. |
| 229 | 232 | <p> |
| 233 | If the callback returns a <code>String</code> or <code>String[]</code>, the |
| 234 | returned memory will be valid until the returned object is GC'd. |
| 235 | <p> |
| 230 | 236 | If your native code initializes function pointers within a struct, JNA will |
| 231 | 237 | automatically generate an <code>Callback</code> instance matching the declared |
| 232 | 238 | type. This enables you to easily call the function supplied by native code |
| ... | ...@@ -1,5 +1,17 @@ |
| 1 | | /* Standard C calling convention tests. */ |
| 1 | /* Copyright (c) 2007-2008 Timothy Wall, All Rights Reserved |
| 2 | * |
| 3 | * This library is free software; you can redistribute it and/or |
| 4 | * modify it under the terms of the GNU Lesser General Public |
| 5 | * License as published by the Free Software Foundation; either |
| 6 | * version 2.1 of the License, or (at your option) any later version. |
| 7 | * <p/> |
| 8 | * This library is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 11 | * Lesser General Public License for more details. |
| 12 | */ |
| 2 | 13 | |
| 14 | /* Native library implementation to support JUnit tests. */ |
| 3 | 15 | #ifdef __cplusplus |
| 4 | 16 | extern "C" { |
| 5 | 17 | #endif |
| ... | ...@@ -513,6 +525,11 @@ |
| 513 | 525 | return (*func)(arg); |
| 514 | 526 | } |
| 515 | 527 | |
| 528 | EXPORT char** |
| 529 | callStringArrayCallback(char** (*func)(char** arg), char** arg) { |
| 530 | return (*func)(arg); |
| 531 | } |
| 532 | |
| 516 | 533 | EXPORT wchar_t* |
| 517 | 534 | callWideStringCallback(wchar_t* (*func)(wchar_t* arg), wchar_t* arg) { |
| 518 | 535 | return (*func)(arg); |
| ... | ...@@ -1,4 +1,4 @@ |
| 1 | | /* Copyright (c) 2007 Timothy Wall, All Rights Reserved |
| 1 | /* Copyright (c) 2007-2008 Timothy Wall, All Rights Reserved |
| 2 | 2 | * |
| 3 | 3 | * This library is free software; you can redistribute it and/or |
| 4 | 4 | * modify it under the terms of the GNU Lesser General Public |
| ... | ...@@ -32,7 +32,7 @@ |
| 32 | 32 | |
| 33 | 33 | static final Map callbackMap = new WeakHashMap(); |
| 34 | 34 | static final Map altCallbackMap = new WeakHashMap(); |
| 35 | | private static final Map nativeStrings = new WeakHashMap(); |
| 35 | private static final Map allocations = new WeakHashMap(); |
| 36 | 36 | |
| 37 | 37 | /** Return a Callback associated with the given function pointer. |
| 38 | 38 | * If the pointer refers to a Java callback trampoline, return the original |
| ... | ...@@ -145,6 +145,8 @@ |
| 145 | 145 | } |
| 146 | 146 | else if (cls == String.class |
| 147 | 147 | || cls == WString.class |
| 148 | || cls == String[].class |
| 149 | || cls == WString[].class |
| 148 | 150 | || Callback.class.isAssignableFrom(cls)) { |
| 149 | 151 | return Pointer.class; |
| 150 | 152 | } |
| ... | ...@@ -310,6 +312,10 @@ |
| 310 | 312 | else if (dstType == WString.class) { |
| 311 | 313 | value = new WString(((Pointer)value).getString(0, true)); |
| 312 | 314 | } |
| 315 | else if (dstType == String[].class |
| 316 | || dstType == WString[].class) { |
| 317 | value = ((Pointer)value).getStringArray(0, dstType == WString[].class); |
| 318 | } |
| 313 | 319 | else if (Callback.class.isAssignableFrom(dstType)) { |
| 314 | 320 | value = getCallback(dstType, (Pointer)value); |
| 315 | 321 | } |
| ... | ...@@ -351,12 +357,19 @@ |
| 351 | 357 | Function.INTEGER_TRUE : Function.INTEGER_FALSE; |
| 352 | 358 | } |
| 353 | 359 | else if (cls == String.class || cls == WString.class) { |
| 354 | | // Store in a weak hash map to delay GC until string |
| 355 | | // itself is GC'd. |
| 356 | 360 | NativeString ns = new NativeString(value.toString(), cls == WString.class); |
| 357 | | nativeStrings.put(value, ns); |
| 361 | // Delay GC until string itself is GC'd. |
| 362 | allocations.put(value, ns); |
| 358 | 363 | return ns.getPointer(); |
| 359 | 364 | } |
| 365 | else if (cls == String[].class || cls == WString.class) { |
| 366 | StringArray sa = cls == String[].class |
| 367 | ? new StringArray((String[])value) |
| 368 | : new StringArray((WString[])value); |
| 369 | // Delay GC until array itself is GC'd. |
| 370 | allocations.put(value, sa); |
| 371 | return sa; |
| 372 | } |
| 360 | 373 | else if (Callback.class.isAssignableFrom(cls)) { |
| 361 | 374 | return getFunctionPointer((Callback)value); |
| 362 | 375 | } |
To list