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