Fri Mar 29 16:09:54 CET 2002 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / assembly.c
index 8f495a057d5f7112bdb1e1e88f1c1b3a8c9f4224..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
@@ -46,13 +51,32 @@ g_concat_dir_and_file (const char *dir, const char *file)
 }
 
 static char *
-default_assembly_name_resolver (const char *name)
+default_assembly_name_resolver (const char *base_dir, const char *name)
 {
        char *file, *path;
        
-       if (strcmp (name, "mscorlib") == 0)
+       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);
+
        file = g_strconcat (name, ".dll", NULL);
        path = g_concat_dir_and_file (MONO_ASSEMBLIES, file);
        g_free (file);
@@ -80,45 +104,54 @@ mono_assembly_open (const char *filename, MonoAssemblyResolverFn resolver,
        MonoImage *image;
        MonoTableInfo *t;
        int i;
-       const char *basename = strrchr (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;
+       if (assemblies == NULL)
+               assemblies = g_hash_table_new (g_str_hash, g_str_equal);
+
+       if ((ass = g_hash_table_lookup (assemblies, filename)) != NULL){
+               ass->ref_count++;
+               return ass;
+       }
+       
+       if (base_name == NULL)
+               base_name = filename;
        else
-               basename++;
+               base_name++;
 
-       /*
-        * Temporary hack until we have a complete corlib.dll
-        */
-       if (strcmp (basename, CORLIB_NAME) == 0) {
-               char *fullname;
-               
-               if (corlib != NULL)
-                       return corlib;
-               fullname = g_concat_dir_and_file (MONO_ASSEMBLIES, CORLIB_NAME);
-               image = mono_image_open (fullname, status);
-               g_free (fullname);
-       } else
-               image = mono_image_open (filename, status);
+       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;
-
        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
@@ -137,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;
                        
@@ -145,7 +178,7 @@ 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);
 
@@ -162,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;
 }
 
@@ -179,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;
+}