X-Git-Url: https://git.street.me.uk/andy/viking.git/blobdiff_plain/b146adc790532ca69e6d43c563cb36ef5b076f2b..e96fe99dfb8c926ba4c6ee558380cc3f7f5241bc:/src/vikgotoxmltool.c diff --git a/src/vikgotoxmltool.c b/src/vikgotoxmltool.c index 06767f58..d0b6a009 100644 --- a/src/vikgotoxmltool.c +++ b/src/vikgotoxmltool.c @@ -35,18 +35,17 @@ #include #include "viking.h" -#include "util.h" -#include "curl_download.h" #include "vikgotoxmltool.h" -static void vik_goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ); -static void vik_goto_xml_tool_init ( VikGotoXmlTool *vwd ); +static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ); +static void _goto_xml_tool_init ( VikGotoXmlTool *self ); -static void vik_goto_xml_tool_finalize ( GObject *gob ); +static void _goto_xml_tool_finalize ( GObject *gob ); -static int vik_goto_xml_tool_get_coord ( VikGotoTool *self, VikWindow *vw, VikViewport *vvp, gchar *srch_str, VikCoord *coord ); +static gchar *_goto_xml_tool_get_url_format ( VikGotoTool *self ); +static gboolean _goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll); typedef struct _VikGotoXmlToolPrivate VikGotoXmlToolPrivate; @@ -54,7 +53,9 @@ struct _VikGotoXmlToolPrivate { gchar *url_format; gchar *lat_path; + gchar *lat_attr; gchar *lon_path; + gchar *lon_attr; struct LatLon ll; }; @@ -74,12 +75,12 @@ GType vik_goto_xml_tool_get_type() sizeof (VikGotoXmlToolClass), NULL, /* base_init */ NULL, /* base_finalize */ - (GClassInitFunc) vik_goto_xml_tool_class_init, + (GClassInitFunc) _goto_xml_tool_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (VikGotoXmlTool), 0, - (GInstanceInitFunc) vik_goto_xml_tool_init, + (GInstanceInitFunc) _goto_xml_tool_init, }; w_type = g_type_register_static ( VIK_GOTO_TOOL_TYPE, "VikGotoXmlTool", &w_info, 0 ); } @@ -93,17 +94,20 @@ enum PROP_URL_FORMAT, PROP_LAT_PATH, + PROP_LAT_ATTR, PROP_LON_PATH, + PROP_LON_ATTR, }; static void -xml_goto_tool_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) +_goto_xml_tool_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) { VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object); VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); + gchar **splitted = NULL; switch (property_id) { @@ -113,13 +117,53 @@ xml_goto_tool_set_property (GObject *object, break; case PROP_LAT_PATH: + splitted = g_strsplit (g_value_get_string (value), "@", 2); g_free (priv->lat_path); - priv->lat_path = g_value_dup_string (value); + priv->lat_path = splitted[0]; + if (splitted[1]) + { + g_object_set (object, "lat-attr", splitted[1], NULL); + g_free (splitted[1]); + } + /* only free the tab, not the strings */ + g_free (splitted); + splitted = NULL; + break; + + case PROP_LAT_ATTR: + /* Avoid to overwrite XPATH value */ + /* NB: This disable future overwriting, + but as property is CONSTRUCT_ONLY there is no matter */ + if (!priv->lat_attr || g_value_get_string (value)) + { + g_free (priv->lat_attr); + priv->lat_attr = g_value_dup_string (value); + } break; case PROP_LON_PATH: + splitted = g_strsplit (g_value_get_string (value), "@", 2); g_free (priv->lon_path); - priv->lon_path = g_value_dup_string (value); + priv->lon_path = splitted[0]; + if (splitted[1]) + { + g_object_set (object, "lon-attr", splitted[1], NULL); + g_free (splitted[1]); + } + /* only free the tab, not the strings */ + g_free (splitted); + splitted = NULL; + break; + + case PROP_LON_ATTR: + /* Avoid to overwrite XPATH value */ + /* NB: This disable future overwriting, + but as property is CONSTRUCT_ONLY there is no matter */ + if (!priv->lon_attr || g_value_get_string (value)) + { + g_free (priv->lon_attr); + priv->lon_attr = g_value_dup_string (value); + } break; default: @@ -130,10 +174,10 @@ xml_goto_tool_set_property (GObject *object, } static void -xml_goto_tool_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) +_goto_xml_tool_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) { VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object); VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); @@ -148,10 +192,18 @@ xml_goto_tool_get_property (GObject *object, g_value_set_string (value, priv->lat_path); break; + case PROP_LAT_ATTR: + g_value_set_string (value, priv->lat_attr); + break; + case PROP_LON_PATH: g_value_set_string (value, priv->lon_path); break; + case PROP_LON_ATTR: + g_value_set_string (value, priv->lon_attr); + break; + default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -159,7 +211,7 @@ xml_goto_tool_get_property (GObject *object, } } -static void vik_goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) +static void _goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) { GObjectClass *object_class; VikGotoToolClass *parent_class; @@ -167,9 +219,9 @@ static void vik_goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) object_class = G_OBJECT_CLASS (klass); - object_class->finalize = vik_goto_xml_tool_finalize; - object_class->set_property = xml_goto_tool_set_property; - object_class->get_property = xml_goto_tool_get_property; + object_class->finalize = _goto_xml_tool_finalize; + object_class->set_property = _goto_xml_tool_set_property; + object_class->get_property = _goto_xml_tool_get_property; pspec = g_param_spec_string ("url-format", @@ -182,7 +234,7 @@ static void vik_goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) pspec); pspec = g_param_spec_string ("lat-path", - "Lat path", + "Latitude path", "XPath of the latitude", "" /* default value */, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); @@ -190,8 +242,17 @@ static void vik_goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) PROP_LAT_PATH, pspec); + pspec = g_param_spec_string ("lat-attr", + "Latitude attribute", + "XML attribute of the latitude", + NULL /* default value */, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_LAT_ATTR, + pspec); + pspec = g_param_spec_string ("lon-path", - "Lon path", + "Longitude path", "XPath of the longitude", "" /* default value */, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); @@ -199,9 +260,19 @@ static void vik_goto_xml_tool_class_init ( VikGotoXmlToolClass *klass ) PROP_LON_PATH, pspec); + pspec = g_param_spec_string ("lon-attr", + "Longitude attribute", + "XML attribute of the longitude", + NULL /* default value */, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + g_object_class_install_property (object_class, + PROP_LON_ATTR, + pspec); + parent_class = VIK_GOTO_TOOL_CLASS (klass); - parent_class->get_coord = vik_goto_xml_tool_get_coord; + parent_class->get_url_format = _goto_xml_tool_get_url_format; + parent_class->parse_file_for_latlon = _goto_xml_tool_parse_file_for_latlon; g_type_class_add_private (klass, sizeof (VikGotoXmlToolPrivate)); } @@ -211,18 +282,20 @@ VikGotoXmlTool *vik_goto_xml_tool_new () return VIK_GOTO_XML_TOOL ( g_object_new ( VIK_GOTO_XML_TOOL_TYPE, "label", "Google", NULL ) ); } -static void vik_goto_xml_tool_init ( VikGotoXmlTool *self ) +static void _goto_xml_tool_init ( VikGotoXmlTool *self ) { VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); priv->url_format = NULL; priv->lat_path = NULL; + priv->lat_attr = NULL; priv->lon_path = NULL; + priv->lon_attr = NULL; // priv->ll.lat = NAN; priv->ll.lon = NAN; } -static void vik_goto_xml_tool_finalize ( GObject *gob ) +static void _goto_xml_tool_finalize ( GObject *gob ) { G_OBJECT_GET_CLASS(gob)->finalize(gob); } @@ -256,6 +329,46 @@ stack_is_path (const GSList *stack, return equal; } +/* Called for open tags */ +static void +_start_element (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (user_data); + VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); + const GSList *stack = g_markup_parse_context_get_element_stack (context); + /* Longitude */ + if (priv->lon_attr != NULL && isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path)) + { + int i=0; + while (attribute_names[i] != NULL) + { + if (strcmp (attribute_names[i], priv->lon_attr) == 0) + { + priv->ll.lon = g_ascii_strtod(attribute_values[i], NULL); + } + i++; + } + } + /* Latitude */ + if (priv->lat_attr != NULL && isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path)) + { + int i=0; + while (attribute_names[i] != NULL) + { + if (strcmp (attribute_names[i], priv->lat_attr) == 0) + { + priv->ll.lat = g_ascii_strtod(attribute_values[i], NULL); + } + i++; + } + } +} + /* Called for character data */ /* text is not nul-terminated */ static void @@ -270,11 +383,11 @@ _text (GMarkupParseContext *context, const GSList *stack = g_markup_parse_context_get_element_stack (context); gchar *textl = g_strndup(text, text_len); /* Store only first result */ - if (isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path)) + if (priv->lat_attr == NULL && isnan(priv->ll.lat) && stack_is_path (stack, priv->lat_path)) { priv->ll.lat = g_ascii_strtod(textl, NULL); } - if (isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path)) + if (priv->lon_attr == NULL && isnan(priv->ll.lon) && stack_is_path (stack, priv->lon_path)) { priv->ll.lon = g_ascii_strtod(textl, NULL); } @@ -282,12 +395,18 @@ _text (GMarkupParseContext *context, } static gboolean -parse_file_for_latlon(VikGotoXmlTool *self, gchar *filename, struct LatLon *ll) +_goto_xml_tool_parse_file_for_latlon(VikGotoTool *self, gchar *filename, struct LatLon *ll) { GMarkupParser xml_parser; - GMarkupParseContext *xml_context; - GError *error; + GMarkupParseContext *xml_context = NULL; + GError *error = NULL; VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); + g_return_val_if_fail(priv != NULL, FALSE); + + g_debug ("%s: %s@%s, %s@%s", + __FUNCTION__, + priv->lat_path, priv->lat_attr, + priv->lon_path, priv->lon_attr); FILE *file = g_fopen (filename, "r"); if (file == NULL) @@ -295,9 +414,17 @@ parse_file_for_latlon(VikGotoXmlTool *self, gchar *filename, struct LatLon *ll) return FALSE; /* setup context parse (ie callbacks) */ - xml_parser.start_element = NULL; + if (priv->lat_attr != NULL || priv->lon_attr != NULL) + // At least one coordinate uses an attribute + xml_parser.start_element = &_start_element; + else + xml_parser.start_element = NULL; xml_parser.end_element = NULL; - xml_parser.text = &_text; + if (priv->lat_attr == NULL || priv->lon_attr == NULL) + // At least one coordinate uses a raw element + xml_parser.text = &_text; + else + xml_parser.text = NULL; xml_parser.passthrough = NULL; xml_parser.error = NULL; @@ -309,16 +436,28 @@ parse_file_for_latlon(VikGotoXmlTool *self, gchar *filename, struct LatLon *ll) gchar buff[BUFSIZ]; size_t nb; - while ((nb = fread (buff, sizeof(gchar), BUFSIZ, file)) > 0) + while (xml_context && + (nb = fread (buff, sizeof(gchar), BUFSIZ, file)) > 0) { if (!g_markup_parse_context_parse(xml_context, buff, nb, &error)) - fprintf(stderr, "%s: parsing error.\n", __FUNCTION__); + { + fprintf(stderr, "%s: parsing error: %s.\n", + __FUNCTION__, error->message); + g_markup_parse_context_free(xml_context); + xml_context = NULL; + } + g_clear_error (&error); } /* cleanup */ - if (!g_markup_parse_context_end_parse(xml_context, &error)) - fprintf(stderr, "%s: errors occurred reading file.\n", __FUNCTION__); + if (xml_context && + !g_markup_parse_context_end_parse(xml_context, &error)) + fprintf(stderr, "%s: errors occurred while reading file: %s.\n", + __FUNCTION__, error->message); + g_clear_error (&error); - g_markup_parse_context_free(xml_context); + if (xml_context) + g_markup_parse_context_free(xml_context); + xml_context = NULL; fclose (file); if (ll != NULL) @@ -333,54 +472,10 @@ parse_file_for_latlon(VikGotoXmlTool *self, gchar *filename, struct LatLon *ll) return TRUE; } -static int vik_goto_xml_tool_get_coord ( VikGotoTool *object, VikWindow *vw, VikViewport *vvp, gchar *srch_str, VikCoord *coord ) +static gchar * +_goto_xml_tool_get_url_format ( VikGotoTool *self ) { - FILE *tmp_file; - int tmp_fd; - gchar *tmpname; - gchar *uri; - gchar *escaped_srch_str; - int ret = 0; /* OK */ - struct LatLon ll; - - g_debug("%s: raw goto: %s", __FUNCTION__, srch_str); - - escaped_srch_str = uri_escape(srch_str); - - g_debug("%s: escaped goto: %s", __FUNCTION__, escaped_srch_str); - - if ((tmp_fd = g_file_open_tmp ("GOTO.XXXXXX", &tmpname, NULL)) == -1) { - g_critical(_("couldn't open temp file")); - exit(1); - } - - VikGotoXmlTool *self = VIK_GOTO_XML_TOOL (object); VikGotoXmlToolPrivate *priv = GOTO_XML_TOOL_GET_PRIVATE (self); - - tmp_file = fdopen(tmp_fd, "r+"); - uri = g_strdup_printf(priv->url_format, escaped_srch_str); - - /* TODO: curl may not be available */ - if (curl_download_uri(uri, tmp_file, NULL)) { /* error */ - fclose(tmp_file); - tmp_file = NULL; - ret = -1; - goto done; - } - - fclose(tmp_file); - tmp_file = NULL; - g_debug("%s: %s", __FILE__, tmpname); - if (!parse_file_for_latlon(self, tmpname, &ll)) { - ret = -1; - goto done; - } - vik_coord_load_from_latlon ( coord, vik_viewport_get_coord_mode(vvp), &ll ); - -done: - g_free(escaped_srch_str); - g_free(uri); - g_remove(tmpname); - g_free(tmpname); - return ret; + g_return_val_if_fail(priv != NULL, NULL); + return priv->url_format; }