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