diff options
author | Jens Georg <mail@jensge.org> | 2012-11-29 00:11:25 +0100 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2012-11-30 15:51:28 +0100 |
commit | c1a77ee6eddc66d9674c9b391b5e0d2d2cf034ba (patch) | |
tree | e943bf2afe7406d6a53c40b39b69663a42d506ed | |
parent | 83302a3b8eeb9ec255482c9c6464678261fea5fc (diff) | |
download | gupnp-av-c1a77ee6eddc66d9674c9b391b5e0d2d2cf034ba.tar.gz |
Add LastChange parser for CDS:3
https://bugzilla.gnome.org/show_bug.cgi?id=689276
-rw-r--r-- | doc/gupnp-av-docs.sgml | 1 | ||||
-rw-r--r-- | doc/gupnp-av-sections.txt | 31 | ||||
-rw-r--r-- | doc/gupnp-av.types | 2 | ||||
-rw-r--r-- | libgupnp-av/Makefile.am | 3 | ||||
-rw-r--r-- | libgupnp-av/gupnp-av.h | 1 | ||||
-rw-r--r-- | libgupnp-av/gupnp-cds-last-change-parser.c | 379 | ||||
-rw-r--r-- | libgupnp-av/gupnp-cds-last-change-parser.h | 112 |
7 files changed, 528 insertions, 1 deletions
diff --git a/doc/gupnp-av-docs.sgml b/doc/gupnp-av-docs.sgml index 93b6340..0e2b00e 100644 --- a/doc/gupnp-av-docs.sgml +++ b/doc/gupnp-av-docs.sgml @@ -58,6 +58,7 @@ <xi:include href="xml/gupnp-didl-lite-contributor.xml"/> <xi:include href="xml/gupnp-didl-lite-create-class.xml"/> <xi:include href="xml/gupnp-last-change-parser.xml"/> + <xi:include href="xml/gupnp-cds-last-change-parser.xml"/> <xi:include href="xml/gupnp-search-criteria-parser.xml"/> <xi:include href="xml/gupnp-protocol-info.xml"/> <xi:include href="xml/gupnp-feature.xml"/> diff --git a/doc/gupnp-av-sections.txt b/doc/gupnp-av-sections.txt index 6351590..e373bc6 100644 --- a/doc/gupnp-av-sections.txt +++ b/doc/gupnp-av-sections.txt @@ -435,7 +435,6 @@ gupnp_feature_list_parser_get_type <SECTION> <FILE>gupnp-media-collection</FILE> <TITLE>GUPnPMediaCollection</TITLE> -GUPnPMediaCollectionType GUPnPMediaCollection gupnp_media_collection_new gupnp_media_collection_new_from_string @@ -460,6 +459,36 @@ gupnp_media_collection_get_type </SECTION> <SECTION> +<FILE>gupnp-cds-last-change-parser</FILE> +<TITLE>GUPnPCDSLastChangeParser</TITLE> +GUPnPCDSLastChangeParser +GUPnPCDSLastChangeEvent +GUPnPCDSLastChangeEntry +gupnp_cds_last_change_parser_new +gupnp_cds_last_change_parser_parse +gupnp_cds_last_change_entry_ref +gupnp_cds_last_change_entry_unref +gupnp_cds_last_change_entry_get_event +gupnp_cds_last_change_entry_get_object_id +gupnp_cds_last_change_entry_get_parent_id +gupnp_cds_last_change_entry_get_class +gupnp_cds_last_change_entry_is_subtree_update +gupnp_cds_last_change_entry_get_update_id +<SUBSECTION Standard> +GUPnPCDSLastChangeParserClass +GUPNP_CDS_LAST_CHANGE_PARSER +GUPNP_CDS_LAST_CHANGE_PARSER_CLASS +GUPNP_CDS_LAST_CHANGE_PARSER_GET_CLASS +GUPNP_IS_CDS_LAST_CHANGE_PARSER +GUPNP_IS_CDS_LAST_CHANGE_PARSER_CLASS +GUPNP_TYPE_CDS_LAST_CHANGE_PARSER +GUPnPCDSLastChangeParserPrivate +gupnp_cds_last_change_entry_get_type +gupnp_cds_last_change_parser_get_type +</SECTION> + + +<SECTION> <FILE>gupnp-av-error</FILE> <TITLE>Error codes</TITLE> GUPNP_PROTOCOL_ERROR diff --git a/doc/gupnp-av.types b/doc/gupnp-av.types index 1e488f9..9f48dc6 100644 --- a/doc/gupnp-av.types +++ b/doc/gupnp-av.types @@ -15,3 +15,5 @@ gupnp_search_criteria_op_get_type gupnp_feature_get_type gupnp_feature_list_parser_get_type gupnp_media_collection_get_type +gupnp_cds_last_change_parser_get_type +gupnp_cds_last_change_entry_get_type diff --git a/libgupnp-av/Makefile.am b/libgupnp-av/Makefile.am index e4f7bc7..7db04eb 100644 --- a/libgupnp-av/Makefile.am +++ b/libgupnp-av/Makefile.am @@ -27,6 +27,7 @@ libgupnp_av_inc_HEADERS = gupnp-didl-lite-object.h \ gupnp-protocol-info.h \ gupnp-search-criteria-parser.h \ gupnp-last-change-parser.h \ + gupnp-cds-last-change-parser.h \ gupnp-media-collection.h \ gupnp-feature.h \ gupnp-feature-list-parser.h \ @@ -67,6 +68,7 @@ libgupnp_av_1_0_la_SOURCES = gupnp-didl-lite-object.c \ gupnp-protocol-info.c \ gupnp-search-criteria-parser.c \ gupnp-last-change-parser.c \ + gupnp-cds-last-change-parser.c \ gupnp-media-collection.c \ gupnp-feature.c \ gupnp-feature-list-parser.c \ @@ -111,6 +113,7 @@ introspection_sources = \ $(top_srcdir)/libgupnp-av/gupnp-protocol-info.c \ $(top_srcdir)/libgupnp-av/gupnp-search-criteria-parser.c \ $(top_srcdir)/libgupnp-av/gupnp-last-change-parser.c \ + $(top_srcdir)/libgupnp-av/gupnp-cds-last-change-parser.c \ $(top_srcdir)/libgupnp-av/gupnp-media-collection.c \ $(top_srcdir)/libgupnp-av/gupnp-feature.c \ $(top_srcdir)/libgupnp-av/gupnp-feature-list-parser.c \ diff --git a/libgupnp-av/gupnp-av.h b/libgupnp-av/gupnp-av.h index dbf9df0..6741c02 100644 --- a/libgupnp-av/gupnp-av.h +++ b/libgupnp-av/gupnp-av.h @@ -33,6 +33,7 @@ #include "gupnp-protocol-info.h" #include "gupnp-search-criteria-parser.h" #include "gupnp-last-change-parser.h" +#include "gupnp-cds-last-change-parser.h" #include "gupnp-feature.h" #include "gupnp-feature-list-parser.h" #include "gupnp-dlna.h" diff --git a/libgupnp-av/gupnp-cds-last-change-parser.c b/libgupnp-av/gupnp-cds-last-change-parser.c new file mode 100644 index 0000000..1f120de --- /dev/null +++ b/libgupnp-av/gupnp-cds-last-change-parser.c @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2012 Intel Corporation. + * + * Authors: Jens Georg <jensg@openismus.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-cds-last-change-parser + * @short_description: LastChange parser for the format used in + * CDS:3 + * + * #GUPnPCDSLastChangeParser parses XML strings from + * CDS's LastChange state variable. + * + */ + +#include <libgupnp/gupnp-error.h> + +#include "xml-util.h" +#include "gupnp-cds-last-change-parser.h" + +/** + * GUPnPCDSLastChangeEntry: + * + * Opaque struct which contains information about the event. + **/ +struct _GUPnPCDSLastChangeEntry { + int ref_count; + GUPnPCDSLastChangeEvent event; + char *object_id; + char *parent_id; + char *class; + guint32 update_id; + gboolean is_subtree_update; +}; + +G_DEFINE_TYPE (GUPnPCDSLastChangeParser, + gupnp_cds_last_change_parser, + G_TYPE_OBJECT) + +G_DEFINE_BOXED_TYPE (GUPnPCDSLastChangeEntry, + gupnp_cds_last_change_entry, + gupnp_cds_last_change_entry_ref, + gupnp_cds_last_change_entry_unref); + +static void +gupnp_cds_last_change_parser_init (GUPnPCDSLastChangeParser *parser) +{ +} + +static void +gupnp_cds_last_change_parser_class_init (GUPnPCDSLastChangeParserClass *klass) +{ +} + +/** + * gupnp_cds_last_change_parser_new: + * + * Create a new #GUPnPCDSLastChangeParser. + * + * This parser is able to parse LastChange as defined in the + * ContentDirectory:3 specification. + * + * Returns:(transfer full): A new instance of #GUPnPCDSLastChangeParser. + **/ +GUPnPCDSLastChangeParser * +gupnp_cds_last_change_parser_new (void) +{ + return g_object_new (GUPNP_TYPE_CDS_LAST_CHANGE_PARSER, + NULL); +} + +/** + * gupnp_cds_last_change_parser_parse: + * @parser: #GUPnPCDSLastChangeParser + * @last_change: XML string to parse + * @error: Return value for parser error or %NULL to ingore + * + * Parse a LastChange XML document in the flavor defined by the + * ContentDirectory:3 specification. + * + * Returns: (element-type GUPnPCDSLastChangeEntry)(transfer full): + * List of #GUPnPCDSLastChangeEntry<!-- -->s + **/ +GList * +gupnp_cds_last_change_parser_parse (GUPnPCDSLastChangeParser *parser, + const char *last_change, + GError **error) + +{ + xmlDoc *doc; + xmlNode *state_event, *it; + GList *result = NULL; + GUPnPCDSLastChangeEntry *entry; + + g_return_val_if_fail (GUPNP_IS_CDS_LAST_CHANGE_PARSER (parser), + NULL); + + doc = xmlParseDoc ((const xmlChar *) last_change); + if (doc == NULL) { + g_set_error (error, + GUPNP_XML_ERROR, + GUPNP_XML_ERROR_PARSE, + "Could not parse LastChange XML"); + + goto out; + } + + state_event = xml_util_get_element ((xmlNode *) doc, + "StateEvent", + NULL); + if (state_event == NULL) { + g_set_error (error, + GUPNP_XML_ERROR, + GUPNP_XML_ERROR_PARSE, + "Missing StateEvent node"); + + goto out; + } + + for (it = state_event->children; it != NULL; it = it->next) { + if (it->type == XML_TEXT_NODE) + continue; + else if (g_ascii_strcasecmp ((const char *) it->name, + "objAdd") == 0) { + const char *tmp; + + entry = g_slice_new0 (GUPnPCDSLastChangeEntry); + entry->ref_count = 1; + entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED; + + tmp = xml_util_get_attribute_content (it, "objID"); + entry->object_id = g_strdup (tmp); + + tmp = xml_util_get_attribute_content (it, + "objParentID"); + entry->parent_id = g_strdup (tmp); + + tmp = xml_util_get_attribute_content (it, "objClass"); + entry->class = g_strdup (tmp); + + entry->update_id = xml_util_get_uint_child_element + (it, + "updateID", + 0); + entry->is_subtree_update = + xml_util_get_boolean_attribute + (it, + "stUpdate"); + } else if (g_ascii_strcasecmp ((const char *) it->name, + "objMod") == 0) { + const char *tmp; + + entry = g_slice_new0 (GUPnPCDSLastChangeEntry); + entry->ref_count = 1; + entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED; + + tmp = xml_util_get_attribute_content (it, "objID"); + entry->object_id = g_strdup (tmp); + + entry->update_id = xml_util_get_uint_child_element + (it, + "updateID", + 0); + entry->is_subtree_update = + xml_util_get_boolean_attribute + (it, + "stUpdate"); + } else if (g_ascii_strcasecmp ((const char *) it->name, + "objDel") == 0) { + const char *tmp; + + entry = g_slice_new0 (GUPnPCDSLastChangeEntry); + entry->ref_count = 1; + entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_REMOVED; + + tmp = xml_util_get_attribute_content (it, "objID"); + entry->object_id = g_strdup (tmp); + + entry->update_id = xml_util_get_uint_child_element + (it, + "updateID", + 0); + entry->is_subtree_update = + xml_util_get_boolean_attribute + (it, + "stUpdate"); + } else if (g_ascii_strcasecmp ((const char *) it->name, + "stDone") == 0) { + const char *tmp; + + entry = g_slice_new0 (GUPnPCDSLastChangeEntry); + entry->ref_count = 1; + entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_ST_DONE; + + tmp = xml_util_get_attribute_content (it, "objID"); + entry->object_id = g_strdup (tmp); + + entry->update_id = xml_util_get_uint_child_element + (it, + "updateID", + 0); + } else { + g_warning ("Skipping invalid LastChange entry: %s", + (const char *) it->name); + continue; + } + + result = g_list_prepend (result, entry); + } + + result = g_list_reverse (result); +out: + if (doc != NULL) { + xmlFreeDoc (doc); + } + + return result; + +} + +/** + * gupnp_cds_last_change_entry_ref: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Increase reference count of a #GUPnPCDSLastChangeEntry. + * + * Returns:(transfer full): The object passed in @entry. + **/ +GUPnPCDSLastChangeEntry * +gupnp_cds_last_change_entry_ref (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + g_return_val_if_fail (entry->ref_count > 0, NULL); + + g_atomic_int_inc (&entry->ref_count); + + return entry; +} + +/** + * gupnp_cds_last_change_entry_unref: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Decrease reference count of a #GUPnPCDSLastChangeEntry. If the reference + * count drops to 0, @entry is freed. + **/ +void +gupnp_cds_last_change_entry_unref (GUPnPCDSLastChangeEntry *entry) +{ + g_return_if_fail (entry != NULL); + g_return_if_fail (entry->ref_count > 0); + + if (g_atomic_int_dec_and_test (&entry->ref_count)) { + g_free (entry->class); + g_free (entry->object_id); + g_free (entry->parent_id); + + g_slice_free (GUPnPCDSLastChangeEntry, entry); + } +} + +/** + * gupnp_cds_last_change_entry_get_event: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Get the type of the last change entry as defined in + * #GUPnPCDSLastChangeEvent. + * + * Returns: An event from the #GUPnPCDSLastChangeEvent or + * %GUPNP_CDS_LAST_CHANGE_EVENT_INVALID if the entry is not valid. + **/ +GUPnPCDSLastChangeEvent +gupnp_cds_last_change_entry_get_event (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, + GUPNP_CDS_LAST_CHANGE_EVENT_INVALID); + + return entry->event; +} + +/** + * gupnp_cds_last_change_entry_get_object_id: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Get the ID of the object in this change entry. + * + * Returns: (transfer none): The id of the object of this entry. + **/ +const char * +gupnp_cds_last_change_entry_get_object_id (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + + return entry->object_id; +} + +/** + * gupnp_cds_last_change_entry_get_parent_id: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Get the parent object id of the object in this change entry. This is only + * valid if gupnp_cds_last_change_entry_get_event() returns + * %GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED. + * + * Returns: (transfer none): The id of the object's parent of this entry. + **/ +const char * +gupnp_cds_last_change_entry_get_parent_id (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + + return entry->parent_id; +} + +/** + * gupnp_cds_last_change_entry_get_class: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Get the class of the object in this change entry. This is only + * valid if gupnp_cds_last_change_entry_get_event() returns + * %GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED. + * + * Returns: (transfer none): The upnp class of the object of this entry. + **/ +const char * +gupnp_cds_last_change_entry_get_class (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, NULL); + + return entry->class; +} + +/** + * gupnp_cds_last_change_entry_is_subtree_update: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Returns whether this entry is part of a subtree update. + * + * Returns: %TRUE, if the entry is part of a subtree update, %FALSE otherwise. + **/ +gboolean +gupnp_cds_last_change_entry_is_subtree_update (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, FALSE); + + return entry->is_subtree_update; +} + +/** + * gupnp_cds_last_change_entry_get_update_id: + * @entry: A #GUPnPCDSLastChangeEntry + * + * Get the update id of the last change entry. + * + * Returns: update id of the entry or 0 if the entry is not valid. + **/ +guint32 +gupnp_cds_last_change_entry_get_update_id (GUPnPCDSLastChangeEntry *entry) +{ + g_return_val_if_fail (entry != NULL, 0); + + return entry->update_id; +} diff --git a/libgupnp-av/gupnp-cds-last-change-parser.h b/libgupnp-av/gupnp-cds-last-change-parser.h new file mode 100644 index 0000000..279e108 --- /dev/null +++ b/libgupnp-av/gupnp-cds-last-change-parser.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 Intel Corporation. + * + * Authors: Jens Georg <jensg@openismus.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. + */ + +#ifndef __GUPNP_CDS_LAST_CHANGE_PARSER_H__ +#define __GUPNP_CDS_LAST_CHANGE_PARSER_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +GType +gupnp_cds_last_change_parser_get_type (void) G_GNUC_CONST; + +GType +gupnp_cds_last_change_entry_get_type (void) G_GNUC_CONST; + +#define GUPNP_TYPE_CDS_LAST_CHANGE_PARSER \ + (gupnp_cds_last_change_parser_get_type ()) +#define GUPNP_CDS_LAST_CHANGE_PARSER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GUPNP_TYPE_CDS_LAST_CHANGE_PARSER, \ + GUPnPCDSLastChangeParser)) +#define GUPNP_CDS_LAST_CHANGE_PARSER_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_CAST ((obj), \ + GUPNP_TYPE_CDS_LAST_CHANGE_PARSER, \ + GUPnPCDSLastChangeParserClass)) +#define GUPNP_IS_CDS_LAST_CHANGE_PARSER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GUPNP_TYPE_CDS_LAST_CHANGE_PARSER)) +#define GUPNP_IS_CDS_LAST_CHANGE_PARSER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + GUPNP_TYPE_CDS_LAST_CHANGE_PARSER)) +#define GUPNP_CDS_LAST_CHANGE_PARSER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GUPNP_TYPE_CDS_LAST_CHANGE_PARSER, \ + GUPnPCDSLastChangeParserClass)) + +typedef struct _GUPnPCDSLastChangeParser GUPnPCDSLastChangeParser; +typedef struct _GUPnPCDSLastChangeParserClass GUPnPCDSLastChangeParserClass; +typedef struct _GUPnPCDSLastChangeParserPrivate GUPnPCDSLastChangeParserPrivate; +typedef struct _GUPnPCDSLastChangeEntry GUPnPCDSLastChangeEntry; + +struct _GUPnPCDSLastChangeParser { + GObject parent; + + GUPnPCDSLastChangeParserPrivate *priv; +}; + +struct _GUPnPCDSLastChangeParserClass { + GObjectClass parent_class; +}; + +typedef enum GUPnPCDSLastChangeEvent { + GUPNP_CDS_LAST_CHANGE_EVENT_INVALID, + GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED, + GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_REMOVED, + GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED, + GUPNP_CDS_LAST_CHANGE_EVENT_ST_DONE +} GUPnPCDSLastChangeEvent; + +GUPnPCDSLastChangeParser * +gupnp_cds_last_change_parser_new (void); + +GList * +gupnp_cds_last_change_parser_parse (GUPnPCDSLastChangeParser *parser, + const char *last_change, + GError **error); + +GUPnPCDSLastChangeEntry * +gupnp_cds_last_change_entry_ref (GUPnPCDSLastChangeEntry *entry); +void +gupnp_cds_last_change_entry_unref (GUPnPCDSLastChangeEntry *entry); + +GUPnPCDSLastChangeEvent +gupnp_cds_last_change_entry_get_event (GUPnPCDSLastChangeEntry *entry); + +const char * +gupnp_cds_last_change_entry_get_object_id (GUPnPCDSLastChangeEntry *entry); + +const char * +gupnp_cds_last_change_entry_get_parent_id (GUPnPCDSLastChangeEntry *entry); + +const char * +gupnp_cds_last_change_entry_get_class (GUPnPCDSLastChangeEntry *entry); + +gboolean +gupnp_cds_last_change_entry_is_subtree_update (GUPnPCDSLastChangeEntry *entry); + +guint32 +gupnp_cds_last_change_parser_get_update_id (GUPnPCDSLastChangeEntry *entry); + +G_END_DECLS + +#endif /* __GUPNP_CDS_LAST_CHANGE_PARSER_H__ */ |