using CPF.Mac.ObjCRuntime; using System; using System.Collections.Generic; using System.Runtime.InteropServices; namespace CPF.Mac.CoreFoundation { [Since(3, 2)] internal class CFDictionary : INativeObject, IDisposable { public static IntPtr KeyCallbacks; public static IntPtr ValueCallbacks; public IntPtr Handle { get; private set; } public int Count => CFDictionaryGetCount(Handle); public CFDictionary(IntPtr handle) : this(handle, owns: false) { } public CFDictionary(IntPtr handle, bool owns) { if (!owns) { CFObject.CFRetain(handle); } Handle = handle; } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", EntryPoint = "CFDictionaryGetTypeID")] public static extern int GetTypeID(); ~CFDictionary() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } public virtual void Dispose(bool disposing) { if (Handle != IntPtr.Zero) { CFObject.CFRelease(Handle); Handle = IntPtr.Zero; } } static CFDictionary() { IntPtr handle = Dlfcn.dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", 0); try { KeyCallbacks = Dlfcn.GetIndirect(handle, "kCFTypeDictionaryKeyCallBacks"); ValueCallbacks = Dlfcn.GetIndirect(handle, "kCFTypeDictionaryValueCallBacks"); } finally { Dlfcn.dlclose(handle); } } public static CFDictionary FromObjectAndKey(INativeObject obj, INativeObject key) { return new CFDictionary(CFDictionaryCreate(IntPtr.Zero, new IntPtr[1] { key.Handle }, new IntPtr[1] { obj.Handle }, 1, KeyCallbacks, ValueCallbacks), owns: true); } public static CFDictionary FromObjectsAndKeys(INativeObject[] objects, INativeObject[] keys) { if (objects == null) { throw new ArgumentNullException("objects"); } if (keys == null) { throw new ArgumentNullException("keys"); } if (objects.Length != keys.Length) { throw new ArgumentException("The length of both arrays must be the same"); } IntPtr[] array = new IntPtr[keys.Length]; IntPtr[] array2 = new IntPtr[keys.Length]; for (int i = 0; i < array.Length; i++) { array[i] = keys[i].Handle; array2[i] = objects[i].Handle; } return new CFDictionary(CFDictionaryCreate(IntPtr.Zero, array, array2, array.Length, KeyCallbacks, ValueCallbacks), owns: true); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern IntPtr CFDictionaryCreate(IntPtr allocator, IntPtr[] keys, IntPtr[] vals, int len, IntPtr keyCallbacks, IntPtr valCallbacks); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern IntPtr CFDictionaryGetValue(IntPtr theDict, IntPtr key); public static IntPtr GetValue(IntPtr theDict, IntPtr key) { return CFDictionaryGetValue(theDict, key); } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern int CFDictionaryGetCount(IntPtr theDict); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern void CFDictionaryGetKeysAndValues(IntPtr theDict, IntPtr[] keys, IntPtr[] values); public void GetKeysAndValues(out IntPtr[] keys, out IntPtr[] values) { int count = Count; keys = new IntPtr[count]; values = new IntPtr[count]; CFDictionaryGetKeysAndValues(Handle, keys, values); } public static bool GetBooleanValue(IntPtr theDict, IntPtr key) { IntPtr value = GetValue(theDict, key); if (value == IntPtr.Zero) { return false; } return CFBoolean.GetValue(value); } public string GetStringValue(string key) { using (CFString cFString = new CFString(key)) { return CFString.FetchString(CFDictionaryGetValue(Handle, cFString.handle)); } } public int GetInt32Value(string key) { int value = 0; using (CFString cFString = new CFString(key)) { if (!CFNumberGetValue(CFDictionaryGetValue(Handle, cFString.Handle), 3, out value)) { throw new KeyNotFoundException($"Key {key} not found"); } return value; } } public long GetInt64Value(string key) { long value = 0L; using (CFString cFString = new CFString(key)) { if (!CFNumberGetValue(CFDictionaryGetValue(Handle, cFString.Handle), 4, out value)) { throw new KeyNotFoundException($"Key {key} not found"); } return value; } } public IntPtr GetIntPtrValue(string key) { using (CFString cFString = new CFString(key)) { return CFDictionaryGetValue(Handle, cFString.handle); } } public CFDictionary GetDictionaryValue(string key) { using (CFString cFString = new CFString(key)) { IntPtr intPtr = CFDictionaryGetValue(Handle, cFString.handle); return (intPtr == IntPtr.Zero) ? null : new CFDictionary(intPtr); } } public bool ContainsKey(string key) { using (CFString cFString = new CFString(key)) { return CFDictionaryContainsKey(Handle, cFString.handle); } } [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern bool CFNumberGetValue(IntPtr number, int theType, out int value); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern bool CFNumberGetValue(IntPtr number, int theType, out long value); [DllImport("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation")] private static extern bool CFDictionaryContainsKey(IntPtr theDict, IntPtr key); } }