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