2 * Copyright (C) 2012 Intel Corporation.
4 * Authors: Jens Georg <jensg@openismus.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * SECTION:gupnp-cds-last-change-parser
24 * @short_description: LastChange parser for the format used in
27 * #GUPnPCDSLastChangeParser parses XML strings from
28 * CDS's LastChange state variable.
32 #include <libgupnp/gupnp-error.h>
35 #include "gupnp-cds-last-change-parser.h"
38 * GUPnPCDSLastChangeEntry:
40 * Opaque struct which contains information about the event.
42 struct _GUPnPCDSLastChangeEntry {
44 GUPnPCDSLastChangeEvent event;
49 gboolean is_subtree_update;
52 G_DEFINE_TYPE (GUPnPCDSLastChangeParser,
53 gupnp_cds_last_change_parser,
56 G_DEFINE_BOXED_TYPE (GUPnPCDSLastChangeEntry,
57 gupnp_cds_last_change_entry,
58 gupnp_cds_last_change_entry_ref,
59 gupnp_cds_last_change_entry_unref);
62 gupnp_cds_last_change_parser_init (GUPnPCDSLastChangeParser *parser)
67 gupnp_cds_last_change_parser_class_init (GUPnPCDSLastChangeParserClass *klass)
72 * gupnp_cds_last_change_parser_new:
74 * Create a new #GUPnPCDSLastChangeParser.
76 * This parser is able to parse LastChange as defined in the
77 * ContentDirectory:3 specification.
79 * Returns:(transfer full): A new instance of #GUPnPCDSLastChangeParser.
81 GUPnPCDSLastChangeParser *
82 gupnp_cds_last_change_parser_new (void)
84 return g_object_new (GUPNP_TYPE_CDS_LAST_CHANGE_PARSER,
89 * gupnp_cds_last_change_parser_parse:
90 * @parser: #GUPnPCDSLastChangeParser
91 * @last_change: XML string to parse
92 * @error: Return value for parser error or %NULL to ingore
94 * Parse a LastChange XML document in the flavor defined by the
95 * ContentDirectory:3 specification.
97 * Returns: (element-type GUPnPCDSLastChangeEntry)(transfer full):
98 * List of #GUPnPCDSLastChangeEntry<!-- -->s
101 gupnp_cds_last_change_parser_parse (GUPnPCDSLastChangeParser *parser,
102 const char *last_change,
107 xmlNode *state_event, *it;
108 GList *result = NULL;
109 GUPnPCDSLastChangeEntry *entry;
111 g_return_val_if_fail (GUPNP_IS_CDS_LAST_CHANGE_PARSER (parser),
114 doc = xmlParseDoc ((const xmlChar *) last_change);
118 GUPNP_XML_ERROR_PARSE,
119 "Could not parse LastChange XML");
124 state_event = xml_util_get_element ((xmlNode *) doc,
127 if (state_event == NULL) {
130 GUPNP_XML_ERROR_PARSE,
131 "Missing StateEvent node");
136 for (it = state_event->children; it != NULL; it = it->next) {
137 if (it->type == XML_TEXT_NODE)
139 else if (g_ascii_strcasecmp ((const char *) it->name,
143 entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
144 entry->ref_count = 1;
145 entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED;
147 tmp = xml_util_get_attribute_content (it, "objID");
148 entry->object_id = g_strdup (tmp);
150 tmp = xml_util_get_attribute_content (it,
152 entry->parent_id = g_strdup (tmp);
154 tmp = xml_util_get_attribute_content (it, "objClass");
155 entry->class = g_strdup (tmp);
157 entry->update_id = (guint32) xml_util_get_uint_attribute
161 entry->is_subtree_update =
162 xml_util_get_boolean_attribute
165 } else if (g_ascii_strcasecmp ((const char *) it->name,
169 entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
170 entry->ref_count = 1;
171 entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED;
173 tmp = xml_util_get_attribute_content (it, "objID");
174 entry->object_id = g_strdup (tmp);
176 entry->update_id = (guint32) xml_util_get_uint_attribute
180 entry->is_subtree_update =
181 xml_util_get_boolean_attribute
184 } else if (g_ascii_strcasecmp ((const char *) it->name,
188 entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
189 entry->ref_count = 1;
190 entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_REMOVED;
192 tmp = xml_util_get_attribute_content (it, "objID");
193 entry->object_id = g_strdup (tmp);
195 entry->update_id = (guint32) xml_util_get_uint_attribute
199 entry->is_subtree_update =
200 xml_util_get_boolean_attribute
203 } else if (g_ascii_strcasecmp ((const char *) it->name,
207 entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
208 entry->ref_count = 1;
209 entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_ST_DONE;
211 tmp = xml_util_get_attribute_content (it, "objID");
212 entry->object_id = g_strdup (tmp);
214 entry->update_id = (guint32) xml_util_get_uint_attribute
219 g_warning ("Skipping invalid LastChange entry: %s",
220 (const char *) it->name);
224 result = g_list_prepend (result, entry);
227 result = g_list_reverse (result);
238 * gupnp_cds_last_change_entry_ref:
239 * @entry: A #GUPnPCDSLastChangeEntry
241 * Increase reference count of a #GUPnPCDSLastChangeEntry.
243 * Returns:(transfer full): The object passed in @entry.
245 GUPnPCDSLastChangeEntry *
246 gupnp_cds_last_change_entry_ref (GUPnPCDSLastChangeEntry *entry)
248 g_return_val_if_fail (entry != NULL, NULL);
249 g_return_val_if_fail (entry->ref_count > 0, NULL);
251 g_atomic_int_inc (&entry->ref_count);
257 * gupnp_cds_last_change_entry_unref:
258 * @entry: A #GUPnPCDSLastChangeEntry
260 * Decrease reference count of a #GUPnPCDSLastChangeEntry. If the reference
261 * count drops to 0, @entry is freed.
264 gupnp_cds_last_change_entry_unref (GUPnPCDSLastChangeEntry *entry)
266 g_return_if_fail (entry != NULL);
267 g_return_if_fail (entry->ref_count > 0);
269 if (g_atomic_int_dec_and_test (&entry->ref_count)) {
270 g_free (entry->class);
271 g_free (entry->object_id);
272 g_free (entry->parent_id);
274 g_slice_free (GUPnPCDSLastChangeEntry, entry);
279 * gupnp_cds_last_change_entry_get_event:
280 * @entry: A #GUPnPCDSLastChangeEntry
282 * Get the type of the last change entry as defined in
283 * #GUPnPCDSLastChangeEvent.
285 * Returns: An event from the #GUPnPCDSLastChangeEvent or
286 * %GUPNP_CDS_LAST_CHANGE_EVENT_INVALID if the entry is not valid.
288 GUPnPCDSLastChangeEvent
289 gupnp_cds_last_change_entry_get_event (GUPnPCDSLastChangeEntry *entry)
291 g_return_val_if_fail (entry != NULL,
292 GUPNP_CDS_LAST_CHANGE_EVENT_INVALID);
298 * gupnp_cds_last_change_entry_get_object_id:
299 * @entry: A #GUPnPCDSLastChangeEntry
301 * Get the ID of the object in this change entry.
303 * Returns: (transfer none): The id of the object of this entry.
306 gupnp_cds_last_change_entry_get_object_id (GUPnPCDSLastChangeEntry *entry)
308 g_return_val_if_fail (entry != NULL, NULL);
310 return entry->object_id;
314 * gupnp_cds_last_change_entry_get_parent_id:
315 * @entry: A #GUPnPCDSLastChangeEntry
317 * Get the parent object id of the object in this change entry. This is only
318 * valid if gupnp_cds_last_change_entry_get_event() returns
319 * %GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED.
321 * Returns: (transfer none): The id of the object's parent of this entry.
324 gupnp_cds_last_change_entry_get_parent_id (GUPnPCDSLastChangeEntry *entry)
326 g_return_val_if_fail (entry != NULL, NULL);
328 return entry->parent_id;
332 * gupnp_cds_last_change_entry_get_class:
333 * @entry: A #GUPnPCDSLastChangeEntry
335 * Get the class of the object in this change entry. This is only
336 * valid if gupnp_cds_last_change_entry_get_event() returns
337 * %GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED.
339 * Returns: (transfer none): The upnp class of the object of this entry.
342 gupnp_cds_last_change_entry_get_class (GUPnPCDSLastChangeEntry *entry)
344 g_return_val_if_fail (entry != NULL, NULL);
350 * gupnp_cds_last_change_entry_is_subtree_update:
351 * @entry: A #GUPnPCDSLastChangeEntry
353 * Returns whether this entry is part of a subtree update.
355 * Returns: %TRUE, if the entry is part of a subtree update, %FALSE otherwise.
358 gupnp_cds_last_change_entry_is_subtree_update (GUPnPCDSLastChangeEntry *entry)
360 g_return_val_if_fail (entry != NULL, FALSE);
362 return entry->is_subtree_update;
366 * gupnp_cds_last_change_entry_get_update_id:
367 * @entry: A #GUPnPCDSLastChangeEntry
369 * Get the update id of the last change entry.
371 * Returns: update id of the entry or 0 if the entry is not valid.
374 gupnp_cds_last_change_entry_get_update_id (GUPnPCDSLastChangeEntry *entry)
376 g_return_val_if_fail (entry != NULL, 0);
378 return entry->update_id;