155682Smarkm/*
2178825Sdfr * Copyright (c) 1997 - 2006 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "gen_locl.h"
35178825Sdfr#include "lex.h"
3655682Smarkm
37178825SdfrRCSID("$Id: gen_decode.c 21503 2007-07-12 11:57:19Z lha $");
3855682Smarkm
3955682Smarkmstatic void
40178825Sdfrdecode_primitive (const char *typename, const char *name, const char *forwstr)
4155682Smarkm{
42178825Sdfr#if 0
4355682Smarkm    fprintf (codefile,
4455682Smarkm	     "e = decode_%s(p, len, %s, &l);\n"
45178825Sdfr	     "%s;\n",
4655682Smarkm	     typename,
47178825Sdfr	     name,
48178825Sdfr	     forwstr);
49178825Sdfr#else
50178825Sdfr    fprintf (codefile,
51178825Sdfr	     "e = der_get_%s(p, len, %s, &l);\n"
52178825Sdfr	     "if(e) %s;\np += l; len -= l; ret += l;\n",
53178825Sdfr	     typename,
54178825Sdfr	     name,
55178825Sdfr	     forwstr);
56178825Sdfr#endif
5755682Smarkm}
5855682Smarkm
59178825Sdfrstatic int
60178825Sdfris_primitive_type(int type)
61178825Sdfr{
62178825Sdfr    switch(type) {
63178825Sdfr    case TInteger:
64178825Sdfr    case TBoolean:
65178825Sdfr    case TOctetString:
66178825Sdfr    case TBitString:
67178825Sdfr    case TEnumerated:
68178825Sdfr    case TGeneralizedTime:
69178825Sdfr    case TGeneralString:
70178825Sdfr    case TOID:
71178825Sdfr    case TUTCTime:
72178825Sdfr    case TUTF8String:
73178825Sdfr    case TPrintableString:
74178825Sdfr    case TIA5String:
75178825Sdfr    case TBMPString:
76178825Sdfr    case TUniversalString:
77178825Sdfr    case TVisibleString:
78178825Sdfr    case TNull:
79178825Sdfr	return 1;
80178825Sdfr    default:
81178825Sdfr	return 0;
82178825Sdfr    }
83178825Sdfr}
84178825Sdfr
8555682Smarkmstatic void
86178825Sdfrfind_tag (const Type *t,
87178825Sdfr	  Der_class *cl, Der_type *ty, unsigned *tag)
8855682Smarkm{
8972445Sassar    switch (t->type) {
90178825Sdfr    case TBitString:
91178825Sdfr	*cl  = ASN1_C_UNIV;
92178825Sdfr	*ty  = PRIM;
93178825Sdfr	*tag = UT_BitString;
94178825Sdfr	break;
95178825Sdfr    case TBoolean:
96178825Sdfr	*cl  = ASN1_C_UNIV;
97178825Sdfr	*ty  = PRIM;
98178825Sdfr	*tag = UT_Boolean;
99178825Sdfr	break;
100178825Sdfr    case TChoice:
101178825Sdfr	errx(1, "Cannot have recursive CHOICE");
102178825Sdfr    case TEnumerated:
103178825Sdfr	*cl  = ASN1_C_UNIV;
104178825Sdfr	*ty  = PRIM;
105178825Sdfr	*tag = UT_Enumerated;
106178825Sdfr	break;
107178825Sdfr    case TGeneralString:
108178825Sdfr	*cl  = ASN1_C_UNIV;
109178825Sdfr	*ty  = PRIM;
110178825Sdfr	*tag = UT_GeneralString;
111178825Sdfr	break;
112178825Sdfr    case TGeneralizedTime:
113178825Sdfr	*cl  = ASN1_C_UNIV;
114178825Sdfr	*ty  = PRIM;
115178825Sdfr	*tag = UT_GeneralizedTime;
116178825Sdfr	break;
117178825Sdfr    case TIA5String:
118178825Sdfr	*cl  = ASN1_C_UNIV;
119178825Sdfr	*ty  = PRIM;
120178825Sdfr	*tag = UT_IA5String;
121178825Sdfr	break;
122178825Sdfr    case TInteger:
123178825Sdfr	*cl  = ASN1_C_UNIV;
124178825Sdfr	*ty  = PRIM;
125178825Sdfr	*tag = UT_Integer;
126178825Sdfr	break;
127178825Sdfr    case TNull:
128178825Sdfr	*cl  = ASN1_C_UNIV;
129178825Sdfr	*ty  = PRIM;
130178825Sdfr	*tag = UT_Null;
131178825Sdfr	break;
132178825Sdfr    case TOID:
133178825Sdfr	*cl  = ASN1_C_UNIV;
134178825Sdfr	*ty  = PRIM;
135178825Sdfr	*tag = UT_OID;
136178825Sdfr	break;
137178825Sdfr    case TOctetString:
138178825Sdfr	*cl  = ASN1_C_UNIV;
139178825Sdfr	*ty  = PRIM;
140178825Sdfr	*tag = UT_OctetString;
141178825Sdfr	break;
142178825Sdfr    case TPrintableString:
143178825Sdfr	*cl  = ASN1_C_UNIV;
144178825Sdfr	*ty  = PRIM;
145178825Sdfr	*tag = UT_PrintableString;
146178825Sdfr	break;
147178825Sdfr    case TSequence:
148178825Sdfr    case TSequenceOf:
149178825Sdfr	*cl  = ASN1_C_UNIV;
150178825Sdfr	*ty  = CONS;
151178825Sdfr	*tag = UT_Sequence;
152178825Sdfr	break;
153178825Sdfr    case TSet:
154178825Sdfr    case TSetOf:
155178825Sdfr	*cl  = ASN1_C_UNIV;
156178825Sdfr	*ty  = CONS;
157178825Sdfr	*tag = UT_Set;
158178825Sdfr	break;
159178825Sdfr    case TTag:
160178825Sdfr	*cl  = t->tag.tagclass;
161178825Sdfr	*ty  = is_primitive_type(t->subtype->type) ? PRIM : CONS;
162178825Sdfr	*tag = t->tag.tagvalue;
163178825Sdfr	break;
164178825Sdfr    case TType:
165178825Sdfr	if ((t->symbol->stype == Stype && t->symbol->type == NULL)
166178825Sdfr	    || t->symbol->stype == SUndefined) {
167178825Sdfr	    error_message("%s is imported or still undefined, "
168178825Sdfr			  " can't generate tag checking data in CHOICE "
169178825Sdfr			  "without this information",
170178825Sdfr			  t->symbol->name);
171178825Sdfr	    exit(1);
172178825Sdfr	}
173178825Sdfr	find_tag(t->symbol->type, cl, ty, tag);
174178825Sdfr	return;
175178825Sdfr    case TUTCTime:
176178825Sdfr	*cl  = ASN1_C_UNIV;
177178825Sdfr	*ty  = PRIM;
178178825Sdfr	*tag = UT_UTCTime;
179178825Sdfr	break;
180178825Sdfr    case TUTF8String:
181178825Sdfr	*cl  = ASN1_C_UNIV;
182178825Sdfr	*ty  = PRIM;
183178825Sdfr	*tag = UT_UTF8String;
184178825Sdfr	break;
185178825Sdfr    case TBMPString:
186178825Sdfr	*cl  = ASN1_C_UNIV;
187178825Sdfr	*ty  = PRIM;
188178825Sdfr	*tag = UT_BMPString;
189178825Sdfr	break;
190178825Sdfr    case TUniversalString:
191178825Sdfr	*cl  = ASN1_C_UNIV;
192178825Sdfr	*ty  = PRIM;
193178825Sdfr	*tag = UT_UniversalString;
194178825Sdfr	break;
195178825Sdfr    case TVisibleString:
196178825Sdfr	*cl  = ASN1_C_UNIV;
197178825Sdfr	*ty  = PRIM;
198178825Sdfr	*tag = UT_VisibleString;
199178825Sdfr	break;
200178825Sdfr    default:
201178825Sdfr	abort();
202178825Sdfr    }
203178825Sdfr}
204178825Sdfr
205178825Sdfrstatic void
206178825Sdfrrange_check(const char *name,
207178825Sdfr	    const char *length,
208178825Sdfr	    const char *forwstr,
209178825Sdfr	    struct range *r)
210178825Sdfr{
211178825Sdfr    if (r->min == r->max + 2 || r->min < r->max)
21272445Sassar	fprintf (codefile,
213178825Sdfr		 "if ((%s)->%s > %d) {\n"
214178825Sdfr		 "e = ASN1_MAX_CONSTRAINT; %s;\n"
215178825Sdfr		 "}\n",
216178825Sdfr		 name, length, r->max, forwstr);
217178825Sdfr    if (r->min - 1 == r->max || r->min < r->max)
218178825Sdfr	fprintf (codefile,
219178825Sdfr		 "if ((%s)->%s < %d) {\n"
220178825Sdfr		 "e = ASN1_MIN_CONSTRAINT; %s;\n"
221178825Sdfr		 "}\n",
222178825Sdfr		 name, length, r->min, forwstr);
223178825Sdfr    if (r->max == r->min)
224178825Sdfr	fprintf (codefile,
225178825Sdfr		 "if ((%s)->%s != %d) {\n"
226178825Sdfr		 "e = ASN1_EXACT_CONSTRAINT; %s;\n"
227178825Sdfr		 "}\n",
228178825Sdfr		 name, length, r->min, forwstr);
229178825Sdfr}
230178825Sdfr
231178825Sdfrstatic int
232178825Sdfrdecode_type (const char *name, const Type *t, int optional,
233178825Sdfr	     const char *forwstr, const char *tmpstr)
234178825Sdfr{
235178825Sdfr    switch (t->type) {
236178825Sdfr    case TType: {
237178825Sdfr	if (optional)
238178825Sdfr	    fprintf(codefile,
239178825Sdfr		    "%s = calloc(1, sizeof(*%s));\n"
240178825Sdfr		    "if (%s == NULL) %s;\n",
241178825Sdfr		    name, name, name, forwstr);
242178825Sdfr	fprintf (codefile,
243178825Sdfr		 "e = decode_%s(p, len, %s, &l);\n",
24472445Sassar		 t->symbol->gen_name, name);
245178825Sdfr	if (optional) {
246178825Sdfr	    fprintf (codefile,
247178825Sdfr		     "if(e) {\n"
248178825Sdfr		     "free(%s);\n"
249178825Sdfr		     "%s = NULL;\n"
250178825Sdfr		     "} else {\n"
251178825Sdfr		     "p += l; len -= l; ret += l;\n"
252178825Sdfr		     "}\n",
253178825Sdfr		     name, name);
254178825Sdfr	} else {
255178825Sdfr	    fprintf (codefile,
256178825Sdfr		     "if(e) %s;\n",
257178825Sdfr		     forwstr);
258178825Sdfr	    fprintf (codefile,
259178825Sdfr		     "p += l; len -= l; ret += l;\n");
260178825Sdfr	}
26172445Sassar	break;
262178825Sdfr    }
26372445Sassar    case TInteger:
264178825Sdfr	if(t->members) {
265178825Sdfr	    fprintf(codefile,
266178825Sdfr		    "{\n"
267178825Sdfr		    "int enumint;\n");
268178825Sdfr	    decode_primitive ("integer", "&enumint", forwstr);
269178825Sdfr	    fprintf(codefile,
270178825Sdfr		    "*%s = enumint;\n"
271178825Sdfr		    "}\n",
272178825Sdfr		    name);
273178825Sdfr	} else if (t->range == NULL) {
274178825Sdfr	    decode_primitive ("heim_integer", name, forwstr);
275178825Sdfr	} else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
276178825Sdfr	    decode_primitive ("integer", name, forwstr);
277178825Sdfr	} else if (t->range->min == 0 && t->range->max == UINT_MAX) {
278178825Sdfr	    decode_primitive ("unsigned", name, forwstr);
279178825Sdfr	} else if (t->range->min == 0 && t->range->max == INT_MAX) {
280178825Sdfr	    decode_primitive ("unsigned", name, forwstr);
281178825Sdfr	} else
282178825Sdfr	    errx(1, "%s: unsupported range %d -> %d",
283178825Sdfr		 name, t->range->min, t->range->max);
28472445Sassar	break;
285178825Sdfr    case TBoolean:
286178825Sdfr      decode_primitive ("boolean", name, forwstr);
287178825Sdfr      break;
28890926Snectar    case TEnumerated:
289178825Sdfr	decode_primitive ("enumerated", name, forwstr);
29090926Snectar	break;
29172445Sassar    case TOctetString:
292178825Sdfr	decode_primitive ("octet_string", name, forwstr);
293178825Sdfr	if (t->range)
294178825Sdfr	    range_check(name, "length", forwstr, t->range);
29572445Sassar	break;
29672445Sassar    case TBitString: {
29772445Sassar	Member *m;
298178825Sdfr	int pos = 0;
29955682Smarkm
300178825Sdfr	if (ASN1_TAILQ_EMPTY(t->members)) {
301178825Sdfr	    decode_primitive ("bit_string", name, forwstr);
302178825Sdfr	    break;
303178825Sdfr	}
304178825Sdfr	fprintf(codefile,
305178825Sdfr		"if (len < 1) return ASN1_OVERRUN;\n"
306178825Sdfr		"p++; len--; ret++;\n");
307178825Sdfr	fprintf(codefile,
308178825Sdfr		"do {\n"
309178825Sdfr		"if (len < 1) break;\n");
310178825Sdfr	ASN1_TAILQ_FOREACH(m, t->members, members) {
31172445Sassar	    while (m->val / 8 > pos / 8) {
31272445Sassar		fprintf (codefile,
313178825Sdfr			 "p++; len--; ret++;\n"
314178825Sdfr			 "if (len < 1) break;\n");
31572445Sassar		pos += 8;
31672445Sassar	    }
31772445Sassar	    fprintf (codefile,
318178825Sdfr		     "(%s)->%s = (*p >> %d) & 1;\n",
31972445Sassar		     name, m->gen_name, 7 - m->val % 8);
32072445Sassar	}
321178825Sdfr	fprintf(codefile,
322178825Sdfr		"} while(0);\n");
32372445Sassar	fprintf (codefile,
324178825Sdfr		 "p += len; ret += len;\n");
32572445Sassar	break;
32655682Smarkm    }
32772445Sassar    case TSequence: {
32872445Sassar	Member *m;
32955682Smarkm
33072445Sassar	if (t->members == NULL)
33172445Sassar	    break;
33255682Smarkm
333178825Sdfr	ASN1_TAILQ_FOREACH(m, t->members, members) {
334178825Sdfr	    char *s;
33555682Smarkm
336178825Sdfr	    if (m->ellipsis)
337178825Sdfr		continue;
338178825Sdfr
339178825Sdfr	    asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&",
340178825Sdfr		      name, m->gen_name);
341178825Sdfr	    if (s == NULL)
342178825Sdfr		errx(1, "malloc");
343178825Sdfr	    decode_type (s, m->type, m->optional, forwstr, m->gen_name);
344178825Sdfr	    free (s);
345178825Sdfr	}
346178825Sdfr
347178825Sdfr	break;
348178825Sdfr    }
349178825Sdfr    case TSet: {
350178825Sdfr	Member *m;
351178825Sdfr	unsigned int memno;
352178825Sdfr
353178825Sdfr	if(t->members == NULL)
354178825Sdfr	    break;
355178825Sdfr
356178825Sdfr	fprintf(codefile, "{\n");
357178825Sdfr	fprintf(codefile, "unsigned int members = 0;\n");
358178825Sdfr	fprintf(codefile, "while(len > 0) {\n");
359178825Sdfr	fprintf(codefile,
360178825Sdfr		"Der_class class;\n"
361178825Sdfr		"Der_type type;\n"
362178825Sdfr		"int tag;\n"
363178825Sdfr		"e = der_get_tag (p, len, &class, &type, &tag, NULL);\n"
364178825Sdfr		"if(e) %s;\n", forwstr);
365178825Sdfr	fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n");
366178825Sdfr	memno = 0;
367178825Sdfr	ASN1_TAILQ_FOREACH(m, t->members, members) {
36872445Sassar	    char *s;
36955682Smarkm
370178825Sdfr	    assert(m->type->type == TTag);
371178825Sdfr
372178825Sdfr	    fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n",
373178825Sdfr		    classname(m->type->tag.tagclass),
374178825Sdfr		    is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS",
375178825Sdfr		    valuename(m->type->tag.tagclass, m->type->tag.tagvalue));
376178825Sdfr
37772445Sassar	    asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name);
378178825Sdfr	    if (s == NULL)
379178825Sdfr		errx(1, "malloc");
380178825Sdfr	    if(m->optional)
381178825Sdfr		fprintf(codefile,
382178825Sdfr			"%s = calloc(1, sizeof(*%s));\n"
383178825Sdfr			"if (%s == NULL) { e = ENOMEM; %s; }\n",
384178825Sdfr			s, s, s, forwstr);
385178825Sdfr	    decode_type (s, m->type, 0, forwstr, m->gen_name);
38672445Sassar	    free (s);
387178825Sdfr
388178825Sdfr	    fprintf(codefile, "members |= (1 << %d);\n", memno);
389178825Sdfr	    memno++;
390178825Sdfr	    fprintf(codefile, "break;\n");
39172445Sassar	}
392178825Sdfr	fprintf(codefile,
393178825Sdfr		"default:\n"
394178825Sdfr		"return ASN1_MISPLACED_FIELD;\n"
395178825Sdfr		"break;\n");
396178825Sdfr	fprintf(codefile, "}\n");
397178825Sdfr	fprintf(codefile, "}\n");
398178825Sdfr	memno = 0;
399178825Sdfr	ASN1_TAILQ_FOREACH(m, t->members, members) {
400178825Sdfr	    char *s;
40172445Sassar
402178825Sdfr	    asprintf (&s, "%s->%s", name, m->gen_name);
403178825Sdfr	    if (s == NULL)
404178825Sdfr		errx(1, "malloc");
405178825Sdfr	    fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno);
406178825Sdfr	    if(m->optional)
407178825Sdfr		fprintf(codefile, "%s = NULL;\n", s);
408178825Sdfr	    else if(m->defval)
409178825Sdfr		gen_assign_defval(s, m->defval);
410178825Sdfr	    else
411178825Sdfr		fprintf(codefile, "return ASN1_MISSING_FIELD;\n");
412178825Sdfr	    free(s);
413178825Sdfr	    memno++;
414178825Sdfr	}
415178825Sdfr	fprintf(codefile, "}\n");
41672445Sassar	break;
41755682Smarkm    }
418178825Sdfr    case TSetOf:
41972445Sassar    case TSequenceOf: {
42072445Sassar	char *n;
421178825Sdfr	char *sname;
42255682Smarkm
42372445Sassar	fprintf (codefile,
42472445Sassar		 "{\n"
425178825Sdfr		 "size_t %s_origlen = len;\n"
426178825Sdfr		 "size_t %s_oldret = ret;\n"
427178825Sdfr		 "size_t %s_olen = 0;\n"
428178825Sdfr		 "void *%s_tmp;\n"
42972445Sassar		 "ret = 0;\n"
43072445Sassar		 "(%s)->len = 0;\n"
431178825Sdfr		 "(%s)->val = NULL;\n",
432178825Sdfr		 tmpstr,
433178825Sdfr		 tmpstr,
434178825Sdfr		 tmpstr,
435178825Sdfr		 tmpstr,
436178825Sdfr		 name,
437178825Sdfr		 name);
438178825Sdfr
439178825Sdfr	fprintf (codefile,
440178825Sdfr		 "while(ret < %s_origlen) {\n"
441178825Sdfr		 "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n"
442178825Sdfr		 "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n"
443178825Sdfr		 "%s_olen = %s_nlen;\n"
444178825Sdfr		 "%s_tmp = realloc((%s)->val, %s_olen);\n"
445178825Sdfr		 "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n"
446178825Sdfr		 "(%s)->val = %s_tmp;\n",
447178825Sdfr		 tmpstr,
448178825Sdfr		 tmpstr, tmpstr, name,
449178825Sdfr		 tmpstr, tmpstr, forwstr,
450178825Sdfr		 tmpstr, tmpstr,
451178825Sdfr		 tmpstr, name, tmpstr,
452178825Sdfr		 tmpstr, forwstr,
453178825Sdfr		 name, tmpstr);
454178825Sdfr
455178825Sdfr	asprintf (&n, "&(%s)->val[(%s)->len]", name, name);
456178825Sdfr	if (n == NULL)
457178825Sdfr	    errx(1, "malloc");
458178825Sdfr	asprintf (&sname, "%s_s_of", tmpstr);
459178825Sdfr	if (sname == NULL)
460178825Sdfr	    errx(1, "malloc");
461178825Sdfr	decode_type (n, t->subtype, 0, forwstr, sname);
462178825Sdfr	fprintf (codefile,
46372445Sassar		 "(%s)->len++;\n"
464178825Sdfr		 "len = %s_origlen - ret;\n"
46572445Sassar		 "}\n"
466178825Sdfr		 "ret += %s_oldret;\n"
467178825Sdfr		 "}\n",
468178825Sdfr		 name,
469178825Sdfr		 tmpstr, tmpstr);
470178825Sdfr	if (t->range)
471178825Sdfr	    range_check(name, "len", forwstr, t->range);
47272445Sassar	free (n);
473178825Sdfr	free (sname);
47472445Sassar	break;
47572445Sassar    }
47672445Sassar    case TGeneralizedTime:
477178825Sdfr	decode_primitive ("generalized_time", name, forwstr);
47872445Sassar	break;
47972445Sassar    case TGeneralString:
480178825Sdfr	decode_primitive ("general_string", name, forwstr);
48172445Sassar	break;
482178825Sdfr    case TTag:{
483178825Sdfr    	char *tname;
484178825Sdfr
485178825Sdfr	fprintf(codefile,
486178825Sdfr		"{\n"
487178825Sdfr		"size_t %s_datalen, %s_oldlen;\n",
488178825Sdfr		tmpstr, tmpstr);
489178825Sdfr	if(dce_fix)
490178825Sdfr	    fprintf(codefile,
491178825Sdfr		    "int dce_fix;\n");
492178825Sdfr	fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, %s, %s, "
493178825Sdfr		"&%s_datalen, &l);\n",
494178825Sdfr		classname(t->tag.tagclass),
495178825Sdfr		is_primitive_type(t->subtype->type) ? "PRIM" : "CONS",
496178825Sdfr		valuename(t->tag.tagclass, t->tag.tagvalue),
497178825Sdfr		tmpstr);
498178825Sdfr	if(optional) {
499178825Sdfr	    fprintf(codefile,
500178825Sdfr		    "if(e) {\n"
501178825Sdfr		    "%s = NULL;\n"
502178825Sdfr		    "} else {\n"
503178825Sdfr		     "%s = calloc(1, sizeof(*%s));\n"
504178825Sdfr		     "if (%s == NULL) { e = ENOMEM; %s; }\n",
505178825Sdfr		     name, name, name, name, forwstr);
506178825Sdfr	} else {
507178825Sdfr	    fprintf(codefile, "if(e) %s;\n", forwstr);
508178825Sdfr	}
50972445Sassar	fprintf (codefile,
510178825Sdfr		 "p += l; len -= l; ret += l;\n"
511178825Sdfr		 "%s_oldlen = len;\n",
512178825Sdfr		 tmpstr);
513178825Sdfr	if(dce_fix)
514178825Sdfr	    fprintf (codefile,
515178825Sdfr		     "if((dce_fix = _heim_fix_dce(%s_datalen, &len)) < 0)\n"
516178825Sdfr		     "{ e = ASN1_BAD_FORMAT; %s; }\n",
517178825Sdfr		     tmpstr, forwstr);
518178825Sdfr	else
519178825Sdfr	    fprintf(codefile,
520178825Sdfr		    "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n"
521178825Sdfr		    "len = %s_datalen;\n", tmpstr, forwstr, tmpstr);
522178825Sdfr	asprintf (&tname, "%s_Tag", tmpstr);
523178825Sdfr	if (tname == NULL)
524178825Sdfr	    errx(1, "malloc");
525178825Sdfr	decode_type (name, t->subtype, 0, forwstr, tname);
526178825Sdfr	if(dce_fix)
527178825Sdfr	    fprintf(codefile,
528178825Sdfr		    "if(dce_fix){\n"
529178825Sdfr		    "e = der_match_tag_and_length (p, len, "
530178825Sdfr		    "(Der_class)0,(Der_type)0, UT_EndOfContent, "
531178825Sdfr		    "&%s_datalen, &l);\n"
532178825Sdfr		    "if(e) %s;\np += l; len -= l; ret += l;\n"
533178825Sdfr		    "} else \n", tmpstr, forwstr);
534178825Sdfr	fprintf(codefile,
535178825Sdfr		"len = %s_oldlen - %s_datalen;\n",
536178825Sdfr		tmpstr, tmpstr);
537178825Sdfr	if(optional)
538178825Sdfr	    fprintf(codefile,
539178825Sdfr		    "}\n");
540178825Sdfr	fprintf(codefile,
54172445Sassar		"}\n");
542178825Sdfr	free(tname);
543178825Sdfr	break;
544178825Sdfr    }
545178825Sdfr    case TChoice: {
546178825Sdfr	Member *m, *have_ellipsis = NULL;
547178825Sdfr	const char *els = "";
54855682Smarkm
549178825Sdfr	if (t->members == NULL)
550178825Sdfr	    break;
551178825Sdfr
552178825Sdfr	ASN1_TAILQ_FOREACH(m, t->members, members) {
553178825Sdfr	    const Type *tt = m->type;
554178825Sdfr	    char *s;
555178825Sdfr	    Der_class cl;
556178825Sdfr	    Der_type  ty;
557178825Sdfr	    unsigned  tag;
558178825Sdfr
559178825Sdfr	    if (m->ellipsis) {
560178825Sdfr		have_ellipsis = m;
561178825Sdfr		continue;
562178825Sdfr	    }
563178825Sdfr
564178825Sdfr	    find_tag(tt, &cl, &ty, &tag);
565178825Sdfr
566178825Sdfr	    fprintf(codefile,
567178825Sdfr		    "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n",
568178825Sdfr		    els,
569178825Sdfr		    classname(cl),
570178825Sdfr		    ty ? "CONS" : "PRIM",
571178825Sdfr		    valuename(cl, tag));
572178825Sdfr	    asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&",
573178825Sdfr		      name, m->gen_name);
574178825Sdfr	    if (s == NULL)
575178825Sdfr		errx(1, "malloc");
576178825Sdfr	    decode_type (s, m->type, m->optional, forwstr, m->gen_name);
577178825Sdfr	    fprintf(codefile,
578178825Sdfr		    "(%s)->element = %s;\n",
579178825Sdfr		    name, m->label);
580178825Sdfr	    free(s);
581178825Sdfr	    fprintf(codefile,
582178825Sdfr		    "}\n");
583178825Sdfr	    els = "else ";
584178825Sdfr	}
585178825Sdfr	if (have_ellipsis) {
586178825Sdfr	    fprintf(codefile,
587178825Sdfr		    "else {\n"
588178825Sdfr		    "(%s)->u.%s.data = calloc(1, len);\n"
589178825Sdfr		    "if ((%s)->u.%s.data == NULL) {\n"
590178825Sdfr		    "e = ENOMEM; %s;\n"
591178825Sdfr		    "}\n"
592178825Sdfr		    "(%s)->u.%s.length = len;\n"
593178825Sdfr		    "memcpy((%s)->u.%s.data, p, len);\n"
594178825Sdfr		    "(%s)->element = %s;\n"
595178825Sdfr		    "p += len;\n"
596178825Sdfr		    "ret += len;\n"
597178825Sdfr		    "len -= len;\n"
598178825Sdfr		    "}\n",
599178825Sdfr		    name, have_ellipsis->gen_name,
600178825Sdfr		    name, have_ellipsis->gen_name,
601178825Sdfr		    forwstr,
602178825Sdfr		    name, have_ellipsis->gen_name,
603178825Sdfr		    name, have_ellipsis->gen_name,
604178825Sdfr		    name, have_ellipsis->label);
605178825Sdfr	} else {
606178825Sdfr	    fprintf(codefile,
607178825Sdfr		    "else {\n"
608178825Sdfr		    "e = ASN1_PARSE_ERROR;\n"
609178825Sdfr		    "%s;\n"
610178825Sdfr		    "}\n",
611178825Sdfr		    forwstr);
612178825Sdfr	}
61372445Sassar	break;
614178825Sdfr    }
615178825Sdfr    case TUTCTime:
616178825Sdfr	decode_primitive ("utctime", name, forwstr);
617178825Sdfr	break;
618178825Sdfr    case TUTF8String:
619178825Sdfr	decode_primitive ("utf8string", name, forwstr);
620178825Sdfr	break;
621178825Sdfr    case TPrintableString:
622178825Sdfr	decode_primitive ("printable_string", name, forwstr);
623178825Sdfr	break;
624178825Sdfr    case TIA5String:
625178825Sdfr	decode_primitive ("ia5_string", name, forwstr);
626178825Sdfr	break;
627178825Sdfr    case TBMPString:
628178825Sdfr	decode_primitive ("bmp_string", name, forwstr);
629178825Sdfr	break;
630178825Sdfr    case TUniversalString:
631178825Sdfr	decode_primitive ("universal_string", name, forwstr);
632178825Sdfr	break;
633178825Sdfr    case TVisibleString:
634178825Sdfr	decode_primitive ("visible_string", name, forwstr);
635178825Sdfr	break;
636178825Sdfr    case TNull:
637178825Sdfr	fprintf (codefile, "/* NULL */\n");
638178825Sdfr	break;
639178825Sdfr    case TOID:
640178825Sdfr	decode_primitive ("oid", name, forwstr);
641178825Sdfr	break;
64272445Sassar    default :
64372445Sassar	abort ();
64472445Sassar    }
645178825Sdfr    return 0;
64655682Smarkm}
64755682Smarkm
64855682Smarkmvoid
64955682Smarkmgenerate_type_decode (const Symbol *s)
65055682Smarkm{
651178825Sdfr    int preserve = preserve_type(s->name) ? TRUE : FALSE;
65255682Smarkm
65355682Smarkm    fprintf (headerfile,
654178825Sdfr	     "int    "
655178825Sdfr	     "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
65655682Smarkm	     s->gen_name, s->gen_name);
65755682Smarkm
65855682Smarkm    fprintf (codefile, "int\n"
659178825Sdfr	     "decode_%s(const unsigned char *p,"
660178825Sdfr	     " size_t len, %s *data, size_t *size)\n"
66155682Smarkm	     "{\n",
66255682Smarkm	     s->gen_name, s->gen_name);
66355682Smarkm
664178825Sdfr    switch (s->type->type) {
665178825Sdfr    case TInteger:
666178825Sdfr    case TBoolean:
667178825Sdfr    case TOctetString:
668178825Sdfr    case TOID:
669178825Sdfr    case TGeneralizedTime:
670178825Sdfr    case TGeneralString:
671178825Sdfr    case TUTF8String:
672178825Sdfr    case TPrintableString:
673178825Sdfr    case TIA5String:
674178825Sdfr    case TBMPString:
675178825Sdfr    case TUniversalString:
676178825Sdfr    case TVisibleString:
677178825Sdfr    case TUTCTime:
678178825Sdfr    case TNull:
679178825Sdfr    case TEnumerated:
680178825Sdfr    case TBitString:
681178825Sdfr    case TSequence:
682178825Sdfr    case TSequenceOf:
683178825Sdfr    case TSet:
684178825Sdfr    case TSetOf:
685178825Sdfr    case TTag:
686178825Sdfr    case TType:
687178825Sdfr    case TChoice:
688178825Sdfr	fprintf (codefile,
689178825Sdfr		 "size_t ret = 0;\n"
690178825Sdfr		 "size_t l;\n"
691178825Sdfr		 "int e;\n");
692178825Sdfr	if (preserve)
693178825Sdfr	    fprintf (codefile, "const unsigned char *begin = p;\n");
69455682Smarkm
695178825Sdfr	fprintf (codefile, "\n");
696178825Sdfr	fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
697178825Sdfr
698178825Sdfr	decode_type ("data", s->type, 0, "goto fail", "Top");
699178825Sdfr	if (preserve)
700178825Sdfr	    fprintf (codefile,
701178825Sdfr		     "data->_save.data = calloc(1, ret);\n"
702178825Sdfr		     "if (data->_save.data == NULL) { \n"
703178825Sdfr		     "e = ENOMEM; goto fail; \n"
704178825Sdfr		     "}\n"
705178825Sdfr		     "data->_save.length = ret;\n"
706178825Sdfr		     "memcpy(data->_save.data, begin, ret);\n");
707178825Sdfr	fprintf (codefile,
708178825Sdfr		 "if(size) *size = ret;\n"
709178825Sdfr		 "return 0;\n");
710178825Sdfr	fprintf (codefile,
711178825Sdfr		 "fail:\n"
712178825Sdfr		 "free_%s(data);\n"
713178825Sdfr		 "return e;\n",
714178825Sdfr		 s->gen_name);
715178825Sdfr	break;
716178825Sdfr    default:
717178825Sdfr	abort ();
718178825Sdfr    }
71955682Smarkm    fprintf (codefile, "}\n\n");
72055682Smarkm}
721