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