[gupnp-dlna] Add "native" profile backend.



commit e1d3b216cce3f1aa6a40a092b7f9a168b0abc323
Author: Krzesimir Nowak <krnowak openismus com>
Date:   Thu Nov 15 15:16:55 2012 +0100

    Add "native" profile backend.
    
    This backend implements profile guessing using the sets added
    earlier. In future this is going to be merged into GUPnPDLNAProfile
    and GUPnPDLNAProfileGuesser.

 .../native/gupnp-dlna-native-profile-backend.c     |   40 +
 .../native/gupnp-dlna-native-profile-backend.h     |   41 +
 .../gupnp-dlna-native-profile-guesser-impl.c       |  702 ++++++++++++++++
 .../gupnp-dlna-native-profile-guesser-impl.h       |   77 ++
 .../native/gupnp-dlna-native-profile-loader.c      |  864 ++++++++++++++++++++
 .../native/gupnp-dlna-native-profile-loader.h      |   77 ++
 .../native/gupnp-dlna-native-profile.c             |  260 ++++++
 .../native/gupnp-dlna-native-profile.h             |   93 +++
 .../native/gupnp-dlna-native-sets.h                |   30 +
 .../native/gupnp-dlna-native-utils.c               |   61 ++
 .../native/gupnp-dlna-native-utils.h               |   37 +
 libgupnp-dlna/profile-backends/native/native.am    |   59 ++
 12 files changed, 2341 insertions(+), 0 deletions(-)
