summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Georg <mail@jensge.org>2022-10-20 00:38:05 +0200
committerJens Georg <mail@jensge.org>2022-10-20 21:50:40 +0200
commit03d996353cf6eca52ce28e37b5dc560605d110e2 (patch)
tree78a27cd161b77d83d408b0c2bf276cee68795899
parente9fb08b74971b87d59f50cd8d11e6ce0422f24da (diff)
downloadgupnp-av-wip/phako/clocksync.tar.gz
wip: Implement BOOKMARKS featurewip/phako/clocksync
-rw-r--r--libgupnp-av/gupnp-didl-lite-createclass.h1
-rw-r--r--libgupnp-av/gupnp-feature-clocksync.c0
-rw-r--r--libgupnp-av/gupnp-feature-clocksync.h0
-rw-r--r--libgupnp-av/gupnp-feature-container-shortcuts.c124
-rw-r--r--libgupnp-av/gupnp-feature-container-shortcuts.h52
-rw-r--r--libgupnp-av/gupnp-feature-list-parser.c18
-rw-r--r--libgupnp-av/gupnp-feature-private.h19
-rw-r--r--libgupnp-av/gupnp-feature.c82
-rw-r--r--libgupnp-av/meson.build1
-rw-r--r--libgupnp-av/xml-util.c6
-rw-r--r--tests/check-feature-list-parser.c41
11 files changed, 334 insertions, 10 deletions
diff --git a/libgupnp-av/gupnp-didl-lite-createclass.h b/libgupnp-av/gupnp-didl-lite-createclass.h
index 3d33f9e..3f734ea 100644
--- a/libgupnp-av/gupnp-didl-lite-createclass.h
+++ b/libgupnp-av/gupnp-didl-lite-createclass.h
@@ -15,7 +15,6 @@
#include <glib-object.h>
#include <libxml/tree.h>
-#include "gupnp-didl-lite-container.h"
G_BEGIN_DECLS
diff --git a/libgupnp-av/gupnp-feature-clocksync.c b/libgupnp-av/gupnp-feature-clocksync.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libgupnp-av/gupnp-feature-clocksync.c
diff --git a/libgupnp-av/gupnp-feature-clocksync.h b/libgupnp-av/gupnp-feature-clocksync.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libgupnp-av/gupnp-feature-clocksync.h
diff --git a/libgupnp-av/gupnp-feature-container-shortcuts.c b/libgupnp-av/gupnp-feature-container-shortcuts.c
new file mode 100644
index 0000000..8dffd6d
--- /dev/null
+++ b/libgupnp-av/gupnp-feature-container-shortcuts.c
@@ -0,0 +1,124 @@
+#include "gupnp-feature-container-shortcuts.h"
+#include "gupnp-feature-private.h"
+#include "xml-util.h"
+
+#include <libxml/tree.h>
+
+struct _GUPnPContainerShortcut {
+ GUPnPAVXMLDoc *doc;
+ xmlNodePtr node;
+};
+
+
+struct _GUPnPFeatureContainerShortcuts {
+ GUPnPFeature parent;
+};
+
+G_DEFINE_TYPE (GUPnPFeatureContainerShortcuts,
+ gupnp_feature_container_shortcuts,
+ GUPNP_TYPE_FEATURE)
+
+static void
+gupnp_feature_container_shortcuts_init (GUPnPFeatureContainerShortcuts *self)
+{
+}
+
+static void
+gupnp_feature_container_shortcuts_class_init (
+ GUPnPFeatureContainerShortcutsClass *klass)
+{
+}
+
+/**
+ * gupnp_feature_container_shortcuts_get_list:
+ *
+ * Get the supported shortcuts on that feature.
+ *
+ * Returns: (element-type: GUPnPContainerShortcut): List
+ * of shortcuts included in this feature.
+ */
+GSList *
+gupnp_feature_container_shortcuts_get_list (
+ GUPnPFeatureContainerShortcuts *self)
+{
+ xmlNode *node = gupnp_feature_get_node (GUPNP_FEATURE (self));
+ xmlNode *shortcuts_node =
+ av_xml_util_get_element (node, "shortcutlist", NULL);
+
+ if (shortcuts_node == NULL) {
+ return NULL;
+ }
+
+ GList *shortcuts =
+ av_xml_util_get_child_elements_by_name (shortcuts_node,
+ "shortcut");
+ GList *it = shortcuts;
+ GSList *retval = NULL;
+
+ while (it != NULL) {
+ GUPnPContainerShortcut *shortcut =
+ g_rc_box_new0 (GUPnPContainerShortcut);
+
+ shortcut->doc = gupnp_feature_get_doc (GUPNP_FEATURE (self));
+ shortcut->node = it->data;
+
+ retval = g_slist_prepend (retval, shortcut);
+ it = it->next;
+ }
+
+ return g_slist_reverse(retval);
+}
+
+/**
+ * gupnp_container_shortcut_type:
+ *
+ * Get the gtype for GUPnPServiceActon
+ *
+ * Return value: The gtype of GUPnPServiceAction
+ **/
+GType
+gupnp_container_shortcut_get_type (void)
+{
+ static GType our_type = 0;
+
+ if (our_type == 0)
+ our_type = g_boxed_type_register_static (
+ "GUPnPServiceAction",
+ (GBoxedCopyFunc) gupnp_container_shortcut_ref,
+ (GBoxedFreeFunc) gupnp_container_shortcut_unref);
+
+ return our_type;
+}
+
+GUPnPContainerShortcut *
+gupnp_container_shortcut_ref (GUPnPContainerShortcut *shortcut)
+{
+ return g_rc_box_acquire (shortcut);
+}
+
+static void
+gupnp_container_shortcut_free (GUPnPContainerShortcut *shortcut)
+{
+ g_clear_pointer (&shortcut->doc, av_xml_doc_unref);
+}
+
+void
+gupnp_container_shortcut_unref (GUPnPContainerShortcut *shortcut)
+{
+ g_rc_box_release_full (shortcut,
+ (GDestroyNotify) gupnp_container_shortcut_free);
+}
+
+
+const char *
+gupnp_container_shortcut_get_name (GUPnPContainerShortcut *shortcut)
+{
+ return av_xml_util_get_child_element_content (shortcut->node, "name");
+}
+
+const char *
+gupnp_container_shortcut_get_object_id (GUPnPContainerShortcut *shortcut)
+{
+ return av_xml_util_get_child_element_content (shortcut->node,
+ "objectID");
+}
diff --git a/libgupnp-av/gupnp-feature-container-shortcuts.h b/libgupnp-av/gupnp-feature-container-shortcuts.h
new file mode 100644
index 0000000..5fb475d
--- /dev/null
+++ b/libgupnp-av/gupnp-feature-container-shortcuts.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2022 Jens Georg <mail@jensge.org>
+
+#pragma once
+
+#include <config.h>
+
+#include "gupnp-feature.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_FEATURE_CONTAINER_SHORTCUTS \
+ (gupnp_feature_container_shortcuts_get_type ())
+
+G_DECLARE_FINAL_TYPE (GUPnPFeatureContainerShortcuts,
+ gupnp_feature_container_shortcuts,
+ GUPNP,
+ FEATURE_CONTAINER_SHORTCUTS,
+ GUPnPFeature)
+
+typedef struct _GUPnPContainerShortcut GUPnPContainerShortcut;
+
+#define GUPNP_TYPE_CONTAINER_SHORTCUT (gupnp_container_shortcut_get_type ())
+
+struct _GUPnPFeatureContainerShortcutsClass {
+ GUPnPFeature parent_class;
+};
+
+GSList *gupnp_feature_container_shortcuts_get_list(
+ GUPnPFeatureContainerShortcuts *self);
+
+GType
+gupnp_container_shortcut_get_type (void);
+
+GUPnPContainerShortcut *
+gupnp_container_shortcut_ref (GUPnPContainerShortcut *);
+
+void
+gupnp_container_shortcut_unref (GUPnPContainerShortcut *);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GUPnPContainerShortcut,
+ gupnp_container_shortcut_unref)
+
+const char *
+gupnp_container_shortcut_get_name (GUPnPContainerShortcut *);
+
+const char *
+gupnp_container_shortcut_get_object_id (GUPnPContainerShortcut *);
+
+G_END_DECLS
diff --git a/libgupnp-av/gupnp-feature-list-parser.c b/libgupnp-av/gupnp-feature-list-parser.c
index 16208b5..f4fe357 100644
--- a/libgupnp-av/gupnp-feature-list-parser.c
+++ b/libgupnp-av/gupnp-feature-list-parser.c
@@ -113,6 +113,7 @@ gupnp_feature_list_parser_parse_text
xmlDoc *doc;
xmlNode *element;
GList *feature_list = NULL;
+ GUPnPAVXMLDoc *xml_doc = NULL;
doc = xmlRecoverMemory (text, strlen (text));
if (doc == NULL) {
@@ -124,6 +125,8 @@ gupnp_feature_list_parser_parse_text
return NULL;
}
+ xml_doc = av_xml_doc_new (doc);
+
/* Get a pointer to root element */
element = av_xml_util_get_element ((xmlNode *) doc, "Features", NULL);
if (element == NULL) {
@@ -168,9 +171,16 @@ gupnp_feature_list_parser_parse_text
object_ids = get_feature_object_ids (element);
feature = g_object_new (GUPNP_TYPE_FEATURE,
- "name", name,
- "version", version,
- "object-ids", object_ids,
+ "doc",
+ xml_doc,
+ "node",
+ element,
+ "name",
+ name,
+ "version",
+ version,
+ "object-ids",
+ object_ids,
NULL);
feature_list = g_list_append (feature_list, feature);
@@ -179,7 +189,7 @@ gupnp_feature_list_parser_parse_text
}
}
- xmlFreeDoc (doc);
+ av_xml_doc_unref (xml_doc);
return feature_list;
}
diff --git a/libgupnp-av/gupnp-feature-private.h b/libgupnp-av/gupnp-feature-private.h
new file mode 100644
index 0000000..908ac5d
--- /dev/null
+++ b/libgupnp-av/gupnp-feature-private.h
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+// SPDX-FileCopyrightText: 2022 Jens Georg <mail@jensge.org>
+
+#pragma once
+
+#include "gupnp-feature.h"
+#include "xml-util.h"
+
+G_BEGIN_DECLS
+
+G_GNUC_INTERNAL
+GUPnPAVXMLDoc *
+gupnp_feature_get_doc (GUPnPFeature *feature);
+
+G_GNUC_INTERNAL
+xmlNode *
+gupnp_feature_get_node (GUPnPFeature *feature);
+
+G_END_DECLS
diff --git a/libgupnp-av/gupnp-feature.c b/libgupnp-av/gupnp-feature.c
index ee12015..0f3f566 100644
--- a/libgupnp-av/gupnp-feature.c
+++ b/libgupnp-av/gupnp-feature.c
@@ -17,11 +17,18 @@
#include <config.h>
#include "gupnp-feature.h"
+#include "gupnp-feature-private.h"
+
+#include "xml-util.h"
+
+#include <libxml/tree.h>
struct _GUPnPFeaturePrivate {
char *name;
char *version;
char *object_ids;
+ GUPnPAVXMLDoc *doc;
+ xmlNode *node;
};
typedef struct _GUPnPFeaturePrivate GUPnPFeaturePrivate;
@@ -33,7 +40,9 @@ enum {
PROP_0,
PROP_NAME,
PROP_VERSION,
- PROP_OBJECT_IDS
+ PROP_OBJECT_IDS,
+ PROP_DOC,
+ PROP_NODE
};
static void
@@ -78,6 +87,12 @@ gupnp_feature_get_property (GObject *object,
g_value_set_string (value,
gupnp_feature_get_object_ids (feature));
break;
+ case PROP_DOC:
+ g_value_set_boxed (value, gupnp_feature_get_doc (feature));
+ break;
+ case PROP_NODE:
+ g_value_set_pointer (value, gupnp_feature_get_node (feature));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -101,7 +116,16 @@ gupnp_feature_set_property (GObject *object,
priv->version = g_value_dup_string (value);
break;
case PROP_OBJECT_IDS:
- priv->object_ids = g_value_dup_string (value);
+ if (G_VALUE_HOLDS(value, G_TYPE_STRING))
+ priv->object_ids = g_value_dup_string (value);
+ else
+ priv->object_ids = NULL;
+ break;
+ case PROP_DOC:
+ priv->doc = g_value_dup_boxed (value);
+ break;
+ case PROP_NODE:
+ priv->node = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -173,6 +197,37 @@ gupnp_feature_class_init (GUPnPFeatureClass *klass)
G_PARAM_STATIC_NAME |
G_PARAM_STATIC_NICK |
G_PARAM_STATIC_BLURB));
+
+ /**
+ * GUPnPFeature:doc:
+ *
+ * The XML Doc of the feature list that contains this feature.
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_DOC,
+ g_param_spec_boxed ("doc",
+ "XML document",
+ "XML document for the feature list that "
+ "contains this feature",
+ av_xml_doc_get_type (),
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GUPnPFeature:node:
+ *
+ * The XML node for this feature
+ **/
+ g_object_class_install_property (
+ object_class,
+ PROP_OBJECT_IDS,
+ g_param_spec_pointer ("node",
+ "XML node",
+ "XML node of this feature",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
}
/**
@@ -209,6 +264,24 @@ gupnp_feature_get_version (GUPnPFeature *feature)
return priv->version;
}
+GUPnPAVXMLDoc *
+gupnp_feature_get_doc (GUPnPFeature *feature)
+{
+ GUPnPFeaturePrivate *priv =
+ gupnp_feature_get_instance_private (GUPNP_FEATURE (feature));
+
+ return av_xml_doc_ref (priv->doc);
+}
+
+xmlNode *
+gupnp_feature_get_node (GUPnPFeature *feature)
+{
+ GUPnPFeaturePrivate *priv =
+ gupnp_feature_get_instance_private (GUPNP_FEATURE (feature));
+
+ return priv->node;
+}
+
/**
* gupnp_feature_get_object_ids:
* @feature: #GUPnPFeature
@@ -216,8 +289,11 @@ gupnp_feature_get_version (GUPnPFeature *feature)
* Get the object IDs related to the @feature.
*
* Return value: The object IDs related to the @feature.
+ *
+ * Deprecated. Use gupnp_feature_bookmarks_get_object_ids() or
+ * gupnp_feature_epg_get_object_ids() instead
**/
-const char *
+G_GNUC_DEPRECATED const char *
gupnp_feature_get_object_ids (GUPnPFeature *feature)
{
GUPnPFeaturePrivate *priv =
diff --git a/libgupnp-av/meson.build b/libgupnp-av/meson.build
index 89cc927..769c886 100644
--- a/libgupnp-av/meson.build
+++ b/libgupnp-av/meson.build
@@ -16,6 +16,7 @@ introspection_sources = [
'gupnp-didl-lite-writer.c',
'gupnp-dlna.c',
'gupnp-feature.c',
+ 'gupnp-feature-container-shortcuts.c',
'gupnp-feature-list-parser.c',
'gupnp-last-change-parser.c',
'gupnp-media-collection.c',
diff --git a/libgupnp-av/xml-util.c b/libgupnp-av/xml-util.c
index 0d1661b..a72ad00 100644
--- a/libgupnp-av/xml-util.c
+++ b/libgupnp-av/xml-util.c
@@ -54,6 +54,12 @@ av_xml_doc_free (GUPnPAVXMLDoc *doc)
g_clear_pointer (&doc->doc, xmlFreeDoc);
}
+GUPnPAVXMLDoc *
+av_xml_doc_ref (GUPnPAVXMLDoc *doc)
+{
+ return g_rc_box_acquire (doc);
+}
+
void
av_xml_doc_unref (GUPnPAVXMLDoc *doc)
{
diff --git a/tests/check-feature-list-parser.c b/tests/check-feature-list-parser.c
index 94e968a..7011a67 100644
--- a/tests/check-feature-list-parser.c
+++ b/tests/check-feature-list-parser.c
@@ -10,17 +10,21 @@
#include <config.h>
#include <libgupnp-av/gupnp-feature-list-parser.h>
+#include <libgupnp-av/gupnp-feature-container-shortcuts.h>
+
#include <stdlib.h>
#include <string.h>
static const char * const names[] = {
"BOOKMARK",
"EPG",
+ "CONTAINER_SHORTCUTS",
};
static const char * const versions[] = {
"1",
"2",
+ "1",
};
static const char * const ids[] = {
@@ -28,6 +32,17 @@ static const char * const ids[] = {
"epg1,epg2",
};
+static const char *const container_names[] = {
+ "MUSIC_GENRES",
+ "IMAGES_ALL",
+};
+
+static const char *const container_ids[] = {
+ "container:genre",
+ "container:images_all",
+};
+
+//clang-format off
static const char *text =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
"<Features "
@@ -43,7 +58,20 @@ static const char *text =
"<Feature name=\"EPG\" version=\"2\">"
"<objectIDs>epg1,epg2</objectIDs>"
"</Feature>"
+ "<Feature name=\"CONTAINER_SHORTCUTS\" version=\"1\">"
+ "<shortcutlist>"
+ "<shortcut>"
+ "<name>MUSIC_GENRES</name>"
+ "<objectID>container:genre</objectID>"
+ "</shortcut>"
+ "<shortcut>"
+ "<name>IMAGES_ALL</name>"
+ "<objectID>container:images_all</objectID>"
+ "</shortcut>"
+ "</shortcutlist>"
+ "</Feature>"
"</Features>";
+// clang-format on
static gboolean
check_feature (GUPnPFeature *feature)
@@ -54,11 +82,20 @@ check_feature (GUPnPFeature *feature)
return FALSE;
if (strcmp (versions[index], gupnp_feature_get_version (feature)))
- return FALSE;
+ return FALSE;
- if (strcmp (ids[index], gupnp_feature_get_object_ids (feature)))
+ if (index < 2) {
+ if (strcmp (ids[index], gupnp_feature_get_object_ids (feature)))
+ return FALSE;
+ } else {
+ if (!GUPNP_IS_FEATURE_CONTAINER_SHORTCUTS (feature))
return FALSE;
+ GUPnPFeatureContainerShortcuts *f =
+ GUPNP_FEATURE_CONTAINER_SHORTCUTS (feature);
+
+ GSList *s = gupnp_feature_container_shortcuts_get_list (f);
+ }
index++;
return TRUE;