blob: b7d38fbaeb289b6d258c6c54561213c203bf65a1 [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 Walkin4ce78ca2004-08-25 01:34:11 +000034 ptr = ((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 */
Lev Walkincc93b0f2004-09-10 09:18:20 +0000241 if(elm->flags & ATF_POINTER) {
242 /* Member is a pointer to another structure */
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 Walkincc93b0f2004-09-10 09:18:20 +0000389 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000390 memb_ptr = *(void **)((char *)struct_ptr + elm->memb_offset);
391 if(memb_ptr == 0) {
Lev Walkincc93b0f2004-09-10 09:18:20 +0000392 if(elm->optional) {
393 erval.encoded = 0;
394 } else {
395 /* Mandatory element absent */
396 erval.encoded = -1;
397 erval.failed_type = td;
398 erval.structure_ptr = struct_ptr;
399 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000400 return erval;
401 }
402 } else {
403 memb_ptr = (void *)((char *)struct_ptr + elm->memb_offset);
404 }
405
406 /*
407 * If the CHOICE itself is tagged EXPLICIT:
408 * T ::= [2] EXPLICIT CHOICE { ... }
409 * Then emit the appropriate tags.
410 */
Lev Walkin449f8322004-08-20 13:23:42 +0000411 if(tag_mode == 1 || td->tags_count) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000412 /*
413 * For this, we need to pre-compute the member.
414 */
415 ssize_t ret;
416
417 /* Encode member with its tag */
418 erval = elm->type->der_encoder(elm->type, memb_ptr,
419 elm->tag_mode, elm->tag, 0, 0);
420 if(erval.encoded == -1)
421 return erval;
422
423 /* Encode CHOICE with parent or my own tag */
Lev Walkin449f8322004-08-20 13:23:42 +0000424 ret = der_write_tags(td, erval.encoded, tag_mode, tag,
Lev Walkinf15320b2004-06-03 03:38:44 +0000425 cb, app_key);
426 if(ret == -1) {
427 erval.encoded = -1;
Lev Walkin449f8322004-08-20 13:23:42 +0000428 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000429 erval.structure_ptr = struct_ptr;
430 return erval;
431 }
432 computed_size += ret;
433 }
434
435 /*
436 * Encode the single underlying member.
437 */
438 erval = elm->type->der_encoder(elm->type, memb_ptr,
439 elm->tag_mode, elm->tag, cb, app_key);
440 if(erval.encoded == -1)
441 return erval;
442
443 ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)",
444 (long)erval.encoded, (long)computed_size);
445
446 erval.encoded += computed_size;
447
448 return erval;
449}
450
451ber_tlv_tag_t
452CHOICE_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 +0000453 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000454 int present;
455
456 assert(tag_mode == 0);
457 assert(tag == 0);
458
459 /*
460 * Figure out which CHOICE element is encoded.
461 */
462 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
463
Lev Walkin449f8322004-08-20 13:23:42 +0000464 if(present > 0 || present <= td->elements_count) {
465 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkin70e70282004-06-05 01:45:48 +0000466 const void *memb_ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000467
Lev Walkincc93b0f2004-09-10 09:18:20 +0000468 if(elm->flags & ATF_POINTER) {
Lev Walkin70e70282004-06-05 01:45:48 +0000469 memb_ptr = *(const void * const *)
470 ((const char *)ptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000471 } else {
Lev Walkin70e70282004-06-05 01:45:48 +0000472 memb_ptr = (const void *)
473 ((const char *)ptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000474 }
475
476 return asn1_TYPE_outmost_tag(elm->type, memb_ptr,
477 elm->tag_mode, elm->tag);
478 } else {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000479 return (ber_tlv_tag_t)-1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000480 }
481}
482
483int
484CHOICE_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
485 asn_app_consume_bytes_f *app_errlog, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000486 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000487 int present;
488
489 if(!sptr) {
Lev Walkinba4e5182004-08-11 09:44:13 +0000490 _ASN_ERRLOG(app_errlog, app_key,
Lev Walkin16835b62004-08-22 13:47:59 +0000491 "%s: value not given (%s:%d)",
492 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +0000493 return -1;
494 }
495
496 /*
497 * Figure out which CHOICE element is encoded.
498 */
499 present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
Lev Walkin449f8322004-08-20 13:23:42 +0000500 if(present > 0 && present <= td->elements_count) {
501 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000502 const void *memb_ptr;
503
Lev Walkincc93b0f2004-09-10 09:18:20 +0000504 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000505 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
Lev Walkincc93b0f2004-09-10 09:18:20 +0000506 if(!memb_ptr) {
507 if(elm->optional)
508 return 0;
509 _ASN_ERRLOG(app_errlog, app_key,
510 "%s: mandatory CHOICE element %s absent (%s:%d)",
511 td->name, elm->name, __FILE__, __LINE__);
512 return -1;
513 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000514 } else {
515 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
516 }
517
Lev Walkin449f8322004-08-20 13:23:42 +0000518 if(elm->memb_constraints) {
519 return elm->memb_constraints(elm->type, memb_ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000520 app_errlog, app_key);
Lev Walkin449f8322004-08-20 13:23:42 +0000521 } else {
522 int ret = elm->type->check_constraints(elm->type,
523 memb_ptr, app_errlog, app_key);
524 /*
525 * Cannot inherit it eralier:
526 * need to make sure we get the updated version.
527 */
528 elm->memb_constraints = elm->type->check_constraints;
529 return ret;
530 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000531 } else {
Lev Walkinba4e5182004-08-11 09:44:13 +0000532 _ASN_ERRLOG(app_errlog, app_key,
Lev Walkind34a8512004-08-22 13:55:49 +0000533 "%s: no CHOICE element given (%s:%d)",
Lev Walkin16835b62004-08-22 13:47:59 +0000534 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +0000535 return -1;
536 }
537}
538
539int
540CHOICE_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
541 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000542 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000543 int present;
544
545 if(!sptr) return cb("<absent>", 8, app_key);
546
547 /*
548 * Figure out which CHOICE element is encoded.
549 */
550 present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size);
551
552 /*
553 * Free that element.
554 */
Lev Walkin449f8322004-08-20 13:23:42 +0000555 if(present > 0 && present <= td->elements_count) {
556 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000557 const void *memb_ptr;
558
Lev Walkincc93b0f2004-09-10 09:18:20 +0000559 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000560 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
561 if(!memb_ptr) return cb("<absent>", 8, app_key);
562 } else {
563 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
564 }
565
566 /* Print member's name and stuff */
567 if(cb(elm->name, strlen(elm->name), app_key)
568 || cb(": ", 2, app_key))
569 return -1;
570
571 return elm->type->print_struct(elm->type, memb_ptr, ilevel,
572 cb, app_key);
573 } else {
574 return cb("<absent>", 8, app_key);
575 }
576}
577
578void
579CHOICE_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000580 asn1_CHOICE_specifics_t *specs = (asn1_CHOICE_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000581 int present;
582
583 if(!td || !ptr)
584 return;
585
586 ASN_DEBUG("Freeing %s as CHOICE", td->name);
587
588 /*
589 * Figure out which CHOICE element is encoded.
590 */
591 present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size);
592
593 /*
594 * Free that element.
595 */
Lev Walkin449f8322004-08-20 13:23:42 +0000596 if(present > 0 && present <= td->elements_count) {
597 asn1_TYPE_member_t *elm = &td->elements[present-1];
Lev Walkinf15320b2004-06-03 03:38:44 +0000598 void *memb_ptr;
599
Lev Walkincc93b0f2004-09-10 09:18:20 +0000600 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000601 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
602 if(memb_ptr)
603 elm->type->free_struct(elm->type, memb_ptr, 0);
604 } else {
605 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
606 elm->type->free_struct(elm->type, memb_ptr, 1);
607 }
608 }
609
610 if(!contents_only) {
611 FREEMEM(ptr);
612 }
613}
614
615
616/*
617 * The following functions functions offer protection against -fshort-enums,
618 * compatible with little- and big-endian machines.
619 * If assertion is triggered, either disable -fshort-enums, or add an entry
620 * here with the ->pres_size of your target stracture.
621 * Unless the target structure is packed, the ".present" member
622 * is guaranteed to be aligned properly. ASN.1 compiler itself does not
623 * produce packed code.
624 */
Lev Walkin91f5cd02004-08-11 09:10:59 +0000625static int
Lev Walkinf15320b2004-06-03 03:38:44 +0000626_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) {
627 const void *present_ptr;
628 int present;
629
630 present_ptr = ((const char *)struct_ptr) + pres_offset;
631
632 switch(pres_size) {
633 case sizeof(int): present = *(const int *)present_ptr; break;
634 case sizeof(short): present = *(const short *)present_ptr; break;
635 case sizeof(char): present = *(const char *)present_ptr; break;
636 default:
637 /* ANSI C mandates enum to be equivalent to integer */
638 assert(pres_size != sizeof(int));
639 return 0; /* If not aborted, pass back safe value */
640 }
641
642 return present;
643}
644
Lev Walkin91f5cd02004-08-11 09:10:59 +0000645static void
Lev Walkinf15320b2004-06-03 03:38:44 +0000646_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) {
647 void *present_ptr;
648 present_ptr = ((char *)struct_ptr) + pres_offset;
649
650 switch(pres_size) {
651 case sizeof(int): *(int *)present_ptr = present; break;
652 case sizeof(short): *(short *)present_ptr = present; break;
653 case sizeof(char): *(char *)present_ptr = present; break;
654 default:
655 /* ANSI C mandates enum to be equivalent to integer */
656 assert(pres_size != sizeof(int));
657 }
658}