summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorljsachs <larry.j.sachs@intel.com>2016-10-11 14:19:41 -0700
committerGitHub <noreply@github.com>2016-10-11 14:19:41 -0700
commitc9812c82bd5706b072e75bc840c8c8934655c1db (patch)
tree291bbecef3766ab9a7750c3b6740b996f7aeaf8e
parentd045708ef41cb65b14cc4113fe8e2242642f91d7 (diff)
downloaddleyna-server-ljsachs-patch-1.tar.gz
fix for issue #156ljsachs-patch-1
-rw-r--r--props.c2182
1 files changed, 2182 insertions, 0 deletions
diff --git a/props.c b/props.c
new file mode 100644
index 0000000..fdef7b5
--- /dev/null
+++ b/props.c
@@ -0,0 +1,2182 @@
+/*
+ * dLeyna
+ *
+ * Copyright (C) 2012-2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Mark Ryan <mark.d.ryan@intel.com>
+ *
+ */
+
+#include <string.h>
+#include <libgupnp-av/gupnp-didl-lite-contributor.h>
+#include <libgupnp-av/gupnp-dlna.h>
+#include <libgupnp-av/gupnp-protocol-info.h>
+
+#include <libdleyna/core/log.h>
+
+#include "device.h"
+#include "interface.h"
+#include "path.h"
+#include "props.h"
+
+static const gchar gUPnPObject[] = "object";
+static const gchar gUPnPContainer[] = "object.container";
+static const gchar gUPnPAudioItem[] = "object.item.audioItem";
+static const gchar gUPnPVideoItem[] = "object.item.videoItem";
+static const gchar gUPnPImageItem[] = "object.item.imageItem";
+static const gchar gUPnPItem[] = "object.item";
+
+static const unsigned int gUPnPObjectLen =
+ (sizeof(gUPnPObject) / sizeof(gchar)) - 1;
+static const unsigned int gUPnPContainerLen =
+ (sizeof(gUPnPContainer) / sizeof(gchar)) - 1;
+static const unsigned int gUPnPAudioItemLen =
+ (sizeof(gUPnPAudioItem) / sizeof(gchar)) - 1;
+static const unsigned int gUPnPVideoItemLen =
+ (sizeof(gUPnPVideoItem) / sizeof(gchar)) - 1;
+static const unsigned int gUPnPImageItemLen =
+ (sizeof(gUPnPImageItem) / sizeof(gchar)) - 1;
+static const unsigned int gUPnPItemLen =
+ (sizeof(gUPnPItem) / sizeof(gchar)) - 1;
+
+static const gchar gUPnPMusicTrack[] = "object.item.audioItem.musicTrack";
+static const gchar gUPnPMovie[] = "object.item.videoItem.movie";
+static const gchar gUPnPPhoto[] = "object.item.imageItem.photo";
+
+static const gchar gMediaSpec2Container[] = "container";
+static const gchar gMediaSpec2AudioMusic[] = "music";
+static const gchar gMediaSpec2Audio[] = "audio";
+static const gchar gMediaSpec2Video[] = "video";
+static const gchar gMediaSpec2VideoMovie[] = "video.movie";
+static const gchar gMediaSpec2Image[] = "image";
+static const gchar gMediaSpec2ImagePhoto[] = "image.photo";
+static const gchar gMediaSpec2ItemUnclassified[] = "item.unclassified";
+
+static const gchar gMediaSpec2ExItem[] = "item";
+
+static const unsigned int gMediaSpec2ExItemLen =
+ (sizeof(gMediaSpec2ExItem) / sizeof(gchar)) - 1;
+
+static const unsigned int gMediaSpec2ContainerLen =
+ (sizeof(gMediaSpec2Container) / sizeof(gchar)) - 1;
+
+typedef struct dls_prop_dlna_t_ dls_prop_dlna_t;
+struct dls_prop_dlna_t_ {
+ guint dlna_flag;
+ const gchar *prop_name;
+};
+
+static const dls_prop_dlna_t g_prop_dlna_ci[] = {
+{GUPNP_DLNA_CONVERSION_TRANSCODED, "Transcoded"},
+{0, NULL}
+};
+
+static const dls_prop_dlna_t g_prop_dlna_op[] = {
+{GUPNP_DLNA_OPERATION_RANGE, "RangeSeek"},
+{GUPNP_DLNA_OPERATION_TIMESEEK, "TimeSeek"},
+{0, NULL}
+};
+
+static const dls_prop_dlna_t g_prop_dlna_flags[] = {
+{GUPNP_DLNA_FLAGS_SENDER_PACED, "SenderPaced"},
+{GUPNP_DLNA_FLAGS_TIME_BASED_SEEK, "TimeBased"},
+{GUPNP_DLNA_FLAGS_BYTE_BASED_SEEK, "ByteBased"},
+{GUPNP_DLNA_FLAGS_PLAY_CONTAINER, "PlayContainer"},
+{GUPNP_DLNA_FLAGS_S0_INCREASE, "S0Increase"},
+{GUPNP_DLNA_FLAGS_SN_INCREASE, "SNIncrease"},
+{GUPNP_DLNA_FLAGS_RTSP_PAUSE, "RTSPPause"},
+{GUPNP_DLNA_FLAGS_STREAMING_TRANSFER_MODE, "StreamingTM"},
+{GUPNP_DLNA_FLAGS_INTERACTIVE_TRANSFER_MODE, "InteractiveTM"},
+{GUPNP_DLNA_FLAGS_BACKGROUND_TRANSFER_MODE, "BackgroundTM"},
+{GUPNP_DLNA_FLAGS_CONNECTION_STALL, "ConnectionStall"},
+{GUPNP_DLNA_FLAGS_DLNA_V15, "DLNA_V15"},
+{0, NULL}
+};
+
+static const dls_prop_dlna_t g_prop_dlna_ocm[] = {
+{GUPNP_OCM_FLAGS_UPLOAD, "Upload"},
+{GUPNP_OCM_FLAGS_CREATE_CONTAINER, "CreateContainer"},
+{GUPNP_OCM_FLAGS_DESTROYABLE, "Delete"},
+{GUPNP_OCM_FLAGS_UPLOAD_DESTROYABLE, "UploadDelete"},
+{GUPNP_OCM_FLAGS_CHANGE_METADATA, "ChangeMeta"},
+{0, NULL}
+};
+
+static dls_prop_map_t *prv_prop_map_new(const gchar *prop_name,
+ dls_upnp_prop_mask type,
+ gboolean filter,
+ gboolean searchable,
+ gboolean updateable)
+{
+ dls_prop_map_t *retval = g_new(dls_prop_map_t, 1);
+ retval->upnp_prop_name = prop_name;
+ retval->type = type;
+ retval->filter = filter;
+ retval->searchable = searchable;
+ retval->updateable = updateable;
+ return retval;
+}
+
+void dls_prop_maps_new(GHashTable **property_map, GHashTable **filter_map)
+{
+ dls_prop_map_t *prop_t;
+ GHashTable *p_map;
+ GHashTable *f_map;
+
+ p_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
+ f_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
+
+ /* @childCount */
+ prop_t = prv_prop_map_new("@childCount",
+ DLS_UPNP_MASK_PROP_CHILD_COUNT,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CHILD_COUNT, prop_t);
+ g_hash_table_insert(p_map, "@childCount",
+ DLS_INTERFACE_PROP_CHILD_COUNT);
+
+ /* @id */
+ prop_t = prv_prop_map_new("@id",
+ DLS_UPNP_MASK_PROP_PATH,
+ FALSE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_PATH, prop_t);
+ g_hash_table_insert(p_map, "@id", DLS_INTERFACE_PROP_PATH);
+
+ /* @parentID */
+ prop_t = prv_prop_map_new("@parentID",
+ DLS_UPNP_MASK_PROP_PARENT,
+ FALSE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_PARENT, prop_t);
+ g_hash_table_insert(p_map, "@parentID", DLS_INTERFACE_PROP_PARENT);
+
+ /* @refID */
+ prop_t = prv_prop_map_new("@refID",
+ DLS_UPNP_MASK_PROP_REFPATH,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_REFPATH, prop_t);
+ g_hash_table_insert(p_map, "@refID", DLS_INTERFACE_PROP_REFPATH);
+
+ /* @restricted */
+ prop_t = prv_prop_map_new("@restricted",
+ DLS_UPNP_MASK_PROP_RESTRICTED,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_RESTRICTED, prop_t);
+ g_hash_table_insert(p_map, "@restricted",
+ DLS_INTERFACE_PROP_RESTRICTED);
+
+ /* @searchable */
+ prop_t = prv_prop_map_new("@searchable",
+ DLS_UPNP_MASK_PROP_SEARCHABLE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_SEARCHABLE, prop_t);
+ g_hash_table_insert(p_map, "@searchable",
+ DLS_INTERFACE_PROP_SEARCHABLE);
+
+ /* dc:creator */
+ prop_t = prv_prop_map_new("dc:creator",
+ DLS_UPNP_MASK_PROP_CREATOR,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CREATOR, prop_t);
+ g_hash_table_insert(p_map, "dc:creator", DLS_INTERFACE_PROP_CREATOR);
+
+ /* dc:date */
+ prop_t = prv_prop_map_new("dc:date",
+ DLS_UPNP_MASK_PROP_DATE,
+ TRUE, TRUE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DATE, prop_t);
+ g_hash_table_insert(p_map, "dc:date", DLS_INTERFACE_PROP_DATE);
+
+ /* dc:title */
+ prop_t = prv_prop_map_new("dc:title",
+ DLS_UPNP_MASK_PROP_DISPLAY_NAME,
+ FALSE, TRUE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DISPLAY_NAME, prop_t);
+ g_hash_table_insert(p_map, "dc:title", DLS_INTERFACE_PROP_DISPLAY_NAME);
+
+ /* dlna:dlnaManaged */
+ prop_t = prv_prop_map_new("dlna:dlnaManaged",
+ DLS_UPNP_MASK_PROP_DLNA_MANAGED,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_MANAGED, prop_t);
+ g_hash_table_insert(p_map, "dlna:dlnaManaged",
+ DLS_INTERFACE_PROP_DLNA_MANAGED);
+
+ /* res */
+ /* res - RES */
+ prop_t = prv_prop_map_new("res",
+ DLS_UPNP_MASK_PROP_RESOURCES,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_RESOURCES, prop_t);
+
+ /* res - URL */
+ prop_t = prv_prop_map_new("res",
+ DLS_UPNP_MASK_PROP_URL,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_URL, prop_t);
+
+ /* res - URLS */
+ prop_t = prv_prop_map_new("res",
+ DLS_UPNP_MASK_PROP_URLS,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_URLS, prop_t);
+
+ /* res@bitrate */
+ prop_t = prv_prop_map_new("res@bitrate",
+ DLS_UPNP_MASK_PROP_BITRATE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_BITRATE, prop_t);
+ g_hash_table_insert(p_map, "res@bitrate", DLS_INTERFACE_PROP_BITRATE);
+
+ /* res@bitsPerSample */
+ prop_t = prv_prop_map_new("res@bitsPerSample",
+ DLS_UPNP_MASK_PROP_BITS_PER_SAMPLE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_BITS_PER_SAMPLE, prop_t);
+ g_hash_table_insert(p_map, "res@bitsPerSample",
+ DLS_INTERFACE_PROP_BITS_PER_SAMPLE);
+
+ /* res@colorDepth */
+ prop_t = prv_prop_map_new("res@colorDepth",
+ DLS_UPNP_MASK_PROP_COLOR_DEPTH,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_COLOR_DEPTH, prop_t);
+ g_hash_table_insert(p_map, "res@colorDepth",
+ DLS_INTERFACE_PROP_COLOR_DEPTH);
+
+ /* res@duration */
+ prop_t = prv_prop_map_new("res@duration",
+ DLS_UPNP_MASK_PROP_DURATION,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DURATION, prop_t);
+ g_hash_table_insert(p_map, "res@duration",
+ DLS_INTERFACE_PROP_DURATION);
+
+ /* res@protocolInfo */
+ /* res@protocolInfo - DLNA PROFILE*/
+ prop_t = prv_prop_map_new("res@protocolInfo",
+ DLS_UPNP_MASK_PROP_DLNA_PROFILE,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_PROFILE, prop_t);
+
+ /* res@protocolInfo - DLNA CONVERSION*/
+ prop_t = prv_prop_map_new("res@protocolInfo",
+ DLS_UPNP_MASK_PROP_DLNA_CONVERSION,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_CONVERSION, prop_t);
+
+ /* res@protocolInfo - DLNA OPERATION*/
+ prop_t = prv_prop_map_new("res@protocolInfo",
+ DLS_UPNP_MASK_PROP_DLNA_OPERATION,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_OPERATION, prop_t);
+
+ /* res@protocolInfo - DLNA FLAGS*/
+ prop_t = prv_prop_map_new("res@protocolInfo",
+ DLS_UPNP_MASK_PROP_DLNA_FLAGS,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_DLNA_FLAGS, prop_t);
+
+ /* res@protocolInfo - MIME TYPES*/
+ prop_t = prv_prop_map_new("res@protocolInfo",
+ DLS_UPNP_MASK_PROP_MIME_TYPE,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_MIME_TYPE, prop_t);
+
+ /* res@resolution */
+ /* res@resolution - HEIGH */
+ prop_t = prv_prop_map_new("res@resolution",
+ DLS_UPNP_MASK_PROP_HEIGHT,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_HEIGHT, prop_t);
+
+ /* res@resolution - WIDTH */
+ prop_t = prv_prop_map_new("res@resolution",
+ DLS_UPNP_MASK_PROP_WIDTH,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_WIDTH, prop_t);
+
+ /* res@sampleFrequency */
+ prop_t = prv_prop_map_new("res@sampleFrequency",
+ DLS_UPNP_MASK_PROP_SAMPLE_RATE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_SAMPLE_RATE, prop_t);
+ g_hash_table_insert(p_map, "res@sampleFrequency",
+ DLS_INTERFACE_PROP_SAMPLE_RATE);
+
+ /* res@size */
+ prop_t = prv_prop_map_new("res@size",
+ DLS_UPNP_MASK_PROP_SIZE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_SIZE, prop_t);
+ g_hash_table_insert(p_map, "res@size", DLS_INTERFACE_PROP_SIZE);
+
+ /* res@updateCount */
+ prop_t = prv_prop_map_new("res@updateCount",
+ DLS_UPNP_MASK_PROP_UPDATE_COUNT,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_UPDATE_COUNT, prop_t);
+ g_hash_table_insert(p_map, "res@updateCount",
+ DLS_INTERFACE_PROP_UPDATE_COUNT);
+
+ /* upnp:album */
+ prop_t = prv_prop_map_new("upnp:album",
+ DLS_UPNP_MASK_PROP_ALBUM,
+ TRUE, TRUE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ALBUM, prop_t);
+ g_hash_table_insert(p_map, "upnp:album", DLS_INTERFACE_PROP_ALBUM);
+
+ /* upnp:albumArtURI */
+ prop_t = prv_prop_map_new("upnp:albumArtURI",
+ DLS_UPNP_MASK_PROP_ALBUM_ART_URL,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ALBUM_ART_URL, prop_t);
+ g_hash_table_insert(p_map, "upnp:albumArtURI",
+ DLS_INTERFACE_PROP_ALBUM_ART_URL);
+
+ /* upnp:artist */
+ /* upnp:artist - ARTIST*/
+ prop_t = prv_prop_map_new("upnp:artist",
+ DLS_UPNP_MASK_PROP_ARTIST,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ARTIST, prop_t);
+ g_hash_table_insert(p_map, "upnp:artist", DLS_INTERFACE_PROP_ARTIST);
+
+ /* upnp:artist - ARTISTS*/
+ prop_t = prv_prop_map_new("upnp:artist",
+ DLS_UPNP_MASK_PROP_ARTISTS,
+ TRUE, FALSE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_ARTISTS, prop_t);
+
+ /* upnp:class */
+ prop_t = prv_prop_map_new("upnp:class",
+ DLS_UPNP_MASK_PROP_TYPE,
+ FALSE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TYPE, prop_t);
+ g_hash_table_insert(p_map, "upnp:class", DLS_INTERFACE_PROP_TYPE);
+
+ prop_t = prv_prop_map_new("upnp:class",
+ DLS_UPNP_MASK_PROP_TYPE_EX,
+ FALSE, TRUE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TYPE_EX, prop_t);
+
+ /* upnp:containerUpdateID */
+ prop_t = prv_prop_map_new("upnp:containerUpdateID",
+ DLS_UPNP_MASK_PROP_CONTAINER_UPDATE_ID,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID,
+ prop_t);
+ g_hash_table_insert(p_map, "upnp:containerUpdateID",
+ DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID);
+
+ /* upnp:createClass */
+ prop_t = prv_prop_map_new("upnp:createClass",
+ DLS_UPNP_MASK_PROP_CREATE_CLASSES,
+ TRUE, FALSE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_CREATE_CLASSES, prop_t);
+
+ /* upnp:genre */
+ prop_t = prv_prop_map_new("upnp:genre",
+ DLS_UPNP_MASK_PROP_GENRE,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_GENRE, prop_t);
+ g_hash_table_insert(p_map, "upnp:genre", DLS_INTERFACE_PROP_GENRE);
+
+ /* upnp:objectUpdateID */
+ prop_t = prv_prop_map_new("upnp:objectUpdateID",
+ DLS_UPNP_MASK_PROP_OBJECT_UPDATE_ID,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_OBJECT_UPDATE_ID, prop_t);
+ g_hash_table_insert(p_map, "upnp:objectUpdateID",
+ DLS_INTERFACE_PROP_OBJECT_UPDATE_ID);
+
+ /* upnp:originalTrackNumber */
+ prop_t = prv_prop_map_new("upnp:originalTrackNumber",
+ DLS_UPNP_MASK_PROP_TRACK_NUMBER,
+ TRUE, TRUE, TRUE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TRACK_NUMBER, prop_t);
+ g_hash_table_insert(p_map, "upnp:originalTrackNumber",
+ DLS_INTERFACE_PROP_TRACK_NUMBER);
+
+ /* upnp:totalDeletedChildCount */
+ prop_t = prv_prop_map_new("upnp:totalDeletedChildCount",
+ DLS_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT,
+ TRUE, TRUE, FALSE);
+ g_hash_table_insert(f_map, DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT,
+ prop_t);
+ g_hash_table_insert(p_map, "upnp:totalDeletedChildCount",
+ DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT);
+
+ *filter_map = f_map;
+ *property_map = p_map;
+}
+
+static gchar *prv_compute_upnp_filter(GHashTable *upnp_props)
+{
+ gpointer key;
+ GString *str;
+ GHashTableIter iter;
+
+ str = g_string_new("");
+ g_hash_table_iter_init(&iter, upnp_props);
+ if (g_hash_table_iter_next(&iter, &key, NULL)) {
+ g_string_append(str, (const gchar *)key);
+ while (g_hash_table_iter_next(&iter, &key, NULL)) {
+ g_string_append(str, ",");
+ g_string_append(str, (const gchar *)key);
+ }
+ }
+
+ return g_string_free(str, FALSE);
+}
+
+static dls_upnp_prop_mask prv_parse_filter_list(GHashTable *filter_map,
+ GVariant *filter,
+ gchar **upnp_filter)
+{
+ GVariantIter viter;
+ const gchar *prop;
+ dls_prop_map_t *prop_map;
+ GHashTable *upnp_props;
+ dls_upnp_prop_mask mask = 0;
+
+ upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+ (void) g_variant_iter_init(&viter, filter);
+
+ while (g_variant_iter_next(&viter, "&s", &prop)) {
+ prop_map = g_hash_table_lookup(filter_map, prop);
+ if (!prop_map)
+ continue;
+
+ mask |= prop_map->type;
+
+ if (!prop_map->filter)
+ continue;
+
+ g_hash_table_insert(upnp_props,
+ (gpointer) prop_map->upnp_prop_name, NULL);
+ }
+
+ *upnp_filter = prv_compute_upnp_filter(upnp_props);
+ g_hash_table_unref(upnp_props);
+
+ return mask;
+}
+
+dls_upnp_prop_mask dls_props_parse_filter(GHashTable *filter_map,
+ GVariant *filter,
+ gchar **upnp_filter)
+{
+ gchar *str;
+ gboolean parse_filter = TRUE;
+ dls_upnp_prop_mask mask;
+
+ if (g_variant_n_children(filter) == 1) {
+ g_variant_get_child(filter, 0, "&s", &str);
+ if (!strcmp(str, "*"))
+ parse_filter = FALSE;
+ }
+
+ if (parse_filter) {
+ mask = prv_parse_filter_list(filter_map, filter, upnp_filter);
+ } else {
+ mask = DLS_UPNP_MASK_ALL_PROPS;
+ *upnp_filter = g_strdup("*");
+ }
+
+ return mask;
+}
+
+gboolean dls_props_parse_update_filter(GHashTable *filter_map,
+ GVariant *to_add_update,
+ GVariant *to_delete,
+ dls_upnp_prop_mask *mask,
+ gchar **upnp_filter)
+{
+ GVariantIter viter;
+ const gchar *prop;
+ GVariant *value;
+ dls_prop_map_t *prop_map;
+ GHashTable *upnp_props;
+ gboolean retval = FALSE;
+
+ *mask = 0;
+
+ upnp_props = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, NULL);
+
+ (void) g_variant_iter_init(&viter, to_add_update);
+
+ while (g_variant_iter_next(&viter, "{&sv}", &prop, &value)) {
+ DLEYNA_LOG_DEBUG("to_add_update = %s", prop);
+
+ prop_map = g_hash_table_lookup(filter_map, prop);
+
+ if ((!prop_map) || (!prop_map->updateable))
+ goto on_error;
+
+ *mask |= prop_map->type;
+
+ if (!prop_map->filter)
+ continue;
+
+ g_hash_table_insert(upnp_props,
+ (gpointer) prop_map->upnp_prop_name, NULL);
+ }
+
+ (void) g_variant_iter_init(&viter, to_delete);
+
+ while (g_variant_iter_next(&viter, "&s", &prop)) {
+ DLEYNA_LOG_DEBUG("to_delete = %s", prop);
+
+ prop_map = g_hash_table_lookup(filter_map, prop);
+
+ if ((!prop_map) || (!prop_map->updateable) ||
+ (*mask & prop_map->type) != 0)
+ goto on_error;
+
+ *mask |= prop_map->type;
+
+ if (!prop_map->filter)
+ continue;
+
+ g_hash_table_insert(upnp_props,
+ (gpointer) prop_map->upnp_prop_name, NULL);
+ }
+
+ *upnp_filter = prv_compute_upnp_filter(upnp_props);
+
+ retval = TRUE;
+
+on_error:
+
+ g_hash_table_unref(upnp_props);
+
+ return retval;
+}
+
+static void prv_add_string_prop(GVariantBuilder *vb, const gchar *key,
+ const gchar *value)
+{
+ if (value) {
+ DLEYNA_LOG_DEBUG("Prop %s = %s", key, value);
+
+ g_variant_builder_add(vb, "{sv}", key,
+ g_variant_new_string(value));
+ }
+}
+
+static void prv_add_strv_prop(GVariantBuilder *vb, const gchar *key,
+ const gchar **value, unsigned int len)
+{
+ if (value && *value && len > 0)
+ g_variant_builder_add(vb, "{sv}", key,
+ g_variant_new_strv(value, len));
+}
+
+static void prv_add_path_prop(GVariantBuilder *vb, const gchar *key,
+ const gchar *value)
+{
+ if (value) {
+ DLEYNA_LOG_DEBUG("Prop %s = %s", key, value);
+
+ g_variant_builder_add(vb, "{sv}", key,
+ g_variant_new_object_path(value));
+ }
+}
+
+static void prv_add_uint_prop(GVariantBuilder *vb, const gchar *key,
+ unsigned int value)
+{
+ DLEYNA_LOG_DEBUG("Prop %s = %u", key, value);
+
+ g_variant_builder_add(vb, "{sv}", key, g_variant_new_uint32(value));
+}
+
+static void prv_add_int_prop(GVariantBuilder *vb, const gchar *key,
+ int value)
+{
+ if (value != -1)
+ g_variant_builder_add(vb, "{sv}", key,
+ g_variant_new_int32(value));
+}
+
+static void prv_add_variant_prop(GVariantBuilder *vb, const gchar *key,
+ GVariant *prop)
+{
+ if (prop)
+ g_variant_builder_add(vb, "{sv}", key, prop);
+}
+
+void dls_props_add_child_count(GVariantBuilder *item_vb, gint value)
+{
+ prv_add_uint_prop(item_vb, DLS_INTERFACE_PROP_CHILD_COUNT, value);
+}
+
+static void prv_add_bool_prop(GVariantBuilder *vb, const gchar *key,
+ gboolean value)
+{
+ DLEYNA_LOG_DEBUG("Prop %s = %u", key, value);
+
+ g_variant_builder_add(vb, "{sv}", key, g_variant_new_boolean(value));
+}
+
+static void prv_add_int64_prop(GVariantBuilder *vb, const gchar *key,
+ gint64 value)
+{
+ if (value != -1) {
+ DLEYNA_LOG_DEBUG("Prop %s = %"G_GINT64_FORMAT, key, value);
+
+ g_variant_builder_add(vb, "{sv}", key,
+ g_variant_new_int64(value));
+ }
+}
+
+static void prv_add_list_dlna_str(gpointer data, gpointer user_data)
+{
+ GVariantBuilder *vb = (GVariantBuilder *)user_data;
+ gchar *cap_str = (gchar *)data;
+ gchar *str;
+ int value = 0;
+
+ if (g_str_has_prefix(cap_str, "srs-rt-retention-period-")) {
+ str = cap_str + strlen("srs-rt-retention-period-");
+ cap_str = "srs-rt-retention-period";
+
+ if (*str) {
+ if (!g_strcmp0(str, "infinity"))
+ value = -1;
+ else
+ value = atoi(str);
+ }
+ }
+
+ prv_add_uint_prop(vb, cap_str, value);
+}
+
+static GVariant *prv_add_list_dlna_prop(GList *list)
+{
+ GVariantBuilder vb;
+
+ g_variant_builder_init(&vb, G_VARIANT_TYPE("a{sv}"));
+
+ g_list_foreach(list, prv_add_list_dlna_str, &vb);
+
+ return g_variant_builder_end(&vb);
+}
+
+static GVariant *prv_props_get_dlna_info_dict(guint flags,
+ const dls_prop_dlna_t *dfa)
+{
+ GVariantBuilder builder;
+ gboolean set;
+ gint i = 0;
+
+ g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sb}"));
+
+ while (dfa[i].dlna_flag) {
+ set = (flags & dfa[i].dlna_flag) != 0;
+ g_variant_builder_add(&builder, "{sb}", dfa[i].prop_name, set);
+ i++;
+ }
+
+ return g_variant_builder_end(&builder);
+}
+
+static void prv_add_list_artists_str(gpointer data, gpointer user_data)
+{
+ GVariantBuilder *vb = (GVariantBuilder *)user_data;
+ GUPnPDIDLLiteContributor *contributor = data;
+ const char *str;
+
+ str = gupnp_didl_lite_contributor_get_name(contributor);
+ g_variant_builder_add(vb, "s", str);
+}
+
+static GVariant *prv_get_artists_prop(GList *list)
+{
+ GVariantBuilder vb;
+
+ g_variant_builder_init(&vb, G_VARIANT_TYPE("as"));
+ g_list_foreach(list, prv_add_list_artists_str, &vb);
+
+ return g_variant_builder_end(&vb);
+}
+
+void dls_props_add_device(GUPnPDeviceInfo *root_proxy,
+ GUPnPDeviceInfo *proxy,
+ GUPnPServiceProxy *ems_proxy,
+ const dls_device_t *device,
+ GVariantBuilder *vb)
+{
+ gchar *str;
+ GList *list;
+ GVariant *dlna_caps;
+
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_LOCATION,
+ gupnp_device_info_get_location(proxy));
+
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_UDN,
+ gupnp_device_info_get_udn(proxy));
+
+ if (proxy != root_proxy)
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_ROOT_UDN,
+ gupnp_device_info_get_udn(root_proxy));
+
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_DEVICE_TYPE,
+ gupnp_device_info_get_device_type(proxy));
+
+ str = gupnp_device_info_get_friendly_name(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_FRIENDLY_NAME, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_manufacturer(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_MANUFACTURER, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_manufacturer_url(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_MANUFACTURER_URL, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_model_description(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_DESCRIPTION, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_model_name(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_NAME, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_model_number(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_NUMBER, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_model_url(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_MODEL_URL, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_serial_number(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_SERIAL_NUMBER, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_presentation_url(proxy);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_PRESENTATION_URL, str);
+ g_free(str);
+
+ str = gupnp_device_info_get_icon_url(proxy, NULL, -1, -1, -1, FALSE,
+ NULL, NULL, NULL, NULL);
+ prv_add_string_prop(vb, DLS_INTERFACE_PROP_ICON_URL, str);
+ g_free(str);
+
+ list = gupnp_device_info_list_dlna_capabilities(proxy);
+ if (list != NULL) {
+ dlna_caps = prv_add_list_dlna_prop(list);
+ g_variant_builder_add(vb, "{sv}",
+ DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES,
+ dlna_caps);
+ g_list_free_full(list, g_free);
+ }
+
+ if (device->search_caps != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES,
+ device->search_caps);
+
+ if (device->sort_caps != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES,
+ device->sort_caps);
+
+ if (device->sort_ext_caps != NULL)
+ g_variant_builder_add(
+ vb, "{sv}",
+ DLS_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES,
+ device->sort_ext_caps);
+
+ if (device->feature_list != NULL)
+ g_variant_builder_add(vb, "{sv}",
+ DLS_INTERFACE_PROP_SV_FEATURE_LIST,
+ device->feature_list);
+}
+
+GVariant *dls_props_get_device_prop(GUPnPDeviceInfo *root_proxy,
+ GUPnPDeviceInfo *proxy,
+ const dls_device_t *device,
+ const gchar *prop)
+{
+ GVariant *dlna_caps = NULL;
+ GVariant *retval = NULL;
+ const gchar *str = NULL;
+ gchar *copy = NULL;
+ GList *list;
+
+ if (!strcmp(DLS_INTERFACE_PROP_LOCATION, prop)) {
+ str = gupnp_device_info_get_location(proxy);
+ } else if (!strcmp(DLS_INTERFACE_PROP_UDN, prop)) {
+ str = gupnp_device_info_get_udn(proxy);
+ } else if (!strcmp(DLS_INTERFACE_PROP_ROOT_UDN, prop)) {
+ if (proxy != root_proxy)
+ str = gupnp_device_info_get_udn(root_proxy);
+ } else if (!strcmp(DLS_INTERFACE_PROP_DEVICE_TYPE, prop)) {
+ str = gupnp_device_info_get_device_type(proxy);
+ } else if (!strcmp(DLS_INTERFACE_PROP_FRIENDLY_NAME, prop)) {
+ copy = gupnp_device_info_get_friendly_name(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_MANUFACTURER, prop)) {
+ copy = gupnp_device_info_get_manufacturer(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_MANUFACTURER_URL, prop)) {
+ copy = gupnp_device_info_get_manufacturer_url(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_DESCRIPTION, prop)) {
+ copy = gupnp_device_info_get_model_description(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_NAME, prop)) {
+ copy = gupnp_device_info_get_model_name(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_NUMBER, prop)) {
+ copy = gupnp_device_info_get_model_number(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_MODEL_URL, prop)) {
+ copy = gupnp_device_info_get_model_url(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_SERIAL_NUMBER, prop)) {
+ copy = gupnp_device_info_get_serial_number(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_PRESENTATION_URL, prop)) {
+ copy = gupnp_device_info_get_presentation_url(proxy);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_ICON_URL, prop)) {
+ copy = gupnp_device_info_get_icon_url(proxy, NULL,
+ -1, -1, -1, FALSE,
+ NULL, NULL, NULL, NULL);
+ str = copy;
+ } else if (!strcmp(DLS_INTERFACE_PROP_SV_DLNA_CAPABILITIES, prop)) {
+ list = gupnp_device_info_list_dlna_capabilities(proxy);
+ if (list != NULL) {
+ dlna_caps = prv_add_list_dlna_prop(list);
+ g_list_free_full(list, g_free);
+ retval = g_variant_ref_sink(dlna_caps);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ copy = g_variant_print(dlna_caps, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(DLS_INTERFACE_PROP_SV_SEARCH_CAPABILITIES, prop)) {
+ if (device->search_caps != NULL) {
+ retval = g_variant_ref(device->search_caps);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->search_caps, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(DLS_INTERFACE_PROP_SV_SORT_CAPABILITIES, prop)) {
+ if (device->sort_caps != NULL) {
+ retval = g_variant_ref(device->sort_caps);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->sort_caps, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(DLS_INTERFACE_PROP_SV_SORT_EXT_CAPABILITIES, prop)) {
+ if (device->sort_ext_caps != NULL) {
+ retval = g_variant_ref(device->sort_ext_caps);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->sort_ext_caps, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ } else if (!strcmp(DLS_INTERFACE_PROP_SV_FEATURE_LIST, prop)) {
+ if (device->feature_list != NULL) {
+ retval = g_variant_ref(device->feature_list);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ copy = g_variant_print(device->feature_list, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, copy);
+#endif
+ }
+ }
+
+ if (!retval) {
+ if (str) {
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ }
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_WARNING
+ else
+ DLEYNA_LOG_WARNING("Property %s not defined", prop);
+#endif
+ }
+
+ g_free(copy);
+
+ return retval;
+}
+
+static GUPnPDIDLLiteResource *prv_match_resource(GUPnPDIDLLiteResource *res,
+ gchar **pi_str_array)
+{
+ GUPnPDIDLLiteResource *retval = NULL;
+ GUPnPProtocolInfo *res_pi;
+ GUPnPProtocolInfo *pi;
+ unsigned int i;
+ gboolean match;
+
+ if (!pi_str_array) {
+ retval = res;
+ goto done;
+ }
+
+ res_pi = gupnp_didl_lite_resource_get_protocol_info(res);
+ if (!res_pi)
+ goto done;
+
+ for (i = 0; pi_str_array[i]; ++i) {
+ pi = gupnp_protocol_info_new_from_string(pi_str_array[i],
+ NULL);
+ if (!pi)
+ continue;
+ match = gupnp_protocol_info_is_compatible(pi, res_pi);
+ g_object_unref(pi);
+ if (match) {
+ retval = res;
+ break;
+ }
+ }
+done:
+
+ return retval;
+}
+
+static GUPnPDIDLLiteResource *prv_get_matching_resource
+ (GUPnPDIDLLiteObject *object, const gchar *protocol_info)
+{
+ GUPnPDIDLLiteResource *retval = NULL;
+ GUPnPDIDLLiteResource *res;
+ GList *resources;
+ GList *ptr;
+ gchar **pi_str_array = NULL;
+
+ if (protocol_info)
+ pi_str_array = g_strsplit(protocol_info, ",", 0);
+
+ resources = gupnp_didl_lite_object_get_resources(object);
+ ptr = resources;
+
+ while (ptr) {
+ res = ptr->data;
+ if (!retval) {
+ retval = prv_match_resource(res, pi_str_array);
+ if (!retval)
+ g_object_unref(res);
+ } else {
+ g_object_unref(res);
+ }
+
+ ptr = ptr->next;
+ }
+
+ g_list_free(resources);
+ if (pi_str_array)
+ g_strfreev(pi_str_array);
+
+ return retval;
+}
+
+static void prv_parse_common_resources(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteResource *res,
+ dls_upnp_prop_mask filter_mask)
+{
+ GUPnPProtocolInfo *protocol_info;
+ gint64 int64_val;
+ guint uint_val;
+ const char *str_val;
+ GUPnPDLNAConversion conv;
+ GUPnPDLNAOperation ope;
+ GUPnPDLNAFlags flags;
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_SIZE) {
+ int64_val = gupnp_didl_lite_resource_get_size64(res);
+ prv_add_int64_prop(item_vb, DLS_INTERFACE_PROP_SIZE, int64_val);
+ }
+
+ if ((filter_mask & DLS_UPNP_MASK_PROP_UPDATE_COUNT) &&
+ gupnp_didl_lite_resource_update_count_is_set(res)) {
+ uint_val = gupnp_didl_lite_resource_get_update_count(res);
+ prv_add_uint_prop(item_vb, DLS_INTERFACE_PROP_UPDATE_COUNT,
+ uint_val);
+ }
+
+ protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_PROFILE) {
+ str_val = gupnp_protocol_info_get_dlna_profile(protocol_info);
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_DLNA_PROFILE,
+ str_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_CONVERSION) {
+ conv = gupnp_protocol_info_get_dlna_conversion(protocol_info);
+ prv_add_variant_prop(item_vb,
+ DLS_INTERFACE_PROP_DLNA_CONVERSION,
+ prv_props_get_dlna_info_dict(
+ conv, g_prop_dlna_ci));
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_OPERATION) {
+ ope = gupnp_protocol_info_get_dlna_operation(protocol_info);
+ prv_add_variant_prop(item_vb,
+ DLS_INTERFACE_PROP_DLNA_OPERATION,
+ prv_props_get_dlna_info_dict(
+ ope, g_prop_dlna_op));
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_FLAGS) {
+ flags = gupnp_protocol_info_get_dlna_flags(protocol_info);
+ prv_add_variant_prop(item_vb,
+ DLS_INTERFACE_PROP_DLNA_FLAGS,
+ prv_props_get_dlna_info_dict(
+ flags, g_prop_dlna_flags));
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_MIME_TYPE) {
+ str_val = gupnp_protocol_info_get_mime_type(protocol_info);
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_MIME_TYPE,
+ str_val);
+ }
+}
+
+static void prv_parse_all_resources(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteResource *res,
+ dls_upnp_prop_mask filter_mask)
+{
+ int int_val;
+
+ prv_parse_common_resources(item_vb, res, filter_mask);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_BITRATE) {
+ int_val = gupnp_didl_lite_resource_get_bitrate(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_BITRATE, int_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_SAMPLE_RATE) {
+ int_val = gupnp_didl_lite_resource_get_sample_freq(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_SAMPLE_RATE,
+ int_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_BITS_PER_SAMPLE) {
+ int_val = gupnp_didl_lite_resource_get_bits_per_sample(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_BITS_PER_SAMPLE,
+ int_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DURATION) {
+ int_val = (int) gupnp_didl_lite_resource_get_duration(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_DURATION, int_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_WIDTH) {
+ int_val = (int) gupnp_didl_lite_resource_get_width(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_WIDTH, int_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_HEIGHT) {
+ int_val = (int) gupnp_didl_lite_resource_get_height(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_HEIGHT, int_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_COLOR_DEPTH) {
+ int_val = (int) gupnp_didl_lite_resource_get_color_depth(res);
+ prv_add_int_prop(item_vb, DLS_INTERFACE_PROP_COLOR_DEPTH,
+ int_val);
+ }
+}
+
+static GVariant *prv_compute_create_classes(GUPnPDIDLLiteContainer *container)
+{
+ GVariantBuilder create_classes_vb;
+ GList *create_classes;
+ GList *ptr;
+ GUPnPDIDLLiteCreateClass *create_class;
+ const char *content;
+ const char *ms2_class;
+ gboolean inc_derived;
+
+ g_variant_builder_init(&create_classes_vb, G_VARIANT_TYPE("a(sb)"));
+
+ create_classes = gupnp_didl_lite_container_get_create_classes_full(
+ container);
+ ptr = create_classes;
+ while (ptr) {
+ create_class = ptr->data;
+ content = gupnp_didl_lite_create_class_get_content(
+ create_class);
+ ms2_class = dls_props_upnp_class_to_media_spec_ex(content);
+ inc_derived = gupnp_didl_lite_create_class_get_include_derived(
+ create_class);
+ g_variant_builder_add(&create_classes_vb,
+ "(sb)", ms2_class, inc_derived);
+ g_object_unref(ptr->data);
+ ptr = g_list_next(ptr);
+ }
+ g_list_free(create_classes);
+
+ return g_variant_builder_end(&create_classes_vb);
+}
+
+static const gchar *prv_media_spec_to_upnp_class(const gchar *m2spec_class)
+{
+ const gchar *retval = NULL;
+
+ if (!strcmp(m2spec_class, gMediaSpec2Container))
+ retval = gUPnPContainer;
+ else if (!strcmp(m2spec_class, gMediaSpec2AudioMusic))
+ retval = gUPnPMusicTrack;
+ else if (!strcmp(m2spec_class, gMediaSpec2Audio))
+ retval = gUPnPAudioItem;
+ else if (!strcmp(m2spec_class, gMediaSpec2VideoMovie))
+ retval = gUPnPMovie;
+ else if (!strcmp(m2spec_class, gMediaSpec2Video))
+ retval = gUPnPVideoItem;
+ else if (!strcmp(m2spec_class, gMediaSpec2ImagePhoto))
+ retval = gUPnPPhoto;
+ else if (!strcmp(m2spec_class, gMediaSpec2Image))
+ retval = gUPnPImageItem;
+
+ return retval;
+}
+
+const gchar *dls_props_media_spec_to_upnp_class(const gchar *m2spec_class)
+{
+ const gchar *retval = NULL;
+
+ if (!m2spec_class)
+ goto on_error;
+
+ retval = prv_media_spec_to_upnp_class(m2spec_class);
+
+ if (!retval && !strcmp(m2spec_class, gMediaSpec2ItemUnclassified))
+ retval = gUPnPItem;
+
+on_error:
+
+ return retval;
+}
+
+gchar *dls_props_media_spec_ex_to_upnp_class(const gchar *m2spec_class)
+{
+ gchar *retval = NULL;
+ const gchar *basic_type;
+ const gchar *ptr = NULL;
+
+ if (!m2spec_class)
+ goto on_error;
+
+ basic_type = prv_media_spec_to_upnp_class(m2spec_class);
+ if (basic_type) {
+ retval = g_strdup(basic_type);
+ } else {
+ if (!strncmp(m2spec_class, gMediaSpec2ExItem,
+ gMediaSpec2ExItemLen))
+ ptr = m2spec_class + gMediaSpec2ExItemLen;
+ else if (!strncmp(m2spec_class, gMediaSpec2Container,
+ gMediaSpec2ContainerLen))
+ ptr = m2spec_class + gMediaSpec2ContainerLen;
+ if (ptr && (!*ptr || *ptr == '.'))
+ retval = g_strdup_printf("object.%s", m2spec_class);
+ }
+
+on_error:
+
+ return retval;
+}
+
+static const gchar *prv_upnp_class_to_media_spec(const gchar *upnp_class,
+ gboolean *exact)
+{
+ const gchar *retval = NULL;
+ const gchar *ptr;
+
+ if (!upnp_class)
+ goto on_error;
+
+ if (!strncmp(upnp_class, gUPnPContainer, gUPnPContainerLen)) {
+ ptr = upnp_class + gUPnPContainerLen;
+ if (!*ptr || *ptr == '.') {
+ retval = gMediaSpec2Container;
+ *exact = *ptr == 0;
+ }
+ } else if (!strncmp(upnp_class, gUPnPAudioItem, gUPnPAudioItemLen)) {
+ ptr = upnp_class + gUPnPAudioItemLen;
+ if (!strcmp(ptr, ".musicTrack")) {
+ retval = gMediaSpec2AudioMusic;
+ *exact = TRUE;
+ } else if (!*ptr || *ptr == '.') {
+ retval = gMediaSpec2Audio;
+ *exact = *ptr == 0;
+ }
+ } else if (!strncmp(upnp_class, gUPnPVideoItem, gUPnPVideoItemLen)) {
+ ptr = upnp_class + gUPnPVideoItemLen;
+ if (!strcmp(ptr, ".movie")) {
+ retval = gMediaSpec2VideoMovie;
+ *exact = TRUE;
+ } else if (!*ptr || *ptr == '.') {
+ retval = gMediaSpec2Video;
+ *exact = *ptr == 0;
+ }
+ } else if (!strncmp(upnp_class, gUPnPImageItem, gUPnPImageItemLen)) {
+ ptr = upnp_class + gUPnPImageItemLen;
+ if (!strcmp(ptr, ".photo")) {
+ retval = gMediaSpec2ImagePhoto;
+ *exact = TRUE;
+ } else if (!*ptr || *ptr == '.') {
+ retval = gMediaSpec2Image;
+ *exact = *ptr == 0;
+ }
+ } else if (!strncmp(upnp_class, gUPnPItem, gUPnPItemLen)) {
+ ptr = upnp_class + gUPnPItemLen;
+ if (!*ptr || *ptr == '.') {
+ retval = gMediaSpec2ItemUnclassified;
+ *exact = *ptr == 0;
+ }
+ }
+
+on_error:
+
+ return retval;
+}
+
+const gchar *dls_props_upnp_class_to_media_spec(const gchar *upnp_class)
+{
+ gboolean exact;
+
+ return prv_upnp_class_to_media_spec(upnp_class, &exact);
+}
+
+const gchar *dls_props_upnp_class_to_media_spec_ex(const gchar *upnp_class)
+{
+ const gchar *retval;
+ gboolean exact;
+
+ retval = prv_upnp_class_to_media_spec(upnp_class, &exact);
+ if (!retval)
+ goto on_error;
+
+ if (exact) {
+ if (retval == gMediaSpec2ItemUnclassified)
+ retval = gMediaSpec2ExItem;
+ } else {
+ retval = upnp_class + gUPnPObjectLen + 1;
+ }
+
+on_error:
+
+ return retval;
+}
+
+static GVariant *prv_compute_resources(GUPnPDIDLLiteObject *object,
+ dls_upnp_prop_mask filter_mask,
+ gboolean all_res)
+{
+ GUPnPDIDLLiteResource *res = NULL;
+ GList *resources;
+ GList *ptr;
+ GVariantBuilder *res_array_vb;
+ GVariantBuilder *res_vb;
+ const char *str_val;
+ GVariant *retval;
+
+ res_array_vb = g_variant_builder_new(G_VARIANT_TYPE("aa{sv}"));
+
+ resources = gupnp_didl_lite_object_get_resources(object);
+ ptr = resources;
+
+ while (ptr) {
+ res = ptr->data;
+ res_vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ if (filter_mask & DLS_UPNP_MASK_PROP_URL) {
+ str_val = gupnp_didl_lite_resource_get_uri(res);
+ prv_add_string_prop(res_vb, DLS_INTERFACE_PROP_URL,
+ str_val);
+ }
+
+ if (all_res)
+ prv_parse_all_resources(res_vb, res, filter_mask);
+ else
+ prv_parse_common_resources(res_vb, res, filter_mask);
+
+ g_variant_builder_add(res_array_vb, "@a{sv}",
+ g_variant_builder_end(res_vb));
+ g_variant_builder_unref(res_vb);
+ g_object_unref(ptr->data);
+ ptr = g_list_next(ptr);
+ }
+ retval = g_variant_builder_end(res_array_vb);
+ g_variant_builder_unref(res_array_vb);
+
+ g_list_free(resources);
+
+ return retval;
+}
+
+static void prv_add_resources(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteObject *object,
+ dls_upnp_prop_mask filter_mask,
+ gboolean all_res)
+{
+ GVariant *val;
+
+ val = prv_compute_resources(object, filter_mask, all_res);
+
+ if (g_variant_n_children(val))
+ g_variant_builder_add(item_vb, "{sv}",
+ DLS_INTERFACE_PROP_RESOURCES, val);
+ else
+ g_variant_unref(val);
+}
+
+gboolean dls_props_add_object(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteObject *object,
+ const char *root_path,
+ const gchar *parent_path,
+ dls_upnp_prop_mask filter_mask)
+{
+ gchar *path = NULL;
+ const char *id;
+ const char *title;
+ const char *creator;
+ const char *upnp_class;
+ const char *media_spec_type;
+ const char *media_spec_type_ex;
+ gboolean retval = FALSE;
+ gboolean rest;
+ GUPnPOCMFlags flags;
+ guint uint_val;
+
+ id = gupnp_didl_lite_object_get_id(object);
+ if (!id)
+ goto on_error;
+
+ upnp_class = gupnp_didl_lite_object_get_upnp_class(object);
+ media_spec_type = dls_props_upnp_class_to_media_spec(upnp_class);
+
+ if (!media_spec_type)
+ goto on_error;
+
+ media_spec_type_ex = dls_props_upnp_class_to_media_spec_ex(upnp_class);
+
+ title = gupnp_didl_lite_object_get_title(object);
+ creator = gupnp_didl_lite_object_get_creator(object);
+ rest = gupnp_didl_lite_object_get_restricted(object);
+ path = dls_path_from_id(root_path, id);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DISPLAY_NAME)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_DISPLAY_NAME,
+ title);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_CREATOR)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_CREATOR,
+ creator);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_PATH)
+ prv_add_path_prop(item_vb, DLS_INTERFACE_PROP_PATH, path);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_PARENT)
+ prv_add_path_prop(item_vb, DLS_INTERFACE_PROP_PARENT,
+ parent_path);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_TYPE)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_TYPE,
+ media_spec_type);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_TYPE_EX)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_TYPE_EX,
+ media_spec_type_ex);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_RESTRICTED)
+ prv_add_bool_prop(item_vb, DLS_INTERFACE_PROP_RESTRICTED, rest);
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DLNA_MANAGED) {
+ flags = gupnp_didl_lite_object_get_dlna_managed(object);
+
+ if (flags != GUPNP_OCM_FLAGS_NONE)
+ prv_add_variant_prop(item_vb,
+ DLS_INTERFACE_PROP_DLNA_MANAGED,
+ prv_props_get_dlna_info_dict(
+ flags,
+ g_prop_dlna_ocm));
+ }
+
+ if ((filter_mask & DLS_UPNP_MASK_PROP_OBJECT_UPDATE_ID) &&
+ gupnp_didl_lite_object_update_id_is_set(object)) {
+ uint_val = gupnp_didl_lite_object_get_update_id(object);
+ prv_add_uint_prop(item_vb, DLS_INTERFACE_PROP_OBJECT_UPDATE_ID,
+ uint_val);
+ }
+
+ retval = TRUE;
+
+on_error:
+
+ g_free(path);
+
+ return retval;
+}
+
+void dls_props_add_container(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteContainer *object,
+ dls_upnp_prop_mask filter_mask,
+ const gchar *protocol_info,
+ gboolean *have_child_count)
+{
+ int child_count;
+ gboolean searchable;
+ guint uint_val;
+ GUPnPDIDLLiteResource *res;
+ GVariant *val;
+ const char *str_val;
+
+ *have_child_count = FALSE;
+ if (filter_mask & DLS_UPNP_MASK_PROP_CHILD_COUNT) {
+ child_count = gupnp_didl_lite_container_get_child_count(object);
+ if (child_count >= 0) {
+ prv_add_uint_prop(item_vb,
+ DLS_INTERFACE_PROP_CHILD_COUNT,
+ (unsigned int) child_count);
+ *have_child_count = TRUE;
+ }
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_SEARCHABLE) {
+ searchable = gupnp_didl_lite_container_get_searchable(object);
+ prv_add_bool_prop(item_vb, DLS_INTERFACE_PROP_SEARCHABLE,
+ searchable);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_CREATE_CLASSES) {
+ val = prv_compute_create_classes(object);
+
+ if (g_variant_n_children(val))
+ prv_add_variant_prop(item_vb,
+ DLS_INTERFACE_PROP_CREATE_CLASSES,
+ val);
+ else
+ g_variant_unref(val);
+ }
+
+ if ((filter_mask & DLS_UPNP_MASK_PROP_CONTAINER_UPDATE_ID) &&
+ gupnp_didl_lite_container_container_update_id_is_set(object)) {
+ uint_val = gupnp_didl_lite_container_get_container_update_id(
+ object);
+ prv_add_uint_prop(item_vb,
+ DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID,
+ uint_val);
+ }
+
+ if ((filter_mask & DLS_UPNP_MASK_PROP_TOTAL_DELETED_CHILD_COUNT) &&
+ gupnp_didl_lite_container_total_deleted_child_count_is_set(
+ object)) {
+ uint_val =
+ gupnp_didl_lite_container_get_total_deleted_child_count(object);
+
+ prv_add_uint_prop(item_vb,
+ DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT,
+ uint_val);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_RESOURCES)
+ prv_add_resources(item_vb, GUPNP_DIDL_LITE_OBJECT(object),
+ filter_mask, FALSE);
+
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_ARTIST) {
+ GUPnPDIDLLiteObject *obj = GUPNP_DIDL_LITE_OBJECT(object);
+ const char *artist = gupnp_didl_lite_object_get_artist(obj);
+ prv_add_string_prop (item_vb,
+ DLS_INTERFACE_PROP_ARTIST,
+ artist);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_ALBUM_ART_URL) {
+ GUPnPDIDLLiteObject *obj = GUPNP_DIDL_LITE_OBJECT(object);
+ const char *url = gupnp_didl_lite_object_get_album_art(obj);
+ prv_add_string_prop (item_vb,
+ DLS_INTERFACE_PROP_ALBUM_ART_URL,
+ url);
+ }
+
+ res = prv_get_matching_resource(GUPNP_DIDL_LITE_OBJECT(object),
+ protocol_info);
+ if (res) {
+ if (filter_mask & DLS_UPNP_MASK_PROP_URLS) {
+ str_val = gupnp_didl_lite_resource_get_uri(res);
+ prv_add_strv_prop(item_vb, DLS_INTERFACE_PROP_URLS,
+ &str_val, 1);
+ }
+ prv_parse_common_resources(item_vb, res, filter_mask);
+ g_object_unref(res);
+ }
+}
+
+void dls_props_add_item(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteObject *object,
+ const gchar *root_path,
+ dls_upnp_prop_mask filter_mask,
+ const gchar *protocol_info)
+{
+ int track_number;
+ GUPnPDIDLLiteResource *res;
+ const char *str_val;
+ char *path;
+ GList *list;
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_ARTIST)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_ARTIST,
+ gupnp_didl_lite_object_get_artist(object));
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_ARTISTS) {
+ list = gupnp_didl_lite_object_get_artists(object);
+ if (list != NULL) {
+ prv_add_variant_prop(item_vb,
+ DLS_INTERFACE_PROP_ARTISTS,
+ prv_get_artists_prop(list));
+ g_list_free_full(list, g_object_unref);
+ }
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_ALBUM)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_ALBUM,
+ gupnp_didl_lite_object_get_album(object));
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_DATE)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_DATE,
+ gupnp_didl_lite_object_get_date(object));
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_GENRE)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_GENRE,
+ gupnp_didl_lite_object_get_genre(object));
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_TRACK_NUMBER) {
+ track_number = gupnp_didl_lite_object_get_track_number(object);
+ if (track_number >= 0)
+ prv_add_int_prop(item_vb,
+ DLS_INTERFACE_PROP_TRACK_NUMBER,
+ track_number);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_ALBUM_ART_URL)
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_ALBUM_ART_URL,
+ gupnp_didl_lite_object_get_album_art(
+ object));
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_REFPATH) {
+ str_val = gupnp_didl_lite_item_get_ref_id(
+ GUPNP_DIDL_LITE_ITEM(object));
+ if (str_val != NULL) {
+ path = dls_path_from_id(root_path, str_val);
+ prv_add_path_prop(item_vb, DLS_INTERFACE_PROP_REFPATH,
+ path);
+ g_free(path);
+ }
+ }
+
+ res = prv_get_matching_resource(object, protocol_info);
+ if (res) {
+ if (filter_mask & DLS_UPNP_MASK_PROP_URLS) {
+ str_val = gupnp_didl_lite_resource_get_uri(res);
+ prv_add_strv_prop(item_vb, DLS_INTERFACE_PROP_URLS,
+ &str_val, 1);
+ }
+ prv_parse_all_resources(item_vb, res, filter_mask);
+ g_object_unref(res);
+ }
+
+ if (filter_mask & DLS_UPNP_MASK_PROP_RESOURCES)
+ prv_add_resources(item_vb, object, filter_mask, TRUE);
+}
+
+void dls_props_add_resource(GVariantBuilder *item_vb,
+ GUPnPDIDLLiteObject *object,
+ dls_upnp_prop_mask filter_mask,
+ const gchar *protocol_info)
+{
+ GUPnPDIDLLiteResource *res;
+ const char *str_val;
+
+ res = prv_get_matching_resource(object, protocol_info);
+ if (res) {
+ if (filter_mask & DLS_UPNP_MASK_PROP_URL) {
+ str_val = gupnp_didl_lite_resource_get_uri(res);
+ prv_add_string_prop(item_vb, DLS_INTERFACE_PROP_URL,
+ str_val);
+ }
+
+ if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
+ prv_parse_common_resources(item_vb, res, filter_mask);
+ else
+ prv_parse_all_resources(item_vb, res, filter_mask);
+
+ g_object_unref(res);
+ }
+}
+
+
+static GVariant *prv_get_common_resource_property(const gchar *prop,
+ GUPnPDIDLLiteResource *res)
+{
+ gint64 int64_val;
+ guint uint_val;
+ const char *str_val;
+ GVariant *retval = NULL;
+ GUPnPProtocolInfo *protocol_info;
+ GUPnPDLNAConversion conv;
+ GUPnPDLNAOperation ope;
+ GUPnPDLNAFlags flags;
+
+ if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_PROFILE)) {
+ protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
+ if (!protocol_info)
+ goto on_error;
+ str_val = gupnp_protocol_info_get_dlna_profile(protocol_info);
+ if (!str_val)
+ goto on_error;
+ retval = g_variant_ref_sink(g_variant_new_string(str_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_CONVERSION)) {
+ protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
+ conv = gupnp_protocol_info_get_dlna_conversion(protocol_info);
+ retval = prv_props_get_dlna_info_dict(conv, g_prop_dlna_ci);
+ if (retval)
+ retval = g_variant_ref_sink(retval);
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_OPERATION)) {
+ protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
+ ope = gupnp_protocol_info_get_dlna_operation(protocol_info);
+ retval = prv_props_get_dlna_info_dict(ope, g_prop_dlna_op);
+ if (retval)
+ retval = g_variant_ref_sink(retval);
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_FLAGS)) {
+ protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
+ flags = gupnp_protocol_info_get_dlna_flags(protocol_info);
+ retval = prv_props_get_dlna_info_dict(flags,
+ g_prop_dlna_flags);
+ if (retval)
+ retval = g_variant_ref_sink(retval);
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_MIME_TYPE)) {
+ protocol_info = gupnp_didl_lite_resource_get_protocol_info(res);
+ if (!protocol_info)
+ goto on_error;
+ str_val = gupnp_protocol_info_get_mime_type(protocol_info);
+ if (!str_val)
+ goto on_error;
+ retval = g_variant_ref_sink(g_variant_new_string(str_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_SIZE)) {
+ int64_val = gupnp_didl_lite_resource_get_size64(res);
+ if (int64_val == -1)
+ goto on_error;
+ retval = g_variant_ref_sink(g_variant_new_int64(int64_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_URLS)) {
+ str_val = gupnp_didl_lite_resource_get_uri(res);
+ if (str_val)
+ retval = g_variant_ref_sink(g_variant_new_strv(&str_val,
+ 1));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_UPDATE_COUNT) &&
+ gupnp_didl_lite_resource_update_count_is_set(res)) {
+ uint_val = gupnp_didl_lite_resource_get_update_count(res);
+ retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
+ }
+
+on_error:
+
+ return retval;
+}
+
+static GVariant *prv_get_item_resource_property(const gchar *prop,
+ GUPnPDIDLLiteResource *res)
+{
+ int int_val;
+ GVariant *retval;
+
+ retval = prv_get_common_resource_property(prop, res);
+
+ if (retval)
+ goto on_exit;
+
+ if (!strcmp(prop, DLS_INTERFACE_PROP_DURATION)) {
+ int_val = (int) gupnp_didl_lite_resource_get_duration(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_BITRATE)) {
+ int_val = gupnp_didl_lite_resource_get_bitrate(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_SAMPLE_RATE)) {
+ int_val = gupnp_didl_lite_resource_get_sample_freq(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_BITS_PER_SAMPLE)) {
+ int_val = gupnp_didl_lite_resource_get_bits_per_sample(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_WIDTH)) {
+ int_val = (int) gupnp_didl_lite_resource_get_width(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_HEIGHT)) {
+ int_val = (int) gupnp_didl_lite_resource_get_height(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_COLOR_DEPTH)) {
+ int_val = (int) gupnp_didl_lite_resource_get_color_depth(res);
+ if (int_val == -1)
+ goto on_exit;
+ retval = g_variant_ref_sink(g_variant_new_int32(int_val));
+ }
+
+on_exit:
+
+ return retval;
+}
+
+GVariant *dls_props_get_object_prop(const gchar *prop, const gchar *root_path,
+ GUPnPDIDLLiteObject *object)
+{
+ const char *object_id;
+ const char *parent_id;
+ gchar *path;
+ const char *upnp_class;
+ const char *media_spec_type;
+ const char *title;
+ gboolean rest;
+ GVariant *retval = NULL;
+ GUPnPOCMFlags dlna_managed;
+ guint uint_val;
+
+ if (!strcmp(prop, DLS_INTERFACE_PROP_PARENT)) {
+ object_id = gupnp_didl_lite_object_get_id(object);
+ if (!object_id)
+ goto on_error;
+
+ parent_id = gupnp_didl_lite_object_get_parent_id(object);
+ if (!parent_id)
+ goto on_error;
+
+ if (!strcmp(object_id, "0") || !strcmp(parent_id, "-1")) {
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, root_path);
+
+ retval = g_variant_ref_sink(g_variant_new_string(
+ root_path));
+ } else {
+ path = dls_path_from_id(root_path, parent_id);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, path);
+
+ retval = g_variant_ref_sink(g_variant_new_string(
+ path));
+ g_free(path);
+ }
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_PATH)) {
+ object_id = gupnp_didl_lite_object_get_id(object);
+ if (!object_id)
+ goto on_error;
+
+ path = dls_path_from_id(root_path, object_id);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, path);
+
+ retval = g_variant_ref_sink(g_variant_new_string(path));
+ g_free(path);
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE)) {
+ upnp_class = gupnp_didl_lite_object_get_upnp_class(object);
+ media_spec_type =
+ dls_props_upnp_class_to_media_spec(upnp_class);
+ if (!media_spec_type)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, media_spec_type);
+
+ retval = g_variant_ref_sink(g_variant_new_string(
+ media_spec_type));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_TYPE_EX)) {
+ upnp_class = gupnp_didl_lite_object_get_upnp_class(object);
+ media_spec_type =
+ dls_props_upnp_class_to_media_spec_ex(upnp_class);
+ if (!media_spec_type)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, media_spec_type);
+
+ retval = g_variant_ref_sink(g_variant_new_string(
+ media_spec_type));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_DISPLAY_NAME)) {
+ title = gupnp_didl_lite_object_get_title(object);
+ if (!title)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, title);
+
+ retval = g_variant_ref_sink(g_variant_new_string(title));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_CREATOR)) {
+ title = gupnp_didl_lite_object_get_creator(object);
+ if (!title)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, title);
+
+ retval = g_variant_ref_sink(g_variant_new_string(title));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_RESTRICTED)) {
+ rest = gupnp_didl_lite_object_get_restricted(object);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %d", prop, rest);
+
+ retval = g_variant_ref_sink(g_variant_new_boolean(rest));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_DLNA_MANAGED)) {
+ dlna_managed = gupnp_didl_lite_object_get_dlna_managed(object);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %0x", prop, dlna_managed);
+
+ retval = g_variant_ref_sink(prv_props_get_dlna_info_dict(
+ dlna_managed, g_prop_dlna_ocm));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_OBJECT_UPDATE_ID) &&
+ gupnp_didl_lite_object_update_id_is_set(object)) {
+ uint_val = gupnp_didl_lite_object_get_update_id(object);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %u", prop, uint_val);
+
+ retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
+ }
+
+on_error:
+
+ return retval;
+}
+
+GVariant *dls_props_get_item_prop(const gchar *prop, const gchar *root_path,
+ GUPnPDIDLLiteObject *object,
+ const gchar *protocol_info)
+{
+ const gchar *str;
+ gchar *path;
+ gint track_number;
+ GUPnPDIDLLiteResource *res;
+ GVariant *retval = NULL;
+ GList *list;
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ gchar *prop_str;
+#endif
+
+ if (GUPNP_IS_DIDL_LITE_CONTAINER(object))
+ goto on_error;
+
+ if (!strcmp(prop, DLS_INTERFACE_PROP_ARTIST)) {
+ str = gupnp_didl_lite_object_get_artist(object);
+ if (!str)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_ARTISTS)) {
+ list = gupnp_didl_lite_object_get_artists(object);
+ if (!list)
+ goto on_error;
+
+ retval = g_variant_ref_sink(prv_get_artists_prop(list));
+ g_list_free_full(list, g_object_unref);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+#endif
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_ALBUM)) {
+ str = gupnp_didl_lite_object_get_album(object);
+ if (!str)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_DATE)) {
+ str = gupnp_didl_lite_object_get_date(object);
+ if (!str)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_GENRE)) {
+ str = gupnp_didl_lite_object_get_genre(object);
+ if (!str)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_TRACK_NUMBER)) {
+ track_number = gupnp_didl_lite_object_get_track_number(object);
+ if (track_number < 0)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %d", prop, track_number);
+
+ retval = g_variant_ref_sink(
+ g_variant_new_int32(track_number));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_ALBUM_ART_URL)) {
+ str = gupnp_didl_lite_object_get_album_art(object);
+ if (!str)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ retval = g_variant_ref_sink(g_variant_new_string(str));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_REFPATH)) {
+ str = gupnp_didl_lite_item_get_ref_id(
+ GUPNP_DIDL_LITE_ITEM(object));
+ if (!str)
+ goto on_error;
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, str);
+
+ path = dls_path_from_id(root_path, str);
+ retval = g_variant_ref_sink(g_variant_new_string(path));
+ g_free(path);
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_RESOURCES)) {
+ retval = g_variant_ref_sink(
+ prv_compute_resources(object, DLS_UPNP_MASK_ALL_PROPS,
+ TRUE));
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+#endif
+ } else {
+ res = prv_get_matching_resource(object, protocol_info);
+ if (!res)
+ goto on_error;
+
+ retval = prv_get_item_resource_property(prop, res);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ if (retval) {
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+ }
+#endif
+ g_object_unref(res);
+ }
+
+on_error:
+
+ return retval;
+}
+
+GVariant *dls_props_get_container_prop(const gchar *prop,
+ GUPnPDIDLLiteObject *object,
+ const gchar *protocol_info)
+{
+ gint child_count;
+ gboolean searchable;
+ GUPnPDIDLLiteContainer *container;
+ GVariant *retval = NULL;
+ guint uint_val;
+ GUPnPDIDLLiteResource *res;
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ gchar *prop_str;
+#endif
+ if (!GUPNP_IS_DIDL_LITE_CONTAINER(object))
+ goto on_error;
+
+ container = (GUPnPDIDLLiteContainer *)object;
+ if (!strcmp(prop, DLS_INTERFACE_PROP_CHILD_COUNT)) {
+ child_count =
+ gupnp_didl_lite_container_get_child_count(container);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %d", prop, child_count);
+
+ if (child_count >= 0) {
+ retval = g_variant_new_uint32((guint) child_count);
+ retval = g_variant_ref_sink(retval);
+ }
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_SEARCHABLE)) {
+ searchable =
+ gupnp_didl_lite_container_get_searchable(container);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %d", prop, searchable);
+
+ retval = g_variant_ref_sink(
+ g_variant_new_boolean(searchable));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_CREATE_CLASSES)) {
+ retval = g_variant_ref_sink(
+ prv_compute_create_classes(container));
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+#endif
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_CONTAINER_UPDATE_ID) &&
+ gupnp_didl_lite_container_container_update_id_is_set(
+ container)) {
+ uint_val = gupnp_didl_lite_container_get_container_update_id(
+ container);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %u", prop, uint_val);
+
+ retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
+ } else if (!strcmp(prop,
+ DLS_INTERFACE_PROP_TOTAL_DELETED_CHILD_COUNT) &&
+ gupnp_didl_lite_container_total_deleted_child_count_is_set(
+ container)) {
+ uint_val =
+ gupnp_didl_lite_container_get_total_deleted_child_count(
+ container);
+
+ DLEYNA_LOG_DEBUG("Prop %s = %u", prop, uint_val);
+
+ retval = g_variant_ref_sink(g_variant_new_uint32(uint_val));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_ARTIST)) {
+ const char *strval = gupnp_didl_lite_object_get_artist(
+ GUPNP_DIDL_LITE_OBJECT(object));
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, strval);
+
+ retval = g_variant_ref_sink(g_variant_new_string(strval));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_ALBUM_ART_URL)) {
+ const char *strval = gupnp_didl_lite_object_get_album_art(
+ GUPNP_DIDL_LITE_OBJECT(object));
+
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, strval);
+
+ retval = g_variant_ref_sink(g_variant_new_string(strval));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_RESOURCES)) {
+ retval = g_variant_ref_sink(
+ prv_compute_resources(object, DLS_UPNP_MASK_ALL_PROPS,
+ FALSE));
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+#endif
+ } else {
+ res = prv_get_matching_resource(object, protocol_info);
+ if (!res)
+ goto on_error;
+
+ retval = prv_get_common_resource_property(prop, res);
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ if (retval) {
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+ }
+#endif
+ g_object_unref(res);
+ }
+
+on_error:
+
+ return retval;
+}
+
+static GVariant *prv_build_wl_entries(dleyna_settings_t *settings)
+{
+ GVariant *result;
+
+ result = dleyna_settings_white_list_entries(settings);
+
+ if (result == NULL)
+ result = g_variant_new("as", NULL);
+
+ return result;
+}
+
+void dls_props_add_manager(dleyna_settings_t *settings, GVariantBuilder *vb)
+{
+ prv_add_bool_prop(vb, DLS_INTERFACE_PROP_NEVER_QUIT,
+ dleyna_settings_is_never_quit(settings));
+
+ prv_add_bool_prop(vb, DLS_INTERFACE_PROP_WHITE_LIST_ENABLED,
+ dleyna_settings_is_white_list_enabled(settings));
+
+ g_variant_builder_add(vb, "{sv}", DLS_INTERFACE_PROP_WHITE_LIST_ENTRIES,
+ prv_build_wl_entries(settings));
+}
+
+GVariant *dls_props_get_manager_prop(dleyna_settings_t *settings,
+ const gchar *prop)
+{
+ GVariant *retval = NULL;
+ gboolean b_value;
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ gchar *prop_str;
+#endif
+
+ if (!strcmp(prop, DLS_INTERFACE_PROP_NEVER_QUIT)) {
+ b_value = dleyna_settings_is_never_quit(settings);
+ retval = g_variant_ref_sink(g_variant_new_boolean(b_value));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_WHITE_LIST_ENABLED)) {
+ b_value = dleyna_settings_is_white_list_enabled(settings);
+ retval = g_variant_ref_sink(g_variant_new_boolean(b_value));
+ } else if (!strcmp(prop, DLS_INTERFACE_PROP_WHITE_LIST_ENTRIES)) {
+ retval = g_variant_ref_sink(prv_build_wl_entries(settings));
+ }
+
+#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG
+ if (retval) {
+ prop_str = g_variant_print(retval, FALSE);
+ DLEYNA_LOG_DEBUG("Prop %s = %s", prop, prop_str);
+ g_free(prop_str);
+ }
+#endif
+
+ return retval;
+}
+
+GVariant *dls_props_get_error_prop(GError *error)
+{
+ GVariantBuilder gvb;
+
+ g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(&gvb, "{sv}",
+ DLS_INTERFACE_PROP_ERROR_ID,
+ g_variant_new_int32(error->code));
+
+/* NOTE: We should modify the dleyna-connector API to add a new method to
+ * retrieve the error string. Direct call to DBUS are forbidden.
+ *
+ * g_variant_builder_add(&gvb, "{sv}",
+ * DLS_INTERFACE_PROP_ERROR_NAME,
+ * g_variant_new_string(
+ * g_dbus_error_get_remote_error(cb_data->error)));
+*/
+
+ g_variant_builder_add(&gvb, "{sv}",
+ DLS_INTERFACE_PROP_ERROR_MESSAGE,
+ g_variant_new_string(error->message));
+
+ return g_variant_builder_end(&gvb);
+}