]> git.stg.codes - stg.git/blob - libs/smux/constr_CHOICE.c
Reorganize plugins.
[stg.git] / libs / smux / constr_CHOICE.c
1 /*
2  * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>.
3  * 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
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 int _fetch_present_idx(const void *struct_ptr, int off, int size);
66 static void _set_present_idx(void *sptr, int offset, int size, int pres);
67
68 /*
69  * Tags are canonically sorted in the tag to member table.
70  */
71 static int
72 _search4tag(const void *ap, const void *bp) {
73         const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap;
74         const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp;
75
76         int a_class = BER_TAG_CLASS(a->el_tag);
77         int b_class = BER_TAG_CLASS(b->el_tag);
78
79         if(a_class == b_class) {
80                 ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
81                 ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
82
83                 if(a_value == b_value)
84                         return 0;
85                 else if(a_value < b_value)
86                         return -1;
87                 else
88                         return 1;
89         } else if(a_class < b_class) {
90                 return -1;
91         } else {
92                 return 1;
93         }
94 }
95
96 /*
97  * The decoder of the CHOICE type.
98  */
99 asn_dec_rval_t
100 CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
101         void **struct_ptr, const void *ptr, size_t size, int tag_mode) {
102         /*
103          * Bring closer parts of structure description.
104          */
105         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
106         asn_TYPE_member_t *elements = td->elements;
107
108         /*
109          * Parts of the structure being constructed.
110          */
111         void *st = *struct_ptr; /* Target structure. */
112         asn_struct_ctx_t *ctx;  /* Decoder context */
113
114         ber_tlv_tag_t tlv_tag;  /* T from TLV */
115         ssize_t tag_len;        /* Length of TLV's T */
116         asn_dec_rval_t rval;    /* Return code from subparsers */
117
118         ssize_t consumed_myself = 0;    /* Consumed bytes from ptr */
119
120         ASN_DEBUG("Decoding %s as CHOICE", td->name);
121
122         /*
123          * Create the target structure if it is not present already.
124          */
125         if(st == 0) {
126                 st = *struct_ptr = CALLOC(1, specs->struct_size);
127                 if(st == 0) {
128                         RETURN(RC_FAIL);
129                 }
130         }
131
132         /*
133          * Restore parsing context.
134          */
135         ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
136         
137         /*
138          * Start to parse where left previously
139          */
140         switch(ctx->phase) {
141         case 0:
142                 /*
143                  * PHASE 0.
144                  * Check that the set of tags associated with given structure
145                  * perfectly fits our expectations.
146                  */
147
148                 if(tag_mode || td->tags_count) {
149                         rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size,
150                                 tag_mode, -1, &ctx->left, 0);
151                         if(rval.code != RC_OK) {
152                                 ASN_DEBUG("%s tagging check failed: %d",
153                                         td->name, rval.code);
154                                 return rval;
155                         }
156
157                         if(ctx->left >= 0) {
158                                 /* ?Substracted below! */
159                                 ctx->left += rval.consumed;
160                         }
161                         ADVANCE(rval.consumed);
162                 } else {
163                         ctx->left = -1;
164                 }
165
166                 NEXT_PHASE(ctx);
167
168                 ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
169                         (long)ctx->left, (long)size);
170
171                 /* Fall through */
172         case 1:
173                 /*
174                  * Fetch the T from TLV.
175                  */
176                 tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
177                 ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len);
178                 switch(tag_len) {
179                 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
180                         /* Fall through */
181                 case -1: RETURN(RC_FAIL);
182                 }
183
184                 do {
185                         asn_TYPE_tag2member_t *t2m;
186                         asn_TYPE_tag2member_t key;
187
188                         key.el_tag = tlv_tag;
189                         t2m = (asn_TYPE_tag2member_t *)bsearch(&key,
190                                         specs->tag2el, specs->tag2el_count,
191                                         sizeof(specs->tag2el[0]), _search4tag);
192                         if(t2m) {
193                                 /*
194                                  * Found the element corresponding to the tag.
195                                  */
196                                 NEXT_PHASE(ctx);
197                                 ctx->step = t2m->el_no;
198                                 break;
199                         } else if(specs->ext_start == -1) {
200                                 ASN_DEBUG("Unexpected tag %s "
201                                         "in non-extensible CHOICE %s",
202                                         ber_tlv_tag_string(tlv_tag), td->name);
203                                 RETURN(RC_FAIL);
204                         } else {
205                                 /* Skip this tag */
206                                 ssize_t skip;
207
208                                 ASN_DEBUG("Skipping unknown tag %s",
209                                         ber_tlv_tag_string(tlv_tag));
210
211                                 skip = ber_skip_length(opt_codec_ctx,
212                                         BER_TLV_CONSTRUCTED(ptr),
213                                         (const char *)ptr + tag_len,
214                                         LEFT - tag_len);
215
216                                 switch(skip) {
217                                 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
218                                         /* Fall through */
219                                 case -1: RETURN(RC_FAIL);
220                                 }
221
222                                 ADVANCE(skip + tag_len);
223                                 RETURN(RC_OK);
224                         }
225                 } while(0);
226
227         case 2:
228                 /*
229                  * PHASE 2.
230                  * Read in the element.
231                  */
232             do {
233                 asn_TYPE_member_t *elm;/* CHOICE's element */
234                 void *memb_ptr;         /* Pointer to the member */
235                 void **memb_ptr2;       /* Pointer to that pointer */
236
237                 elm = &elements[ctx->step];
238
239                 /*
240                  * Compute the position of the member inside a structure,
241                  * and also a type of containment (it may be contained
242                  * as pointer or using inline inclusion).
243                  */
244                 if(elm->flags & ATF_POINTER) {
245                         /* Member is a pointer to another structure */
246                         memb_ptr2 = (void **)((char *)st + elm->memb_offset);
247                 } else {
248                         /*
249                          * A pointer to a pointer
250                          * holding the start of the structure
251                          */
252                         memb_ptr = (char *)st + elm->memb_offset;
253                         memb_ptr2 = &memb_ptr;
254                 }
255                 /* Set presence to be able to free it properly at any time */
256                 _set_present_idx(st, specs->pres_offset,
257                                 specs->pres_size, ctx->step + 1);
258                 /*
259                  * Invoke the member fetch routine according to member's type
260                  */
261                 rval = elm->type->ber_decoder(opt_codec_ctx, elm->type,
262                                 memb_ptr2, ptr, LEFT, elm->tag_mode);
263                 switch(rval.code) {
264                 case RC_OK:
265                         break;
266                 case RC_WMORE: /* More data expected */
267                         if(!SIZE_VIOLATION) {
268                                 ADVANCE(rval.consumed);
269                                 RETURN(RC_WMORE);
270                         }
271                         RETURN(RC_FAIL);
272                 case RC_FAIL: /* Fatal error */
273                         RETURN(rval.code);
274                 } /* switch(rval) */
275                 
276                 ADVANCE(rval.consumed);
277           } while(0);
278
279                 NEXT_PHASE(ctx);
280
281                 /* Fall through */
282         case 3:
283                 ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
284                         td->name, (long)ctx->left, (long)size,
285                         tag_mode, td->tags_count);
286
287                 if(ctx->left > 0) {
288                         /*
289                          * The type must be fully decoded
290                          * by the CHOICE member-specific decoder.
291                          */
292                         RETURN(RC_FAIL);
293                 }
294
295                 if(ctx->left == -1
296                 && !(tag_mode || td->tags_count)) {
297                         /*
298                          * This is an untagged CHOICE.
299                          * It doesn't contain nothing
300                          * except for the member itself, including all its tags.
301                          * The decoding is completed.
302                          */
303                         NEXT_PHASE(ctx);
304                         break;
305                 }
306
307                 /*
308                  * Read in the "end of data chunks"'s.
309                  */
310                 while(ctx->left < 0) {
311                         ssize_t tl;
312
313                         tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
314                         switch(tl) {
315                         case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
316                                 /* Fall through */
317                         case -1: RETURN(RC_FAIL);
318                         }
319
320                         /*
321                          * Expected <0><0>...
322                          */
323                         if(((const uint8_t *)ptr)[0] == 0) {
324                                 if(LEFT < 2) {
325                                         if(SIZE_VIOLATION)
326                                                 RETURN(RC_FAIL);
327                                         else
328                                                 RETURN(RC_WMORE);
329                                 } else if(((const uint8_t *)ptr)[1] == 0) {
330                                         /*
331                                          * Correctly finished with <0><0>.
332                                          */
333                                         ADVANCE(2);
334                                         ctx->left++;
335                                         continue;
336                                 }
337                         } else {
338                                 ASN_DEBUG("Unexpected continuation in %s",
339                                         td->name);
340                                 RETURN(RC_FAIL);
341                         }
342
343                         /* UNREACHABLE */
344                 }
345
346                 NEXT_PHASE(ctx);
347         case 4:
348                 /* No meaningful work here */
349                 break;
350         }
351         
352         RETURN(RC_OK);
353 }
354
355 asn_enc_rval_t
356 CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr,
357                 int tag_mode, ber_tlv_tag_t tag,
358                 asn_app_consume_bytes_f *cb, void *app_key) {
359         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
360         asn_TYPE_member_t *elm; /* CHOICE element */
361         asn_enc_rval_t erval;
362         void *memb_ptr;
363         size_t computed_size = 0;
364         int present;
365
366         if(!sptr) _ASN_ENCODE_FAILED;
367
368         ASN_DEBUG("%s %s as CHOICE",
369                 cb?"Encoding":"Estimating", td->name);
370
371         present = _fetch_present_idx(sptr,
372                 specs->pres_offset, specs->pres_size);
373
374         /*
375          * If the structure was not initialized, it cannot be encoded:
376          * can't deduce what to encode in the choice type.
377          */
378         if(present <= 0 || present > td->elements_count) {
379                 if(present == 0 && td->elements_count == 0) {
380                         /* The CHOICE is empty?! */
381                         erval.encoded = 0;
382                         _ASN_ENCODED_OK(erval);
383                 }
384                 _ASN_ENCODE_FAILED;
385         }
386
387         /*
388          * Seek over the present member of the structure.
389          */
390         elm = &td->elements[present-1];
391         if(elm->flags & ATF_POINTER) {
392                 memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
393                 if(memb_ptr == 0) {
394                         if(elm->optional) {
395                                 erval.encoded = 0;
396                                 _ASN_ENCODED_OK(erval);
397                         }
398                         /* Mandatory element absent */
399                         _ASN_ENCODE_FAILED;
400                 }
401         } else {
402                 memb_ptr = (void *)((char *)sptr + elm->memb_offset);
403         }
404
405         /*
406          * If the CHOICE itself is tagged EXPLICIT:
407          * T ::= [2] EXPLICIT CHOICE { ... }
408          * Then emit the appropriate tags.
409          */
410         if(tag_mode == 1 || td->tags_count) {
411                 /*
412                  * For this, we need to pre-compute the member.
413                  */
414                 ssize_t ret;
415
416                 /* Encode member with its tag */
417                 erval = elm->type->der_encoder(elm->type, memb_ptr,
418                         elm->tag_mode, elm->tag, 0, 0);
419                 if(erval.encoded == -1)
420                         return erval;
421
422                 /* Encode CHOICE with parent or my own tag */
423                 ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag,
424                         cb, app_key);
425                 if(ret == -1)
426                         _ASN_ENCODE_FAILED;
427                 computed_size += ret;
428         }
429
430         /*
431          * Encode the single underlying member.
432          */
433         erval = elm->type->der_encoder(elm->type, memb_ptr,
434                 elm->tag_mode, elm->tag, cb, app_key);
435         if(erval.encoded == -1)
436                 return erval;
437
438         ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
439                 (long)erval.encoded, (long)computed_size);
440
441         erval.encoded += computed_size;
442
443         return erval;
444 }
445
446 ber_tlv_tag_t
447 CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
448         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
449         int present;
450
451         assert(tag_mode == 0); (void)tag_mode;
452         assert(tag == 0); (void)tag;
453
454         /*
455          * Figure out which CHOICE element is encoded.
456          */
457         present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
458
459         if(present > 0 || present <= td->elements_count) {
460                 asn_TYPE_member_t *elm = &td->elements[present-1];
461                 const void *memb_ptr;
462
463                 if(elm->flags & ATF_POINTER) {
464                         memb_ptr = *(const void * const *)
465                                         ((const char *)ptr + elm->memb_offset);
466                 } else {
467                         memb_ptr = (const void *)
468                                         ((const char *)ptr + elm->memb_offset);
469                 }
470
471                 return asn_TYPE_outmost_tag(elm->type, memb_ptr,
472                         elm->tag_mode, elm->tag);
473         } else {
474                 return (ber_tlv_tag_t)-1;
475         }
476 }
477
478 int
479 CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
480                 asn_app_constraint_failed_f *ctfailcb, void *app_key) {
481         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
482         int present;
483
484         if(!sptr) {
485                 _ASN_CTFAIL(app_key, td,
486                         "%s: value not given (%s:%d)",
487                         td->name, __FILE__, __LINE__);
488                 return -1;
489         }
490
491         /*
492          * Figure out which CHOICE element is encoded.
493          */
494         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
495         if(present > 0 && present <= td->elements_count) {
496                 asn_TYPE_member_t *elm = &td->elements[present-1];
497                 const void *memb_ptr;
498
499                 if(elm->flags & ATF_POINTER) {
500                         memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
501                         if(!memb_ptr) {
502                                 if(elm->optional)
503                                         return 0;
504                                 _ASN_CTFAIL(app_key, td,
505                                         "%s: mandatory CHOICE element %s absent (%s:%d)",
506                                         td->name, elm->name, __FILE__, __LINE__);
507                                 return -1;
508                         }
509                 } else {
510                         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
511                 }
512
513                 if(elm->memb_constraints) {
514                         return elm->memb_constraints(elm->type, memb_ptr,
515                                 ctfailcb, app_key);
516                 } else {
517                         int ret = elm->type->check_constraints(elm->type,
518                                         memb_ptr, ctfailcb, app_key);
519                         /*
520                          * Cannot inherit it eralier:
521                          * need to make sure we get the updated version.
522                          */
523                         elm->memb_constraints = elm->type->check_constraints;
524                         return ret;
525                 }
526         } else {
527                 _ASN_CTFAIL(app_key, td,
528                         "%s: no CHOICE element given (%s:%d)",
529                         td->name, __FILE__, __LINE__);
530                 return -1;
531         }
532 }
533
534 #undef  XER_ADVANCE
535 #define XER_ADVANCE(num_bytes)  do {                    \
536                 size_t num = num_bytes;                 \
537                 buf_ptr = ((const char *)buf_ptr) + num;\
538                 size -= num;                            \
539                 consumed_myself += num;                 \
540         } while(0)
541
542 /*
543  * Decode the XER (XML) data.
544  */
545 asn_dec_rval_t
546 CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
547         void **struct_ptr, const char *opt_mname,
548                 const void *buf_ptr, size_t size) {
549         /*
550          * Bring closer parts of structure description.
551          */
552         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
553         const char *xml_tag = opt_mname ? opt_mname : td->xml_tag;
554
555         /*
556          * Parts of the structure being constructed.
557          */
558         void *st = *struct_ptr; /* Target structure. */
559         asn_struct_ctx_t *ctx;  /* Decoder context */
560
561         asn_dec_rval_t rval;            /* Return value of a decoder */
562         ssize_t consumed_myself = 0;    /* Consumed bytes from ptr */
563         int edx;                        /* Element index */
564
565         /*
566          * Create the target structure if it is not present already.
567          */
568         if(st == 0) {
569                 st = *struct_ptr = CALLOC(1, specs->struct_size);
570                 if(st == 0) RETURN(RC_FAIL);
571         }
572
573         /*
574          * Restore parsing context.
575          */
576         ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
577         if(ctx->phase == 0 && !*xml_tag)
578                 ctx->phase = 1; /* Skip the outer tag checking phase */
579
580         /*
581          * Phases of XER/XML processing:
582          * Phase 0: Check that the opening tag matches our expectations.
583          * Phase 1: Processing body and reacting on closing tag.
584          * Phase 2: Processing inner type.
585          * Phase 3: Only waiting for closing tag.
586          * Phase 4: Skipping unknown extensions.
587          * Phase 5: PHASED OUT
588          */
589         for(edx = ctx->step; ctx->phase <= 4;) {
590                 pxer_chunk_type_e ch_type;      /* XER chunk type */
591                 ssize_t ch_size;                /* Chunk size */
592                 xer_check_tag_e tcv;            /* Tag check value */
593                 asn_TYPE_member_t *elm;
594
595                 /*
596                  * Go inside the member.
597                  */
598                 if(ctx->phase == 2) {
599                         asn_dec_rval_t tmprval;
600                         void *memb_ptr;         /* Pointer to the member */
601                         void **memb_ptr2;       /* Pointer to that pointer */
602
603                         elm = &td->elements[edx];
604
605                         if(elm->flags & ATF_POINTER) {
606                                 /* Member is a pointer to another structure */
607                                 memb_ptr2 = (void **)((char *)st
608                                         + elm->memb_offset);
609                         } else {
610                                 memb_ptr = (char *)st + elm->memb_offset;
611                                 memb_ptr2 = &memb_ptr;
612                         }
613
614                         /* Start/Continue decoding the inner member */
615                         tmprval = elm->type->xer_decoder(opt_codec_ctx,
616                                         elm->type, memb_ptr2, elm->name,
617                                         buf_ptr, size);
618                         XER_ADVANCE(tmprval.consumed);
619                         ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d",
620                                 elm->type->name, tmprval.code);
621                         if(tmprval.code != RC_OK)
622                                 RETURN(tmprval.code);
623                         assert(_fetch_present_idx(st,
624                                 specs->pres_offset, specs->pres_size) == 0);
625                         /* Record what we've got */
626                         _set_present_idx(st,
627                                 specs->pres_offset, specs->pres_size, edx + 1);
628                         ctx->phase = 3;
629                         /* Fall through */
630                 }
631
632                 /* No need to wait for closing tag; special mode. */
633                 if(ctx->phase == 3 && !*xml_tag) {
634                         ctx->phase = 5; /* Phase out */
635                         RETURN(RC_OK);
636                 }
637
638                 /*
639                  * Get the next part of the XML stream.
640                  */
641                 ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type);
642                 switch(ch_size) {
643                 case -1: RETURN(RC_FAIL);
644                 case 0:  RETURN(RC_WMORE);
645                 default:
646                         switch(ch_type) {
647                         case PXER_COMMENT:      /* Got XML comment */
648                         case PXER_TEXT:         /* Ignore free-standing text */
649                                 XER_ADVANCE(ch_size);   /* Skip silently */
650                                 continue;
651                         case PXER_TAG:
652                                 break;  /* Check the rest down there */
653                         }
654                 }
655
656                 tcv = xer_check_tag(buf_ptr, ch_size, xml_tag);
657                 ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d",
658                         ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
659                         ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
660                         ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
661                         ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
662                 xml_tag, tcv);
663
664                 /* Skip the extensions section */
665                 if(ctx->phase == 4) {
666                         ASN_DEBUG("skip_unknown(%d, %ld)",
667                                 tcv, (long)ctx->left);
668                         switch(xer_skip_unknown(tcv, &ctx->left)) {
669                         case -1:
670                                 ctx->phase = 5;
671                                 RETURN(RC_FAIL);
672                                 continue;
673                         case 1:
674                                 ctx->phase = 3;
675                                 /* Fall through */
676                         case 0:
677                                 XER_ADVANCE(ch_size);
678                                 continue;
679                         case 2:
680                                 ctx->phase = 3;
681                                 break;
682                         }
683                 }
684
685                 switch(tcv) {
686                 case XCT_BOTH:
687                         break;  /* No CHOICE? */
688                 case XCT_CLOSING:
689                         if(ctx->phase != 3)
690                                 break;
691                         XER_ADVANCE(ch_size);
692                         ctx->phase = 5; /* Phase out */
693                         RETURN(RC_OK);
694                 case XCT_OPENING:
695                         if(ctx->phase == 0) {
696                                 XER_ADVANCE(ch_size);
697                                 ctx->phase = 1; /* Processing body phase */
698                                 continue;
699                         }
700                         /* Fall through */
701                 case XCT_UNKNOWN_OP:
702                 case XCT_UNKNOWN_BO:
703
704                         if(ctx->phase != 1)
705                                 break;  /* Really unexpected */
706
707                         /*
708                          * Search which inner member corresponds to this tag.
709                          */
710                         for(edx = 0; edx < td->elements_count; edx++) {
711                                 elm = &td->elements[edx];
712                                 tcv = xer_check_tag(buf_ptr,ch_size,elm->name);
713                                 switch(tcv) {
714                                 case XCT_BOTH:
715                                 case XCT_OPENING:
716                                         /*
717                                          * Process this member.
718                                          */
719                                         ctx->step = edx;
720                                         ctx->phase = 2;
721                                         break;
722                                 case XCT_UNKNOWN_OP:
723                                 case XCT_UNKNOWN_BO:
724                                         continue;
725                                 default:
726                                         edx = td->elements_count;
727                                         break;  /* Phase out */
728                                 }
729                                 break;
730                         }
731                         if(edx != td->elements_count)
732                                 continue;
733
734                         /* It is expected extension */
735                         if(specs->ext_start != -1) {
736                                 ASN_DEBUG("Got anticipated extension");
737                                 /*
738                                  * Check for (XCT_BOTH or XCT_UNKNOWN_BO)
739                                  * By using a mask. Only record a pure
740                                  * <opening> tags.
741                                  */
742                                 if(tcv & XCT_CLOSING) {
743                                         /* Found </extension> without body */
744                                         ctx->phase = 3; /* Terminating */
745                                 } else {
746                                         ctx->left = 1;
747                                         ctx->phase = 4; /* Skip ...'s */
748                                 }
749                                 XER_ADVANCE(ch_size);
750                                 continue;
751                         }
752
753                         /* Fall through */
754                 default:
755                         break;
756                 }
757
758                 ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]"
759                         " (ph=%d, tag=%s)",
760                         ch_size>0?((const uint8_t *)buf_ptr)[0]:'?',
761                         ch_size>1?((const uint8_t *)buf_ptr)[1]:'?',
762                         ch_size>2?((const uint8_t *)buf_ptr)[2]:'?',
763                         ch_size>3?((const uint8_t *)buf_ptr)[3]:'?',
764                         td->name, ctx->phase, xml_tag);
765                 break;
766         }
767
768         ctx->phase = 5; /* Phase out, just in case */
769         RETURN(RC_FAIL);
770 }
771
772
773 asn_enc_rval_t
774 CHOICE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
775         int ilevel, enum xer_encoder_flags_e flags,
776                 asn_app_consume_bytes_f *cb, void *app_key) {
777         asn_CHOICE_specifics_t *specs=(asn_CHOICE_specifics_t *)td->specifics;
778         asn_enc_rval_t er;
779         int present;
780
781         if(!sptr)
782                 _ASN_ENCODE_FAILED;
783
784         /*
785          * Figure out which CHOICE element is encoded.
786          */
787         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
788
789         if(present <= 0 || present > td->elements_count) {
790                 _ASN_ENCODE_FAILED;
791         }  else {
792                 asn_enc_rval_t tmper;
793                 asn_TYPE_member_t *elm = &td->elements[present-1];
794                 void *memb_ptr;
795                 const char *mname = elm->name;
796                 unsigned int mlen = strlen(mname);
797
798                 if(elm->flags & ATF_POINTER) {
799                         memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
800                         if(!memb_ptr) _ASN_ENCODE_FAILED;
801                 } else {
802                         memb_ptr = (void *)((char *)sptr + elm->memb_offset);
803                 }
804
805                 er.encoded = 0;
806
807                 if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel);
808                 _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
809
810                 tmper = elm->type->xer_encoder(elm->type, memb_ptr,
811                                 ilevel + 1, flags, cb, app_key);
812                 if(tmper.encoded == -1) return tmper;
813
814                 _ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
815
816                 er.encoded += 5 + (2 * mlen) + tmper.encoded;
817         }
818
819         if(!(flags & XER_F_CANONICAL)) _i_ASN_TEXT_INDENT(1, ilevel - 1);
820
821         _ASN_ENCODED_OK(er);
822 cb_failed:
823         _ASN_ENCODE_FAILED;
824 }
825
826 asn_dec_rval_t
827 CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
828         asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) {
829         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
830         asn_dec_rval_t rv;
831         asn_per_constraint_t *ct;
832         asn_TYPE_member_t *elm; /* CHOICE's element */
833         void *memb_ptr;
834         void **memb_ptr2;
835         void *st = *sptr;
836         int value;
837
838         if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx))
839                 _ASN_DECODE_FAILED;
840
841         /*
842          * Create the target structure if it is not present already.
843          */
844         if(!st) {
845                 st = *sptr = CALLOC(1, specs->struct_size);
846                 if(!st) _ASN_DECODE_FAILED;
847         }
848
849         if(constraints) ct = &constraints->value;
850         else if(td->per_constraints) ct = &td->per_constraints->value;
851         else ct = 0;
852
853         if(ct && ct->flags & APC_EXTENSIBLE) {
854                 value = per_get_few_bits(pd, 1);
855                 if(value < 0) _ASN_DECODE_STARVED;
856                 if(value) ct = 0;       /* Not restricted */
857         }
858
859         if(ct && ct->range_bits >= 0) {
860                 value = per_get_few_bits(pd, ct->range_bits);
861                 if(value < 0) _ASN_DECODE_STARVED;
862                 ASN_DEBUG("CHOICE %s got index %d in range %d",
863                         td->name, value, ct->range_bits);
864                 if(value > ct->upper_bound)
865                         _ASN_DECODE_FAILED;
866         } else {
867                 if(specs->ext_start == -1)
868                         _ASN_DECODE_FAILED;
869                 value = uper_get_nsnnwn(pd);
870                 if(value < 0) _ASN_DECODE_STARVED;
871                 value += specs->ext_start;
872                 if(value >= td->elements_count)
873                         _ASN_DECODE_FAILED;
874                 ASN_DEBUG("NOT IMPLEMENTED YET");
875                 _ASN_DECODE_FAILED;
876         }
877
878         /* Adjust if canonical order is different from natural order */
879         if(specs->canonical_order)
880                 value = specs->canonical_order[value];
881
882         /* Set presence to be able to free it later */
883         _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1);
884
885         elm = &td->elements[value];
886         if(elm->flags & ATF_POINTER) {
887                 /* Member is a pointer to another structure */
888                 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
889         } else {
890                 memb_ptr = (char *)st + elm->memb_offset;
891                 memb_ptr2 = &memb_ptr;
892         }
893         ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name);
894
895         rv = elm->type->uper_decoder(opt_codec_ctx, elm->type,
896                         elm->per_constraints, memb_ptr2, pd);
897         if(rv.code != RC_OK)
898                 ASN_DEBUG("Failed to decode %s in %s (CHOICE)",
899                         elm->name, td->name);
900         return rv;
901 }
902    
903 asn_enc_rval_t
904 CHOICE_encode_uper(asn_TYPE_descriptor_t *td,
905         asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) {
906         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
907         asn_TYPE_member_t *elm; /* CHOICE's element */
908         asn_per_constraint_t *ct;
909         void *memb_ptr;
910         int present;
911
912         if(!sptr) _ASN_ENCODE_FAILED;
913
914         ASN_DEBUG("Encoding %s as CHOICE", td->name);
915
916         if(constraints) ct = &constraints->value;
917         else if(td->per_constraints) ct = &td->per_constraints->value;
918         else ct = 0;
919
920         present = _fetch_present_idx(sptr,
921                 specs->pres_offset, specs->pres_size);
922
923         /*
924          * If the structure was not initialized properly, it cannot be encoded:
925          * can't deduce what to encode in the choice type.
926          */
927         if(present <= 0 || present > td->elements_count)
928                 _ASN_ENCODE_FAILED;
929         else
930                 present--;
931
932         /* Adjust if canonical order is different from natural order */
933         if(specs->canonical_order)
934                 present = specs->canonical_order[present];
935
936         ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present);
937
938         if(ct && ct->range_bits >= 0) {
939                 if(present < ct->lower_bound
940                 || present > ct->upper_bound) {
941                         if(ct->flags & APC_EXTENSIBLE) {
942                                 if(per_put_few_bits(po, 1, 1))
943                                         _ASN_ENCODE_FAILED;
944                         } else {
945                                 _ASN_ENCODE_FAILED;
946                         }
947                         ct = 0;
948                 }
949         }
950         if(ct && ct->flags & APC_EXTENSIBLE)
951                 if(per_put_few_bits(po, 0, 1))
952                         _ASN_ENCODE_FAILED;
953
954         if(ct && ct->range_bits >= 0) {
955                 if(per_put_few_bits(po, present, ct->range_bits))
956                         _ASN_ENCODE_FAILED;
957         } else {
958                 if(specs->ext_start == -1)
959                         _ASN_ENCODE_FAILED;
960                 if(uper_put_nsnnwn(po, present - specs->ext_start))
961                         _ASN_ENCODE_FAILED;
962                 ASN_DEBUG("NOT IMPLEMENTED YET");
963                 _ASN_ENCODE_FAILED;
964         }
965
966         elm = &td->elements[present];
967         if(elm->flags & ATF_POINTER) {
968                 /* Member is a pointer to another structure */
969                 memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
970                 if(!memb_ptr) _ASN_ENCODE_FAILED;
971         } else {
972                 memb_ptr = (char *)sptr + elm->memb_offset;
973         }
974
975         return elm->type->uper_encoder(elm->type, elm->per_constraints,
976                         memb_ptr, po);
977 }
978    
979
980 int
981 CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
982                 asn_app_consume_bytes_f *cb, void *app_key) {
983         asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics;
984         int present;
985
986         if(!sptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
987
988         /*
989          * Figure out which CHOICE element is encoded.
990          */
991         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
992
993         /*
994          * Print that element.
995          */
996         if(present > 0 && present <= td->elements_count) {
997                 asn_TYPE_member_t *elm = &td->elements[present-1];
998                 const void *memb_ptr;
999
1000                 if(elm->flags & ATF_POINTER) {
1001                         memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
1002                         if(!memb_ptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1003                 } else {
1004                         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
1005                 }
1006
1007                 /* Print member's name and stuff */
1008                 if(0) {
1009                         if(cb(elm->name, strlen(elm->name), app_key) < 0
1010                         || cb(": ", 2, app_key) < 0)
1011                                 return -1;
1012                 }
1013
1014                 return elm->type->print_struct(elm->type, memb_ptr, ilevel,
1015                         cb, app_key);
1016         } else {
1017                 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
1018         }
1019 }
1020
1021 void
1022 CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
1023         asn_CHOICE_specifics_t *specs = td ? (asn_CHOICE_specifics_t *)td->specifics : NULL;
1024         int present;
1025
1026         if(!td || !ptr)
1027                 return;
1028
1029         ASN_DEBUG("Freeing %s as CHOICE", td->name);
1030
1031         /*
1032          * Figure out which CHOICE element is encoded.
1033          */
1034         present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
1035
1036         /*
1037          * Free that element.
1038          */
1039         if(present > 0 && present <= td->elements_count) {
1040                 asn_TYPE_member_t *elm = &td->elements[present-1];
1041                 void *memb_ptr;
1042
1043                 if(elm->flags & ATF_POINTER) {
1044                         memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
1045                         if(memb_ptr)
1046                                 ASN_STRUCT_FREE(*elm->type, memb_ptr);
1047                 } else {
1048                         memb_ptr = (void *)((char *)ptr + elm->memb_offset);
1049                         ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr);
1050                 }
1051         }
1052
1053         if(!contents_only) {
1054                 FREEMEM(ptr);
1055         }
1056 }
1057
1058
1059 /*
1060  * The following functions functions offer protection against -fshort-enums,
1061  * compatible with little- and big-endian machines.
1062  * If assertion is triggered, either disable -fshort-enums, or add an entry
1063  * here with the ->pres_size of your target stracture.
1064  * Unless the target structure is packed, the ".present" member
1065  * is guaranteed to be aligned properly. ASN.1 compiler itself does not
1066  * produce packed code.
1067  */
1068 static int
1069 _fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
1070         const void *present_ptr;
1071         int present;
1072
1073         present_ptr = ((const char *)struct_ptr) + pres_offset;
1074
1075         switch(pres_size) {
1076         case sizeof(int):       present =   *(const int *)present_ptr; break;
1077         case sizeof(short):     present = *(const short *)present_ptr; break;
1078         case sizeof(char):      present =  *(const char *)present_ptr; break;
1079         default:
1080                 /* ANSI C mandates enum to be equivalent to integer */
1081                 assert(pres_size != sizeof(int));
1082                 return 0;       /* If not aborted, pass back safe value */
1083         }
1084
1085         return present;
1086 }
1087
1088 static void
1089 _set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
1090         void *present_ptr;
1091         present_ptr = ((char *)struct_ptr) + pres_offset;
1092
1093         switch(pres_size) {
1094         case sizeof(int):       *(int *)present_ptr   = present; break;
1095         case sizeof(short):     *(short *)present_ptr = present; break;
1096         case sizeof(char):      *(char *)present_ptr  = present; break;
1097         default:
1098                 /* ANSI C mandates enum to be equivalent to integer */
1099                 assert(pres_size != sizeof(int));
1100         }
1101 }