]> git.street.me.uk Git - andy/viking.git/blame - src/vikgotoxmltool.c
Fix a minor missing include
[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 *
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
42static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass );
43static void _goto_xml_tool_init ( VikGotoXmlTool *self );
51f93b0b 44
0c6b26d3 45static void _goto_xml_tool_finalize ( GObject *gob );
51f93b0b 46
0c6b26d3
GB
47static gchar *_goto_xml_tool_get_url_format ( VikGotoTool *self );
48static gboolean _goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll);
51f93b0b 49
34e71b99 50typedef struct _VikGotoXmlToolPrivate VikGotoXmlToolPrivate;
51f93b0b 51
34e71b99 52struct _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 67GType 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
91enum
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
102static 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
176static 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 214static 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 280VikGotoXmlTool *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 285static 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 298static void _goto_xml_tool_finalize ( GObject *gob )
51f93b0b
GB
299{
300 G_OBJECT_GET_CLASS(gob)->finalize(gob);
301}
302
303static gboolean
304stack_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"> */
333static 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 */
374static 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
397static 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
475static 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}