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;
21 using System.Security.Permissions;
24 using Mono.Security.Cryptography;
26 namespace System.Reflection.Emit {
28 internal struct RefEmitPermissionSet {
29 public SecurityAction action;
32 public RefEmitPermissionSet (SecurityAction action, string pset) {
38 internal struct MonoResource {
41 public string filename;
42 public ResourceAttributes attrs;
46 public sealed class AssemblyBuilder : Assembly {
47 #region Sync with reflection.h
48 private IntPtr dynamic_assembly;
49 private MethodInfo entry_point;
50 private ModuleBuilder[] modules;
53 private CustomAttributeBuilder[] cattrs;
54 private MonoResource[] resources;
60 PEFileKinds pekind = PEFileKinds.Dll;
64 internal Type corlib_object_type = typeof (System.Object);
65 internal Type corlib_value_type = typeof (System.ValueType);
66 internal Type corlib_enum_type = typeof (System.Enum);
67 internal Type corlib_void_type = typeof (void);
68 ArrayList resource_writers = null;
72 [MethodImplAttribute(MethodImplOptions.InternalCall)]
73 private static extern void basic_init (AssemblyBuilder ab);
75 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) {
77 if (directory == null || directory == String.Empty)
78 dir = Directory.GetCurrentDirectory ();
81 this.access = (uint)access;
83 /* Set defaults from n */
84 if (n.CultureInfo != null) {
85 culture = n.CultureInfo.Name;
87 Version v = n.Version;
89 version = v.ToString ();
95 public override string CodeBase {
97 throw not_supported ();
101 public override MethodInfo EntryPoint {
107 public override string Location {
109 throw not_supported ();
114 /* This is to keep signature compatibility with MS.NET */
115 public override string ImageRuntimeVersion {
117 return base.ImageRuntimeVersion;
122 public void AddResourceFile (string name, string fileName)
124 AddResourceFile (name, fileName, ResourceAttributes.Public);
127 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
129 AddResourceFile (name, fileName, attribute, true);
132 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
134 check_name_and_filename (name, fileName, fileNeedsToExists);
136 // Resource files are created/searched under the assembly storage
139 fileName = Path.Combine (dir, fileName);
141 if (resources != null) {
142 MonoResource[] new_r = new MonoResource [resources.Length + 1];
143 System.Array.Copy(resources, new_r, resources.Length);
146 resources = new MonoResource [1];
148 int p = resources.Length - 1;
149 resources [p].name = name;
150 resources [p].filename = fileName;
151 resources [p].attrs = attribute;
154 public void EmbedResourceFile (string name, string fileName)
156 EmbedResourceFile (name, fileName, ResourceAttributes.Public);
159 public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
161 if (resources != null) {
162 MonoResource[] new_r = new MonoResource [resources.Length + 1];
163 System.Array.Copy(resources, new_r, resources.Length);
166 resources = new MonoResource [1];
168 int p = resources.Length - 1;
169 resources [p].name = name;
170 resources [p].attrs = attribute;
172 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
174 resources [p].data = new byte [len];
175 s.Read (resources [p].data, 0, (int)len);
182 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
184 if (resources != null) {
185 MonoResource[] new_r = new MonoResource [resources.Length + 1];
186 System.Array.Copy(resources, new_r, resources.Length);
189 resources = new MonoResource [1];
191 int p = resources.Length - 1;
192 resources [p].name = name;
193 resources [p].attrs = attribute;
194 resources [p].data = blob;
197 public ModuleBuilder DefineDynamicModule (string name)
199 return DefineDynamicModule (name, name, false, true);
202 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
204 return DefineDynamicModule (name, name, emitSymbolInfo, true);
207 public ModuleBuilder DefineDynamicModule(string name, string fileName)
209 return DefineDynamicModule (name, fileName, false, false);
212 public ModuleBuilder DefineDynamicModule (string name, string fileName,
215 return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
218 private ModuleBuilder DefineDynamicModule (string name, string fileName,
219 bool emitSymbolInfo, bool transient)
221 check_name_and_filename (name, fileName, false);
224 if (Path.GetExtension (fileName) == String.Empty)
225 throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
227 throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
229 throw new InvalidOperationException ("Assembly was already saved.");
232 ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
234 if ((modules != null) && is_module_only)
235 throw new InvalidOperationException ("A module-only assembly can only contain one module.");
237 if (modules != null) {
238 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
239 System.Array.Copy(modules, new_modules, modules.Length);
240 new_modules [modules.Length] = r;
241 modules = new_modules;
243 modules = new ModuleBuilder [1];
249 public IResourceWriter DefineResource (string name, string description, string fileName)
251 return DefineResource (name, description, fileName, ResourceAttributes.Public);
254 public IResourceWriter DefineResource (string name, string description,
255 string fileName, ResourceAttributes attribute)
257 IResourceWriter writer;
259 // description seems to be ignored
260 AddResourceFile (name, fileName, attribute, false);
261 writer = new ResourceWriter (fileName);
262 if (resource_writers == null)
263 resource_writers = new ArrayList ();
264 resource_writers.Add (writer);
269 public void DefineUnmanagedResource (byte[] resource)
271 if (resource == null)
272 throw new ArgumentNullException ("resource");
274 throw new NotImplementedException ();
278 public void DefineUnmanagedResource (string resourceFileName)
280 if (resourceFileName == null)
281 throw new ArgumentNullException ("resourceFileName");
282 if (resourceFileName == String.Empty)
283 throw new ArgumentException ("resourceFileName");
284 if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
285 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory.");
287 throw new NotImplementedException ();
291 public void DefineVersionInfoResource ()
293 throw new NotImplementedException ();
297 public void DefineVersionInfoResource (string product, string productVersion,
298 string company, string copyright, string trademark)
300 throw new NotImplementedException ();
303 public ModuleBuilder GetDynamicModule (string name)
306 throw new ArgumentNullException ("name");
308 throw new ArgumentException ("Name can't be null");
311 for (int i = 0; i < modules.Length; ++i)
312 if (modules [i].name == name)
317 public override Type[] GetExportedTypes ()
319 throw not_supported ();
322 public override FileStream GetFile (string name)
324 throw not_supported ();
327 public override FileStream[] GetFiles(bool getResourceModules) {
328 throw not_supported ();
331 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
332 throw not_supported ();
335 public override string[] GetManifestResourceNames() {
336 throw not_supported ();
339 public override Stream GetManifestResourceStream(string name) {
340 throw not_supported ();
342 public override Stream GetManifestResourceStream(Type type, string name) {
343 throw not_supported ();
346 internal bool IsSave {
348 return access != (uint)AssemblyBuilderAccess.Run;
352 internal string AssemblyDir {
359 * Mono extension. If this is set, the assembly can only contain one
360 * module, access should be Save, and the saved image will not contain an
363 internal bool IsModuleOnly {
365 return is_module_only;
368 is_module_only = value;
372 public void Save (string assemblyFileName)
374 if (resource_writers != null) {
375 foreach (IResourceWriter writer in resource_writers) {
381 // Create a main module if not already created
382 ModuleBuilder mainModule = null;
383 foreach (ModuleBuilder module in modules)
384 if (module.FullyQualifiedName == assemblyFileName)
386 if (mainModule == null)
387 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
390 mainModule.IsMain = true;
392 foreach (ModuleBuilder module in modules)
393 if (module != mainModule)
396 // Write out the main module at the end, because it needs to
397 // contain the hash of the other modules
403 public void SetEntryPoint (MethodInfo entryMethod)
405 SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
408 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
410 if (entryMethod == null)
411 throw new ArgumentNullException ("entryMethod");
412 if (entryMethod.DeclaringType.Assembly != this)
413 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
415 entry_point = entryMethod;
419 public void SetCustomAttribute( CustomAttributeBuilder customBuilder)
421 if (customBuilder == null)
422 throw new ArgumentNullException ("customBuilder");
424 string attrname = customBuilder.Ctor.ReflectedType.FullName;
427 Mono.Security.StrongName sn;
428 if (attrname == "System.Reflection.AssemblyVersionAttribute") {
429 data = customBuilder.Data;
431 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
432 version = create_assembly_version (CustomAttributeBuilder.string_from_bytes (data, pos, len));
434 } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") {
435 data = customBuilder.Data;
437 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
438 string keyfile_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
439 if (keyfile_name == String.Empty)
441 using (FileStream fs = new FileStream (keyfile_name, FileMode.Open)) {
442 byte[] snkeypair = new byte [fs.Length];
443 fs.Read (snkeypair, 0, snkeypair.Length);
445 // this will import public or private/public keys
446 RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
447 // and export only the public part
448 sn = new Mono.Security.StrongName (rsa);
449 public_key = sn.PublicKey;
452 } else if (attrname == "System.Reflection.AssemblyKeyNameAttribute") {
453 data = customBuilder.Data;
455 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
456 string key_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
457 if (key_name == String.Empty)
459 CspParameters csparam = new CspParameters ();
460 csparam.KeyContainerName = key_name;
461 RSA rsacsp = new RSACryptoServiceProvider (csparam);
462 sn = new Mono.Security.StrongName (rsacsp);
463 public_key = sn.PublicKey;
465 } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
466 data = customBuilder.Data;
468 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
469 culture = CustomAttributeBuilder.string_from_bytes (data, pos, len);
470 } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
471 data = customBuilder.Data;
473 algid = (uint)data [pos];
474 algid |= ((uint)data [pos + 1]) << 8;
475 algid |= ((uint)data [pos + 2]) << 16;
476 algid |= ((uint)data [pos + 3]) << 24;
477 } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
478 data = customBuilder.Data;
480 flags = (uint)data [pos];
481 flags |= ((uint)data [pos + 1]) << 8;
482 flags |= ((uint)data [pos + 2]) << 16;
483 flags |= ((uint)data [pos + 3]) << 24;
485 } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") {
486 data = customBuilder.Data;
488 delay_sign = data [2] != 0;
490 if (cattrs != null) {
491 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
492 cattrs.CopyTo (new_array, 0);
493 new_array [cattrs.Length] = customBuilder;
496 cattrs = new CustomAttributeBuilder [1];
497 cattrs [0] = customBuilder;
500 public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
502 throw new ArgumentNullException ("con");
503 if (binaryAttribute == null)
504 throw new ArgumentNullException ("binaryAttribute");
506 SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
509 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) {
510 this.corlib_object_type = corlib_object_type;
511 this.corlib_value_type = corlib_value_type;
512 this.corlib_enum_type = corlib_enum_type;
515 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type)
517 SetCorlibTypeBuilders (corlib_object_type, corlib_value_type, corlib_enum_type);
518 this.corlib_void_type = corlib_void_type;
521 private Exception not_supported () {
522 // Strange message but this is what MS.NET prints...
523 return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
526 private void check_name_and_filename (string name, string fileName,
527 bool fileNeedsToExists) {
529 throw new ArgumentNullException ("name");
530 if (fileName == null)
531 throw new ArgumentNullException ("fileName");
533 throw new ArgumentException ("name cannot be empty", "name");
535 throw new ArgumentException ("fileName cannot be empty", "fileName");
536 if (Path.GetFileName (fileName) != fileName)
537 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.");
539 // Resource files are created/searched under the assembly storage
541 string fullFileName = fileName;
543 fullFileName = Path.Combine (dir, fileName);
545 if (fileNeedsToExists && !File.Exists (fullFileName))
546 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
548 if (resources != null) {
549 for (int i = 0; i < resources.Length; ++i) {
550 if (resources [i].filename == fullFileName)
551 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
552 if (resources [i].name == name)
553 throw new ArgumentException ("Duplicate name '" + name + "'");
557 if (modules != null) {
558 for (int i = 0; i < modules.Length; ++i) {
559 // Use fileName instead of fullFileName here
560 if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
561 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
562 if (modules [i].Name == name)
563 throw new ArgumentException ("Duplicate name '" + name + "'");
568 private String create_assembly_version (String version) {
569 String[] parts = version.Split ('.');
570 int[] ver = new int [4] { 0, 0, 0, 0 };
572 if ((parts.Length < 0) || (parts.Length > 4))
573 throw new ArgumentException ("The version specified '" + version + "' is invalid");
575 for (int i = 0; i < parts.Length; ++i) {
576 if (parts [i] == "*") {
577 DateTime now = DateTime.Now;
580 ver [2] = (now - new DateTime (2000, 1, 1)).Days;
581 if (parts.Length == 3)
582 ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
586 ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
588 throw new ArgumentException ("The version specified '" + version + "' is invalid");
592 ver [i] = Int32.Parse (parts [i]);
594 catch (FormatException) {
595 throw new ArgumentException ("The version specified '" + version + "' is invalid");
600 return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];