---
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-backend.c b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-backend.c
new file mode 100644
index 0000000..0521960
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-backend.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gupnp-dlna-native-profile-loader.h"
+#include "gupnp-dlna-native-profile-guesser-impl.h"
+#include "gupnp-dlna-native-profile-backend.h"
+
+GUPnPDLNAProfileLoader *
+gupnp_dlna_native_profile_backend_get_loader (gboolean relaxed_mode,
+                                              gboolean extended_mode)
+{
+        return GUPNP_DLNA_PROFILE_LOADER
+                (gupnp_dlna_native_profile_loader_new (relaxed_mode,
+                                                       extended_mode));
+}
+
+GUPnPDLNAProfileGuesserImpl *
+gupnp_dlna_native_profile_backend_get_guesser_impl (void)
+{
+        return GUPNP_DLNA_PROFILE_GUESSER_IMPL
+                (gupnp_dlna_native_profile_guesser_impl_new ());
+}
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-backend.h b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-backend.h
new file mode 100644
index 0000000..a9a81ae
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-backend.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_DLNA_NATIVE_PROFILE_BACKEND_H__
+#define __GUPNP_DLNA_NATIVE_PROFILE_BACKEND_H__
+
+#include "gupnp-dlna-profile-loader.h"
+
+G_BEGIN_DECLS
+
+void
+gupnp_dlna_native_profile_backend_init (void);
+
+GUPnPDLNAProfileLoader *
+gupnp_dlna_native_profile_backend_get_loader (gboolean relaxed_mode,
+                                              gboolean extended_mode);
+
+GUPnPDLNAProfileGuesserImpl *
+gupnp_dlna_native_profile_backend_get_guesser_impl (void);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_NATIVE_PROFILE_BACKEND_H__ */
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-guesser-impl.c b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-guesser-impl.c
new file mode 100644
index 0000000..f12a7e3
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-guesser-impl.c
@@ -0,0 +1,702 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Arun Raghavan <arun raghavan collabora co uk>
+ *          Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+
+#include "gupnp-dlna-native-profile.h"
+#include "gupnp-dlna-native-profile-guesser-impl.h"
+#include "gupnp-dlna-information.h"
+#include "gupnp-dlna-audio-information.h"
+#include "gupnp-dlna-container-information.h"
+#include "gupnp-dlna-image-information.h"
+#include "gupnp-dlna-video-information.h"
+#include "gupnp-dlna-native-sets.h"
+#include "gupnp-dlna-native-utils.h"
+
+G_DEFINE_TYPE (GUPnPDLNANativeProfileGuesserImpl,
+               gupnp_dlna_native_profile_guesser_impl,
+               GUPNP_TYPE_DLNA_PROFILE_GUESSER_IMPL)
+
+struct _GUPnPDLNANativeProfileGuesserImplPrivate {
+        gpointer placeholder;
+};
+
+
+static gboolean
+is_video_profile (GUPnPDLNANativeProfile *profile)
+{
+        GList *container_restrictions =
+                 gupnp_dlna_native_profile_get_container_restrictions (profile);
+        GList *video_restrictions =
+                     gupnp_dlna_native_profile_get_video_restrictions (profile);
+
+        return (container_restrictions != NULL && video_restrictions != NULL);
+}
+
+static gboolean
+match_profile (GUPnPDLNANativeProfile *profile,
+               GUPnPDLNANativeInfoSet *stream_info_set,
+               GList                  *profile_restrictions)
+{
+        GUPnPDLNAProfile *dlna_profile = GUPNP_DLNA_PROFILE (profile);
+        const gchar *name = gupnp_dlna_profile_get_name (dlna_profile);
+        GList *iter;
+        gchar *stream_dump;
+        gchar *restrictions_dump;
+
+        /* Profiles with an empty name are used only for inheritance
+         * and should not be matched against. */
+        if (name == NULL || name[0] == '\0') {
+                /* TODO: if this warning never happens, then remove
+                 * profile parameter from this function.
+                 */
+                g_warning ("Profiles weren't cleaned up properly?");
+                return FALSE;
+        }
+
+        stream_dump = gupnp_dlna_native_info_set_to_string (stream_info_set);
+        restrictions_dump = gupnp_dlna_native_utils_restrictions_list_to_string
+                                        (profile_restrictions);
+        g_debug ("Stream: %s\nRestrictions: %s",
+                 stream_dump,
+                 restrictions_dump);
+        g_free (stream_dump);
+        g_free (restrictions_dump);
+
+        for (iter = profile_restrictions; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeRestriction *restriction =
+                                     GUPNP_DLNA_NATIVE_RESTRICTION (iter->data);
+
+                if (restriction != NULL &&
+                    gupnp_dlna_native_info_set_fits_restriction
+                                        (stream_info_set,
+                                         restriction))
+                        return TRUE;
+        }
+
+        return FALSE;
+}
+
+static void
+add_bool (GUPnPDLNANativeInfoSet *info_set,
+          const gchar            *name,
+          GUPnPDLNABoolValue      value,
+          const gchar            *type)
+{
+        switch (value.state) {
+        case GUPNP_DLNA_VALUE_STATE_SET:
+                if (!gupnp_dlna_native_info_set_add_bool (info_set,
+                                                          name,
+                                                          value.value))
+                        g_warning ("Failed to add '%s' bool value (%s) to %s "
+                                   "info set.",
+                                   name,
+                                   (value.value ? "true" : "false"),
+                                   type);
+
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSET:
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSUPPORTED:
+                if (!gupnp_dlna_native_info_set_add_unsupported_bool (info_set,
+                                                                      name))
+                        g_warning ("Failed to add '%s' bool unsupported value"
+                                   " to %s info set.",
+                                   name,
+                                   type);
+
+                break;
+        default:
+                g_critical ("Wrong value state value (%d).", value.state);
+        }
+}
+
+static void
+add_fraction (GUPnPDLNANativeInfoSet *info_set,
+              const gchar            *name,
+              GUPnPDLNAFractionValue  value,
+              const gchar            *type)
+{
+        switch (value.state) {
+        case GUPNP_DLNA_VALUE_STATE_SET:
+                if (!gupnp_dlna_native_info_set_add_fraction
+                                        (info_set,
+                                         name,
+                                         value.numerator,
+                                         value.denominator))
+                        g_warning ("Failed to add '%s' fraction value (%d/%d)"
+                                   " to %s info set.",
+                                   name,
+                                   value.numerator,
+                                   value.denominator,
+                                   type);
+
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSET:
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSUPPORTED:
+                if (!gupnp_dlna_native_info_set_add_unsupported_fraction
+                                        (info_set,
+                                         name))
+                        g_warning ("Failed to add '%s' fraction unsupported"
+                                   " value to %s info set.",
+                                   name,
+                                   type);
+
+                break;
+        default:
+                g_critical ("Wrong value state value (%d).", value.state);
+        }
+}
+
+static void
+add_int (GUPnPDLNANativeInfoSet *info_set,
+          const gchar            *name,
+          GUPnPDLNAIntValue       value,
+          const gchar            *type)
+{
+        switch (value.state) {
+        case GUPNP_DLNA_VALUE_STATE_SET:
+                if (!gupnp_dlna_native_info_set_add_int (info_set,
+                                                         name,
+                                                         value.value))
+                        g_warning ("Failed to add '%s' int value (%d) to %s "
+                                   "info set.",
+                                   name,
+                                   value.value,
+                                   type);
+
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSET:
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSUPPORTED:
+                if (!gupnp_dlna_native_info_set_add_unsupported_int (info_set,
+                                                                     name))
+                        g_warning ("Failed to add '%s' int unsupported value"
+                                   " to %s info set.",
+                                   name,
+                                   type);
+
+                break;
+        default:
+                g_critical ("Wrong value state value (%d).", value.state);
+        }
+}
+
+static void
+add_string (GUPnPDLNANativeInfoSet *info_set,
+            const gchar            *name,
+            GUPnPDLNAStringValue    value,
+            const gchar            *type)
+{
+        switch (value.state) {
+        case GUPNP_DLNA_VALUE_STATE_SET:
+                if (!gupnp_dlna_native_info_set_add_string (info_set,
+                                                            name,
+                                                            value.value))
+                        g_warning ("Failed to add '%s' int value (%s) to %s "
+                                   "info set.",
+                                   name,
+                                   value.value,
+                                   type);
+                g_free (value.value);
+
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSET:
+                break;
+        case GUPNP_DLNA_VALUE_STATE_UNSUPPORTED:
+                if (!gupnp_dlna_native_info_set_add_unsupported_string
+                                        (info_set,
+                                         name))
+                        g_warning ("Failed to add '%s' string unsupported value"
+                                   " to %s info set.",
+                                   name,
+                                   type);
+
+                break;
+        default:
+                g_critical ("Wrong value state value (%d).", value.state);
+        }
+}
+
+static GUPnPDLNANativeInfoSet *
+create_info_set (GUPnPDLNAStringValue  value,
+                 const gchar          *type)
+{
+        gchar *mime;
+        gchar *lctype;
+        GUPnPDLNANativeInfoSet *info_set;
+
+        if (value.state == GUPNP_DLNA_VALUE_STATE_SET) {
+                mime = value.value;
+                lctype = g_ascii_strdown (type, -1);
+        } else {
+                g_warning ("%s information holds no mime type, expect it"
+                           "to match to no DLNA profile.",
+                           type);
+                mime = g_ascii_strdown (type, -1);
+                lctype = g_strdup (mime);
+        }
+
+        info_set = gupnp_dlna_native_info_set_new (mime);
+        if (info_set == NULL)
+                g_warning ("Failed to create %s info set with mime '%s'.",
+                           lctype,
+                           mime);
+        g_free (mime);
+        g_free (lctype);
+
+        return info_set;
+}
+
+static GUPnPDLNANativeInfoSet *
+info_set_from_container_information (GUPnPDLNAContainerInformation *info)
+{
+        static const gchar *const type = "container";
+        GUPnPDLNANativeInfoSet *info_set = create_info_set
+                              (gupnp_dlna_container_information_get_mime (info),
+                               "Container");
+
+        if (info_set == NULL)
+                return NULL;
+
+        add_int (info_set,
+                 "mpegversion",
+                 gupnp_dlna_container_information_get_mpeg_version (info),
+                 type);
+
+        add_int (info_set,
+                 "packetsize",
+                 gupnp_dlna_container_information_get_packet_size (info),
+                 type);
+
+        add_string (info_set,
+                    "profile",
+                    gupnp_dlna_container_information_get_profile (info),
+                    type);
+
+        add_bool (info_set,
+                  "systemstream",
+                  gupnp_dlna_container_information_is_system_stream (info),
+                  type);
+
+        add_string (info_set,
+                    "variant",
+                    gupnp_dlna_container_information_get_variant (info),
+                    type);
+
+        return info_set;
+}
+
+static gboolean
+check_container_profile (GUPnPDLNAInformation   *info,
+                         GUPnPDLNANativeProfile *profile)
+{
+        GUPnPDLNAContainerInformation *container_info =
+                        gupnp_dlna_information_get_container_information (info);
+        gboolean matched = FALSE;
+        GList *profile_restrictions =
+                 gupnp_dlna_native_profile_get_container_restrictions (profile);
+
+        if (profile_restrictions != NULL && container_info != NULL) {
+                GUPnPDLNANativeInfoSet *stream_info_set =
+                           info_set_from_container_information (container_info);
+
+                if (match_profile (profile,
+                                   stream_info_set,
+                                   profile_restrictions))
+                        matched = TRUE;
+                else
+                        g_debug ("Container did not match.");
+                gupnp_dlna_native_info_set_free (stream_info_set);
+        } else if (profile_restrictions == NULL && container_info == NULL)
+                matched = TRUE;
+
+        return matched;
+}
+
+static GUPnPDLNANativeInfoSet *
+info_set_from_audio_information (GUPnPDLNAAudioInformation *info)
+{
+        static const gchar *const type = "audio";
+        GUPnPDLNANativeInfoSet *info_set = create_info_set
+                                  (gupnp_dlna_audio_information_get_mime (info),
+                                   "Audio");
+
+        if (info_set == NULL)
+                return NULL;
+
+        add_int (info_set,
+                 "bitrate",
+                 gupnp_dlna_audio_information_get_bitrate (info),
+                 type);
+
+        add_int (info_set,
+                 "channels",
+                 gupnp_dlna_audio_information_get_channels (info),
+                 type);
+
+        add_int (info_set,
+                 "depth",
+                 gupnp_dlna_audio_information_get_depth (info),
+                 type);
+
+        add_int (info_set,
+                 "layer",
+                 gupnp_dlna_audio_information_get_layer (info),
+                 type);
+
+        add_string (info_set,
+                    "level",
+                    gupnp_dlna_audio_information_get_level (info),
+                    type);
+
+        add_int (info_set,
+                 "mpegaudioversion",
+                 gupnp_dlna_audio_information_get_mpeg_audio_version (info),
+                 type);
+
+        add_int (info_set,
+                 "mpegversion",
+                 gupnp_dlna_audio_information_get_mpeg_version (info),
+                 type);
+
+        add_string (info_set,
+                    "profile",
+                    gupnp_dlna_audio_information_get_profile (info),
+                    type);
+
+        add_int (info_set,
+                 "rate",
+                 gupnp_dlna_audio_information_get_rate (info),
+                 type);
+
+        add_string (info_set,
+                    "stream-format",
+                    gupnp_dlna_audio_information_get_stream_format (info),
+                    type);
+
+        add_int (info_set,
+                 "wmaversion",
+                 gupnp_dlna_audio_information_get_wma_version (info),
+                 type);
+
+        return info_set;
+}
+
+static gboolean
+check_audio_profile (GUPnPDLNAInformation   *info,
+                     GUPnPDLNANativeProfile *profile)
+{
+        GUPnPDLNANativeInfoSet *info_set;
+        gboolean matched;
+        GUPnPDLNAAudioInformation *audio_info;
+        GList *restrictions;
+
+        if (is_video_profile (profile))
+                return FALSE;
+
+        matched = FALSE;
+        audio_info = gupnp_dlna_information_get_audio_information (info);
+        info_set = info_set_from_audio_information (audio_info);
+        restrictions =
+                     gupnp_dlna_native_profile_get_audio_restrictions (profile);
+        if (match_profile (profile, info_set, restrictions))
+                matched = TRUE;
+        else
+                g_debug ("Audio did not match.");
+        gupnp_dlna_native_info_set_free (info_set);
+
+        return matched;
+}
+
+static GUPnPDLNANativeInfoSet *
+info_set_from_video_information (GUPnPDLNAVideoInformation *info)
+{
+        static const gchar *const type = "video";
+        GUPnPDLNANativeInfoSet *info_set = create_info_set
+                                  (gupnp_dlna_video_information_get_mime (info),
+                                   "Video");
+
+        if (info_set == NULL)
+                return NULL;
+
+        add_int (info_set,
+                 "bitrate",
+                 gupnp_dlna_video_information_get_bitrate (info),
+                 type);
+
+        add_fraction (info_set,
+                      "framerate",
+                      gupnp_dlna_video_information_get_framerate (info),
+                      type);
+
+        add_int (info_set,
+                 "height",
+                 gupnp_dlna_video_information_get_height (info),
+                 type);
+
+        add_bool (info_set,
+                  "interlaced",
+                  gupnp_dlna_video_information_is_interlaced (info),
+                  type);
+
+        add_string (info_set,
+                    "level",
+                    gupnp_dlna_video_information_get_level (info),
+                    type);
+
+        add_int (info_set,
+                 "mpegversion",
+                 gupnp_dlna_video_information_get_mpeg_version (info),
+                 type);
+
+        add_fraction
+                    (info_set,
+                     "pixel-aspect-ratio",
+                     gupnp_dlna_video_information_get_pixel_aspect_ratio (info),
+                     type);
+
+        add_string (info_set,
+                    "profile",
+                    gupnp_dlna_video_information_get_profile (info),
+                    type);
+
+        add_bool (info_set,
+                  "systemstream",
+                  gupnp_dlna_video_information_is_system_stream (info),
+                  type);
+
+        add_int (info_set,
+                 "width",
+                 gupnp_dlna_video_information_get_width (info),
+                 type);
+
+        return info_set;
+}
+
+static gboolean
+check_video_profile (GUPnPDLNAInformation *info,
+                     GUPnPDLNANativeProfile *profile)
+{
+        GUPnPDLNAVideoInformation *video_info =
+                            gupnp_dlna_information_get_video_information (info);
+        GUPnPDLNAAudioInformation *audio_info =
+                            gupnp_dlna_information_get_audio_information (info);
+        GUPnPDLNANativeInfoSet *info_set = NULL;
+        GList *restrictions;
+        gboolean result = FALSE;
+
+        if (video_info == NULL || audio_info == NULL)
+                goto out;
+
+        restrictions = gupnp_dlna_native_profile_get_video_restrictions
+                                        (profile);
+        info_set = info_set_from_video_information (video_info);
+        if (!match_profile (profile, info_set, restrictions)) {
+                g_debug ("Video did not match");
+
+                goto out;
+        }
+        gupnp_dlna_native_info_set_free (info_set);
+
+        restrictions = gupnp_dlna_native_profile_get_audio_restrictions
+                                        (profile);
+        info_set = info_set_from_audio_information (audio_info);
+        if (!match_profile (profile, info_set, restrictions)) {
+                g_debug ("Audio did not match");
+
+                goto out;
+        }
+
+        if (check_container_profile (info, profile))
+                result = TRUE;
+ out:
+        gupnp_dlna_native_info_set_free (info_set);
+
+        return result;
+}
+
+static GUPnPDLNANativeInfoSet *
+info_set_from_image_information (GUPnPDLNAImageInformation *info)
+{
+        static const gchar *const type = "image";
+        GUPnPDLNANativeInfoSet *info_set = create_info_set
+                                  (gupnp_dlna_image_information_get_mime (info),
+                                   "Image");
+
+        if (info_set == NULL)
+                return NULL;
+
+        add_int (info_set,
+                 "depth",
+                 gupnp_dlna_image_information_get_depth (info),
+                 type);
+
+        add_int (info_set,
+                 "height",
+                 gupnp_dlna_image_information_get_height (info),
+                 type);
+
+        add_int (info_set,
+                 "width",
+                 gupnp_dlna_image_information_get_width (info),
+                 type);
+
+        return info_set;
+}
+
+static GUPnPDLNAProfile *
+backend_guess_image_profile
+                       (GUPnPDLNAProfileGuesserImpl *guesser_impl G_GNUC_UNUSED,
+                        GUPnPDLNAInformation        *info,
+                        GList                       *profiles)
+{
+        GList *iter;
+        GUPnPDLNAImageInformation *image_info =
+                            gupnp_dlna_information_get_image_information (info);
+        GUPnPDLNANativeInfoSet *info_set;
+        GUPnPDLNAProfile *profile;
+
+        if (!image_info)
+                return NULL;
+
+        info_set = info_set_from_image_information (image_info);
+        profile = NULL;
+
+        for (iter = profiles; iter; iter = iter->next) {
+                GUPnPDLNANativeProfile *native_profile =
+                                        GUPNP_DLNA_NATIVE_PROFILE (iter->data);
+                GList *restrictions =
+                                gupnp_dlna_native_profile_get_image_restrictions
+                                        (native_profile);
+
+                g_debug ("Matching image against profile: %s",
+                         gupnp_dlna_profile_get_name
+                                        (GUPNP_DLNA_PROFILE (native_profile)));
+
+                if (match_profile (native_profile, info_set, restrictions)) {
+                        profile = GUPNP_DLNA_PROFILE (native_profile);
+
+                        break;
+                } else
+                        g_debug ("Image did not match");
+        }
+
+        gupnp_dlna_native_info_set_free (info_set);
+
+        return profile;
+}
+
+static GUPnPDLNAProfile *
+backend_guess_video_profile
+                       (GUPnPDLNAProfileGuesserImpl *guesser_impl G_GNUC_UNUSED,
+                        GUPnPDLNAInformation        *info,
+                        GList                       *profiles)
+{
+        GUPnPDLNAProfile *profile = NULL;
+        GList *iter;
+
+        for (iter = profiles; iter; iter = iter->next) {
+                GUPnPDLNANativeProfile *native_profile =
+                                        GUPNP_DLNA_NATIVE_PROFILE (iter->data);
+
+                g_debug ("Matching video against profile: %s",
+                         gupnp_dlna_profile_get_name
+                                        (GUPNP_DLNA_PROFILE (native_profile)));
+
+                if (check_video_profile (info, native_profile)) {
+                        profile = GUPNP_DLNA_PROFILE (native_profile);
+
+                        break;
+                }
+        }
+
+        return profile;
+}
+
+static GUPnPDLNAProfile *
+backend_guess_audio_profile
+                       (GUPnPDLNAProfileGuesserImpl *guesser_impl G_GNUC_UNUSED,
+                        GUPnPDLNAInformation        *info,
+                        GList                       *profiles)
+{
+        GList *iter;
+        GUPnPDLNAProfile *profile = NULL;
+
+        for (iter = profiles; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeProfile *native_profile =
+                                        GUPNP_DLNA_NATIVE_PROFILE (iter->data);
+
+                g_debug ("Matching audio against profile: %s",
+                         gupnp_dlna_profile_get_name
+                                        (GUPNP_DLNA_PROFILE (native_profile)));
+
+                if (check_audio_profile (info, native_profile) &&
+                    check_container_profile (info, native_profile)) {
+                        profile = GUPNP_DLNA_PROFILE (native_profile);
+
+                        break;
+                }
+        }
+
+        return profile;
+}
+
+static void
+gupnp_dlna_native_profile_guesser_impl_class_init
+             (GUPnPDLNANativeProfileGuesserImplClass *native_guesser_impl_class)
+{
+        GUPnPDLNAProfileGuesserImplClass *guesser_impl_class =
+              GUPNP_DLNA_PROFILE_GUESSER_IMPL_CLASS (native_guesser_impl_class);
+
+        guesser_impl_class->guess_image_profile = backend_guess_image_profile;
+        guesser_impl_class->guess_video_profile = backend_guess_video_profile;
+        guesser_impl_class->guess_audio_profile = backend_guess_audio_profile;
+
+        g_type_class_add_private
+                            (native_guesser_impl_class,
+                             sizeof (GUPnPDLNANativeProfileGuesserImplPrivate));
+}
+
+static void
+gupnp_dlna_native_profile_guesser_impl_init
+                               (GUPnPDLNANativeProfileGuesserImpl *guesser_impl)
+{
+        GUPnPDLNANativeProfileGuesserImplPrivate *priv =
+                G_TYPE_INSTANCE_GET_PRIVATE
+                                   (guesser_impl,
+                                    GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL,
+                                    GUPnPDLNANativeProfileGuesserImplPrivate);
+
+        guesser_impl->priv = priv;
+}
+
+GUPnPDLNANativeProfileGuesserImpl*
+gupnp_dlna_native_profile_guesser_impl_new (void)
+{
+        return GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL
+                                  (g_object_new
+                                   (GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL,
+                                    NULL));
+}
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-guesser-impl.h b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-guesser-impl.h
new file mode 100644
index 0000000..df8e1bc
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-guesser-impl.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL_H__
+#define __GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL_H__
+
+#include <glib-object.h>
+#include "gupnp-dlna-profile-guesser-impl.h"
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL \
+        (gupnp_dlna_native_profile_guesser_impl_get_type())
+
+#define GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL(obj) \
+     (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL, \
+                                  GUPnPDLNANativeProfileGuesserImpl))
+
+#define GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL, \
+                                  GUPnPDLNANativeProfileGuesserImplClass))
+
+#define GUPNP_IS_DLNA_NATIVE_PROFILE_GUESSER_IMPL(obj) \
+      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+                                   GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL))
+
+#define GUPNP_IS_DLNA_NATIVE_PROFILE_GUESSER_IMPL_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL))
+
+#define GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL_GET_CLASS(obj) \
+      (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE_GUESSER_IMPL, \
+                                  GUPnPDLNANativeProfileGuesserImplClass))
+
+typedef struct _GUPnPDLNANativeProfileGuesserImplPrivate
+                GUPnPDLNANativeProfileGuesserImplPrivate;
+
+typedef struct {
+        GUPnPDLNAProfileGuesserImpl parent;
+
+        GUPnPDLNANativeProfileGuesserImplPrivate *priv;
+} GUPnPDLNANativeProfileGuesserImpl;
+
+typedef struct {
+        GUPnPDLNAProfileGuesserImplClass parent_class;
+} GUPnPDLNANativeProfileGuesserImplClass;
+
+GType
+gupnp_dlna_native_profile_guesser_impl_get_type (void) G_GNUC_CONST;
+
+GUPnPDLNANativeProfileGuesserImpl *
+gupnp_dlna_native_profile_guesser_impl_new (void);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_NATIVE_PROFILE_GUESSER_IMPL_H__ */
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-loader.c b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-loader.c
new file mode 100644
index 0000000..a90d170
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-loader.c
@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Arun Raghavan <arun raghavan collabora co uk>
+ *          Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gupnp-dlna-native-profile-loader.h"
+#include "gupnp-dlna-native-profile.h"
+#include "gupnp-dlna-native-sets.h"
+#include "gupnp-dlna-native-utils.h"
+
+G_DEFINE_TYPE (GUPnPDLNANativeProfileLoader,
+               gupnp_dlna_native_profile_loader,
+               GUPNP_TYPE_DLNA_PROFILE_LOADER)
+
+typedef enum {
+        GUPNP_DLNA_NATIVE_PARSED_ELEMENT_RESTRICTIONS,
+        GUPNP_DLNA_NATIVE_PARSED_ELEMENT_RESTRICTION,
+        GUPNP_DLNA_NATIVE_PARSED_ELEMENT_FIELD,
+        GUPNP_DLNA_NATIVE_PARSED_ELEMENT_PARENT,
+        GUPNP_DLNA_NATIVE_PARSED_ELEMENT_DLNA_PROFILE,
+        GUPNP_DLNA_NATIVE_PARSED_ELEMENT_INVALID
+} GUPnPDLNANativeParsedElement;
+
+typedef enum {
+        GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_AUDIO,
+        GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_CONTAINER,
+        GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_IMAGE,
+        GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_VIDEO,
+        GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_INVALID
+} GUPnPDLNANativeRestrictionType;
+
+typedef struct {
+        GList *audios;
+        GList *containers;
+        GList *images;
+        GList *videos;
+} GUPnPDLNANativeProfileData;
+
+typedef struct {
+        gchar                    *name;
+        GUPnPDLNANativeValueList *list;
+} GUPnPDLNANativeNameValueListPair;
+
+typedef struct {
+        GList *name_list_pairs;
+        GList *parents;
+} GUPnPDLNANativeRestrictionData;
+
+typedef struct {
+        GUPnPDLNANativeRestriction     *restriction;
+        GUPnPDLNANativeRestrictionType  type;
+} GUPnPDLNANativeDescription;
+
+struct _GUPnPDLNANativeProfileLoaderPrivate {
+        GHashTable *descriptions;
+        GList      *tags_stack;
+        GList      *dlna_profile_data_stack;
+        GList      *restriction_data_stack;
+};
+
+static GUPnPDLNANativeNameValueListPair *
+gupnp_dlna_native_name_value_list_pair_new (const gchar              *name,
+                                            GUPnPDLNANativeValueList *list)
+{
+        GUPnPDLNANativeNameValueListPair *pair =
+                                 g_slice_new (GUPnPDLNANativeNameValueListPair);
+
+        pair->name = g_strdup (name);
+        pair->list = list;
+
+        return pair;
+}
+
+static void
+gupnp_dlna_native_name_value_list_pair_free
+                                        (GUPnPDLNANativeNameValueListPair *pair)
+{
+        if (pair == NULL)
+                return;
+        g_free (pair->name);
+        gupnp_dlna_native_value_list_free (pair->list);
+        g_slice_free (GUPnPDLNANativeNameValueListPair, pair);
+}
+
+static GUPnPDLNANativeDescription *
+gupnp_dlna_native_description_new (GUPnPDLNANativeRestriction     *restriction,
+                                   GUPnPDLNANativeRestrictionType  type)
+{
+        GUPnPDLNANativeDescription *description =
+                                       g_slice_new (GUPnPDLNANativeDescription);
+
+        description->restriction = restriction;
+        description->type = type;
+
+        return description;
+}
+
+static void
+gupnp_dlna_native_description_free (GUPnPDLNANativeDescription *description)
+{
+        if (description == NULL)
+                return;
+
+        gupnp_dlna_native_restriction_free (description->restriction);
+        g_slice_free (GUPnPDLNANativeDescription, description);
+}
+
+static GUPnPDLNANativeProfileData*
+gupnp_dlna_native_profile_data_new (void)
+{
+        GUPnPDLNANativeProfileData* data =
+                                       g_slice_new (GUPnPDLNANativeProfileData);
+
+        data->audios = NULL;
+        data->containers = NULL;
+        data->images = NULL;
+        data->videos = NULL;
+
+        return data;
+}
+
+static void
+gupnp_dlna_native_profile_data_free (GUPnPDLNANativeProfileData *data)
+{
+        if (data == NULL)
+                return;
+
+        gupnp_dlna_native_utils_free_restrictions (data->audios);
+        gupnp_dlna_native_utils_free_restrictions (data->containers);
+        gupnp_dlna_native_utils_free_restrictions (data->images);
+        gupnp_dlna_native_utils_free_restrictions (data->videos);
+        g_slice_free (GUPnPDLNANativeProfileData, data);
+}
+
+static GUPnPDLNANativeRestrictionData *
+gupnp_dlna_native_restriction_data_new (void)
+{
+        GUPnPDLNANativeRestrictionData* data =
+                                   g_slice_new (GUPnPDLNANativeRestrictionData);
+
+        data->name_list_pairs = NULL;
+        data->parents = NULL;
+
+        return data;
+}
+
+static void
+gupnp_dlna_native_restriction_data_free (GUPnPDLNANativeRestrictionData *data)
+{
+        if (data == NULL)
+                return;
+
+        if (data->name_list_pairs != NULL)
+                g_list_free_full
+                 (data->name_list_pairs,
+                  (GDestroyNotify) gupnp_dlna_native_name_value_list_pair_free);
+        if (data->parents != NULL)
+                g_list_free_full
+                          (data->parents,
+                           (GDestroyNotify) gupnp_dlna_native_restriction_free);
+        g_slice_free (GUPnPDLNANativeRestrictionData, data);
+}
+
+static void
+gupnp_dlna_native_profile_data_stack_free (GList* stack)
+{
+        g_list_free_full (stack,
+                          (GDestroyNotify) gupnp_dlna_native_profile_data_free);
+}
+
+static void
+gupnp_dlna_native_restriction_data_stack_free (GList* stack)
+{
+        g_list_free_full
+                     (stack,
+                      (GDestroyNotify) gupnp_dlna_native_restriction_data_free);
+}
+
+static void
+push_tag (GUPnPDLNANativeProfileLoader *native_loader,
+          GUPnPDLNANativeParsedElement  element)
+{
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        gint raw_element = (gint) element;
+
+        priv->tags_stack = g_list_prepend (priv->tags_stack,
+                                           GINT_TO_POINTER (raw_element));
+}
+
+static void
+pop_tag (GUPnPDLNANativeProfileLoader *native_loader)
+{
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+
+        priv->tags_stack = g_list_delete_link (priv->tags_stack,
+                                               priv->tags_stack);
+}
+
+static GUPnPDLNANativeParsedElement
+top_tag (GUPnPDLNANativeProfileLoader *native_loader)
+{
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+
+        if (priv->tags_stack != NULL) {
+                gint top_raw = GPOINTER_TO_INT (priv->tags_stack->data);
+
+                return (GUPnPDLNANativeParsedElement) top_raw;
+        }
+
+        return GUPNP_DLNA_NATIVE_PARSED_ELEMENT_INVALID;
+}
+
+static void
+backend_pre_field (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+
+        push_tag (native_loader, GUPNP_DLNA_NATIVE_PARSED_ELEMENT_FIELD);
+}
+
+static GUPnPDLNANativeValueType *
+value_type_from_string (const gchar *type)
+{
+        if (!g_strcmp0 (type, "boolean"))
+                return gupnp_dlna_native_value_type_bool ();
+        else if (!g_strcmp0 (type, "float")) {
+                g_warning ("'float' data type is not yet supported.");
+
+                return NULL;
+        } else if (!g_strcmp0 (type, "fourcc")) {
+                g_warning ("'fourcc' data type is not yet supported.");
+
+                return NULL;
+        } else if (!g_strcmp0 (type, "fraction"))
+                return gupnp_dlna_native_value_type_fraction ();
+        else if (!g_strcmp0 (type, "int"))
+                return gupnp_dlna_native_value_type_int ();
+        else if (!g_strcmp0 (type, "string"))
+                return gupnp_dlna_native_value_type_string ();
+        g_critical ("Unknown value type: %s", type);
+
+        return NULL;
+}
+
+static void
+append_value_to_list (GUPnPDLNAFieldValue      *value,
+                      GUPnPDLNANativeValueList *list)
+{
+        if (value == NULL)
+                return;
+
+        switch (value->type) {
+        case GUPNP_DLNA_FIELD_VALUE_TYPE_RANGE:
+                gupnp_dlna_native_value_list_add_range (list,
+                                                        value->value.range.min,
+                                                        value->value.range.max);
+
+                break;
+        case GUPNP_DLNA_FIELD_VALUE_TYPE_SINGLE:
+                gupnp_dlna_native_value_list_add_single (list,
+                                                         value->value.single);
+
+                break;
+        default:
+                g_critical ("Unknown field value type: %d", (gint) value->type);
+        }
+}
+
+static void
+backend_post_field (GUPnPDLNAProfileLoader *loader,
+                    const gchar            *name,
+                    const gchar            *type,
+                    GList                  *values)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv;
+        GUPnPDLNANativeRestrictionData *restriction_data;
+        GUPnPDLNANativeNameValueListPair *pair;
+        GUPnPDLNANativeValueList *value_list;
+        GUPnPDLNANativeValueType* value_type;
+        GList *iter;
+
+        pop_tag (native_loader);
+
+        if (name == NULL || type == NULL)
+                return;
+
+        value_type = value_type_from_string (type);
+
+        if (value_type == NULL)
+                return;
+
+        priv = native_loader->priv;
+        restriction_data =
+          (GUPnPDLNANativeRestrictionData *) priv->restriction_data_stack->data;
+        value_list = gupnp_dlna_native_value_list_new (value_type);
+
+        for (iter = values; iter != NULL; iter = iter->next) {
+                GUPnPDLNAFieldValue *field_value =
+                                        (GUPnPDLNAFieldValue *) iter->data;
+
+                append_value_to_list (field_value, value_list);
+        }
+
+        pair = gupnp_dlna_native_name_value_list_pair_new (name, value_list);
+        restriction_data->name_list_pairs = g_list_prepend
+                                        (restriction_data->name_list_pairs,
+                                         pair);
+}
+
+static void
+backend_merge_restrictions (GUPnPDLNANativeProfileLoader *native_loader,
+                            GUPnPDLNANativeDescription   *description)
+{
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeProfileData* data =
+             (GUPnPDLNANativeProfileData *) priv->dlna_profile_data_stack->data;
+        GList **target_list;
+        GUPnPDLNANativeRestriction *copy;
+
+        if (description == NULL || description->restriction == NULL)
+                return;
+
+        switch (description->type) {
+        case GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_AUDIO:
+                target_list = &data->audios;
+
+                break;
+        case GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_CONTAINER:
+                target_list = &data->containers;
+
+                break;
+        case GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_IMAGE:
+                target_list = &data->images;
+
+                break;
+        case GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_VIDEO:
+                target_list = &data->videos;
+
+                break;
+        default:
+                g_assert_not_reached ();
+        }
+
+        copy = gupnp_dlna_native_restriction_copy (description->restriction);
+        *target_list = g_list_prepend (*target_list, copy);
+}
+
+static void
+backend_merge_restrictions_if_in_dlna_profile
+                                   (GUPnPDLNANativeProfileLoader *native_loader,
+                                    GUPnPDLNANativeDescription   *description)
+{
+        GUPnPDLNANativeParsedElement element = top_tag (native_loader);
+
+        if (element == GUPNP_DLNA_NATIVE_PARSED_ELEMENT_DLNA_PROFILE)
+                backend_merge_restrictions (native_loader, description);
+}
+
+static void
+backend_collect_parents (GUPnPDLNANativeProfileLoader *native_loader,
+                         GUPnPDLNANativeDescription   *description)
+{
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeRestrictionData *data =
+          (GUPnPDLNANativeRestrictionData *) priv->restriction_data_stack->data;
+
+        if (description != NULL && description->restriction != NULL) {
+                /* Collect parents in a list - we'll
+                 * coalesce them later */
+                GUPnPDLNANativeRestriction *copy =
+                  gupnp_dlna_native_restriction_copy (description->restriction);
+
+                data->parents = g_list_prepend (data->parents, copy);
+        }
+}
+
+static void
+backend_collect_parents_if_in_restriction
+                                   (GUPnPDLNANativeProfileLoader *native_loader,
+                                    GUPnPDLNANativeDescription   *description)
+{
+        GUPnPDLNANativeParsedElement element = top_tag (native_loader);
+
+        if (element == GUPNP_DLNA_NATIVE_PARSED_ELEMENT_RESTRICTION)
+                backend_collect_parents (native_loader, description);
+}
+
+static void
+backend_pre_parent (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+
+        push_tag (native_loader, GUPNP_DLNA_NATIVE_PARSED_ELEMENT_PARENT);
+}
+
+static void
+backend_post_parent (GUPnPDLNAProfileLoader *loader,
+                     const gchar            *parent)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+
+        pop_tag (native_loader);
+
+        if (parent != NULL) {
+                GUPnPDLNANativeDescription *description = g_hash_table_lookup
+                                        (priv->descriptions,
+                                         parent);
+
+                backend_merge_restrictions_if_in_dlna_profile (native_loader,
+                                                               description);
+                backend_collect_parents_if_in_restriction (native_loader,
+                                                           description);
+        }
+}
+
+static void
+backend_pre_restriction (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeRestrictionData *data =
+                                      gupnp_dlna_native_restriction_data_new ();
+
+        push_tag (native_loader, GUPNP_DLNA_NATIVE_PARSED_ELEMENT_RESTRICTION);
+
+        priv->restriction_data_stack = g_list_prepend
+                                        (priv->restriction_data_stack,
+                                         data);
+}
+
+static GUPnPDLNANativeRestrictionType
+restriction_type_from_string (const gchar *type)
+{
+        if (!g_strcmp0 (type, "audio"))
+                return GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_AUDIO;
+        else if (!g_strcmp0 (type, "container"))
+                return GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_CONTAINER;
+        else if (!g_strcmp0 (type, "image"))
+                return GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_IMAGE;
+        else if (!g_strcmp0 (type, "video"))
+                return GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_VIDEO;
+
+        return GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_INVALID;
+}
+
+static void
+backend_post_restriction (GUPnPDLNAProfileLoader *loader,
+                          const gchar            *restriction_type,
+                          const gchar            *id,
+                          const gchar            *name)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeRestrictionData *data =
+          (GUPnPDLNANativeRestrictionData *) priv->restriction_data_stack->data;
+        GUPnPDLNANativeRestriction *restriction;
+        GUPnPDLNANativeDescription *description;
+        GUPnPDLNANativeRestrictionType type;
+        GList *iter;
+
+        pop_tag (native_loader);
+
+        /* If this is NULL then it means that 'used' attribute was
+           different from relaxed_mode setting. In this case we just
+           ignore it.
+         */
+        if (restriction_type == NULL)
+                goto out;
+
+        restriction = gupnp_dlna_native_restriction_new (name);
+
+        for (iter = data->name_list_pairs; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeNameValueListPair *pair =
+                                (GUPnPDLNANativeNameValueListPair *) iter->data;
+
+                if (gupnp_dlna_native_restriction_add_value_list (restriction,
+                                                                  pair->name,
+                                                                  pair->list))
+                        pair->list = NULL;
+        }
+
+        type = restriction_type_from_string (restriction_type);
+
+        if (type == GUPNP_DLNA_NATIVE_RESTRICTION_TYPE_INVALID) {
+                g_warning ("Support for '%s' restrictions not yet implemented.",
+                           restriction_type);
+                goto out;
+        }
+
+        iter = data->parents = g_list_reverse (data->parents);
+        for (iter = data->parents; iter != NULL; iter = iter->next) {
+                /* Merge all the parent caps. The child overrides parent
+                 * attributes */
+                GUPnPDLNANativeRestriction *parent =
+                                      (GUPnPDLNANativeRestriction *) iter->data;
+
+                if (gupnp_dlna_native_restriction_merge
+                   (restriction,
+                    parent,
+                    GUPNP_DLNA_NATIVE_RESTRICTION_MERGE_RESOLUTION_FROM_TARGET))
+                        iter->data = NULL;
+                else
+                        g_critical ("Failed to do restriction overriding "
+                                    "merge.");
+        }
+
+        description = gupnp_dlna_native_description_new (restriction, type);
+        backend_merge_restrictions_if_in_dlna_profile (native_loader,
+                                                       description);
+        if (id != NULL)
+                g_hash_table_replace (priv->descriptions,
+                                      g_strdup (id),
+                                      description);
+        else
+                gupnp_dlna_native_description_free (description);
+
+ out:
+        gupnp_dlna_native_restriction_data_free (data);
+        priv->restriction_data_stack = g_list_delete_link
+                                        (priv->restriction_data_stack,
+                                         priv->restriction_data_stack);
+}
+
+static void
+backend_pre_restrictions (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+
+        push_tag (native_loader, GUPNP_DLNA_NATIVE_PARSED_ELEMENT_RESTRICTIONS);
+}
+
+static void
+backend_post_restrictions (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+
+        pop_tag (native_loader);
+}
+
+static void
+backend_pre_dlna_profile (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeProfileData* data =
+                                        gupnp_dlna_native_profile_data_new ();
+
+        push_tag (native_loader, GUPNP_DLNA_NATIVE_PARSED_ELEMENT_DLNA_PROFILE);
+        priv->dlna_profile_data_stack = g_list_prepend
+                                        (priv->dlna_profile_data_stack,
+                                         data);
+}
+
+static GList *
+copy_restrictions_list (GList *list)
+{
+        GList *dup = NULL;
+        GList *iter;
+
+        for (iter = list; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeRestriction *restriction =
+                                     GUPNP_DLNA_NATIVE_RESTRICTION (iter->data);
+                GUPnPDLNANativeRestriction *copy =
+                               gupnp_dlna_native_restriction_copy (restriction);
+
+                if (copy)
+                        dup = g_list_prepend (dup, copy);
+        }
+
+        return dup;
+}
+
+static void
+merge_base_restrictions (GUPnPDLNANativeProfileData *data,
+                         GUPnPDLNANativeProfile     *profile)
+{
+        GList *audio_restrictions =
+                     gupnp_dlna_native_profile_get_audio_restrictions (profile);
+        GList *container_restrictions =
+                 gupnp_dlna_native_profile_get_container_restrictions (profile);
+        GList *image_restrictions =
+                     gupnp_dlna_native_profile_get_image_restrictions (profile);
+        GList *video_restrictions =
+                     gupnp_dlna_native_profile_get_video_restrictions (profile);
+
+        if (audio_restrictions != NULL) {
+                GList *copy = copy_restrictions_list (audio_restrictions);
+
+                data->audios = g_list_concat (copy, data->audios);
+        }
+        if (container_restrictions != NULL) {
+                GList *copy = copy_restrictions_list (container_restrictions);
+
+                data->containers = g_list_concat (copy, data->containers);
+        }
+        if (image_restrictions != NULL) {
+                GList *copy = copy_restrictions_list (image_restrictions);
+
+                data->images = g_list_concat (copy, data->images);
+        }
+        if (video_restrictions != NULL) {
+                GList *copy = copy_restrictions_list (video_restrictions);
+
+                data->videos = g_list_concat (copy, data->videos);
+        }
+}
+
+static gboolean
+restrictions_list_is_empty (GList *list)
+{
+        GList *iter;
+
+        for (iter = list; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeRestriction *restriction =
+                                     GUPNP_DLNA_NATIVE_RESTRICTION (iter->data);
+
+                if (restriction != NULL &&
+                    !gupnp_dlna_native_restriction_is_empty (restriction))
+                        return FALSE;
+        }
+
+        return TRUE;
+}
+
+static GUPnPDLNAProfile *
+backend_create_profile (GUPnPDLNAProfileLoader *loader,
+                        GUPnPDLNAProfile       *base,
+                        const gchar            *name,
+                        const gchar            *mime,
+                        gboolean                extended)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeProfileData *data =
+             (GUPnPDLNANativeProfileData *) priv->dlna_profile_data_stack->data;
+        GUPnPDLNANativeProfile *profile;
+        GList *audio_restrictions = NULL;
+        GList *container_restrictions = NULL;
+        GList *image_restrictions = NULL;
+        GList *video_restrictions = NULL;
+
+        /* Inherit from base profile, if it exists */
+        if (GUPNP_IS_DLNA_NATIVE_PROFILE (base))
+                merge_base_restrictions (data,
+                                         GUPNP_DLNA_NATIVE_PROFILE (base));
+
+        /* The merged caps will be our new GUPnPDLNAProfile */
+        if (!restrictions_list_is_empty (data->audios)) {
+                audio_restrictions = g_list_reverse (data->audios);
+                data->audios = NULL;
+        }
+        if (!restrictions_list_is_empty (data->containers)) {
+                container_restrictions = g_list_reverse (data->containers);
+                data->containers = NULL;
+        }
+        if (!restrictions_list_is_empty (data->images)) {
+                image_restrictions = g_list_reverse (data->images);
+                data->images = NULL;
+        }
+        if (!restrictions_list_is_empty (data->videos)) {
+                video_restrictions = g_list_reverse (data->videos);
+                data->videos = NULL;
+        }
+
+        profile = gupnp_dlna_native_profile_new (name,
+                                                 mime,
+                                                 audio_restrictions,
+                                                 container_restrictions,
+                                                 image_restrictions,
+                                                 video_restrictions,
+                                                 extended);
+
+        return GUPNP_DLNA_PROFILE (profile);
+}
+
+static void
+backend_post_dlna_profile (GUPnPDLNAProfileLoader *loader)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (loader);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GUPnPDLNANativeProfileData *data =
+             (GUPnPDLNANativeProfileData *) priv->dlna_profile_data_stack->data;
+
+        pop_tag (native_loader);
+        gupnp_dlna_native_profile_data_free (data);
+        priv->dlna_profile_data_stack = g_list_delete_link
+                                        (priv->dlna_profile_data_stack,
+                                         priv->dlna_profile_data_stack);
+}
+
+static GList *
+backend_cleanup (GUPnPDLNAProfileLoader *loader G_GNUC_UNUSED,
+                 GList *profiles)
+{
+        /* Now that we're done loading profiles, remove all profiles
+         * with no name which are only used for inheritance and not
+         * matching. */
+        GList *iter = profiles;
+
+        while (iter != NULL) {
+                GList *next = iter->next;
+
+                if (GUPNP_IS_DLNA_NATIVE_PROFILE (iter->data)) {
+                        GUPnPDLNANativeProfile *profile =
+                                        GUPNP_DLNA_NATIVE_PROFILE (iter->data);
+                        const gchar *name = gupnp_dlna_profile_get_name
+                                        (GUPNP_DLNA_PROFILE (profile));
+
+                        if (name == NULL || name[0] == '\0') {
+                                profiles = g_list_delete_link (profiles, iter);
+                                g_object_unref (profile);
+                        } else {
+                                /* TODO: simplify restrictions in
+                                 * profile if possible.
+                                 */
+                        }
+                } else {
+                        g_critical
+                                  ("Profile in list is not from this backend.");
+                }
+
+                iter = next;
+        }
+
+        for (iter = profiles; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeProfile *profile = GUPNP_DLNA_NATIVE_PROFILE
+                                        (iter->data);
+                GUPnPDLNAProfile *dlna_profile = GUPNP_DLNA_PROFILE (profile);
+                gchar *acaps =
+                             gupnp_dlna_native_utils_restrictions_list_to_string
+                   (gupnp_dlna_native_profile_get_audio_restrictions (profile));
+                gchar *ccaps =
+                             gupnp_dlna_native_utils_restrictions_list_to_string
+                           (gupnp_dlna_native_profile_get_container_restrictions
+                                        (profile));
+                gchar *icaps =
+                             gupnp_dlna_native_utils_restrictions_list_to_string
+                   (gupnp_dlna_native_profile_get_image_restrictions (profile));
+                gchar *vcaps =
+                             gupnp_dlna_native_utils_restrictions_list_to_string
+                   (gupnp_dlna_native_profile_get_video_restrictions (profile));
+
+                g_debug ("Loaded profile: %s\nMIME: %s\naudio caps: %s\n"
+                         "container caps: %s\nimage caps: %s\nvideo caps: %s\n",
+                         gupnp_dlna_profile_get_name (dlna_profile),
+                         gupnp_dlna_profile_get_mime (dlna_profile),
+                         acaps,
+                         ccaps,
+                         icaps,
+                         vcaps);
+                g_free (acaps);
+                g_free (ccaps);
+                g_free (icaps);
+                g_free (vcaps);
+        }
+
+        return profiles;
+}
+
+static void
+gupnp_dlna_native_profile_loader_dispose (GObject *object)
+{
+        GUPnPDLNANativeProfileLoader *native_loader =
+                                      GUPNP_DLNA_NATIVE_PROFILE_LOADER (object);
+        GUPnPDLNANativeProfileLoaderPrivate *priv = native_loader->priv;
+        GObjectClass *parent =
+                 G_OBJECT_CLASS (gupnp_dlna_native_profile_loader_parent_class);
+
+        g_clear_pointer (&priv->descriptions, g_hash_table_unref);
+        g_clear_pointer (&priv->tags_stack, g_list_free);
+        g_clear_pointer (&priv->dlna_profile_data_stack,
+                         gupnp_dlna_native_profile_data_stack_free);
+        g_clear_pointer (&priv->restriction_data_stack,
+                         gupnp_dlna_native_restriction_data_stack_free);
+
+        parent->dispose (object);
+}
+
+static void
+gupnp_dlna_native_profile_loader_class_init
+                        (GUPnPDLNANativeProfileLoaderClass *native_loader_class)
+{
+        GUPnPDLNAProfileLoaderClass *loader_class =
+                          GUPNP_DLNA_PROFILE_LOADER_CLASS (native_loader_class);
+        GObjectClass *object_class = G_OBJECT_CLASS (native_loader_class);
+
+        object_class->dispose = gupnp_dlna_native_profile_loader_dispose;
+        loader_class->pre_field = backend_pre_field;
+        loader_class->post_field = backend_post_field;
+        loader_class->pre_parent = backend_pre_parent;
+        loader_class->post_parent = backend_post_parent;
+        loader_class->pre_restriction = backend_pre_restriction;
+        loader_class->post_restriction = backend_post_restriction;
+        loader_class->pre_restrictions = backend_pre_restrictions;
+        loader_class->post_restrictions = backend_post_restrictions;
+        loader_class->pre_dlna_profile = backend_pre_dlna_profile;
+        loader_class->create_profile = backend_create_profile;
+        loader_class->post_dlna_profile = backend_post_dlna_profile;
+        loader_class->cleanup = backend_cleanup;
+
+        g_type_class_add_private (native_loader_class,
+                                  sizeof (GUPnPDLNANativeProfileLoaderPrivate));
+}
+
+static void
+gupnp_dlna_native_profile_loader_init (GUPnPDLNANativeProfileLoader *self)
+{
+        GUPnPDLNANativeProfileLoaderPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE
+                                        (self,
+                                         GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER,
+                                         GUPnPDLNANativeProfileLoaderPrivate);
+
+        priv->descriptions = g_hash_table_new_full
+                          (g_str_hash,
+                           g_str_equal,
+                           g_free,
+                           (GDestroyNotify) gupnp_dlna_native_description_free);
+        priv->tags_stack = NULL;
+        priv->dlna_profile_data_stack = NULL;
+        priv->restriction_data_stack = NULL;
+        self->priv = priv;
+}
+
+GUPnPDLNANativeProfileLoader *
+gupnp_dlna_native_profile_loader_new (gboolean relaxed_mode,
+                                      gboolean extended_mode)
+{
+        return GUPNP_DLNA_NATIVE_PROFILE_LOADER (g_object_new
+                                        (GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER,
+                                         "relaxed-mode", relaxed_mode,
+                                         "extended-mode", extended_mode,
+                                         NULL));
+}
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-loader.h b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-loader.h
new file mode 100644
index 0000000..c8ab8a1
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile-loader.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_DLNA_NATIVE_PROFILE_LOADER_H__
+#define __GUPNP_DLNA_NATIVE_PROFILE_LOADER_H__
+
+#include "gupnp-dlna-profile-loader.h"
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER \
+        (gupnp_dlna_native_profile_loader_get_type ())
+
+#define GUPNP_DLNA_NATIVE_PROFILE_LOADER(obj) \
+        (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+                                     GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER, \
+                                     GUPnPDLNANativeProfileLoader))
+
+#define GUPNP_DLNA_NATIVE_PROFILE_LOADER_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_CAST ((klass), \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER, \
+                                  GUPnPDLNANativeProfileLoaderClass))
+
+#define GUPNP_IS_DLNA_NATIVE_PROFILE_LOADER(obj) \
+        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+                                     GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER))
+
+#define GUPNP_IS_DLNA_NATIVE_PROFILE_LOADER_CLASS(klass) \
+        (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER))
+
+#define GUPNP_DLNA_NATIVE_PROFILE_LOADER_GET_CLASS(obj) \
+        (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+                                    GUPNP_TYPE_DLNA_NATIVE_PROFILE_LOADER, \
+                                    GUPnPDLNANativeProfileLoaderClass))
+
+typedef struct _GUPnPDLNANativeProfileLoaderPrivate
+                GUPnPDLNANativeProfileLoaderPrivate;
+
+typedef struct {
+        GUPnPDLNAProfileLoader parent;
+
+        GUPnPDLNANativeProfileLoaderPrivate *priv;
+} GUPnPDLNANativeProfileLoader;
+
+typedef struct {
+        GUPnPDLNAProfileLoaderClass parent_class;
+} GUPnPDLNANativeProfileLoaderClass;
+
+GType
+gupnp_dlna_native_profile_loader_get_type (void);
+
+GUPnPDLNANativeProfileLoader *
+gupnp_dlna_native_profile_loader_new (gboolean relaxed_mode,
+                                      gboolean extended_mode);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_NATIVE_PROFILE_LOADER_H__ */
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile.c b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile.c
new file mode 100644
index 0000000..162c705
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Arun Raghavan <arun raghavan collabora co uk>
+ *          Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gupnp-dlna-native-profile.h"
+#include "gupnp-dlna-native-utils.h"
+
+G_DEFINE_TYPE (GUPnPDLNANativeProfile,
+               gupnp_dlna_native_profile,
+               GUPNP_TYPE_DLNA_PROFILE)
+
+struct _GUPnPDLNANativeProfilePrivate {
+        GList *audio_restrictions;
+        GList *container_restrictions;
+        GList *image_restrictions;
+        GList *video_restrictions;
+};
+
+enum {
+        PROP_0,
+        PROP_AUDIO_RESTRICTIONS,
+        PROP_CONTAINER_RESTRICTIONS,
+        PROP_IMAGE_RESTRICTIONS,
+        PROP_VIDEO_RESTRICTIONS
+};
+
+static void
+gupnp_dlna_native_profile_get_property (GObject    *object,
+                                        guint       property_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+        GUPnPDLNANativeProfile *self = GUPNP_DLNA_NATIVE_PROFILE (object);
+        GUPnPDLNANativeProfilePrivate *priv = self->priv;
+
+        switch (property_id) {
+                case PROP_AUDIO_RESTRICTIONS:
+                        g_value_set_pointer (value, priv->audio_restrictions);
+
+                        break;
+                case PROP_CONTAINER_RESTRICTIONS:
+                        g_value_set_pointer
+                                        (value, priv->container_restrictions);
+
+                        break;
+                case PROP_IMAGE_RESTRICTIONS:
+                        g_value_set_pointer (value, priv->image_restrictions);
+
+                        break;
+                case PROP_VIDEO_RESTRICTIONS:
+                        g_value_set_pointer (value, priv->video_restrictions);
+
+                        break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+                                                           property_id,
+                                                           pspec);
+
+                        break;
+        }
+}
+
+static void
+gupnp_dlna_native_profile_set_property (GObject      *object,
+                                        guint         property_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+        GUPnPDLNANativeProfile *self = GUPNP_DLNA_NATIVE_PROFILE (object);
+        GUPnPDLNANativeProfilePrivate *priv = self->priv;
+
+        switch (property_id) {
+                case PROP_AUDIO_RESTRICTIONS:
+                        gupnp_dlna_native_utils_free_restrictions
+                                        (priv->audio_restrictions);
+                        priv->audio_restrictions = g_value_get_pointer (value);
+
+                        break;
+                case PROP_CONTAINER_RESTRICTIONS:
+                        gupnp_dlna_native_utils_free_restrictions
+                                        (priv->container_restrictions);
+                        priv->container_restrictions =
+                                        g_value_get_pointer (value);
+
+                        break;
+                case PROP_IMAGE_RESTRICTIONS:
+                        gupnp_dlna_native_utils_free_restrictions
+                                        (priv->image_restrictions);
+                        priv->image_restrictions = g_value_get_pointer (value);
+
+                        break;
+                case PROP_VIDEO_RESTRICTIONS:
+                        gupnp_dlna_native_utils_free_restrictions
+                                        (priv->video_restrictions);
+                        priv->video_restrictions = g_value_get_pointer (value);
+
+                        break;
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object,
+                                                           property_id,
+                                                           pspec);
+
+                        break;
+        }
+}
+
+static void
+gupnp_dlna_native_profile_finalize (GObject *object)
+{
+        GUPnPDLNANativeProfile *self = GUPNP_DLNA_NATIVE_PROFILE (object);
+        GUPnPDLNANativeProfilePrivate *priv = self->priv;
+        GObjectClass *parent_class =
+                        G_OBJECT_CLASS (gupnp_dlna_native_profile_parent_class);
+
+        gupnp_dlna_native_utils_free_restrictions (priv->audio_restrictions);
+        gupnp_dlna_native_utils_free_restrictions
+                                        (priv->container_restrictions);
+        gupnp_dlna_native_utils_free_restrictions (priv->image_restrictions);
+        gupnp_dlna_native_utils_free_restrictions (priv->video_restrictions);
+
+        parent_class->finalize (object);
+}
+
+static void
+gupnp_dlna_native_profile_class_init
+                             (GUPnPDLNANativeProfileClass *native_profile_class)
+{
+        GObjectClass *object_class = G_OBJECT_CLASS (native_profile_class);
+        GParamSpec *pspec;
+
+        object_class->get_property = gupnp_dlna_native_profile_get_property;
+        object_class->set_property = gupnp_dlna_native_profile_set_property;
+        object_class->finalize = gupnp_dlna_native_profile_finalize;
+
+        pspec = g_param_spec_pointer ("audio-restrictions",
+                                      "Audio restrictions",
+                                      "Audio restrictions for the DLNA Profile",
+                                      G_PARAM_READWRITE |
+                                      G_PARAM_CONSTRUCT_ONLY);
+        g_object_class_install_property (object_class,
+                                         PROP_AUDIO_RESTRICTIONS,
+                                         pspec);
+        pspec = g_param_spec_pointer ("container-restrictions",
+                                      "Container restrictions",
+                                      "Container restrictions for the DLNA "
+                                      "Profile",
+                                      G_PARAM_READWRITE |
+                                      G_PARAM_CONSTRUCT_ONLY);
+        g_object_class_install_property (object_class,
+                                         PROP_CONTAINER_RESTRICTIONS,
+                                         pspec);
+        pspec = g_param_spec_pointer ("image-restrictions",
+                                      "Image restrictions",
+                                      "Image restrictions for the DLNA Profile",
+                                      G_PARAM_READWRITE |
+                                      G_PARAM_CONSTRUCT_ONLY);
+        g_object_class_install_property (object_class,
+                                         PROP_IMAGE_RESTRICTIONS,
+                                         pspec);
+        pspec = g_param_spec_pointer ("video-restrictions",
+                                      "Video restrictions",
+                                      "Video restrictions for the DLNA Profile",
+                                      G_PARAM_READWRITE |
+                                      G_PARAM_CONSTRUCT_ONLY);
+        g_object_class_install_property (object_class,
+                                         PROP_VIDEO_RESTRICTIONS,
+                                         pspec);
+
+        g_type_class_add_private (native_profile_class,
+                                  sizeof (GUPnPDLNANativeProfilePrivate));
+}
+
+static void
+gupnp_dlna_native_profile_init (GUPnPDLNANativeProfile *self)
+{
+        GUPnPDLNANativeProfilePrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE
+                                        (self,
+                                         GUPNP_TYPE_DLNA_NATIVE_PROFILE,
+                                         GUPnPDLNANativeProfilePrivate);
+
+        priv->audio_restrictions = NULL;
+        priv->container_restrictions = NULL;
+        priv->image_restrictions = NULL;
+        priv->video_restrictions = NULL;
+        self->priv = priv;
+}
+
+GList *
+gupnp_dlna_native_profile_get_audio_restrictions (GUPnPDLNANativeProfile *self)
+{
+        g_return_val_if_fail (GUPNP_IS_DLNA_NATIVE_PROFILE (self), NULL);
+
+        return self->priv->audio_restrictions;
+}
+
+GList *
+gupnp_dlna_native_profile_get_container_restrictions
+                                        (GUPnPDLNANativeProfile *self)
+{
+        g_return_val_if_fail (GUPNP_IS_DLNA_NATIVE_PROFILE (self), NULL);
+
+        return self->priv->container_restrictions;
+}
+
+GList *
+gupnp_dlna_native_profile_get_image_restrictions (GUPnPDLNANativeProfile *self)
+{
+        g_return_val_if_fail (GUPNP_IS_DLNA_NATIVE_PROFILE (self), NULL);
+
+        return self->priv->image_restrictions;
+}
+
+GList *
+gupnp_dlna_native_profile_get_video_restrictions (GUPnPDLNANativeProfile *self)
+{
+        g_return_val_if_fail (GUPNP_IS_DLNA_NATIVE_PROFILE (self), NULL);
+
+        return self->priv->video_restrictions;
+}
+
+GUPnPDLNANativeProfile *
+gupnp_dlna_native_profile_new (const gchar *name,
+                               const gchar *mime,
+                               GList       *audio_restrictions,
+                               GList       *container_restrictions,
+                               GList       *image_restrictions,
+                               GList       *video_restrictions,
+                               gboolean     extended)
+{
+        return GUPNP_DLNA_NATIVE_PROFILE
+                             (g_object_new
+                              (GUPNP_TYPE_DLNA_NATIVE_PROFILE,
+                               "name", name,
+                               "mime", mime,
+                               "audio-restrictions", audio_restrictions,
+                               "container-restrictions", container_restrictions,
+                               "image-restrictions", image_restrictions,
+                               "video-restrictions", video_restrictions,
+                               "extended", extended,
+                               NULL));
+}
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile.h b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile.h
new file mode 100644
index 0000000..ca68ab8
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-profile.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_DLNA_NATIVE_PROFILE_H__
+#define __GUPNP_DLNA_NATIVE_PROFILE_H__
+
+#include <glib-object.h>
+#include "gupnp-dlna-profile.h"
+#include "gupnp-dlna-native-sets.h"
+
+G_BEGIN_DECLS
+
+#define GUPNP_TYPE_DLNA_NATIVE_PROFILE gupnp_dlna_native_profile_get_type()
+
+#define GUPNP_DLNA_NATIVE_PROFILE(obj)                               \
+        (G_TYPE_CHECK_INSTANCE_CAST ((obj),                   \
+                                     GUPNP_TYPE_DLNA_NATIVE_PROFILE, \
+                                     GUPnPDLNANativeProfile))
+
+#define GUPNP_DLNA_NATIVE_PROFILE_CLASS(klass)                    \
+        (G_TYPE_CHECK_CLASS_CAST ((klass),                 \
+                                  GUPNP_TYPE_DLNA_NATIVE_PROFILE, \
+                                  GUPnPDLNANativeProfileClass))
+
+#define GUPNP_IS_DLNA_NATIVE_PROFILE(obj)                                   \
+        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GUPNP_TYPE_DLNA_NATIVE_PROFILE))
+
+#define GUPNP_IS_DLNA_NATIVE_PROFILE_CLASS(klass)                           \
+        (G_TYPE_CHECK_CLASS_TYPE ((klass), GUPNP_TYPE_DLNA_NATIVE_PROFILE))
+
+#define GUPNP_DLNA_NATIVE_PROFILE_GET_CLASS(obj)                    \
+        (G_TYPE_INSTANCE_GET_CLASS ((obj),                   \
+                                    GUPNP_TYPE_DLNA_NATIVE_PROFILE, \
+                                    GUPnPDLNANativeProfileClass))
+
+typedef struct _GUPnPDLNANativeProfilePrivate GUPnPDLNANativeProfilePrivate;
+
+typedef struct {
+        GUPnPDLNAProfile parent;
+
+        GUPnPDLNANativeProfilePrivate *priv;
+} GUPnPDLNANativeProfile;
+
+typedef struct {
+        GUPnPDLNAProfileClass parent_class;
+} GUPnPDLNANativeProfileClass;
+
+GType
+gupnp_dlna_native_profile_get_type (void);
+
+GUPnPDLNANativeProfile *
+gupnp_dlna_native_profile_new (const gchar *name,
+                               const gchar *mime,
+                               GList       *audio_restrictions,
+                               GList       *container_restrictions,
+                               GList       *image_restrictions,
+                               GList       *video_restrictions,
+                               gboolean     extended);
+
+GList *
+gupnp_dlna_native_profile_get_container_restrictions
+                                        (GUPnPDLNANativeProfile *self);
+
+GList *
+gupnp_dlna_native_profile_get_audio_restrictions (GUPnPDLNANativeProfile *self);
+
+GList *
+gupnp_dlna_native_profile_get_image_restrictions (GUPnPDLNANativeProfile *self);
+
+GList *
+gupnp_dlna_native_profile_get_video_restrictions (GUPnPDLNANativeProfile *self);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_NATIVE_PROFILE_H__ */
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-sets.h b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-sets.h
new file mode 100644
index 0000000..2ef015b
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-sets.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_DLNA_NATIVE_SETS_H__
+#define __GUPNP_DLNA_NATIVE_SETS_H__
+
+#include "gupnp-dlna-native-value-type.h"
+#include "gupnp-dlna-native-value-list.h"
+#include "gupnp-dlna-native-restriction.h"
+#include "gupnp-dlna-native-info-set.h"
+
+#endif /* __GUPNP_DLNA_NATIVE_SETS_H__ */
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-utils.c b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-utils.c
new file mode 100644
index 0000000..f43ef03
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-utils.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "gupnp-dlna-native-utils.h"
+#include "gupnp-dlna-native-sets.h"
+
+void
+gupnp_dlna_native_utils_free_restrictions (GList *list)
+{
+        if (list == NULL)
+                return;
+        g_list_free_full (list,
+                          (GDestroyNotify) gupnp_dlna_native_restriction_free);
+}
+
+gchar *
+gupnp_dlna_native_utils_restrictions_list_to_string (GList *list)
+{
+        GList *iter;
+        GPtrArray *strings = g_ptr_array_new_with_free_func (g_free);
+        gchar *final_string;
+
+        for (iter = list; iter != NULL; iter = iter->next) {
+                GUPnPDLNANativeRestriction *restriction =
+                                     GUPNP_DLNA_NATIVE_RESTRICTION (iter->data);
+
+                if (restriction)
+                        g_ptr_array_add (strings,
+                                         gupnp_dlna_native_restriction_to_string
+                                                            (restriction));
+        }
+
+        if (strings->len) {
+                g_ptr_array_add (strings, NULL);
+                final_string = g_strjoinv ("; ",
+                                           (gchar **) strings->pdata);
+        }
+        else
+                final_string = g_strdup ("EMPTY");
+        g_ptr_array_unref (strings);
+
+        return final_string;
+}
diff --git a/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-utils.h b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-utils.h
new file mode 100644
index 0000000..c8b079b
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/gupnp-dlna-native-utils.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Authors: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GUPNP_DLNA_NATIVE_UTILS_H__
+#define __GUPNP_DLNA_NATIVE_UTILS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+void
+gupnp_dlna_native_utils_free_restrictions (GList *list);
+
+gchar *
+gupnp_dlna_native_utils_restrictions_list_to_string (GList *list);
+
+G_END_DECLS
+
+#endif /* __GUPNP_DLNA_NATIVE_UTILS_H__ */
diff --git a/libgupnp-dlna/profile-backends/native/native.am b/libgupnp-dlna/profile-backends/native/native.am
new file mode 100644
index 0000000..2991cbe
--- /dev/null
+++ b/libgupnp-dlna/profile-backends/native/native.am
@@ -0,0 +1,59 @@
+native_profile_backend = \
+	profile-backends/native/libnativeprofilebackend.la
+native_loader = \
+	profile-backends/native/libnativeloader.la
+native_guesser = \
+	profile-backends/native/libnativeguesser.la
+
+native_cflags = \
+	$(common_cflags) \
+	-I$(top_srcdir)/libgupnp-dlna/profile-backends/native/sets
+
+noinst_LTLIBRARIES += \
+	$(native_profile_backend) \
+	$(native_loader) \
+	$(native_guesser)
+
+gupnp_cflags += \
+	-I$(top_srcdir)/libgupnp-dlna/profile-backends/native
+gupnp_libadd += \
+	$(native_profile_backend)
+
+include $(top_srcdir)/libgupnp-dlna/profile-backends/native/sets/sets.am
+
+profile_backends_native_libnativeloader_la_SOURCES = \
+	profile-backends/native/gupnp-dlna-native-profile-loader.c \
+	profile-backends/native/gupnp-dlna-native-profile-loader.h
+profile_backends_native_libnativeloader_la_LIBADD = \
+	$(common_libadd)
+profile_backends_native_libnativeloader_la_CFLAGS = \
+	$(loader_log_cflags) \
+	$(native_cflags)
+
+profile_backends_native_libnativeguesser_la_SOURCES = \
+	$(sets_sources) \
+	profile-backends/native/gupnp-dlna-native-profile-guesser-impl.c \
+	profile-backends/native/gupnp-dlna-native-profile-guesser-impl.h
+profile_backends_native_libnativeguesser_la_LIBADD = \
+	$(common_libadd)
+profile_backends_native_libnativeguesser_la_CFLAGS = \
+	$(guesser_log_cflags) \
+	$(native_cflags) \
+	$(metadata_cflags)
+
+profile_backends_native_libnativeprofilebackend_la_SOURCES = \
+	profile-backends/native/gupnp-dlna-native-profile-backend.c \
+	profile-backends/native/gupnp-dlna-native-profile-backend.h \
+	profile-backends/native/gupnp-dlna-native-profile.c \
+	profile-backends/native/gupnp-dlna-native-profile.h \
+	profile-backends/native/gupnp-dlna-native-sets.h \
+	profile-backends/native/gupnp-dlna-native-utils.c \
+	profile-backends/native/gupnp-dlna-native-utils.h
+profile_backends_native_libnativeprofilebackend_la_LIBADD = \
+	$(common_libadd) \
+	$(native_loader) \
+	$(native_guesser)
+profile_backends_native_libnativeprofilebackend_la_CFLAGS = \
+	$(general_log_cflags) \
+	$(native_cflags) \
+	$(metadata_cflags)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]