710022ca9cce52f2d222f6f7cfd071badf27438e
[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 /**
25  * g_concat_dir_and_file:
26  * @dir:  directory name
27  * @file: filename.
28  *
29  * returns a new allocated string that is the concatenation of dir and file,
30  * takes care of the exact details for concatenating them.
31  */
32 static char *
33 g_concat_dir_and_file (const char *dir, const char *file)
34 {
35         g_return_val_if_fail (dir != NULL, NULL);
36         g_return_val_if_fail (file != NULL, NULL);
37
38         /*
39          * If the directory name doesn't have a / on the end, we need
40          * to add one so we get a proper path to the file
41          */
42         if (dir [strlen(dir) - 1] != G_DIR_SEPARATOR)
43                 return g_strconcat (dir, G_DIR_SEPARATOR_S, file, NULL);
44         else
45                 return g_strconcat (dir, file, NULL);
46 }
47
48 static char *
49 default_assembly_name_resolver (const char *name)
50 {
51         char *file, *path;
52         
53         if (strcmp (name, "mscorlib") == 0)
54                 return g_concat_dir_and_file (MONO_ASSEMBLIES, CORLIB_NAME);
55
56         file = g_strconcat (name, ".dll", NULL);
57         path = g_concat_dir_and_file (MONO_ASSEMBLIES, file);
58         g_free (file);
59
60         return path;
61 }
62
63 /**
64  * mono_assembly_open:
65  * @filename: Opens the assembly pointed out by this name
66  * @resolver: A user provided function to resolve assembly references
67  * @status: where a status code can be returned
68  *
69  * mono_assembly_open opens the PE-image pointed by @filename, and
70  * loads any external assemblies referenced by it.
71  *
72  * NOTE: we could do lazy loading of the assemblies.  Or maybe not worth
73  * it. 
74  */
75 MonoAssembly *
76 mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
77                     enum MonoImageOpenStatus *status)
78 {
79         MonoAssembly *ass;
80         MonoImage *image;
81         MonoTableInfo *t;
82         int i;
83         const char *basename = strrchr (filename, '/');
84         static MonoAssembly *corlib;
85         
86         g_return_val_if_fail (filename != NULL, NULL);
87
88         if (basename == NULL)
89                 basename = filename;
90         else
91                 basename++;
92
93
94         /*
95          * Temporary hack until we have a complete corlib.dll
96          */
97         if (strcmp (basename, CORLIB_NAME) == 0) {
98                 char *fullname;
99                 
100                 if (corlib != NULL)
101                         return corlib;
102                 fullname = g_concat_dir_and_file (MONO_ASSEMBLIES, CORLIB_NAME);
103                 image = mono_image_open (fullname, status);
104                 g_free (fullname);
105         } else
106                 image = mono_image_open (filename, status);
107         
108         if (!image){
109                 if (status)
110                         *status = MONO_IMAGE_ERROR_ERRNO;
111                 return NULL;
112         }
113
114         if (resolver == NULL)
115                 resolver = default_assembly_name_resolver;
116
117         t = &image->tables [MONO_TABLE_ASSEMBLYREF];
118
119         image->references = g_new0 (MonoAssembly *, t->rows + 1);
120
121         ass = g_new (MonoAssembly, 1);
122         ass->image = image;
123         
124         /*
125          * Load any assemblies this image references
126          */
127         for (i = 0; i < t->rows; i++){
128                 char *assembly_ref;
129                 const char *name;
130                 guint32 cols [MONO_ASSEMBLYREF_SIZE];
131
132                 mono_metadata_decode_row (t, i, cols, CSIZE (cols));
133                 name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
134
135                 /*
136                  * Special case until we have a passable corlib:
137                  *
138                  * ie, references to mscorlib from corlib.dll are ignored 
139                  * and we do not load corlib twice.
140                  */
141                 if (strcmp (basename, CORLIB_NAME) == 0){
142                         if (corlib == NULL)
143                                 corlib = ass;
144                         
145                         if (strcmp (name, "mscorlib") == 0)
146                                 continue;
147                 }
148                 
149                 assembly_ref = (*resolver) (name);
150
151                 image->references [i] = mono_assembly_open (assembly_ref, resolver, status);
152
153                 if (image->references [i] == NULL){
154                         int j;
155                         
156                         for (j = 0; j < i; j++)
157                                 mono_assembly_close (image->references [j]);
158                         g_free (image->references);
159                         mono_image_close (image);
160
161                         g_warning ("Could not find assembly %s %s", name, assembly_ref);
162                         g_free (assembly_ref);
163                         if (status)
164                                 *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
165                         g_free (ass);
166                         return NULL;
167                 }
168                 g_free (assembly_ref);
169         }
170         image->references [i] = NULL;
171
172         return ass;
173 }
174
175 void
176 mono_assembly_close (MonoAssembly *assembly)
177 {
178         MonoImage *image;
179         int i;
180         
181         g_return_if_fail (assembly != NULL);
182
183         image = assembly->image;
184         for (i = 0; image->references [i] != NULL; i++)
185                 mono_image_close (image->references [i]->image);
186         g_free (image->references);
187              
188         mono_image_close (assembly->image);
189         g_free (assembly);
190 }
191