using CPF.Mac.ObjCRuntime; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; namespace CPF.Mac.Foundation { [Register("NSDictionary", true)] public class NSDictionary : NSObject, IDictionary, ICollection, IEnumerable, IDictionary, ICollection>, IEnumerable> { private class ShimEnumerator : IDictionaryEnumerator, IEnumerator, IDisposable { private IEnumerator> e; public DictionaryEntry Entry { get { DictionaryEntry result = default(DictionaryEntry); result.Key = e.Current.Key; result.Value = e.Current.Value; return result; } } public object Key => e.Current.Key; public object Value => e.Current.Value; public object Current => Entry; public ShimEnumerator(NSDictionary host) { e = host.GetEnumerator(); } public void Dispose() { e.Dispose(); } public bool MoveNext() { return e.MoveNext(); } public void Reset() { e.Reset(); } } private static readonly NSObject marker = new NSObject(); private static readonly IntPtr selCountHandle = Selector.GetHandle("count"); private static readonly IntPtr selAllKeysHandle = Selector.GetHandle("allKeys"); private static readonly IntPtr selAllValuesHandle = Selector.GetHandle("allValues"); private static readonly IntPtr selDescriptionInStringsFileFormatHandle = Selector.GetHandle("descriptionInStringsFileFormat"); private static readonly IntPtr selObjectEnumeratorHandle = Selector.GetHandle("objectEnumerator"); private static readonly IntPtr selDictionaryWithContentsOfFile_Handle = Selector.GetHandle("dictionaryWithContentsOfFile:"); private static readonly IntPtr selDictionaryWithContentsOfURL_Handle = Selector.GetHandle("dictionaryWithContentsOfURL:"); private static readonly IntPtr selDictionaryWithObjectForKey_Handle = Selector.GetHandle("dictionaryWithObject:forKey:"); private static readonly IntPtr selDictionaryWithDictionary_Handle = Selector.GetHandle("dictionaryWithDictionary:"); private static readonly IntPtr selDictionaryWithObjectsForKeysCount_Handle = Selector.GetHandle("dictionaryWithObjects:forKeys:count:"); private static readonly IntPtr selDictionaryWithObjectsForKeys_Handle = Selector.GetHandle("dictionaryWithObjects:forKeys:"); private static readonly IntPtr selInitWithDictionary_Handle = Selector.GetHandle("initWithDictionary:"); private static readonly IntPtr selInitWithContentsOfFile_Handle = Selector.GetHandle("initWithContentsOfFile:"); private static readonly IntPtr selInitWithObjectsForKeys_Handle = Selector.GetHandle("initWithObjects:forKeys:"); private static readonly IntPtr selInitWithContentsOfURL_Handle = Selector.GetHandle("initWithContentsOfURL:"); private static readonly IntPtr selObjectForKey_Handle = Selector.GetHandle("objectForKey:"); private static readonly IntPtr selAllKeysForObject_Handle = Selector.GetHandle("allKeysForObject:"); private static readonly IntPtr selIsEqualToDictionary_Handle = Selector.GetHandle("isEqualToDictionary:"); private static readonly IntPtr selObjectsForKeysNotFoundMarker_Handle = Selector.GetHandle("objectsForKeys:notFoundMarker:"); private static readonly IntPtr selWriteToFileAtomically_Handle = Selector.GetHandle("writeToFile:atomically:"); private static readonly IntPtr selWriteToURLAtomically_Handle = Selector.GetHandle("writeToURL:atomically:"); private static readonly IntPtr selSharedKeySetForKeys_Handle = Selector.GetHandle("sharedKeySetForKeys:"); private static readonly IntPtr class_ptr = Class.GetHandle("NSDictionary"); private object __mt_Keys_var; private object __mt_Values_var; private object __mt_ObjectEnumerator_var; int ICollection.Count => (int)Count; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => this; int ICollection>.Count => (int)Count; bool ICollection>.IsReadOnly => true; bool IDictionary.IsFixedSize => true; bool IDictionary.IsReadOnly => true; object IDictionary.this[object key] { get { NSObject nSObject = key as NSObject; if (nSObject == null) { return null; } return ObjectForKey(nSObject); } set { throw new NotSupportedException(); } } ICollection IDictionary.Keys => Keys; ICollection IDictionary.Values => Values; public virtual NSObject this[NSObject key] { get { if (key == null) { throw new ArgumentNullException("key"); } return ObjectForKey(key); } set { throw new NotSupportedException(); } } public virtual NSObject this[NSString key] { get { if (key == null) { throw new ArgumentNullException("key"); } return ObjectForKey(key); } set { throw new NotSupportedException(); } } public virtual NSObject this[string key] { get { if (key == null) { throw new ArgumentNullException("key"); } using (NSString key2 = new NSString(key)) { return ObjectForKey(key2); } } set { throw new NotSupportedException(); } } ICollection IDictionary.Keys => Keys; ICollection IDictionary.Values => Values; public override IntPtr ClassHandle => class_ptr; public virtual ulong Count { [Export("count")] get { if (IsDirectBinding) { return Messaging.UInt64_objc_msgSend(base.Handle, selCountHandle); } return Messaging.UInt64_objc_msgSendSuper(base.SuperHandle, selCountHandle); } } public virtual NSObject[] Keys { [Export("allKeys")] get { using (new NSAutoreleasePool()) { return (NSObject[])(__mt_Keys_var = ((!IsDirectBinding) ? NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, selAllKeysHandle)) : NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSend(base.Handle, selAllKeysHandle)))); } } } public virtual NSObject[] Values { [Export("allValues")] get { using (new NSAutoreleasePool()) { return (NSObject[])(__mt_Values_var = ((!IsDirectBinding) ? NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, selAllValuesHandle)) : NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSend(base.Handle, selAllValuesHandle)))); } } } public virtual string DescriptionInStringsFileFormat { [Export("descriptionInStringsFileFormat")] get { if (IsDirectBinding) { return NSString.FromHandle(Messaging.IntPtr_objc_msgSend(base.Handle, selDescriptionInStringsFileFormatHandle)); } return NSString.FromHandle(Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, selDescriptionInStringsFileFormatHandle)); } } public virtual NSEnumerator ObjectEnumerator { [Export("objectEnumerator")] get { return (NSEnumerator)(__mt_ObjectEnumerator_var = ((!IsDirectBinding) ? ((NSEnumerator)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, selObjectEnumeratorHandle))) : ((NSEnumerator)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend(base.Handle, selObjectEnumeratorHandle))))); } } public NSDictionary(NSObject first, NSObject second, params NSObject[] args) : this(PickOdd(second, args), PickEven(first, args)) { } public NSDictionary(object first, object second, params object[] args) : this(PickOdd(second, args), PickEven(first, args)) { } private static NSArray PickEven(NSObject f, NSObject[] args) { int num = args.Length; if (num % 2 != 0) { throw new ArgumentException("The arguments to NSDictionary should be a multiple of two", "args"); } NSObject[] array = new NSObject[1 + num / 2]; array[0] = f; int i = 0; int num2 = 1; for (; i < num; i += 2) { array[num2++] = args[i]; } return NSArray.FromNSObjects(array); } private static NSArray PickOdd(NSObject f, NSObject[] args) { NSObject[] array = new NSObject[1 + args.Length / 2]; array[0] = f; int i = 1; int num = 1; for (; i < args.Length; i += 2) { array[num++] = args[i]; } return NSArray.FromNSObjects(array); } private static NSArray PickEven(object f, object[] args) { int num = args.Length; if (num % 2 != 0) { throw new ArgumentException("The arguments to NSDictionary should be a multiple of two", "args"); } object[] array = new object[1 + num / 2]; array[0] = f; int i = 0; int num2 = 1; for (; i < num; i += 2) { array[num2++] = args[i]; } return NSArray.FromObjects(array); } private static NSArray PickOdd(object f, object[] args) { object[] array = new object[1 + args.Length / 2]; array[0] = f; int i = 1; int num = 1; for (; i < args.Length; i += 2) { array[num++] = args[i]; } return NSArray.FromObjects(array); } public static NSDictionary FromObjectsAndKeys(NSObject[] objects, NSObject[] keys) { if (objects.Length != keys.Length) { throw new ArgumentException("objects and keys arrays have different sizes"); } NSArray nSArray = NSArray.FromNSObjects(objects); NSArray nSArray2 = NSArray.FromNSObjects(keys); NSDictionary result = FromObjectsAndKeysInternal(nSArray, nSArray2); nSArray.Dispose(); nSArray2.Dispose(); return result; } public static NSDictionary FromObjectsAndKeys(object[] objects, object[] keys) { if (objects.Length != keys.Length) { throw new ArgumentException("objects and keys arrays have different sizes"); } NSArray nSArray = NSArray.FromObjects(objects); NSArray nSArray2 = NSArray.FromObjects(keys); NSDictionary result = FromObjectsAndKeysInternal(nSArray, nSArray2); nSArray.Dispose(); nSArray2.Dispose(); return result; } public static NSDictionary FromObjectsAndKeys(NSObject[] objects, NSObject[] keys, int count) { if (objects.Length != keys.Length) { throw new ArgumentException("objects and keys arrays have different sizes"); } if (count < 1 || objects.Length < count || keys.Length < count) { throw new ArgumentException("count"); } NSArray nSArray = NSArray.FromNSObjects(objects, count); NSArray nSArray2 = NSArray.FromNSObjects(keys, count); NSDictionary result = FromObjectsAndKeysInternal(nSArray, nSArray2); nSArray.Dispose(); nSArray2.Dispose(); return result; } public static NSDictionary FromObjectsAndKeys(object[] objects, object[] keys, int count) { if (objects.Length != keys.Length) { throw new ArgumentException("objects and keys arrays have different sizes"); } if (count < 1 || objects.Length < count || keys.Length < count) { throw new ArgumentException("count"); } NSArray nSArray = NSArray.FromObjects(count, objects); NSArray nSArray2 = NSArray.FromObjects(count, keys); NSDictionary result = FromObjectsAndKeysInternal(nSArray, nSArray2); nSArray.Dispose(); nSArray2.Dispose(); return result; } internal bool ContainsKeyValuePair(KeyValuePair pair) { if (!TryGetValue(pair.Key, out NSObject value)) { return false; } return EqualityComparer.Default.Equals(pair.Value, value); } void ICollection.CopyTo(Array array, int arrayIndex) { if (array == null) { throw new ArgumentNullException("array"); } if (arrayIndex < 0) { throw new ArgumentOutOfRangeException("arrayIndex"); } if (array.Rank > 1) { throw new ArgumentException("array is multidimensional"); } if (array.Length > 0 && arrayIndex >= array.Length) { throw new ArgumentException("arrayIndex is equal to or greater than array.Length"); } if (arrayIndex + (int)Count > array.Length) { throw new ArgumentException("Not enough room from arrayIndex to end of array for this Hashtable"); } IDictionaryEnumerator enumerator = ((IDictionary)this).GetEnumerator(); int num = arrayIndex; while (enumerator.MoveNext()) { array.SetValue(enumerator.Entry, num++); } } void ICollection>.Add(KeyValuePair item) { throw new NotSupportedException(); } void ICollection>.Clear() { throw new NotSupportedException(); } bool ICollection>.Contains(KeyValuePair keyValuePair) { return ContainsKeyValuePair(keyValuePair); } void ICollection>.CopyTo(KeyValuePair[] array, int index) { if (array == null) { throw new ArgumentNullException("array"); } if (index < 0) { throw new ArgumentOutOfRangeException("index"); } if (index > array.Length) { throw new ArgumentException("index larger than largest valid index of array"); } if (array.Length - index < (int)Count) { throw new ArgumentException("Destination array cannot hold the requested elements!"); } IEnumerator> enumerator = GetEnumerator(); while (enumerator.MoveNext()) { array[index++] = enumerator.Current; } } bool ICollection>.Remove(KeyValuePair keyValuePair) { throw new NotSupportedException(); } void IDictionary.Add(object key, object value) { throw new NotSupportedException(); } void IDictionary.Clear() { throw new NotSupportedException(); } bool IDictionary.Contains(object key) { if (key == null) { throw new ArgumentNullException("key"); } NSObject nSObject = key as NSObject; if (nSObject == null) { return false; } return ContainsKey(nSObject); } IDictionaryEnumerator IDictionary.GetEnumerator() { return new ShimEnumerator(this); } void IDictionary.Remove(object key) { throw new NotSupportedException(); } void IDictionary.Add(NSObject key, NSObject value) { throw new NotSupportedException(); } public bool ContainsKey(NSObject key) { if (key == null) { throw new ArgumentNullException("key"); } return ObjectForKey(key) != null; } bool IDictionary.Remove(NSObject key) { throw new NotSupportedException(); } public bool TryGetValue(NSObject key, out NSObject value) { if (key == null) { throw new ArgumentNullException("key"); } value = ObjectForKey(key); if (value == null) { return false; } return true; } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public IEnumerator> GetEnumerator() { NSObject[] keys = Keys; foreach (NSObject key in keys) { yield return new KeyValuePair(key, ObjectForKey(key)); } } public IntPtr LowlevelObjectForKey(IntPtr key) { return Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, selObjectForKey_Handle, key); } [EditorBrowsable(EditorBrowsableState.Advanced)] [Export("init")] public NSDictionary() : base(NSObjectFlag.Empty) { if (IsDirectBinding) { base.Handle = Messaging.IntPtr_objc_msgSend(base.Handle, Selector.Init); } else { base.Handle = Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, Selector.Init); } } [EditorBrowsable(EditorBrowsableState.Advanced)] [Export("initWithCoder:")] public NSDictionary(NSCoder coder) : base(NSObjectFlag.Empty) { if (IsDirectBinding) { base.Handle = Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, Selector.InitWithCoder, coder.Handle); } else { base.Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, Selector.InitWithCoder, coder.Handle); } } [EditorBrowsable(EditorBrowsableState.Advanced)] public NSDictionary(NSObjectFlag t) : base(t) { } [EditorBrowsable(EditorBrowsableState.Advanced)] public NSDictionary(IntPtr handle) : base(handle) { } [Export("dictionaryWithContentsOfFile:")] public static NSDictionary FromFile(string path) { if (path == null) { throw new ArgumentNullException("path"); } IntPtr intPtr = NSString.CreateNative(path); NSDictionary result = (NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selDictionaryWithContentsOfFile_Handle, intPtr)); NSString.ReleaseNative(intPtr); return result; } [Export("dictionaryWithContentsOfURL:")] public static NSDictionary FromUrl(NSUrl url) { if (url == null) { throw new ArgumentNullException("url"); } return (NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selDictionaryWithContentsOfURL_Handle, url.Handle)); } [Export("dictionaryWithObject:forKey:")] public static NSDictionary FromObjectAndKey(NSObject obj, NSObject key) { if (obj == null) { throw new ArgumentNullException("obj"); } if (key == null) { throw new ArgumentNullException("key"); } return (NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr(class_ptr, selDictionaryWithObjectForKey_Handle, obj.Handle, key.Handle)); } [Export("dictionaryWithDictionary:")] public static NSDictionary FromDictionary(NSDictionary source) { if (source == null) { throw new ArgumentNullException("source"); } return (NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selDictionaryWithDictionary_Handle, source.Handle)); } [Export("dictionaryWithObjects:forKeys:count:")] internal static NSDictionary FromObjectsAndKeysInternal(NSArray objects, NSArray keys, ulong count) { return (NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr_UInt64(class_ptr, selDictionaryWithObjectsForKeysCount_Handle, objects?.Handle ?? IntPtr.Zero, keys?.Handle ?? IntPtr.Zero, count)); } [Export("dictionaryWithObjects:forKeys:")] internal static NSDictionary FromObjectsAndKeysInternal(NSArray objects, NSArray keys) { return (NSDictionary)Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr(class_ptr, selDictionaryWithObjectsForKeys_Handle, objects?.Handle ?? IntPtr.Zero, keys?.Handle ?? IntPtr.Zero)); } [Export("initWithDictionary:")] public NSDictionary(NSDictionary other) : base(NSObjectFlag.Empty) { if (other == null) { throw new ArgumentNullException("other"); } if (IsDirectBinding) { base.Handle = Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, selInitWithDictionary_Handle, other.Handle); } else { base.Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, selInitWithDictionary_Handle, other.Handle); } } [Export("initWithContentsOfFile:")] public NSDictionary(string fileName) : base(NSObjectFlag.Empty) { if (fileName == null) { throw new ArgumentNullException("fileName"); } IntPtr intPtr = NSString.CreateNative(fileName); if (IsDirectBinding) { base.Handle = Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, selInitWithContentsOfFile_Handle, intPtr); } else { base.Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, selInitWithContentsOfFile_Handle, intPtr); } NSString.ReleaseNative(intPtr); } [Export("initWithObjects:forKeys:")] internal NSDictionary(NSArray objects, NSArray keys) : base(NSObjectFlag.Empty) { if (objects == null) { throw new ArgumentNullException("objects"); } if (keys == null) { throw new ArgumentNullException("keys"); } if (IsDirectBinding) { base.Handle = Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr(base.Handle, selInitWithObjectsForKeys_Handle, objects.Handle, keys.Handle); } else { base.Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr_IntPtr(base.SuperHandle, selInitWithObjectsForKeys_Handle, objects.Handle, keys.Handle); } } [Export("initWithContentsOfURL:")] public NSDictionary(NSUrl url) : base(NSObjectFlag.Empty) { if (url == null) { throw new ArgumentNullException("url"); } if (IsDirectBinding) { base.Handle = Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, selInitWithContentsOfURL_Handle, url.Handle); } else { base.Handle = Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, selInitWithContentsOfURL_Handle, url.Handle); } } [Export("objectForKey:")] public virtual NSObject ObjectForKey(NSObject key) { if (key == null) { throw new ArgumentNullException("key"); } if (IsDirectBinding) { return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, selObjectForKey_Handle, key.Handle)); } return Runtime.GetNSObject(Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, selObjectForKey_Handle, key.Handle)); } [Export("allKeysForObject:")] public virtual NSObject[] KeysForObject(NSObject obj) { using (new NSAutoreleasePool()) { if (obj == null) { throw new ArgumentNullException("obj"); } if (IsDirectBinding) { return NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSend_IntPtr(base.Handle, selAllKeysForObject_Handle, obj.Handle)); } return NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSendSuper_IntPtr(base.SuperHandle, selAllKeysForObject_Handle, obj.Handle)); } } [Export("isEqualToDictionary:")] public virtual bool IsEqualToDictionary(NSDictionary other) { if (other == null) { throw new ArgumentNullException("other"); } if (IsDirectBinding) { return Messaging.bool_objc_msgSend_IntPtr(base.Handle, selIsEqualToDictionary_Handle, other.Handle); } return Messaging.bool_objc_msgSendSuper_IntPtr(base.SuperHandle, selIsEqualToDictionary_Handle, other.Handle); } [Export("objectsForKeys:notFoundMarker:")] public virtual NSObject[] ObjectsForKeys(NSArray keys, NSObject marker) { using (new NSAutoreleasePool()) { if (keys == null) { throw new ArgumentNullException("keys"); } if (marker == null) { throw new ArgumentNullException("marker"); } if (IsDirectBinding) { return NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr(base.Handle, selObjectsForKeysNotFoundMarker_Handle, keys.Handle, marker.Handle)); } return NSArray.ArrayFromHandle(Messaging.IntPtr_objc_msgSendSuper_IntPtr_IntPtr(base.SuperHandle, selObjectsForKeysNotFoundMarker_Handle, keys.Handle, marker.Handle)); } } [Export("writeToFile:atomically:")] public virtual bool WriteToFile(string path, bool useAuxiliaryFile) { if (path == null) { throw new ArgumentNullException("path"); } IntPtr intPtr = NSString.CreateNative(path); bool result = (!IsDirectBinding) ? Messaging.bool_objc_msgSendSuper_IntPtr_bool(base.SuperHandle, selWriteToFileAtomically_Handle, intPtr, useAuxiliaryFile) : Messaging.bool_objc_msgSend_IntPtr_bool(base.Handle, selWriteToFileAtomically_Handle, intPtr, useAuxiliaryFile); NSString.ReleaseNative(intPtr); return result; } [Export("writeToURL:atomically:")] public virtual bool WriteToUrl(NSUrl url, bool atomically) { if (url == null) { throw new ArgumentNullException("url"); } if (IsDirectBinding) { return Messaging.bool_objc_msgSend_IntPtr_bool(base.Handle, selWriteToURLAtomically_Handle, url.Handle, atomically); } return Messaging.bool_objc_msgSendSuper_IntPtr_bool(base.SuperHandle, selWriteToURLAtomically_Handle, url.Handle, atomically); } [Export("sharedKeySetForKeys:")] public static NSObject GetSharedKeySetForKeys(NSObject[] keys) { if (keys == null) { throw new ArgumentNullException("keys"); } NSArray nSArray = NSArray.FromNSObjects(keys); NSObject nSObject = Runtime.GetNSObject(Messaging.IntPtr_objc_msgSend_IntPtr(class_ptr, selSharedKeySetForKeys_Handle, nSArray.Handle)); nSArray.Dispose(); return nSObject; } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (base.Handle == IntPtr.Zero) { __mt_Keys_var = null; __mt_Values_var = null; __mt_ObjectEnumerator_var = null; } } } }