/[zanavi_public1]/navit/navit/xmlconfig.c
ZANavi

Contents of /navit/navit/xmlconfig.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 27 - (hide annotations) (download)
Mon Apr 9 21:27:36 2012 UTC (12 years ago) by zoff99
File MIME type: text/plain
File size: 32347 byte(s)
lots of new stuff, tranlsations, bug fixes ...
1 zoff99 2 /**
2     * Navit, a modular navigation system.
3     * Copyright (C) 2005-2009 Navit Team
4     *
5     * This program is free software; you can redistribute it and/or
6     * modify it under the terms of the GNU General Public License
7     * version 2 as published by the Free Software Foundation.
8     *
9     * This program is distributed in the hope that it will be useful,
10     * but WITHOUT ANY WARRANTY; without even the implied warranty of
11     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12     * GNU General Public License for more details.
13     *
14     * You should have received a copy of the GNU General Public License
15     * along with this program; if not, write to the
16     * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     * Boston, MA 02110-1301, USA.
18     */
19    
20     /* see http://library.gnome.org/devel/glib/stable/glib-Simple-XML-Subset-Parser.html
21     * for details on how the xml file parser works.
22     */
23    
24     #include <stdlib.h>
25     #include <glib.h>
26     #include <glib/gprintf.h>
27     #include <string.h>
28     #include <ctype.h>
29     #include "debug.h"
30     #include "config.h"
31     #include "file.h"
32     #include "coord.h"
33     #include "layout.h"
34     #include "mapset.h"
35     #include "projection.h"
36     #include "map.h"
37     #include "navigation.h"
38     #include "navit.h"
39     #include "plugin.h"
40     #include "route.h"
41     #include "speech.h"
42     #include "track.h"
43     #include "vehicle.h"
44     #include "point.h"
45     #include "graphics.h"
46     #include "gui.h"
47     #include "osd.h"
48     #include "log.h"
49     #include "announcement.h"
50     #include "vehicleprofile.h"
51     #include "roadprofile.h"
52     #include "config_.h"
53     #include "xmlconfig.h"
54    
55     #ifdef HAVE_GLIB
56     #define ATTR_DISTANCE 1
57     const int xml_attr_distance=1;
58     #else
59     #include "ezxml.h"
60 zoff99 27 const int xml_attr_distance = 2;
61 zoff99 2 #define ATTR_DISTANCE 2
62     #define G_MARKUP_ERROR 0
63     #define G_MARKUP_ERROR_INVALID_CONTENT 0
64     #define G_MARKUP_ERROR_PARSE 0
65     #define G_MARKUP_ERROR_UNKNOWN_ELEMENT 0
66     typedef void * GMarkupParseContext;
67     #endif
68    
69 zoff99 27 struct xistate
70     {
71 zoff99 2 struct xistate *parent;
72     struct xistate *child;
73     const gchar *element;
74     const gchar **attribute_names;
75     const gchar **attribute_values;
76     };
77    
78 zoff99 27 struct xmldocument
79     {
80 zoff99 2 const gchar *href;
81     const gchar *xpointer;
82     gpointer user_data;
83     struct xistate *first;
84     struct xistate *last;
85     int active;
86     int level;
87     };
88    
89 zoff99 27 struct xmlstate
90     {
91 zoff99 2 const gchar **attribute_names;
92     const gchar **attribute_values;
93     struct xmlstate *parent;
94     struct attr element_attr;
95     const gchar *element;
96     xmlerror **error;
97     struct element_func *func;
98     struct object_func *object_func;
99     struct xmldocument *document;
100     };
101    
102 zoff99 27 struct attr_fixme
103     {
104 zoff99 2 char *element;
105     char **attr_fixme;
106     };
107    
108     static struct attr ** convert_to_attrs(struct xmlstate *state, struct attr_fixme *fixme)
109     {
110 zoff99 27 const gchar **attribute_name = state->attribute_names;
111     const gchar **attribute_value = state->attribute_values;
112 zoff99 2 const gchar *name;
113 zoff99 27 int count = 0;
114 zoff99 2 struct attr **ret;
115     static int fixme_count;
116    
117 zoff99 27 while (*attribute_name)
118     {
119 zoff99 2 count++;
120     attribute_name++;
121 zoff99 27 }ret=g_new(struct attr *, count+1);
122     attribute_name = state->attribute_names;
123     count = 0;
124     while (*attribute_name)
125     {
126     name = *attribute_name;
127     if (fixme)
128     {
129     char **attr_fixme = fixme->attr_fixme;
130     while (attr_fixme[0])
131     {
132     if (!strcmp(name, attr_fixme[0]))
133     {
134     name = attr_fixme[1];
135 zoff99 2 if (fixme_count++ < 10)
136 zoff99 27 {
137     //dbg(0,"Please change attribute '%s' to '%s' in <%s />\n",attr_fixme[0], attr_fixme[1], fixme->element);
138     }
139 zoff99 2 break;
140     }
141 zoff99 27 attr_fixme += 2;
142 zoff99 2 }
143     }
144 zoff99 27 ret[count] = attr_new_from_text(name, *attribute_value);
145 zoff99 2 if (ret[count])
146 zoff99 27 {
147 zoff99 2 count++;
148 zoff99 27 }
149     else if (strcmp(*attribute_name, "enabled") && strcmp(*attribute_name, "xmlns:xi"))
150     {
151     // dbg(0, "failed to create attribute '%s' with value '%s'\n", *attribute_name, *attribute_value);
152     }
153 zoff99 2 attribute_name++;
154     attribute_value++;
155     }
156 zoff99 27 ret[count] = NULL;
157     //dbg(1, "ret=%p\n", ret);
158 zoff99 2 return ret;
159     }
160    
161     static const char * find_attribute(struct xmlstate *state, const char *attribute, int required)
162     {
163 zoff99 27 const gchar **attribute_name = state->attribute_names;
164     const gchar **attribute_value = state->attribute_values;
165     while (*attribute_name)
166     {
167     if (!g_ascii_strcasecmp(attribute, *attribute_name))
168 zoff99 2 return *attribute_value;
169     attribute_name++;
170     attribute_value++;
171     }
172     if (required)
173 zoff99 27 g_set_error(state->error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "element '%s' is missing attribute '%s'", state->element, attribute);
174 zoff99 2 return NULL;
175     }
176    
177 zoff99 27 static int find_boolean(struct xmlstate *state, const char *attribute, int deflt, int required)
178 zoff99 2 {
179     const char *value;
180    
181 zoff99 27 value = find_attribute(state, attribute, required);
182     if (!value)
183 zoff99 2 return deflt;
184 zoff99 27 if (g_ascii_strcasecmp(value, "no") && g_ascii_strcasecmp(value, "0") && g_ascii_strcasecmp(value, "false"))
185 zoff99 2 return 1;
186     return 0;
187     }
188    
189     /**
190     * * Convert a string number to int
191     * *
192     * * @param val the string value to convert
193     * * @returns int value of converted string
194     * */
195 zoff99 27 static int convert_number(const char *val)
196 zoff99 2 {
197     if (val)
198 zoff99 27 return g_ascii_strtoull(val, NULL, 0);
199 zoff99 2 else
200     return 0;
201     }
202    
203 zoff99 27 static int xmlconfig_announce(struct xmlstate *state)
204 zoff99 2 {
205 zoff99 27 const char *type, *value;
206 zoff99 2 char key[32];
207     int level[3];
208     int i;
209     enum item_type itype;
210     char *tok, *type_str, *str;
211    
212 zoff99 27 type = find_attribute(state, "type", 1);
213     if (!type)
214 zoff99 2 return 0;
215 zoff99 27 for (i = 0; i < 3; i++)
216     {
217     sprintf(key, "level%d", i);
218     value = find_attribute(state, key, 0);
219 zoff99 2 if (value)
220 zoff99 27 level[i] = convert_number(value);
221 zoff99 2 else
222 zoff99 27 level[i] = -1;
223 zoff99 2 }
224 zoff99 27 type_str = g_strdup(type);
225     str = type_str;
226     while ((tok = strtok(str, ",")))
227     {
228     itype = item_from_name(tok);
229 zoff99 2 navigation_set_announce(state->parent->element_attr.u.data, itype, level);
230 zoff99 27 str = NULL;
231 zoff99 2 }
232     g_free(type_str);
233     return 1;
234     }
235     /**
236     * * Define the elements in our config
237     * *
238     * */
239    
240     #define NEW(x) (void *(*)(struct attr *, struct attr **))(x)
241     #define GET(x) (int (*)(void *, enum attr_type type, struct attr *attr, struct attr_iter *iter))(x)
242     #define ITERN(x) (struct attr_iter * (*)(void *))(x)
243     #define ITERD(x) (void (*)(struct attr_iter *iter))(x)
244     #define SET(x) (int (*)(void *, struct attr *attr))(x)
245     #define ADD(x) (int (*)(void *, struct attr *attr))(x)
246     #define REMOVE(x) (int (*)(void *, struct attr *attr))(x)
247     #define INIT(x) (int (*)(void *))(x)
248     #define DESTROY(x) (void (*)(void *))(x)
249    
250 zoff99 27 static struct object_func object_funcs[] =
251     {
252     { attr_announcement, NEW(announcement_new), GET(announcement_get_attr), NULL, NULL, SET(announcement_set_attr), ADD(announcement_add_attr) },
253     { attr_arrows, NEW(arrows_new) },
254     { attr_circle, NEW(circle_new), NULL, NULL, NULL, NULL, ADD(element_add_attr) },
255     { attr_config, NEW(config_new), GET(config_get_attr), ITERN(config_attr_iter_new), ITERD(config_attr_iter_destroy), SET(config_set_attr), ADD(config_add_attr), REMOVE(config_remove_attr), NULL, DESTROY(config_destroy) },
256     { attr_coord, NEW(coord_new_from_attrs) },
257     { attr_cursor, NEW(cursor_new), NULL, NULL, NULL, NULL, ADD(cursor_add_attr) },
258     { attr_debug, NEW(debug_new) },
259     { attr_graphics, NEW(graphics_new) },
260     { attr_gui, NEW(gui_new), GET(gui_get_attr), NULL, NULL, SET(gui_set_attr), ADD(gui_add_attr) },
261     { attr_icon, NEW(icon_new), NULL, NULL, NULL, NULL, ADD(element_add_attr) },
262     { attr_image, NEW(image_new) },
263     { attr_itemgra, NEW(itemgra_new), NULL, NULL, NULL, NULL, ADD(itemgra_add_attr) },
264     { attr_layer, NEW(layer_new), NULL, NULL, NULL, NULL, ADD(layer_add_attr) },
265     { attr_layout, NEW(layout_new), NULL, NULL, NULL, NULL, ADD(layout_add_attr) },
266     { attr_log, NEW(log_new) },
267     { attr_map, NEW(map_new) },
268     { attr_mapset, NEW(mapset_new), NULL, NULL, NULL, NULL, ADD(mapset_add_attr_name) },
269     { attr_navigation, NEW(navigation_new), GET(navigation_get_attr) },
270     { attr_navit, NEW(navit_new), GET(navit_get_attr), ITERN(navit_attr_iter_new), ITERD(navit_attr_iter_destroy), SET(navit_set_attr), ADD(navit_add_attr), REMOVE(navit_remove_attr), INIT(navit_init), DESTROY(navit_destroy) },
271     { attr_osd, NEW(osd_new) },
272     { attr_plugins, NEW(plugins_new), NULL, NULL, NULL, NULL, NULL, NULL, INIT(plugins_init) },
273     { attr_plugin, NEW(plugin_new) },
274     { attr_polygon, NEW(polygon_new), NULL, NULL, NULL, NULL, ADD(element_add_attr) },
275     { attr_polyline, NEW(polyline_new), NULL, NULL, NULL, NULL, ADD(element_add_attr) },
276     { attr_roadprofile, NEW(roadprofile_new), GET(roadprofile_get_attr), NULL, NULL, SET(roadprofile_set_attr), ADD(roadprofile_add_attr) },
277     { attr_route, NEW(route_new), GET(route_get_attr), NULL, NULL, SET(route_set_attr), ADD(route_add_attr), REMOVE(route_remove_attr) },
278     { attr_speech, NEW(speech_new), GET(speech_get_attr), NULL, NULL, SET(speech_set_attr) },
279     { attr_text, NEW(text_new) },
280     { attr_tracking, NEW(tracking_new) },
281     { attr_vehicle, NEW(vehicle_new), GET(vehicle_get_attr), NULL, NULL, SET(vehicle_set_attr), ADD(vehicle_add_attr), REMOVE(vehicle_remove_attr) },
282     { attr_vehicleprofile, NEW(vehicleprofile_new), GET(vehicleprofile_get_attr), NULL, NULL, SET(vehicleprofile_set_attr), ADD(vehicleprofile_add_attr) }, };
283 zoff99 2
284     struct object_func *
285     object_func_lookup(enum attr_type type)
286     {
287     int i;
288 zoff99 27 for (i = 0; i < sizeof(object_funcs) / sizeof(struct object_func); i++)
289     {
290 zoff99 2 if (object_funcs[i].type == type)
291     return &object_funcs[i];
292     }
293     return NULL;
294     }
295    
296 zoff99 27 struct element_func
297     {
298 zoff99 2 char *name;
299     char *parent;
300     int (*func)(struct xmlstate *state);
301     enum attr_type type;
302     };
303     struct element_func *elements;
304    
305 zoff99 27 static char *attr_fixme_itemgra[] =
306     { "type", "item_types", NULL, NULL, };
307 zoff99 2
308 zoff99 27 static char *attr_fixme_text[] =
309     { "label_size", "text_size", NULL, NULL, };
310 zoff99 2
311 zoff99 27 static char *attr_fixme_circle[] =
312     { "label_size", "text_size", NULL, NULL, };
313 zoff99 2
314 zoff99 27 static struct attr_fixme attr_fixmes[] =
315     {
316     { "item", attr_fixme_itemgra },
317     { "itemgra", attr_fixme_itemgra },
318     { "text", attr_fixme_text },
319     { "label", attr_fixme_text },
320     { "circle", attr_fixme_circle },
321     { NULL, NULL }, };
322 zoff99 2
323 zoff99 27 static char *element_fixmes[] =
324     { "item", "itemgra", "label", "text", NULL, NULL, };
325 zoff99 2
326 zoff99 27 static void initStatic(void)
327     {
328 zoff99 2 elements=g_new0(struct element_func,40); //39 is a number of elements + ending NULL element
329    
330 zoff99 27 elements[0].name = "config";
331     elements[0].parent = NULL;
332     elements[0].func = NULL;
333     elements[0].type = attr_config;
334 zoff99 2
335 zoff99 27 elements[1].name = "announce";
336     elements[1].parent = "navigation";
337     elements[1].func = xmlconfig_announce;
338 zoff99 2
339 zoff99 27 elements[2].name = "speech";
340     elements[2].parent = "navit";
341     elements[2].func = NULL;
342     elements[2].type = attr_speech;
343 zoff99 2
344 zoff99 27 elements[3].name = "tracking";
345     elements[3].parent = "navit";
346     elements[3].func = NULL;
347     elements[3].type = attr_tracking;
348 zoff99 2
349 zoff99 27 elements[4].name = "route";
350     elements[4].parent = "navit";
351     elements[4].func = NULL;
352     elements[4].type = attr_route;
353 zoff99 2
354 zoff99 27 elements[5].name = "mapset";
355     elements[5].parent = "navit";
356     elements[5].func = NULL;
357     elements[5].type = attr_mapset;
358 zoff99 2
359 zoff99 27 elements[6].name = "map";
360     elements[6].parent = "mapset";
361     elements[6].func = NULL;
362     elements[6].type = attr_map;
363 zoff99 2
364 zoff99 27 elements[7].name = "debug";
365     elements[7].parent = "config";
366     elements[7].func = NULL;
367     elements[7].type = attr_debug;
368 zoff99 2
369 zoff99 27 elements[8].name = "osd";
370     elements[8].parent = "navit";
371     elements[8].func = NULL;
372     elements[8].type = attr_osd;
373 zoff99 2
374 zoff99 27 elements[9].name = "navigation";
375     elements[9].parent = "navit";
376     elements[9].func = NULL;
377     elements[9].type = attr_navigation;
378 zoff99 2
379 zoff99 27 elements[10].name = "navit";
380     elements[10].parent = "config";
381     elements[10].func = NULL;
382     elements[10].type = attr_navit;
383 zoff99 2
384 zoff99 27 elements[11].name = "graphics";
385     elements[11].parent = "navit";
386     elements[11].func = NULL;
387     elements[11].type = attr_graphics;
388 zoff99 2
389 zoff99 27 elements[12].name = "gui";
390     elements[12].parent = "navit";
391     elements[12].func = NULL;
392     elements[12].type = attr_gui;
393 zoff99 2
394 zoff99 27 elements[13].name = "layout";
395     elements[13].parent = "navit";
396     elements[13].func = NULL;
397     elements[13].type = attr_layout;
398 zoff99 2
399 zoff99 27 elements[14].name = "cursor";
400     elements[14].parent = "layout";
401     elements[14].func = NULL;
402     elements[14].type = attr_cursor;
403 zoff99 2
404 zoff99 27 elements[15].name = "layer";
405     elements[15].parent = "layout";
406     elements[15].func = NULL;
407     elements[15].type = attr_layer;
408 zoff99 2
409 zoff99 27 elements[16].name = "itemgra";
410     elements[16].parent = "layer";
411     elements[16].func = NULL;
412     elements[16].type = attr_itemgra;
413 zoff99 2
414 zoff99 27 elements[17].name = "circle";
415     elements[17].parent = "itemgra";
416     elements[17].func = NULL;
417     elements[17].type = attr_circle;
418 zoff99 2
419 zoff99 27 elements[18].name = "coord";
420     elements[18].parent = "circle";
421     elements[18].func = NULL;
422     elements[18].type = attr_coord;
423 zoff99 2
424 zoff99 27 elements[19].name = "icon";
425     elements[19].parent = "itemgra";
426     elements[19].func = NULL;
427     elements[19].type = attr_icon;
428 zoff99 2
429 zoff99 27 elements[20].name = "coord";
430     elements[20].parent = "icon";
431     elements[20].func = NULL;
432     elements[20].type = attr_coord;
433 zoff99 2
434 zoff99 27 elements[21].name = "image";
435     elements[21].parent = "itemgra";
436     elements[21].func = NULL;
437     elements[21].type = attr_image;
438 zoff99 2
439 zoff99 27 elements[22].name = "text";
440     elements[22].parent = "itemgra";
441     elements[22].func = NULL;
442     elements[22].type = attr_text;
443 zoff99 2
444 zoff99 27 elements[23].name = "polygon";
445     elements[23].parent = "itemgra";
446     elements[23].func = NULL;
447     elements[23].type = attr_polygon;
448 zoff99 2
449 zoff99 27 elements[24].name = "coord";
450     elements[24].parent = "polygon";
451     elements[24].func = NULL;
452     elements[24].type = attr_coord;
453 zoff99 2
454 zoff99 27 elements[25].name = "polyline";
455     elements[25].parent = "itemgra";
456     elements[25].func = NULL;
457     elements[25].type = attr_polyline;
458 zoff99 2
459 zoff99 27 elements[26].name = "coord";
460     elements[26].parent = "polyline";
461     elements[26].func = NULL;
462     elements[26].type = attr_coord;
463 zoff99 2
464 zoff99 27 elements[27].name = "arrows";
465     elements[27].parent = "itemgra";
466     elements[27].func = NULL;
467     elements[27].type = attr_arrows;
468 zoff99 2
469 zoff99 27 elements[28].name = "vehicle";
470     elements[28].parent = "navit";
471     elements[28].func = NULL;
472     elements[28].type = attr_vehicle;
473 zoff99 2
474 zoff99 27 elements[29].name = "vehicleprofile";
475     elements[29].parent = "navit";
476     elements[29].func = NULL;
477     elements[29].type = attr_vehicleprofile;
478 zoff99 2
479 zoff99 27 elements[30].name = "roadprofile";
480     elements[30].parent = "vehicleprofile";
481     elements[30].func = NULL;
482     elements[30].type = attr_roadprofile;
483 zoff99 2
484 zoff99 27 elements[31].name = "announcement";
485     elements[31].parent = "roadprofile";
486     elements[31].func = NULL;
487     elements[31].type = attr_announcement;
488 zoff99 2
489 zoff99 27 elements[32].name = "cursor";
490     elements[32].parent = "vehicle";
491     elements[32].func = NULL;
492     elements[32].type = attr_cursor;
493 zoff99 2
494 zoff99 27 elements[33].name = "itemgra";
495     elements[33].parent = "cursor";
496     elements[33].func = NULL;
497     elements[33].type = attr_itemgra;
498 zoff99 2
499 zoff99 27 elements[34].name = "log";
500     elements[34].parent = "vehicle";
501     elements[34].func = NULL;
502     elements[34].type = attr_log;
503 zoff99 2
504 zoff99 27 elements[35].name = "log";
505     elements[35].parent = "navit";
506     elements[35].func = NULL;
507     elements[35].type = attr_log;
508 zoff99 2
509 zoff99 27 elements[36].name = "plugins";
510     elements[36].parent = "config";
511     elements[36].func = NULL;
512     elements[36].type = attr_plugins;
513 zoff99 2
514 zoff99 27 elements[37].name = "plugin";
515     elements[37].parent = "plugins";
516     elements[37].func = NULL;
517     elements[37].type = attr_plugin;
518 zoff99 2 }
519    
520     /**
521     * * Parse the opening tag of a config element
522     * *
523     * * @param context document parse context
524     * * @param element_name the current tag name
525     * * @param attribute_names ptr to return the set of attribute names
526     * * @param attribute_values ptr return the set of attribute values
527     * * @param user_data ptr to xmlstate structure
528     * * @param error ptr return error context
529     * * @returns nothing
530     * */
531    
532 zoff99 27 static void start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, xmlerror **error)
533 zoff99 2 {
534 zoff99 27 struct xmlstate *new = NULL, **parent = user_data;
535     struct element_func *e = elements, *func = NULL;
536     struct attr_fixme *attr_fixme = attr_fixmes;
537     char **element_fixme = element_fixmes;
538     int found = 0;
539 zoff99 2 static int fixme_count;
540 zoff99 27 const char *parent_name = NULL;
541     char *s, *sep = "", *possible_parents;
542 zoff99 2 struct attr *parent_attr;
543 zoff99 27 // dbg(2, "name='%s' parent='%s'\n", element_name, *parent ? (*parent)->element : NULL);
544 zoff99 2
545 zoff99 27 if (!strcmp(element_name, "xml"))
546 zoff99 2 return;
547     /* determine if we have to fix any attributes */
548 zoff99 27 while (attr_fixme[0].element)
549     {
550     if (!strcmp(element_name, attr_fixme[0].element))
551 zoff99 2 break;
552     attr_fixme++;
553     }
554     if (!attr_fixme[0].element)
555 zoff99 27 attr_fixme = NULL;
556 zoff99 2
557     /* tell user to fix deprecated element names */
558 zoff99 27 while (element_fixme[0])
559     {
560     if (!strcmp(element_name, element_fixme[0]))
561     {
562     element_name = element_fixme[1];
563 zoff99 2 if (fixme_count++ < 10)
564 zoff99 27 {
565     // dbg(0, "Please change <%s /> to <%s /> in config file\n",element_fixme[0], element_fixme[1]);
566     }
567 zoff99 2 }
568 zoff99 27 element_fixme += 2;
569 zoff99 2 }
570     /* validate that this element is valid
571     * and that the element has a valid parent */
572 zoff99 27 possible_parents = g_strdup("");
573 zoff99 2 if (*parent)
574 zoff99 27 parent_name = (*parent)->element;
575     while (e->name)
576     {
577     if (!g_ascii_strcasecmp(element_name, e->name))
578     {
579     found = 1;
580     s = g_strconcat(possible_parents, sep, e->parent, NULL);
581 zoff99 2 g_free(possible_parents);
582 zoff99 27 possible_parents = s;
583     sep = ",";
584     if ((parent_name && e->parent && !g_ascii_strcasecmp(parent_name, e->parent)) || (!parent_name && !e->parent))
585     func = e;
586 zoff99 2 }
587     e++;
588     }
589 zoff99 27 if (!found)
590     {
591     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "Unknown element '%s'", element_name);
592 zoff99 2 g_free(possible_parents);
593     return;
594     }
595 zoff99 27 if (!func)
596     {
597     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "Element '%s' within unexpected context '%s'. Expected '%s'%s", element_name, parent_name, possible_parents,
598     !strcmp(possible_parents, "config") ? "\nPlease add <config> </config> tags at the beginning/end of your navit.xml" : "");
599 zoff99 2 g_free(possible_parents);
600     return;
601     }
602     g_free(possible_parents);
603    
604     new=g_new(struct xmlstate, 1);
605 zoff99 27 new->attribute_names = attribute_names;
606     new->attribute_values = attribute_values;
607     new->parent = *parent;
608     new->element_attr.u.data = NULL;
609     new->element = element_name;
610     new->error = error;
611     new->func = func;
612     new->object_func = NULL;
613     *parent = new;
614 zoff99 2 if (!find_boolean(new, "enabled", 1, 0))
615     return;
616     if (new->parent && !new->parent->element_attr.u.data)
617     return;
618 zoff99 27 if (func->func)
619     {
620     if (!func->func(new))
621     {
622 zoff99 2 return;
623     }
624 zoff99 27 }
625     else
626     {
627 zoff99 2 struct attr **attrs;
628    
629 zoff99 27 new->object_func = object_func_lookup(func->type);
630     if (!new->object_func)
631 zoff99 2 return;
632 zoff99 27 attrs = convert_to_attrs(new, attr_fixme);
633     new->element_attr.type = attr_none;
634 zoff99 2 if (!new->parent || new->parent->element_attr.type == attr_none)
635 zoff99 27 parent_attr = NULL;
636 zoff99 2 else
637 zoff99 27 parent_attr = &new->parent->element_attr;
638 zoff99 2 new->element_attr.u.data = new->object_func->create(parent_attr, attrs);
639 zoff99 27 if (!new->element_attr.u.data)
640 zoff99 2 return;
641 zoff99 27 new->element_attr.type = attr_from_name(element_name);
642 zoff99 2 if (new->element_attr.type == attr_none)
643 zoff99 27 {
644     // dbg(0, "failed to create object of type '%s'\n", element_name);
645     }
646 zoff99 2 if (new->parent && new->parent->object_func && new->parent->object_func->add_attr)
647     new->parent->object_func->add_attr(new->parent->element_attr.u.data, &new->element_attr);
648     }
649     return;
650     }
651    
652     /* Called for close tags </foo> */
653 zoff99 27 static void end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, xmlerror **error)
654 zoff99 2 {
655     struct xmlstate *curr, **state = user_data;
656    
657 zoff99 27 if (!strcmp(element_name, "xml"))
658     {
659 zoff99 2 return;
660 zoff99 27 }
661     // dbg(2, "name='%s'\n", element_name);
662     curr = *state;
663 zoff99 2 if (curr->object_func && curr->object_func->init)
664     curr->object_func->init(curr->element_attr.u.data);
665 zoff99 27 *state = curr->parent;
666 zoff99 2 g_free(curr);
667     }
668    
669     static gboolean parse_file(struct xmldocument *document, xmlerror **error);
670    
671 zoff99 27 static void xinclude(GMarkupParseContext *context, const gchar **attribute_names, const gchar **attribute_values, struct xmldocument *doc_old, xmlerror **error)
672 zoff99 2 {
673     struct xmldocument doc_new;
674     struct file_wordexp *we;
675 zoff99 27 int i, count;
676     const char *href = NULL;
677 zoff99 2 char **we_files;
678    
679 zoff99 27 if (doc_old->level >= 16)
680     {
681     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "xi:include recursion too deep");
682 zoff99 2 return;
683     }
684     memset(&doc_new, 0, sizeof(doc_new));
685 zoff99 27 i = 0;
686     while (attribute_names[i])
687     {
688     if (!g_ascii_strcasecmp("href", attribute_names[i]))
689     {
690 zoff99 2 if (!href)
691 zoff99 27 href = attribute_values[i];
692     else
693     {
694     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has more than one href");
695 zoff99 2 return;
696     }
697 zoff99 27 }
698     else if (!g_ascii_strcasecmp("xpointer", attribute_names[i]))
699     {
700 zoff99 2 if (!doc_new.xpointer)
701 zoff99 27 doc_new.xpointer = attribute_values[i];
702     else
703     {
704     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has more than one xpointer");
705 zoff99 2 return;
706     }
707 zoff99 27 }
708     else
709     {
710     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has invalid attributes");
711 zoff99 2 return;
712     }
713     i++;
714     }
715 zoff99 27 if (!doc_new.xpointer && !href)
716     {
717     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "xi:include has neither href nor xpointer");
718 zoff99 2 return;
719     }
720 zoff99 27 doc_new.level = doc_old->level + 1;
721     doc_new.user_data = doc_old->user_data;
722     if (!href)
723     {
724     //dbg(1, "no href, using '%s'\n", doc_old->href);
725     doc_new.href = doc_old->href;
726     if (file_exists(doc_new.href))
727     {
728     parse_file(&doc_new, error);
729 zoff99 2 }
730 zoff99 27 else
731     {
732     //dbg(0, "Unable to include %s\n", doc_new.href);
733     }
734     }
735     else
736     {
737     //dbg(1, "expanding '%s'\n", href);
738     we = file_wordexp_new(href);
739     we_files = file_wordexp_get_array(we);
740     count = file_wordexp_get_count(we);
741     //dbg(1, "%d results\n", count);
742     if (file_exists(we_files[0]))
743     {
744     for (i = 0; i < count; i++)
745     {
746     //dbg(1, "result[%d]='%s'\n", i, we_files[i]);
747     doc_new.href = we_files[i];
748 zoff99 2 parse_file(&doc_new, error);
749     }
750     }
751 zoff99 27 else
752     {
753     //dbg(0, "Unable to include %s\n", we_files[0]);
754     }
755 zoff99 2 file_wordexp_destroy(we);
756    
757     }
758    
759     }
760    
761 zoff99 27 static int strncmp_len(const char *s1, int s1len, const char *s2)
762 zoff99 2 {
763     int ret;
764     #if 0
765     char c[s1len+1];
766     strncpy(c, s1, s1len);
767     c[s1len]='\0';
768 zoff99 27 //dbg(0,"'%s' vs '%s'\n", c, s2);
769 zoff99 2 #endif
770    
771 zoff99 27 ret = strncmp(s1, s2, s1len);
772 zoff99 2 if (ret)
773     return ret;
774 zoff99 27 return strlen(s2) - s1len;
775 zoff99 2 }
776    
777 zoff99 27 static int xpointer_value(const char *test, int len, struct xistate *elem, const char **out, int out_len)
778 zoff99 2 {
779 zoff99 27 int i, ret = 0;
780     if (len <= 0 || out_len <= 0)
781     {
782 zoff99 2 return 0;
783     }
784 zoff99 27 if (!(strncmp_len(test, len, "name(.)")))
785     {
786     out[0] = elem->element;
787 zoff99 2 return 1;
788     }
789 zoff99 27 if (test[0] == '@')
790     {
791     i = 0;
792     while (elem->attribute_names[i] && out_len > 0)
793     {
794     if (!strncmp_len(test + 1, len - 1, elem->attribute_names[i]))
795     {
796     out[ret++] = elem->attribute_values[i];
797 zoff99 2 out_len--;
798     }
799     i++;
800     }
801     return ret;
802     }
803     return 0;
804     }
805    
806 zoff99 27 static int xpointer_test(const char *test, int len, struct xistate *elem)
807 zoff99 2 {
808 zoff99 27 int eq, i, count, vlen, cond_req = 1, cond = 0;
809 zoff99 2 char c;
810     const char *tmp[16];
811     #if 0
812     char test2[len+1];
813    
814     strncpy(test2, test, len);
815     test2[len]='\0';
816 zoff99 27 //dbg(0,"%s\n", test2);
817 zoff99 2 #endif
818     if (!len)
819     return 0;
820 zoff99 27 c = test[len - 1];
821 zoff99 2 if (c != '\'' && c != '"')
822     return 0;
823 zoff99 27 eq = strcspn(test, "=");
824     if (eq >= len || test[eq + 1] != c)
825 zoff99 2 return 0;
826 zoff99 27 vlen = eq;
827     if (eq > 0 && test[eq - 1] == '!')
828     {
829     cond_req = 0;
830 zoff99 2 vlen--;
831     }
832 zoff99 27 count = xpointer_value(test, vlen, elem, tmp, 16);
833     for (i = 0; i < count; i++)
834     {
835     if (!strncmp_len(test + eq + 2, len - eq - 3, tmp[i]))
836     cond = 1;
837 zoff99 2 }
838     if (cond == cond_req)
839     return 1;
840     return 0;
841     }
842    
843 zoff99 27 static int xpointer_element_match(const char *xpointer, int len, struct xistate *elem)
844 zoff99 2 {
845 zoff99 27 int start, tlen, tlen2;
846 zoff99 2 #if 0
847     char test2[len+1];
848    
849     strncpy(test2, xpointer, len);
850     test2[len]='\0';
851 zoff99 27 //dbg(0,"%s\n", test2);
852 zoff99 2 #endif
853 zoff99 27 start = strcspn(xpointer, "[");
854 zoff99 2 if (start > len)
855 zoff99 27 start = len;
856 zoff99 2 if (strncmp_len(xpointer, start, elem->element) && (start != 1 || xpointer[0] != '*'))
857     return 0;
858     if (start == len)
859     return 1;
860 zoff99 27 if (xpointer[len - 1] != ']')
861 zoff99 2 return 0;
862 zoff99 27 tlen = len - start - 2;
863     for (;;)
864     {
865 zoff99 2 start++;
866 zoff99 27 tlen2 = strcspn(xpointer + start, "]");
867 zoff99 2 if (start + tlen2 > len)
868     return 1;
869 zoff99 27 if (!xpointer_test(xpointer + start, tlen2, elem))
870 zoff99 2 return 0;
871 zoff99 27 start += tlen2 + 1;
872 zoff99 2 }
873     }
874    
875 zoff99 27 static int xpointer_xpointer_match(const char *xpointer, int len, struct xistate *first)
876 zoff99 2 {
877     const char *c;
878     int s;
879 zoff99 27 //dbg(2, "%s\n", xpointer);
880 zoff99 2 if (xpointer[0] != '/')
881     return 0;
882 zoff99 27 c = xpointer + 1;
883 zoff99 2 len--;
884 zoff99 27 do
885     {
886     s = strcspn(c, "/");
887 zoff99 2 if (s > len)
888 zoff99 27 s = len;
889     if (!xpointer_element_match(c, s, first))
890 zoff99 2 return 0;
891 zoff99 27 first = first->child;
892     c += s + 1;
893     len -= s + 1;
894     }
895     while (len > 0 && first);
896 zoff99 2 if (len > 0)
897     return 0;
898     return 1;
899     }
900    
901 zoff99 27 static int xpointer_match(const char *xpointer, struct xistate *first)
902 zoff99 2 {
903 zoff99 27 char *prefix = "xpointer(";
904 zoff99 2 int len;
905 zoff99 27 if (!xpointer)
906 zoff99 2 return 1;
907 zoff99 27 len = strlen(xpointer);
908     if (strncmp(xpointer, prefix, strlen(prefix)))
909 zoff99 2 return 0;
910 zoff99 27 if (xpointer[len - 1] != ')')
911 zoff99 2 return 0;
912 zoff99 27 return xpointer_xpointer_match(xpointer + strlen(prefix), len - strlen(prefix) - 1, first);
913 zoff99 2
914     }
915    
916 zoff99 27 static void xi_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, xmlerror **error)
917 zoff99 2 {
918 zoff99 27 struct xmldocument *doc = user_data;
919 zoff99 2 struct xistate *xistate;
920 zoff99 27 int i, count = 0;
921     while (attribute_names[count++ * ATTR_DISTANCE])
922     ;xistate=g_new0(struct xistate, 1);
923     xistate->element = element_name;
924 zoff99 2 xistate->attribute_names=g_new0(const char *, count);
925     xistate->attribute_values=g_new0(const char *, count);
926 zoff99 27 for (i = 0; i < count; i++)
927     {
928     if (attribute_names[i * ATTR_DISTANCE] && attribute_values[i * ATTR_DISTANCE])
929     {
930     xistate->attribute_names[i] = g_strdup(attribute_names[i * ATTR_DISTANCE]);
931     xistate->attribute_values[i] = g_strdup(attribute_values[i * ATTR_DISTANCE]);
932 zoff99 2 }
933     }
934 zoff99 27 xistate->parent = doc->last;
935 zoff99 2
936 zoff99 27 if (doc->last)
937     {
938     doc->last->child = xistate;
939     }
940     else
941     doc->first = xistate;
942     doc->last = xistate;
943     if (doc->active > 0 || xpointer_match(doc->xpointer, doc->first))
944     {
945     if (!g_ascii_strcasecmp("xi:include", element_name))
946     {
947 zoff99 2 xinclude(context, xistate->attribute_names, xistate->attribute_values, doc, error);
948     return;
949     }
950     start_element(context, element_name, xistate->attribute_names, xistate->attribute_values, doc->user_data, error);
951     doc->active++;
952     }
953    
954     }
955     /**
956     * * Reached closing tag of a config element
957     * *
958     * * @param context
959     * * @param element name
960     * * @param user_data ptr to xmldocument
961     * * @param error ptr to struct for error information
962     * * @returns nothing
963     * */
964    
965 zoff99 27 static void xi_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, xmlerror **error)
966 zoff99 2 {
967 zoff99 27 struct xmldocument *doc = user_data;
968     struct xistate *xistate = doc->last;
969     int i = 0;
970     doc->last = doc->last->parent;
971     if (!doc->last)
972     doc->first = NULL;
973 zoff99 2 else
974 zoff99 27 doc->last->child = NULL;
975     if (doc->active > 0)
976     {
977     if (!g_ascii_strcasecmp("xi:include", element_name))
978     {
979 zoff99 2 return;
980     }
981     end_element(context, element_name, doc->user_data, error);
982     doc->active--;
983     }
984 zoff99 27 while (xistate->attribute_names[i])
985     {
986     g_free((char *) (xistate->attribute_names[i]));
987     g_free((char *) (xistate->attribute_values[i]));
988 zoff99 2 i++;
989     }
990     g_free(xistate->attribute_names);
991     g_free(xistate->attribute_values);
992     g_free(xistate);
993     }
994    
995     /* Called for character data */
996     /* text is not nul-terminated */
997 zoff99 27 static void xi_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, xmlerror **error)
998 zoff99 2 {
999 zoff99 27 struct xmldocument *doc = user_data;
1000 zoff99 2 int i;
1001 zoff99 27 if (doc->active)
1002     {
1003     for (i = 0; i < text_len; i++)
1004     {
1005     if (!isspace(text[i]))
1006     {
1007     struct xmldocument *doc = user_data;
1008 zoff99 2 struct xmlstate *curr, **state = doc->user_data;
1009     struct attr attr;
1010 zoff99 27 char *text_dup = malloc(text_len + 1);
1011 zoff99 2
1012 zoff99 27 curr = *state;
1013 zoff99 2 strncpy(text_dup, text, text_len);
1014 zoff99 27 text_dup[text_len] = '\0';
1015     attr.type = attr_xml_text;
1016     attr.u.str = text_dup;
1017 zoff99 2 if (curr->object_func && curr->object_func->add_attr && curr->element_attr.u.data)
1018     curr->object_func->add_attr(curr->element_attr.u.data, &attr);
1019     free(text_dup);
1020     return;
1021     }
1022     }
1023     }
1024     }
1025    
1026     #ifndef HAVE_GLIB
1027 zoff99 27 static void parse_node_text(ezxml_t node, void *data, void(*start)(void *, const char *, const char **, const char **, void *, void *), void(*end)(void *, const char *, void *, void *), void(*text)(void *, const char *, int, void *, void *))
1028 zoff99 2 {
1029 zoff99 27 while (node)
1030     {
1031 zoff99 2 if (start)
1032 zoff99 27 start(NULL, node->name, (const char **) node->attr, (const char **) (node->attr + 1), data, NULL);
1033 zoff99 2 if (text && node->txt)
1034     text(NULL, node->txt, strlen(node->txt), data, NULL);
1035     if (node->child)
1036     parse_node_text(node->child, data, start, end, text);
1037     if (end)
1038     end(NULL, node->name, data, NULL);
1039 zoff99 27 node = node->ordered;
1040 zoff99 2 }
1041     }
1042     #endif
1043    
1044 zoff99 27 void xml_parse_text(const char *document, void *data, void(*start)(void *, const char *, const char **, const char **, void *, void *), void(*end)(void *, const char *, void *, void *), void(*text)(void *, const char *, int, void *, void *))
1045 zoff99 2 {
1046     #ifdef HAVE_GLIB
1047 zoff99 27 GMarkupParser parser =
1048     { start, end, text, NULL, NULL};
1049 zoff99 2 GMarkupParseContext *context;
1050     gboolean result;
1051    
1052     context = g_markup_parse_context_new (&parser, 0, data, NULL);
1053     result = g_markup_parse_context_parse (context, document, strlen(document), NULL);
1054     g_markup_parse_context_free (context);
1055     #else
1056 zoff99 27 char *str = g_strdup(document);
1057 zoff99 2 ezxml_t root = ezxml_parse_str(str, strlen(str));
1058     if (!root)
1059     return;
1060     parse_node_text(root, data, start, end, text);
1061     ezxml_free(root);
1062     g_free(str);
1063     #endif
1064     }
1065    
1066     #ifdef HAVE_GLIB
1067    
1068 zoff99 27 static const GMarkupParser parser =
1069     {
1070 zoff99 2 xi_start_element,
1071     xi_end_element,
1072     xi_text,
1073     NULL,
1074     NULL
1075     };
1076     /**
1077     * * Parse the contents of the configuration file
1078     * *
1079     * * @param document struct holding info about the config file
1080     * * @param error info on any errors detected
1081     * * @returns boolean TRUE or FALSE
1082     * */
1083    
1084     static gboolean
1085     parse_file(struct xmldocument *document, xmlerror **error)
1086     {
1087     GMarkupParseContext *context;
1088     gchar *contents, *message;
1089     gsize len;
1090     gint line, chr;
1091     gboolean result;
1092     char *xmldir,*newxmldir,*xmlfile,*newxmlfile,*sep;
1093    
1094 zoff99 27 //dbg(1,"enter filename='%s'\n", document->href);
1095 zoff99 2 #if GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION < 12
1096     #define G_MARKUP_TREAT_CDATA_AS_TEXT 0
1097     #endif
1098     context = g_markup_parse_context_new (&parser, G_MARKUP_TREAT_CDATA_AS_TEXT, document, NULL);
1099    
1100 zoff99 27 if (!g_file_get_contents (document->href, &contents, &len, error))
1101     {
1102 zoff99 2 g_markup_parse_context_free (context);
1103     return FALSE;
1104     }
1105     xmldir=getenv("XMLDIR");
1106     xmlfile=getenv("XMLFILE");
1107     newxmlfile=g_strdup(document->href);
1108     newxmldir=g_strdup(document->href);
1109 zoff99 27 if ((sep=strrchr(newxmldir,'/')))
1110     *sep='\0';
1111     else
1112     {
1113 zoff99 2 g_free(newxmldir);
1114     newxmldir=g_strdup(".");
1115     }
1116     setenv("XMLDIR",newxmldir,1);
1117     setenv("XMLFILE",newxmlfile,1);
1118     document->active=document->xpointer ? 0:1;
1119     document->first=NULL;
1120     document->last=NULL;
1121     result = g_markup_parse_context_parse (context, contents, len, error);
1122 zoff99 27 if (!result && error && *error)
1123     {
1124 zoff99 2 g_markup_parse_context_get_position(context, &line, &chr);
1125     message=g_strdup_printf("%s at line %d, char %d\n", (*error)->message, line, chr);
1126     g_free((*error)->message);
1127     (*error)->message=message;
1128     }
1129     g_markup_parse_context_free (context);
1130     g_free (contents);
1131     if (xmldir)
1132 zoff99 27 setenv("XMLDIR",xmldir,1);
1133 zoff99 2 else
1134     #ifndef __MINGW32__
1135 zoff99 27 unsetenv("XMLDIR");
1136 zoff99 2 #else
1137 zoff99 27 putenv("XMLDIR=");
1138 zoff99 2 #endif /* __MINGW32__ */
1139     if (xmlfile)
1140 zoff99 27 setenv("XMLFILE",xmlfile,1);
1141 zoff99 2 else
1142     #ifndef __MINGW32__
1143 zoff99 27 unsetenv("XMLFILE");
1144 zoff99 2 #else
1145 zoff99 27 putenv("XMLFILE=");
1146 zoff99 2 #endif /* __MINGW32__ */
1147     g_free(newxmldir);
1148     g_free(newxmlfile);
1149 zoff99 27 //dbg(1,"return %d\n", result);
1150 zoff99 2
1151     return result;
1152     }
1153     #else
1154 zoff99 27 static void parse_node(struct xmldocument *document, ezxml_t node)
1155 zoff99 2 {
1156 zoff99 27 while (node)
1157     {
1158     xi_start_element(NULL, node->name, node->attr, node->attr + 1, document, NULL);
1159 zoff99 2 if (node->txt)
1160 zoff99 27 {
1161     xi_text(NULL, node->txt, strlen(node->txt), document, NULL);
1162     }
1163 zoff99 2 if (node->child)
1164 zoff99 27 {
1165 zoff99 2 parse_node(document, node->child);
1166 zoff99 27 }
1167     xi_end_element(NULL, node->name, document, NULL);
1168     node = node->ordered;
1169 zoff99 2 }
1170     }
1171    
1172 zoff99 27 static gboolean parse_file(struct xmldocument *document, xmlerror **error)
1173 zoff99 2 {
1174     FILE *f;
1175     ezxml_t root;
1176    
1177 zoff99 27 f = fopen(document->href, "rb");
1178 zoff99 2 if (!f)
1179     return FALSE;
1180     root = ezxml_parse_fp(f);
1181     fclose(f);
1182     if (!root)
1183     return FALSE;
1184 zoff99 27 document->active = document->xpointer ? 0 : 1;
1185     document->first = NULL;
1186     document->last = NULL;
1187 zoff99 2
1188     parse_node(document, root);
1189    
1190     return TRUE;
1191     }
1192     #endif
1193    
1194     /**
1195     * * Load and parse the master config file
1196     * *
1197     * * @param filename FQFN of the file
1198     * * @param error ptr to error details, if any
1199     * * @returns boolean TRUE or FALSE (if error detected)
1200     * */
1201    
1202     gboolean config_load(const char *filename, xmlerror **error)
1203     {
1204     struct xmldocument document;
1205 zoff99 27 struct xmlstate *curr = NULL;
1206 zoff99 2 gboolean result;
1207    
1208     initStatic();
1209    
1210 zoff99 27 //dbg(1, "enter filename='%s'\n", filename);
1211 zoff99 2 memset(&document, 0, sizeof(document));
1212 zoff99 27 document.href = filename;
1213     document.user_data = &curr;
1214     result = parse_file(&document, error);
1215     if (result && curr)
1216     {
1217     g_set_error(error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "element '%s' not closed", curr->element);
1218     result = FALSE;
1219 zoff99 2 }
1220 zoff99 27 //dbg(1, "return %d\n", result);
1221 zoff99 2 return result;
1222     }
1223    

   
Visit the ZANavi Wiki