|
Packit |
712bc5 |
/*
|
|
Packit |
712bc5 |
* Copyright (C) 2012 Intel Corporation
|
|
Packit |
712bc5 |
*
|
|
Packit |
712bc5 |
* Authors: Krzesimir Nowak <krnowak@openismus.com>
|
|
Packit |
712bc5 |
*
|
|
Packit |
712bc5 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
712bc5 |
* modify it under the terms of the GNU Library General Public
|
|
Packit |
712bc5 |
* License as published by the Free Software Foundation; either
|
|
Packit |
712bc5 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit |
712bc5 |
*
|
|
Packit |
712bc5 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
712bc5 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
712bc5 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
712bc5 |
* Library General Public License for more details.
|
|
Packit |
712bc5 |
*
|
|
Packit |
712bc5 |
* You should have received a copy of the GNU Library General Public
|
|
Packit |
712bc5 |
* License along with this library; if not, write to the
|
|
Packit |
712bc5 |
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Packit |
712bc5 |
* Boston, MA 02110-1301, USA.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
#include <stdarg.h>
|
|
Packit |
712bc5 |
#include <libxml/parserInternals.h>
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
#include "fragment-util.h"
|
|
Packit |
712bc5 |
#include "xml-util.h"
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
typedef struct {
|
|
Packit |
712bc5 |
gchar *node_name;
|
|
Packit |
712bc5 |
gchar *attribute_name;
|
|
Packit |
712bc5 |
} NodeDiff;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static NodeDiff *
|
|
Packit |
712bc5 |
node_diff_new (const xmlChar *node_name,
|
|
Packit |
712bc5 |
const xmlChar *attribute_name)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
NodeDiff *diff = g_slice_new (NodeDiff);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
diff->node_name = g_strdup ((gchar *) node_name);
|
|
Packit |
712bc5 |
diff->attribute_name = g_strdup ((gchar *) attribute_name);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return diff;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static void
|
|
Packit |
712bc5 |
node_diff_free (NodeDiff *diff)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
if (diff != NULL) {
|
|
Packit |
712bc5 |
g_free (diff->node_name);
|
|
Packit |
712bc5 |
g_free (diff->attribute_name);
|
|
Packit |
712bc5 |
g_slice_free (NodeDiff, diff);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static GList *
|
|
Packit |
712bc5 |
get_toplevel_changes (xmlNodePtr current_node,
|
|
Packit |
712bc5 |
xmlNodePtr new_node)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlAttrPtr attribute;
|
|
Packit |
712bc5 |
GHashTable *current_attributes = xml_util_get_attributes_map
|
|
Packit |
712bc5 |
(current_node);
|
|
Packit |
712bc5 |
GList *changes = NULL;
|
|
Packit |
712bc5 |
const xmlChar *name = new_node->name;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
/* compare attributes */
|
|
Packit |
712bc5 |
for (attribute = new_node->properties;
|
|
Packit |
712bc5 |
attribute != NULL;
|
|
Packit |
712bc5 |
attribute = attribute->next) {
|
|
Packit |
712bc5 |
const xmlChar *value = NULL;
|
|
Packit |
712bc5 |
const xmlChar *key = attribute->name;
|
|
Packit |
712bc5 |
gboolean differs = FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (g_hash_table_lookup_extended (current_attributes,
|
|
Packit |
712bc5 |
key,
|
|
Packit |
712bc5 |
NULL,
|
|
Packit |
712bc5 |
(gpointer *) &value)) {
|
|
Packit |
712bc5 |
if (xmlStrcmp (value, attribute->children->content))
|
|
Packit |
712bc5 |
differs = TRUE;
|
|
Packit |
712bc5 |
g_hash_table_remove (current_attributes, key);
|
|
Packit |
712bc5 |
} else
|
|
Packit |
712bc5 |
differs = TRUE;
|
|
Packit |
712bc5 |
if (differs)
|
|
Packit |
712bc5 |
changes = g_list_prepend (changes,
|
|
Packit |
712bc5 |
node_diff_new (name,
|
|
Packit |
712bc5 |
key));
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (g_hash_table_size (current_attributes) > 0) {
|
|
Packit |
712bc5 |
GHashTableIter iter;
|
|
Packit |
712bc5 |
xmlChar *key = NULL;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
g_hash_table_iter_init (&iter, current_attributes);
|
|
Packit |
712bc5 |
while (g_hash_table_iter_next (&iter,
|
|
Packit |
712bc5 |
(gpointer *) &key,
|
|
Packit |
712bc5 |
NULL))
|
|
Packit |
712bc5 |
changes = g_list_prepend (changes, node_diff_new (name,
|
|
Packit |
712bc5 |
key));
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
g_hash_table_unref (current_attributes);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return changes;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
#if GLIB_CHECK_VERSION (2, 32, 0)
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
#define hash_table_contains g_hash_table_contains
|
|
Packit |
712bc5 |
#define hash_table_add g_hash_table_add
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
#else
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gboolean
|
|
Packit |
712bc5 |
hash_table_contains (GHashTable *table,
|
|
Packit |
712bc5 |
gpointer key)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
return g_hash_table_lookup_extended (table, key, NULL, NULL);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static void
|
|
Packit |
712bc5 |
hash_table_add (GHashTable *table,
|
|
Packit |
712bc5 |
gpointer key)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
g_hash_table_replace (table, key, key);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
#endif
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gboolean
|
|
Packit |
712bc5 |
is_read_only (const gchar *changed_element,
|
|
Packit |
712bc5 |
const gchar *changed_attribute)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
static GHashTable *readonly_props = NULL;
|
|
Packit |
712bc5 |
static gsize readonly_props_loaded = 0;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (g_once_init_enter (&readonly_props_loaded)) {
|
|
Packit |
712bc5 |
readonly_props = g_hash_table_new (g_str_hash,
|
|
Packit |
712bc5 |
g_str_equal);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "@id");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "@parentID");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "@refID");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "@restricted");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "@searchable");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "@childCount");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "searchClass");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "searchClass@name");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "searchClass@includeDerived");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "createClass");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "createClass@name");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "createClass@includeDerived");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "writeStatus");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "res@importUri");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "storageTotal");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "storageUsed");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "storageFree");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "storageMaxPartition");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "storageMedium");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "playbackCount");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "srsRecordScheduleID");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "srsRecordTaskID");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "price");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "price@currency");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "payPerView");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "dateTimeRange");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer)
|
|
Packit |
712bc5 |
"dateTimeRange@daylightSaving");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "signalStrength");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "signalLocked");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "tuned");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "containerUpdateID");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "objectUpdateID");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "totalDeletedChildCount");
|
|
Packit |
712bc5 |
hash_table_add (readonly_props, (gpointer) "res@updateCount");
|
|
Packit |
712bc5 |
g_once_init_leave (&readonly_props_loaded, 1);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
if (changed_element != NULL) {
|
|
Packit |
712bc5 |
if (changed_attribute != NULL) {
|
|
Packit |
712bc5 |
gchar *test_prop = g_strdup_printf ("%s@%s",
|
|
Packit |
712bc5 |
changed_element,
|
|
Packit |
712bc5 |
changed_attribute);
|
|
Packit |
712bc5 |
gboolean result = hash_table_contains (readonly_props,
|
|
Packit |
712bc5 |
test_prop);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
g_free (test_prop);
|
|
Packit |
712bc5 |
if (result)
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
test_prop = g_strdup_printf ("@%s", changed_attribute);
|
|
Packit |
712bc5 |
result = hash_table_contains (readonly_props,
|
|
Packit |
712bc5 |
test_prop);
|
|
Packit |
712bc5 |
g_free (test_prop);
|
|
Packit |
712bc5 |
if (result)
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return hash_table_contains (readonly_props, changed_element);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gboolean
|
|
Packit |
712bc5 |
is_any_change_read_only (xmlNodePtr current_node,
|
|
Packit |
712bc5 |
xmlNodePtr new_node)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
GList *changes = get_toplevel_changes (current_node, new_node);
|
|
Packit |
712bc5 |
GList *iter;
|
|
Packit |
712bc5 |
gboolean read_only = FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
for (iter = changes; iter != NULL; iter = iter->next) {
|
|
Packit |
712bc5 |
NodeDiff *diff = (NodeDiff *) iter->data;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (is_read_only (diff->node_name,
|
|
Packit |
712bc5 |
diff->attribute_name)) {
|
|
Packit |
712bc5 |
read_only = TRUE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
break;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (changes != NULL)
|
|
Packit |
712bc5 |
g_list_free_full (changes, (GDestroyNotify) node_diff_free);
|
|
Packit |
712bc5 |
return read_only;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static GUPnPDIDLLiteFragmentResult
|
|
Packit |
712bc5 |
apply_temporary_modification (DocNode *modified,
|
|
Packit |
712bc5 |
xmlNodePtr current_node,
|
|
Packit |
712bc5 |
xmlNodePtr new_node,
|
|
Packit |
712bc5 |
XSDData *xsd_data)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlNodePtr mod_cur_node = xml_util_find_node (modified->node,
|
|
Packit |
712bc5 |
current_node);
|
|
Packit |
712bc5 |
xmlNodePtr new_node_copy = xml_util_copy_node (new_node);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (mod_cur_node == NULL) {
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_UNKNOWN_ERROR;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
xmlUnlinkNode (new_node_copy);
|
|
Packit |
712bc5 |
mod_cur_node = xmlReplaceNode (mod_cur_node, new_node_copy);
|
|
Packit |
712bc5 |
xmlUnlinkNode (mod_cur_node);
|
|
Packit |
712bc5 |
xmlFreeNode (mod_cur_node);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (!xsd_data_validate_doc (xsd_data, modified->doc))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_NEW_INVALID;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static GUPnPDIDLLiteFragmentResult
|
|
Packit |
712bc5 |
apply_temporary_addition (DocNode *modified,
|
|
Packit |
712bc5 |
xmlNodePtr sibling,
|
|
Packit |
712bc5 |
xmlNodePtr new_node,
|
|
Packit |
712bc5 |
XSDData *xsd_data)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlNodePtr mod_sibling;
|
|
Packit |
712bc5 |
xmlNodePtr new_node_copy = xml_util_copy_node (new_node);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (sibling->doc == modified->doc)
|
|
Packit |
712bc5 |
mod_sibling = sibling;
|
|
Packit |
712bc5 |
else
|
|
Packit |
712bc5 |
mod_sibling = xml_util_find_node (modified->node, sibling);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (mod_sibling == NULL)
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_UNKNOWN_ERROR;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
xmlUnlinkNode (new_node_copy);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (xmlAddNextSibling (mod_sibling, new_node_copy) == NULL) {
|
|
Packit |
712bc5 |
xmlFreeNode (new_node_copy);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_UNKNOWN_ERROR;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (!xsd_data_validate_doc (xsd_data, modified->doc))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_NEW_INVALID;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static GUPnPDIDLLiteFragmentResult
|
|
Packit |
712bc5 |
apply_temporary_removal (DocNode *modified,
|
|
Packit |
712bc5 |
xmlNodePtr current_node,
|
|
Packit |
712bc5 |
XSDData *xsd_data)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlNodePtr mod_cur_node = xml_util_find_node (modified->node,
|
|
Packit |
712bc5 |
current_node);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (mod_cur_node == NULL)
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_UNKNOWN_ERROR;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
xmlUnlinkNode (mod_cur_node);
|
|
Packit |
712bc5 |
xmlFreeNode (mod_cur_node);
|
|
Packit |
712bc5 |
if (!xsd_data_validate_doc (xsd_data, modified->doc))
|
|
Packit |
712bc5 |
/* not sure if this is correct */
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_REQUIRED_TAG;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
typedef struct {
|
|
Packit |
712bc5 |
gboolean required;
|
|
Packit |
712bc5 |
GHashTable* required_dep_props; /* string set */
|
|
Packit |
712bc5 |
GHashTable* required_indep_props; /* string to indep prop */
|
|
Packit |
712bc5 |
} IndependentProperty;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static void
|
|
Packit |
712bc5 |
independent_property_free (IndependentProperty *indep)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
if (indep != NULL) {
|
|
Packit |
712bc5 |
g_hash_table_unref (indep->required_dep_props);
|
|
Packit |
712bc5 |
g_hash_table_unref (indep->required_indep_props);
|
|
Packit |
712bc5 |
g_slice_free (IndependentProperty, indep);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static IndependentProperty *
|
|
Packit |
712bc5 |
independent_property_new (gboolean required)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
IndependentProperty *indep = g_slice_new (IndependentProperty);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
indep->required = required;
|
|
Packit |
712bc5 |
indep->required_dep_props = g_hash_table_new_full (g_str_hash,
|
|
Packit |
712bc5 |
g_str_equal,
|
|
Packit |
712bc5 |
g_free,
|
|
Packit |
712bc5 |
NULL);
|
|
Packit |
712bc5 |
indep->required_indep_props = g_hash_table_new_full
|
|
Packit |
712bc5 |
(g_str_hash,
|
|
Packit |
712bc5 |
g_str_equal,
|
|
Packit |
712bc5 |
g_free,
|
|
Packit |
712bc5 |
(GDestroyNotify) independent_property_free);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return indep;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static void
|
|
Packit |
712bc5 |
insert_indep_prop (GHashTable *props,
|
|
Packit |
712bc5 |
const gchar *name,
|
|
Packit |
712bc5 |
IndependentProperty *prop)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
g_hash_table_insert (props, g_strdup (name), prop);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static void
|
|
Packit |
712bc5 |
insert_indep_prop_to_indep (IndependentProperty *prop,
|
|
Packit |
712bc5 |
const gchar *name,
|
|
Packit |
712bc5 |
IndependentProperty *req_prop)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
insert_indep_prop (prop->required_indep_props, name, req_prop);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static void
|
|
Packit |
712bc5 |
add_dep_prop (IndependentProperty *indep,
|
|
Packit |
712bc5 |
const gchar *name)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
hash_table_add (indep->required_dep_props, g_strdup (name));
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static IndependentProperty *
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props (gboolean required,
|
|
Packit |
712bc5 |
const gchar *dep_prop,
|
|
Packit |
712bc5 |
...)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
IndependentProperty *indep = independent_property_new (required);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (dep_prop != NULL) {
|
|
Packit |
712bc5 |
va_list var_args;
|
|
Packit |
712bc5 |
const gchar *name = dep_prop;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
va_start (var_args, dep_prop);
|
|
Packit |
712bc5 |
do {
|
|
Packit |
712bc5 |
add_dep_prop (indep, name);
|
|
Packit |
712bc5 |
name = va_arg (var_args, gchar *);
|
|
Packit |
712bc5 |
} while (name != NULL);
|
|
Packit |
712bc5 |
va_end (var_args);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return indep;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static IndependentProperty *
|
|
Packit |
712bc5 |
create_foreign_metadata_props (void)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
IndependentProperty *fm = independent_property_new (FALSE);
|
|
Packit |
712bc5 |
IndependentProperty *other;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
add_dep_prop (fm, "type");
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
other = independent_property_new (TRUE);
|
|
Packit |
712bc5 |
insert_indep_prop_to_indep (fm, "fmId", other);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
other = independent_property_new (TRUE);
|
|
Packit |
712bc5 |
insert_indep_prop_to_indep (fm, "fmClass", other);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
other = independent_property_new (TRUE);
|
|
Packit |
712bc5 |
insert_indep_prop_to_indep (fm, "fmProvider", other);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
other = independent_property_new (TRUE);
|
|
Packit |
712bc5 |
add_dep_prop (other, "xmlFlag");
|
|
Packit |
712bc5 |
insert_indep_prop_to_indep (fm, "fmBody", other);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return fm;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static GHashTable *
|
|
Packit |
712bc5 |
get_required_properties (void)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
static GHashTable *required_props = NULL;
|
|
Packit |
712bc5 |
static gsize required_props_loaded = 0;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (g_once_init_enter (&required_props_loaded)) {
|
|
Packit |
712bc5 |
required_props = g_hash_table_new_full
|
|
Packit |
712bc5 |
(g_str_hash,
|
|
Packit |
712bc5 |
g_str_equal,
|
|
Packit |
712bc5 |
g_free,
|
|
Packit |
712bc5 |
(GDestroyNotify) independent_property_free);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"id",
|
|
Packit |
712bc5 |
"parentID",
|
|
Packit |
712bc5 |
"restricted",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"title",
|
|
Packit |
712bc5 |
independent_property_new (TRUE));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"class",
|
|
Packit |
712bc5 |
independent_property_new (TRUE));
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"res",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"protocolInfo",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"programID",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"type",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"seriesID",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"type",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"channelID",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"type",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"programCode",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"type",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"channelGroupName",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"id",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"price",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"currency",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"desc",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"nameSpace",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"deviceUDN",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"serviceType",
|
|
Packit |
712bc5 |
"serviceId",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"stateVariableCollection",
|
|
Packit |
712bc5 |
create_prop_with_required_dep_props
|
|
Packit |
712bc5 |
(FALSE,
|
|
Packit |
712bc5 |
"serviceName",
|
|
Packit |
712bc5 |
"rcsInstanceType",
|
|
Packit |
712bc5 |
NULL));
|
|
Packit |
712bc5 |
insert_indep_prop (required_props,
|
|
Packit |
712bc5 |
"foreignMetadata",
|
|
Packit |
712bc5 |
create_foreign_metadata_props ());
|
|
Packit |
712bc5 |
g_once_init_leave (&required_props_loaded, 1);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return required_props;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gboolean
|
|
Packit |
712bc5 |
is_required (const xmlChar *changed_element,
|
|
Packit |
712bc5 |
const xmlChar *changed_attribute)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
GHashTable *required_props = get_required_properties ();
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (changed_element != NULL) {
|
|
Packit |
712bc5 |
IndependentProperty *toplevel_prop = g_hash_table_lookup
|
|
Packit |
712bc5 |
(required_props,
|
|
Packit |
712bc5 |
"");
|
|
Packit |
712bc5 |
IndependentProperty *this_prop = g_hash_table_lookup
|
|
Packit |
712bc5 |
(required_props,
|
|
Packit |
712bc5 |
(gpointer) changed_element);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (changed_attribute != NULL) {
|
|
Packit |
712bc5 |
if (hash_table_contains
|
|
Packit |
712bc5 |
(toplevel_prop->required_dep_props,
|
|
Packit |
712bc5 |
changed_attribute))
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
if (hash_table_contains (this_prop->required_dep_props,
|
|
Packit |
712bc5 |
changed_attribute))
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
if (hash_table_contains (toplevel_prop->required_indep_props,
|
|
Packit |
712bc5 |
changed_element))
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
/* TODO: check if changed element is not a required
|
|
Packit |
712bc5 |
* property of its parent element. That needs some
|
|
Packit |
712bc5 |
* additions in IndepependentProperty.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static GUPnPDIDLLiteFragmentResult
|
|
Packit |
712bc5 |
new_doc_is_valid_modification (DocNode *modified,
|
|
Packit |
712bc5 |
xmlDocPtr current_doc,
|
|
Packit |
712bc5 |
xmlDocPtr new_doc,
|
|
Packit |
712bc5 |
XSDData *xsd_data)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlNodePtr current_node = current_doc->children->children;
|
|
Packit |
712bc5 |
xmlNodePtr new_node = new_doc->children->children;
|
|
Packit |
712bc5 |
xmlNodePtr last_sibling = NULL;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
while (current_node != NULL && new_node != NULL) {
|
|
Packit |
712bc5 |
GUPnPDIDLLiteFragmentResult result;
|
|
Packit |
712bc5 |
xmlNodePtr temp_current_node = current_node;
|
|
Packit |
712bc5 |
xmlNodePtr temp_new_node = new_node;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
last_sibling = new_node;
|
|
Packit |
712bc5 |
/* We can't put this line into for instruction,
|
|
Packit |
712bc5 |
* because new_node could be unlinked from its
|
|
Packit |
712bc5 |
* document and put into another one in
|
|
Packit |
712bc5 |
* apply_temporary_modification. We have to get its
|
|
Packit |
712bc5 |
* sibling before that could happen.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
new_node = new_node->next;
|
|
Packit |
712bc5 |
current_node = current_node->next;
|
|
Packit |
712bc5 |
if (xml_util_node_deep_equal (temp_current_node, temp_new_node))
|
|
Packit |
712bc5 |
/* This is just a context, skip the checks. */
|
|
Packit |
712bc5 |
continue;
|
|
Packit |
712bc5 |
if (xmlStrcmp (temp_current_node->name, temp_new_node->name))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_NEW_INVALID;
|
|
Packit |
712bc5 |
if (is_any_change_read_only (temp_current_node, temp_new_node))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_READONLY_TAG;
|
|
Packit |
712bc5 |
result = apply_temporary_modification (modified,
|
|
Packit |
712bc5 |
temp_current_node,
|
|
Packit |
712bc5 |
temp_new_node,
|
|
Packit |
712bc5 |
xsd_data);
|
|
Packit |
712bc5 |
if (result != GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK)
|
|
Packit |
712bc5 |
return result;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
if (last_sibling == NULL) {
|
|
Packit |
712bc5 |
if (modified->node->children != NULL)
|
|
Packit |
712bc5 |
last_sibling = modified->node->last;
|
|
Packit |
712bc5 |
else
|
|
Packit |
712bc5 |
/* We expect that modified object has some
|
|
Packit |
712bc5 |
* required tags like <upnp:class> or
|
|
Packit |
712bc5 |
* <dc:title>.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_UNKNOWN_ERROR;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
/* If there are some more nodes in current fragment then it
|
|
Packit |
712bc5 |
* means they are going to be removed. Check against required
|
|
Packit |
712bc5 |
* or read-only tag removal.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
while (current_node != NULL) {
|
|
Packit |
712bc5 |
GUPnPDIDLLiteFragmentResult result;
|
|
Packit |
712bc5 |
xmlNodePtr temp_node = current_node;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
current_node = current_node->next;
|
|
Packit |
712bc5 |
/* TODO: should we check if there are some readonly
|
|
Packit |
712bc5 |
* attributes when we remove whole element?
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
if (is_read_only ((gchar *) temp_node->name, NULL))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_READONLY_TAG;
|
|
Packit |
712bc5 |
/* We don't check for required attributes or
|
|
Packit |
712bc5 |
* subelements, because most of them are required only
|
|
Packit |
712bc5 |
* when the element exists. And we are removing this
|
|
Packit |
712bc5 |
* one.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
if (is_required (temp_node->name, NULL))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_REQUIRED_TAG;
|
|
Packit |
712bc5 |
result = apply_temporary_removal (modified,
|
|
Packit |
712bc5 |
temp_node,
|
|
Packit |
712bc5 |
xsd_data);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (result != GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK)
|
|
Packit |
712bc5 |
return result;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
/* If there are some more nodes in new fragment then it means
|
|
Packit |
712bc5 |
* they are going to be added. Check against read-only tags
|
|
Packit |
712bc5 |
* addition and general sanity check.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
while (new_node != NULL) {
|
|
Packit |
712bc5 |
GUPnPDIDLLiteFragmentResult result;
|
|
Packit |
712bc5 |
xmlNodePtr temp_node;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (is_read_only ((gchar *) new_node->name, NULL))
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_READONLY_TAG;
|
|
Packit |
712bc5 |
/* TODO: We probably should check if newly added node
|
|
Packit |
712bc5 |
* has all required properties. Maybe XSD check could
|
|
Packit |
712bc5 |
* do that for us.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
temp_node = new_node;
|
|
Packit |
712bc5 |
new_node = new_node->next;
|
|
Packit |
712bc5 |
result = apply_temporary_addition (modified,
|
|
Packit |
712bc5 |
last_sibling,
|
|
Packit |
712bc5 |
temp_node,
|
|
Packit |
712bc5 |
xsd_data);
|
|
Packit |
712bc5 |
if (result != GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK)
|
|
Packit |
712bc5 |
return result;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return GUPNP_DIDL_LITE_FRAGMENT_RESULT_OK;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gchar *
|
|
Packit |
712bc5 |
fix_fragment (const gchar *fragment)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
return g_strdup_printf
|
|
Packit |
712bc5 |
("\n"
|
|
Packit |
712bc5 |
"
|
|
Packit |
712bc5 |
"xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
|
|
Packit |
712bc5 |
"xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\"\n"
|
|
Packit |
712bc5 |
"xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\"\n"
|
|
Packit |
712bc5 |
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
|
|
Packit |
712bc5 |
">%s</DIDLLiteFragment>\n",
|
|
Packit |
712bc5 |
fragment);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gboolean
|
|
Packit |
712bc5 |
is_current_doc_part_of_original_doc (DocNode *original,
|
|
Packit |
712bc5 |
xmlDocPtr current_doc)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlNodePtr current_node = current_doc->children->children;
|
|
Packit |
712bc5 |
xmlNodePtr this_node;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
/* No current node means that we want to add new elements to
|
|
Packit |
712bc5 |
the document. */
|
|
Packit |
712bc5 |
if (current_node == NULL)
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
this_node = xml_util_find_node (original->node, current_node);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (this_node == NULL)
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
for (current_node = current_node->next, this_node = this_node->next;
|
|
Packit |
712bc5 |
current_node != NULL && this_node != NULL;
|
|
Packit |
712bc5 |
current_node = current_node->next, this_node = this_node->next)
|
|
Packit |
712bc5 |
if (!xml_util_node_deep_equal (current_node, this_node))
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
GUPnPDIDLLiteFragmentResult
|
|
Packit |
712bc5 |
fragment_util_check_fragments (DocNode *original,
|
|
Packit |
712bc5 |
DocNode *modified,
|
|
Packit |
712bc5 |
const gchar *current_fragment,
|
|
Packit |
712bc5 |
const gchar *new_fragment,
|
|
Packit |
712bc5 |
XSDData *xsd_data)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
gchar *fixed_current_fragment = fix_fragment (current_fragment);
|
|
Packit |
712bc5 |
gchar *fixed_new_fragment = fix_fragment (new_fragment);
|
|
Packit |
712bc5 |
xmlDocPtr current_doc = xmlReadDoc (BAD_CAST (fixed_current_fragment),
|
|
Packit |
712bc5 |
NULL,
|
|
Packit |
712bc5 |
NULL,
|
|
Packit |
712bc5 |
XML_PARSE_NONET);
|
|
Packit |
712bc5 |
xmlDocPtr new_doc = xmlReadDoc (BAD_CAST (fixed_new_fragment),
|
|
Packit |
712bc5 |
NULL,
|
|
Packit |
712bc5 |
NULL,
|
|
Packit |
712bc5 |
XML_PARSE_NONET);
|
|
Packit |
712bc5 |
GUPnPDIDLLiteFragmentResult result;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (current_doc == NULL || current_doc->children == NULL) {
|
|
Packit |
712bc5 |
result = GUPNP_DIDL_LITE_FRAGMENT_RESULT_CURRENT_BAD_XML;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
goto out;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (new_doc == NULL || new_doc->children == NULL) {
|
|
Packit |
712bc5 |
result = GUPNP_DIDL_LITE_FRAGMENT_RESULT_NEW_BAD_XML;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
goto out;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
/* Assuming current_doc->children is non-NULL. */
|
|
Packit |
712bc5 |
if (current_doc->children->children != NULL) {
|
|
Packit |
712bc5 |
/* If the child element is title or class,
|
|
Packit |
712bc5 |
* it must not be set to empty or removed.
|
|
Packit |
712bc5 |
*/
|
|
Packit |
712bc5 |
if (g_strrstr ((char *) current_doc->children->children->name,
|
|
Packit |
712bc5 |
"title") != NULL ||
|
|
Packit |
712bc5 |
g_strrstr ((char *) current_doc->children->children->name,
|
|
Packit |
712bc5 |
"class") != NULL) {
|
|
Packit |
712bc5 |
/* If the new tag has no corresponding title or class element */
|
|
Packit |
712bc5 |
if (new_doc->children->children == NULL) {
|
|
Packit |
712bc5 |
result = GUPNP_DIDL_LITE_FRAGMENT_RESULT_REQUIRED_TAG;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
goto out;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
/* If the new tag has an empty value for title or class */
|
|
Packit |
712bc5 |
if (new_doc->children->children->children == NULL) {
|
|
Packit |
712bc5 |
result = GUPNP_DIDL_LITE_FRAGMENT_RESULT_REQUIRED_TAG;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
goto out;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (!is_current_doc_part_of_original_doc (original, current_doc)) {
|
|
Packit |
712bc5 |
result = GUPNP_DIDL_LITE_FRAGMENT_RESULT_CURRENT_INVALID;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
goto out;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
result = new_doc_is_valid_modification (modified,
|
|
Packit |
712bc5 |
current_doc,
|
|
Packit |
712bc5 |
new_doc,
|
|
Packit |
712bc5 |
xsd_data);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
out:
|
|
Packit |
712bc5 |
if (new_doc != NULL)
|
|
Packit |
712bc5 |
xmlFreeDoc (new_doc);
|
|
Packit |
712bc5 |
if (current_doc != NULL)
|
|
Packit |
712bc5 |
xmlFreeDoc (current_doc);
|
|
Packit |
712bc5 |
g_free (fixed_new_fragment);
|
|
Packit |
712bc5 |
g_free (fixed_current_fragment);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return result;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static const gchar *
|
|
Packit |
712bc5 |
get_data_dir (void)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
const gchar *datadir = g_getenv ("GUPNP_AV_DATADIR");
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (datadir == NULL)
|
|
Packit |
712bc5 |
/* that's a macro defined by -DDATADIR=foo */
|
|
Packit |
712bc5 |
datadir = DATADIR;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return datadir;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static gchar *
|
|
Packit |
712bc5 |
get_xsd_path (const gchar *path)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
return g_strdup_printf ("%s" G_DIR_SEPARATOR_S "%s",
|
|
Packit |
712bc5 |
get_data_dir (),
|
|
Packit |
712bc5 |
path);
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
static xmlParserInputPtr
|
|
Packit |
712bc5 |
our_own_loader (const char *url,
|
|
Packit |
712bc5 |
const char *id,
|
|
Packit |
712bc5 |
xmlParserCtxtPtr context)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
gchar *basename;
|
|
Packit |
712bc5 |
gchar *path;
|
|
Packit |
712bc5 |
xmlParserInputPtr input;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
g_debug ("URL: %s, ID: %s.", url, id);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
basename = g_path_get_basename (url);
|
|
Packit |
712bc5 |
path = get_xsd_path (basename);
|
|
Packit |
712bc5 |
g_debug ("BASENAME: %s, PATH: %s", basename, path);
|
|
Packit |
712bc5 |
input = xmlNewInputFromFile (context, path);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
g_free (basename);
|
|
Packit |
712bc5 |
g_free (path);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return input;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
XSDData *
|
|
Packit |
712bc5 |
fragment_util_get_didl_lite_xsd_data (void)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
gchar *path = get_xsd_path ("didl-lite-v2.xsd");
|
|
Packit |
712bc5 |
xmlExternalEntityLoader original_loader = xmlGetExternalEntityLoader ();
|
|
Packit |
712bc5 |
XSDData *xsd_data;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
xmlSetExternalEntityLoader (our_own_loader);
|
|
Packit |
712bc5 |
xsd_data = xsd_data_new (path);
|
|
Packit |
712bc5 |
xmlSetExternalEntityLoader (original_loader);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
g_free (path);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return xsd_data;
|
|
Packit |
712bc5 |
}
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
gboolean
|
|
Packit |
712bc5 |
fragment_util_apply_modification (xmlNodePtr *node_ptr,
|
|
Packit |
712bc5 |
DocNode *modified)
|
|
Packit |
712bc5 |
{
|
|
Packit |
712bc5 |
xmlNodePtr node_copy;
|
|
Packit |
712bc5 |
xmlNodePtr old;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (node_ptr == NULL || *node_ptr == NULL)
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
node_copy = xml_util_copy_node (modified->node);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (node_copy == NULL)
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
old = xmlReplaceNode (*node_ptr, node_copy);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
if (old == NULL)
|
|
Packit |
712bc5 |
return FALSE;
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
*node_ptr = node_copy;
|
|
Packit |
712bc5 |
xmlFreeNode (old);
|
|
Packit |
712bc5 |
|
|
Packit |
712bc5 |
return TRUE;
|
|
Packit |
712bc5 |
}
|