Fri Mar 29 16:09:54 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / assembly.c
index ad07a4dcf4bea5c81e9dc688d7c24704544e147d..3d9a59b2f3a4fa45464706c6a532e88d09db6684 100644 (file)
 
 #define CSIZE(x) (sizeof (x) / 4)
 
+/*
+ * keeps track of loaded assemblies
+ */
+static GHashTable *assemblies;
+
+/**
+ * g_concat_dir_and_file:
+ * @dir:  directory name
+ * @file: filename.
+ *
+ * returns a new allocated string that is the concatenation of dir and file,
+ * takes care of the exact details for concatenating them.
+ */
+static char *
+g_concat_dir_and_file (const char *dir, const char *file)
+{
+       g_return_val_if_fail (dir != NULL, NULL);
+       g_return_val_if_fail (file != NULL, NULL);
+
+        /*
+        * If the directory name doesn't have a / on the end, we need
+        * to add one so we get a proper path to the file
+        */
+       if (dir [strlen(dir) - 1] != G_DIR_SEPARATOR)
+               return g_strconcat (dir, G_DIR_SEPARATOR_S, file, NULL);
+       else
+               return g_strconcat (dir, file, NULL);
+}
+
 static char *
-default_assembly_name_resolver (const char *name)
+default_assembly_name_resolver (const char *base_dir, const char *name)
 {
-       if (strcmp (name, "mscorlib") == 0)
-               return g_strdup (MONO_ASSEMBLIES "/" CORLIB_NAME);
+       char *file, *path;
+       
+       if ((strcmp (name, "mscorlib") == 0) ||
+                       (strcmp (name, "mscorlib.dll") == 0) ||
+                       (strcmp (name, "corlib.dll") == 0) ||
+                       (strcmp (name, "corlib") == 0))
+               return g_concat_dir_and_file (MONO_ASSEMBLIES, CORLIB_NAME);
+
+       path = g_concat_dir_and_file (base_dir, name);
+       if (g_file_test (name, G_FILE_TEST_EXISTS))
+               return path;
+
+       file = path;
+       path = g_strconcat (file, ".dll", NULL);
+       g_free (file);
+       if (g_file_test (path, G_FILE_TEST_EXISTS))
+               return path;
+       g_free (path);
+       
+       path = g_concat_dir_and_file (MONO_ASSEMBLIES, name);
+       if (g_file_test (path, G_FILE_TEST_EXISTS))
+               return path;
+       g_free (path);
 
-       return g_strconcat (MONO_ASSEMBLIES "/", name, ".dll", NULL);
+       file = g_strconcat (name, ".dll", NULL);
+       path = g_concat_dir_and_file (MONO_ASSEMBLIES, file);
+       g_free (file);
+
+       return path;
 }
 
 /**
@@ -49,45 +103,55 @@ mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
        MonoAssembly *ass;
        MonoImage *image;
        MonoTableInfo *t;
-       MonoMetadata *m;
        int i;
-       const char *basename = strrchr (filename, '/');
-       const char *fullname = filename;
+       char *fullname, *base_dir;
+       const char *base_name = strrchr (filename, G_DIR_SEPARATOR);
        static MonoAssembly *corlib;
        
        g_return_val_if_fail (filename != NULL, NULL);
 
-       if (basename == NULL)
-               basename = filename;
-       else
-               basename++;
+       if (assemblies == NULL)
+               assemblies = g_hash_table_new (g_str_hash, g_str_equal);
 
-       /*
-        * Temporary hack until we have a complete corlib.dll
-        */
-       if (!strcmp (basename, CORLIB_NAME)) {
-               if (corlib != NULL)
-                       return corlib;
-               fullname = MONO_ASSEMBLIES "/" CORLIB_NAME;
+       if ((ass = g_hash_table_lookup (assemblies, filename)) != NULL){
+               ass->ref_count++;
+               return ass;
        }
        
+       if (base_name == NULL)
+               base_name = filename;
+       else
+               base_name++;
+
+       if (resolver == NULL)
+               resolver = default_assembly_name_resolver;
+
+       base_dir = g_path_get_dirname (fullname);
+       
+       fullname = resolver (base_dir, filename);
        image = mono_image_open (fullname, status);
+
        if (!image){
                if (status)
                        *status = MONO_IMAGE_ERROR_ERRNO;
+               g_free (fullname);
+               g_free (base_dir);
                return NULL;
        }
 
-       if (resolver == NULL)
-               resolver = default_assembly_name_resolver;
-
-       m = &image->metadata;
-       t = &m->tables [MONO_TABLE_ASSEMBLYREF];
+       t = &image->tables [MONO_TABLE_ASSEMBLYREF];
 
        image->references = g_new0 (MonoAssembly *, t->rows + 1);
 
+       /*
+        * Create assembly struct, and enter it into the assembly cache
+        */
        ass = g_new (MonoAssembly, 1);
+       ass->name = fullname;
        ass->image = image;
+
+       g_hash_table_insert (assemblies, image->name, ass);
+       g_hash_table_insert (assemblies, ass->name, ass);
        
        /*
         * Load any assemblies this image references
@@ -98,7 +162,7 @@ mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
                guint32 cols [MONO_ASSEMBLYREF_SIZE];
 
                mono_metadata_decode_row (t, i, cols, CSIZE (cols));
-               name = mono_metadata_string_heap (m, cols [MONO_ASSEMBLYREF_NAME]);
+               name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLYREF_NAME]);
 
                /*
                 * Special case until we have a passable corlib:
@@ -106,7 +170,7 @@ mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
                 * ie, references to mscorlib from corlib.dll are ignored 
                 * and we do not load corlib twice.
                 */
-               if (strcmp (basename, CORLIB_NAME) == 0){
+               if (strcmp (base_name, CORLIB_NAME) == 0){
                        if (corlib == NULL)
                                corlib = ass;
                        
@@ -114,9 +178,10 @@ mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
                                continue;
                }
                
-               assembly_ref = (*resolver) (name);
+               assembly_ref = (*resolver) (base_dir, name);
 
                image->references [i] = mono_assembly_open (assembly_ref, resolver, status);
+
                if (image->references [i] == NULL){
                        int j;
                        
@@ -130,12 +195,14 @@ mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
                        if (status)
                                *status = MONO_IMAGE_MISSING_ASSEMBLYREF;
                        g_free (ass);
+                       g_free (base_dir);
                        return NULL;
                }
                g_free (assembly_ref);
        }
        image->references [i] = NULL;
 
+       g_free (base_dir);
        return ass;
 }
 
@@ -147,12 +214,27 @@ mono_assembly_close (MonoAssembly *assembly)
        
        g_return_if_fail (assembly != NULL);
 
+       if (--assembly->ref_count != 0)
+               return;
+       
        image = assembly->image;
        for (i = 0; image->references [i] != NULL; i++)
                mono_image_close (image->references [i]->image);
        g_free (image->references);
             
        mono_image_close (assembly->image);
+
+       g_hash_table_remove (assemblies, assembly->name);
+                            
+       g_free (assembly->name);
        g_free (assembly);
 }
 
+/*
+ * Temporary hack until we get AppDomains
+ */
+GHashTable *
+mono_get_assemblies ()
+{
+       return assemblies;
+}