blob: 15a118f8cadda4821ffc07b776fb92dcb3babe0d [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 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00005#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00006#include <constr_SET.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00007#include <assert.h> /* for assert() */
8
Lev Walkin2c962732004-08-11 05:58:52 +00009#ifndef WIN32
10#include <netinet/in.h> /* for ntohl() */
11#else
12#include <winsock2.h> /* for ntohl() */
13#endif
14
Lev Walkinf15320b2004-06-03 03:38:44 +000015/*
16 * Number of bytes left for this structure.
17 * (ctx->left) indicates the number of bytes _transferred_ for the structure.
18 * (size) contains the number of bytes in the buffer passed.
19 */
Lev Walkinec1ffd42004-08-18 04:53:32 +000020#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left)
Lev Walkinf15320b2004-06-03 03:38:44 +000021
22/*
23 * If the subprocessor function returns with an indication that it wants
24 * more data, it may well be a fatal decoding problem, because the
25 * size is constrained by the <TLV>'s L, even if the buffer size allows
26 * reading more data.
27 * For example, consider the buffer containing the following TLVs:
28 * <T:5><L:1><V> <T:6>...
29 * The TLV length clearly indicates that one byte is expected in V, but
30 * if the V processor returns with "want more data" even if the buffer
31 * contains way more data than the V processor have seen.
32 */
Lev Walkind9bd7752004-06-05 08:17:50 +000033#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size)
Lev Walkinf15320b2004-06-03 03:38:44 +000034
35/*
36 * This macro "eats" the part of the buffer which is definitely "consumed",
37 * i.e. was correctly converted into local representation or rightfully skipped.
38 */
Lev Walkincc6a9102004-09-23 22:06:26 +000039#undef ADVANCE
Lev Walkinf15320b2004-06-03 03:38:44 +000040#define ADVANCE(num_bytes) do { \
41 size_t num = num_bytes; \
Lev Walkin4ce78ca2004-08-25 01:34:11 +000042 ptr = ((char *)ptr) + num; \
Lev Walkinf15320b2004-06-03 03:38:44 +000043 size -= num; \
44 if(ctx->left >= 0) \
45 ctx->left -= num; \
46 consumed_myself += num; \
47 } while(0)
48
49/*
50 * Switch to the next phase of parsing.
51 */
Lev Walkincc6a9102004-09-23 22:06:26 +000052#undef NEXT_PHASE
Lev Walkinf15320b2004-06-03 03:38:44 +000053#define NEXT_PHASE(ctx) do { \
54 ctx->phase++; \
55 ctx->step = 0; \
56 } while(0)
57
58/*
59 * Return a standardized complex structure.
60 */
Lev Walkincc6a9102004-09-23 22:06:26 +000061#undef RETURN
Lev Walkinf15320b2004-06-03 03:38:44 +000062#define RETURN(_code) do { \
63 rval.code = _code; \
64 rval.consumed = consumed_myself;\
65 return rval; \
66 } while(0)
67
68/*
69 * Tags are canonically sorted in the tag2element map.
70 */
71static int
72_t2e_cmp(const void *ap, const void *bp) {
Lev Walkin5e033762004-09-29 13:26:15 +000073 const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap;
74 const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp;
Lev Walkinc2346572004-08-11 09:07:36 +000075
Lev Walkinf15320b2004-06-03 03:38:44 +000076 int a_class = BER_TAG_CLASS(a->el_tag);
77 int b_class = BER_TAG_CLASS(b->el_tag);
78
79 if(a_class == b_class) {
80 ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag);
81 ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag);
82
83 if(a_value == b_value)
84 return 0;
85 else if(a_value < b_value)
86 return -1;
87 else
88 return 1;
89 } else if(a_class < b_class) {
90 return -1;
91 } else {
92 return 1;
93 }
94}
95
96/*
97 * The decoder of the SET type.
98 */
Lev Walkindc06f6b2004-10-20 15:50:55 +000099asn_dec_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000100SET_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
Lev Walkinf15320b2004-06-03 03:38:44 +0000101 void **struct_ptr, void *ptr, size_t size, int tag_mode) {
102 /*
103 * Bring closer parts of structure description.
104 */
Lev Walkin5e033762004-09-29 13:26:15 +0000105 asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
106 asn_TYPE_member_t *elements = td->elements;
Lev Walkinf15320b2004-06-03 03:38:44 +0000107
108 /*
109 * Parts of the structure being constructed.
110 */
111 void *st = *struct_ptr; /* Target structure. */
Lev Walkin5e033762004-09-29 13:26:15 +0000112 asn_struct_ctx_t *ctx; /* Decoder context */
Lev Walkinf15320b2004-06-03 03:38:44 +0000113
114 ber_tlv_tag_t tlv_tag; /* T from TLV */
Lev Walkindc06f6b2004-10-20 15:50:55 +0000115 asn_dec_rval_t rval; /* Return code from subparsers */
Lev Walkinf15320b2004-06-03 03:38:44 +0000116
117 ssize_t consumed_myself = 0; /* Consumed bytes from ptr */
118 int edx; /* SET element's index */
119
Lev Walkin449f8322004-08-20 13:23:42 +0000120 ASN_DEBUG("Decoding %s as SET", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000121
122 /*
123 * Create the target structure if it is not present already.
124 */
125 if(st == 0) {
126 st = *struct_ptr = CALLOC(1, specs->struct_size);
127 if(st == 0) {
128 RETURN(RC_FAIL);
129 }
130 }
131
132 /*
133 * Restore parsing context.
134 */
Lev Walkin5e033762004-09-29 13:26:15 +0000135 ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000136
137 /*
138 * Start to parse where left previously
139 */
140 switch(ctx->phase) {
141 case 0:
142 /*
143 * PHASE 0.
144 * Check that the set of tags associated with given structure
145 * perfectly fits our expectations.
146 */
147
Lev Walkin5e033762004-09-29 13:26:15 +0000148 rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size,
Lev Walkin8e8078a2004-09-26 13:10:40 +0000149 tag_mode, 1, &ctx->left, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000150 if(rval.code != RC_OK) {
151 ASN_DEBUG("%s tagging check failed: %d",
Lev Walkin449f8322004-08-20 13:23:42 +0000152 td->name, rval.code);
Lev Walkin4ab42cd2004-10-05 06:36:44 +0000153 return rval;
Lev Walkinf15320b2004-06-03 03:38:44 +0000154 }
155
156 if(ctx->left >= 0)
157 ctx->left += rval.consumed; /* ?Substracted below! */
158 ADVANCE(rval.consumed);
159
160 NEXT_PHASE(ctx);
161
162 ASN_DEBUG("Structure advertised %ld bytes, "
163 "buffer contains %ld", (long)ctx->left, (long)size);
164
165 /* Fall through */
166 case 1:
167 /*
168 * PHASE 1.
169 * From the place where we've left it previously,
170 * try to decode the next member from the list of
171 * this structure's elements.
Lev Walkin3e478ed2004-10-28 13:04:02 +0000172 * Note that elements in BER may arrive out of
Lev Walkinf15320b2004-06-03 03:38:44 +0000173 * order, yet DER mandates that they shall arive in the
174 * canonical order of their tags. So, there is a room
175 * for optimization.
176 */
Lev Walkin3e478ed2004-10-28 13:04:02 +0000177 for(;; ctx->step = 0) {
178 asn_TYPE_tag2member_t *t2m;
179 asn_TYPE_tag2member_t key;
Lev Walkinf15320b2004-06-03 03:38:44 +0000180 void *memb_ptr; /* Pointer to the member */
Lev Walkinc2346572004-08-11 09:07:36 +0000181 void **memb_ptr2; /* Pointer to that pointer */
Lev Walkinf15320b2004-06-03 03:38:44 +0000182 ssize_t tag_len; /* Length of TLV's T */
183
Lev Walkin3e478ed2004-10-28 13:04:02 +0000184 if(ctx->step & 1) {
185 edx = ctx->step >> 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000186 goto microphase2;
Lev Walkin3e478ed2004-10-28 13:04:02 +0000187 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000188
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
Lev Walkin3e478ed2004-10-28 13:04:02 +0000227 key.el_tag = tlv_tag;
Lev Walkinc17d90f2005-01-17 14:32:45 +0000228 t2m = (asn_TYPE_tag2member_t *)bsearch(&key,
Lev Walkin3e478ed2004-10-28 13:04:02 +0000229 specs->tag2el, specs->tag2el_count,
230 sizeof(specs->tag2el[0]), _t2e_cmp);
231 if(t2m) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000232 /*
Lev Walkin3e478ed2004-10-28 13:04:02 +0000233 * Found the element corresponding to the tag.
Lev Walkinf15320b2004-06-03 03:38:44 +0000234 */
Lev Walkin3e478ed2004-10-28 13:04:02 +0000235 edx = t2m->el_no;
236 ctx->step = (edx << 1) + 1;
237 ASN_DEBUG("Got tag %s (%s), edx %d",
238 ber_tlv_tag_string(tlv_tag), td->name, edx);
239 } else if(specs->extensible == 0) {
240 ASN_DEBUG("Unexpected tag %s "
241 "in non-extensible SET %s",
242 ber_tlv_tag_string(tlv_tag), td->name);
243 RETURN(RC_FAIL);
Lev Walkinf15320b2004-06-03 03:38:44 +0000244 } else {
Lev Walkin3e478ed2004-10-28 13:04:02 +0000245 /* Skip this tag */
246 ssize_t skip;
Lev Walkinf15320b2004-06-03 03:38:44 +0000247
Lev Walkin3e478ed2004-10-28 13:04:02 +0000248 ASN_DEBUG("Skipping unknown tag %s",
249 ber_tlv_tag_string(tlv_tag));
Lev Walkinf15320b2004-06-03 03:38:44 +0000250
Lev Walkin3e478ed2004-10-28 13:04:02 +0000251 skip = ber_skip_length(opt_codec_ctx,
252 BER_TLV_CONSTRUCTED(ptr),
253 (char *)ptr + tag_len, LEFT - tag_len);
Lev Walkinf15320b2004-06-03 03:38:44 +0000254
Lev Walkin3e478ed2004-10-28 13:04:02 +0000255 switch(skip) {
256 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
257 /* Fall through */
258 case -1: RETURN(RC_FAIL);
Lev Walkinf15320b2004-06-03 03:38:44 +0000259 }
Lev Walkin3e478ed2004-10-28 13:04:02 +0000260
261 ADVANCE(skip + tag_len);
262 continue; /* Try again with the next tag */
Lev Walkinf15320b2004-06-03 03:38:44 +0000263 }
264
265 /*
266 * MICROPHASE 2: Invoke the member-specific decoder.
267 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000268 microphase2:
269
270 /*
271 * Check for duplications: must not overwrite
272 * already decoded elements.
273 */
Lev Walkin4d9528c2004-08-11 08:10:13 +0000274 if(ASN_SET_ISPRESENT2((char *)st + specs->pres_offset, edx)) {
Lev Walkinbbe04752004-07-01 00:47:16 +0000275 ASN_DEBUG("SET %s: Duplicate element %s (%d)",
Lev Walkin449f8322004-08-20 13:23:42 +0000276 td->name, elements[edx].name, edx);
Lev Walkinf15320b2004-06-03 03:38:44 +0000277 RETURN(RC_FAIL);
278 }
279
280 /*
281 * Compute the position of the member inside a structure,
282 * and also a type of containment (it may be contained
283 * as pointer or using inline inclusion).
284 */
Lev Walkincc93b0f2004-09-10 09:18:20 +0000285 if(elements[edx].flags & ATF_POINTER) {
286 /* Member is a pointer to another structure */
Lev Walkinc2346572004-08-11 09:07:36 +0000287 memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000288 } else {
289 /*
290 * A pointer to a pointer
291 * holding the start of the structure
292 */
293 memb_ptr = (char *)st + elements[edx].memb_offset;
294 memb_ptr2 = &memb_ptr;
295 }
296 /*
297 * Invoke the member fetch routine according to member's type
298 */
Lev Walkin5e033762004-09-29 13:26:15 +0000299 rval = elements[edx].type->ber_decoder(opt_codec_ctx,
Lev Walkinc2346572004-08-11 09:07:36 +0000300 elements[edx].type,
Lev Walkinf15320b2004-06-03 03:38:44 +0000301 memb_ptr2, ptr, LEFT,
302 elements[edx].tag_mode);
303 switch(rval.code) {
304 case RC_OK:
Lev Walkin4d9528c2004-08-11 08:10:13 +0000305 ASN_SET_MKPRESENT((char *)st + specs->pres_offset, edx);
Lev Walkinf15320b2004-06-03 03:38:44 +0000306 break;
307 case RC_WMORE: /* More data expected */
308 if(!SIZE_VIOLATION) {
309 ADVANCE(rval.consumed);
310 RETURN(RC_WMORE);
311 }
312 /* Fail through */
313 case RC_FAIL: /* Fatal error */
314 RETURN(RC_FAIL);
315 } /* switch(rval) */
316
317 ADVANCE(rval.consumed);
318 } /* for(all structure members) */
319
320 phase3:
321 ctx->phase = 3;
322 /* Fall through */
323 case 3:
324 case 4: /* Only 00 is expected */
325 ASN_DEBUG("SET %s Leftover: %ld, size = %ld",
Lev Walkin449f8322004-08-20 13:23:42 +0000326 td->name, (long)ctx->left, (long)size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000327
328 /*
329 * Skip everything until the end of the SET.
330 */
331 while(ctx->left) {
332 ssize_t tl, ll;
333
334 tl = ber_fetch_tag(ptr, LEFT, &tlv_tag);
335 switch(tl) {
336 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
337 /* Fall through */
338 case -1: RETURN(RC_FAIL);
339 }
340
341 /*
342 * If expected <0><0>...
343 */
344 if(ctx->left < 0
345 && ((uint8_t *)ptr)[0] == 0) {
346 if(LEFT < 2) {
347 if(SIZE_VIOLATION)
348 RETURN(RC_FAIL);
349 else
350 RETURN(RC_WMORE);
351 } else if(((uint8_t *)ptr)[1] == 0) {
352 /*
353 * Correctly finished with <0><0>.
354 */
355 ADVANCE(2);
356 ctx->left++;
357 ctx->phase = 4;
358 continue;
359 }
360 }
361
362 if(specs->extensible == 0 || ctx->phase == 4) {
363 ASN_DEBUG("Unexpected continuation "
Lev Walkin3e478ed2004-10-28 13:04:02 +0000364 "of a non-extensible type %s "
365 "(ptr=%02x)",
366 td->name, *(uint8_t *)ptr);
Lev Walkinf15320b2004-06-03 03:38:44 +0000367 RETURN(RC_FAIL);
368 }
369
Lev Walkinbaaa24f2004-09-29 14:19:14 +0000370 ll = ber_skip_length(opt_codec_ctx,
Lev Walkinf15320b2004-06-03 03:38:44 +0000371 BER_TLV_CONSTRUCTED(ptr),
Lev Walkin4d9528c2004-08-11 08:10:13 +0000372 (char *)ptr + tl, LEFT - tl);
Lev Walkinf15320b2004-06-03 03:38:44 +0000373 switch(ll) {
374 case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE);
375 /* Fall through */
376 case -1: RETURN(RC_FAIL);
377 }
378
379 ADVANCE(tl + ll);
380 }
381
382 ctx->phase = 5;
383 case 5:
384 /*
385 * Check that all mandatory elements are present.
386 */
Lev Walkin449f8322004-08-20 13:23:42 +0000387 for(edx = 0; edx < td->elements_count;
Lev Walkinf15320b2004-06-03 03:38:44 +0000388 edx += (8 * sizeof(specs->_mandatory_elements[0]))) {
389 unsigned int midx, pres, must;
390
391 midx = edx/(8 * sizeof(specs->_mandatory_elements[0]));
Lev Walkin4d9528c2004-08-11 08:10:13 +0000392 pres = ((unsigned int *)((char *)st+specs->pres_offset))[midx];
Lev Walkinf15320b2004-06-03 03:38:44 +0000393 must = ntohl(specs->_mandatory_elements[midx]);
394
395 if((pres & must) == must) {
396 /*
397 * Yes, everything seems to be in place.
398 */
399 } else {
400 ASN_DEBUG("One or more mandatory elements "
401 "of a SET %s %d (%08x.%08x)=%08x "
402 "are not present",
Lev Walkin449f8322004-08-20 13:23:42 +0000403 td->name,
Lev Walkinf15320b2004-06-03 03:38:44 +0000404 midx,
405 pres,
406 must,
407 (~(pres & must) & must)
408 );
409 RETURN(RC_FAIL);
410 }
411 }
412
413 NEXT_PHASE(ctx);
414 }
415
416 RETURN(RC_OK);
417}
418
419/*
420 * The DER encoder of the SET type.
421 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000422asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000423SET_encode_der(asn_TYPE_descriptor_t *td,
Lev Walkind5193802004-10-03 09:12:07 +0000424 void *sptr, int tag_mode, ber_tlv_tag_t tag,
Lev Walkinf15320b2004-06-03 03:38:44 +0000425 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin5e033762004-09-29 13:26:15 +0000426 asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000427 size_t computed_size = 0;
Lev Walkind5193802004-10-03 09:12:07 +0000428 asn_enc_rval_t er;
Lev Walkin449f8322004-08-20 13:23:42 +0000429 int t2m_build_own = (specs->tag2el_count != td->elements_count);
Lev Walkin5e033762004-09-29 13:26:15 +0000430 asn_TYPE_tag2member_t *t2m;
Lev Walkinf15320b2004-06-03 03:38:44 +0000431 int t2m_count;
432 ssize_t ret;
433 int edx;
434
435 /*
436 * Use existing, or build our own tags map.
437 */
438 if(t2m_build_own) {
Lev Walkinc17d90f2005-01-17 14:32:45 +0000439 t2m = (asn_TYPE_tag2member_t *)alloca(
440 td->elements_count * sizeof(t2m[0]));
Lev Walkind5193802004-10-03 09:12:07 +0000441 if(!t2m) _ASN_ENCODE_FAILED; /* There are such platforms */
Lev Walkinc2346572004-08-11 09:07:36 +0000442 t2m_count = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000443 } else {
444 /*
445 * There is no untagged CHOICE in this SET.
446 * Employ existing table.
447 */
448 t2m = specs->tag2el;
449 t2m_count = specs->tag2el_count;
450 }
451
452 /*
453 * Gather the length of the underlying members sequence.
454 */
Lev Walkin449f8322004-08-20 13:23:42 +0000455 for(edx = 0; edx < td->elements_count; edx++) {
Lev Walkin5e033762004-09-29 13:26:15 +0000456 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkind5193802004-10-03 09:12:07 +0000457 asn_enc_rval_t tmper;
Lev Walkinf15320b2004-06-03 03:38:44 +0000458 void *memb_ptr;
459
460 /*
461 * Compute the length of the encoding of this member.
462 */
Lev Walkincc93b0f2004-09-10 09:18:20 +0000463 if(elm->flags & ATF_POINTER) {
Lev Walkind5193802004-10-03 09:12:07 +0000464 memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000465 if(!memb_ptr) {
466 if(t2m_build_own) {
467 t2m[t2m_count].el_no = edx;
468 t2m[t2m_count].el_tag = 0;
469 t2m_count++;
470 }
471 continue;
472 }
473 } else {
Lev Walkind5193802004-10-03 09:12:07 +0000474 memb_ptr = (void *)((char *)sptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000475 }
Lev Walkind5193802004-10-03 09:12:07 +0000476 tmper = elm->type->der_encoder(elm->type, memb_ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000477 elm->tag_mode, elm->tag,
478 0, 0);
Lev Walkind5193802004-10-03 09:12:07 +0000479 if(tmper.encoded == -1)
480 return tmper;
481 computed_size += tmper.encoded;
Lev Walkinf15320b2004-06-03 03:38:44 +0000482
483 /*
484 * Remember the outmost tag of this member.
485 */
486 if(t2m_build_own) {
487 t2m[t2m_count].el_no = edx;
Lev Walkin5e033762004-09-29 13:26:15 +0000488 t2m[t2m_count].el_tag = asn_TYPE_outmost_tag(
Lev Walkinf15320b2004-06-03 03:38:44 +0000489 elm->type, memb_ptr, elm->tag_mode, elm->tag);
490 t2m_count++;
491 } else {
492 /*
493 * No dynamic sorting is necessary.
494 */
495 }
496 }
497
498 /*
499 * Finalize order of the components.
500 */
Lev Walkin449f8322004-08-20 13:23:42 +0000501 assert(t2m_count == td->elements_count);
Lev Walkinf15320b2004-06-03 03:38:44 +0000502 if(t2m_build_own) {
503 /*
504 * Sort the underlying members according to their
505 * canonical tags order. DER encoding mandates it.
506 */
507 qsort(t2m, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp);
508 } else {
509 /*
510 * Tags are already sorted by the compiler.
511 */
512 }
513
514 /*
515 * Encode the TLV for the sequence itself.
516 */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000517 ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key);
Lev Walkind5193802004-10-03 09:12:07 +0000518 if(ret == -1) _ASN_ENCODE_FAILED;
519 er.encoded = computed_size + ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000520
Lev Walkind5193802004-10-03 09:12:07 +0000521 if(!cb) return er;
Lev Walkinf15320b2004-06-03 03:38:44 +0000522
523 /*
524 * Encode all members.
525 */
Lev Walkin449f8322004-08-20 13:23:42 +0000526 for(edx = 0; edx < td->elements_count; edx++) {
Lev Walkin5e033762004-09-29 13:26:15 +0000527 asn_TYPE_member_t *elm;
Lev Walkind5193802004-10-03 09:12:07 +0000528 asn_enc_rval_t tmper;
Lev Walkinf15320b2004-06-03 03:38:44 +0000529 void *memb_ptr;
530
531 /* Encode according to the tag order */
Lev Walkin449f8322004-08-20 13:23:42 +0000532 elm = &td->elements[t2m[edx].el_no];
Lev Walkinf15320b2004-06-03 03:38:44 +0000533
Lev Walkincc93b0f2004-09-10 09:18:20 +0000534 if(elm->flags & ATF_POINTER) {
Lev Walkind5193802004-10-03 09:12:07 +0000535 memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000536 if(!memb_ptr) continue;
537 } else {
Lev Walkind5193802004-10-03 09:12:07 +0000538 memb_ptr = (void *)((char *)sptr + elm->memb_offset);
Lev Walkinf15320b2004-06-03 03:38:44 +0000539 }
Lev Walkind5193802004-10-03 09:12:07 +0000540 tmper = elm->type->der_encoder(elm->type, memb_ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000541 elm->tag_mode, elm->tag,
542 cb, app_key);
Lev Walkind5193802004-10-03 09:12:07 +0000543 if(tmper.encoded == -1)
544 return tmper;
545 computed_size -= tmper.encoded;
Lev Walkinf15320b2004-06-03 03:38:44 +0000546 }
547
548 if(computed_size != 0) {
549 /*
550 * Encoded size is not equal to the computed size.
551 */
Lev Walkind5193802004-10-03 09:12:07 +0000552 _ASN_ENCODE_FAILED;
Lev Walkinf15320b2004-06-03 03:38:44 +0000553 }
554
Lev Walkind5193802004-10-03 09:12:07 +0000555 return er;
Lev Walkinf15320b2004-06-03 03:38:44 +0000556}
557
Lev Walkina9cc46e2004-09-22 16:06:28 +0000558asn_enc_rval_t
Lev Walkin5e033762004-09-29 13:26:15 +0000559SET_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
Lev Walkina9cc46e2004-09-22 16:06:28 +0000560 int ilevel, enum xer_encoder_flags_e flags,
561 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkind5193802004-10-03 09:12:07 +0000562 asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000563 asn_enc_rval_t er;
564 int xcan = (flags & XER_F_CANONICAL);
Lev Walkind5193802004-10-03 09:12:07 +0000565 asn_TYPE_tag2member_t *t2m = specs->tag2el_cxer;
566 int t2m_count = specs->tag2el_cxer_count;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000567 int edx;
568
569 if(!sptr)
570 _ASN_ENCODE_FAILED;
571
Lev Walkind5193802004-10-03 09:12:07 +0000572 assert(t2m_count == td->elements_count);
573
Lev Walkina9cc46e2004-09-22 16:06:28 +0000574 er.encoded = 0;
575
Lev Walkind5193802004-10-03 09:12:07 +0000576 for(edx = 0; edx < t2m_count; edx++) {
Lev Walkina9cc46e2004-09-22 16:06:28 +0000577 asn_enc_rval_t tmper;
Lev Walkind5193802004-10-03 09:12:07 +0000578 asn_TYPE_member_t *elm;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000579 void *memb_ptr;
Lev Walkind5193802004-10-03 09:12:07 +0000580 const char *mname;
581 unsigned int mlen;
582
583 elm = &td->elements[t2m[edx].el_no];
584 mname = elm->name;
585 mlen = strlen(elm->name);
Lev Walkina9cc46e2004-09-22 16:06:28 +0000586
587 if(elm->flags & ATF_POINTER) {
588 memb_ptr = *(void **)((char *)sptr + elm->memb_offset);
589 if(!memb_ptr) continue; /* OPTIONAL element? */
590 } else {
591 memb_ptr = (void *)((char *)sptr + elm->memb_offset);
592 }
593
594 if(!xcan)
595 _i_ASN_TEXT_INDENT(1, ilevel);
596 _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1);
597
598 /* Print the member itself */
599 tmper = elm->type->xer_encoder(elm->type, memb_ptr,
600 ilevel + 1, flags, cb, app_key);
601 if(tmper.encoded == -1) return tmper;
602
603 _ASN_CALLBACK3("</", 2, mname, mlen, ">", 1);
604
605 er.encoded += 5 + (2 * mlen) + tmper.encoded;
606 }
607
608 if(!xcan) _i_ASN_TEXT_INDENT(1, ilevel - 1);
609
610 return er;
Lev Walkind5193802004-10-03 09:12:07 +0000611cb_failed:
612 _ASN_ENCODE_FAILED;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000613}
614
Lev Walkinf15320b2004-06-03 03:38:44 +0000615int
Lev Walkin5e033762004-09-29 13:26:15 +0000616SET_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel,
Lev Walkinf15320b2004-06-03 03:38:44 +0000617 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000618 int edx;
619 int ret;
620
Lev Walkin8e8078a2004-09-26 13:10:40 +0000621 if(!sptr) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000622
623 /* Dump preamble */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000624 if(cb(td->name, strlen(td->name), app_key) < 0
625 || cb(" ::= {", 6, app_key) < 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000626 return -1;
627
Lev Walkin449f8322004-08-20 13:23:42 +0000628 for(edx = 0; edx < td->elements_count; edx++) {
Lev Walkin5e033762004-09-29 13:26:15 +0000629 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkinf15320b2004-06-03 03:38:44 +0000630 const void *memb_ptr;
631
Lev Walkincc93b0f2004-09-10 09:18:20 +0000632 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000633 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
634 if(!memb_ptr) continue;
635 } else {
636 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
637 }
638
Lev Walkin8e8078a2004-09-26 13:10:40 +0000639 _i_INDENT(1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000640
641 /* Print the member's name and stuff */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000642 if(cb(elm->name, strlen(elm->name), app_key) < 0
643 || cb(": ", 2, app_key) < 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000644 return -1;
645
646 /* Print the member itself */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000647 ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 1,
Lev Walkinf15320b2004-06-03 03:38:44 +0000648 cb, app_key);
649 if(ret) return ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000650 }
651
Lev Walkin8e8078a2004-09-26 13:10:40 +0000652 ilevel--;
653 _i_INDENT(1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000654
Lev Walkin8e8078a2004-09-26 13:10:40 +0000655 return (cb("}", 1, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000656}
657
658void
Lev Walkin5e033762004-09-29 13:26:15 +0000659SET_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000660 int edx;
661
662 if(!td || !ptr)
663 return;
664
665 ASN_DEBUG("Freeing %s as SET", td->name);
666
Lev Walkin449f8322004-08-20 13:23:42 +0000667 for(edx = 0; edx < td->elements_count; edx++) {
Lev Walkin5e033762004-09-29 13:26:15 +0000668 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkinf15320b2004-06-03 03:38:44 +0000669 void *memb_ptr;
Lev Walkincc93b0f2004-09-10 09:18:20 +0000670 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000671 memb_ptr = *(void **)((char *)ptr + elm->memb_offset);
672 if(memb_ptr)
673 elm->type->free_struct(elm->type, memb_ptr, 0);
674 } else {
675 memb_ptr = (void *)((char *)ptr + elm->memb_offset);
676 elm->type->free_struct(elm->type, memb_ptr, 1);
677 }
678 }
679
680 if(!contents_only) {
681 FREEMEM(ptr);
682 }
683}
684
685int
Lev Walkin5e033762004-09-29 13:26:15 +0000686SET_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000687 asn_app_consume_bytes_f *app_errlog, void *app_key) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000688 int edx;
689
690 if(!sptr) {
Lev Walkinba4e5182004-08-11 09:44:13 +0000691 _ASN_ERRLOG(app_errlog, app_key,
Lev Walkin16835b62004-08-22 13:47:59 +0000692 "%s: value not given (%s:%d)",
693 td->name, __FILE__, __LINE__);
Lev Walkinf15320b2004-06-03 03:38:44 +0000694 return -1;
695 }
696
697 /*
698 * Iterate over structure members and check their validity.
699 */
Lev Walkin449f8322004-08-20 13:23:42 +0000700 for(edx = 0; edx < td->elements_count; edx++) {
Lev Walkin5e033762004-09-29 13:26:15 +0000701 asn_TYPE_member_t *elm = &td->elements[edx];
Lev Walkinf15320b2004-06-03 03:38:44 +0000702 const void *memb_ptr;
703
Lev Walkincc93b0f2004-09-10 09:18:20 +0000704 if(elm->flags & ATF_POINTER) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000705 memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset);
706 if(!memb_ptr) {
Lev Walkincc93b0f2004-09-10 09:18:20 +0000707 if(elm->optional)
708 continue;
709 _ASN_ERRLOG(app_errlog, app_key,
710 "%s: mandatory element %s absent (%s:%d)",
711 td->name, elm->name, __FILE__, __LINE__);
712 return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000713 }
714 } else {
715 memb_ptr = (const void *)((const char *)sptr + elm->memb_offset);
716 }
717
Lev Walkin449f8322004-08-20 13:23:42 +0000718 if(elm->memb_constraints) {
719 int ret = elm->memb_constraints(elm->type, memb_ptr,
720 app_errlog, app_key);
721 if(ret) return ret;
722 } else {
723 int ret = elm->type->check_constraints(elm->type,
724 memb_ptr, app_errlog, app_key);
725 if(ret) return ret;
726 /*
727 * Cannot inherit it earlier:
728 * need to make sure we get the updated version.
729 */
730 elm->memb_constraints = elm->type->check_constraints;
731 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000732 }
733
734 return 0;
735}