Skip to content

Commit 54fc662

Browse files
Merge pull request #1501 from matthiasblaesing/function_encoding
Fix usage of encoding property for Function
2 parents 195ebb4 + b347cd9 commit 54fc662

File tree

4 files changed

+173
-2
lines changed

4 files changed

+173
-2
lines changed

CHANGES.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Features
1010

1111
Bug Fixes
1212
---------
13-
13+
* [#1501](https://github.com/java-native-access/jna/pull/1501): `Library.OPTION_STRING_ENCODING` is ignore for string arguments function calls - [@matthiasblaesing](https://github.com/matthiasblaesing).
1414

1515
Release (5.13.0)
1616
================

native/testlib.c

+31
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ extern "C" {
3131
#include <stdio.h>
3232
#include <stdarg.h>
3333
#include <stdlib.h>
34+
#include <string.h>
35+
3436
#if !defined(_WIN32_WCE)
3537
#include <errno.h>
3638
#endif
@@ -1078,6 +1080,35 @@ returnLastElementOfComponentsDSDAL(DemoStructureDifferentArrayLengths ts, int de
10781080
return result;
10791081
}
10801082

1083+
/**
1084+
* Copy the input char array to the output char array. The caller is responsible
1085+
* to allocate a correctly sized buffer.
1086+
*/
1087+
EXPORT size_t copyString(char* input, char* output) {
1088+
size_t len = strlen(input) + 1;
1089+
memcpy(output, input, len);
1090+
return len;
1091+
}
1092+
1093+
/**
1094+
* Copy the input array of char arrays to the output char array. The caller is
1095+
* responsible to allocate a correctly sized buffer.
1096+
*/
1097+
EXPORT size_t copyStringArray(char** input, char* output) {
1098+
size_t len = 0;
1099+
for(int i = 0;; i++) {
1100+
char* currInput = input[i];
1101+
if(currInput == NULL) {
1102+
break;
1103+
}
1104+
size_t localLen = strlen(currInput) + 1;
1105+
memcpy(output, currInput, localLen);
1106+
output += localLen;
1107+
len += localLen;
1108+
}
1109+
return len;
1110+
}
1111+
10811112
#ifdef __cplusplus
10821113
}
10831114
#endif

src/com/sun/jna/Function.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ private Object convertArgument(Object[] args, int index,
561561
// than in native code so that the values will be valid until
562562
// this method returns.
563563
// Convert String to native pointer (const)
564-
return new NativeString((String)arg, false).getPointer();
564+
return new NativeString((String)arg, encoding).getPointer();
565565
} else if (arg instanceof WString) {
566566
// Convert WString to native pointer (const)
567567
return new NativeString(arg.toString(), true).getPointer();

test/com/sun/jna/FunctionTest.java

+140
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@
2323
*/
2424
package com.sun.jna;
2525

26+
import java.io.UnsupportedEncodingException;
27+
import java.util.Arrays;
28+
import java.util.Collections;
2629
import junit.framework.TestCase;
30+
import org.junit.Assert;
2731

2832
/** Exercise the {@link Function} class.
2933
*
@@ -32,6 +36,29 @@
3236
//@SuppressWarnings("unused")
3337
public class FunctionTest extends TestCase {
3438

39+
private NativeLibrary libUTF8;
40+
private NativeLibrary libLatin1;
41+
private TestLibUTF8 libUTF8Direct;
42+
private TestLibLatin1 libLatin1Direct;
43+
private TestLib libUTF8Interface;
44+
private TestLib libLatin1Interface;
45+
46+
@Override
47+
protected void setUp() {
48+
libUTF8 = NativeLibrary.getInstance("testlib",
49+
Collections.singletonMap(Library.OPTION_STRING_ENCODING, "UTF-8"));
50+
libLatin1 = NativeLibrary.getInstance("testlib",
51+
Collections.singletonMap(Library.OPTION_STRING_ENCODING, "ISO-8859-1"));
52+
Native.register(TestLibUTF8.class, libUTF8);
53+
Native.register(TestLibLatin1.class, libLatin1);
54+
libUTF8Direct = new TestLibUTF8();
55+
libLatin1Direct = new TestLibLatin1();
56+
libUTF8Interface = Native.load("testlib", TestLib.class,
57+
Collections.singletonMap(Library.OPTION_STRING_ENCODING, "UTF-8"));
58+
libLatin1Interface = Native.load("testlib", TestLib.class,
59+
Collections.singletonMap(Library.OPTION_STRING_ENCODING, "ISO-8859-1"));
60+
}
61+
3562
public void testTooManyArgs() {
3663
NativeLibrary lib = NativeLibrary.getInstance(Platform.C_LIBRARY_NAME);
3764
Function f = lib.getFunction("printf");
@@ -58,8 +85,121 @@ public void testUnsupportedReturnType() {
5885
}
5986
}
6087

88+
public void testStringEncodingArgument() throws UnsupportedEncodingException {
89+
// String with german umlauts
90+
String input = "Hallo äöüß";
91+
byte[] result = new byte[32];
92+
Arrays.fill(result, (byte) 0);
93+
libUTF8Interface.copyString(input, result);
94+
Assert.assertArrayEquals(toByteArray(input, "UTF-8", 32), result);
95+
Arrays.fill(result, (byte) 0);
96+
libLatin1Interface.copyString(input, result);
97+
Assert.assertArrayEquals(toByteArray(input, "ISO-8859-1", 32), result);
98+
99+
// String array with german umlauts
100+
String[] inputArray = new String[]{"1Hallo äöüß1", "2Hallo äöüß2"};
101+
result = new byte[64];
102+
Arrays.fill(result, (byte) 0);
103+
libUTF8Interface.copyStringArray(inputArray, result);
104+
Assert.assertArrayEquals(toByteArray(inputArray, "UTF-8", 64), result);
105+
Arrays.fill(result, (byte) 0);
106+
libLatin1Interface.copyStringArray(inputArray, result);
107+
Assert.assertArrayEquals(toByteArray(inputArray, "ISO-8859-1", 64), result);
108+
}
109+
110+
public void testStringEncodingArgumentDirect() throws UnsupportedEncodingException {
111+
// String with german umlauts
112+
String input = "Hallo äöüß";
113+
byte[] result = new byte[32];
114+
Arrays.fill(result, (byte) 0);
115+
libUTF8Direct.copyString(input, result);
116+
Assert.assertArrayEquals(toByteArray(input, "UTF-8", 32), result);
117+
Arrays.fill(result, (byte) 0);
118+
libLatin1Direct.copyString(input, result);
119+
Assert.assertArrayEquals(toByteArray(input, "ISO-8859-1", 32), result);
120+
}
121+
122+
public void testStringReturn() throws UnsupportedEncodingException {
123+
// String with german umlauts
124+
String input = "Hallo äöüß";
125+
126+
String result;
127+
Memory mem = new Memory(32);
128+
mem.clear();
129+
mem.write(0, input.getBytes("UTF-8"), 0, input.getBytes("UTF-8").length);
130+
result = libUTF8Interface.returnStringArgument(mem);
131+
assertEquals(input, result);
132+
mem.clear();
133+
mem.write(0, input.getBytes("ISO-8859-1"), 0, input.getBytes("ISO-8859-1").length);
134+
result = libLatin1Interface.returnStringArgument(mem);
135+
assertEquals(input, result);
136+
}
137+
138+
public void testStringReturnDirect() throws UnsupportedEncodingException {
139+
// String with german umlauts
140+
String input = "Hallo äöüß";
141+
142+
String result;
143+
Memory mem = new Memory(32);
144+
mem.clear();
145+
mem.write(0, input.getBytes("UTF-8"), 0, input.getBytes("UTF-8").length);
146+
result = libUTF8Direct.returnStringArgument(mem);
147+
assertEquals(input, result);
148+
mem.clear();
149+
mem.write(0, input.getBytes("ISO-8859-1"), 0, input.getBytes("ISO-8859-1").length);
150+
result = libLatin1Direct.returnStringArgument(mem);
151+
assertEquals(input, result);
152+
}
153+
154+
private byte[] toByteArray(String input, String encoding, int targetLength) throws UnsupportedEncodingException {
155+
byte[] result = new byte[targetLength];
156+
byte[] encoded = input.getBytes(encoding);
157+
System.arraycopy(encoded, 0, result, 0, encoded.length);
158+
return result;
159+
}
160+
161+
private byte[] toByteArray(String[] input, String encoding, int targetLength) throws UnsupportedEncodingException {
162+
byte[] result = new byte[targetLength];
163+
int offset = 0;
164+
for(String currInput: input) {
165+
byte[] encoded = currInput.getBytes(encoding);
166+
System.arraycopy(encoded, 0, result, offset, encoded.length);
167+
offset += encoded.length;
168+
offset++;
169+
}
170+
return result;
171+
}
172+
61173
public static void main(java.lang.String[] argList) {
62174
junit.textui.TestRunner.run(FunctionTest.class);
63175
}
64176

177+
private static class TestLibUTF8 implements Library {
178+
native String returnStringArgument(Pointer input);
179+
native SizeT copyString(String input, byte[] output);
180+
}
181+
182+
private static class TestLibLatin1 implements Library {
183+
native String returnStringArgument(Pointer input);
184+
native SizeT copyString(String input, byte[] output);
185+
}
186+
187+
private interface TestLib extends Library {
188+
public String returnStringArgument(Pointer input);
189+
public SizeT copyString(String input, byte[] output);
190+
public SizeT copyStringArray(String[] input, byte[] output);
191+
}
192+
193+
private static class SizeT extends IntegerType {
194+
public static final int SIZE = Native.SIZE_T_SIZE;
195+
196+
public SizeT() {
197+
this(0);
198+
}
199+
200+
public SizeT(long value) {
201+
super(SIZE, value, true);
202+
}
203+
204+
}
65205
}

0 commit comments

Comments
 (0)