Blame libgupnp-av/gupnp-cds-last-change-parser.c

Packit 712bc5
/*
Packit 712bc5
 * Copyright (C) 2012 Intel Corporation.
Packit 712bc5
 *
Packit 712bc5
 * Authors: Jens Georg <jensg@openismus.com>
Packit 712bc5
 *
Packit 712bc5
 * This library is free software; you can redistribute it and/or
Packit 712bc5
 * modify it under the terms of the GNU Library General Public
Packit 712bc5
 * License as published by the Free Software Foundation; either
Packit 712bc5
 * version 2 of the License, or (at your option) any later version.
Packit 712bc5
 *
Packit 712bc5
 * This library is distributed in the hope that it will be useful,
Packit 712bc5
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 712bc5
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 712bc5
 * Library General Public License for more details.
Packit 712bc5
 *
Packit 712bc5
 * You should have received a copy of the GNU Library General Public
Packit 712bc5
 * License along with this library; if not, write to the
Packit 712bc5
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit 712bc5
 * Boston, MA 02110-1301, USA.
Packit 712bc5
 */
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * SECTION:gupnp-cds-last-change-parser
Packit 712bc5
 * @short_description: LastChange parser for the format used in
Packit 712bc5
 * CDS:3
Packit 712bc5
 *
Packit 712bc5
 * #GUPnPCDSLastChangeParser parses XML strings from
Packit 712bc5
 * CDS's LastChange state variable.
Packit 712bc5
 *
Packit 712bc5
 */
Packit 712bc5
Packit 712bc5
#include "xml-util.h"
Packit 712bc5
#include "gupnp-cds-last-change-parser.h"
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * GUPnPCDSLastChangeEntry:
Packit 712bc5
 *
Packit 712bc5
 * Opaque struct which contains information about the event.
Packit 712bc5
 **/
Packit 712bc5
struct _GUPnPCDSLastChangeEntry {
Packit 712bc5
        int ref_count;
Packit 712bc5
        GUPnPCDSLastChangeEvent event;
Packit 712bc5
        char *object_id;
Packit 712bc5
        char *parent_id;
Packit 712bc5
        char *class;
Packit 712bc5
        guint32 update_id;
Packit 712bc5
        gboolean is_subtree_update;
Packit 712bc5
};
Packit 712bc5
Packit 712bc5
G_DEFINE_TYPE (GUPnPCDSLastChangeParser,
Packit 712bc5
               gupnp_cds_last_change_parser,
Packit 712bc5
               G_TYPE_OBJECT)
Packit 712bc5
Packit 712bc5
G_DEFINE_BOXED_TYPE (GUPnPCDSLastChangeEntry,
Packit 712bc5
                     gupnp_cds_last_change_entry,
Packit 712bc5
                     gupnp_cds_last_change_entry_ref,
Packit 712bc5
                     gupnp_cds_last_change_entry_unref);
