2 // System.Reflection.Emit/AssemblyBuilder.cs
5 // Paolo Molaro (lupus@ximian.com)
7 // (C) 2001 Ximian, Inc. http://www.ximian.com
11 using System.Reflection;
12 using System.Resources;
14 using System.Security.Policy;
15 using System.Runtime.Serialization;
16 using System.Globalization;
17 using System.Runtime.CompilerServices;
18 using System.Collections;
19 using System.Runtime.InteropServices;
20 using System.Security.Cryptography;
23 using Mono.Security.Cryptography;
25 namespace System.Reflection.Emit {
27 internal struct MonoResource {
30 public string filename;
31 public ResourceAttributes attrs;
34 public sealed class AssemblyBuilder : Assembly {
35 private IntPtr dynamic_assembly;
36 private MethodInfo entry_point;
37 private ModuleBuilder[] modules;
40 private CustomAttributeBuilder[] cattrs;
41 private MonoResource[] resources;
47 PEFileKinds pekind = PEFileKinds.Dll;
50 internal Type corlib_object_type = typeof (System.Object);
51 internal Type corlib_value_type = typeof (System.ValueType);
52 internal Type corlib_enum_type = typeof (System.Enum);
53 internal Type corlib_void_type = typeof (void);
54 ArrayList resource_writers = null;
57 [MethodImplAttribute(MethodImplOptions.InternalCall)]
58 private static extern void basic_init (AssemblyBuilder ab);
60 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) {
62 if (directory == null || directory == String.Empty)
63 dir = Directory.GetCurrentDirectory ();
66 this.access = (uint)access;
68 /* Set defaults from n */
69 if (n.CultureInfo != null) {
70 culture = n.CultureInfo.Name;
72 Version v = n.Version;
74 version = v.ToString ();
80 public override string CodeBase {
82 throw not_supported ();
86 public override MethodInfo EntryPoint {
92 public override string Location {
94 throw not_supported ();
98 public void AddResourceFile (string name, string fileName)
100 AddResourceFile (name, fileName, ResourceAttributes.Public);
103 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
105 AddResourceFile (name, fileName, attribute, true);
108 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
110 check_name_and_filename (name, fileName, fileNeedsToExists);
112 // Resource files are created/searched under the assembly storage
115 fileName = Path.Combine (dir, fileName);
117 if (resources != null) {
118 MonoResource[] new_r = new MonoResource [resources.Length + 1];
119 System.Array.Copy(resources, new_r, resources.Length);
122 resources = new MonoResource [1];
124 int p = resources.Length - 1;
125 resources [p].name = name;
126 resources [p].filename = fileName;
127 resources [p].attrs = attribute;
130 public void EmbedResourceFile (string name, string fileName)
132 EmbedResourceFile (name, fileName, ResourceAttributes.Public);
135 public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
137 if (resources != null) {
138 MonoResource[] new_r = new MonoResource [resources.Length + 1];
139 System.Array.Copy(resources, new_r, resources.Length);
142 resources = new MonoResource [1];
144 int p = resources.Length - 1;
145 resources [p].name = name;
146 resources [p].attrs = attribute;
148 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
150 resources [p].data = new byte [len];
151 s.Read (resources [p].data, 0, (int)len);
158 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
160 if (resources != null) {
161 MonoResource[] new_r = new MonoResource [resources.Length + 1];
162 System.Array.Copy(resources, new_r, resources.Length);
165 resources = new MonoResource [1];
167 int p = resources.Length - 1;
168 resources [p].name = name;
169 resources [p].attrs = attribute;
170 resources [p].data = blob;
173 public ModuleBuilder DefineDynamicModule (string name)
175 return DefineDynamicModule (name, name, false, true);
178 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
180 return DefineDynamicModule (name, name, emitSymbolInfo, true);
183 public ModuleBuilder DefineDynamicModule(string name, string fileName)
185 return DefineDynamicModule (name, fileName, false, false);
188 public ModuleBuilder DefineDynamicModule (string name, string fileName,
191 return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
194 public ModuleBuilder DefineDynamicModule (string name, string fileName,
195 bool emitSymbolInfo, bool transient)
197 check_name_and_filename (name, fileName, false);
200 if (Path.GetExtension (fileName) == String.Empty)
201 throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
203 throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
205 throw new InvalidOperationException ("Assembly was already saved.");
208 ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
210 if (modules != null) {
211 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
212 System.Array.Copy(modules, new_modules, modules.Length);
213 new_modules [modules.Length] = r;
214 modules = new_modules;
216 modules = new ModuleBuilder [1];
222 public IResourceWriter DefineResource (string name, string description, string fileName)
224 return DefineResource (name, description, fileName, ResourceAttributes.Public);
227 public IResourceWriter DefineResource (string name, string description,
228 string fileName, ResourceAttributes attribute)
230 IResourceWriter writer;
232 // description seems to be ignored
233 AddResourceFile (name, fileName, attribute, false);
234 writer = new ResourceWriter (fileName);
235 if (resource_writers == null)
236 resource_writers = new ArrayList ();
237 resource_writers.Add (writer);
242 public void DefineUnmanagedResource (byte[] resource)
244 if (resource == null)
245 throw new ArgumentNullException ("resource");
247 throw new NotImplementedException ();
251 public void DefineUnmanagedResource (string resourceFileName)
253 if (resourceFileName == null)
254 throw new ArgumentNullException ("resourceFileName");
255 if (resourceFileName == String.Empty)
256 throw new ArgumentException ("resourceFileName");
257 if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
258 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory.");
260 throw new NotImplementedException ();
264 public void DefineVersionInfoResource ()
266 throw new NotImplementedException ();
270 public void DefineVersionInfoResource (string product, string productVersion,
271 string company, string copyright, string trademark)
273 throw new NotImplementedException ();
276 public ModuleBuilder GetDynamicModule (string name)
279 throw new ArgumentNullException ("name");
281 throw new ArgumentException ("Name can't be null");
284 for (int i = 0; i < modules.Length; ++i)
285 if (modules [i].name == name)
290 public override Type[] GetExportedTypes ()
292 throw not_supported ();
295 public override FileStream GetFile (string name)
297 throw not_supported ();
300 public override FileStream[] GetFiles() {
301 throw not_supported ();
304 public override FileStream[] GetFiles(bool getResourceModules) {
305 throw not_supported ();
308 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
309 throw not_supported ();
312 public override string[] GetManifestResourceNames() {
313 throw not_supported ();
316 public override Stream GetManifestResourceStream(string name) {
317 throw not_supported ();
319 public override Stream GetManifestResourceStream(Type type, string name) {
320 throw not_supported ();
323 internal bool IsSave {
325 return access != (uint)AssemblyBuilderAccess.Run;
329 internal string AssemblyDir {
335 public void Save (string assemblyFileName)
337 if (resource_writers != null) {
338 foreach (IResourceWriter writer in resource_writers) {
344 // Create a main module if not already created
345 ModuleBuilder mainModule = null;
346 foreach (ModuleBuilder module in modules)
347 if (module.FullyQualifiedName == assemblyFileName)
349 if (mainModule == null)
350 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
352 mainModule.IsMain = true;
354 foreach (ModuleBuilder module in modules)
360 public void SetEntryPoint (MethodInfo entryMethod)
362 SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
365 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
367 if (entryMethod == null)
368 throw new ArgumentNullException ("entryMethod");
369 if (entryMethod.DeclaringType.Assembly != this)
370 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
372 entry_point = entryMethod;
376 public void SetCustomAttribute( CustomAttributeBuilder customBuilder)
378 if (customBuilder == null)
379 throw new ArgumentNullException ("customBuilder");
381 string attrname = customBuilder.Ctor.ReflectedType.FullName;
384 Mono.Security.StrongName sn;
385 if (attrname == "System.Reflection.AssemblyVersionAttribute") {
386 data = customBuilder.Data;
388 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
389 version = CustomAttributeBuilder.string_from_bytes (data, pos, len);
391 } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") {
392 data = customBuilder.Data;
394 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
395 string keyfile_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
396 if (keyfile_name == String.Empty)
398 using (FileStream fs = new FileStream (keyfile_name, FileMode.Open)) {
399 byte[] snkeypair = new byte [fs.Length];
400 fs.Read (snkeypair, 0, snkeypair.Length);
402 // this will import public or private/public keys
403 RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
404 // and export only the public part
405 sn = new Mono.Security.StrongName (rsa);
406 public_key = sn.PublicKey;
409 } else if (attrname == "System.Reflection.AssemblyKeyNameAttribute") {
410 data = customBuilder.Data;
412 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
413 string key_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
414 if (key_name == String.Empty)
416 CspParameters csparam = new CspParameters ();
417 csparam.KeyContainerName = key_name;
418 RSA rsacsp = new RSACryptoServiceProvider (csparam);
419 sn = new Mono.Security.StrongName (rsacsp);
420 public_key = sn.PublicKey;
422 } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
423 data = customBuilder.Data;
425 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
426 culture = CustomAttributeBuilder.string_from_bytes (data, pos, len);
427 } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
428 data = customBuilder.Data;
430 algid = (uint)data [pos];
431 algid |= ((uint)data [pos + 1]) << 8;
432 algid |= ((uint)data [pos + 2]) << 16;
433 algid |= ((uint)data [pos + 3]) << 24;
434 } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
435 data = customBuilder.Data;
437 flags = (uint)data [pos];
438 flags |= ((uint)data [pos + 1]) << 8;
439 flags |= ((uint)data [pos + 2]) << 16;
440 flags |= ((uint)data [pos + 3]) << 24;
442 } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") {
443 data = customBuilder.Data;
445 delay_sign = data [2] != 0;
447 if (cattrs != null) {
448 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
449 cattrs.CopyTo (new_array, 0);
450 new_array [cattrs.Length] = customBuilder;
453 cattrs = new CustomAttributeBuilder [1];
454 cattrs [0] = customBuilder;
457 public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
459 throw new ArgumentNullException ("con");
460 if (binaryAttribute == null)
461 throw new ArgumentNullException ("binaryAttribute");
463 SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
466 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) {
467 this.corlib_object_type = corlib_object_type;
468 this.corlib_value_type = corlib_value_type;
469 this.corlib_enum_type = corlib_enum_type;
472 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type)
474 SetCorlibTypeBuilders (corlib_object_type, corlib_value_type, corlib_enum_type);
475 this.corlib_void_type = corlib_void_type;
478 private Exception not_supported () {
479 // Strange message but this is what MS.NET prints...
480 return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
483 private void check_name_and_filename (string name, string fileName,
484 bool fileNeedsToExists) {
486 throw new ArgumentNullException ("name");
487 if (fileName == null)
488 throw new ArgumentNullException ("fileName");
490 throw new ArgumentException ("name cannot be empty", "name");
492 throw new ArgumentException ("fileName cannot be empty", "fileName");
493 if (Path.GetFileName (fileName) != fileName)
494 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.");
496 // Resource files are created/searched under the assembly storage
498 string fullFileName = fileName;
500 fullFileName = Path.Combine (dir, fileName);
502 if (fileNeedsToExists && !File.Exists (fullFileName))
503 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
505 if (resources != null) {
506 for (int i = 0; i < resources.Length; ++i) {
507 if (resources [i].filename == fullFileName)
508 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
509 if (resources [i].name == name)
510 throw new ArgumentException ("Duplicate name '" + name + "'");
514 if (modules != null) {
515 for (int i = 0; i < modules.Length; ++i) {
516 // Use fileName instead of fullFileName here
517 if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
518 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
519 if (modules [i].Name == name)
520 throw new ArgumentException ("Duplicate name '" + name + "'");
525 // Same as in Mono.Security/Mono>Security.Cryptography/CryptoConvert.cs