SIM-115: update simulator to use latest E2SM KPM version 3
[sim/e2-interface.git] / e2sim / asn1c / constr_CHOICE.c
1 /*
2  * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
3  * Redistribution and modifications are permitted subject to BSD license.
4  */
5 #include <asn_internal.h>
6 #include <constr_CHOICE.h>
7
8 asn_TYPE_operation_t asn_OP_CHOICE = {
9     CHOICE_free,
10 #if !defined(ASN_DISABLE_PRINT_SUPPORT)
11     CHOICE_print,
12 #else
13     0,
14 #endif  /* !defined(ASN_DISABLE_PRINT_SUPPORT) */
15     CHOICE_compare,
16 #if !defined(ASN_DISABLE_BER_SUPPORT)
17     CHOICE_decode_ber,
18     CHOICE_encode_der,
19 #else
20     0,
21     0,
22 #endif  /* !defined(ASN_DISABLE_BER_SUPPORT) */
23 #if !defined(ASN_DISABLE_XER_SUPPORT)
24     CHOICE_decode_xer,
25     CHOICE_encode_xer,
26 #else
27     0,
28     0,
29 #endif  /* !defined(ASN_DISABLE_XER_SUPPORT) */
30 #if !defined(ASN_DISABLE_JER_SUPPORT)
31     CHOICE_encode_jer,
32 #else
33     0,
34 #endif  /* !defined(ASN_DISABLE_JER_SUPPORT) */
35 #if !defined(ASN_DISABLE_OER_SUPPORT)
36     CHOICE_decode_oer,
37     CHOICE_encode_oer,
38 #else
39     0,
40     0,
41 #endif  /* !defined(ASN_DISABLE_OER_SUPPORT) */
42 #if !defined(ASN_DISABLE_UPER_SUPPORT)
43     CHOICE_decode_uper,
44     CHOICE_encode_uper,
45 #else
46     0,
47     0,
48 #endif  /* !defined(ASN_DISABLE_UPER_SUPPORT) */
49 #if !defined(ASN_DISABLE_APER_SUPPORT)
50     CHOICE_decode_aper,
51     CHOICE_encode_aper,
52 #else
53     0,
54     0,
55 #endif  /* !defined(ASN_DISABLE_APER_SUPPORT) */
56 #if !defined(ASN_DISABLE_RFILL_SUPPORT)
57     CHOICE_random_fill,
58 #else
59     0,
60 #endif  /* !defined(ASN_DISABLE_RFILL_SUPPORT) */
61     CHOICE_outmost_tag
62 };
63
64 ber_tlv_tag_t
65 CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
66     const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics;
67     unsigned present;
68
69     assert(tag_mode == 0); (void)tag_mode;
70     assert(tag == 0); (void)tag;
71
72     /*
73      * Figure out which CHOICE element is encoded.
74      */
75     present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
76
77     if(present > 0 && present <= td->elements_count) {
78         const asn_TYPE_member_t *elm = &td->elements[present-1];
79         const void *memb_ptr;
80
81         if(elm->flags & ATF_POINTER) {
82             memb_ptr = *(const void * const *)
83                     ((const char *)ptr + elm->memb_offset);
84         } else {
85             memb_ptr = (const void *)
86                     ((const char *)ptr + elm->memb_offset);
87         }
88
89         return asn_TYPE_outmost_tag(elm->type, memb_ptr,
90                                     elm->tag_mode, elm->tag);
91     } else {
92         return (ber_tlv_tag_t)-1;
93     }
94 }
95
96 /*
97  * See the definitions.
98  */
99 static const void *_get_member_ptr(const asn_TYPE_descriptor_t *,
100                                    const void *sptr, asn_TYPE_member_t **elm,
101                                    unsigned *present);
102
103 int
104 CHOICE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr,
105                   asn_app_constraint_failed_f *ctfailcb, void *app_key) {
106     const asn_CHOICE_specifics_t *specs =
107         (const asn_CHOICE_specifics_t *)td->specifics;
108     unsigned present;
109
110         if(!sptr) {
111                 ASN__CTFAIL(app_key, td, sptr,
112                         "%s: value not given (%s:%d)",
113                         td->name, __FILE__, __LINE__);
114                 return -1;
115         }
116
117         /*
118          * Figure out which CHOICE element is encoded.
119          */
120         present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
121         if(present > 0 && present <= td->elements_count) {
122                 asn_TYPE_member_t *elm = &td->elements[present-1];
123                 const void *memb_ptr;
124
125                 if(elm->flags & ATF_POINTER) {
126                         memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
127                         if(!memb_ptr) {
128                                 if(elm->optional)
129                                         return 0;
130                                 ASN__CTFAIL(app_key, td, sptr,
131                                         "%s: mandatory CHOICE element %s absent (%s:%d)",
132                                         td->name, elm->name, __FILE__, __LINE__);
133                                 return -1;
134                         }
135                 } else {
136                         memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
137                 }
138
139                 if(elm->encoding_constraints.general_constraints) {
140                         return elm->encoding_constraints.general_constraints(elm->type, memb_ptr,
141                                 ctfailcb, app_key);
142                 } else {
143                         return elm->type->encoding_constraints.general_constraints(elm->type,
144                                         memb_ptr, ctfailcb, app_key);
145                 }
146         } else {
147                 ASN__CTFAIL(app_key, td, sptr,
148                         "%s: no CHOICE element given (%s:%d)",
149                         td->name, __FILE__, __LINE__);
150                 return -1;
151         }
152 }
153
154 void
155 CHOICE_free(const asn_TYPE_descriptor_t *td, void *ptr,
156             enum asn_struct_free_method method) {
157     const asn_CHOICE_specifics_t *specs =
158         (const asn_CHOICE_specifics_t *)td->specifics;
159     unsigned present;
160
161         if(!td || !ptr)
162                 return;
163
164         ASN_DEBUG("Freeing %s as CHOICE", td->name);
165
166         /*
167          * Figure out which CHOICE element is encoded.
168          */
169         present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
170
171         /*
172          * Free that element.
173          */
174         if(present > 0 && present <= td->elements_count) {
175                 asn_TYPE_member_t *elm = &td->elements[present-1];
176                 void *memb_ptr;
177
178                 if(elm->flags & ATF_POINTER) {
179                         memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
180                         if(memb_ptr)
181                                 ASN_STRUCT_FREE(*elm->type, memb_ptr);
182                 } else {
183                         memb_ptr = (void *)((char *)ptr + elm->memb_offset);
184                         ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr);
185                 }
186         }
187
188     switch(method) {
189     case ASFM_FREE_EVERYTHING:
190         FREEMEM(ptr);
191         break;
192     case ASFM_FREE_UNDERLYING:
193         break;
194     case ASFM_FREE_UNDERLYING_AND_RESET:
195         memset(ptr, 0, specs->struct_size);
196         break;
197     }
198 }
199
200
201 /*
202  * The following functions functions offer protection against -fshort-enums,
203  * compatible with little- and big-endian machines.
204  * If assertion is triggered, either disable -fshort-enums, or add an entry
205  * here with the ->pres_size of your target stracture.
206  * Unless the target structure is packed, the ".present" member
207  * is guaranteed to be aligned properly. ASN.1 compiler itself does not
208  * produce packed code.
209  */
210 unsigned
211 _fetch_present_idx(const void *struct_ptr, unsigned pres_offset,
212                    unsigned pres_size) {
213     const void *present_ptr;
214         unsigned present;
215
216         present_ptr = ((const char *)struct_ptr) + pres_offset;
217
218         switch(pres_size) {
219         case sizeof(int):       present = *(const unsigned int *)present_ptr; break;
220         case sizeof(short):     present = *(const unsigned short *)present_ptr; break;
221         case sizeof(char):      present = *(const unsigned char *)present_ptr; break;
222         default:
223                 /* ANSI C mandates enum to be equivalent to integer */
224                 assert(pres_size != sizeof(int));
225                 return 0;       /* If not aborted, pass back safe value */
226         }
227
228         return present;
229 }
230
231 void
232 _set_present_idx(void *struct_ptr, unsigned pres_offset, unsigned pres_size,
233                  unsigned present) {
234     void *present_ptr;
235         present_ptr = ((char *)struct_ptr) + pres_offset;
236
237         switch(pres_size) {
238         case sizeof(int):       *(unsigned int *)present_ptr   = present; break;
239         case sizeof(short):     *(unsigned short *)present_ptr = present; break;
240         case sizeof(char):      *(unsigned char *)present_ptr  = present; break;
241         default:
242                 /* ANSI C mandates enum to be equivalent to integer */
243                 assert(pres_size != sizeof(int));
244         }
245 }
246
247 static const void *
248 _get_member_ptr(const asn_TYPE_descriptor_t *td, const void *sptr,
249                 asn_TYPE_member_t **elm_ptr, unsigned *present_out) {
250     const asn_CHOICE_specifics_t *specs =
251         (const asn_CHOICE_specifics_t *)td->specifics;
252     unsigned present;
253
254     if(!sptr) {
255         *elm_ptr = NULL;
256         *present_out = 0;
257         return NULL;
258     }
259
260     /*
261          * Figure out which CHOICE element is encoded.
262          */
263         present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
264     *present_out = present;
265
266     /*
267      * The presence index is intentionally 1-based to avoid
268      * treating zeroed structure as a valid one.
269      */
270         if(present > 0 && present <= td->elements_count) {
271         asn_TYPE_member_t *const elm = &td->elements[present - 1];
272         const void *memb_ptr;
273
274                 if(elm->flags & ATF_POINTER) {
275             memb_ptr =
276                 *(const void *const *)((const char *)sptr + elm->memb_offset);
277         } else {
278             memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
279         }
280         *elm_ptr = elm;
281         return memb_ptr;
282     } else {
283         *elm_ptr = NULL;
284         return NULL;
285     }
286
287 }
288
289 int
290 CHOICE_compare(const asn_TYPE_descriptor_t *td, const void *aptr, const void *bptr) {
291     asn_TYPE_member_t *aelm;
292     asn_TYPE_member_t *belm;
293     unsigned apresent = 0;
294     unsigned bpresent = 0;
295     const void *amember = _get_member_ptr(td, aptr, &aelm, &apresent);
296     const void *bmember = _get_member_ptr(td, bptr, &belm, &bpresent);
297
298     if(amember && bmember) {
299         if(apresent == bpresent) {
300             assert(aelm == belm);
301             return aelm->type->op->compare_struct(aelm->type, amember, bmember);
302         } else if(apresent < bpresent) {
303             return -1;
304         } else {
305             return 1;
306         }
307     } else if(!amember) {
308         return -1;
309     } else {
310         return 1;
311     }
312 }
313
314 /*
315  * Return the 1-based choice variant presence index.
316  * Returns 0 in case of error.
317  */
318 unsigned
319 CHOICE_variant_get_presence(const asn_TYPE_descriptor_t *td, const void *sptr) {
320     const asn_CHOICE_specifics_t *specs =
321         (const asn_CHOICE_specifics_t *)td->specifics;
322     return _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
323 }
324
325 /*
326  * Sets or resets the 1-based choice variant presence index.
327  * In case a previous index is not zero, the currently selected structure
328  * member is freed and zeroed-out first.
329  * Returns 0 on success and -1 on error.
330  */
331 int
332 CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, void *sptr,
333                             unsigned present) {
334     const asn_CHOICE_specifics_t *specs =
335         (const asn_CHOICE_specifics_t *)td->specifics;
336     unsigned old_present;
337
338     if(!sptr) {
339         return -1;
340     }
341
342     if(present > td->elements_count)
343         return -1;
344
345     old_present =
346         _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
347     if(present == old_present)
348         return 0;
349
350     if(old_present != 0) {
351         assert(old_present <= td->elements_count);
352         ASN_STRUCT_RESET(*td, sptr);
353     }
354
355     _set_present_idx(sptr, specs->pres_offset, specs->pres_size, present);
356
357     return 0;
358 }