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