From a88b8a6c2192523d2601fcb1c272c4766876c46b Mon Sep 17 00:00:00 2001 From: demon36 Date: Tue, 6 Jul 2021 10:43:59 +0200 Subject: [PATCH 1/8] fix #30 DirectMemoryIO.getString() fails for non UTF-8 --- .../jnr/ffi/provider/jffi/DirectMemoryIO.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java index 1574b0ba..ea0f818c 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java +++ b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java @@ -25,6 +25,7 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; class DirectMemoryIO extends AbstractMemoryIO { static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); @@ -186,8 +187,30 @@ public String getString(long offset) { public String getString(long offset, int maxLength, Charset cs) { - final byte[] bytes = IO.getZeroTerminatedByteArray(address() + offset, maxLength); - return cs.decode(ByteBuffer.wrap(bytes)).toString(); + if(cs == StandardCharsets.UTF_8){ + final byte[] bytes = IO.getZeroTerminatedByteArray(address() + offset, maxLength); + return cs.decode(ByteBuffer.wrap(bytes)).toString(); + }else{ + byte[] bytes = new byte[maxLength]; + IO.getByteArray(address() + offset, bytes, 0, maxLength); + final byte[] nullCharBytes = new String("\0").getBytes(cs); + int nullIndex = maxLength; + int matchingBytesCount = 0; + for(int i = 0; i < (int)bytes.length; i++){ + if(bytes[i] == nullCharBytes[matchingBytesCount]){ + matchingBytesCount++; + } else { + matchingBytesCount = 0; + } + + if(matchingBytesCount == nullCharBytes.length){ + nullIndex = i; + break; + } + } + + return new String(bytes, 0, nullIndex, cs); + } } public void putString(long offset, String string, int maxLength, Charset cs) { From 3fb7cec94fa4b5c50f02a1221b3214967b6cc63c Mon Sep 17 00:00:00 2001 From: demon36 Date: Fri, 6 Aug 2021 11:05:35 +0200 Subject: [PATCH 2/8] implement WStringRef (mapping for wchar_t*), make set() work efficiently with more charsets, fix DirectMemoryIO.getString() --- src/main/java/jnr/ffi/Struct.java | 61 ++++++++++++++++--- .../jnr/ffi/provider/jffi/DirectMemoryIO.java | 13 ++-- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/main/java/jnr/ffi/Struct.java b/src/main/java/jnr/ffi/Struct.java index 9cbd012d..c064a513 100755 --- a/src/main/java/jnr/ffi/Struct.java +++ b/src/main/java/jnr/ffi/Struct.java @@ -30,10 +30,12 @@ import jnr.ffi.provider.ParameterFlags; import jnr.ffi.provider.jffi.ArrayMemoryIO; import jnr.ffi.util.EnumMapper; +import jnr.ffi.Platform; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; /** * Representation of C structures in java. @@ -2291,7 +2293,7 @@ public Enum(Class enumClass) { abstract public class String extends AbstractMember { protected final Charset charset; - protected final int length; + protected int length; protected String(int size, int align, int length, Charset cs) { super(size, align); @@ -2318,8 +2320,8 @@ public final java.lang.String toString() { } public class UTFString extends String { - public UTFString(int length, Charset cs) { - super(length * 8, 8, length, cs); // FIXME: This won't work for non-ASCII + public UTFString(int lengthInBytes, Charset cs) { + super(lengthInBytes * 8, 8, lengthInBytes, cs); // FIXME: This won't work for non-ASCII } protected jnr.ffi.Pointer getStringMemory() { @@ -2347,6 +2349,12 @@ public AsciiString(int size) { } } + public class WString extends UTFString { + public WString(int size) { + super(size * getWideCharWidthInBytes(), getCharset()); + } + } + public class UTFStringRef extends String { private jnr.ffi.Pointer valueHolder; @@ -2369,16 +2377,30 @@ public final java.lang.String get() { } public final void set(java.lang.String value) { - if (value != null) { - valueHolder = getRuntime().getMemoryManager().allocateDirect(length() * 4); - valueHolder.putString(0, value, length() * 4, charset); - getMemory().putPointer(offset(), valueHolder); - - } else { + if(value == null) { this.valueHolder = null; + this.length = 0; getMemory().putAddress(offset(), 0); + return; } + + value += "\0"; + byte[] bytes = value.getBytes(charset); + if(bytes.length > length || valueHolder == null){ + valueHolder = getRuntime().getMemoryManager().allocateDirect(bytes.length); + length = bytes.length; + getMemory().putPointer(offset(), valueHolder); + } + valueHolder.put(0, bytes, 0, bytes.length); + } + + public final void reAllocate(int sizeBytes){ + valueHolder = getRuntime().getMemoryManager().allocateDirect(sizeBytes); + length = sizeBytes; + getMemory().putPointer(offset(), valueHolder); } + + //TODO: implement bool isNull() } public class UTF8StringRef extends UTFStringRef { @@ -2399,6 +2421,27 @@ public AsciiStringRef() { } } + public class WStringRef extends UTFStringRef { + public WStringRef(int size) { + super(size, getCharset()); + } + public WStringRef() { + super(0, getCharset()); + } + } + + private static Charset getCharset() { + if(Platform.getPlatform().getOS() == Platform.OS.WINDOWS) { + return StandardCharsets.UTF_16LE; + } else { + return Charset.forName("UTF-32LE");//unless -fshort-wchar is used for compiling native libs + } + } + + private static int getWideCharWidthInBytes() { + return Platform.getPlatform().getOS() == Platform.OS.WINDOWS ? 2 : 4; + } + /** * Specialized padding fields for structs. Use this instead of arrays of other * members for more efficient struct construction. diff --git a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java index ea0f818c..ff6cc0f9 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java +++ b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java @@ -191,25 +191,30 @@ public String getString(long offset, int maxLength, Charset cs) { final byte[] bytes = IO.getZeroTerminatedByteArray(address() + offset, maxLength); return cs.decode(ByteBuffer.wrap(bytes)).toString(); }else{ + //TODO: change this to only allocate an array of needed size byte[] bytes = new byte[maxLength]; IO.getByteArray(address() + offset, bytes, 0, maxLength); final byte[] nullCharBytes = new String("\0").getBytes(cs); - int nullIndex = maxLength; + int nullTerminatedLen = maxLength; int matchingBytesCount = 0; - for(int i = 0; i < (int)bytes.length; i++){ + int i = 0; + while(i < (int)bytes.length){ if(bytes[i] == nullCharBytes[matchingBytesCount]){ matchingBytesCount++; + i++; } else { matchingBytesCount = 0; + i += nullCharBytes.length - (i%nullCharBytes.length);//jump to start of next character + continue; } if(matchingBytesCount == nullCharBytes.length){ - nullIndex = i; + nullTerminatedLen = i; break; } } - return new String(bytes, 0, nullIndex, cs); + return new String(bytes, 0, nullTerminatedLen, cs); } } From b4ab1810112919b2c2d0060baadea2285e199ff4 Mon Sep 17 00:00:00 2001 From: demon36 Date: Thu, 12 Aug 2021 15:35:01 +0200 Subject: [PATCH 3/8] bug fix for null terminated strings of allocated size less than maxLength --- .../java/jnr/ffi/provider/jffi/DirectMemoryIO.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java index ff6cc0f9..9c17719b 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java +++ b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java @@ -191,15 +191,13 @@ public String getString(long offset, int maxLength, Charset cs) { final byte[] bytes = IO.getZeroTerminatedByteArray(address() + offset, maxLength); return cs.decode(ByteBuffer.wrap(bytes)).toString(); }else{ - //TODO: change this to only allocate an array of needed size - byte[] bytes = new byte[maxLength]; - IO.getByteArray(address() + offset, bytes, 0, maxLength); + long baseAddress = address() + offset; final byte[] nullCharBytes = new String("\0").getBytes(cs); int nullTerminatedLen = maxLength; int matchingBytesCount = 0; int i = 0; - while(i < (int)bytes.length){ - if(bytes[i] == nullCharBytes[matchingBytesCount]){ + while(i < maxLength){ + if(IO.getByte(baseAddress+i) == nullCharBytes[matchingBytesCount]){ matchingBytesCount++; i++; } else { @@ -209,12 +207,14 @@ public String getString(long offset, int maxLength, Charset cs) { } if(matchingBytesCount == nullCharBytes.length){ - nullTerminatedLen = i; + nullTerminatedLen = i-nullCharBytes.length;//trim to the last byte just before null terminator break; } } - return new String(bytes, 0, nullTerminatedLen, cs); + byte[] bytes = new byte[nullTerminatedLen]; + IO.getByteArray(address() + offset, bytes, 0, nullTerminatedLen); + return new String(bytes, 0, bytes.length, cs); } } From d1658b911d522f8f00348f2a77d1dad1565dee91 Mon Sep 17 00:00:00 2001 From: demon36 Date: Thu, 12 Aug 2021 19:31:25 +0200 Subject: [PATCH 4/8] utf-16/32 support for getCharSequence() --- src/main/java/jnr/ffi/util/BufferUtil.java | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/main/java/jnr/ffi/util/BufferUtil.java b/src/main/java/jnr/ffi/util/BufferUtil.java index 6165a65e..f21e7dfc 100644 --- a/src/main/java/jnr/ffi/util/BufferUtil.java +++ b/src/main/java/jnr/ffi/util/BufferUtil.java @@ -64,7 +64,8 @@ public static CharSequence getCharSequence(ByteBuffer buf, Charset charset) { final ByteBuffer buffer = buf.slice(); // Find the NUL terminator and limit to that, so the // StringBuffer/StringBuilder does not have superfluous NUL chars - int end = indexOf(buffer, (byte) 0); + final byte[] nullCharBytes = new String("\0").getBytes(charset); + int end = indexOf(buffer, nullCharBytes) - nullCharBytes.length; if (end < 0) { end = buffer.limit(); } @@ -141,6 +142,47 @@ public static int indexOf(ByteBuffer buf, byte value) { return -1; } + public static int indexOf(ByteBuffer buf, byte[] value) { + int matchingBytesCount = 0; + int offset = 0; + if (buf.hasArray()) { + byte[] array = buf.array(); + int begin = buf.arrayOffset() + buf.position(); + int end = buf.arrayOffset() + buf.limit(); + while(offset < end && offset > -1){ + if(array[begin + offset] == value[matchingBytesCount]){ + matchingBytesCount++; + offset++; + } else { + matchingBytesCount = 0; + offset += value.length - (offset%value.length);//jump to start of next character + continue; + } + + if(matchingBytesCount == value.length){ + return offset; + } + } + } else { + int begin = buf.position(); + while(offset < buf.limit()){ + if(buf.get(begin + offset) == value[matchingBytesCount]){ + matchingBytesCount++; + offset++; + } else { + matchingBytesCount = 0; + offset += value.length - (offset%value.length);//jump to start of next character + continue; + } + + if(matchingBytesCount == value.length){ + return offset; + } + } + } + return -1; + } + public static int indexOf(ByteBuffer buf, int offset, byte value) { if (buf.hasArray()) { byte[] array = buf.array(); From 61ce834646e947c4984dad2fe15a2081cbc7d650 Mon Sep 17 00:00:00 2001 From: demon36 Date: Fri, 13 Aug 2021 14:05:46 +0200 Subject: [PATCH 5/8] revert unneeded length change, add WStringRef.reAllocate() & setMaxLength() that works with wide chars, default max length to max int --- src/main/java/jnr/ffi/Struct.java | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/main/java/jnr/ffi/Struct.java b/src/main/java/jnr/ffi/Struct.java index c064a513..b291ab7c 100755 --- a/src/main/java/jnr/ffi/Struct.java +++ b/src/main/java/jnr/ffi/Struct.java @@ -2350,8 +2350,8 @@ public AsciiString(int size) { } public class WString extends UTFString { - public WString(int size) { - super(size * getWideCharWidthInBytes(), getCharset()); + public WString(int sizeInChars) { + super(sizeInChars * getWideCharWidthInBytes(), getCharset()); } } @@ -2379,7 +2379,6 @@ public final java.lang.String get() { public final void set(java.lang.String value) { if(value == null) { this.valueHolder = null; - this.length = 0; getMemory().putAddress(offset(), 0); return; } @@ -2394,7 +2393,7 @@ public final void set(java.lang.String value) { valueHolder.put(0, bytes, 0, bytes.length); } - public final void reAllocate(int sizeBytes){ + public void reAllocate(int sizeBytes){ valueHolder = getRuntime().getMemoryManager().allocateDirect(sizeBytes); length = sizeBytes; getMemory().putPointer(offset(), valueHolder); @@ -2422,11 +2421,21 @@ public AsciiStringRef() { } public class WStringRef extends UTFStringRef { - public WStringRef(int size) { - super(size, getCharset()); + public WStringRef(int sizeInChars) { + super(sizeInChars * getWideCharWidthInBytes(), getCharset()); } + public WStringRef() { - super(0, getCharset()); + super(Integer.MAX_VALUE, getCharset()); + } + + public final void setMaxLength(int sizeInChars){ + length = sizeInChars * getWideCharWidthInBytes(); + } + + @Override + public void reAllocate(int sizeInChars){ + super.reAllocate(sizeInChars * getWideCharWidthInBytes()); } } From 9d1d5629ba71bb6b4cfa5cca9db06e297b718914 Mon Sep 17 00:00:00 2001 From: demon36 Date: Fri, 13 Aug 2021 14:06:27 +0200 Subject: [PATCH 6/8] possible fixes for DirectMemoryIO.getString() --- .../jnr/ffi/provider/jffi/DirectMemoryIO.java | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java index 9c17719b..82ed6135 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java +++ b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java @@ -187,13 +187,18 @@ public String getString(long offset) { public String getString(long offset, int maxLength, Charset cs) { + long baseAddress = address() + offset; + if(cs == StandardCharsets.UTF_8){ - final byte[] bytes = IO.getZeroTerminatedByteArray(address() + offset, maxLength); + final byte[] bytes = IO.getZeroTerminatedByteArray(baseAddress, maxLength); return cs.decode(ByteBuffer.wrap(bytes)).toString(); }else{ - long baseAddress = address() + offset; + if(address() == 0) { + return null; + } + final byte[] nullCharBytes = new String("\0").getBytes(cs); - int nullTerminatedLen = maxLength; + int nullTerminatedLen = 0; int matchingBytesCount = 0; int i = 0; while(i < maxLength){ @@ -205,15 +210,18 @@ public String getString(long offset, int maxLength, Charset cs) { i += nullCharBytes.length - (i%nullCharBytes.length);//jump to start of next character continue; } - if(matchingBytesCount == nullCharBytes.length){ nullTerminatedLen = i-nullCharBytes.length;//trim to the last byte just before null terminator break; } } + if(nullTerminatedLen == 0) { + return ""; + } + byte[] bytes = new byte[nullTerminatedLen]; - IO.getByteArray(address() + offset, bytes, 0, nullTerminatedLen); + IO.getByteArray(baseAddress, bytes, 0, nullTerminatedLen); return new String(bytes, 0, bytes.length, cs); } } From b7969744b9f9521daa676ddad351b953285f28a0 Mon Sep 17 00:00:00 2001 From: demon36 Date: Tue, 17 Aug 2021 16:47:21 +0200 Subject: [PATCH 7/8] more compliant spacing --- src/main/java/jnr/ffi/Struct.java | 6 +++--- .../jnr/ffi/provider/jffi/DirectMemoryIO.java | 16 ++++++++-------- src/main/java/jnr/ffi/util/BufferUtil.java | 12 ++++++------ 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/jnr/ffi/Struct.java b/src/main/java/jnr/ffi/Struct.java index b291ab7c..96c24182 100755 --- a/src/main/java/jnr/ffi/Struct.java +++ b/src/main/java/jnr/ffi/Struct.java @@ -2385,7 +2385,7 @@ public final void set(java.lang.String value) { value += "\0"; byte[] bytes = value.getBytes(charset); - if(bytes.length > length || valueHolder == null){ + if(bytes.length > length || valueHolder == null) { valueHolder = getRuntime().getMemoryManager().allocateDirect(bytes.length); length = bytes.length; getMemory().putPointer(offset(), valueHolder); @@ -2393,7 +2393,7 @@ public final void set(java.lang.String value) { valueHolder.put(0, bytes, 0, bytes.length); } - public void reAllocate(int sizeBytes){ + public void reAllocate(int sizeBytes) { valueHolder = getRuntime().getMemoryManager().allocateDirect(sizeBytes); length = sizeBytes; getMemory().putPointer(offset(), valueHolder); @@ -2429,7 +2429,7 @@ public WStringRef() { super(Integer.MAX_VALUE, getCharset()); } - public final void setMaxLength(int sizeInChars){ + public final void setMaxLength(int sizeInChars) { length = sizeInChars * getWideCharWidthInBytes(); } diff --git a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java index 82ed6135..e174f3a6 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java +++ b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java @@ -189,10 +189,10 @@ public String getString(long offset) { public String getString(long offset, int maxLength, Charset cs) { long baseAddress = address() + offset; - if(cs == StandardCharsets.UTF_8){ + if(cs == StandardCharsets.UTF_8) { final byte[] bytes = IO.getZeroTerminatedByteArray(baseAddress, maxLength); return cs.decode(ByteBuffer.wrap(bytes)).toString(); - }else{ + } else { if(address() == 0) { return null; } @@ -201,8 +201,8 @@ public String getString(long offset, int maxLength, Charset cs) { int nullTerminatedLen = 0; int matchingBytesCount = 0; int i = 0; - while(i < maxLength){ - if(IO.getByte(baseAddress+i) == nullCharBytes[matchingBytesCount]){ + while(i < maxLength) { + if(IO.getByte(baseAddress+i) == nullCharBytes[matchingBytesCount]) { matchingBytesCount++; i++; } else { @@ -210,7 +210,7 @@ public String getString(long offset, int maxLength, Charset cs) { i += nullCharBytes.length - (i%nullCharBytes.length);//jump to start of next character continue; } - if(matchingBytesCount == nullCharBytes.length){ + if(matchingBytesCount == nullCharBytes.length) { nullTerminatedLen = i-nullCharBytes.length;//trim to the last byte just before null terminator break; } @@ -218,9 +218,9 @@ public String getString(long offset, int maxLength, Charset cs) { if(nullTerminatedLen == 0) { return ""; - } - - byte[] bytes = new byte[nullTerminatedLen]; + } + + byte[] bytes = new byte[nullTerminatedLen]; IO.getByteArray(baseAddress, bytes, 0, nullTerminatedLen); return new String(bytes, 0, bytes.length, cs); } diff --git a/src/main/java/jnr/ffi/util/BufferUtil.java b/src/main/java/jnr/ffi/util/BufferUtil.java index f21e7dfc..a9afd312 100644 --- a/src/main/java/jnr/ffi/util/BufferUtil.java +++ b/src/main/java/jnr/ffi/util/BufferUtil.java @@ -149,8 +149,8 @@ public static int indexOf(ByteBuffer buf, byte[] value) { byte[] array = buf.array(); int begin = buf.arrayOffset() + buf.position(); int end = buf.arrayOffset() + buf.limit(); - while(offset < end && offset > -1){ - if(array[begin + offset] == value[matchingBytesCount]){ + while(offset < end && offset > -1) { + if(array[begin + offset] == value[matchingBytesCount]) { matchingBytesCount++; offset++; } else { @@ -159,14 +159,14 @@ public static int indexOf(ByteBuffer buf, byte[] value) { continue; } - if(matchingBytesCount == value.length){ + if(matchingBytesCount == value.length) { return offset; } } } else { int begin = buf.position(); - while(offset < buf.limit()){ - if(buf.get(begin + offset) == value[matchingBytesCount]){ + while(offset < buf.limit()) { + if(buf.get(begin + offset) == value[matchingBytesCount]) { matchingBytesCount++; offset++; } else { @@ -175,7 +175,7 @@ public static int indexOf(ByteBuffer buf, byte[] value) { continue; } - if(matchingBytesCount == value.length){ + if(matchingBytesCount == value.length) { return offset; } } From badc99ee9b242d4e9f559c971526af9afe839e2a Mon Sep 17 00:00:00 2001 From: demon36 Date: Wed, 18 Aug 2021 08:00:26 +0200 Subject: [PATCH 8/8] make use of StringUtil.terminatorWidth() for better performance --- .../jnr/ffi/provider/converters/StringUtil.java | 4 ++-- .../jnr/ffi/provider/jffi/DirectMemoryIO.java | 15 +++++++-------- src/main/java/jnr/ffi/util/BufferUtil.java | 4 +++- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/java/jnr/ffi/provider/converters/StringUtil.java b/src/main/java/jnr/ffi/provider/converters/StringUtil.java index 0d5bc704..8025bc4b 100644 --- a/src/main/java/jnr/ffi/provider/converters/StringUtil.java +++ b/src/main/java/jnr/ffi/provider/converters/StringUtil.java @@ -35,7 +35,7 @@ import java.util.Arrays; import java.util.Collection; -final class StringUtil { +final public class StringUtil { private StringUtil() {} static CharsetEncoder getEncoder(Charset charset, ThreadLocal> localEncoder) { @@ -121,7 +121,7 @@ static void throwException(CoderResult result) { private static final Charset UTF16LE = Charset.forName("UTF-16LE"); private static final Charset UTF16BE = Charset.forName("UTF-16BE"); - static int terminatorWidth(Charset charset) { + public static int terminatorWidth(Charset charset) { if (charset.equals(UTF8) || charset.equals(USASCII) || charset.equals(ISO8859_1)) { return 1; diff --git a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java index e174f3a6..31a2453b 100644 --- a/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java +++ b/src/main/java/jnr/ffi/provider/jffi/DirectMemoryIO.java @@ -22,10 +22,10 @@ import jnr.ffi.Runtime; import jnr.ffi.provider.AbstractMemoryIO; import jnr.ffi.provider.DelegatingMemoryIO; +import jnr.ffi.provider.converters.StringUtil; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; class DirectMemoryIO extends AbstractMemoryIO { static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); @@ -188,8 +188,8 @@ public String getString(long offset) { public String getString(long offset, int maxLength, Charset cs) { long baseAddress = address() + offset; - - if(cs == StandardCharsets.UTF_8) { + int nullTermSize = StringUtil.terminatorWidth(cs); + if(nullTermSize == 1) { final byte[] bytes = IO.getZeroTerminatedByteArray(baseAddress, maxLength); return cs.decode(ByteBuffer.wrap(bytes)).toString(); } else { @@ -197,21 +197,20 @@ public String getString(long offset, int maxLength, Charset cs) { return null; } - final byte[] nullCharBytes = new String("\0").getBytes(cs); int nullTerminatedLen = 0; int matchingBytesCount = 0; int i = 0; while(i < maxLength) { - if(IO.getByte(baseAddress+i) == nullCharBytes[matchingBytesCount]) { + if(IO.getByte(baseAddress+i) == 0) { matchingBytesCount++; i++; } else { matchingBytesCount = 0; - i += nullCharBytes.length - (i%nullCharBytes.length);//jump to start of next character + i += nullTermSize - (i%nullTermSize);//jump to start of next character continue; } - if(matchingBytesCount == nullCharBytes.length) { - nullTerminatedLen = i-nullCharBytes.length;//trim to the last byte just before null terminator + if(matchingBytesCount == nullTermSize) { + nullTerminatedLen = i-nullTermSize;//trim to the last byte just before null terminator break; } } diff --git a/src/main/java/jnr/ffi/util/BufferUtil.java b/src/main/java/jnr/ffi/util/BufferUtil.java index a9afd312..82444e70 100644 --- a/src/main/java/jnr/ffi/util/BufferUtil.java +++ b/src/main/java/jnr/ffi/util/BufferUtil.java @@ -26,6 +26,8 @@ import java.nio.charset.CharsetEncoder; import java.nio.charset.CodingErrorAction; +import jnr.ffi.provider.converters.StringUtil; + /** * */ @@ -64,7 +66,7 @@ public static CharSequence getCharSequence(ByteBuffer buf, Charset charset) { final ByteBuffer buffer = buf.slice(); // Find the NUL terminator and limit to that, so the // StringBuffer/StringBuilder does not have superfluous NUL chars - final byte[] nullCharBytes = new String("\0").getBytes(charset); + final byte[] nullCharBytes = new byte[StringUtil.terminatorWidth(charset)]; int end = indexOf(buffer, nullCharBytes) - nullCharBytes.length; if (end < 0) { end = buffer.limit();