Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

285 lines
5.7 KiB
C#

//
// 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;
}