Skip to content

Commit

Permalink
Better type mappings
Browse files Browse the repository at this point in the history
  • Loading branch information
dbwiddis committed Sep 3, 2019
1 parent b1cb0a5 commit be82280
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 71 deletions.
77 changes: 68 additions & 9 deletions contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ public interface CoreFoundation extends Library {
* Foundation objects.
*/
class CFTypeRef extends PointerType {
public CFTypeRef() {
super();
}

public CFTypeRef(Pointer p) {
super(p);
}
}

/**
Expand All @@ -84,6 +91,13 @@ class CFAllocatorRef extends CFTypeRef {
* A reference to a {@code CFNumber} object.
*/
class CFNumberRef extends CFTypeRef {
public CFNumberRef() {
super();
}

public CFNumberRef(Pointer p) {
super(p);
}
}

/**
Expand All @@ -102,6 +116,13 @@ enum CFNumberType {
* A reference to a {@code CFBoolean} object.
*/
class CFBooleanRef extends CFTypeRef {
public CFBooleanRef() {
super();
}

public CFBooleanRef(Pointer p) {
super(p);
}
}

/**
Expand All @@ -112,24 +133,52 @@ class CFBooleanRef extends CFTypeRef {
* parameter, you can pass in a {@link #CFArrayRef}.
*/
class CFArrayRef extends CFTypeRef {
public CFArrayRef() {
super();
}

public CFArrayRef(Pointer p) {
super(p);
}
}

/**
* A reference to an immutable {@code CFData} object.
*/
class CFDataRef extends CFTypeRef {
public CFDataRef() {
super();
}

public CFDataRef(Pointer p) {
super(p);
}
}

/**
* A reference to an immutable {@code CFDictionary} object.
*/
class CFDictionaryRef extends CFTypeRef {
public CFDictionaryRef() {
super();
}

public CFDictionaryRef(Pointer p) {
super(p);
}
}

/**
* A reference to a mutable {@code CFDictionary} object.
*/
class CFMutableDictionaryRef extends CFDictionaryRef {
public CFMutableDictionaryRef() {
super();
}

public CFMutableDictionaryRef(Pointer p) {
super(p);
}
}

/**
Expand All @@ -138,6 +187,14 @@ class CFMutableDictionaryRef extends CFDictionaryRef {
* the characteristics and behavior of {@code CFString} objects.
*/
class CFStringRef extends CFTypeRef {
public CFStringRef() {
super();
}

public CFStringRef(Pointer p) {
super(p);
}

/**
* Convenience function which calls {@link #CFStringCreateWithCharacters} to
* create a new {@code CFString} from the given Java {@link java.lang.String}
Expand Down Expand Up @@ -314,7 +371,7 @@ public static CFStringRef toCFString(String s) {
* @return A new dictionary, or {@code null} if there was a problem creating the
* object.
*/
CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capacity, Pointer keyCallBacks,
CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capacity, PointerType keyCallBacks,
Pointer valueCallBacks);

/**
Expand Down Expand Up @@ -394,7 +451,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* {@link #CFDictionaryGetValueIfPresent} to distinguish between a value
* that is not found, and a {@code null} value.
*/
CFTypeRef CFDictionaryGetValue(CFTypeRef theDict, CFStringRef key);
Pointer CFDictionaryGetValue(CFTypeRef theDict, PointerType key);

/**
* Returns a boolean value that indicates whether a given value for a given key
Expand All @@ -420,7 +477,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* was present).
* @return {@code true} if a matching key was found, otherwise {@code false}.
*/
boolean CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, CFStringRef key, PointerType value);
boolean CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, PointerType key, PointerByReference value);

/**
* Sets the value corresponding to a given key.
Expand All @@ -447,7 +504,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* released. {@code value} must be of the type expected by the retain
* and release callbacks.
*/
void CFDictionarySetValue(CFMutableDictionaryRef theDict, CFTypeRef key, CFTypeRef value);
void CFDictionarySetValue(CFMutableDictionaryRef theDict, PointerType key, PointerType value);

/**
* Copies the character contents of a string to a local C string buffer after
Expand Down Expand Up @@ -503,7 +560,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* @return A constant that indicates the data type of the value contained in
* number. See {@link CFNumberType} for a list of possible values.
*/
int CFNumberGetType(CFTypeRef number);
int CFNumberGetType(CFNumberRef number);

/**
* Obtains the value of a {@code CFNumber} object cast to a specified type.
Expand All @@ -515,8 +572,10 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* {@link CFNumberType} for a list of possible values.
* @param On
* return, contains the value of {@code number}.
* @return {@code true} if the operation was successful, otherwise
* {@code false}.
*/
void CFNumberGetValue(CFTypeRef number, int theType, ByReference valuePtr);
boolean CFNumberGetValue(CFNumberRef number, int theType, ByReference valuePtr);

