Merge pull request #1375 from echampet/cleanup
[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 #if NET_4_5
462                 public static AssemblyBuilder DefineDynamicAssembly (AssemblyName name, AssemblyBuilderAccess access)
463                 {
464                         if (name == null)
465                                 throw new ArgumentNullException ("name");
466
467                         return new AssemblyBuilder (name, null, access, false);
468                 }
469 #endif
470
471                 public ModuleBuilder DefineDynamicModule (string name)
472                 {
473                         return DefineDynamicModule (name, name, false, true);
474                 }
475
476                 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
477                 {
478                         return DefineDynamicModule (name, name, emitSymbolInfo, true);
479                 }
480
481                 public ModuleBuilder DefineDynamicModule(string name, string fileName)
482                 {
483                         return DefineDynamicModule (name, fileName, false, false);
484                 }
485
486                 public ModuleBuilder DefineDynamicModule (string name, string fileName,
487                                                           bool emitSymbolInfo)
488                 {
489                         return DefineDynamicModule (name, fileName, emitSymbolInfo, false);
490                 }
491
492                 private ModuleBuilder DefineDynamicModule (string name, string fileName, bool emitSymbolInfo, bool transient)
493                 {
494                         check_name_and_filename (name, fileName, false);
495
496                         if (!transient) {
497                                 if (Path.GetExtension (fileName) == String.Empty)
498                                         throw new ArgumentException ("Module file name '" + fileName + "' must have file extension.");
499                                 if (!IsSave)
500                                         throw new NotSupportedException ("Persistable modules are not supported in a dynamic assembly created with AssemblyBuilderAccess.Run");
501                                 if (created)
502                                         throw new InvalidOperationException ("Assembly was already saved.");
503                         }
504
505                         ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, transient);
506
507                         if ((modules != null) && is_module_only)
508                                 throw new InvalidOperationException ("A module-only assembly can only contain one module.");
509
510                         if (modules != null) {
511                                 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
512                                 System.Array.Copy(modules, new_modules, modules.Length);
513                                 modules = new_modules;
514                         } else {
515                                 modules = new ModuleBuilder [1];
516                         }
517                         modules [modules.Length - 1] = r;
518                         return r;
519                 }
520
521                 public IResourceWriter DefineResource (string name, string description, string fileName)
522                 {
523                         return DefineResource (name, description, fileName, ResourceAttributes.Public);
524                 }
525
526                 public IResourceWriter DefineResource (string name, string description,
527                                                        string fileName, ResourceAttributes attribute)
528                 {
529                         IResourceWriter writer;
530
531                         // description seems to be ignored
532                         AddResourceFile (name, fileName, attribute, false);
533                         writer = new ResourceWriter (fileName);
534                         if (resource_writers == null)
535                                 resource_writers = new ArrayList ();
536                         resource_writers.Add (writer);
537                         return writer;
538                 }
539
540                 private void AddUnmanagedResource (Win32Resource res) {
541                         MemoryStream ms = new MemoryStream ();
542                         res.WriteTo (ms);
543
544                         if (win32_resources != null) {
545                                 MonoWin32Resource[] new_res = new MonoWin32Resource [win32_resources.Length + 1];
546                                 System.Array.Copy (win32_resources, new_res, win32_resources.Length);
547                                 win32_resources = new_res;
548                         }
549                         else
550                                 win32_resources = new MonoWin32Resource [1];
551
552                         win32_resources [win32_resources.Length - 1] = new MonoWin32Resource (res.Type.Id, res.Name.Id, res.Language, ms.ToArray ());
553                 }
554
555                 [MonoTODO ("Not currently implemenented")]
556                 public void DefineUnmanagedResource (byte[] resource)
557                 {
558                         if (resource == null)
559                                 throw new ArgumentNullException ("resource");
560                         if (native_resource != NativeResourceType.None)
561                                 throw new ArgumentException ("Native resource has already been defined.");
562
563                         // avoid definition of more than one unmanaged resource
564                         native_resource = NativeResourceType.Unmanaged;
565
566                         /*
567                          * The format of the argument byte array is not documented
568                          * so this method is impossible to implement.
569                          *
570                          * https://connect.microsoft.com/VisualStudio/feedback/details/95784/fatal-assemblybuilder-defineunmanagedresource-byte-and-modulebuilder-defineunmanagedresource-byte-bugs-renders-them-useless
571                          */
572
573                         throw new NotImplementedException ();
574                 }
575
576                 public void DefineUnmanagedResource (string resourceFileName)
577                 {
578                         if (resourceFileName == null)
579                                 throw new ArgumentNullException ("resourceFileName");
580                         if (resourceFileName.Length == 0)
581                                 throw new ArgumentException ("resourceFileName");
582                         if (!File.Exists (resourceFileName) || Directory.Exists (resourceFileName))
583                                 throw new FileNotFoundException ("File '" + resourceFileName + "' does not exist or is a directory.");
584                         if (native_resource != NativeResourceType.None)
585                                 throw new ArgumentException ("Native resource has already been defined.");
586
587                         // avoid definition of more than one unmanaged resource
588                         native_resource = NativeResourceType.Unmanaged;
589
590                         using (FileStream fs = new FileStream (resourceFileName, FileMode.Open, FileAccess.Read)) {
591                                 Win32ResFileReader reader = new Win32ResFileReader (fs);
592
593                                 foreach (Win32EncodedResource res in reader.ReadResources ()) {
594                                         if (res.Name.IsName || res.Type.IsName)
595                                                 throw new InvalidOperationException ("resource files with named resources or non-default resource types are not supported.");
596
597                                         AddUnmanagedResource (res);
598                                 }
599                         }
600                 }
601
602                 public void DefineVersionInfoResource ()
603                 {
604                         if (native_resource != NativeResourceType.None)
605                                 throw new ArgumentException ("Native resource has already been defined.");
606
607                         // avoid definition of more than one unmanaged resource
608                         native_resource = NativeResourceType.Assembly;
609
610                         version_res = new Win32VersionResource (1, 0, false);
611                 }
612
613                 public void DefineVersionInfoResource (string product, string productVersion,
614                                                        string company, string copyright, string trademark)
615                 {
616                         if (native_resource != NativeResourceType.None)
617                                 throw new ArgumentException ("Native resource has already been defined.");
618
619                         // avoid definition of more than one unmanaged resource
620                         native_resource = NativeResourceType.Explicit;
621
622                         /*
623                          * We can only create the resource later, when the file name and
624                          * the binary version is known.
625                          */
626
627                         version_res = new Win32VersionResource (1, 0, false);
628                         version_res.ProductName = product != null ? product : " ";
629                         version_res.ProductVersion = productVersion != null ? productVersion : " ";
630                         version_res.CompanyName = company != null ? company : " ";
631                         version_res.LegalCopyright = copyright != null ? copyright : " ";
632                         version_res.LegalTrademarks = trademark != null ? trademark : " ";
633                 }
634
635                 private void DefineVersionInfoResourceImpl (string fileName)
636                 {
637                         if (versioninfo_culture != null)
638                                 version_res.FileLanguage = new CultureInfo (versioninfo_culture).LCID;
639                         version_res.Version = version == null ? "0.0.0.0" : version;
640
641                         if (cattrs != null) {
642                                 switch (native_resource) {
643                                 case NativeResourceType.Assembly:
644                                         foreach (CustomAttributeBuilder cb in cattrs) {
645                                                 string attrname = cb.Ctor.ReflectedType.FullName;
646
647                                                 if (attrname == "System.Reflection.AssemblyProductAttribute")
648                                                         version_res.ProductName = cb.string_arg ();
649                                                 else if (attrname == "System.Reflection.AssemblyCompanyAttribute")
650                                                         version_res.CompanyName = cb.string_arg ();
651                                                 else if (attrname == "System.Reflection.AssemblyCopyrightAttribute")
652                                                         version_res.LegalCopyright = cb.string_arg ();
653                                                 else if (attrname == "System.Reflection.AssemblyTrademarkAttribute")
654                                                         version_res.LegalTrademarks = cb.string_arg ();
655                                                 else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
656                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
657                                                 } else if (attrname == "System.Reflection.AssemblyFileVersionAttribute") {
658                                                         version_res.FileVersion = cb.string_arg ();
659                                                 } else if (attrname == "System.Reflection.AssemblyInformationalVersionAttribute")
660                                                         version_res.ProductVersion = cb.string_arg ();
661                                                 else if (attrname == "System.Reflection.AssemblyTitleAttribute")
662                                                         version_res.FileDescription = cb.string_arg ();
663                                                 else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
664                                                         version_res.Comments = cb.string_arg ();
665                                         }
666                                         break;
667                                 case NativeResourceType.Explicit:
668                                         foreach (CustomAttributeBuilder cb in cattrs) {
669                                                 string attrname = cb.Ctor.ReflectedType.FullName;
670
671                                                 if (attrname == "System.Reflection.AssemblyCultureAttribute") {
672                                                         version_res.FileLanguage = new CultureInfo (cb.string_arg ()).LCID;
673                                                 } else if (attrname == "System.Reflection.AssemblyDescriptionAttribute")
674                                                         version_res.Comments = cb.string_arg ();
675                                         }
676                                         break;
677                                 }
678                         }
679
680                         version_res.OriginalFilename = fileName;
681                         version_res.InternalName = Path.GetFileNameWithoutExtension (fileName);
682
683                         AddUnmanagedResource (version_res);
684                 }
685
686                 public ModuleBuilder GetDynamicModule (string name)
687                 {
688                         if (name == null)
689                                 throw new ArgumentNullException ("name");
690                         if (name.Length == 0)
691                                 throw new ArgumentException ("Empty name is not legal.", "name");
692
693                         if (modules != null)
694                                 for (int i = 0; i < modules.Length; ++i)
695                                         if (modules [i].name == name)
696                                                 return modules [i];
697                         return null;
698                 }
699
700                 public override Type[] GetExportedTypes ()
701                 {
702                         throw not_supported ();
703                 }
704
705                 public override FileStream GetFile (string name)
706                 {
707                         throw not_supported ();
708                 }
709
710                 public override FileStream[] GetFiles(bool getResourceModules) {
711                         throw not_supported ();
712                 }
713
714                 internal override Module[] GetModulesInternal () {
715                         if (modules == null)
716                                 return new Module [0];
717                         else
718                                 return (Module[])modules.Clone ();
719                 }
720
721                 internal override Type[] GetTypes (bool exportedOnly) {
722                         Type[] res = null;
723                         if (modules != null) {
724                                 for (int i = 0; i < modules.Length; ++i) {
725                                         Type[] types = modules [i].GetTypes ();
726                                         if (res == null)
727                                                 res = types;
728                                         else {
729                                                 Type[] tmp = new Type [res.Length + types.Length];
730                                                 Array.Copy (res, 0, tmp, 0, res.Length);
731                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
732                                         }
733                                 }
734                         }
735                         if (loaded_modules != null) {
736                                 for (int i = 0; i < loaded_modules.Length; ++i) {
737                                         Type[] types = loaded_modules [i].GetTypes ();
738                                         if (res == null)
739                                                 res = types;
740                                         else {
741                                                 Type[] tmp = new Type [res.Length + types.Length];
742                                                 Array.Copy (res, 0, tmp, 0, res.Length);
743                                                 Array.Copy (types, 0, tmp, res.Length, types.Length);
744                                         }
745                                 }
746                         }
747
748                         if (res != null) {
749                                 List<Exception> exceptions = null;
750                                 foreach (var type in res) {
751                                         if (type is TypeBuilder) {
752                                                 if (exceptions == null)
753                                                         exceptions = new List <Exception> ();
754                                                 exceptions.Add (new TypeLoadException (string.Format ("Type '{0}' is not finished", type.FullName))); 
755                                         }
756                                 }
757                                 if (exceptions != null)
758                                         throw new ReflectionTypeLoadException (new Type [exceptions.Count], exceptions.ToArray ());
759                         }
760                         
761                         return res == null ? Type.EmptyTypes : res;
762                 }
763
764                 public override ManifestResourceInfo GetManifestResourceInfo(string resourceName) {
765                         throw not_supported ();
766                 }
767
768                 public override string[] GetManifestResourceNames() {
769                         throw not_supported ();
770                 }
771
772                 public override Stream GetManifestResourceStream(string name) {
773                         throw not_supported ();
774                 }
775                 public override Stream GetManifestResourceStream(Type type, string name) {
776                         throw not_supported ();
777                 }
778
779                 internal bool IsSave {
780                         get {
781                                 return access != (uint)AssemblyBuilderAccess.Run;
782                         }
783                 }
784
785                 internal bool IsRun {
786                         get {
787                                 return access == (uint)AssemblyBuilderAccess.Run || access == (uint)AssemblyBuilderAccess.RunAndSave
788 #if NET_4_0
789                                          || access == (uint)AssemblyBuilderAccess.RunAndCollect
790 #endif
791                                 ;
792
793                         }
794                 }
795 /*
796                 internal bool IsCollectible {
797                         get {
798                                 return access == (uint)AssemblyBuilderAccess.RunAndCollect;
799                         }
800                 }
801 */
802                 internal string AssemblyDir {
803                         get {
804                                 return dir;
805                         }
806                 }
807
808                 /*
809                  * Mono extension. If this is set, the assembly can only contain one
810                  * module, access should be Save, and the saved image will not contain an
811                  * assembly manifest.
812                  */
813                 internal bool IsModuleOnly {
814                         get {
815                                 return is_module_only;
816                         }
817                         set {
818                                 is_module_only = value;
819                         }
820                 }
821
822                 ModuleBuilder manifest_module;
823
824                 //
825                 // MS.NET seems to return a ModuleBuilder when GetManifestModule () is called
826                 // on an assemblybuilder.
827                 //
828                 internal override Module GetManifestModule () {
829                         if (manifest_module == null)
830                                 manifest_module = DefineDynamicModule ("Default Dynamic Module");
831                         return manifest_module;
832                 }
833
834                 [MonoLimitation ("No support for PE32+ assemblies for AMD64 and IA64")]
835                 public 
836                 void Save (string assemblyFileName, PortableExecutableKinds portableExecutableKind, ImageFileMachine imageFileMachine)
837                 {
838                         this.peKind = portableExecutableKind;
839                         this.machine = imageFileMachine;
840
841                         if ((peKind & PortableExecutableKinds.PE32Plus) != 0 || (peKind & PortableExecutableKinds.Unmanaged32Bit) != 0)
842                                 throw new NotImplementedException (peKind.ToString ());
843                         if (machine == ImageFileMachine.IA64 || machine == ImageFileMachine.AMD64)
844                                 throw new NotImplementedException (machine.ToString ());
845
846                         if (resource_writers != null) {
847                                 foreach (IResourceWriter writer in resource_writers) {
848                                         writer.Generate ();
849                                         writer.Close ();
850                                 }
851                         }
852
853                         // Create a main module if not already created
854                         ModuleBuilder mainModule = null;
855                         if (modules != null) {
856                                 foreach (ModuleBuilder module in modules)
857                                         if (module.FullyQualifiedName == assemblyFileName)
858                                                 mainModule = module;
859                         }
860                         if (mainModule == null)
861                                 mainModule = DefineDynamicModule ("RefEmit_OnDiskManifestModule", assemblyFileName);
862
863                         if (!is_module_only)
864                                 mainModule.IsMain = true;
865
866                         /* 
867                          * Create a new entry point if the one specified
868                          * by the user is in another module.
869                          */
870                         if ((entry_point != null) && entry_point.DeclaringType.Module != mainModule) {
871                                 Type[] paramTypes;
872                                 if (entry_point.GetParametersCount () == 1)
873                                         paramTypes = new Type [] { typeof (string) };
874                                 else
875                                         paramTypes = Type.EmptyTypes;
876
877                                 MethodBuilder mb = mainModule.DefineGlobalMethod ("__EntryPoint$", MethodAttributes.Static|MethodAttributes.PrivateScope, entry_point.ReturnType, paramTypes);
878                                 ILGenerator ilgen = mb.GetILGenerator ();
879                                 if (paramTypes.Length == 1)
880                                         ilgen.Emit (OpCodes.Ldarg_0);
881                                 ilgen.Emit (OpCodes.Tailcall);
882                                 ilgen.Emit (OpCodes.Call, entry_point);
883                                 ilgen.Emit (OpCodes.Ret);
884
885                                 entry_point = mb;
886                         }
887
888                         if (version_res != null)
889                                 DefineVersionInfoResourceImpl (assemblyFileName);
890
891                         if (sn != null) {
892                                 // runtime needs to value to embed it into the assembly
893                                 public_key = sn.PublicKey;
894                         }
895
896                         foreach (ModuleBuilder module in modules)
897                                 if (module != mainModule)
898                                         module.Save ();
899
900                         // Write out the main module at the end, because it needs to
901                         // contain the hash of the other modules
902                         mainModule.Save ();
903
904                         if ((sn != null) && (sn.CanSign)) {
905                                 sn.Sign (System.IO.Path.Combine (this.AssemblyDir, assemblyFileName));
906                         }
907
908                         created = true;
909                 }
910
911                 public void Save (string assemblyFileName)
912                 {
913                         Save (assemblyFileName, PortableExecutableKinds.ILOnly, ImageFileMachine.I386);
914                 }
915
916                 public void SetEntryPoint (MethodInfo entryMethod)
917                 {
918                         SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
919                 }
920
921                 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
922                 {
923                         if (entryMethod == null)
924                                 throw new ArgumentNullException ("entryMethod");
925                         if (entryMethod.DeclaringType.Assembly != this)
926                                 throw new InvalidOperationException ("Entry method is not defined in the same assembly.");
927
928                         entry_point = entryMethod;
929                         pekind = fileKind;
930                 }
931
932                 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) 
933                 {
934                         if (customBuilder == null)
935                                 throw new ArgumentNullException ("customBuilder");
936
937                         if (cattrs != null) {
938                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
939                                 cattrs.CopyTo (new_array, 0);
940                                 new_array [cattrs.Length] = customBuilder;
941                                 cattrs = new_array;
942                         } else {
943                                 cattrs = new CustomAttributeBuilder [1];
944                                 cattrs [0] = customBuilder;
945                         }
946                 }
947
948                 [ComVisible (true)]
949                 public void SetCustomAttribute ( ConstructorInfo con, byte[] binaryAttribute) {
950                         if (con == null)
951                                 throw new ArgumentNullException ("con");
952                         if (binaryAttribute == null)
953                                 throw new ArgumentNullException ("binaryAttribute");
954
955                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
956                 }
957
958                 private Exception not_supported () {
959                         // Strange message but this is what MS.NET prints...
960                         return new NotSupportedException ("The invoked member is not supported in a dynamic module.");
961                 }
962
963                 private void check_name_and_filename (string name, string fileName,
964                                                                                           bool fileNeedsToExists) {
965                         if (name == null)
966                                 throw new ArgumentNullException ("name");
967                         if (fileName == null)
968                                 throw new ArgumentNullException ("fileName");
969                         if (name.Length == 0)
970                                 throw new ArgumentException ("Empty name is not legal.", "name");
971                         if (fileName.Length == 0)
972                                 throw new ArgumentException ("Empty file name is not legal.", "fileName");
973                         if (Path.GetFileName (fileName) != fileName)
974                                 throw new ArgumentException ("fileName '" + fileName + "' must not include a path.", "fileName");
975
976                         // Resource files are created/searched under the assembly storage
977                         // directory
978                         string fullFileName = fileName;
979                         if (dir != null)
980                                 fullFileName = Path.Combine (dir, fileName);
981
982                         if (fileNeedsToExists && !File.Exists (fullFileName))
983                                 throw new FileNotFoundException ("Could not find file '" + fileName + "'");
984
985                         if (resources != null) {
986                                 for (int i = 0; i < resources.Length; ++i) {
987                                         if (resources [i].filename == fullFileName)
988                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
989                                         if (resources [i].name == name)
990                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
991                                 }
992                         }
993
994                         if (modules != null) {
995                                 for (int i = 0; i < modules.Length; ++i) {
996                                         // Use fileName instead of fullFileName here
997                                         if (!modules [i].IsTransient () && (modules [i].FileName == fileName))
998                                                 throw new ArgumentException ("Duplicate file name '" + fileName + "'");
999                                         if (modules [i].Name == name)
1000                                                 throw new ArgumentException ("Duplicate name '" + name + "'");
1001                                 }
1002                         }
1003                 }
1004
1005                 private String create_assembly_version (String version) {
1006                         String[] parts = version.Split ('.');
1007                         int[] ver = new int [4] { 0, 0, 0, 0 };
1008
1009                         if ((parts.Length < 0) || (parts.Length > 4))
1010                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1011
1012                         for (int i = 0; i < parts.Length; ++i) {
1013                                 if (parts [i] == "*") {
1014                                         DateTime now = DateTime.Now;
1015
1016                                         if (i == 2) {
1017                                                 ver [2] = (now - new DateTime (2000, 1, 1)).Days;
1018                                                 if (parts.Length == 3)
1019                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1020                                         }
1021                                         else
1022                                                 if (i == 3)
1023                                                         ver [3] = (now.Second + (now.Minute * 60) + (now.Hour * 3600)) / 2;
1024                                         else
1025                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1026                                 }
1027                                 else {
1028                                         try {
1029                                                 ver [i] = Int32.Parse (parts [i]);
1030                                         }
1031                                         catch (FormatException) {
1032                                                 throw new ArgumentException ("The version specified '" + version + "' is invalid");
1033                                         }
1034                                 }
1035                         }
1036
1037                         return ver [0] + "." + ver [1] + "." + ver [2] + "." + ver [3];
1038                 }
1039
1040                 private string GetCultureString (string str)
1041                 {
1042                         return (str == "neutral" ? String.Empty : str);
1043                 }
1044
1045                 internal override AssemblyName UnprotectedGetName ()
1046                 {
1047                         AssemblyName an = base.UnprotectedGetName ();
1048                         if (sn != null) {
1049                                 an.SetPublicKey (sn.PublicKey);
1050                                 an.SetPublicKeyToken (sn.PublicKeyToken);
1051                         }
1052                         return an;
1053                 }
1054
1055                 /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
1056                 internal Type MakeGenericType (Type gtd, Type[] typeArguments)
1057                 {
1058                         return new MonoGenericClass (gtd, typeArguments);
1059                 }
1060
1061                 void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
1062                 {
1063                         throw new NotImplementedException ();
1064                 }
1065
1066                 void _AssemblyBuilder.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
1067                 {
1068                         throw new NotImplementedException ();
1069                 }
1070
1071                 void _AssemblyBuilder.GetTypeInfoCount (out uint pcTInfo)
1072                 {
1073                         throw new NotImplementedException ();
1074                 }
1075
1076                 void _AssemblyBuilder.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams, IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
1077                 {
1078                         throw new NotImplementedException ();
1079                 }
1080
1081 #if NET_4_0
1082                 public override Type GetType (string name, bool throwOnError, bool ignoreCase)
1083                 {
1084                         if (name == null)
1085                                 throw new ArgumentNullException (name);
1086                         if (name.Length == 0)
1087                         throw new ArgumentException ("name", "Name cannot be empty");
1088
1089                         var res = InternalGetType (null, name, throwOnError, ignoreCase);
1090                         if (res is TypeBuilder) {
1091                                 if (throwOnError)
1092                                         throw new TypeLoadException (string.Format ("Could not load type '{0}' from assembly '{1}'", name, this.name));
1093                                 return null;
1094                         }
1095                         return res;
1096                 }
1097
1098                 public override Module GetModule (String name)
1099                 {
1100                         if (name == null)
1101                                 throw new ArgumentNullException ("name");
1102                         if (name.Length == 0)
1103                                 throw new ArgumentException ("Name can't be empty");
1104
1105                         if (modules == null)
1106                                 return null;
1107
1108                         foreach (Module module in modules) {
1109                                 if (module.ScopeName == name)
1110                                         return module;
1111                         }
1112
1113                         return null;
1114                 }
1115
1116                 public override Module[] GetModules (bool getResourceModules)
1117                 {
1118                         Module[] modules = GetModulesInternal ();
1119
1120                         if (!getResourceModules) {
1121                                 var result = new List<Module> (modules.Length);
1122                                 foreach (Module m in modules)
1123                                         if (!m.IsResource ())
1124                                                 result.Add (m);
1125                                 return result.ToArray ();
1126                         }
1127                         return modules;
1128                 }
1129
1130                 public override AssemblyName GetName (bool copiedName)
1131                 {
1132                         return base.GetName (copiedName);
1133                 }
1134
1135                 [MonoTODO ("This always returns an empty array")]
1136                 public override AssemblyName[] GetReferencedAssemblies () {
1137                         return GetReferencedAssemblies (this);
1138                 }
1139
1140                 public override Module[] GetLoadedModules (bool getResourceModules)
1141                 {
1142                         return GetModules (getResourceModules);
1143                 }
1144
1145                 //FIXME MS has issues loading satelite assemblies from SRE
1146                 public override Assembly GetSatelliteAssembly (CultureInfo culture)
1147                 {
1148                         return GetSatelliteAssembly (culture, null, true);
1149                 }
1150
1151                 //FIXME MS has issues loading satelite assemblies from SRE
1152                 public override Assembly GetSatelliteAssembly (CultureInfo culture, Version version)
1153                 {
1154                         return GetSatelliteAssembly (culture, version, true);
1155                 }
1156
1157                 public override Module ManifestModule {
1158                         get {
1159                                 return GetManifestModule ();
1160                         }
1161                 }
1162
1163                 public override bool GlobalAssemblyCache {
1164                         get {
1165                                 return false;
1166                         }
1167                 }
1168
1169                 public override bool IsDynamic {
1170                         get { return true; }
1171                 }
1172
1173                 public override bool Equals (object obj)
1174                 {
1175                         return base.Equals (obj);
1176                 }
1177
1178                 public override int GetHashCode ()
1179                 {
1180                         return base.GetHashCode ();
1181                 }
1182
1183                 public override bool IsDefined (Type attributeType, bool inherit)
1184                 {
1185                         return base.IsDefined (attributeType, inherit);
1186                 }
1187
1188                 public override object[] GetCustomAttributes (bool inherit)
1189                 {
1190                         return base.GetCustomAttributes (inherit);
1191                 }
1192
1193                 public override object[] GetCustomAttributes (Type attributeType, bool inherit)
1194                 {
1195                         return base.GetCustomAttributes (attributeType, inherit);
1196                 }
1197
1198                 public override string FullName {
1199                         get { return base.FullName; }
1200                 }
1201 #endif
1202         }
1203 }
1204 #endif