// // file: peer.cs // author: Dan Lewis (dihlewis@yahoo.co.uk) // (C) 2002 // using System; using System.Reflection; using System.Collections; class Peer { public Peer (Type clr_type, string name, bool is_opaque) { this.clr_type = clr_type; this.name = name; this.is_opaque = is_opaque; this.nearest_base = null; // resolve later this.underlying = null; this.enum_constants = null; this.fields = new PeerFieldCollection (); this.is_enum = CLRIsEnum (clr_type); this.is_value_type = CLRIsValueType (clr_type); } public string Name { get { return name; } } public Type CLRType { get { return clr_type; } } public bool IsOpaque { get { return is_opaque; } } public bool IsValueType { get { return is_value_type; } } public bool IsEnum { get { return is_enum; } } public Peer NearestBase { get { return nearest_base; } set { nearest_base = value; } } public Peer UnderlyingPeer { get { return underlying; } set { underlying = value; } } public IDictionary EnumConstants { get { return enum_constants; } set { enum_constants = value; } } public PeerFieldCollection Fields { get { return fields; } } public string GetTypedef (int refs) { if (refs == 0) return String.Format ("{0} ", name); return String.Format ("{0} {1}", name, new string ('*', refs)); } // internal internal static bool CLRIsValueType (Type clr_type) { return clr_type.IsValueType; /* if (clr_type.BaseType == null) return false; return clr_type.BaseType.FullName == "System.ValueType" || clr_type.BaseType.FullName == "System.Enum"; */ } internal static bool CLRIsEnum (Type clr_type) { return clr_type.IsEnum; /* if (clr_type.BaseType == null) return false; return clr_type.BaseType.FullName == "System.Enum"; */ } internal static Type CLRUnderlyingType (Type clr_type) { return Enum.GetUnderlyingType (clr_type); /* Type ebase = type.BaseType; return (Type)ebase.InvokeMember ("GetUnderlyingType", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, null, new object[] { type } ); */ } // private private Type clr_type; private bool is_opaque; private bool is_value_type; private bool is_enum; private string name; private Peer nearest_base; private Peer underlying; private IDictionary enum_constants; private PeerFieldCollection fields; } class PeerField { public PeerField (Peer peer, string name) { this.peer = peer; this.name = name; } public Peer Peer { get { return peer; } } public string Name { get { return name; } } private Peer peer; private string name; } class PeerFieldCollection : CollectionBase { public void Add (PeerField f) { List.Add (f); } public PeerField this[int i] { get { return (PeerField)List[i]; } } } class PeerMap { public PeerMap () { peers = new Hashtable (); } public void Add (Peer peer) { Add (peer.CLRType, peer); } public void Add (Type clr_type, Peer peer) { peers.Add (clr_type, peer); } public ICollection Peers { get { return peers.Values; } } public Peer this[Type clr_type] { get { if (peers.Contains (clr_type)) return (Peer)peers[clr_type]; return null; } } public Peer GetPeer (Type clr_type) { Peer peer; if (Peer.CLRIsValueType (clr_type)) { peer = this[clr_type]; if (peer != null) return peer; if (Peer.CLRIsEnum (clr_type)) { peer = this[Peer.CLRUnderlyingType (clr_type)]; if (peer != null) return peer; throw new ArgumentException ("Could not find peer or underlying peer for enum " + clr_type); } else throw new ArgumentException ("Could not find peer for value type " + clr_type); } else { Type type = clr_type; while (type != null) { peer = this[type]; if (peer != null) return peer; type = type.BaseType; } throw new ArgumentException ("Could not find peer for class " + clr_type); } } public void ResolvePeers () { BindingFlags binding = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; // base type foreach (Peer peer in Peers) { if (peer.IsOpaque || peer.IsValueType || peer.CLRType.BaseType == null) continue; peer.NearestBase = GetPeer (peer.CLRType.BaseType); if (peer.NearestBase == null) { Console.Error.WriteLine ("Error: cannot find an internal base type for {0}.", peer.Name); Environment.Exit (-1); } } // fields foreach (Peer peer in Peers) { if (peer.IsOpaque || peer.IsEnum) continue; Type clr_base = null; if (peer.NearestBase != null) clr_base = peer.NearestBase.CLRType; Stack declared = new Stack (); Type type = peer.CLRType; while (type != clr_base) { declared.Push (type); type = type.BaseType; } // build declared field list while (declared.Count > 0) { type = (Type)declared.Pop (); foreach (FieldInfo info in type.GetFields (binding)) { PeerField field = new PeerField ( GetPeer (info.FieldType), info.Name ); peer.Fields.Add (field); } } } // enums foreach (Peer peer in Peers) { if (peer.IsOpaque || !peer.IsEnum) continue; Type clr_type = peer.CLRType; // constants Hashtable constants = new Hashtable (); foreach (string name in Enum.GetNames (clr_type)) constants.Add (name, (int)Enum.Parse (clr_type, name)); peer.UnderlyingPeer = GetPeer (Enum.GetUnderlyingType (clr_type)); peer.EnumConstants = constants; } } // private private Hashtable peers; }