]> git.stg.codes - stg.git/blob - libs/smux/constr_CHOICE.c
Merge remote-tracking branch 'github/master'
[stg.git] / libs / smux / constr_CHOICE.c
1 /*
2  * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 #include <asn_internal.h>
6 #include <constr_CHOICE.h>
7 #include <per_opentype.h>
8
9 /*
10  * Number of bytes left for this structure.
11  * (ctx->left) indicates the number of bytes _transferred_ for the structure.
12  * (size) contains the number of bytes in the buffer passed.
13  */
14 #define LEFT    ((size<(size_t)ctx->left)?size:(size_t)ctx->left)
15
16 /*
17  * If the subprocessor function returns with an indication that it wants
18  * more data, it may well be a fatal decoding problem, because the
19  * size is constrained by the <TLV>'s L, even if the buffer size allows
20  * reading more data.
21  * For example, consider the buffer containing the following TLVs:
22  * <T:5><L:1><V> <T:6>...
23  * The TLV length clearly indicates that one byte is expected in V, but
24  * if the V processor returns with "want more data" even if the buffer
25  * contains way more data than the V processor have seen.
26  */
27 #define SIZE_VIOLATION  (ctx->left >= 0 && (size_t)ctx->left <= size)
28
29 /*
30  * This macro "eats" the part of the buffer which is definitely "consumed",
31  * i.e. was correctly converted into local representation or rightfully skipped.
32  */
33 #undef  ADVANCE
34 #define ADVANCE(num_bytes)      do {            \
35                 size_t num = num_bytes;         \
36                 ptr = ((const char *)ptr) + num;\
37                 size -= num;                    \
38                 if(ctx->left >= 0)              \
39                         ctx->left -= num;       \
40                 consumed_myself += num;         \
41         } while(0)
42
43 /*
44  * Switch to the next phase of parsing.
45  */
46 #undef  NEXT_PHASE
47 #define NEXT_PHASE(ctx) do {                    \
48                 ctx->phase++;                   \
49                 ctx->step = 0;                  \
50         } while(0)
51
52 /*
53  * Return a standardized complex structure.
54  */
55 #undef  RETURN
56 #define RETURN(_code)   do {                    \
57                 rval.code = _code;              \
58                 rval.consumed = consumed_myself;\
59                 return rval;                    \
60         } while(0)
61
62 /*
63  * See the definitions.
64  */
65 static unsigned _fetch_present_idx(const void *struct_ptr, unsigned off,
66                                    unsigned size);
67 static void _set_present_idx(void *sptr, unsigned offset, unsigned size,
68                              unsigned pres);
69 static const void *_get_member_ptr(const asn_TYPE_descriptor_t *,
70                                    const void *sptr, asn_TYPE_member_t **elm,
71                                    unsigned *present);
72
73 /*
74  * Tags are canonically sorted in the tag to member table.
75  */
76 static int
77 _search4tag(const void *ap, const void *bp) {
78         const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap;
79         const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp;
80
81         int a_class = BER_TAG_CLASS(a->el_tag);
82         int b_class = BER_TAG_CLASS(b->el_tag);
83
84         if(a_class == b_class) {
85                 ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
86                 ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
87
88                 if(a_value == b_value)
89                         return 0;
90                 else if(a_value < b_value)
91                         return -1;
92                 else
93                         return 1;
94         } else if(a_class < b_class) {
95                 return -1;
96         } else {
97                 return 1;
98         }
99 }
100
101 /*
102  * The decoder of the CHOICE type.
103  */
104 asn_dec_rval_t
105 CHOICE_decode_ber(const asn_codec_ctx_t *opt_codec_ctx,
106                   const asn_TYPE_descriptor_t *td, void **struct_ptr,
107                   const void *ptr, size_t size, int tag_mode) {
108     /*
109          * Bring closer parts of structure description.
110          */
111         const asn_CHOICE_specifics_t *specs =
112                 (const asn_CHOICE_specifics_t *)td->specifics;
113         asn_TYPE_member_t *elements = td->elements;
114
115         /*
116          * Parts of the structure being constructed.
117          */
118         void *st = *struct_ptr; /* Target structure. */
119         asn_struct_ctx_t *ctx;  /* Decoder context */
120
121         ber_tlv_tag_t tlv_tag;  /* T from TLV */
122         ssize_t tag_len;        /* Length of TLV's T */
123         asn_dec_rval_t rval;    /* Return code from subparsers */
124
125         ssize_t consumed_myself = 0;    /* Consumed bytes from ptr */
126
127         ASN_DEBUG("Decoding %s as CHOICE", td->name);
128
129         /*
130          * Create the target structure if it is not present already.
131          */
132         if(st == 0) {
133                 st = *struct_ptr = CALLOC(1, specs->struct_size);
134                 if(st == 0) {
135                         RETURN(RC_FAIL);
136                 }
137         }
138
139         /*
140          * Restore parsing context.
141          */
142         ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
143         
144         /*
145          * Start to parse where left previously
146          */
147         switch(ctx->phase) {
148         case 0:
149                 /*
150                  * PHASE 0.
151                  * Check that the set of tags associated with given structure
152                  * perfectly fits our expectations.
153                  */
154
155                 if(tag_mode || td->tags_count) {
156                         rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size,
157                                 tag_mode, -1, &ctx->left, 0);
158                         if(rval.code != RC_OK) {
159                                 ASN_DEBUG("%s tagging check failed: %d",
160                                         td->name, rval.code);
161                                 return rval;
162                         }
163
164                         if(ctx->left >= 0) {
165                                 /* ?Substracted below! */
166                                 ctx->left += rval.consumed;
167                         }
168                         ADVANCE(rval.consumed);
169                 } else {
170                         ctx->left = -1;
171                 }
172
173                 NEXT_PHASE(ctx);
174
175                 ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
176                         (long)ctx->left, (long)size);
177
178                 /* Fall through */
179         case 1:
180                 /*
181                  * Fetch the T from TLV.
182                  */
183                 tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
184                 ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len);
185                 switch(tag_len) {
186                 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
187                         /* Fall through */
188                 case -1: RETURN(RC_FAIL);
189                 }
190
191                 do {
192                         const asn_TYPE_tag2member_t *t2m;
193                         asn_TYPE_tag2member_t key;
194
195                         key.el_tag = tlv_tag;
196                         t2m = (const asn_TYPE_tag2member_t *)bsearch(&key,
197                                         specs->tag2el, specs->tag2el_count,
198                                         sizeof(specs->tag2el[0]), _search4tag);
199                         if(t2m) {
200                                 /*
201                                  * Found the element corresponding to the tag.
202                                  */
203                                 NEXT_PHASE(ctx);
204                                 ctx->step = t2m->el_no;
205                                 break;
206                         } else if(specs->ext_start == -1) {
207                                 ASN_DEBUG("Unexpected tag %s "
208                                         "in non-extensible CHOICE %s",
209                                         ber_tlv_tag_string(tlv_tag), td->name);
210                                 RETURN(RC_FAIL);
211                         } else {
212                                 /* Skip this tag */
213                                 ssize_t skip;
214
215                                 ASN_DEBUG("Skipping unknown tag %s",
216                                         ber_tlv_tag_string(tlv_tag));
217
218                                 skip = ber_skip_length(opt_codec_ctx,
219                                         BER_TLV_CONSTRUCTED(ptr),
220                                         (const char *)ptr + tag_len,
221                                         LEFT - tag_len);
222
223                                 switch(skip) {
224                                 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
225                                         /* Fall through */
226                                 case -1: RETURN(RC_FAIL);
227                                 }
228
229                                 ADVANCE(skip + tag_len);
230                                 RETURN(RC_OK);
231                         }
232                 } while(0);
233
234         case 2:
235                 /*
236                  * PHASE 2.
237                  * Read in the element.
238                  */
239             do {
240                 asn_TYPE_member_t *elm;/* CHOICE's element */
241                 void *memb_ptr;         /* Pointer to the member */
242                 void **memb_ptr2;       /* Pointer to that pointer */
243
244                 elm = &elements[ctx->step];
245
246                 /*
247                  * Compute the position of the member inside a structure,
248                  * and also a type of containment (it may be contained
249                  * as pointer or using inline inclusion).
250                  */
251                 if(elm->flags & ATF_POINTER) {
252                         /* Member is a pointer to another structure */
253                         memb_ptr2 = (void **)((char *)st + elm->memb_offset);
254                 } else {
255                         /*
256                          * A pointer to a pointer
257                          * holding the start of the structure
258                          */
259                         memb_ptr = (char *)st + elm->memb_offset;
260                         memb_ptr2 = &memb_ptr;
261                 }
262                 /* Set presence to be able to free it properly at any time */
263                 _set_present_idx(st, specs->pres_offset,
264                                 specs->pres_size, ctx->step + 1);
265                 /*
266                  * Invoke the member fetch routine according to member's type
267                  */
268                 rval = elm->type->op->ber_decoder(opt_codec_ctx, elm->type,
269                                 memb_ptr2, ptr, LEFT, elm->tag_mode);
270                 switch(rval.code) {
271                 case RC_OK:
272                         break;
273                 case RC_WMORE: /* More data expected */
274                         if(!SIZE_VIOLATION) {
275                                 ADVANCE(rval.consumed);
276                                 RETURN(RC_WMORE);
277                         }
278                         RETURN(RC_FAIL);
279                 case RC_FAIL: /* Fatal error */
280                         RETURN(rval.code);
281                 } /* switch(rval) */
282                 
283                 ADVANCE(rval.consumed);
284           } while(0);
285
286                 NEXT_PHASE(ctx);
287
288                 /* Fall through */
289         case 3:
290                 ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
291                         td->name, (long)ctx->left, (long)size,
292                         tag_mode, td->tags_count);
293
294                 if(ctx->left > 0) {
295                         /*
296                          * The type must be fully decoded
297                          * by the CHOICE member-specific decoder.
298                          */
299                         RETURN(RC_FAIL);
300                 }
301
302                 if(ctx->left == -1
303                 && !(tag_mode || td->tags_count)) {
304                         /*
305                          * This is an untagged CHOICE.
306                          * It doesn't contain nothing
307                          * except for the member itself, including all its tags.
308                          * The decoding is completed.
309                          */
310                         NEXT_PHASE(ctx);
311                         break;
312                 }
313
314                 /*
315                  * Read in the "end of data chunks"'s.
316                  */
317                 while(ctx->left < 0) {
318                         ssize_t tl;
319
320                         tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
321                         switch(tl) {
322                         case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
323                                 /* Fall through */
324                         case -1: RETURN(RC_FAIL);
325                         }
326
327                         /*
328                          * Expected <0><0>...
329                          */
330                         if(((const uint8_t *)ptr)[0] == 0) {
331                                 if(LEFT < 2) {
332                                         if(SIZE_VIOLATION)
333                                                 RETURN(RC_FAIL);
334                                         else
335                                                 RETURN(RC_WMORE);
336                                 } else if(((const uint8_t *)ptr)[1] == 0) {
337                                         /*
338                                          * Correctly finished with <0><0>.
339                                          */
340                                         ADVANCE(2);
341                                         ctx->left++;
342                                         continue;
343                                 }
344                         } else {
345                                 ASN_DEBUG("Unexpected continuation in %s",
346                                         td->name);
347                                 RETURN(RC_FAIL);
348                         }
349
350                         /* UNREACHABLE */
351                 }
352
353                 NEXT_PHASE(ctx);
354         case 4:
355                 /* No meaningful work here */
356                 break;
357         }
358         
359         RETURN(RC_OK);
360 }
361
362 asn_enc_rval_t
363 CHOICE_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr,
364                   int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb,
365                   void *app_key) {
366     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
367         asn_TYPE_member_t *elm; /* CHOICE element */
368         asn_enc_rval_t erval;
369         const void *memb_ptr;
370         size_t computed_size = 0;
371         unsigned present;
372
373         if(!sptr) ASN__ENCODE_FAILED;
374
375         ASN_DEBUG("%s %s as CHOICE",
376                 cb?"Encoding":"Estimating", td->name);
377
378         present = _fetch_present_idx(sptr,
379                 specs->pres_offset, specs->pres_size);
380
381         /*
382          * If the structure was not initialized, it cannot be encoded:
383          * can't deduce what to encode in the choice type.
384          */
385         if(present == 0 || present > td->elements_count) {
386                 if(present == 0 && td->elements_count == 0) {
387                         /* The CHOICE is empty?! */
388                         erval.encoded = 0;
389                         ASN__ENCODED_OK(erval);
390                 }
391                 ASN__ENCODE_FAILED;
392         }
393
394         /*
395          * Seek over the present member of the structure.
396          */
397         elm = &td->elements[present-1];
398         if(elm->flags & ATF_POINTER) {
399         memb_ptr =
400             *(const void *const *)((const char *)sptr + elm->memb_offset);
401         if(memb_ptr == 0) {
402                         if(elm->optional) {
403                                 erval.encoded = 0;
404                                 ASN__ENCODED_OK(erval);
405                         }
406                         /* Mandatory element absent */
407                         ASN__ENCODE_FAILED;
408                 }
409         } else {
410         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
411     }
412
413         /*
414          * If the CHOICE itself is tagged EXPLICIT:
415          * T ::= [2] EXPLICIT CHOICE { ... }
416          * Then emit the appropriate tags.
417          */
418         if(tag_mode == 1 || td->tags_count) {
419                 /*
420                  * For this, we need to pre-compute the member.
421                  */
422                 ssize_t ret;
423
424                 /* Encode member with its tag */
425                 erval = elm->type->op->der_encoder(elm->type, memb_ptr,
426                         elm->tag_mode, elm->tag, 0, 0);
427                 if(erval.encoded == -1)
428                         return erval;
429
430                 /* Encode CHOICE with parent or my own tag */
431                 ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag,
432                         cb, app_key);
433                 if(ret == -1)
434                         ASN__ENCODE_FAILED;
435                 computed_size += ret;
436         }
437
438         /*
439          * Encode the single underlying member.
440          */
441         erval = elm->type->op->der_encoder(elm->type, memb_ptr,
442                 elm->tag_mode, elm->tag, cb, app_key);
443         if(erval.encoded == -1)
444                 return erval;
445
446         ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
447                 (long)erval.encoded, (long)computed_size);
448
449         erval.encoded += computed_size;
450
451         return erval;
452 }
453
454 ber_tlv_tag_t
455 CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
456         const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
457         unsigned present;
458
459         assert(tag_mode == 0); (void)tag_mode;
460         assert(tag == 0); (void)tag;
461
462         /*
463          * Figure out which CHOICE element is encoded.
464          */
465         present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
466
467         if(present > 0 && present <= td->elements_count) {
468                 const asn_TYPE_member_t *elm = &td->elements[present-1];
469                 const void *memb_ptr;
470
471                 if(elm->flags & ATF_POINTER) {
472                         memb_ptr = *(const void * const *)
473                                         ((const char *)ptr + elm->memb_offset);
474                 } else {
475                         memb_ptr = (const void *)
476                                         ((const char *)ptr + elm->memb_offset);
477                 }
478
479                 return asn_TYPE_outmost_tag(elm->type, memb_ptr,
480                         elm->tag_mode, elm->tag);
481         } else {
482                 return (ber_tlv_tag_t)-1;
483         }
484 }
485
486 int
487 CHOICE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
488                   asn_app_constraint_failed_f *ctfailcb, void *app_key) {
489     const asn_CHOICE_specifics_t *specs =
490         (const asn_CHOICE_specifics_t *)td->specifics;
491     unsigned present;
492
493         if(!sptr) {
494                 ASN__CTFAIL(app_key, td, sptr,
495                         "%s: value not given (%s:%d)",
496                         td->name, __FILE__, __LINE__);
497                 return -1;
498         }
499
500         /*
501          * Figure out which CHOICE element is encoded.
502          */
503         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
504         if(present > 0 && present <= td->elements_count) {
505                 asn_TYPE_member_t *elm = &td->elements[present-1];
506                 const void *memb_ptr;
507
508                 if(elm->flags & ATF_POINTER) {
509                         memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
510                         if(!memb_ptr) {
511                                 if(elm->optional)
512                                         return 0;
513                                 ASN__CTFAIL(app_key, td, sptr,
514                                         "%s: mandatory CHOICE element %s absent (%s:%d)",
515                                         td->name, elm->name, __FILE__, __LINE__);
516                                 return -1;
517                         }
518                 } else {
519                         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
520                 }
521
522                 if(elm->encoding_constraints.general_constraints) {
523                         return elm->encoding_constraints.general_constraints(elm->type, memb_ptr,
524                                 ctfailcb, app_key);
525                 } else {
526                         return elm->type->encoding_constraints.general_constraints(elm->type,
527                                         memb_ptr, ctfailcb, app_key);
528                 }
529         } else {
530                 ASN__CTFAIL(app_key, td, sptr,
531                         "%s: no CHOICE element given (%s:%d)",
532                         td->name, __FILE__, __LINE__);
533                 return -1;
534         }
535 }
536
537 #undef  XER_ADVANCE
538 #define XER_ADVANCE(num_bytes)  do {                    \
539                 size_t num = num_bytes;                 \
540                 buf_ptr = (const void *)(((const char *)buf_ptr) + num); \
541                 size -= num;                            \
542                 consumed_myself += num;                 \
543         } while(0)
544
545 /*
546  * Decode the XER (XML) data.
547  */
548 asn_dec_rval_t
549 CHOICE_decode_xer(const asn_codec_ctx_t *opt_codec_ctx,
550                   const asn_TYPE_descriptor_t *td, void **struct_ptr,
551                   const char *opt_mname, const void *buf_ptr, size_t size) {
552     /*
553          * Bring closer parts of structure description.
554          */
555         const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
556         const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
557
558         /*
559          * Parts of the structure being constructed.
560          */
561         void *st = *struct_ptr; /* Target structure. */
562         asn_struct_ctx_t *ctx;  /* Decoder context */
563
564         asn_dec_rval_t rval;            /* Return value of a decoder */
565         ssize_t consumed_myself = 0;    /* Consumed bytes from ptr */
566         size_t edx;                     /* Element index */
567
568         /*
569          * Create the target structure if it is not present already.
570          */
571         if(st == 0) {
572                 st = *struct_ptr = CALLOC(1, specs->struct_size);
573                 if(st == 0) RETURN(RC_FAIL);
574         }
575
576         /*
577          * Restore parsing context.
578          */
579         ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
580         if(ctx->phase == 0 && !*xml_tag)
581                 ctx->phase = 1; /* Skip the outer tag checking phase */
582
583         /*
584          * Phases of XER/XML processing:
585          * Phase 0: Check that the opening tag matches our expectations.
586          * Phase 1: Processing body and reacting on closing tag.
587          * Phase 2: Processing inner type.
588          * Phase 3: Only waiting for closing tag.
589          * Phase 4: Skipping unknown extensions.
590          * Phase 5: PHASED OUT
591          */
592         for(edx = ctx->step; ctx->phase <= 4;) {
593                 pxer_chunk_type_e ch_type;      /* XER chunk type */
594                 ssize_t ch_size;                /* Chunk size */
595                 xer_check_tag_e tcv;            /* Tag check value */
596                 asn_TYPE_member_t *elm;
597
598                 /*
599                  * Go inside the member.
600                  */
601                 if(ctx->phase == 2) {
602                         asn_dec_rval_t tmprval;
603                         void *memb_ptr;         /* Pointer to the member */
604                         void **memb_ptr2;       /* Pointer to that pointer */
605                         unsigned old_present;
606
607                         elm = &td->elements[edx];
608
609                         if(elm->flags & ATF_POINTER) {
610                                 /* Member is a pointer to another structure */
611                                 memb_ptr2 = (void **)((char *)st
612                                         + elm->memb_offset);
613                         } else {
614                                 memb_ptr = (char *)st + elm->memb_offset;
615                                 memb_ptr2 = &memb_ptr;
616                         }
617
618                         /* Start/Continue decoding the inner member */
619                         tmprval = elm->type->op->xer_decoder(opt_codec_ctx,
620                                         elm->type, memb_ptr2, elm->name,
621                                         buf_ptr, size);
622                         XER_ADVANCE(tmprval.consumed);
623                         ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d",
624                                 elm->type->name, tmprval.code);
625                         old_present = _fetch_present_idx(st,
626                                 specs->pres_offset, specs->pres_size);
627                         assert(old_present == 0 || old_present == edx + 1);
628                         /* Record what we've got */
629                         _set_present_idx(st,
630                                 specs->pres_offset, specs->pres_size, edx + 1);
631                         if(tmprval.code != RC_OK)
632                                 RETURN(tmprval.code);
633                         ctx->phase = 3;
634                         /* Fall through */
635                 }
636
637                 /* No need to wait for closing tag; special mode. */
638                 if(ctx->phase == 3 && !*xml_tag) {
639                         ctx->phase = 5; /* Phase out */
640                         RETURN(RC_OK);
641                 }
642
643                 /*
644                  * Get the next part of the XML stream.
645                  */
646                 ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type);
647                 if(ch_size == -1) {
648             RETURN(RC_FAIL);
649         } else {
650                         switch(ch_type) {
651                         case PXER_WMORE:
652                 RETURN(RC_WMORE);
653                         case PXER_COMMENT:      /* Got XML comment */
654                         case PXER_TEXT:         /* Ignore free-standing text */
655                                 XER_ADVANCE(ch_size);   /* Skip silently */
656                                 continue;
657                         case PXER_TAG:
658                                 break;  /* Check the rest down there */
659                         }
660                 }
661
662                 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
663                 ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d",
664                         ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
665                         ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
666                         ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
667                         ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
668                 xml_tag, tcv);
669
670                 /* Skip the extensions section */
671                 if(ctx->phase == 4) {
672                         ASN_DEBUG("skip_unknown(%d, %ld)",
673                                 tcv, (long)ctx->left);
674                         switch(xer_skip_unknown(tcv, &ctx->left)) {
675                         case -1:
676                                 ctx->phase = 5;
677                                 RETURN(RC_FAIL);
678                         case 1:
679                                 ctx->phase = 3;
680                                 /* Fall through */
681                         case 0:
682                                 XER_ADVANCE(ch_size);
683                                 continue;
684                         case 2:
685                                 ctx->phase = 3;
686                                 break;
687                         }
688                 }
689
690                 switch(tcv) {
691                 case XCT_BOTH:
692                         break;  /* No CHOICE? */
693                 case XCT_CLOSING:
694                         if(ctx->phase != 3)
695                                 break;
696                         XER_ADVANCE(ch_size);
697                         ctx->phase = 5; /* Phase out */
698                         RETURN(RC_OK);
699                 case XCT_OPENING:
700                         if(ctx->phase == 0) {
701                                 XER_ADVANCE(ch_size);
702                                 ctx->phase = 1; /* Processing body phase */
703                                 continue;
704                         }
705                         /* Fall through */
706                 case XCT_UNKNOWN_OP:
707                 case XCT_UNKNOWN_BO:
708
709                         if(ctx->phase != 1)
710                                 break;  /* Really unexpected */
711
712                         /*
713                          * Search which inner member corresponds to this tag.
714                          */
715                         for(edx = 0; edx < td->elements_count; edx++) {
716                                 elm = &td->elements[edx];
717                                 tcv = xer_check_tag(buf_ptr,ch_size,elm->name);
718                                 switch(tcv) {
719                                 case XCT_BOTH:
720                                 case XCT_OPENING:
721                                         /*
722                                          * Process this member.
723                                          */
724                                         ctx->step = edx;
725                                         ctx->phase = 2;
726                                         break;
727                                 case XCT_UNKNOWN_OP:
728                                 case XCT_UNKNOWN_BO:
729                                         continue;
730                                 default:
731                                         edx = td->elements_count;
732                                         break;  /* Phase out */
733                                 }
734                                 break;
735                         }
736                         if(edx != td->elements_count)
737                                 continue;
738
739                         /* It is expected extension */
740                         if(specs->ext_start != -1) {
741                                 ASN_DEBUG("Got anticipated extension");
742                                 /*
743                                  * Check for (XCT_BOTH or XCT_UNKNOWN_BO)
744                                  * By using a mask. Only record a pure
745                                  * <opening> tags.
746                                  */
747                                 if(tcv & XCT_CLOSING) {
748                                         /* Found </extension> without body */
749                                         ctx->phase = 3; /* Terminating */
750                                 } else {
751                                         ctx->left = 1;
752                                         ctx->phase = 4; /* Skip ...'s */
753                                 }
754                                 XER_ADVANCE(ch_size);
755                                 continue;
756                         }
757
758                         /* Fall through */
759                 default:
760                         break;
761                 }
762
763                 ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]"
764                         " (ph=%d, tag=%s)",
765                         ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
766                         ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
767                         ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
768                         ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
769                         td->name, ctx->phase, xml_tag);
770                 break;
771         }
772
773         ctx->phase = 5; /* Phase out, just in case */
774         RETURN(RC_FAIL);
775 }
776
777
778 asn_enc_rval_t
779 CHOICE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
780                   enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb,
781                   void *app_key) {
782     const asn_CHOICE_specifics_t *specs =
783         (const asn_CHOICE_specifics_t *)td->specifics;
784     asn_enc_rval_t er;
785         unsigned present;
786
787         if(!sptr)
788                 ASN__ENCODE_FAILED;
789
790         /*
791          * Figure out which CHOICE element is encoded.
792          */
793         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
794
795         if(present == 0 || present > td->elements_count) {
796                 ASN__ENCODE_FAILED;
797         }  else {
798                 asn_enc_rval_t tmper;
799                 asn_TYPE_member_t *elm = &td->elements[present-1];
800                 const void *memb_ptr;
801                 const char *mname = elm->name;
802                 unsigned int mlen = strlen(mname);
803
804                 if(elm->flags & ATF_POINTER) {
805             memb_ptr =
806                 *(const void *const *)((const char *)sptr + elm->memb_offset);
807             if(!memb_ptr) ASN__ENCODE_FAILED;
808                 } else {
809             memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
810         }
811
812         er.encoded = 0;
813
814                 if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel);
815                 ASN__CALLBACK3("<", 1, mname, mlen, ">", 1);
816
817                 tmper = elm->type->op->xer_encoder(elm->type, memb_ptr,
818                                 ilevel + 1, flags, cb, app_key);
819                 if(tmper.encoded == -1) return tmper;
820                 er.encoded += tmper.encoded;
821
822                 ASN__CALLBACK3("</", 2, mname, mlen, ">", 1);
823         }
824
825         if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel - 1);
826
827         ASN__ENCODED_OK(er);
828 cb_failed:
829         ASN__ENCODE_FAILED;
830 }
831
832 asn_dec_rval_t
833 CHOICE_decode_uper(const asn_codec_ctx_t *opt_codec_ctx,
834                    const asn_TYPE_descriptor_t *td,
835                    const asn_per_constraints_t *constraints, void **sptr,
836                    asn_per_data_t *pd) {
837     const asn_CHOICE_specifics_t *specs =
838         (const asn_CHOICE_specifics_t *)td->specifics;
839     asn_dec_rval_t rv;
840         const asn_per_constraint_t *ct;
841         asn_TYPE_member_t *elm; /* CHOICE's element */
842         void *memb_ptr;
843         void **memb_ptr2;
844         void *st = *sptr;
845         int value;
846
847         if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
848                 ASN__DECODE_FAILED;
849
850         /*
851          * Create the target structure if it is not present already.
852          */
853         if(!st) {
854                 st = *sptr = CALLOC(1, specs->struct_size);
855                 if(!st) ASN__DECODE_FAILED;
856         }
857
858         if(constraints) ct = &constraints->value;
859         else if(td->encoding_constraints.per_constraints) ct = &td->encoding_constraints.per_constraints->value;
860         else ct = 0;
861
862         if(ct && ct->flags & APC_EXTENSIBLE) {
863                 value = per_get_few_bits(pd, 1);
864                 if(value < 0) ASN__DECODE_STARVED;
865                 if(value) ct = 0;       /* Not restricted */
866         }
867
868         if(ct && ct->range_bits >= 0) {
869                 value = per_get_few_bits(pd, ct->range_bits);
870                 if(value < 0) ASN__DECODE_STARVED;
871                 ASN_DEBUG("CHOICE %s got index %d in range %d",
872                         td->name, value, ct->range_bits);
873                 if(value > ct->upper_bound)
874                         ASN__DECODE_FAILED;
875         } else {
876                 if(specs->ext_start == -1)
877                         ASN__DECODE_FAILED;
878                 value = uper_get_nsnnwn(pd);
879                 if(value < 0) ASN__DECODE_STARVED;
880                 value += specs->ext_start;
881                 if((unsigned)value >= td->elements_count)
882                         ASN__DECODE_FAILED;
883         }
884
885         /* Adjust if canonical order is different from natural order */
886         if(specs->from_canonical_order) {
887         ASN_DEBUG("CHOICE presence from wire %d", value);
888                 value = specs->from_canonical_order[value];
889         ASN_DEBUG("CHOICE presence index effective %d", value);
890     }
891
892         /* Set presence to be able to free it later */
893         _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1);
894
895         elm = &td->elements[value];
896         if(elm->flags & ATF_POINTER) {
897                 /* Member is a pointer to another structure */
898                 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
899         } else {
900                 memb_ptr = (char *)st + elm->memb_offset;
901                 memb_ptr2 = &memb_ptr;
902         }
903         ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
904
905         if(ct && ct->range_bits >= 0) {
906                 rv = elm->type->op->uper_decoder(opt_codec_ctx, elm->type,
907                         elm->encoding_constraints.per_constraints, memb_ptr2, pd);
908         } else {
909                 rv = uper_open_type_get(opt_codec_ctx, elm->type,
910                         elm->encoding_constraints.per_constraints, memb_ptr2, pd);
911         }
912
913         if(rv.code != RC_OK)
914                 ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d",
915                         elm->name, td->name, rv.code);
916         return rv;
917 }
918
919 asn_enc_rval_t
920 CHOICE_encode_uper(const asn_TYPE_descriptor_t *td,
921                    const asn_per_constraints_t *constraints, const void *sptr,
922                    asn_per_outp_t *po) {
923     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
924         asn_TYPE_member_t *elm; /* CHOICE's element */
925         const asn_per_constraint_t *ct;
926         const void *memb_ptr;
927         unsigned present;
928         int present_enc;
929
930         if(!sptr) ASN__ENCODE_FAILED;
931
932         ASN_DEBUG("Encoding %s as CHOICE", td->name);
933
934         if(constraints) ct = &constraints->value;
935         else if(td->encoding_constraints.per_constraints)
936                 ct = &td->encoding_constraints.per_constraints->value;
937         else ct = 0;
938
939         present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
940
941         /*
942          * If the structure was not initialized properly, it cannot be encoded:
943          * can't deduce what to encode in the choice type.
944          */
945         if(present == 0 || present > td->elements_count)
946                 ASN__ENCODE_FAILED;
947         else
948                 present--;
949
950         ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
951
952     /* Adjust if canonical order is different from natural order */
953     if(specs->to_canonical_order)
954         present_enc = specs->to_canonical_order[present];
955     else
956         present_enc = present;
957
958     if(ct && ct->range_bits >= 0) {
959                 if(present_enc < ct->lower_bound
960                 || present_enc > ct->upper_bound) {
961                         if(ct->flags & APC_EXTENSIBLE) {
962                 ASN_DEBUG(
963                     "CHOICE member %d (enc %d) is an extension (%ld..%ld)",
964                     present, present_enc, ct->lower_bound, ct->upper_bound);
965                 if(per_put_few_bits(po, 1, 1))
966                                         ASN__ENCODE_FAILED;
967                         } else {
968                                 ASN__ENCODE_FAILED;
969                         }
970                         ct = 0;
971                 }
972         }
973         if(ct && ct->flags & APC_EXTENSIBLE) {
974         ASN_DEBUG("CHOICE member %d (enc %d) is not an extension (%ld..%ld)",
975                   present, present_enc, ct->lower_bound, ct->upper_bound);
976         if(per_put_few_bits(po, 0, 1))
977                         ASN__ENCODE_FAILED;
978     }
979
980
981         elm = &td->elements[present];
982     ASN_DEBUG("CHOICE member \"%s\" %d (as %d)", elm->name, present,
983               present_enc);
984     if(elm->flags & ATF_POINTER) {
985                 /* Member is a pointer to another structure */
986         memb_ptr =
987             *(const void *const *)((const char *)sptr + elm->memb_offset);
988         if(!memb_ptr) ASN__ENCODE_FAILED;
989         } else {
990         memb_ptr = (const char *)sptr + elm->memb_offset;
991     }
992
993     if(ct && ct->range_bits >= 0) {
994         if(per_put_few_bits(po, present_enc, ct->range_bits))
995             ASN__ENCODE_FAILED;
996
997         return elm->type->op->uper_encoder(
998             elm->type, elm->encoding_constraints.per_constraints, memb_ptr, po);
999     } else {
1000         asn_enc_rval_t rval;
1001         if(specs->ext_start == -1) ASN__ENCODE_FAILED;
1002         if(uper_put_nsnnwn(po, present_enc - specs->ext_start))
1003             ASN__ENCODE_FAILED;
1004         if(uper_open_type_put(elm->type,
1005                               elm->encoding_constraints.per_constraints,
1006                               memb_ptr, po))
1007             ASN__ENCODE_FAILED;
1008         rval.encoded = 0;
1009         ASN__ENCODED_OK(rval);
1010     }
1011 }
1012
1013
1014 int
1015 CHOICE_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
1016              asn_app_consume_bytes_f *cb, void *app_key) {
1017     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
1018         unsigned present;
1019
1020         if(!sptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1021
1022         /*
1023          * Figure out which CHOICE element is encoded.
1024          */
1025         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
1026
1027         /*
1028          * Print that element.
1029          */
1030         if(present > 0 && present <= td->elements_count) {
1031                 asn_TYPE_member_t *elm = &td->elements[present-1];
1032                 const void *memb_ptr;
1033
1034                 if(elm->flags & ATF_POINTER) {
1035                         memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
1036                         if(!memb_ptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1037                 } else {
1038                         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
1039                 }
1040
1041                 /* Print member's name and stuff */
1042                 if(0) {
1043                         if(cb(elm->name, strlen(elm->name), app_key) < 0
1044                         || cb(": ", 2, app_key) < 0)
1045                                 return -1;
1046                 }
1047
1048                 return elm->type->op->print_struct(elm->type, memb_ptr, ilevel,
1049                         cb, app_key);
1050         } else {
1051                 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1052         }
1053 }
1054
1055 void
1056 CHOICE_free(const asn_TYPE_descriptor_t *td, void *ptr,
1057             enum asn_struct_free_method method) {
1058     const asn_CHOICE_specifics_t *specs =
1059         (const asn_CHOICE_specifics_t *)td->specifics;
1060     unsigned present;
1061
1062         if(!td || !ptr)
1063                 return;
1064
1065         ASN_DEBUG("Freeing %s as CHOICE", td->name);
1066
1067         /*
1068          * Figure out which CHOICE element is encoded.
1069          */
1070         present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
1071
1072         /*
1073          * Free that element.
1074          */
1075         if(present > 0 && present <= td->elements_count) {
1076                 asn_TYPE_member_t *elm = &td->elements[present-1];
1077                 void *memb_ptr;
1078
1079                 if(elm->flags & ATF_POINTER) {
1080                         memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
1081                         if(memb_ptr)
1082                                 ASN_STRUCT_FREE(*elm->type, memb_ptr);
1083                 } else {
1084                         memb_ptr = (void *)((char *)ptr + elm->memb_offset);
1085                         ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr);
1086                 }
1087         }
1088
1089     switch(method) {
1090     case ASFM_FREE_EVERYTHING:
1091         FREEMEM(ptr);
1092         break;
1093     case ASFM_FREE_UNDERLYING:
1094         break;
1095     case ASFM_FREE_UNDERLYING_AND_RESET:
1096         memset(ptr, 0, specs->struct_size);
1097         break;
1098     }
1099 }
1100
1101
1102 /*
1103  * The following functions functions offer protection against -fshort-enums,
1104  * compatible with little- and big-endian machines.
1105  * If assertion is triggered, either disable -fshort-enums, or add an entry
1106  * here with the ->pres_size of your target stracture.
1107  * Unless the target structure is packed, the ".present" member
1108  * is guaranteed to be aligned properly. ASN.1 compiler itself does not
1109  * produce packed code.
1110  */
1111 static unsigned
1112 _fetch_present_idx(const void *struct_ptr, unsigned pres_offset,
1113                    unsigned pres_size) {
1114     const void *present_ptr;
1115         unsigned present;
1116
1117         present_ptr = ((const char *)struct_ptr) + pres_offset;
1118
1119         switch(pres_size) {
1120         case sizeof(int):       present = *(const unsigned int *)present_ptr; break;
1121         case sizeof(short):     present = *(const unsigned short *)present_ptr; break;
1122         case sizeof(char):      present = *(const unsigned char *)present_ptr; break;
1123         default:
1124                 /* ANSI C mandates enum to be equivalent to integer */
1125                 assert(pres_size != sizeof(int));
1126                 return 0;       /* If not aborted, pass back safe value */
1127         }
1128
1129         return present;
1130 }
1131
1132 static void
1133 _set_present_idx(void *struct_ptr, unsigned pres_offset, unsigned pres_size,
1134                  unsigned present) {
1135     void *present_ptr;
1136         present_ptr = ((char *)struct_ptr) + pres_offset;
1137
1138         switch(pres_size) {
1139         case sizeof(int):       *(unsigned int *)present_ptr   = present; break;
1140         case sizeof(short):     *(unsigned short *)present_ptr = present; break;
1141         case sizeof(char):      *(unsigned char *)present_ptr  = present; break;
1142         default:
1143                 /* ANSI C mandates enum to be equivalent to integer */
1144                 assert(pres_size != sizeof(int));
1145         }
1146 }
1147
1148 static const void *
1149 _get_member_ptr(const asn_TYPE_descriptor_t *td, const void *sptr,
1150                 asn_TYPE_member_t **elm_ptr, unsigned *present_out) {
1151     const asn_CHOICE_specifics_t *specs =
1152         (const asn_CHOICE_specifics_t *)td->specifics;
1153     unsigned present;
1154
1155     if(!sptr) {
1156         *elm_ptr = NULL;
1157         *present_out = 0;
1158         return NULL;
1159     }
1160
1161     /*
1162          * Figure out which CHOICE element is encoded.
1163          */
1164         present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
1165     *present_out = present;
1166
1167     /*
1168      * The presence index is intentionally 1-based to avoid
1169      * treating zeroed structure as a valid one.
1170      */
1171         if(present > 0 && present <= td->elements_count) {
1172         asn_TYPE_member_t *const elm = &td->elements[present - 1];
1173         const void *memb_ptr;
1174
1175                 if(elm->flags & ATF_POINTER) {
1176             memb_ptr =
1177                 *(const void *const *)((const char *)sptr + elm->memb_offset);
1178         } else {
1179             memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
1180         }
1181         *elm_ptr = elm;
1182         return memb_ptr;
1183     } else {
1184         *elm_ptr = NULL;
1185         return NULL;
1186     }
1187
1188 }
1189
1190 int
1191 CHOICE_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) {
1192     asn_TYPE_member_t *aelm;
1193     asn_TYPE_member_t *belm;
1194     unsigned apresent = 0;
1195     unsigned bpresent = 0;
1196     const void *amember = _get_member_ptr(td, aptr, &aelm, &apresent);
1197     const void *bmember = _get_member_ptr(td, bptr, &belm, &bpresent);
1198
1199     if(amember && bmember) {
1200         if(apresent == bpresent) {
1201             assert(aelm == belm);
1202             return aelm->type->op->compare_struct(aelm->type, amember, bmember);
1203         } else if(apresent < bpresent) {
1204             return -1;
1205         } else {
1206             return 1;
1207         }
1208     } else if(!amember) {
1209         return -1;
1210     } else {
1211         return 1;
1212     }
1213 }
1214
1215 /*
1216  * Return the 1-based choice variant presence index.
1217  * Returns 0 in case of error.
1218  */
1219 unsigned
1220 CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td, const void *sptr) {
1221     const asn_CHOICE_specifics_t *specs =
1222         (const asn_CHOICE_specifics_t *)td->specifics;
1223     return _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
1224 }
1225
1226 /*
1227  * Sets or resets the 1-based choice variant presence index.
1228  * In case a previous index is not zero, the currently selected structure
1229  * member is freed and zeroed-out first.
1230  * Returns 0 on success and -1 on error.
1231  */
1232 int
1233 CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, void *sptr,
1234                             unsigned present) {
1235     const asn_CHOICE_specifics_t *specs =
1236         (const asn_CHOICE_specifics_t *)td->specifics;
1237     unsigned old_present;
1238
1239     if(!sptr) {
1240         return -1;
1241     }
1242
1243     if(present > td->elements_count)
1244         return -1;
1245
1246     old_present =
1247         _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
1248     if(present == old_present)
1249         return 0;
1250
1251     if(old_present != 0) {
1252         assert(old_present <= td->elements_count);
1253         ASN_STRUCT_RESET(*td, sptr);
1254     }
1255
1256     _set_present_idx(sptr, specs->pres_offset, specs->pres_size, present);
1257
1258     return 0;
1259 }
1260
1261
1262 asn_random_fill_result_t
1263 CHOICE_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
1264                    const asn_encoding_constraints_t *constr,
1265                    size_t max_length) {
1266     const asn_CHOICE_specifics_t *specs =
1267         (const asn_CHOICE_specifics_t *)td->specifics;
1268     asn_random_fill_result_t res;
1269     asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
1270     asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
1271     const asn_TYPE_member_t *elm;
1272     unsigned present;
1273     void *memb_ptr;   /* Pointer to the member */
1274     void **memb_ptr2; /* Pointer to that pointer */
1275     void *st = *sptr;
1276
1277     if(max_length == 0) return result_skipped;
1278
1279     (void)constr;
1280
1281     if(st == NULL) {
1282         st = CALLOC(1, specs->struct_size);
1283         if(st == NULL) {
1284             return result_failed;
1285         }
1286     }
1287
1288     present = asn_random_between(1, td->elements_count);
1289     elm = &td->elements[present - 1];
1290
1291         if(elm->flags & ATF_POINTER) {
1292                 /* Member is a pointer to another structure */
1293                 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
1294         } else {
1295                 memb_ptr = (char *)st + elm->memb_offset;
1296                 memb_ptr2 = &memb_ptr;
1297         }
1298
1299     res = elm->type->op->random_fill(elm->type, memb_ptr2,
1300                                     &elm->encoding_constraints, max_length);
1301     _set_present_idx(st, specs->pres_offset, specs->pres_size, present);
1302     if(res.code == ARFILL_OK) {
1303         *sptr = st;
1304     } else {
1305         if(st == *sptr) {
1306             ASN_STRUCT_RESET(*td, st);
1307         } else {
1308             ASN_STRUCT_FREE(*td, st);
1309         }
1310     }
1311
1312     return res;
1313 }
1314
1315
1316 asn_TYPE_operation_t asn_OP_CHOICE = {
1317         CHOICE_free,
1318         CHOICE_print,
1319         CHOICE_compare,
1320         CHOICE_decode_ber,
1321         CHOICE_encode_der,
1322         CHOICE_decode_xer,
1323         CHOICE_encode_xer,
1324 #ifdef  ASN_DISABLE_OER_SUPPORT
1325         0,
1326         0,
1327 #else
1328         CHOICE_decode_oer,
1329         CHOICE_encode_oer,
1330 #endif  /* ASN_DISABLE_OER_SUPPORT */
1331 #ifdef ASN_DISABLE_PER_SUPPORT
1332         0,
1333         0,
1334 #else
1335         CHOICE_decode_uper,
1336         CHOICE_encode_uper,
1337 #endif  /* ASN_DISABLE_PER_SUPPORT */
1338         CHOICE_random_fill,
1339         CHOICE_outmost_tag
1340 };