2 * Copyright (c) 2003-2017 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
5 #include <asn_internal.h>
6 #include <constr_CHOICE.h>
8 asn_TYPE_operation_t asn_OP_CHOICE = {
10 #if !defined(ASN_DISABLE_PRINT_SUPPORT)
14 #endif /* !defined(ASN_DISABLE_PRINT_SUPPORT) */
16 #if !defined(ASN_DISABLE_BER_SUPPORT)
22 #endif /* !defined(ASN_DISABLE_BER_SUPPORT) */
23 #if !defined(ASN_DISABLE_XER_SUPPORT)
29 #endif /* !defined(ASN_DISABLE_XER_SUPPORT) */
30 #if !defined(ASN_DISABLE_JER_SUPPORT)
34 #endif /* !defined(ASN_DISABLE_JER_SUPPORT) */
35 #if !defined(ASN_DISABLE_OER_SUPPORT)
41 #endif /* !defined(ASN_DISABLE_OER_SUPPORT) */
42 #if !defined(ASN_DISABLE_UPER_SUPPORT)
48 #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) */
49 #if !defined(ASN_DISABLE_APER_SUPPORT)
55 #endif /* !defined(ASN_DISABLE_APER_SUPPORT) */
56 #if !defined(ASN_DISABLE_RFILL_SUPPORT)
60 #endif /* !defined(ASN_DISABLE_RFILL_SUPPORT) */
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;
69 assert(tag_mode == 0); (void)tag_mode;
70 assert(tag == 0); (void)tag;
73 * Figure out which CHOICE element is encoded.
75 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
77 if(present > 0 && present <= td->elements_count) {
78 const asn_TYPE_member_t *elm = &td->elements[present-1];
81 if(elm->flags & ATF_POINTER) {
82 memb_ptr = *(const void * const *)
83 ((const char *)ptr + elm->memb_offset);
85 memb_ptr = (const void *)
86 ((const char *)ptr + elm->memb_offset);
89 return asn_TYPE_outmost_tag(elm->type, memb_ptr,
90 elm->tag_mode, elm->tag);
92 return (ber_tlv_tag_t)-1;
97 * See the definitions.
99 static const void *_get_member_ptr(const asn_TYPE_descriptor_t *,
100 const void *sptr, asn_TYPE_member_t **elm,
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;
111 ASN__CTFAIL(app_key, td, sptr,
112 "%s: value not given (%s:%d)",
113 td->name, __FILE__, __LINE__);
118 * Figure out which CHOICE element is encoded.
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;
125 if(elm->flags & ATF_POINTER) {
126 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
130 ASN__CTFAIL(app_key, td, sptr,
131 "%s: mandatory CHOICE element %s absent (%s:%d)",
132 td->name, elm->name, __FILE__, __LINE__);
136 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
139 if(elm->encoding_constraints.general_constraints) {
140 return elm->encoding_constraints.general_constraints(elm->type, memb_ptr,
143 return elm->type->encoding_constraints.general_constraints(elm->type,
144 memb_ptr, ctfailcb, app_key);
147 ASN__CTFAIL(app_key, td, sptr,
148 "%s: no CHOICE element given (%s:%d)",
149 td->name, __FILE__, __LINE__);
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;
164 ASN_DEBUG("Freeing %s as CHOICE", td->name);
167 * Figure out which CHOICE element is encoded.
169 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
174 if(present > 0 && present <= td->elements_count) {
175 asn_TYPE_member_t *elm = &td->elements[present-1];
178 if(elm->flags & ATF_POINTER) {
179 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
181 ASN_STRUCT_FREE(*elm->type, memb_ptr);
183 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
184 ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr);
189 case ASFM_FREE_EVERYTHING:
192 case ASFM_FREE_UNDERLYING:
194 case ASFM_FREE_UNDERLYING_AND_RESET:
195 memset(ptr, 0, specs->struct_size);
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.
211 _fetch_present_idx(const void *struct_ptr, unsigned pres_offset,
212 unsigned pres_size) {
213 const void *present_ptr;
216 present_ptr = ((const char *)struct_ptr) + pres_offset;
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;
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 */
232 _set_present_idx(void *struct_ptr, unsigned pres_offset, unsigned pres_size,
235 present_ptr = ((char *)struct_ptr) + pres_offset;
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;
242 /* ANSI C mandates enum to be equivalent to integer */
243 assert(pres_size != sizeof(int));
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;
261 * Figure out which CHOICE element is encoded.
263 present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
264 *present_out = present;
267 * The presence index is intentionally 1-based to avoid
268 * treating zeroed structure as a valid one.
270 if(present > 0 && present <= td->elements_count) {
271 asn_TYPE_member_t *const elm = &td->elements[present - 1];
272 const void *memb_ptr;
274 if(elm->flags & ATF_POINTER) {
276 *(const void *const *)((const char *)sptr + elm->memb_offset);
278 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
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);
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) {
307 } else if(!amember) {
315 * Return the 1-based choice variant presence index.
316 * Returns 0 in case of error.
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);
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.
332 CHOICE_variant_set_presence(const asn_TYPE_descriptor_t *td, void *sptr,
334 const asn_CHOICE_specifics_t *specs =
335 (const asn_CHOICE_specifics_t *)td->specifics;
336 unsigned old_present;
342 if(present > td->elements_count)
346 _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size);
347 if(present == old_present)
350 if(old_present != 0) {
351 assert(old_present <= td->elements_count);
352 ASN_STRUCT_RESET(*td, sptr);
355 _set_present_idx(sptr, specs->pres_offset, specs->pres_size, present);