[gnome-keyring/trust-store: 102/105] [egg] Must select which choice when building ASN.1.



commit ac64040c2de1b78f26d1c289f09dfcb2a5c5461b
Author: Stef Walter <stefw collabora co uk>
Date:   Tue Nov 23 02:04:18 2010 +0000

    [egg] Must select which choice when building ASN.1.
    
    When building up ASN.1 must select which choice by using
    the egg_asn1x_set_choice() function.

 egg/egg-asn1x.c       |  151 +++++++++++++++++++++++++++++++------------------
 egg/egg-asn1x.h       |    3 +
 egg/tests/test-asn1.c |   56 ++++++++++++++++++
 3 files changed, 154 insertions(+), 56 deletions(-)
---
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index f8c95a6..ce1be8b 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -131,11 +131,16 @@ struct _Anode {
 	const ASN1_ARRAY_TYPE *def;
 	const ASN1_ARRAY_TYPE *join;
 	GList *opts;
+
 	Atlv *tlv;
 	Aenc *enc;
+
 	gpointer user_data;
 	GDestroyNotify destroy;
+
 	gchar* failure;
+
+	gint chosen : 1;
 };
 
 struct _Abuf {
@@ -822,14 +827,24 @@ anode_decode_tlv_for_contents (Atlv *outer, gboolean first, Atlv *tlv)
 static gboolean
 anode_decode_choice (GNode *node, Atlv *tlv)
 {
+	gboolean have = FALSE;
 	GNode *child;
+	Anode *an;
 
 	for (child = node->children; child; child = child->next) {
-		if (anode_decode_anything (child, tlv))
-			return TRUE;
+		an = (Anode*)child->data;
+		if (!have && anode_decode_anything (child, tlv)) {
+			an->chosen = 1;
+			have = TRUE;
+		} else {
+			an->chosen = 0;
+		}
 	}
 
-	return anode_failure (node, "no choice is present");
+	if (!have)
+		return anode_failure (node, "no choice is present");
+
+	return TRUE;
 }
 
 static gboolean
@@ -1150,21 +1165,6 @@ egg_asn1x_decode (GNode *asn, gconstpointer data, gsize n_data)
  * ENCODING
  */
 
-static GNode*
-find_chosen_with_tlv_for_choice (GNode *node)
-{
-	GNode *child;
-
-	g_assert (anode_def_type (node) == TYPE_CHOICE);
-
-	for (child = node->children; child; child = child->next) {
-		if (anode_get_tlv_data (child) != NULL)
-			return child;
-	}
-
-	return NULL;
-}
-
 static void
 anode_encode_length (gulong len, guchar *ans, gint *cb)
 {
@@ -1335,7 +1335,7 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
 
 	/* If it's a choice node, use the choice for calculations */
 	if (type == TYPE_CHOICE) {
-		node = find_chosen_with_tlv_for_choice (node);
+		node = egg_asn1x_get_choice (node);
 		g_return_val_if_fail (node, FALSE);
 	}
 
@@ -1507,7 +1507,7 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
 	tlv = anode_get_tlv_data (node);
 	g_return_val_if_fail (tlv, FALSE);
 
-	child = find_chosen_with_tlv_for_choice (node);
+	child = egg_asn1x_get_choice (node);
 	g_return_val_if_fail (child, FALSE);
 
 	ctlv = anode_get_tlv_data (child);
@@ -1574,48 +1574,53 @@ anode_encode_prepare_simple (GNode *node)
 }
 
 static gboolean
+anode_encode_prepare_choice (GNode *node)
+{
+	Atlv *tlv;
+	GNode *child;
+	gint type;
+
+	type = anode_def_type (node);
+	g_assert (type == TYPE_CHOICE);
+
+	child = egg_asn1x_get_choice (node);
+	if (!child)
+		return FALSE;
+
+	if (!anode_encode_prepare (child))
+		return FALSE;
+
+	tlv = anode_get_tlv_data (child);
+	g_return_val_if_fail (tlv, FALSE);
+	anode_clr_tlv_data (node);
+	anode_set_tlv_data (node, tlv);
+	anode_set_enc_data (node, anode_encoder_choice, node);
+
+	return TRUE;
+
+}
+
+static gboolean
 anode_encode_prepare_structured (GNode *node)
 {
 	gsize length = 0;
-	gboolean had;
 	Atlv *tlv;
 	GNode *child;
 	gint type;
 
 	type = anode_def_type (node);
 
-	had = FALSE;
 	length = 0;
 
 	for (child = node->children; child; child = child->next) {
 		if (anode_encode_prepare (child)) {
 			tlv = anode_get_tlv_data (child);
-			had = TRUE;
-			g_return_val_if_fail (tlv, had);
-			length += tlv->off + tlv->len;
-			if (type == TYPE_CHOICE)
-				break;
-		}
-	}
-
-	if (!had)
-		return FALSE;
-
-	/* Choice type, take over the child's encoding */
-	if (type == TYPE_CHOICE) {
-		if (child) {
-			tlv = anode_get_tlv_data (child);
 			g_return_val_if_fail (tlv, FALSE);
-			anode_clr_tlv_data (node);
-			anode_set_tlv_data (node, tlv);
-			anode_set_enc_data (node, anode_encoder_choice, node);
+			length += tlv->off + tlv->len;
 		}
-
-	/* Other container types */
-	} else {
-		anode_encode_tlv_and_enc (node, length, anode_encoder_structured, node, NULL);
 	}
 
+	anode_encode_tlv_and_enc (node, length, anode_encoder_structured, node, NULL);
 	return TRUE;
 }
 
@@ -1638,9 +1643,11 @@ anode_encode_prepare (GNode *node)
 	case TYPE_SEQUENCE_OF:
 	case TYPE_SET:
 	case TYPE_SET_OF:
-	case TYPE_CHOICE:
 		return anode_encode_prepare_structured (node);
 		break;
+	case TYPE_CHOICE:
+		return anode_encode_prepare_choice (node);
+		break;
 	default:
 		g_return_val_if_reached (FALSE);
 	};
