s4:heimdal: import lorikeet-heimdal-200911122202 (commit 9291fd2d101f3eecec550178634f...
[samba.git] / source4 / heimdal / lib / asn1 / gen_decode.c
1 /*
2  * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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.
16  *
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.
20  *
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.
32  */
33
34 #include "gen_locl.h"
35 #include "lex.h"
36
37 RCSID("$Id$");
38
39 static void
40 decode_primitive (const char *typename, const char *name, const char *forwstr)
41 {
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
57 }
58
59 static int
60 is_primitive_type(int type)
61 {
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;
83     }
84 }
85
86 static void
87 find_tag (const Type *t,
88           Der_class *cl, Der_type *ty, unsigned *tag)
89 {
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);
178         }
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();
208     }
209 }
210
211 static void
212 range_check(const char *name,
213             const char *length,
214             const char *forwstr,
215             struct range *r)
216 {
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);
235 }
236
237 static int
238 decode_type (const char *name, const Type *t, int optional,
239              const char *forwstr, const char *tmpstr, const char *dertype)
240 {
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");
266         }
267         break;
268     }
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");
305         }
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;
315
316         if (ASN1_TAILQ_EMPTY(t->members)) {
317             decode_primitive ("bit_string", name, forwstr);
318             break;
319         }
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;
332             }
333             fprintf (codefile,
334                      "(%s)->%s = (*p >> %d) & 1;\n",
335                      name, m->gen_name, 7 - m->val % 8);
336         }
337         fprintf(codefile,
338                 "} while(0);\n");
339         fprintf (codefile,
340                  "p += len; ret += len;\n");
341         break;
342     }
343     case TSequence: {
344         Member *m;
345
346         if (t->members == NULL)
347             break;
348
349         ASN1_TAILQ_FOREACH(m, t->members, members) {
350             char *s;
351
352             if (m->ellipsis)
353                 continue;
354
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);
361         }
362
363         break;
364     }
365     case TSet: {
366         Member *m;
367         unsigned int memno;
368
369         if(t->members == NULL)
370             break;
371
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;
385
386             assert(m->type->type == TTag);
387
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));
392
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);
403
404             fprintf(codefile, "members |= (1 << %d);\n", memno);
405             memno++;
406             fprintf(codefile, "break;\n");
407         }
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;
417
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++;
430         }
431         fprintf(codefile, "}\n");
432         break;
433     }
434     case TSetOf:
435     case TSequenceOf: {
436         char *n;
437         char *sname;
438
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);
454
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);
470
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;
491     }
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;
504
505         asprintf(&typestring, "%s_type", tmpstr);
506
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");
515
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);
522
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");
531         }
532
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);
543         }
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;
588     }
589     case TChoice: {
590         Member *m, *have_ellipsis = NULL;
591         const char *els = "";
592
593         if (t->members == NULL)
594             break;
595
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;
602
603             if (m->ellipsis) {
604                 have_ellipsis = m;
605                 continue;
606             }
607
608             find_tag(tt, &cl, &ty, &tag);
609
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 ";
628         }
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);
656         }
657         break;
658     }
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 ();
688     }
689     return 0;
690 }
691
692 void
693 generate_type_decode (const Symbol *s)
694 {
695     int preserve = preserve_type(s->name) ? TRUE : FALSE;
696
697     fprintf (headerfile,
698              "int    "
699              "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
700              s->gen_name, s->gen_name);
701
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);
707
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");
739
740         fprintf (codefile, "\n");
741         fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */
742
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 ();
763     }
764     fprintf (codefile, "}\n\n");
765 }