/* * Copyright (C) 2007 Zeeshan Ali (Khattak) * Copyright (C) 2007 OpenedHand Ltd * * Authors: Zeeshan Ali (Khattak) * Jorn Baayen * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * SECTION:gupnp-last-change-parser * @short_description: A/V LastChange event XML parser * * #GUPnPLastChangeParser parses XML strings from LastChange events that are * generated by AVTransport and RenderingControl services. * */ #include #include "gupnp-last-change-parser.h" #include "gvalue-util.h" #include "xml-util.h" G_DEFINE_TYPE (GUPnPLastChangeParser, gupnp_last_change_parser, G_TYPE_OBJECT); static void gupnp_last_change_parser_init (G_GNUC_UNUSED GUPnPLastChangeParser *parser) { } static void gupnp_last_change_parser_dispose (GObject *object) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (gupnp_last_change_parser_parent_class); gobject_class->dispose (object); } static void gupnp_last_change_parser_class_init (GUPnPLastChangeParserClass *klass) { GObjectClass *object_class; object_class = G_OBJECT_CLASS (klass); object_class->dispose = gupnp_last_change_parser_dispose; } /* Reads a value of state variable @variable_name to an initialised GValue pair * from the InstanceID node of a LastChange xml doc */ static gboolean read_state_variable (const char *variable_name, GValue *value, xmlNode *instance_node) { xmlNode *variable_node; const char *val_str; variable_node = xml_util_get_element (instance_node, variable_name, NULL); if (!variable_node) return FALSE; val_str = xml_util_get_attribute_content (variable_node, "val"); if (!val_str) { g_warning ("No value provided for variable \"%s\" in " "LastChange event", variable_name); return FALSE; } gvalue_util_set_value_from_string (value, val_str); return TRUE; } static xmlNode * get_instance_node (xmlDoc *doc, guint instance_id) { xmlNode *node; if (doc->children == NULL) return NULL; for (node = doc->children->children; node; node = node->next) { if (node->type != XML_ELEMENT_NODE) continue; if (!xmlStrcmp (node->name, BAD_CAST ("InstanceID")) && xml_util_get_uint_attribute (node, "val", 0) == instance_id) break; } return node; } /** * gupnp_last_change_parser_new: * * Return value: A new #GUPnPLastChangeParser **/ GUPnPLastChangeParser * gupnp_last_change_parser_new (void) { return g_object_new (GUPNP_TYPE_LAST_CHANGE_PARSER, NULL); } /** * gupnp_last_change_parser_parse_last_change_valist: * @parser: A #GUPnPLastChangeParser * @instance_id: The ID of the AV instance caller is interested in * @last_change_xml: The xml from the "LastChange" event to parse * @error: The location where to store any error, or NULL * @var_args: A va_list of tuples of state variable name, state variable type, * and state variable value location, terminated with NULL. The state variable * values should be freed after use * * See gupnp_last_change_parser_parse_last_change(); this version takes a * va_list for use by language bindings. * * Return value: TRUE on success. **/ gboolean gupnp_last_change_parser_parse_last_change_valist (G_GNUC_UNUSED GUPnPLastChangeParser *parser, guint instance_id, const char *last_change_xml, GError **error, va_list var_args) { const char *variable_name; xmlDoc *doc; xmlNode *instance_node; g_return_val_if_fail (last_change_xml, FALSE); doc = xmlParseDoc ((const xmlChar *) last_change_xml); if (doc == NULL) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "Could not parse LastChange xml"); return FALSE; } instance_node = get_instance_node (doc, instance_id); if (instance_node == NULL) { /* This is not an error since the caller of this function * doesn't (need to) know if the instance of his interest is * part of the LastChange event received. */ xmlFreeDoc (doc); return FALSE; } /* Variables */ variable_name = va_arg (var_args, const char *); while (variable_name) { GType variable_type; GValue value = { 0, }; char *copy_error = NULL; variable_type = va_arg (var_args, GType); g_value_init (&value, variable_type); if (read_state_variable (variable_name, &value, instance_node)) { G_VALUE_LCOPY (&value, var_args, 0, ©_error); } else { va_arg (var_args, gpointer); } g_value_unset (&value); if (copy_error) { g_warning ("Error copying value: %s", copy_error); g_free (copy_error); } variable_name = va_arg (var_args, const char *); } /* Cleanup */ xmlFreeDoc (doc); return TRUE; } /** * gupnp_last_change_parser_parse_last_change: * @parser: A #GUPnPLastChangeParser * @instance_id: The ID of the AV instance caller is interested in * @last_change_xml: The xml from the "LastChange" event to parse * @error: The location where to store any error, or NULL * @...: tuples of state variable name, state variable type, and state * variable value location, terminated with NULL. The state variable values * should be freed after use. * * Parses the xml fragment from a LastChange event. * * Return value: TRUE on success. **/ gboolean gupnp_last_change_parser_parse_last_change (GUPnPLastChangeParser *parser, guint instance_id, const char *last_change_xml, GError **error, ...) { va_list var_args; gboolean ret; va_start (var_args, error); ret = gupnp_last_change_parser_parse_last_change_valist (parser, instance_id, last_change_xml, error, var_args); va_end (var_args); return ret; }