blob: d1036c94f2515b8d5493867ad6f879fa9b85544c [file] [log] [blame]
vlmfa67ddc2004-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_SET.h>
vlmfa67ddc2004-06-03 03:38:44 +00006#include <assert.h> /* for assert() */
7
vlm97ed74f2004-08-11 05:58:52 +00008#ifndef WIN32
9#include <netinet/in.h> /* for ntohl() */
10#else
11#include <winsock2.h> /* for ntohl() */
12#endif
13
vlmfa67ddc2004-06-03 03:38:44 +000014/*
15 * Number of bytes left for this structure.
16 * (ctx->left) indicates the number of bytes _transferred_ for the structure.
17 * (size) contains the number of bytes in the buffer passed.
18 */
vlmc5190612004-08-18 04:53:32 +000019#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left)
vlmfa67ddc2004-06-03 03:38:44 +000020
21/*
22 * If the subprocessor function returns with an indication that it wants
23 * more data, it may well be a fatal decoding problem, because the
24 * size is constrained by the <TLV>'s L, even if the buffer size allows
25 * reading more data.
26 * For example, consider the buffer containing the following TLVs:
27 * <T:5><L:1><V> <T:6>...
28 * The TLV length clearly indicates that one byte is expected in V, but
29 * if the V processor returns with "want more data" even if the buffer
30 * contains way more data than the V processor have seen.
31 */
vlmb42843a2004-06-05 08:17:50 +000032#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size)
vlmfa67ddc2004-06-03 03:38:44 +000033
34/*
35 * This macro "eats" the part of the buffer which is definitely "consumed",
36 * i.e. was correctly converted into local representation or rightfully skipped.
37 */
38#define ADVANCE(num_bytes) do { \
39 size_t num = num_bytes; \
vlm1ff928d2004-08-11 08:10:13 +000040 (char *)ptr += num; \
vlmfa67ddc2004-06-03 03:38:44 +000041 size -= num; \
42 if(ctx->left >= 0) \
43 ctx->left -= num; \
44 consumed_myself += num; \
45 } while(0)
46
47/*
48 * Switch to the next phase of parsing.
49 */
50#define NEXT_PHASE(ctx) do { \
51 ctx->phase++; \
52 ctx->step = 0; \
53 } while(0)
54
55/*
56 * Return a standardized complex structure.
57 */
58#define RETURN(_code) do { \
59 rval.code = _code; \
60 rval.consumed = consumed_myself;\
61 return rval; \
62 } while(0)
63
64/*
65 * Tags are canonically sorted in the tag2element map.
66 */
67static int
68_t2e_cmp(const void *ap, const void *bp) {
vlmda674682004-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
vlmfa67ddc2004-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 SET type.
94 */
95ber_dec_rval_t
96SET_decode_ber(asn1_TYPE_descriptor_t *sd,
97 void **struct_ptr, void *ptr, size_t size, int tag_mode) {
98 /*
99 * Bring closer parts of structure description.
100 */
vlmda674682004-08-11 09:07:36 +0000101 asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)sd->specifics;
vlmfa67ddc2004-06-03 03:38:44 +0000102 asn1_SET_element_t *elements = specs->elements;
103
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 //ber_tlv_len_t tlv_len; /* L from TLV */
112 ber_dec_rval_t rval; /* Return code from subparsers */
113
114 ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
115 int edx; /* SET element's index */
116
117 ASN_DEBUG("Decoding %s as SET", sd->name);
118
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 */
vlm1ff928d2004-08-11 08:10:13 +0000132 ctx = (ber_dec_ctx_t *)((char *)st + specs->ctx_offset);
vlmfa67ddc2004-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
145 rval = ber_check_tags(sd, ctx, ptr, size,
146 tag_mode, &ctx->left, 0);
147 if(rval.code != RC_OK) {
148 ASN_DEBUG("%s tagging check failed: %d",
149 sd->name, rval.code);
150 consumed_myself += rval.consumed;
151 RETURN(rval.code);
152 }
153
154 if(ctx->left >= 0)
155 ctx->left += rval.consumed; /* ?Substracted below! */
156 ADVANCE(rval.consumed);
157
158 NEXT_PHASE(ctx);
159
160 ASN_DEBUG("Structure advertised %ld bytes, "
161 "buffer contains %ld", (long)ctx->left, (long)size);
162
163 /* Fall through */
164 case 1:
165 /*
166 * PHASE 1.
167 * From the place where we've left it previously,
168 * try to decode the next member from the list of
169 * this structure's elements.
170 * (ctx->step) stores the member being processed
171 * between invocations and the microphase {0,1} of parsing
172 * that member:
173 * step = (2 * <member_number> + <microphase>).
174 * Note, however, that the elements in BER may arrive out of
175 * order, yet DER mandates that they shall arive in the
176 * canonical order of their tags. So, there is a room
177 * for optimization.
178 */
179 for(edx = (ctx->step >> 1); edx < specs->elements_count;
180 ctx->step = (ctx->step & ~1) + 2,
181 edx = (ctx->step >> 1)) {
182 void *memb_ptr; /* Pointer to the member */
vlmda674682004-08-11 09:07:36 +0000183 void **memb_ptr2; /* Pointer to that pointer */
vlmfa67ddc2004-06-03 03:38:44 +0000184 ssize_t tag_len; /* Length of TLV's T */
185
186 if(ctx->step & 1)
187 goto microphase2;
188
189 /*
190 * MICROPHASE 1: Synchronize decoding.
191 */
192
193 if(ctx->left == 0)
194 /*
195 * No more things to decode.
196 * Exit out of here and check whether all mandatory
197 * elements have been received (in the next phase).
198 */
199 break;
200
201 /*
202 * Fetch the T from TLV.
203 */
204 tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag);
205 switch(tag_len) {
206 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
207 /* Fall through */
208 case -1: RETURN(RC_FAIL);
209 }
210
211 if(ctx->left < 0 && ((uint8_t *)ptr)[0] == 0) {
212 if(LEFT < 2) {
213 if(SIZE_VIOLATION)
214 RETURN(RC_FAIL);
215 else
216 RETURN(RC_WMORE);
217 } else if(((uint8_t *)ptr)[1] == 0) {
218 /*
219 * Found the terminator of the
220 * indefinite length structure.
221 * Invoke the generic finalization function.
222 */
223 goto phase3;
224 }
225 }
226
227 if(BER_TAGS_EQUAL(tlv_tag, elements[edx].tag)) {
228 /*
229 * The elements seem to go in order.
230 * This is not particularly strange,
231 * but is not strongly anticipated either.
232 */
233 } else {
vlm31473082004-06-06 07:20:02 +0000234 asn1_TYPE_tag2member_t *t2m;
235 asn1_TYPE_tag2member_t key;
vlmfa67ddc2004-06-03 03:38:44 +0000236
237 key.el_tag = tlv_tag;
vlmda674682004-08-11 09:07:36 +0000238 (void *)t2m = bsearch(&key,
239 specs->tag2el, specs->tag2el_count,
vlmfa67ddc2004-06-03 03:38:44 +0000240 sizeof(specs->tag2el[0]), _t2e_cmp);
241 if(t2m) {
242 /*
243 * Found the element corresponding to the tag.
244 */
245 edx = t2m->el_no;
246 ctx->step = 2 * edx;
247 } else if(specs->extensible == 0) {
248 ASN_DEBUG("Unexpected tag %s "
249 "in non-extensible SET %s",
250 ber_tlv_tag_string(tlv_tag), sd->name);
251 RETURN(RC_FAIL);
252 } else {
253 /* Skip this tag */
254 ssize_t skip;
255
256 ASN_DEBUG("Skipping unknown tag %s",
257 ber_tlv_tag_string(tlv_tag));
258
259 skip = ber_skip_length(
260 BER_TLV_CONSTRUCTED(ptr),
vlm1ff928d2004-08-11 08:10:13 +0000261 (char *)ptr + tag_len, LEFT - tag_len);
vlmfa67ddc2004-06-03 03:38:44 +0000262
263 switch(skip) {
264 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
265 /* Fall through */
266 case -1: RETURN(RC_FAIL);
267 }
268
269 ADVANCE(skip + tag_len);
270 ctx->step -= 2;
271 edx--;
272 continue; /* Try again with the next tag */
273 }
274 }
275
276 /*
277 * MICROPHASE 2: Invoke the member-specific decoder.
278 */
279 ctx->step |= 1; /* Confirm entering next microphase */
280 microphase2:
281
282 /*
283 * Check for duplications: must not overwrite
284 * already decoded elements.
285 */
vlm1ff928d2004-08-11 08:10:13 +0000286 if(ASN_SET_ISPRESENT2((char *)st + specs->pres_offset, edx)) {
vlme26690f2004-07-01 00:47:16 +0000287 ASN_DEBUG("SET %s: Duplicate element %s (%d)",
288 sd->name, elements[edx].name, edx);
vlmfa67ddc2004-06-03 03:38:44 +0000289 RETURN(RC_FAIL);
290 }
291
292 /*
293 * Compute the position of the member inside a structure,
294 * and also a type of containment (it may be contained
295 * as pointer or using inline inclusion).
296 */
297 if(elements[edx].optional) {
298 /* Optional member, hereby, a simple pointer */
vlmda674682004-08-11 09:07:36 +0000299 memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset);
vlmfa67ddc2004-06-03 03:38:44 +0000300 } else {
301 /*
302 * A pointer to a pointer
303 * holding the start of the structure
304 */
305 memb_ptr = (char *)st + elements[edx].memb_offset;
306 memb_ptr2 = &memb_ptr;
307 }
308 /*
309 * Invoke the member fetch routine according to member's type
310 */
311 rval = elements[edx].type->ber_decoder(
vlmda674682004-08-11 09:07:36 +0000312 elements[edx].type,
vlmfa67ddc2004-06-03 03:38:44 +0000313 memb_ptr2, ptr, LEFT,
314 elements[edx].tag_mode);
315 switch(rval.code) {
316 case RC_OK:
vlm1ff928d2004-08-11 08:10:13 +0000317 ASN_SET_MKPRESENT((char *)st + specs->pres_offset, edx);
vlmfa67ddc2004-06-03 03:38:44 +0000318 break;
319 case RC_WMORE: /* More data expected */
320 if(!SIZE_VIOLATION) {
321 ADVANCE(rval.consumed);
322 RETURN(RC_WMORE);
323 }
324 /* Fail through */
325 case RC_FAIL: /* Fatal error */
326 RETURN(RC_FAIL);
327 } /* switch(rval) */
328
329 ADVANCE(rval.consumed);
330 } /* for(all structure members) */
331
332 phase3:
333 ctx->phase = 3;
334 /* Fall through */
335 case 3:
336 case 4: /* Only 00 is expected */
337 ASN_DEBUG("SET %s Leftover: %ld, size = %ld",
338 sd->name, (long)ctx->left, (long)size);
339
340 /*
341 * Skip everything until the end of the SET.
342 */
343 while(ctx->left) {
344 ssize_t tl, ll;
345
346 tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
347 switch(tl) {
348 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
349 /* Fall through */
350 case -1: RETURN(RC_FAIL);
351 }
352
353 /*
354 * If expected <0><0>...
355 */
356 if(ctx->left < 0
357 && ((uint8_t *)ptr)[0] == 0) {
358 if(LEFT < 2) {
359 if(SIZE_VIOLATION)
360 RETURN(RC_FAIL);
361 else
362 RETURN(RC_WMORE);
363 } else if(((uint8_t *)ptr)[1] == 0) {
364 /*
365 * Correctly finished with <0><0>.
366 */
367 ADVANCE(2);
368 ctx->left++;
369 ctx->phase = 4;
370 continue;
371 }
372 }
373
374 if(specs->extensible == 0 || ctx->phase == 4) {
375 ASN_DEBUG("Unexpected continuation "
376 "of a non-extensible type %s",
377 sd->name);
378 RETURN(RC_FAIL);
379 }
380
381 ll = ber_skip_length(
382 BER_TLV_CONSTRUCTED(ptr),
vlm1ff928d2004-08-11 08:10:13 +0000383 (char *)ptr + tl, LEFT - tl);
vlmfa67ddc2004-06-03 03:38:44 +0000384 switch(ll) {
385 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
386 /* Fall through */
387 case -1: RETURN(RC_FAIL);
388 }
389
390 ADVANCE(tl + ll);
391 }
392
393 ctx->phase = 5;
394 case 5:
395 /*
396 * Check that all mandatory elements are present.
397 */
398 for(edx = 0; edx < specs->elements_count;
399 edx += (8 * sizeof(specs->_mandatory_elements[0]))) {
400 unsigned int midx, pres, must;
401
402 midx = edx/(8 * sizeof(specs->_mandatory_elements[0]));
vlm1ff928d2004-08-11 08:10:13 +0000403 pres = ((unsigned int *)((char *)st+specs->pres_offset))[midx];
vlmfa67ddc2004-06-03 03:38:44 +0000404 must = ntohl(specs->_mandatory_elements[midx]);
405
406 if((pres & must) == must) {
407 /*
408 * Yes, everything seems to be in place.
409 */
410 } else {
411 ASN_DEBUG("One or more mandatory elements "
412 "of a SET %s %d (%08x.%08x)=%08x "
413 "are not present",
414 sd->name,
415 midx,
416 pres,
417 must,
418 (~(pres & must) & must)
419 );
420 RETURN(RC_FAIL);
421 }
422 }
423
424 NEXT_PHASE(ctx);
425 }
426
427 RETURN(RC_OK);
428}
429
430/*
431 * The DER encoder of the SET type.
432 */
433der_enc_rval_t
434SET_encode_der(asn1_TYPE_descriptor_t *sd,
435 void *ptr, int tag_mode, ber_tlv_tag_t tag,
436 asn_app_consume_bytes_f *cb, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000437 asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)sd->specifics;
vlmfa67ddc2004-06-03 03:38:44 +0000438 size_t computed_size = 0;
439 der_enc_rval_t my_erval;
440 int t2m_build_own = (specs->tag2el_count != specs->elements_count);
vlm31473082004-06-06 07:20:02 +0000441 asn1_TYPE_tag2member_t *t2m;
vlmfa67ddc2004-06-03 03:38:44 +0000442 int t2m_count;
443 ssize_t ret;
444 int edx;
445
446 /*
447 * Use existing, or build our own tags map.
448 */
449 if(t2m_build_own) {
vlmda674682004-08-11 09:07:36 +0000450 (void *)t2m = alloca(specs->elements_count * sizeof(t2m[0]));
vlm7a6a60e2004-08-11 07:41:45 +0000451 if(!t2m) { /* There are such platforms */
452 my_erval.encoded = -1;
453 my_erval.failed_type = sd;
454 my_erval.structure_ptr = ptr;
455 return my_erval;
456 }
vlmda674682004-08-11 09:07:36 +0000457 t2m_count = 0;
vlmfa67ddc2004-06-03 03:38:44 +0000458 } else {
459 /*
460 * There is no untagged CHOICE in this SET.
461 * Employ existing table.
462 */
463 t2m = specs->tag2el;
464 t2m_count = specs->tag2el_count;
465 }
466
467 /*
468 * Gather the length of the underlying members sequence.
469 */
470 for(edx = 0; edx < specs->elements_count; edx++) {
471 asn1_SET_element_t *elm = &specs->elements[edx];
472 der_enc_rval_t erval;
473 void *memb_ptr;
474
475 /*
476 * Compute the length of the encoding of this member.
477 */
478 if(elm->optional) {
479 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
480 if(!memb_ptr) {
481 if(t2m_build_own) {
482 t2m[t2m_count].el_no = edx;
483 t2m[t2m_count].el_tag = 0;
484 t2m_count++;
485 }
486 continue;
487 }
488 } else {
489 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
490 }
491 erval = elm->type->der_encoder(elm->type, memb_ptr,
492 elm->tag_mode, elm->tag,
493 0, 0);
494 if(erval.encoded == -1)
495 return erval;
496 computed_size += erval.encoded;
497
498 /*
499 * Remember the outmost tag of this member.
500 */
501 if(t2m_build_own) {
502 t2m[t2m_count].el_no = edx;
503 t2m[t2m_count].el_tag = asn1_TYPE_outmost_tag(
504 elm->type, memb_ptr, elm->tag_mode, elm->tag);
505 t2m_count++;
506 } else {
507 /*
508 * No dynamic sorting is necessary.
509 */
510 }
511 }
512
513 /*
514 * Finalize order of the components.
515 */
516 assert(t2m_count == specs->elements_count);
517 if(t2m_build_own) {
518 /*
519 * Sort the underlying members according to their
520 * canonical tags order. DER encoding mandates it.
521 */
522 qsort(t2m, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
523 } else {
524 /*
525 * Tags are already sorted by the compiler.
526 */
527 }
528
529 /*
530 * Encode the TLV for the sequence itself.
531 */
532 ret = der_write_tags(sd, computed_size, tag_mode, tag, cb, app_key);
533 if(ret == -1) {
534 my_erval.encoded = -1;
535 my_erval.failed_type = sd;
536 my_erval.structure_ptr = ptr;
537 return my_erval;
538 }
539 my_erval.encoded = computed_size + ret;
540
541 if(!cb) return my_erval;
542
543 /*
544 * Encode all members.
545 */
546 for(edx = 0; edx < specs->elements_count; edx++) {
547 asn1_SET_element_t *elm;
548 der_enc_rval_t erval;
549 void *memb_ptr;
550
551 /* Encode according to the tag order */
552 elm = &specs->elements[t2m[edx].el_no];
553
554 if(elm->optional) {
555 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
556 if(!memb_ptr) continue;
557 } else {
558 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
559 }
560 erval = elm->type->der_encoder(elm->type, memb_ptr,
561 elm->tag_mode, elm->tag,
562 cb, app_key);
563 if(erval.encoded == -1)
564 return erval;
565 computed_size -= erval.encoded;
566 }
567
568 if(computed_size != 0) {
569 /*
570 * Encoded size is not equal to the computed size.
571 */
572 my_erval.encoded = -1;
573 my_erval.failed_type = sd;
574 my_erval.structure_ptr = ptr;
575 }
576
577 return my_erval;
578}
579
580int
581SET_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
582 asn_app_consume_bytes_f *cb, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000583 asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
vlmfa67ddc2004-06-03 03:38:44 +0000584 int edx;
585 int ret;
586
587 if(!sptr) return cb("<absent>", 8, app_key);
588
589 /* Dump preamble */
590 if(cb(td->name, strlen(td->name), app_key)
591 || cb(" ::= {\n", 7, app_key))
592 return -1;
593
594 for(edx = 0; edx < specs->elements_count; edx++) {
595 asn1_SET_element_t *elm = &specs->elements[edx];
596 const void *memb_ptr;
597
598 if(elm->optional) {
599 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
600 if(!memb_ptr) continue;
601 } else {
602 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
603 }
604
605 /* Indentation */
606 for(ret = 0; ret < ilevel; ret++) cb(" ", 1, app_key);
607
608 /* Print the member's name and stuff */
609 if(cb(elm->name, strlen(elm->name), app_key)
610 || cb(": ", 2, app_key))
611 return -1;
612
613 /* Print the member itself */
614 ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 4,
615 cb, app_key);
616 if(ret) return ret;
617
618 ret = cb("\n", 1, app_key);
619 if(ret) return ret;
620 }
621
622 /* Indentation */
623 for(ret = 0; ret < ilevel - 4; ret++) cb(" ", 1, app_key);
624
625 return cb("}", 1, app_key);
626}
627
628void
629SET_free(asn1_TYPE_descriptor_t *td, void *ptr, int contents_only) {
vlmda674682004-08-11 09:07:36 +0000630 asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
vlmfa67ddc2004-06-03 03:38:44 +0000631 int edx;
632
633 if(!td || !ptr)
634 return;
635
636 ASN_DEBUG("Freeing %s as SET", td->name);
637
638 for(edx = 0; edx < specs->elements_count; edx++) {
639 asn1_SET_element_t *elm = &specs->elements[edx];
640 void *memb_ptr;
641 if(elm->optional) {
642 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
643 if(memb_ptr)
644 elm->type->free_struct(elm->type, memb_ptr, 0);
645 } else {
646 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
647 elm->type->free_struct(elm->type, memb_ptr, 1);
648 }
649 }
650
651 if(!contents_only) {
652 FREEMEM(ptr);
653 }
654}
655
656int
657SET_constraint(asn1_TYPE_descriptor_t *td, const void *sptr,
658 asn_app_consume_bytes_f *app_errlog, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000659 asn1_SET_specifics_t *specs = (asn1_SET_specifics_t *)td->specifics;
vlmfa67ddc2004-06-03 03:38:44 +0000660 int edx;
661
662 if(!sptr) {
vlme3f0f282004-08-11 09:44:13 +0000663 _ASN_ERRLOG(app_errlog, app_key,
664 "%s: value not given", td->name);
vlmfa67ddc2004-06-03 03:38:44 +0000665 return -1;
666 }
667
668 /*
669 * Iterate over structure members and check their validity.
670 */
671 for(edx = 0; edx < specs->elements_count; edx++) {
672 asn1_SET_element_t *elm = &specs->elements[edx];
673 const void *memb_ptr;
674
675 if(elm->optional) {
676 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
677 if(!memb_ptr) {
678 if(ASN_SET_ISPRESENT2(
679 &(specs->_mandatory_elements), edx)) {
vlme3f0f282004-08-11 09:44:13 +0000680 _ASN_ERRLOG(app_errlog, app_key,
vlmfa67ddc2004-06-03 03:38:44 +0000681 "%s: mandatory element "
682 "%s absent",
683 td->name, elm->name);
684 return -1;
685 }
686 continue;
687 }
688 } else {
689 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
690 }
691
692 return elm->type->check_constraints(elm->type, memb_ptr,
693 app_errlog, app_key);
694 }
695
696 return 0;
697}