]>
Commit | Line | Data |
---|---|---|
51f93b0b GB |
1 | /* |
2 | * viking -- GPS Data and Topo Analyzer, Explorer, and Manager | |
3 | * | |
4 | * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net> | |
d260d798 | 5 | * Copyright (C) 2009, Guilhem Bonnefille <guilhem.bonnefille@gmail.com> |
51f93b0b GB |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
20 | * | |
51f93b0b GB |
21 | */ |
22 | #ifdef HAVE_CONFIG_H | |
23 | #include "config.h" | |
24 | #endif | |
25 | #include <stdlib.h> | |
26 | #include <stdio.h> | |
27 | #include <string.h> | |
bc9cecab | 28 | #ifdef HAVE_MATH_H |
fc4142a1 | 29 | #include <math.h> |
bc9cecab | 30 | #endif |
51f93b0b GB |
31 | #include <glib.h> |
32 | #include <glib/gstdio.h> | |
33 | #include <glib/gprintf.h> | |
34 | #include <glib/gi18n.h> | |
35 | ||
36 | #include "viking.h" | |
51f93b0b | 37 | |
34e71b99 | 38 | #include "vikgotoxmltool.h" |
51f93b0b GB |
39 | |
40 | ||
0c6b26d3 GB |
41 | static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ); |
42 | static void _goto_xml_tool_init ( VikGotoXmlTool *self ); | |
51f93b0b | 43 | |
0c6b26d3 | 44 | static void _goto_xml_tool_finalize ( GObject *gob ); |
51f93b0b | 45 | |
0c6b26d3 GB |
46 | static gchar *_goto_xml_tool_get_url_format ( VikGotoTool *self ); |
47 | static gboolean _goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll); | |
51f93b0b | 48 | |
34e71b99 | 49 | typedef struct _VikGotoXmlToolPrivate VikGotoXmlToolPrivate; |
51f93b0b | 50 | |
34e71b99 | 51 | struct _VikGotoXmlToolPrivate |
51f93b0b GB |
52 | { |
53 | gchar *url_format; | |
54 | gchar *lat_path; | |
e0b9ef7a | 55 | gchar *lat_attr; |
51f93b0b | 56 | gchar *lon_path; |
e0b9ef7a | 57 | gchar *lon_attr; |
51f93b0b GB |
58 | |
59 | struct LatLon ll; | |
60 | }; | |
61 | ||
34e71b99 GB |
62 | #define GOTO_XML_TOOL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ |
63 | VIK_GOTO_XML_TOOL_TYPE, \ | |
64 | VikGotoXmlToolPrivate)) | |
51f93b0b | 65 | |
34e71b99 | 66 | GType vik_goto_xml_tool_get_type() |
51f93b0b GB |
67 | { |
68 | static GType w_type = 0; | |
69 | ||
70 | if (!w_type) | |
71 | { | |
72 | static const GTypeInfo w_info = | |
73 | { | |
34e71b99 | 74 | sizeof (VikGotoXmlToolClass), |
51f93b0b GB |
75 | NULL, /* base_init */ |
76 | NULL, /* base_finalize */ | |
0c6b26d3 | 77 | (GClassInitFunc) _goto_xml_tool_class_init, |
51f93b0b GB |
78 | NULL, /* class_finalize */ |
79 | NULL, /* class_data */ | |
34e71b99 | 80 | sizeof (VikGotoXmlTool), |
51f93b0b | 81 | 0, |
0c6b26d3 | 82 | (GInstanceInitFunc) _goto_xml_tool_init, |
51f93b0b | 83 | }; |
34e71b99 | 84 | w_type = g_type_register_static ( VIK_GOTO_TOOL_TYPE, "VikGotoXmlTool", &w_info, 0 ); |
51f93b0b GB |
85 | } |
86 | ||
87 | return w_type; | |
88 | } | |
89 | ||
90 | enum | |
91 | { | |
92 | PROP_0, | |
93 | ||
94 | PROP_URL_FORMAT, | |
95 | PROP_LAT_PATH, | |
e0b9ef7a | 96 | PROP_LAT_ATTR, |
51f93b0b | 97 | PROP_LON_PATH, |
e0b9ef7a | 98 | PROP_LON_ATTR, |
51f93b0b GB |
99 | }; |
100 | ||
101 | static void | |
0c6b26d3 GB |
102 | _goto_xml_tool_set_property (GObject *object, |
103 | guint property_id, | |
104 | const GValue *value, | |
105 | GParamSpec *pspec) | |
51f93b0b | 106 | { |
34e71b99 GB |
107 | VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object); |
108 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); | |
87b8d3d4 | 109 | gchar **splitted = NULL; |
51f93b0b GB |
110 | |
111 | switch (property_id) | |
112 | { | |
113 | case PROP_URL_FORMAT: | |
114 | g_free (priv->url_format); | |
115 | priv->url_format = g_value_dup_string (value); | |
116 | break; | |
117 | ||
118 | case PROP_LAT_PATH: | |
87b8d3d4 | 119 | splitted = g_strsplit (g_value_get_string (value), "@", 2); |
51f93b0b | 120 | g_free (priv->lat_path); |
87b8d3d4 GB |
121 | priv->lat_path = splitted[0]; |
122 | if (splitted[1]) | |
123 | { | |
124 | g_object_set (object, "lat-attr", splitted[1], NULL); | |
125 | g_free (splitted[1]); | |
126 | } | |
127 | /* only free the tab, not the strings */ | |
128 | g_free (splitted); | |
129 | splitted = NULL; | |
51f93b0b GB |
130 | break; |
131 | ||
e0b9ef7a | 132 | case PROP_LAT_ATTR: |
87b8d3d4 GB |
133 | /* Avoid to overwrite XPATH value */ |
134 | /* NB: This disable future overwriting, | |
135 | but as property is CONSTRUCT_ONLY there is no matter */ | |
136 | if (!priv->lat_attr || g_value_get_string (value)) | |
137 | { | |
138 | g_free (priv->lat_attr); | |
139 | priv->lat_attr = g_value_dup_string (value); | |
140 | } | |
e0b9ef7a GB |
141 | break; |
142 | ||
51f93b0b | 143 | case PROP_LON_PATH: |
87b8d3d4 | 144 | splitted = g_strsplit (g_value_get_string (value), "@", 2); |
51f93b0b | 145 | g_free (priv->lon_path); |
87b8d3d4 GB |
146 | priv->lon_path = splitted[0]; |
147 | if (splitted[1]) | |
148 | { | |
149 | g_object_set (object, "lon-attr", splitted[1], NULL); | |
150 | g_free (splitted[1]); | |
151 | } | |
152 | /* only free the tab, not the strings */ | |
153 | g_free (splitted); | |
154 | splitted = NULL; | |
51f93b0b GB |
155 | break; |
156 | ||
e0b9ef7a | 157 | case PROP_LON_ATTR: |
87b8d3d4 GB |
158 | /* Avoid to overwrite XPATH value */ |
159 | /* NB: This disable future overwriting, | |
160 | but as property is CONSTRUCT_ONLY there is no matter */ | |
161 | if (!priv->lon_attr || g_value_get_string (value)) | |
162 | { | |
163 | g_free (priv->lon_attr); | |
164 | priv->lon_attr = g_value_dup_string (value); | |
165 | } | |
e0b9ef7a GB |
166 | break; |
167 | ||
51f93b0b GB |
168 | default: |
169 | /* We don't have any other property... */ | |
170 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); | |
171 | break; | |
172 | } | |
173 | } | |
174 | ||
175 | static void | |
0c6b26d3 GB |
176 | _goto_xml_tool_get_property (GObject *object, |
177 | guint property_id, | |
178 | GValue *value, | |
179 | GParamSpec *pspec) | |
51f93b0b | 180 | { |
34e71b99 GB |
181 | VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object); |
182 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); | |
51f93b0b GB |
183 | |
184 | switch (property_id) | |
185 | { | |
186 | case PROP_URL_FORMAT: | |
187 | g_value_set_string (value, priv->url_format); | |
188 | break; | |
189 | ||
190 | case PROP_LAT_PATH: | |
191 | g_value_set_string (value, priv->lat_path); | |
192 | break; | |
193 | ||
e0b9ef7a GB |
194 | case PROP_LAT_ATTR: |
195 | g_value_set_string (value, priv->lat_attr); | |
196 | break; | |
197 | ||
51f93b0b GB |
198 | case PROP_LON_PATH: |
199 | g_value_set_string (value, priv->lon_path); | |
200 | break; | |
201 | ||
e0b9ef7a GB |
202 | case PROP_LON_ATTR: |
203 | g_value_set_string (value, priv->lon_attr); | |
204 | break; | |
205 | ||
51f93b0b GB |
206 | default: |
207 | /* We don't have any other property... */ | |
208 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); | |
209 | break; | |
210 | } | |
211 | } | |
212 | ||
0c6b26d3 | 213 | static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) |
51f93b0b GB |
214 | { |
215 | GObjectClass *object_class; | |
34e71b99 | 216 | VikGotoToolClass *parent_class; |
51f93b0b GB |
217 | GParamSpec *pspec; |
218 | ||
219 | object_class = G_OBJECT_CLASS (klass); | |
220 | ||
0c6b26d3 GB |
221 | object_class->finalize = _goto_xml_tool_finalize; |
222 | object_class->set_property = _goto_xml_tool_set_property; | |
223 | object_class->get_property = _goto_xml_tool_get_property; | |
51f93b0b GB |
224 | |
225 | ||
226 | pspec = g_param_spec_string ("url-format", | |
227 | "URL format", | |
228 | "The format of the URL", | |
229 | "<no-set>" /* default value */, | |
230 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); | |
231 | g_object_class_install_property (object_class, | |
232 | PROP_URL_FORMAT, | |
233 | pspec); | |
234 | ||
235 | pspec = g_param_spec_string ("lat-path", | |
e0b9ef7a | 236 | "Latitude path", |
51f93b0b GB |
237 | "XPath of the latitude", |
238 | "<no-set>" /* default value */, | |
239 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); | |
240 | g_object_class_install_property (object_class, | |
241 | PROP_LAT_PATH, | |
242 | pspec); | |
243 | ||
e0b9ef7a GB |
244 | pspec = g_param_spec_string ("lat-attr", |
245 | "Latitude attribute", | |
246 | "XML attribute of the latitude", | |
247 | NULL /* default value */, | |
248 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); | |
249 | g_object_class_install_property (object_class, | |
250 | PROP_LAT_ATTR, | |
251 | pspec); | |
252 | ||
51f93b0b | 253 | pspec = g_param_spec_string ("lon-path", |
e0b9ef7a | 254 | "Longitude path", |
51f93b0b GB |
255 | "XPath of the longitude", |
256 | "<no-set>" /* default value */, | |
257 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); | |
258 | g_object_class_install_property (object_class, | |
259 | PROP_LON_PATH, | |
260 | pspec); | |
261 | ||
e0b9ef7a GB |
262 | pspec = g_param_spec_string ("lon-attr", |
263 | "Longitude attribute", | |
264 | "XML attribute of the longitude", | |
265 | NULL /* default value */, | |
266 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); | |
267 | g_object_class_install_property (object_class, | |
268 | PROP_LON_ATTR, | |
269 | pspec); | |
270 | ||
34e71b99 | 271 | parent_class = VIK_GOTO_TOOL_CLASS (klass); |
51f93b0b | 272 | |
0c6b26d3 GB |
273 | parent_class->get_url_format = _goto_xml_tool_get_url_format; |
274 | parent_class->parse_file_for_latlon = _goto_xml_tool_parse_file_for_latlon; | |
51f93b0b | 275 | |
34e71b99 | 276 | g_type_class_add_private (klass, sizeof (VikGotoXmlToolPrivate)); |
51f93b0b GB |
277 | } |
278 | ||
34e71b99 | 279 | VikGotoXmlTool *vik_goto_xml_tool_new () |
51f93b0b | 280 | { |
34e71b99 | 281 | return VIK_GOTO_XML_TOOL ( g_object_new ( VIK_GOTO_XML_TOOL_TYPE, "label", "Google", NULL ) ); |
51f93b0b GB |
282 | } |
283 | ||
0c6b26d3 | 284 | static void _goto_xml_tool_init ( VikGotoXmlTool *self ) |
51f93b0b | 285 | { |
34e71b99 | 286 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); |
51f93b0b GB |
287 | priv->url_format = NULL; |
288 | priv->lat_path = NULL; | |
e0b9ef7a | 289 | priv->lat_attr = NULL; |
51f93b0b | 290 | priv->lon_path = NULL; |
e0b9ef7a | 291 | priv->lon_attr = NULL; |
bc9cecab GB |
292 | // |
293 | priv->ll.lat = NAN; | |
294 | priv->ll.lon = NAN; | |
51f93b0b GB |
295 | } |
296 | ||
0c6b26d3 | 297 | static void _goto_xml_tool_finalize ( GObject *gob ) |
51f93b0b GB |
298 | { |
299 | G_OBJECT_GET_CLASS(gob)->finalize(gob); | |
300 | } | |
301 | ||
302 | static gboolean | |
303 | stack_is_path (const GSList *stack, | |
304 | const gchar *path) | |
305 | { | |
bc9cecab | 306 | gboolean equal = TRUE; |
b146adc7 | 307 | int stack_len = g_list_length((GList *)stack); |
bc9cecab GB |
308 | int i = 0; |
309 | i = stack_len - 1; | |
310 | while (equal == TRUE && i >= 0) | |
311 | { | |
312 | if (*path != '/') | |
313 | equal = FALSE; | |
314 | else | |
315 | path++; | |
b146adc7 | 316 | const gchar *current = g_list_nth_data((GList *)stack, i); |
bc9cecab GB |
317 | size_t len = strlen(current); |
318 | if (strncmp(path, current, len) != 0 ) | |
319 | equal = FALSE; | |
320 | else | |
321 | { | |
322 | path += len; | |
323 | } | |
324 | i--; | |
325 | } | |
326 | if (*path != '\0') | |
327 | equal = FALSE; | |
51f93b0b GB |
328 | return equal; |
329 | } | |
330 | ||
e0b9ef7a GB |
331 | /* Called for open tags <foo bar="baz"> */ |
332 | static void | |
333 | _start_element (GMarkupParseContext *context, | |
334 | const gchar *element_name, | |
335 | const gchar **attribute_names, | |
336 | const gchar **attribute_values, | |
337 | gpointer user_data, | |
338 | GError **error) | |
339 | { | |
340 | VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (user_data); | |
341 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); | |
342 | const GSList *stack = g_markup_parse_context_get_element_stack (context); | |
343 | /* Longitude */ | |
344 | if (priv->lon_attr != NULL && isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path)) | |
345 | { | |
346 | int i=0; | |
347 | while (attribute_names[i] != NULL) | |
348 | { | |
349 | if (strcmp (attribute_names[i], priv->lon_attr) == 0) | |
350 | { | |
351 | priv->ll.lon = g_ascii_strtod(attribute_values[i], NULL); | |
352 | } | |
353 | i++; | |
354 | } | |
355 | } | |
356 | /* Latitude */ | |
357 | if (priv->lat_attr != NULL && isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path)) | |
358 | { | |
359 | int i=0; | |
360 | while (attribute_names[i] != NULL) | |
361 | { | |
362 | if (strcmp (attribute_names[i], priv->lat_attr) == 0) | |
363 | { | |
364 | priv->ll.lat = g_ascii_strtod(attribute_values[i], NULL); | |
365 | } | |
366 | i++; | |
367 | } | |
368 | } | |
369 | } | |
370 | ||
51f93b0b GB |
371 | /* Called for character data */ |
372 | /* text is not nul-terminated */ | |
373 | static void | |
374 | _text (GMarkupParseContext *context, | |
375 | const gchar *text, | |
376 | gsize text_len, | |
377 | gpointer user_data, | |
378 | GError **error) | |
379 | { | |
34e71b99 GB |
380 | VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (user_data); |
381 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); | |
51f93b0b | 382 | const GSList *stack = g_markup_parse_context_get_element_stack (context); |
bc9cecab | 383 | gchar *textl = g_strndup(text, text_len); |
039bdd14 | 384 | /* Store only first result */ |
e0b9ef7a | 385 | if (priv->lat_attr == NULL && isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path)) |
51f93b0b | 386 | { |
bc9cecab | 387 | priv->ll.lat = g_ascii_strtod(textl, NULL); |
51f93b0b | 388 | } |
e0b9ef7a | 389 | if (priv->lon_attr == NULL && isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path)) |
51f93b0b | 390 | { |
bc9cecab | 391 | priv->ll.lon = g_ascii_strtod(textl, NULL); |
51f93b0b | 392 | } |
bc9cecab | 393 | g_free(textl); |
51f93b0b GB |
394 | } |
395 | ||
396 | static gboolean | |
0c6b26d3 | 397 | _goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll) |
51f93b0b GB |
398 | { |
399 | GMarkupParser xml_parser; | |
7a7bab00 GB |
400 | GMarkupParseContext *xml_context = NULL; |
401 | GError *error = NULL; | |
34e71b99 | 402 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); |
0c6b26d3 | 403 | g_return_val_if_fail(priv != NULL, FALSE); |
51f93b0b | 404 | |
87b8d3d4 GB |
405 | g_debug ("%s: %s@%s, %s@%s", |
406 | __FUNCTION__, | |
407 | priv->lat_path, priv->lat_attr, | |
408 | priv->lon_path, priv->lon_attr); | |
409 | ||
51f93b0b GB |
410 | FILE *file = g_fopen (filename, "r"); |
411 | if (file == NULL) | |
412 | /* TODO emit warning */ | |
413 | return FALSE; | |
414 | ||
415 | /* setup context parse (ie callbacks) */ | |
e0b9ef7a GB |
416 | if (priv->lat_attr != NULL || priv->lon_attr != NULL) |
417 | // At least one coordinate uses an attribute | |
418 | xml_parser.start_element = &_start_element; | |
419 | else | |
420 | xml_parser.start_element = NULL; | |
51f93b0b | 421 | xml_parser.end_element = NULL; |
e0b9ef7a GB |
422 | if (priv->lat_attr == NULL || priv->lon_attr == NULL) |
423 | // At least one coordinate uses a raw element | |
424 | xml_parser.text = &_text; | |
425 | else | |
426 | xml_parser.text = NULL; | |
51f93b0b GB |
427 | xml_parser.passthrough = NULL; |
428 | xml_parser.error = NULL; | |
429 | ||
430 | xml_context = g_markup_parse_context_new(&xml_parser, 0, self, NULL); | |
bc9cecab GB |
431 | |
432 | /* setup result */ | |
433 | priv->ll.lat = NAN; | |
434 | priv->ll.lon = NAN; | |
51f93b0b GB |
435 | |
436 | gchar buff[BUFSIZ]; | |
437 | size_t nb; | |
7a7bab00 GB |
438 | while (xml_context && |
439 | (nb = fread (buff, sizeof(gchar), BUFSIZ, file)) > 0) | |
51f93b0b GB |
440 | { |
441 | if (!g_markup_parse_context_parse(xml_context, buff, nb, &error)) | |
7a7bab00 GB |
442 | { |
443 | fprintf(stderr, "%s: parsing error: %s.\n", | |
444 | __FUNCTION__, error->message); | |
445 | g_markup_parse_context_free(xml_context); | |
446 | xml_context = NULL; | |
447 | } | |
448 | g_clear_error (&error); | |
51f93b0b GB |
449 | } |
450 | /* cleanup */ | |
7a7bab00 GB |
451 | if (xml_context && |
452 | !g_markup_parse_context_end_parse(xml_context, &error)) | |
453 | fprintf(stderr, "%s: errors occurred while reading file: %s.\n", | |
454 | __FUNCTION__, error->message); | |
455 | g_clear_error (&error); | |
51f93b0b | 456 | |
7a7bab00 GB |
457 | if (xml_context) |
458 | g_markup_parse_context_free(xml_context); | |
459 | xml_context = NULL; | |
51f93b0b GB |
460 | fclose (file); |
461 | ||
462 | if (ll != NULL) | |
463 | { | |
51f93b0b GB |
464 | *ll = priv->ll; |
465 | } | |
466 | ||
bc9cecab GB |
467 | if (isnan(priv->ll.lat) || isnan(priv->ll.lat)) |
468 | /* At least one coordinate not found */ | |
469 | return FALSE; | |
470 | else | |
471 | return TRUE; | |
51f93b0b GB |
472 | } |
473 | ||
0c6b26d3 GB |
474 | static gchar * |
475 | _goto_xml_tool_get_url_format ( VikGotoTool *self ) | |
51f93b0b | 476 | { |
34e71b99 | 477 | VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); |
0c6b26d3 GB |
478 | g_return_val_if_fail(priv != NULL, NULL); |
479 | return priv->url_format; | |
51f93b0b | 480 | } |