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