AssemblyInspector.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. if (metaReader.GetString (typeRef.Name) != "CSComponent")
  57. continue;
  58. var inspector = new CSComponentInspector (typeDef, peFile, metaReader);
  59. var icomponent = inspector.Inspect ();
  60. if (icomponent != null)
  61. InspectorComponents [icomponent.Name] = icomponent;
  62. }
  63. }
  64. }
  65. void ParseEnums ()
  66. {
  67. foreach (var handle in metaReader.TypeDefinitions) {
  68. var typeDef = metaReader.GetTypeDefinition (handle);
  69. var baseTypeHandle = typeDef.BaseType;
  70. if (baseTypeHandle.Kind == HandleKind.TypeReference) {
  71. var typeRef = metaReader.GetTypeReference ((TypeReferenceHandle)baseTypeHandle);
  72. if (metaReader.GetString (typeRef.Name) == "Enum") {
  73. ParseEnum (typeDef);
  74. }
  75. }
  76. }
  77. }
  78. void ParseEnum (TypeDefinition enumTypeDef)
  79. {
  80. // TODO: verify that int32 is the enums storage type for constant read below
  81. InspectorEnum ienum = new InspectorEnum ();
  82. ienum.Name = metaReader.GetString (enumTypeDef.Name);
  83. InspectorEnums [ienum.Name] = ienum;
  84. var fields = enumTypeDef.GetFields ();
  85. foreach (var fieldHandle in fields) {
  86. var inspectorField = new InspectorField ();
  87. var fieldDef = metaReader.GetFieldDefinition (fieldHandle);
  88. if ((fieldDef.Attributes & FieldAttributes.HasDefault) != 0) {
  89. var constantHandle = fieldDef.GetDefaultValue ();
  90. var constant = metaReader.GetConstant (constantHandle);
  91. BlobReader constantReader = metaReader.GetBlobReader (constant.Value);
  92. ienum.Values [metaReader.GetString (fieldDef.Name)] = constantReader.ReadInt32 ();
  93. }
  94. }
  95. return;
  96. }
  97. }
  98. internal class InspectorEnum
  99. {
  100. public String Name;
  101. public Dictionary<string, int> Values = new Dictionary<string, int> ();
  102. public Dictionary<string, object> GetJSONDict ()
  103. {
  104. var dict = new Dictionary<string,object> ();
  105. dict ["name"] = Name;
  106. dict ["values"] = Values;
  107. return dict;
  108. }
  109. }
  110. internal class InspectorComponent
  111. {
  112. public String Name;
  113. public Dictionary<string, InspectorField> Fields = new Dictionary<string, InspectorField> ();
  114. public Dictionary<string, object> GetJSONDict ()
  115. {
  116. var dict = new Dictionary<string,object> ();
  117. dict ["name"] = Name;
  118. var fieldList = new List<object> ();
  119. foreach (var entry in Fields) {
  120. fieldList.Add (entry.Value.GetJSONDict ());
  121. }
  122. dict ["fields"] = fieldList;
  123. return dict;
  124. }
  125. }
  126. internal class InspectorField
  127. {
  128. public Dictionary<string, object> GetJSONDict ()
  129. {
  130. var dict = new Dictionary<string,object> ();
  131. dict ["isEnum"] = IsEnum;
  132. dict ["typeName"] = TypeName;
  133. dict ["name"] = Name;
  134. dict ["defaultValue"] = DefaultValue;
  135. dict ["caPos"] = CustomAttrPositionalArgs;
  136. dict ["caNamed"] = CustomAttrNamedArgs;
  137. return dict;
  138. }
  139. public bool IsEnum = false;
  140. public string TypeName;
  141. // the Name of the InspectorField
  142. public string Name;
  143. // The DefaultValue if supplied
  144. public string DefaultValue;
  145. // custom attributes, positional and named
  146. public List<string> CustomAttrPositionalArgs = new List<string> ();
  147. public Dictionary<string, string> CustomAttrNamedArgs = new Dictionary<string, string> ();
  148. }
  149. }