blob: 3fbf194ac51f7a11e2de7ab18a5725c2e36671b7 [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 Walkin449f8322004-08-20 13:23:42 +0000255 printf("elm->name = %s\n", elm->name);
256 printf("elm->td = %p\n", elm->type);
257 printf("elm->td->name = %s\n", elm->type->name);
Lev Walkinc2346572004-08-11 09:07:36 +0000258 rval = elm->type->ber_decoder(elm->type,
Lev Walkinf15320b2004-06-03 03:38:44 +0000259 memb_ptr2, ptr, LEFT,
260 elm->tag_mode);
261 switch(rval.code) {
262 case RC_OK:
263 _set_present_idx(st, specs->pres_offset,
264 specs->pres_size, ctx->step + 1);
265 break;
266 case RC_WMORE: /* More data expected */
267 if(!SIZE_VIOLATION) {
268 ADVANCE(rval.consumed);
269 RETURN(RC_WMORE);
270 }
271 RETURN(RC_FAIL);
272 case RC_FAIL: /* Fatal error */
273 RETURN(rval.code);
274 } /* switch(rval) */
275
276 ADVANCE(rval.consumed);
277 } while(0);
278
279 NEXT_PHASE(ctx);
280
281 /* Fall through */
282 case 3:
283 ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d",
Lev Walkin449f8322004-08-20 13:23:42 +0000284 td->name, (long)ctx->left, (long)size,
285 tag_mode, td->tags_count);
Lev Walkinf15320b2004-06-03 03:38:44 +0000286
287 if(ctx->left > 0) {
288 /*
289 * The type must be fully decoded
290 * by the CHOICE member-specific decoder.
291 */
292 RETURN(RC_FAIL);
293 }
294
295 if(ctx->left == -1
Lev Walkin449f8322004-08-20 13:23:42 +0000296 && !(tag_mode || td->tags_count)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000297 /*
298 * This is an untagged CHOICE.
299 * It doesn't contain nothing
300 * except for the member itself, including all its tags.
301 * The decoding is completed.
302 */
303 NEXT_PHASE(ctx);
304 break;
305 }
306
307 /*
308 * Read in the "end of data chunks"'s.
309 */
310 while(ctx->left < 0) {
311 ssize_t tl;
312
313 tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
314 switch(tl) {
315 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
316 /* Fall through */
317 case -1: RETURN(RC_FAIL);
318 }
319
320 /*
321 * Expected <0><0>...
322 */
323 if(((uint8_t *)ptr)[0] == 0) {
324 if(LEFT < 2) {
325 if(SIZE_VIOLATION)
326 RETURN(RC_FAIL);
327 else
328 RETURN(RC_WMORE);
329 } else if(((uint8_t *)ptr)[1] == 0) {
330 /*
331 * Correctly finished with <0><0>.
332 */
333 continue;
334 }
335 } else {
336 ASN_DEBUG("Unexpected continuation in %s",
Lev Walkin449f8322004-08-20 13:23:42 +0000337 td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000338 RETURN(RC_FAIL);
339 }
340
341 ADVANCE(2);
342 ctx->left++;
343 }
344
345 NEXT_PHASE(ctx);
346 case 4:
347 /* No meaningful work here */
348 break;
349 }
350
351 RETURN(RC_OK);
352}
353
354der_enc_rval_t
Lev Walkin449f8322004-08-20 13:23:42 +0000355CHOICE_encode_der(asn1_TYPE_descriptor_t *td,
Lev Walkinf15320b2004-06-03 03:38:44 +0000356 void *struct_ptr,
357 int tag_mode, ber_tlv_tag_t tag,
358 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin449f8322004-08-20 13:23:42 +0000359 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
360 asn1_TYPE_member_t *elm; /* CHOICE element */
Lev Walkinf15320b2004-06-03 03:38:44 +0000361 der_enc_rval_t erval;
362 void *memb_ptr;
363 size_t computed_size = 0;
364 int present;
365
366 ASN_DEBUG("%s %s as CHOICE",
Lev Walkin449f8322004-08-20 13:23:42 +0000367 cb?"Encoding":"Estimating", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000368
369 present = _fetch_present_idx(struct_ptr,
370 specs->pres_offset, specs->pres_size);
371
372 /*
373 * If the structure was not initialized, it cannot be encoded:
374 * can't deduce what to encode in the choice type.
375 */
Lev Walkin449f8322004-08-20 13:23:42 +0000376 if(present <= 0 || present > td->elements_count) {
377 if(present == 0 && td->elements_count == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000378 /* The CHOICE is empty?! */
379 erval.encoded = 0;
380 return erval;
381 }
382 erval.encoded = -1;
Lev Walkin449f8322004-08-20 13:23:42 +0000383 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000384 erval.structure_ptr = struct_ptr;
385 return erval;
386 }
387
388 /*
389 * Seek over the present member of the structure.
390 */
Lev Walkin449f8322004-08-20 13:23:42 +0000391 elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000392 if(elm->optional) {
393 memb_ptr = *(void **)((char *)struct_ptr + elm->memb_offset);
394 if(memb_ptr == 0) {
395 erval.encoded = 0;
396 return erval;
397 }
398 } else {
399 memb_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
400 }
401
402 /*
403 * If the CHOICE itself is tagged EXPLICIT:
404 * T ::= [2] EXPLICIT CHOICE { ... }
405 * Then emit the appropriate tags.
406 */
Lev Walkin449f8322004-08-20 13:23:42 +0000407 if(tag_mode == 1 || td->tags_count) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000408 /*
409 * For this, we need to pre-compute the member.
410 */
411 ssize_t ret;
412
413 /* Encode member with its tag */
414 erval = elm->type->der_encoder(elm->type, memb_ptr,
415 elm->tag_mode, elm->tag, 0, 0);
416 if(erval.encoded == -1)
417 return erval;
418
419 /* Encode CHOICE with parent or my own tag */
Lev Walkin449f8322004-08-20 13:23:42 +0000420 ret = der_write_tags(td, erval.encoded, tag_mode, tag,
Lev Walkinf15320b2004-06-03 03:38:44 +0000421 cb, app_key);
422 if(ret == -1) {
423 erval.encoded = -1;
Lev Walkin449f8322004-08-20 13:23:42 +0000424 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000425 erval.structure_ptr = struct_ptr;
426 return erval;
427 }
428 computed_size += ret;
429 }
430
431 /*
432 * Encode the single underlying member.
433 */
434 erval = elm->type->der_encoder(elm->type, memb_ptr,
435 elm->tag_mode, elm->tag, cb, app_key);
436 if(erval.encoded == -1)
437 return erval;
438
439 ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
440 (long)erval.encoded, (long)computed_size);
441
442 erval.encoded += computed_size;
443
444 return erval;
445}
446
447ber_tlv_tag_t
448CHOICE_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 +0000449 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000450 int present;
451
452 assert(tag_mode == 0);
453 assert(tag == 0);
454
455 /*
456 * Figure out which CHOICE element is encoded.
457 */
458 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
459
Lev Walkin449f8322004-08-20 13:23:42 +0000460 if(present > 0 || present <= td->elements_count) {
461 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkin70e70282004-06-05 01:45:48 +0000462 const void *memb_ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000463
464 if(elm->optional) {
Lev Walkin70e70282004-06-05 01:45:48 +0000465 memb_ptr = *(const void * const *)
466 ((const char *)ptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000467 } else {
Lev Walkin70e70282004-06-05 01:45:48 +0000468 memb_ptr = (const void *)
469 ((const char *)ptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000470 }
471
472 return asn1_TYPE_outmost_tag(elm->type, memb_ptr,
473 elm->tag_mode, elm->tag);
474 } else {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000475 return (ber_tlv_tag_t)-1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000476 }
477}
478
479int
480CHOICE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
481 asn_app_consume_bytes_f *app_errlog, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000482 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000483 int present;
484
485 if(!sptr) {
Lev Walkinba4e5182004-08-11 09:44:13 +0000486 _ASN_ERRLOG(app_errlog, app_key,
487 "%s: value not given", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000488 return -1;
489 }
490
491 /*
492 * Figure out which CHOICE element is encoded.
493 */
494 present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
Lev Walkin449f8322004-08-20 13:23:42 +0000495 if(present > 0 && present <= td->elements_count) {
496 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000497 const void *memb_ptr;
498
499 if(elm->optional) {
500 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
501 if(!memb_ptr) return 0;
502 } else {
503 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
504 }
505
Lev Walkin449f8322004-08-20 13:23:42 +0000506 if(elm->memb_constraints) {
507 return elm->memb_constraints(elm->type, memb_ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000508 app_errlog, app_key);
Lev Walkin449f8322004-08-20 13:23:42 +0000509 } else {
510 int ret = elm->type->check_constraints(elm->type,
511 memb_ptr, app_errlog, app_key);
512 /*
513 * Cannot inherit it eralier:
514 * need to make sure we get the updated version.
515 */
516 elm->memb_constraints = elm->type->check_constraints;
517 return ret;
518 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000519 } else {
Lev Walkinba4e5182004-08-11 09:44:13 +0000520 _ASN_ERRLOG(app_errlog, app_key,
521 "%s: no CHOICE element given", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000522 return -1;
523 }
524}
525
526int
527CHOICE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
528 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000529 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000530 int present;
531
532 if(!sptr) return cb("<absent>", 8, app_key);
533
534 /*
535 * Figure out which CHOICE element is encoded.
536 */
537 present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
538
539 /*
540 * Free that element.
541 */
Lev Walkin449f8322004-08-20 13:23:42 +0000542 if(present > 0 && present <= td->elements_count) {
543 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000544 const void *memb_ptr;
545
546 if(elm->optional) {
547 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
548 if(!memb_ptr) return cb("<absent>", 8, app_key);
549 } else {
550 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
551 }
552
553 /* Print member's name and stuff */
554 if(cb(elm->name, strlen(elm->name), app_key)
555 || cb(": ", 2, app_key))
556 return -1;
557
558 return elm->type->print_struct(elm->type, memb_ptr, ilevel,
559 cb, app_key);
560 } else {
561 return cb("<absent>", 8, app_key);
562 }
563}
564
565void
566CHOICE_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000567 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000568 int present;
569
570 if(!td || !ptr)
571 return;
572
573 ASN_DEBUG("Freeing %s as CHOICE", td->name);
574
575 /*
576 * Figure out which CHOICE element is encoded.
577 */
578 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
579
580 /*
581 * Free that element.
582 */
Lev Walkin449f8322004-08-20 13:23:42 +0000583 if(present > 0 && present <= td->elements_count) {
584 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000585 void *memb_ptr;
586
587 if(elm->optional) {
588 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
589 if(memb_ptr)
590 elm->type->free_struct(elm->type, memb_ptr, 0);
591 } else {
592 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
593 elm->type->free_struct(elm->type, memb_ptr, 1);
594 }
595 }
596
597 if(!contents_only) {
598 FREEMEM(ptr);
599 }
600}
601
602
603/*
604 * The following functions functions offer protection against -fshort-enums,
605 * compatible with little- and big-endian machines.
606 * If assertion is triggered, either disable -fshort-enums, or add an entry
607 * here with the ->pres_size of your target stracture.
608 * Unless the target structure is packed, the ".present" member
609 * is guaranteed to be aligned properly. ASN.1 compiler itself does not
610 * produce packed code.
611 */
Lev Walkin91f5cd02004-08-11 09:10:59 +0000612static int
Lev Walkinf15320b2004-06-03 03:38:44 +0000613_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
614 const void *present_ptr;
615 int present;
616
617 present_ptr = ((const char *)struct_ptr) + pres_offset;
618
619 switch(pres_size) {
620 case sizeof(int): present = *(const int *)present_ptr; break;
621 case sizeof(short): present = *(const short *)present_ptr; break;
622 case sizeof(char): present = *(const char *)present_ptr; break;
623 default:
624 /* ANSI C mandates enum to be equivalent to integer */
625 assert(pres_size != sizeof(int));
626 return 0; /* If not aborted, pass back safe value */
627 }
628
629 return present;
630}
631
Lev Walkin91f5cd02004-08-11 09:10:59 +0000632static void
Lev Walkinf15320b2004-06-03 03:38:44 +0000633_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
634 void *present_ptr;
635 present_ptr = ((char *)struct_ptr) + pres_offset;
636
637 switch(pres_size) {
638 case sizeof(int): *(int *)present_ptr = present; break;
639 case sizeof(short): *(short *)present_ptr = present; break;
640 case sizeof(char): *(char *)present_ptr = present; break;
641 default:
642 /* ANSI C mandates enum to be equivalent to integer */
643 assert(pres_size != sizeof(int));
644 }
645}