diff --git a/lasso/xml/private.h b/lasso/xml/private.h index 629d6ca5..b1ec0979 100644 --- a/lasso/xml/private.h +++ b/lasso/xml/private.h @@ -62,6 +62,7 @@ typedef enum { SNIPPET_ALLOW_TEXT = 1 << 26, /* allow text childs in list of nodes */ SNIPPET_KEEP_XMLNODE = 1 << 27, /* force keep xmlNode */ SNIPPET_PRIVATE = 1 << 28, /* means that the offset is relative to a private extension */ + SNIPPET_MANDATORY = 1 << 29, /* means that the element cardinality is at least 1 */ } SnippetType; typedef enum { diff --git a/lasso/xml/xml.c b/lasso/xml/xml.c index 753d8174..b7b29f95 100644 --- a/lasso/xml/xml.c +++ b/lasso/xml/xml.c @@ -1365,15 +1365,43 @@ is_snippet_type(struct XmlSnippet *snippet, SnippetType simple_type) { return (snippet->type & 0xff) == simple_type; } +static inline gboolean +is_snippet_mandatory(struct XmlSnippet *snippet) +{ + return snippet->type & SNIPPET_MANDATORY ? TRUE : FALSE; +} + +static inline gboolean +is_snippet_multiple(struct XmlSnippet *snippet) +{ + switch (snippet->type & 0xff) { + case SNIPPET_LIST_XMLNODES: + case SNIPPET_LIST_CONTENT: + case SNIPPET_LIST_NODES: + case SNIPPET_EXTENSION: + return TRUE; + default: + return FALSE; + } +} + static inline gboolean node_match_snippet(xmlNode *parent, xmlNode *node, struct XmlSnippet *snippet) { + gboolean rc = TRUE; + /* special case of ArtifactResponse */ - if (snippet->type & SNIPPET_ANY) + if (snippet->type & SNIPPET_ANY) { return TRUE; - return (lasso_strisequal(snippet->name, (char*)node->name) - && ((!snippet->ns_uri && lasso_equal_namespace(parent->ns, node->ns)) || - (node->ns && lasso_strisequal((char*)node->ns->href, snippet->ns_uri)))); + } else { + rc = rc && lasso_strisequal(snippet->name, (char*)node->name); + rc = rc && + ((!snippet->ns_uri && + lasso_equal_namespace(parent->ns, node->ns)) || + (node->ns && + lasso_strisequal((char*)node->ns->href, snippet->ns_uri))); + return rc; + } } /** FIXME: return a real error code */ @@ -1564,28 +1592,54 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) xmlNode *first_child = NULL; GList **list = NULL; xmlChar *content = NULL; + gboolean match = FALSE; + struct XmlSnippet *matched_snippet = NULL; - /* Find a matching snippet */ - while (class_iter && ! node_match_snippet(xmlnode, t, snippet)) { - snippet++; +#define ADVANCE \ + snippet++; \ next_node_snippet(&class_iter, &snippet); - } - if (! class_iter) { - /* If we cannot find one, terminate here. */ - break; - } - class = class_iter->data; - g_type = G_TYPE_FROM_CLASS(class); - value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet); - list = value; +#define ERROR \ + error("Element %s:%s cannot be parsed", \ + t->ns != NULL ? (char*)t->ns->prefix : "", \ + t->name); \ + rc = 1; \ + goto cleanup; + /* Find a matching snippet */ + while (class_iter && snippet) { + gboolean mandatory = is_snippet_mandatory(snippet); + gboolean multiple = is_snippet_multiple(snippet); - if (snippet->offset || (snippet->type & SNIPPET_PRIVATE)) { - switch (snippet->type & 0xff) { + if ((match = node_match_snippet(xmlnode, t, snippet))) { + matched_snippet = snippet; + class = class_iter->data; + g_type = G_TYPE_FROM_CLASS(class); + value = SNIPPET_STRUCT_MEMBER_P(node, g_type, snippet); + list = value; + if (! multiple) { + ADVANCE; + } + break; + } else { + if (mandatory) { + break; + } else { + ADVANCE; + } + } + } + if (! match) { + ERROR; + } +#undef ADVANCE +#undef ERROR + + if (matched_snippet->offset || (matched_snippet->type & SNIPPET_PRIVATE)) { + switch (matched_snippet->type & 0xff) { case SNIPPET_LIST_NODES: case SNIPPET_NODE: subnode = lasso_node_new_from_xmlNode_with_type(t, - snippet->class_name); - if (is_snippet_type(snippet, SNIPPET_NODE)) { + matched_snippet->class_name); + if (is_snippet_type(matched_snippet, SNIPPET_NODE)) { lasso_assign_new_gobject(*(LassoNode**)value, subnode); } else { lasso_list_add_new_gobject(*list, subnode); @@ -1595,7 +1649,7 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) first_child = xmlSecGetNextElementNode(t->children); if (first_child) { subnode = lasso_node_new_from_xmlNode_with_type(first_child, - snippet->class_name); + matched_snippet->class_name); lasso_assign_new_gobject(*(LassoNode**)value, subnode); } break; @@ -1609,8 +1663,8 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) case SNIPPET_CONTENT: case SNIPPET_LIST_CONTENT: content = xmlNodeGetContent(t); - if (is_snippet_type(snippet, SNIPPET_CONTENT)) { - snippet_set_value(node, class, snippet, content); + if (is_snippet_type(matched_snippet, SNIPPET_CONTENT)) { + snippet_set_value(node, class, matched_snippet, content); } else { /* only list of string-like xsd:type supported */ lasso_list_add_string(*list, (char*)content); } @@ -1626,22 +1680,9 @@ lasso_node_impl_init_from_xml(LassoNode *node, xmlNode *xmlnode) } /* When creating a new LassoNode and option KEEP_XMLNODE is present, * we attached the xmlNode to the LassoNode */ - if (subnode && (snippet->type & SNIPPET_KEEP_XMLNODE)) { + if (subnode && (matched_snippet->type & SNIPPET_KEEP_XMLNODE)) { lasso_node_set_original_xmlnode(subnode, t); } - switch (snippet->type & 0xff) { - case SNIPPET_NODE: - case SNIPPET_NODE_IN_CHILD: - case SNIPPET_XMLNODE: - case SNIPPET_CONTENT: - case SNIPPET_SIGNATURE: - /* Only one node to read, advance ! */ - ++snippet; - next_node_snippet(&class_iter, &snippet); - break; - default: - break; - } } else { g_assert_not_reached(); } @@ -2797,6 +2838,7 @@ lasso_node_build_xmlNode_from_snippets(LassoNode *node, LassoNodeClass *class, x case SNIPPET_ANY: case SNIPPET_KEEP_XMLNODE: case SNIPPET_PRIVATE: + case SNIPPET_MANDATORY: case SNIPPET_UNUSED1: g_assert_not_reached(); } diff --git a/tests/basic_tests.c b/tests/basic_tests.c index 78c70d7b..e4b6920d 100644 --- a/tests/basic_tests.c +++ b/tests/basic_tests.c @@ -137,6 +137,22 @@ START_TEST(test07_registry_functional_mapping) } END_TEST +static struct XmlSnippet schema_snippets[] = { + {NULL, 0, 0, NULL, NULL, NULL} +}; + +static void +class_init(LassoNodeClass *klass) +{ + LassoNodeClass *nclass = LASSO_NODE_CLASS(klass); + + nclass->node_data = g_new0(LassoNodeClassData, 1); + lasso_node_class_set_nodename(nclass, "Assertion"); + lasso_node_class_set_ns(nclass,LASSO_SAML2_ASSERTION_HREF, LASSO_SAML2_ASSERTION_PREFIX); + lasso_node_class_add_snippets(nclass, schema_snippets); + +} + START_TEST(test08_test_new_from_xmlNode) { static GType this_type = 0; @@ -147,7 +163,7 @@ START_TEST(test08_test_new_from_xmlNode) sizeof (LassoNodeClass), NULL, NULL, - NULL, + (GClassInitFunc) class_init, NULL, NULL, sizeof(LassoNode),