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