Coverage Report

Created: 2026-07-14 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}