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 ModuleBuilder mainModule;
51 internal Type corlib_object_type = typeof (System.Object);
52 internal Type corlib_value_type = typeof (System.ValueType);
53 internal Type corlib_enum_type = typeof (System.Enum);
54 internal Type corlib_void_type = typeof (void);
55 private int[] table_indexes;
56 Hashtable us_string_cache = new Hashtable ();
57 ArrayList resource_writers = null;
60 [MethodImplAttribute(MethodImplOptions.InternalCall)]
61 private static extern void basic_init (AssemblyBuilder ab);
63 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) {
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 internal int get_next_table_index (object obj, int table, bool inc) {
81 if (table_indexes == null) {
82 table_indexes = new int [64];
83 for (int i=0; i < 64; ++i)
84 table_indexes [i] = 1;
85 /* allow room for .<Module> in TypeDef table */
86 table_indexes [0x02] = 2;
88 // Console.WriteLine ("getindex for table "+table.ToString()+" got "+table_indexes [table].ToString());
90 return table_indexes [table]++;
91 return table_indexes [table];
94 public override string CodeBase {
96 throw not_supported ();
100 public override MethodInfo EntryPoint {
106 public override string Location {
108 throw not_supported ();
112 public void AddResourceFile (string name, string fileName)
114 AddResourceFile (name, fileName, ResourceAttributes.Public);
117 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
119 AddResourceFile (name, fileName, attribute, true);
122 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
124 check_name_and_filename (name, fileName, fileNeedsToExists);
126 // Resource files are created/searched under the assembly storage
129 fileName = Path.Combine (dir, fileName);
131 if (resources != null) {
132 MonoResource[] new_r = new MonoResource [resources.Length + 1];
133 System.Array.Copy(resources, new_r, resources.Length);
136 resources = new MonoResource [1];
138 int p = resources.Length - 1;
139 resources [p].name = name;
140 resources [p].filename = fileName;
141 resources [p].attrs = attribute;
144 public void EmbedResourceFile (string name, string fileName)
146 EmbedResourceFile (name, fileName, ResourceAttributes.Public);
149 public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
151 if (resources != null) {
152 MonoResource[] new_r = new MonoResource [resources.Length + 1];
153 System.Array.Copy(resources, new_r, resources.Length);
156 resources = new MonoResource [1];
158 int p = resources.Length - 1;
159 resources [p].name = name;
160 resources [p].attrs = attribute;
162 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
164 resources [p].data = new byte [len];
165 s.Read (resources [p].data, 0, (int)len);
172 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
174 if (resources != null) {
175 MonoResource[] new_r = new MonoResource [resources.Length + 1];
176 System.Array.Copy(resources, new_r, resources.Length);
179 resources = new MonoResource [1];
181 int p = resources.Length - 1;
182 resources [p].name = name;
183 resources [p].attrs = attribute;
184 resources [p].data = blob;
187 public ModuleBuilder DefineDynamicModule (string name)
189 return DefineDynamicModule (name, name, false, true);
192 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
194 return DefineDynamicModule (name, name, emitSymbolInfo, true);
197 public ModuleBuilder DefineDynamicModule(string name, string fileName)
199 return DefineDynamicModule (name, fileName, false, false);
202 public ModuleBuilder DefineDynamicModule (string name, string fileName,
205 return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
208 public ModuleBuilder DefineDynamicModule (string name, string fileName,
209 bool emitSymbolInfo, bool transient)
211 check_name_and_filename (name, fileName, false);
214 if (Path.GetExtension (fileName) == String.Empty)
215 throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
217 throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
219 throw new InvalidOperationException ("Assembly was already saved.");
222 ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
224 if (modules != null) {
225 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
226 System.Array.Copy(modules, new_modules, modules.Length);
227 new_modules [modules.Length] = r;
228 modules = new_modules;
230 modules = new ModuleBuilder [1];
236 public IResourceWriter DefineResource (string name, string description, string fileName)
238 return DefineResource (name, description, fileName, ResourceAttributes.Public);
241 public IResourceWriter DefineResource (string name, string description,
242 string fileName, ResourceAttributes attribute)
244 IResourceWriter writer;
246 // description seems to be ignored
247 AddResourceFile (name, fileName, attribute, false);
248 writer = new ResourceWriter (fileName);
249 if (resource_writers == null)
250 resource_writers = new ArrayList ();
251 resource_writers.Add (writer);
256 public void DefineUnmanagedResource (byte[] resource)
258 if (resource == null)
259 throw new ArgumentNullException ("resource");
261 throw new NotImplementedException ();
265 public void DefineUnmanagedResource (string resourceFileName)
267 if (resourceFileName == null)
268 throw new ArgumentNullException ("resourceFileName");
269 if (resourceFileName == String.Empty)
270 throw new ArgumentException ("resourceFileName");
271 if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
272 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exists or is a directory.");
274 throw new NotImplementedException ();
278 public void DefineVersionInfoResource ()
280 throw new NotImplementedException ();
284 public void DefineVersionInfoResource (string product, string productVersion,
285 string company, string copyright, string trademark)
287 throw new NotImplementedException ();
290 public ModuleBuilder GetDynamicModule (string name)
293 throw new ArgumentNullException ("name");
295 throw new ArgumentException ("Name can't be null");
298 for (int i = 0; i < modules.Length; ++i)
299 if (modules [i].name == name)
304 public override Type[] GetExportedTypes ()
306 throw not_supported ();
309 public override FileStream GetFile (string name)
311 throw not_supported ();
314 public override FileStream[] GetFiles() {
315 throw not_supported ();
318 public override FileStream[] GetFiles(bool getResourceModules) {
319 throw not_supported ();
322 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
323 throw not_supported ();
326 public override string[] GetManifestResourceNames() {
327 throw not_supported ();
330 public override Stream GetManifestResourceStream(string name) {
331 throw not_supported ();
333 public override Stream GetManifestResourceStream(Type type, string name) {
334 throw not_supported ();
337 [MethodImplAttribute(MethodImplOptions.InternalCall)]
338 private static extern int getUSIndex (AssemblyBuilder ab, string str);
340 [MethodImplAttribute(MethodImplOptions.InternalCall)]
341 private static extern int getToken (AssemblyBuilder ab, object obj);
343 internal int GetToken (string str) {
344 if (us_string_cache.Contains (str))
345 return (int)us_string_cache [str];
346 int result = getUSIndex (this, str);
347 us_string_cache [str] = result;
351 internal int GetToken (MemberInfo member) {
352 return getToken (this, member);
355 internal int GetToken (SignatureHelper helper) {
356 return getToken (this, helper);
359 internal bool IsSave {
361 return access != (uint)AssemblyBuilderAccess.Run;
365 [MethodImplAttribute(MethodImplOptions.InternalCall)]
366 private static extern int getDataChunk (AssemblyBuilder ab, byte[] buf, int offset);
368 public void Save (string assemblyFileName)
370 byte[] buf = new byte [65536];
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);
389 build_metadata (this);
391 foreach (ModuleBuilder module in modules)
395 assemblyFileName = String.Format ("{0}{1}{2}", dir, System.IO.Path.DirectorySeparatorChar, assemblyFileName);
398 file = new FileStream (assemblyFileName, FileMode.Create, FileAccess.Write);
401 while ((count = getDataChunk (this, buf, offset)) != 0) {
402 file.Write (buf, 0, count);
410 // The constant 0x80000000 is internal to Mono, it means `make executable'
412 File.SetAttributes (assemblyFileName, (FileAttributes) (unchecked ((int) 0x80000000)));
415 [MethodImplAttribute(MethodImplOptions.InternalCall)]
416 private static extern void build_metadata (AssemblyBuilder ab);
418 public void SetEntryPoint (MethodInfo entryMethod)
420 SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
423 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
425 if (entryMethod == null)
426 throw new ArgumentNullException ("entryMethod");
427 if (entryMethod.DeclaringType.Assembly != this)
428 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
430 entry_point = entryMethod;
434 public void SetCustomAttribute( CustomAttributeBuilder customBuilder)
436 if (customBuilder == null)
437 throw new ArgumentNullException ("customBuilder");
439 string attrname = customBuilder.Ctor.ReflectedType.FullName;
442 Mono.Security.StrongName sn;
443 if (attrname == "System.Reflection.AssemblyVersionAttribute") {
444 data = customBuilder.Data;
446 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
447 version = CustomAttributeBuilder.string_from_bytes (data, pos, len);
449 } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") {
450 data = customBuilder.Data;
452 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
453 string keyfile_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
454 if (keyfile_name == String.Empty)
456 using (FileStream fs = new FileStream (keyfile_name, FileMode.Open)) {
457 byte[] snkeypair = new byte [fs.Length];
458 fs.Read (snkeypair, 0, snkeypair.Length);
460 // this will import public or private/public keys
461 RSA rsa = CryptoConvert.FromCapiKeyBlob (snkeypair);
462 // and export only the public part
463 sn = new Mono.Security.StrongName (rsa);
464 public_key = sn.PublicKey;
467 } else if (attrname == "System.Reflection.AssemblyKeyNameAttribute") {
468 data = customBuilder.Data;
470 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
471 string key_name = CustomAttributeBuilder.string_from_bytes (data, pos, len);
472 if (key_name == String.Empty)
474 CspParameters csparam = new CspParameters ();
475 csparam.KeyContainerName = key_name;
476 RSA rsacsp = new RSACryptoServiceProvider (csparam);
477 sn = new Mono.Security.StrongName (rsacsp);
478 public_key = sn.PublicKey;
480 } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
481 data = customBuilder.Data;
483 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
484 culture = CustomAttributeBuilder.string_from_bytes (data, pos, len);
485 } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
486 data = customBuilder.Data;
488 algid = (uint)data [pos];
489 algid |= ((uint)data [pos + 1]) << 8;
490 algid |= ((uint)data [pos + 2]) << 16;
491 algid |= ((uint)data [pos + 3]) << 24;
492 } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
493 data = customBuilder.Data;
495 flags = (uint)data [pos];
496 flags |= ((uint)data [pos + 1]) << 8;
497 flags |= ((uint)data [pos + 2]) << 16;
498 flags |= ((uint)data [pos + 3]) << 24;
500 } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") {
501 data = customBuilder.Data;
503 delay_sign = data [2] != 0;
505 if (cattrs != null) {
506 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
507 cattrs.CopyTo (new_array, 0);
508 new_array [cattrs.Length] = customBuilder;
511 cattrs = new CustomAttributeBuilder [1];
512 cattrs [0] = customBuilder;
515 public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
517 throw new ArgumentNullException ("con");
518 if (binaryAttribute == null)
519 throw new ArgumentNullException ("binaryAttribute");
521 SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
524 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) {
525 this.corlib_object_type = corlib_object_type;
526 this.corlib_value_type = corlib_value_type;
527 this.corlib_enum_type = corlib_enum_type;
530 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type, Type corlib_void_type)
532 SetCorlibTypeBuilders (corlib_object_type, corlib_value_type, corlib_enum_type);
533 this.corlib_void_type = corlib_void_type;
536 private Exception not_supported () {
537 // Strange message but this is what MS.NET prints...
538 return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
541 private void check_name_and_filename (string name, string fileName,
542 bool fileNeedsToExists) {
544 throw new ArgumentNullException ("name");
545 if (fileName == null)
546 throw new ArgumentNullException ("fileName");
548 throw new ArgumentException ("name cannot be empty", "name");
550 throw new ArgumentException ("fileName cannot be empty", "fileName");
551 if (Path.GetFileName (fileName) != fileName)
552 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.");
554 // Resource files are created/searched under the assembly storage
556 string fullFileName = fileName;
558 fullFileName = Path.Combine (dir, fileName);
560 if (fileNeedsToExists && !File.Exists (fullFileName))
561 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
563 if (resources != null) {
564 for (int i = 0; i < resources.Length; ++i) {
565 if (resources [i].filename == fullFileName)
566 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
567 if (resources [i].name == name)
568 throw new ArgumentException ("Duplicate name '" + name + "'");
572 if (modules != null) {
573 for (int i = 0; i < modules.Length; ++i) {
574 // Use fileName instead of fullFileName here
575 if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
576 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
577 if (modules [i].Name == name)
578 throw new ArgumentException ("Duplicate name '" + name + "'");
583 // Same as in Mono.Security/Mono>Security.Cryptography/CryptoConvert.cs