2003-02-07 Martin Baulig <martin@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 using System;
11 using System.Reflection;
12 using System.Resources;
13 using System.IO;
14 using System.Security.Policy;
15 using System.Runtime.Serialization;
16 using System.Globalization;
17 using System.Runtime.CompilerServices;
18 using System.Collections;
19
20 namespace System.Reflection.Emit {
21
22         internal struct MonoResource {
23                 public byte[] data;
24                 public string name;
25                 public string filename;
26                 public ResourceAttributes attrs;
27         }
28
29         public sealed class AssemblyBuilder : Assembly {
30                 private IntPtr dynamic_assembly;
31                 private MethodInfo entry_point;
32                 private ModuleBuilder[] modules;
33                 private string name;
34                 private string dir;
35                 private CustomAttributeBuilder[] cattrs;
36                 private MonoResource[] resources;
37                 string keyfile;
38                 string version;
39                 string culture;
40                 uint algid;
41                 uint flags;
42                 PEFileKinds pekind = PEFileKinds.Dll;
43                 bool delay_sign;
44                 internal Type corlib_object_type = typeof (System.Object);
45                 internal Type corlib_value_type = typeof (System.ValueType);
46                 internal Type corlib_enum_type = typeof (System.Enum);
47                 private int[] table_indexes;
48                 internal ArrayList methods;
49                 Hashtable us_string_cache = new Hashtable ();
50
51                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
52                 private static extern void basic_init (AssemblyBuilder ab);
53                 
54                 internal AssemblyBuilder (AssemblyName n, string directory, AssemblyBuilderAccess access) {
55                         name = n.Name;
56                         dir = directory;
57                         basic_init (this);
58                 }
59
60                 internal int get_next_table_index (object obj, int table, bool inc) {
61                         if (table_indexes == null) {
62                                 table_indexes = new int [64];
63                                 for (int i=0; i < 64; ++i)
64                                         table_indexes [i] = 1;
65                                 /* allow room for .<Module> in TypeDef table */
66                                 table_indexes [0x02] = 2;
67                         }
68                         // Console.WriteLine ("getindex for table "+table.ToString()+" got "+table_indexes [table].ToString());
69                         if (inc) {
70                                 if ((table == 0x06) && (methods != null))
71                                         methods.Add (obj);
72                                 return table_indexes [table]++;
73                         }
74                         return table_indexes [table];
75                 }
76
77                 public override string CodeBase {
78                         get {
79                                 return null;
80                         }
81                 }
82                 
83                 public override MethodInfo EntryPoint {
84                         get {
85                                 return entry_point;
86                         }
87                 }
88
89                 public override string Location {
90                         get {
91                                 return null;
92                         }
93                 }
94
95                 public void AddResourceFile (string name, string fileName)
96                 {
97                         AddResourceFile (name, fileName, ResourceAttributes.Public);
98                 }
99
100                 public void AddResourceFile (string name, string fileName, ResourceAttributes attribute)
101                 {
102                         if (resources != null) {
103                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
104                                 System.Array.Copy(resources, new_r, resources.Length);
105                                 resources = new_r;
106                         } else {
107                                 resources = new MonoResource [1];
108                         }
109                         int p = resources.Length - 1;
110                         resources [p].name = name;
111                         resources [p].filename = fileName;
112                         resources [p].attrs = attribute;
113                 }
114
115                 public void EmbedResourceFile (string name, string fileName)
116                 {
117                         EmbedResourceFile (name, fileName, ResourceAttributes.Public);
118                 }
119
120                 public void EmbedResourceFile (string name, string fileName, ResourceAttributes attribute)
121                 {
122                         if (resources != null) {
123                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
124                                 System.Array.Copy(resources, new_r, resources.Length);
125                                 resources = new_r;
126                         } else {
127                                 resources = new MonoResource [1];
128                         }
129                         int p = resources.Length - 1;
130                         resources [p].name = name;
131                         resources [p].attrs = attribute;
132                         try {
133                                 FileStream s = new FileStream (fileName, FileMode.Open, FileAccess.Read);
134                                 long len = s.Length;
135                                 resources [p].data = new byte [len];
136                                 s.Read (resources [p].data, 0, (int)len);
137                                 s.Close ();
138                         } catch {
139                                 /* do something */
140                         }
141                 }
142
143                 internal void EmbedResource (string name, byte[] blob, ResourceAttributes attribute)
144                 {
145                         if (resources != null) {
146                                 MonoResource[] new_r = new MonoResource [resources.Length + 1];
147                                 System.Array.Copy(resources, new_r, resources.Length);
148                                 resources = new_r;
149                         } else {
150                                 resources = new MonoResource [1];
151                         }
152                         int p = resources.Length - 1;
153                         resources [p].name = name;
154                         resources [p].attrs = attribute;
155                         resources [p].data = blob;
156                 }
157
158                 public ModuleBuilder DefineDynamicModule (string name)
159                 {
160                         return DefineDynamicModule (name, name, false);
161                 }
162
163                 public ModuleBuilder DefineDynamicModule (string name, bool emitSymbolInfo)
164                 {
165                         return DefineDynamicModule (name, name, emitSymbolInfo);
166                 }
167
168                 public ModuleBuilder DefineDynamicModule(string name, string fileName)
169                 {
170                         return DefineDynamicModule (name, fileName, false);
171                 }
172
173                 public ModuleBuilder DefineDynamicModule (string name, string fileName,
174                                                           bool emitSymbolInfo)
175                 {
176                         ModuleBuilder r = new ModuleBuilder (this, name, fileName, emitSymbolInfo, modules == null);
177
178                         if (modules != null) {
179                                 ModuleBuilder[] new_modules = new ModuleBuilder [modules.Length + 1];
180                                 System.Array.Copy(modules, new_modules, modules.Length);
181                                 new_modules [modules.Length] = r;
182                                 modules = new_modules;
183                         } else {
184                                 modules = new ModuleBuilder [1];
185                                 modules [0] = r;
186                         }
187                         return r;
188                 }
189
190                 public IResourceWriter DefineResource (string name, string description, string fileName)
191                 {
192                         return DefineResource (name, description, fileName, ResourceAttributes.Public);
193                 }
194
195                 public IResourceWriter DefineResource (string name, string description,
196                                                        string fileName, ResourceAttributes attribute)
197                 {
198                         return null;
199                 }
200
201                 public void DefineUnmanagedResource (byte[] resource)
202                 {
203                 }
204
205                 public void DefineUnmanagedResource (string resourceFileName)
206                 {
207                 }
208
209                 public void DefineVersionInfoResource ()
210                 {
211                 }
212
213                 public void DefineVersionInfoResource (string product, string productVersion,
214                                                        string company, string copyright, string trademark)
215                 {
216                 }
217
218                 public ModuleBuilder GetDynamicModule (string name)
219                 {
220                         return null;
221                 }
222
223                 public override Type[] GetExportedTypes ()
224                 {
225                         return null;
226                 }
227
228                 public override FileStream GetFile (string name)
229                 {
230                         return null;
231                 }
232
233                 /*public virtual FileStream[] GetFiles() {
234                         return null;
235                 }
236                 public override FileStream[] GetFiles(bool getResourceModules) {
237                         return null;
238                 }*/
239
240                 /*public virtual ManifestResourceInfo GetManifestResourceInfo(string resourceName)
241                   {
242                         return null;
243                 }
244                 public virtual string[] GetManifestResourceNames() {
245                         return null;
246                 }
247                 public virtual Stream GetManifestResourceStream(string name) {
248                         return null;
249                 }
250                 public virtual Stream GetManifestResourceStream(Type type, string name) {
251                         return null;
252                 }*/
253
254                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
255                 private static extern int getUSIndex (AssemblyBuilder ab, string str);
256
257                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
258                 private static extern int getToken (AssemblyBuilder ab, object obj);
259
260                 internal int GetToken (string str) {
261                         if (us_string_cache.Contains (str))
262                                 return (int)us_string_cache [str];
263                         int result = getUSIndex (this, str);
264                         us_string_cache [str] = result;
265                         return result;
266                 }
267                 
268                 internal int GetToken (MemberInfo member) {
269                         return getToken (this, member);
270                 }
271
272                 internal int GetToken (SignatureHelper helper) {
273                         return getToken (this, helper);
274                 }
275
276                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
277                 private static extern int getDataChunk (AssemblyBuilder ab, byte[] buf, int offset);
278
279                 public void Save (string assemblyFileName)
280                 {
281                         byte[] buf = new byte [65536];
282                         FileStream file;
283                         int count, offset;
284
285                         build_metadata (this);
286
287                         foreach (ModuleBuilder module in modules)
288                                 module.Save ();
289
290                         if (dir != null) {
291                                 assemblyFileName = String.Format ("{0}{1}{2}", dir, System.IO.Path.DirectorySeparatorChar, assemblyFileName);
292                         }
293
294                         file = new FileStream (assemblyFileName, FileMode.Create, FileAccess.Write);
295
296                         offset = 0;
297                         while ((count = getDataChunk (this, buf, offset)) != 0) {
298                                 file.Write (buf, 0, count);
299                                 offset += count;
300                         }
301                         file.Close ();
302
303                         //
304                         // The constant 0x80000000 is internal to Mono, it means `make executable'
305                         //
306                         File.SetAttributes (assemblyFileName, (FileAttributes) (unchecked ((int) 0x80000000)));
307                 }
308
309                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
310                 private static extern void build_metadata (AssemblyBuilder ab);
311
312                 public void SetEntryPoint (MethodInfo entryMethod)
313                 {
314                         SetEntryPoint (entryMethod, PEFileKinds.ConsoleApplication);
315                 }
316
317                 public void SetEntryPoint (MethodInfo entryMethod, PEFileKinds fileKind)
318                 {
319                         entry_point = entryMethod;
320                         pekind = fileKind;
321                 }
322
323                 public void SetCustomAttribute( CustomAttributeBuilder customBuilder) {
324                         string attrname = customBuilder.Ctor.ReflectedType.FullName;
325                         byte[] data;
326                         int len, pos;
327                         if (attrname == "System.Reflection.AssemblyVersionAttribute") {
328                                 data = customBuilder.Data;
329                                 pos = 2;
330                                 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
331                                 version = CustomAttributeBuilder.string_from_bytes (data, pos, len);
332                                 return;
333                         } else if (attrname == "System.Reflection.AssemblyKeyFileAttribute") {
334                                 data = customBuilder.Data;
335                                 pos = 2;
336                                 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
337                                 keyfile = CustomAttributeBuilder.string_from_bytes (data, pos, len);
338                         } else if (attrname == "System.Reflection.AssemblyCultureAttribute") {
339                                 data = customBuilder.Data;
340                                 pos = 2;
341                                 len = CustomAttributeBuilder.decode_len (data, pos, out pos);
342                                 culture = CustomAttributeBuilder.string_from_bytes (data, pos, len);
343                         } else if (attrname == "System.Reflection.AssemblyAlgorithmIdAttribute") {
344                                 data = customBuilder.Data;
345                                 pos = 2;
346                                 algid = (uint)data [pos];
347                                 algid |= ((uint)data [pos + 1]) << 8;
348                                 algid |= ((uint)data [pos + 2]) << 16;
349                                 algid |= ((uint)data [pos + 3]) << 24;
350                         } else if (attrname == "System.Reflection.AssemblyFlagsAttribute") {
351                                 data = customBuilder.Data;
352                                 pos = 2;
353                                 flags = (uint)data [pos];
354                                 flags |= ((uint)data [pos + 1]) << 8;
355                                 flags |= ((uint)data [pos + 2]) << 16;
356                                 flags |= ((uint)data [pos + 3]) << 24;
357                                 return;
358                         } else if (attrname == "System.Reflection.AssemblyDelaySignAttribute") {
359                                 data = customBuilder.Data;
360                                 pos = 2;
361                                 delay_sign = data [2] != 0;
362                         }
363                         if (cattrs != null) {
364                                 CustomAttributeBuilder[] new_array = new CustomAttributeBuilder [cattrs.Length + 1];
365                                 cattrs.CopyTo (new_array, 0);
366                                 new_array [cattrs.Length] = customBuilder;
367                                 cattrs = new_array;
368                         } else {
369                                 cattrs = new CustomAttributeBuilder [1];
370                                 cattrs [0] = customBuilder;
371                         }
372                 }
373                 public void SetCustomAttribute( ConstructorInfo con, byte[] binaryAttribute) {
374                         SetCustomAttribute (new CustomAttributeBuilder (con, binaryAttribute));
375                 }
376
377                 public void SetCorlibTypeBuilders (Type corlib_object_type, Type corlib_value_type, Type corlib_enum_type) {
378                         this.corlib_object_type = corlib_object_type;
379                         this.corlib_value_type = corlib_value_type;
380                         this.corlib_enum_type = corlib_enum_type;
381                 }
382         }
383 }