2005-05-03 Lluis Sanchez Gual <lluis@novell.com>
authorLluis Sanchez <lluis@novell.com>
Tue, 3 May 2005 15:02:55 +0000 (15:02 -0000)
committerLluis Sanchez <lluis@novell.com>
Tue, 3 May 2005 15:02:55 +0000 (15:02 -0000)
* appdomain.c: Moved methods for parsing and freeing assembly
names to assembly.c.
* assembly.c, domain-internals.h: Created public methods for parsing
assembly names. Fixed mono_assembly_load_with_partial_name:
it now finds the best match, taking into account the version,
token and culture specified in the partial name. Also return
the latest version if no version information is specified.

svn path=/trunk/mono/; revision=43932

mono/metadata/ChangeLog
mono/metadata/appdomain.c
mono/metadata/assembly.c
mono/metadata/domain-internals.h

index a7f988fc587bb6497e61aa2d8ffa91a055bc15bb..887dd62f20b41b6a7e5746b6b520c4789baa71b8 100644 (file)
@@ -1,3 +1,12 @@
+2005-05-03  Lluis Sanchez Gual <lluis@novell.com>
+
+       * appdomain.c: Moved methods for parsing and freeing assembly
+       names to assembly.c.
+       * assembly.c, domain-internals.h: Created public methods for parsing
+       assembly names. Fixed mono_assembly_load_with_partial_name:
+       it now finds the best match, taking into account the version,
+       token and culture specified in the partial name. Also return
+       the latest version if no version information is specified.
 
 Mon May 2 15:47:57 CEST 2005 Paolo Molaro <lupus@ximian.com>
 
index 0a949638efd1850eeedde2a7853d42a5900a813c..1e61c04e9ebe68f07f0c3be13df3ea6615754092 100644 (file)
@@ -896,95 +896,6 @@ ves_icall_System_Reflection_Assembly_LoadFrom (MonoString *fname, MonoBoolean re
        return mono_assembly_get_object (domain, ass);
 }
 
