Comparar commits
16 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 38ac62cedd | |||
| ce280731af | |||
| 751fb57f71 | |||
| be7d90abbf | |||
| d59585dd4f | |||
| 7a695707a2 | |||
| 4e590c9450 | |||
| b069d1c9e9 | |||
| 9fa1f7b981 | |||
| 4a68e4cd9d | |||
| 8320b6fd7c | |||
| e40cf0a1c4 | |||
| 19106985d7 | |||
| 3d817c54da | |||
| ca31877107 | |||
| f5f9afefb0 |
+2
-2
@@ -34,13 +34,13 @@
|
||||
<!-- JNA library release version -->
|
||||
<property name="jna.major" value="3"/>
|
||||
<property name="jna.minor" value="2"/>
|
||||
<property name="jna.revision" value="1"/>
|
||||
<property name="jna.revision" value="2"/>
|
||||
<property name="jna.build" value="${build.number}"/>
|
||||
<property name="jna.version" value="${jna.major}.${jna.minor}.${jna.revision}"/>
|
||||
<!-- jnidispatch library release version -->
|
||||
<property name="jni.major" value="3"/>
|
||||
<property name="jni.minor" value="2"/>
|
||||
<property name="jni.revision" value="0"/>
|
||||
<property name="jni.revision" value="1"/>
|
||||
<property name="jni.build" value="${build.number}"/>
|
||||
<property name="jni.version" value="${jni.major}.${jni.minor}.${jni.revision}"/>
|
||||
<property name="jni.md5" value="c870290c36c8d3fdf85db7c782febc3f"/>
|
||||
|
||||
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
externo
BIN
Arquivo binário não exibido.
@@ -27,7 +27,7 @@ OS=$(shell uname | sed -e 's/\(CYGWIN\|MINGW32\).*/win32/g' \
|
||||
-e 's/Darwin.*/darwin/g' \
|
||||
-e 's/Linux.*/linux/g')
|
||||
|
||||
VERSION=3.2.0 # auto-generated by ant
|
||||
VERSION=3.2.1 # auto-generated by ant
|
||||
CHECKSUM=c870290c36c8d3fdf85db7c782febc3f # auto-generated by ant
|
||||
|
||||
JAVA_INCLUDES=-I"$(JAVA_HOME)/include" \
|
||||
|
||||
+98
-93
@@ -1805,7 +1805,7 @@ getArrayComponentType(JNIEnv *env, jobject obj) {
|
||||
|
||||
static void*
|
||||
getBufferArray(JNIEnv* env, jobject buf,
|
||||
jobject* arrayp, void **elemp,
|
||||
jobject* arrayp, void **basep,
|
||||
void **releasep) {
|
||||
void *ptr = NULL;
|
||||
int offset = 0;
|
||||
@@ -1846,7 +1846,7 @@ do { \
|
||||
GET_ARRAY(Double, 8);
|
||||
}
|
||||
if (ptr != NULL) {
|
||||
if (elemp) *elemp = ptr;
|
||||
if (basep) *basep = ptr;
|
||||
if (arrayp) *arrayp = array;
|
||||
ptr = (char *)ptr + offset;
|
||||
}
|
||||
@@ -2581,106 +2581,111 @@ method_handler(ffi_cif* cif, void* volatile resp, void** argp, void *cdata) {
|
||||
|
||||
if (data->flags) {
|
||||
objects = alloca(data->cif.nargs * sizeof(void*));
|
||||
memset(objects, 0, data->cif.nargs * sizeof(void*));
|
||||
release = alloca(data->cif.nargs * sizeof(release_t));
|
||||
memset(release, 0, data->cif.nargs * sizeof(release_t));
|
||||
elems = alloca(data->cif.nargs * sizeof(void*));
|
||||
for (i=0;i < data->cif.nargs;i++) {
|
||||
if (data->flags[i] != CVT_DEFAULT) {
|
||||
if (data->arg_types[i]->type == FFI_TYPE_POINTER
|
||||
&& *(void **)args[i] == NULL) continue;
|
||||
switch(data->flags[i]) {
|
||||
case CVT_INTEGER_TYPE:
|
||||
{
|
||||
jlong value = getIntegerTypeValue(env, *(void **)args[i]);
|
||||
if (cif->arg_types[i+2]->size < data->cif.arg_types[i]->size) {
|
||||
args[i] = alloca(data->cif.arg_types[i]->size);
|
||||
}
|
||||
if (data->cif.arg_types[i]->size > sizeof(ffi_arg)) {
|
||||
*(jlong *)args[i] = value;
|
||||
}
|
||||
else {
|
||||
*(ffi_arg *)args[i] = (ffi_arg)value;
|
||||
if (data->flags[i] == CVT_DEFAULT) {
|
||||
continue;
|
||||
}
|
||||
if (data->arg_types[i]->type == FFI_TYPE_POINTER
|
||||
&& *(void **)args[i] == NULL) {
|
||||
continue;
|
||||
}
|
||||
switch(data->flags[i]) {
|
||||
case CVT_INTEGER_TYPE:
|
||||
{
|
||||
jlong value = getIntegerTypeValue(env, *(void **)args[i]);
|
||||
if (cif->arg_types[i+2]->size < data->cif.arg_types[i]->size) {
|
||||
args[i] = alloca(data->cif.arg_types[i]->size);
|
||||
}
|
||||
if (data->cif.arg_types[i]->size > sizeof(ffi_arg)) {
|
||||
*(jlong *)args[i] = value;
|
||||
}
|
||||
else {
|
||||
*(ffi_arg *)args[i] = (ffi_arg)value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CVT_POINTER_TYPE:
|
||||
*(void **)args[i] = getPointerTypeAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_TYPE_MAPPER:
|
||||
{
|
||||
void* valuep = args[i];
|
||||
int jtype = get_jtype_from_ffi_type(data->closure_cif.arg_types[i+2]);
|
||||
jobject obj = jtype == '*'
|
||||
? *(void **)valuep
|
||||
: new_object(env, (char)jtype, valuep, JNI_FALSE);
|
||||
if (cif->arg_types[i+2]->size < data->cif.arg_types[i]->size) {
|
||||
args[i] = alloca(data->cif.arg_types[i]->size);
|
||||
}
|
||||
toNativeTypeMapped(env, obj, args[i],
|
||||
data->cif.arg_types[i]->size,
|
||||
data->to_native[i]);
|
||||
}
|
||||
break;
|
||||
case CVT_NATIVE_MAPPED:
|
||||
toNative(env, *(void **)args[i], args[i], data->cif.arg_types[i]->size, JNI_FALSE);
|
||||
break;
|
||||
case CVT_POINTER:
|
||||
*(void **)args[i] = getNativeAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_STRUCTURE:
|
||||
objects[i] = *(void **)args[i];
|
||||
writeStructure(env, *(void **)args[i]);
|
||||
*(void **)args[i] = getStructureAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_STRUCTURE_BYVAL:
|
||||
objects[i] = *(void **)args[i];
|
||||
writeStructure(env, objects[i]);
|
||||
args[i] = getStructureAddress(env, objects[i]);
|
||||
break;
|
||||
case CVT_STRING:
|
||||
*(void **)args[i] = newCStringEncoding(env, (jstring)*(void **)args[i], jna_encoding);
|
||||
break;
|
||||
case CVT_WSTRING:
|
||||
{
|
||||
jstring s = (*env)->CallObjectMethod(env, *(void **)args[i], MID_Object_toString);
|
||||
*(void **)args[i] = newWideCString(env, s);
|
||||
}
|
||||
break;
|
||||
case CVT_CALLBACK:
|
||||
*(void **)args[i] = getCallbackAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_BUFFER:
|
||||
{
|
||||
void *ptr = (*env)->GetDirectBufferAddress(env, *(void **)args[i]);
|
||||
if (ptr != NULL) {
|
||||
objects[i] = NULL;
|
||||
release[i] = NULL;
|
||||
}
|
||||
else {
|
||||
ptr = getBufferArray(env, *(jobject *)args[i], (jobject *)&objects[i], &elems[i], (void**)&release[i]);
|
||||
if (ptr == NULL) {
|
||||
throw_type = EIllegalArgument;
|
||||
throw_msg = "Buffer arguments must be direct or have a primitive backing array";
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CVT_POINTER_TYPE:
|
||||
*(void **)args[i] = getPointerTypeAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_TYPE_MAPPER:
|
||||
{
|
||||
void* valuep = args[i];
|
||||
int jtype = get_jtype_from_ffi_type(data->closure_cif.arg_types[i+2]);
|
||||
jobject obj = jtype == '*'
|
||||
? *(void **)valuep
|
||||
: new_object(env, (char)jtype, valuep, JNI_FALSE);
|
||||
if (cif->arg_types[i+2]->size < data->cif.arg_types[i]->size) {
|
||||
args[i] = alloca(data->cif.arg_types[i]->size);
|
||||
}
|
||||
toNativeTypeMapped(env, obj, args[i],
|
||||
data->cif.arg_types[i]->size,
|
||||
data->to_native[i]);
|
||||
}
|
||||
break;
|
||||
case CVT_NATIVE_MAPPED:
|
||||
toNative(env, *(void **)args[i], args[i], data->cif.arg_types[i]->size, JNI_FALSE);
|
||||
break;
|
||||
case CVT_POINTER:
|
||||
*(void **)args[i] = getNativeAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_STRUCTURE:
|
||||
objects[i] = *(void **)args[i];
|
||||
writeStructure(env, *(void **)args[i]);
|
||||
*(void **)args[i] = getStructureAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_STRUCTURE_BYVAL:
|
||||
objects[i] = *(void **)args[i];
|
||||
writeStructure(env, objects[i]);
|
||||
args[i] = getStructureAddress(env, objects[i]);
|
||||
break;
|
||||
case CVT_STRING:
|
||||
*(void **)args[i] = newCStringEncoding(env, (jstring)*(void **)args[i], jna_encoding);
|
||||
break;
|
||||
case CVT_WSTRING:
|
||||
{
|
||||
jstring s = (*env)->CallObjectMethod(env, *(void **)args[i], MID_Object_toString);
|
||||
*(void **)args[i] = newWideCString(env, s);
|
||||
}
|
||||
break;
|
||||
case CVT_CALLBACK:
|
||||
*(void **)args[i] = getCallbackAddress(env, *(void **)args[i]);
|
||||
break;
|
||||
case CVT_BUFFER:
|
||||
{
|
||||
void *ptr = (*env)->GetDirectBufferAddress(env, *(void **)args[i]);
|
||||
if (ptr != NULL) {
|
||||
objects[i] = NULL;
|
||||
release[i] = NULL;
|
||||
}
|
||||
else {
|
||||
ptr = getBufferArray(env, *(jobject *)args[i], (jobject *)&objects[i], &elems[i], (void**)&release[i]);
|
||||
if (ptr == NULL) {
|
||||
throw_type = EIllegalArgument;
|
||||
throw_msg = "Buffer arguments must be direct or have a primitive backing array";
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
*(void **)args[i] = ptr;
|
||||
}
|
||||
break;
|
||||
#define ARRAY(Type) \
|
||||
*(void **)args[i] = ptr;
|
||||
}
|
||||
break;
|
||||
#define ARRAY(Type) \
|
||||
do { \
|
||||
objects[i] = *(void **)args[i]; \
|
||||
release[i] = (void *)(*env)->Release##Type##ArrayElements; \
|
||||
elems[i] = *(void **)args[i] = (*env)->Get##Type##ArrayElements(env, objects[i], NULL); } while(0)
|
||||
case CVT_ARRAY_BYTE: ARRAY(Byte); break;
|
||||
case CVT_ARRAY_SHORT: ARRAY(Short); break;
|
||||
case CVT_ARRAY_CHAR: ARRAY(Char); break;
|
||||
case CVT_ARRAY_INT: ARRAY(Int); break;
|
||||
case CVT_ARRAY_LONG: ARRAY(Long); break;
|
||||
case CVT_ARRAY_FLOAT: ARRAY(Float); break;
|
||||
case CVT_ARRAY_DOUBLE: ARRAY(Double); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case CVT_ARRAY_BYTE: ARRAY(Byte); break;
|
||||
case CVT_ARRAY_SHORT: ARRAY(Short); break;
|
||||
case CVT_ARRAY_CHAR: ARRAY(Char); break;
|
||||
case CVT_ARRAY_INT: ARRAY(Int); break;
|
||||
case CVT_ARRAY_LONG: ARRAY(Long); break;
|
||||
case CVT_ARRAY_FLOAT: ARRAY(Float); break;
|
||||
case CVT_ARRAY_DOUBLE: ARRAY(Double); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,6 +712,24 @@ fillInt64Buffer(int64_t *buf, int len, int64_t value) {
|
||||
return len;
|
||||
}
|
||||
|
||||
EXPORT int32_t
|
||||
fillFloatBuffer(float *buf, int len, float value) {
|
||||
int i;
|
||||
for (i=0;i < len;i++) {
|
||||
buf[i] = value;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
EXPORT int32_t
|
||||
fillDoubleBuffer(double *buf, int len, double value) {
|
||||
int i;
|
||||
for (i=0;i < len;i++) {
|
||||
buf[i] = value;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
EXPORT int32_t
|
||||
addInt32VarArgs(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
|
||||
+1
-2
@@ -6,7 +6,7 @@
|
||||
<groupId>net.java.dev.jna</groupId>
|
||||
<artifactId>jna</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>3.2.1</version>
|
||||
<version>3.2.2</version>
|
||||
<name>Java Native Access</name>
|
||||
|
||||
<distributionManagement>
|
||||
@@ -33,7 +33,6 @@
|
||||
<tasks>
|
||||
<!--<ant dir="." target="dist" />-->
|
||||
<attachArtifact file="dist/jna.jar" />
|
||||
<attachArtifact file="dist/examples.jar" />
|
||||
<attachArtifact file="dist/src-mvn.zip" classifier="sources" type="jar"/>
|
||||
</tasks>
|
||||
</configuration>
|
||||
|
||||
@@ -1,4 +1,21 @@
|
||||
<a name="top"></a>
|
||||
<h2>Release 3.2.2</h2>
|
||||
<b>Features</b><br>
|
||||
<ul>
|
||||
<li>Provide length-specified Pointer.getStringArray()
|
||||
</ul>
|
||||
<b>Bug Fixes</b><br>
|
||||
<ul>
|
||||
<li>Fix crash with direct mapping if NULL struct* used (<a href="https://jna.dev.java.net/issues/show_bug.cgi?id=125">Issue 125</a>).
|
||||
<li>Fix case where null-valued Structure fields would get non-null values on
|
||||
write.
|
||||
<li>Synch callback Structure/Structure[] arguments on callback return.
|
||||
<li>Fix NPE when mapping an interface to the current process.
|
||||
<li>Automatically load proper C library version from current process on Linux
|
||||
(avoids crashing bug on Ubuntu with libc-i686 packages active).
|
||||
<li>Avoid scanning structure contents in Structure.toString if contents aren't
|
||||
actually used.
|
||||
</ul>
|
||||
<h2>Release 3.2.1</h2>
|
||||
<b>Features</b><br>
|
||||
<ul>
|
||||
|
||||
@@ -393,6 +393,14 @@ class CallbackReference extends WeakReference {
|
||||
Native.getCallbackExceptionHandler().uncaughtException(cb, e.getTargetException());
|
||||
}
|
||||
}
|
||||
// Synch any structure arguments back to native memory
|
||||
for (int i=0;i < callbackArgs.length;i++) {
|
||||
if (callbackArgs[i] instanceof Structure
|
||||
&& !(callbackArgs[i] instanceof Structure.ByValue)) {
|
||||
((Structure)callbackArgs[i]).autoWrite();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
/** Called from native code. All arguments are in an array of
|
||||
|
||||
@@ -268,10 +268,7 @@ public class Function extends Pointer {
|
||||
}
|
||||
}
|
||||
else if (Structure[].class.isAssignableFrom(inArg.getClass())) {
|
||||
Structure[] ss = (Structure[])inArg;
|
||||
for (int si=0;si < ss.length;si++) {
|
||||
ss[si].autoRead();
|
||||
}
|
||||
Structure.autoRead((Structure[])inArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -495,18 +492,8 @@ public class Function extends Pointer {
|
||||
return ss[0].getPointer();
|
||||
}
|
||||
else {
|
||||
Pointer base = ss[0].getPointer();
|
||||
int size = ss[0].size();
|
||||
ss[0].autoWrite();
|
||||
for (int si=1;si < ss.length;si++) {
|
||||
if (ss[si].getPointer().peer != base.peer + size*si) {
|
||||
String msg = "Structure array elements must use"
|
||||
+ " contiguous memory (at element index " + si + ")";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
ss[si].autoWrite();
|
||||
}
|
||||
return base;
|
||||
Structure.autoWrite(ss);
|
||||
return ss[0].getPointer();
|
||||
}
|
||||
}
|
||||
else if (argClass.isArray()){
|
||||
|
||||
@@ -122,7 +122,7 @@ public interface Library {
|
||||
private final Map functions = new WeakHashMap();
|
||||
public Handler(String libname, Class interfaceClass, Map options) {
|
||||
|
||||
if ("".equals(libname.trim())) {
|
||||
if (libname != null && "".equals(libname.trim())) {
|
||||
throw new IllegalArgumentException("Invalid library name \""
|
||||
+ libname + "\"");
|
||||
}
|
||||
|
||||
@@ -137,7 +137,9 @@ public class NativeLibrary {
|
||||
//
|
||||
libraryPath = matchLibrary(libraryName, searchPath);
|
||||
if (libraryPath != null) {
|
||||
try { handle = open(libraryPath); }
|
||||
try {
|
||||
handle = open(libraryPath);
|
||||
}
|
||||
catch(UnsatisfiedLinkError e2) { e = e2; }
|
||||
}
|
||||
}
|
||||
@@ -146,7 +148,9 @@ public class NativeLibrary {
|
||||
libraryPath = "/System/Library/Frameworks/" + libraryName
|
||||
+ ".framework/" + libraryName;
|
||||
if (new File(libraryPath).exists()) {
|
||||
try { handle = open(libraryPath); }
|
||||
try {
|
||||
handle = open(libraryPath);
|
||||
}
|
||||
catch(UnsatisfiedLinkError e2) { e = e2; }
|
||||
}
|
||||
}
|
||||
@@ -216,6 +220,11 @@ public class NativeLibrary {
|
||||
options.put(Library.OPTION_CALLING_CONVENTION, new Integer(Function.C_CONVENTION));
|
||||
}
|
||||
|
||||
// Use current process to load libraries we know are already
|
||||
// loaded by the VM to ensure we get the correct version
|
||||
if (Platform.isLinux() && "c".equals(libraryName)) {
|
||||
libraryName = null;
|
||||
}
|
||||
synchronized (libraries) {
|
||||
WeakReference ref = (WeakReference)libraries.get(libraryName + options);
|
||||
NativeLibrary library = ref != null ? (NativeLibrary)ref.get() : null;
|
||||
|
||||
@@ -66,6 +66,12 @@ public class NativeMappedConverter implements TypeConverter {
|
||||
}
|
||||
|
||||
public Object toNative(Object value, ToNativeContext context) {
|
||||
return value == null ? defaultValue().toNative() : ((NativeMapped)value).toNative();
|
||||
if (value == null) {
|
||||
if (Pointer.class.isAssignableFrom(nativeType)) {
|
||||
return null;
|
||||
}
|
||||
value = defaultValue();
|
||||
}
|
||||
return ((NativeMapped)value).toNative();
|
||||
}
|
||||
}
|
||||
@@ -377,6 +377,7 @@ public class Pointer {
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Object getValue(long offset, Class type, Object currentValue) {
|
||||
|
||||
Object result = null;
|
||||
if (Structure.class.isAssignableFrom(type)) {
|
||||
Structure s = (Structure)currentValue;
|
||||
@@ -457,7 +458,7 @@ public class Pointer {
|
||||
Pointer oldbp = currentValue == null ? null
|
||||
: Native.getDirectBufferPointer((Buffer)currentValue);
|
||||
if (oldbp == null || !oldbp.equals(bp)) {
|
||||
throw new IllegalStateException("Can't autogenerate a direct buffers on memory read");
|
||||
throw new IllegalStateException("Can't autogenerate a direct buffer on memory read");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -465,7 +466,7 @@ public class Pointer {
|
||||
NativeMapped nm = (NativeMapped)currentValue;
|
||||
if (nm != null) {
|
||||
Object value = getValue(offset, nm.nativeType(), null);
|
||||
nm.fromNative(value, new FromNativeContext(type));
|
||||
result = nm.fromNative(value, new FromNativeContext(type));
|
||||
}
|
||||
else {
|
||||
NativeMappedConverter tc = NativeMappedConverter.getInstance(type);
|
||||
@@ -809,7 +810,14 @@ v * @param wide whether to convert from a wide or standard C string
|
||||
* NULL-valued terminating element.
|
||||
*/
|
||||
public String[] getStringArray(long base) {
|
||||
return getStringArray(base, false);
|
||||
return getStringArray(base, -1, false);
|
||||
}
|
||||
|
||||
/** Returns an array of <code>String</code> based on a native array
|
||||
* of <code>char *</code>, using the given array length.
|
||||
*/
|
||||
public String[] getStringArray(long base, int length) {
|
||||
return getStringArray(base, length, false);
|
||||
}
|
||||
|
||||
/** Returns an array of <code>String</code> based on a native array
|
||||
@@ -818,13 +826,32 @@ v * @param wide whether to convert from a wide or standard C string
|
||||
* NULL-valued terminating element.
|
||||
*/
|
||||
public String[] getStringArray(long base, boolean wide) {
|
||||
return getStringArray(base, -1, wide);
|
||||
}
|
||||
|
||||
/** Returns an array of <code>String</code> based on a native array
|
||||
* of <code>char*</code> or <code>wchar_t*</code> based on the
|
||||
* <code>wide</code> parameter, using the given array length.
|
||||
*/
|
||||
public String[] getStringArray(long base, int length, boolean wide) {
|
||||
|
||||
List strings = new ArrayList();
|
||||
int offset = 0;
|
||||
Pointer p = getPointer(base);
|
||||
while (p != null) {
|
||||
strings.add(p.getString(0, wide));
|
||||
offset += SIZE;
|
||||
p = getPointer(base + offset);
|
||||
if (length != -1) {
|
||||
int count = 0;
|
||||
while (count++ < length) {
|
||||
strings.add(p.getString(0, wide));
|
||||
offset += SIZE;
|
||||
p = getPointer(base + offset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (p != null) {
|
||||
strings.add(p.getString(0, wide));
|
||||
offset += SIZE;
|
||||
p = getPointer(base + offset);
|
||||
}
|
||||
}
|
||||
return (String[])strings.toArray(new String[strings.size()]);
|
||||
}
|
||||
@@ -834,6 +861,7 @@ v * @param wide whether to convert from a wide or standard C string
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setValue(long offset, Object value, Class type) {
|
||||
|
||||
// Set the value at the offset according to its type
|
||||
if (type == boolean.class || type == Boolean.class) {
|
||||
setInt(offset, Boolean.TRUE.equals(value) ? -1 : 0);
|
||||
|
||||
@@ -220,6 +220,7 @@ public abstract class Structure {
|
||||
// from the ctor, to ensure fields are properly scanned and allocated
|
||||
try {
|
||||
this.memory = m.share(offset, size());
|
||||
this.array = null;
|
||||
}
|
||||
catch(IndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException("Structure exceeds provided memory bounds");
|
||||
@@ -297,21 +298,57 @@ public abstract class Structure {
|
||||
will change if structure field values change.
|
||||
*/
|
||||
class StructureSet extends AbstractCollection implements Set {
|
||||
private Collection list = new ArrayList();
|
||||
public int size() { return list.size(); }
|
||||
private Structure[] elements;
|
||||
private int count;
|
||||
private void ensureCapacity(int size) {
|
||||
if (elements == null) {
|
||||
elements = new Structure[size*3/2];
|
||||
}
|
||||
else if (elements.length < size) {
|
||||
Structure[] e = new Structure[size*3/2];
|
||||
System.arraycopy(elements, 0, e, 0, elements.length);
|
||||
elements = e;
|
||||
}
|
||||
}
|
||||
public int size() { return count; }
|
||||
public boolean contains(Object o) {
|
||||
for (Iterator i=iterator();i.hasNext();) {
|
||||
if (o == i.next())
|
||||
return true;
|
||||
return indexOf(o) != -1;
|
||||
}
|
||||
public boolean add(Object o) {
|
||||
if (!contains(o)) {
|
||||
ensureCapacity(count+1);
|
||||
elements[count++] = (Structure)o;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private int indexOf(Object o) {
|
||||
Structure s1 = (Structure)o;
|
||||
for (int i=0;i < count;i++) {
|
||||
Structure s2 = (Structure)elements[i];
|
||||
if (s1 == s2
|
||||
|| (s1.baseClass() == s2.baseClass()
|
||||
&& s1.size() == s2.size()
|
||||
&& s1.getPointer().equals(s2.getPointer()))) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public boolean remove(Object o) {
|
||||
int idx = indexOf(o);
|
||||
if (idx != -1) {
|
||||
if (--count > 0) {
|
||||
elements[idx] = elements[count];
|
||||
elements[count] = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public boolean add(Object o) {
|
||||
if (!contains(o))
|
||||
return list.add(o);
|
||||
return true;
|
||||
public Iterator iterator() {
|
||||
// never actually used
|
||||
return null;
|
||||
}
|
||||
public Iterator iterator() { return list.iterator(); }
|
||||
}
|
||||
protected synchronized Object initialValue() {
|
||||
return new StructureSet();
|
||||
@@ -820,7 +857,7 @@ public abstract class Structure {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return toString(0);
|
||||
return toString(0, true);
|
||||
}
|
||||
|
||||
private String format(Class type) {
|
||||
@@ -829,7 +866,7 @@ public abstract class Structure {
|
||||
return s.substring(dot + 1);
|
||||
}
|
||||
|
||||
private String toString(int indent) {
|
||||
private String toString(int indent, boolean showContents) {
|
||||
String LS = System.getProperty("line.separator");
|
||||
String name = format(getClass()) + "(" + getPointer() + ")";
|
||||
if (!(getPointer() instanceof Memory)) {
|
||||
@@ -839,9 +876,11 @@ public abstract class Structure {
|
||||
for (int idx=0;idx < indent;idx++) {
|
||||
prefix += " ";
|
||||
}
|
||||
String contents = "";
|
||||
// Write all fields
|
||||
for (Iterator i=structFields.values().iterator();i.hasNext();) {
|
||||
String contents = LS;
|
||||
if (!showContents) {
|
||||
contents = "...}";
|
||||
}
|
||||
else for (Iterator i=structFields.values().iterator();i.hasNext();) {
|
||||
StructField sf = (StructField)i.next();
|
||||
Object value = getField(sf);
|
||||
String type = format(sf.type);
|
||||
@@ -854,16 +893,7 @@ public abstract class Structure {
|
||||
contents += " " + type + " "
|
||||
+ sf.name + index + "@" + Integer.toHexString(sf.offset);
|
||||
if (value instanceof Structure) {
|
||||
if (value instanceof Structure.ByReference) {
|
||||
String v = value.toString();
|
||||
if (v.indexOf(LS) != -1) {
|
||||
v = v.substring(0, v.indexOf(LS));
|
||||
}
|
||||
value = v + "...}";
|
||||
}
|
||||
else {
|
||||
value = ((Structure)value).toString(indent + 1);
|
||||
}
|
||||
value = ((Structure)value).toString(indent + 1, !(value instanceof Structure.ByReference));
|
||||
}
|
||||
contents += "=";
|
||||
if (value instanceof Long) {
|
||||
@@ -899,7 +929,7 @@ public abstract class Structure {
|
||||
}
|
||||
contents += "]";
|
||||
}
|
||||
return name + " {" + LS + contents;
|
||||
return name + " {" + contents;
|
||||
}
|
||||
|
||||
/** Returns a view of this structure's memory as an array of structures.
|
||||
@@ -927,7 +957,8 @@ public abstract class Structure {
|
||||
array[i].read();
|
||||
}
|
||||
|
||||
if (this instanceof ByReference) {
|
||||
if (!(this instanceof ByValue)) {
|
||||
// keep track for later auto-read/writes
|
||||
this.array = array;
|
||||
}
|
||||
|
||||
@@ -943,6 +974,15 @@ public abstract class Structure {
|
||||
return toArray((Structure[])Array.newInstance(getClass(), size));
|
||||
}
|
||||
|
||||
private Class baseClass() {
|
||||
if ((this instanceof Structure.ByReference
|
||||
|| this instanceof Structure.ByValue)
|
||||
&& Structure.class.isAssignableFrom(getClass().getSuperclass())) {
|
||||
return getClass().getSuperclass();
|
||||
}
|
||||
return getClass();
|
||||
}
|
||||
|
||||
/** This structure is only equal to another based on the same native
|
||||
* memory address and data type.
|
||||
*/
|
||||
@@ -951,24 +991,9 @@ public abstract class Structure {
|
||||
return true;
|
||||
if (o == null)
|
||||
return false;
|
||||
if (o.getClass() != getClass()) {
|
||||
// Only allow one class derived from the other and implementing
|
||||
// ByReference or ByValue, or both implementing
|
||||
// ByReference/ByValue on the same base class
|
||||
if (!((o.getClass().isAssignableFrom(getClass())
|
||||
&& (ByReference.class.isAssignableFrom(getClass())
|
||||
|| ByValue.class.isAssignableFrom(getClass())))
|
||||
|| (getClass().isAssignableFrom(o.getClass())
|
||||
&& (ByReference.class.isAssignableFrom(o.getClass())
|
||||
|| ByValue.class.isAssignableFrom(o.getClass())))
|
||||
|| ((ByReference.class.isAssignableFrom(o.getClass())
|
||||
|| ByValue.class.isAssignableFrom(o.getClass()))
|
||||
&& (ByReference.class.isAssignableFrom(getClass())
|
||||
|| ByValue.class.isAssignableFrom(getClass()))
|
||||
&& (o.getClass().getSuperclass()
|
||||
== getClass().getSuperclass())))) {
|
||||
return false;
|
||||
}
|
||||
if (o.getClass() != getClass()
|
||||
&& ((Structure)o).baseClass() != baseClass()) {
|
||||
return false;
|
||||
}
|
||||
Structure s = (Structure)o;
|
||||
if (s.size() == size()) {
|
||||
@@ -1233,6 +1258,30 @@ public abstract class Structure {
|
||||
}
|
||||
}
|
||||
|
||||
private static void structureArrayCheck(Structure[] ss) {
|
||||
Pointer base = ss[0].getPointer();
|
||||
int size = ss[0].size();
|
||||
for (int si=1;si < ss.length;si++) {
|
||||
if (ss[si].getPointer().peer != base.peer + size*si) {
|
||||
String msg = "Structure array elements must use"
|
||||
+ " contiguous memory (bad backing address at Structure array index " + si + ")";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void autoRead(Structure[] ss) {
|
||||
structureArrayCheck(ss);
|
||||
if (ss[0].array == ss) {
|
||||
ss[0].autoRead();
|
||||
}
|
||||
else {
|
||||
for (int si=0;si < ss.length;si++) {
|
||||
ss[si].autoRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void autoRead() {
|
||||
if (getAutoRead()) {
|
||||
read();
|
||||
@@ -1244,6 +1293,18 @@ public abstract class Structure {
|
||||
}
|
||||
}
|
||||
|
||||
public static void autoWrite(Structure[] ss) {
|
||||
structureArrayCheck(ss);
|
||||
if (ss[0].array == ss) {
|
||||
ss[0].autoWrite();
|
||||
}
|
||||
else {
|
||||
for (int si=0;si < ss.length;si++) {
|
||||
ss[si].autoWrite();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void autoWrite() {
|
||||
if (getAutoWrite()) {
|
||||
write();
|
||||
|
||||
@@ -14,6 +14,8 @@ package com.sun.jna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
@@ -81,17 +83,23 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
int fillInt16Buffer(short[] buf, int len, short value);
|
||||
int fillInt32Buffer(int[] buf, int len, int value);
|
||||
int fillInt64Buffer(long[] buf, int len, long value);
|
||||
int fillFloatBuffer(float[] buf, int len, float value);
|
||||
int fillDoubleBuffer(double[] buf, int len, double value);
|
||||
|
||||
// ByteBuffer alternative definitions
|
||||
int fillInt8Buffer(ByteBuffer buf, int len, byte value);
|
||||
int fillInt16Buffer(ByteBuffer buf, int len, short value);
|
||||
int fillInt32Buffer(ByteBuffer buf, int len, int value);
|
||||
int fillInt64Buffer(ByteBuffer buf, int len, long value);
|
||||
int fillFloatBuffer(ByteBuffer buf, int len, float value);
|
||||
int fillDoubleBuffer(ByteBuffer buf, int len, double value);
|
||||
|
||||
// {Short,Int,Long}Buffer alternative definitions
|
||||
// {Short|Int|Long|,Float|Double}Buffer alternative definitions
|
||||
int fillInt16Buffer(ShortBuffer buf, int len, short value);
|
||||
int fillInt32Buffer(IntBuffer buf, int len, int value);
|
||||
int fillInt64Buffer(LongBuffer buf, int len, long value);
|
||||
int fillFloatBuffer(FloatBuffer buf, int len, float value);
|
||||
int fillDoubleBuffer(DoubleBuffer buf, int len, double value);
|
||||
|
||||
// Nonexistent functions
|
||||
boolean returnBooleanArgument(Object arg);
|
||||
@@ -323,6 +331,10 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
+ "parameter type, not argument type",
|
||||
struct.getPointer(),
|
||||
lib.testStructurePointerArgument(struct));
|
||||
|
||||
struct = null;
|
||||
assertNull("Null argument should be returned",
|
||||
lib.testStructurePointerArgument(struct));
|
||||
}
|
||||
|
||||
public void testStructureByValueArgument() {
|
||||
@@ -353,7 +365,6 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
public void testWriteStructureArrayArgumentMemory() {
|
||||
final int LENGTH = 10;
|
||||
TestLibrary.CheckFieldAlignment block = new TestLibrary.CheckFieldAlignment();
|
||||
block.useMemory(new Memory(block.size() * LENGTH));
|
||||
TestLibrary.CheckFieldAlignment[] array =
|
||||
(TestLibrary.CheckFieldAlignment[])block.toArray(LENGTH);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
@@ -508,6 +519,67 @@ public class ArgumentsMarshalTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testWrappedByteArrayArgument() {
|
||||
byte[] array = new byte[1024];
|
||||
ByteBuffer buf = ByteBuffer.wrap(array, 512, 512).slice();
|
||||
final byte MAGIC = (byte)0xAB;
|
||||
lib.fillInt8Buffer(buf, 512, MAGIC);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
assertEquals("Bad value at index " + i,
|
||||
i < 512 ? 0 : MAGIC, array[i]);
|
||||
}
|
||||
}
|
||||
public void testWrappedShortArrayArgument() {
|
||||
short[] array = new short[1024];
|
||||
ShortBuffer buf = ShortBuffer.wrap(array, 512, 512).slice();
|
||||
final short MAGIC = (short)0xABED;
|
||||
lib.fillInt16Buffer(buf, 512, MAGIC);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
assertEquals("Bad value at index " + i,
|
||||
i < 512 ? 0 : MAGIC, array[i]);
|
||||
}
|
||||
}
|
||||
public void testWrappedIntArrayArgument() {
|
||||
int[] array = new int[1024];
|
||||
IntBuffer buf = IntBuffer.wrap(array, 512, 512).slice();
|
||||
final int MAGIC = 0xABEDCF23;
|
||||
lib.fillInt32Buffer(buf, 512, MAGIC);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
assertEquals("Bad value at index " + i,
|
||||
i < 512 ? 0 : MAGIC, array[i]);
|
||||
}
|
||||
}
|
||||
public void testWrappedLongArrayArguent() {
|
||||
long[] array = new long[1024];
|
||||
LongBuffer buf = LongBuffer.wrap(array, 512, 512).slice();
|
||||
final long MAGIC = 0x1234567887654321L;
|
||||
lib.fillInt64Buffer(buf, 512, MAGIC);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
assertEquals("Bad value at index " + i,
|
||||
i < 512 ? 0 : MAGIC, array[i]);
|
||||
}
|
||||
}
|
||||
public void testWrappedFloatArrayArguent() {
|
||||
float[] array = new float[1024];
|
||||
FloatBuffer buf = FloatBuffer.wrap(array, 512, 512).slice();
|
||||
final float MAGIC = -118.625f;
|
||||
lib.fillFloatBuffer(buf, 512, MAGIC);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
assertEquals("Bad value at index " + i,
|
||||
i < 512 ? 0 : MAGIC, array[i]);
|
||||
}
|
||||
}
|
||||
public void testWrappedDoubleArrayArguent() {
|
||||
double[] array = new double[1024];
|
||||
DoubleBuffer buf = DoubleBuffer.wrap(array, 512, 512).slice();
|
||||
final double MAGIC = -118.625;
|
||||
lib.fillDoubleBuffer(buf, 512, MAGIC);
|
||||
for (int i=0;i < array.length;i++) {
|
||||
assertEquals("Bad value at index " + i,
|
||||
i < 512 ? 0 : MAGIC, array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void testInvalidArgument() {
|
||||
try {
|
||||
lib.returnBooleanArgument(this);
|
||||
|
||||
@@ -354,19 +354,45 @@ public class CallbacksTest extends TestCase {
|
||||
|
||||
public void testCallStructureCallback() {
|
||||
final boolean[] called = {false};
|
||||
final Structure[] cbarg = { null };
|
||||
final Pointer[] cbarg = { null };
|
||||
final SmallTestStructure s = new SmallTestStructure();
|
||||
final double MAGIC = 118.625;
|
||||
TestLibrary.StructureCallback cb = new TestLibrary.StructureCallback() {
|
||||
public SmallTestStructure callback(SmallTestStructure arg) {
|
||||
called[0] = true;
|
||||
cbarg[0] = arg;
|
||||
cbarg[0] = arg.getPointer();
|
||||
arg.value = MAGIC;
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
SmallTestStructure value = lib.callStructureCallback(cb, s);
|
||||
assertTrue("Callback not called", called[0]);
|
||||
assertEquals("Wrong argument passed to callback", s, cbarg[0]);
|
||||
assertEquals("Wrong structure return", s, value);
|
||||
assertEquals("Wrong argument passed to callback", s.getPointer(), cbarg[0]);
|
||||
assertEquals("Structure argument not synched on callback return",
|
||||
MAGIC, s.value);
|
||||
assertEquals("Wrong structure return", s.getPointer(), value.getPointer());
|
||||
assertEquals("Structure return not synched",
|
||||
MAGIC, value.value);
|
||||
}
|
||||
|
||||
public void testCallStructureArrayCallback() {
|
||||
final SmallTestStructure s = new SmallTestStructure();
|
||||
final SmallTestStructure[] array = (SmallTestStructure[])s.toArray(2);
|
||||
final double MAGIC = 118.625;
|
||||
TestLibrary.StructureCallback cb = new TestLibrary.StructureCallback() {
|
||||
public SmallTestStructure callback(SmallTestStructure arg) {
|
||||
SmallTestStructure[] array =
|
||||
(SmallTestStructure[])arg.toArray(2);
|
||||
array[0].value = MAGIC;
|
||||
array[1].value = MAGIC*2;
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
SmallTestStructure value = lib.callStructureCallback(cb, s);
|
||||
assertEquals("Structure array element 0 not synched on callback return",
|
||||
MAGIC, array[0].value);
|
||||
assertEquals("Structure array element 1 not synched on callback return",
|
||||
MAGIC*2, array[1].value);
|
||||
}
|
||||
|
||||
public void testCallBooleanCallback() {
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
package com.sun.jna;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
@@ -60,17 +62,23 @@ public class DirectArgumentsMarshalTest extends ArgumentsMarshalTest {
|
||||
public native int fillInt16Buffer(short[] buf, int len, short value);
|
||||
public native int fillInt32Buffer(int[] buf, int len, int value);
|
||||
public native int fillInt64Buffer(long[] buf, int len, long value);
|
||||
public native int fillFloatBuffer(float[] buf, int len, float value);
|
||||
public native int fillDoubleBuffer(double[] buf, int len, double value);
|
||||
|
||||
// ByteBuffer alternative definitions
|
||||
public native int fillInt8Buffer(ByteBuffer buf, int len, byte value);
|
||||
public native int fillInt16Buffer(ByteBuffer buf, int len, short value);
|
||||
public native int fillInt32Buffer(ByteBuffer buf, int len, int value);
|
||||
public native int fillInt64Buffer(ByteBuffer buf, int len, long value);
|
||||
public native int fillFloatBuffer(ByteBuffer buf, int len, float value);
|
||||
public native int fillDoubleBuffer(ByteBuffer buf, int len, double value);
|
||||
|
||||
// {Short,Int,Long}Buffer alternative definitions
|
||||
// {Short|Int|Long|Float|Double}Buffer alternative definitions
|
||||
public native int fillInt16Buffer(ShortBuffer buf, int len, short value);
|
||||
public native int fillInt32Buffer(IntBuffer buf, int len, int value);
|
||||
public native int fillInt64Buffer(LongBuffer buf, int len, long value);
|
||||
public native int fillFloatBuffer(FloatBuffer buf, int len, float value);
|
||||
public native int fillDoubleBuffer(DoubleBuffer buf, int len, double value);
|
||||
|
||||
// dummy to avoid causing Native.register to fail
|
||||
public boolean returnBooleanArgument(Object arg) {throw new IllegalArgumentException();}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright (c) 2009 Timothy Wall, All Rights Reserved
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
* <p/>
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*/
|
||||
package com.sun.jna;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/** General structure by value functionality tests. */
|
||||
public class DirectStructureByValueTest extends StructureByValueTest {
|
||||
|
||||
public static void main(java.lang.String[] argList) {
|
||||
junit.textui.TestRunner.run(DirectStructureByValueTest.class);
|
||||
}
|
||||
|
||||
public static class DirectTestLibrary implements TestLibrary {
|
||||
public native byte testStructureByValueArgument8(ByValue8 arg);
|
||||
public native short testStructureByValueArgument16(ByValue16 arg);
|
||||
public native int testStructureByValueArgument32(ByValue32 arg);
|
||||
public native long testStructureByValueArgument64(ByValue64 arg);
|
||||
public native long testStructureByValueArgument128(ByValue128 arg);
|
||||
static {
|
||||
Native.register("testlib");
|
||||
}
|
||||
}
|
||||
|
||||
protected void setUp() {
|
||||
lib = new DirectTestLibrary();
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,9 @@ public class LibraryLoadTest extends TestCase {
|
||||
int wcslen(WString wstr);
|
||||
int strlen(String str);
|
||||
int atol(String str);
|
||||
|
||||
Pointer getpwuid(int uid);
|
||||
int geteuid();
|
||||
}
|
||||
|
||||
public void testLoadAWTAfterJNA() {
|
||||
@@ -144,6 +147,16 @@ public class LibraryLoadTest extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
// Ubuntu bug when arch-specific libc is active
|
||||
// Only fails on *some* functions
|
||||
public void testLoadProperCLibraryVersion() {
|
||||
if (Platform.isWindows()) return;
|
||||
|
||||
CLibrary lib = (CLibrary)Native.loadLibrary("c", CLibrary.class);
|
||||
assertNotNull("Couldn't get current user",
|
||||
lib.getpwuid(lib.geteuid()));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(LibraryLoadTest.class);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -256,6 +257,27 @@ public class PointerTest extends TestCase {
|
||||
assertEquals("Wrong value", tp, p.getValue(0, TestPointerType.class, null));
|
||||
}
|
||||
|
||||
public void testGetStringArray() {
|
||||
Pointer p = new Memory(Pointer.SIZE*3);
|
||||
String VALUE1 = getName();
|
||||
String VALUE2 = getName() + "2";
|
||||
|
||||
p.setPointer(0, new NativeString(VALUE1).getPointer());
|
||||
p.setPointer(Pointer.SIZE, new NativeString(VALUE2).getPointer());
|
||||
p.setPointer(Pointer.SIZE*2, null);
|
||||
|
||||
assertEquals("Wrong null-terminated String array",
|
||||
Arrays.asList(new String[] { VALUE1, VALUE2 }),
|
||||
Arrays.asList(p.getStringArray(0)));
|
||||
|
||||
assertEquals("Wrong length-specified String array (1)",
|
||||
Arrays.asList(new String[] { VALUE1 }),
|
||||
Arrays.asList(p.getStringArray(0, 1)));
|
||||
assertEquals("Wrong length-specified String array (2)",
|
||||
Arrays.asList(new String[] { VALUE1, VALUE2 }),
|
||||
Arrays.asList(p.getStringArray(0, 2)));
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
junit.textui.TestRunner.run(PointerTest.class);
|
||||
}
|
||||
|
||||
@@ -730,7 +730,7 @@ public class StructureTest extends TestCase {
|
||||
s.s1 = new StructureTest.PublicTestStructure.ByReference();
|
||||
s.s1.x = -1;
|
||||
s.write();
|
||||
assertEquals("Structure.ByReference not written automatically",
|
||||
assertEquals("Structure.ByReference field not written automatically",
|
||||
-1, s.s1.getPointer().getInt(0));
|
||||
}
|
||||
|
||||
@@ -860,11 +860,34 @@ public class StructureTest extends TestCase {
|
||||
|
||||
public void testNativeMappedWrite() {
|
||||
class TestStructure extends Structure {
|
||||
public ByteByReference ref;
|
||||
public ByteByReference ref;
|
||||
}
|
||||
TestStructure s = new TestStructure();
|
||||
ByteByReference ref = s.ref = new ByteByReference();
|
||||
s.write();
|
||||
assertEquals("Value not properly written", ref.getPointer(), s.getPointer().getPointer(0));
|
||||
|
||||
s.ref = null;
|
||||
s.write();
|
||||
assertNull("Non-null value was written: " + s.getPointer().getPointer(0), s.getPointer().getPointer(0));
|
||||
}
|
||||
|
||||
public void testNativeMappedRead() {
|
||||
class TestStructure extends Structure {
|
||||
public ByteByReference ref;
|
||||
}
|
||||
TestStructure s = new TestStructure();
|
||||
s.read();
|
||||
assertNull("Should read null for initial field value", s.ref);
|
||||
|
||||
ByteByReference ref = new ByteByReference();
|
||||
s.getPointer().setPointer(0, ref.getPointer());
|
||||
s.read();
|
||||
assertEquals("Field incorrectly read", ref, s.ref);
|
||||
|
||||
s.getPointer().setPointer(0, null);
|
||||
s.read();
|
||||
assertNull("Null field incorrectly read", s.ref);
|
||||
}
|
||||
|
||||
public static class ROStructure extends Structure {
|
||||
@@ -1075,16 +1098,31 @@ public class StructureTest extends TestCase {
|
||||
assertTrue("Structure equals should ignore padding", s1.equals(s2));
|
||||
}
|
||||
|
||||
public void testRecursiveReadWrite() {
|
||||
public void testRecursiveReadWriteDetection() {
|
||||
class TestStructureByRef extends Structure implements Structure.ByReference{
|
||||
public TestStructureByRef(Pointer p) { super(p); }
|
||||
public TestStructureByRef() { }
|
||||
public int unique;
|
||||
public TestStructureByRef s;
|
||||
}
|
||||
TestStructureByRef s = new TestStructureByRef();
|
||||
s.s = s;
|
||||
s.write();
|
||||
s.read();
|
||||
s.s = new TestStructureByRef();
|
||||
s.unique = 1;
|
||||
s.s.s = s;
|
||||
s.s.unique = 2;
|
||||
|
||||
assertEquals("Temporary storage should be cleared",
|
||||
0, s.busy().size());
|
||||
s.write();
|
||||
assertEquals("Structure field contents not written",
|
||||
1, s.getPointer().getInt(0));
|
||||
assertEquals("ByReference structure field contents not written",
|
||||
2, s.s.getPointer().getInt(0));
|
||||
|
||||
s.s.unique = 0;
|
||||
s.read();
|
||||
assertEquals("ByReference structure field contents not read",
|
||||
2, s.s.unique);
|
||||
|
||||
assertTrue("Temporary storage should be cleared",
|
||||
s.busy().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ package com.sun.jna;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JScrollPane;
|
||||
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.io.File;
|
||||
@@ -31,7 +32,9 @@ import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Iterator;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
@@ -66,7 +69,10 @@ public class WebStartTest extends TestCase {
|
||||
// but will cause unsigned jars to fail (irrespective of policy)
|
||||
+ " <security><all-permissions/></security>\n"
|
||||
+ " <resources>\n"
|
||||
+ " <j2se version='1.4+'/>\n"
|
||||
// Explicitly supply javawebstart.version, which is missing in NetX
|
||||
// Boo, java-vm-args doesn't work in NetX
|
||||
// and neither does javaws -J<arg>
|
||||
+ " <j2se version='1.4+' java-vm-args='-Djavawebstart.version=0.0'/>\n"
|
||||
+ " <jar href='jna-test.jar'/>\n"
|
||||
+ " <jar href='jna.jar'/>\n"
|
||||
+ " <jar href='junit.jar'/>{CLOVER}\n"
|
||||
@@ -77,6 +83,8 @@ public class WebStartTest extends TestCase {
|
||||
+ " <argument>{CLASS}</argument>\n"
|
||||
+ " <argument>{METHOD}</argument>\n"
|
||||
+ " <argument>{PORT}</argument>\n"
|
||||
// NetX doesn't set javawebstart.version, so explicitly flag it
|
||||
+ " <argument>javawebstart</argument>\n"
|
||||
+ " </application-desc>\n"
|
||||
+ "</jnlp>";
|
||||
|
||||
@@ -139,7 +147,7 @@ public class WebStartTest extends TestCase {
|
||||
String path = findJWS();
|
||||
String[] cmd = {
|
||||
path,
|
||||
"-Xnosplash",
|
||||
"-Xnosplash",
|
||||
"-wait",
|
||||
jnlp.toURI().toURL().toString(),
|
||||
};
|
||||
@@ -258,42 +266,38 @@ public class WebStartTest extends TestCase {
|
||||
|
||||
private String findJWS() throws IOException {
|
||||
String JAVA_HOME = System.getProperty("java.home");
|
||||
String BIN = new File(JAVA_HOME, "/bin").getAbsolutePath();
|
||||
String LIB = new File(JAVA_HOME, "/lib").getAbsolutePath();
|
||||
if (!new File(LIB, "javaws.jar").exists()) {
|
||||
LIB = new File("/System/Library/Frameworks/JavaVM.framework/Resources/Deploy.bundle/Contents/Home/lib").getAbsolutePath();
|
||||
if (!new File(LIB, "javaws.jar").exists()) {
|
||||
if (!Platform.isWindows())
|
||||
throw new IOException("javaws.jar not found");
|
||||
}
|
||||
}
|
||||
String PS = System.getProperty("path.separator");
|
||||
String path = System.getProperty("java.home") + "/bin/javaws";
|
||||
File javaws = new File(path);
|
||||
// NOTE: OSX puts javaws somewhere else entirely
|
||||
// NOTE: win64 only includes javaws in the system path
|
||||
File javaws = new File(BIN, "javaws" + (Platform.isWindows()?".exe":""));
|
||||
if (!javaws.exists()) {
|
||||
// NOTE: OSX puts javaws somewhere else entirely
|
||||
if (Platform.isMac()) {
|
||||
javaws = new File(JAVA_HOME, "../Commands/javaws");
|
||||
}
|
||||
// NOTE: win64 only includes javaws in the system path
|
||||
if (Platform.isWindows()) {
|
||||
FolderInfo info = (FolderInfo)
|
||||
Native.loadLibrary("shell32", FolderInfo.class);
|
||||
char[] buf = new char[FolderInfo.MAX_PATH];
|
||||
int flags = 0;
|
||||
int result = info.SHGetFolderPathW(null, FolderInfo.CSIDL_WINDOWS, null, 0, buf);
|
||||
path = Native.toString(buf);
|
||||
String path = Native.toString(buf);
|
||||
if (Platform.is64Bit()) {
|
||||
javaws = new File(path, "SysWOW64/javaws.exe");
|
||||
}
|
||||
else {
|
||||
javaws = new File(path, "system32/javaws.exe");
|
||||
}
|
||||
path = javaws.getAbsolutePath();
|
||||
}
|
||||
else {
|
||||
path = javaws.getName();
|
||||
if (!javaws.exists()) {
|
||||
throw new IOException("javaws executable not found");
|
||||
}
|
||||
}
|
||||
return path;
|
||||
return javaws.getAbsolutePath();
|
||||
}
|
||||
|
||||
// TODO: find some way of querying the current VM for the deployment
|
||||
// properties path
|
||||
private File findDeploymentProperties() {
|
||||
String path = System.getProperty("user.home");
|
||||
File deployment;
|
||||
@@ -402,27 +406,44 @@ public class WebStartTest extends TestCase {
|
||||
}
|
||||
|
||||
private static void showMessage(String msg) {
|
||||
showMessage(msg, 60000);
|
||||
}
|
||||
|
||||
private static void showMessage(String msg, int timeout) {
|
||||
JFrame f = new JFrame("Web Start Test Failure");
|
||||
f.getContentPane().add(new JLabel(msg));
|
||||
f.getContentPane().add(new JScrollPane(new JLabel(msg)));
|
||||
f.pack();
|
||||
f.setLocation(100, 100);
|
||||
f.setVisible(true);
|
||||
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
try { Thread.sleep(60000); } catch(Exception e) { }
|
||||
if (timeout != 0) {
|
||||
try { Thread.sleep(timeout); } catch(Exception e) { }
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
if (runningWebStart()) {
|
||||
String testClass = args.length > 0
|
||||
? args[0] : WebStartTest.class.getName();
|
||||
String testMethod = args.length > 1
|
||||
? args[1] : "testLaunchedUnderWebStart";
|
||||
int port = args.length > 2
|
||||
? Integer.parseInt(args[2]) : 8080;
|
||||
runTestCaseTest(testClass, testMethod, port);
|
||||
try {
|
||||
if (args.length == 4
|
||||
&& "javawebstart".equals(args[3])
|
||||
&& !runningWebStart()) {
|
||||
System.setProperty("javawebstart.version", "fake");
|
||||
}
|
||||
if (runningWebStart()) {
|
||||
|
||||
String testClass = args.length > 0
|
||||
? args[0] : WebStartTest.class.getName();
|
||||
String testMethod = args.length > 1
|
||||
? args[1] : "testLaunchedUnderWebStart";
|
||||
int port = args.length > 2
|
||||
? Integer.parseInt(args[2]) : 8080;
|
||||
runTestCaseTest(testClass, testMethod, port);
|
||||
}
|
||||
else {
|
||||
junit.textui.TestRunner.run(WebStartTest.class);
|
||||
}
|
||||
}
|
||||
else {
|
||||
junit.textui.TestRunner.run(WebStartTest.class);
|
||||
catch(Throwable t) {
|
||||
showMessage("ERROR: " + t.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário