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