From e8e3e59dd71dd7cc3b5cf6fa9a550a658e1b6d50 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Fri, 30 Aug 2019 19:23:19 -0700 Subject: [PATCH 01/28] Add mappings for Core Foundation framework --- CHANGES.md | 3 +- .../sun/jna/platform/mac/CoreFoundation.java | 573 ++++++++++++++++++ .../jna/platform/mac/CoreFoundationUtil.java | 142 +++++ .../jna/platform/mac/CoreFoundationTest.java | 196 ++++++ 4 files changed, 913 insertions(+), 1 deletion(-) create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java create mode 100644 contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java diff --git a/CHANGES.md b/CHANGES.md index 02bdfddeb8..c7e2c842af 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,11 +2,12 @@ NOTE: as of JNA 4.0, JNA is now dual-licensed under LGPL and AL 2.0 (see LICENSE NOTE: JNI native support is typically incompatible between minor versions, and almost always incompatible between major versions. -Next Release (5.4.1) +Next Release (5.5.0) ==================== Features -------- +* [#1131](https://github.com/java-native-access/jna/pull/1131): Add Core Foundation mappings in `c.s.j.p.mac.CoreFoundation` with a Util class. [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java new file mode 100644 index 0000000000..488c7144f9 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.PointerType; +import com.sun.jna.ptr.ByReference; +import com.sun.jna.ptr.PointerByReference; + +/** + * Core Foundation is a framework that provides fundamental software services + * useful to application services, application environments, and to applications + * themselves. Core Foundation also provides abstractions for common data types. + *

+ * Core Foundation functions have names that indicate when you own a returned + * object: Object-creation functions have “Create” embedded in the name, and + * Object-duplication functions that have “Copy” embedded in the name. If you + * own an object, it is your responsibility to relinquish ownership (using + * {@link #CFRelease}) when you have finished with it. + *

+ * If you receive an object from any Core Foundation function other than a + * creation or copy function—such as a Get function—you do not own it and cannot + * be certain of the object’s life span. If you want to ensure that such an + * object is not disposed of while you are using it, you must claim ownership + * (with the {@link #CFRetain} function). + */ +public interface CoreFoundation extends Library { + + CoreFoundation INSTANCE = Native.load("CoreFoundation", CoreFoundation.class); + + int kCFNotFound = -1; + + int kCFStringEncodingMacRoman = 0; + int kCFStringEncodingWindowsLatin1 = 0x0500; + int kCFStringEncodingISOLatin1 = 0x0201; + int kCFStringEncodingNextStepLatin = 0x0B01; + int kCFStringEncodingASCII = 0x0600; + int kCFStringEncodingUnicode = 0x0100; + int kCFStringEncodingUTF8 = 0x08000100; + int kCFStringEncodingNonLossyASCII = 0x0BFF; + + /** + * The {@code CFTypeRef} type is the base type defined in Core Foundation. It is + * used as the type and return value in several polymorphic functions. It is a + * generic object reference that acts as a placeholder for other true Core + * Foundation objects. + */ + class CFTypeRef extends PointerType { + } + + /** + * A reference type used in many Core Foundation parameters and function + * results. It refers to a {@code CFAllocator} object, which allocates, + * reallocates, and deallocates memory for Core Foundation objects. + */ + class CFAllocatorRef extends CFTypeRef { + } + + /** + * A reference to a {@code CFNumber} object. + */ + class CFNumberRef extends CFTypeRef { + } + + /** + * Enum of values used for {@link CFNumberType} in {@link #CFNumberGetValue} and + * {@link #CFNumberGetType}. Use {@link java.lang.Enum#ordinal} for the expected + * integer value corresponding to the C-style enum. + */ + enum CFNumberType { + unusedZero, kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt64Type, + kCFNumberFloat32Type, kCFNumberFloat64Type, kCFNumberCharType, kCFNumberShortType, kCFNumberIntType, + kCFNumberLongType, kCFNumberLongLongType, kCFNumberFloatType, kCFNumberDoubleType, kCFNumberCFIndexType, + kCFNumberNSIntegerType, kCFNumberCGFloatType, kCFNumberMaxType; + } + + /** + * A reference to a {@code CFBoolean} object. + */ + class CFBooleanRef extends CFTypeRef { + } + + /** + * A reference to an immutable {@code CFArray} object. + *

+ * CFArray is “toll-free bridged” with its Cocoa Foundation counterpart, + * {@code NSArray}. Therefore, in a method where you see an {@code NSArray *} + * parameter, you can pass in a {@link #CFArrayRef}. + */ + class CFArrayRef extends CFTypeRef { + } + + /** + * A reference to an immutable {@code CFData} object. + */ + class CFDataRef extends CFTypeRef { + } + + /** + * A reference to an immutable {@code CFDictionary} object. + */ + class CFDictionaryRef extends CFTypeRef { + } + + /** + * A reference to a mutable {@code CFDictionary} object. + */ + class CFMutableDictionaryRef extends CFDictionaryRef { + } + + /** + * A reference to a {@code CFString} object, which “encapsulates” a Unicode + * string along with its length. {@code CFString} is an opaque type that defines + * the characteristics and behavior of {@code CFString} objects. + */ + class CFStringRef extends CFTypeRef { + /** + * Convenience function which calls {@link #CFStringCreateWithCharacters} to + * create a new {@code CFString} from the given Java {@link java.lang.String} + * and returns its reference pointer. + *

+ * This reference must be released with {@link #CFRelease} to avoid leaking + * references. + * + * @param s + * A {@link java.lang.String}. + * @return An immutable string containing {@code s}, or {@code null} if there + * was a problem creating the object. + */ + public static CFStringRef toCFString(String s) { + final char[] chars = s.toCharArray(); + return INSTANCE.CFStringCreateWithCharacters(null, chars, chars.length); + } + } + + /** + * Returns the number of values currently in an array. + * + * @param theArray + * a {@link #CFArrayRef} object. + * @return The number of values in {@code array}. + */ + int CFArrayGetCount(CFArrayRef theArray); + + /** + * Creates a string from a buffer of Unicode characters. + *

+ * This reference must be released with {@link #CFRelease} to avoid leaking + * references. + * + * @param alloc + * The allocator to use to allocate memory for the new string. Pass + * {@code null} or {@code kCFAllocatorDefault} to use the current + * default allocator. + * @param chars + * The buffer of Unicode characters to copy into the new string. + * @param length + * The number of characters in the buffer pointed to by chars. Only + * this number of characters will be copied to internal storage. + * @return An immutable string containing {@code chars}, or {@code null} if + * there was a problem creating the object. + */ + CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, char[] chars, long length); + + /** + * Creates a {@code CFNumber} object using a specified value. + *

+ * This reference must be released with {@link #CFRelease} to avoid leaking + * references. + * + * @param alloc + * The allocator to use to allocate memory for the new object. Pass + * {@code null} or {@code kCFAllocatorDefault} to use the current + * default allocator. + * @param theType + * A constant that specifies the data type of the value to convert. + * The ordinal value of the enum. + *

+ * The {@code theType} parameter is not necessarily preserved when + * creating a new {@code CFNumber} object. The {@code CFNumber} + * object will be created using whatever internal storage type the + * creation function deems appropriate. Use the function + * {@link #CFNumberGetType} to find out what type the + * {@code CFNumber} object used to store your value. + * @param valuePtr + * A pointer to the value for the returned number object. + * @return A new number with the value specified by {@code valuePtr}. + */ + CFNumberRef CFNumberCreate(CFAllocatorRef alloc, int theType, PointerType valuePtr); + + /** + * Creates a new immutable array with the given values. + *

+ * This reference must be released with {@link #CFRelease} to avoid leaking + * references. + * + * @param alloc + * The allocator to use to allocate memory for the new array and its + * storage for values. Pass {@code null} or + * {@code kCFAllocatorDefault} to use the current default allocator. + * @param values + * A C array of the pointer-sized values to be in the new array. The + * values in the new array are ordered in the same order in which + * they appear in this C array. This value may be {@code null} if + * {@code numValues} is 0. This C array is not changed or freed by + * this function. If {@code values} is not a valid pointer to a C + * array of at least {@code numValues} elements, the behavior is + * undefined. + * @param numValues + * The number of values to copy from the {@code values} C array into + * the new array. This number will be the count of the new array—it + * must not be negative or greater than the number of elements in + * values. + * @param callBacks + * A pointer to a {@code CFArrayCallBacks} structure initialized with + * the callbacks for the array to use on each value in the + * collection. The retain callback is used within this function, for + * example, to retain all of the new values from the {@code values} C + * array. A copy of the contents of the callbacks structure is made, + * so that a pointer to a structure on the stack can be passed in or + * can be reused for multiple collection creations. + *

+ * This value may be {@code null}, which is treated as if a valid + * structure of version 0 with all fields {@code null} had been + * passed in. + * @return A new immutable array containing {@code numValues} from + * {@code values}, or {@code null} if there was a problem creating the + * object. + */ + CFArrayRef CFArrayCreate(CFAllocatorRef alloc, Pointer values, long numValues, Pointer callBacks); + + /** + * Creates an immutable {@code CFData} object using data copied from a specified + * byte buffer. + *

+ * This reference must be released with {@link #CFRelease} to avoid leaking + * references. + * + * @param alloc + * The allocator to use to allocate memory for the new object. Pass + * {@code null} or {@code kCFAllocatorDefault} to use the current + * default allocator. + * @param bytes + * A pointer to the byte buffer that contains the raw data to be + * copied into the Data. + * @param length + * The number of bytes in the buffer ({@code bytes}). + * @return A new {@code CFData} object, or {@code null} if there was a problem + * creating the object. + */ + CFDataRef CFDataCreate(CFAllocatorRef alloc, Pointer bytes, long length); + + /** + * Creates a new mutable dictionary. + *

+ * This reference must be released with {@link #CFRelease} to avoid leaking + * references. + * + * @param alloc + * The allocator to use to allocate memory for the new string. Pass + * {@code null} or {@code kCFAllocatorDefault} to use the current + * default allocator. + * @param capacity + * The maximum number of key-value pairs that can be contained by the + * new dictionary. The dictionary starts empty and can grow to this + * number of key-value pairs (and it can have less). + *

+ * Pass 0 to specify that the maximum capacity is not limited. The + * value must not be negative. + * @param keyCallBacks + * A pointer to a {@code CFDictionaryKeyCallBacks} structure + * initialized with the callbacks to use to retain, release, + * describe, and compare keys in the dictionary. A copy of the + * contents of the callbacks structure is made, so that a pointer to + * a structure on the stack can be passed in or can be reused for + * multiple collection creations. + *

+ * This value may be {@code null}, which is treated as a valid + * structure of version 0 with all fields {@code null}. + * @param valueCallBacks + * A pointer to a {@code CFDictionaryValueCallBacks} structure + * initialized with the callbacks to use to retain, release, + * describe, and compare values in the dictionary. A copy of the + * contents of the callbacks structure is made, so that a pointer to + * a structure on the stack can be passed in or can be reused for + * multiple collection creations. + *

+ * This value may be {@code null}, which is treated as a valid + * structure of version 0 with all fields {@code null}. + * @return A new dictionary, or {@code null} if there was a problem creating the + * object. + */ + CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capacity, Pointer keyCallBacks, + Pointer valueCallBacks); + + /** + * Returns a textual description of a Core Foundation object. + *

+ * The nature of the description differs by object. For example, a description + * of a CFArray object would include descriptions of each of the elements in the + * collection. + *

+ * You can use this function for debugging Core Foundation objects in your code. + * Note, however, that the description for a given object may be different in + * different releases of the operating system. Do not create dependencies in + * your code on the content or format of the information returned by this + * function. + * + * @param cf + * The {@code CFType} object (a generic reference of type + * {@code CFTypeRef}) from which to derive a description. + * @return A string that contains a description of {@code cf}. + */ + CFStringRef CFCopyDescription(CFTypeRef cf); + + /** + * Releases a Core Foundation object. + *

+ * If the retain count of {@code cf} becomes zero the memory allocated to the + * object is deallocated and the object is destroyed. If you create, copy, or + * explicitly retain (see the {@link #CFRetain} function) a Core Foundation + * object, you are responsible for releasing it when you no longer need it. + * + * @param cf + * A {@code CFType} object to release. This value must not be + * {@code null}. + */ + void CFRelease(CFTypeRef cf); + + /** + * Retains a Core Foundation object. You should retain a Core Foundation object + * when you receive it from elsewhere (that is, you did not create or copy it) + * and you want it to persist. + *

+ * If you retain a Core Foundation object you are responsible for releasing it + * with {@link #CFRelease}. + * + * @param cf + * The {@code CFType} object to retain. This value must not be + * {@code null}. + * @return The input value, {code cf}. + */ + CFTypeRef CFRetain(CFTypeRef cf); + + /** + * Returns the reference count of a Core Foundation object. + * + * @param cf + * The {@code CFType} object to examine. + * @return A number representing the reference count of {code cf}. + */ + long CFGetRetainCount(CFTypeRef cf); + + /** + * Returns the value associated with a given key. + * + * @param theDict + * The dictionary to examine. + * @param key + * The key for which to find a match in {@code theDict}. The key hash + * and equal callbacks provided when the dictionary was created are + * used to compare. If the hash callback was {@code null}, the key is + * treated as a pointer and converted to an integer. If the equal + * callback was {@code null}, pointer equality (in C, ==) is used. If + * {@code key}, or any of the keys in {@code theDict}, is not + * understood by the equal callback, the behavior is undefined. + * @return The value associated with key in {@code theDict}, or {@code null} if + * no key-value pair matching key exists. Since {@code null} is also a + * valid value in some dictionaries, use + * {@link #CFDictionaryGetValueIfPresent} to distinguish between a value + * that is not found, and a {@code null} value. + */ + CFTypeRef CFDictionaryGetValue(CFTypeRef theDict, CFStringRef key); + + /** + * Returns a boolean value that indicates whether a given value for a given key + * is in a dictionary, and returns that value indirectly if it exists. + * + * @param theDict + * The dictionary to examine. + * @param key + * The key for which to find a match in {@code theDict}. The key hash + * and equal callbacks provided when the dictionary was created are + * used to compare. If the hash callback was {@code null}, the key is + * treated as a pointer and converted to an integer. If the equal + * callback was {@code null}, pointer equality (in C, ==) is used. If + * {@code key}, or any of the keys in {@code theDict}, is not + * understood by the equal callback, the behavior is undefined. + * @param value + * A pointer to memory which, on return, is filled with the + * pointer-sized value if a matching key is found. If no key match is + * found, the contents of the storage pointed to by this parameter + * are undefined. This value may be {@code null}, in which case the + * value from the dictionary is not returned (but the return value of + * this function still indicates whether or not the key-value pair + * was present). + * @return {@code true} if a matching key was found, otherwise {@code false}. + */ + boolean CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, CFStringRef key, PointerType value); + + /** + * Sets the value corresponding to a given key. + * + * @param theDict + * The dictionary to modify. If this parameter is a fixed-capacity + * dictionary and it is full before this operation, and the key does + * not exist in the dictionary, the behavior is undefined. + * @param key + * The key of the value to set in {@code theDict}. If a key which + * matches {@code key} is already present in the dictionary, only the + * value for the key is changed ("add if absent, replace if + * present"). If no key matches {@code key}, the key-value pair is + * added to the dictionary. + *

+ * If a key-value pair is added, both key and value are retained by + * the dictionary, using the retain callback provided when + * {@code theDict} was created. {@code key} must be of the type + * expected by the key retain callback. + * @param value + * The value to add to or replace in {@code theDict}. {@code value} + * is retained using the value retain callback provided when + * {@code theDict} was created, and the previous value if any is + * released. {@code value} must be of the type expected by the retain + * and release callbacks. + */ + void CFDictionarySetValue(CFMutableDictionaryRef theDict, CFTypeRef key, CFTypeRef value); + + /** + * Copies the character contents of a string to a local C string buffer after + * converting the characters to a given encoding. + * + * @param theString + * The string whose contents you wish to access. + * @param bufferToFill + * The C string buffer into which to copy the string. On return, the + * buffer contains the converted characters. If there is an error in + * conversion, the buffer contains only partial results. + *

+ * The buffer must be large enough to contain the converted + * characters and a NUL terminator. + * @param bufferSize + * The length of {@code buffer} in bytes. + * @param encoding + * The string encoding to which the character contents of + * {@code theString} should be converted. The encoding must specify + * an 8-bit encoding. + * @return {@code true} upon success or {@code false} if the conversion fails or + * the provided buffer is too small. + */ + boolean CFStringGetCString(CFTypeRef theString, Pointer bufferToFill, long bufferSize, int encoding); + + /** + * Returns the value of a {@code CFBoolean} object. + * + * @param bool + * The boolean to examine. + * @return The value of {@code bool}. + */ + boolean CFBooleanGetValue(CFTypeRef bool); + + /** + * Retrieves a value at a given index. + * + * @param theArray + * The array to examine. + * @param idx + * The index of the value to retrieve. If the index is outside the + * index space of {@code theArray} (0 to N-1 inclusive (where N is + * the count of {@code theArray})), the behavior is undefined. + * @return The value at the {@code idx} index in {@code theArray}). + */ + CFTypeRef CFArrayGetValueAtIndex(CFArrayRef theArray, int idx); + + /** + * Returns the type used by a {@code CFNumber} object to store its value. + * + * @param number + * The {@code CFNumber} object to examine. + * @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); + + /** + * Obtains the value of a {@code CFNumber} object cast to a specified type. + * + * @param number + * The {@code CFNumber} object to examine. + * @param theType + * A constant that specifies the data type to return. See + * {@link CFNumberType} for a list of possible values. + * @param On + * return, contains the value of {@code number}. + */ + void CFNumberGetValue(CFTypeRef number, int theType, ByReference valuePtr); + + /** + * Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a + * string. + * + * @param theString + * The string to examine. + * @return The number (in terms of UTF-16 code pairs) of characters stored in + * {@code theString}. + */ + long CFStringGetLength(CFTypeRef theString); + + /** + * Returns the maximum number of bytes a string of a specified length (in + * Unicode characters) will take up if encoded in a specified encoding. + * + * @param length + * The number of Unicode characters to evaluate. + * @param encoding + * The string encoding for the number of characters specified by + * length. + * @return a long. + */ + long CFStringGetMaximumSizeForEncoding(long length, int encoding); + + /** + * Gets the default allocator object for the current thread. + * + * @return A reference to the default allocator for the current thread. If none + * has been explicitly set, returns the generic system allocator. + *

+ * The default allocator can never be released, so it is not necessary + * to {@link #CFRetain} this reference. + */ + CFAllocatorRef CFAllocatorGetDefault(); + + /** + * Returns the number of bytes contained by a {@code CFData} object. + * + * @param theData + * The {@code CFData} object to examine. + * @return An index that specifies the number of bytes in {@code theData}. + */ + long CFDataGetLength(CFTypeRef theData); + + /** + * Returns a read-only pointer to the bytes of a {@code CFData} object. + * + * @param theData + * The {@code CFData} object to examine. + * @return A read-only pointer to the bytes associated with {@code theData}. + */ + PointerByReference CFDataGetBytePtr(CFTypeRef theData); +} diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java new file mode 100644 index 0000000000..34ff00f725 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import static com.sun.jna.platform.mac.CoreFoundation.kCFStringEncodingUTF8; + +import java.util.Collection; + +import com.sun.jna.Memory; +import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; +import com.sun.jna.platform.mac.CoreFoundation.CFNumberType; +import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.LongByReference; + +/** + * Provides utilities for Core Foundations + */ +public class CoreFoundationUtil { + + private static final CoreFoundation CF = CoreFoundation.INSTANCE; + + public static final CFAllocatorRef ALLOCATOR = CF.CFAllocatorGetDefault(); + + private CoreFoundationUtil() { + } + + /** + * Convert a reference to a Core Foundations LongLong into its {@code long} + * + * @param theLong + * The pointer to a 64-bit integer + * @return The corresponding {@code long} + */ + public static long cfPointerToLong(CFTypeRef 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} + * + * @param p + * The pointer to an integer + * @return The corresponding {@code int} + */ + public static int cfPointerToInt(CFTypeRef p) { + IntByReference ibr = new IntByReference(); + CF.CFNumberGetValue(p, CFNumberType.kCFNumberIntType.ordinal(), ibr); + return ibr.getValue(); + } + + /** + * Convert a reference to a Core Foundations Boolean into its {@code boolean} + * + * @param cfBoolean + * The pointer to a boolean + * @return The corresponding {@code boolean} + */ + public static boolean cfPointerToBoolean(CFTypeRef cfBoolean) { + return CF.CFBooleanGetValue(cfBoolean); + } + + /** + * Convert a reference to a Core Foundations String into its + * {@link java.lang.String} + * + * @param cfTypeRef + * The pointer to a CFString + * @return The corresponding {@link java.lang.String} + */ + public static String cfPointerToString(CFTypeRef cfTypeRef) { + if (cfTypeRef == null) { + return "null"; + } + long length = CF.CFStringGetLength(cfTypeRef); + 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); + } + + /** + * Releases a CF reference. If the retain count of {@code ref} becomes zero the + * memory allocated to the object is deallocated and the object is destroyed. If + * you create, copy, or explicitly retain (see the + * {@link CoreFoundation#CFRetain} function) a Core Foundation object, you are + * responsible for releasing it when you no longer need it. + * + * @param ref + * The reference to release + */ + public static void release(CFTypeRef ref) { + if (ref != null) { + CF.CFRelease(ref); + } + } + + /** + * Releases a collection of CF references. If the retain count of a reference + * becomes zero the memory allocated to the object is deallocated and the object + * is destroyed. If you create, copy, or explicitly retain (see the + * {@link CoreFoundation#CFRetain} function) a Core Foundation object, you are + * responsible for releasing it when you no longer need it. + * + * @param + * A type extending {@link CFTypeRef}. + * @param refs + * The collection of references to release + */ + public static void releaseAll(Collection refs) { + for (CFTypeRef ref : refs) { + release(ref); + } + } +} \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java new file mode 100644 index 0000000000..ebba50c95b --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import static com.sun.jna.platform.mac.CoreFoundationUtil.release; +import static com.sun.jna.platform.mac.CoreFoundationUtil.releaseAll; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import com.sun.jna.Memory; +import com.sun.jna.Native; +import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; +import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDataRef; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +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.DoubleByReference; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.LongByReference; +import com.sun.jna.ptr.PointerByReference; + +public class CoreFoundationTest { + + private static final CoreFoundation CF = CoreFoundation.INSTANCE; + + @Test + public void testCFStringRef() { + String awesome = "JNA is awesome"; + CFStringRef cfAwesome = CFStringRef.toCFString(awesome); + assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome)); + assertEquals(awesome, CoreFoundationUtil.cfPointerToString(cfAwesome)); + + Memory mem = new Memory(awesome.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(); + for (int i = 0; i < awesomeArr.length; i++) { + assertEquals((byte) awesomeArr[i], awesomeBytes[i]); + } + // Essentially a toString, can't rely on format but should contain the string + CFStringRef desc = CF.CFCopyDescription(cfAwesome); + assertTrue(CoreFoundationUtil.cfPointerToString(desc).contains(awesome)); + + release(desc); + release(cfAwesome); + } + + @Test + public void testCFNumberRef() { + LongByReference max = new LongByReference(Long.MAX_VALUE); + CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.ordinal(), max); + assertEquals(Long.MAX_VALUE, CoreFoundationUtil.cfPointerToLong(cfMax)); + release(cfMax); + + IntByReference zero = new IntByReference(0); + 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)); + release(cfZero); + release(cfOne); + } + + @Test + public void testCFRetainCount() { + DoubleByReference pi = new DoubleByReference(Math.PI); + DoubleByReference e = new DoubleByReference(Math.E); + CFNumberRef cfE = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.ordinal(), e); + CFNumberRef cfPi = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.ordinal(), pi); + assertEquals(1, CF.CFGetRetainCount(cfE)); + assertEquals(1, CF.CFGetRetainCount(cfPi)); + CF.CFRetain(cfE); + CF.CFRetain(cfPi); + CF.CFRetain(cfPi); + assertEquals(2, CF.CFGetRetainCount(cfE)); + assertEquals(3, CF.CFGetRetainCount(cfPi)); + + List irrationalReferences = new ArrayList<>(); + irrationalReferences.add(cfE); + irrationalReferences.add(cfPi); + releaseAll(irrationalReferences); + + assertEquals(1, CF.CFGetRetainCount(cfE)); + assertEquals(2, CF.CFGetRetainCount(cfPi)); + release(cfPi); + assertEquals(1, CF.CFGetRetainCount(cfPi)); + release(cfE); + release(cfPi); + } + + @Test + public void testCFArray() { + CFNumberRef[] refArray = new CFNumberRef[3]; + int size = Native.getNativeSize(CFNumberRef.class); + Memory contiguousArray = new Memory(size * refArray.length); + for (int i = 0; i < refArray.length; i++) { + refArray[i] = CF.CFNumberCreate(null, CoreFoundation.CFNumberType.kCFNumberIntType.ordinal(), + new IntByReference(i)); + contiguousArray.setPointer(i * size, refArray[i].getPointer()); + } + CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, refArray.length, null); + + assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray)); + for (int i = 0; i < refArray.length; i++) { + CFTypeRef numRef = CF.CFArrayGetValueAtIndex(cfPtrArray, i); + assertEquals(i, CoreFoundationUtil.cfPointerToInt(numRef)); + } + + for (int i = 0; i < refArray.length; i++) { + release(refArray[i]); + } + release(cfPtrArray); + } + + @Test + public void testCFData() { + String deadBug = "The only good bug is a dead bug."; + Memory bugBytes = new Memory(deadBug.length() + 1); + bugBytes.clear(); + bugBytes.setString(0, deadBug); + + CFDataRef cfBug = CF.CFDataCreate(null, bugBytes, bugBytes.size()); + assertEquals(bugBytes.size(), CF.CFDataGetLength(cfBug)); + + PointerByReference bytes = CF.CFDataGetBytePtr(cfBug); + assertEquals(deadBug, bytes.getPointer().getString(0)); + + release(cfBug); + } + + @Test + public void testCFDictionary() { + CFAllocatorRef alloc = CF.CFAllocatorGetDefault(); + CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, 2, null, null); + CFStringRef oneKey = CFStringRef.toCFString("one"); + + // Key does not exist, returns null + assertFalse(CF.CFDictionaryGetValueIfPresent(dict, oneKey, null)); + CFTypeRef cfNull = CF.CFDictionaryGetValue(dict, oneKey); + assertNull(cfNull); + + // Store and retrieve null value + CF.CFDictionarySetValue(dict, oneKey, null); + assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneKey, null)); + CFTypeRef cfNullValue = CF.CFDictionaryGetValue(dict, oneKey); + 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); + release(cfOne); + release(dict); + } +} From 4c727911136d80198f1c7d02cd3a35dd86f6ac64 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sun, 1 Sep 2019 21:10:55 -0700 Subject: [PATCH 02/28] Add mappings for IOKit --- .../src/com/sun/jna/platform/mac/IOKit.java | 418 ++++++++++++++++++ .../com/sun/jna/platform/mac/IOKitTest.java | 261 +++++++++++ 2 files changed, 679 insertions(+) create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/IOKit.java create mode 100644 contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java new file mode 100644 index 0000000000..47884b926d --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import com.sun.jna.Library; +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.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +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; +import com.sun.jna.ptr.PointerByReference; + +/** + * The I/O Kit framework implements non-kernel access to I/O Kit objects + * (drivers and nubs) through the device-interface mechanism. + */ +public interface IOKit extends Library { + + int kIORegistryIterateRecursively = 0x00000001; + int kIORegistryIterateParents = 0x00000002; + + double kIOPSTimeRemainingUnlimited = -2.0; + double kIOPSTimeRemainingUnknown = -1.0; + + IOKit INSTANCE = Native.load("IOKit", IOKit.class); + + /** + * Returns the mach port used to initiate communication with IOKit. + * + * @param bootstrapPort + * Pass 0 for the default. + * @param masterPort + * The master port is returned, and should be released by the caller + * when finished. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IOMasterPort(long bootstrapPort, LongByReference masterPort); + + /** + * Create a matching dictionary that specifies an {@code IOService} class match. + * + * @param name + * The class name. Class matching is successful on {@code IOService}s + * of this class or any subclass. + * @return The matching dictionary created, is returned on success, or + * {@code null} on failure. + *

+ * The dictionary is commonly passed to + * {@link #IOServiceGetMatchingServices} which will consume a reference, + * otherwise it should be released with {@link CoreFoundation#CFRelease} + * by the caller. + */ + CFMutableDictionaryRef IOServiceMatching(String name); + + /** + * Create a matching dictionary that specifies an {@code IOService} name match. + * + * @param name + * The {@code IOService} name. + * @return The matching dictionary created, is returned on success, or + * {@code null} on failure. + *

+ * The dictionary is commonly passed to + * {@link #IOServiceGetMatchingServices} which will consume a reference, + * otherwise it should be released with {@link CoreFoundation#CFRelease} + * by the caller. + */ + CFMutableDictionaryRef IOServiceNameMatching(String name); + + /** + * Create a matching dictionary that specifies an {@code IOService} match based + * on BSD device name. + * + * @param masterPort + * The master port obtained from {@link #IOMasterPort}. + * @param options + * No options are currently defined. + * @param bsdName + * The BSD name. + * @return The matching dictionary created, is returned on success, or + * {@code null} on failure. + *

+ * The dictionary is commonly passed to + * {@link #IOServiceGetMatchingServices} which will consume a reference, + * otherwise it should be released with {@link CoreFoundation#CFRelease} + * by the caller. + */ + CFMutableDictionaryRef IOBSDNameMatching(long masterPort, int options, String bsdName); + + /** + * Look up a registered IOService object that matches a matching dictionary. + * + * @param masterPort + * The master port obtained from {@link #IOMasterPort}. + * @param matchingDictionary + * A CF dictionary containing matching information, of which one + * reference is always consumed by this function. IOKitLib can + * construct matching dictionaries for common criteria with helper + * functions such as {@link #IOServiceMatching}, + * {@link #IOServiceNameMatching}, and {@link #IOBSDNameMatching}. + * @return The first service matched is returned on success. + *

+ * The service must be released by the caller. + */ + long IOServiceGetMatchingService(long masterPort, CFMutableDictionaryRef matchingDictionary); + + /** + * Look up registered IOService objects that match a matching dictionary. + * + * @param masterPort + * The master port obtained from {@link #IOMasterPort}. + * @param matchingDictionary + * A CF dictionary containing matching information, of which one + * reference is always consumed by this function. IOKitLib can + * construct matching dictionaries for common criteria with helper + * functions such as {@link #IOServiceMatching}, + * {@link #IOServiceNameMatching}, and {@link #IOBSDNameMatching}. + * @param existing + * An iterator handle is returned on success, and should be released + * by the caller when the iteration is finished. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IOServiceGetMatchingServices(long masterPort, CFMutableDictionaryRef matchingDictionary, + LongByReference existing); + + /** + * Returns the next object in an iteration. + * + * @param iterator + * An IOKit iterator handle. + * @return If the iterator handle is valid, the next element in the iteration is + * returned, otherwise zero is returned. The element should be released + * by the caller when it is finished. + */ + long IOIteratorNext(long iterator); + + /** + * Create a CF representation of a registry entry's property. + * + * @param entry + * TThe registry entry handle whose property to copy. + * @param key + * A {@code CFString} specifying the property name. + * @param allocator + * The CF allocator to use when creating the CF container. + * @param options + * No options are currently defined. + * @return A CF container is created and returned the caller on success. + *

+ * The caller should release with {@link CoreFoundation#CFRelease}. + */ + CFTypeRef IORegistryEntryCreateCFProperty(long entry, CFStringRef key, CFAllocatorRef allocator, int options); + + /** + * Create a CF dictionary representation of a registry entry's property table. + * + * @param entry + * The registry entry handle whose property table to copy. + * @param properties + * A CFDictionary is created and returned the caller on success. The + * caller should release with CFRelease. + * @param allocator + * The CF allocator to use when creating the CF containers. + * @param options + * No options are currently defined. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryCreateCFProperties(long entry, PointerByReference properties, CFAllocatorRef allocator, + int options); + + /** + * Create a CF representation of a registry entry's property. + * + * @param entry + * The registry entry at which to start the search. + * @param plane + * The name of an existing registry plane. Plane names are defined in + * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. + * @param key + * A {@code CFString} specifying the property name. + * @param allocator + * The CF allocator to use when creating the CF container. + * @param options + * {@link #kIORegistryIterateRecursively} may be set to recurse + * automatically into the registry hierarchy. Without this option, + * this method degenerates into the standard + * {@link #IORegistryEntryCreateCFProperty} call. + * {@link #kIORegistryIterateParents} may be set to iterate the + * parents of the entry, in place of the children. + * @return A CF container is created and returned the caller on success. The + * caller should release with CFRelease. + */ + CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef key, CFAllocatorRef allocator, + int options); + + /** + * Returns an ID for the registry entry that is global to all tasks. + * + * @param entry + * The registry entry handle whose ID to look up. + * @param id + * The resulting ID. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryGetRegistryEntryID(long entry, LongByReference id); + + /** + * Returns a name assigned to a registry entry. + * + * @param entry + * The registry entry handle whose name to look up. + * @param name + * The caller's buffer to receive the name. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryGetName(long entry, Pointer name); + + /** + * Returns an iterator over a registry entry’s child entries in a plane. + * + * @param entry + * The registry entry whose children to iterate over. + * @param plane + * The name of an existing registry plane. Plane names are defined in + * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. + * @param iter + * The created iterator over the children of the entry, on success. + * The iterator must be released when the iteration is finished. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryGetChildIterator(long entry, String plane, LongByReference iter); + + /** + * Returns the first child of a registry entry in a plane. + * + * @param entry + * The registry entry whose child to look up. + * @param plane + * The name of an existing registry plane. Plane names are defined in + * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. + * @param child + * The first child of the registry entry, on success. The child must + * be released by the caller. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryGetChildEntry(long entry, String plane, LongByReference child); + + /** + * Returns the first parent of a registry entry in a plane. + * + * @param entry + * The registry entry whose parent to look up. + * @param plane + * The name of an existing registry plane. Plane names are defined in + * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. + * @param parent + * The first parent of the registry entry, on success. The parent + * must be released by the caller. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryGetParentEntry(long entry, String plane, LongByReference parent); + + /** + * Return a handle to the registry root. + * + * @param masterPort + * The master port obtained from {@link #IOMasterPort}. + * @return A handle to the IORegistryEntry root instance, to be released with + * {@link #IOObjectRelease} by the caller, or 0 on failure. + */ + long IORegistryGetRootEntry(long masterPort); + + /** + * Performs an OSDynamicCast operation on an IOKit object. + * + * @param object + * An IOKit object. + * @param className + * The name of the class. + * @return If the object handle is valid, and represents an object in the kernel + * that dynamic casts to the class true is returned, otherwise false. + */ + boolean IOObjectConformsTo(long object, String className); + + /** + * Releases an object handle previously returned by {@code IOKitLib}. + * + * @param object + * The IOKit object to release. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IOObjectRelease(long object); + + /** + * A request to create a connection to an IOService. + * + * @param service + * The IOService object to open a connection to, usually obtained via + * the {@link #IOServiceGetMatchingServices} API. + * @param owningTask + * The mach task requesting the connection. + * @param type + * A constant specifying the type of connection to be created, + * interpreted only by the IOService's family. + * @param connect + * An {@code io_connect_t} handle is returned on success, to be used + * with the IOConnectXXX APIs. It should be destroyed with + * {@link IOServiceClose}. + * @return A return code generated by {@code IOService::newUserClient}. + */ + int IOServiceOpen(long service, long owningTask, int type, LongByReference connect); + + /** + * Returns the busyState of an IOService. + * + * @param service + * The IOService whose busyState to return. + * @param busyState + * The busyState count is returned. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IOServiceGetBusyState(long service, IntByReference busyState); + + /** + * Close a connection to an IOService and destroy the connect handle. + * + * @param connect + * The connect handle created by IOServiceOpen. It will be destroyed + * by this function, and should not be released with IOObjectRelease. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IOServiceClose(long connect); + + /** + * Returns a blob of Power Source information in an opaque CFTypeRef. + * + * @return {@code null} if errors were encountered, a {@link CFTypeRef} + * otherwise. + *

+ * Caller must {@link CoreFoundation#CFRelease} the return value when + * done accessing it. + */ + CFTypeRef IOPSCopyPowerSourcesInfo(); + + /** + * Returns a CFArray of Power Source handles, each of type CFTypeRef. + * + * @param blob + * Takes the {@link CFTypeRef} returned by + * {@link #IOPSCopyPowerSourcesInfo} + * @return {@code null} if errors were encountered, otherwise a CFArray of + * {@link CFTypeRef}s. + *

+ * Caller must {@link CoreFoundation#CFRelease} the returned + * {@link CFArrayRef}. + */ + CFArrayRef IOPSCopyPowerSourcesList(CFTypeRef blob); + + /** + * Returns a CFDictionary with readable information about the specific power + * source. + * + * @param blob + * the {@link CFTypeRef} returned by + * {@link #IOPSCopyPowerSourcesInfo} + * @param ps + * One of the {@link CFTypeRef}s in the CFArray returned by + * {@link #IOPSCopyPowerSourcesList}. + * @return {@code null} if an error was encountered, otherwise a CFDictionary. + *

+ * Caller should NOT release the returned CFDictionary - it will be + * released as part of the {@link CFTypeRef} returned by + * {@link IOPSCopyPowerSourcesInfo}. + */ + CFDictionaryRef IOPSGetPowerSourceDescription(CFTypeRef blob, CFTypeRef ps); + + /** + * Returns the estimated seconds remaining until all power sources (battery + * and/or UPS's) are empty. + * + * @return Returns {@link #kIOPSTimeRemainingUnknown} if the OS cannot determine + * the time remaining. + *

+ * Returns {@link #kIOPSTimeRemainingUnlimited} if the system has an + * unlimited power source. + *

+ * Otherwise returns a positive number indicating the time remaining in + * seconds until all power sources are depleted. + */ + double IOPSGetTimeRemainingEstimate(); +} diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java new file mode 100644 index 0000000000..6d88329e50 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import static com.sun.jna.platform.mac.CoreFoundationUtil.ALLOCATOR; +import static com.sun.jna.platform.mac.CoreFoundationUtil.release; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import com.sun.jna.Memory; +import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +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; +import com.sun.jna.ptr.PointerByReference; + +public class IOKitTest { + + private static final CoreFoundation CF = CoreFoundation.INSTANCE; + private static final IOKit IO = IOKit.INSTANCE; + + @Test + public void testMatching() { + LongByReference masterPortPtr = new LongByReference(); + assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); + long masterPort = masterPortPtr.getValue(); + + String match = "matching BSD Name"; + CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); + CFStringRef bsdNameKey = CFStringRef.toCFString("BSD Name"); + CFTypeRef cfBsdName = CF.CFDictionaryGetValue(dict, bsdNameKey); + assertEquals(match, CoreFoundationUtil.cfPointerToString(cfBsdName)); + release(bsdNameKey); + release(dict); + + match = "matching IOClass Name"; + dict = IO.IOServiceNameMatching(match); + CFStringRef classNameKey = CFStringRef.toCFString("IONameMatch"); + CFTypeRef cfClassName = CF.CFDictionaryGetValue(dict, classNameKey); + assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClassName)); + release(classNameKey); + release(dict); + + match = "IOPlatformExpertDevice"; + dict = IO.IOServiceMatching(match); + CFStringRef classKey = CFStringRef.toCFString("IOProviderClass"); + CFTypeRef cfClass = CF.CFDictionaryGetValue(dict, classKey); + assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClass)); + release(classKey); + + // Get matching service (consumes dict reference) + long platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); + assertNotEquals(0, platformExpert); + // Get a single key + CFStringRef serialKey = CFStringRef.toCFString("IOPlatformSerialNumber"); + CFTypeRef cfSerial = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, ALLOCATOR, 0); + assertNotNull(cfSerial); + String serialNumber = CoreFoundationUtil.cfPointerToString(cfSerial); + release(cfSerial); + assertEquals(12, serialNumber.length()); + // Get all the keys + PointerByReference properties = new PointerByReference(); + assertEquals(0, IO.IORegistryEntryCreateCFProperties(platformExpert, properties, ALLOCATOR, 0)); + dict = new CFMutableDictionaryRef(); + dict.setPointer(properties.getValue()); + assertTrue(CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); + cfSerial = CF.CFDictionaryGetValue(dict, serialKey); + assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); + release(dict); + assertEquals(0, IO.IOObjectRelease(platformExpert)); + + // Get a single key from a nested entry + long root = IO.IORegistryGetRootEntry(masterPort); + assertNotEquals(0, root); + cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, ALLOCATOR, 0); + // without recursive search should be null + assertNull(cfSerial); + cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, ALLOCATOR, + IOKit.kIORegistryIterateRecursively); + // with recursive search should return a match + assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); + release(serialKey); + release(cfSerial); + + assertEquals(0, IO.IOObjectRelease(root)); + assertEquals(0, IO.IOObjectRelease(masterPort)); + } + + @Test + public void testIteratorParentChild() { + LongByReference masterPortPtr = new LongByReference(); + assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); + long masterPort = masterPortPtr.getValue(); + + Set uniqueEntryIdSet = new HashSet<>(); + // Create matching dictionary for USB Controller class + CFMutableDictionaryRef dict = IO.IOServiceMatching("IOUSBController"); + // Iterate over USB Controllers. All devices are children of one of + // these controllers in the "IOService" plane + LongByReference iter = new LongByReference(); + assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iter)); + // iter is a pointer to first device; iterate until 0 + long controllerDevice = IO.IOIteratorNext(iter.getValue()); + while (controllerDevice != 0) { + LongByReference id = new LongByReference(); + IO.IORegistryEntryGetRegistryEntryID(controllerDevice, id); + // EntryIDs 0 thru 19 are reserved, all are unique + assertTrue(id.getValue() > 19); + assertFalse(uniqueEntryIdSet.contains(id.getValue())); + uniqueEntryIdSet.add(id.getValue()); + + // Get device name + // Corresponds to io_name_t which is char[128] + Memory buffer = new Memory(128); + IO.IORegistryEntryGetName(controllerDevice, buffer); + // Root controllers always begin with "AppleUSB" + assertEquals("AppleUSB", buffer.getString(0).substring(0, 8)); + + // Get the first child, to test vs. iterator + LongByReference firstChild = new LongByReference(); + boolean testFirstChild = 0 == IO.IORegistryEntryGetChildEntry(controllerDevice, "IOService", firstChild); + + // Now iterate the children of this device in the "IOService" plane. + LongByReference childIter = new LongByReference(); + IO.IORegistryEntryGetChildIterator(controllerDevice, "IOService", childIter); + long childDevice = IO.IOIteratorNext(childIter.getValue()); + while (childDevice != 0) { + assertTrue(IO.IOObjectConformsTo(childDevice, "IOUSBDevice")); + + LongByReference childId = new LongByReference(); + IO.IORegistryEntryGetRegistryEntryID(childDevice, childId); + assertTrue(childId.getValue() > 19); + assertFalse(uniqueEntryIdSet.contains(childId.getValue())); + uniqueEntryIdSet.add(childId.getValue()); + + // If first child, test and release + if (testFirstChild) { + assertEquals(childDevice, firstChild.getValue()); + IO.IOObjectRelease(firstChild.getValue()); + testFirstChild = false; + } + + // Get this device's parent in IOService plane, matches controller + LongByReference parent = new LongByReference(); + IO.IORegistryEntryGetParentEntry(childDevice, "IOService", parent); + assertEquals(controllerDevice, parent.getValue()); + IO.IOObjectRelease(parent.getValue()); + + // Release this device and iterate to the next one + IO.IOObjectRelease(childDevice); + childDevice = IO.IOIteratorNext(childIter.getValue()); + } + IO.IOObjectRelease(childIter.getValue()); + + // Release this controller and iterate to the next one + assertEquals(0, IO.IOObjectRelease(controllerDevice)); + controllerDevice = IO.IOIteratorNext(iter.getValue()); + } + assertEquals(0, IO.IOObjectRelease(iter.getValue())); + assertEquals(0, IO.IOObjectRelease(masterPort)); + } + + @Test + public void testIOConnect() { + LongByReference masterPortPtr = new LongByReference(); + assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); + long masterPort = masterPortPtr.getValue(); + + // Open a connection to SMC + CFMutableDictionaryRef dict = IO.IOServiceMatching("AppleSMC"); + // consumes dict references + long smcService = IO.IOServiceGetMatchingService(masterPort, dict); + assertNotEquals(0, smcService); + LongByReference conn = new LongByReference(); + assertEquals(0, IO.IOServiceOpen(smcService, SystemB.INSTANCE.mach_task_self(), 0, conn)); + + IntByReference busy = new IntByReference(Integer.MIN_VALUE); + IO.IOServiceGetBusyState(smcService, busy); + assertTrue(busy.getValue() >= 0); + + IO.IOServiceClose(conn.getValue()); + IO.IOObjectRelease(smcService); + assertEquals(0, IO.IOObjectRelease(masterPort)); + } + + @Test + public void testPowerSources() { + CFTypeRef powerSourcesInfo = IO.IOPSCopyPowerSourcesInfo(); + assertNotNull(powerSourcesInfo); + CFArrayRef powerSourcesList = IO.IOPSCopyPowerSourcesList(powerSourcesInfo); + assertNotNull(powerSourcesList); + double timeRemaining = IO.IOPSGetTimeRemainingEstimate(); + assertTrue(timeRemaining > 0 || timeRemaining == IOKit.kIOPSTimeRemainingUnknown + || timeRemaining == IOKit.kIOPSTimeRemainingUnlimited); + + CFStringRef isPresentKey = CFStringRef.toCFString("Is Present"); + CFStringRef currentCapacityKey = CFStringRef.toCFString("Current Capacity"); + CFStringRef maxCapacityKey = CFStringRef.toCFString("Max Capacity"); + int powerSourcesCount = CF.CFArrayGetCount(powerSourcesList); + for (int ps = 0; ps < powerSourcesCount; ps++) { + // Get the dictionary for that Power Source + CFTypeRef powerSource = CoreFoundation.INSTANCE.CFArrayGetValueAtIndex(powerSourcesList, ps); + CFDictionaryRef dictionary = IOKit.INSTANCE.IOPSGetPowerSourceDescription(powerSourcesInfo, powerSource); + + // Get values from dictionary (See IOPSKeys.h) + // Skip if not present + CFTypeRef isPresentRef = CF.CFDictionaryGetValue(dictionary, isPresentKey); + if (isPresentRef != null && CF.CFBooleanGetValue(isPresentRef)) { + // Remaining Capacity = current / max + IntByReference currentCapacity = new IntByReference(); + if (!CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, currentCapacity)) { + currentCapacity.setValue(0); + } + IntByReference maxCapacity = new IntByReference(); + if (!CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, maxCapacity)) { + maxCapacity.setValue(1); + } + assertTrue(currentCapacity.getValue() <= maxCapacity.getValue()); + } + } + release(isPresentKey); + release(currentCapacityKey); + release(maxCapacityKey); + release(powerSourcesList); + release(powerSourcesInfo); + } +} \ No newline at end of file From 6940d755f8cb13c08c729c1d8453b6dad4824e51 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sun, 1 Sep 2019 21:37:45 -0700 Subject: [PATCH 03/28] Add mappings for DiskArbitration --- CHANGES.md | 2 +- .../sun/jna/platform/mac/DiskArbitration.java | 127 +++++++++++++++++ .../jna/platform/mac/DiskArbitrationTest.java | 131 ++++++++++++++++++ 3 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java create mode 100644 contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java diff --git a/CHANGES.md b/CHANGES.md index c7e2c842af..8b2bc2a020 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,7 @@ Next Release (5.5.0) Features -------- -* [#1131](https://github.com/java-native-access/jna/pull/1131): Add Core Foundation mappings in `c.s.j.p.mac.CoreFoundation` with a Util class. [@dbwiddis](https://github.com/dbwiddis). +* [#1131](https://github.com/java-native-access/jna/pull/1131): Add CoreFoundation, IOKit, and DiskArbitration mappings in `c.s.j.p.mac` with a `CoreFoundationUtil` class. [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java b/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java new file mode 100644 index 0000000000..9c34d4fc32 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; + +/** + * Disk Arbitration is a low-level framework based on Core Foundation. The Disk + * Arbitration framework provides the ability to get various pieces of + * information about a volume. + */ +public interface DiskArbitration extends Library { + + DiskArbitration INSTANCE = Native.load("DiskArbitration", DiskArbitration.class); + + /** + * Type of a reference to {@code DASession} instances. + */ + class DASessionRef extends CFTypeRef { + } + + /** + * Type of a reference to {@code DADisk} instances. + */ + class DADiskRef extends CFTypeRef { + } + + /** + * Creates a new session. The caller of this function receives a reference to + * the returned object. + *

+ * The caller also implicitly retains the object and is responsible for + * releasing it with {@link CoreFoundation#CFRelease}. + * + * @param alloc + * The allocator object to be used to allocate memory. + * @return A reference to a new {@code DASession}. + */ + DASessionRef DASessionCreate(CFAllocatorRef alloc); + + /** + * Creates a new disk object. The caller of this function receives a reference + * to the returned object. + *

+ * The caller also implicitly retains the object and is responsible for + * releasing it with {@link CoreFoundation#CFRelease}. + * + * @param alloc + * The allocator object to be used to allocate memory. + * @param session + * The {@code DASession} in which to contact Disk Arbitration. + * @param diskName + * the BSD device name. + * @return A reference to a new {@code DADisk}. + */ + DADiskRef DADiskCreateFromBSDName(CFAllocatorRef alloc, DASessionRef session, String diskName); + + /** + * Creates a new disk object. The caller of this function receives a reference + * to the returned object. + *

+ * The caller also implicitly retains the object and is responsible for + * releasing it with {@link CoreFoundation#CFRelease}. + * + * @param allocator + * The allocator object to be used to allocate memory. + * @param session + * The {@code DASession} in which to contact Disk Arbitration. + * @param media + * The I/O Kit media object. + * @return A reference to a new {@code DADisk}. + */ + DADiskRef DADiskCreateFromIOMedia(CFAllocatorRef allocator, DASessionRef session, long media); + + /** + * Obtains the Disk Arbitration description of the specified disk. This function + * will contact Disk Arbitration to acquire the latest description of the + * specified disk, unless this function is called on a disk object passed within + * the context of a registered callback, in which case the description is + * current as of that callback event. + *

+ * The caller of this function receives a reference to the returned object. The + * caller also implicitly retains the object and is responsible for releasing it + * with {@link CoreFoundation#CFRelease}. + * + * @param disk + * The {@code DADisk} for which to obtain the Disk Arbitration + * description. + * @return The disk's Disk Arbitration description. + */ + CFDictionaryRef DADiskCopyDescription(DADiskRef disk); + + /** + * Obtains the BSD device name for the specified disk. + * + * @param disk + * The {@code DADisk} for which to obtain the BSD device name. + * @return The disk's BSD device name. + */ + String DADiskGetBSDName(DADiskRef disk); +} \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java new file mode 100644 index 0000000000..d1c6fa0516 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import static com.sun.jna.platform.mac.CoreFoundationUtil.ALLOCATOR; +import static com.sun.jna.platform.mac.CoreFoundationUtil.release; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; +import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.platform.mac.DiskArbitration.DADiskRef; +import com.sun.jna.platform.mac.DiskArbitration.DASessionRef; +import com.sun.jna.ptr.LongByReference; + +public class DiskArbitrationTest { + + private static final DiskArbitration DA = DiskArbitration.INSTANCE; + private static final CoreFoundation CF = CoreFoundation.INSTANCE; + private static final IOKit IO = IOKit.INSTANCE; + + @Test + public void testDiskCreate() { + LongByReference masterPortPtr = new LongByReference(); + assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); + long masterPort = masterPortPtr.getValue(); + + // Create some keys we'll need + CFStringRef daMediaBSDName = CFStringRef.toCFString("DAMediaBSDName"); + CFStringRef daMediaWhole = CFStringRef.toCFString("DAMediaWhole"); + CFStringRef daMediaSize = CFStringRef.toCFString("DAMediaSize"); + CFStringRef daMediaBlockSize = CFStringRef.toCFString("DAMediaBlockSize"); + + // Open a DiskArbitration session + DASessionRef session = DA.DASessionCreate(ALLOCATOR); + assertNotNull(session); + + // Get IOMedia objects representing whole drives and save the BSD Name + List bsdNames = new ArrayList<>(); + LongByReference iter = new LongByReference(); + + CFMutableDictionaryRef dict = IOKit.INSTANCE.IOServiceMatching("IOMedia"); + // Consumes a reference to dict + assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iter)); + long media = IO.IOIteratorNext(iter.getValue()); + while (media != 0) { + CFStringRef wholeKey = CFStringRef.toCFString("Whole"); + CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, ALLOCATOR, 0); + CoreFoundationUtil.release(wholeKey); + assertNotNull(cfWhole); + + if (CoreFoundationUtil.cfPointerToBoolean(cfWhole)) { + DADiskRef disk = DA.DADiskCreateFromIOMedia(ALLOCATOR, session, media); + bsdNames.add(DA.DADiskGetBSDName(disk)); + release(disk); + } + CoreFoundationUtil.release(cfWhole); + IO.IOObjectRelease(media); + media = IO.IOIteratorNext(iter.getValue()); + } + IO.IOObjectRelease(iter.getValue()); + + // Now iterate the bsdNames + for (String bsdName : bsdNames) { + // Get a reference to the disk - only matching /dev/disk* + String path = "/dev/" + bsdName; + File f = new File(path); + assertTrue(f.exists()); + // Get the DiskArbitration dictionary for this disk, which has size (capacity) + DADiskRef disk = DA.DADiskCreateFromBSDName(ALLOCATOR, session, path); + assertNotNull(disk); + CFDictionaryRef diskInfo = DA.DADiskCopyDescription(disk); + assertNotNull(diskInfo); + + // Since we looked up "whole" BSD disks these should match + CFTypeRef bsdNamePtr = CF.CFDictionaryGetValue(diskInfo, daMediaBSDName); + assertEquals(bsdName, CoreFoundationUtil.cfPointerToString(bsdNamePtr)); + CFTypeRef bsdWholePtr = CF.CFDictionaryGetValue(diskInfo, daMediaWhole); + assertTrue(CoreFoundationUtil.cfPointerToBoolean(bsdWholePtr)); + + // Size is a multiple of block size + CFTypeRef sizePtr = CF.CFDictionaryGetValue(diskInfo, daMediaSize); + long size = CoreFoundationUtil.cfPointerToLong(sizePtr); + CFTypeRef blockSizePtr = CF.CFDictionaryGetValue(diskInfo, daMediaBlockSize); + long blockSize = CoreFoundationUtil.cfPointerToLong(blockSizePtr); + assertEquals(0, size % blockSize); + + release(diskInfo); + release(disk); + } + release(daMediaBSDName); + release(daMediaWhole); + release(daMediaSize); + release(daMediaBlockSize); + + release(session); + + assertEquals(0, IO.IOObjectRelease(masterPort)); + } +} From b1cb0a5513e8b1c0018387ac1c1c16b66d6b0096 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Mon, 2 Sep 2019 14:41:20 -0700 Subject: [PATCH 04/28] Don't persist CFAllocatorRef --- .../sun/jna/platform/mac/CoreFoundationUtil.java | 3 --- .../sun/jna/platform/mac/DiskArbitrationTest.java | 9 ++++----- .../test/com/sun/jna/platform/mac/IOKitTest.java | 13 +++++++------ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java index 34ff00f725..632ff74f7a 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java @@ -29,7 +29,6 @@ import java.util.Collection; import com.sun.jna.Memory; -import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; import com.sun.jna.platform.mac.CoreFoundation.CFNumberType; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.ptr.IntByReference; @@ -42,8 +41,6 @@ public class CoreFoundationUtil { private static final CoreFoundation CF = CoreFoundation.INSTANCE; - public static final CFAllocatorRef ALLOCATOR = CF.CFAllocatorGetDefault(); - private CoreFoundationUtil() { } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index d1c6fa0516..bb21a09718 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -24,7 +24,6 @@ */ package com.sun.jna.platform.mac; -import static com.sun.jna.platform.mac.CoreFoundationUtil.ALLOCATOR; import static com.sun.jna.platform.mac.CoreFoundationUtil.release; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -63,7 +62,7 @@ public void testDiskCreate() { CFStringRef daMediaBlockSize = CFStringRef.toCFString("DAMediaBlockSize"); // Open a DiskArbitration session - DASessionRef session = DA.DASessionCreate(ALLOCATOR); + DASessionRef session = DA.DASessionCreate(CF.CFAllocatorGetDefault()); assertNotNull(session); // Get IOMedia objects representing whole drives and save the BSD Name @@ -76,12 +75,12 @@ public void testDiskCreate() { long media = IO.IOIteratorNext(iter.getValue()); while (media != 0) { CFStringRef wholeKey = CFStringRef.toCFString("Whole"); - CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, ALLOCATOR, 0); + CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); CoreFoundationUtil.release(wholeKey); assertNotNull(cfWhole); if (CoreFoundationUtil.cfPointerToBoolean(cfWhole)) { - DADiskRef disk = DA.DADiskCreateFromIOMedia(ALLOCATOR, session, media); + DADiskRef disk = DA.DADiskCreateFromIOMedia(CF.CFAllocatorGetDefault(), session, media); bsdNames.add(DA.DADiskGetBSDName(disk)); release(disk); } @@ -98,7 +97,7 @@ public void testDiskCreate() { File f = new File(path); assertTrue(f.exists()); // Get the DiskArbitration dictionary for this disk, which has size (capacity) - DADiskRef disk = DA.DADiskCreateFromBSDName(ALLOCATOR, session, path); + DADiskRef disk = DA.DADiskCreateFromBSDName(CF.CFAllocatorGetDefault(), session, path); assertNotNull(disk); CFDictionaryRef diskInfo = DA.DADiskCopyDescription(disk); assertNotNull(diskInfo); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 6d88329e50..9525d011de 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -24,7 +24,6 @@ */ package com.sun.jna.platform.mac; -import static com.sun.jna.platform.mac.CoreFoundationUtil.ALLOCATOR; import static com.sun.jna.platform.mac.CoreFoundationUtil.release; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -87,14 +86,16 @@ public void testMatching() { assertNotEquals(0, platformExpert); // Get a single key CFStringRef serialKey = CFStringRef.toCFString("IOPlatformSerialNumber"); - CFTypeRef cfSerial = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, ALLOCATOR, 0); + CFTypeRef cfSerial = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, CF.CFAllocatorGetDefault(), + 0); assertNotNull(cfSerial); String serialNumber = CoreFoundationUtil.cfPointerToString(cfSerial); release(cfSerial); assertEquals(12, serialNumber.length()); // Get all the keys PointerByReference properties = new PointerByReference(); - assertEquals(0, IO.IORegistryEntryCreateCFProperties(platformExpert, properties, ALLOCATOR, 0)); + assertEquals(0, + IO.IORegistryEntryCreateCFProperties(platformExpert, properties, CF.CFAllocatorGetDefault(), 0)); dict = new CFMutableDictionaryRef(); dict.setPointer(properties.getValue()); assertTrue(CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); @@ -106,10 +107,10 @@ public void testMatching() { // Get a single key from a nested entry long root = IO.IORegistryGetRootEntry(masterPort); assertNotEquals(0, root); - cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, ALLOCATOR, 0); + cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), 0); // without recursive search should be null assertNull(cfSerial); - cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, ALLOCATOR, + cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), IOKit.kIORegistryIterateRecursively); // with recursive search should return a match assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); @@ -258,4 +259,4 @@ public void testPowerSources() { release(powerSourcesList); release(powerSourcesInfo); } -} \ No newline at end of file +} From cd000363133c16753d0889fbd814af39656cd03b Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Mon, 2 Sep 2019 22:43:53 -0700 Subject: [PATCH 05/28] Better type mappings --- .../sun/jna/platform/mac/CoreFoundation.java | 75 +++++++++++++++++-- .../jna/platform/mac/CoreFoundationUtil.java | 41 ++++++---- .../jna/platform/mac/CoreFoundationTest.java | 54 ++++++++----- .../jna/platform/mac/DiskArbitrationTest.java | 26 +++++-- .../com/sun/jna/platform/mac/IOKitTest.java | 60 +++++++++------ 5 files changed, 186 insertions(+), 70 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index 488c7144f9..bf29f779e6 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -70,6 +70,13 @@ public interface CoreFoundation extends Library { * Foundation objects. */ class CFTypeRef extends PointerType { + public CFTypeRef() { + super(); + } + + public CFTypeRef(Pointer p) { + super(p); + } } /** @@ -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); + } } /** @@ -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); + } } /** @@ -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); + } } /** @@ -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} @@ -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 @@ -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. @@ -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 @@ -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. @@ -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 @@ -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 @@ -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. @@ -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); } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java index 632ff74f7a..3d4f997cd0 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java @@ -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; @@ -45,13 +48,18 @@ 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}. + *

+ * 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(); @@ -59,48 +67,53 @@ public static long cfPointerToLong(CFTypeRef theLong) { /** * Convert a reference to a Core Foundations Int into its {@code int} + *

+ * 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"); } /** diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index ebba50c95b..cc2732d269 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -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; @@ -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); @@ -89,10 +90,10 @@ 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)); + release(cfZero); release(cfOne); } @@ -138,7 +139,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)); } @@ -168,28 +170,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); } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index bb21a09718..0843892948 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -26,6 +26,7 @@ import static com.sun.jna.platform.mac.CoreFoundationUtil.release; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -35,8 +36,11 @@ import org.junit.Test; +import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.platform.mac.DiskArbitration.DADiskRef; @@ -58,6 +62,7 @@ public void testDiskCreate() { // Create some keys we'll need CFStringRef daMediaBSDName = CFStringRef.toCFString("DAMediaBSDName"); CFStringRef daMediaWhole = CFStringRef.toCFString("DAMediaWhole"); + CFStringRef daMediaLeaf = CFStringRef.toCFString("DAMediaLeaf"); CFStringRef daMediaSize = CFStringRef.toCFString("DAMediaSize"); CFStringRef daMediaBlockSize = CFStringRef.toCFString("DAMediaBlockSize"); @@ -78,8 +83,8 @@ public void testDiskCreate() { CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); CoreFoundationUtil.release(wholeKey); assertNotNull(cfWhole); - - if (CoreFoundationUtil.cfPointerToBoolean(cfWhole)) { + CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); + if (CoreFoundationUtil.cfPointerToBoolean(cfWholeBool)) { DADiskRef disk = DA.DADiskCreateFromIOMedia(CF.CFAllocatorGetDefault(), session, media); bsdNames.add(DA.DADiskGetBSDName(disk)); release(disk); @@ -103,15 +108,23 @@ public void testDiskCreate() { assertNotNull(diskInfo); // Since we looked up "whole" BSD disks these should match - CFTypeRef bsdNamePtr = CF.CFDictionaryGetValue(diskInfo, daMediaBSDName); + Pointer result = CF.CFDictionaryGetValue(diskInfo, daMediaBSDName); + CFStringRef bsdNamePtr = new CFStringRef(result); assertEquals(bsdName, CoreFoundationUtil.cfPointerToString(bsdNamePtr)); - CFTypeRef bsdWholePtr = CF.CFDictionaryGetValue(diskInfo, daMediaWhole); + result = CF.CFDictionaryGetValue(diskInfo, daMediaWhole); + CFBooleanRef bsdWholePtr = new CFBooleanRef(result); assertTrue(CoreFoundationUtil.cfPointerToBoolean(bsdWholePtr)); + result = CF.CFDictionaryGetValue(diskInfo, daMediaLeaf); + CFBooleanRef bsdLeafPtr = new CFBooleanRef(result); + assertFalse(CoreFoundationUtil.cfPointerToBoolean(bsdLeafPtr)); + // Size is a multiple of block size - CFTypeRef sizePtr = CF.CFDictionaryGetValue(diskInfo, daMediaSize); + result = CF.CFDictionaryGetValue(diskInfo, daMediaSize); + CFNumberRef sizePtr = new CFNumberRef(result); long size = CoreFoundationUtil.cfPointerToLong(sizePtr); - CFTypeRef blockSizePtr = CF.CFDictionaryGetValue(diskInfo, daMediaBlockSize); + result = CF.CFDictionaryGetValue(diskInfo, daMediaBlockSize); + CFNumberRef blockSizePtr = new CFNumberRef(result); long blockSize = CoreFoundationUtil.cfPointerToLong(blockSizePtr); assertEquals(0, size % blockSize); @@ -120,6 +133,7 @@ public void testDiskCreate() { } release(daMediaBSDName); release(daMediaWhole); + release(daMediaLeaf); release(daMediaSize); release(daMediaBlockSize); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 9525d011de..2449d7440b 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -38,9 +38,12 @@ import org.junit.Test; import com.sun.jna.Memory; +import com.sun.jna.Pointer; import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; +import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.ptr.IntByReference; @@ -61,7 +64,8 @@ public void testMatching() { String match = "matching BSD Name"; CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); CFStringRef bsdNameKey = CFStringRef.toCFString("BSD Name"); - CFTypeRef cfBsdName = CF.CFDictionaryGetValue(dict, bsdNameKey); + Pointer result = CF.CFDictionaryGetValue(dict, bsdNameKey); + CFStringRef cfBsdName = new CFStringRef(result); assertEquals(match, CoreFoundationUtil.cfPointerToString(cfBsdName)); release(bsdNameKey); release(dict); @@ -69,7 +73,8 @@ public void testMatching() { match = "matching IOClass Name"; dict = IO.IOServiceNameMatching(match); CFStringRef classNameKey = CFStringRef.toCFString("IONameMatch"); - CFTypeRef cfClassName = CF.CFDictionaryGetValue(dict, classNameKey); + result = CF.CFDictionaryGetValue(dict, classNameKey); + CFStringRef cfClassName = new CFStringRef(result); assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClassName)); release(classNameKey); release(dict); @@ -77,7 +82,8 @@ public void testMatching() { match = "IOPlatformExpertDevice"; dict = IO.IOServiceMatching(match); CFStringRef classKey = CFStringRef.toCFString("IOProviderClass"); - CFTypeRef cfClass = CF.CFDictionaryGetValue(dict, classKey); + result = CF.CFDictionaryGetValue(dict, classKey); + CFStringRef cfClass = new CFStringRef(result); assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClass)); release(classKey); @@ -86,11 +92,12 @@ public void testMatching() { assertNotEquals(0, platformExpert); // Get a single key CFStringRef serialKey = CFStringRef.toCFString("IOPlatformSerialNumber"); - CFTypeRef cfSerial = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, CF.CFAllocatorGetDefault(), - 0); - assertNotNull(cfSerial); + CFTypeRef cfSerialAsType = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, + CF.CFAllocatorGetDefault(), 0); + assertNotNull(cfSerialAsType); + CFStringRef cfSerial = new CFStringRef(cfSerialAsType.getPointer()); String serialNumber = CoreFoundationUtil.cfPointerToString(cfSerial); - release(cfSerial); + release(cfSerialAsType); assertEquals(12, serialNumber.length()); // Get all the keys PointerByReference properties = new PointerByReference(); @@ -99,7 +106,8 @@ public void testMatching() { dict = new CFMutableDictionaryRef(); dict.setPointer(properties.getValue()); assertTrue(CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); - cfSerial = CF.CFDictionaryGetValue(dict, serialKey); + result = CF.CFDictionaryGetValue(dict, serialKey); + cfSerial = new CFStringRef(result); assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); release(dict); assertEquals(0, IO.IOObjectRelease(platformExpert)); @@ -107,15 +115,17 @@ public void testMatching() { // Get a single key from a nested entry long root = IO.IORegistryGetRootEntry(masterPort); assertNotEquals(0, root); - cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), 0); + cfSerialAsType = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), + 0); // without recursive search should be null - assertNull(cfSerial); - cfSerial = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), + assertNull(cfSerialAsType); + cfSerialAsType = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), IOKit.kIORegistryIterateRecursively); // with recursive search should return a match + cfSerial = new CFStringRef(cfSerialAsType.getPointer()); assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); release(serialKey); - release(cfSerial); + release(cfSerialAsType); assertEquals(0, IO.IOObjectRelease(root)); assertEquals(0, IO.IOObjectRelease(masterPort)); @@ -239,18 +249,22 @@ public void testPowerSources() { // Get values from dictionary (See IOPSKeys.h) // Skip if not present - CFTypeRef isPresentRef = CF.CFDictionaryGetValue(dictionary, isPresentKey); - if (isPresentRef != null && CF.CFBooleanGetValue(isPresentRef)) { - // Remaining Capacity = current / max - IntByReference currentCapacity = new IntByReference(); - if (!CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, currentCapacity)) { - currentCapacity.setValue(0); - } - IntByReference maxCapacity = new IntByReference(); - if (!CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, maxCapacity)) { - maxCapacity.setValue(1); + PointerByReference result = new PointerByReference(); + if (CF.CFDictionaryGetValueIfPresent(dictionary, isPresentKey, result)) { + CFBooleanRef isPresentRef = new CFBooleanRef(result.getValue()); + if (CF.CFBooleanGetValue(isPresentRef)) { + int currentCapacity = 0; + if (CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, result)) { + CFNumberRef cap = new CFNumberRef(result.getValue()); + currentCapacity = CoreFoundationUtil.cfPointerToInt(cap); + } + int maxCapacity = 100; + if (CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, result)) { + CFNumberRef cap = new CFNumberRef(result.getValue()); + maxCapacity = CoreFoundationUtil.cfPointerToInt(cap); + } + assertTrue(currentCapacity <= maxCapacity); } - assertTrue(currentCapacity.getValue() <= maxCapacity.getValue()); } } release(isPresentKey); From 7c3db24f579f84cce413bae8eb3fa8382f2b144c Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 3 Sep 2019 19:13:32 -0700 Subject: [PATCH 06/28] Fix Boolean, CFIndex, and Pointer typing --- .../sun/jna/platform/mac/CoreFoundation.java | 35 ++++++++----------- .../jna/platform/mac/CoreFoundationUtil.java | 2 +- .../jna/platform/mac/CoreFoundationTest.java | 16 ++++----- .../com/sun/jna/platform/mac/IOKitTest.java | 10 +++--- 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index bf29f779e6..d9f9e96f1d 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -54,14 +54,8 @@ public interface CoreFoundation extends Library { int kCFNotFound = -1; - int kCFStringEncodingMacRoman = 0; - int kCFStringEncodingWindowsLatin1 = 0x0500; - int kCFStringEncodingISOLatin1 = 0x0201; - int kCFStringEncodingNextStepLatin = 0x0B01; int kCFStringEncodingASCII = 0x0600; - int kCFStringEncodingUnicode = 0x0100; int kCFStringEncodingUTF8 = 0x08000100; - int kCFStringEncodingNonLossyASCII = 0x0BFF; /** * The {@code CFTypeRef} type is the base type defined in Core Foundation. It is @@ -267,7 +261,7 @@ public static CFStringRef toCFString(String s) { * A pointer to the value for the returned number object. * @return A new number with the value specified by {@code valuePtr}. */ - CFNumberRef CFNumberCreate(CFAllocatorRef alloc, int theType, PointerType valuePtr); + CFNumberRef CFNumberCreate(CFAllocatorRef alloc, long theType, PointerType valuePtr); /** * Creates a new immutable array with the given values. @@ -475,9 +469,9 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * value from the dictionary is not returned (but the return value of * this function still indicates whether or not the key-value pair * was present). - * @return {@code true} if a matching key was found, otherwise {@code false}. + * @return 1 if a matching key was found, otherwise 0. */ - boolean CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, PointerType key, PointerByReference value); + byte CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, PointerType key, PointerByReference value); /** * Sets the value corresponding to a given key. @@ -525,19 +519,19 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * The string encoding to which the character contents of * {@code theString} should be converted. The encoding must specify * an 8-bit encoding. - * @return {@code true} upon success or {@code false} if the conversion fails or - * the provided buffer is too small. + * @return 1 upon success or 0 if the conversion fails or the provided buffer is + * too small. */ - boolean CFStringGetCString(CFTypeRef theString, Pointer bufferToFill, long bufferSize, int encoding); + byte CFStringGetCString(CFTypeRef theString, Pointer bufferToFill, long bufferSize, int encoding); /** * Returns the value of a {@code CFBoolean} object. * * @param bool * The boolean to examine. - * @return The value of {@code bool}. + * @return 1 if the value of {@code bool} is {@code true}, 0 otherwise. */ - boolean CFBooleanGetValue(CFTypeRef bool); + byte CFBooleanGetValue(CFTypeRef bool); /** * Retrieves a value at a given index. @@ -560,7 +554,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(CFNumberRef number); + long CFNumberGetType(CFNumberRef number); /** * Obtains the value of a {@code CFNumber} object cast to a specified type. @@ -572,10 +566,9 @@ 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}. + * @return 1 if the operation was successful, otherwise 0. */ - boolean CFNumberGetValue(CFNumberRef number, int theType, ByReference valuePtr); + byte CFNumberGetValue(CFNumberRef number, long theType, ByReference valuePtr); /** * Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a @@ -597,7 +590,9 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * @param encoding * The string encoding for the number of characters specified by * length. - * @return a long. + * @return The maximum number of bytes that could be needed to represent length + * number of Unicode characters with the string encoding encoding, or + * {@link #kCFNotFound} if the number exceeds {@link Long#MAX_VALUE}. */ long CFStringGetMaximumSizeForEncoding(long length, int encoding); @@ -628,5 +623,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(CFDataRef theData); + Pointer CFDataGetBytePtr(CFDataRef theData); } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java index 3d4f997cd0..bc259462e8 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java @@ -91,7 +91,7 @@ public static int cfPointerToInt(CFNumberRef theInt) { * @return The corresponding {@code boolean} */ public static boolean cfPointerToBoolean(CFBooleanRef theBoolean) { - return CF.CFBooleanGetValue(theBoolean); + return 0 != CF.CFBooleanGetValue(theBoolean); } /** diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index cc2732d269..cf1dc83310 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -27,7 +27,7 @@ import static com.sun.jna.platform.mac.CoreFoundationUtil.release; import static com.sun.jna.platform.mac.CoreFoundationUtil.releaseAll; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -65,7 +65,7 @@ public void testCFStringRef() { Memory mem = new Memory(awesome.getBytes().length + 1); mem.clear(); - assertTrue(CF.CFStringGetCString(cfAwesome, mem, mem.size(), CoreFoundation.kCFStringEncodingUTF8)); + assertNotEquals(0, CF.CFStringGetCString(cfAwesome, mem, mem.size(), CoreFoundation.kCFStringEncodingUTF8)); byte[] awesomeBytes = mem.getByteArray(0, (int) mem.size() - 1); byte[] awesomeArr = awesome.getBytes(); for (int i = 0; i < awesomeArr.length; i++) { @@ -160,8 +160,8 @@ public void testCFData() { CFDataRef cfBug = CF.CFDataCreate(null, bugBytes, bugBytes.size()); assertEquals(bugBytes.size(), CF.CFDataGetLength(cfBug)); - PointerByReference bytes = CF.CFDataGetBytePtr(cfBug); - assertEquals(deadBug, bytes.getPointer().getString(0)); + Pointer bytes = CF.CFDataGetBytePtr(cfBug); + assertEquals(deadBug, bytes.getString(0)); release(cfBug); } @@ -173,13 +173,13 @@ public void testCFDictionary() { CFStringRef oneStr = CFStringRef.toCFString("one"); // Key does not exist, returns null - assertFalse(CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); + assertEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); Pointer cfNull = CF.CFDictionaryGetValue(dict, oneStr); assertNull(cfNull); // Store and retrieve null value CF.CFDictionarySetValue(dict, oneStr, null); - assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); + assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); Pointer cfNullValue = CF.CFDictionaryGetValue(dict, oneStr); assertNull(cfNullValue); @@ -188,13 +188,13 @@ public void testCFDictionary() { CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), one); CF.CFDictionarySetValue(dict, oneStr, cfOne); - assertTrue(CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); + assertNotEquals(0, 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)); + assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, resultPtr)); numRef = new CFNumberRef(resultPtr.getValue()); assertEquals(1, CoreFoundationUtil.cfPointerToInt(numRef)); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 2449d7440b..91cd73be04 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -105,7 +105,7 @@ public void testMatching() { IO.IORegistryEntryCreateCFProperties(platformExpert, properties, CF.CFAllocatorGetDefault(), 0)); dict = new CFMutableDictionaryRef(); dict.setPointer(properties.getValue()); - assertTrue(CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); + assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); result = CF.CFDictionaryGetValue(dict, serialKey); cfSerial = new CFStringRef(result); assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); @@ -250,16 +250,16 @@ public void testPowerSources() { // Get values from dictionary (See IOPSKeys.h) // Skip if not present PointerByReference result = new PointerByReference(); - if (CF.CFDictionaryGetValueIfPresent(dictionary, isPresentKey, result)) { + if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, isPresentKey, result)) { CFBooleanRef isPresentRef = new CFBooleanRef(result.getValue()); - if (CF.CFBooleanGetValue(isPresentRef)) { + if (CoreFoundationUtil.cfPointerToBoolean(isPresentRef)) { int currentCapacity = 0; - if (CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, result)) { + if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); currentCapacity = CoreFoundationUtil.cfPointerToInt(cap); } int maxCapacity = 100; - if (CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, result)) { + if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); maxCapacity = CoreFoundationUtil.cfPointerToInt(cap); } From 0515f66c18352f8463a5e07e3c79642cb4b10a8b Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 3 Sep 2019 19:58:47 -0700 Subject: [PATCH 07/28] Refactor Release to CFTypeRef class --- .../sun/jna/platform/mac/CoreFoundation.java | 14 +++++++ .../jna/platform/mac/CoreFoundationUtil.java | 37 ------------------- .../jna/platform/mac/CoreFoundationTest.java | 36 +++++++++--------- .../jna/platform/mac/DiskArbitrationTest.java | 23 ++++++------ .../com/sun/jna/platform/mac/IOKitTest.java | 30 +++++++-------- 5 files changed, 57 insertions(+), 83 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index d9f9e96f1d..c591921bab 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -71,6 +71,20 @@ public CFTypeRef() { public CFTypeRef(Pointer p) { super(p); } + + /** + * Convenience method for {@link CoreFoundation#CFRetain} on this object. + */ + public void retain() { + INSTANCE.CFRetain(this); + } + + /** + * Convenience method for {@link CoreFoundation#CFRelease} on this object. + */ + public void release() { + INSTANCE.CFRelease(this); + } } /** diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java index bc259462e8..b2e5e4384b 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java @@ -26,14 +26,11 @@ import static com.sun.jna.platform.mac.CoreFoundation.kCFStringEncodingUTF8; -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; @@ -115,38 +112,4 @@ public static String cfPointerToString(CFStringRef theString) { CF.CFStringGetCString(theString, buf, maxSize, kCFStringEncodingUTF8); return buf.getString(0, "UTF8"); } - - /** - * Releases a CF reference. If the retain count of {@code ref} becomes zero the - * memory allocated to the object is deallocated and the object is destroyed. If - * you create, copy, or explicitly retain (see the - * {@link CoreFoundation#CFRetain} function) a Core Foundation object, you are - * responsible for releasing it when you no longer need it. - * - * @param ref - * The reference to release - */ - public static void release(CFTypeRef ref) { - if (ref != null) { - CF.CFRelease(ref); - } - } - - /** - * Releases a collection of CF references. If the retain count of a reference - * becomes zero the memory allocated to the object is deallocated and the object - * is destroyed. If you create, copy, or explicitly retain (see the - * {@link CoreFoundation#CFRetain} function) a Core Foundation object, you are - * responsible for releasing it when you no longer need it. - * - * @param - * A type extending {@link CFTypeRef}. - * @param refs - * The collection of references to release - */ - public static void releaseAll(Collection refs) { - for (CFTypeRef ref : refs) { - release(ref); - } - } } \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index cf1dc83310..94fccbf1c1 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -24,8 +24,6 @@ */ package com.sun.jna.platform.mac; -import static com.sun.jna.platform.mac.CoreFoundationUtil.release; -import static com.sun.jna.platform.mac.CoreFoundationUtil.releaseAll; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; @@ -75,8 +73,8 @@ public void testCFStringRef() { CFStringRef desc = CF.CFCopyDescription(cfAwesome); assertTrue(CoreFoundationUtil.cfPointerToString(desc).contains(awesome)); - release(desc); - release(cfAwesome); + desc.release(); + cfAwesome.release(); } @Test @@ -84,7 +82,7 @@ public void testCFNumberRef() { LongByReference max = new LongByReference(Long.MAX_VALUE); CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.ordinal(), max); assertEquals(Long.MAX_VALUE, CoreFoundationUtil.cfPointerToLong(cfMax)); - release(cfMax); + cfMax.release(); IntByReference zero = new IntByReference(0); IntByReference one = new IntByReference(1); @@ -93,9 +91,8 @@ public void testCFNumberRef() { assertEquals(0, CoreFoundationUtil.cfPointerToInt(cfZero)); assertEquals(1, CoreFoundationUtil.cfPointerToInt(cfOne)); - - release(cfZero); - release(cfOne); + cfZero.release(); + cfOne.release(); } @Test @@ -115,14 +112,16 @@ public void testCFRetainCount() { List irrationalReferences = new ArrayList<>(); irrationalReferences.add(cfE); irrationalReferences.add(cfPi); - releaseAll(irrationalReferences); + for (CFTypeRef value : irrationalReferences) { + value.release(); + } assertEquals(1, CF.CFGetRetainCount(cfE)); assertEquals(2, CF.CFGetRetainCount(cfPi)); - release(cfPi); + cfPi.release(); assertEquals(1, CF.CFGetRetainCount(cfPi)); - release(cfE); - release(cfPi); + cfE.release(); + cfPi.release(); } @Test @@ -145,9 +144,9 @@ public void testCFArray() { } for (int i = 0; i < refArray.length; i++) { - release(refArray[i]); + refArray[i].release(); } - release(cfPtrArray); + cfPtrArray.release(); } @Test @@ -162,8 +161,7 @@ public void testCFData() { Pointer bytes = CF.CFDataGetBytePtr(cfBug); assertEquals(deadBug, bytes.getString(0)); - - release(cfBug); + cfBug.release(); } @Test @@ -205,8 +203,8 @@ public void testCFDictionary() { CFStringRef strRef = new CFStringRef(result); assertEquals("one", CoreFoundationUtil.cfPointerToString(strRef)); - release(oneStr); - release(cfOne); - release(dict); + oneStr.release(); + cfOne.release(); + dict.release(); } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 0843892948..2dde087b34 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -24,7 +24,6 @@ */ package com.sun.jna.platform.mac; -import static com.sun.jna.platform.mac.CoreFoundationUtil.release; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -81,15 +80,15 @@ public void testDiskCreate() { while (media != 0) { CFStringRef wholeKey = CFStringRef.toCFString("Whole"); CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); - CoreFoundationUtil.release(wholeKey); + wholeKey.release(); assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); if (CoreFoundationUtil.cfPointerToBoolean(cfWholeBool)) { DADiskRef disk = DA.DADiskCreateFromIOMedia(CF.CFAllocatorGetDefault(), session, media); bsdNames.add(DA.DADiskGetBSDName(disk)); - release(disk); + disk.release(); } - CoreFoundationUtil.release(cfWhole); + cfWhole.release(); IO.IOObjectRelease(media); media = IO.IOIteratorNext(iter.getValue()); } @@ -128,16 +127,16 @@ public void testDiskCreate() { long blockSize = CoreFoundationUtil.cfPointerToLong(blockSizePtr); assertEquals(0, size % blockSize); - release(diskInfo); - release(disk); + diskInfo.release(); + disk.release(); } - release(daMediaBSDName); - release(daMediaWhole); - release(daMediaLeaf); - release(daMediaSize); - release(daMediaBlockSize); + daMediaBSDName.release(); + daMediaWhole.release(); + daMediaLeaf.release(); + daMediaSize.release(); + daMediaBlockSize.release(); - release(session); + session.release(); assertEquals(0, IO.IOObjectRelease(masterPort)); } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 91cd73be04..1a9c57d30a 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -24,7 +24,6 @@ */ package com.sun.jna.platform.mac; -import static com.sun.jna.platform.mac.CoreFoundationUtil.release; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; @@ -67,8 +66,8 @@ public void testMatching() { Pointer result = CF.CFDictionaryGetValue(dict, bsdNameKey); CFStringRef cfBsdName = new CFStringRef(result); assertEquals(match, CoreFoundationUtil.cfPointerToString(cfBsdName)); - release(bsdNameKey); - release(dict); + bsdNameKey.release(); + dict.release(); match = "matching IOClass Name"; dict = IO.IOServiceNameMatching(match); @@ -76,8 +75,8 @@ public void testMatching() { result = CF.CFDictionaryGetValue(dict, classNameKey); CFStringRef cfClassName = new CFStringRef(result); assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClassName)); - release(classNameKey); - release(dict); + classNameKey.release(); + dict.release(); match = "IOPlatformExpertDevice"; dict = IO.IOServiceMatching(match); @@ -85,7 +84,7 @@ public void testMatching() { result = CF.CFDictionaryGetValue(dict, classKey); CFStringRef cfClass = new CFStringRef(result); assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClass)); - release(classKey); + classKey.release(); // Get matching service (consumes dict reference) long platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); @@ -97,7 +96,8 @@ public void testMatching() { assertNotNull(cfSerialAsType); CFStringRef cfSerial = new CFStringRef(cfSerialAsType.getPointer()); String serialNumber = CoreFoundationUtil.cfPointerToString(cfSerial); - release(cfSerialAsType); + cfSerialAsType.release(); + assertEquals(12, serialNumber.length()); // Get all the keys PointerByReference properties = new PointerByReference(); @@ -109,7 +109,7 @@ public void testMatching() { result = CF.CFDictionaryGetValue(dict, serialKey); cfSerial = new CFStringRef(result); assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); - release(dict); + dict.release(); assertEquals(0, IO.IOObjectRelease(platformExpert)); // Get a single key from a nested entry @@ -124,8 +124,8 @@ public void testMatching() { // with recursive search should return a match cfSerial = new CFStringRef(cfSerialAsType.getPointer()); assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); - release(serialKey); - release(cfSerialAsType); + serialKey.release(); + cfSerialAsType.release(); assertEquals(0, IO.IOObjectRelease(root)); assertEquals(0, IO.IOObjectRelease(masterPort)); @@ -267,10 +267,10 @@ public void testPowerSources() { } } } - release(isPresentKey); - release(currentCapacityKey); - release(maxCapacityKey); - release(powerSourcesList); - release(powerSourcesInfo); + isPresentKey.release(); + currentCapacityKey.release(); + maxCapacityKey.release(); + powerSourcesList.release(); + powerSourcesInfo.release(); } } From 667e2f949411f236daa33fa42f83b5aae6f96a8e Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 3 Sep 2019 22:05:17 -0700 Subject: [PATCH 08/28] Eliminate CoreFoundationUtil --- CHANGES.md | 2 +- .../sun/jna/platform/mac/CoreFoundation.java | 142 +++++++++++++++++- .../jna/platform/mac/CoreFoundationUtil.java | 115 -------------- .../jna/platform/mac/CoreFoundationTest.java | 28 ++-- .../jna/platform/mac/DiskArbitrationTest.java | 24 +-- .../com/sun/jna/platform/mac/IOKitTest.java | 32 ++-- 6 files changed, 183 insertions(+), 160 deletions(-) delete mode 100644 contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java diff --git a/CHANGES.md b/CHANGES.md index 8b2bc2a020..845a4e9258 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,7 +7,7 @@ Next Release (5.5.0) Features -------- -* [#1131](https://github.com/java-native-access/jna/pull/1131): Add CoreFoundation, IOKit, and DiskArbitration mappings in `c.s.j.p.mac` with a `CoreFoundationUtil` class. [@dbwiddis](https://github.com/dbwiddis). +* [#1131](https://github.com/java-native-access/jna/pull/1131): Add CoreFoundation, IOKit, and DiskArbitration mappings in `c.s.j.p.mac`. [@dbwiddis](https://github.com/dbwiddis). Bug Fixes --------- diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index c591921bab..6a42bb91b7 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -25,11 +25,18 @@ package com.sun.jna.platform.mac; import com.sun.jna.Library; +import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.PointerType; import com.sun.jna.ptr.ByReference; +import com.sun.jna.ptr.ByteByReference; +import com.sun.jna.ptr.DoubleByReference; +import com.sun.jna.ptr.FloatByReference; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; +import com.sun.jna.ptr.ShortByReference; /** * Core Foundation is a framework that provides fundamental software services @@ -106,6 +113,108 @@ public CFNumberRef() { public CFNumberRef(Pointer p) { super(p); } + + /** + * Convert this {@code CFNumber} to a {@code long}. + *

+ * This method assumes a 64-bit integer is stored and does not do type checking. + * Users should use {@link #CFNumberGetType} to determine the appropriate type + * conversion. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this method + * returns an approximate value. + * + * @return The corresponding {@code long} + */ + public long longValue() { + LongByReference lbr = new LongByReference(); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberLongLongType.ordinal(), lbr); + return lbr.getValue(); + } + + /** + * Convert this {@code CFNumber} to an {@code int}. + *

+ * This method assumes a 32-bit integer is stored and does not do type checking. + * Users should use {@link #CFNumberGetType} to determine the appropriate type + * conversion. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this method + * returns an approximate value. + * + * @return The corresponding {@code int} + */ + public int intValue() { + IntByReference ibr = new IntByReference(); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberIntType.ordinal(), ibr); + return ibr.getValue(); + } + + /** + * Convert this {@code CFNumber} to a {@code short}. + *

+ * This method assumes a 16-bit integer is stored and does not do type checking. + * Users should use {@link #CFNumberGetType} to determine the appropriate type + * conversion. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this method + * returns an approximate value. + * + * @return The corresponding {@code short} + */ + public short shortValue() { + ShortByReference sbr = new ShortByReference(); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberShortType.ordinal(), sbr); + return sbr.getValue(); + } + + /** + * Convert this {@code CFNumber} to a {@code byte}. + *

+ * This method assumes an 8-bit integer is stored and does not do type checking. + * Users should use {@link #CFNumberGetType} to determine the appropriate type + * conversion. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this method + * returns an approximate value. + * + * @return The corresponding {@code byte} + */ + public byte byteValue() { + ByteByReference bbr = new ByteByReference(); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberCharType.ordinal(), bbr); + return bbr.getValue(); + } + + /** + * Convert this {@code CFNumber} to a {@code double}. + *

+ * This method assumes a 64-bit floating point value is stored and does not do + * type checking. Users should use {@link #CFNumberGetType} to determine the + * appropriate type conversion. If this object's type differs from the return + * type, and the conversion is lossy or the return value is out of range, then + * this method returns an approximate value. + * + * @return The corresponding {@code double} + */ + public double doubleValue() { + DoubleByReference dbr = new DoubleByReference(); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberDoubleType.ordinal(), dbr); + return dbr.getValue(); + } + + /** + * Convert this {@code CFNumber} to a {@code float}. + *

+ * This method assumes a 32-bit floating point value is stored and does not do + * type checking. Users should use {@link #CFNumberGetType} to determine the + * appropriate type conversion. If this object's type differs from the return + * type, and the conversion is lossy or the return value is out of range, then + * this method returns an approximate value. + * + * @return The corresponding {@code float} + */ + public float floatValue() { + FloatByReference fbr = new FloatByReference(); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberFloatType.ordinal(), fbr); + return fbr.getValue(); + } } /** @@ -131,6 +240,15 @@ public CFBooleanRef() { public CFBooleanRef(Pointer p) { super(p); } + + /** + * Convert a reference to a Core Foundations Boolean into its {@code boolean} + * + * @return The corresponding {@code boolean} + */ + public boolean booleanValue() { + return 0 != INSTANCE.CFBooleanGetValue(this); + } } /** @@ -205,7 +323,7 @@ public CFStringRef(Pointer p) { /** * Convenience function which calls {@link #CFStringCreateWithCharacters} to - * create a new {@code CFString} from the given Java {@link java.lang.String} + * create a new {@link CFStringRef} from the given Java {@link java.lang.String} * and returns its reference pointer. *

* This reference must be released with {@link #CFRelease} to avoid leaking @@ -216,10 +334,30 @@ public CFStringRef(Pointer p) { * @return An immutable string containing {@code s}, or {@code null} if there * was a problem creating the object. */ - public static CFStringRef toCFString(String s) { + public static CFStringRef createCFString(String s) { final char[] chars = s.toCharArray(); return INSTANCE.CFStringCreateWithCharacters(null, chars, chars.length); } + + /** + * Convert a reference to a Core Foundations String into its + * {@link java.lang.String} + * + * @return The corresponding {@link java.lang.String}, or null if the conversion + * failed. + */ + public String stringValue() { + long length = INSTANCE.CFStringGetLength(this); + long maxSize = INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + if (maxSize == kCFNotFound) { + return null; + } + Memory buf = new Memory(maxSize); + if (0 != INSTANCE.CFStringGetCString(this, buf, maxSize, kCFStringEncodingUTF8)) { + return buf.getString(0, "UTF8"); + } + return null; + } } /** diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java deleted file mode 100644 index b2e5e4384b..0000000000 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundationUtil.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2019 Daniel Widdis - * - * The contents of this file is dual-licensed under 2 - * alternative Open Source/Free licenses: LGPL 2.1 or later and - * Apache License 2.0. (starting with JNA version 4.0.0). - * - * You can freely decide which license you want to apply to - * the project. - * - * You may obtain a copy of the LGPL License at: - * - * http://www.gnu.org/licenses/licenses.html - * - * A copy is also included in the downloadable source code package - * containing JNA, in file "LGPL2.1". - * - * You may obtain a copy of the Apache License at: - * - * http://www.apache.org/licenses/ - * - * A copy is also included in the downloadable source code package - * containing JNA, in file "AL2.0". - */ -package com.sun.jna.platform.mac; - -import static com.sun.jna.platform.mac.CoreFoundation.kCFStringEncodingUTF8; - -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.ptr.IntByReference; -import com.sun.jna.ptr.LongByReference; - -/** - * Provides utilities for Core Foundations - */ -public class CoreFoundationUtil { - - private static final CoreFoundation CF = CoreFoundation.INSTANCE; - - private CoreFoundationUtil() { - } - - /** - * Convert a reference to a Core Foundations LongLong into its {@code long}. - *

- * 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(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} - *

- * 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 theInt - * The pointer to an integer - * @return The corresponding {@code int} - */ - public static int cfPointerToInt(CFNumberRef theInt) { - IntByReference ibr = new IntByReference(); - CF.CFNumberGetValue(theInt, CFNumberType.kCFNumberIntType.ordinal(), ibr); - return ibr.getValue(); - } - - /** - * Convert a reference to a Core Foundations Boolean into its {@code boolean} - * - * @param theBoolean - * The pointer to a boolean - * @return The corresponding {@code boolean} - */ - public static boolean cfPointerToBoolean(CFBooleanRef theBoolean) { - return 0 != CF.CFBooleanGetValue(theBoolean); - } - - /** - * Convert a reference to a Core Foundations String into its - * {@link java.lang.String} - * - * @param theString - * The pointer to a CFString - * @return The corresponding {@link java.lang.String} - */ - public static String cfPointerToString(CFStringRef theString) { - if (theString == null) { - return "null"; - } - 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(theString, buf, maxSize, kCFStringEncodingUTF8); - return buf.getString(0, "UTF8"); - } -} \ No newline at end of file diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index 94fccbf1c1..b78e719d04 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -57,9 +57,9 @@ public class CoreFoundationTest { @Test public void testCFStringRef() { String awesome = "ǝɯosǝʍɐ sı ∀Nſ"; // Unicode - CFStringRef cfAwesome = CFStringRef.toCFString(awesome); + CFStringRef cfAwesome = CFStringRef.createCFString(awesome); assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome)); - assertEquals(awesome, CoreFoundationUtil.cfPointerToString(cfAwesome)); + assertEquals(awesome, cfAwesome.stringValue()); Memory mem = new Memory(awesome.getBytes().length + 1); mem.clear(); @@ -71,7 +71,7 @@ public void testCFStringRef() { } // Essentially a toString, can't rely on format but should contain the string CFStringRef desc = CF.CFCopyDescription(cfAwesome); - assertTrue(CoreFoundationUtil.cfPointerToString(desc).contains(awesome)); + assertTrue(desc.stringValue().contains(awesome)); desc.release(); cfAwesome.release(); @@ -81,7 +81,7 @@ public void testCFStringRef() { public void testCFNumberRef() { LongByReference max = new LongByReference(Long.MAX_VALUE); CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.ordinal(), max); - assertEquals(Long.MAX_VALUE, CoreFoundationUtil.cfPointerToLong(cfMax)); + assertEquals(Long.MAX_VALUE, cfMax.longValue()); cfMax.release(); IntByReference zero = new IntByReference(0); @@ -89,8 +89,8 @@ public void testCFNumberRef() { 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(0, cfZero.intValue()); + assertEquals(1, cfOne.intValue()); cfZero.release(); cfOne.release(); } @@ -103,9 +103,9 @@ public void testCFRetainCount() { CFNumberRef cfPi = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.ordinal(), pi); assertEquals(1, CF.CFGetRetainCount(cfE)); assertEquals(1, CF.CFGetRetainCount(cfPi)); - CF.CFRetain(cfE); - CF.CFRetain(cfPi); - CF.CFRetain(cfPi); + cfE.retain(); + cfPi.retain(); + cfPi.retain(); assertEquals(2, CF.CFGetRetainCount(cfE)); assertEquals(3, CF.CFGetRetainCount(cfPi)); @@ -140,7 +140,7 @@ public void testCFArray() { for (int i = 0; i < refArray.length; i++) { CFTypeRef result = CF.CFArrayGetValueAtIndex(cfPtrArray, i); CFNumberRef numRef = new CFNumberRef(result.getPointer()); - assertEquals(i, CoreFoundationUtil.cfPointerToInt(numRef)); + assertEquals(i, numRef.intValue()); } for (int i = 0; i < refArray.length; i++) { @@ -168,7 +168,7 @@ public void testCFData() { public void testCFDictionary() { CFAllocatorRef alloc = CF.CFAllocatorGetDefault(); CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, 2, null, null); - CFStringRef oneStr = CFStringRef.toCFString("one"); + CFStringRef oneStr = CFStringRef.createCFString("one"); // Key does not exist, returns null assertEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); @@ -189,19 +189,19 @@ public void testCFDictionary() { assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); Pointer result = CF.CFDictionaryGetValue(dict, oneStr); CFNumberRef numRef = new CFNumberRef(result); - assertEquals(1, CoreFoundationUtil.cfPointerToInt(numRef)); + assertEquals(1, numRef.intValue()); PointerByReference resultPtr = new PointerByReference(); assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, resultPtr)); numRef = new CFNumberRef(resultPtr.getValue()); - assertEquals(1, CoreFoundationUtil.cfPointerToInt(numRef)); + assertEquals(1, numRef.intValue()); // 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)); + assertEquals("one", strRef.stringValue()); oneStr.release(); cfOne.release(); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 2dde087b34..bfe3f8eb22 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -59,11 +59,11 @@ public void testDiskCreate() { long masterPort = masterPortPtr.getValue(); // Create some keys we'll need - CFStringRef daMediaBSDName = CFStringRef.toCFString("DAMediaBSDName"); - CFStringRef daMediaWhole = CFStringRef.toCFString("DAMediaWhole"); - CFStringRef daMediaLeaf = CFStringRef.toCFString("DAMediaLeaf"); - CFStringRef daMediaSize = CFStringRef.toCFString("DAMediaSize"); - CFStringRef daMediaBlockSize = CFStringRef.toCFString("DAMediaBlockSize"); + CFStringRef daMediaBSDName = CFStringRef.createCFString("DAMediaBSDName"); + CFStringRef daMediaWhole = CFStringRef.createCFString("DAMediaWhole"); + CFStringRef daMediaLeaf = CFStringRef.createCFString("DAMediaLeaf"); + CFStringRef daMediaSize = CFStringRef.createCFString("DAMediaSize"); + CFStringRef daMediaBlockSize = CFStringRef.createCFString("DAMediaBlockSize"); // Open a DiskArbitration session DASessionRef session = DA.DASessionCreate(CF.CFAllocatorGetDefault()); @@ -78,12 +78,12 @@ public void testDiskCreate() { assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iter)); long media = IO.IOIteratorNext(iter.getValue()); while (media != 0) { - CFStringRef wholeKey = CFStringRef.toCFString("Whole"); + CFStringRef wholeKey = CFStringRef.createCFString("Whole"); CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); wholeKey.release(); assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); - if (CoreFoundationUtil.cfPointerToBoolean(cfWholeBool)) { + if (cfWholeBool.booleanValue()) { DADiskRef disk = DA.DADiskCreateFromIOMedia(CF.CFAllocatorGetDefault(), session, media); bsdNames.add(DA.DADiskGetBSDName(disk)); disk.release(); @@ -109,22 +109,22 @@ public void testDiskCreate() { // Since we looked up "whole" BSD disks these should match Pointer result = CF.CFDictionaryGetValue(diskInfo, daMediaBSDName); CFStringRef bsdNamePtr = new CFStringRef(result); - assertEquals(bsdName, CoreFoundationUtil.cfPointerToString(bsdNamePtr)); + assertEquals(bsdName, bsdNamePtr.stringValue()); result = CF.CFDictionaryGetValue(diskInfo, daMediaWhole); CFBooleanRef bsdWholePtr = new CFBooleanRef(result); - assertTrue(CoreFoundationUtil.cfPointerToBoolean(bsdWholePtr)); + assertTrue(bsdWholePtr.booleanValue()); result = CF.CFDictionaryGetValue(diskInfo, daMediaLeaf); CFBooleanRef bsdLeafPtr = new CFBooleanRef(result); - assertFalse(CoreFoundationUtil.cfPointerToBoolean(bsdLeafPtr)); + assertFalse(bsdLeafPtr.booleanValue()); // Size is a multiple of block size result = CF.CFDictionaryGetValue(diskInfo, daMediaSize); CFNumberRef sizePtr = new CFNumberRef(result); - long size = CoreFoundationUtil.cfPointerToLong(sizePtr); + long size = sizePtr.longValue(); result = CF.CFDictionaryGetValue(diskInfo, daMediaBlockSize); CFNumberRef blockSizePtr = new CFNumberRef(result); - long blockSize = CoreFoundationUtil.cfPointerToLong(blockSizePtr); + long blockSize = blockSizePtr.longValue(); assertEquals(0, size % blockSize); diskInfo.release(); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 1a9c57d30a..0a548e0250 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -62,40 +62,40 @@ public void testMatching() { String match = "matching BSD Name"; CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); - CFStringRef bsdNameKey = CFStringRef.toCFString("BSD Name"); + CFStringRef bsdNameKey = CFStringRef.createCFString("BSD Name"); Pointer result = CF.CFDictionaryGetValue(dict, bsdNameKey); CFStringRef cfBsdName = new CFStringRef(result); - assertEquals(match, CoreFoundationUtil.cfPointerToString(cfBsdName)); + assertEquals(match, cfBsdName.stringValue()); bsdNameKey.release(); dict.release(); match = "matching IOClass Name"; dict = IO.IOServiceNameMatching(match); - CFStringRef classNameKey = CFStringRef.toCFString("IONameMatch"); + CFStringRef classNameKey = CFStringRef.createCFString("IONameMatch"); result = CF.CFDictionaryGetValue(dict, classNameKey); CFStringRef cfClassName = new CFStringRef(result); - assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClassName)); + assertEquals(match, cfClassName.stringValue()); classNameKey.release(); dict.release(); match = "IOPlatformExpertDevice"; dict = IO.IOServiceMatching(match); - CFStringRef classKey = CFStringRef.toCFString("IOProviderClass"); + CFStringRef classKey = CFStringRef.createCFString("IOProviderClass"); result = CF.CFDictionaryGetValue(dict, classKey); CFStringRef cfClass = new CFStringRef(result); - assertEquals(match, CoreFoundationUtil.cfPointerToString(cfClass)); + assertEquals(match, cfClass.stringValue()); classKey.release(); // Get matching service (consumes dict reference) long platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); assertNotEquals(0, platformExpert); // Get a single key - CFStringRef serialKey = CFStringRef.toCFString("IOPlatformSerialNumber"); + CFStringRef serialKey = CFStringRef.createCFString("IOPlatformSerialNumber"); CFTypeRef cfSerialAsType = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, CF.CFAllocatorGetDefault(), 0); assertNotNull(cfSerialAsType); CFStringRef cfSerial = new CFStringRef(cfSerialAsType.getPointer()); - String serialNumber = CoreFoundationUtil.cfPointerToString(cfSerial); + String serialNumber = cfSerial.stringValue(); cfSerialAsType.release(); assertEquals(12, serialNumber.length()); @@ -108,7 +108,7 @@ public void testMatching() { assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); result = CF.CFDictionaryGetValue(dict, serialKey); cfSerial = new CFStringRef(result); - assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); + assertEquals(serialNumber, cfSerial.stringValue()); dict.release(); assertEquals(0, IO.IOObjectRelease(platformExpert)); @@ -123,7 +123,7 @@ public void testMatching() { IOKit.kIORegistryIterateRecursively); // with recursive search should return a match cfSerial = new CFStringRef(cfSerialAsType.getPointer()); - assertEquals(serialNumber, CoreFoundationUtil.cfPointerToString(cfSerial)); + assertEquals(serialNumber, cfSerial.stringValue()); serialKey.release(); cfSerialAsType.release(); @@ -238,9 +238,9 @@ public void testPowerSources() { assertTrue(timeRemaining > 0 || timeRemaining == IOKit.kIOPSTimeRemainingUnknown || timeRemaining == IOKit.kIOPSTimeRemainingUnlimited); - CFStringRef isPresentKey = CFStringRef.toCFString("Is Present"); - CFStringRef currentCapacityKey = CFStringRef.toCFString("Current Capacity"); - CFStringRef maxCapacityKey = CFStringRef.toCFString("Max Capacity"); + CFStringRef isPresentKey = CFStringRef.createCFString("Is Present"); + CFStringRef currentCapacityKey = CFStringRef.createCFString("Current Capacity"); + CFStringRef maxCapacityKey = CFStringRef.createCFString("Max Capacity"); int powerSourcesCount = CF.CFArrayGetCount(powerSourcesList); for (int ps = 0; ps < powerSourcesCount; ps++) { // Get the dictionary for that Power Source @@ -252,16 +252,16 @@ public void testPowerSources() { PointerByReference result = new PointerByReference(); if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, isPresentKey, result)) { CFBooleanRef isPresentRef = new CFBooleanRef(result.getValue()); - if (CoreFoundationUtil.cfPointerToBoolean(isPresentRef)) { + if (isPresentRef.booleanValue()) { int currentCapacity = 0; if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); - currentCapacity = CoreFoundationUtil.cfPointerToInt(cap); + currentCapacity = cap.intValue(); } int maxCapacity = 100; if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); - maxCapacity = CoreFoundationUtil.cfPointerToInt(cap); + maxCapacity = cap.intValue(); } assertTrue(currentCapacity <= maxCapacity); } From bd5928387d79e199672660607acc1e6a65c31619 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sat, 7 Sep 2019 13:10:07 -0700 Subject: [PATCH 09/28] CoreFoundation type fixes --- .../sun/jna/platform/mac/CoreFoundation.java | 14 ++++---- .../jna/platform/mac/CoreFoundationTest.java | 35 ++++++++++++------- .../com/sun/jna/platform/mac/IOKitTest.java | 6 ++-- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index 6a42bb91b7..a2ad1e7a4b 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -367,7 +367,7 @@ public String stringValue() { * a {@link #CFArrayRef} object. * @return The number of values in {@code array}. */ - int CFArrayGetCount(CFArrayRef theArray); + long CFArrayGetCount(CFArrayRef theArray); /** * Creates a string from a buffer of Unicode characters. @@ -413,7 +413,7 @@ public String stringValue() { * A pointer to the value for the returned number object. * @return A new number with the value specified by {@code valuePtr}. */ - CFNumberRef CFNumberCreate(CFAllocatorRef alloc, long theType, PointerType valuePtr); + CFNumberRef CFNumberCreate(CFAllocatorRef alloc, long theType, ByReference valuePtr); /** * Creates a new immutable array with the given values. @@ -517,7 +517,7 @@ public String stringValue() { * @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, long capacity, Pointer keyCallBacks, Pointer valueCallBacks); /** @@ -597,7 +597,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * {@link #CFDictionaryGetValueIfPresent} to distinguish between a value * that is not found, and a {@code null} value. */ - Pointer CFDictionaryGetValue(CFTypeRef theDict, PointerType key); + Pointer CFDictionaryGetValue(CFDictionaryRef theDict, PointerType key); /** * Returns a boolean value that indicates whether a given value for a given key @@ -674,7 +674,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * @return 1 upon success or 0 if the conversion fails or the provided buffer is * too small. */ - byte CFStringGetCString(CFTypeRef theString, Pointer bufferToFill, long bufferSize, int encoding); + byte CFStringGetCString(CFStringRef theString, Pointer bufferToFill, long bufferSize, int encoding); /** * Returns the value of a {@code CFBoolean} object. @@ -683,7 +683,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * The boolean to examine. * @return 1 if the value of {@code bool} is {@code true}, 0 otherwise. */ - byte CFBooleanGetValue(CFTypeRef bool); + byte CFBooleanGetValue(CFBooleanRef bool); /** * Retrieves a value at a given index. @@ -696,7 +696,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, int capac * the count of {@code theArray})), the behavior is undefined. * @return The value at the {@code idx} index in {@code theArray}). */ - CFTypeRef CFArrayGetValueAtIndex(CFArrayRef theArray, int idx); + Pointer CFArrayGetValueAtIndex(CFArrayRef theArray, long idx); /** * Returns the type used by a {@code CFNumber} object to store its value. diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index b78e719d04..36bd4836a9 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -24,6 +24,7 @@ */ package com.sun.jna.platform.mac; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; @@ -31,6 +32,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Random; import org.junit.Test; @@ -138,8 +140,8 @@ public void testCFArray() { assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray)); for (int i = 0; i < refArray.length; i++) { - CFTypeRef result = CF.CFArrayGetValueAtIndex(cfPtrArray, i); - CFNumberRef numRef = new CFNumberRef(result.getPointer()); + Pointer result = CF.CFArrayGetValueAtIndex(cfPtrArray, i); + CFNumberRef numRef = new CFNumberRef(result); assertEquals(i, numRef.intValue()); } @@ -151,17 +153,24 @@ public void testCFArray() { @Test public void testCFData() { - String deadBug = "The only good bug is a dead bug."; - Memory bugBytes = new Memory(deadBug.length() + 1); - bugBytes.clear(); - bugBytes.setString(0, deadBug); - - CFDataRef cfBug = CF.CFDataCreate(null, bugBytes, bugBytes.size()); - assertEquals(bugBytes.size(), CF.CFDataGetLength(cfBug)); - - Pointer bytes = CF.CFDataGetBytePtr(cfBug); - assertEquals(deadBug, bytes.getString(0)); - cfBug.release(); + int size = 128; + // Create some random bytes + byte[] randomBytes = new byte[size]; + new Random().nextBytes(randomBytes); + // Fill native memory with them + Memory nativeBytes = new Memory(size); + for (int i = 0; i < size; i++) { + nativeBytes.setByte(i, randomBytes[i]); + } + // Create a CF reference to the data + CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, size); + long dataSize = CF.CFDataGetLength(cfData); + assertEquals(size, dataSize); + // Read it back out and convert to an array + Pointer bytes = CF.CFDataGetBytePtr(cfData); + byte[] dataBytes = bytes.getByteArray(0, (int) dataSize); + assertArrayEquals(randomBytes, dataBytes); + cfData.release(); } @Test diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 0a548e0250..b0ebf46712 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -241,10 +241,12 @@ public void testPowerSources() { CFStringRef isPresentKey = CFStringRef.createCFString("Is Present"); CFStringRef currentCapacityKey = CFStringRef.createCFString("Current Capacity"); CFStringRef maxCapacityKey = CFStringRef.createCFString("Max Capacity"); - int powerSourcesCount = CF.CFArrayGetCount(powerSourcesList); + long powerSourcesCount = CF.CFArrayGetCount(powerSourcesList); for (int ps = 0; ps < powerSourcesCount; ps++) { // Get the dictionary for that Power Source - CFTypeRef powerSource = CoreFoundation.INSTANCE.CFArrayGetValueAtIndex(powerSourcesList, ps); + Pointer pwrSrcPtr = CoreFoundation.INSTANCE.CFArrayGetValueAtIndex(powerSourcesList, ps); + CFTypeRef powerSource = new CFTypeRef(); + powerSource.setPointer(pwrSrcPtr); CFDictionaryRef dictionary = IOKit.INSTANCE.IOPSGetPowerSourceDescription(powerSourcesInfo, powerSource); // Get values from dictionary (See IOPSKeys.h) From a216ab5f5e9a4b479309ee5dee6f1f6223c2de06 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sun, 8 Sep 2019 01:56:27 -0700 Subject: [PATCH 10/28] IOKit Object classes --- .../sun/jna/platform/mac/DiskArbitration.java | 5 +- .../src/com/sun/jna/platform/mac/IOKit.java | 152 +++++++++++++++--- .../jna/platform/mac/DiskArbitrationTest.java | 31 ++-- .../com/sun/jna/platform/mac/IOKitTest.java | 97 ++++++----- 4 files changed, 203 insertions(+), 82 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java b/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java index 9c34d4fc32..fdc7a34838 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java @@ -29,6 +29,7 @@ import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.platform.mac.IOKit.IOObject; /** * Disk Arbitration is a low-level framework based on Core Foundation. The Disk @@ -96,7 +97,7 @@ class DADiskRef extends CFTypeRef { * The I/O Kit media object. * @return A reference to a new {@code DADisk}. */ - DADiskRef DADiskCreateFromIOMedia(CFAllocatorRef allocator, DASessionRef session, long media); + DADiskRef DADiskCreateFromIOMedia(CFAllocatorRef allocator, DASessionRef session, IOObject media); /** * Obtains the Disk Arbitration description of the specified disk. This function @@ -124,4 +125,4 @@ class DADiskRef extends CFTypeRef { * @return The disk's BSD device name. */ String DADiskGetBSDName(DADiskRef disk); -} \ No newline at end of file +} diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 47884b926d..b0fc23fb81 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -27,6 +27,7 @@ import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Pointer; +import com.sun.jna.PointerType; import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; @@ -43,25 +44,120 @@ */ public interface IOKit extends Library { + IOKit INSTANCE = Native.load("IOKit", IOKit.class); + int kIORegistryIterateRecursively = 0x00000001; int kIORegistryIterateParents = 0x00000002; double kIOPSTimeRemainingUnlimited = -2.0; double kIOPSTimeRemainingUnknown = -1.0; - IOKit INSTANCE = Native.load("IOKit", IOKit.class); + MachPort MACH_PORT_NULL = new MachPort(); + + /** + * IOKitLib implements non-kernel task access to common IOKit object types - + * IORegistryEntry, IOService, IOIterator etc. These functions are generic - + * families may provide API that is more specific. + *

+ * IOKitLib represents IOKit objects outside the kernel with the types + * io_object_t, io_registry_entry_t, io_service_t, & io_connect_t. Function + * names usually begin with the type of object they are compatible with - e.g., + * IOObjectRelease can be used with any io_object_t. Inside the kernel, the c++ + * class hierarchy allows the subclasses of each object type to receive the same + * requests from user level clients, for example in the kernel, IOService is a + * subclass of IORegistryEntry, which means any of the IORegistryEntryXXX + * functions in IOKitLib may be used with io_service_t's as well as + * io_registry_t's. There are functions available to introspect the class of the + * kernel object which any io_object_t et al. represents. IOKit objects returned + * by all functions should be released with IOObjectRelease. + */ + class IOObject extends PointerType { + public IOObject() { + super(); + } + + public IOObject(Pointer p) { + super(p); + } + } + + /** + * An IOKit iterator handle. + */ + class IOIterator extends IOObject { + public IOIterator() { + super(); + } + + public IOIterator(Pointer p) { + super(p); + } + } + + /** + * The base class for most I/O Kit families, devices, and drivers. + */ + class IOService extends IOObject { + } + + /** + * The base class for all objects in the registry. + */ + class IORegistryEntry extends IOObject { + public IORegistryEntry() { + super(); + } + + public IORegistryEntry(Pointer p) { + super(p); + } + } + + /** + * For an application to communicate with a device, the first thing it must do + * is create a connection between itself and the in-kernel object representing + * the device. To do this, it creates a user client object. + */ + class IOConnect extends IOObject { + public IOConnect() { + super(); + } + + public IOConnect(Pointer p) { + super(p); + } + } + + /** + * Communication between tasks is an important element of the Mach philosophy. + * Mach supports a client/server system structure in which tasks (clients) + * access services by making requests of other tasks (servers) via messages sent + * over a communication channel. + *

+ * The endpoints of these communication channels in Mach are called ports, while + * port rights denote permission to use the channel. + */ + class MachPort extends IOObject { + public MachPort() { + super(); + } + + public MachPort(Pointer p) { + super(p); + } + } /** * Returns the mach port used to initiate communication with IOKit. * * @param bootstrapPort - * Pass 0 for the default. + * Pass {@link #MACH_PORT_NULL} for the default. * @param masterPort - * The master port is returned, and should be released by the caller - * when finished. + * A pointer to the master port is returned, and should be released + * by the caller when finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOMasterPort(long bootstrapPort, LongByReference masterPort); + int IOMasterPort(MachPort bootstrapPort, PointerByReference masterPort); /** * Create a matching dictionary that specifies an {@code IOService} class match. @@ -112,7 +208,7 @@ public interface IOKit extends Library { * otherwise it should be released with {@link CoreFoundation#CFRelease} * by the caller. */ - CFMutableDictionaryRef IOBSDNameMatching(long masterPort, int options, String bsdName); + CFMutableDictionaryRef IOBSDNameMatching(MachPort masterPort, int options, String bsdName); /** * Look up a registered IOService object that matches a matching dictionary. @@ -129,7 +225,7 @@ public interface IOKit extends Library { *

* The service must be released by the caller. */ - long IOServiceGetMatchingService(long masterPort, CFMutableDictionaryRef matchingDictionary); + IOService IOServiceGetMatchingService(MachPort masterPort, CFMutableDictionaryRef matchingDictionary); /** * Look up registered IOService objects that match a matching dictionary. @@ -147,8 +243,8 @@ public interface IOKit extends Library { * by the caller when the iteration is finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOServiceGetMatchingServices(long masterPort, CFMutableDictionaryRef matchingDictionary, - LongByReference existing); + int IOServiceGetMatchingServices(MachPort masterPort, CFMutableDictionaryRef matchingDictionary, + PointerByReference existing); /** * Returns the next object in an iteration. @@ -159,13 +255,13 @@ int IOServiceGetMatchingServices(long masterPort, CFMutableDictionaryRef matchin * returned, otherwise zero is returned. The element should be released * by the caller when it is finished. */ - long IOIteratorNext(long iterator); + IOObject IOIteratorNext(IOIterator iterator); /** * Create a CF representation of a registry entry's property. * * @param entry - * TThe registry entry handle whose property to copy. + * The registry entry handle whose property to copy. * @param key * A {@code CFString} specifying the property name. * @param allocator @@ -176,7 +272,8 @@ int IOServiceGetMatchingServices(long masterPort, CFMutableDictionaryRef matchin *

* The caller should release with {@link CoreFoundation#CFRelease}. */ - CFTypeRef IORegistryEntryCreateCFProperty(long entry, CFStringRef key, CFAllocatorRef allocator, int options); + CFTypeRef IORegistryEntryCreateCFProperty(IORegistryEntry entry, CFStringRef key, CFAllocatorRef allocator, + int options); /** * Create a CF dictionary representation of a registry entry's property table. @@ -192,7 +289,8 @@ int IOServiceGetMatchingServices(long masterPort, CFMutableDictionaryRef matchin * No options are currently defined. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IORegistryEntryCreateCFProperties(long entry, PointerByReference properties, CFAllocatorRef allocator, + int IORegistryEntryCreateCFProperties(IORegistryEntry entry, PointerByReference properties, + CFAllocatorRef allocator, int options); /** @@ -217,7 +315,8 @@ int IORegistryEntryCreateCFProperties(long entry, PointerByReference properties, * @return A CF container is created and returned the caller on success. The * caller should release with CFRelease. */ - CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef key, CFAllocatorRef allocator, + CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, CFStringRef key, + CFAllocatorRef allocator, int options); /** @@ -229,7 +328,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * The resulting ID. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IORegistryEntryGetRegistryEntryID(long entry, LongByReference id); + int IORegistryEntryGetRegistryEntryID(IORegistryEntry entry, LongByReference id); /** * Returns a name assigned to a registry entry. @@ -237,10 +336,11 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * @param entry * The registry entry handle whose name to look up. * @param name - * The caller's buffer to receive the name. + * The caller's buffer to receive the name. This must be a 128-byte + * buffer. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IORegistryEntryGetName(long entry, Pointer name); + int IORegistryEntryGetName(IORegistryEntry entry, Pointer name); /** * Returns an iterator over a registry entry’s child entries in a plane. @@ -255,7 +355,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * The iterator must be released when the iteration is finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IORegistryEntryGetChildIterator(long entry, String plane, LongByReference iter); + int IORegistryEntryGetChildIterator(IORegistryEntry entry, String plane, PointerByReference iter); /** * Returns the first child of a registry entry in a plane. @@ -270,7 +370,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * be released by the caller. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IORegistryEntryGetChildEntry(long entry, String plane, LongByReference child); + int IORegistryEntryGetChildEntry(IORegistryEntry entry, String plane, PointerByReference child); /** * Returns the first parent of a registry entry in a plane. @@ -285,7 +385,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * must be released by the caller. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IORegistryEntryGetParentEntry(long entry, String plane, LongByReference parent); + int IORegistryEntryGetParentEntry(IORegistryEntry entry, String plane, PointerByReference parent); /** * Return a handle to the registry root. @@ -295,7 +395,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * @return A handle to the IORegistryEntry root instance, to be released with * {@link #IOObjectRelease} by the caller, or 0 on failure. */ - long IORegistryGetRootEntry(long masterPort); + IORegistryEntry IORegistryGetRootEntry(MachPort masterPort); /** * Performs an OSDynamicCast operation on an IOKit object. @@ -307,7 +407,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * @return If the object handle is valid, and represents an object in the kernel * that dynamic casts to the class true is returned, otherwise false. */ - boolean IOObjectConformsTo(long object, String className); + boolean IOObjectConformsTo(IOObject object, String className); /** * Releases an object handle previously returned by {@code IOKitLib}. @@ -316,7 +416,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * The IOKit object to release. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOObjectRelease(long object); + int IOObjectRelease(IOObject object); /** * A request to create a connection to an IOService. @@ -335,7 +435,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * {@link IOServiceClose}. * @return A return code generated by {@code IOService::newUserClient}. */ - int IOServiceOpen(long service, long owningTask, int type, LongByReference connect); + int IOServiceOpen(IOService service, MachPort owningTask, int type, PointerByReference connect); /** * Returns the busyState of an IOService. @@ -346,7 +446,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * The busyState count is returned. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOServiceGetBusyState(long service, IntByReference busyState); + int IOServiceGetBusyState(IOService service, IntByReference busyState); /** * Close a connection to an IOService and destroy the connect handle. @@ -356,7 +456,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(long entry, String plane, CFStringRef * by this function, and should not be released with IOObjectRelease. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOServiceClose(long connect); + int IOServiceClose(IOConnect connect); /** * Returns a blob of Power Source information in an opaque CFTypeRef. diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index bfe3f8eb22..30b8214661 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -25,7 +25,6 @@ package com.sun.jna.platform.mac; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -44,7 +43,11 @@ import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.platform.mac.DiskArbitration.DADiskRef; import com.sun.jna.platform.mac.DiskArbitration.DASessionRef; -import com.sun.jna.ptr.LongByReference; +import com.sun.jna.platform.mac.IOKit.IOIterator; +import com.sun.jna.platform.mac.IOKit.IOObject; +import com.sun.jna.platform.mac.IOKit.IORegistryEntry; +import com.sun.jna.platform.mac.IOKit.MachPort; +import com.sun.jna.ptr.PointerByReference; public class DiskArbitrationTest { @@ -54,9 +57,9 @@ public class DiskArbitrationTest { @Test public void testDiskCreate() { - LongByReference masterPortPtr = new LongByReference(); - assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); - long masterPort = masterPortPtr.getValue(); + PointerByReference masterPortPtr = new PointerByReference(); + assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); + MachPort masterPort = new MachPort(masterPortPtr.getValue()); // Create some keys we'll need CFStringRef daMediaBSDName = CFStringRef.createCFString("DAMediaBSDName"); @@ -71,13 +74,15 @@ public void testDiskCreate() { // Get IOMedia objects representing whole drives and save the BSD Name List bsdNames = new ArrayList<>(); - LongByReference iter = new LongByReference(); + PointerByReference iterPtr = new PointerByReference(); CFMutableDictionaryRef dict = IOKit.INSTANCE.IOServiceMatching("IOMedia"); // Consumes a reference to dict - assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iter)); - long media = IO.IOIteratorNext(iter.getValue()); - while (media != 0) { + assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); + IOIterator iter = new IOIterator(iterPtr.getValue()); + IOObject mediaObj = IO.IOIteratorNext(iter); + while (mediaObj != null) { + IORegistryEntry media = new IORegistryEntry(mediaObj.getPointer()); CFStringRef wholeKey = CFStringRef.createCFString("Whole"); CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); wholeKey.release(); @@ -90,9 +95,9 @@ public void testDiskCreate() { } cfWhole.release(); IO.IOObjectRelease(media); - media = IO.IOIteratorNext(iter.getValue()); + mediaObj = IO.IOIteratorNext(iter); } - IO.IOObjectRelease(iter.getValue()); + IO.IOObjectRelease(iter); // Now iterate the bsdNames for (String bsdName : bsdNames) { @@ -114,10 +119,6 @@ public void testDiskCreate() { CFBooleanRef bsdWholePtr = new CFBooleanRef(result); assertTrue(bsdWholePtr.booleanValue()); - result = CF.CFDictionaryGetValue(diskInfo, daMediaLeaf); - CFBooleanRef bsdLeafPtr = new CFBooleanRef(result); - assertFalse(bsdLeafPtr.booleanValue()); - // Size is a multiple of block size result = CF.CFDictionaryGetValue(diskInfo, daMediaSize); CFNumberRef sizePtr = new CFNumberRef(result); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index b0ebf46712..1ee5c2b369 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -45,6 +45,12 @@ import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.platform.mac.IOKit.IOConnect; +import com.sun.jna.platform.mac.IOKit.IOIterator; +import com.sun.jna.platform.mac.IOKit.IOObject; +import com.sun.jna.platform.mac.IOKit.IORegistryEntry; +import com.sun.jna.platform.mac.IOKit.IOService; +import com.sun.jna.platform.mac.IOKit.MachPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; @@ -56,9 +62,9 @@ public class IOKitTest { @Test public void testMatching() { - LongByReference masterPortPtr = new LongByReference(); - assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); - long masterPort = masterPortPtr.getValue(); + PointerByReference masterPortPtr = new PointerByReference(); + assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); + MachPort masterPort = new MachPort(masterPortPtr.getValue()); String match = "matching BSD Name"; CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); @@ -87,8 +93,9 @@ public void testMatching() { classKey.release(); // Get matching service (consumes dict reference) - long platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); - assertNotEquals(0, platformExpert); + IOService platformExpertSvc = IO.IOServiceGetMatchingService(masterPort, dict); + assertNotNull(platformExpertSvc.getPointer()); + IORegistryEntry platformExpert = new IORegistryEntry(platformExpertSvc.getPointer()); // Get a single key CFStringRef serialKey = CFStringRef.createCFString("IOPlatformSerialNumber"); CFTypeRef cfSerialAsType = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, @@ -113,7 +120,7 @@ public void testMatching() { assertEquals(0, IO.IOObjectRelease(platformExpert)); // Get a single key from a nested entry - long root = IO.IORegistryGetRootEntry(masterPort); + IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); assertNotEquals(0, root); cfSerialAsType = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), 0); @@ -133,20 +140,22 @@ public void testMatching() { @Test public void testIteratorParentChild() { - LongByReference masterPortPtr = new LongByReference(); - assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); - long masterPort = masterPortPtr.getValue(); + PointerByReference masterPortPtr = new PointerByReference(); + assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); + MachPort masterPort = new MachPort(masterPortPtr.getValue()); Set uniqueEntryIdSet = new HashSet<>(); // Create matching dictionary for USB Controller class CFMutableDictionaryRef dict = IO.IOServiceMatching("IOUSBController"); // Iterate over USB Controllers. All devices are children of one of // these controllers in the "IOService" plane - LongByReference iter = new LongByReference(); - assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iter)); - // iter is a pointer to first device; iterate until 0 - long controllerDevice = IO.IOIteratorNext(iter.getValue()); - while (controllerDevice != 0) { + PointerByReference iterPtr = new PointerByReference(); + assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); + IOIterator iter = new IOIterator(iterPtr.getValue()); + // iter is a pointer to first device; iterate until null + IOObject controllerDeviceObj = IO.IOIteratorNext(iter); + while (controllerDeviceObj != null) { + IORegistryEntry controllerDevice = new IORegistryEntry(controllerDeviceObj.getPointer()); LongByReference id = new LongByReference(); IO.IORegistryEntryGetRegistryEntryID(controllerDevice, id); // EntryIDs 0 thru 19 are reserved, all are unique @@ -162,68 +171,78 @@ public void testIteratorParentChild() { assertEquals("AppleUSB", buffer.getString(0).substring(0, 8)); // Get the first child, to test vs. iterator - LongByReference firstChild = new LongByReference(); - boolean testFirstChild = 0 == IO.IORegistryEntryGetChildEntry(controllerDevice, "IOService", firstChild); + PointerByReference firstChildPtr = new PointerByReference(); + boolean testFirstChild = true; + // If this returns 0, we have at least one child entry to test + // If not, the iterator will never check whether to test + IO.IORegistryEntryGetChildEntry(controllerDevice, "IOService", firstChildPtr); // Now iterate the children of this device in the "IOService" plane. - LongByReference childIter = new LongByReference(); - IO.IORegistryEntryGetChildIterator(controllerDevice, "IOService", childIter); - long childDevice = IO.IOIteratorNext(childIter.getValue()); - while (childDevice != 0) { - assertTrue(IO.IOObjectConformsTo(childDevice, "IOUSBDevice")); + PointerByReference childIterPtr = new PointerByReference(); + IO.IORegistryEntryGetChildIterator(controllerDevice, "IOService", childIterPtr); + IOIterator childIter = new IOIterator(childIterPtr.getValue()); + IOObject childDeviceObj = IO.IOIteratorNext(childIter); + while (childDeviceObj != null) { + assertTrue(IO.IOObjectConformsTo(childDeviceObj, "IOUSBDevice")); + IORegistryEntry childDevice = new IORegistryEntry(childDeviceObj.getPointer()); LongByReference childId = new LongByReference(); IO.IORegistryEntryGetRegistryEntryID(childDevice, childId); assertTrue(childId.getValue() > 19); assertFalse(uniqueEntryIdSet.contains(childId.getValue())); uniqueEntryIdSet.add(childId.getValue()); - // If first child, test and release + // If first child, test and release the retained first child pointer if (testFirstChild) { - assertEquals(childDevice, firstChild.getValue()); - IO.IOObjectRelease(firstChild.getValue()); + IOObject firstChild = new IOObject(firstChildPtr.getValue()); + assertEquals(childDevice, firstChild); + IO.IOObjectRelease(firstChild); testFirstChild = false; } // Get this device's parent in IOService plane, matches controller - LongByReference parent = new LongByReference(); - IO.IORegistryEntryGetParentEntry(childDevice, "IOService", parent); - assertEquals(controllerDevice, parent.getValue()); - IO.IOObjectRelease(parent.getValue()); + PointerByReference parentPtr = new PointerByReference(); + IO.IORegistryEntryGetParentEntry(childDevice, "IOService", parentPtr); + IORegistryEntry parent = new IORegistryEntry(parentPtr.getValue()); + assertEquals(controllerDevice, parent); + IO.IOObjectRelease(parent); // Release this device and iterate to the next one IO.IOObjectRelease(childDevice); - childDevice = IO.IOIteratorNext(childIter.getValue()); + childDeviceObj = IO.IOIteratorNext(childIter); } - IO.IOObjectRelease(childIter.getValue()); + IO.IOObjectRelease(childIter); // Release this controller and iterate to the next one assertEquals(0, IO.IOObjectRelease(controllerDevice)); - controllerDevice = IO.IOIteratorNext(iter.getValue()); + controllerDeviceObj = IO.IOIteratorNext(iter); } - assertEquals(0, IO.IOObjectRelease(iter.getValue())); + assertEquals(0, IO.IOObjectRelease(iter)); assertEquals(0, IO.IOObjectRelease(masterPort)); } @Test public void testIOConnect() { - LongByReference masterPortPtr = new LongByReference(); - assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); - long masterPort = masterPortPtr.getValue(); + PointerByReference masterPortPtr = new PointerByReference(); + assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); + MachPort masterPort = new MachPort(masterPortPtr.getValue()); // Open a connection to SMC CFMutableDictionaryRef dict = IO.IOServiceMatching("AppleSMC"); // consumes dict references - long smcService = IO.IOServiceGetMatchingService(masterPort, dict); + IOService smcService = IO.IOServiceGetMatchingService(masterPort, dict); assertNotEquals(0, smcService); - LongByReference conn = new LongByReference(); - assertEquals(0, IO.IOServiceOpen(smcService, SystemB.INSTANCE.mach_task_self(), 0, conn)); + PointerByReference connPtr = new PointerByReference(); + // Uh oh... + MachPort taskSelf = new MachPort(Pointer.createConstant(SystemB.INSTANCE.mach_task_self())); + assertEquals(0, IO.IOServiceOpen(smcService, taskSelf, 0, connPtr)); + IOConnect conn = new IOConnect(connPtr.getValue()); IntByReference busy = new IntByReference(Integer.MIN_VALUE); IO.IOServiceGetBusyState(smcService, busy); assertTrue(busy.getValue() >= 0); - IO.IOServiceClose(conn.getValue()); + IO.IOServiceClose(conn); IO.IOObjectRelease(smcService); assertEquals(0, IO.IOObjectRelease(masterPort)); } From b478d79487c57a227c33cda0b4c548472a5d22a3 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sun, 8 Sep 2019 10:59:44 -0700 Subject: [PATCH 11/28] Convenience methods for IOObject#release and IOIterator#next --- .../sun/jna/platform/mac/CoreFoundation.java | 6 ++-- .../src/com/sun/jna/platform/mac/IOKit.java | 22 ++++++++++++- .../jna/platform/mac/DiskArbitrationTest.java | 10 +++--- .../com/sun/jna/platform/mac/IOKitTest.java | 32 +++++++++---------- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index a2ad1e7a4b..334ed19a56 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -364,7 +364,7 @@ public String stringValue() { * Returns the number of values currently in an array. * * @param theArray - * a {@link #CFArrayRef} object. + * a {@link CFArrayRef} object. * @return The number of values in {@code array}. */ long CFArrayGetCount(CFArrayRef theArray); @@ -716,8 +716,8 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * @param theType * A constant that specifies the data type to return. See * {@link CFNumberType} for a list of possible values. - * @param On - * return, contains the value of {@code number}. + * @param valuePtr + * On return, contains the value of {@code number}. * @return 1 if the operation was successful, otherwise 0. */ byte CFNumberGetValue(CFNumberRef number, long theType, ByReference valuePtr); diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index b0fc23fb81..18cb076cf0 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -60,7 +60,7 @@ public interface IOKit extends Library { * families may provide API that is more specific. *

* IOKitLib represents IOKit objects outside the kernel with the types - * io_object_t, io_registry_entry_t, io_service_t, & io_connect_t. Function + * io_object_t, io_registry_entry_t, io_service_t, and io_connect_t. Function * names usually begin with the type of object they are compatible with - e.g., * IOObjectRelease can be used with any io_object_t. Inside the kernel, the c++ * class hierarchy allows the subclasses of each object type to receive the same @@ -79,6 +79,15 @@ public IOObject() { public IOObject(Pointer p) { super(p); } + + /** + * Convenience method for {@link IOKit#IOObjectRelease} on this object. + * + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int release() { + return INSTANCE.IOObjectRelease(this); + } } /** @@ -92,6 +101,17 @@ public IOIterator() { public IOIterator(Pointer p) { super(p); } + + /** + * Convenience method for {@link IOKit#IOIteratorNext} on this object. + * + * @return If the iterator handle is valid, the next element in the iteration is + * returned, otherwise zero is returned. The element should be released + * by the caller when it is finished. + */ + public IOObject next() { + return INSTANCE.IOIteratorNext(this); + } } /** diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 30b8214661..d3b14aaa55 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -80,7 +80,7 @@ public void testDiskCreate() { // Consumes a reference to dict assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); IOIterator iter = new IOIterator(iterPtr.getValue()); - IOObject mediaObj = IO.IOIteratorNext(iter); + IOObject mediaObj = iter.next(); while (mediaObj != null) { IORegistryEntry media = new IORegistryEntry(mediaObj.getPointer()); CFStringRef wholeKey = CFStringRef.createCFString("Whole"); @@ -94,10 +94,10 @@ public void testDiskCreate() { disk.release(); } cfWhole.release(); - IO.IOObjectRelease(media); - mediaObj = IO.IOIteratorNext(iter); + assertEquals(0, media.release()); + mediaObj = iter.next(); } - IO.IOObjectRelease(iter); + assertEquals(0, iter.release()); // Now iterate the bsdNames for (String bsdName : bsdNames) { @@ -139,6 +139,6 @@ public void testDiskCreate() { session.release(); - assertEquals(0, IO.IOObjectRelease(masterPort)); + assertEquals(0, masterPort.release()); } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 1ee5c2b369..41b1e73b90 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -117,7 +117,7 @@ public void testMatching() { cfSerial = new CFStringRef(result); assertEquals(serialNumber, cfSerial.stringValue()); dict.release(); - assertEquals(0, IO.IOObjectRelease(platformExpert)); + assertEquals(0, platformExpert.release()); // Get a single key from a nested entry IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); @@ -134,8 +134,8 @@ public void testMatching() { serialKey.release(); cfSerialAsType.release(); - assertEquals(0, IO.IOObjectRelease(root)); - assertEquals(0, IO.IOObjectRelease(masterPort)); + assertEquals(0, root.release()); + assertEquals(0, masterPort.release()); } @Test @@ -153,7 +153,7 @@ public void testIteratorParentChild() { assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); IOIterator iter = new IOIterator(iterPtr.getValue()); // iter is a pointer to first device; iterate until null - IOObject controllerDeviceObj = IO.IOIteratorNext(iter); + IOObject controllerDeviceObj = iter.next(); while (controllerDeviceObj != null) { IORegistryEntry controllerDevice = new IORegistryEntry(controllerDeviceObj.getPointer()); LongByReference id = new LongByReference(); @@ -181,7 +181,7 @@ public void testIteratorParentChild() { PointerByReference childIterPtr = new PointerByReference(); IO.IORegistryEntryGetChildIterator(controllerDevice, "IOService", childIterPtr); IOIterator childIter = new IOIterator(childIterPtr.getValue()); - IOObject childDeviceObj = IO.IOIteratorNext(childIter); + IOObject childDeviceObj = childIter.next(); while (childDeviceObj != null) { assertTrue(IO.IOObjectConformsTo(childDeviceObj, "IOUSBDevice")); @@ -196,7 +196,7 @@ public void testIteratorParentChild() { if (testFirstChild) { IOObject firstChild = new IOObject(firstChildPtr.getValue()); assertEquals(childDevice, firstChild); - IO.IOObjectRelease(firstChild); + assertEquals(0, firstChild.release()); testFirstChild = false; } @@ -205,20 +205,20 @@ public void testIteratorParentChild() { IO.IORegistryEntryGetParentEntry(childDevice, "IOService", parentPtr); IORegistryEntry parent = new IORegistryEntry(parentPtr.getValue()); assertEquals(controllerDevice, parent); - IO.IOObjectRelease(parent); + assertEquals(0, parent.release()); // Release this device and iterate to the next one - IO.IOObjectRelease(childDevice); - childDeviceObj = IO.IOIteratorNext(childIter); + assertEquals(0, childDevice.release()); + childDeviceObj = childIter.next(); } - IO.IOObjectRelease(childIter); + assertEquals(0, childIter.release()); // Release this controller and iterate to the next one - assertEquals(0, IO.IOObjectRelease(controllerDevice)); - controllerDeviceObj = IO.IOIteratorNext(iter); + assertEquals(0, controllerDevice.release()); + controllerDeviceObj = iter.next(); } - assertEquals(0, IO.IOObjectRelease(iter)); - assertEquals(0, IO.IOObjectRelease(masterPort)); + assertEquals(0, iter.release()); + assertEquals(0, masterPort.release()); } @Test @@ -243,8 +243,8 @@ public void testIOConnect() { assertTrue(busy.getValue() >= 0); IO.IOServiceClose(conn); - IO.IOObjectRelease(smcService); - assertEquals(0, IO.IOObjectRelease(masterPort)); + assertEquals(0, smcService.release()); + assertEquals(0, masterPort.release()); } @Test From b666a931fa6acb83c05d1fa7d345bf1383f5d8c9 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sun, 8 Sep 2019 20:54:50 -0700 Subject: [PATCH 12/28] MachPort does not extend IOObject and master port does not get released --- .../src/com/sun/jna/platform/mac/IOKit.java | 43 +++++++++---------- .../jna/platform/mac/DiskArbitrationTest.java | 2 - .../com/sun/jna/platform/mac/IOKitTest.java | 3 -- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 18cb076cf0..1064756cbb 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -54,6 +54,25 @@ public interface IOKit extends Library { MachPort MACH_PORT_NULL = new MachPort(); + /** + * Communication between tasks is an important element of the Mach philosophy. + * Mach supports a client/server system structure in which tasks (clients) + * access services by making requests of other tasks (servers) via messages sent + * over a communication channel. + *

+ * The endpoints of these communication channels in Mach are called ports, while + * port rights denote permission to use the channel. + */ + class MachPort extends PointerType { + public MachPort() { + super(); + } + + public MachPort(Pointer p) { + super(p); + } + } + /** * IOKitLib implements non-kernel task access to common IOKit object types - * IORegistryEntry, IOService, IOIterator etc. These functions are generic - @@ -71,7 +90,7 @@ public interface IOKit extends Library { * kernel object which any io_object_t et al. represents. IOKit objects returned * by all functions should be released with IOObjectRelease. */ - class IOObject extends PointerType { + class IOObject extends MachPort { public IOObject() { super(); } @@ -148,33 +167,13 @@ public IOConnect(Pointer p) { } } - /** - * Communication between tasks is an important element of the Mach philosophy. - * Mach supports a client/server system structure in which tasks (clients) - * access services by making requests of other tasks (servers) via messages sent - * over a communication channel. - *

- * The endpoints of these communication channels in Mach are called ports, while - * port rights denote permission to use the channel. - */ - class MachPort extends IOObject { - public MachPort() { - super(); - } - - public MachPort(Pointer p) { - super(p); - } - } - /** * Returns the mach port used to initiate communication with IOKit. * * @param bootstrapPort * Pass {@link #MACH_PORT_NULL} for the default. * @param masterPort - * A pointer to the master port is returned, and should be released - * by the caller when finished. + * A pointer to the master port is returned. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ int IOMasterPort(MachPort bootstrapPort, PointerByReference masterPort); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index d3b14aaa55..5d7b5bd300 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -138,7 +138,5 @@ public void testDiskCreate() { daMediaBlockSize.release(); session.release(); - - assertEquals(0, masterPort.release()); } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 41b1e73b90..f9a193a6a3 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -135,7 +135,6 @@ public void testMatching() { cfSerialAsType.release(); assertEquals(0, root.release()); - assertEquals(0, masterPort.release()); } @Test @@ -218,7 +217,6 @@ public void testIteratorParentChild() { controllerDeviceObj = iter.next(); } assertEquals(0, iter.release()); - assertEquals(0, masterPort.release()); } @Test @@ -244,7 +242,6 @@ public void testIOConnect() { IO.IOServiceClose(conn); assertEquals(0, smcService.release()); - assertEquals(0, masterPort.release()); } @Test From 0db5ae2679d4afb2601b6d947d81cd35adb20a73 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Mon, 9 Sep 2019 21:52:56 -0700 Subject: [PATCH 13/28] Function mapper for properly typed mach ports --- .../src/com/sun/jna/platform/mac/SystemB.java | 456 +++++++++++------- .../platform/mac/SystemBFunctionMapper.java | 50 ++ .../com/sun/jna/platform/mac/IOKitTest.java | 4 +- .../com/sun/jna/platform/mac/SystemBTest.java | 46 +- 4 files changed, 352 insertions(+), 204 deletions(-) create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java index 9fed4bf1e3..ea6523c776 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java @@ -25,24 +25,30 @@ package com.sun.jna.platform.mac; -import java.util.Arrays; -import java.util.List; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.Structure; +import com.sun.jna.platform.mac.IOKit.MachPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; -/** - * Author: Daniel Widdis Date: 6/5/15 - */ public interface SystemB extends Library { - SystemB INSTANCE = Native.load("System", SystemB.class); + Map OPTIONS = Collections.unmodifiableMap(new HashMap() { + private static final long serialVersionUID = 1L; // we're not serializing it + { + put(OPTION_FUNCTION_MAPPER, new SystemBFunctionMapper()); + } + }); + + SystemB INSTANCE = Native.load("System", SystemB.class, OPTIONS); // host_statistics() int HOST_LOAD_INFO = 1;// System loading stats @@ -92,22 +98,20 @@ public interface SystemB extends Library { // resource.h int RUSAGE_INFO_V2 = 2; - @Structure.FieldOrder({"cpu_ticks"}) + @Structure.FieldOrder({ "cpu_ticks" }) public static class HostCpuLoadInfo extends Structure { public int cpu_ticks[] = new int[CPU_STATE_MAX]; } - @Structure.FieldOrder({"avenrun", "mach_factor"}) + @Structure.FieldOrder({ "avenrun", "mach_factor" }) public static class HostLoadInfo extends Structure { public int[] avenrun = new int[3]; // scaled by LOAD_SCALE public int[] mach_factor = new int[3]; // scaled by LOAD_SCALE } - @Structure.FieldOrder({"free_count", "active_count", - "inactive_count", "wire_count", "zero_fill_count", - "reactivations", "pageins", "pageouts", "faults", - "cow_faults", "lookups", "hits", "purgeable_count", - "purges", "speculative_count"}) + @Structure.FieldOrder({ "free_count", "active_count", "inactive_count", "wire_count", "zero_fill_count", + "reactivations", "pageins", "pageouts", "faults", "cow_faults", "lookups", "hits", "purgeable_count", + "purges", "speculative_count" }) public static class VMStatistics extends Structure { public int free_count; // # of pages free public int active_count; // # of pages active @@ -127,19 +131,11 @@ public static class VMStatistics extends Structure { public int speculative_count; } - @Structure.FieldOrder({"free_count", "active_count", - "inactive_count", "wire_count", - "zero_fill_count", "reactivations", - "pageins", "pageouts", - "faults", "cow_faults", - "lookups", "hits", - "purges", - "purgeable_count", "speculative_count", - "decompressions", "compressions", - "swapins", "swapouts", - "compressor_page_count", "throttled_count", - "external_page_count", "internal_page_count", - "total_uncompressed_pages_in_compressor"}) + @Structure.FieldOrder({ "free_count", "active_count", "inactive_count", "wire_count", "zero_fill_count", + "reactivations", "pageins", "pageouts", "faults", "cow_faults", "lookups", "hits", "purges", + "purgeable_count", "speculative_count", "decompressions", "compressions", "swapins", "swapouts", + "compressor_page_count", "throttled_count", "external_page_count", "internal_page_count", + "total_uncompressed_pages_in_compressor" }) public static class VMStatistics64 extends Structure { public int free_count; // # of pages free public int active_count; // # of pages active @@ -173,16 +169,15 @@ public static class VMStatistics64 extends Structure { public long total_uncompressed_pages_in_compressor; } - @Structure.FieldOrder({"pbsd", "ptinfo"}) + @Structure.FieldOrder({ "pbsd", "ptinfo" }) class ProcTaskAllInfo extends Structure { public ProcBsdInfo pbsd; public ProcTaskInfo ptinfo; } - @Structure.FieldOrder({"pbi_flags", "pbi_status", "pbi_xstatus", "pbi_pid", "pbi_ppid", - "pbi_uid", "pbi_gid", "pbi_ruid", "pbi_rgid", "pbi_svuid", "pbi_svgid", "rfu_1", "pbi_comm", - "pbi_name", "pbi_nfiles", "pbi_pgid", "pbi_pjobc", "e_tdev", "e_tpgid", "pbi_nice", - "pbi_start_tvsec", "pbi_start_tvusec"}) + @Structure.FieldOrder({ "pbi_flags", "pbi_status", "pbi_xstatus", "pbi_pid", "pbi_ppid", "pbi_uid", "pbi_gid", + "pbi_ruid", "pbi_rgid", "pbi_svuid", "pbi_svgid", "rfu_1", "pbi_comm", "pbi_name", "pbi_nfiles", "pbi_pgid", + "pbi_pjobc", "e_tdev", "e_tpgid", "pbi_nice", "pbi_start_tvsec", "pbi_start_tvusec" }) class ProcBsdInfo extends Structure { public int pbi_flags; public int pbi_status; @@ -208,10 +203,10 @@ class ProcBsdInfo extends Structure { public long pbi_start_tvusec; } - @Structure.FieldOrder({"pti_virtual_size", "pti_resident_size", "pti_total_user", - "pti_total_system", "pti_threads_user", "pti_threads_system", "pti_policy", "pti_faults", - "pti_pageins", "pti_cow_faults", "pti_messages_sent", "pti_messages_received", "pti_syscalls_mach", - "pti_syscalls_unix", "pti_csw", "pti_threadnum", "pti_numrunning", "pti_priority"}) + @Structure.FieldOrder({ "pti_virtual_size", "pti_resident_size", "pti_total_user", "pti_total_system", + "pti_threads_user", "pti_threads_system", "pti_policy", "pti_faults", "pti_pageins", "pti_cow_faults", + "pti_messages_sent", "pti_messages_received", "pti_syscalls_mach", "pti_syscalls_unix", "pti_csw", + "pti_threadnum", "pti_numrunning", "pti_priority" }) class ProcTaskInfo extends Structure { public long pti_virtual_size; /* virtual memory size (bytes) */ public long pti_resident_size; /* resident memory size (bytes) */ @@ -233,12 +228,11 @@ class ProcTaskInfo extends Structure { public int pti_priority; /* task priority */ } - @Structure.FieldOrder({"v_swtch", "v_trap", "v_syscall", "v_intr", "v_soft", "v_faults", - "v_lookups", "v_hits", "v_vm_faults", "v_cow_faults", "v_swpin", "v_swpout", "v_pswpin", - "v_pswpout", "v_pageins", "v_pageouts", "v_pgpgin", "v_pgpgout", "v_intrans", "v_reactivated", - "v_rev", "v_scan", "v_dfree", "v_pfree", "v_zfod", "v_nzfod", "v_page_size", "v_kernel_pages", - "v_free_target", "v_free_min", "v_free_count", "v_wire_count", "v_active_count", - "v_inactive_target", "v_inactive_count"}) + @Structure.FieldOrder({ "v_swtch", "v_trap", "v_syscall", "v_intr", "v_soft", "v_faults", "v_lookups", "v_hits", + "v_vm_faults", "v_cow_faults", "v_swpin", "v_swpout", "v_pswpin", "v_pswpout", "v_pageins", "v_pageouts", + "v_pgpgin", "v_pgpgout", "v_intrans", "v_reactivated", "v_rev", "v_scan", "v_dfree", "v_pfree", "v_zfod", + "v_nzfod", "v_page_size", "v_kernel_pages", "v_free_target", "v_free_min", "v_free_count", "v_wire_count", + "v_active_count", "v_inactive_target", "v_inactive_count" }) class VMMeter extends Structure { /* * General system activity. @@ -288,11 +282,11 @@ class VMMeter extends Structure { public int v_inactive_count; /* number of pages inactive */ } - @Structure.FieldOrder({"ri_uuid", "ri_user_time", "ri_system_time", "ri_pkg_idle_wkups", - "ri_interrupt_wkups", "ri_pageins", "ri_wired_size", "ri_resident_size", "ri_phys_footprint", - "ri_proc_start_abstime", "ri_proc_exit_abstime", "ri_child_user_time", "ri_child_system_time", - "ri_child_pkg_idle_wkups", "ri_child_interrupt_wkups", "ri_child_pageins", - "ri_child_elapsed_abstime", "ri_diskio_bytesread", "ri_diskio_byteswritten" }) + @Structure.FieldOrder({ "ri_uuid", "ri_user_time", "ri_system_time", "ri_pkg_idle_wkups", "ri_interrupt_wkups", + "ri_pageins", "ri_wired_size", "ri_resident_size", "ri_phys_footprint", "ri_proc_start_abstime", + "ri_proc_exit_abstime", "ri_child_user_time", "ri_child_system_time", "ri_child_pkg_idle_wkups", + "ri_child_interrupt_wkups", "ri_child_pageins", "ri_child_elapsed_abstime", "ri_diskio_bytesread", + "ri_diskio_byteswritten" }) class RUsageInfoV2 extends Structure { public byte[] ri_uuid = new byte[16]; public long ri_user_time; @@ -315,14 +309,14 @@ class RUsageInfoV2 extends Structure { public long ri_diskio_byteswritten; } - @Structure.FieldOrder({"vip_vi", "vip_path"}) + @Structure.FieldOrder({ "vip_vi", "vip_path" }) class VnodeInfoPath extends Structure { public byte[] vip_vi = new byte[152]; // vnode_info but we don't // need its data public byte[] vip_path = new byte[MAXPATHLEN]; } - @Structure.FieldOrder({"pvi_cdir", "pvi_rdir"}) + @Structure.FieldOrder({ "pvi_cdir", "pvi_rdir" }) class VnodePathInfo extends Structure { public VnodeInfoPath pvi_cdir; public VnodeInfoPath pvi_rdir; @@ -330,12 +324,12 @@ class VnodePathInfo extends Structure { /** * The statfs() routine returns information about a mounted file system. The - * path argument is the path name of any file or directory within the - * mounted file system. The buf argument is a pointer to a statfs structure. + * path argument is the path name of any file or directory within the mounted + * file system. The buf argument is a pointer to a statfs structure. */ - @Structure.FieldOrder({"f_bsize", "f_iosize", "f_blocks", "f_bfree", "f_bavail", "f_files", - "f_ffree", "f_fsid", "f_owner", "f_type", "f_flags", "f_fssubtype", "f_fstypename", "f_mntonname", - "f_mntfromname", "f_reserved" }) + @Structure.FieldOrder({ "f_bsize", "f_iosize", "f_blocks", "f_bfree", "f_bavail", "f_files", "f_ffree", "f_fsid", + "f_owner", "f_type", "f_flags", "f_fssubtype", "f_fstypename", "f_mntonname", "f_mntfromname", + "f_reserved" }) class Statfs extends Structure { public int f_bsize; /* fundamental file system block size */ public int f_iosize; /* optimal transfer block size */ @@ -361,7 +355,7 @@ class Statfs extends Structure { /** * Return type for sysctl vm.swapusage */ - @Structure.FieldOrder({"xsu_total", "xsu_avail", "xsu_used", "xsu_pagesize", "xsu_encrypted"}) + @Structure.FieldOrder({ "xsu_total", "xsu_avail", "xsu_used", "xsu_pagesize", "xsu_encrypted" }) class XswUsage extends Structure { public long xsu_total; public long xsu_avail; @@ -373,12 +367,11 @@ class XswUsage extends Structure { /** * Data type as part of IFmsgHdr */ - @Structure.FieldOrder({"ifi_type", "ifi_typelen", "ifi_physical", "ifi_addrlen", "ifi_hdrlen", - "ifi_recvquota", "ifi_xmitquota", "ifi_unused1", "ifi_mtu", "ifi_metric", "ifi_baudrate", - "ifi_ipackets", "ifi_ierrors", "ifi_opackets", "ifi_oerrors", "ifi_collisions", "ifi_ibytes", - "ifi_obytes", "ifi_imcasts", "ifi_omcasts", "ifi_iqdrops", "ifi_noproto", "ifi_recvtiming", - "ifi_xmittiming", "ifi_lastchange", "ifi_unused2", "ifi_hwassist", "ifi_reserved1", - "ifi_reserved2"}) + @Structure.FieldOrder({ "ifi_type", "ifi_typelen", "ifi_physical", "ifi_addrlen", "ifi_hdrlen", "ifi_recvquota", + "ifi_xmitquota", "ifi_unused1", "ifi_mtu", "ifi_metric", "ifi_baudrate", "ifi_ipackets", "ifi_ierrors", + "ifi_opackets", "ifi_oerrors", "ifi_collisions", "ifi_ibytes", "ifi_obytes", "ifi_imcasts", "ifi_omcasts", + "ifi_iqdrops", "ifi_noproto", "ifi_recvtiming", "ifi_xmittiming", "ifi_lastchange", "ifi_unused2", + "ifi_hwassist", "ifi_reserved1", "ifi_reserved2" }) class IFdata extends Structure { public byte ifi_type; // ethernet, tokenring, etc public byte ifi_typelen; // Length of frame type id @@ -414,8 +407,8 @@ class IFdata extends Structure { /** * Return type for sysctl CTL_NET,PF_ROUTE */ - @Structure.FieldOrder({"ifm_msglen", "ifm_version", "ifm_type", "ifm_addrs", "ifm_flags", - "ifm_index", "ifm_data" }) + @Structure.FieldOrder({ "ifm_msglen", "ifm_version", "ifm_type", "ifm_addrs", "ifm_flags", "ifm_index", + "ifm_data" }) class IFmsgHdr extends Structure { public short ifm_msglen; // to skip over non-understood messages public byte ifm_version; // future binary compatability @@ -437,11 +430,10 @@ public IFmsgHdr(Pointer p) { /** * Data type as part of IFmsgHdr */ - @Structure.FieldOrder({ "ifi_type", "ifi_typelen", "ifi_physical", "ifi_addrlen", "ifi_hdrlen", - "ifi_recvquota", "ifi_xmitquota", "ifi_unused1", "ifi_mtu", "ifi_metric", "ifi_baudrate", - "ifi_ipackets", "ifi_ierrors", "ifi_opackets", "ifi_oerrors", "ifi_collisions", "ifi_ibytes", - "ifi_obytes", "ifi_imcasts", "ifi_omcasts", "ifi_iqdrops", "ifi_noproto", "ifi_recvtiming", - "ifi_xmittiming", "ifi_lastchange"}) + @Structure.FieldOrder({ "ifi_type", "ifi_typelen", "ifi_physical", "ifi_addrlen", "ifi_hdrlen", "ifi_recvquota", + "ifi_xmitquota", "ifi_unused1", "ifi_mtu", "ifi_metric", "ifi_baudrate", "ifi_ipackets", "ifi_ierrors", + "ifi_opackets", "ifi_oerrors", "ifi_collisions", "ifi_ibytes", "ifi_obytes", "ifi_imcasts", "ifi_omcasts", + "ifi_iqdrops", "ifi_noproto", "ifi_recvtiming", "ifi_xmittiming", "ifi_lastchange" }) class IFdata64 extends Structure { public byte ifi_type; // ethernet, tokenring, etc public byte ifi_typelen; // Length of frame type id @@ -473,8 +465,8 @@ class IFdata64 extends Structure { /** * Return type for sysctl CTL_NET,PF_ROUTE */ - @Structure.FieldOrder({ "ifm_msglen", "ifm_version", "ifm_type", "ifm_addrs", "ifm_flags", - "ifm_index", "ifm_snd_len", "ifm_snd_maxlen", "ifm_snd_drops", "ifm_timer", "ifm_data"}) + @Structure.FieldOrder({ "ifm_msglen", "ifm_version", "ifm_type", "ifm_addrs", "ifm_flags", "ifm_index", + "ifm_snd_len", "ifm_snd_maxlen", "ifm_snd_drops", "ifm_timer", "ifm_data" }) class IFmsgHdr2 extends Structure { public short ifm_msglen; // to skip over non-understood messages public byte ifm_version; // future binary compatability @@ -496,8 +488,8 @@ public IFmsgHdr2(Pointer p) { /** * Return type for getpwuid */ - @Structure.FieldOrder({"pw_name", "pw_passwd", "pw_uid", "pw_gid", "pw_change", "pw_class", - "pw_gecos", "pw_dir", "pw_shell", "pw_expire", "pw_fields" }) + @Structure.FieldOrder({ "pw_name", "pw_passwd", "pw_uid", "pw_gid", "pw_change", "pw_class", "pw_gecos", "pw_dir", + "pw_shell", "pw_expire", "pw_fields" }) class Passwd extends Structure { public String pw_name; // user name public String pw_passwd; // encrypted password @@ -515,7 +507,7 @@ class Passwd extends Structure { /** * Return type for getgrgid */ - @Structure.FieldOrder({"gr_name", "gr_passwd", "gr_gid", "gr_mem"}) + @Structure.FieldOrder({ "gr_name", "gr_passwd", "gr_gid", "gr_mem" }) class Group extends Structure { public String gr_name; /* group name */ public String gr_passwd; /* group password */ @@ -526,7 +518,7 @@ class Group extends Structure { /** * Time value */ - @Structure.FieldOrder({"tv_sec", "tv_usec"}) + @Structure.FieldOrder({ "tv_sec", "tv_usec" }) class Timeval extends Structure { public NativeLong tv_sec; // seconds public int tv_usec; // microseconds @@ -535,80 +527,143 @@ class Timeval extends Structure { /** * Time Zone */ - @Structure.FieldOrder({ "tz_minuteswest", "tz_dsttime"}) + @Structure.FieldOrder({ "tz_minuteswest", "tz_dsttime" }) class Timezone extends Structure { public int tz_minuteswest; /* of Greenwich */ public int tz_dsttime; /* type of dst correction to apply */ } /** - * The system's notion of the current Greenwich time and the current time - * zone is obtained with the gettimeofday() call, and set with the - * settimeofday() call. The time is expressed in seconds and microseconds - * since midnight (0 hour), January 1, 1970. The resolution of the system - * clock is hardware dependent, and the time may be updated continuously or - * in ``ticks.'' If tp is NULL and tzp is non-NULL, gettimeofday() will - * populate the timezone struct in tzp. If tp is non-NULL and tzp is NULL, - * then only the timeval struct in tp is populated. If both tp and tzp are - * NULL, nothing is returned. + * The system's notion of the current Greenwich time and the current time zone + * is obtained with the gettimeofday() call, and set with the settimeofday() + * call. The time is expressed in seconds and microseconds since midnight (0 + * hour), January 1, 1970. The resolution of the system clock is hardware + * dependent, and the time may be updated continuously or in ``ticks.'' If tp is + * NULL and tzp is non-NULL, gettimeofday() will populate the timezone struct in + * tzp. If tp is non-NULL and tzp is NULL, then only the timeval struct in tp is + * populated. If both tp and tzp are NULL, nothing is returned. * * @param tp * Timeval structure * @param tzp * Timezone structure - * @return A 0 return value indicates that the call succeeded. A -1 return - * value indicates an error occurred, and in this case an error code - * is stored into the global variable errno. + * @return A 0 return value indicates that the call succeeded. A -1 return value + * indicates an error occurred, and in this case an error code is stored + * into the global variable errno. */ int gettimeofday(Timeval tp, Timezone tzp); /** - * The mach_host_self system call returns the calling thread's host name + * The {@code mach_host_self} system call returns the calling thread's host name * port. It has an effect equivalent to receiving a send right for the host * port. * + * @return a pointer to the host's name port + */ + MachPort mach_host_self_ptr(); + + /** + * The mach_host_self system call returns the calling thread's host name port. + * It has an effect equivalent to receiving a send right for the host port. + * * @return the host's name port + * + * @deprecated Using the 32-bit return type may corrupt the stack. Use + * {@link #mach_host_self_ptr} instead. */ + @Deprecated int mach_host_self(); /** - * The mach_task_self system call returns the calling thread's task_self + * The {@code mach_task_self} system call returns the calling thread's task_self * port. It has an effect equivalent to receiving a send right for the task's * kernel port. * + * @return a pointer to the task's kernel port + */ + MachPort mach_task_self_ptr(); + + /** + * The mach_task_self system call returns the calling thread's task_self port. + * It has an effect equivalent to receiving a send right for the task's kernel + * port. + * * @return the task's kernel port + * + * @deprecated Using the 32-bit return type may corrupt the stack. Use + * {@link #mach_task_self_ptr} instead. */ + @Deprecated int mach_task_self(); /** * The host_page_size function returns the page size for the given host. * * @param machPort - * The name (or control) port for the host for which the page - * size is desired. + * The name (or control) port for the host for which the page size is + * desired. + * @param pPageSize + * The host's page size (in bytes), set on success. + * @return 0 on success; sets errno on failure + */ + int host_page_size_ptr(MachPort machPort, LongByReference pPageSize); + + /** + * The host_page_size function returns the page size for the given host. + * + * @param machPort + * The name (or control) port for the host for which the page size is + * desired. * @param pPageSize * The host's page size (in bytes), set on success. * @return 0 on success; sets errno on failure + * + * @deprecated Using the 32-bit port type argument may corrupt the stack. Use + * {@link #host_page_size_ptr} instead. */ + @Deprecated int host_page_size(int machPort, LongByReference pPageSize); /** - * The host_statistics function returns scheduling and virtual memory - * statistics concerning the host as specified by hostStat. + * The host_statistics function returns scheduling and virtual memory statistics + * concerning the host as specified by hostStat. + * + * @param machPort + * The control port for the host for which information is to be + * obtained. + * @param hostStat + * The type of statistics desired (HOST_LOAD_INFO, HOST_VM_INFO, or + * HOST_CPU_LOAD_INFO) + * @param stats + * Statistics about the specified host. + * @param count + * On input, the maximum size of the buffer; on output, the size + * returned (in natural-sized units). + * @return 0 on success; sets errno on failure + */ + int host_statistics_ptr(MachPort machPort, int hostStat, Structure stats, IntByReference count); + + /** + * The host_statistics function returns scheduling and virtual memory statistics + * concerning the host as specified by hostStat. * * @param machPort * The control port for the host for which information is to be * obtained. * @param hostStat - * The type of statistics desired (HOST_LOAD_INFO, HOST_VM_INFO, - * or HOST_CPU_LOAD_INFO) + * The type of statistics desired (HOST_LOAD_INFO, HOST_VM_INFO, or + * HOST_CPU_LOAD_INFO) * @param stats * Statistics about the specified host. * @param count * On input, the maximum size of the buffer; on output, the size * returned (in natural-sized units). * @return 0 on success; sets errno on failure + * + * @deprecated Using the 32-bit port type argument may corrupt the stack. Use + * {@link #host_statistics_ptr} instead. */ + @Deprecated int host_statistics(int machPort, int hostStat, Structure stats, IntByReference count); /** @@ -627,35 +682,57 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ + int host_statistics64_ptr(MachPort machPort, int hostStat, Structure stats, IntByReference count); + + /** + * The host_statistics64 function returns 64-bit virtual memory statistics + * concerning the host as specified by hostStat. + * + * @param machPort + * The control port for the host for which information is to be + * obtained. + * @param hostStat + * The type of statistics desired (HOST_VM_INFO64) + * @param stats + * Statistics about the specified host. + * @param count + * On input, the maximum size of the buffer; on output, the size + * returned (in natural-sized units). + * @return 0 on success; sets errno on failure + * + * @deprecated Using the 32-bit port type argument may corrupt the stack. Use + * {@link #host_statistics64_ptr} instead. + */ + @Deprecated int host_statistics64(int machPort, int hostStat, Structure stats, IntByReference count); /** - * The sysctl() function retrieves system information and allows processes - * with appropriate privileges to set system information. The information - * available from sysctl() consists of integers, strings, and tables. + * The sysctl() function retrieves system information and allows processes with + * appropriate privileges to set system information. The information available + * from sysctl() consists of integers, strings, and tables. * * The state is described using a "Management Information Base" (MIB) style * name, listed in name, which is a namelen length array of integers. * - * The information is copied into the buffer specified by oldp. The size of - * the buffer is given by the location specified by oldlenp before the call, - * and that location gives the amount of data copied after a successful call - * and after a call that returns with the error code ENOMEM. If the amount - * of data available is greater than the size of the buffer supplied, the - * call supplies as much data as fits in the buffer provided and returns - * with the error code ENOMEM. If the old value is not desired, oldp and - * oldlenp should be set to NULL. - * - * The size of the available data can be determined by calling sysctl() with - * the NULL argument for oldp. The size of the available data will be - * returned in the location pointed to by oldlenp. For some operations, the - * amount of space may change often. For these operations, the system - * attempts to round up so that the returned size is large enough for a call - * to return the data shortly thereafter. - * - * To set a new value, newp is set to point to a buffer of length newlen - * from which the requested value is to be taken. If a new value is not to - * be set, newp should be set to NULL and newlen set to 0. + * The information is copied into the buffer specified by oldp. The size of the + * buffer is given by the location specified by oldlenp before the call, and + * that location gives the amount of data copied after a successful call and + * after a call that returns with the error code ENOMEM. If the amount of data + * available is greater than the size of the buffer supplied, the call supplies + * as much data as fits in the buffer provided and returns with the error code + * ENOMEM. If the old value is not desired, oldp and oldlenp should be set to + * NULL. + * + * The size of the available data can be determined by calling sysctl() with the + * NULL argument for oldp. The size of the available data will be returned in + * the location pointed to by oldlenp. For some operations, the amount of space + * may change often. For these operations, the system attempts to round up so + * that the returned size is large enough for a call to return the data shortly + * thereafter. + * + * To set a new value, newp is set to point to a buffer of length newlen from + * which the requested value is to be taken. If a new value is not to be set, + * newp should be set to NULL and newlen set to 0. * * @param name * MIB array of integers @@ -671,13 +748,12 @@ class Timezone extends Structure { * Size of information to be written * @return 0 on success; sets errno on failure */ - int sysctl(int[] name, int namelen, Pointer oldp, IntByReference oldlenp, - Pointer newp, int newlen); + int sysctl(int[] name, int namelen, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen); /** - * The sysctlbyname() function accepts an ASCII representation of the name - * and internally looks up the integer name vector. Apart from that, it - * behaves the same as the standard sysctl() function. + * The sysctlbyname() function accepts an ASCII representation of the name and + * internally looks up the integer name vector. Apart from that, it behaves the + * same as the standard sysctl() function. * * @param name * ASCII representation of the MIB name @@ -691,37 +767,34 @@ int sysctl(int[] name, int namelen, Pointer oldp, IntByReference oldlenp, * Size of information to be written * @return 0 on success; sets errno on failure */ - int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, - Pointer newp, int newlen); + int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen); /** - * The sysctlnametomib() function accepts an ASCII representation of the - * name, looks up the integer name vector, and returns the numeric - * representation in the mib array pointed to by mibp. The number of - * elements in the mib array is given by the location specified by sizep - * before the call, and that location gives the number of entries copied - * after a successful call. The resulting mib and size may be used in - * subsequent sysctl() calls to get the data associated with the requested - * ASCII name. This interface is intended for use by applications that want - * to repeatedly request the same variable (the sysctl() function runs in - * about a third the time as the same request made via the sysctlbyname() - * function). + * The sysctlnametomib() function accepts an ASCII representation of the name, + * looks up the integer name vector, and returns the numeric representation in + * the mib array pointed to by mibp. The number of elements in the mib array is + * given by the location specified by sizep before the call, and that location + * gives the number of entries copied after a successful call. The resulting mib + * and size may be used in subsequent sysctl() calls to get the data associated + * with the requested ASCII name. This interface is intended for use by + * applications that want to repeatedly request the same variable (the sysctl() + * function runs in about a third the time as the same request made via the + * sysctlbyname() function). * * The number of elements in the mib array can be determined by calling * sysctlnametomib() with the NULL argument for mibp. * - * The sysctlnametomib() function is also useful for fetching mib prefixes. - * If size on input is greater than the number of elements written, the - * array still contains the additional elements which may be written - * programmatically. + * The sysctlnametomib() function is also useful for fetching mib prefixes. If + * size on input is greater than the number of elements written, the array still + * contains the additional elements which may be written programmatically. * * @param name * ASCII representation of the name * @param mibp * Integer array containing the corresponding name vector. * @param size - * On input, number of elements in the returned array; on output, - * the number of entries copied. + * On input, number of elements in the returned array; on output, the + * number of entries copied. * @return 0 on success; sets errno on failure */ int sysctlnametomib(String name, Pointer mibp, IntByReference size); @@ -742,28 +815,53 @@ int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, * Pointer to number of elements in the returned structure * @return 0 on success; sets errno on failure */ - int host_processor_info(int machPort, int flavor, IntByReference procCount, - PointerByReference procInfo, IntByReference procInfoCount); + int host_processor_info_ptr(MachPort machPort, int flavor, IntByReference procCount, PointerByReference procInfo, + IntByReference procInfoCount); + + /** + * The host_processor_info function returns information about processors. + * + * @param machPort + * The control port for the host for which information is to be + * obtained. + * @param flavor + * The type of information requested. + * @param procCount + * Pointer to the number of processors + * @param procInfo + * Pointer to the structure corresponding to the requested flavor + * @param procInfoCount + * Pointer to number of elements in the returned structure + * @return 0 on success; sets errno on failure + * + * @deprecated Using the 32-bit port type argument may corrupt the stack. Use + * {@link #host_processor_info_ptr} instead. + */ + @Deprecated + int host_processor_info(int machPort, int flavor, IntByReference procCount, PointerByReference procInfo, + IntByReference procInfoCount); /** - * The getloadavg() function returns the number of processes in the system - * run queue averaged over various periods of time. Up to nelem samples are - * retrieved and assigned to successive elements of loadavg[]. The system - * imposes a maximum of 3 samples, representing averages over the last 1, 5, - * and 15 minutes, respectively. + * The getloadavg() function returns the number of processes in the system run + * queue averaged over various periods of time. Up to nelem samples are + * retrieved and assigned to successive elements of loadavg[]. The system + * imposes a maximum of 3 samples, representing averages over the last 1, 5, and + * 15 minutes, respectively. + * * @param loadavg * An array of doubles which will be filled with the results * @param nelem * Number of samples to return - * @return If the load average was unobtainable, -1 is returned; otherwise, - * the number of samples actually retrieved is returned. - * @see getloadavg(3) + * @return If the load average was unobtainable, -1 is returned; otherwise, the + * number of samples actually retrieved is returned. + * @see getloadavg(3) */ int getloadavg(double[] loadavg, int nelem); /** - * This function searches the password database for the given user uid, - * always returning the first one encountered. + * This function searches the password database for the given user uid, always + * returning the first one encountered. * * @param uid * The user ID @@ -772,9 +870,9 @@ int host_processor_info(int machPort, int flavor, IntByReference procCount, Passwd getpwuid(int uid); /** - * This function searches the group database for the given group name - * pointed to by the group id given by gid, returning the first one - * encountered. Identical group gids may result in undefined behavior. + * This function searches the group database for the given group name pointed to + * by the group id given by gid, returning the first one encountered. Identical + * group gids may result in undefined behavior. * * @param gid * The group ID @@ -792,18 +890,18 @@ int host_processor_info(int machPort, int flavor, IntByReference procCount, * @param buffer * a C array of int-sized values to be filled with process * identifiers that hold an open file reference matching the - * specified path or volume. Pass NULL to obtain the minimum - * buffer size needed to hold the currently active processes. + * specified path or volume. Pass NULL to obtain the minimum buffer + * size needed to hold the currently active processes. * @param buffersize * the size (in bytes) of the provided buffer. - * @return the number of bytes of data returned in the provided buffer; -1 - * if an error was encountered; + * @return the number of bytes of data returned in the provided buffer; -1 if an + * error was encountered; */ int proc_listpids(int type, int typeinfo, int[] buffer, int buffersize); /** - * Return in buffer a proc_*info structure corresponding to the flavor for - * the specified process + * Return in buffer a proc_*info structure corresponding to the flavor for the + * specified process * * @param pid * the process identifier @@ -815,8 +913,8 @@ int host_processor_info(int machPort, int flavor, IntByReference procCount, * holds results * @param buffersize * size of results - * @return the number of bytes of data returned in the provided buffer; -1 - * if an error was encountered; + * @return the number of bytes of data returned in the provided buffer; -1 if an + * error was encountered; */ int proc_pidinfo(int pid, int flavor, long arg, Structure buffer, int buffersize); @@ -829,8 +927,7 @@ int host_processor_info(int machPort, int flavor, IntByReference procCount, * holds results * @param buffersize * size of results - * @return the length of the name returned in buffer if successful; 0 - * otherwise + * @return the length of the name returned in buffer if successful; 0 otherwise */ int proc_pidpath(int pid, Pointer buffer, int buffersize); @@ -850,31 +947,30 @@ int host_processor_info(int machPort, int flavor, IntByReference procCount, int proc_pid_rusage(int pid, int flavor, RUsageInfoV2 buffer); /** - * The getfsstat() function returns information about all mounted file - * systems. The buf argument is a pointer to an array of statfs structures. + * The getfsstat() function returns information about all mounted file systems. + * The buf argument is a pointer to an array of statfs structures. * * Fields that are undefined for a particular file system are set to -1. The * buffer is filled with an array of statfs structures, one for each mounted * file system up to the size specified by bufsize. * * @param buf - * Array of statfs structures that will be filled with results. - * If buf is given as NULL, getfsstat() returns just the number - * of mounted file systems. + * Array of statfs structures that will be filled with results. If + * buf is given as NULL, getfsstat() returns just the number of + * mounted file systems. * @param bufsize * Size of the buffer to fill * @param flags - * If flags is set to MNT_NOWAIT, getfsstat() will directly - * return the information retained in the kernel to avoid delays - * caused by waiting for updated information from a file system - * that is perhaps temporarily unable to respond. Some of the - * information returned may be out of date, however; if flags is - * set to MNT_WAIT or MNT_DWAIT instead, getfsstat() will request - * updated information from each mounted filesystem before - * returning. + * If flags is set to MNT_NOWAIT, getfsstat() will directly return + * the information retained in the kernel to avoid delays caused by + * waiting for updated information from a file system that is perhaps + * temporarily unable to respond. Some of the information returned + * may be out of date, however; if flags is set to MNT_WAIT or + * MNT_DWAIT instead, getfsstat() will request updated information + * from each mounted filesystem before returning. * @return Upon successful completion, the number of statfs structures is - * returned. Otherwise, -1 is returned and the global variable errno - * is set to indicate the error. + * returned. Otherwise, -1 is returned and the global variable errno is + * set to indicate the error. */ int getfsstat64(Statfs[] buf, int bufsize, int flags); diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java new file mode 100644 index 0000000000..dff46269fa --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; + +import com.sun.jna.FunctionMapper; +import com.sun.jna.NativeLibrary; + +public class SystemBFunctionMapper implements FunctionMapper { + private static Collection mappedFunctions = Arrays.asList("mach_host_self_ptr", "mach_task_self_ptr", + "host_page_size_ptr", "host_statistics_ptr", "host_statistics64_ptr", "host_processor_info_ptr"); + + /** + * Removes the _ptr suffix from methods which use the properly sized pointer + * rather than 32-bit int. + */ + @Override + public String getFunctionName(NativeLibrary library, Method method) { + String name = method.getName(); + if (mappedFunctions.contains(name)) { + return name.substring(0, name.length() - 4); + } + return name; + } +} diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index f9a193a6a3..5ce46f1197 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -231,8 +231,8 @@ public void testIOConnect() { IOService smcService = IO.IOServiceGetMatchingService(masterPort, dict); assertNotEquals(0, smcService); PointerByReference connPtr = new PointerByReference(); - // Uh oh... - MachPort taskSelf = new MachPort(Pointer.createConstant(SystemB.INSTANCE.mach_task_self())); + + MachPort taskSelf = SystemB.INSTANCE.mach_task_self_ptr(); assertEquals(0, IO.IOServiceOpen(smcService, taskSelf, 0, connPtr)); IOConnect conn = new IOConnect(connPtr.getValue()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java index 5df6c70e55..bbee8f818f 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java @@ -27,6 +27,7 @@ import com.sun.jna.Native; import com.sun.jna.Platform; import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.IOKit.MachPort; import com.sun.jna.platform.mac.SystemB.Group; import com.sun.jna.platform.mac.SystemB.HostCpuLoadInfo; import com.sun.jna.platform.mac.SystemB.HostLoadInfo; @@ -93,11 +94,11 @@ public void testSysctl() { } public void testHostPageSize() { - int machPort = SystemB.INSTANCE.mach_host_self(); - assertTrue(machPort > 0); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); LongByReference pPageSize = new LongByReference(); - int ret = SystemB.INSTANCE.host_page_size(machPort, pPageSize); + int ret = SystemB.INSTANCE.host_page_size_ptr(machPort, pPageSize); assertEquals(ret, 0); // Probably 4096, definitely a power of 2 assertTrue(pPageSize.getValue() > 0); @@ -105,11 +106,11 @@ public void testHostPageSize() { } public void testVMInfo() { - int machPort = SystemB.INSTANCE.mach_host_self(); - assertTrue(machPort > 0); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); VMStatistics vmStats = new VMStatistics(); - int ret = SystemB.INSTANCE.host_statistics(machPort, + int ret = SystemB.INSTANCE.host_statistics_ptr(machPort, SystemB.HOST_VM_INFO, vmStats, new IntByReference(vmStats.size() / SystemB.INT_SIZE)); assertEquals(ret, 0); @@ -118,7 +119,7 @@ public void testVMInfo() { if (Platform.is64Bit()) { VMStatistics64 vmStats64 = new VMStatistics64(); - ret = SystemB.INSTANCE.host_statistics64(machPort, + ret = SystemB.INSTANCE.host_statistics64_ptr(machPort, SystemB.HOST_VM_INFO, vmStats64, new IntByReference( vmStats64.size() / SystemB.INT_SIZE)); assertEquals(ret, 0); @@ -128,11 +129,11 @@ SystemB.HOST_VM_INFO, vmStats64, new IntByReference( } public void testCpuLoad() { - int machPort = SystemB.INSTANCE.mach_host_self(); - assertTrue(machPort > 0); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); HostCpuLoadInfo cpuLoadInfo = new HostCpuLoadInfo(); - int ret = SystemB.INSTANCE.host_statistics(machPort, + int ret = SystemB.INSTANCE.host_statistics_ptr(machPort, SystemB.HOST_CPU_LOAD_INFO, cpuLoadInfo, new IntByReference( cpuLoadInfo.size())); assertEquals(ret, 0); @@ -141,11 +142,11 @@ SystemB.HOST_CPU_LOAD_INFO, cpuLoadInfo, new IntByReference( } public void testHostLoad() { - int machPort = SystemB.INSTANCE.mach_host_self(); - assertTrue(machPort > 0); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); HostLoadInfo hostLoadInfo = new HostLoadInfo(); - int ret = SystemB.INSTANCE.host_statistics(machPort, + int ret = SystemB.INSTANCE.host_statistics_ptr(machPort, SystemB.HOST_CPU_LOAD_INFO, hostLoadInfo, new IntByReference( hostLoadInfo.size())); assertEquals(ret, 0); @@ -157,13 +158,13 @@ SystemB.HOST_CPU_LOAD_INFO, hostLoadInfo, new IntByReference( } public void testHostProcessorInfo() { - int machPort = SystemB.INSTANCE.mach_host_self(); - assertTrue(machPort > 0); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); IntByReference procCount = new IntByReference(); PointerByReference procCpuLoadInfo = new PointerByReference(); IntByReference procInfoCount = new IntByReference(); - int ret = SystemB.INSTANCE.host_processor_info(machPort, + int ret = SystemB.INSTANCE.host_processor_info_ptr(machPort, SystemB.PROCESSOR_CPU_LOAD_INFO, procCount, procCpuLoadInfo, procInfoCount); assertEquals(ret, 0); @@ -174,10 +175,10 @@ public void testHostProcessorInfo() { } public void testMachPorts() { - int machPort = SystemB.INSTANCE.mach_host_self(); - assertTrue(machPort > 0); - machPort = SystemB.INSTANCE.mach_task_self(); - assertTrue(machPort > 0); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); + machPort = SystemB.INSTANCE.mach_task_self_ptr(); + assertNotNull(machPort); } public void testGetLoadAvg() { @@ -208,9 +209,10 @@ public void testTimeofDay() { } public void testVMMeter() { - int machPort = SystemB.INSTANCE.mach_host_self(); + MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(machPort); VMMeter vmstats = new VMMeter(); - assertEquals(0, SystemB.INSTANCE.host_statistics(machPort, SystemB.HOST_VM_INFO, vmstats, + assertEquals(0, SystemB.INSTANCE.host_statistics_ptr(machPort, SystemB.HOST_VM_INFO, vmstats, new IntByReference(vmstats.size()))); assertTrue(vmstats.v_lookups >= 0); } From a51ab2ae8befa9941103aa702c24053b4464ad37 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 10 Sep 2019 22:36:10 -0700 Subject: [PATCH 14/28] Consistent IOObject hierarchy --- .../src/com/sun/jna/platform/mac/IOKit.java | 29 ++++++++++++------- .../jna/platform/mac/DiskArbitrationTest.java | 8 ++--- .../com/sun/jna/platform/mac/IOKitTest.java | 21 ++++++-------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 1064756cbb..99ba7cac6d 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -128,17 +128,11 @@ public IOIterator(Pointer p) { * returned, otherwise zero is returned. The element should be released * by the caller when it is finished. */ - public IOObject next() { + public IOService next() { return INSTANCE.IOIteratorNext(this); } } - /** - * The base class for most I/O Kit families, devices, and drivers. - */ - class IOService extends IOObject { - } - /** * The base class for all objects in the registry. */ @@ -152,12 +146,25 @@ public IORegistryEntry(Pointer p) { } } + /** + * The base class for most I/O Kit families, devices, and drivers. + */ + class IOService extends IORegistryEntry { + public IOService() { + super(); + } + + public IOService(Pointer p) { + super(p); + } + } + /** * For an application to communicate with a device, the first thing it must do * is create a connection between itself and the in-kernel object representing * the device. To do this, it creates a user client object. */ - class IOConnect extends IOObject { + class IOConnect extends IOService { public IOConnect() { super(); } @@ -257,13 +264,13 @@ public IOConnect(Pointer p) { * construct matching dictionaries for common criteria with helper * functions such as {@link #IOServiceMatching}, * {@link #IOServiceNameMatching}, and {@link #IOBSDNameMatching}. - * @param existing + * @param iterator * An iterator handle is returned on success, and should be released * by the caller when the iteration is finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ int IOServiceGetMatchingServices(MachPort masterPort, CFMutableDictionaryRef matchingDictionary, - PointerByReference existing); + PointerByReference iterator); /** * Returns the next object in an iteration. @@ -274,7 +281,7 @@ int IOServiceGetMatchingServices(MachPort masterPort, CFMutableDictionaryRef mat * returned, otherwise zero is returned. The element should be released * by the caller when it is finished. */ - IOObject IOIteratorNext(IOIterator iterator); + IOService IOIteratorNext(IOIterator iterator); /** * Create a CF representation of a registry entry's property. diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 5d7b5bd300..9e34c2d5a1 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -44,7 +44,6 @@ import com.sun.jna.platform.mac.DiskArbitration.DADiskRef; import com.sun.jna.platform.mac.DiskArbitration.DASessionRef; import com.sun.jna.platform.mac.IOKit.IOIterator; -import com.sun.jna.platform.mac.IOKit.IOObject; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.MachPort; import com.sun.jna.ptr.PointerByReference; @@ -80,9 +79,8 @@ public void testDiskCreate() { // Consumes a reference to dict assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); IOIterator iter = new IOIterator(iterPtr.getValue()); - IOObject mediaObj = iter.next(); - while (mediaObj != null) { - IORegistryEntry media = new IORegistryEntry(mediaObj.getPointer()); + IORegistryEntry media = iter.next(); + while (media != null) { CFStringRef wholeKey = CFStringRef.createCFString("Whole"); CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); wholeKey.release(); @@ -95,7 +93,7 @@ public void testDiskCreate() { } cfWhole.release(); assertEquals(0, media.release()); - mediaObj = iter.next(); + media = iter.next(); } assertEquals(0, iter.release()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 5ce46f1197..36897282ff 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -93,9 +93,8 @@ public void testMatching() { classKey.release(); // Get matching service (consumes dict reference) - IOService platformExpertSvc = IO.IOServiceGetMatchingService(masterPort, dict); - assertNotNull(platformExpertSvc.getPointer()); - IORegistryEntry platformExpert = new IORegistryEntry(platformExpertSvc.getPointer()); + IORegistryEntry platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); + assertNotNull(platformExpert.getPointer()); // Get a single key CFStringRef serialKey = CFStringRef.createCFString("IOPlatformSerialNumber"); CFTypeRef cfSerialAsType = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, @@ -152,9 +151,8 @@ public void testIteratorParentChild() { assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); IOIterator iter = new IOIterator(iterPtr.getValue()); // iter is a pointer to first device; iterate until null - IOObject controllerDeviceObj = iter.next(); - while (controllerDeviceObj != null) { - IORegistryEntry controllerDevice = new IORegistryEntry(controllerDeviceObj.getPointer()); + IORegistryEntry controllerDevice = iter.next(); + while (controllerDevice != null) { LongByReference id = new LongByReference(); IO.IORegistryEntryGetRegistryEntryID(controllerDevice, id); // EntryIDs 0 thru 19 are reserved, all are unique @@ -180,11 +178,10 @@ public void testIteratorParentChild() { PointerByReference childIterPtr = new PointerByReference(); IO.IORegistryEntryGetChildIterator(controllerDevice, "IOService", childIterPtr); IOIterator childIter = new IOIterator(childIterPtr.getValue()); - IOObject childDeviceObj = childIter.next(); - while (childDeviceObj != null) { - assertTrue(IO.IOObjectConformsTo(childDeviceObj, "IOUSBDevice")); + IORegistryEntry childDevice = childIter.next(); + while (childDevice != null) { + assertTrue(IO.IOObjectConformsTo(childDevice, "IOUSBDevice")); - IORegistryEntry childDevice = new IORegistryEntry(childDeviceObj.getPointer()); LongByReference childId = new LongByReference(); IO.IORegistryEntryGetRegistryEntryID(childDevice, childId); assertTrue(childId.getValue() > 19); @@ -208,13 +205,13 @@ public void testIteratorParentChild() { // Release this device and iterate to the next one assertEquals(0, childDevice.release()); - childDeviceObj = childIter.next(); + childDevice = childIter.next(); } assertEquals(0, childIter.release()); // Release this controller and iterate to the next one assertEquals(0, controllerDevice.release()); - controllerDeviceObj = iter.next(); + controllerDevice = iter.next(); } assertEquals(0, iter.release()); } From 79475618aae9667e856fe044fe30d4fab577b6da Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 11 Sep 2019 10:48:11 -0700 Subject: [PATCH 15/28] Allow MachPorts to be deallocated --- .../src/com/sun/jna/platform/mac/IOKit.java | 44 +++++++++++-------- .../jna/platform/mac/DiskArbitrationTest.java | 1 + .../com/sun/jna/platform/mac/IOKitTest.java | 3 ++ 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 99ba7cac6d..483720c2f1 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -54,24 +54,7 @@ public interface IOKit extends Library { MachPort MACH_PORT_NULL = new MachPort(); - /** - * Communication between tasks is an important element of the Mach philosophy. - * Mach supports a client/server system structure in which tasks (clients) - * access services by making requests of other tasks (servers) via messages sent - * over a communication channel. - *

- * The endpoints of these communication channels in Mach are called ports, while - * port rights denote permission to use the channel. - */ - class MachPort extends PointerType { - public MachPort() { - super(); - } - public MachPort(Pointer p) { - super(p); - } - } /** * IOKitLib implements non-kernel task access to common IOKit object types - @@ -90,7 +73,7 @@ public MachPort(Pointer p) { * kernel object which any io_object_t et al. represents. IOKit objects returned * by all functions should be released with IOObjectRelease. */ - class IOObject extends MachPort { + class IOObject extends PointerType { public IOObject() { super(); } @@ -109,6 +92,25 @@ public int release() { } } + /** + * Communication between tasks is an important element of the Mach philosophy. + * Mach supports a client/server system structure in which tasks (clients) + * access services by making requests of other tasks (servers) via messages sent + * over a communication channel. + *

+ * The endpoints of these communication channels in Mach are called ports, while + * port rights denote permission to use the channel. + */ + class MachPort extends IOObject { + public MachPort() { + super(); + } + + public MachPort(Pointer p) { + super(p); + } + } + /** * An IOKit iterator handle. */ @@ -180,7 +182,11 @@ public IOConnect(Pointer p) { * @param bootstrapPort * Pass {@link #MACH_PORT_NULL} for the default. * @param masterPort - * A pointer to the master port is returned. + * A pointer to the master port is returned. Multiple calls to + * IOMasterPort will not result in leaking ports (each call to + * IOMasterPort adds another send right to the port) but it is + * considered good programming practice to deallocate the port when + * you are finished with it using {@link #IOObjectRelease} * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ int IOMasterPort(MachPort bootstrapPort, PointerByReference masterPort); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 9e34c2d5a1..05028f3e4c 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -136,5 +136,6 @@ public void testDiskCreate() { daMediaBlockSize.release(); session.release(); + assertEquals(0, masterPort.release()); } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 36897282ff..79a1b733c7 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -134,6 +134,7 @@ public void testMatching() { cfSerialAsType.release(); assertEquals(0, root.release()); + assertEquals(0, masterPort.release()); } @Test @@ -214,6 +215,7 @@ public void testIteratorParentChild() { controllerDevice = iter.next(); } assertEquals(0, iter.release()); + assertEquals(0, masterPort.release()); } @Test @@ -239,6 +241,7 @@ public void testIOConnect() { IO.IOServiceClose(conn); assertEquals(0, smcService.release()); + assertEquals(0, masterPort.release()); } @Test From 56c4b2e79279b460c53556a786e34a9c4f29d74b Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 11 Sep 2019 17:51:34 -0700 Subject: [PATCH 16/28] Add CFIndex extending NativeLong --- .../sun/jna/platform/mac/CoreFoundation.java | 74 ++++++++++++------- .../jna/platform/mac/CoreFoundationTest.java | 28 +++---- .../com/sun/jna/platform/mac/IOKitTest.java | 5 +- 3 files changed, 66 insertions(+), 41 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index 334ed19a56..3b807fe095 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -27,6 +27,7 @@ import com.sun.jna.Library; import com.sun.jna.Memory; import com.sun.jna.Native; +import com.sun.jna.NativeLong; import com.sun.jna.Pointer; import com.sun.jna.PointerType; import com.sun.jna.ptr.ByReference; @@ -127,7 +128,7 @@ public CFNumberRef(Pointer p) { */ public long longValue() { LongByReference lbr = new LongByReference(); - INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberLongLongType.ordinal(), lbr); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberLongLongType.typeIndex(), lbr); return lbr.getValue(); } @@ -144,7 +145,7 @@ public long longValue() { */ public int intValue() { IntByReference ibr = new IntByReference(); - INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberIntType.ordinal(), ibr); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberIntType.typeIndex(), ibr); return ibr.getValue(); } @@ -161,7 +162,7 @@ public int intValue() { */ public short shortValue() { ShortByReference sbr = new ShortByReference(); - INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberShortType.ordinal(), sbr); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberShortType.typeIndex(), sbr); return sbr.getValue(); } @@ -178,7 +179,7 @@ public short shortValue() { */ public byte byteValue() { ByteByReference bbr = new ByteByReference(); - INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberCharType.ordinal(), bbr); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberCharType.typeIndex(), bbr); return bbr.getValue(); } @@ -195,7 +196,7 @@ public byte byteValue() { */ public double doubleValue() { DoubleByReference dbr = new DoubleByReference(); - INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberDoubleType.ordinal(), dbr); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberDoubleType.typeIndex(), dbr); return dbr.getValue(); } @@ -212,14 +213,14 @@ public double doubleValue() { */ public float floatValue() { FloatByReference fbr = new FloatByReference(); - INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberFloatType.ordinal(), fbr); + INSTANCE.CFNumberGetValue(this, CFNumberType.kCFNumberFloatType.typeIndex(), fbr); return fbr.getValue(); } } /** * Enum of values used for {@link CFNumberType} in {@link #CFNumberGetValue} and - * {@link #CFNumberGetType}. Use {@link java.lang.Enum#ordinal} for the expected + * {@link #CFNumberGetType}. Use {@link CFNumberType#typeIndex} for the expected * integer value corresponding to the C-style enum. */ enum CFNumberType { @@ -227,6 +228,15 @@ enum CFNumberType { kCFNumberFloat32Type, kCFNumberFloat64Type, kCFNumberCharType, kCFNumberShortType, kCFNumberIntType, kCFNumberLongType, kCFNumberLongLongType, kCFNumberFloatType, kCFNumberDoubleType, kCFNumberCFIndexType, kCFNumberNSIntegerType, kCFNumberCGFloatType, kCFNumberMaxType; + + /** + * Index for the type of {@link CFNumberRef} stored. + * + * @return a {@link CFIndex} representing the enum ordinal. + */ + public CFIndex typeIndex() { + return new CFIndex(this.ordinal()); + } } /** @@ -336,7 +346,7 @@ public CFStringRef(Pointer p) { */ public static CFStringRef createCFString(String s) { final char[] chars = s.toCharArray(); - return INSTANCE.CFStringCreateWithCharacters(null, chars, chars.length); + return INSTANCE.CFStringCreateWithCharacters(null, chars, new CFIndex(chars.length)); } /** @@ -347,12 +357,12 @@ public static CFStringRef createCFString(String s) { * failed. */ public String stringValue() { - long length = INSTANCE.CFStringGetLength(this); - long maxSize = INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - if (maxSize == kCFNotFound) { + CFIndex length = INSTANCE.CFStringGetLength(this); + CFIndex maxSize = INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + if (maxSize.intValue() == kCFNotFound) { return null; } - Memory buf = new Memory(maxSize); + Memory buf = new Memory(maxSize.longValue()); if (0 != INSTANCE.CFStringGetCString(this, buf, maxSize, kCFStringEncodingUTF8)) { return buf.getString(0, "UTF8"); } @@ -360,6 +370,18 @@ public String stringValue() { } } + /** + * A wrapper for the {@link NativeLong} type, used for {@link CFNumberRef} + * types, {@link CFStringRef} lengths, and {@link CFArrayRef} sizes and indices. + */ + class CFIndex extends NativeLong { + private static final long serialVersionUID = 1L; + + public CFIndex(long value) { + super(value); + } + } + /** * Returns the number of values currently in an array. * @@ -367,7 +389,7 @@ public String stringValue() { * a {@link CFArrayRef} object. * @return The number of values in {@code array}. */ - long CFArrayGetCount(CFArrayRef theArray); + CFIndex CFArrayGetCount(CFArrayRef theArray); /** * Creates a string from a buffer of Unicode characters. @@ -387,7 +409,7 @@ public String stringValue() { * @return An immutable string containing {@code chars}, or {@code null} if * there was a problem creating the object. */ - CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, char[] chars, long length); + CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, char[] chars, CFIndex length); /** * Creates a {@code CFNumber} object using a specified value. @@ -413,7 +435,7 @@ public String stringValue() { * A pointer to the value for the returned number object. * @return A new number with the value specified by {@code valuePtr}. */ - CFNumberRef CFNumberCreate(CFAllocatorRef alloc, long theType, ByReference valuePtr); + CFNumberRef CFNumberCreate(CFAllocatorRef alloc, CFIndex theType, ByReference valuePtr); /** * Creates a new immutable array with the given values. @@ -454,7 +476,7 @@ public String stringValue() { * {@code values}, or {@code null} if there was a problem creating the * object. */ - CFArrayRef CFArrayCreate(CFAllocatorRef alloc, Pointer values, long numValues, Pointer callBacks); + CFArrayRef CFArrayCreate(CFAllocatorRef alloc, Pointer values, CFIndex numValues, Pointer callBacks); /** * Creates an immutable {@code CFData} object using data copied from a specified @@ -475,7 +497,7 @@ public String stringValue() { * @return A new {@code CFData} object, or {@code null} if there was a problem * creating the object. */ - CFDataRef CFDataCreate(CFAllocatorRef alloc, Pointer bytes, long length); + CFDataRef CFDataCreate(CFAllocatorRef alloc, Pointer bytes, CFIndex length); /** * Creates a new mutable dictionary. @@ -517,7 +539,7 @@ public String stringValue() { * @return A new dictionary, or {@code null} if there was a problem creating the * object. */ - CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capacity, Pointer keyCallBacks, + CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, CFIndex capacity, Pointer keyCallBacks, Pointer valueCallBacks); /** @@ -576,7 +598,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * The {@code CFType} object to examine. * @return A number representing the reference count of {code cf}. */ - long CFGetRetainCount(CFTypeRef cf); + CFIndex CFGetRetainCount(CFTypeRef cf); /** * Returns the value associated with a given key. @@ -674,7 +696,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * @return 1 upon success or 0 if the conversion fails or the provided buffer is * too small. */ - byte CFStringGetCString(CFStringRef theString, Pointer bufferToFill, long bufferSize, int encoding); + byte CFStringGetCString(CFStringRef theString, Pointer bufferToFill, CFIndex bufferSize, int encoding); /** * Returns the value of a {@code CFBoolean} object. @@ -696,7 +718,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * the count of {@code theArray})), the behavior is undefined. * @return The value at the {@code idx} index in {@code theArray}). */ - Pointer CFArrayGetValueAtIndex(CFArrayRef theArray, long idx); + Pointer CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx); /** * Returns the type used by a {@code CFNumber} object to store its value. @@ -706,7 +728,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * @return A constant that indicates the data type of the value contained in * number. See {@link CFNumberType} for a list of possible values. */ - long CFNumberGetType(CFNumberRef number); + CFIndex CFNumberGetType(CFNumberRef number); /** * Obtains the value of a {@code CFNumber} object cast to a specified type. @@ -720,7 +742,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * On return, contains the value of {@code number}. * @return 1 if the operation was successful, otherwise 0. */ - byte CFNumberGetValue(CFNumberRef number, long theType, ByReference valuePtr); + byte CFNumberGetValue(CFNumberRef number, CFIndex theType, ByReference valuePtr); /** * Returns the number (in terms of UTF-16 code pairs) of Unicode characters in a @@ -731,7 +753,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * @return The number (in terms of UTF-16 code pairs) of characters stored in * {@code theString}. */ - long CFStringGetLength(CFStringRef theString); + CFIndex CFStringGetLength(CFStringRef theString); /** * Returns the maximum number of bytes a string of a specified length (in @@ -746,7 +768,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * number of Unicode characters with the string encoding encoding, or * {@link #kCFNotFound} if the number exceeds {@link Long#MAX_VALUE}. */ - long CFStringGetMaximumSizeForEncoding(long length, int encoding); + CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, int encoding); /** * Gets the default allocator object for the current thread. @@ -766,7 +788,7 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, long capa * The {@code CFData} object to examine. * @return An index that specifies the number of bytes in {@code theData}. */ - long CFDataGetLength(CFDataRef theData); + CFIndex CFDataGetLength(CFDataRef theData); /** * Returns a read-only pointer to the bytes of a {@code CFData} object. diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index 36bd4836a9..023b9eb7b1 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -42,6 +42,7 @@ import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; import com.sun.jna.platform.mac.CoreFoundation.CFDataRef; +import com.sun.jna.platform.mac.CoreFoundation.CFIndex; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFNumberType; @@ -65,7 +66,8 @@ public void testCFStringRef() { Memory mem = new Memory(awesome.getBytes().length + 1); mem.clear(); - assertNotEquals(0, CF.CFStringGetCString(cfAwesome, mem, mem.size(), CoreFoundation.kCFStringEncodingUTF8)); + assertNotEquals(0, + CF.CFStringGetCString(cfAwesome, mem, new CFIndex(mem.size()), CoreFoundation.kCFStringEncodingUTF8)); byte[] awesomeBytes = mem.getByteArray(0, (int) mem.size() - 1); byte[] awesomeArr = awesome.getBytes(); for (int i = 0; i < awesomeArr.length; i++) { @@ -82,14 +84,14 @@ public void testCFStringRef() { @Test public void testCFNumberRef() { LongByReference max = new LongByReference(Long.MAX_VALUE); - CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.ordinal(), max); + CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.typeIndex(), max); assertEquals(Long.MAX_VALUE, cfMax.longValue()); cfMax.release(); IntByReference zero = new IntByReference(0); IntByReference one = new IntByReference(1); - CFNumberRef cfZero = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), zero); - CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), one); + CFNumberRef cfZero = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.typeIndex(), zero); + CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.typeIndex(), one); assertEquals(0, cfZero.intValue()); assertEquals(1, cfOne.intValue()); @@ -101,8 +103,8 @@ public void testCFNumberRef() { public void testCFRetainCount() { DoubleByReference pi = new DoubleByReference(Math.PI); DoubleByReference e = new DoubleByReference(Math.E); - CFNumberRef cfE = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.ordinal(), e); - CFNumberRef cfPi = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.ordinal(), pi); + CFNumberRef cfE = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.typeIndex(), e); + CFNumberRef cfPi = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.typeIndex(), pi); assertEquals(1, CF.CFGetRetainCount(cfE)); assertEquals(1, CF.CFGetRetainCount(cfPi)); cfE.retain(); @@ -132,15 +134,15 @@ public void testCFArray() { int size = Native.getNativeSize(CFNumberRef.class); Memory contiguousArray = new Memory(size * refArray.length); for (int i = 0; i < refArray.length; i++) { - refArray[i] = CF.CFNumberCreate(null, CoreFoundation.CFNumberType.kCFNumberIntType.ordinal(), + refArray[i] = CF.CFNumberCreate(null, CoreFoundation.CFNumberType.kCFNumberIntType.typeIndex(), new IntByReference(i)); contiguousArray.setPointer(i * size, refArray[i].getPointer()); } - CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, refArray.length, null); + CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, new CFIndex(refArray.length), null); assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray)); for (int i = 0; i < refArray.length; i++) { - Pointer result = CF.CFArrayGetValueAtIndex(cfPtrArray, i); + Pointer result = CF.CFArrayGetValueAtIndex(cfPtrArray, new CFIndex(i)); CFNumberRef numRef = new CFNumberRef(result); assertEquals(i, numRef.intValue()); } @@ -163,8 +165,8 @@ public void testCFData() { nativeBytes.setByte(i, randomBytes[i]); } // Create a CF reference to the data - CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, size); - long dataSize = CF.CFDataGetLength(cfData); + CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, new CFIndex(size)); + long dataSize = CF.CFDataGetLength(cfData).intValue(); assertEquals(size, dataSize); // Read it back out and convert to an array Pointer bytes = CF.CFDataGetBytePtr(cfData); @@ -176,7 +178,7 @@ public void testCFData() { @Test public void testCFDictionary() { CFAllocatorRef alloc = CF.CFAllocatorGetDefault(); - CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, 2, null, null); + CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, new CFIndex(2), null, null); CFStringRef oneStr = CFStringRef.createCFString("one"); // Key does not exist, returns null @@ -192,7 +194,7 @@ public void testCFDictionary() { // Store (replace the null) and retrieve integer value IntByReference one = new IntByReference(1); - CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.ordinal(), one); + CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.typeIndex(), one); CF.CFDictionarySetValue(dict, oneStr, cfOne); assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 79a1b733c7..8e6d2636ba 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -41,6 +41,7 @@ import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFIndex; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; @@ -257,10 +258,10 @@ public void testPowerSources() { CFStringRef isPresentKey = CFStringRef.createCFString("Is Present"); CFStringRef currentCapacityKey = CFStringRef.createCFString("Current Capacity"); CFStringRef maxCapacityKey = CFStringRef.createCFString("Max Capacity"); - long powerSourcesCount = CF.CFArrayGetCount(powerSourcesList); + int powerSourcesCount = CF.CFArrayGetCount(powerSourcesList).intValue(); for (int ps = 0; ps < powerSourcesCount; ps++) { // Get the dictionary for that Power Source - Pointer pwrSrcPtr = CoreFoundation.INSTANCE.CFArrayGetValueAtIndex(powerSourcesList, ps); + Pointer pwrSrcPtr = CoreFoundation.INSTANCE.CFArrayGetValueAtIndex(powerSourcesList, new CFIndex(ps)); CFTypeRef powerSource = new CFTypeRef(); powerSource.setPointer(pwrSrcPtr); CFDictionaryRef dictionary = IOKit.INSTANCE.IOPSGetPowerSourceDescription(powerSourcesInfo, powerSource); From 52ec379cc7f0b0c901da26b0e48d389f8a8419de Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 11 Sep 2019 22:06:12 -0700 Subject: [PATCH 17/28] Add IOKitUtil class --- .../sun/jna/platform/mac/CoreFoundation.java | 4 + .../src/com/sun/jna/platform/mac/IOKit.java | 12 +- .../com/sun/jna/platform/mac/IOKitUtil.java | 346 ++++++++++++++++++ .../jna/platform/mac/CoreFoundationTest.java | 18 +- .../jna/platform/mac/DiskArbitrationTest.java | 10 + .../com/sun/jna/platform/mac/IOKitTest.java | 40 +- 6 files changed, 388 insertions(+), 42 deletions(-) create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index 3b807fe095..f8a77adb6a 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -377,6 +377,10 @@ public String stringValue() { class CFIndex extends NativeLong { private static final long serialVersionUID = 1L; + public CFIndex() { + super(); + } + public CFIndex(long value) { super(value); } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 483720c2f1..edc437dc7a 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -54,8 +54,6 @@ public interface IOKit extends Library { MachPort MACH_PORT_NULL = new MachPort(); - - /** * IOKitLib implements non-kernel task access to common IOKit object types - * IORegistryEntry, IOService, IOIterator etc. These functions are generic - @@ -257,7 +255,7 @@ public IOConnect(Pointer p) { *

* The service must be released by the caller. */ - IOService IOServiceGetMatchingService(MachPort masterPort, CFMutableDictionaryRef matchingDictionary); + IOService IOServiceGetMatchingService(MachPort masterPort, CFDictionaryRef matchingDictionary); /** * Look up registered IOService objects that match a matching dictionary. @@ -275,7 +273,7 @@ public IOConnect(Pointer p) { * by the caller when the iteration is finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOServiceGetMatchingServices(MachPort masterPort, CFMutableDictionaryRef matchingDictionary, + int IOServiceGetMatchingServices(MachPort masterPort, CFDictionaryRef matchingDictionary, PointerByReference iterator); /** @@ -322,8 +320,7 @@ CFTypeRef IORegistryEntryCreateCFProperty(IORegistryEntry entry, CFStringRef key * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ int IORegistryEntryCreateCFProperties(IORegistryEntry entry, PointerByReference properties, - CFAllocatorRef allocator, - int options); + CFAllocatorRef allocator, int options); /** * Create a CF representation of a registry entry's property. @@ -348,8 +345,7 @@ int IORegistryEntryCreateCFProperties(IORegistryEntry entry, PointerByReference * caller should release with CFRelease. */ CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, CFStringRef key, - CFAllocatorRef allocator, - int options); + CFAllocatorRef allocator, int options); /** * Returns an ID for the registry entry that is global to all tasks. diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java new file mode 100644 index 0000000000..34be4914ce --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import com.sun.jna.Pointer; +import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDataRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; +import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; +import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.platform.mac.IOKit.IOIterator; +import com.sun.jna.platform.mac.IOKit.IORegistryEntry; +import com.sun.jna.platform.mac.IOKit.IOService; +import com.sun.jna.platform.mac.IOKit.MachPort; +import com.sun.jna.ptr.PointerByReference; + +/** + * Provides utilities for IOKit. + */ +public class IOKitUtil { + private static final IOKit IO = IOKit.INSTANCE; + private static final CoreFoundation CF = CoreFoundation.INSTANCE; + + private IOKitUtil() { + } + + /** + * Gets a pointer to the Mach Master Port. + * + * @return The master port. + *

+ * Multiple calls to {@link #getMasterPort} will not result in leaking + * ports (each call to {@link IOKit#IOMasterPort} adds another send + * right to the port) but it is considered good programming practice to + * deallocate the port when you are finished with it, using + * {@link IOKit#IOObjectRelease}. + */ + public static MachPort getMasterPort() { + PointerByReference port = new PointerByReference(); + IO.IOMasterPort(IOKit.MACH_PORT_NULL, port); + return new MachPort(port.getValue()); + } + + /** + * Gets the IO Registry root. + * + * @return a handle to the IORoot. Callers should release when finished, using + * {@link IOKit#IOObjectRelease}. + */ + public static IORegistryEntry getRoot() { + MachPort masterPort = getMasterPort(); + IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); + masterPort.release(); + return root; + } + + /** + * Opens a the first IOService matching a service name. + * + * @param serviceName + * The service name to match + * @return a handle to an IOService if successful, {@code null} if failed. + * Callers should release when finished, using + * {@link IOKit#IOObjectRelease}. + */ + public static IOService getMatchingService(String serviceName) { + CFMutableDictionaryRef dict = IO.IOServiceMatching(serviceName); + if (dict != null) { + return getMatchingService(dict); + } + return null; + } + + /** + * Opens a the first IOService matching a dictionary. + * + * @param matchingDictionary + * The dictionary to match. This method will consume a reference to + * the dictionary. + * @return a handle to an IOService if successful, {@code null} if failed. + * Callers should release when finished, using + * {@link IOKit#IOObjectRelease}. + */ + public static IOService getMatchingService(CFDictionaryRef matchingDictionary) { + MachPort masterPort = getMasterPort(); + IOService service = IO.IOServiceGetMatchingService(masterPort, matchingDictionary); + masterPort.release(); + return service; + } + + /** + * Convenience method to get IOService objects matching a service name. + * + * @param serviceName + * The service name to match + * @return a handle to an IOIterator if successful, {@code null} if failed. + * Callers should release when finished, using + * {@link IOKit#IOObjectRelease}. + */ + public static IOIterator getMatchingServices(String serviceName) { + CFMutableDictionaryRef dict = IO.IOServiceMatching(serviceName); + if (dict != null) { + return getMatchingServices(dict); + } + return null; + } + + /** + * Convenience method to get IOService objects matching a dictionary. + * + * @param matchingDictionary + * The dictionary to match. This method will consume a reference to + * the dictionary. + * @return a handle to an IOIterator if successful, {@code null} if failed. + * Callers should release when finished, using + * {@link IOKit#IOObjectRelease}. + */ + public static IOIterator getMatchingServices(CFDictionaryRef matchingDictionary) { + MachPort masterPort = getMasterPort(); + PointerByReference serviceIterator = new PointerByReference(); + int result = IO.IOServiceGetMatchingServices(masterPort, matchingDictionary, serviceIterator); + masterPort.release(); + if (result == 0 && serviceIterator.getValue() != null) { + return new IOIterator(serviceIterator.getValue()); + } + return null; + } + + /** + * Convenience method to get the IO dictionary matching a bsd name. + * + * @param bsdName + * The bsd name of the registry entry + * @return The dictionary ref if successful, {@code null} if failed. Callers + * should release when finished, using {@link IOKit#IOObjectRelease}. + */ + public static CFMutableDictionaryRef getBSDNameMatchingDict(String bsdName) { + MachPort masterPort = getMasterPort(); + CFMutableDictionaryRef result = IO.IOBSDNameMatching(masterPort, 0, bsdName); + masterPort.release(); + return result; + } + + /** + * Convenience method to get a String value from an IO Registry + * + * @param entry + * A handle to the registry entry + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists;{@code null} otherwise + */ + public static String getIORegistryStringProperty(IORegistryEntry entry, String key) { + String value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), + 0); + if (valueAsCFType != null && valueAsCFType.getPointer() != null) { + CFStringRef valueAsCFString = new CFStringRef(valueAsCFType.getPointer()); + value = valueAsCFString.stringValue(); + } + keyAsCFString.release(); + if (valueAsCFType != null) { + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a {@code long} value from an IO Registry. + * + * @param entry + * A handle to the registry entry + * @param key + * The string name of the key to retrieve + * @param defaultValue + * The value to return if unsuccessful + * @return The value of the registry entry if it exists. + *

+ * This method assumes a 64-bit integer is stored and does not do type + * checking. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this + * method returns an approximate value. If the value does not exist, the + * {@code defaultValue} is returned. + */ + public static long getIORegistryLongProperty(IORegistryEntry entry, String key, long defaultValue) { + long value = defaultValue; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), + 0); + if (valueAsCFType != null && valueAsCFType.getPointer() != null) { + CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); + value = valueAsCFNumber.longValue(); + } + keyAsCFString.release(); + if (valueAsCFType != null) { + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get an {@code int} value from an IO Registry. + * + * @param entry + * A handle to the registry entry + * @param key + * The string name of the key to retrieve + * @param defaultValue + * The value to return if unsuccessful + * @return The value of the registry entry if it exists. + *

+ * This method assumes a 32-bit integer is stored and does not do type + * checking. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this + * method returns an approximate value. If the value does not exist, the + * {@code defaultValue} is returned. + */ + public static int getIORegistryIntProperty(IORegistryEntry entry, String key, int defaultValue) { + int value = defaultValue; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), + 0); + if (valueAsCFType != null) { + CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); + value = valueAsCFNumber.intValue(); + } + keyAsCFString.release(); + if (valueAsCFType != null) { + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a {@code double} value from an IO Registry. + * + * @param entry + * A handle to the registry entry + * @param key + * The string name of the key to retrieve + * @param defaultValue + * The value to return if unsuccessful + * @return The value of the registry entry if it exists. + *

+ * This method assumes a floating point value is stored and does not do + * type checking. If this object's type differs from the return type, + * and the conversion is lossy or the return value is out of range, then + * this method returns an approximate value. If the value does not + * exist, the {@code defaultValue} is returned. + */ + public static double getIORegistryIntProperty(IORegistryEntry entry, String key, double defaultValue) { + double value = defaultValue; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), + 0); + if (valueAsCFType != null) { + CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); + value = valueAsCFNumber.doubleValue(); + } + keyAsCFString.release(); + if (valueAsCFType != null) { + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a Boolean value from an IO Registry. + * + * @param entry + * A handle to the registry entry + * @param key + * The string name of the key to retrieve + * @param defaultValue + * The value to return if unsuccessful + * @return The value of the registry entry if it exists; {@code defaultValue} + * otherwise + */ + public static boolean getIORegistryBooleanProperty(IORegistryEntry entry, String key, boolean defaultValue) { + boolean value = defaultValue; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), + 0); + if (valueAsCFType != null) { + CFBooleanRef valueAsCFBoolean = new CFBooleanRef(valueAsCFType.getPointer()); + value = valueAsCFBoolean.booleanValue(); + } + keyAsCFString.release(); + if (valueAsCFType != null) { + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a byte array value from an IO Registry. + * + * @param entry + * A handle to the registry entry + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + */ + public static byte[] getIORegistryByteArrayProperty(IORegistryEntry entry, String key) { + byte[] value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), + 0); + if (valueAsCFType != null) { + CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); + int length = CF.CFDataGetLength(valueAsCFData).intValue(); + Pointer p = CF.CFDataGetBytePtr(valueAsCFData); + value = p.getByteArray(0, length); + } + keyAsCFString.release(); + if (valueAsCFType != null) { + valueAsCFType.release(); + } + return value; + } +} diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index 023b9eb7b1..a6d1a173a8 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -61,7 +61,7 @@ public class CoreFoundationTest { public void testCFStringRef() { String awesome = "ǝɯosǝʍɐ sı ∀Nſ"; // Unicode CFStringRef cfAwesome = CFStringRef.createCFString(awesome); - assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome)); + assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome).intValue()); assertEquals(awesome, cfAwesome.stringValue()); Memory mem = new Memory(awesome.getBytes().length + 1); @@ -105,13 +105,13 @@ public void testCFRetainCount() { DoubleByReference e = new DoubleByReference(Math.E); CFNumberRef cfE = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.typeIndex(), e); CFNumberRef cfPi = CF.CFNumberCreate(null, CFNumberType.kCFNumberDoubleType.typeIndex(), pi); - assertEquals(1, CF.CFGetRetainCount(cfE)); - assertEquals(1, CF.CFGetRetainCount(cfPi)); + assertEquals(1, CF.CFGetRetainCount(cfE).intValue()); + assertEquals(1, CF.CFGetRetainCount(cfPi).intValue()); cfE.retain(); cfPi.retain(); cfPi.retain(); - assertEquals(2, CF.CFGetRetainCount(cfE)); - assertEquals(3, CF.CFGetRetainCount(cfPi)); + assertEquals(2, CF.CFGetRetainCount(cfE).intValue()); + assertEquals(3, CF.CFGetRetainCount(cfPi).intValue()); List irrationalReferences = new ArrayList<>(); irrationalReferences.add(cfE); @@ -120,10 +120,10 @@ public void testCFRetainCount() { value.release(); } - assertEquals(1, CF.CFGetRetainCount(cfE)); - assertEquals(2, CF.CFGetRetainCount(cfPi)); + assertEquals(1, CF.CFGetRetainCount(cfE).intValue()); + assertEquals(2, CF.CFGetRetainCount(cfPi).intValue()); cfPi.release(); - assertEquals(1, CF.CFGetRetainCount(cfPi)); + assertEquals(1, CF.CFGetRetainCount(cfPi).intValue()); cfE.release(); cfPi.release(); } @@ -140,7 +140,7 @@ public void testCFArray() { } CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, new CFIndex(refArray.length), null); - assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray)); + assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray).intValue()); for (int i = 0; i < refArray.length; i++) { Pointer result = CF.CFArrayGetValueAtIndex(cfPtrArray, new CFIndex(i)); CFNumberRef numRef = new CFNumberRef(result); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 05028f3e4c..6906ca19ff 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -25,6 +25,7 @@ package com.sun.jna.platform.mac; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -87,9 +88,18 @@ public void testDiskCreate() { assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); if (cfWholeBool.booleanValue()) { + // check that util boolean matches + assertTrue(IOKitUtil.getIORegistryBooleanProperty(media, "Whole", false)); + // check long and int values for major + long majorLong = IOKitUtil.getIORegistryLongProperty(media, "BSD Major", Long.MAX_VALUE); + int majorInt = IOKitUtil.getIORegistryIntProperty(media, "BSD Major", Integer.MAX_VALUE); + assertEquals(majorLong, majorInt); + DADiskRef disk = DA.DADiskCreateFromIOMedia(CF.CFAllocatorGetDefault(), session, media); bsdNames.add(DA.DADiskGetBSDName(disk)); disk.release(); + } else { + assertFalse(IOKitUtil.getIORegistryBooleanProperty(media, "Whole", true)); } cfWhole.release(); assertEquals(0, media.release()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 8e6d2636ba..a49f61932b 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -63,9 +63,7 @@ public class IOKitTest { @Test public void testMatching() { - PointerByReference masterPortPtr = new PointerByReference(); - assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); - MachPort masterPort = new MachPort(masterPortPtr.getValue()); + MachPort masterPort = IOKitUtil.getMasterPort(); String match = "matching BSD Name"; CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); @@ -103,7 +101,10 @@ public void testMatching() { assertNotNull(cfSerialAsType); CFStringRef cfSerial = new CFStringRef(cfSerialAsType.getPointer()); String serialNumber = cfSerial.stringValue(); - cfSerialAsType.release(); + + // Test util method for the same thing + String serialNumberViaUtil = IOKitUtil.getIORegistryStringProperty(platformExpert, "IOPlatformSerialNumber"); + assertEquals(serialNumber, serialNumberViaUtil); assertEquals(12, serialNumber.length()); // Get all the keys @@ -120,8 +121,8 @@ public void testMatching() { assertEquals(0, platformExpert.release()); // Get a single key from a nested entry - IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); - assertNotEquals(0, root); + IORegistryEntry root = IOKitUtil.getRoot(); + assertNotNull(root); cfSerialAsType = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), 0); // without recursive search should be null @@ -140,19 +141,13 @@ public void testMatching() { @Test public void testIteratorParentChild() { - PointerByReference masterPortPtr = new PointerByReference(); - assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); - MachPort masterPort = new MachPort(masterPortPtr.getValue()); + MachPort masterPort = IOKitUtil.getMasterPort(); Set uniqueEntryIdSet = new HashSet<>(); - // Create matching dictionary for USB Controller class - CFMutableDictionaryRef dict = IO.IOServiceMatching("IOUSBController"); // Iterate over USB Controllers. All devices are children of one of // these controllers in the "IOService" plane - PointerByReference iterPtr = new PointerByReference(); - assertEquals(0, IO.IOServiceGetMatchingServices(masterPort, dict, iterPtr)); - IOIterator iter = new IOIterator(iterPtr.getValue()); - // iter is a pointer to first device; iterate until null + IOIterator iter = IOKitUtil.getMatchingServices("IOUSBController"); + assertNotNull(iter); IORegistryEntry controllerDevice = iter.next(); while (controllerDevice != null) { LongByReference id = new LongByReference(); @@ -221,17 +216,12 @@ public void testIteratorParentChild() { @Test public void testIOConnect() { - PointerByReference masterPortPtr = new PointerByReference(); - assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); - MachPort masterPort = new MachPort(masterPortPtr.getValue()); - - // Open a connection to SMC - CFMutableDictionaryRef dict = IO.IOServiceMatching("AppleSMC"); - // consumes dict references - IOService smcService = IO.IOServiceGetMatchingService(masterPort, dict); - assertNotEquals(0, smcService); - PointerByReference connPtr = new PointerByReference(); + MachPort masterPort = IOKitUtil.getMasterPort(); + IOService smcService = IOKitUtil.getMatchingService("AppleSMC"); + assertNotNull(smcService); + + PointerByReference connPtr = new PointerByReference(); MachPort taskSelf = SystemB.INSTANCE.mach_task_self_ptr(); assertEquals(0, IO.IOServiceOpen(smcService, taskSelf, 0, connPtr)); IOConnect conn = new IOConnect(connPtr.getValue()); From 6c9a8c02edb72baf417773c859384aafcca6c70f Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Sat, 14 Sep 2019 18:50:11 -0700 Subject: [PATCH 18/28] Properly type mach_port_t and friends --- .../src/com/sun/jna/platform/mac/IOKit.java | 31 +--- .../com/sun/jna/platform/mac/IOKitUtil.java | 14 +- .../src/com/sun/jna/platform/mac/SystemB.java | 174 +++++++++++++----- .../platform/mac/SystemBFunctionMapper.java | 9 +- .../jna/platform/mac/DiskArbitrationTest.java | 6 +- .../com/sun/jna/platform/mac/IOKitTest.java | 11 +- .../com/sun/jna/platform/mac/SystemBTest.java | 68 ++++--- 7 files changed, 189 insertions(+), 124 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index edc437dc7a..1fc7c5b796 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -34,6 +34,8 @@ import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; +import com.sun.jna.platform.mac.SystemB.MachPort; +import com.sun.jna.platform.mac.SystemB.TaskPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; @@ -52,8 +54,6 @@ public interface IOKit extends Library { double kIOPSTimeRemainingUnlimited = -2.0; double kIOPSTimeRemainingUnknown = -1.0; - MachPort MACH_PORT_NULL = new MachPort(); - /** * IOKitLib implements non-kernel task access to common IOKit object types - * IORegistryEntry, IOService, IOIterator etc. These functions are generic - @@ -90,25 +90,6 @@ public int release() { } } - /** - * Communication between tasks is an important element of the Mach philosophy. - * Mach supports a client/server system structure in which tasks (clients) - * access services by making requests of other tasks (servers) via messages sent - * over a communication channel. - *

- * The endpoints of these communication channels in Mach are called ports, while - * port rights denote permission to use the channel. - */ - class MachPort extends IOObject { - public MachPort() { - super(); - } - - public MachPort(Pointer p) { - super(p); - } - } - /** * An IOKit iterator handle. */ @@ -128,7 +109,7 @@ public IOIterator(Pointer p) { * returned, otherwise zero is returned. The element should be released * by the caller when it is finished. */ - public IOService next() { + public IORegistryEntry next() { return INSTANCE.IOIteratorNext(this); } } @@ -178,7 +159,7 @@ public IOConnect(Pointer p) { * Returns the mach port used to initiate communication with IOKit. * * @param bootstrapPort - * Pass {@link #MACH_PORT_NULL} for the default. + * Pass {@link SystemB#MACH_PORT_NULL} for the default. * @param masterPort * A pointer to the master port is returned. Multiple calls to * IOMasterPort will not result in leaking ports (each call to @@ -285,7 +266,7 @@ int IOServiceGetMatchingServices(MachPort masterPort, CFDictionaryRef matchingDi * returned, otherwise zero is returned. The element should be released * by the caller when it is finished. */ - IOService IOIteratorNext(IOIterator iterator); + IORegistryEntry IOIteratorNext(IOIterator iterator); /** * Create a CF representation of a registry entry's property. @@ -463,7 +444,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, C * {@link IOServiceClose}. * @return A return code generated by {@code IOService::newUserClient}. */ - int IOServiceOpen(IOService service, MachPort owningTask, int type, PointerByReference connect); + int IOServiceOpen(IOService service, TaskPort owningTask, int type, PointerByReference connect); /** * Returns the busyState of an IOService. diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java index 34be4914ce..8e050cd597 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java @@ -35,7 +35,7 @@ import com.sun.jna.platform.mac.IOKit.IOIterator; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.IOService; -import com.sun.jna.platform.mac.IOKit.MachPort; +import com.sun.jna.platform.mac.SystemB.MachPort; import com.sun.jna.ptr.PointerByReference; /** @@ -57,11 +57,11 @@ private IOKitUtil() { * ports (each call to {@link IOKit#IOMasterPort} adds another send * right to the port) but it is considered good programming practice to * deallocate the port when you are finished with it, using - * {@link IOKit#IOObjectRelease}. + * {@link SystemB#mach_port_deallocate}. */ public static MachPort getMasterPort() { PointerByReference port = new PointerByReference(); - IO.IOMasterPort(IOKit.MACH_PORT_NULL, port); + IO.IOMasterPort(SystemB.MACH_PORT_NULL, port); return new MachPort(port.getValue()); } @@ -74,7 +74,7 @@ public static MachPort getMasterPort() { public static IORegistryEntry getRoot() { MachPort masterPort = getMasterPort(); IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); - masterPort.release(); + masterPort.deallocate(); return root; } @@ -108,7 +108,7 @@ public static IOService getMatchingService(String serviceName) { public static IOService getMatchingService(CFDictionaryRef matchingDictionary) { MachPort masterPort = getMasterPort(); IOService service = IO.IOServiceGetMatchingService(masterPort, matchingDictionary); - masterPort.release(); + masterPort.deallocate(); return service; } @@ -143,7 +143,7 @@ public static IOIterator getMatchingServices(CFDictionaryRef matchingDictionary) MachPort masterPort = getMasterPort(); PointerByReference serviceIterator = new PointerByReference(); int result = IO.IOServiceGetMatchingServices(masterPort, matchingDictionary, serviceIterator); - masterPort.release(); + masterPort.deallocate(); if (result == 0 && serviceIterator.getValue() != null) { return new IOIterator(serviceIterator.getValue()); } @@ -161,7 +161,7 @@ public static IOIterator getMatchingServices(CFDictionaryRef matchingDictionary) public static CFMutableDictionaryRef getBSDNameMatchingDict(String bsdName) { MachPort masterPort = getMasterPort(); CFMutableDictionaryRef result = IO.IOBSDNameMatching(masterPort, 0, bsdName); - masterPort.release(); + masterPort.deallocate(); return result; } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java index ea6523c776..d32c6d806e 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java @@ -29,12 +29,13 @@ import java.util.HashMap; import java.util.Map; +import com.sun.jna.IntegerType; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; +import com.sun.jna.PointerType; import com.sun.jna.Structure; -import com.sun.jna.platform.mac.IOKit.MachPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; @@ -50,6 +51,7 @@ public interface SystemB extends Library { SystemB INSTANCE = Native.load("System", SystemB.class, OPTIONS); + // host_statistics() int HOST_LOAD_INFO = 1;// System loading stats int HOST_VM_INFO = 2; // Virtual memory stats @@ -98,6 +100,83 @@ public interface SystemB extends Library { // resource.h int RUSAGE_INFO_V2 = 2; + MachPort MACH_PORT_NULL = new MachPort(); + + /** + * Mach ports are the endpoints to Mach-implemented communications channels + * (usually uni-directional message queues, but other types also exist). + *

+ * Unique collections of these endpoints are maintained for each Mach task. Each + * Mach port in the task's collection is given a task-local name to identify it + * - and the the various "rights" held by the task for that specific endpoint. + */ + class MachPort extends PointerType { + public MachPort() { + super(); + } + + public MachPort(Pointer p) { + super(p); + } + + /** + * Casts the port's pointer value to its name. + * + * @return The port's {@link MachPortName}. + */ + public MachPortName castToName() { + return new MachPortName(Pointer.nativeValue(this.getPointer())); + } + + /** + * Convenience method for {@link SystemB#mach_port_deallocate} on this port. + * + * @return 0 if successful, a {@code kern_return_t} code otherwise. + */ + public int deallocate() { + return INSTANCE.mach_port_deallocate(INSTANCE.mach_task_self_ptr(), this.castToName()); + } + } + + /** + * Holds the port name of a host name port (or short: host port). Any task can + * get a send right to the name port of the host running the task using the + * mach_host_self system call. The name port can be used to query information + * about the host, for example the current time. + */ + class HostPort extends MachPort { + } + + /** + * Mach Tasks are units of resource ownership; each task consists of a virtual + * address space, a port right namespace, and one or more threads. (Similar to a + * process.) + */ + class TaskPort extends MachPort { + } + + /** + * The name is Mach port namespace specific. It is used to identify the rights + * held for that port by the task whose namespace is implied [or specifically + * provided]. + *

+ * Use of this type usually implies just a name - no rights. + *

+ * This is an unsigned 32-bit integer type. + */ + class MachPortName extends IntegerType { + private static final long serialVersionUID = 1L; + + /** Create a zero-valued MachPortName. */ + public MachPortName() { + this(0); + } + + /** Create a MachPortName with the given value. */ + public MachPortName(long value) { + super(4, value, true); + } + } @Structure.FieldOrder({ "cpu_ticks" }) public static class HostCpuLoadInfo extends Structure { public int cpu_ticks[] = new int[CPU_STATE_MAX]; @@ -554,13 +633,12 @@ class Timezone extends Structure { int gettimeofday(Timeval tp, Timezone tzp); /** - * The {@code mach_host_self} system call returns the calling thread's host name - * port. It has an effect equivalent to receiving a send right for the host - * port. + * The mach_host_self system call returns the calling thread's host name port. + * It has an effect equivalent to receiving a send right for the host port. * - * @return a pointer to the host's name port + * @return the host's name port */ - MachPort mach_host_self_ptr(); + HostPort mach_host_self_ptr(); /** * The mach_host_self system call returns the calling thread's host name port. @@ -575,13 +653,13 @@ class Timezone extends Structure { int mach_host_self(); /** - * The {@code mach_task_self} system call returns the calling thread's task_self - * port. It has an effect equivalent to receiving a send right for the task's - * kernel port. + * The mach_task_self system call returns the calling thread's task_self port. + * It has an effect equivalent to receiving a send right for the task's kernel + * port. * - * @return a pointer to the task's kernel port + * @return the task's kernel port */ - MachPort mach_task_self_ptr(); + TaskPort mach_task_self_ptr(); /** * The mach_task_self system call returns the calling thread's task_self port. @@ -596,17 +674,28 @@ class Timezone extends Structure { @Deprecated int mach_task_self(); + /** + * Decrement the target port right's user reference count. + * + * @param port + * The port holding the right. + * @param name + * The port's name for the right. + * @return 0 if successful, a {@code kern_return_t} code otherwise. + */ + int mach_port_deallocate(MachPort port, MachPortName name); + /** * The host_page_size function returns the page size for the given host. * - * @param machPort + * @param hostPort * The name (or control) port for the host for which the page size is * desired. * @param pPageSize * The host's page size (in bytes), set on success. * @return 0 on success; sets errno on failure */ - int host_page_size_ptr(MachPort machPort, LongByReference pPageSize); + int host_page_size(HostPort hostPort, LongByReference pPageSize); /** * The host_page_size function returns the page size for the given host. @@ -619,7 +708,7 @@ class Timezone extends Structure { * @return 0 on success; sets errno on failure * * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_page_size_ptr} instead. + * {@link #host_page_size(HostPort, LongByReference)} instead. */ @Deprecated int host_page_size(int machPort, LongByReference pPageSize); @@ -628,12 +717,12 @@ class Timezone extends Structure { * The host_statistics function returns scheduling and virtual memory statistics * concerning the host as specified by hostStat. * - * @param machPort + * @param hostPort * The control port for the host for which information is to be * obtained. * @param hostStat - * The type of statistics desired (HOST_LOAD_INFO, HOST_VM_INFO, or - * HOST_CPU_LOAD_INFO) + * The type of statistics desired ({@link #HOST_LOAD_INFO}, + * {@link #HOST_VM_INFO}, or {@link #HOST_CPU_LOAD_INFO}) * @param stats * Statistics about the specified host. * @param count @@ -641,7 +730,7 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ - int host_statistics_ptr(MachPort machPort, int hostStat, Structure stats, IntByReference count); + int host_statistics(HostPort hostPort, int hostStat, Structure stats, IntByReference count); /** * The host_statistics function returns scheduling and virtual memory statistics @@ -651,8 +740,8 @@ class Timezone extends Structure { * The control port for the host for which information is to be * obtained. * @param hostStat - * The type of statistics desired (HOST_LOAD_INFO, HOST_VM_INFO, or - * HOST_CPU_LOAD_INFO) + * The type of statistics desired ({@link #HOST_LOAD_INFO}, + * {@link #HOST_VM_INFO}, or {@link #HOST_CPU_LOAD_INFO}) * @param stats * Statistics about the specified host. * @param count @@ -661,7 +750,8 @@ class Timezone extends Structure { * @return 0 on success; sets errno on failure * * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_statistics_ptr} instead. + * {@link #host_statistics(HostPort, int, Structure, IntByReference)} + * instead. */ @Deprecated int host_statistics(int machPort, int hostStat, Structure stats, IntByReference count); @@ -670,11 +760,11 @@ class Timezone extends Structure { * The host_statistics64 function returns 64-bit virtual memory statistics * concerning the host as specified by hostStat. * - * @param machPort + * @param hostPort * The control port for the host for which information is to be * obtained. * @param hostStat - * The type of statistics desired (HOST_VM_INFO64) + * The type of statistics desired ({@link #HOST_VM_INFO64}) * @param stats * Statistics about the specified host. * @param count @@ -682,7 +772,7 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ - int host_statistics64_ptr(MachPort machPort, int hostStat, Structure stats, IntByReference count); + int host_statistics64(HostPort hostPort, int hostStat, Structure stats, IntByReference count); /** * The host_statistics64 function returns 64-bit virtual memory statistics @@ -692,7 +782,7 @@ class Timezone extends Structure { * The control port for the host for which information is to be * obtained. * @param hostStat - * The type of statistics desired (HOST_VM_INFO64) + * The type of statistics desired ({@link #HOST_VM_INFO64}) * @param stats * Statistics about the specified host. * @param count @@ -701,7 +791,8 @@ class Timezone extends Structure { * @return 0 on success; sets errno on failure * * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_statistics64_ptr} instead. + * {@link #host_statistics64(HostPort, int, Structure, IntByReference)} + * instead. */ @Deprecated int host_statistics64(int machPort, int hostStat, Structure stats, IntByReference count); @@ -770,20 +861,20 @@ class Timezone extends Structure { int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp, Pointer newp, int newlen); /** - * The sysctlnametomib() function accepts an ASCII representation of the name, - * looks up the integer name vector, and returns the numeric representation in - * the mib array pointed to by mibp. The number of elements in the mib array is - * given by the location specified by sizep before the call, and that location - * gives the number of entries copied after a successful call. The resulting mib - * and size may be used in subsequent sysctl() calls to get the data associated - * with the requested ASCII name. This interface is intended for use by - * applications that want to repeatedly request the same variable (the sysctl() - * function runs in about a third the time as the same request made via the - * sysctlbyname() function). - * + * This function accepts an ASCII representation of the name, looks up the + * integer name vector, and returns the numeric representation in the mib array + * pointed to by mibp. The number of elements in the mib array is given by the + * location specified by sizep before the call, and that location gives the + * number of entries copied after a successful call. The resulting mib and size + * may be used in subsequent sysctl() calls to get the data associated with the + * requested ASCII name. This interface is intended for use by applications that + * want to repeatedly request the same variable (the sysctl() function runs in + * about a third the time as the same request made via the sysctlbyname() + * function). + *

* The number of elements in the mib array can be determined by calling * sysctlnametomib() with the NULL argument for mibp. - * + *

* The sysctlnametomib() function is also useful for fetching mib prefixes. If * size on input is greater than the number of elements written, the array still * contains the additional elements which may be written programmatically. @@ -802,7 +893,7 @@ class Timezone extends Structure { /** * The host_processor_info function returns information about processors. * - * @param machPort + * @param hostPort * The control port for the host for which information is to be * obtained. * @param flavor @@ -815,7 +906,7 @@ class Timezone extends Structure { * Pointer to number of elements in the returned structure * @return 0 on success; sets errno on failure */ - int host_processor_info_ptr(MachPort machPort, int flavor, IntByReference procCount, PointerByReference procInfo, + int host_processor_info(HostPort hostPort, int flavor, IntByReference procCount, PointerByReference procInfo, IntByReference procInfoCount); /** @@ -835,7 +926,8 @@ int host_processor_info_ptr(MachPort machPort, int flavor, IntByReference procCo * @return 0 on success; sets errno on failure * * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_processor_info_ptr} instead. + * {@link #host_processor_info(HostPort, int, IntByReference, PointerByReference, IntByReference)} + * instead. */ @Deprecated int host_processor_info(int machPort, int flavor, IntByReference procCount, PointerByReference procInfo, diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java index dff46269fa..0bc57f3ea8 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java @@ -25,24 +25,19 @@ package com.sun.jna.platform.mac; import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; import com.sun.jna.FunctionMapper; import com.sun.jna.NativeLibrary; public class SystemBFunctionMapper implements FunctionMapper { - private static Collection mappedFunctions = Arrays.asList("mach_host_self_ptr", "mach_task_self_ptr", - "host_page_size_ptr", "host_statistics_ptr", "host_statistics64_ptr", "host_processor_info_ptr"); - /** - * Removes the _ptr suffix from methods which use the properly sized pointer + * Removes the _ptr suffix from methods which return the properly sized pointer * rather than 32-bit int. */ @Override public String getFunctionName(NativeLibrary library, Method method) { String name = method.getName(); - if (mappedFunctions.contains(name)) { + if (name.equals("mach_task_self_ptr") || name.equals("mach_host_self_ptr")) { return name.substring(0, name.length() - 4); } return name; diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 6906ca19ff..85792fee59 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -46,7 +46,7 @@ import com.sun.jna.platform.mac.DiskArbitration.DASessionRef; import com.sun.jna.platform.mac.IOKit.IOIterator; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; -import com.sun.jna.platform.mac.IOKit.MachPort; +import com.sun.jna.platform.mac.SystemB.MachPort; import com.sun.jna.ptr.PointerByReference; public class DiskArbitrationTest { @@ -58,7 +58,7 @@ public class DiskArbitrationTest { @Test public void testDiskCreate() { PointerByReference masterPortPtr = new PointerByReference(); - assertEquals(0, IO.IOMasterPort(IOKit.MACH_PORT_NULL, masterPortPtr)); + assertEquals(0, IO.IOMasterPort(SystemB.MACH_PORT_NULL, masterPortPtr)); MachPort masterPort = new MachPort(masterPortPtr.getValue()); // Create some keys we'll need @@ -146,6 +146,6 @@ public void testDiskCreate() { daMediaBlockSize.release(); session.release(); - assertEquals(0, masterPort.release()); + assertEquals(0, masterPort.deallocate()); } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index a49f61932b..1adb3b8ff2 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -51,7 +51,8 @@ import com.sun.jna.platform.mac.IOKit.IOObject; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.IOService; -import com.sun.jna.platform.mac.IOKit.MachPort; +import com.sun.jna.platform.mac.SystemB.MachPort; +import com.sun.jna.platform.mac.SystemB.TaskPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; @@ -136,7 +137,7 @@ public void testMatching() { cfSerialAsType.release(); assertEquals(0, root.release()); - assertEquals(0, masterPort.release()); + assertEquals(0, masterPort.deallocate()); } @Test @@ -211,7 +212,7 @@ public void testIteratorParentChild() { controllerDevice = iter.next(); } assertEquals(0, iter.release()); - assertEquals(0, masterPort.release()); + assertEquals(0, masterPort.deallocate()); } @Test @@ -222,7 +223,7 @@ public void testIOConnect() { assertNotNull(smcService); PointerByReference connPtr = new PointerByReference(); - MachPort taskSelf = SystemB.INSTANCE.mach_task_self_ptr(); + TaskPort taskSelf = SystemB.INSTANCE.mach_task_self_ptr(); assertEquals(0, IO.IOServiceOpen(smcService, taskSelf, 0, connPtr)); IOConnect conn = new IOConnect(connPtr.getValue()); @@ -232,7 +233,7 @@ public void testIOConnect() { IO.IOServiceClose(conn); assertEquals(0, smcService.release()); - assertEquals(0, masterPort.release()); + assertEquals(0, masterPort.deallocate()); } @Test diff --git a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java index bbee8f818f..e12d7b33ed 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java @@ -27,16 +27,17 @@ import com.sun.jna.Native; import com.sun.jna.Platform; import com.sun.jna.Pointer; -import com.sun.jna.platform.mac.IOKit.MachPort; import com.sun.jna.platform.mac.SystemB.Group; import com.sun.jna.platform.mac.SystemB.HostCpuLoadInfo; import com.sun.jna.platform.mac.SystemB.HostLoadInfo; +import com.sun.jna.platform.mac.SystemB.HostPort; import com.sun.jna.platform.mac.SystemB.IFmsgHdr; import com.sun.jna.platform.mac.SystemB.IFmsgHdr2; import com.sun.jna.platform.mac.SystemB.Passwd; import com.sun.jna.platform.mac.SystemB.ProcTaskAllInfo; import com.sun.jna.platform.mac.SystemB.RUsageInfoV2; import com.sun.jna.platform.mac.SystemB.Statfs; +import com.sun.jna.platform.mac.SystemB.TaskPort; import com.sun.jna.platform.mac.SystemB.Timeval; import com.sun.jna.platform.mac.SystemB.Timezone; import com.sun.jna.platform.mac.SystemB.VMMeter; @@ -94,11 +95,11 @@ public void testSysctl() { } public void testHostPageSize() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); LongByReference pPageSize = new LongByReference(); - int ret = SystemB.INSTANCE.host_page_size_ptr(machPort, pPageSize); + int ret = SystemB.INSTANCE.host_page_size(hostPort, pPageSize); assertEquals(ret, 0); // Probably 4096, definitely a power of 2 assertTrue(pPageSize.getValue() > 0); @@ -106,12 +107,11 @@ public void testHostPageSize() { } public void testVMInfo() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); VMStatistics vmStats = new VMStatistics(); - int ret = SystemB.INSTANCE.host_statistics_ptr(machPort, - SystemB.HOST_VM_INFO, vmStats, + int ret = SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_VM_INFO, vmStats, new IntByReference(vmStats.size() / SystemB.INT_SIZE)); assertEquals(ret, 0); // Nonnegative @@ -119,9 +119,8 @@ public void testVMInfo() { if (Platform.is64Bit()) { VMStatistics64 vmStats64 = new VMStatistics64(); - ret = SystemB.INSTANCE.host_statistics64_ptr(machPort, - SystemB.HOST_VM_INFO, vmStats64, new IntByReference( - vmStats64.size() / SystemB.INT_SIZE)); + ret = SystemB.INSTANCE.host_statistics64(hostPort, SystemB.HOST_VM_INFO, vmStats64, + new IntByReference(vmStats64.size() / SystemB.INT_SIZE)); assertEquals(ret, 0); // Nonnegative assertTrue(vmStats64.free_count >= 0); @@ -129,26 +128,24 @@ SystemB.HOST_VM_INFO, vmStats64, new IntByReference( } public void testCpuLoad() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); HostCpuLoadInfo cpuLoadInfo = new HostCpuLoadInfo(); - int ret = SystemB.INSTANCE.host_statistics_ptr(machPort, - SystemB.HOST_CPU_LOAD_INFO, cpuLoadInfo, new IntByReference( - cpuLoadInfo.size())); + int ret = SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_CPU_LOAD_INFO, cpuLoadInfo, + new IntByReference(cpuLoadInfo.size())); assertEquals(ret, 0); // Should be int[4] assertEquals(cpuLoadInfo.cpu_ticks.length, SystemB.CPU_STATE_MAX); } public void testHostLoad() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); HostLoadInfo hostLoadInfo = new HostLoadInfo(); - int ret = SystemB.INSTANCE.host_statistics_ptr(machPort, - SystemB.HOST_CPU_LOAD_INFO, hostLoadInfo, new IntByReference( - hostLoadInfo.size())); + int ret = SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_CPU_LOAD_INFO, hostLoadInfo, + new IntByReference(hostLoadInfo.size())); assertEquals(ret, 0); // Should be two int[3]'s assertEquals(hostLoadInfo.avenrun.length, 3); @@ -158,27 +155,27 @@ SystemB.HOST_CPU_LOAD_INFO, hostLoadInfo, new IntByReference( } public void testHostProcessorInfo() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); IntByReference procCount = new IntByReference(); PointerByReference procCpuLoadInfo = new PointerByReference(); IntByReference procInfoCount = new IntByReference(); - int ret = SystemB.INSTANCE.host_processor_info_ptr(machPort, - SystemB.PROCESSOR_CPU_LOAD_INFO, procCount, procCpuLoadInfo, - procInfoCount); + int ret = SystemB.INSTANCE.host_processor_info(hostPort, SystemB.PROCESSOR_CPU_LOAD_INFO, procCount, + procCpuLoadInfo, procInfoCount); assertEquals(ret, 0); assertTrue(procCount.getValue() > 0); - assertEquals(procCpuLoadInfo.getValue().getIntArray(0, - procInfoCount.getValue()).length, procInfoCount.getValue()); + assertEquals(procCpuLoadInfo.getValue().getIntArray(0, procInfoCount.getValue()).length, + procInfoCount.getValue()); } public void testMachPorts() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); - machPort = SystemB.INSTANCE.mach_task_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); + assertEquals(Pointer.nativeValue(hostPort.getPointer()) & 0xffffffff, hostPort.castToName().intValue()); + TaskPort taskPort = SystemB.INSTANCE.mach_task_self_ptr(); + assertNotNull(taskPort); } public void testGetLoadAvg() { @@ -209,10 +206,10 @@ public void testTimeofDay() { } public void testVMMeter() { - MachPort machPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(machPort); + HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); + assertNotNull(hostPort); VMMeter vmstats = new VMMeter(); - assertEquals(0, SystemB.INSTANCE.host_statistics_ptr(machPort, SystemB.HOST_VM_INFO, vmstats, + assertEquals(0, SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_VM_INFO, vmstats, new IntByReference(vmstats.size()))); assertTrue(vmstats.v_lookups >= 0); } @@ -332,7 +329,6 @@ public void testIFs() { IFmsgHdr2 if2m = new IFmsgHdr2(p); if2m.read(); - assertTrue(if2m.ifm_index >= 0); assertTrue(if2m.ifm_data.ifi_ibytes >= 0); assertTrue(if2m.ifm_data.ifi_lastchange.tv_usec >= 0); From 06c3257b4a58a4910e9f7e35061d0ac81336e5b0 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Mon, 16 Sep 2019 18:58:24 -0700 Subject: [PATCH 19/28] Mach ports back to 32-bit ints --- .../src/com/sun/jna/platform/mac/IOKit.java | 21 +- .../com/sun/jna/platform/mac/IOKitUtil.java | 27 +-- .../src/com/sun/jna/platform/mac/SystemB.java | 215 +----------------- .../platform/mac/SystemBFunctionMapper.java | 45 ---- .../jna/platform/mac/DiskArbitrationTest.java | 11 +- .../com/sun/jna/platform/mac/IOKitTest.java | 20 +- .../com/sun/jna/platform/mac/SystemBTest.java | 39 ++-- 7 files changed, 61 insertions(+), 317 deletions(-) delete mode 100644 contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 1fc7c5b796..a16013ce2f 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -34,8 +34,6 @@ import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; -import com.sun.jna.platform.mac.SystemB.MachPort; -import com.sun.jna.platform.mac.SystemB.TaskPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; @@ -159,16 +157,17 @@ public IOConnect(Pointer p) { * Returns the mach port used to initiate communication with IOKit. * * @param bootstrapPort - * Pass {@link SystemB#MACH_PORT_NULL} for the default. - * @param masterPort + * Pass 0 for the default. + * @param port * A pointer to the master port is returned. Multiple calls to * IOMasterPort will not result in leaking ports (each call to * IOMasterPort adds another send right to the port) but it is * considered good programming practice to deallocate the port when - * you are finished with it using {@link #IOObjectRelease} + * you are finished with it using + * {@link SystemB#mach_port_deallocate}. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOMasterPort(MachPort bootstrapPort, PointerByReference masterPort); + int IOMasterPort(int bootstrapPort, IntByReference port); /** * Create a matching dictionary that specifies an {@code IOService} class match. @@ -219,7 +218,7 @@ public IOConnect(Pointer p) { * otherwise it should be released with {@link CoreFoundation#CFRelease} * by the caller. */ - CFMutableDictionaryRef IOBSDNameMatching(MachPort masterPort, int options, String bsdName); + CFMutableDictionaryRef IOBSDNameMatching(int masterPort, int options, String bsdName); /** * Look up a registered IOService object that matches a matching dictionary. @@ -236,7 +235,7 @@ public IOConnect(Pointer p) { *

* The service must be released by the caller. */ - IOService IOServiceGetMatchingService(MachPort masterPort, CFDictionaryRef matchingDictionary); + IOService IOServiceGetMatchingService(int masterPort, CFDictionaryRef matchingDictionary); /** * Look up registered IOService objects that match a matching dictionary. @@ -254,7 +253,7 @@ public IOConnect(Pointer p) { * by the caller when the iteration is finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOServiceGetMatchingServices(MachPort masterPort, CFDictionaryRef matchingDictionary, + int IOServiceGetMatchingServices(int masterPort, CFDictionaryRef matchingDictionary, PointerByReference iterator); /** @@ -404,7 +403,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, C * @return A handle to the IORegistryEntry root instance, to be released with * {@link #IOObjectRelease} by the caller, or 0 on failure. */ - IORegistryEntry IORegistryGetRootEntry(MachPort masterPort); + IORegistryEntry IORegistryGetRootEntry(int masterPort); /** * Performs an OSDynamicCast operation on an IOKit object. @@ -444,7 +443,7 @@ CFTypeRef IORegistryEntrySearchCFProperty(IORegistryEntry entry, String plane, C * {@link IOServiceClose}. * @return A return code generated by {@code IOService::newUserClient}. */ - int IOServiceOpen(IOService service, TaskPort owningTask, int type, PointerByReference connect); + int IOServiceOpen(IOService service, int owningTask, int type, PointerByReference connect); /** * Returns the busyState of an IOService. diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java index 8e050cd597..60ce834a9b 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java @@ -35,7 +35,7 @@ import com.sun.jna.platform.mac.IOKit.IOIterator; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.IOService; -import com.sun.jna.platform.mac.SystemB.MachPort; +import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; /** @@ -44,6 +44,7 @@ public class IOKitUtil { private static final IOKit IO = IOKit.INSTANCE; private static final CoreFoundation CF = CoreFoundation.INSTANCE; + private static final SystemB SYS = SystemB.INSTANCE; private IOKitUtil() { } @@ -59,10 +60,10 @@ private IOKitUtil() { * deallocate the port when you are finished with it, using * {@link SystemB#mach_port_deallocate}. */ - public static MachPort getMasterPort() { - PointerByReference port = new PointerByReference(); - IO.IOMasterPort(SystemB.MACH_PORT_NULL, port); - return new MachPort(port.getValue()); + public static int getMasterPort() { + IntByReference port = new IntByReference(); + IO.IOMasterPort(0, port); + return port.getValue(); } /** @@ -72,9 +73,9 @@ public static MachPort getMasterPort() { * {@link IOKit#IOObjectRelease}. */ public static IORegistryEntry getRoot() { - MachPort masterPort = getMasterPort(); + int masterPort = getMasterPort(); IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); - masterPort.deallocate(); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); return root; } @@ -106,9 +107,9 @@ public static IOService getMatchingService(String serviceName) { * {@link IOKit#IOObjectRelease}. */ public static IOService getMatchingService(CFDictionaryRef matchingDictionary) { - MachPort masterPort = getMasterPort(); + int masterPort = getMasterPort(); IOService service = IO.IOServiceGetMatchingService(masterPort, matchingDictionary); - masterPort.deallocate(); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); return service; } @@ -140,10 +141,10 @@ public static IOIterator getMatchingServices(String serviceName) { * {@link IOKit#IOObjectRelease}. */ public static IOIterator getMatchingServices(CFDictionaryRef matchingDictionary) { - MachPort masterPort = getMasterPort(); + int masterPort = getMasterPort(); PointerByReference serviceIterator = new PointerByReference(); int result = IO.IOServiceGetMatchingServices(masterPort, matchingDictionary, serviceIterator); - masterPort.deallocate(); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); if (result == 0 && serviceIterator.getValue() != null) { return new IOIterator(serviceIterator.getValue()); } @@ -159,9 +160,9 @@ public static IOIterator getMatchingServices(CFDictionaryRef matchingDictionary) * should release when finished, using {@link IOKit#IOObjectRelease}. */ public static CFMutableDictionaryRef getBSDNameMatchingDict(String bsdName) { - MachPort masterPort = getMasterPort(); + int masterPort = getMasterPort(); CFMutableDictionaryRef result = IO.IOBSDNameMatching(masterPort, 0, bsdName); - masterPort.deallocate(); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); return result; } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java index d32c6d806e..2fefff44f3 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java @@ -25,16 +25,10 @@ package com.sun.jna.platform.mac; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.sun.jna.IntegerType; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.NativeLong; import com.sun.jna.Pointer; -import com.sun.jna.PointerType; import com.sun.jna.Structure; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; @@ -42,15 +36,7 @@ public interface SystemB extends Library { - Map OPTIONS = Collections.unmodifiableMap(new HashMap() { - private static final long serialVersionUID = 1L; // we're not serializing it - { - put(OPTION_FUNCTION_MAPPER, new SystemBFunctionMapper()); - } - }); - - SystemB INSTANCE = Native.load("System", SystemB.class, OPTIONS); - + SystemB INSTANCE = Native.load("System", SystemB.class); // host_statistics() int HOST_LOAD_INFO = 1;// System loading stats @@ -100,83 +86,6 @@ public interface SystemB extends Library { // resource.h int RUSAGE_INFO_V2 = 2; - MachPort MACH_PORT_NULL = new MachPort(); - - /** - * Mach ports are the endpoints to Mach-implemented communications channels - * (usually uni-directional message queues, but other types also exist). - *

- * Unique collections of these endpoints are maintained for each Mach task. Each - * Mach port in the task's collection is given a task-local name to identify it - * - and the the various "rights" held by the task for that specific endpoint. - */ - class MachPort extends PointerType { - public MachPort() { - super(); - } - - public MachPort(Pointer p) { - super(p); - } - - /** - * Casts the port's pointer value to its name. - * - * @return The port's {@link MachPortName}. - */ - public MachPortName castToName() { - return new MachPortName(Pointer.nativeValue(this.getPointer())); - } - - /** - * Convenience method for {@link SystemB#mach_port_deallocate} on this port. - * - * @return 0 if successful, a {@code kern_return_t} code otherwise. - */ - public int deallocate() { - return INSTANCE.mach_port_deallocate(INSTANCE.mach_task_self_ptr(), this.castToName()); - } - } - - /** - * Holds the port name of a host name port (or short: host port). Any task can - * get a send right to the name port of the host running the task using the - * mach_host_self system call. The name port can be used to query information - * about the host, for example the current time. - */ - class HostPort extends MachPort { - } - - /** - * Mach Tasks are units of resource ownership; each task consists of a virtual - * address space, a port right namespace, and one or more threads. (Similar to a - * process.) - */ - class TaskPort extends MachPort { - } - - /** - * The name is Mach port namespace specific. It is used to identify the rights - * held for that port by the task whose namespace is implied [or specifically - * provided]. - *

- * Use of this type usually implies just a name - no rights. - *

- * This is an unsigned 32-bit integer type. - */ - class MachPortName extends IntegerType { - private static final long serialVersionUID = 1L; - - /** Create a zero-valued MachPortName. */ - public MachPortName() { - this(0); - } - - /** Create a MachPortName with the given value. */ - public MachPortName(long value) { - super(4, value, true); - } - } @Structure.FieldOrder({ "cpu_ticks" }) public static class HostCpuLoadInfo extends Structure { public int cpu_ticks[] = new int[CPU_STATE_MAX]; @@ -638,18 +547,6 @@ class Timezone extends Structure { * * @return the host's name port */ - HostPort mach_host_self_ptr(); - - /** - * The mach_host_self system call returns the calling thread's host name port. - * It has an effect equivalent to receiving a send right for the host port. - * - * @return the host's name port - * - * @deprecated Using the 32-bit return type may corrupt the stack. Use - * {@link #mach_host_self_ptr} instead. - */ - @Deprecated int mach_host_self(); /** @@ -659,19 +556,6 @@ class Timezone extends Structure { * * @return the task's kernel port */ - TaskPort mach_task_self_ptr(); - - /** - * The mach_task_self system call returns the calling thread's task_self port. - * It has an effect equivalent to receiving a send right for the task's kernel - * port. - * - * @return the task's kernel port - * - * @deprecated Using the 32-bit return type may corrupt the stack. Use - * {@link #mach_task_self_ptr} instead. - */ - @Deprecated int mach_task_self(); /** @@ -683,7 +567,7 @@ class Timezone extends Structure { * The port's name for the right. * @return 0 if successful, a {@code kern_return_t} code otherwise. */ - int mach_port_deallocate(MachPort port, MachPortName name); + int mach_port_deallocate(int port, int name); /** * The host_page_size function returns the page size for the given host. @@ -695,23 +579,7 @@ class Timezone extends Structure { * The host's page size (in bytes), set on success. * @return 0 on success; sets errno on failure */ - int host_page_size(HostPort hostPort, LongByReference pPageSize); - - /** - * The host_page_size function returns the page size for the given host. - * - * @param machPort - * The name (or control) port for the host for which the page size is - * desired. - * @param pPageSize - * The host's page size (in bytes), set on success. - * @return 0 on success; sets errno on failure - * - * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_page_size(HostPort, LongByReference)} instead. - */ - @Deprecated - int host_page_size(int machPort, LongByReference pPageSize); + int host_page_size(int hostPort, LongByReference pPageSize); /** * The host_statistics function returns scheduling and virtual memory statistics @@ -730,31 +598,7 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ - int host_statistics(HostPort hostPort, int hostStat, Structure stats, IntByReference count); - - /** - * The host_statistics function returns scheduling and virtual memory statistics - * concerning the host as specified by hostStat. - * - * @param machPort - * The control port for the host for which information is to be - * obtained. - * @param hostStat - * The type of statistics desired ({@link #HOST_LOAD_INFO}, - * {@link #HOST_VM_INFO}, or {@link #HOST_CPU_LOAD_INFO}) - * @param stats - * Statistics about the specified host. - * @param count - * On input, the maximum size of the buffer; on output, the size - * returned (in natural-sized units). - * @return 0 on success; sets errno on failure - * - * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_statistics(HostPort, int, Structure, IntByReference)} - * instead. - */ - @Deprecated - int host_statistics(int machPort, int hostStat, Structure stats, IntByReference count); + int host_statistics(int hostPort, int hostStat, Structure stats, IntByReference count); /** * The host_statistics64 function returns 64-bit virtual memory statistics @@ -772,30 +616,7 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ - int host_statistics64(HostPort hostPort, int hostStat, Structure stats, IntByReference count); - - /** - * The host_statistics64 function returns 64-bit virtual memory statistics - * concerning the host as specified by hostStat. - * - * @param machPort - * The control port for the host for which information is to be - * obtained. - * @param hostStat - * The type of statistics desired ({@link #HOST_VM_INFO64}) - * @param stats - * Statistics about the specified host. - * @param count - * On input, the maximum size of the buffer; on output, the size - * returned (in natural-sized units). - * @return 0 on success; sets errno on failure - * - * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_statistics64(HostPort, int, Structure, IntByReference)} - * instead. - */ - @Deprecated - int host_statistics64(int machPort, int hostStat, Structure stats, IntByReference count); + int host_statistics64(int hostPort, int hostStat, Structure stats, IntByReference count); /** * The sysctl() function retrieves system information and allows processes with @@ -906,31 +727,7 @@ class Timezone extends Structure { * Pointer to number of elements in the returned structure * @return 0 on success; sets errno on failure */ - int host_processor_info(HostPort hostPort, int flavor, IntByReference procCount, PointerByReference procInfo, - IntByReference procInfoCount); - - /** - * The host_processor_info function returns information about processors. - * - * @param machPort - * The control port for the host for which information is to be - * obtained. - * @param flavor - * The type of information requested. - * @param procCount - * Pointer to the number of processors - * @param procInfo - * Pointer to the structure corresponding to the requested flavor - * @param procInfoCount - * Pointer to number of elements in the returned structure - * @return 0 on success; sets errno on failure - * - * @deprecated Using the 32-bit port type argument may corrupt the stack. Use - * {@link #host_processor_info(HostPort, int, IntByReference, PointerByReference, IntByReference)} - * instead. - */ - @Deprecated - int host_processor_info(int machPort, int flavor, IntByReference procCount, PointerByReference procInfo, + int host_processor_info(int hostPort, int flavor, IntByReference procCount, PointerByReference procInfo, IntByReference procInfoCount); /** diff --git a/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java deleted file mode 100644 index 0bc57f3ea8..0000000000 --- a/contrib/platform/src/com/sun/jna/platform/mac/SystemBFunctionMapper.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2019 Daniel Widdis - * - * The contents of this file is dual-licensed under 2 - * alternative Open Source/Free licenses: LGPL 2.1 or later and - * Apache License 2.0. (starting with JNA version 4.0.0). - * - * You can freely decide which license you want to apply to - * the project. - * - * You may obtain a copy of the LGPL License at: - * - * http://www.gnu.org/licenses/licenses.html - * - * A copy is also included in the downloadable source code package - * containing JNA, in file "LGPL2.1". - * - * You may obtain a copy of the Apache License at: - * - * http://www.apache.org/licenses/ - * - * A copy is also included in the downloadable source code package - * containing JNA, in file "AL2.0". - */ -package com.sun.jna.platform.mac; - -import java.lang.reflect.Method; - -import com.sun.jna.FunctionMapper; -import com.sun.jna.NativeLibrary; - -public class SystemBFunctionMapper implements FunctionMapper { - /** - * Removes the _ptr suffix from methods which return the properly sized pointer - * rather than 32-bit int. - */ - @Override - public String getFunctionName(NativeLibrary library, Method method) { - String name = method.getName(); - if (name.equals("mach_task_self_ptr") || name.equals("mach_host_self_ptr")) { - return name.substring(0, name.length() - 4); - } - return name; - } -} diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 85792fee59..b4735543a2 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -46,7 +46,7 @@ import com.sun.jna.platform.mac.DiskArbitration.DASessionRef; import com.sun.jna.platform.mac.IOKit.IOIterator; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; -import com.sun.jna.platform.mac.SystemB.MachPort; +import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.PointerByReference; public class DiskArbitrationTest { @@ -54,12 +54,13 @@ public class DiskArbitrationTest { private static final DiskArbitration DA = DiskArbitration.INSTANCE; private static final CoreFoundation CF = CoreFoundation.INSTANCE; private static final IOKit IO = IOKit.INSTANCE; + private static final SystemB SYS = SystemB.INSTANCE; @Test public void testDiskCreate() { - PointerByReference masterPortPtr = new PointerByReference(); - assertEquals(0, IO.IOMasterPort(SystemB.MACH_PORT_NULL, masterPortPtr)); - MachPort masterPort = new MachPort(masterPortPtr.getValue()); + IntByReference masterPortPtr = new IntByReference(); + assertEquals(0, IO.IOMasterPort(0, masterPortPtr)); + int masterPort = masterPortPtr.getValue(); // Create some keys we'll need CFStringRef daMediaBSDName = CFStringRef.createCFString("DAMediaBSDName"); @@ -146,6 +147,6 @@ public void testDiskCreate() { daMediaBlockSize.release(); session.release(); - assertEquals(0, masterPort.deallocate()); + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 1adb3b8ff2..bfa00016a2 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -51,8 +51,6 @@ import com.sun.jna.platform.mac.IOKit.IOObject; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.IOService; -import com.sun.jna.platform.mac.SystemB.MachPort; -import com.sun.jna.platform.mac.SystemB.TaskPort; import com.sun.jna.ptr.IntByReference; import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; @@ -61,10 +59,11 @@ public class IOKitTest { private static final CoreFoundation CF = CoreFoundation.INSTANCE; private static final IOKit IO = IOKit.INSTANCE; + private static final SystemB SYS = SystemB.INSTANCE; @Test public void testMatching() { - MachPort masterPort = IOKitUtil.getMasterPort(); + int masterPort = IOKitUtil.getMasterPort(); String match = "matching BSD Name"; CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); @@ -137,12 +136,13 @@ public void testMatching() { cfSerialAsType.release(); assertEquals(0, root.release()); - assertEquals(0, masterPort.deallocate()); + assertEquals(0, SYS.mach_port_deallocate(SystemB.INSTANCE.mach_task_self(), + masterPort)); } @Test public void testIteratorParentChild() { - MachPort masterPort = IOKitUtil.getMasterPort(); + int masterPort = IOKitUtil.getMasterPort(); Set uniqueEntryIdSet = new HashSet<>(); // Iterate over USB Controllers. All devices are children of one of @@ -212,18 +212,19 @@ public void testIteratorParentChild() { controllerDevice = iter.next(); } assertEquals(0, iter.release()); - assertEquals(0, masterPort.deallocate()); + assertEquals(0, SYS.mach_port_deallocate(SystemB.INSTANCE.mach_task_self(), + masterPort)); } @Test public void testIOConnect() { - MachPort masterPort = IOKitUtil.getMasterPort(); + int masterPort = IOKitUtil.getMasterPort(); IOService smcService = IOKitUtil.getMatchingService("AppleSMC"); assertNotNull(smcService); PointerByReference connPtr = new PointerByReference(); - TaskPort taskSelf = SystemB.INSTANCE.mach_task_self_ptr(); + int taskSelf = SYS.mach_task_self(); assertEquals(0, IO.IOServiceOpen(smcService, taskSelf, 0, connPtr)); IOConnect conn = new IOConnect(connPtr.getValue()); @@ -233,7 +234,8 @@ public void testIOConnect() { IO.IOServiceClose(conn); assertEquals(0, smcService.release()); - assertEquals(0, masterPort.deallocate()); + assertEquals(0, SYS.mach_port_deallocate(SystemB.INSTANCE.mach_task_self(), + masterPort)); } @Test diff --git a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java index e12d7b33ed..f24040314f 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/SystemBTest.java @@ -23,6 +23,8 @@ */ package com.sun.jna.platform.mac; +import static org.junit.Assert.assertNotEquals; + import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Platform; @@ -30,14 +32,12 @@ import com.sun.jna.platform.mac.SystemB.Group; import com.sun.jna.platform.mac.SystemB.HostCpuLoadInfo; import com.sun.jna.platform.mac.SystemB.HostLoadInfo; -import com.sun.jna.platform.mac.SystemB.HostPort; import com.sun.jna.platform.mac.SystemB.IFmsgHdr; import com.sun.jna.platform.mac.SystemB.IFmsgHdr2; import com.sun.jna.platform.mac.SystemB.Passwd; import com.sun.jna.platform.mac.SystemB.ProcTaskAllInfo; import com.sun.jna.platform.mac.SystemB.RUsageInfoV2; import com.sun.jna.platform.mac.SystemB.Statfs; -import com.sun.jna.platform.mac.SystemB.TaskPort; import com.sun.jna.platform.mac.SystemB.Timeval; import com.sun.jna.platform.mac.SystemB.Timezone; import com.sun.jna.platform.mac.SystemB.VMMeter; @@ -54,10 +54,7 @@ /** * Exercise the {@link SystemB} class. - * - * @author widdis@gmail.com */ -// @SuppressWarnings("unused") public class SystemBTest extends TestCase { public void testSysctl() { @@ -95,8 +92,8 @@ public void testSysctl() { } public void testHostPageSize() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); + int hostPort = SystemB.INSTANCE.mach_host_self(); + assertNotEquals(0, hostPort); LongByReference pPageSize = new LongByReference(); int ret = SystemB.INSTANCE.host_page_size(hostPort, pPageSize); @@ -107,8 +104,8 @@ public void testHostPageSize() { } public void testVMInfo() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); + int hostPort = SystemB.INSTANCE.mach_host_self(); + assertNotEquals(0, hostPort); VMStatistics vmStats = new VMStatistics(); int ret = SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_VM_INFO, vmStats, @@ -128,8 +125,8 @@ public void testVMInfo() { } public void testCpuLoad() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); + int hostPort = SystemB.INSTANCE.mach_host_self(); + assertNotEquals(0, hostPort); HostCpuLoadInfo cpuLoadInfo = new HostCpuLoadInfo(); int ret = SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_CPU_LOAD_INFO, cpuLoadInfo, @@ -140,8 +137,8 @@ public void testCpuLoad() { } public void testHostLoad() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); + int hostPort = SystemB.INSTANCE.mach_host_self(); + assertNotEquals(0, hostPort); HostLoadInfo hostLoadInfo = new HostLoadInfo(); int ret = SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_CPU_LOAD_INFO, hostLoadInfo, @@ -155,8 +152,8 @@ public void testHostLoad() { } public void testHostProcessorInfo() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); + int hostPort = SystemB.INSTANCE.mach_host_self(); + assertNotEquals(0, hostPort); IntByReference procCount = new IntByReference(); PointerByReference procCpuLoadInfo = new PointerByReference(); @@ -170,14 +167,6 @@ public void testHostProcessorInfo() { procInfoCount.getValue()); } - public void testMachPorts() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); - assertEquals(Pointer.nativeValue(hostPort.getPointer()) & 0xffffffff, hostPort.castToName().intValue()); - TaskPort taskPort = SystemB.INSTANCE.mach_task_self_ptr(); - assertNotNull(taskPort); - } - public void testGetLoadAvg() { double[] loadavg = new double[3]; int retval = SystemB.INSTANCE.getloadavg(loadavg, 3); @@ -206,8 +195,8 @@ public void testTimeofDay() { } public void testVMMeter() { - HostPort hostPort = SystemB.INSTANCE.mach_host_self_ptr(); - assertNotNull(hostPort); + int hostPort = SystemB.INSTANCE.mach_host_self(); + assertNotEquals(0, hostPort); VMMeter vmstats = new VMMeter(); assertEquals(0, SystemB.INSTANCE.host_statistics(hostPort, SystemB.HOST_VM_INFO, vmstats, new IntByReference(vmstats.size()))); From 1ab47ac875d71c72c74c434234cd10c4bd882e3b Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 17 Sep 2019 11:50:20 -0700 Subject: [PATCH 20/28] Simplify tests and enable null return util --- .../com/sun/jna/platform/mac/IOKitUtil.java | 65 +++++++++---------- .../jna/platform/mac/CoreFoundationTest.java | 25 +++---- .../jna/platform/mac/DiskArbitrationTest.java | 23 ++++--- 3 files changed, 53 insertions(+), 60 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java index 60ce834a9b..246abab48f 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java @@ -173,7 +173,8 @@ public static CFMutableDictionaryRef getBSDNameMatchingDict(String bsdName) { * A handle to the registry entry * @param key * The string name of the key to retrieve - * @return The value of the registry entry if it exists;{@code null} otherwise + * @return The value of the registry entry if it exists; {@code null} + * otherwise */ public static String getIORegistryStringProperty(IORegistryEntry entry, String key) { String value = null; @@ -198,18 +199,16 @@ public static String getIORegistryStringProperty(IORegistryEntry entry, String k * A handle to the registry entry * @param key * The string name of the key to retrieve - * @param defaultValue - * The value to return if unsuccessful - * @return The value of the registry entry if it exists. + * @return The value of the registry entry if it exists; {@code null} + * otherwise *

- * This method assumes a 64-bit integer is stored and does not do type - * checking. If this object's type differs from the return type, and the - * conversion is lossy or the return value is out of range, then this - * method returns an approximate value. If the value does not exist, the - * {@code defaultValue} is returned. + * This method assumes a 64-bit integer is stored and does not do + * type checking. If this object's type differs from the return + * type, and the conversion is lossy or the return value is out of + * range, then this method returns an approximate value. */ - public static long getIORegistryLongProperty(IORegistryEntry entry, String key, long defaultValue) { - long value = defaultValue; + public static Long getIORegistryLongProperty(IORegistryEntry entry, String key) { + Long value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), 0); @@ -231,18 +230,16 @@ public static long getIORegistryLongProperty(IORegistryEntry entry, String key, * A handle to the registry entry * @param key * The string name of the key to retrieve - * @param defaultValue - * The value to return if unsuccessful - * @return The value of the registry entry if it exists. + * @return The value of the registry entry if it exists; {@code null} + * otherwise *

- * This method assumes a 32-bit integer is stored and does not do type - * checking. If this object's type differs from the return type, and the - * conversion is lossy or the return value is out of range, then this - * method returns an approximate value. If the value does not exist, the - * {@code defaultValue} is returned. + * This method assumes a 32-bit integer is stored and does not do + * type checking. If this object's type differs from the return + * type, and the conversion is lossy or the return value is out of + * range, then this method returns an approximate value. */ - public static int getIORegistryIntProperty(IORegistryEntry entry, String key, int defaultValue) { - int value = defaultValue; + public static Integer getIORegistryIntProperty(IORegistryEntry entry, String key) { + Integer value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), 0); @@ -264,18 +261,16 @@ public static int getIORegistryIntProperty(IORegistryEntry entry, String key, in * A handle to the registry entry * @param key * The string name of the key to retrieve - * @param defaultValue - * The value to return if unsuccessful - * @return The value of the registry entry if it exists. + * @return The value of the registry entry if it exists; {@code null} + * otherwise *

- * This method assumes a floating point value is stored and does not do - * type checking. If this object's type differs from the return type, - * and the conversion is lossy or the return value is out of range, then - * this method returns an approximate value. If the value does not - * exist, the {@code defaultValue} is returned. + * This method assumes a floating point value is stored and does not + * do type checking. If this object's type differs from the return + * type, and the conversion is lossy or the return value is out of + * range, then this method returns an approximate value. */ - public static double getIORegistryIntProperty(IORegistryEntry entry, String key, double defaultValue) { - double value = defaultValue; + public static Double getIORegistryDoubleProperty(IORegistryEntry entry, String key) { + Double value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), 0); @@ -297,13 +292,11 @@ public static double getIORegistryIntProperty(IORegistryEntry entry, String key, * A handle to the registry entry * @param key * The string name of the key to retrieve - * @param defaultValue - * The value to return if unsuccessful - * @return The value of the registry entry if it exists; {@code defaultValue} + * @return The value of the registry entry if it exists; {@code null} * otherwise */ - public static boolean getIORegistryBooleanProperty(IORegistryEntry entry, String key, boolean defaultValue) { - boolean value = defaultValue; + public static Boolean getIORegistryBooleanProperty(IORegistryEntry entry, String key) { + Boolean value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), 0); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index a6d1a173a8..566a10eed2 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -30,7 +30,8 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.util.ArrayList; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; import java.util.List; import java.util.Random; @@ -58,21 +59,19 @@ public class CoreFoundationTest { private static final CoreFoundation CF = CoreFoundation.INSTANCE; @Test - public void testCFStringRef() { + 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()); - Memory mem = new Memory(awesome.getBytes().length + 1); + byte[] awesomeArr = awesome.getBytes("UTF-8"); + Memory mem = new Memory(awesomeArr.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); - byte[] awesomeArr = awesome.getBytes(); - for (int i = 0; i < awesomeArr.length; i++) { - assertEquals(awesomeArr[i], awesomeBytes[i]); - } + assertArrayEquals(awesomeArr, awesomeBytes); // Essentially a toString, can't rely on format but should contain the string CFStringRef desc = CF.CFCopyDescription(cfAwesome); assertTrue(desc.stringValue().contains(awesome)); @@ -113,9 +112,7 @@ public void testCFRetainCount() { assertEquals(2, CF.CFGetRetainCount(cfE).intValue()); assertEquals(3, CF.CFGetRetainCount(cfPi).intValue()); - List irrationalReferences = new ArrayList<>(); - irrationalReferences.add(cfE); - irrationalReferences.add(cfPi); + List irrationalReferences = Arrays.asList(cfE, cfPi); for (CFTypeRef value : irrationalReferences) { value.release(); } @@ -161,16 +158,14 @@ public void testCFData() { new Random().nextBytes(randomBytes); // Fill native memory with them Memory nativeBytes = new Memory(size); - for (int i = 0; i < size; i++) { - nativeBytes.setByte(i, randomBytes[i]); - } + nativeBytes.write(0, randomBytes, 0, randomBytes.length); // Create a CF reference to the data CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, new CFIndex(size)); - long dataSize = CF.CFDataGetLength(cfData).intValue(); + int dataSize = CF.CFDataGetLength(cfData).intValue(); assertEquals(size, dataSize); // Read it back out and convert to an array Pointer bytes = CF.CFDataGetBytePtr(cfData); - byte[] dataBytes = bytes.getByteArray(0, (int) dataSize); + byte[] dataBytes = bytes.getByteArray(0, dataSize); assertArrayEquals(randomBytes, dataBytes); cfData.release(); } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index b4735543a2..eb65660a2c 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -68,13 +68,14 @@ public void testDiskCreate() { CFStringRef daMediaLeaf = CFStringRef.createCFString("DAMediaLeaf"); CFStringRef daMediaSize = CFStringRef.createCFString("DAMediaSize"); CFStringRef daMediaBlockSize = CFStringRef.createCFString("DAMediaBlockSize"); + CFStringRef wholeKey = CFStringRef.createCFString("Whole"); // Open a DiskArbitration session DASessionRef session = DA.DASessionCreate(CF.CFAllocatorGetDefault()); assertNotNull(session); // Get IOMedia objects representing whole drives and save the BSD Name - List bsdNames = new ArrayList<>(); + List bsdNames = new ArrayList(); PointerByReference iterPtr = new PointerByReference(); CFMutableDictionaryRef dict = IOKit.INSTANCE.IOServiceMatching("IOMedia"); @@ -83,24 +84,27 @@ public void testDiskCreate() { IOIterator iter = new IOIterator(iterPtr.getValue()); IORegistryEntry media = iter.next(); while (media != null) { - CFStringRef wholeKey = CFStringRef.createCFString("Whole"); CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); - wholeKey.release(); assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); if (cfWholeBool.booleanValue()) { // check that util boolean matches - assertTrue(IOKitUtil.getIORegistryBooleanProperty(media, "Whole", false)); - // check long and int values for major - long majorLong = IOKitUtil.getIORegistryLongProperty(media, "BSD Major", Long.MAX_VALUE); - int majorInt = IOKitUtil.getIORegistryIntProperty(media, "BSD Major", Integer.MAX_VALUE); - assertEquals(majorLong, majorInt); + assertTrue(IOKitUtil.getIORegistryBooleanProperty(media, "Whole")); + // check long, int, double values for major + Long majorLong = IOKitUtil.getIORegistryLongProperty(media, "BSD Major"); + Integer majorInt = IOKitUtil.getIORegistryIntProperty(media, "BSD Major"); + Double majorDouble = IOKitUtil.getIORegistryDoubleProperty(media, "BSD Major"); + assertNotNull(majorLong); + assertNotNull(majorInt); + assertNotNull(majorDouble); + assertEquals(majorLong.intValue(), majorInt.intValue()); + assertEquals(majorDouble.doubleValue(), majorInt.doubleValue(), 1e-15); DADiskRef disk = DA.DADiskCreateFromIOMedia(CF.CFAllocatorGetDefault(), session, media); bsdNames.add(DA.DADiskGetBSDName(disk)); disk.release(); } else { - assertFalse(IOKitUtil.getIORegistryBooleanProperty(media, "Whole", true)); + assertFalse(IOKitUtil.getIORegistryBooleanProperty(media, "Whole")); } cfWhole.release(); assertEquals(0, media.release()); @@ -140,6 +144,7 @@ public void testDiskCreate() { diskInfo.release(); disk.release(); } + wholeKey.release(); daMediaBSDName.release(); daMediaWhole.release(); daMediaLeaf.release(); From 8b49dea15b372c2d519fa1c297f5a782fa5f8f70 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 17 Sep 2019 18:24:44 -0700 Subject: [PATCH 21/28] Move registry getters to IORegistryEntry class --- .../src/com/sun/jna/platform/mac/IOKit.java | 161 +++++++++++++++- .../com/sun/jna/platform/mac/IOKitUtil.java | 179 ------------------ .../jna/platform/mac/DiskArbitrationTest.java | 10 +- .../com/sun/jna/platform/mac/IOKitTest.java | 8 +- 4 files changed, 165 insertions(+), 193 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index a16013ce2f..b47bb96678 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -30,8 +30,11 @@ import com.sun.jna.PointerType; import com.sun.jna.platform.mac.CoreFoundation.CFAllocatorRef; import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; +import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; +import com.sun.jna.platform.mac.CoreFoundation.CFDataRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.ptr.IntByReference; @@ -67,7 +70,7 @@ public interface IOKit extends Library { * functions in IOKitLib may be used with io_service_t's as well as * io_registry_t's. There are functions available to introspect the class of the * kernel object which any io_object_t et al. represents. IOKit objects returned - * by all functions should be released with IOObjectRelease. + * by all functions should be released with {@link IOKit#IOObjectRelease}. */ class IOObject extends PointerType { public IOObject() { @@ -104,8 +107,8 @@ public IOIterator(Pointer p) { * Convenience method for {@link IOKit#IOIteratorNext} on this object. * * @return If the iterator handle is valid, the next element in the iteration is - * returned, otherwise zero is returned. The element should be released - * by the caller when it is finished. + * returned, otherwise {@code null} is returned. The element should be + * released by the caller when it is finished. */ public IORegistryEntry next() { return INSTANCE.IOIteratorNext(this); @@ -123,6 +126,155 @@ public IORegistryEntry() { public IORegistryEntry(Pointer p) { super(p); } + + /** + * Convenience method to get a {@link java.lang.String} value from this IO + * Registry Entry. + * + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + */ + public String getStringProperty(String key) { + String value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFStringRef valueAsCFString = new CFStringRef(valueAsCFType.getPointer()); + value = valueAsCFString.stringValue(); + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a {@link java.lang.Long} value from this IO + * Registry Entry. + * + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + *

+ * This method assumes a 64-bit integer is stored and does not do type + * checking. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this + * method returns an approximate value. + */ + public Long getLongProperty(String key) { + Long value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); + value = valueAsCFNumber.longValue(); + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get an {@link java.lang.Integer} value from this IO + * Registry Entry. + * + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + *

+ * This method assumes a 32-bit integer is stored and does not do type + * checking. If this object's type differs from the return type, and the + * conversion is lossy or the return value is out of range, then this + * method returns an approximate value. + */ + public Integer getIntegerProperty(String key) { + Integer value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); + value = valueAsCFNumber.intValue(); + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a {@link java.lang.Double} value from this IO + * Registry Entry. + * + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + *

+ * This method assumes a floating point value is stored and does not do + * type checking. If this object's type differs from the return type, + * and the conversion is lossy or the return value is out of range, then + * this method returns an approximate value. + */ + public Double getDoubleProperty(String key) { + Double value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); + value = valueAsCFNumber.doubleValue(); + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a {@link java.lang.Boolean} value from this IO + * Registry Entry. + * + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + */ + public Boolean getBooleanProperty(String key) { + Boolean value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFBooleanRef valueAsCFBoolean = new CFBooleanRef(valueAsCFType.getPointer()); + value = valueAsCFBoolean.booleanValue(); + valueAsCFType.release(); + } + return value; + } + + /** + * Convenience method to get a {@link java.lang.byte} array value from this IO + * Registry Entry. + * + * @param key + * The string name of the key to retrieve + * @return The value of the registry entry if it exists; {@code null} otherwise + */ + public byte[] getByteArrayProperty(String key) { + byte[] value = null; + CFStringRef keyAsCFString = CFStringRef.createCFString(key); + CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); + int length = CoreFoundation.INSTANCE.CFDataGetLength(valueAsCFData).intValue(); + Pointer p = CoreFoundation.INSTANCE.CFDataGetBytePtr(valueAsCFData); + value = p.getByteArray(0, length); + valueAsCFType.release(); + } + return value; + } } /** @@ -253,8 +405,7 @@ public IOConnect(Pointer p) { * by the caller when the iteration is finished. * @return 0 if successful, otherwise a {@code kern_return_t} error code. */ - int IOServiceGetMatchingServices(int masterPort, CFDictionaryRef matchingDictionary, - PointerByReference iterator); + int IOServiceGetMatchingServices(int masterPort, CFDictionaryRef matchingDictionary, PointerByReference iterator); /** * Returns the next object in an iteration. diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java index 246abab48f..dbe567b0ab 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java @@ -24,14 +24,8 @@ */ package com.sun.jna.platform.mac; -import com.sun.jna.Pointer; -import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; -import com.sun.jna.platform.mac.CoreFoundation.CFDataRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; -import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; -import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; -import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.platform.mac.IOKit.IOIterator; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.IOService; @@ -43,7 +37,6 @@ */ public class IOKitUtil { private static final IOKit IO = IOKit.INSTANCE; - private static final CoreFoundation CF = CoreFoundation.INSTANCE; private static final SystemB SYS = SystemB.INSTANCE; private IOKitUtil() { @@ -165,176 +158,4 @@ public static CFMutableDictionaryRef getBSDNameMatchingDict(String bsdName) { SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); return result; } - - /** - * Convenience method to get a String value from an IO Registry - * - * @param entry - * A handle to the registry entry - * @param key - * The string name of the key to retrieve - * @return The value of the registry entry if it exists; {@code null} - * otherwise - */ - public static String getIORegistryStringProperty(IORegistryEntry entry, String key) { - String value = null; - CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), - 0); - if (valueAsCFType != null && valueAsCFType.getPointer() != null) { - CFStringRef valueAsCFString = new CFStringRef(valueAsCFType.getPointer()); - value = valueAsCFString.stringValue(); - } - keyAsCFString.release(); - if (valueAsCFType != null) { - valueAsCFType.release(); - } - return value; - } - - /** - * Convenience method to get a {@code long} value from an IO Registry. - * - * @param entry - * A handle to the registry entry - * @param key - * The string name of the key to retrieve - * @return The value of the registry entry if it exists; {@code null} - * otherwise - *

- * This method assumes a 64-bit integer is stored and does not do - * type checking. If this object's type differs from the return - * type, and the conversion is lossy or the return value is out of - * range, then this method returns an approximate value. - */ - public static Long getIORegistryLongProperty(IORegistryEntry entry, String key) { - Long value = null; - CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), - 0); - if (valueAsCFType != null && valueAsCFType.getPointer() != null) { - CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); - value = valueAsCFNumber.longValue(); - } - keyAsCFString.release(); - if (valueAsCFType != null) { - valueAsCFType.release(); - } - return value; - } - - /** - * Convenience method to get an {@code int} value from an IO Registry. - * - * @param entry - * A handle to the registry entry - * @param key - * The string name of the key to retrieve - * @return The value of the registry entry if it exists; {@code null} - * otherwise - *

- * This method assumes a 32-bit integer is stored and does not do - * type checking. If this object's type differs from the return - * type, and the conversion is lossy or the return value is out of - * range, then this method returns an approximate value. - */ - public static Integer getIORegistryIntProperty(IORegistryEntry entry, String key) { - Integer value = null; - CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), - 0); - if (valueAsCFType != null) { - CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); - value = valueAsCFNumber.intValue(); - } - keyAsCFString.release(); - if (valueAsCFType != null) { - valueAsCFType.release(); - } - return value; - } - - /** - * Convenience method to get a {@code double} value from an IO Registry. - * - * @param entry - * A handle to the registry entry - * @param key - * The string name of the key to retrieve - * @return The value of the registry entry if it exists; {@code null} - * otherwise - *

- * This method assumes a floating point value is stored and does not - * do type checking. If this object's type differs from the return - * type, and the conversion is lossy or the return value is out of - * range, then this method returns an approximate value. - */ - public static Double getIORegistryDoubleProperty(IORegistryEntry entry, String key) { - Double value = null; - CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), - 0); - if (valueAsCFType != null) { - CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); - value = valueAsCFNumber.doubleValue(); - } - keyAsCFString.release(); - if (valueAsCFType != null) { - valueAsCFType.release(); - } - return value; - } - - /** - * Convenience method to get a Boolean value from an IO Registry. - * - * @param entry - * A handle to the registry entry - * @param key - * The string name of the key to retrieve - * @return The value of the registry entry if it exists; {@code null} - * otherwise - */ - public static Boolean getIORegistryBooleanProperty(IORegistryEntry entry, String key) { - Boolean value = null; - CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), - 0); - if (valueAsCFType != null) { - CFBooleanRef valueAsCFBoolean = new CFBooleanRef(valueAsCFType.getPointer()); - value = valueAsCFBoolean.booleanValue(); - } - keyAsCFString.release(); - if (valueAsCFType != null) { - valueAsCFType.release(); - } - return value; - } - - /** - * Convenience method to get a byte array value from an IO Registry. - * - * @param entry - * A handle to the registry entry - * @param key - * The string name of the key to retrieve - * @return The value of the registry entry if it exists; {@code null} otherwise - */ - public static byte[] getIORegistryByteArrayProperty(IORegistryEntry entry, String key) { - byte[] value = null; - CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = IO.IORegistryEntryCreateCFProperty(entry, keyAsCFString, CF.CFAllocatorGetDefault(), - 0); - if (valueAsCFType != null) { - CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); - int length = CF.CFDataGetLength(valueAsCFData).intValue(); - Pointer p = CF.CFDataGetBytePtr(valueAsCFData); - value = p.getByteArray(0, length); - } - keyAsCFString.release(); - if (valueAsCFType != null) { - valueAsCFType.release(); - } - return value; - } } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index eb65660a2c..70acf03d20 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -89,11 +89,11 @@ public void testDiskCreate() { CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); if (cfWholeBool.booleanValue()) { // check that util boolean matches - assertTrue(IOKitUtil.getIORegistryBooleanProperty(media, "Whole")); + assertTrue(media.getBooleanProperty("Whole")); // check long, int, double values for major - Long majorLong = IOKitUtil.getIORegistryLongProperty(media, "BSD Major"); - Integer majorInt = IOKitUtil.getIORegistryIntProperty(media, "BSD Major"); - Double majorDouble = IOKitUtil.getIORegistryDoubleProperty(media, "BSD Major"); + Long majorLong = media.getLongProperty("BSD Major"); + Integer majorInt = media.getIntegerProperty("BSD Major"); + Double majorDouble = media.getDoubleProperty("BSD Major"); assertNotNull(majorLong); assertNotNull(majorInt); assertNotNull(majorDouble); @@ -104,7 +104,7 @@ public void testDiskCreate() { bsdNames.add(DA.DADiskGetBSDName(disk)); disk.release(); } else { - assertFalse(IOKitUtil.getIORegistryBooleanProperty(media, "Whole")); + assertFalse(media.getBooleanProperty("Whole")); } cfWhole.release(); assertEquals(0, media.release()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index bfa00016a2..adf6d73306 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -103,7 +103,7 @@ public void testMatching() { String serialNumber = cfSerial.stringValue(); // Test util method for the same thing - String serialNumberViaUtil = IOKitUtil.getIORegistryStringProperty(platformExpert, "IOPlatformSerialNumber"); + String serialNumberViaUtil = platformExpert.getStringProperty("IOPlatformSerialNumber"); assertEquals(serialNumber, serialNumberViaUtil); assertEquals(12, serialNumber.length()); @@ -136,7 +136,7 @@ public void testMatching() { cfSerialAsType.release(); assertEquals(0, root.release()); - assertEquals(0, SYS.mach_port_deallocate(SystemB.INSTANCE.mach_task_self(), + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } @@ -212,7 +212,7 @@ public void testIteratorParentChild() { controllerDevice = iter.next(); } assertEquals(0, iter.release()); - assertEquals(0, SYS.mach_port_deallocate(SystemB.INSTANCE.mach_task_self(), + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } @@ -234,7 +234,7 @@ public void testIOConnect() { IO.IOServiceClose(conn); assertEquals(0, smcService.release()); - assertEquals(0, SYS.mach_port_deallocate(SystemB.INSTANCE.mach_task_self(), + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } From 1c2f2136f39932b7dd4d4b10d1dd55c303fde30b Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 17 Sep 2019 20:23:25 -0700 Subject: [PATCH 22/28] CoreFoundation convenience methods --- .../sun/jna/platform/mac/CoreFoundation.java | 173 +++++++++++++++++- .../src/com/sun/jna/platform/mac/IOKit.java | 4 +- .../jna/platform/mac/CoreFoundationTest.java | 37 ++-- .../jna/platform/mac/DiskArbitrationTest.java | 9 +- .../com/sun/jna/platform/mac/IOKitTest.java | 29 ++- 5 files changed, 209 insertions(+), 43 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index f8a77adb6a..1c67a775a8 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -80,6 +80,13 @@ public CFTypeRef(Pointer p) { super(p); } + /** + * Convenience method for {@link CoreFoundation#CFGetTypeID} on this object. + */ + public CFTypeID getTypeID() { + return INSTANCE.CFGetTypeID(this); + } + /** * Convenience method for {@link CoreFoundation#CFRetain} on this object. */ @@ -276,6 +283,26 @@ public CFArrayRef() { public CFArrayRef(Pointer p) { super(p); } + + /** + * Convenience method for {@link #CFArrayGetCount} on this object + * + * @return The number of values in this array. + */ + public CFIndex getCount() { + return INSTANCE.CFArrayGetCount(this); + } + + /** + * Convenience method for {@link #CFArrayGetValueAtIndex} on this object + * + * @param idx + * The index of the value to retrieve. + * @return The value at the {@code idx} index. + */ + public Pointer getValueAtIndex(CFIndex idx) { + return INSTANCE.CFArrayGetValueAtIndex(this, idx); + } } /** @@ -289,6 +316,25 @@ public CFDataRef() { public CFDataRef(Pointer p) { super(p); } + + /** + * Convenience method for {@link #CFDataGetLength} on this object + * + * @return An index that specifies the number of bytes associated with this + * object. + */ + public CFIndex getLength() { + return INSTANCE.CFDataGetLength(this); + } + + /** + * Convenience method for {@link #CFDataGetBytePtr} on this object + * + * @return A read-only pointer to the bytes associated with this object. + */ + public Pointer getBytePtr() { + return INSTANCE.CFDataGetBytePtr(this); + } } /** @@ -302,6 +348,34 @@ public CFDictionaryRef() { public CFDictionaryRef(Pointer p) { super(p); } + + /** + * Convenience method for {@link CoreFoundation#CFDictionaryGetValue} on this + * object. + * + * @param key + * The key for which to find a match. + * @return The value associated with key, or {@code null} if no key-value pair + * matching key exists. + */ + public Pointer getValue(PointerType key) { + return INSTANCE.CFDictionaryGetValue(this, key); + } + + /** + * Convenience method for {@link CoreFoundation#CFDictionaryGetValueIfPresent} + * on this object. + * + * @param key + * The key for which to find a match. + * @param value + * A pointer to memory which, on return, is filled with the + * pointer-sized value if a matching key is found. + * @return 1 if a matching key was found, otherwise 0 + */ + public byte getValueIfPresent(PointerType key, PointerByReference value) { + return INSTANCE.CFDictionaryGetValueIfPresent(this, key, value); + } } /** @@ -315,6 +389,21 @@ public CFMutableDictionaryRef() { public CFMutableDictionaryRef(Pointer p) { super(p); } + + /** + * Convenience method for {@link CoreFoundation#CFDictionarySetValue} on this + * object. + * + * @param theDict + * The dictionary to modify. + * @param key + * The key of the value to set. + * @param value + * The value to add to or replace . + */ + public void setValue(PointerType key, PointerType value) { + INSTANCE.CFDictionarySetValue(this, key, value); + } } /** @@ -387,13 +476,25 @@ public CFIndex(long value) { } /** - * Returns the number of values currently in an array. - * - * @param theArray - * a {@link CFArrayRef} object. - * @return The number of values in {@code array}. + * A type for unique, constant integer values that identify particular Core + * Foundation opaque types. + *

+ * Because the value for a type ID can change from release to release, your code + * should not rely on stored or hard-coded type IDs nor should it hard-code any + * observed properties of a type ID (such as, for example, it being a small + * integer). */ - CFIndex CFArrayGetCount(CFArrayRef theArray); + class CFTypeID extends NativeLong { + private static final long serialVersionUID = 1L; + + public CFTypeID() { + super(); + } + + public CFTypeID(long value) { + super(value); + } + } /** * Creates a string from a buffer of Unicode characters. @@ -711,6 +812,15 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, CFIndex c */ byte CFBooleanGetValue(CFBooleanRef bool); + /** + * Returns the number of values currently in an array. + * + * @param theArray + * a {@link CFArrayRef} object. + * @return The number of values in {@code array}. + */ + CFIndex CFArrayGetCount(CFArrayRef theArray); + /** * Retrieves a value at a given index. * @@ -802,4 +912,55 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef alloc, CFIndex c * @return A read-only pointer to the bytes associated with {@code theData}. */ Pointer CFDataGetBytePtr(CFDataRef theData); + + /** + * Returns the type of a {@code CFType} object. + * + * @param theObject + * The {@code CFData} object to examine. + * @return A value of type {@link CFTypeID} that identifies the opaque type of + * {@code cf}. + */ + CFTypeID CFGetTypeID(CFTypeRef theObject); + + /** + * @return The type identifier for the {@code CFArray} opaque type. + */ + CFTypeID CFArrayGetTypeID(); + + /** + * @return The type identifier for the {@code CFBoolean} opaque type. + */ + CFTypeID CFBooleanGetTypeID(); + + /** + * @return The type identifier for the {@code CFDate} opaque type. + */ + CFTypeID CFDateGetTypeID(); + + /** + * @return The type identifier for the {@code CFData} opaque type. + *

+ * {@code CFMutableData} objects have the same type identifier as + * {@code CFData} objects. + */ + CFTypeID CFDataGetTypeID(); + + /** + * @return The type identifier for the {@code CFDictionary} opaque type. + *

+ * {@code CFMutableDictionary} objects have the same type identifier as + * {@code CFDictionary} objects. + */ + CFTypeID CFDictionaryGetTypeID(); + + /** + * @return The type identifier for the {@code CFNumber} opaque type. + */ + CFTypeID CFNumberGetTypeID(); + + /** + * @return The type identifier for the {@code CFString} opaque type. + */ + CFTypeID CFStringGetTypeID(); } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index b47bb96678..814f4d58f7 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -268,8 +268,8 @@ public byte[] getByteArrayProperty(String key) { keyAsCFString.release(); if (valueAsCFType != null) { CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); - int length = CoreFoundation.INSTANCE.CFDataGetLength(valueAsCFData).intValue(); - Pointer p = CoreFoundation.INSTANCE.CFDataGetBytePtr(valueAsCFData); + int length = valueAsCFData.getLength().intValue(); + Pointer p = valueAsCFData.getBytePtr(); value = p.getByteArray(0, length); valueAsCFType.release(); } diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index 566a10eed2..1d51e57d9a 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -64,6 +64,7 @@ public void testCFStringRef() throws UnsupportedEncodingException { CFStringRef cfAwesome = CFStringRef.createCFString(awesome); assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome).intValue()); assertEquals(awesome, cfAwesome.stringValue()); + assertEquals(CF.CFStringGetTypeID(), cfAwesome.getTypeID()); byte[] awesomeArr = awesome.getBytes("UTF-8"); Memory mem = new Memory(awesomeArr.length + 1); @@ -85,6 +86,7 @@ public void testCFNumberRef() { LongByReference max = new LongByReference(Long.MAX_VALUE); CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.typeIndex(), max); assertEquals(Long.MAX_VALUE, cfMax.longValue()); + assertEquals(CF.CFNumberGetTypeID(), cfMax.getTypeID()); cfMax.release(); IntByReference zero = new IntByReference(0); @@ -136,10 +138,11 @@ public void testCFArray() { contiguousArray.setPointer(i * size, refArray[i].getPointer()); } CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, new CFIndex(refArray.length), null); + assertEquals(CF.CFArrayGetTypeID(), cfPtrArray.getTypeID()); - assertEquals(refArray.length, CF.CFArrayGetCount(cfPtrArray).intValue()); + assertEquals(refArray.length, cfPtrArray.getCount().intValue()); for (int i = 0; i < refArray.length; i++) { - Pointer result = CF.CFArrayGetValueAtIndex(cfPtrArray, new CFIndex(i)); + Pointer result = cfPtrArray.getValueAtIndex(new CFIndex(i)); CFNumberRef numRef = new CFNumberRef(result); assertEquals(i, numRef.intValue()); } @@ -161,10 +164,12 @@ public void testCFData() { nativeBytes.write(0, randomBytes, 0, randomBytes.length); // Create a CF reference to the data CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, new CFIndex(size)); - int dataSize = CF.CFDataGetLength(cfData).intValue(); + assertEquals(CF.CFDataGetTypeID(), cfData.getTypeID()); + + int dataSize = cfData.getLength().intValue(); assertEquals(size, dataSize); // Read it back out and convert to an array - Pointer bytes = CF.CFDataGetBytePtr(cfData); + Pointer bytes = cfData.getBytePtr(); byte[] dataBytes = bytes.getByteArray(0, dataSize); assertArrayEquals(randomBytes, dataBytes); cfData.release(); @@ -174,38 +179,40 @@ public void testCFData() { public void testCFDictionary() { CFAllocatorRef alloc = CF.CFAllocatorGetDefault(); CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, new CFIndex(2), null, null); + assertEquals(CF.CFDictionaryGetTypeID(), dict.getTypeID()); + CFStringRef oneStr = CFStringRef.createCFString("one"); // Key does not exist, returns null - assertEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); - Pointer cfNull = CF.CFDictionaryGetValue(dict, oneStr); + assertEquals(0, dict.getValueIfPresent(oneStr, null)); + Pointer cfNull = dict.getValue(oneStr); assertNull(cfNull); // Store and retrieve null value - CF.CFDictionarySetValue(dict, oneStr, null); - assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); - Pointer cfNullValue = CF.CFDictionaryGetValue(dict, oneStr); + dict.setValue(oneStr, null); + assertNotEquals(0, dict.getValueIfPresent(oneStr, null)); + Pointer cfNullValue = dict.getValue(oneStr); assertNull(cfNullValue); // Store (replace the null) and retrieve integer value IntByReference one = new IntByReference(1); CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.typeIndex(), one); - CF.CFDictionarySetValue(dict, oneStr, cfOne); + dict.setValue(oneStr, cfOne); - assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, null)); - Pointer result = CF.CFDictionaryGetValue(dict, oneStr); + assertNotEquals(0, dict.getValueIfPresent(oneStr, null)); + Pointer result = dict.getValue(oneStr); CFNumberRef numRef = new CFNumberRef(result); assertEquals(1, numRef.intValue()); PointerByReference resultPtr = new PointerByReference(); - assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, oneStr, resultPtr)); + assertNotEquals(0, dict.getValueIfPresent(oneStr, resultPtr)); numRef = new CFNumberRef(resultPtr.getValue()); assertEquals(1, numRef.intValue()); // Test non-CF type as key IntByReference onePtr = new IntByReference(1); - CF.CFDictionarySetValue(dict, onePtr, oneStr); - result = CF.CFDictionaryGetValue(dict, onePtr); + dict.setValue(onePtr, oneStr); + result = dict.getValue(onePtr); CFStringRef strRef = new CFStringRef(result); assertEquals("one", strRef.stringValue()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 70acf03d20..50530b7f7c 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -87,6 +87,7 @@ public void testDiskCreate() { CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); + assertEquals(CF.CFBooleanGetTypeID(), cfWholeBool.getTypeID()); if (cfWholeBool.booleanValue()) { // check that util boolean matches assertTrue(media.getBooleanProperty("Whole")); @@ -125,18 +126,18 @@ public void testDiskCreate() { assertNotNull(diskInfo); // Since we looked up "whole" BSD disks these should match - Pointer result = CF.CFDictionaryGetValue(diskInfo, daMediaBSDName); + Pointer result = diskInfo.getValue(daMediaBSDName); CFStringRef bsdNamePtr = new CFStringRef(result); assertEquals(bsdName, bsdNamePtr.stringValue()); - result = CF.CFDictionaryGetValue(diskInfo, daMediaWhole); + result = diskInfo.getValue(daMediaWhole); CFBooleanRef bsdWholePtr = new CFBooleanRef(result); assertTrue(bsdWholePtr.booleanValue()); // Size is a multiple of block size - result = CF.CFDictionaryGetValue(diskInfo, daMediaSize); + result = diskInfo.getValue(daMediaSize); CFNumberRef sizePtr = new CFNumberRef(result); long size = sizePtr.longValue(); - result = CF.CFDictionaryGetValue(diskInfo, daMediaBlockSize); + result = diskInfo.getValue(daMediaBlockSize); CFNumberRef blockSizePtr = new CFNumberRef(result); long blockSize = blockSizePtr.longValue(); assertEquals(0, size % blockSize); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index adf6d73306..92c261bbae 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -68,7 +68,7 @@ public void testMatching() { String match = "matching BSD Name"; CFMutableDictionaryRef dict = IO.IOBSDNameMatching(masterPort, 0, match); CFStringRef bsdNameKey = CFStringRef.createCFString("BSD Name"); - Pointer result = CF.CFDictionaryGetValue(dict, bsdNameKey); + Pointer result = dict.getValue(bsdNameKey); CFStringRef cfBsdName = new CFStringRef(result); assertEquals(match, cfBsdName.stringValue()); bsdNameKey.release(); @@ -77,7 +77,7 @@ public void testMatching() { match = "matching IOClass Name"; dict = IO.IOServiceNameMatching(match); CFStringRef classNameKey = CFStringRef.createCFString("IONameMatch"); - result = CF.CFDictionaryGetValue(dict, classNameKey); + result = dict.getValue(classNameKey); CFStringRef cfClassName = new CFStringRef(result); assertEquals(match, cfClassName.stringValue()); classNameKey.release(); @@ -86,7 +86,7 @@ public void testMatching() { match = "IOPlatformExpertDevice"; dict = IO.IOServiceMatching(match); CFStringRef classKey = CFStringRef.createCFString("IOProviderClass"); - result = CF.CFDictionaryGetValue(dict, classKey); + result = dict.getValue(classKey); CFStringRef cfClass = new CFStringRef(result); assertEquals(match, cfClass.stringValue()); classKey.release(); @@ -113,8 +113,8 @@ public void testMatching() { IO.IORegistryEntryCreateCFProperties(platformExpert, properties, CF.CFAllocatorGetDefault(), 0)); dict = new CFMutableDictionaryRef(); dict.setPointer(properties.getValue()); - assertNotEquals(0, CF.CFDictionaryGetValueIfPresent(dict, serialKey, null)); - result = CF.CFDictionaryGetValue(dict, serialKey); + assertNotEquals(0, dict.getValueIfPresent(serialKey, null)); + result = dict.getValue(serialKey); cfSerial = new CFStringRef(result); assertEquals(serialNumber, cfSerial.stringValue()); dict.release(); @@ -136,8 +136,7 @@ public void testMatching() { cfSerialAsType.release(); assertEquals(0, root.release()); - assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), - masterPort)); + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } @Test @@ -212,8 +211,7 @@ public void testIteratorParentChild() { controllerDevice = iter.next(); } assertEquals(0, iter.release()); - assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), - masterPort)); + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } @Test @@ -234,8 +232,7 @@ public void testIOConnect() { IO.IOServiceClose(conn); assertEquals(0, smcService.release()); - assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), - masterPort)); + assertEquals(0, SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort)); } @Test @@ -251,10 +248,10 @@ public void testPowerSources() { CFStringRef isPresentKey = CFStringRef.createCFString("Is Present"); CFStringRef currentCapacityKey = CFStringRef.createCFString("Current Capacity"); CFStringRef maxCapacityKey = CFStringRef.createCFString("Max Capacity"); - int powerSourcesCount = CF.CFArrayGetCount(powerSourcesList).intValue(); + int powerSourcesCount = powerSourcesList.getCount().intValue(); for (int ps = 0; ps < powerSourcesCount; ps++) { // Get the dictionary for that Power Source - Pointer pwrSrcPtr = CoreFoundation.INSTANCE.CFArrayGetValueAtIndex(powerSourcesList, new CFIndex(ps)); + Pointer pwrSrcPtr = powerSourcesList.getValueAtIndex(new CFIndex(ps)); CFTypeRef powerSource = new CFTypeRef(); powerSource.setPointer(pwrSrcPtr); CFDictionaryRef dictionary = IOKit.INSTANCE.IOPSGetPowerSourceDescription(powerSourcesInfo, powerSource); @@ -262,16 +259,16 @@ public void testPowerSources() { // Get values from dictionary (See IOPSKeys.h) // Skip if not present PointerByReference result = new PointerByReference(); - if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, isPresentKey, result)) { + if (0 != dictionary.getValueIfPresent(isPresentKey, result)) { CFBooleanRef isPresentRef = new CFBooleanRef(result.getValue()); if (isPresentRef.booleanValue()) { int currentCapacity = 0; - if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, currentCapacityKey, result)) { + if (0 != dictionary.getValueIfPresent(currentCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); currentCapacity = cap.intValue(); } int maxCapacity = 100; - if (0 != CF.CFDictionaryGetValueIfPresent(dictionary, maxCapacityKey, result)) { + if (0 != dictionary.getValueIfPresent(maxCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); maxCapacity = cap.intValue(); } From 46e9ec4acf7fac7064df2ace16337bb80adba90e Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 17 Sep 2019 22:13:38 -0700 Subject: [PATCH 23/28] IOKit convenience methods --- .../src/com/sun/jna/platform/mac/IOKit.java | 154 ++++++++++++++++-- .../jna/platform/mac/DiskArbitrationTest.java | 2 +- .../com/sun/jna/platform/mac/IOKitTest.java | 27 ++- 3 files changed, 154 insertions(+), 29 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 814f4d58f7..295b18d998 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -81,6 +81,18 @@ public IOObject(Pointer p) { super(p); } + /** + * Convenience method for {@link IOKit#IOObjectConformsTo} on this object. + * + * @param className + * The name of the class. + * @return If the object handle is valid, and represents an object in the kernel + * that dynamic casts to the class true is returned, otherwise false. + */ + public boolean conformsTo(String className) { + return INSTANCE.IOObjectConformsTo(this, className); + } + /** * Convenience method for {@link IOKit#IOObjectRelease} on this object. * @@ -127,6 +139,130 @@ public IORegistryEntry(Pointer p) { super(p); } + /** + * Convenience method for {@link #IORegistryEntryGetRegistryEntryID} to return + * an ID for this registry entry that is global to all tasks. + * + * @param id + * The resulting ID. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int getRegistryEntryID(LongByReference id) { + return INSTANCE.IORegistryEntryGetRegistryEntryID(this, id); + } + + /** + * Convenience method for {@link #IORegistryEntryGetName} to return a name + * assigned to this registry entry. + * + * @param name + * The caller's buffer to receive the name. This must be a 128-byte + * buffer. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int getName(Pointer name) { + return INSTANCE.IORegistryEntryGetName(this, name); + } + + /** + * Convenience method for {@link #IORegistryEntryGetChildIterator} to return an + * iterator over this registry entry’s child entries in a plane. + * + * @param plane + * The name of an existing registry plane. Plane names are defined in + * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. + * @param iter + * The created iterator over the children of the entry, on success. + * The iterator must be released when the iteration is finished. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int getChildIterator(String plane, PointerByReference iter) { + return INSTANCE.IORegistryEntryGetChildIterator(this, plane, iter); + } + + /** + * Convenience method for {@link #IORegistryEntryGetChildEntry} to return the + * first child of this registry entry in a plane. + * + * @param plane + * The name of an existing registry plane. + * @param child + * The first child of the registry entry, on success. The child must + * be released by the caller. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int getChildEntry(String plane, PointerByReference child) { + return INSTANCE.IORegistryEntryGetChildEntry(this, plane, child); + } + + /** + * Convenience method for {@link #IORegistryEntryGetParentEntry} to return the + * first parent of this registry entry in a plane. + * + * @param plane + * The name of an existing registry plane. + * @param parent + * The first parent of the registry entry, on success. The parent + * must be released by the caller. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int getParentEntry(String plane, PointerByReference parent) { + return INSTANCE.IORegistryEntryGetParentEntry(this, plane, parent); + } + + /** + * Convenience method for {@link #IORegistryEntryCreateCFProperty} to create a + * CF representation of this registry entry's property. + * + * @param key + * A {@code CFString} specifying the property name. + * @return A CF container is created and returned the caller on success. + *

+ * The caller should release with {@link CoreFoundation#CFRelease}. + */ + public CFTypeRef createCFProperty(CFStringRef key) { + return INSTANCE.IORegistryEntryCreateCFProperty(this, key, CoreFoundation.INSTANCE.CFAllocatorGetDefault(), + 0); + } + + /** + * Convenience method for {@link #IORegistryEntryCreateCFProperties} to create a + * CF dictionary representation of this registry entry's property table. + * + * @param properties + * A CFDictionary is created and returned the caller on success. The + * caller should release with CFRelease. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int createCFProperties(PointerByReference properties) { + return INSTANCE.IORegistryEntryCreateCFProperties(this, properties, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + } + + /** + * Convenience method for {@link #IORegistryEntrySearchCFProperty} to create a + * CF representation of a registry entry's property searched from this object. + * + * @param plane + * The name of an existing registry plane. Plane names are defined in + * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. + * @param key + * A {@code CFString} specifying the property name. + * @param options + * {@link #kIORegistryIterateRecursively} may be set to recurse + * automatically into the registry hierarchy. Without this option, + * this method degenerates into the standard + * {@link #IORegistryEntryCreateCFProperty} call. + * {@link #kIORegistryIterateParents} may be set to iterate the + * parents of the entry, in place of the children. + * @return A CF container is created and returned the caller on success. The + * caller should release with CFRelease. + */ + CFTypeRef searchCFProperty(String plane, CFStringRef key, int options) { + return INSTANCE.IORegistryEntrySearchCFProperty(this, plane, key, + CoreFoundation.INSTANCE.CFAllocatorGetDefault(), options); + } + /** * Convenience method to get a {@link java.lang.String} value from this IO * Registry Entry. @@ -138,8 +274,7 @@ public IORegistryEntry(Pointer p) { public String getStringProperty(String key) { String value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, - CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + CFTypeRef valueAsCFType = this.createCFProperty(keyAsCFString); keyAsCFString.release(); if (valueAsCFType != null) { CFStringRef valueAsCFString = new CFStringRef(valueAsCFType.getPointer()); @@ -165,8 +300,7 @@ public String getStringProperty(String key) { public Long getLongProperty(String key) { Long value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, - CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + CFTypeRef valueAsCFType = this.createCFProperty(keyAsCFString); keyAsCFString.release(); if (valueAsCFType != null) { CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); @@ -192,8 +326,7 @@ public Long getLongProperty(String key) { public Integer getIntegerProperty(String key) { Integer value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, - CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + CFTypeRef valueAsCFType = this.createCFProperty(keyAsCFString); keyAsCFString.release(); if (valueAsCFType != null) { CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); @@ -219,8 +352,7 @@ public Integer getIntegerProperty(String key) { public Double getDoubleProperty(String key) { Double value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, - CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + CFTypeRef valueAsCFType = this.createCFProperty(keyAsCFString); keyAsCFString.release(); if (valueAsCFType != null) { CFNumberRef valueAsCFNumber = new CFNumberRef(valueAsCFType.getPointer()); @@ -241,8 +373,7 @@ public Double getDoubleProperty(String key) { public Boolean getBooleanProperty(String key) { Boolean value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, - CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + CFTypeRef valueAsCFType = this.createCFProperty(keyAsCFString); keyAsCFString.release(); if (valueAsCFType != null) { CFBooleanRef valueAsCFBoolean = new CFBooleanRef(valueAsCFType.getPointer()); @@ -263,8 +394,7 @@ public Boolean getBooleanProperty(String key) { public byte[] getByteArrayProperty(String key) { byte[] value = null; CFStringRef keyAsCFString = CFStringRef.createCFString(key); - CFTypeRef valueAsCFType = INSTANCE.IORegistryEntryCreateCFProperty(this, keyAsCFString, - CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + CFTypeRef valueAsCFType = this.createCFProperty(keyAsCFString); keyAsCFString.release(); if (valueAsCFType != null) { CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 50530b7f7c..0a53a64cc8 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -84,7 +84,7 @@ public void testDiskCreate() { IOIterator iter = new IOIterator(iterPtr.getValue()); IORegistryEntry media = iter.next(); while (media != null) { - CFTypeRef cfWhole = IO.IORegistryEntryCreateCFProperty(media, wholeKey, CF.CFAllocatorGetDefault(), 0); + CFTypeRef cfWhole = media.createCFProperty(wholeKey); assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); assertEquals(CF.CFBooleanGetTypeID(), cfWholeBool.getTypeID()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 92c261bbae..9017f080ea 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -57,7 +57,6 @@ public class IOKitTest { - private static final CoreFoundation CF = CoreFoundation.INSTANCE; private static final IOKit IO = IOKit.INSTANCE; private static final SystemB SYS = SystemB.INSTANCE; @@ -96,8 +95,7 @@ public void testMatching() { assertNotNull(platformExpert.getPointer()); // Get a single key CFStringRef serialKey = CFStringRef.createCFString("IOPlatformSerialNumber"); - CFTypeRef cfSerialAsType = IO.IORegistryEntryCreateCFProperty(platformExpert, serialKey, - CF.CFAllocatorGetDefault(), 0); + CFTypeRef cfSerialAsType = platformExpert.createCFProperty(serialKey); assertNotNull(cfSerialAsType); CFStringRef cfSerial = new CFStringRef(cfSerialAsType.getPointer()); String serialNumber = cfSerial.stringValue(); @@ -109,8 +107,7 @@ public void testMatching() { assertEquals(12, serialNumber.length()); // Get all the keys PointerByReference properties = new PointerByReference(); - assertEquals(0, - IO.IORegistryEntryCreateCFProperties(platformExpert, properties, CF.CFAllocatorGetDefault(), 0)); + assertEquals(0, platformExpert.createCFProperties(properties)); dict = new CFMutableDictionaryRef(); dict.setPointer(properties.getValue()); assertNotEquals(0, dict.getValueIfPresent(serialKey, null)); @@ -123,12 +120,10 @@ public void testMatching() { // Get a single key from a nested entry IORegistryEntry root = IOKitUtil.getRoot(); assertNotNull(root); - cfSerialAsType = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), - 0); + cfSerialAsType = root.searchCFProperty("IOService", serialKey, 0); // without recursive search should be null assertNull(cfSerialAsType); - cfSerialAsType = IO.IORegistryEntrySearchCFProperty(root, "IOService", serialKey, CF.CFAllocatorGetDefault(), - IOKit.kIORegistryIterateRecursively); + cfSerialAsType = root.searchCFProperty("IOService", serialKey, IOKit.kIORegistryIterateRecursively); // with recursive search should return a match cfSerial = new CFStringRef(cfSerialAsType.getPointer()); assertEquals(serialNumber, cfSerial.stringValue()); @@ -151,7 +146,7 @@ public void testIteratorParentChild() { IORegistryEntry controllerDevice = iter.next(); while (controllerDevice != null) { LongByReference id = new LongByReference(); - IO.IORegistryEntryGetRegistryEntryID(controllerDevice, id); + assertEquals(0, controllerDevice.getRegistryEntryID(id)); // EntryIDs 0 thru 19 are reserved, all are unique assertTrue(id.getValue() > 19); assertFalse(uniqueEntryIdSet.contains(id.getValue())); @@ -160,7 +155,7 @@ public void testIteratorParentChild() { // Get device name // Corresponds to io_name_t which is char[128] Memory buffer = new Memory(128); - IO.IORegistryEntryGetName(controllerDevice, buffer); + controllerDevice.getName(buffer); // Root controllers always begin with "AppleUSB" assertEquals("AppleUSB", buffer.getString(0).substring(0, 8)); @@ -169,18 +164,18 @@ public void testIteratorParentChild() { boolean testFirstChild = true; // If this returns 0, we have at least one child entry to test // If not, the iterator will never check whether to test - IO.IORegistryEntryGetChildEntry(controllerDevice, "IOService", firstChildPtr); + controllerDevice.getChildEntry("IOService", firstChildPtr); // Now iterate the children of this device in the "IOService" plane. PointerByReference childIterPtr = new PointerByReference(); - IO.IORegistryEntryGetChildIterator(controllerDevice, "IOService", childIterPtr); + controllerDevice.getChildIterator("IOService", childIterPtr); IOIterator childIter = new IOIterator(childIterPtr.getValue()); IORegistryEntry childDevice = childIter.next(); while (childDevice != null) { - assertTrue(IO.IOObjectConformsTo(childDevice, "IOUSBDevice")); + assertTrue(childDevice.conformsTo("IOUSBDevice")); LongByReference childId = new LongByReference(); - IO.IORegistryEntryGetRegistryEntryID(childDevice, childId); + childDevice.getRegistryEntryID(childId); assertTrue(childId.getValue() > 19); assertFalse(uniqueEntryIdSet.contains(childId.getValue())); uniqueEntryIdSet.add(childId.getValue()); @@ -195,7 +190,7 @@ public void testIteratorParentChild() { // Get this device's parent in IOService plane, matches controller PointerByReference parentPtr = new PointerByReference(); - IO.IORegistryEntryGetParentEntry(childDevice, "IOService", parentPtr); + childDevice.getParentEntry("IOService", parentPtr); IORegistryEntry parent = new IORegistryEntry(parentPtr.getValue()); assertEquals(controllerDevice, parent); assertEquals(0, parent.release()); From a9db43b3d65141503f2f7cd1d2a3c6b1f08a97c3 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Tue, 17 Sep 2019 23:49:53 -0700 Subject: [PATCH 24/28] TypeID checking --- .../sun/jna/platform/mac/CoreFoundation.java | 63 +++++++++++++++++++ .../jna/platform/mac/CoreFoundationTest.java | 17 +++-- .../jna/platform/mac/DiskArbitrationTest.java | 2 +- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index 1c67a775a8..b54b47083d 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -65,6 +65,14 @@ public interface CoreFoundation extends Library { int kCFStringEncodingASCII = 0x0600; int kCFStringEncodingUTF8 = 0x08000100; + CFTypeID ARRAY_TYPE_ID = INSTANCE.CFArrayGetTypeID(); + CFTypeID BOOLEAN_TYPE_ID = INSTANCE.CFBooleanGetTypeID(); + CFTypeID DATA_TYPE_ID = INSTANCE.CFDataGetTypeID(); + CFTypeID DATE_TYPE_ID = INSTANCE.CFDateGetTypeID(); + CFTypeID DICTIONARY_TYPE_ID = INSTANCE.CFDictionaryGetTypeID(); + CFTypeID NUMBER_TYPE_ID = INSTANCE.CFNumberGetTypeID(); + CFTypeID STRING_TYPE_ID = INSTANCE.CFStringGetTypeID(); + /** * The {@code CFTypeRef} type is the base type defined in Core Foundation. It is * used as the type and return value in several polymorphic functions. It is a @@ -82,11 +90,27 @@ public CFTypeRef(Pointer p) { /** * Convenience method for {@link CoreFoundation#CFGetTypeID} on this object. + * + * @return The {@link CFTypeID} */ public CFTypeID getTypeID() { + if (this.getPointer() == null) { + return new CFTypeID(0); + } return INSTANCE.CFGetTypeID(this); } + /** + * Test whether this object has the specified ID + * + * @param typeID + * The {@link CFTypeID} for the class to test + * @return true if this object has the same ID as {@code typeID} + */ + public boolean isTypeID(CFTypeID typeID) { + return getTypeID().equals(typeID); + } + /** * Convenience method for {@link CoreFoundation#CFRetain} on this object. */ @@ -120,6 +144,9 @@ public CFNumberRef() { public CFNumberRef(Pointer p) { super(p); + if (!isTypeID(NUMBER_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFNumber. Type ID: " + getTypeID()); + } } /** @@ -256,6 +283,9 @@ public CFBooleanRef() { public CFBooleanRef(Pointer p) { super(p); + if (!isTypeID(BOOLEAN_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFBoolean. Type ID: " + getTypeID()); + } } /** @@ -282,6 +312,9 @@ public CFArrayRef() { public CFArrayRef(Pointer p) { super(p); + if (!isTypeID(ARRAY_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFArray. Type ID: " + getTypeID()); + } } /** @@ -315,6 +348,9 @@ public CFDataRef() { public CFDataRef(Pointer p) { super(p); + if (!isTypeID(DATA_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFData. Type ID: " + getTypeID()); + } } /** @@ -347,6 +383,9 @@ public CFDictionaryRef() { public CFDictionaryRef(Pointer p) { super(p); + if (!isTypeID(DICTIONARY_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFDictionary. Type ID: " + getTypeID()); + } } /** @@ -418,6 +457,9 @@ public CFStringRef() { public CFStringRef(Pointer p) { super(p); + if (!isTypeID(STRING_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFString. Type ID: " + getTypeID()); + } } /** @@ -494,6 +536,27 @@ public CFTypeID() { public CFTypeID(long value) { super(value); } + + @Override + public String toString() { + if (this.equals(ARRAY_TYPE_ID)) { + return "CFArray"; + } else if (this.equals(BOOLEAN_TYPE_ID)) { + return "CFBoolean"; + } else if (this.equals(DATA_TYPE_ID)) { + return "CFData"; + } else if (this.equals(DATE_TYPE_ID)) { + return "CFDate"; + } else if (this.equals(DICTIONARY_TYPE_ID)) { + return "CFDictionary"; + } else if (this.equals(NUMBER_TYPE_ID)) { + return "CFNumber"; + } else if (this.equals(STRING_TYPE_ID)) { + return "CFString"; + } else { + return super.toString(); + } + } } /** diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index 1d51e57d9a..57e6a292f4 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.UnsupportedEncodingException; import java.util.Arrays; @@ -64,7 +65,7 @@ public void testCFStringRef() throws UnsupportedEncodingException { CFStringRef cfAwesome = CFStringRef.createCFString(awesome); assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome).intValue()); assertEquals(awesome, cfAwesome.stringValue()); - assertEquals(CF.CFStringGetTypeID(), cfAwesome.getTypeID()); + assertEquals(CoreFoundation.STRING_TYPE_ID, cfAwesome.getTypeID()); byte[] awesomeArr = awesome.getBytes("UTF-8"); Memory mem = new Memory(awesomeArr.length + 1); @@ -86,7 +87,7 @@ public void testCFNumberRef() { LongByReference max = new LongByReference(Long.MAX_VALUE); CFNumberRef cfMax = CF.CFNumberCreate(null, CFNumberType.kCFNumberLongLongType.typeIndex(), max); assertEquals(Long.MAX_VALUE, cfMax.longValue()); - assertEquals(CF.CFNumberGetTypeID(), cfMax.getTypeID()); + assertEquals(CoreFoundation.NUMBER_TYPE_ID, cfMax.getTypeID()); cfMax.release(); IntByReference zero = new IntByReference(0); @@ -138,11 +139,17 @@ public void testCFArray() { contiguousArray.setPointer(i * size, refArray[i].getPointer()); } CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, new CFIndex(refArray.length), null); - assertEquals(CF.CFArrayGetTypeID(), cfPtrArray.getTypeID()); + assertEquals(CoreFoundation.ARRAY_TYPE_ID, cfPtrArray.getTypeID()); assertEquals(refArray.length, cfPtrArray.getCount().intValue()); for (int i = 0; i < refArray.length; i++) { Pointer result = cfPtrArray.getValueAtIndex(new CFIndex(i)); + try { + new CFStringRef(result); + fail("Should have thrown a ClassCastExcpetion."); + } catch (ClassCastException expected) { + assertEquals("Unable to cast to CFString. Type ID: CFNumber", expected.getMessage()); + } CFNumberRef numRef = new CFNumberRef(result); assertEquals(i, numRef.intValue()); } @@ -164,7 +171,7 @@ public void testCFData() { nativeBytes.write(0, randomBytes, 0, randomBytes.length); // Create a CF reference to the data CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, new CFIndex(size)); - assertEquals(CF.CFDataGetTypeID(), cfData.getTypeID()); + assertEquals(CoreFoundation.DATA_TYPE_ID, cfData.getTypeID()); int dataSize = cfData.getLength().intValue(); assertEquals(size, dataSize); @@ -179,7 +186,7 @@ public void testCFData() { public void testCFDictionary() { CFAllocatorRef alloc = CF.CFAllocatorGetDefault(); CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, new CFIndex(2), null, null); - assertEquals(CF.CFDictionaryGetTypeID(), dict.getTypeID()); + assertEquals(CoreFoundation.DICTIONARY_TYPE_ID, dict.getTypeID()); CFStringRef oneStr = CFStringRef.createCFString("one"); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java index 0a53a64cc8..60c106ed79 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java @@ -87,7 +87,7 @@ public void testDiskCreate() { CFTypeRef cfWhole = media.createCFProperty(wholeKey); assertNotNull(cfWhole); CFBooleanRef cfWholeBool = new CFBooleanRef(cfWhole.getPointer()); - assertEquals(CF.CFBooleanGetTypeID(), cfWholeBool.getTypeID()); + assertEquals(CoreFoundation.BOOLEAN_TYPE_ID, cfWholeBool.getTypeID()); if (cfWholeBool.booleanValue()) { // check that util boolean matches assertTrue(media.getBooleanProperty("Whole")); From 3528421852777464bad88ea8556fe020b6dc4ed4 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 18 Sep 2019 12:09:24 -0700 Subject: [PATCH 25/28] Return primitive types from convenience methods --- .../sun/jna/platform/mac/CoreFoundation.java | 23 ++++++++++--------- .../src/com/sun/jna/platform/mac/IOKit.java | 2 +- .../jna/platform/mac/CoreFoundationTest.java | 15 ++++++------ .../com/sun/jna/platform/mac/IOKitTest.java | 17 ++++++-------- 4 files changed, 28 insertions(+), 29 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java index b54b47083d..c456781eb5 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -322,8 +322,8 @@ public CFArrayRef(Pointer p) { * * @return The number of values in this array. */ - public CFIndex getCount() { - return INSTANCE.CFArrayGetCount(this); + public int getCount() { + return INSTANCE.CFArrayGetCount(this).intValue(); } /** @@ -333,8 +333,8 @@ public CFIndex getCount() { * The index of the value to retrieve. * @return The value at the {@code idx} index. */ - public Pointer getValueAtIndex(CFIndex idx) { - return INSTANCE.CFArrayGetValueAtIndex(this, idx); + public Pointer getValueAtIndex(int idx) { + return INSTANCE.CFArrayGetValueAtIndex(this, new CFIndex(idx)); } } @@ -359,8 +359,8 @@ public CFDataRef(Pointer p) { * @return An index that specifies the number of bytes associated with this * object. */ - public CFIndex getLength() { - return INSTANCE.CFDataGetLength(this); + public int getLength() { + return INSTANCE.CFDataGetLength(this).intValue(); } /** @@ -402,18 +402,19 @@ public Pointer getValue(PointerType key) { } /** - * Convenience method for {@link CoreFoundation#CFDictionaryGetValueIfPresent} - * on this object. + * Convenience method for + * {@link CoreFoundation#CFDictionaryGetValueIfPresent} on this object. * * @param key * The key for which to find a match. * @param value * A pointer to memory which, on return, is filled with the * pointer-sized value if a matching key is found. - * @return 1 if a matching key was found, otherwise 0 + * @return {@code true} if a matching key was found, otherwise + * {@code false} */ - public byte getValueIfPresent(PointerType key, PointerByReference value) { - return INSTANCE.CFDictionaryGetValueIfPresent(this, key, value); + public boolean getValueIfPresent(PointerType key, PointerByReference value) { + return INSTANCE.CFDictionaryGetValueIfPresent(this, key, value) > 0; } } diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 295b18d998..18d0b73038 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -398,7 +398,7 @@ public byte[] getByteArrayProperty(String key) { keyAsCFString.release(); if (valueAsCFType != null) { CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); - int length = valueAsCFData.getLength().intValue(); + int length = valueAsCFData.getLength(); Pointer p = valueAsCFData.getBytePtr(); value = p.getByteArray(0, length); valueAsCFType.release(); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java index 57e6a292f4..a7d621789d 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -141,9 +142,9 @@ public void testCFArray() { CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, new CFIndex(refArray.length), null); assertEquals(CoreFoundation.ARRAY_TYPE_ID, cfPtrArray.getTypeID()); - assertEquals(refArray.length, cfPtrArray.getCount().intValue()); + assertEquals(refArray.length, cfPtrArray.getCount()); for (int i = 0; i < refArray.length; i++) { - Pointer result = cfPtrArray.getValueAtIndex(new CFIndex(i)); + Pointer result = cfPtrArray.getValueAtIndex(i); try { new CFStringRef(result); fail("Should have thrown a ClassCastExcpetion."); @@ -173,7 +174,7 @@ public void testCFData() { CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, new CFIndex(size)); assertEquals(CoreFoundation.DATA_TYPE_ID, cfData.getTypeID()); - int dataSize = cfData.getLength().intValue(); + int dataSize = cfData.getLength(); assertEquals(size, dataSize); // Read it back out and convert to an array Pointer bytes = cfData.getBytePtr(); @@ -191,13 +192,13 @@ public void testCFDictionary() { CFStringRef oneStr = CFStringRef.createCFString("one"); // Key does not exist, returns null - assertEquals(0, dict.getValueIfPresent(oneStr, null)); + assertFalse(dict.getValueIfPresent(oneStr, null)); Pointer cfNull = dict.getValue(oneStr); assertNull(cfNull); // Store and retrieve null value dict.setValue(oneStr, null); - assertNotEquals(0, dict.getValueIfPresent(oneStr, null)); + assertTrue(dict.getValueIfPresent(oneStr, null)); Pointer cfNullValue = dict.getValue(oneStr); assertNull(cfNullValue); @@ -206,13 +207,13 @@ public void testCFDictionary() { CFNumberRef cfOne = CF.CFNumberCreate(null, CFNumberType.kCFNumberIntType.typeIndex(), one); dict.setValue(oneStr, cfOne); - assertNotEquals(0, dict.getValueIfPresent(oneStr, null)); + assertTrue(dict.getValueIfPresent(oneStr, null)); Pointer result = dict.getValue(oneStr); CFNumberRef numRef = new CFNumberRef(result); assertEquals(1, numRef.intValue()); PointerByReference resultPtr = new PointerByReference(); - assertNotEquals(0, dict.getValueIfPresent(oneStr, resultPtr)); + assertTrue(dict.getValueIfPresent(oneStr, resultPtr)); numRef = new CFNumberRef(resultPtr.getValue()); assertEquals(1, numRef.intValue()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index 9017f080ea..d71f4c23cd 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -41,7 +41,6 @@ import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef; -import com.sun.jna.platform.mac.CoreFoundation.CFIndex; import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef; import com.sun.jna.platform.mac.CoreFoundation.CFStringRef; @@ -108,8 +107,7 @@ public void testMatching() { // Get all the keys PointerByReference properties = new PointerByReference(); assertEquals(0, platformExpert.createCFProperties(properties)); - dict = new CFMutableDictionaryRef(); - dict.setPointer(properties.getValue()); + dict = new CFMutableDictionaryRef(properties.getValue()); assertNotEquals(0, dict.getValueIfPresent(serialKey, null)); result = dict.getValue(serialKey); cfSerial = new CFStringRef(result); @@ -243,27 +241,26 @@ public void testPowerSources() { CFStringRef isPresentKey = CFStringRef.createCFString("Is Present"); CFStringRef currentCapacityKey = CFStringRef.createCFString("Current Capacity"); CFStringRef maxCapacityKey = CFStringRef.createCFString("Max Capacity"); - int powerSourcesCount = powerSourcesList.getCount().intValue(); + int powerSourcesCount = powerSourcesList.getCount(); for (int ps = 0; ps < powerSourcesCount; ps++) { // Get the dictionary for that Power Source - Pointer pwrSrcPtr = powerSourcesList.getValueAtIndex(new CFIndex(ps)); - CFTypeRef powerSource = new CFTypeRef(); - powerSource.setPointer(pwrSrcPtr); + Pointer pwrSrcPtr = powerSourcesList.getValueAtIndex(ps); + CFTypeRef powerSource = new CFTypeRef(pwrSrcPtr); CFDictionaryRef dictionary = IOKit.INSTANCE.IOPSGetPowerSourceDescription(powerSourcesInfo, powerSource); // Get values from dictionary (See IOPSKeys.h) // Skip if not present PointerByReference result = new PointerByReference(); - if (0 != dictionary.getValueIfPresent(isPresentKey, result)) { + if (dictionary.getValueIfPresent(isPresentKey, result)) { CFBooleanRef isPresentRef = new CFBooleanRef(result.getValue()); if (isPresentRef.booleanValue()) { int currentCapacity = 0; - if (0 != dictionary.getValueIfPresent(currentCapacityKey, result)) { + if (dictionary.getValueIfPresent(currentCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); currentCapacity = cap.intValue(); } int maxCapacity = 100; - if (0 != dictionary.getValueIfPresent(maxCapacityKey, result)) { + if (dictionary.getValueIfPresent(maxCapacityKey, result)) { CFNumberRef cap = new CFNumberRef(result.getValue()); maxCapacity = cap.intValue(); } From 7fae6aba0ff2ae7772f85fa0ddeb62a5483fe356 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 18 Sep 2019 14:43:18 -0700 Subject: [PATCH 26/28] IOReturn exception handling --- .../src/com/sun/jna/platform/mac/IOKit.java | 136 +++++++++++------- .../jna/platform/mac/IOReturnException.java | 107 ++++++++++++++ .../com/sun/jna/platform/mac/IOKitTest.java | 51 +++---- .../platform/mac/IOReturnExceptionTest.java | 46 ++++++ 4 files changed, 258 insertions(+), 82 deletions(-) create mode 100644 contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java create mode 100644 contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index 18d0b73038..f9c233e953 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -25,6 +25,7 @@ package com.sun.jna.platform.mac; import com.sun.jna.Library; +import com.sun.jna.Memory; import com.sun.jna.Native; import com.sun.jna.Pointer; import com.sun.jna.PointerType; @@ -52,6 +53,8 @@ public interface IOKit extends Library { int kIORegistryIterateRecursively = 0x00000001; int kIORegistryIterateParents = 0x00000002; + int kIOReturnNoDevice = 0xe00002c0; + double kIOPSTimeRemainingUnlimited = -2.0; double kIOPSTimeRemainingUnknown = -1.0; @@ -140,74 +143,101 @@ public IORegistryEntry(Pointer p) { } /** - * Convenience method for {@link #IORegistryEntryGetRegistryEntryID} to return - * an ID for this registry entry that is global to all tasks. + * Convenience method for {@link #IORegistryEntryGetRegistryEntryID} to + * return an ID for this registry entry that is global to all tasks. * - * @param id - * The resulting ID. - * @return 0 if successful, otherwise a {@code kern_return_t} error code. + * @return the ID. + * @throws IOReturnException + * if the ID could not be retrieved. */ - public int getRegistryEntryID(LongByReference id) { - return INSTANCE.IORegistryEntryGetRegistryEntryID(this, id); + public long getRegistryEntryID() { + LongByReference id = new LongByReference(); + int kr = INSTANCE.IORegistryEntryGetRegistryEntryID(this, id); + if (kr != 0) { + throw new IOReturnException(kr); + } + return id.getValue(); } /** - * Convenience method for {@link #IORegistryEntryGetName} to return a name - * assigned to this registry entry. + * Convenience method for {@link #IORegistryEntryGetName} to return a + * name assigned to this registry entry. * - * @param name - * The caller's buffer to receive the name. This must be a 128-byte - * buffer. - * @return 0 if successful, otherwise a {@code kern_return_t} error code. + * @return The name + * @throws IOReturnException + * if the name could not be retrieved. */ - public int getName(Pointer name) { - return INSTANCE.IORegistryEntryGetName(this, name); + public String getName() { + Memory name = new Memory(128); + int kr = INSTANCE.IORegistryEntryGetName(this, name); + if (kr != 0) { + throw new IOReturnException(kr); + } + return name.getString(0); } /** - * Convenience method for {@link #IORegistryEntryGetChildIterator} to return an - * iterator over this registry entry’s child entries in a plane. + * Convenience method for {@link #IORegistryEntryGetChildIterator} to + * return an iterator over this registry entry’s child entries in a + * plane. * * @param plane - * The name of an existing registry plane. Plane names are defined in - * {@code IOKitKeys.h}, for example, {@code kIOServicePlane}. - * @param iter - * The created iterator over the children of the entry, on success. - * The iterator must be released when the iteration is finished. - * @return 0 if successful, otherwise a {@code kern_return_t} error code. + * The name of an existing registry plane. Plane names are + * defined in {@code IOKitKeys.h}, for example, + * {@code kIOServicePlane}. + * @return The iterator + * @throws IOReturnException + * if the iterator could not be retrieved. */ - public int getChildIterator(String plane, PointerByReference iter) { - return INSTANCE.IORegistryEntryGetChildIterator(this, plane, iter); + public IOIterator getChildIterator(String plane) { + PointerByReference iter = new PointerByReference(); + int kr = INSTANCE.IORegistryEntryGetChildIterator(this, plane, iter); + if (kr != 0) { + throw new IOReturnException(kr); + } + return new IOIterator(iter.getValue()); } /** - * Convenience method for {@link #IORegistryEntryGetChildEntry} to return the - * first child of this registry entry in a plane. + * Convenience method for {@link #IORegistryEntryGetChildEntry} to + * return the first child of this registry entry in a plane. * * @param plane * The name of an existing registry plane. - * @param child - * The first child of the registry entry, on success. The child must - * be released by the caller. - * @return 0 if successful, otherwise a {@code kern_return_t} error code. + * @return The child registry entry, if a child exists, null otherwise + * @throws IOReturnException + * if the entry exists but could not be retrieved. */ - public int getChildEntry(String plane, PointerByReference child) { - return INSTANCE.IORegistryEntryGetChildEntry(this, plane, child); + public IORegistryEntry getChildEntry(String plane) { + PointerByReference child = new PointerByReference(); + int kr = INSTANCE.IORegistryEntryGetChildEntry(this, plane, child); + if (kr == kIOReturnNoDevice) { + return null; + } else if (kr != 0) { + throw new IOReturnException(kr); + } + return new IORegistryEntry(child.getValue()); } /** - * Convenience method for {@link #IORegistryEntryGetParentEntry} to return the - * first parent of this registry entry in a plane. + * Convenience method for {@link #IORegistryEntryGetParentEntry} to + * return the first parent of this registry entry in a plane. * * @param plane * The name of an existing registry plane. - * @param parent - * The first parent of the registry entry, on success. The parent - * must be released by the caller. - * @return 0 if successful, otherwise a {@code kern_return_t} error code. + * @return The parent registry entry, if a parent exists, null otherwise + * @throws IOReturnException + * if the entry exists but could not be retrieved. */ - public int getParentEntry(String plane, PointerByReference parent) { - return INSTANCE.IORegistryEntryGetParentEntry(this, plane, parent); + public IORegistryEntry getParentEntry(String plane) { + PointerByReference parent = new PointerByReference(); + int kr = INSTANCE.IORegistryEntryGetParentEntry(this, plane, parent); + if (kr == kIOReturnNoDevice) { + return null; + } else if (kr != 0) { + throw new IOReturnException(kr); + } + return new IORegistryEntry(parent.getValue()); } /** @@ -226,17 +256,25 @@ public CFTypeRef createCFProperty(CFStringRef key) { } /** - * Convenience method for {@link #IORegistryEntryCreateCFProperties} to create a - * CF dictionary representation of this registry entry's property table. + * Convenience method for {@link #IORegistryEntryCreateCFProperties} to + * create a CF dictionary representation of this registry entry's + * property table. * - * @param properties - * A CFDictionary is created and returned the caller on success. The - * caller should release with CFRelease. - * @return 0 if successful, otherwise a {@code kern_return_t} error code. + * @return The property table. + *

+ * The caller should release with + * {@link CoreFoundation#CFRelease}. + * @throws IOReturnException + * if the entry could not be retrieved. */ - public int createCFProperties(PointerByReference properties) { - return INSTANCE.IORegistryEntryCreateCFProperties(this, properties, + public CFMutableDictionaryRef createCFProperties() { + PointerByReference properties = new PointerByReference(); + int kr = INSTANCE.IORegistryEntryCreateCFProperties(this, properties, CoreFoundation.INSTANCE.CFAllocatorGetDefault(), 0); + if (kr != 0) { + throw new IOReturnException(kr); + } + return new CFMutableDictionaryRef(properties.getValue()); } /** diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java b/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java new file mode 100644 index 0000000000..8b1b260665 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +/** + * Exception encapsulating {@code IOReturn} I/O Kit Error Return Values, defined + * as {@code kern_return_t} values in {@code IOKit/IOReturn.h} + *

+ * The return value supplies information in three separate bit fields: the high + * 6 bits specify the system in which the error occurred, the next 12 bits + * specify the subsystem, and the final 14 bits specify the error code itself. + */ +public class IOReturnException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private int ioReturn; + + /** + * New exception from {@code kern_return_t} + * + * @param kr + * The return value + */ + public IOReturnException(int kr) { + this(kr, formatMessage(kr)); + } + + /** + * New exception from {@code kern_return_t} with specified message + * + * @param kr + * The return value + * @param msg + * The exception message + */ + protected IOReturnException(int kr, String msg) { + super(msg); + this.ioReturn = kr; + } + + /** + * @return the IOReturn code + */ + public int getIOReturnCode() { + return ioReturn; + } + + /** + * The high 6 bits of the return value encode the system. + * + * @param kr + * The return value + * @return the system value + */ + public static int getSystem(int kr) { + return (kr >> 26) & 0x3f; + } + + /** + * The middle 12 bits of the return value encode the subsystem. + * + * @param kr + * The return value + * @return the subsystem value + */ + public static int getSubSystem(int kr) { + return (kr >> 14) & 0xfff; + } + + /** + * The low 14 bits of the return value encode the return code. + * + * @param kr + * The return value + * @return the return code + */ + public static int getCode(int kr) { + return kr & 0x3fff; + } + + private static String formatMessage(int kr) { + return "IOReturn error code: " + kr + " (system=" + getSystem(kr) + ", subSystem=" + getSubSystem(kr) + + ", code=" + getCode(kr) + ")"; + } +} diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index d71f4c23cd..c370e8fa76 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -36,7 +36,6 @@ import org.junit.Test; -import com.sun.jna.Memory; import com.sun.jna.Pointer; import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef; import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef; @@ -47,11 +46,9 @@ import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef; import com.sun.jna.platform.mac.IOKit.IOConnect; import com.sun.jna.platform.mac.IOKit.IOIterator; -import com.sun.jna.platform.mac.IOKit.IOObject; import com.sun.jna.platform.mac.IOKit.IORegistryEntry; import com.sun.jna.platform.mac.IOKit.IOService; import com.sun.jna.ptr.IntByReference; -import com.sun.jna.ptr.LongByReference; import com.sun.jna.ptr.PointerByReference; public class IOKitTest { @@ -91,7 +88,7 @@ public void testMatching() { // Get matching service (consumes dict reference) IORegistryEntry platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); - assertNotNull(platformExpert.getPointer()); + assertNull(platformExpert.getChildEntry("IOService")); // Get a single key CFStringRef serialKey = CFStringRef.createCFString("IOPlatformSerialNumber"); CFTypeRef cfSerialAsType = platformExpert.createCFProperty(serialKey); @@ -105,9 +102,7 @@ public void testMatching() { assertEquals(12, serialNumber.length()); // Get all the keys - PointerByReference properties = new PointerByReference(); - assertEquals(0, platformExpert.createCFProperties(properties)); - dict = new CFMutableDictionaryRef(properties.getValue()); + dict = platformExpert.createCFProperties(); assertNotEquals(0, dict.getValueIfPresent(serialKey, null)); result = dict.getValue(serialKey); cfSerial = new CFStringRef(result); @@ -118,6 +113,7 @@ public void testMatching() { // Get a single key from a nested entry IORegistryEntry root = IOKitUtil.getRoot(); assertNotNull(root); + assertNull(root.getParentEntry("IOService")); cfSerialAsType = root.searchCFProperty("IOService", serialKey, 0); // without recursive search should be null assertNull(cfSerialAsType); @@ -143,53 +139,42 @@ public void testIteratorParentChild() { assertNotNull(iter); IORegistryEntry controllerDevice = iter.next(); while (controllerDevice != null) { - LongByReference id = new LongByReference(); - assertEquals(0, controllerDevice.getRegistryEntryID(id)); + long id = controllerDevice.getRegistryEntryID(); // EntryIDs 0 thru 19 are reserved, all are unique - assertTrue(id.getValue() > 19); - assertFalse(uniqueEntryIdSet.contains(id.getValue())); - uniqueEntryIdSet.add(id.getValue()); + assertTrue(id > 19); + assertFalse(uniqueEntryIdSet.contains(id)); + uniqueEntryIdSet.add(id); // Get device name - // Corresponds to io_name_t which is char[128] - Memory buffer = new Memory(128); - controllerDevice.getName(buffer); + String controllerName = controllerDevice.getName(); // Root controllers always begin with "AppleUSB" - assertEquals("AppleUSB", buffer.getString(0).substring(0, 8)); + assertEquals("AppleUSB", controllerName.substring(0, 8)); // Get the first child, to test vs. iterator - PointerByReference firstChildPtr = new PointerByReference(); boolean testFirstChild = true; - // If this returns 0, we have at least one child entry to test - // If not, the iterator will never check whether to test - controllerDevice.getChildEntry("IOService", firstChildPtr); + IORegistryEntry firstChild = controllerDevice.getChildEntry("IOService"); + // If this returns non-null, we have at least one child entry to + // test. If not, the iterator will never check whether to test // Now iterate the children of this device in the "IOService" plane. - PointerByReference childIterPtr = new PointerByReference(); - controllerDevice.getChildIterator("IOService", childIterPtr); - IOIterator childIter = new IOIterator(childIterPtr.getValue()); + IOIterator childIter = controllerDevice.getChildIterator("IOService"); IORegistryEntry childDevice = childIter.next(); while (childDevice != null) { assertTrue(childDevice.conformsTo("IOUSBDevice")); - - LongByReference childId = new LongByReference(); - childDevice.getRegistryEntryID(childId); - assertTrue(childId.getValue() > 19); - assertFalse(uniqueEntryIdSet.contains(childId.getValue())); - uniqueEntryIdSet.add(childId.getValue()); + long childId = childDevice.getRegistryEntryID(); + assertTrue(childId > 19); + assertFalse(uniqueEntryIdSet.contains(childId)); + uniqueEntryIdSet.add(childId); // If first child, test and release the retained first child pointer if (testFirstChild) { - IOObject firstChild = new IOObject(firstChildPtr.getValue()); assertEquals(childDevice, firstChild); assertEquals(0, firstChild.release()); testFirstChild = false; } // Get this device's parent in IOService plane, matches controller - PointerByReference parentPtr = new PointerByReference(); - childDevice.getParentEntry("IOService", parentPtr); - IORegistryEntry parent = new IORegistryEntry(parentPtr.getValue()); + IORegistryEntry parent = childDevice.getParentEntry("IOService"); assertEquals(controllerDevice, parent); assertEquals(0, parent.release()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java new file mode 100644 index 0000000000..e312b7bda5 --- /dev/null +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Daniel Widdis + * + * The contents of this file is dual-licensed under 2 + * alternative Open Source/Free licenses: LGPL 2.1 or later and + * Apache License 2.0. (starting with JNA version 4.0.0). + * + * You can freely decide which license you want to apply to + * the project. + * + * You may obtain a copy of the LGPL License at: + * + * http://www.gnu.org/licenses/licenses.html + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "LGPL2.1". + * + * You may obtain a copy of the Apache License at: + * + * http://www.apache.org/licenses/ + * + * A copy is also included in the downloadable source code package + * containing JNA, in file "AL2.0". + */ +package com.sun.jna.platform.mac; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class IOReturnExceptionTest { + + @Test + public void testException() { + try { + throw new IOReturnException(-536870206); + } catch (IOReturnException e) { + int code = e.getIOReturnCode(); + assertEquals(0xE00002C2, code); + assertEquals(0x38, IOReturnException.getSystem(code)); // io_kit + assertEquals(0x0, IOReturnException.getSubSystem(code)); // sub_iokit_common + assertEquals(0x2C2, IOReturnException.getCode(code)); // kIOReturnBadArgument + assertEquals("IOReturn error code: -536870206 (system=56, subSystem=0, code=706)", e.getMessage()); + } + } +} From 962816241432bfab3ff64b8314fb12a42e80b1f9 Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 18 Sep 2019 16:55:24 -0700 Subject: [PATCH 27/28] Fix tests --- .../src/com/sun/jna/platform/mac/IOKit.java | 4 ++++ .../com/sun/jna/platform/mac/IOKitTest.java | 24 +++++++++++++------ .../platform/mac/IOReturnExceptionTest.java | 8 +++---- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java index f9c233e953..8355349e56 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -53,6 +53,10 @@ public interface IOKit extends Library { int kIORegistryIterateRecursively = 0x00000001; int kIORegistryIterateParents = 0x00000002; + /** + * Return value when attempting parent or child in registry and they do not + * exist + */ int kIOReturnNoDevice = 0xe00002c0; double kIOPSTimeRemainingUnlimited = -2.0; diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java index c370e8fa76..f7400f088c 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOKitTest.java @@ -56,6 +56,8 @@ public class IOKitTest { private static final IOKit IO = IOKit.INSTANCE; private static final SystemB SYS = SystemB.INSTANCE; + private static final String IO_SERVICE = "IOService"; + @Test public void testMatching() { int masterPort = IOKitUtil.getMasterPort(); @@ -88,7 +90,6 @@ public void testMatching() { // Get matching service (consumes dict reference) IORegistryEntry platformExpert = IO.IOServiceGetMatchingService(masterPort, dict); - assertNull(platformExpert.getChildEntry("IOService")); // Get a single key CFStringRef serialKey = CFStringRef.createCFString("IOPlatformSerialNumber"); CFTypeRef cfSerialAsType = platformExpert.createCFProperty(serialKey); @@ -113,11 +114,20 @@ public void testMatching() { // Get a single key from a nested entry IORegistryEntry root = IOKitUtil.getRoot(); assertNotNull(root); - assertNull(root.getParentEntry("IOService")); - cfSerialAsType = root.searchCFProperty("IOService", serialKey, 0); + // Root should have no parent + assertNull(root.getParentEntry(IO_SERVICE)); + // Follow down the chain for a child, shouldn't reach a depth of 50 + int treeDepth = 0; + IORegistryEntry child = root.getChildEntry(IO_SERVICE); + while (child != null && ++treeDepth < 50) { + child = child.getChildEntry(IO_SERVICE); + } + assertNotEquals(50, treeDepth); + + cfSerialAsType = root.searchCFProperty(IO_SERVICE, serialKey, 0); // without recursive search should be null assertNull(cfSerialAsType); - cfSerialAsType = root.searchCFProperty("IOService", serialKey, IOKit.kIORegistryIterateRecursively); + cfSerialAsType = root.searchCFProperty(IO_SERVICE, serialKey, IOKit.kIORegistryIterateRecursively); // with recursive search should return a match cfSerial = new CFStringRef(cfSerialAsType.getPointer()); assertEquals(serialNumber, cfSerial.stringValue()); @@ -152,12 +162,12 @@ public void testIteratorParentChild() { // Get the first child, to test vs. iterator boolean testFirstChild = true; - IORegistryEntry firstChild = controllerDevice.getChildEntry("IOService"); + IORegistryEntry firstChild = controllerDevice.getChildEntry(IO_SERVICE); // If this returns non-null, we have at least one child entry to // test. If not, the iterator will never check whether to test // Now iterate the children of this device in the "IOService" plane. - IOIterator childIter = controllerDevice.getChildIterator("IOService"); + IOIterator childIter = controllerDevice.getChildIterator(IO_SERVICE); IORegistryEntry childDevice = childIter.next(); while (childDevice != null) { assertTrue(childDevice.conformsTo("IOUSBDevice")); @@ -174,7 +184,7 @@ public void testIteratorParentChild() { } // Get this device's parent in IOService plane, matches controller - IORegistryEntry parent = childDevice.getParentEntry("IOService"); + IORegistryEntry parent = childDevice.getParentEntry(IO_SERVICE); assertEquals(controllerDevice, parent); assertEquals(0, parent.release()); diff --git a/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java b/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java index e312b7bda5..e2ce4fa01e 100644 --- a/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java +++ b/contrib/platform/test/com/sun/jna/platform/mac/IOReturnExceptionTest.java @@ -33,14 +33,14 @@ public class IOReturnExceptionTest { @Test public void testException() { try { - throw new IOReturnException(-536870206); + throw new IOReturnException(IOKit.kIOReturnNoDevice); } catch (IOReturnException e) { int code = e.getIOReturnCode(); - assertEquals(0xE00002C2, code); + assertEquals(0xe00002c0, code); assertEquals(0x38, IOReturnException.getSystem(code)); // io_kit assertEquals(0x0, IOReturnException.getSubSystem(code)); // sub_iokit_common - assertEquals(0x2C2, IOReturnException.getCode(code)); // kIOReturnBadArgument - assertEquals("IOReturn error code: -536870206 (system=56, subSystem=0, code=706)", e.getMessage()); + assertEquals(0x2c0, IOReturnException.getCode(code)); // kIOReturnNoDevice + assertEquals("IOReturn error code: -536870208 (system=56, subSystem=0, code=704)", e.getMessage()); } } } From fb2163381e98a38ae96b2d6453928d62ef91334e Mon Sep 17 00:00:00 2001 From: Daniel Widdis Date: Wed, 18 Sep 2019 17:12:11 -0700 Subject: [PATCH 28/28] Checkstyle doesn't like trailing spaces --- .../com/sun/jna/platform/mac/IOReturnException.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java b/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java index 8b1b260665..0285f70cbb 100644 --- a/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOReturnException.java @@ -39,7 +39,7 @@ public class IOReturnException extends RuntimeException { /** * New exception from {@code kern_return_t} - * + * * @param kr * The return value */ @@ -49,7 +49,7 @@ public IOReturnException(int kr) { /** * New exception from {@code kern_return_t} with specified message - * + * * @param kr * The return value * @param msg @@ -69,7 +69,7 @@ public int getIOReturnCode() { /** * The high 6 bits of the return value encode the system. - * + * * @param kr * The return value * @return the system value @@ -80,7 +80,7 @@ public static int getSystem(int kr) { /** * The middle 12 bits of the return value encode the subsystem. - * + * * @param kr * The return value * @return the subsystem value @@ -91,7 +91,7 @@ public static int getSubSystem(int kr) { /** * The low 14 bits of the return value encode the return code. - * + * * @param kr * The return value * @return the return code