/**
* Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a
Expand All @@ -527,7 +586,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* @return The number (in terms of UTF-16 code pairs) of characters stored in
* {@code theString}.
*/
long CFStringGetLength(CFTypeRef theString);
long CFStringGetLength(CFStringRef theString);

/**
* Returns the maximum number of bytes a string of a specified length (in
Expand Down Expand Up @@ -560,7 +619,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* The {@code CFData} object to examine.
* @return An index that specifies the number of bytes in {@code theData}.
*/
long CFDataGetLength(CFTypeRef theData);
long CFDataGetLength(CFDataRef theData);

/**
* Returns a read-only pointer to the bytes of a {@code CFData} object.
Expand All @@ -569,5 +628,5 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac
* The {@code CFData} object to examine.
* @return A read-only pointer to the bytes associated with {@code theData}.
*/
PointerByReference CFDataGetBytePtr(CFTypeRef theData);
PointerByReference CFDataGetBytePtr(CFDataRef theData);
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
import java.util.Collection;

import com.sun.jna.Memory;
import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef;
import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef;
import com.sun.jna.platform.mac.CoreFoundation.CFNumberType;
import com.sun.jna.platform.mac.CoreFoundation.CFStringRef;
import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.ptr.LongByReference;
Expand All @@ -45,62 +48,72 @@ private CoreFoundationUtil() {
}

/**
* Convert a reference to a Core Foundations LongLong into its {@code long}
* Convert a reference to a Core Foundations LongLong into its {@code long}.
* <p>
* This method assumes a 64-bit number is stored and does not do type checking.
* If the argument type differs from the return type, and the conversion is
* lossy or the return value is out of range, then this function passes back an
* approximate value.
*
* @param theLong
* The pointer to a 64-bit integer
* @return The corresponding {@code long}
*/
public static long cfPointerToLong(CFTypeRef theLong) {
public static long cfPointerToLong(CFNumberRef theLong) {
LongByReference lbr = new LongByReference();
CF.CFNumberGetValue(theLong, CFNumberType.kCFNumberLongLongType.ordinal(), lbr);
return lbr.getValue();
}

/**
* Convert a reference to a Core Foundations Int into its {@code int}
* <p>
* This method assumes a 32-bit number is stored and does not do type checking.
* If the argument type differs from the return type, and the conversion is
* lossy or the return value is out of range, then this function passes back an
* approximate value.
*
* @param p
* @param theInt
* The pointer to an integer
* @return The corresponding {@code int}
*/
public static int cfPointerToInt(CFTypeRef p) {
public static int cfPointerToInt(CFNumberRef theInt) {
IntByReference ibr = new IntByReference();
CF.CFNumberGetValue(p, CFNumberType.kCFNumberIntType.ordinal(), ibr);
CF.CFNumberGetValue(theInt, CFNumberType.kCFNumberIntType.ordinal(), ibr);
return ibr.getValue();
}

/**
* Convert a reference to a Core Foundations Boolean into its {@code boolean}
*
* @param cfBoolean
* @param theBoolean
* The pointer to a boolean
* @return The corresponding {@code boolean}
*/
public static boolean cfPointerToBoolean(CFTypeRef cfBoolean) {
return CF.CFBooleanGetValue(cfBoolean);
public static boolean cfPointerToBoolean(CFBooleanRef theBoolean) {
return CF.CFBooleanGetValue(theBoolean);
}

/**
* Convert a reference to a Core Foundations String into its
* {@link java.lang.String}
*
* @param cfTypeRef
* @param theString
* The pointer to a CFString
* @return The corresponding {@link java.lang.String}
*/
public static String cfPointerToString(CFTypeRef cfTypeRef) {
if (cfTypeRef == null) {
public static String cfPointerToString(CFStringRef theString) {
if (theString == null) {
return "null";
}
long length = CF.CFStringGetLength(cfTypeRef);
long length = CF.CFStringGetLength(theString);
long maxSize = CF.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
if (maxSize == CoreFoundation.kCFNotFound) {
maxSize = 4 * (length + 1);
}
Memory buf = new Memory(maxSize);
CF.CFStringGetCString(cfTypeRef, buf, maxSize, kCFStringEncodingUTF8);
return buf.getString(0);
CF.CFStringGetCString(theString, buf, maxSize, kCFStringEncodingUTF8);
return buf.getString(0, "UTF8");
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef;
import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef;
import com.sun.jna.platform.mac.CoreFoundation.CFDataRef;
Expand All @@ -57,18 +58,18 @@ public class CoreFoundationTest {

@Test
public void testCFStringRef() {
String awesome = "JNA is awesome";
String awesome = "ǝɯosǝʍɐ sı ∀Nſ"; // Unicode
CFStringRef cfAwesome = CFStringRef.toCFString(awesome);
assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome));
assertEquals(awesome, CoreFoundationUtil.cfPointerToString(cfAwesome));

Memory mem = new Memory(awesome.length() + 1);
Memory mem = new Memory(awesome.getBytes().length + 1);
mem.clear();
assertTrue(CF.CFStringGetCString(cfAwesome, mem, mem.size(), CoreFoundation.kCFStringEncodingUTF8));
byte[] awesomeBytes = mem.getByteArray(0, (int) mem.size() - 1);
char[] awesomeArr = awesome.toCharArray();
byte[] awesomeArr = awesome.getBytes();
for (int i = 0; i < awesomeArr.length; i++) {
assertEquals((byte) awesomeArr[i], awesomeBytes[i]);
assertEquals(awesomeArr[i], awesomeBytes[i]);
}
// Essentially a toString, can't rely on format but should contain the string
CFStringRef desc = CF.CFCopyDescription(cfAwesome);
Expand All @@ -89,10 +90,11 @@ public void testCFNumberRef() {
IntByReference one = new IntByReference(1);
CFNumberRef cfZero = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), zero);
CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), one);

assertEquals(0, CoreFoundationUtil.cfPointerToInt(cfZero));
assertEquals(1, CoreFoundationUtil.cfPointerToInt(cfOne));
assertEquals(false, CoreFoundationUtil.cfPointerToBoolean(cfZero));
assertEquals(true, CoreFoundationUtil.cfPointerToBoolean(cfOne));
// assertEquals(false, CoreFoundationUtil.cfPointerToBoolean(cfZero));
// assertEquals(true, CoreFoundationUtil.cfPointerToBoolean(cfOne));
release(cfZero);
release(cfOne);
}
Expand Down Expand Up @@ -138,7 +140,8 @@ public void testCFArray() {

assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray));
for (int i = 0; i < refArray.length; i++) {
CFTypeRef numRef = CF.CFArrayGetValueAtIndex(cfPtrArray, i);
CFTypeRef result = CF.CFArrayGetValueAtIndex(cfPtrArray, i);
CFNumberRef numRef = new CFNumberRef(result.getPointer());
assertEquals(i, CoreFoundationUtil.cfPointerToInt(numRef));
}

Expand Down Expand Up @@ -168,28 +171,42 @@ public void testCFData() {
public void testCFDictionary() {
CFAllocatorRef alloc = CF.CFAllocatorGetDefault();
CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, 2, null, null);
CFStringRef oneKey = CFStringRef.toCFString("one");
CFStringRef oneStr = CFStringRef.toCFString("one");

// Key does not exist, returns null
assertFalse(CF.CFDictionaryGetValueIfPresent(dict, oneKey, null));
CFTypeRef cfNull = CF.CFDictionaryGetValue(dict, oneKey);
assertFalse(CF.CFDictionaryGetValueIfPresent(dict, oneStr, null));
Pointer cfNull = CF.CFDictionaryGetValue(dict, oneStr);
assertNull(cfNull);

// Store and retrieve null value
CF.CFDictionarySetValue(dict, oneKey, null);
assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneKey, null));
CFTypeRef cfNullValue = CF.CFDictionaryGetValue(dict, oneKey);
CF.CFDictionarySetValue(dict, oneStr, null);
assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneStr, null));
Pointer cfNullValue = CF.CFDictionaryGetValue(dict, oneStr);
assertNull(cfNullValue);

