diff options
Diffstat (limited to 'gstreamer-sharp/glib-sharp/GType.cs')
-rw-r--r-- | gstreamer-sharp/glib-sharp/GType.cs | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/gstreamer-sharp/glib-sharp/GType.cs b/gstreamer-sharp/glib-sharp/GType.cs new file mode 100644 index 0000000..c3f0940 --- /dev/null +++ b/gstreamer-sharp/glib-sharp/GType.cs @@ -0,0 +1,426 @@ +// GLib.Type.cs - GLib GType class implementation +// +// Author: Mike Kestner <mkestner@speakeasy.net> +// +// Copyright (c) 2003 Mike Kestner +// Copyright (c) 2003 Novell, Inc. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the Lesser GNU General +// Public License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this program; if not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + + +namespace GLib { + + using System; + using System.Collections; + using System.IO; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Text; + + public delegate System.Type TypeResolutionHandler (GLib.GType gtype, string gtype_name); + + [StructLayout(LayoutKind.Sequential)] + public struct GType { + + IntPtr val; + + struct GTypeInfo { + public ushort class_size; + IntPtr base_init; + IntPtr base_finalize; + IntPtr class_init; + IntPtr class_finalize; + IntPtr class_data; + public ushort instance_size; + ushort n_preallocs; + IntPtr instance_init; + IntPtr value_table; + } + + struct GTypeQuery { + public IntPtr type; + public IntPtr type_name; + public uint class_size; + public uint instance_size; + } + + public GType (IntPtr val) + { + this.val = val; + } + + public static GType FromName (string native_name) + { + return new GType (g_type_from_name (native_name)); + } + + public static readonly GType Invalid = new GType ((IntPtr) TypeFundamentals.TypeInvalid); + public static readonly GType None = new GType ((IntPtr) TypeFundamentals.TypeNone); + public static readonly GType Interface = new GType ((IntPtr) TypeFundamentals.TypeInterface); + public static readonly GType Char = new GType ((IntPtr) TypeFundamentals.TypeChar); + public static readonly GType UChar = new GType ((IntPtr) TypeFundamentals.TypeUChar); + public static readonly GType Boolean = new GType ((IntPtr) TypeFundamentals.TypeBoolean); + public static readonly GType Int = new GType ((IntPtr) TypeFundamentals.TypeInt); + public static readonly GType UInt = new GType ((IntPtr) TypeFundamentals.TypeUInt); + public static readonly GType Long = new GType ((IntPtr) TypeFundamentals.TypeLong); + public static readonly GType ULong = new GType ((IntPtr) TypeFundamentals.TypeULong); + public static readonly GType Int64 = new GType ((IntPtr) TypeFundamentals.TypeInt64); + public static readonly GType UInt64 = new GType ((IntPtr) TypeFundamentals.TypeUInt64); + public static readonly GType Enum = new GType ((IntPtr) TypeFundamentals.TypeEnum); + public static readonly GType Flags = new GType ((IntPtr) TypeFundamentals.TypeFlags); + public static readonly GType Float = new GType ((IntPtr) TypeFundamentals.TypeFloat); + public static readonly GType Double = new GType ((IntPtr) TypeFundamentals.TypeDouble); + public static readonly GType String = new GType ((IntPtr) TypeFundamentals.TypeString); + public static readonly GType Pointer = new GType ((IntPtr) TypeFundamentals.TypePointer); + public static readonly GType Boxed = new GType ((IntPtr) TypeFundamentals.TypeBoxed); + public static readonly GType Param = new GType ((IntPtr) TypeFundamentals.TypeParam); + public static readonly GType Object = new GType ((IntPtr) TypeFundamentals.TypeObject); + + static Hashtable types = new Hashtable (); + static Hashtable gtypes = new Hashtable (); + + public static void Register (GType native_type, System.Type type) + { + if (native_type != GType.Pointer && native_type != GType.Boxed && native_type != ManagedValue.GType) + types[native_type.Val] = type; + if (type != null) + gtypes[type] = native_type; + } + + static GType () + { + if (!GLib.Thread.Supported) + GLib.Thread.Init (); + + g_type_init (); + + Register (GType.Char, typeof (sbyte)); + Register (GType.UChar, typeof (byte)); + Register (GType.Boolean, typeof (bool)); + Register (GType.Int, typeof (int)); + Register (GType.UInt, typeof (uint)); + Register (GType.Int64, typeof (long)); + Register (GType.UInt64, typeof (ulong)); + Register (GType.Float, typeof (float)); + Register (GType.Double, typeof (double)); + Register (GType.String, typeof (string)); + Register (GType.Pointer, typeof (IntPtr)); + Register (GType.Object, typeof (GLib.Object)); + Register (GType.Pointer, typeof (IntPtr)); + + // One-way mapping + gtypes[typeof (char)] = GType.UInt; + } + + public static explicit operator GType (System.Type type) + { + GType gtype; + + if (gtypes.Contains (type)) + return (GType)gtypes[type]; + + if (type.IsSubclassOf (typeof (GLib.Object))) { + gtype = GLib.Object.LookupGType (type); + Register (gtype, type); + return gtype; + } + + PropertyInfo pi = type.GetProperty ("GType", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy); + if (pi != null) + gtype = (GType) pi.GetValue (null, null); + else if (type.IsDefined (typeof (GTypeAttribute), false)) { + GTypeAttribute gattr = (GTypeAttribute)Attribute.GetCustomAttribute (type, typeof (GTypeAttribute), false); + pi = gattr.WrapperType.GetProperty ("GType", BindingFlags.Public | BindingFlags.Static); + gtype = (GType) pi.GetValue (null, null); + } else if (type.IsSubclassOf (typeof (GLib.Opaque))) + gtype = GType.Pointer; + else + gtype = ManagedValue.GType; + + Register (gtype, type); + return gtype; + } + + static string GetQualifiedName (string cname) + { + for (int i = 1; i < cname.Length; i++) { + if (System.Char.IsUpper (cname[i])) { + if (i == 1 && cname [0] == 'G') + return "GLib." + cname.Substring (1); + else + return cname.Substring (0, i) + "." + cname.Substring (i); + } + } + + return null; + } + + public static explicit operator Type (GType gtype) + { + return LookupType (gtype.Val); + } + + public static void Init () + { + // cctor already calls g_type_init. + } + + public static event TypeResolutionHandler ResolveType; + + public static Type LookupType (IntPtr typeid) + { + if (types.Contains (typeid)) + return (Type)types[typeid]; + + string native_name = Marshaller.Utf8PtrToString (g_type_name (typeid)); + + if (ResolveType != null) { + GLib.GType gt = new GLib.GType (typeid); + + Delegate[] invocation_list = ResolveType.GetInvocationList (); + foreach (Delegate d in invocation_list) { + TypeResolutionHandler handler = (TypeResolutionHandler) d; + System.Type tmp = handler (gt, native_name); + if (tmp != null) { + Register (gt, tmp); + return tmp; + } + } + } + + string type_name = GetQualifiedName (native_name); + if (type_name == null) + return null; + Type result = null; + Assembly[] assemblies = (Assembly[]) AppDomain.CurrentDomain.GetAssemblies ().Clone (); + foreach (Assembly asm in assemblies) { + result = asm.GetType (type_name); + if (result != null) + break; + } + + if (result == null) { + // Because of lazy loading of references, it's possible the type's assembly + // needs to be loaded. We will look for it by name in the references of + // the currently loaded assemblies. Hopefully a recursive traversal is + // not needed. We avoid one for now because of problems experienced + // in a patch from bug #400595, and a desire to keep memory usage low + // by avoiding a complete loading of all dependent assemblies. + string ns = type_name.Substring (0, type_name.LastIndexOf ('.')); + string asm_name = ns.ToLower ().Replace ('.', '-') + "-sharp"; + foreach (Assembly asm in assemblies) { + foreach (AssemblyName ref_name in asm.GetReferencedAssemblies ()) { + if (ref_name.Name != asm_name) + continue; + string asm_dir = Path.GetDirectoryName (asm.Location); + try { + Assembly ref_asm; + if (File.Exists (Path.Combine (asm_dir, ref_name.Name + ".dll"))) + ref_asm = Assembly.LoadFrom (Path.Combine (asm_dir, ref_name.Name + ".dll")); + else + ref_asm = Assembly.Load (ref_name); + result = ref_asm.GetType (type_name); + if (result != null) + break; + } catch (Exception) { + /* Failure to load a referenced assembly is not an error */ + } + } + if (result != null) + break; + } + } + + Register (new GType (typeid), result); + return result; + } + + public IntPtr Val { + get { return val; } + } + + public static bool operator == (GType a, GType b) + { + return a.Val == b.Val; + } + + public static bool operator != (GType a, GType b) + { + return a.Val != b.Val; + } + + public override bool Equals (object o) + { + if (!(o is GType)) + return false; + + return ((GType) o) == this; + } + + public override int GetHashCode () + { + return val.GetHashCode (); + } + + public override string ToString () + { + return Marshaller.Utf8PtrToString (g_type_name (val)); + } + + public IntPtr ClassPtr { + get { + IntPtr klass = g_type_class_peek (val); + if (klass == IntPtr.Zero) + klass = g_type_class_ref (val); + return klass; + } + } + + public GType BaseType { + get { + IntPtr parent = g_type_parent (this.Val); + if (parent == IntPtr.Zero) + return GType.None; + else + return new GType (parent); + } + } + + public GType ThresholdType { + get { + GLib.GType curr_type = this; + while (curr_type.ToString ().StartsWith ("__gtksharp_")) { + curr_type = curr_type.BaseType; + } + return curr_type; + } + } + + public uint ClassSize { + get { + GTypeQuery query; + g_type_query (this.Val, out query); + return query.class_size; + } + } + + internal void EnsureClass () + { + if (g_type_class_peek (val) == IntPtr.Zero) + g_type_class_ref (val); + } + + static int type_uid; + static string BuildEscapedName (System.Type t) + { + string qn = t.FullName; + // Just a random guess + StringBuilder sb = new StringBuilder (20 + qn.Length); + sb.Append ("__gtksharp_"); + sb.Append (type_uid++); + sb.Append ("_"); + foreach (char c in qn) { + if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + sb.Append (c); + else if (c == '.') + sb.Append ('_'); + else if ((uint) c <= byte.MaxValue) { + sb.Append ('+'); + sb.Append (((byte) c).ToString ("x2")); + } else { + sb.Append ('-'); + sb.Append (((uint) c).ToString ("x4")); + } + } + return sb.ToString (); + } + + internal static GType RegisterGObjectType (System.Type t) + { + GType parent_gtype = LookupGObjectType (t.BaseType); + string name = BuildEscapedName (t); + IntPtr native_name = GLib.Marshaller.StringToPtrGStrdup (name); + GTypeQuery query; + g_type_query (parent_gtype.Val, out query); + GTypeInfo info = new GTypeInfo (); + info.class_size = (ushort) query.class_size; + info.instance_size = (ushort) query.instance_size; + GType gtype = new GType (g_type_register_static (parent_gtype.Val, native_name, ref info, 0)); + GLib.Marshaller.Free (native_name); + Register (gtype, t); + return gtype; + } + + internal static GType LookupGObjectType (System.Type t) + { + if (gtypes.Contains (t)) + return (GType) gtypes [t]; + + PropertyInfo pi = t.GetProperty ("GType", BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public); + if (pi != null) + return (GType) pi.GetValue (null, null); + + return GLib.Object.RegisterGType (t); + } + + internal static IntPtr ValFromInstancePtr (IntPtr handle) + { + if (handle == IntPtr.Zero) + return IntPtr.Zero; + + // First field of instance is a GTypeClass*. + IntPtr klass = Marshal.ReadIntPtr (handle); + // First field of GTypeClass is a GType. + return Marshal.ReadIntPtr (klass); + } + + internal static bool Is (IntPtr type, GType is_a_type) + { + return g_type_is_a (type, is_a_type.Val); + } + + public bool IsInstance (IntPtr raw) + { + return GType.Is (ValFromInstancePtr (raw), this); + } + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_type_class_peek (IntPtr gtype); + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_type_class_ref (IntPtr gtype); + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_type_from_name (string name); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_type_init (); + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_type_name (IntPtr raw); + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_type_parent (IntPtr type); + + [DllImport("libgobject-2.0-0.dll")] + static extern void g_type_query (IntPtr type, out GTypeQuery query); + + [DllImport("libgobject-2.0-0.dll")] + static extern IntPtr g_type_register_static (IntPtr parent, IntPtr name, ref GTypeInfo info, int flags); + + [DllImport("libgobject-2.0-0.dll")] + static extern bool g_type_is_a (IntPtr type, IntPtr is_a_type); + } +} |