[runtime] Remove ia64 backend, the Itanium architecture is dead. (#4859)
[mono.git] / mono / metadata / mono-config.c
1 /**
2  * \file
3  *
4  * Runtime and assembly configuration file support routines.
5  *
6  * Author: Paolo Molaro (lupus@ximian.com)
7  *
8  * Copyright 2002-2003 Ximian, Inc (http://www.ximian.com)
9  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
10  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
11  */
12 #include "config.h"
13 #include <glib.h>
14 #include <string.h>
15
16 #include "mono/metadata/assembly.h"
17 #include "mono/metadata/loader.h"
18 #include "mono/metadata/mono-config.h"
19 #include "mono/metadata/metadata-internals.h"
20 #include "mono/metadata/object-internals.h"
21 #include "mono/utils/mono-logger-internals.h"
22
23 #if defined(TARGET_PS3)
24 #define CONFIG_OS "CellOS"
25 #elif defined(__linux__)
26 #define CONFIG_OS "linux"
27 #elif defined(__APPLE__)
28 #define CONFIG_OS "osx"
29 #elif defined(sun)
30 #define CONFIG_OS "solaris"
31 #elif defined(__FreeBSD__)
32 #define CONFIG_OS "freebsd"
33 #elif defined(__NetBSD__)
34 #define CONFIG_OS "netbsd"
35 #elif defined(__OpenBSD__)
36 #define CONFIG_OS "openbsd"
37 #elif defined(__WIN32__) || defined(TARGET_WIN32)
38 #define CONFIG_OS "windows"
39 #elif defined(_IBMR2)
40 #define CONFIG_OS "aix"
41 #elif defined(__hpux)
42 #define CONFIG_OS "hpux"
43 #elif defined(__HAIKU__)
44 #define CONFIG_OS "haiku"
45 #else
46 #warning Unknown operating system
47 #define CONFIG_OS "unknownOS"
48 #endif
49
50 #ifndef CONFIG_CPU
51 #if defined(__i386__) || defined(TARGET_X86)
52 #define CONFIG_CPU "x86"
53 #define CONFIG_WORDSIZE "32"
54 #elif defined(__x86_64__) || defined(TARGET_AMD64)
55 #define CONFIG_CPU "x86-64"
56 #define CONFIG_WORDSIZE "64"
57 #elif defined(sparc) || defined(__sparc__)
58 #define CONFIG_CPU "sparc"
59 #define CONFIG_WORDSIZE "32"
60 #elif defined(__ppc64__) || defined(__powerpc64__) || defined(TARGET_POWERPC)
61 #define CONFIG_WORDSIZE "64"
62 #ifdef __mono_ppc_ilp32__ 
63 #   define CONFIG_CPU "ppc64ilp32"
64 #else
65 #   define CONFIG_CPU "ppc64"
66 #endif
67 #elif defined(__ppc__) || defined(__powerpc__)
68 #define CONFIG_CPU "ppc"
69 #define CONFIG_WORDSIZE "32"
70 #elif defined(__s390x__)
71 #define CONFIG_CPU "s390x"
72 #define CONFIG_WORDSIZE "64"
73 #elif defined(__s390__)
74 #define CONFIG_CPU "s390"
75 #define CONFIG_WORDSIZE "32"
76 #elif defined(__arm__)
77 #define CONFIG_CPU "arm"
78 #define CONFIG_WORDSIZE "32"
79 #elif defined(__aarch64__)
80 #define CONFIG_CPU "armv8"
81 #define CONFIG_WORDSIZE "64"
82 #elif defined(mips) || defined(__mips) || defined(_mips)
83 #define CONFIG_CPU "mips"
84 #define CONFIG_WORDSIZE "32"
85 #else
86 #error Unknown CPU
87 #define CONFIG_CPU "unknownCPU"
88 #endif
89 #endif
90
91 /**
92  * mono_config_get_os:
93  *
94  * Returns the operating system that Mono is running on, as used for dllmap entries.
95  */
96 const char *
97 mono_config_get_os (void)
98 {
99         return CONFIG_OS;
100 }
101
102 /**
103  * mono_config_get_cpu:
104  *
105  * Returns the architecture that Mono is running on, as used for dllmap entries.
106  */
107 const char *
108 mono_config_get_cpu (void)
109 {
110         return CONFIG_CPU;
111 }
112
113 /**
114  * mono_config_get_wordsize:
115  *
116  * Returns the word size that Mono is running on, as used for dllmap entries.
117  */
118 const char *
119 mono_config_get_wordsize (void)
120 {
121         return CONFIG_WORDSIZE;
122 }
123
124 static void start_element (GMarkupParseContext *context, 
125                            const gchar         *element_name,
126                            const gchar        **attribute_names,
127                            const gchar        **attribute_values,
128                            gpointer             user_data,
129                            GError             **error);
130
131 static void end_element   (GMarkupParseContext *context,
132                            const gchar         *element_name,
133                            gpointer             user_data,
134                            GError             **error);
135
136 static void parse_text    (GMarkupParseContext *context,
137                            const gchar         *text,
138                            gsize                text_len,
139                            gpointer             user_data,
140                            GError             **error);
141
142 static void passthrough   (GMarkupParseContext *context,
143                            const gchar         *text,
144                            gsize                text_len,
145                            gpointer             user_data,
146                            GError             **error);
147
148 static void parse_error   (GMarkupParseContext *context,
149                            GError              *error,
150                            gpointer             user_data);
151
152 static const GMarkupParser 
153 mono_parser = {
154         start_element,
155         end_element,
156         parse_text,
157         passthrough,
158         parse_error
159 };
160
161 static GHashTable *config_handlers;
162
163 static char *mono_cfg_dir = NULL;
164
165 /* when this interface is stable, export it. */
166 typedef struct MonoParseHandler MonoParseHandler;
167
168 struct MonoParseHandler {
169         const char *element_name;
170         void*(*init)   (MonoImage *assembly);
171         void (*start)  (gpointer user_data, const gchar *name,
172                         const gchar **attributes,
173                         const gchar **values);
174         void (*text)   (gpointer user_data, const char *text, gsize test_len);
175         void (*end)    (gpointer user_data, const char *name);
176         void (*finish) (gpointer user_data);
177 };
178
179 typedef struct {
180         MonoAssemblyBindingInfo *info;
181         void (*info_parsed)(MonoAssemblyBindingInfo *info, void *user_data);
182         void *user_data;
183 } ParserUserData;
184
185 typedef struct {
186         MonoParseHandler *current;
187         void *user_data;
188         MonoImage *assembly;
189         int inited;
190 } ParseState;
191
192 static void start_element (GMarkupParseContext *context, 
193                            const gchar         *element_name,
194                            const gchar        **attribute_names,
195                            const gchar        **attribute_values,
196                            gpointer             user_data,
197                            GError             **error)
198 {
199         ParseState *state = (ParseState *)user_data;
200         if (!state->current) {
201                 state->current = (MonoParseHandler *)g_hash_table_lookup (config_handlers, element_name);
202                 if (state->current && state->current->init)
203                         state->user_data = state->current->init (state->assembly);
204         }
205         if (state->current && state->current->start)
206                 state->current->start (state->user_data, element_name, attribute_names, attribute_values);
207 }
208
209 static void end_element   (GMarkupParseContext *context,
210                            const gchar         *element_name,
211                            gpointer             user_data,
212                            GError             **error)
213 {
214         ParseState *state = (ParseState *)user_data;
215         if (state->current) {
216                 if (state->current->end)
217                         state->current->end (state->user_data, element_name);
218                 if (strcmp (state->current->element_name, element_name) == 0) {
219                         if (state->current->finish)
220                                 state->current->finish (state->user_data);
221                         state->current = NULL;
222                         state->user_data = NULL;
223                 }
224         }
225 }
226
227 static void parse_text    (GMarkupParseContext *context,
228                            const gchar         *text,
229                            gsize                text_len,
230                            gpointer             user_data,
231                            GError             **error)
232 {
233         ParseState *state = (ParseState *)user_data;
234         if (state->current && state->current->text)
235                 state->current->text (state->user_data, text, text_len);
236 }
237
238 static void passthrough   (GMarkupParseContext *context,
239                            const gchar         *text,
240                            gsize                text_len,
241                            gpointer             user_data,
242                            GError             **error)
243 {
244         /* do nothing */
245 }
246
247 static void parse_error   (GMarkupParseContext *context,
248                            GError              *error,
249                            gpointer             user_data)
250 {
251         ParseState *state = (ParseState *)user_data;
252         const gchar *msg;
253         const gchar *filename;
254
255         filename = state && state->user_data ? (gchar *) state->user_data : "<unknown>";
256         msg = error && error->message ? error->message : "";
257         g_warning ("Error parsing %s: %s", filename, msg);
258 }
259
260 static int
261 arch_matches (const char* arch, const char *value)
262 {
263         char **splitted, **p;
264         int found = FALSE;
265         if (value [0] == '!')
266                 return !arch_matches (arch, value + 1);
267         p = splitted = g_strsplit (value, ",", 0);
268         while (*p) {
269                 if (strcmp (arch, *p) == 0) {
270                         found = TRUE;
271                         break;
272                 }
273                 p++;
274         }
275         g_strfreev (splitted);
276         return found;
277 }
278
279 typedef struct {
280         char *dll;
281         char *target;
282         int ignore;
283         MonoImage *assembly;
284 } DllInfo;
285
286 static void*
287 dllmap_init (MonoImage *assembly) {
288         DllInfo *info = g_new0 (DllInfo, 1);
289         info->assembly = assembly;
290         return info;
291 }
292
293 static void
294 dllmap_start (gpointer user_data, 
295               const gchar         *element_name,
296               const gchar        **attribute_names,
297               const gchar        **attribute_values)
298 {
299         int i;
300         DllInfo *info = (DllInfo *)user_data;
301         
302         if (strcmp (element_name, "dllmap") == 0) {
303                 g_free (info->dll);
304                 g_free (info->target);
305                 info->dll = info->target = NULL;
306                 info->ignore = FALSE;
307                 for (i = 0; attribute_names [i]; ++i) {
308                         if (strcmp (attribute_names [i], "dll") == 0)
309                                 info->dll = g_strdup (attribute_values [i]);
310                         else if (strcmp (attribute_names [i], "target") == 0){
311                                 char *p = strstr (attribute_values [i], "$mono_libdir");
312                                 if (p != NULL){
313                                         char *libdir = mono_native_getrootdir ();
314                                         size_t libdir_len = strlen (libdir);
315                                         char *result;
316                                         
317                                         result = (char *)g_malloc (libdir_len-strlen("$mono_libdir")+strlen(attribute_values[i])+1);
318                                         strncpy (result, attribute_values[i], p-attribute_values[i]);
319                                         strcpy (result+(p-attribute_values[i]), libdir);
320                                         g_free (libdir);
321                                         strcat (result, p+strlen("$mono_libdir"));
322                                         info->target = result;
323                                 } else 
324                                         info->target = g_strdup (attribute_values [i]);
325                         } else if (strcmp (attribute_names [i], "os") == 0 && !arch_matches (CONFIG_OS, attribute_values [i]))
326                                 info->ignore = TRUE;
327                         else if (strcmp (attribute_names [i], "cpu") == 0 && !arch_matches (CONFIG_CPU, attribute_values [i]))
328                                 info->ignore = TRUE;
329                         else if (strcmp (attribute_names [i], "wordsize") == 0 && !arch_matches (CONFIG_WORDSIZE, attribute_values [i]))
330                                 info->ignore = TRUE;
331                 }
332                 if (!info->ignore)
333                         mono_dllmap_insert (info->assembly, info->dll, NULL, info->target, NULL);
334         } else if (strcmp (element_name, "dllentry") == 0) {
335                 const char *name = NULL, *target = NULL, *dll = NULL;
336                 int ignore = FALSE;
337                 for (i = 0; attribute_names [i]; ++i) {
338                         if (strcmp (attribute_names [i], "dll") == 0)
339                                 dll = attribute_values [i];
340                         else if (strcmp (attribute_names [i], "target") == 0)
341                                 target = attribute_values [i];
342                         else if (strcmp (attribute_names [i], "name") == 0)
343                                 name = attribute_values [i];
344                         else if (strcmp (attribute_names [i], "os") == 0 && !arch_matches (CONFIG_OS, attribute_values [i]))
345                                 ignore = TRUE;
346                         else if (strcmp (attribute_names [i], "cpu") == 0 && !arch_matches (CONFIG_CPU, attribute_values [i]))
347                                 ignore = TRUE;
348                         else if (strcmp (attribute_names [i], "wordsize") == 0 && !arch_matches (CONFIG_WORDSIZE, attribute_values [i]))
349                                 ignore = TRUE;
350                 }
351                 if (!dll)
352                         dll = info->dll;
353                 if (!info->ignore && !ignore)
354                         mono_dllmap_insert (info->assembly, info->dll, name, dll, target);
355         }
356 }
357
358 static void
359 dllmap_finish (gpointer user_data)
360 {
361         DllInfo *info = (DllInfo *)user_data;
362
363         g_free (info->dll);
364         g_free (info->target);
365         g_free (info);
366 }
367
368 static const MonoParseHandler
369 dllmap_handler = {
370         "dllmap",
371         dllmap_init,
372         dllmap_start,
373         NULL, /* text */
374         NULL, /* end */
375         dllmap_finish
376 };
377
378 static void
379 legacyUEP_start (gpointer user_data, 
380               const gchar         *element_name,
381               const gchar        **attribute_names,
382               const gchar        **attribute_values) {
383         if ((strcmp (element_name, "legacyUnhandledExceptionPolicy") == 0) &&
384                         (attribute_names [0] != NULL) &&
385                         (strcmp (attribute_names [0], "enabled") == 0)) {
386                 if ((strcmp (attribute_values [0], "1") == 0) ||
387                                 (g_ascii_strcasecmp (attribute_values [0], "true") == 0)) {
388                         mono_runtime_unhandled_exception_policy_set (MONO_UNHANDLED_POLICY_LEGACY);
389                 }
390         }
391 }
392
393 static const MonoParseHandler
394 legacyUEP_handler = {
395         "legacyUnhandledExceptionPolicy",
396         NULL, /* init */
397         legacyUEP_start,
398         NULL, /* text */
399         NULL, /* end */
400         NULL, /* finish */
401 };
402
403 static void
404 aot_cache_start (gpointer user_data,
405                                  const gchar         *element_name,
406                                  const gchar        **attribute_names,
407                                  const gchar        **attribute_values)
408 {
409         int i;
410         MonoAotCacheConfig *config;
411
412         if (strcmp (element_name, "aotcache") != 0)
413                 return;
414
415         config = mono_get_aot_cache_config ();
416
417         /* Per-app configuration */
418         for (i = 0; attribute_names [i]; ++i) {
419                 if (!strcmp (attribute_names [i], "app")) {
420                         config->apps = g_slist_prepend (config->apps, g_strdup (attribute_values [i]));
421                 }
422         }
423
424         /* Global configuration */
425         for (i = 0; attribute_names [i]; ++i) {
426                 if (!strcmp (attribute_names [i], "assemblies")) {
427                         char **parts, **ptr;
428                         char *part;
429
430                         parts = g_strsplit (attribute_values [i], " ", -1);
431                         for (ptr = parts; ptr && *ptr; ptr ++) {
432                                 part = *ptr;
433                                 config->assemblies = g_slist_prepend (config->assemblies, g_strdup (part));
434                         }
435                         g_strfreev (parts);
436                 } else if (!strcmp (attribute_names [i], "options")) {
437                         config->aot_options = g_strdup (attribute_values [i]);
438                 }
439         }
440 }
441
442 static const MonoParseHandler
443 aot_cache_handler = {
444         "aotcache",
445         NULL, /* init */
446         aot_cache_start,
447         NULL, /* text */
448         NULL, /* end */
449         NULL, /* finish */
450 };
451
452 static int inited = 0;
453
454 static void
455 mono_config_init (void)
456 {
457         inited = 1;
458         config_handlers = g_hash_table_new (g_str_hash, g_str_equal);
459         g_hash_table_insert (config_handlers, (gpointer) dllmap_handler.element_name, (gpointer) &dllmap_handler);
460         g_hash_table_insert (config_handlers, (gpointer) legacyUEP_handler.element_name, (gpointer) &legacyUEP_handler);
461         g_hash_table_insert (config_handlers, (gpointer) aot_cache_handler.element_name, (gpointer) &aot_cache_handler);
462 }
463
464 /**
465  * mono_config_cleanup:
466  */
467 void
468 mono_config_cleanup (void)
469 {
470         if (config_handlers)
471                 g_hash_table_destroy (config_handlers);
472         g_free (mono_cfg_dir);
473 }
474
475 /* FIXME: error handling */
476
477 static void
478 mono_config_parse_xml_with_context (ParseState *state, const char *text, gsize len)
479 {
480         GMarkupParseContext *context;
481
482         if (!inited)
483                 mono_config_init ();
484
485         context = g_markup_parse_context_new (&mono_parser, (GMarkupParseFlags)0, state, NULL);
486         if (g_markup_parse_context_parse (context, text, len, NULL)) {
487                 g_markup_parse_context_end_parse (context, NULL);
488         }
489         g_markup_parse_context_free (context);
490 }
491
492 /* If assembly is NULL, parse in the global context */
493 static int
494 mono_config_parse_file_with_context (ParseState *state, const char *filename)
495 {
496         gchar *text;
497         gsize len;
498         gint offset;
499
500         mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_CONFIG,
501                         "Config attempting to parse: '%s'.", filename);
502
503         if (!g_file_get_contents (filename, &text, &len, NULL))
504                 return 0;
505
506         offset = 0;
507         if (len > 3 && text [0] == '\xef' && text [1] == (gchar) '\xbb' && text [2] == '\xbf')
508                 offset = 3; /* Skip UTF-8 BOM */
509         if (state->user_data == NULL)
510                 state->user_data = (gpointer) filename;
511         mono_config_parse_xml_with_context (state, text + offset, len - offset);
512         g_free (text);
513         return 1;
514 }
515
516 /**
517  * mono_config_parse_memory:
518  * \param buffer a pointer to an string XML representation of the configuration
519  * Parses the configuration from a buffer
520  */
521 void
522 mono_config_parse_memory (const char *buffer)
523 {
524         ParseState state = {NULL};
525
526         state.user_data = (gpointer) "<buffer>";
527         mono_config_parse_xml_with_context (&state, buffer, strlen (buffer));
528 }
529
530 static void
531 mono_config_parse_file (const char *filename)
532 {
533         ParseState state = {NULL};
534         state.user_data = (gpointer) filename;
535         mono_config_parse_file_with_context (&state, filename);
536 }
537
538 /* 
539  * use the equivalent lookup code from the GAC when available.
540  * Depending on state, this should give something like:
541  *      aname/version-pubtoken/
542  *      aname/version/
543  *      aname
544  */
545 static char*
546 get_assembly_filename (MonoImage *image, int state)
547 {
548         switch (state) {
549         case 0:
550                 return g_strdup (mono_image_get_name (image));
551         default:
552                 return NULL;
553         }
554 }
555
556 typedef struct _BundledConfig BundledConfig;
557
558 struct _BundledConfig {
559         BundledConfig *next;
560         const char* aname;
561         const char* config_xml;
562 };
563
564 static BundledConfig *bundled_configs = NULL;
565
566 static const char *bundled_machine_config = NULL;
567
568 /**
569  * mono_register_config_for_assembly:
570  */
571 void
572 mono_register_config_for_assembly (const char* assembly_name, const char* config_xml)
573 {
574         BundledConfig *bconfig;
575
576         bconfig = g_new0 (BundledConfig, 1);
577         bconfig->aname = assembly_name;
578         bconfig->config_xml = config_xml;
579         bconfig->next = bundled_configs;
580         bundled_configs = bconfig;
581 }
582
583 /**
584  * mono_config_string_for_assembly_file:
585  */
586 const char *
587 mono_config_string_for_assembly_file (const char *filename)
588 {
589         BundledConfig *bconfig;
590         
591         for (bconfig = bundled_configs; bconfig; bconfig = bconfig->next) {
592                 if (bconfig->aname && strcmp (bconfig->aname, filename) == 0)
593                         return bconfig->config_xml;
594         }
595         return NULL;
596 }
597
598 /**
599  * mono_config_for_assembly:
600  */
601 void 
602 mono_config_for_assembly (MonoImage *assembly)
603 {
604         ParseState state = {NULL};
605         int got_it = 0, i;
606         char *aname, *cfg, *cfg_name;
607         const char *bundled_config;
608         
609         state.assembly = assembly;
610
611         bundled_config = mono_config_string_for_assembly_file (assembly->module_name);
612         if (bundled_config) {
613                 state.user_data = (gpointer) "<bundled>";
614                 mono_config_parse_xml_with_context (&state, bundled_config, strlen (bundled_config));
615         }
616
617         cfg_name = g_strdup_printf ("%s.config", mono_image_get_filename (assembly));
618         mono_config_parse_file_with_context (&state, cfg_name);
619         g_free (cfg_name);
620
621         cfg_name = g_strdup_printf ("%s.config", mono_image_get_name (assembly));
622
623         for (i = 0; (aname = get_assembly_filename (assembly, i)) != NULL; ++i) {
624                 cfg = g_build_filename (mono_get_config_dir (), "mono", "assemblies", aname, cfg_name, NULL);
625                 got_it += mono_config_parse_file_with_context (&state, cfg);
626                 g_free (cfg);
627
628 #ifdef TARGET_WIN32
629                 const char *home = g_get_home_dir ();
630                 cfg = g_build_filename (home, ".mono", "assemblies", aname, cfg_name, NULL);
631                 got_it += mono_config_parse_file_with_context (&state, cfg);
632                 g_free (cfg);
633 #endif
634                 g_free (aname);
635                 if (got_it)
636                         break;
637         }
638         g_free (cfg_name);
639 }
640
641 /**
642  * mono_config_parse:
643  * \param filename the filename to load the configuration variables from.
644  * Pass a NULL filename to parse the default config files
645  * (or the file in the \c MONO_CONFIG env var).
646  */
647 void
648 mono_config_parse (const char *filename) {
649         const char *home;
650         char *mono_cfg;
651 #ifndef TARGET_WIN32
652         char *user_cfg;
653 #endif
654
655         if (filename) {
656                 mono_config_parse_file (filename);
657                 return;
658         }
659
660         // FIXME: leak, do we store any references to home
661         char *env_home = g_getenv ("MONO_CONFIG");
662         if (env_home) {
663                 mono_config_parse_file (env_home);
664                 return;
665         }
666
667         mono_cfg = g_build_filename (mono_get_config_dir (), "mono", "config", NULL);
668         mono_config_parse_file (mono_cfg);
669         g_free (mono_cfg);
670
671 #if !defined(TARGET_WIN32) && !defined(__native_client__)
672         home = g_get_home_dir ();
673         user_cfg = g_strconcat (home, G_DIR_SEPARATOR_S, ".mono/config", NULL);
674         mono_config_parse_file (user_cfg);
675         g_free (user_cfg);
676 #endif
677 }
678
679 /**
680  * mono_set_config_dir:
681  * Invoked during startup
682  */
683 void
684 mono_set_config_dir (const char *dir)
685 {
686         /* If this environment variable is set, overrides the directory computed */
687         char *env_mono_cfg_dir = g_getenv ("MONO_CFG_DIR");
688         if (env_mono_cfg_dir == NULL && dir != NULL)
689                 env_mono_cfg_dir = strdup (dir);
690
691         mono_cfg_dir = env_mono_cfg_dir;
692 }
693
694 /**
695  * mono_get_config_dir:
696  */
697 const char* 
698 mono_get_config_dir (void)
699 {
700         if (mono_cfg_dir == NULL)
701                 mono_set_dirs (NULL, NULL);
702
703         return mono_cfg_dir;
704 }
705
706 /**
707  * mono_register_machine_config:
708  */
709 void
710 mono_register_machine_config (const char *config_xml)
711 {
712         bundled_machine_config = config_xml;
713 }
714
715 /**
716  * mono_get_machine_config:
717  */
718 const char *
719 mono_get_machine_config (void)
720 {
721         return bundled_machine_config;
722 }
723
724 static void
725 assembly_binding_end (gpointer user_data, const char *element_name)
726 {
727         ParserUserData *pud = (ParserUserData *)user_data;
728
729         if (!strcmp (element_name, "dependentAssembly")) {
730                 if (pud->info_parsed && pud->info) {
731                         pud->info_parsed (pud->info, pud->user_data);
732                         g_free (pud->info->name);
733                         g_free (pud->info->culture);
734                 }
735         }
736 }
737
738 static void
739 publisher_policy_start (gpointer user_data,
740                 const gchar *element_name,
741                 const gchar **attribute_names,
742                 const gchar **attribute_values)
743 {
744         ParserUserData *pud;
745         MonoAssemblyBindingInfo *info;
746         int n;
747
748         pud = (ParserUserData *)user_data;
749         info = pud->info;
750         if (!strcmp (element_name, "dependentAssembly")) {
751                 info->name = NULL;
752                 info->culture = NULL;
753                 info->has_old_version_bottom = FALSE;
754                 info->has_old_version_top = FALSE;
755                 info->has_new_version = FALSE;
756                 info->is_valid = FALSE;
757                 memset (&info->old_version_bottom, 0, sizeof (info->old_version_bottom));
758                 memset (&info->old_version_top, 0, sizeof (info->old_version_top));
759                 memset (&info->new_version, 0, sizeof (info->new_version));
760         } else if (!strcmp (element_name, "assemblyIdentity")) {
761                 for (n = 0; attribute_names [n]; n++) {
762                         const gchar *attribute_name = attribute_names [n];
763                         
764                         if (!strcmp (attribute_name, "name"))
765                                 info->name = g_strdup (attribute_values [n]);
766                         else if (!strcmp (attribute_name, "publicKeyToken")) {
767                                 if (strlen (attribute_values [n]) == MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)
768                                         g_strlcpy ((char *) info->public_key_token, attribute_values [n], MONO_PUBLIC_KEY_TOKEN_LENGTH);
769                         } else if (!strcmp (attribute_name, "culture")) {
770                                 if (!strcmp (attribute_values [n], "neutral"))
771                                         info->culture = g_strdup ("");
772                                 else
773                                         info->culture = g_strdup (attribute_values [n]);
774                         }
775                 }
776         } else if (!strcmp (element_name, "bindingRedirect")) {
777                 for (n = 0; attribute_names [n]; n++) {
778                         const gchar *attribute_name = attribute_names [n];
779
780                         if (!strcmp (attribute_name, "oldVersion")) {
781                                 gchar **numbers, **version, **versions;
782                                 gint major, minor, build, revision;
783
784                                 /* Invalid value */
785                                 if (!strcmp (attribute_values [n], ""))
786                                         return;
787                                 
788                                 versions = g_strsplit (attribute_values [n], "-", 2);
789                                 version = g_strsplit (*versions, ".", 4);
790
791                                 /* We assign the values to gint vars to do the checks */
792                                 numbers = version;
793                                 major = *numbers ? atoi (*numbers++) : -1;
794                                 minor = *numbers ? atoi (*numbers++) : -1;
795                                 build = *numbers ? atoi (*numbers++) : -1;
796                                 revision = *numbers ? atoi (*numbers) : -1;
797                                 g_strfreev (version);
798                                 if (major < 0 || minor < 0 || build < 0 || revision < 0) {
799                                         g_strfreev (versions);
800                                         return;
801                                 }
802
803                                 info->old_version_bottom.major = major;
804                                 info->old_version_bottom.minor = minor;
805                                 info->old_version_bottom.build = build;
806                                 info->old_version_bottom.revision = revision;
807                                 info->has_old_version_bottom = TRUE;
808
809                                 if (!*(versions + 1)) {
810                                         g_strfreev (versions);
811                                         continue;
812                                 }
813                                 
814                                 numbers = version = g_strsplit (*(versions + 1), ".", 4);
815                                 major = *numbers ? atoi (*numbers++) : -1;
816                                 minor = *numbers ? atoi (*numbers++) : -1;
817                                 build = *numbers ? atoi (*numbers++) : -1;
818                                 revision = *numbers ? atoi (*numbers) : 1;
819                                 g_strfreev (version);
820                                 if (major < 0 || minor < 0 || build < 0 || revision < 0) {
821                                         g_strfreev (versions);
822                                         return;
823                                 }
824
825                                 info->old_version_top.major = major;
826                                 info->old_version_top.minor = minor;
827                                 info->old_version_top.build = build;
828                                 info->old_version_top.revision = revision;
829                                 info->has_old_version_top = TRUE;
830
831                                 g_strfreev (versions);
832                         } else if (!strcmp (attribute_name, "newVersion")) {
833                                 gchar **numbers, **version;
834
835                                 /* Invalid value */
836                                 if (!strcmp (attribute_values [n], ""))
837                                         return;
838
839                                 numbers = version = g_strsplit (attribute_values [n], ".", 4);
840                                 info->new_version.major = *numbers ? atoi (*numbers++) : -1;
841                                 info->new_version.minor = *numbers ? atoi (*numbers++) : -1;
842                                 info->new_version.build = *numbers ? atoi (*numbers++) : -1;
843                                 info->new_version.revision = *numbers ? atoi (*numbers) : -1;
844                                 info->has_new_version = TRUE;
845                                 g_strfreev (version);
846                         }
847                 }
848         }
849 }
850
851 static MonoParseHandler
852 publisher_policy_parser = {
853         "", /* We don't need to use declare an xml element */
854         NULL,
855         publisher_policy_start,
856         NULL,
857         NULL,
858         NULL
859 };
860
861 void
862 mono_config_parse_publisher_policy (const gchar *filename, MonoAssemblyBindingInfo *info)
863 {
864         ParserUserData user_data = {
865                 info,
866                 NULL,
867                 NULL
868         };
869         ParseState state = {
870                 &publisher_policy_parser, /* MonoParseHandler */
871                 &user_data, /* user_data */
872                 NULL, /* MonoImage (we don't need it right now)*/
873                 TRUE /* We are already inited */
874         };
875         
876         mono_config_parse_file_with_context (&state, filename);
877 }
878
879 static MonoParseHandler
880 config_assemblybinding_parser = {
881         "", /* We don't need to use declare an xml element */
882         NULL,
883         publisher_policy_start,
884         NULL,
885         assembly_binding_end,
886         NULL
887 };
888
889 void
890 mono_config_parse_assembly_bindings (const char *filename, int amajor, int aminor, void *user_data, void (*infocb)(MonoAssemblyBindingInfo *info, void *user_data))
891 {
892         MonoAssemblyBindingInfo info;
893         ParserUserData pud;
894         ParseState state;
895
896         info.major = amajor;
897         info.minor = aminor;
898
899         pud.info = &info;
900         pud.info_parsed = infocb;
901         pud.user_data = user_data;
902
903         state.current = &config_assemblybinding_parser;  /* MonoParseHandler */
904         state.user_data = &pud;
905         state.assembly = NULL; /* MonoImage (we don't need it right now)*/
906         state.inited = TRUE; /* We are already inited */
907
908         mono_config_parse_file_with_context (&state, filename);
909 }
910
911 static mono_bool mono_server_mode = FALSE;
912
913 /**
914  * mono_config_set_server_mode:
915  */
916 void
917 mono_config_set_server_mode (mono_bool server_mode)
918 {
919         mono_server_mode = server_mode;
920 }
921
922 /**
923  * mono_config_is_server_mode:
924  */
925 mono_bool
926 mono_config_is_server_mode (void)
927 {
928         return mono_server_mode;
929 }
930