// Store (replace the null) and retrieve integer value
IntByReference one = new IntByReference(1);
CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), one);
CF.CFDictionarySetValue(dict, oneKey, cfOne);
assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneKey, null));
CFTypeRef cfValue = CF.CFDictionaryGetValue(dict, oneKey);
assertEquals(1, CoreFoundationUtil.cfPointerToInt(cfValue));

release(oneKey);
CF.CFDictionarySetValue(dict, oneStr, cfOne);

assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneStr, null));
Pointer result = CF.CFDictionaryGetValue(dict, oneStr);
CFNumberRef numRef = new CFNumberRef(result);
assertEquals(1, CoreFoundationUtil.cfPointerToInt(numRef));

PointerByReference resultPtr = new PointerByReference();
assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneStr, resultPtr));
numRef = new CFNumberRef(resultPtr.getValue());
assertEquals(1, CoreFoundationUtil.cfPointerToInt(numRef));

// Test non-CF type as key
IntByReference onePtr = new IntByReference(1);
CF.CFDictionarySetValue(dict, onePtr, oneStr);
result = CF.CFDictionaryGetValue(dict, onePtr);
CFStringRef strRef = new CFStringRef(result);
assertEquals("one", CoreFoundationUtil.cfPointerToString(strRef));

release(oneStr);
release(cfOne);
release(dict);
}
Expand Down
Loading

0 comments on commit be82280

Please sign in to comment.