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