Add support for CHOICE in ASN.1 encoder
authorGreg Hudson <ghudson@mit.edu>
Fri, 6 Jan 2012 21:13:59 +0000 (21:13 +0000)
committerGreg Hudson <ghudson@mit.edu>
Fri, 6 Jan 2012 21:13:59 +0000 (21:13 +0000)
Add a new field type where the length offset indicates a distinguisher
and the data offset indicates a union address.  The field's type is an
atype_choice containing a seq_info indexed by the distinguisher.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25616 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/asn.1/asn1_encode.c
src/lib/krb5/asn.1/asn1_encode.h

index 5fc1efdfd35c31146d92ba508d6e637045a90998..e654b728668405707e9e98815cc79a1fba9d6603 100644 (file)
@@ -504,6 +504,24 @@ encode_a_field(asn1buf *buf, const void *val, const struct field_info *field,
             assert(omit_tag == NULL && !field->tag_implicit);
         break;
     }
+    case field_choice:
+    {
+        const void *dataptr = (const char *)val + field->dataoff;
+        unsigned int choice;
+        const struct seq_info *seq;
+
+        assert(omit_tag == NULL);
+        assert(field->atype->type == atype_choice);
+        seq = field->atype->tinfo;
+        retval = get_field_len(val, field, &choice);
+        if (retval)
+            return retval;
+        if (choice > seq->n_fields)
+            return ASN1_MISSING_FIELD;
+        retval = encode_a_field(buf, dataptr, &seq->fields[choice], &length,
+                                NULL);
+        break;
+    }
     default:
         assert(field->ftype > field_min);
         assert(field->ftype < field_max);
index 85e4861a53af0f1f6cd670fdd1970b7481f471ae..c1486d2be0284855f83e64a9d0346a8390e4049b 100644 (file)
@@ -193,6 +193,12 @@ enum atype_type {
     atype_ptr,
     /* Sequence.  tinfo is a struct seq_info *. */
     atype_sequence,
+    /*
+     * Choice.  tinfo is a struct seq_info *, with the optional field ignored.
+     * Only usable with the field_choice field type.  Cannot be used with an
+     * implicit context tag.
+     */
+    atype_choice,
     /*
      * Sequence-of, with pointer to base type descriptor, represented
      * as a null-terminated array of pointers (and thus the "base"
@@ -383,6 +389,15 @@ struct uint_info {
     const struct atype_info krb5int_asn1type_##DESCNAME = {             \
         atype_sequence, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME      \
     }
+/* A choice, selected from the indicated series of fields. */
+#define DEFCHOICETYPE(DESCNAME, CTYPENAME, FIELDS)                      \
+    typedef CTYPENAME aux_typedefname_##DESCNAME;                       \
+    static const struct seq_info aux_seqinfo_##DESCNAME = {             \
+        NULL, FIELDS, sizeof(FIELDS)/sizeof(FIELDS[0])                  \
+    };                                                                  \
+    const struct atype_info krb5int_asn1type_##DESCNAME = {             \
+        atype_choice, sizeof(CTYPENAME), &aux_seqinfo_##DESCNAME        \
+    }
 /* Integer types.  */
 #define DEFINTTYPE(DESCNAME, CTYPENAME)                                 \
     typedef CTYPENAME aux_typedefname_##DESCNAME;                       \
@@ -574,6 +589,12 @@ enum field_type {
      * described by ATYPE.
      */
     field_sequenceof_len,
+    /*
+     * LENOFF indicates a distinguisher and DATAOFF indicates a union base
+     * address.  ATYPE is an atype_choice type pointing to a seq_info
+     * containing a field type for each choice element.
+     */
+    field_choice,
     /* Unused except for range checking.  */
     field_max
 };
@@ -711,6 +732,17 @@ struct field_info {
 #define FIELDOF_SEQOF_INT32(STYPE,DESC,PTRFIELD,LENFIELD,TAG,IMPLICIT)  \
     FIELDOF_SEQOF_LEN(STYPE,DESC,PTRFIELD,LENFIELD,int32,TAG,IMPLICIT)
 
+#define FIELDOF_OPTCHOICE(STYPE,DESC,PTRFIELD,CHOICEFIELD,LENTYPE,TAG,OPT) \
+    { \
+        field_choice,                                                   \
+            OFFOF(STYPE, PTRFIELD, aux_typedefname_##DESC),             \
+            OFFOF(STYPE, CHOICEFIELD, aux_typedefname_##LENTYPE),       \
+            TAG, 0, OPT,                                                \
+            &krb5int_asn1type_##DESC, &krb5int_asn1type_##LENTYPE       \
+            }
+#define FIELDOF_CHOICE(STYPE,DESC,PTRFIELD,CHOICEFIELD,LENTYPE,TAG)     \
+    FIELDOF_OPTCHOICE(STYPE,DESC,PTRFIELD,CHOICEFIELD,LENTYPE,TAG,-1)
+
 struct seq_info {
     /*
      * If present, returns a bitmask indicating which fields are