cddddd8bdb4c69dad6f05a3eda454070dcf4522c
[profile/ivi/GUPnP-AV.git] / libgupnp-av / gupnp-last-change-parser.c
1 /*
2  * Copyright (C) 2007 Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
3  * Copyright (C) 2007 OpenedHand Ltd
4  *
5  * Authors: Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
6  *          Jorn Baayen <jorn@openedhand.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:gupnp-last-change-parser
26  * @short_description: A/V LastChange event XML parser
27  *
28  * #GUPnPLastChangeParser parses XML strings from LastChange events that are
29  * generated by AVTransport and RenderingControl services.
30  *
31  */
32
33
34 #include <gobject/gvaluecollector.h>
35
36 #include "gupnp-last-change-parser.h"
37 #include "gvalue-util.h"
38 #include "xml-util.h"
39
40 G_DEFINE_TYPE (GUPnPLastChangeParser,
41                gupnp_last_change_parser,
42                G_TYPE_OBJECT);
43
44 static void
45 gupnp_last_change_parser_init (GUPnPLastChangeParser *parser)
46 {
47 }
48
49 static void
50 gupnp_last_change_parser_dispose (GObject *object)
51 {
52         GObjectClass   *gobject_class;
53
54         gobject_class = G_OBJECT_CLASS (gupnp_last_change_parser_parent_class);
55         gobject_class->dispose (object);
56 }
57
58 static void
59 gupnp_last_change_parser_class_init (GUPnPLastChangeParserClass *klass)
60 {
61         GObjectClass *object_class;
62
63         object_class = G_OBJECT_CLASS (klass);
64
65         object_class->dispose = gupnp_last_change_parser_dispose;
66 }
67
68 /* Reads a value of state variable @variable_name to an initialised GValue pair
69  * from the InstanceID node of a LastChange xml doc */
70 static gboolean
71 read_state_variable (const char *variable_name,
72                      GValue     *value,
73                      xmlNode    *instance_node)
74 {
75         xmlNode    *variable_node;
76         const char *val_str;
77
78         variable_node = xml_util_get_element (instance_node,
79                                               variable_name,
80                                               NULL);
81         if (!variable_node)
82                 return FALSE;
83
84         val_str = xml_util_get_attribute_content (variable_node, "val");
85         if (!val_str) {
86                 g_warning ("No value provided for variable \"%s\" in "
87                            "LastChange event",
88                            variable_name);
89
90                 return FALSE;
91         }
92
93         gvalue_util_set_value_from_string (value, val_str);
94
95         return TRUE;
96 }
97
98 static xmlNode *
99 get_instance_node (xmlDoc *doc,
100                    guint   instance_id)
101 {
102         xmlNode *node;
103
104         if (doc->children == NULL)
105                 return NULL;
106
107         for (node = doc->children->children;
108              node;
109              node = node->next) {
110                 if (node->type != XML_ELEMENT_NODE)
111                         continue;
112
113                 if (!xmlStrcmp (node->name, BAD_CAST ("InstanceID")) &&
114                     xml_util_get_uint_attribute (node, "val", 0) == instance_id)
115                         break;
116         }
117
118         return node;
119 }
120
121 /**
122  * gupnp_last_change_parser_new:
123  *
124  * Return value: A new #GUPnPLastChangeParser
125  **/
126 GUPnPLastChangeParser *
127 gupnp_last_change_parser_new (void)
128 {
129         return g_object_new (GUPNP_TYPE_LAST_CHANGE_PARSER,
130                              NULL);
131 }
132
133 /**
134  * gupnp_last_change_parser_parse_last_change_valist:
135  * @parser: A #GUPnPLastChangeParser
136  * @instance_id: The ID of the AV instance caller is interested in
137  * @last_change_xml: The xml from the "LastChange" event to parse
138  * @error: The location where to store any error, or NULL
139  * @var_args: A va_list of tuples of state variable name, state variable type,
140  * and state variable value location, terminated with NULL. The state variable
141  * values should be freed after use
142  *
143  * See gupnp_last_change_parser_parse_last_change(); this version takes a
144  * va_list for use by language bindings.
145  *
146  * Return value: TRUE on success.
147  **/
148 gboolean
149 gupnp_last_change_parser_parse_last_change_valist
150                                        (GUPnPLastChangeParser *parser,
151                                         guint                  instance_id,
152                                         const char            *last_change_xml,
153                                         GError               **error,
154                                         va_list                var_args)
155 {
156         const char *variable_name;
157         xmlDoc  *doc;
158         xmlNode *instance_node;
159
160         g_return_val_if_fail (last_change_xml, FALSE);
161
162         doc = xmlParseDoc ((const xmlChar *) last_change_xml);
163         if (doc == NULL) {
164                 g_set_error (error,
165                              GUPNP_XML_ERROR,
166                              GUPNP_XML_ERROR_PARSE,
167                              "Could not parse LastChange xml");
168
169                 return FALSE;
170         }
171
172         instance_node = get_instance_node (doc, instance_id);
173         if (instance_node == NULL) {
174                 /* This is not an error since the caller of this function
175                  * doesn't (need to) know if the instance of his interest is
176                  * part of the LastChange event received.
177                  */
178                 xmlFreeDoc (doc);
179
180                 return FALSE;
181         }
182
183         /* Variables */
184         variable_name = va_arg (var_args, const char *);
185         while (variable_name) {
186                 GType variable_type;
187                 GValue value = { 0, };
188                 char *copy_error = NULL;
189
190                 variable_type = va_arg (var_args, GType);
191
192                 g_value_init (&value, variable_type);
193
194                 if (read_state_variable (variable_name,
195                                          &value,
196                                          instance_node)) {
197                         G_VALUE_LCOPY (&value, var_args, 0, &copy_error);
198                 } else {
199                         va_arg (var_args, gpointer);
200                 }
201
202                 g_value_unset (&value);
203
204                 if (copy_error) {
205                         g_warning ("Error copying value: %s", copy_error);
206
207                         g_free (copy_error);
208                 }
209
210                 variable_name = va_arg (var_args, const char *);
211         }
212
213         /* Cleanup */
214         xmlFreeDoc (doc);
215
216         return TRUE;
217 }
218
219 /**
220  * gupnp_last_change_parser_parse_last_change:
221  * @parser: A #GUPnPLastChangeParser
222  * @instance_id: The ID of the AV instance caller is interested in
223  * @last_change_xml: The xml from the "LastChange" event to parse
224  * @error: The location where to store any error, or NULL
225  * @Varargs: tuples of state variable name, state variable type, and state
226  * variable value location, terminated with NULL. The state variable values
227  * should be freed after use.
228  *
229  * Parses the xml fragment from a LastChange event.
230  *
231  * Return value: TRUE on success.
232  **/
233 gboolean
234 gupnp_last_change_parser_parse_last_change
235                                 (GUPnPLastChangeParser *parser,
236                                  guint                  instance_id,
237                                  const char            *last_change_xml,
238                                  GError               **error,
239                                  ...)
240 {
241         va_list var_args;
242         gboolean ret;
243
244         va_start (var_args, error);
245         ret = gupnp_last_change_parser_parse_last_change_valist
246                                                 (parser,
247                                                  instance_id,
248                                                  last_change_xml,
249                                                  error,
250                                                  var_args);
251         va_end (var_args);
252
253         return ret;
254 }
255