using System; using System.IO; using System.Diagnostics; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Reflection; using System.Reflection.Metadata; using System.Reflection.PortableExecutable; using System.Reflection.Metadata.Ecma335; using System.Text; using AtomicEngine; using File = System.IO.File; namespace AtomicTools { class AssemblyInspector { Dictionary InspectorEnums = new Dictionary (); Dictionary InspectorComponents = new Dictionary (); PEReader peFile; MetadataReader metaReader; public AssemblyInspector () { } public string DumpToJSON () { var dict = new Dictionary (); var enumList = new List (); var componentList = new List (); foreach (var entry in InspectorEnums) { enumList.Add (entry.Value.GetJSONDict ()); } foreach (var entry in InspectorComponents) { componentList.Add (entry.Value.GetJSONDict ()); } dict ["enums"] = enumList; dict ["components"] = componentList; return MiniJSON.Json.Serialize (dict); } public void Inspect (String pathToAssembly) { using (var stream = File.OpenRead (pathToAssembly)) using (peFile = new PEReader (stream)) { metaReader = peFile.GetMetadataReader (); ParseEnums (); ParseComponents (); } } void ParseComponents () { foreach (var handle in metaReader.TypeDefinitions) { var typeDef = metaReader.GetTypeDefinition (handle); var baseTypeHandle = typeDef.BaseType; if (baseTypeHandle.Kind == HandleKind.TypeReference) { var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle); var name = metaReader.GetString (typeRef.Name); if (name != "CSComponent") continue; var inspector = new CSComponentInspector (typeDef, peFile, metaReader); var icomponent = inspector.Inspect (); if (icomponent != null) InspectorComponents [icomponent.Name] = icomponent; } } } void ParseEnums () { foreach (var handle in metaReader.TypeDefinitions) { var typeDef = metaReader.GetTypeDefinition (handle); var baseTypeHandle = typeDef.BaseType; if (baseTypeHandle.Kind == HandleKind.TypeReference) { var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle); if (metaReader.GetString (typeRef.Name) == "Enum") { ParseEnum (typeDef); } } } } void ParseEnum (TypeDefinition enumTypeDef) { // TODO: verify that int32 is the enums storage type for constant read below InspectorEnum ienum = new InspectorEnum (); ienum.Name = metaReader.GetString (enumTypeDef.Name); InspectorEnums [ienum.Name] = ienum; var fields = enumTypeDef.GetFields (); foreach (var fieldHandle in fields) { var inspectorField = new InspectorField (); var fieldDef = metaReader.GetFieldDefinition (fieldHandle); if ((fieldDef.Attributes & FieldAttributes.HasDefault) != 0) { var constantHandle = fieldDef.GetDefaultValue (); var constant = metaReader.GetConstant (constantHandle); BlobReader constantReader = metaReader.GetBlobReader (constant.Value); ienum.Values [metaReader.GetString (fieldDef.Name)] = constantReader.ReadInt32 (); } } return; } } internal class InspectorEnum { public String Name; public Dictionary Values = new Dictionary (); public Dictionary GetJSONDict () { var dict = new Dictionary (); dict ["name"] = Name; dict ["values"] = Values; return dict; } } internal class InspectorComponent { public String Name; public String Namespace; public Dictionary Fields = new Dictionary (); public Dictionary GetJSONDict () { var dict = new Dictionary (); dict ["name"] = Name; dict ["namespace"] = Namespace; var fieldList = new List (); foreach (var entry in Fields) { fieldList.Add (entry.Value.GetJSONDict ()); } dict ["fields"] = fieldList; return dict; } } internal class InspectorField { public Dictionary GetJSONDict () { var dict = new Dictionary (); dict ["isEnum"] = IsEnum; dict ["typeName"] = TypeName; dict ["name"] = Name; dict ["defaultValue"] = DefaultValue; dict ["caPos"] = CustomAttrPositionalArgs; dict ["caNamed"] = CustomAttrNamedArgs; return dict; } public bool IsEnum = false; public string TypeName; // the Name of the InspectorField public string Name; // The DefaultValue if supplied public string DefaultValue; // custom attributes, positional and named public List CustomAttrPositionalArgs = new List (); public Dictionary CustomAttrNamedArgs = new Dictionary (); } }