blob: 4ac71a64e4acd7f3bd2d98763409bf5428d62fb5 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <constr_CHOICE.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00006#include <assert.h>
7
8/*
9 * Number of bytes left for this structure.
10 * (ctx->left) indicates the number of bytes _transferred_ for the structure.
11 * (size) contains the number of bytes in the buffer passed.
12 */
Lev Walkinec1ffd42004-08-18 04:53:32 +000013#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left)
Lev Walkinf15320b2004-06-03 03:38:44 +000014
15/*
16 * If the subprocessor function returns with an indication that it wants
17 * more data, it may well be a fatal decoding problem, because the
18 * size is constrained by the <TLV>'s L, even if the buffer size allows
19 * reading more data.
20 * For example, consider the buffer containing the following TLVs:
21 * <T:5><L:1><V> <T:6>...
22 * The TLV length clearly indicates that one byte is expected in V, but
23 * if the V processor returns with "want more data" even if the buffer
24 * contains way more data than the V processor have seen.
25 */
Lev Walkind9bd7752004-06-05 08:17:50 +000026#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size)
Lev Walkinf15320b2004-06-03 03:38:44 +000027
28/*
29 * This macro "eats" the part of the buffer which is definitely "consumed",
30 * i.e. was correctly converted into local representation or rightfully skipped.
31 */
32#define ADVANCE(num_bytes) do { \
33 size_t num = num_bytes; \
Lev Walkin4d9528c2004-08-11 08:10:13 +000034 (char *)ptr += num; \
Lev Walkinf15320b2004-06-03 03:38:44 +000035 size -= num; \
36 if(ctx->left >= 0) \
37 ctx->left -= num; \
38 consumed_myself += num; \
39 } while(0)
40
41/*
42 * Switch to the next phase of parsing.
43 */
44#define NEXT_PHASE(ctx) do { \
45 ctx->phase++; \
46 ctx->step = 0; \
47 } while(0)
48
49/*
50 * Return a standardized complex structure.
51 */
52#define RETURN(_code) do { \
53 rval.code = _code; \
54 rval.consumed = consumed_myself;\
55 return rval; \
56 } while(0)
57
58/*
59 * See the definitions.
60 */
Lev Walkin91f5cd02004-08-11 09:10:59 +000061static int _fetch_present_idx(const void *struct_ptr, int off, int size);
62static void _set_present_idx(void *sptr, int offset, int size, int pres);
Lev Walkinf15320b2004-06-03 03:38:44 +000063
64/*
65 * Tags are canonically sorted in the tag to member table.
66 */
67static int
68_search4tag(const void *ap, const void *bp) {
Lev Walkinc2346572004-08-11 09:07:36 +000069 const asn1_TYPE_tag2member_t *a = (const asn1_TYPE_tag2member_t *)ap;
70 const asn1_TYPE_tag2member_t *b = (const asn1_TYPE_tag2member_t *)bp;
71
Lev Walkinf15320b2004-06-03 03:38:44 +000072 int a_class = BER_TAG_CLASS(a->el_tag);
73 int b_class = BER_TAG_CLASS(b->el_tag);
74
75 if(a_class == b_class) {
76 ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
77 ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
78
79 if(a_value == b_value)
80 return 0;
81 else if(a_value < b_value)
82 return -1;
83 else
84 return 1;
85 } else if(a_class < b_class) {
86 return -1;
87 } else {
88 return 1;
89 }
90}
91
92/*
93 * The decoder of the CHOICE type.
94 */
95ber_dec_rval_t
Lev Walkin449f8322004-08-20 13:23:42 +000096CHOICE_decode_ber(asn1_TYPE_descriptor_t *td,
Lev Walkinf15320b2004-06-03 03:38:44 +000097 void **struct_ptr, void *ptr, size_t size, int tag_mode) {
98 /*
99 * Bring closer parts of structure description.
100 */
Lev Walkin449f8322004-08-20 13:23:42 +0000101 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
102 asn1_TYPE_member_t *elements = td->elements;
Lev Walkinf15320b2004-06-03 03:38:44 +0000103
104 /*
105 * Parts of the structure being constructed.
106 */
107 void *st = *struct_ptr; /* Target structure. */
108 ber_dec_ctx_t *ctx; /* Decoder context */
109
110 ber_tlv_tag_t tlv_tag; /* T from TLV */
111 ssize_t tag_len; /* Length of TLV's T */
112 //ber_tlv_len_t tlv_len; /* L from TLV */
113 ber_dec_rval_t rval; /* Return code from subparsers */
114
115 ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
116
Lev Walkin449f8322004-08-20 13:23:42 +0000117 ASN_DEBUG("Decoding %s as CHOICE", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000118
119 /*
120 * Create the target structure if it is not present already.
121 */
122 if(st == 0) {
123 st = *struct_ptr = CALLOC(1, specs->struct_size);
124 if(st == 0) {
125 RETURN(RC_FAIL);
126 }
127 }
128
129 /*
130 * Restore parsing context.
131 */
Lev Walkin4d9528c2004-08-11 08:10:13 +0000132 ctx = (ber_dec_ctx_t *)((char *)st + specs->ctx_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000133
134 /*
135 * Start to parse where left previously
136 */
137 switch(ctx->phase) {
138 case 0:
139 /*
140 * PHASE 0.
141 * Check that the set of tags associated with given structure
142 * perfectly fits our expectations.
143 */
144
Lev Walkin449f8322004-08-20 13:23:42 +0000145 if(tag_mode || td->tags_count) {
146 rval = ber_check_tags(td, ctx, ptr, size,
Lev Walkinf15320b2004-06-03 03:38:44 +0000147 tag_mode, &ctx->left, 0);
148 if(rval.code != RC_OK) {
149 ASN_DEBUG("%s tagging check failed: %d",
Lev Walkin449f8322004-08-20 13:23:42 +0000150 td->name, rval.code);
Lev Walkinf15320b2004-06-03 03:38:44 +0000151 consumed_myself += rval.consumed;
152 RETURN(rval.code);
153 }
154
155 if(ctx->left >= 0) {
156 /* ?Substracted below! */
157 ctx->left += rval.consumed;
158 }
159 ADVANCE(rval.consumed);
160 } else {
161 ctx->left = -1;
162 }
163
164 NEXT_PHASE(ctx);
165
166 ASN_DEBUG("Structure consumes %ld bytes, buffer %ld",
167 (long)ctx->left, (long)size);
168
169 /* Fall through */
170 case 1:
171 /*
172 * Fetch the T from TLV.
173 */
174 tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
Lev Walkin449f8322004-08-20 13:23:42 +0000175 ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len);
Lev Walkinf15320b2004-06-03 03:38:44 +0000176 switch(tag_len) {
177 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
178 /* Fall through */
179 case -1: RETURN(RC_FAIL);
180 }
181
182 do {
Lev Walkin4c36e302004-06-06 07:20:02 +0000183 asn1_TYPE_tag2member_t *t2m;
184 asn1_TYPE_tag2member_t key;
Lev Walkinf15320b2004-06-03 03:38:44 +0000185
186 key.el_tag = tlv_tag;
Lev Walkinc2346572004-08-11 09:07:36 +0000187 (void *)t2m = bsearch(&key,
188 specs->tag2el, specs->tag2el_count,
Lev Walkinf15320b2004-06-03 03:38:44 +0000189 sizeof(specs->tag2el[0]), _search4tag);
190 if(t2m) {
191 /*
192 * Found the element corresponding to the tag.
193 */
194 NEXT_PHASE(ctx);
195 ctx->step = t2m->el_no;
196 break;
197 } else if(specs->extensible == 0) {
198 ASN_DEBUG("Unexpected tag %s "
199 "in non-extensible CHOICE %s",
Lev Walkin449f8322004-08-20 13:23:42 +0000200 ber_tlv_tag_string(tlv_tag), td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000201 RETURN(RC_FAIL);
202 } else {
203 /* Skip this tag */
204 ssize_t skip;
205
206 ASN_DEBUG("Skipping unknown tag %s",
207 ber_tlv_tag_string(tlv_tag));
208
209 skip = ber_skip_length(
210 BER_TLV_CONSTRUCTED(ptr),
Lev Walkin4d9528c2004-08-11 08:10:13 +0000211 (char *)ptr + tag_len, LEFT - tag_len);
Lev Walkinf15320b2004-06-03 03:38:44 +0000212
213 switch(skip) {
214 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
215 /* Fall through */
216 case -1: RETURN(RC_FAIL);
217 }
218
219 ADVANCE(skip + tag_len);
220 RETURN(RC_OK);
221 }
222 } while(0);
223
224 case 2:
225 /*
226 * PHASE 2.
227 * Read in the element.
228 */
229 do {
Lev Walkin449f8322004-08-20 13:23:42 +0000230 asn1_TYPE_member_t *elm;/* CHOICE's element */
Lev Walkinf15320b2004-06-03 03:38:44 +0000231 void *memb_ptr; /* Pointer to the member */
Lev Walkinc2346572004-08-11 09:07:36 +0000232 void **memb_ptr2; /* Pointer to that pointer */
Lev Walkinf15320b2004-06-03 03:38:44 +0000233
234 elm = &elements[ctx->step];
235
236 /*
237 * Compute the position of the member inside a structure,
238 * and also a type of containment (it may be contained
239 * as pointer or using inline inclusion).
240 */
241 if(elm->optional) {
242 /* Optional member, hereby, a simple pointer */
Lev Walkinc2346572004-08-11 09:07:36 +0000243 memb_ptr2 = (void **)((char *)st + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000244 } else {
245 /*
246 * A pointer to a pointer
247 * holding the start of the structure
248 */
249 memb_ptr = (char *)st + elm->memb_offset;
250 memb_ptr2 = &memb_ptr;
251 }
252 /*
253 * Invoke the member fetch routine according to member's type
254 */
Lev Walkinc2346572004-08-11 09:07:36 +0000255 rval = elm->type->ber_decoder(elm->type,
Lev Walkinf15320b2004-06-03 03:38:44 +0000256 memb_ptr2, ptr, LEFT,
257 elm->tag_mode);
258 switch(rval.code) {
259 case RC_OK:
260 _set_present_idx(st, specs->pres_offset,
261 specs->pres_size, ctx->step + 1);
262 break;
263 case RC_WMORE: /* More data expected */
264 if(!SIZE_VIOLATION) {
265 ADVANCE(rval.consumed);
266 RETURN(RC_WMORE);
267 }
268 RETURN(RC_FAIL);
269 case RC_FAIL: /* Fatal error */
270 RETURN(rval.code);
271 } /* switch(rval) */
272
273 ADVANCE(rval.consumed);
274 } while(0);
275
276 NEXT_PHASE(ctx);
277
278 /* Fall through */
279 case 3:
280 ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
Lev Walkin449f8322004-08-20 13:23:42 +0000281 td->name, (long)ctx->left, (long)size,
282 tag_mode, td->tags_count);
Lev Walkinf15320b2004-06-03 03:38:44 +0000283
284 if(ctx->left > 0) {
285 /*
286 * The type must be fully decoded
287 * by the CHOICE member-specific decoder.
288 */
289 RETURN(RC_FAIL);
290 }
291
292 if(ctx->left == -1
Lev Walkin449f8322004-08-20 13:23:42 +0000293 && !(tag_mode || td->tags_count)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000294 /*
295 * This is an untagged CHOICE.
296 * It doesn't contain nothing
297 * except for the member itself, including all its tags.
298 * The decoding is completed.
299 */
300 NEXT_PHASE(ctx);
301 break;
302 }
303
304 /*
305 * Read in the "end of data chunks"'s.
306 */
307 while(ctx->left < 0) {
308 ssize_t tl;
309
310 tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
311 switch(tl) {
312 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
313 /* Fall through */
314 case -1: RETURN(RC_FAIL);
315 }
316
317 /*
318 * Expected <0><0>...
319 */
320 if(((uint8_t *)ptr)[0] == 0) {
321 if(LEFT < 2) {
322 if(SIZE_VIOLATION)
323 RETURN(RC_FAIL);
324 else
325 RETURN(RC_WMORE);
326 } else if(((uint8_t *)ptr)[1] == 0) {
327 /*
328 * Correctly finished with <0><0>.
329 */
330 continue;
331 }
332 } else {
333 ASN_DEBUG("Unexpected continuation in %s",
Lev Walkin449f8322004-08-20 13:23:42 +0000334 td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000335 RETURN(RC_FAIL);
336 }
337
338 ADVANCE(2);
339 ctx->left++;
340 }
341
342 NEXT_PHASE(ctx);
343 case 4:
344 /* No meaningful work here */
345 break;
346 }
347
348 RETURN(RC_OK);
349}
350
351der_enc_rval_t
Lev Walkin449f8322004-08-20 13:23:42 +0000352CHOICE_encode_der(asn1_TYPE_descriptor_t *td,
Lev Walkinf15320b2004-06-03 03:38:44 +0000353 void *struct_ptr,
354 int tag_mode, ber_tlv_tag_t tag,
355 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin449f8322004-08-20 13:23:42 +0000356 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
357 asn1_TYPE_member_t *elm; /* CHOICE element */
Lev Walkinf15320b2004-06-03 03:38:44 +0000358 der_enc_rval_t erval;
359 void *memb_ptr;
360 size_t computed_size = 0;
361 int present;
362
363 ASN_DEBUG("%s %s as CHOICE",
Lev Walkin449f8322004-08-20 13:23:42 +0000364 cb?"Encoding":"Estimating", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000365
366 present = _fetch_present_idx(struct_ptr,
367 specs->pres_offset, specs->pres_size);
368
369 /*
370 * If the structure was not initialized, it cannot be encoded:
371 * can't deduce what to encode in the choice type.
372 */
Lev Walkin449f8322004-08-20 13:23:42 +0000373 if(present <= 0 || present > td->elements_count) {
374 if(present == 0 && td->elements_count == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000375 /* The CHOICE is empty?! */
376 erval.encoded = 0;
377 return erval;
378 }
379 erval.encoded = -1;
Lev Walkin449f8322004-08-20 13:23:42 +0000380 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000381 erval.structure_ptr = struct_ptr;
382 return erval;
383 }
384
385 /*
386 * Seek over the present member of the structure.
387 */
Lev Walkin449f8322004-08-20 13:23:42 +0000388 elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000389 if(elm->optional) {
390 memb_ptr = *(void **)((char *)struct_ptr + elm->memb_offset);
391 if(memb_ptr == 0) {
392 erval.encoded = 0;
393 return erval;
394 }
395 } else {
396 memb_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
397 }
398
399 /*
400 * If the CHOICE itself is tagged EXPLICIT:
401 * T ::= [2] EXPLICIT CHOICE { ... }
402 * Then emit the appropriate tags.
403 */
Lev Walkin449f8322004-08-20 13:23:42 +0000404 if(tag_mode == 1 || td->tags_count) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000405 /*
406 * For this, we need to pre-compute the member.
407 */
408 ssize_t ret;
409
410 /* Encode member with its tag */
411 erval = elm->type->der_encoder(elm->type, memb_ptr,
412 elm->tag_mode, elm->tag, 0, 0);
413 if(erval.encoded == -1)
414 return erval;
415
416 /* Encode CHOICE with parent or my own tag */
Lev Walkin449f8322004-08-20 13:23:42 +0000417 ret = der_write_tags(td, erval.encoded, tag_mode, tag,
Lev Walkinf15320b2004-06-03 03:38:44 +0000418 cb, app_key);
419 if(ret == -1) {
420 erval.encoded = -1;
Lev Walkin449f8322004-08-20 13:23:42 +0000421 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000422 erval.structure_ptr = struct_ptr;
423 return erval;
424 }
425 computed_size += ret;
426 }
427
428 /*
429 * Encode the single underlying member.
430 */
431 erval = elm->type->der_encoder(elm->type, memb_ptr,
432 elm->tag_mode, elm->tag, cb, app_key);
433 if(erval.encoded == -1)
434 return erval;
435
436 ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
437 (long)erval.encoded, (long)computed_size);
438
439 erval.encoded += computed_size;
440
441 return erval;
442}
443
444ber_tlv_tag_t
445CHOICE_outmost_tag(asn1_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) {
Lev Walkinc2346572004-08-11 09:07:36 +0000446 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000447 int present;
448
449 assert(tag_mode == 0);
450 assert(tag == 0);
451
452 /*
453 * Figure out which CHOICE element is encoded.
454 */
455 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
456
Lev Walkin449f8322004-08-20 13:23:42 +0000457 if(present > 0 || present <= td->elements_count) {
458 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkin70e70282004-06-05 01:45:48 +0000459 const void *memb_ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000460
461 if(elm->optional) {
Lev Walkin70e70282004-06-05 01:45:48 +0000462 memb_ptr = *(const void * const *)
463 ((const char *)ptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000464 } else {
Lev Walkin70e70282004-06-05 01:45:48 +0000465 memb_ptr = (const void *)
466 ((const char *)ptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000467 }
468
469 return asn1_TYPE_outmost_tag(elm->type, memb_ptr,
470 elm->tag_mode, elm->tag);
471 } else {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000472 return (ber_tlv_tag_t)-1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000473 }
474}
475
476int
477CHOICE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
478 asn_app_consume_bytes_f *app_errlog, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000479 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000480 int present;
481
482 if(!sptr) {
Lev Walkinba4e5182004-08-11 09:44:13 +0000483 _ASN_ERRLOG(app_errlog, app_key,
Lev Walkin16835b62004-08-22 13:47:59 +0000484 "%s: value not given (%s:%d)",
485 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +0000486 return -1;
487 }
488
489 /*
490 * Figure out which CHOICE element is encoded.
491 */
492 present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
Lev Walkin449f8322004-08-20 13:23:42 +0000493 if(present > 0 && present <= td->elements_count) {
494 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000495 const void *memb_ptr;
496
497 if(elm->optional) {
498 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
499 if(!memb_ptr) return 0;
500 } else {
501 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
502 }
503
Lev Walkin449f8322004-08-20 13:23:42 +0000504 if(elm->memb_constraints) {
505 return elm->memb_constraints(elm->type, memb_ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000506 app_errlog, app_key);
Lev Walkin449f8322004-08-20 13:23:42 +0000507 } else {
508 int ret = elm->type->check_constraints(elm->type,
509 memb_ptr, app_errlog, app_key);
510 /*
511 * Cannot inherit it eralier:
512 * need to make sure we get the updated version.
513 */
514 elm->memb_constraints = elm->type->check_constraints;
515 return ret;
516 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000517 } else {
Lev Walkinba4e5182004-08-11 09:44:13 +0000518 _ASN_ERRLOG(app_errlog, app_key,
Lev Walkin16835b62004-08-22 13:47:59 +0000519 "%s: no CHOICE element given",
520 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +0000521 return -1;
522 }
523}
524
525int
526CHOICE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
527 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000528 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000529 int present;
530
531 if(!sptr) return cb("<absent>", 8, app_key);
532
533 /*
534 * Figure out which CHOICE element is encoded.
535 */
536 present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
537
538 /*
539 * Free that element.
540 */
Lev Walkin449f8322004-08-20 13:23:42 +0000541 if(present > 0 && present <= td->elements_count) {
542 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000543 const void *memb_ptr;
544
545 if(elm->optional) {
546 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
547 if(!memb_ptr) return cb("<absent>", 8, app_key);
548 } else {
549 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
550 }
551
552 /* Print member's name and stuff */
553 if(cb(elm->name, strlen(elm->name), app_key)
554 || cb(": ", 2, app_key))
555 return -1;
556
557 return elm->type->print_struct(elm->type, memb_ptr, ilevel,
558 cb, app_key);
559 } else {
560 return cb("<absent>", 8, app_key);
561 }
562}
563
564void
565CHOICE_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000566 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000567 int present;
568
569 if(!td || !ptr)
570 return;
571
572 ASN_DEBUG("Freeing %s as CHOICE", td->name);
573
574 /*
575 * Figure out which CHOICE element is encoded.
576 */
577 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
578
579 /*
580 * Free that element.
581 */
Lev Walkin449f8322004-08-20 13:23:42 +0000582 if(present > 0 && present <= td->elements_count) {
583 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000584 void *memb_ptr;
585
586 if(elm->optional) {
587 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
588 if(memb_ptr)
589 elm->type->free_struct(elm->type, memb_ptr, 0);
590 } else {
591 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
592 elm->type->free_struct(elm->type, memb_ptr, 1);
593 }
594 }
595
596 if(!contents_only) {
597 FREEMEM(ptr);
598 }
599}
600
601
602/*
603 * The following functions functions offer protection against -fshort-enums,
604 * compatible with little- and big-endian machines.
605 * If assertion is triggered, either disable -fshort-enums, or add an entry
606 * here with the ->pres_size of your target stracture.
607 * Unless the target structure is packed, the ".present" member
608 * is guaranteed to be aligned properly. ASN.1 compiler itself does not
609 * produce packed code.
610 */
Lev Walkin91f5cd02004-08-11 09:10:59 +0000611static int
Lev Walkinf15320b2004-06-03 03:38:44 +0000612_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
613 const void *present_ptr;
614 int present;
615
616 present_ptr = ((const char *)struct_ptr) + pres_offset;
617
618 switch(pres_size) {
619 case sizeof(int): present = *(const int *)present_ptr; break;
620 case sizeof(short): present = *(const short *)present_ptr; break;
621 case sizeof(char): present = *(const char *)present_ptr; break;
622 default:
623 /* ANSI C mandates enum to be equivalent to integer */
624 assert(pres_size != sizeof(int));
625 return 0; /* If not aborted, pass back safe value */
626 }
627
628 return present;
629}
630
Lev Walkin91f5cd02004-08-11 09:10:59 +0000631static void
Lev Walkinf15320b2004-06-03 03:38:44 +0000632_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
633 void *present_ptr;
634 present_ptr = ((char *)struct_ptr) + pres_offset;
635
636 switch(pres_size) {
637 case sizeof(int): *(int *)present_ptr = present; break;
638 case sizeof(short): *(short *)present_ptr = present; break;
639 case sizeof(char): *(char *)present_ptr = present; break;
640 default:
641 /* ANSI C mandates enum to be equivalent to integer */
642 assert(pres_size != sizeof(int));
643 }
644}