Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / corlib / System.Reflection.Emit / AssemblyBuilder.cs
1 //
2 // System.Reflection.Emit/AssemblyBuilder.cs
3 //
4 // Author:
5 //   Paolo Molaro (lupus@ximian.com)
6 //
7 // (C) 2001 Ximian, Inc.  http://www.ximian.com
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 #if !FULL_AOT_RUNTIME
34 using System;
35 using System.Reflection;
36 using System.Resources;
37 using System.IO;
38 using System.Security.Policy;
39 using System.Runtime.Serialization;
40 using System.Globalization;
41 using System.Runtime.CompilerServices;
42 using System.Collections;
43 using System.Collections.Generic;
44 using System.Runtime.InteropServices;
45 using System.Security;
46 using System.Security.Cryptography;
47 using System.Security.Permissions;
48
49 using Mono.Security;
50 using Mono.Security.Cryptography;
51
52 namespace System.Reflection.Emit
53 {
54         internal enum NativeResourceType
55         {
56                 None,
57                 Unmanaged,
58                 Assembly,
59                 Explicit
60         }
61
62         internal struct RefEmitPermissionSet {
63                 public SecurityAction action;
64                 public string pset;
65
66                 public RefEmitPermissionSet (SecurityAction action, string pset) {
67                         this.action = action;
68                         this.pset = pset;
69                 }
70         }
71
72         internal struct MonoResource {
73 #pragma warning disable 649
74                 public byte[] data;
75                 public string name;
76                 public string filename;
77                 public ResourceAttributes attrs;
78                 public int offset;
79                 public Stream stream;
80 #pragma warning restore 649
81         }
82
83         internal struct MonoWin32Resource {
84                 public int res_type;
85                 public int res_id;
86                 public int lang_id;
87                 public byte[] data;
88
89                 public MonoWin32Resource (int res_type, int res_id, int lang_id, byte[] data) {
90                         this.res_type = res_type;
91                         this.res_id = res_id;
92                         this.lang_id = lang_id;
93                         this.data = data;
94                 }
95         }
96
97         internal class GenericInstanceKey {
98                 Type gtd;
99                 internal Type[] args;
100                 int hash_code;
101
102                 internal GenericInstanceKey (Type gtd, Type[] args)
103                 {
104                         this.gtd = gtd;
105                         this.args = args;
106
107                         hash_code = gtd.GetHashCode ();
108                         for (int i = 0; i < args.Length; ++i)
109                                 hash_code ^= args [i].GetHashCode ();
110                 }
111
112                 static bool IsBoundedVector (Type type) {
113                         ArrayType at = type as ArrayType;
114                         if (at != null)
115                                 return at.GetEffectiveRank () == 1;
116                         return type.ToString ().EndsWith ("[*]", StringComparison.Ordinal); /*Super uggly hack, SR doesn't allow one to query for it */
117                 }
118
119                 static bool TypeEquals (Type a, Type b) {
120                         if (a == b)
121                                 return true;
122
123                         if (a.HasElementType) {
124                                 if (!b.HasElementType)
125                                         return false;
126                                 if (!TypeEquals (a.GetElementType (), b.GetElementType ()))
127                                         return false;
128                                 if (a.IsArray) {
129                                         if (!b.IsArray)
130                                                 return false;
131                                         int rank = a.GetArrayRank ();
132                                         if (rank != b.GetArrayRank ())
133                                                 return false;
134                                         if (rank == 1 && IsBoundedVector (a) != IsBoundedVector (b))
135                                                 return false;
136                                 } else if (a.IsByRef) {
137                                         if (!b.IsByRef)
138                                                 return false;
139                                 } else if (a.IsPointer) {
140                                         if (!b.IsPointer)
141                                                 return false;
142                                 }
143                                 return true;
144                         }
145
146                         if (a.IsGenericType) {
147                                 if (!b.IsGenericType)
148                                         return false;
149                                 if (a.IsGenericParameter)
150                                         return a == b;
151                                 if (a.IsGenericParameter) //previous test should have caught it
152                                         return false;
153
154                                 if (a.IsGenericTypeDefinition) {
155                                         if (!b.IsGenericTypeDefinition)
156                                                 return false;
157                                 } else {
158                                         if (b.IsGenericTypeDefinition)
159                                                 return false;
160                                         if (!TypeEquals (a.GetGenericTypeDefinition (), b.GetGenericTypeDefinition ()))
161                                                 return false;
162
163                                         Type[] argsA = a.GetGenericArguments ();
164                                         Type[] argsB = b.GetGenericArguments ();
165                                         for (int i = 0; i < argsA.Length; ++i) {
166                                                 if (!TypeEquals (argsA [i], argsB [i]))
167                                                         return false;
168                                         }
169                                 }
170                         }
171
172                         /*
173                         Now only non-generic, non compound types are left. To properly deal with user
174                         types we would have to call UnderlyingSystemType, but we let them have their
175                         own instantiation as this is MS behavior and mcs (pre C# 4.0, at least) doesn't
176                         depend on proper UT canonicalization.
177                         */
178                         return a == b;
179                 }
180
181                 public override bool Equals (object obj)
182                 {
183                         GenericInstanceKey other = obj as GenericInstanceKey;
184                         if (other == null)
185                                 return false;
186                         if (gtd != other.gtd)
187                                 return false;
188                         for (int i = 0; i < args.Length; ++i) {
189                                 Type a = args [i];
190                                 Type b = other.args [i];
191                                 /*
192                                 We must cannonicalize as much as we can. Using equals means that some resulting types
193                                 won't have the exact same types as the argument ones. 
194                                 For example, flyweight types used array, pointer and byref will should this behavior.
195                                 MCS seens to be resilient to this problem so hopefully this won't show up.   
196                                 */
197                                 if (a != b && !a.Equals (b))
198                                         return false;
199                         }
200                         return true;
201                 }
202
203                 public override int GetHashCode ()
204                 {
205                         return hash_code;
206                 }
207         }
208
209
210         [ComVisible (true)]
211         [ComDefaultInterface (typeof (_AssemblyBuilder))]
212         [ClassInterface (ClassInterfaceType.None)]
213         [StructLayout (LayoutKind.Sequential)]
214         public sealed class AssemblyBuilder : Assembly, _AssemblyBuilder {
215 #pragma warning disable 169, 414, 649
216                 #region Sync with object-internals.h
217                 private UIntPtr dynamic_assembly; /* GC-tracked */
218                 private MethodInfo entry_point;
219                 private ModuleBuilder[] modules;
220                 private string name;
221                 private string dir;
222                 private CustomAttributeBuilder[] cattrs;
223                 private MonoResource[] resources;
224                 byte[] public_key;
225                 string version;
226                 string culture;
227                 uint algid;
228                 uint flags;
229                 PEFileKinds pekind = PEFileKinds.Dll;
230                 bool delay_sign;
231                 uint access;
232                 Module[] loaded_modules;
233                 MonoWin32Resource[] win32_resources;
234                 private RefEmitPermissionSet[] permissions_minimum;
235                 private RefEmitPermissionSet[] permissions_optional;
236                 private RefEmitPermissionSet[] permissions_refused;
237                 PortableExecutableKinds peKind;
238                 ImageFileMachine machine;
239                 bool corlib_internal;
240                 Type[] type_forwarders;
241                 byte[] pktoken;
242                 #endregion
243 #pragma warning restore 169, 414, 649
244                 
245                 internal Type corlib_object_type = typeof (System.Object);
246                 internal Type corlib_value_type = typeof (System.ValueType);
247                 internal Type corlib_enum_type = typeof (System.Enum);
248                 internal Type corlib_void_type = typeof (void);
249                 ArrayList resource_writers = null;
250                 Win32VersionResource version_res;
251                 bool created;
252                 bool is_module_only;
253                 private Mono.Security.StrongName sn;
254                 NativeResourceType native_resource;
255                 string versioninfo_culture;
256
257                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
258                 private static extern void basic_init (AssemblyBuilder ab);
259
260                 /* Keep this in sync with codegen.cs in mcs */
261                 private const AssemblyBuilderAccess COMPILER_ACCESS = (AssemblyBuilderAccess) 0x800;
262
263                 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access, bool corlib_internal)
264                 {
265                         /* This is obsolete now, as mcs doesn't use SRE any more */
266                         if ((access & COMPILER_ACCESS) != 0)
267                                 throw new NotImplementedException ("COMPILER_ACCESS is no longer supperted, use a newer mcs.");
268
269                         if (!Enum.IsDefined (typeof (AssemblyBuilderAccess), access))
270                                 throw new ArgumentException (string.Format (CultureInfo.InvariantCulture,
271                                         "Argument value {0} is not valid.", (int) access),
272                                         "access");
273
274                         name = n.Name;
275                         this.access = (uint)access;
276                         flags = (uint) n.Flags;
277
278                         // don't call GetCurrentDirectory for Run-only builders (CAS may not like that)
279                         if (IsSave && (directory == null || directory.Length == 0)) {
280                                 dir = Directory.GetCurrentDirectory ();
281                         } else {
282                                 dir = directory;
283                         }
284
285                         /* Set defaults from n */
286                         if (n.CultureInfo != null) {
287                                 culture = n.CultureInfo.Name;
288                                 versioninfo_culture = n.CultureInfo.Name;
289                         }
290                         Version v = n.Version;
291                         if (v != null) {
292                                 version = v.ToString ();
293                         }
294
295                         if (n.KeyPair != null) {
296                                 // full keypair is available (for signing)
297                                 sn = n.KeyPair.StrongName ();
298                         } else {
299                                 // public key is available (for delay-signing)
300                                 byte[] pk = n.GetPublicKey ();
301                                 if ((pk != null) && (pk.Length > 0)) {
302                                         sn = new Mono.Security.StrongName (pk);
303                                 }
304                         }
305
306                         if (sn != null)
307                                 flags |= (uint) AssemblyNameFlags.PublicKey;
308
309                         this.corlib_internal = corlib_internal;
310                         if (sn != null) {
311                                 this.pktoken = new byte[sn.PublicKeyToken.Length * 2];
312                                 int pkti = 0;
313                                 foreach (byte pkb in sn.PublicKeyToken) {
314                                         string part = pkb.ToString("x2");
315                                         this.pktoken[pkti++] = (byte)part[0];
316                                         this.pktoken[pkti++] = (byte)part[1];
317                                 }
318                         }
319
320                         basic_init (this);
321                 }
322
323                 public override string CodeBase {
324                         get {
325                                 throw not_supported ();
326                         }
327                 }
328                 
329                 public override MethodInfo EntryPoint {
330                         get {
331                                 return entry_point;
332                         }
333                 }
334
335                 public override string Location {
336                         get {
337                                 throw not_supported ();
338                         }
339                 }
340
341                 /* This is to keep signature compatibility with MS.NET */
342                 public override string ImageRuntimeVersion {
343                         get {
344                                 return base.ImageRuntimeVersion;
345                         }
346                 }
347
348                 [MonoTODO]
349                 public override bool ReflectionOnly {
350                         get { return base.ReflectionOnly; }
351                 }
352
353                 public void AddResourceFile (string name, string fileName)
354                 {
355                         AddResourceFile (name, fileName, ResourceAttributes.Public);
356                 }
357
358                 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
359                 {
360                         AddResourceFile (name, fileName, attribute, true);
361                 }
362
363                 private void AddResourceFile (string name, string fileName, ResourceAttributes attribute, bool fileNeedsToExists)
364                 {
365                         check_name_and_filename (name, fileName, fileNeedsToExists);
366
367                         // Resource files are created/searched under the assembly storage
368                         // directory
369                         if (dir != null)
370                                 fileName = Path.Combine (dir, fileName);
371
372                         if (resources != null) {
373                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
374                                 System.Array.Copy(resources, new_r, resources.Length);
375                                 resources = new_r;
376                         } else {
377                                 resources = new MonoResource [1];
378                         }
379                         int p = resources.Length - 1;
380                         resources [p].name = name;
381                         resources [p].filename = fileName;
382                         resources [p].attrs = attribute;
383                 }
384
385                 internal void AddPermissionRequests (PermissionSet required, PermissionSet optional, PermissionSet refused)
386                 {
387 #if !NET_2_1
388                         if (created)
389                                 throw new InvalidOperationException ("Assembly was already saved.");
390
391                         // required for base Assembly class (so the permissions
392                         // can be used even if the assembly isn't saved to disk)
393                         _minimum = required;
394                         _optional = optional;
395                         _refuse = refused;
396
397                         // required to reuse AddDeclarativeSecurity support 
398                         // already present in the runtime
399                         if (required != null) {
400                                 permissions_minimum = new RefEmitPermissionSet [1];
401                                 permissions_minimum [0] = new RefEmitPermissionSet (
402                                         SecurityAction.RequestMinimum, required.ToXml ().ToString ());
403                         }
404                         if (optional != null) {
405                                 permissions_optional = new RefEmitPermissionSet [1];
406                                 permissions_optional [0] = new RefEmitPermissionSet (
407                                         SecurityAction.RequestOptional, optional.ToXml ().ToString ());
408                         }
409                         if (refused != null) {
410                                 permissions_refused = new RefEmitPermissionSet [1];
411                                 permissions_refused [0] = new RefEmitPermissionSet (
412                                         SecurityAction.RequestRefuse, refused.ToXml ().ToString ());
413                         }
414 #endif
415                 }
416
417                 // Still in use by al.exe
418                 internal void EmbedResourceFile (string name, string fileName)
419                 {
420                         EmbedResourceFile (name, fileName, ResourceAttributes.Public);
421                 }
422
423                 void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
424                 {
425                         if (resources != null) {
426                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
427                                 System.Array.Copy(resources, new_r, resources.Length);
428                                 resources = new_r;
429                         } else {
430                                 resources = new MonoResource [1];
431                         }
432                         int p = resources.Length - 1;
433                         resources [p].name = name;
434                         resources [p].attrs = attribute;
435                         try {
436                                 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
437                                 long len = s.Length;
438                                 resources [p].data = new byte [len];
439                                 s.Read (resources [p].data, 0, (int)len);
440                                 s.Close ();
441                         } catch {
442                         }
443                 }
444 /*
445                 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
446                 {
447                         if (resources != null) {
448                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
449                                 System.Array.Copy(resources, new_r, resources.Length);
450                                 resources = new_r;
451                         } else {
452                                 resources = new MonoResource [1];
453                         }
454                         int p = resources.Length - 1;
455                         resources [p].name = name;
456                         resources [p].attrs = attribute;
457                         resources [p].data = blob;
458                 }
459 */
460
461                 public ModuleBuilder DefineDynamicModule (string name)
462                 {
463                         return DefineDynamicModule (name, name, false, true);
464                 }
465
466                 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
467                 {
468                         return DefineDynamicModule (name, name, emitSymbolInfo, true);
469                 }
470
471                 public ModuleBuilder DefineDynamicModule(string name, string fileName)
472                 {
473                         return DefineDynamicModule (name, fileName, false, false);
474                 }
475
476                 public ModuleBuilder DefineDynamicModule (string name, string fileName,
477                                                           bool emitSymbolInfo)
478                 {
479                         return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
480                 }
481
482                 private ModuleBuilder DefineDynamicModule (string name, string fileName, bool emitSymbolInfo, bool transient)
483                 {
484                         check_name_and_filename (name, fileName, false);
485
486                         if (!transient) {
487                                 if (Path.GetExtension (fileName) == String.Empty)
488                                         throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
489                                 if (!IsSave)
490                                         throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
491                                 if (created)
492                                         throw new InvalidOperationException ("Assembly was already saved.");
493                         }
494
495                         ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
496
497                         if ((modules != null) && is_module_only)
498                                 throw new InvalidOperationException ("A module-only assembly can only contain one module.");
499
500                         if (modules != null) {
501                                 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
502                                 System.Array.Copy(modules, new_modules, modules.Length);
503                                 modules = new_modules;
504                         } else {
505                                 modules = new ModuleBuilder [1];
506                         }
507                         modules [modules.Length - 1] = r;
508                         return r;
509                 }
510
511                 public IResourceWriter DefineResource (string name, string description, string fileName)
512                 {
513                         return DefineResource (name, description, fileName, ResourceAttributes.Public);
514                 }
515
516                 public IResourceWriter DefineResource (string name, string description,
517                                                        string fileName, ResourceAttributes attribute)
518                 {
519                         IResourceWriter writer;
520
521                         // description seems to be ignored
522                         AddResourceFile (name, fileName, attribute, false);
523                         writer = new ResourceWriter (fileName);
524                         if (resource_writers == null)
525                                 resource_writers = new ArrayList ();
526                         resource_writers.Add (writer);
527                         return writer;
528                 }
529
530                 private void AddUnmanagedResource (Win32Resource res) {
531                         MemoryStream ms = new MemoryStream ();
532                         res.WriteTo (ms);
533
534                         if (win32_resources != null) {
535                                 MonoWin32Resource[] new_res = new MonoWin32Resource [win32_resources.Length + 1];
536                                 System.Array.Copy (win32_resources, new_res, win32_resources.Length);
537                                 win32_resources = new_res;
538                         }
539                         else
540                                 win32_resources = new MonoWin32Resource [1];
541
542                         win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ());
543                 }
544
545                 [MonoTODO ("Not currently implemenented")]
546                 public void DefineUnmanagedResource (byte[] resource)
547                 {
548                         if (resource == null)
549                                 throw new ArgumentNullException ("resource");
550                         if (native_resource != NativeResourceType.None)
551                                 throw new ArgumentException ("Native resource has already been defined.");
552
553                         // avoid definition of more than one unmanaged resource
554                         native_resource = NativeResourceType.Unmanaged;
555
556                         /*
557                          * The format of the argument byte array is not documented
558                          * so this method is impossible to implement.
559                          *
560                          * https://connect.microsoft.com/VisualStudio/feedback/details/95784/fatal-assemblybuilder-defineunmanagedresource-byte-and-modulebuilder-defineunmanagedresource-byte-bugs-renders-them-useless
561                          */
562
563                         throw new NotImplementedException ();
564                 }
565
566                 public void DefineUnmanagedResource (string resourceFileName)
567                 {
568                         if (resourceFileName == null)
569                                 throw new ArgumentNullException ("resourceFileName");
570                         if (resourceFileName.Length == 0)
571                                 throw new ArgumentException ("resourceFileName");
572                         if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
573                                 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exist or is a directory.");
574                         if (native_resource != NativeResourceType.None)
575                                 throw new ArgumentException ("Native resource has already been defined.");
576
577                         // avoid definition of more than one unmanaged resource
578                         native_resource = NativeResourceType.Unmanaged;
579
580                         using (FileStream fs = new FileStream (resourceFileName, FileMode.Open, FileAccess.Read)) {
581                                 Win32ResFileReader reader = new Win32ResFileReader (fs);
582
583                                 foreach (Win32EncodedResource res in reader.ReadResources ()) {
584                                         if (res.Name.IsName || res.Type.IsName)
585                                                 throw new InvalidOperationException ("resource files with named resources or non-default resource types are not supported.");
586
587                                         AddUnmanagedResource (res);
588                                 }
589                         }
590                 }
591
592                 public void DefineVersionInfoResource ()
593                 {
594                         if (native_resource != NativeResourceType.None)
595                                 throw new ArgumentException ("Native resource has already been defined.");
596
597                         // avoid definition of more than one unmanaged resource
598                         native_resource = NativeResourceType.Assembly;
599
600                         version_res = new Win32VersionResource (1, 0, false);
601                 }
602
603                 public void DefineVersionInfoResource (string product, string productVersion,
604                                                        string company, string copyright, string trademark)
605                 {
606                         if (native_resource != NativeResourceType.None)
607                                 throw new ArgumentException ("Native resource has already been defined.");
608
609                         // avoid definition of more than one unmanaged resource
610                         native_resource = NativeResourceType.Explicit;
611
612                         /*
613                          * We can only create the resource later, when the file name and
614                          * the binary version is known.
615                          */
616
617                         version_res = new Win32VersionResource (1, 0, false);
618                         version_res.ProductName = product != null ? product : " ";
619                         version_res.ProductVersion = productVersion != null ? productVersion : " ";
620                         version_res.CompanyName = company != null ? company : " ";
621                         version_res.LegalCopyright = copyright != null ? copyright : " ";
622                         version_res.LegalTrademarks = trademark != null ? trademark : " ";
623                 }
624
625                 private void DefineVersionInfoResourceImpl (string fileName)
626                 {
627                         if (versioninfo_culture != null)
628                                 version_res.FileLanguage = new CultureInfo (versioninfo_culture).LCID;
629                         version_res.Version = version == null ? "0.0.0.0" : version;
630
631                         if (cattrs != null) {
632                                 switch (native_resource) {
633                                 case NativeResourceType.Assembly:
634                                         foreach (CustomAttributeBuilder cb in cattrs) {
635                                                 string attrname = cb.Ctor.ReflectedType.FullName;
636
637                                                 if (attrname == "System.Reflection.AssemblyProductAttribute")
638                                                         version_res.ProductName = cb.string_arg ();
639                                                 else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
640                                                         version_res.CompanyName = cb.string_arg ();
641                                                 else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
642                                                         version_res.LegalCopyright = cb.string_arg ();
643                                                 else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
644                                                         version_res.LegalTrademarks = cb.string_arg ();
645                                                 else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
646                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
647                                                 } else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") {
648                                                         version_res.FileVersion = cb.string_arg ();
649                                                 } else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
650                                                         version_res.ProductVersion = cb.string_arg ();
651                                                 else if (attrname == "System.Reflection.AssemblyTitleAttribute")
652                                                         version_res.FileDescription = cb.string_arg ();
653                                                 else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
654                                                         version_res.Comments = cb.string_arg ();
655                                         }
656                                         break;
657                                 case NativeResourceType.Explicit:
658                                         foreach (CustomAttributeBuilder cb in cattrs) {
659                                                 string attrname = cb.Ctor.ReflectedType.FullName;
660
661                                                 if (attrname == "System.Reflection.AssemblyCultureAttribute") {
662                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
663                                                 } else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
664                                                         version_res.Comments = cb.string_arg ();
665                                         }
666                                         break;
667                                 }
668                         }
669
670                         version_res.OriginalFilename = fileName;
671                         version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
672
673                         AddUnmanagedResource (version_res);
674                 }
675
676                 public ModuleBuilder GetDynamicModule (string name)
677                 {
678                         if (name == null)
679                                 throw new ArgumentNullException ("name");
680                         if (name.Length == 0)
681                                 throw new ArgumentException ("Empty name is not legal.", "name");
682
683                         if (modules != null)
684                                 for (int i = 0; i < modules.Length; ++i)
685                                         if (modules [i].name == name)
686                                                 return modules [i];
687                         return null;
688                 }
689
690                 public override Type[] GetExportedTypes ()
691                 {
692                         throw not_supported ();
693                 }
694
695                 public override FileStream GetFile (string name)
696                 {
697                         throw not_supported ();
698                 }
699
700                 public override FileStream[] GetFiles(bool getResourceModules) {
701                         throw not_supported ();
702                 }
703
704                 internal override Module[] GetModulesInternal () {
705                         if (modules == null)
706                                 return new Module [0];
707                         else
708                                 return (Module[])modules.Clone ();
709                 }
710
711                 internal override Type[] GetTypes (bool exportedOnly) {
712                         Type[] res = null;
713                         if (modules != null) {
714                                 for (int i = 0; i < modules.Length; ++i) {
715                                         Type[] types = modules [i].GetTypes ();
716                                         if (res == null)
717                                                 res = types;
718                                         else {
719                                                 Type[] tmp = new Type [res.Length + types.Length];
720                                                 Array.Copy (res, 0, tmp, 0, res.Length);
721                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
722                                         }
723                                 }
724                         }
725                         if (loaded_modules != null) {
726                                 for (int i = 0; i < loaded_modules.Length; ++i) {
727                                         Type[] types = loaded_modules [i].GetTypes ();
728                                         if (res == null)
729                                                 res = types;
730                                         else {
731                                                 Type[] tmp = new Type [res.Length + types.Length];
732                                                 Array.Copy (res, 0, tmp, 0, res.Length);
733                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
734                                         }
735                                 }
736                         }
737
738                         if (res != null) {
739                                 List<Exception> exceptions = null;
740                                 foreach (var type in res) {
741                                         if (type is TypeBuilder) {
742                                                 if (exceptions == null)
743                                                         exceptions = new List <Exception> ();
744                                                 exceptions.Add (new TypeLoadException (string.Format ("Type '{0}' is not finished", type.FullName))); 
745                                         }
746                                 }
747                                 if (exceptions != null)
748                                         throw new ReflectionTypeLoadException (new Type [exceptions.Count], exceptions.ToArray ());
749                         }
750                         
751                         return res == null ? Type.EmptyTypes : res;
752                 }
753
754                 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
755                         throw not_supported ();
756                 }
757
758                 public override string[] GetManifestResourceNames() {
759                         throw not_supported ();
760                 }
761
762                 public override Stream GetManifestResourceStream(string name) {
763                         throw not_supported ();
764                 }
765                 public override Stream GetManifestResourceStream(Type type, string name) {
766                         throw not_supported ();
767                 }
768
769                 internal bool IsSave {
770                         get {
771                                 return access != (uint)AssemblyBuilderAccess.Run;
772                         }
773                 }
774
775                 internal bool IsRun {
776                         get {
777                                 return access == (uint)AssemblyBuilderAccess.Run || access == (uint)AssemblyBuilderAccess.RunAndSave
778 #if NET_4_0
779                                          || access == (uint)AssemblyBuilderAccess.RunAndCollect
780 #endif
781                                 ;
782
783                         }
784                 }
785 /*
786                 internal bool IsCollectible {
787                         get {
788                                 return access == (uint)AssemblyBuilderAccess.RunAndCollect;
789                         }
790                 }
791 */
792                 internal string AssemblyDir {
793                         get {
794                                 return dir;
795                         }
796                 }
797
798                 /*
799                  * Mono extension. If this is set, the assembly can only contain one
800                  * module, access should be Save, and the saved image will not contain an
801                  * assembly manifest.
802                  */
803                 internal bool IsModuleOnly {
804                         get {
805                                 return is_module_only;
806                         }
807                         set {
808                                 is_module_only = value;
809                         }
810                 }
811
812                 ModuleBuilder manifest_module;
813
814                 //
815                 // MS.NET seems to return a ModuleBuilder when GetManifestModule () is called
816                 // on an assemblybuilder.
817                 //
818                 internal override Module GetManifestModule () {
819                         if (manifest_module == null)
820                                 manifest_module = DefineDynamicModule ("Default Dynamic Module");
821                         return manifest_module;
822                 }
823
824                 [MonoLimitation ("No support for PE32+ assemblies for AMD64 and IA64")]
825                 public 
826                 void Save (string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
827                 {
828                         this.peKind = portableExecutableKind;
829                         this.machine = imageFileMachine;
830
831                         if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || (peKind & PortableExecutableKinds.Unmanaged32Bit) != 0)
832                                 throw new NotImplementedException (peKind.ToString ());
833                         if (machine == ImageFileMachine.IA64 || machine == ImageFileMachine.AMD64)
834                                 throw new NotImplementedException (machine.ToString ());
835
836                         if (resource_writers != null) {
837                                 foreach (IResourceWriter writer in resource_writers) {
838                                         writer.Generate ();
839                                         writer.Close ();
840                                 }
841                         }
842
843                         // Create a main module if not already created
844                         ModuleBuilder mainModule = null;
845                         if (modules != null) {
846                                 foreach (ModuleBuilder module in modules)
847                                         if (module.FullyQualifiedName == assemblyFileName)
848                                                 mainModule = module;
849                         }
850                         if (mainModule == null)
851                                 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
852
853                         if (!is_module_only)
854                                 mainModule.IsMain = true;
855
856                         /* 
857                          * Create a new entry point if the one specified
858                          * by the user is in another module.
859                          */
860                         if ((entry_point != null) && entry_point.DeclaringType.Module != mainModule) {
861                                 Type[] paramTypes;
862                                 if (entry_point.GetParametersCount () == 1)
863                                         paramTypes = new Type [] { typeof (string) };
864                                 else
865                                         paramTypes = Type.EmptyTypes;
866
867                                 MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes);
868                                 ILGenerator ilgen = mb.GetILGenerator ();
869                                 if (paramTypes.Length == 1)
870                                         ilgen.Emit (OpCodes.Ldarg_0);
871                                 ilgen.Emit (OpCodes.Tailcall);
872                                 ilgen.Emit (OpCodes.Call, entry_point);
873                                 ilgen.Emit (OpCodes.Ret);
874
875                                 entry_point = mb;
876                         }
877
878                         if (version_res != null)
879                                 DefineVersionInfoResourceImpl (assemblyFileName);
880
881                         if (sn != null) {
882                                 // runtime needs to value to embed it into the assembly
883                                 public_key = sn.PublicKey;
884                         }
885
886                         foreach (ModuleBuilder module in modules)
887                                 if (module != mainModule)
888                                         module.Save ();
889
890                         // Write out the main module at the end, because it needs to
891                         // contain the hash of the other modules
892                         mainModule.Save ();
893
894                         if ((sn != null) && (sn.CanSign)) {
895                                 sn.Sign (System.IO.Path.Combine (this.AssemblyDir, assemblyFileName));
896                         }
897
898                         created = true;
899                 }
900
901                 public void Save (string assemblyFileName)
902                 {
903                         Save (assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
904                 }
905
906                 public void SetEntryPoint (MethodInfo entryMethod)
907                 {
908                         SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
909                 }
910
911                 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
912                 {
913                         if (entryMethod == null)
914                                 throw new ArgumentNullException ("entryMethod");
915                         if (entryMethod.DeclaringType.Assembly != this)
916                                 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
917
918                         entry_point = entryMethod;
919                         pekind = fileKind;
920                 }
921
922                 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) 
923                 {
924                         if (customBuilder == null)
925                                 throw new ArgumentNullException ("customBuilder");
926
927                         if (cattrs != null) {
928                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
929                                 cattrs.CopyTo (new_array, 0);
930                                 new_array [cattrs.Length] = customBuilder;
931                                 cattrs = new_array;
932                         } else {
933                                 cattrs = new CustomAttributeBuilder [1];
934                                 cattrs [0] = customBuilder;
935                         }
936                 }
937
938                 [ComVisible (true)]
939                 public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
940                         if (con == null)
941                                 throw new ArgumentNullException ("con");
942                         if (binaryAttribute == null)
943                                 throw new ArgumentNullException ("binaryAttribute");
944
945                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
946                 }
947
948                 private Exception not_supported () {
949                         // Strange message but this is what MS.NET prints...
950                         return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
951                 }
952
953                 private void check_name_and_filename (string name, string fileName,
954                                                                                           bool fileNeedsToExists) {
955                         if (name == null)
956                                 throw new ArgumentNullException ("name");
957                         if (fileName == null)
958                                 throw new ArgumentNullException ("fileName");
959                         if (name.Length == 0)
960                                 throw new ArgumentException ("Empty name is not legal.", "name");
961                         if (fileName.Length == 0)
962                                 throw new ArgumentException ("Empty file name is not legal.", "fileName");
963                         if (Path.GetFileName (fileName) != fileName)
964                                 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.", "fileName");
965
966                         // Resource files are created/searched under the assembly storage
967                         // directory
968                         string fullFileName = fileName;
969                         if (dir != null)
970                                 fullFileName = Path.Combine (dir, fileName);
971
972                         if (fileNeedsToExists && !File.Exists (fullFileName))
973                                 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
974
975                         if (resources != null) {
976                                 for (int i = 0; i < resources.Length; ++i) {
977                                         if (resources [i].filename == fullFileName)
978                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
979                                         if (resources [i].name == name)
980                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
981                                 }
982                         }
983
984                         if (modules != null) {
985                                 for (int i = 0; i < modules.Length; ++i) {
986                                         // Use fileName instead of fullFileName here
987                                         if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
988                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
989                                         if (modules [i].Name == name)
990                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
991                                 }
992                         }
993                 }
994
995                 private String create_assembly_version (String version) {
996                         String[] parts = version.Split ('.');
997                         int[] ver = new int [4] { 0, 0, 0, 0 };
998
999                         if ((parts.Length < 0) || (parts.Length > 4))
1000                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1001
1002                         for (int i = 0; i < parts.Length; ++i) {
1003                                 if (parts [i] == "*") {
1004                                         DateTime now = DateTime.Now;
1005
1006                                         if (i == 2) {
1007                                                 ver [2] = (now - new DateTime (2000, 1, 1)).Days;
1008                                                 if (parts.Length == 3)
1009                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1010                                         }
1011                                         else
1012                                                 if (i == 3)
1013                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1014                                         else
1015                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1016                                 }
1017                                 else {
1018                                         try {
1019                                                 ver [i] = Int32.Parse (parts [i]);
1020                                         }
1021                                         catch (FormatException) {
1022                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1023                                         }
1024                                 }
1025                         }
1026
1027                         return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];
1028                 }
1029
1030                 private string GetCultureString (string str)
1031                 {
1032                         return (str == "neutral" ? String.Empty : str);
1033                 }
1034
1035                 internal override AssemblyName UnprotectedGetName ()
1036                 {
1037                         AssemblyName an = base.UnprotectedGetName ();
1038                         if (sn != null) {
1039                                 an.SetPublicKey (sn.PublicKey);
1040                                 an.SetPublicKeyToken (sn.PublicKeyToken);
1041                         }
1042                         return an;
1043                 }
1044
1045                 /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
1046                 internal Type MakeGenericType (Type gtd, Type[] typeArguments)
1047                 {
1048                         return new MonoGenericClass (gtd, typeArguments);
1049                 }
1050
1051                 void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1052                 {
1053                         throw new NotImplementedException ();
1054                 }
1055
1056                 void _AssemblyBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1057                 {
1058                         throw new NotImplementedException ();
1059                 }
1060
1061                 void _AssemblyBuilder.GetTypeInfoCount (out uint pcTInfo)
1062                 {
1063                         throw new NotImplementedException ();
1064                 }
1065
1066                 void _AssemblyBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1067                 {
1068                         throw new NotImplementedException ();
1069                 }
1070
1071 #if NET_4_0
1072                 public override Type GetType (string name, bool throwOnError, bool ignoreCase)
1073                 {
1074                         if (name == null)
1075                                 throw new ArgumentNullException (name);
1076                         if (name.Length == 0)
1077                         throw new ArgumentException ("name", "Name cannot be empty");
1078
1079                         var res = InternalGetType (null, name, throwOnError, ignoreCase);
1080                         if (res is TypeBuilder) {
1081                                 if (throwOnError)
1082                                         throw new TypeLoadException (string.Format ("Could not load type '{0}' from assembly '{1}'", name, this.name));
1083                                 return null;
1084                         }
1085                         return res;
1086                 }
1087
1088                 public override Module GetModule (String name)
1089                 {
1090                         if (name == null)
1091                                 throw new ArgumentNullException ("name");
1092                         if (name.Length == 0)
1093                                 throw new ArgumentException ("Name can't be empty");
1094
1095                         if (modules == null)
1096                                 return null;
1097
1098                         foreach (Module module in modules) {
1099                                 if (module.ScopeName == name)
1100                                         return module;
1101                         }
1102
1103                         return null;
1104                 }
1105
1106                 public override Module[] GetModules (bool getResourceModules)
1107                 {
1108                         Module[] modules = GetModulesInternal ();
1109
1110                         if (!getResourceModules) {
1111                                 var result = new List<Module> (modules.Length);
1112                                 foreach (Module m in modules)
1113                                         if (!m.IsResource ())
1114                                                 result.Add (m);
1115                                 return result.ToArray ();
1116                         }
1117                         return modules;
1118                 }
1119
1120                 public override AssemblyName GetName (bool copiedName)
1121                 {
1122                         return base.GetName (copiedName);
1123                 }
1124
1125                 [MonoTODO ("This always returns an empty array")]
1126                 public override AssemblyName[] GetReferencedAssemblies () {
1127                         return GetReferencedAssemblies (this);
1128                 }
1129
1130                 public override Module[] GetLoadedModules (bool getResourceModules)
1131                 {
1132                         return GetModules (getResourceModules);
1133                 }
1134
1135                 //FIXME MS has issues loading satelite assemblies from SRE
1136                 public override Assembly GetSatelliteAssembly (CultureInfo culture)
1137                 {
1138                         return GetSatelliteAssembly (culture, null, true);
1139                 }
1140
1141                 //FIXME MS has issues loading satelite assemblies from SRE
1142                 public override Assembly GetSatelliteAssembly (CultureInfo culture, Version version)
1143                 {
1144                         return GetSatelliteAssembly (culture, version, true);
1145                 }
1146
1147                 public override Module ManifestModule {
1148                         get {
1149                                 return GetManifestModule ();
1150                         }
1151                 }
1152
1153                 public override bool GlobalAssemblyCache {
1154                         get {
1155                                 return false;
1156                         }
1157                 }
1158
1159                 public override bool IsDynamic {
1160                         get { return true; }
1161                 }
1162
1163                 public override bool Equals (object obj)
1164                 {
1165                         return base.Equals (obj);
1166                 }
1167
1168                 public override int GetHashCode ()
1169                 {
1170                         return base.GetHashCode ();
1171                 }
1172
1173                 public override bool IsDefined (Type attributeType, bool inherit)
1174                 {
1175                         return base.IsDefined (attributeType, inherit);
1176                 }
1177
1178                 public override object[] GetCustomAttributes (bool inherit)
1179                 {
1180                         return base.GetCustomAttributes (inherit);
1181                 }
1182
1183                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
1184                 {
1185                         return base.GetCustomAttributes (attributeType, inherit);
1186                 }
1187
1188                 public override string FullName {
1189                         get { return base.FullName; }
1190                 }
1191 #endif
1192         }
1193 }
1194 #endif