AssemblyInspector.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. using System;
  2. using System.IO;
  3. using System.Diagnostics;
  4. using System.Collections.Generic;
  5. using System.Collections.Immutable;
  6. using System.Linq;
  7. using System.Reflection;
  8. using System.Reflection.Metadata;
  9. using System.Reflection.PortableExecutable;
  10. using System.Reflection.Metadata.Ecma335;
  11. using System.Text;
  12. using AtomicEngine;
  13. using File = System.IO.File;
  14. namespace AtomicTools
  15. {
  16. class AssemblyInspector
  17. {
  18. Dictionary<string, InspectorEnum> InspectorEnums = new Dictionary<string, InspectorEnum> ();
  19. Dictionary<string, InspectorComponent> InspectorComponents = new Dictionary<string, InspectorComponent> ();
  20. PEReader peFile;
  21. MetadataReader metaReader;
  22. public AssemblyInspector ()
  23. {
  24. }
  25. public string DumpToJSON ()
  26. {
  27. var dict = new Dictionary<string, object> ();
  28. var enumList = new List<object> ();
  29. var componentList = new List<object> ();
  30. foreach (var entry in InspectorEnums) {
  31. enumList.Add (entry.Value.GetJSONDict ());
  32. }
  33. foreach (var entry in InspectorComponents) {
  34. componentList.Add (entry.Value.GetJSONDict ());
  35. }
  36. dict ["enums"] = enumList;
  37. dict ["components"] = componentList;
  38. return MiniJSON.Json.Serialize (dict);
  39. }
  40. public void Inspect (String pathToAssembly)
  41. {
  42. using (var stream = File.OpenRead (pathToAssembly))
  43. using (peFile = new PEReader (stream)) {
  44. metaReader = peFile.GetMetadataReader ();
  45. ParseEnums ();
  46. ParseComponents ();
  47. }
  48. }
  49. void ParseComponents ()
  50. {
  51. foreach (var handle in metaReader.TypeDefinitions) {
  52. var typeDef = metaReader.GetTypeDefinition (handle);
  53. var baseTypeHandle = typeDef.BaseType;
  54. if (baseTypeHandle.Kind == HandleKind.TypeReference) {
  55. var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle);
  56. var name = metaReader.GetString (typeRef.Name);
  57. if (name != "CSComponent")
  58. continue;
  59. var inspector = new CSComponentInspector (typeDef, peFile, metaReader);
  60. var icomponent = inspector.Inspect ();
  61. if (icomponent != null)
  62. InspectorComponents [icomponent.Name] = icomponent;
  63. }
  64. }
  65. }
  66. void ParseEnums ()
  67. {
  68. foreach (var handle in metaReader.TypeDefinitions) {
  69. var typeDef = metaReader.GetTypeDefinition (handle);
  70. var baseTypeHandle = typeDef.BaseType;
  71. if (baseTypeHandle.Kind == HandleKind.TypeReference) {
  72. var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle);
  73. if (metaReader.GetString (typeRef.Name) == "Enum") {
  74. ParseEnum (typeDef);
  75. }
  76. }
  77. }
  78. }
  79. void ParseEnum (TypeDefinition enumTypeDef)
  80. {
  81. // TODO: verify that int32 is the enums storage type for constant read below
  82. InspectorEnum ienum = new InspectorEnum ();
  83. ienum.Name = metaReader.GetString (enumTypeDef.Name);
  84. InspectorEnums [ienum.Name] = ienum;
  85. var fields = enumTypeDef.GetFields ();
  86. foreach (var fieldHandle in fields) {
  87. var inspectorField = new InspectorField ();
  88. var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
  89. if ((fieldDef.Attributes & FieldAttributes.HasDefault) != 0) {
  90. var constantHandle = fieldDef.GetDefaultValue ();
  91. var constant = metaReader.GetConstant (constantHandle);
  92. BlobReader constantReader = metaReader.GetBlobReader (constant.Value);
  93. ienum.Values [metaReader.GetString (fieldDef.Name)] = constantReader.ReadInt32 ();
  94. }
  95. }
  96. return;
  97. }
  98. }
  99. internal class InspectorEnum
  100. {
  101. public String Name;
  102. public Dictionary<string, int> Values = new Dictionary<string, int> ();
  103. public Dictionary<string, object> GetJSONDict ()
  104. {
  105. var dict = new Dictionary<string,object> ();
  106. dict ["name"] = Name;
  107. dict ["values"] = Values;
  108. return dict;
  109. }
  110. }
  111. internal class InspectorComponent
  112. {
  113. public String Name;
  114. public String Namespace;
  115. public Dictionary<string, InspectorField> Fields = new Dictionary<string, InspectorField> ();
  116. public Dictionary<string, object> GetJSONDict ()
  117. {
  118. var dict = new Dictionary<string,object> ();
  119. dict ["name"] = Name;
  120. dict ["namespace"] = Namespace;
  121. var fieldList = new List<object> ();
  122. foreach (var entry in Fields) {
  123. fieldList.Add (entry.Value.GetJSONDict ());
  124. }
  125. dict ["fields"] = fieldList;
  126. return dict;
  127. }
  128. }
  129. internal class InspectorField
  130. {
  131. public Dictionary<string, object> GetJSONDict ()
  132. {
  133. var dict = new Dictionary<string,object> ();
  134. dict ["isEnum"] = IsEnum;
  135. dict ["typeName"] = TypeName;
  136. dict ["name"] = Name;
  137. dict ["defaultValue"] = DefaultValue;
  138. dict ["caPos"] = CustomAttrPositionalArgs;
  139. dict ["caNamed"] = CustomAttrNamedArgs;
  140. return dict;
  141. }
  142. public bool IsEnum = false;
  143. public string TypeName;
  144. // the Name of the InspectorField
  145. public string Name;
  146. // The DefaultValue if supplied
  147. public string DefaultValue;
  148. // custom attributes, positional and named
  149. public List<string> CustomAttrPositionalArgs = new List<string> ();
  150. public Dictionary<string, string> CustomAttrNamedArgs = new Dictionary<string, string> ();
  151. }
  152. }