// // Mono.ILASM.ExternTable.cs // // Author(s): // Jackson Harper (Jackson@LatitudeGeo.com) // // (C) 2003 Jackson Harper, All rights reserved // using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Security; using System.Globalization; using PEAPI; namespace Mono.ILASM { public interface IScope { ExternTypeRef GetTypeRef (string full_name, bool is_valuetype); PEAPI.ClassRef GetType (string full_name, bool is_valuetype); string FullName { get; } } public abstract class ExternRef : ICustomAttrTarget, IScope { protected string name; protected Hashtable class_table; protected Hashtable typeref_table; protected ArrayList customattr_list; protected bool is_resolved; public abstract void Resolve (CodeGen codegen); public abstract PEAPI.IExternRef GetExternRef (); public ExternRef (string name) { this.name = name; typeref_table = new Hashtable (); class_table = new Hashtable (); } public string Name { get { return name; } } public virtual string FullName { get { return name; } } public void AddCustomAttribute (CustomAttr customattr) { if (customattr_list == null) customattr_list = new ArrayList (); customattr_list.Add (customattr); } public ExternTypeRef GetTypeRef (string full_name, bool is_valuetype) { string first= full_name; string rest = ""; int slash = full_name.IndexOf ('/'); if (slash > 0) { first = full_name.Substring (0, slash); rest = full_name.Substring (slash + 1); } ExternTypeRef type_ref = typeref_table [first] as ExternTypeRef; if (type_ref != null) { if (is_valuetype && rest == "") type_ref.MakeValueClass (); } else { type_ref = new ExternTypeRef (this, first, is_valuetype); typeref_table [first] = type_ref; } return (rest == "" ? type_ref : type_ref.GetTypeRef (rest, is_valuetype)); } public PEAPI.ClassRef GetType (string full_name, bool is_valuetype) { PEAPI.ClassRef klass = class_table[full_name] as PEAPI.ClassRef; if (klass != null) return klass; string name_space, name; ExternTable.GetNameAndNamespace (full_name, out name_space, out name); if (is_valuetype) klass = (PEAPI.ClassRef) GetExternRef ().AddValueClass (name_space, name); else klass = (PEAPI.ClassRef) GetExternRef ().AddClass (name_space, name); class_table [full_name] = klass; return klass; } } public class ExternModule : ExternRef { public PEAPI.ModuleRef ModuleRef; public ExternModule (string name) : base (name) { } public override string FullName { get { //'name' field should not contain the [.module ] //as its used for resolving return String.Format ("[.module {0}]", name); } } public override void Resolve (CodeGen codegen) { if (is_resolved) return; ModuleRef = codegen.PEFile.AddExternModule (name); if (customattr_list != null) foreach (CustomAttr customattr in customattr_list) customattr.AddTo (codegen, ModuleRef); is_resolved = true; } public override PEAPI.IExternRef GetExternRef () { return ModuleRef; } } public class ExternAssembly : ExternRef, IDeclSecurityTarget { public PEAPI.AssemblyRef AssemblyRef; private int major, minor, build, revision; private byte [] public_key; private byte [] public_key_token; private string locale; private byte [] hash; private DeclSecurity decl_sec; private AssemblyName asmb_name; //flags private PEAPI.AssemAttr attr; public ExternAssembly (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr) : base (name) { this.name = name; this.asmb_name = asmb_name; this.attr = attr; major = minor = build = revision = -1; } public override string FullName { get { //'name' field should not contain the [] //as its used for resolving return String.Format ("[{0}]", name); } } public AssemblyName AssemblyName { get { return asmb_name; } } public DeclSecurity DeclSecurity { get { if (decl_sec == null) decl_sec = new DeclSecurity (); return decl_sec; } } public override void Resolve (CodeGen code_gen) { if (is_resolved) return; AssemblyRef = code_gen.PEFile.AddExternAssembly (name); AssemblyRef.AddAssemblyAttr (attr); if (major != -1) AssemblyRef.AddVersionInfo (major, minor, build, revision); if (public_key != null) AssemblyRef.AddKey (public_key); if (public_key_token != null) AssemblyRef.AddKeyToken (public_key_token); if (locale != null) AssemblyRef.AddCulture (locale); if (hash != null) AssemblyRef.AddHash (hash); if (customattr_list != null) foreach (CustomAttr customattr in customattr_list) customattr.AddTo (code_gen, AssemblyRef); if (decl_sec != null) decl_sec.AddTo (code_gen, AssemblyRef); class_table = new Hashtable (); is_resolved = true; } public override PEAPI.IExternRef GetExternRef () { return AssemblyRef; } public void SetVersion (int major, int minor, int build, int revision) { this.major = major; this.minor = minor; this.build = build; this.revision = revision; asmb_name.Version = new Version (major, minor, build, revision); } public void SetPublicKey (byte [] public_key) { this.public_key = public_key; asmb_name.SetPublicKey (public_key); } public void SetPublicKeyToken (byte [] public_key_token) { this.public_key_token = public_key_token; asmb_name.SetPublicKey (public_key); } public void SetLocale (string locale) { this.locale = locale; //FIXME: is this correct? asmb_name.CultureInfo = new CultureInfo (locale); } public void SetHash (byte [] hash) { this.hash = hash; } } public class ExternClass { string fullName; TypeAttr ta; string assemblyReference; public ExternClass (string fullName, TypeAttr ta, string assemblyReference) { this.fullName = fullName; this.ta = ta; this.assemblyReference = assemblyReference; } public void Resolve (CodeGen code_gen, ExternTable table) { var ar = table.GetAssemblyRef (assemblyReference); if (ar != null) { string ns = null; string name = fullName; int pos = name.LastIndexOf ('.'); if (pos > 0) { ns = name.Substring (0, pos); name = name.Substring (pos + 1); } code_gen.PEFile.AddExternClass (ns, name, ta, ar.AssemblyRef); } } } public class ExternTable { Hashtable assembly_table; Hashtable module_table; List class_table; bool is_resolved; public void AddCorlib () { // Add mscorlib string mscorlib_name = "mscorlib"; AssemblyName mscorlib = new AssemblyName (); mscorlib.Name = mscorlib_name; AddAssembly (mscorlib_name, mscorlib, 0); // Also need to alias corlib, normally corlib and // mscorlib are used interchangably assembly_table["corlib"] = assembly_table["mscorlib"]; } public ExternAssembly AddAssembly (string name, AssemblyName asmb_name, PEAPI.AssemAttr attr) { ExternAssembly ea = null; if (assembly_table == null) { assembly_table = new Hashtable (); } else { ea = assembly_table [name] as ExternAssembly; if (ea != null) return ea; } ea = new ExternAssembly (name, asmb_name, attr); assembly_table [name] = ea; return ea; } public ExternModule AddModule (string name) { ExternModule em = null; if (module_table == null) { module_table = new Hashtable (); } else { em = module_table [name] as ExternModule; if (em != null) return em; } em = new ExternModule (name); module_table [name] = em; return em; } public void AddClass (string name, TypeAttr ta, string assemblyReference) { if (class_table == null) class_table = new List (); class_table.Add (new ExternClass (name, ta, assemblyReference)); } public void Resolve (CodeGen code_gen) { if (is_resolved) return; if (assembly_table != null) foreach (ExternAssembly ext in assembly_table.Values) ext.Resolve (code_gen); if (module_table != null) foreach (ExternModule ext in module_table.Values) ext.Resolve (code_gen); if (class_table != null) foreach (var entry in class_table) entry.Resolve (code_gen, this); is_resolved = true; } public ExternTypeRef GetTypeRef (string asmb_name, string full_name, bool is_valuetype) { ExternAssembly ext_asmb = null; if (assembly_table == null && (asmb_name == "mscorlib" || asmb_name == "corlib")) { /* AddCorlib if mscorlib is being referenced but we haven't encountered a ".assembly 'name'" as yet. */ Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name)); AddCorlib (); } if (assembly_table != null) ext_asmb = assembly_table[asmb_name] as ExternAssembly; if (ext_asmb == null) { System.Reflection.AssemblyName asmname = new System.Reflection.AssemblyName (); asmname.Name = asmb_name; Report.Warning (String.Format ("Reference to undeclared extern assembly '{0}', adding.", asmb_name)); ext_asmb = AddAssembly (asmb_name, asmname, 0); } return ext_asmb.GetTypeRef (full_name, is_valuetype); } public ExternTypeRef GetModuleTypeRef (string mod_name, string full_name, bool is_valuetype) { ExternModule mod = null; if (module_table != null) mod = module_table [mod_name] as ExternModule; if (mod == null) Report.Error ("Module " + mod_name + " not defined."); return mod.GetTypeRef (full_name, is_valuetype); } public ExternAssembly GetAssemblyRef (string assembly_name) { ExternAssembly ass = null; if (assembly_table != null) ass = assembly_table [assembly_name] as ExternAssembly; if (ass == null) Report.Error ("Assembly " + assembly_name + " is not defined."); return ass; } public static void GetNameAndNamespace (string full_name, out string name_space, out string name) { int last_dot = full_name.LastIndexOf ('.'); if (last_dot < 0) { name_space = String.Empty; name = full_name; return; } name_space = full_name.Substring (0, last_dot); name = full_name.Substring (last_dot + 1); } } }