xref: /minix3/crypto/external/bsd/heimdal/dist/lib/asn1/gen_decode.c (revision 69eead77ff7b92014d108017d0765cfa7d3ddba7)
1 /*	$NetBSD: gen_decode.c,v 1.1.1.1 2011/04/13 18:14:40 elric Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "gen_locl.h"
37 #include "lex.h"
38 
39 __RCSID("$NetBSD: gen_decode.c,v 1.1.1.1 2011/04/13 18:14:40 elric Exp $");
40 
41 static void
42 decode_primitive (const char *typename, const char *name, const char *forwstr)
43 {
44 #if 0
45     fprintf (codefile,
46 	     "e = decode_%s(p, len, %s, &l);\n"
47 	     "%s;\n",
48 	     typename,
49 	     name,
50 	     forwstr);
51 #else
52     fprintf (codefile,
53 	     "e = der_get_%s(p, len, %s, &l);\n"
54 	     "if(e) %s;\np += l; len -= l; ret += l;\n",
55 	     typename,
56 	     name,
57 	     forwstr);
58 #endif
59 }
60 
61 static void
62 find_tag (const Type *t,
63 	  Der_class *cl, Der_type *ty, unsigned *tag)
64 {
65     switch (t->type) {
66     case TBitString:
67 	*cl  = ASN1_C_UNIV;
68 	*ty  = PRIM;
69 	*tag = UT_BitString;
70 	break;
71     case TBoolean:
72 	*cl  = ASN1_C_UNIV;
73 	*ty  = PRIM;
74 	*tag = UT_Boolean;
75 	break;
76     case TChoice:
77 	errx(1, "Cannot have recursive CHOICE");
78     case TEnumerated:
79 	*cl  = ASN1_C_UNIV;
80 	*ty  = PRIM;
81 	*tag = UT_Enumerated;
82 	break;
83     case TGeneralString:
84 	*cl  = ASN1_C_UNIV;
85 	*ty  = PRIM;
86 	*tag = UT_GeneralString;
87 	break;
88     case TTeletexString:
89 	*cl  = ASN1_C_UNIV;
90 	*ty  = PRIM;
91 	*tag = UT_TeletexString;
92 	break;
93     case TGeneralizedTime:
94 	*cl  = ASN1_C_UNIV;
95 	*ty  = PRIM;
96 	*tag = UT_GeneralizedTime;
97 	break;
98     case TIA5String:
99 	*cl  = ASN1_C_UNIV;
100 	*ty  = PRIM;
101 	*tag = UT_IA5String;
102 	break;
103     case TInteger:
104 	*cl  = ASN1_C_UNIV;
105 	*ty  = PRIM;
106 	*tag = UT_Integer;
107 	break;
108     case TNull:
109 	*cl  = ASN1_C_UNIV;
110 	*ty  = PRIM;
111 	*tag = UT_Null;
112 	break;
113     case TOID:
114 	*cl  = ASN1_C_UNIV;
115 	*ty  = PRIM;
116 	*tag = UT_OID;
117 	break;
118     case TOctetString:
119 	*cl  = ASN1_C_UNIV;
120 	*ty  = PRIM;
121 	*tag = UT_OctetString;
122 	break;
123     case TPrintableString:
124 	*cl  = ASN1_C_UNIV;
125 	*ty  = PRIM;
126 	*tag = UT_PrintableString;
127 	break;
128     case TSequence:
129     case TSequenceOf:
130 	*cl  = ASN1_C_UNIV;
131 	*ty  = CONS;
132 	*tag = UT_Sequence;
133 	break;
134     case TSet:
135     case TSetOf:
136 	*cl  = ASN1_C_UNIV;
137 	*ty  = CONS;
138 	*tag = UT_Set;
139 	break;
140     case TTag:
141 	*cl  = t->tag.tagclass;
142 	*ty  = is_primitive_type(t->subtype->type) ? PRIM : CONS;
143 	*tag = t->tag.tagvalue;
144 	break;
145     case TType:
146 	if ((t->symbol->stype == Stype && t->symbol->type == NULL)
147 	    || t->symbol->stype == SUndefined) {
148 	    lex_error_message("%s is imported or still undefined, "
149 			      " can't generate tag checking data in CHOICE "
150 			      "without this information",
151 			      t->symbol->name);
152 	    exit(1);
153 	}
154 	find_tag(t->symbol->type, cl, ty, tag);
155 	return;
156     case TUTCTime:
157 	*cl  = ASN1_C_UNIV;
158 	*ty  = PRIM;
159 	*tag = UT_UTCTime;
160 	break;
161     case TUTF8String:
162 	*cl  = ASN1_C_UNIV;
163 	*ty  = PRIM;
164 	*tag = UT_UTF8String;
165 	break;
166     case TBMPString:
167 	*cl  = ASN1_C_UNIV;
168 	*ty  = PRIM;
169 	*tag = UT_BMPString;
170 	break;
171     case TUniversalString:
172 	*cl  = ASN1_C_UNIV;
173 	*ty  = PRIM;
174 	*tag = UT_UniversalString;
175 	break;
176     case TVisibleString:
177 	*cl  = ASN1_C_UNIV;
178 	*ty  = PRIM;
179 	*tag = UT_VisibleString;
180 	break;
181     default:
182 	abort();
183     }
184 }
185 
186 static void
187 range_check(const char *name,
188 	    const char *length,
189 	    const char *forwstr,
190 	    struct range *r)
191 {
192     if (r->min == r->max + 2 || r->min < r->max)
193 	fprintf (codefile,
194 		 "if ((%s)->%s > %d) {\n"
195 		 "e = ASN1_MAX_CONSTRAINT; %s;\n"
196 		 "}\n",
197 		 name, length, r->max, forwstr);
198     if (r->min - 1 == r->max || r->min < r->max)
199 	fprintf (codefile,
200 		 "if ((%s)->%s < %d) {\n"
201 		 "e = ASN1_MIN_CONSTRAINT; %s;\n"
202 		 "}\n",
203 		 name, length, r->min, forwstr);
204     if (r->max == r->min)
205 	fprintf (codefile,
206 		 "if ((%s)->%s != %d) {\n"
207 		 "e = ASN1_EXACT_CONSTRAINT; %s;\n"
208 		 "}\n",
209 		 name, length, r->min, forwstr);
210 }
211 
212 static int
213 decode_type (const char *name, const Type *t, int optional,
214 	     const char *forwstr, const char *tmpstr, const char *dertype)
215 {
216     switch (t->type) {
217     case TType: {
218 	if (optional)
219 	    fprintf(codefile,
220 		    "%s = calloc(1, sizeof(*%s));\n"
221 		    "if (%s == NULL) %s;\n",
222 		    name, name, name, forwstr);
223 	fprintf (codefile,
224 		 "e = decode_%s(p, len, %s, &l);\n",
225 		 t->symbol->gen_name, name);
226 	if (optional) {
227 	    fprintf (codefile,
228 		     "if(e) {\n"
229 		     "free(%s);\n"
230 		     "%s = NULL;\n"
231 		     "} else {\n"
232 		     "p += l; len -= l; ret += l;\n"
233 		     "}\n",
234 		     name, name);
235 	} else {
236 	    fprintf (codefile,
237 		     "if(e) %s;\n",
238 		     forwstr);
239 	    fprintf (codefile,
240 		     "p += l; len -= l; ret += l;\n");
241 	}
242 	break;
243     }
244     case TInteger:
245 	if(t->members) {
246 	    fprintf(codefile,
247 		    "{\n"
248 		    "int enumint;\n");
249 	    decode_primitive ("integer", "&enumint", forwstr);
250 	    fprintf(codefile,
251 		    "*%s = enumint;\n"
252 		    "}\n",
253 		    name);
254 	} else if (t->range == NULL) {
255 	    decode_primitive ("heim_integer", name, forwstr);
256 	} else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
257 	    decode_primitive ("integer", name, forwstr);
258 	} else if (t->range->min == 0 && t->range->max == UINT_MAX) {
259 	    decode_primitive ("unsigned", name, forwstr);
260 	} else if (t->range->min == 0 && t->range->max == INT_MAX) {
261 	    decode_primitive ("unsigned", name, forwstr);
262 	} else
263 	    errx(1, "%s: unsupported range %d -> %d",
264 		 name, t->range->min, t->range->max);
265 	break;
266     case TBoolean:
267       decode_primitive ("boolean", name, forwstr);
268       break;
269     case TEnumerated:
270 	decode_primitive ("enumerated", name, forwstr);
271 	break;
272     case TOctetString:
273 	if (dertype) {
274 	    fprintf(codefile,
275 		    "if (%s == CONS) {\n",
276 		    dertype);
277 	    decode_primitive("octet_string_ber", name, forwstr);
278 	    fprintf(codefile,
279 		    "} else {\n");
280 	}
281 	decode_primitive ("octet_string", name, forwstr);
282 	if (dertype)
283 	    fprintf(codefile, "}\n");
284 	if (t->range)
285 	    range_check(name, "length", forwstr, t->range);
286 	break;
287     case TBitString: {
288 	Member *m;
289 	int pos = 0;
290 
291 	if (ASN1_TAILQ_EMPTY(t->members)) {
292 	    decode_primitive ("bit_string", name, forwstr);
293 	    break;
294 	}
295 	fprintf(codefile,
296 		"if (len < 1) return ASN1_OVERRUN;\n"
297 		"p++; len--; ret++;\n");
298 	fprintf(codefile,
299 		"do {\n"
300 		"if (len < 1) break;\n");
301 	ASN1_TAILQ_FOREACH(m, t->members, members) {
302 	    while (m->val / 8 > pos / 8) {
303 		fprintf (codefile,
304 			 "p++; len--; ret++;\n"
305 			 "if (len < 1) break;\n");
306 		pos += 8;
307 	    }
308 	    fprintf (codefile,
309 		     "(%s)->%s = (*p >> %d) & 1;\n",
310 		     name, m->gen_name, 7 - m->val % 8);
311 	}
312 	fprintf(codefile,
313 		"} while(0);\n");
314 	fprintf (codefile,
315 		 "p += len; ret += len;\n");
316 	break;
317     }
318     case TSequence: {
319 	Member *m;
320 
321 	if (t->members == NULL)
322 	    break;
323 
324 	ASN1_TAILQ_FOREACH(m, t->members, members) {
325 	    char *s = NULL;
326 
327 	    if (m->ellipsis)
328 		continue;
329 
330 	    if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&",
331 			  name, m->gen_name) < 0 || s == NULL)
332 		errx(1, "malloc");
333 	    decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL);
334 	    free (s);
335 	}
336 
337 	break;
338     }
339     case TSet: {
340 	Member *m;
341 	unsigned int memno;
342 
343 	if(t->members == NULL)
344 	    break;
345 
346 	fprintf(codefile, "{\n");
347 	fprintf(codefile, "unsigned int members = 0;\n");
348 	fprintf(codefile, "while(len > 0) {\n");
349 	fprintf(codefile,
350 		"Der_class class;\n"
351 		"Der_type type;\n"
352 		"int tag;\n"
353 		"e = der_get_tag (p, len, &class, &type, &tag, NULL);\n"
354 		"if(e) %s;\n", forwstr);
355 	fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n");
356 	memno = 0;
357 	ASN1_TAILQ_FOREACH(m, t->members, members) {
358 	    char *s;
359 
360 	    assert(m->type->type == TTag);
361 
362 	    fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n",
363 		    classname(m->type->tag.tagclass),
364 		    is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS",
365 		    valuename(m->type->tag.tagclass, m->type->tag.tagvalue));
366 
367 	    if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)
368 		errx(1, "malloc");
369 	    if(m->optional)
370 		fprintf(codefile,
371 			"%s = calloc(1, sizeof(*%s));\n"
372 			"if (%s == NULL) { e = ENOMEM; %s; }\n",
373 			s, s, s, forwstr);
374 	    decode_type (s, m->type, 0, forwstr, m->gen_name, NULL);
375 	    free (s);
376 
377 	    fprintf(codefile, "members |= (1 << %d);\n", memno);
378 	    memno++;
379 	    fprintf(codefile, "break;\n");
380 	}
381 	fprintf(codefile,
382 		"default:\n"
383 		"return ASN1_MISPLACED_FIELD;\n"
384 		"break;\n");
385 	fprintf(codefile, "}\n");
386 	fprintf(codefile, "}\n");
387 	memno = 0;
388 	ASN1_TAILQ_FOREACH(m, t->members, members) {
389 	    char *s;
390 
391 	    if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL)
392 		errx(1, "malloc");
393 	    fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno);
394 	    if(m->optional)
395 		fprintf(codefile, "%s = NULL;\n", s);
396 	    else if(m->defval)
397 		gen_assign_defval(s, m->defval);
398 	    else
399 		fprintf(codefile, "return ASN1_MISSING_FIELD;\n");
400 	    free(s);
401 	    memno++;
402 	}
403 	fprintf(codefile, "}\n");
404 	break;
405     }
406     case TSetOf:
407     case TSequenceOf: {
408 	char *n = NULL;
409 	char *sname = NULL;
410 
411 	fprintf (codefile,
412 		 "{\n"
413 		 "size_t %s_origlen = len;\n"
414 		 "size_t %s_oldret = ret;\n"
415 		 "size_t %s_olen = 0;\n"
416 		 "void *%s_tmp;\n"
417 		 "ret = 0;\n"
418 		 "(%s)->len = 0;\n"
419 		 "(%s)->val = NULL;\n",
420 		 tmpstr,
421 		 tmpstr,
422 		 tmpstr,
423 		 tmpstr,
424 		 name,
425 		 name);
426 
427 	fprintf (codefile,
428 		 "while(ret < %s_origlen) {\n"
429 		 "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n"
430 		 "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n"
431 		 "%s_olen = %s_nlen;\n"
432 		 "%s_tmp = realloc((%s)->val, %s_olen);\n"
433 		 "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n"
434 		 "(%s)->val = %s_tmp;\n",
435 		 tmpstr,
436 		 tmpstr, tmpstr, name,
437 		 tmpstr, tmpstr, forwstr,
438 		 tmpstr, tmpstr,
439 		 tmpstr, name, tmpstr,
440 		 tmpstr, forwstr,
441 		 name, tmpstr);
442 
443 	if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL)
444 	    errx(1, "malloc");
445 	if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL)
446 	    errx(1, "malloc");
447 	decode_type (n, t->subtype, 0, forwstr, sname, NULL);
448 	fprintf (codefile,
449 		 "(%s)->len++;\n"
450 		 "len = %s_origlen - ret;\n"
451 		 "}\n"
452 		 "ret += %s_oldret;\n"
453 		 "}\n",
454 		 name,
455 		 tmpstr, tmpstr);
456 	if (t->range)
457 	    range_check(name, "len", forwstr, t->range);
458 	free (n);
459 	free (sname);
460 	break;
461     }
462     case TGeneralizedTime:
463 	decode_primitive ("generalized_time", name, forwstr);
464 	break;
465     case TGeneralString:
466 	decode_primitive ("general_string", name, forwstr);
467 	break;
468     case TTeletexString:
469 	decode_primitive ("general_string", name, forwstr);
470 	break;
471     case TTag:{
472     	char *tname = NULL, *typestring = NULL;
473 	char *ide = NULL;
474 
475 	if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL)
476 	    errx(1, "malloc");
477 
478 	fprintf(codefile,
479 		"{\n"
480 		"size_t %s_datalen, %s_oldlen;\n"
481 		"Der_type %s;\n",
482 		tmpstr, tmpstr, typestring);
483 	if(support_ber)
484 	    fprintf(codefile,
485 		    "int is_indefinite;\n");
486 
487 	fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, "
488 		"&%s_datalen, &l);\n",
489 		classname(t->tag.tagclass),
490 		typestring,
491 		valuename(t->tag.tagclass, t->tag.tagvalue),
492 		tmpstr);
493 
494 	/* XXX hardcode for now */
495 	if (support_ber && t->subtype->type == TOctetString) {
496 	    ide = typestring;
497 	} else {
498 	    fprintf(codefile,
499 		    "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n",
500 		    typestring,
501 		    is_primitive_type(t->subtype->type) ? "PRIM" : "CONS");
502 	}
503 
504 	if(optional) {
505 	    fprintf(codefile,
506 		    "if(e) {\n"
507 		    "%s = NULL;\n"
508 		    "} else {\n"
509 		     "%s = calloc(1, sizeof(*%s));\n"
510 		     "if (%s == NULL) { e = ENOMEM; %s; }\n",
511 		     name, name, name, name, forwstr);
512 	} else {
513 	    fprintf(codefile, "if(e) %s;\n", forwstr);
514 	}
515 	fprintf (codefile,
516 		 "p += l; len -= l; ret += l;\n"
517 		 "%s_oldlen = len;\n",
518 		 tmpstr);
519 	if(support_ber)
520 	    fprintf (codefile,
521 		     "if((is_indefinite = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
522 		     "{ e = ASN1_BAD_FORMAT; %s; }\n"
523 		     "if (is_indefinite) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }",
524 		     tmpstr, forwstr, forwstr);
525 	else
526 	    fprintf(codefile,
527 		    "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
528 		    "len = %s_datalen;\n", tmpstr, forwstr, tmpstr);
529 	if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL)
530 	    errx(1, "malloc");
531 	decode_type (name, t->subtype, 0, forwstr, tname, ide);
532 	if(support_ber)
533 	    fprintf(codefile,
534 		    "if(is_indefinite){\n"
535 		    "len += 2;\n"
536 		    "e = der_match_tag_and_length(p, len, "
537 		    "(Der_class)0, &%s, UT_EndOfContent, "
538 		    "&%s_datalen, &l);\n"
539 		    "if(e) %s;\n"
540 		    "p += l; len -= l; ret += l;\n"
541 		    "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n"
542 		    "} else \n",
543 		    typestring,
544 		    tmpstr,
545 		    forwstr,
546 		    typestring, forwstr);
547 	fprintf(codefile,
548 		"len = %s_oldlen - %s_datalen;\n",
549 		tmpstr, tmpstr);
550 	if(optional)
551 	    fprintf(codefile,
552 		    "}\n");
553 	fprintf(codefile,
554 		"}\n");
555 	free(tname);
556 	free(typestring);
557 	break;
558     }
559     case TChoice: {
560 	Member *m, *have_ellipsis = NULL;
561 	const char *els = "";
562 
563 	if (t->members == NULL)
564 	    break;
565 
566 	ASN1_TAILQ_FOREACH(m, t->members, members) {
567 	    const Type *tt = m->type;
568 	    char *s = NULL;
569 	    Der_class cl;
570 	    Der_type  ty;
571 	    unsigned  tag;
572 
573 	    if (m->ellipsis) {
574 		have_ellipsis = m;
575 		continue;
576 	    }
577 
578 	    find_tag(tt, &cl, &ty, &tag);
579 
580 	    fprintf(codefile,
581 		    "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n",
582 		    els,
583 		    classname(cl),
584 		    ty ? "CONS" : "PRIM",
585 		    valuename(cl, tag));
586 	    if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&",
587 			  name, m->gen_name) < 0 || s == NULL)
588 		errx(1, "malloc");
589 	    decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL);
590 	    fprintf(codefile,
591 		    "(%s)->element = %s;\n",
592 		    name, m->label);
593 	    free(s);
594 	    fprintf(codefile,
595 		    "}\n");
596 	    els = "else ";
597 	}
598 	if (have_ellipsis) {
599 	    fprintf(codefile,
600 		    "else {\n"
601 		    "(%s)->u.%s.data = calloc(1, len);\n"
602 		    "if ((%s)->u.%s.data == NULL) {\n"
603 		    "e = ENOMEM; %s;\n"
604 		    "}\n"
605 		    "(%s)->u.%s.length = len;\n"
606 		    "memcpy((%s)->u.%s.data, p, len);\n"
607 		    "(%s)->element = %s;\n"
608 		    "p += len;\n"
609 		    "ret += len;\n"
610 		    "len -= len;\n"
611 		    "}\n",
612 		    name, have_ellipsis->gen_name,
613 		    name, have_ellipsis->gen_name,
614 		    forwstr,
615 		    name, have_ellipsis->gen_name,
616 		    name, have_ellipsis->gen_name,
617 		    name, have_ellipsis->label);
618 	} else {
619 	    fprintf(codefile,
620 		    "else {\n"
621 		    "e = ASN1_PARSE_ERROR;\n"
622 		    "%s;\n"
623 		    "}\n",
624 		    forwstr);
625 	}
626 	break;
627     }
628     case TUTCTime:
629 	decode_primitive ("utctime", name, forwstr);
630 	break;
631     case TUTF8String:
632 	decode_primitive ("utf8string", name, forwstr);
633 	break;
634     case TPrintableString:
635 	decode_primitive ("printable_string", name, forwstr);
636 	break;
637     case TIA5String:
638 	decode_primitive ("ia5_string", name, forwstr);
639 	break;
640     case TBMPString:
641 	decode_primitive ("bmp_string", name, forwstr);
642 	break;
643     case TUniversalString:
644 	decode_primitive ("universal_string", name, forwstr);
645 	break;
646     case TVisibleString:
647 	decode_primitive ("visible_string", name, forwstr);
648 	break;
649     case TNull:
650 	fprintf (codefile, "/* NULL */\n");
651 	break;
652     case TOID:
653 	decode_primitive ("oid", name, forwstr);
654 	break;
655     default :
656 	abort ();
657     }
658     return 0;
659 }
660 
661 void
662 generate_type_decode (const Symbol *s)
663 {
664     int preserve = preserve_type(s->name) ? TRUE : FALSE;
665 
666     fprintf (codefile, "int ASN1CALL\n"
667 	     "decode_%s(const unsigned char *p,"
668 	     " size_t len, %s *data, size_t *size)\n"
669 	     "{\n",
670 	     s->gen_name, s->gen_name);
671 
672     switch (s->type->type) {
673     case TInteger:
674     case TBoolean:
675     case TOctetString:
676     case TOID:
677     case TGeneralizedTime:
678     case TGeneralString:
679     case TTeletexString:
680     case TUTF8String:
681     case TPrintableString:
682     case TIA5String:
683     case TBMPString:
684     case TUniversalString:
685     case TVisibleString:
686     case TUTCTime:
687     case TNull:
688     case TEnumerated:
689     case TBitString:
690     case TSequence:
691     case TSequenceOf:
692     case TSet:
693     case TSetOf:
694     case TTag:
695     case TType:
696     case TChoice:
697 	fprintf (codefile,
698 		 "size_t ret = 0;\n"
699 		 "size_t l;\n"
700 		 "int e;\n");
701 	if (preserve)
702 	    fprintf (codefile, "const unsigned char *begin = p;\n");
703 
704 	fprintf (codefile, "\n");
705 	fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
706 
707 	decode_type ("data", s->type, 0, "goto fail", "Top", NULL);
708 	if (preserve)
709 	    fprintf (codefile,
710 		     "data->_save.data = calloc(1, ret);\n"
711 		     "if (data->_save.data == NULL) { \n"
712 		     "e = ENOMEM; goto fail; \n"
713 		     "}\n"
714 		     "data->_save.length = ret;\n"
715 		     "memcpy(data->_save.data, begin, ret);\n");
716 	fprintf (codefile,
717 		 "if(size) *size = ret;\n"
718 		 "return 0;\n");
719 	fprintf (codefile,
720 		 "fail:\n"
721 		 "free_%s(data);\n"
722 		 "return e;\n",
723 		 s->gen_name);
724 	break;
725     default:
726 	abort ();
727     }
728     fprintf (codefile, "}\n\n");
729 }
730