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