2001-07-20 Miguel de Icaza <miguel@ximian.com>
[mono.git] / mono / metadata / assembly.c
1 /*
2  * assembly.c: Routines for loading assemblies.
3  * 
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.  http://www.ximian.com
8  *
9  * TODO:
10  *   Implement big-endian versions of the reading routines.
11  */
12 #include <config.h>
13 #include <stdio.h>
14 #include <glib.h>
15 #include <errno.h>
16 #include <string.h>
17 #include "assembly.h"
18 #include "image.h"
19 #include "cil-coff.h"
20 #include "rawbuffer.h"
21
22 #define CSIZE(x) (sizeof (x) / 4)
23
24 static char *
25 default_assembly_name_resolver (const char *name)
26 {
27         if (strcmp (name, "mscorlib") == 0)
28                 return g_strdup (MONO_ASSEMBLIES "/corlib.dll");
29
30         return g_strconcat (MONO_ASSEMBLIES "/", name, ".dll", NULL);
31 }
32
33 /**
34  * mono_assembly_open:
35  * @filename: Opens the assembly pointed out by this name
36  * @resolver: A user provided function to resolve assembly references
37  * @status: where a status code can be returned
38  *
39  * mono_assembly_open opens the PE-image pointed by @filename, and
40  * loads any external assemblies referenced by it.
41  *
42  * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
43  * it. 
44  */
45 MonoAssembly *
46 mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
47                     enum MonoImageOpenStatus *status)
48 {
49         MonoAssembly *ass;
50         MonoImage *image;
51         metadata_tableinfo_t *t;
52         cli_image_info_t *iinfo;
53         metadata_t *m;
54         int i, j;
55         const char *basename = strrchr (filename, '/');
56         static MonoAssembly *corlib;
57         
58         if (basename == NULL)
59                 basename = filename;
60         else
61                 basename++;
62
63         /*
64          * Temporary hack until we have a complete corlib.dll
65          */
66         if (strcmp (basename, "corlib.dll") && corlib != NULL)
67                 return corlib;
68                 
69         g_return_val_if_fail (filename != NULL, NULL);
70
71         image = mono_image_open (filename, status);
72         if (!image){
73                 if (status)
74                         *status = MONO_IMAGE_ERROR_ERRNO;
75                 return NULL;
76         }
77
78         if (resolver == NULL)
79                 resolver = default_assembly_name_resolver;
80
81         iinfo = image->image_info;
82         m = &iinfo->cli_metadata;
83         t = &m->tables [META_TABLE_ASSEMBLYREF];
84
85         image->references = g_new (MonoAssembly *, t->rows + 1);
86
87         ass = g_new (MonoAssembly, 1);
88         ass->image = image;
89         
90         /*
91          * Load any assemblies this image references
92          */
93         for (i = j = 0; i < t->rows; i++){
94                 char *assembly_ref;
95                 const char *name;
96                 guint32 cols [9];
97
98                 mono_metadata_decode_row (t, i, cols, CSIZE (cols));
99                 name = mono_metadata_string_heap (m, cols [6]);
100
101                 /*
102                  * Special case until we have a passable corlib:
103                  *
104                  * ie, references to mscorlib from corlib.dll are ignored 
105                  * and we do not load corlib twice.
106                  */
107                 if (strcmp (basename, "corlib.dll") == 0){
108                         if (strcmp (name, "mscorlib") == 0)
109                                 continue;
110
111                         if (corlib == NULL)
112                                 corlib = ass;
113                 }
114                 
115                 assembly_ref = (*resolver) (name);
116
117                 image->references [i] = mono_assembly_open (assembly_ref, resolver, status);
118                 
119                 if (image->references [i] == NULL){
120                         int j;
121                         
122                         for (j = 0; j < i; j++)
123                                 mono_assembly_close (image->references [j]);
124                         g_free (image->references);
125                         mono_image_close (image);
126
127                         g_warning ("Could not find assembly %s %s", name, assembly_ref);
128                         g_free (assembly_ref);
129                         if (status)
130                                 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
131                         g_free (ass);
132                         return NULL;
133                 }
134                 g_free (assembly_ref);
135                 j++;
136         }
137         image->references [j] = NULL;
138
139         return ass;
140 }
141
142 void
143 mono_assembly_close (MonoAssembly *assembly)
144 {
145         MonoImage *image;
146         int i;
147         
148         g_return_if_fail (assembly != NULL);
149
150         for (i = 0; image->references [i] != NULL; i++)
151                 mono_image_close (assembly->image);
152         g_free (image->references);
153              
154         mono_image_close (assembly->image);
155         g_free (assembly);
156 }
157