Skip to content

Commit

Permalink
CFStringRef#stringValue buffer needs space for null byte (#1343)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbwiddis committed Apr 22, 2021
1 parent 7a33efb commit 5ac6161
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 15 deletions.
2 changes: 1 addition & 1 deletion CHANGES.md
Expand Up @@ -14,7 +14,7 @@ Features

Bug Fixes
---------

* [#1343](https://github.com/java-native-access/jna/issues/1343): `c.s.j.p.mac.CoreFoundation.CFStringRef#stringValue` buffer needs space for null byte - [@dbwiddis](https://github.com/dbwiddis).

Release 5.8.0
=============
Expand Down
Expand Up @@ -487,14 +487,18 @@ public static CFStringRef createCFString(String s) {
* failed.
*/
public String stringValue() {
// Get number of characters
CFIndex length = INSTANCE.CFStringGetLength(this);
if (length.longValue() == 0) {
return "";
}
// Calculate maximum possible size in UTF8 bytes
CFIndex maxSize = INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
if (maxSize.intValue() == kCFNotFound) {
throw new StringIndexOutOfBoundsException("CFString maximum number of bytes exceeds LONG_MAX.");
}
// Increment size by 1 for a null byte
maxSize.setValue(maxSize.longValue() + 1);
Memory buf = new Memory(maxSize.longValue());
if (0 != INSTANCE.CFStringGetCString(this, buf, maxSize, kCFStringEncodingUTF8)) {
return buf.getString(0, "UTF8");
Expand Down
Expand Up @@ -33,6 +33,7 @@
import static org.junit.Assert.fail;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
Expand Down Expand Up @@ -62,25 +63,27 @@ public class CoreFoundationTest {

@Test
public void testCFStringRef() throws UnsupportedEncodingException {
String awesome = "ǝɯosǝʍɐ sı ∀Nſ"; // Unicode
CFStringRef cfAwesome = CFStringRef.createCFString(awesome);
assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome).intValue());
assertEquals(awesome, cfAwesome.stringValue());
assertEquals(CoreFoundation.STRING_TYPE_ID, cfAwesome.getTypeID());

byte[] awesomeArr = awesome.getBytes("UTF-8");
Memory mem = new Memory(awesomeArr.length + 1);
// Create a unicode string of a single 3-byte character
byte[] alaf = { (byte) 0xe0, (byte) 0xa0, (byte) 0x80 };
String utf8Str = new String(alaf, StandardCharsets.UTF_8);
CFStringRef cfStr = CFStringRef.createCFString(utf8Str);
assertEquals(utf8Str.length(), CF.CFStringGetLength(cfStr).intValue());
assertEquals(utf8Str, cfStr.stringValue());
assertEquals(CoreFoundation.STRING_TYPE_ID, cfStr.getTypeID());

byte[] utf8Arr = utf8Str.getBytes("UTF-8");
Memory mem = new Memory(utf8Arr.length + 1);
mem.clear();
assertNotEquals(0,
CF.CFStringGetCString(cfAwesome, mem, new CFIndex(mem.size()), CoreFoundation.kCFStringEncodingUTF8));
byte[] awesomeBytes = mem.getByteArray(0, (int) mem.size() - 1);
assertArrayEquals(awesomeArr, awesomeBytes);
CF.CFStringGetCString(cfStr, mem, new CFIndex(mem.size()), CoreFoundation.kCFStringEncodingUTF8));
byte[] utf8Bytes = mem.getByteArray(0, (int) mem.size() - 1);
assertArrayEquals(utf8Arr, utf8Bytes);
// Essentially a toString, can't rely on format but should contain the string
CFStringRef desc = CF.CFCopyDescription(cfAwesome);
assertTrue(desc.stringValue().contains(awesome));
CFStringRef desc = CF.CFCopyDescription(cfStr);
assertTrue(desc.stringValue().contains(utf8Str));

desc.release();
cfAwesome.release();
cfStr.release();

CFStringRef cfEmpty = CFStringRef.createCFString("");
assertTrue(cfEmpty.stringValue().equals(""));
Expand Down

0 comments on commit 5ac6161

Please sign in to comment.