Merge branch 'bugfix'
[mono.git] / mcs / class / IKVM.Reflection / Reader / AssemblyReader.cs
1 /*
2   Copyright (C) 2009 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Configuration.Assemblies;
27 using System.IO;
28 using IKVM.Reflection.Metadata;
29
30 namespace IKVM.Reflection.Reader
31 {
32         sealed class AssemblyReader : Assembly
33         {
34                 private const int ContainsNoMetaData = 0x0001;
35                 private readonly string location;
36                 private readonly ModuleReader manifestModule;
37                 private readonly Module[] externalModules;
38
39                 internal AssemblyReader(string location, ModuleReader manifestModule)
40                         : base(manifestModule.universe)
41                 {
42                         this.location = location;
43                         this.manifestModule = manifestModule;
44                         externalModules = new Module[manifestModule.File.records.Length];
45                 }
46
47                 public override string Location
48                 {
49                         get { return location; }
50                 }
51
52                 public override string FullName
53                 {
54                         get { return GetName().FullName; }
55                 }
56
57                 public override AssemblyName GetName()
58                 {
59                         return GetNameImpl(ref manifestModule.AssemblyTable.records[0]);
60                 }
61
62                 private AssemblyName GetNameImpl(ref AssemblyTable.Record rec)
63                 {
64                         AssemblyName name = new AssemblyName();
65                         name.Name = manifestModule.GetString(rec.Name);
66                         name.Version = new Version(rec.MajorVersion, rec.MinorVersion, rec.BuildNumber, rec.RevisionNumber);
67                         if (rec.PublicKey != 0)
68                         {
69                                 name.SetPublicKey(manifestModule.GetBlobCopy(rec.PublicKey));
70                         }
71                         else
72                         {
73                                 name.SetPublicKey(Empty<byte>.Array);
74                         }
75                         if (rec.Culture != 0)
76                         {
77                                 name.CultureInfo = new System.Globalization.CultureInfo(manifestModule.GetString(rec.Culture));
78                         }
79                         else
80                         {
81                                 name.CultureInfo = System.Globalization.CultureInfo.InvariantCulture;
82                         }
83                         name.HashAlgorithm = (AssemblyHashAlgorithm)rec.HashAlgId;
84                         name.CodeBase = this.CodeBase;
85                         name.Flags = (AssemblyNameFlags)rec.Flags;
86                         return name;
87                 }
88
89                 public override Type[] GetTypes()
90                 {
91                         if (externalModules.Length == 0)
92                         {
93                                 return manifestModule.GetTypes();
94                         }
95
96                         List<Type> list = new List<Type>();
97                         foreach (Module module in GetModules(false))
98                         {
99                                 list.AddRange(module.GetTypes());
100                         }
101                         return list.ToArray();
102                 }
103
104                 internal override Type FindType(TypeName typeName)
105                 {
106                         Type type = manifestModule.FindType(typeName);
107                         for (int i = 0; type == null && i < externalModules.Length; i++)
108                         {
109                                 if ((manifestModule.File.records[i].Flags & ContainsNoMetaData) == 0)
110                                 {
111                                         type = GetModule(i).FindType(typeName);
112                                 }
113                         }
114                         return type;
115                 }
116
117                 public override string ImageRuntimeVersion
118                 {
119                         get { return manifestModule.ImageRuntimeVersion; }
120                 }
121
122                 public override Module ManifestModule
123                 {
124                         get { return manifestModule; }
125                 }
126
127                 public override Module[] GetLoadedModules(bool getResourceModules)
128                 {
129                         List<Module> list = new List<Module>();
130                         list.Add(manifestModule);
131                         foreach (Module m in externalModules)
132                         {
133                                 if (m != null)
134                                 {
135                                         list.Add(m);
136                                 }
137                         }
138                         return list.ToArray();
139                 }
140
141                 public override Module[] GetModules(bool getResourceModules)
142                 {
143                         if (externalModules.Length == 0)
144                         {
145                                 return new Module[] { manifestModule };
146                         }
147                         else
148                         {
149                                 List<Module> list = new List<Module>();
150                                 list.Add(manifestModule);
151                                 for (int i = 0; i < manifestModule.File.records.Length; i++)
152                                 {
153                                         if (getResourceModules || (manifestModule.File.records[i].Flags & ContainsNoMetaData) == 0)
154                                         {
155                                                 list.Add(GetModule(i));
156                                         }
157                                 }
158                                 return list.ToArray();
159                         }
160                 }
161
162                 public override Module GetModule(string name)
163                 {
164                         if (name.Equals(manifestModule.ScopeName, StringComparison.InvariantCultureIgnoreCase))
165                         {
166                                 return manifestModule;
167                         }
168                         int index = GetModuleIndex(name);
169                         if (index != -1)
170                         {
171                                 return GetModule(index);
172                         }
173                         return null;
174                 }
175
176                 private int GetModuleIndex(string name)
177                 {
178                         for (int i = 0; i < manifestModule.File.records.Length; i++)
179                         {
180                                 if (name.Equals(manifestModule.GetString(manifestModule.File.records[i].Name), StringComparison.InvariantCultureIgnoreCase))
181                                 {
182                                         return i;
183                                 }
184                         }
185                         return -1;
186                 }
187
188                 private Module GetModule(int index)
189                 {
190                         if (externalModules[index] != null)
191                         {
192                                 return externalModules[index];
193                         }
194                         // TODO add ModuleResolve event
195                         string location = Path.Combine(Path.GetDirectoryName(this.location), manifestModule.GetString(manifestModule.File.records[index].Name));
196                         return LoadModule(index, null, location);
197                 }
198
199                 private Module LoadModule(int index, byte[] rawModule, string location)
200                 {
201                         if ((manifestModule.File.records[index].Flags & ContainsNoMetaData) != 0)
202                         {
203                                 return externalModules[index] = new ResourceModule(manifestModule, index, location);
204                         }
205                         else
206                         {
207                                 if (rawModule == null)
208                                 {
209                                         rawModule = File.ReadAllBytes(location);
210                                 }
211                                 return externalModules[index] = new ModuleReader(this, manifestModule.universe, new MemoryStream(rawModule), location);
212                         }
213                 }
214
215                 public override Module LoadModule(string moduleName, byte[] rawModule)
216                 {
217                         int index = GetModuleIndex(moduleName);
218                         if (index == -1)
219                         {
220                                 throw new ArgumentException();
221                         }
222                         if (externalModules[index] != null)
223                         {
224                                 return externalModules[index];
225                         }
226                         return LoadModule(index, rawModule, null);
227                 }
228
229                 public override MethodInfo EntryPoint
230                 {
231                         get { return manifestModule.GetEntryPoint(); }
232                 }
233
234                 public override string[] GetManifestResourceNames()
235                 {
236                         return manifestModule.GetManifestResourceNames();
237                 }
238
239                 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName)
240                 {
241                         return manifestModule.GetManifestResourceInfo(resourceName);
242                 }
243
244                 public override Stream GetManifestResourceStream(string resourceName)
245                 {
246                         return manifestModule.GetManifestResourceStream(resourceName);
247                 }
248
249                 public override AssemblyName[] GetReferencedAssemblies()
250                 {
251                         return manifestModule.__GetReferencedAssemblies();
252                 }
253
254                 public override AssemblyNameFlags __AssemblyFlags
255                 {
256                         get { return (AssemblyNameFlags)manifestModule.AssemblyTable.records[0].Flags; }
257                 }
258
259                 internal override IList<CustomAttributeData> GetCustomAttributesData(Type attributeType)
260                 {
261                         return manifestModule.GetCustomAttributes(0x20000001, attributeType);
262                 }
263         }
264 }