86dcbb030a6f1b76bec8efdc51eb44b536cfa798
[sim/e2-interface.git] / e2sim / previous / e2apv1sim / ASN1c / 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 = {0,0,0};
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 = {0,0,0};
785         unsigned present = 0;
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 = {0,0,0};
799                 asn_TYPE_member_t *elm = &td->elements[present-1];
800                 const void *memb_ptr = NULL;
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 = {0,0,0};
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 asn_dec_rval_t
1014 CHOICE_decode_aper(const asn_codec_ctx_t *opt_codec_ctx,
1015                    const asn_TYPE_descriptor_t *td,
1016                    const asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
1017         const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
1018         asn_dec_rval_t rv;
1019         const asn_per_constraint_t *ct;
1020         const asn_per_constraint_t *ext_ct = NULL;
1021         asn_TYPE_member_t *elm; /* CHOICE's element */
1022         void *memb_ptr;
1023         void **memb_ptr2;
1024         void *st = *sptr;
1025         int value;
1026
1027         if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
1028                 ASN__DECODE_FAILED;
1029
1030         /*
1031          * Create the target structure if it is not present already.
1032          */
1033         if(!st) {
1034                 st = *sptr = CALLOC(1, specs->struct_size);
1035                 if(!st) ASN__DECODE_FAILED;
1036         }
1037
1038         if(constraints) ct = &constraints->value;
1039         else if(td->encoding_constraints.per_constraints)
1040                 ct = &td->encoding_constraints.per_constraints->value;
1041         else ct = 0;
1042
1043         if(ct && ct->flags & APC_EXTENSIBLE) {
1044                 value = per_get_few_bits(pd, 1);
1045                 if(value < 0) ASN__DECODE_STARVED;
1046                 if(value) {
1047                   ext_ct = ct;
1048                   ct = 0;       /* Not restricted */
1049                 }
1050         }
1051
1052
1053         if(ct && ct->range_bits >= 0) {
1054                 value = per_get_few_bits(pd, ct->range_bits);
1055                 if(value < 0) ASN__DECODE_STARVED;
1056                 ASN_DEBUG("CHOICE %s got index %d in range %d",
1057                           td->name, value, ct->range_bits);
1058                 if(value > ct->upper_bound)
1059                         ASN__DECODE_FAILED;
1060         } else {
1061                 if(specs->ext_start == -1)
1062                         ASN__DECODE_FAILED;
1063                 value = aper_get_nsnnwn(pd, ext_ct->range_bits);
1064                 if(value < 0) ASN__DECODE_STARVED;
1065                 value += specs->ext_start;
1066                 if((unsigned)value >= td->elements_count)
1067                         ASN__DECODE_FAILED;
1068         }
1069
1070         /* Adjust if canonical order is different from natural order */
1071         if(specs->from_canonical_order)
1072                 value = specs->from_canonical_order[value];
1073
1074         /* Set presence to be able to free it later */
1075         _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1);
1076
1077         elm = &td->elements[value];
1078         if(elm->flags & ATF_POINTER) {
1079                 /* Member is a pointer to another structure */
1080                 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
1081         } else {
1082                 memb_ptr = (char *)st + elm->memb_offset;
1083                 memb_ptr2 = &memb_ptr;
1084         }
1085         ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
1086
1087         if(ct && ct->range_bits >= 0) {
1088                 rv = elm->type->op->aper_decoder(opt_codec_ctx, elm->type,
1089                                                  elm->encoding_constraints.per_constraints, memb_ptr2, pd);
1090         } else {
1091                 rv = aper_open_type_get(opt_codec_ctx, elm->type,
1092                                         elm->encoding_constraints.per_constraints, memb_ptr2, pd);
1093         }
1094
1095         if(rv.code != RC_OK)
1096                 ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d",
1097                           elm->name, td->name, rv.code);
1098         return rv;
1099 }
1100
1101 asn_enc_rval_t
1102 CHOICE_encode_aper(const asn_TYPE_descriptor_t *td,
1103                    const asn_per_constraints_t *constraints,
1104                    const void *sptr, asn_per_outp_t *po) {
1105         const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
1106         const asn_TYPE_member_t *elm; /* CHOICE's element */
1107         const asn_per_constraint_t *ct = NULL;
1108         const asn_per_constraint_t *ext_ct = NULL;
1109         const void *memb_ptr;
1110         unsigned present;
1111         int present_enc;
1112         
1113         if(!sptr) ASN__ENCODE_FAILED;
1114
1115         ASN_DEBUG("Encoding %s as CHOICE using ALIGNED PER", td->name);
1116
1117         if(constraints) ct = &constraints->value;
1118         else if(td->encoding_constraints.per_constraints)
1119                 ct = &td->encoding_constraints.per_constraints->value;
1120         else ct = NULL;
1121
1122         present = _fetch_present_idx(sptr,
1123                                      specs->pres_offset, specs->pres_size);
1124
1125         /*
1126          * If the structure was not initialized properly, it cannot be encoded:
1127          * can't deduce what to encode in the choice type.
1128          */
1129         if(present <= 0 || (unsigned)present > td->elements_count)
1130                 ASN__ENCODE_FAILED;
1131         else
1132                 present--;
1133
1134         /* Adjust if canonical order is different from natural order */
1135         if(specs->to_canonical_order)
1136                 present_enc = specs->to_canonical_order[present];
1137         else
1138                 present_enc = present;
1139         
1140         ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
1141
1142         if(ct && (ct->range_bits >= 0)) {
1143           // Value is not within the range of the primary values ?
1144           if(present < ct->lower_bound || present > ct->upper_bound) {
1145             if(ct->flags & APC_EXTENSIBLE) {
1146               ASN_DEBUG("CHOICE member %d (enc %d) is an extension (%ld..%ld)",
1147                         present, present_enc, ct->lower_bound, ct->upper_bound);
1148               // X691/23.5 Extension marker = 1 
1149               if(per_put_few_bits(po, 1, 1)) {
1150                 ASN__ENCODE_FAILED;
1151               }
1152             } else {
1153               ASN__ENCODE_FAILED;
1154             }
1155             // no more need of constraint.
1156             ext_ct = ct;
1157             ct = NULL;
1158           }
1159         }
1160         
1161         if(ct && (ct->flags & APC_EXTENSIBLE)) {
1162           ASN_DEBUG("CHOICE member %d (enc %d) is not an extension (%ld..%ld)",
1163                     present, present, ct->lower_bound, ct->upper_bound);
1164           // X691.23.5 Extension marker = 0
1165           if(per_put_few_bits(po, 0, 1)) {
1166             ASN__ENCODE_FAILED;
1167           }
1168         }
1169
1170         elm = &td->elements[present];
1171         if(elm->flags & ATF_POINTER) {
1172                 /* Member is a pointer to another structure */
1173                 memb_ptr = *(const void *const *)((const char *)sptr + elm->memb_offset);
1174                 if(!memb_ptr) ASN__ENCODE_FAILED;
1175         } else {
1176                 memb_ptr = (const char *)sptr + elm->memb_offset;
1177         }
1178
1179         if(ct && (ct->range_bits >= 0)) {
1180                 // By construction (ct != 0), the alternative value is a non extended one.
1181                 // X691/23.7 X691/23.6 alternative value encoded as a range_bits bits value.
1182                 if(per_put_few_bits(po, present_enc, ct->range_bits))
1183                         ASN__ENCODE_FAILED;
1184
1185                 return elm->type->op->aper_encoder(elm->type, elm->encoding_constraints.per_constraints,
1186                                                    memb_ptr, po);
1187         } else {
1188                 asn_enc_rval_t rval = {0,0,0};
1189                 if(specs->ext_start == -1)
1190                         ASN__ENCODE_FAILED;
1191                 // X691/23.8 normally encoded as a small non negative whole number
1192                 
1193                 if(ext_ct && aper_put_nsnnwn(po, ext_ct->range_bits, present_enc - specs->ext_start))
1194                         ASN__ENCODE_FAILED;
1195                 if(aper_open_type_put(elm->type, elm->encoding_constraints.per_constraints,
1196                                       memb_ptr, po))
1197                         ASN__ENCODE_FAILED;
1198                 rval.encoded = 0;
1199                 ASN__ENCODED_OK(rval);
1200         }
1201 }
1202
1203 int
1204 CHOICE_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
1205              asn_app_consume_bytes_f *cb, void *app_key) {
1206     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
1207         unsigned present;
1208
1209         if(!sptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1210
1211         /*
1212          * Figure out which CHOICE element is encoded.
1213          */
1214         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
1215
1216         /*
1217          * Print that element.
1218          */
1219         if(present > 0 && present <= td->elements_count) {
1220                 asn_TYPE_member_t *elm = &td->elements[present-1];
1221                 const void *memb_ptr;
1222
1223                 if(elm->flags & ATF_POINTER) {
1224                         memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
1225                         if(!memb_ptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1226                 } else {
1227                         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
1228                 }
1229
1230                 /* Print member's name and stuff */
1231                 if(0) {
1232                         if(cb(elm->name, strlen(elm->name), app_key) < 0
1233                         || cb(": ", 2, app_key) < 0)
1234                                 return -1;
1235                 }
1236
1237                 return elm->type->op->print_struct(elm->type, memb_ptr, ilevel,
1238                         cb, app_key);
1239         } else {
1240                 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1241         }
1242 }
1243
1244 void
1245 CHOICE_free(const asn_TYPE_descriptor_t *td, void *ptr,
1246             enum asn_struct_free_method method) {
1247     const asn_CHOICE_specifics_t *specs =
1248         (const asn_CHOICE_specifics_t *)td->specifics;
1249     unsigned present;
1250
1251         if(!td || !ptr)
1252                 return;
1253
1254         ASN_DEBUG("Freeing %s as CHOICE", td->name);
1255
1256         /*
1257          * Figure out which CHOICE element is encoded.
1258          */
1259         present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
1260
1261         /*
1262          * Free that element.
1263          */
1264         if(present > 0 && present <= td->elements_count) {
1265                 asn_TYPE_member_t *elm = &td->elements[present-1];
1266                 void *memb_ptr;
1267
1268                 if(elm->flags & ATF_POINTER) {
1269                         memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
1270                         if(memb_ptr)
1271                                 ASN_STRUCT_FREE(*elm->type, memb_ptr);
1272                 } else {
1273                         memb_ptr = (void *)((char *)ptr + elm->memb_offset);
1274                         ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr);
1275                 }
1276         }
1277
1278     switch(method) {
1279     case ASFM_FREE_EVERYTHING:
1280         FREEMEM(ptr);
1281         break;
1282     case ASFM_FREE_UNDERLYING:
1283         break;
1284     case ASFM_FREE_UNDERLYING_AND_RESET:
1285         memset(ptr, 0, specs->struct_size);
1286         break;
1287     }
1288 }
1289
1290
1291 /*
1292  * The following functions functions offer protection against -fshort-enums,
1293  * compatible with little- and big-endian machines.
1294  * If assertion is triggered, either disable -fshort-enums, or add an entry
1295  * here with the ->pres_size of your target stracture.
1296  * Unless the target structure is packed, the ".present" member
1297  * is guaranteed to be aligned properly. ASN.1 compiler itself does not
1298  * produce packed code.
1299  */
1300 static unsigned
1301 _fetch_present_idx(const void *struct_ptr, unsigned pres_offset,
1302                    unsigned pres_size) {
1303     const void *present_ptr;
1304         unsigned present;
1305
1306         present_ptr = ((const char *)struct_ptr) + pres_offset;
1307
1308         switch(pres_size) {
1309         case sizeof(int):       present = *(const unsigned int *)present_ptr; break;
1310         case sizeof(short):     present = *(const unsigned short *)present_ptr; break;
1311         case sizeof(char):      present = *(const unsigned char *)present_ptr; break;
1312         default:
1313                 /* ANSI C mandates enum to be equivalent to integer */
1314                 assert(pres_size != sizeof(int));
1315                 return 0;       /* If not aborted, pass back safe value */
1316         }
1317
1318         return present;
1319 }
1320
1321 static void
1322 _set_present_idx(void *struct_ptr, unsigned pres_offset, unsigned pres_size,
1323                  unsigned present) {
1324     void *present_ptr;
1325         present_ptr = ((char *)struct_ptr) + pres_offset;
1326
1327         switch(pres_size) {
1328         case sizeof(int):       *(unsigned int *)present_ptr   = present; break;
1329         case sizeof(short):     *(unsigned short *)present_ptr = present; break;
1330         case sizeof(char):      *(unsigned char *)present_ptr  = present; break;
1331         default:
1332                 /* ANSI C mandates enum to be equivalent to integer */
1333                 assert(pres_size != sizeof(int));
1334         }
1335 }
1336
1337 static const void *
1338 _get_member_ptr(const asn_TYPE_descriptor_t *td, const void *sptr,
1339                 asn_TYPE_member_t **elm_ptr, unsigned *present_out) {
1340     const asn_CHOICE_specifics_t *specs =
1341         (const asn_CHOICE_specifics_t *)td->specifics;
1342     unsigned present;
1343
1344     if(!sptr) {
1345         *elm_ptr = NULL;
1346         *present_out = 0;
1347         return NULL;
1348     }
1349
1350     /*
1351          * Figure out which CHOICE element is encoded.
1352          */
1353         present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
1354     *present_out = present;
1355
1356     /*
1357      * The presence index is intentionally 1-based to avoid
1358      * treating zeroed structure as a valid one.
1359      */
1360         if(present > 0 && present <= td->elements_count) {
1361         asn_TYPE_member_t *const elm = &td->elements[present - 1];
1362         const void *memb_ptr;
1363
1364                 if(elm->flags & ATF_POINTER) {
1365             memb_ptr =
1366                 *(const void *const *)((const char *)sptr + elm->memb_offset);
1367         } else {
1368             memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
1369         }
1370         *elm_ptr = elm;
1371         return memb_ptr;
1372     } else {
1373         *elm_ptr = NULL;
1374         return NULL;
1375     }
1376
1377 }
1378
1379 int
1380 CHOICE_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) {
1381     asn_TYPE_member_t *aelm;
1382     asn_TYPE_member_t *belm;
1383     unsigned apresent = 0;
1384     unsigned bpresent = 0;
1385     const void *amember = _get_member_ptr(td, aptr, &aelm, &apresent);
1386     const void *bmember = _get_member_ptr(td, bptr, &belm, &bpresent);
1387
1388     if(amember && bmember) {
1389         if(apresent == bpresent) {
1390             assert(aelm == belm);
1391             return aelm->type->op->compare_struct(aelm->type, amember, bmember);
1392         } else if(apresent < bpresent) {
1393             return -1;
1394         } else {
1395             return 1;
1396         }
1397     } else if(!amember) {
1398         return -1;
1399     } else {
1400         return 1;
1401     }
1402 }
1403
1404 /*
1405  * Return the 1-based choice variant presence index.
1406  * Returns 0 in case of error.
1407  */
1408 unsigned
1409 CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td, const void *sptr) {
1410     const asn_CHOICE_specifics_t *specs =
1411         (const asn_CHOICE_specifics_t *)td->specifics;
1412     return _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
1413 }
1414
1415 /*
1416  * Sets or resets the 1-based choice variant presence index.
1417  * In case a previous index is not zero, the currently selected structure
1418  * member is freed and zeroed-out first.
1419  * Returns 0 on success and -1 on error.
1420  */
1421 int
1422 CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, void *sptr,
1423                             unsigned present) {
1424     const asn_CHOICE_specifics_t *specs =
1425         (const asn_CHOICE_specifics_t *)td->specifics;
1426     unsigned old_present;
1427
1428     if(!sptr) {
1429         return -1;
1430     }
1431
1432     if(present > td->elements_count)
1433         return -1;
1434
1435     old_present =
1436         _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
1437     if(present == old_present)
1438         return 0;
1439
1440     if(old_present != 0) {
1441         assert(old_present <= td->elements_count);
1442         ASN_STRUCT_RESET(*td, sptr);
1443     }
1444
1445     _set_present_idx(sptr, specs->pres_offset, specs->pres_size, present);
1446
1447     return 0;
1448 }
1449
1450
1451 asn_random_fill_result_t
1452 CHOICE_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
1453                    const asn_encoding_constraints_t *constr,
1454                    size_t max_length) {
1455     const asn_CHOICE_specifics_t *specs =
1456         (const asn_CHOICE_specifics_t *)td->specifics;
1457     asn_random_fill_result_t res;
1458     asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
1459     asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
1460     const asn_TYPE_member_t *elm;
1461     unsigned present;
1462     void *memb_ptr;   /* Pointer to the member */
1463     void **memb_ptr2; /* Pointer to that pointer */
1464     void *st = *sptr;
1465
1466     if(max_length == 0) return result_skipped;
1467
1468     (void)constr;
1469
1470     if(st == NULL) {
1471         st = CALLOC(1, specs->struct_size);
1472         if(st == NULL) {
1473             return result_failed;
1474         }
1475     }
1476
1477     present = asn_random_between(1, td->elements_count);
1478     elm = &td->elements[present - 1];
1479
1480         if(elm->flags & ATF_POINTER) {
1481                 /* Member is a pointer to another structure */
1482                 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
1483         } else {
1484                 memb_ptr = (char *)st + elm->memb_offset;
1485                 memb_ptr2 = &memb_ptr;
1486         }
1487
1488     res = elm->type->op->random_fill(elm->type, memb_ptr2,
1489                                     &elm->encoding_constraints, max_length);
1490     _set_present_idx(st, specs->pres_offset, specs->pres_size, present);
1491     if(res.code == ARFILL_OK) {
1492         *sptr = st;
1493     } else {
1494         if(st == *sptr) {
1495             ASN_STRUCT_RESET(*td, st);
1496         } else {
1497             ASN_STRUCT_FREE(*td, st);
1498         }
1499     }
1500
1501     return res;
1502 }
1503
1504
1505 asn_TYPE_operation_t asn_OP_CHOICE = {
1506         CHOICE_free,
1507         CHOICE_print,
1508         CHOICE_compare,
1509         CHOICE_decode_ber,
1510         CHOICE_encode_der,
1511         CHOICE_decode_xer,
1512         CHOICE_encode_xer,
1513 #ifdef  ASN_DISABLE_OER_SUPPORT
1514         0,
1515         0,
1516 #else
1517         CHOICE_decode_oer,
1518         CHOICE_encode_oer,
1519 #endif  /* ASN_DISABLE_OER_SUPPORT */
1520 #ifdef ASN_DISABLE_PER_SUPPORT
1521         0,
1522         0,
1523         0,
1524         0,
1525 #else
1526         CHOICE_decode_uper,
1527         CHOICE_encode_uper,
1528         CHOICE_decode_aper,
1529         CHOICE_encode_aper,
1530 #endif  /* ASN_DISABLE_PER_SUPPORT */
1531         CHOICE_random_fill,
1532         CHOICE_outmost_tag
1533 };