diff --git a/CHANGES.md b/CHANGES.md index 5ab729b844..1dcae5f3eb 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 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 new file mode 100644 index 0000000000..c456781eb5 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/CoreFoundation.java @@ -0,0 +1,1030 @@ +/* + * 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.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; +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 + * 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 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 + * generic object reference that acts as a placeholder for other true Core + * Foundation objects. + */ + class CFTypeRef extends PointerType { + public CFTypeRef() { + super(); + } + + public CFTypeRef(Pointer p) { + super(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. + */ + public void retain() { + INSTANCE.CFRetain(this); + } + + /** + * Convenience method for {@link CoreFoundation#CFRelease} on this object. + */ + public void release() { + INSTANCE.CFRelease(this); + } + } + + /** + * 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 { + public CFNumberRef() { + super(); + } + + public CFNumberRef(Pointer p) { + super(p); + if (!isTypeID(NUMBER_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFNumber. Type ID: " + getTypeID()); + } + } + + /** + * 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.typeIndex(), 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.typeIndex(), 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.typeIndex(), 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.typeIndex(), 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.typeIndex(), 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.typeIndex(), fbr); + return fbr.getValue(); + } + } + + /** + * Enum of values used for {@link CFNumberType} in {@link #CFNumberGetValue} and + * {@link #CFNumberGetType}. Use {@link CFNumberType#typeIndex} 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; + + /** + * Index for the type of {@link CFNumberRef} stored. + * + * @return a {@link CFIndex} representing the enum ordinal. + */ + public CFIndex typeIndex() { + return new CFIndex(this.ordinal()); + } + } + + /** + * A reference to a {@code CFBoolean} object. + */ + class CFBooleanRef extends CFTypeRef { + public CFBooleanRef() { + super(); + } + + public CFBooleanRef(Pointer p) { + super(p); + if (!isTypeID(BOOLEAN_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFBoolean. Type ID: " + getTypeID()); + } + } + + /** + * 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); + } + } + + /** + * 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 { + public CFArrayRef() { + super(); + } + + public CFArrayRef(Pointer p) { + super(p); + if (!isTypeID(ARRAY_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFArray. Type ID: " + getTypeID()); + } + } + + /** + * Convenience method for {@link #CFArrayGetCount} on this object + * + * @return The number of values in this array. + */ + public int getCount() { + return INSTANCE.CFArrayGetCount(this).intValue(); + } + + /** + * 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(int idx) { + return INSTANCE.CFArrayGetValueAtIndex(this, new CFIndex(idx)); + } + } + + /** + * A reference to an immutable {@code CFData} object. + */ + class CFDataRef extends CFTypeRef { + public CFDataRef() { + super(); + } + + public CFDataRef(Pointer p) { + super(p); + if (!isTypeID(DATA_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFData. Type ID: " + getTypeID()); + } + } + + /** + * Convenience method for {@link #CFDataGetLength} on this object + * + * @return An index that specifies the number of bytes associated with this + * object. + */ + public int getLength() { + return INSTANCE.CFDataGetLength(this).intValue(); + } + + /** + * 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); + } + } + + /** + * A reference to an immutable {@code CFDictionary} object. + */ + class CFDictionaryRef extends CFTypeRef { + public CFDictionaryRef() { + super(); + } + + public CFDictionaryRef(Pointer p) { + super(p); + if (!isTypeID(DICTIONARY_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFDictionary. Type ID: " + getTypeID()); + } + } + + /** + * 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 {@code true} if a matching key was found, otherwise + * {@code false} + */ + public boolean getValueIfPresent(PointerType key, PointerByReference value) { + return INSTANCE.CFDictionaryGetValueIfPresent(this, key, value) > 0; + } + } + + /** + * A reference to a mutable {@code CFDictionary} object. + */ + class CFMutableDictionaryRef extends CFDictionaryRef { + public CFMutableDictionaryRef() { + super(); + } + + 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); + } + } + + /** + * 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 { + public CFStringRef() { + super(); + } + + public CFStringRef(Pointer p) { + super(p); + if (!isTypeID(STRING_TYPE_ID)) { + throw new ClassCastException("Unable to cast to CFString. Type ID: " + getTypeID()); + } + } + + /** + * Convenience function which calls {@link #CFStringCreateWithCharacters} to + * 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 + * 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 createCFString(String s) { + final char[] chars = s.toCharArray(); + return INSTANCE.CFStringCreateWithCharacters(null, chars, new CFIndex(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() { + CFIndex length = INSTANCE.CFStringGetLength(this); + CFIndex maxSize = INSTANCE.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); + if (maxSize.intValue() == kCFNotFound) { + return null; + } + Memory buf = new Memory(maxSize.longValue()); + if (0 != INSTANCE.CFStringGetCString(this, buf, maxSize, kCFStringEncodingUTF8)) { + return buf.getString(0, "UTF8"); + } + return null; + } + } + + /** + * 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() { + super(); + } + + public CFIndex(long value) { + super(value); + } + } + + /** + * 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). + */ + class CFTypeID extends NativeLong { + private static final long serialVersionUID = 1L; + + public CFTypeID() { + super(); + } + + 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(); + } + } + } + + /** + * 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, CFIndex 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, CFIndex theType, ByReference 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, CFIndex 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, CFIndex 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, CFIndex 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}. + */ + CFIndex 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. + */ + Pointer CFDictionaryGetValue(CFDictionaryRef theDict, PointerType 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 1 if a matching key was found, otherwise 0. + */ + byte CFDictionaryGetValueIfPresent(CFDictionaryRef theDict, PointerType key, PointerByReference 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, PointerType key, PointerType 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 1 upon success or 0 if the conversion fails or the provided buffer is + * too small. + */ + byte CFStringGetCString(CFStringRef theString, Pointer bufferToFill, CFIndex bufferSize, int encoding); + + /** + * Returns the value of a {@code CFBoolean} object. + * + * @param bool + * The boolean to examine. + * @return 1 if the value of {@code bool} is {@code true}, 0 otherwise. + */ + 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. + * + * @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}). + */ + Pointer CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex 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. + */ + CFIndex CFNumberGetType(CFNumberRef 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 valuePtr + * On return, contains the value of {@code number}. + * @return 1 if the operation was successful, otherwise 0. + */ + byte CFNumberGetValue(CFNumberRef number, CFIndex 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}. + */ + CFIndex CFStringGetLength(CFStringRef 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 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}. + */ + CFIndex CFStringGetMaximumSizeForEncoding(CFIndex 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}. + */ + CFIndex CFDataGetLength(CFDataRef 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}. + */ + 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/DiskArbitration.java b/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java new file mode 100644 index 0000000000..fdc7a34838 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/DiskArbitration.java @@ -0,0 +1,128 @@ +/* + * 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; +import com.sun.jna.platform.mac.IOKit.IOObject; + +/** + * 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, IOObject 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); +} 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..8355349e56 --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKit.java @@ -0,0 +1,849 @@ +/* + * 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.Memory; +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.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; +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 { + + IOKit INSTANCE = Native.load("IOKit", IOKit.class); + + 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; + double kIOPSTimeRemainingUnknown = -1.0; + + /** + * 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, 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 + * 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 {@link IOKit#IOObjectRelease}. + */ + class IOObject extends PointerType { + public IOObject() { + super(); + } + + 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. + * + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + public int release() { + return INSTANCE.IOObjectRelease(this); + } + } + + /** + * An IOKit iterator handle. + */ + class IOIterator extends IOObject { + public IOIterator() { + super(); + } + + 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 {@code null} is returned. The element should be + * released by the caller when it is finished. + */ + public IORegistryEntry next() { + return INSTANCE.IOIteratorNext(this); + } + } + + /** + * The base class for all objects in the registry. + */ + class IORegistryEntry extends IOObject { + public IORegistryEntry() { + super(); + } + + 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. + * + * @return the ID. + * @throws IOReturnException + * if the ID could not be retrieved. + */ + 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. + * + * @return The name + * @throws IOReturnException + * if the name could not be retrieved. + */ + 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. + * + * @param plane + * 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 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. + * + * @param plane + * The name of an existing registry plane. + * @return The child registry entry, if a child exists, null otherwise + * @throws IOReturnException + * if the entry exists but could not be retrieved. + */ + 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. + * + * @param plane + * The name of an existing registry plane. + * @return The parent registry entry, if a parent exists, null otherwise + * @throws IOReturnException + * if the entry exists but could not be retrieved. + */ + 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()); + } + + /** + * 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. + * + * @return The property table. + *
+ * The caller should release with + * {@link CoreFoundation#CFRelease}. + * @throws IOReturnException + * if the entry could not be retrieved. + */ + 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()); + } + + /** + * 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. + * + * @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 = this.createCFProperty(keyAsCFString); + 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 = this.createCFProperty(keyAsCFString); + 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 = this.createCFProperty(keyAsCFString); + 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 = this.createCFProperty(keyAsCFString); + 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 = this.createCFProperty(keyAsCFString); + 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 = this.createCFProperty(keyAsCFString); + keyAsCFString.release(); + if (valueAsCFType != null) { + CFDataRef valueAsCFData = new CFDataRef(valueAsCFType.getPointer()); + int length = valueAsCFData.getLength(); + Pointer p = valueAsCFData.getBytePtr(); + value = p.getByteArray(0, length); + valueAsCFType.release(); + } + return value; + } + } + + /** + * 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 IOService { + public IOConnect() { + super(); + } + + public IOConnect(Pointer p) { + super(p); + } + } + + /** + * Returns the mach port used to initiate communication with IOKit. + * + * @param bootstrapPort + * 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 SystemB#mach_port_deallocate}. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IOMasterPort(int bootstrapPort, IntByReference port); + + /** + * 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(int 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. + */ + IOService IOServiceGetMatchingService(int masterPort, CFDictionaryRef 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 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(int masterPort, CFDictionaryRef matchingDictionary, PointerByReference iterator); + + /** + * 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. + */ + IORegistryEntry IOIteratorNext(IOIterator iterator); + + /** + * Create a CF representation of a registry entry's property. + * + * @param entry + * The 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(IORegistryEntry 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(IORegistryEntry 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(IORegistryEntry 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(IORegistryEntry 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. This must be a 128-byte + * buffer. + * @return 0 if successful, otherwise a {@code kern_return_t} error code. + */ + int IORegistryEntryGetName(IORegistryEntry 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(IORegistryEntry entry, String plane, PointerByReference 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(IORegistryEntry entry, String plane, PointerByReference 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(IORegistryEntry entry, String plane, PointerByReference 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. + */ + IORegistryEntry IORegistryGetRootEntry(int 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(IOObject 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(IOObject 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(IOService service, int owningTask, int type, PointerByReference 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(IOService 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(IOConnect 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/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..dbe567b0ab --- /dev/null +++ b/contrib/platform/src/com/sun/jna/platform/mac/IOKitUtil.java @@ -0,0 +1,161 @@ +/* + * 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.platform.mac.CoreFoundation.CFDictionaryRef; +import com.sun.jna.platform.mac.CoreFoundation.CFMutableDictionaryRef; +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.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; + +/** + * Provides utilities for IOKit. + */ +public class IOKitUtil { + private static final IOKit IO = IOKit.INSTANCE; + private static final SystemB SYS = SystemB.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 SystemB#mach_port_deallocate}. + */ + public static int getMasterPort() { + IntByReference port = new IntByReference(); + IO.IOMasterPort(0, port); + return 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() { + int masterPort = getMasterPort(); + IORegistryEntry root = IO.IORegistryGetRootEntry(masterPort); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); + 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) { + int masterPort = getMasterPort(); + IOService service = IO.IOServiceGetMatchingService(masterPort, matchingDictionary); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); + 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) { + int masterPort = getMasterPort(); + PointerByReference serviceIterator = new PointerByReference(); + int result = IO.IOServiceGetMatchingServices(masterPort, matchingDictionary, serviceIterator); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); + 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) { + int masterPort = getMasterPort(); + CFMutableDictionaryRef result = IO.IOBSDNameMatching(masterPort, 0, bsdName); + SYS.mach_port_deallocate(SYS.mach_task_self(), masterPort); + return result; + } +} 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..0285f70cbb --- /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/src/com/sun/jna/platform/mac/SystemB.java b/contrib/platform/src/com/sun/jna/platform/mac/SystemB.java index 9fed4bf1e3..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,9 +25,6 @@ package com.sun.jna.platform.mac; -import java.util.Arrays; -import java.util.List; - import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.NativeLong; @@ -37,9 +34,6 @@ 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); @@ -92,22 +86,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 +119,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 +157,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 +191,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 +216,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 +270,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 +297,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 +312,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 +343,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 +355,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 +395,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 +418,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 +453,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 +476,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 +495,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 +506,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,73 +515,82 @@ 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 - * 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 the host's name port */ int mach_host_self(); /** - * 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. + * 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 */ 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(int port, int name); + /** * 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 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(int machPort, LongByReference pPageSize); + int host_page_size(int hostPort, 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 + * @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 @@ -609,17 +598,17 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ - 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 * 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 @@ -627,35 +616,35 @@ class Timezone extends Structure { * returned (in natural-sized units). * @return 0 on success; sets errno on failure */ - 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 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 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. + * 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. + * 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 +660,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 +679,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 + * 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. + *
+ * 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);
@@ -729,7 +714,7 @@ int sysctlbyname(String name, Pointer oldp, IntByReference oldlenp,
/**
* 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
@@ -742,28 +727,30 @@ 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(int hostPort, 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 +759,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 +779,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 +802,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 +816,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 +836,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/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..a7d621789d
--- /dev/null
+++ b/contrib/platform/test/com/sun/jna/platform/mac/CoreFoundationTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.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;
+import static org.junit.Assert.fail;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Test;
+
+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;
+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;
+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() throws UnsupportedEncodingException {
+ String awesome = "ǝɯosǝʍɐ sı ∀Nſ"; // Unicode
+ CFStringRef cfAwesome = CFStringRef.createCFString(awesome);
+ assertEquals(awesome.length(), CF.CFStringGetLength(cfAwesome).intValue());
+ assertEquals(awesome, cfAwesome.stringValue());
+ assertEquals(CoreFoundation.STRING_TYPE_ID, cfAwesome.getTypeID());
+
+ byte[] awesomeArr = awesome.getBytes("UTF-8");
+ Memory mem = new Memory(awesomeArr.length + 1);
+ mem.clear();
+ assertNotEquals(0,
+ CF.CFStringGetCString(cfAwesome, mem, new CFIndex(mem.size()), CoreFoundation.kCFStringEncodingUTF8));
+ byte[] awesomeBytes = mem.getByteArray(0, (int) mem.size() - 1);
+ assertArrayEquals(awesomeArr, awesomeBytes);
+ // Essentially a toString, can't rely on format but should contain the string
+ CFStringRef desc = CF.CFCopyDescription(cfAwesome);
+ assertTrue(desc.stringValue().contains(awesome));
+
+ desc.release();
+ cfAwesome.release();
+ }
+
+ @Test
+ 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(CoreFoundation.NUMBER_TYPE_ID, cfMax.getTypeID());
+ cfMax.release();
+
+ IntByReference zero = new IntByReference(0);
+ IntByReference one = new IntByReference(1);
+ 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());
+ cfZero.release();
+ cfOne.release();
+ }
+
+ @Test
+ public void testCFRetainCount() {
+ DoubleByReference pi = new DoubleByReference(Math.PI);
+ 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).intValue());
+ assertEquals(1, CF.CFGetRetainCount(cfPi).intValue());
+ cfE.retain();
+ cfPi.retain();
+ cfPi.retain();
+ assertEquals(2, CF.CFGetRetainCount(cfE).intValue());
+ assertEquals(3, CF.CFGetRetainCount(cfPi).intValue());
+
+ List extends CFTypeRef> irrationalReferences = Arrays.asList(cfE, cfPi);
+ for (CFTypeRef value : irrationalReferences) {
+ value.release();
+ }
+
+ assertEquals(1, CF.CFGetRetainCount(cfE).intValue());
+ assertEquals(2, CF.CFGetRetainCount(cfPi).intValue());
+ cfPi.release();
+ assertEquals(1, CF.CFGetRetainCount(cfPi).intValue());
+ cfE.release();
+ cfPi.release();
+ }
+
+ @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.typeIndex(),
+ new IntByReference(i));
+ contiguousArray.setPointer(i * size, refArray[i].getPointer());
+ }
+ CFArrayRef cfPtrArray = CF.CFArrayCreate(null, contiguousArray, new CFIndex(refArray.length), null);
+ assertEquals(CoreFoundation.ARRAY_TYPE_ID, cfPtrArray.getTypeID());
+
+ assertEquals(refArray.length, cfPtrArray.getCount());
+ for (int i = 0; i < refArray.length; i++) {
+ Pointer result = cfPtrArray.getValueAtIndex(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());
+ }
+
+ for (int i = 0; i < refArray.length; i++) {
+ refArray[i].release();
+ }
+ cfPtrArray.release();
+ }
+
+ @Test
+ public void testCFData() {
+ 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);
+ nativeBytes.write(0, randomBytes, 0, randomBytes.length);
+ // Create a CF reference to the data
+ CFDataRef cfData = CF.CFDataCreate(null, nativeBytes, new CFIndex(size));
+ assertEquals(CoreFoundation.DATA_TYPE_ID, cfData.getTypeID());
+
+ int dataSize = cfData.getLength();
+ assertEquals(size, dataSize);
+ // Read it back out and convert to an array
+ Pointer bytes = cfData.getBytePtr();
+ byte[] dataBytes = bytes.getByteArray(0, dataSize);
+ assertArrayEquals(randomBytes, dataBytes);
+ cfData.release();
+ }
+
+ @Test
+ public void testCFDictionary() {
+ CFAllocatorRef alloc = CF.CFAllocatorGetDefault();
+ CFMutableDictionaryRef dict = CF.CFDictionaryCreateMutable(alloc, new CFIndex(2), null, null);
+ assertEquals(CoreFoundation.DICTIONARY_TYPE_ID, dict.getTypeID());
+
+ CFStringRef oneStr = CFStringRef.createCFString("one");
+
+ // Key does not exist, returns null
+ assertFalse(dict.getValueIfPresent(oneStr, null));
+ Pointer cfNull = dict.getValue(oneStr);
+ assertNull(cfNull);
+
+ // Store and retrieve null value
+ dict.setValue(oneStr, null);
+ assertTrue(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);
+ dict.setValue(oneStr, cfOne);
+
+ assertTrue(dict.getValueIfPresent(oneStr, null));
+ Pointer result = dict.getValue(oneStr);
+ CFNumberRef numRef = new CFNumberRef(result);
+ assertEquals(1, numRef.intValue());
+
+ PointerByReference resultPtr = new PointerByReference();
+ assertTrue(dict.getValueIfPresent(oneStr, resultPtr));
+ numRef = new CFNumberRef(resultPtr.getValue());
+ assertEquals(1, numRef.intValue());
+
+ // Test non-CF type as key
+ IntByReference onePtr = new IntByReference(1);
+ dict.setValue(onePtr, oneStr);
+ result = dict.getValue(onePtr);
+ CFStringRef strRef = new CFStringRef(result);
+ assertEquals("one", strRef.stringValue());
+
+ 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
new file mode 100644
index 0000000000..60c106ed79
--- /dev/null
+++ b/contrib/platform/test/com/sun/jna/platform/mac/DiskArbitrationTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+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.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;
+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.ptr.IntByReference;
+import com.sun.jna.ptr.PointerByReference;
+
+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() {
+ 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");
+ CFStringRef daMediaWhole = CFStringRef.createCFString("DAMediaWhole");
+ 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