Packit 712bc5
Packit 712bc5
static void
Packit 712bc5
gupnp_cds_last_change_parser_init (G_GNUC_UNUSED GUPnPCDSLastChangeParser *parser)
Packit 712bc5
{
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
static void
Packit 712bc5
gupnp_cds_last_change_parser_class_init (G_GNUC_UNUSED GUPnPCDSLastChangeParserClass *klass)
Packit 712bc5
{
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_parser_new:
Packit 712bc5
 *
Packit 712bc5
 * Create a new #GUPnPCDSLastChangeParser.
Packit 712bc5
 *
Packit 712bc5
 * This parser is able to parse LastChange as defined in the
Packit 712bc5
 * ContentDirectory:3 specification.
Packit 712bc5
 *
Packit 712bc5
 * Returns:(transfer full): A new instance of #GUPnPCDSLastChangeParser.
Packit 712bc5
 **/
Packit 712bc5
GUPnPCDSLastChangeParser *
Packit 712bc5
gupnp_cds_last_change_parser_new (void)
Packit 712bc5
{
Packit 712bc5
        return g_object_new (GUPNP_TYPE_CDS_LAST_CHANGE_PARSER,
Packit 712bc5
                             NULL);
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_parser_parse:
Packit 712bc5
 * @parser: #GUPnPCDSLastChangeParser
Packit 712bc5
 * @last_change: XML string to parse
Packit 712bc5
 * @error: Return value for parser error or %NULL to ingore
Packit 712bc5
 *
Packit 712bc5
 * Parse a LastChange XML document in the flavor defined by the
Packit 712bc5
 * ContentDirectory:3 specification.
Packit 712bc5
 *
Packit 712bc5
 * Returns: (element-type GUPnPCDSLastChangeEntry)(transfer full):
Packit 712bc5
 * List of #GUPnPCDSLastChangeEntrys
Packit 712bc5
 **/
Packit 712bc5
GList *
Packit 712bc5
gupnp_cds_last_change_parser_parse (GUPnPCDSLastChangeParser *parser,
Packit 712bc5
                                    const char               *last_change,
Packit 712bc5
                                    GError                  **error)
Packit 712bc5
Packit 712bc5
{
Packit 712bc5
        xmlDoc *doc;
Packit 712bc5
        xmlNode *state_event, *it;
Packit 712bc5
        GList *result = NULL;
Packit 712bc5
        GUPnPCDSLastChangeEntry *entry;
Packit 712bc5
Packit 712bc5
        g_return_val_if_fail (GUPNP_IS_CDS_LAST_CHANGE_PARSER (parser),
Packit 712bc5
                              NULL);
Packit 712bc5
Packit 712bc5
        doc = xmlParseDoc ((const xmlChar *) last_change);
Packit 712bc5
        if (doc == NULL) {
Packit 712bc5
                g_set_error (error,
Packit 712bc5
                             G_MARKUP_ERROR,
Packit 712bc5
                             G_MARKUP_ERROR_PARSE,
Packit 712bc5
                             "Could not parse LastChange XML");
Packit 712bc5
Packit 712bc5
                goto out;
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        state_event = xml_util_get_element ((xmlNode *) doc,
Packit 712bc5
                                            "StateEvent",
Packit 712bc5
                                            NULL);
Packit 712bc5
        if (state_event == NULL) {
Packit 712bc5
                g_set_error (error,
Packit 712bc5
                             G_MARKUP_ERROR,
Packit 712bc5
                             G_MARKUP_ERROR_PARSE,
Packit 712bc5
                             "Missing StateEvent node");
Packit 712bc5
Packit 712bc5
                goto out;
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        for (it = state_event->children; it != NULL; it = it->next) {
Packit 712bc5
                if (it->type == XML_TEXT_NODE)
Packit 712bc5
                        continue;
Packit 712bc5
                else if (g_ascii_strcasecmp ((const char *) it->name,
Packit 712bc5
                                             "objAdd") == 0) {
Packit 712bc5
                        const char *tmp;
Packit 712bc5
Packit 712bc5
                        entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
Packit 712bc5
                        entry->ref_count = 1;
Packit 712bc5
                        entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED;
Packit 712bc5
Packit 712bc5
                        tmp = xml_util_get_attribute_content (it, "objID");
Packit 712bc5
                        entry->object_id = g_strdup (tmp);
Packit 712bc5
Packit 712bc5
                        tmp = xml_util_get_attribute_content (it,
Packit 712bc5
                                                              "objParentID");
Packit 712bc5
                        entry->parent_id = g_strdup (tmp);
Packit 712bc5
Packit 712bc5
                        tmp = xml_util_get_attribute_content (it, "objClass");
Packit 712bc5
                        entry->class = g_strdup (tmp);
Packit 712bc5
Packit 712bc5
                        entry->update_id = (guint32) xml_util_get_uint_attribute
Packit 712bc5
                                        (it,
Packit 712bc5
                                         "updateID",
Packit 712bc5
                                         0);
Packit 712bc5
                        entry->is_subtree_update =
Packit 712bc5
                                        xml_util_get_boolean_attribute
Packit 712bc5
                                                (it,
Packit 712bc5
                                                 "stUpdate");
Packit 712bc5
                } else if (g_ascii_strcasecmp ((const char *) it->name,
Packit 712bc5
                                               "objMod") == 0) {
Packit 712bc5
                        const char *tmp;
Packit 712bc5
Packit 712bc5
                        entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
Packit 712bc5
                        entry->ref_count = 1;
Packit 712bc5
                        entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED;
Packit 712bc5
Packit 712bc5
                        tmp = xml_util_get_attribute_content (it, "objID");
Packit 712bc5
                        entry->object_id = g_strdup (tmp);
Packit 712bc5
Packit 712bc5
                        entry->update_id = (guint32) xml_util_get_uint_attribute
Packit 712bc5
                                        (it,
Packit 712bc5
                                         "updateID",
Packit 712bc5
                                         0);
Packit 712bc5
                        entry->is_subtree_update =
Packit 712bc5
                                        xml_util_get_boolean_attribute
Packit 712bc5
                                                (it,
Packit 712bc5
                                                 "stUpdate");
Packit 712bc5
                } else if (g_ascii_strcasecmp ((const char *) it->name,
Packit 712bc5
                                               "objDel") == 0) {
Packit 712bc5
                        const char *tmp;
Packit 712bc5
Packit 712bc5
                        entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
Packit 712bc5
                        entry->ref_count = 1;
Packit 712bc5
                        entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_REMOVED;
Packit 712bc5
Packit 712bc5
                        tmp = xml_util_get_attribute_content (it, "objID");
Packit 712bc5
                        entry->object_id = g_strdup (tmp);
Packit 712bc5
Packit 712bc5
                        entry->update_id = (guint32) xml_util_get_uint_attribute
Packit 712bc5
                                        (it,
Packit 712bc5
                                         "updateID",
Packit 712bc5
                                         0);
Packit 712bc5
                        entry->is_subtree_update =
Packit 712bc5
                                        xml_util_get_boolean_attribute
Packit 712bc5
                                                (it,
Packit 712bc5
                                                 "stUpdate");
Packit 712bc5
                } else if (g_ascii_strcasecmp ((const char *) it->name,
Packit 712bc5
                                               "stDone") == 0) {
Packit 712bc5
                        const char *tmp;
Packit 712bc5
Packit 712bc5
                        entry = g_slice_new0 (GUPnPCDSLastChangeEntry);
Packit 712bc5
                        entry->ref_count = 1;
Packit 712bc5
                        entry->event = GUPNP_CDS_LAST_CHANGE_EVENT_ST_DONE;
Packit 712bc5
Packit 712bc5
                        tmp = xml_util_get_attribute_content (it, "objID");
Packit 712bc5
                        entry->object_id = g_strdup (tmp);
Packit 712bc5
Packit 712bc5
                        entry->update_id = (guint32) xml_util_get_uint_attribute
Packit 712bc5
                                        (it,
Packit 712bc5
                                         "updateID",
Packit 712bc5
                                         0);
Packit 712bc5
                } else {
Packit 712bc5
                        g_warning ("Skipping invalid LastChange entry: %s",
Packit 712bc5
                                   (const char *) it->name);
Packit 712bc5
                        continue;
Packit 712bc5
                }
Packit 712bc5
Packit 712bc5
                result = g_list_prepend (result, entry);
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        result = g_list_reverse (result);
Packit 712bc5
out:
Packit 712bc5
        if (doc != NULL) {
Packit 712bc5
                xmlFreeDoc (doc);
Packit 712bc5
        }
Packit 712bc5
Packit 712bc5
        return result;
Packit 712bc5
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_ref:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Increase reference count of a #GUPnPCDSLastChangeEntry.
Packit 712bc5
 *
Packit 712bc5
 * Returns:(transfer full): The object passed in @entry.
Packit 712bc5
 **/
Packit 712bc5
GUPnPCDSLastChangeEntry *
Packit 712bc5
gupnp_cds_last_change_entry_ref (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL, NULL);
Packit 712bc5
        g_return_val_if_fail (entry->ref_count > 0, NULL);
Packit 712bc5
Packit 712bc5
        g_atomic_int_inc (&entry->ref_count);
Packit 712bc5
Packit 712bc5
        return entry;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_unref:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Decrease reference count of a #GUPnPCDSLastChangeEntry. If the reference
Packit 712bc5
 * count drops to 0, @entry is freed.
Packit 712bc5
 **/
Packit 712bc5
void
Packit 712bc5
gupnp_cds_last_change_entry_unref (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_if_fail (entry != NULL);
Packit 712bc5
        g_return_if_fail (entry->ref_count > 0);
Packit 712bc5
Packit 712bc5
        if (g_atomic_int_dec_and_test (&entry->ref_count)) {
Packit 712bc5
                g_free (entry->class);
Packit 712bc5
                g_free (entry->object_id);
Packit 712bc5
                g_free (entry->parent_id);
Packit 712bc5
Packit 712bc5
                g_slice_free (GUPnPCDSLastChangeEntry, entry);
Packit 712bc5
        }
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_get_event:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Get the type of the last change entry as defined in
Packit 712bc5
 * #GUPnPCDSLastChangeEvent.
Packit 712bc5
 *
Packit 712bc5
 * Returns: An event from the #GUPnPCDSLastChangeEvent or
Packit 712bc5
 * %GUPNP_CDS_LAST_CHANGE_EVENT_INVALID if the entry is not valid.
Packit 712bc5
 **/
Packit 712bc5
GUPnPCDSLastChangeEvent
Packit 712bc5
gupnp_cds_last_change_entry_get_event (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL,
Packit 712bc5
                              GUPNP_CDS_LAST_CHANGE_EVENT_INVALID);
Packit 712bc5
Packit 712bc5
        return entry->event;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_get_object_id:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Get the ID of the object in this change entry.
Packit 712bc5
 *
Packit 712bc5
 * Returns: (transfer none): The id of the object of this entry.
Packit 712bc5
 **/
Packit 712bc5
const char *
Packit 712bc5
gupnp_cds_last_change_entry_get_object_id (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL, NULL);
Packit 712bc5
Packit 712bc5
        return entry->object_id;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_get_parent_id:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Get the parent object id of the object in this change entry. This is only
Packit 712bc5
 * valid if gupnp_cds_last_change_entry_get_event() returns
Packit 712bc5
 * %GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED.
Packit 712bc5
 *
Packit 712bc5
 * Returns: (transfer none): The id of the object's parent of this entry.
Packit 712bc5
 **/
Packit 712bc5
const char *
Packit 712bc5
gupnp_cds_last_change_entry_get_parent_id (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL, NULL);
Packit 712bc5
Packit 712bc5
        return entry->parent_id;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_get_class:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Get the class of the object in this change entry. This is only
Packit 712bc5
 * valid if gupnp_cds_last_change_entry_get_event() returns
Packit 712bc5
 * %GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_ADDED.
Packit 712bc5
 *
Packit 712bc5
 * Returns: (transfer none): The upnp class of the object of this entry.
Packit 712bc5
 **/
Packit 712bc5
const char *
Packit 712bc5
gupnp_cds_last_change_entry_get_class (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL, NULL);
Packit 712bc5
Packit 712bc5
        return entry->class;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_is_subtree_update:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Returns whether this entry is part of a subtree update.
Packit 712bc5
 *
Packit 712bc5
 * Returns: %TRUE, if the entry is part of a subtree update, %FALSE otherwise.
Packit 712bc5
 **/
Packit 712bc5
gboolean
Packit 712bc5
gupnp_cds_last_change_entry_is_subtree_update (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL, FALSE);
Packit 712bc5
Packit 712bc5
        return entry->is_subtree_update;
Packit 712bc5
}
Packit 712bc5
Packit 712bc5
/**
Packit 712bc5
 * gupnp_cds_last_change_entry_get_update_id:
Packit 712bc5
 * @entry: A #GUPnPCDSLastChangeEntry
Packit 712bc5
 *
Packit 712bc5
 * Get the update id of the last change entry.
Packit 712bc5
 *
Packit 712bc5
 * Returns: update id of the entry or 0 if the entry is not valid.
Packit 712bc5
 **/
Packit 712bc5
guint32
Packit 712bc5
gupnp_cds_last_change_entry_get_update_id (GUPnPCDSLastChangeEntry *entry)
Packit 712bc5
{
Packit 712bc5
        g_return_val_if_fail (entry != NULL, 0);
Packit 712bc5
Packit 712bc5
        return entry->update_id;
Packit 712bc5
}