/*
* Copyright (C) 2007 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
* Copyright (C) 2007 OpenedHand Ltd
*
* Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
* Jorn Baayen <jorn@openedhand.com>
*
* 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 <gobject/gvaluecollector.h>
#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;
}