@@ -1660,8 +1667,10 @@ egg_asn1x_encode (GNode *asn, EggAllocator allocator, gsize *n_data)
 	if (!allocator)
 		allocator = g_realloc;
 
-	if (!anode_encode_prepare (asn))
+	if (!anode_encode_prepare (asn)) {
+		anode_failure (asn, "missing value(s)");
 		return NULL;
+	}
 
 	/* We must sort all the nasty SET OF nodes */
 	g_node_traverse (asn, G_POST_ORDER, G_TRAVERSE_ALL, -1,
@@ -3061,18 +3070,45 @@ GNode*
 egg_asn1x_get_choice (GNode *node)
 {
 	GNode *child;
+	Anode *an;
 
 	g_return_val_if_fail (node, NULL);
 
 	/* One and only one of the children must be set */
 	for (child = node->children; child; child = child->next) {
-		if (anode_get_tlv_data (child))
+		an = (Anode*)child->data;
+		if (an->chosen)
 			return child;
 	}
 
 	return NULL;
 }
 
+gboolean
+egg_asn1x_set_choice (GNode *node, GNode *choice)
+{
+	GNode *child;
+	Anode *an;
+
+	g_return_val_if_fail (node, FALSE);
+
+	/* One and only one of the children must be set */
+	for (child = node->children; child; child = child->next) {
+		an = (Anode*)child->data;
+		if (child == choice) {
+			an->chosen = 1;
+			choice = NULL;
+		} else {
+			an->chosen = 0;
+		}
+	}
+
+	/* The choice is not one of the child nodes */
+	g_return_val_if_fail (!choice, FALSE);
+
+	return TRUE;
+}
+
 /* -----------------------------------------------------------------------------------
  * VALIDATION
  */
@@ -3249,22 +3285,25 @@ anode_validate_time (GNode *node, Atlv *tlv)
 static gboolean
 anode_validate_choice (GNode *node)
 {
-	gboolean have = FALSE;
-	GNode *child;
+	GNode *child, *choice;
+	Anode *an;
 
 	/* One and only one of the children must be set */
+	choice = egg_asn1x_get_choice (node);
+	if (!choice)
+		return anode_failure (node, "one choice must be set");
+
+	if (!anode_validate_anything (choice))
+		return FALSE;
+
 	for (child = node->children; child; child = child->next) {
-		if (anode_get_tlv_data (child)) {
-			if (have)
+		if (child != choice) {
+			an = (Anode*)child->data;
+			if (an->chosen)
 				return anode_failure (node, "only one choice may be set");
-			have = TRUE;
-			if (!anode_validate_anything (child))
-				return FALSE;
 		}
 	}
 
-	if (!have)
-		return anode_failure (node, "one choice must be set");
 	return TRUE;
 }
 
diff --git a/egg/egg-asn1x.h b/egg/egg-asn1x.h
index 197826a..21029ef 100644
--- a/egg/egg-asn1x.h
+++ b/egg/egg-asn1x.h
@@ -75,6 +75,9 @@ gboolean            egg_asn1x_have                   (GNode *node);
 
 GNode*              egg_asn1x_get_choice             (GNode *node);
 
+gboolean            egg_asn1x_set_choice             (GNode *node,
+                                                      GNode *choice);
+
 gboolean            egg_asn1x_get_boolean            (GNode *node,
                                                       gboolean *value);
 
diff --git a/egg/tests/test-asn1.c b/egg/tests/test-asn1.c
index 758b62f..460b76c 100644
--- a/egg/tests/test-asn1.c
+++ b/egg/tests/test-asn1.c
@@ -465,6 +465,30 @@ DEFINE_TEST(asn1_any_set_raw_explicit)
 	g_assert (is_freed);
 }
 
+DEFINE_TEST(asn1_choice_not_chosen)
+{
+	GNode *asn, *node;
+	guchar *data;
+	gsize n_data;
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestAnyChoice");
+	g_assert (asn);
+
+	node = egg_asn1x_node (asn, "choiceShortTag", NULL);
+	g_assert (node);
+
+	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), NULL))
+		g_assert_not_reached ();
+
+	/* egg_asn1x_set_choice() was not called */
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	g_assert (!data);
+	g_assert (egg_asn1x_message (asn));
+	g_assert (strstr (egg_asn1x_message (asn), "TestAnyChoice") != NULL);
+
+	egg_asn1x_destroy (asn);
+}
+
 static void
 perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsize n_encoding)
 {
@@ -480,10 +504,17 @@ perform_asn1_any_choice_set_raw (const gchar *choice, const gchar *encoding, gsi
 	node = egg_asn1x_node (asn, choice, NULL);
 	g_assert (node);
 
+	if (!egg_asn1x_set_choice (asn, node))
+		g_assert_not_reached ();
+
 	if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
 		g_assert_not_reached ();
 
 	data = egg_asn1x_encode (asn, NULL, &n_data);
+	if (!data) {
+		g_printerr ("%s\n", egg_asn1x_message (asn));
+		g_assert_not_reached ();
+	}
 	g_assert (data);
 
 	g_assert_cmpsize (n_data, ==, n_encoding);
@@ -611,6 +642,31 @@ DEFINE_TEST(asn1_setof)
 	egg_asn1x_destroy (asn);
 }
 
+DEFINE_TEST(asn1_setof_empty)
+{
+	GNode *asn;
+	gpointer data;
+	gsize n_data;
+
+	/* SEQUENCE OF with nothing */
+	const gchar SETOF_NONE[] =  "\x31\x00";
+
+	asn = egg_asn1x_create (test_asn1_tab, "TestSetOf");
+	g_assert (asn);
+
+	data = egg_asn1x_encode (asn, NULL, &n_data);
+	if (!data) {
+		g_printerr ("%s\n", egg_asn1x_message (asn));
+		g_assert_not_reached ();
+	}
+
+	g_assert (n_data == XL (SETOF_NONE));
+	g_assert (memcmp (data, SETOF_NONE, n_data) == 0);
+
+	g_free (data);
+	egg_asn1x_destroy (asn);
+}
+
 DEFINE_TEST (asn1_enumerated)
 {
 	GNode *asn;



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