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