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