1194955Strasz/*
2194955Strasz * Copyright (c) 1997 - 2005 Kungliga Tekniska H��gskolan
3194955Strasz * (Royal Institute of Technology, Stockholm, Sweden).
4194955Strasz * All rights reserved.
5194955Strasz *
6194955Strasz * Redistribution and use in source and binary forms, with or without
7194955Strasz * modification, are permitted provided that the following conditions
8194955Strasz * are met:
9194955Strasz *
10194955Strasz * 1. Redistributions of source code must retain the above copyright
11194955Strasz *    notice, this list of conditions and the following disclaimer.
12194955Strasz *
13194955Strasz * 2. Redistributions in binary form must reproduce the above copyright
14194955Strasz *    notice, this list of conditions and the following disclaimer in the
15194955Strasz *    documentation and/or other materials provided with the distribution.
16194955Strasz *
17194955Strasz * 3. Neither the name of the Institute nor the names of its contributors
18194955Strasz *    may be used to endorse or promote products derived from this software
19194955Strasz *    without specific prior written permission.
20194955Strasz *
21194955Strasz * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22194955Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23194955Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24194955Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25194955Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26194955Strasz * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27194955Strasz * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28194955Strasz * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29194955Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30194955Strasz * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31194955Strasz * SUCH DAMAGE.
32194955Strasz */
33194955Strasz
34194955Strasz#include "gen_locl.h"
35194955Strasz
36194955StraszRCSID("$Id$");
37194955Strasz
38194955Straszstatic void
39194955Straszlength_primitive (const char *typename,
40194955Strasz		  const char *name,
41194955Strasz		  const char *variable)
42194955Strasz{
43194955Strasz    fprintf (codefile, "%s += der_length_%s(%s);\n", variable, typename, name);
44194955Strasz}
45194955Strasz
46194955Strasz/* XXX same as der_length_tag */
47194955Straszstatic size_t
48194955Straszlength_tag(unsigned int tag)
49194955Strasz{
50194955Strasz    size_t len = 0;
51194955Strasz
52194955Strasz    if(tag <= 30)
53208811Strasz	return 1;
54194955Strasz    while(tag) {
55194955Strasz	tag /= 128;
56194955Strasz	len++;
57194955Strasz    }
58194955Strasz    return len + 1;
59194955Strasz}
60194955Strasz
61194955Strasz
62194955Straszstatic int
63194955Straszlength_type (const char *name, const Type *t,
64194955Strasz	     const char *variable, const char *tmpstr)
65208811Strasz{
66194955Strasz    switch (t->type) {
67194955Strasz    case TType:
68194955Strasz#if 0
69194955Strasz	length_type (name, t->symbol->type);
70194955Strasz#endif
71194955Strasz	fprintf (codefile, "%s += length_%s(%s);\n",
72194955Strasz		 variable, t->symbol->gen_name, name);
73194955Strasz	break;
74194955Strasz    case TInteger:
75194955Strasz	if(t->members) {
76194955Strasz	    fprintf(codefile,
77194955Strasz		    "{\n"
78194955Strasz		    "int enumint = *%s;\n", name);
79194955Strasz	    length_primitive ("integer", "&enumint", variable);
80194955Strasz	    fprintf(codefile, "}\n");
81194955Strasz	} else if (t->range == NULL) {
82194955Strasz	    length_primitive ("heim_integer", name, variable);
83194955Strasz	} else if (t->range->min == INT_MIN && t->range->max == INT_MAX) {
84208811Strasz	    length_primitive ("integer", name, variable);
85194955Strasz	} else if (t->range->min == 0 && t->range->max == UINT_MAX) {
86194955Strasz	    length_primitive ("unsigned", name, variable);
87194955Strasz	} else if (t->range->min == 0 && t->range->max == INT_MAX) {
88194955Strasz	    length_primitive ("unsigned", name, variable);
89194955Strasz	} else
90194955Strasz	    errx(1, "%s: unsupported range %d -> %d",
91194955Strasz		 name, t->range->min, t->range->max);
92194955Strasz
93194955Strasz	break;
94194955Strasz    case TBoolean:
95194955Strasz	fprintf (codefile, "%s += 1;\n", variable);
96194955Strasz	break;
97194955Strasz    case TEnumerated :
98194955Strasz	length_primitive ("enumerated", name, variable);
99194955Strasz	break;
100194955Strasz    case TOctetString:
101194955Strasz	length_primitive ("octet_string", name, variable);
102194955Strasz	break;
103194955Strasz    case TBitString: {
104194955Strasz	if (ASN1_TAILQ_EMPTY(t->members))
105194955Strasz	    length_primitive("bit_string", name, variable);
106194955Strasz	else {
107194955Strasz	    if (!rfc1510_bitstring) {
108194955Strasz		Member *m;
109194955Strasz		int pos = ASN1_TAILQ_LAST(t->members, memhead)->val;
110194955Strasz
111194955Strasz		fprintf(codefile,
112194955Strasz			"do {\n");
113194955Strasz		ASN1_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
114194955Strasz		    while (m->val / 8 < pos / 8) {
115194955Strasz			pos -= 8;
116194955Strasz		    }
117194955Strasz		    fprintf (codefile,
118194955Strasz			     "if((%s)->%s) { %s += %d; break; }\n",
119194955Strasz			     name, m->gen_name, variable, (pos + 8) / 8);
120194955Strasz		}
121194955Strasz		fprintf(codefile,
122194955Strasz			"} while(0);\n");
123194955Strasz		fprintf (codefile, "%s += 1;\n", variable);
124194955Strasz	    } else {
125194955Strasz		fprintf (codefile, "%s += 5;\n", variable);
126194955Strasz	    }
127194955Strasz	}
128194955Strasz	break;
129194955Strasz    }
130194955Strasz    case TSet:
131194955Strasz    case TSequence:
132194955Strasz    case TChoice: {
133194955Strasz	Member *m, *have_ellipsis = NULL;
134194955Strasz
135194955Strasz	if (t->members == NULL)
136194955Strasz	    break;
137194955Strasz
138194955Strasz	if(t->type == TChoice)
139194955Strasz	    fprintf (codefile, "switch((%s)->element) {\n", name);
140194955Strasz
141194955Strasz	ASN1_TAILQ_FOREACH(m, t->members, members) {
142194955Strasz	    char *s;
143194955Strasz
144208811Strasz	    if (m->ellipsis) {
145194955Strasz		have_ellipsis = m;
146194955Strasz		continue;
147194955Strasz	    }
148194955Strasz
149194955Strasz	    if(t->type == TChoice)
150194955Strasz		fprintf(codefile, "case %s:\n", m->label);
151194955Strasz
152194955Strasz	    if (asprintf (&s, "%s(%s)->%s%s",
153194955Strasz			  m->optional ? "" : "&", name,
154194955Strasz			  t->type == TChoice ? "u." : "", m->gen_name) < 0 || s == NULL)
155194955Strasz		errx(1, "malloc");
156194955Strasz	    if (m->optional)
157194955Strasz		fprintf (codefile, "if(%s)", s);
158208811Strasz	    else if(m->defval)
159194955Strasz		gen_compare_defval(s + 1, m->defval);
160194955Strasz	    fprintf (codefile, "{\n"
161194955Strasz		     "size_t %s_oldret = %s;\n"
162194955Strasz		     "%s = 0;\n", tmpstr, variable, variable);
163194955Strasz	    length_type (s, m->type, "ret", m->gen_name);
164194955Strasz	    fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
165194955Strasz	    fprintf (codefile, "}\n");
166194955Strasz	    free (s);
167194955Strasz	    if(t->type == TChoice)
168194955Strasz		fprintf(codefile, "break;\n");
169194955Strasz	}
170205796Strasz	if(t->type == TChoice) {
171194955Strasz	    if (have_ellipsis)
172194955Strasz		fprintf(codefile,
173194955Strasz			"case %s:\n"
174194955Strasz			"ret += (%s)->u.%s.length;\n"
175194955Strasz			"break;\n",
176194955Strasz			have_ellipsis->label,
177194955Strasz			name,
178194955Strasz			have_ellipsis->gen_name);
179194955Strasz	    fprintf (codefile, "}\n"); /* switch */
180194955Strasz	}
181194955Strasz	break;
182194955Strasz    }
183194955Strasz    case TSetOf:
184194955Strasz    case TSequenceOf: {
185194955Strasz	char *n = NULL;
186194955Strasz	char *sname = NULL;
187194955Strasz
188194955Strasz	fprintf (codefile,
189194955Strasz		 "{\n"
190194955Strasz		 "size_t %s_oldret = %s;\n"
191205796Strasz		 "int i;\n"
192205796Strasz		 "%s = 0;\n",
193205796Strasz		 tmpstr, variable, variable);
194194955Strasz
195194955Strasz	fprintf (codefile, "for(i = (%s)->len - 1; i >= 0; --i){\n", name);
196194955Strasz	fprintf (codefile, "size_t %s_for_oldret = %s;\n"
197194955Strasz		 "%s = 0;\n", tmpstr, variable, variable);
198194955Strasz	if (asprintf (&n, "&(%s)->val[i]", name) < 0  || n == NULL)
199194955Strasz	    errx(1, "malloc");
200194955Strasz	if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL)
201194955Strasz	    errx(1, "malloc");
202194955Strasz	length_type(n, t->subtype, variable, sname);
203194955Strasz	fprintf (codefile, "%s += %s_for_oldret;\n",
204194955Strasz		 variable, tmpstr);
205194955Strasz	fprintf (codefile, "}\n");
206194955Strasz
207194955Strasz	fprintf (codefile,
208194955Strasz		 "%s += %s_oldret;\n"
209194955Strasz		 "}\n", variable, tmpstr);
210194955Strasz	free(n);
211194955Strasz	free(sname);
212194955Strasz	break;
213194955Strasz    }
214194955Strasz    case TGeneralizedTime:
215194955Strasz	length_primitive ("generalized_time", name, variable);
216194955Strasz	break;
217194955Strasz    case TGeneralString:
218194955Strasz	length_primitive ("general_string", name, variable);
219194955Strasz	break;
220194955Strasz    case TTeletexString:
221194955Strasz	length_primitive ("general_string", name, variable);
222194955Strasz	break;
223194955Strasz    case TUTCTime:
224194955Strasz	length_primitive ("utctime", name, variable);
225194955Strasz	break;
226194955Strasz    case TUTF8String:
227194955Strasz	length_primitive ("utf8string", name, variable);
228194955Strasz	break;
229194955Strasz    case TPrintableString:
230194955Strasz	length_primitive ("printable_string", name, variable);
231194955Strasz	break;
232194955Strasz    case TIA5String:
233194955Strasz	length_primitive ("ia5_string", name, variable);
234194955Strasz	break;
235194955Strasz    case TBMPString:
236194955Strasz	length_primitive ("bmp_string", name, variable);
237194955Strasz	break;
238194955Strasz    case TUniversalString:
239194955Strasz	length_primitive ("universal_string", name, variable);
240194955Strasz	break;
241194955Strasz    case TVisibleString:
242194955Strasz	length_primitive ("visible_string", name, variable);
243194955Strasz	break;
244194955Strasz    case TNull:
245194955Strasz	fprintf (codefile, "/* NULL */\n");
246194955Strasz	break;
247194955Strasz    case TTag:{
248194955Strasz    	char *tname = NULL;
249208786Strasz	if (asprintf(&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
250194955Strasz	    errx(1, "malloc");
251194955Strasz	length_type (name, t->subtype, variable, tname);
252194955Strasz	fprintf (codefile, "ret += %lu + der_length_len (ret);\n",
253194955Strasz		 (unsigned long)length_tag(t->tag.tagvalue));
254194955Strasz	free(tname);
255194955Strasz	break;
256194955Strasz    }
257194955Strasz    case TOID:
258194955Strasz	length_primitive ("oid", name, variable);
259194955Strasz	break;
260194955Strasz    default :
261194955Strasz	abort ();
262194955Strasz    }
263194955Strasz    return 0;
264194955Strasz}
265
266void
267generate_type_length (const Symbol *s)
268{
269    fprintf (codefile,
270	     "size_t ASN1CALL\n"
271	     "length_%s(const %s *data)\n"
272	     "{\n"
273	     "size_t ret = 0;\n",
274	     s->gen_name, s->gen_name);
275
276    length_type ("data", s->type, "ret", "Top");
277    fprintf (codefile, "return ret;\n}\n\n");
278}
279
280