-static void
-free_assembly_name (MonoAssemblyName *aname)
-{
-       if (aname == NULL)
-               return;
-
-       g_free ((void *) aname->name);
-       g_free ((void *) aname->culture);
-       g_free ((void *) aname->hash_value);
-}
-
-static gboolean
-get_info_from_assembly_name (MonoString *assRef, MonoAssemblyName *aname)
-{
-       gchar *name;
-       gchar *value;
-       gchar **parts;
-       gchar **tmp;
-       gint major, minor, build, revision;
-
-       memset (aname, 0, sizeof (MonoAssemblyName));
-
-       name = mono_string_to_utf8 (assRef);
-       parts = tmp = g_strsplit (name, ",", 4);
-       g_free (name);
-       if (!tmp || !*tmp) {
-               g_strfreev (tmp);
-               return FALSE;
-       }
-
-       value = g_strstrip (*tmp);
-       /* g_print ("Assembly name: %s\n", value); */
-       aname->name = g_strdup (value);
-       tmp++;
-       if (!*tmp) {
-               g_strfreev (parts);
-               return TRUE;
-       }
-
-       while (*tmp) {
-               value = g_strstrip (*tmp);
-               if (!g_ascii_strncasecmp (value, "Version=", 8)) {
-                       if (sscanf (value + 8, "%u.%u.%u.%u",
-                                   &major, &minor, &build, &revision) != 4) {
-                               g_strfreev (parts);
-                               return FALSE;
-                       }
-                       /* g_print ("Version: %u.%u.%u.%u\n", major, minor, build, revision); */
-                       aname->major = major;
-                       aname->minor = minor;
-                       aname->build = build;
-                       aname->revision = revision;
-                       tmp++;
-                       continue;
-               }
-
-               if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
-                       gchar *t = g_strdup (value + 8);
-                       g_strchug (t);
-                       aname->culture = g_strdup (g_strchomp (t));
-                       tmp++;
-                       g_free (t);
-                       if (g_strcasecmp (aname->culture, "neutral") == 0) {
-                               g_free ((void *) aname->culture);
-                               aname->culture = g_strdup ("");
-                       }
-                       continue;
-               }
-
-               if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
-                       tmp++;
-                       value += 15;
-                       if (*value && strncmp (value, "null", 4)) {
-                               gchar *t = g_strdup (value);
-                               g_strchug (t);
-                               g_strlcpy ((char*)aname->public_key_token, g_strchomp (value), MONO_PUBLIC_KEY_TOKEN_LENGTH);
-                               g_free (t);
-                       }
-                       continue;
-               }
-
-               g_strfreev (parts);
-               return FALSE;
-       }
-
-       g_strfreev (parts);
-       return TRUE;
-}
-
 MonoReflectionAssembly *
 ves_icall_System_AppDomain_LoadAssemblyRaw (MonoAppDomain *ad, 
                                                                                        MonoArray *raw_assembly,
@@ -1027,22 +938,27 @@ ves_icall_System_AppDomain_LoadAssembly (MonoAppDomain *ad,  MonoString *assRef,
        MonoAssembly *ass;
        MonoAssemblyName aname;
        MonoReflectionAssembly *refass = NULL;
+       gchar *name;
+       gboolean parsed;
 
        MONO_ARCH_SAVE_REGS;
 
        g_assert (assRef != NULL);
 
-       if (!get_info_from_assembly_name (assRef, &aname)) {
+       name = mono_string_to_utf8 (assRef);
+       parsed = mono_assembly_name_parse (name, &aname);
+       g_free (name);
+
+       if (!parsed) {
                MonoException *exc;
 
-               free_assembly_name (&aname);
                /* This is a parse error... */
                exc = mono_get_exception_file_not_found (assRef);
                mono_raise_exception (exc);
        }
 
        ass = mono_assembly_load_full (&aname, NULL, &status, refOnly);
-       free_assembly_name (&aname);
+       mono_assembly_name_free (&aname);
 
        if (!ass && (refass = try_assembly_resolve (domain, assRef, refOnly)) == NULL){
                /* FIXME: it doesn't make much sense since we really don't have a filename ... */
index 66e8547d3a0a5583865503b7f0a04f6f58ac50e1..f4a71a0011ac15036d96508d00cc1c9c17a44252 100644 (file)
@@ -1027,58 +1027,244 @@ mono_assembly_load_from (MonoImage *image, const char *fname,
        return mono_assembly_load_from_full (image, fname, status, FALSE);
 }
 
+/**
+* mono_assembly_name_free:
+* @aname: assembly name to free
+* 
+* Frees the provided assembly name object.
+* (it does not frees the object itself, only the name members).
+*/
+void
+mono_assembly_name_free (MonoAssemblyName *aname)
+{
+       if (aname == NULL)
+               return;
+
+       g_free ((void *) aname->name);
+       g_free ((void *) aname->culture);
+       g_free ((void *) aname->hash_value);
+}
+
+static gboolean
+build_assembly_name (const char *name, const char *version, const char *culture, const char *token, MonoAssemblyName *aname)
+{
+       gint major, minor, build, revision;
+
+       memset (aname, 0, sizeof (MonoAssemblyName));
+
+       if (version) {
+               if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
+                       return FALSE;
+
+               aname->major = major;
+               aname->minor = minor;
+               aname->build = build;
+               aname->revision = revision;
+       }
+       
+       aname->name = g_strdup (name);
+       
+       if (culture) {
+               if (g_strcasecmp (culture, "neutral") == 0)
+                       aname->culture = g_strdup ("");
+               else
+                       aname->culture = g_strdup (culture);
+       }
+       
+       if (token && strncmp (token, "null", 4) != 0)
+               g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
+       
+       return TRUE;
+}
+
+static gboolean
+parse_assembly_directory_name (const char *name, const char *dirname, MonoAssemblyName *aname)
+{
+       gchar **parts;
+       gboolean res;
+       
+       parts = g_strsplit (dirname, "_", 3);
+       if (!parts || !parts[0] || !parts[1] || !parts[2]) {
+               g_strfreev (parts);
+               return FALSE;
+       }
+       
+       res = build_assembly_name (name, parts[0], parts[1], parts[2], aname);
+       g_strfreev (parts);
+       return res;
+}
+
+/**
+* mono_assembly_name_parse:
+* @name: name to parse
+* @aname: the destination assembly name
+* Returns: true if the name could be parsed.
+* 
+* Parses an assembly qualified type name and assigns the name,
+* version, culture and token to the provided assembly name object.
+*/
+gboolean
+mono_assembly_name_parse (const char *name, MonoAssemblyName *aname)
+{
+       gchar *dllname;
+       gchar *version = NULL;
+       gchar *culture = NULL;
+       gchar *token = NULL;
+       gboolean res;
+       gchar *value;
+       gchar **parts;
+       gchar **tmp;
+
+       parts = tmp = g_strsplit (name, ",", 4);
+       if (!tmp || !*tmp) {
+               g_strfreev (tmp);
+               return FALSE;
+       }
+
+       dllname = g_strstrip (*tmp);
+       
+       tmp++;
+
+       while (*tmp) {
+               value = g_strstrip (*tmp);
+               if (!g_ascii_strncasecmp (value, "Version=", 8)) {
+                       version = g_strstrip (value + 8);
+                       tmp++;
+                       continue;
+               }
+
+               if (!g_ascii_strncasecmp (value, "Culture=", 8)) {
+                       culture = g_strstrip (value + 8);
+                       tmp++;
+                       continue;
+               }
+
+               if (!g_ascii_strncasecmp (value, "PublicKeyToken=", 15)) {
+                       token = g_strstrip (value + 15);
+                       tmp++;
+                       continue;
+               }
+               
+               g_strfreev (parts);
+               return FALSE;
+       }
+
+       res = build_assembly_name (dllname, version, culture, token, aname);
+       g_strfreev (parts);
+       return res;
+}
+
 static MonoAssembly*
-probe_for_partial_name (const char *basepath, const char *fullname, MonoImageOpenStatus *status)
+probe_for_partial_name (const char *basepath, const char *fullname, MonoAssemblyName *aname, MonoImageOpenStatus *status)
 {
-       MonoAssembly *res = NULL;
-       gchar *fullpath;
+       gchar *fullpath = NULL;
        GDir *dirhandle;
        const char* direntry;
-
+       MonoAssemblyName gac_aname;
+       gint major=-1, minor=0, build=0, revision=0;
+       gboolean exact_version;
+       
        dirhandle = g_dir_open (basepath, 0, NULL);
        if (!dirhandle)
                return NULL;
+               
+       exact_version = (aname->major | aname->minor | aname->build | aname->revision) != 0;
 
        while ((direntry = g_dir_read_name (dirhandle))) {
-               fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
-               res = mono_assembly_open (fullpath, status);
-               g_free (fullpath);
-               if (res)
-                       break;
+               gboolean match = TRUE;
+               
+               parse_assembly_directory_name (aname->name, direntry, &gac_aname);
+               
+               if (aname->culture != NULL && strcmp (aname->culture, gac_aname.culture) != 0)
+                       match = FALSE;
+                       
+               if (match && strlen ((char*)aname->public_key_token) > 0 && 
+                               strcmp ((char*)aname->public_key_token, (char*)gac_aname.public_key_token) != 0)
+                       match = FALSE;
+               
+               if (match) {
+                       if (exact_version) {
+                               match = (aname->major == gac_aname.major && aname->minor == gac_aname.minor &&
+                                                aname->build == gac_aname.build && aname->revision == gac_aname.revision); 
+                       }
+                       else if (gac_aname.major < major)
+                               match = FALSE;
+                       else if (gac_aname.major == major) {
+                               if (gac_aname.minor < minor)
+                                       match = FALSE;
+                               else if (gac_aname.minor == minor) {
+                                       if (gac_aname.build < build)
+                                               match = FALSE;
+                                       else if (gac_aname.build == build && gac_aname.revision <= revision)
+                                               match = FALSE; 
+                               }
+                       }
+               }
+               
+               if (match) {
+                       major = gac_aname.major;
+                       minor = gac_aname.minor;
+                       build = gac_aname.build;
+                       revision = gac_aname.revision;
+                       g_free (fullpath);
+                       fullpath = g_build_path (G_DIR_SEPARATOR_S, basepath, direntry, fullname, NULL);
+               }
+
+               mono_assembly_name_free (&gac_aname);
        }
+       
        g_dir_close (dirhandle);
-
-       return res;
+       
+       if (fullpath == NULL)
+               return NULL;
+       else {
+               MonoAssembly *res = mono_assembly_open (fullpath, status);
+               g_free (fullpath);
+               return res;
+       }
 }
 
 MonoAssembly*
 mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *status)
 {
        MonoAssembly *res;
-       MonoAssemblyName aname;
+       MonoAssemblyName *aname, base_name, maped_aname;
        gchar *fullname, *gacpath;
        gchar **paths;
 
-       memset (&aname, 0, sizeof (MonoAssemblyName));
-       aname.name = name;
+       memset (&base_name, 0, sizeof (MonoAssemblyName));
+       aname = &base_name;
 
-       res = mono_assembly_loaded (&aname);
-       if (res)
+       if (!mono_assembly_name_parse (name, aname))
+               return NULL;
+
+       /* 
+        * If no specific version has been requested, make sure we load the
+        * correct version for system assemblies.
+        */ 
+       if ((aname->major | aname->minor | aname->build | aname->revision) == 0)
+               aname = mono_assembly_remap_version (aname, &maped_aname);
+       
+       res = mono_assembly_loaded (aname);
+       if (res) {
+               mono_assembly_name_free (aname);
                return res;
+       }
 
-       res = invoke_assembly_preload_hook (&aname, assemblies_path);
+       res = invoke_assembly_preload_hook (aname, assemblies_path);
        if (res) {
                res->in_gac = FALSE;
+               mono_assembly_name_free (aname);
                return res;
        }
 
-       fullname = g_strdup_printf ("%s.dll", name);
+       fullname = g_strdup_printf ("%s.dll", aname->name);
 
        if (extra_gac_paths) {
                paths = extra_gac_paths;
                while (!res && *paths) {
-                       gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", name, NULL);
-                       res = probe_for_partial_name (gacpath, fullname, status);
+                       gacpath = g_build_path (G_DIR_SEPARATOR_S, *paths, "lib", "mono", "gac", aname->name, NULL);
+                       res = probe_for_partial_name (gacpath, fullname, aname, status);
                        g_free (gacpath);
                        paths++;
                }
@@ -1087,18 +1273,19 @@ mono_assembly_load_with_partial_name (const char *name, MonoImageOpenStatus *sta
        if (res) {
                res->in_gac = TRUE;
                g_free (fullname);
+               mono_assembly_name_free (aname);
                return res;
-               
        }
 
-       gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", name, NULL);
-       res = probe_for_partial_name (gacpath, fullname, status);
+       gacpath = g_build_path (G_DIR_SEPARATOR_S, mono_assembly_getrootdir (), "mono", "gac", aname->name, NULL);
+       res = probe_for_partial_name (gacpath, fullname, aname, status);
        g_free (gacpath);
 
        if (res)
                res->in_gac = TRUE;
 
        g_free (fullname);
+       mono_assembly_name_free (aname);
 
        return res;
 }
index 20d8d84ab008b56fb3a6cfb88f00c90fb2bc3d02..fbbbda745242d7bcf16e4386a342e7650d5bd920 100644 (file)
@@ -244,4 +244,10 @@ mono_assembly_load_corlib (const MonoRuntimeInfo *runtime, MonoImageOpenStatus *
 const MonoRuntimeInfo*
 mono_get_runtime_info (void);
 
+gboolean
+mono_assembly_name_parse (const char *name, MonoAssemblyName *aname);
+
+void
+mono_assembly_name_free (MonoAssemblyName *aname);
+
 #endif /* __MONO_METADATA_DOMAIN_INTERNALS_H__ */