s4:torture: Adapt KDC canon test to Heimdal upstream changes
[samba.git] / third_party / heimdal / lib / asn1 / gen_encode.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
36 /* XXX same as der_length_tag */
37 static size_t
38 length_tag(unsigned int tag)
39 {
40     size_t len = 0;
41
42     if(tag <= 30)
43         return 1;
44     while(tag) {
45         tag /= 128;
46         len++;
47     }
48     return len + 1;
49 }
50
51 static void
52 encode_primitive (const char *typename, const char *name)
53 {
54     fprintf (codefile,
55              "e = der_put_%s(p, len, %s, &l);\n"
56              "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
57              typename,
58              name);
59 }
60
61 const char *
62 classname(Der_class class)
63 {
64     const char *cn[] = { "ASN1_C_UNIV", "ASN1_C_APPL",
65                          "ASN1_C_CONTEXT", "ASN1_C_PRIV" };
66     if ((int)class >= sizeof(cn) / sizeof(cn[0]))
67         return "???";
68     return cn[class];
69 }
70
71
72 const char *
73 valuename(Der_class class, int value)
74 {
75     static char s[32];
76     struct {
77         int value;
78         const char *s;
79     } *p, values[] = {
80 #define X(Y) { Y, #Y }
81         X(UT_BMPString),
82         X(UT_BitString),
83         X(UT_Boolean),
84         X(UT_EmbeddedPDV),
85         X(UT_Enumerated),
86         X(UT_External),
87         X(UT_GeneralString),
88         X(UT_GeneralizedTime),
89         X(UT_GraphicString),
90         X(UT_IA5String),
91         X(UT_Integer),
92         X(UT_Null),
93         X(UT_NumericString),
94         X(UT_OID),
95         X(UT_ObjectDescriptor),
96         X(UT_OctetString),
97         X(UT_PrintableString),
98         X(UT_Real),
99         X(UT_RelativeOID),
100         X(UT_Sequence),
101         X(UT_Set),
102         X(UT_TeletexString),
103         X(UT_UTCTime),
104         X(UT_UTF8String),
105         X(UT_UniversalString),
106         X(UT_VideotexString),
107         X(UT_VisibleString),
108 #undef X
109         { -1, NULL }
110     };
111     if(class == ASN1_C_UNIV) {
112         for(p = values; p->value != -1; p++)
113             if(p->value == value)
114                 return p->s;
115     }
116     snprintf(s, sizeof(s), "%d", value);
117     return s;
118 }
119
120 static int
121 encode_type (const char *name, const Type *t, const char *tmpstr)
122 {
123     int constructed = 1;
124
125     switch (t->type) {
126     case TType:
127 #if 0
128         encode_type (name, t->symbol->type);
129 #endif
130         fprintf (codefile,
131                  "e = encode_%s(p, len, %s, &l);\n"
132                  "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
133                  t->symbol->gen_name, name);
134         constructed = !is_primitive_type(t);
135         break;
136     case TInteger:
137         if(t->members) {
138             fprintf(codefile,
139                     "{\n"
140                     "int enumint = (int)*%s;\n",
141                     name);
142             encode_primitive("integer", "&enumint");
143             fprintf(codefile, "}\n;");
144         } else if (t->range == NULL) {
145             encode_primitive("heim_integer", name);
146         } else if (t->range->min < 0 &&
147                    (t->range->min < INT_MIN || t->range->max > INT_MAX)) {
148             encode_primitive("integer64", name);
149         } else if (t->range->min < 0) {
150             encode_primitive("integer", name);
151         } else if (t->range->max > UINT_MAX) {
152             encode_primitive("unsigned64", name);
153         } else {
154             encode_primitive("unsigned", name);
155         }
156
157         constructed = 0;
158         break;
159     case TBoolean:
160         encode_primitive ("boolean", name);
161         constructed = 0;
162         break;
163     case TOctetString:
164         encode_primitive ("octet_string", name);
165         constructed = 0;
166         break;
167     case TBitString: {
168         Member *m;
169         int pos;
170
171         if (HEIM_TAILQ_EMPTY(t->members)) {
172             encode_primitive("bit_string", name);
173             constructed = 0;
174             break;
175         }
176
177         fprintf (codefile, "{\n"
178                  "unsigned char c = 0;\n");
179         if (!rfc1510_bitstring)
180             fprintf (codefile,
181                      "int rest = 0;\n"
182                      "int bit_set = 0;\n");
183 #if 0
184         pos = t->members->prev->val;
185         /* fix for buggy MIT (and OSF?) code */
186         if (pos > 31)
187             abort ();
188 #endif
189         /*
190          * It seems that if we do not always set pos to 31 here, the MIT
191          * code will do the wrong thing.
192          *
193          * I hate ASN.1 (and DER), but I hate it even more when everybody
194          * has to screw it up differently.
195          */
196         pos = HEIM_TAILQ_LAST(t->members, memhead)->val;
197         if (rfc1510_bitstring) {
198             if (pos < 31)
199                 pos = 31;
200         }
201
202         HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
203             while (m->val / 8 < pos / 8) {
204                 if (!rfc1510_bitstring)
205                     fprintf (codefile,
206                              "if (c != 0 || bit_set) {\n");
207                 fprintf (codefile,
208                          "if (len < 1) return ASN1_OVERFLOW;\n"
209                          "*p-- = c; len--; ret++;\n");
210                 if (!rfc1510_bitstring)
211                     fprintf (codefile,
212                              "if (!bit_set) {\n"
213                              "rest = 0;\n"
214                              "while(c) { \n"
215                              "if (c & 1) break;\n"
216                              "c = c >> 1;\n"
217                              "rest++;\n"
218                              "}\n"
219                              "bit_set = 1;\n"
220                              "}\n"
221                              "}\n");
222                 fprintf (codefile,
223                          "c = 0;\n");
224                 pos -= 8;
225             }
226             fprintf (codefile,
227                      "if((%s)->%s) {\n"
228                      "c |= 1<<%d;\n",
229                      name, m->gen_name, 7 - m->val % 8);
230             fprintf (codefile,
231                      "}\n");
232         }
233
234         if (!rfc1510_bitstring)
235             fprintf (codefile,
236                      "if (c != 0 || bit_set) {\n");
237         fprintf (codefile,
238                  "if (len < 1) return ASN1_OVERFLOW;\n"
239                  "*p-- = c; len--; ret++;\n");
240         if (!rfc1510_bitstring)
241             fprintf (codefile,
242                      "if (!bit_set) {\n"
243                      "rest = 0;\n"
244                      "if(c) { \n"
245                      "while(c) { \n"
246                      "if (c & 1) break;\n"
247                      "c = c >> 1;\n"
248                      "rest++;\n"
249                      "}\n"
250                      "}\n"
251                      "}\n"
252                      "}\n");
253
254         fprintf (codefile,
255                  "if (len < 1) return ASN1_OVERFLOW;\n"
256                  "*p-- = %s;\n"
257                  "len -= 1;\n"
258                  "ret += 1;\n"
259                  "}\n\n",
260                  rfc1510_bitstring ? "0" : "rest");
261         constructed = 0;
262         break;
263     }
264     case TEnumerated : {
265         encode_primitive ("enumerated", name);
266         constructed = 0;
267         break;
268     }
269
270     case TSet:
271     case TSequence: {
272         Member *m;
273
274         if (t->members == NULL)
275             break;
276
277         HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
278             char *s = NULL;
279
280             if (m->ellipsis)
281                 continue;
282
283             if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL)
284                 errx(1, "malloc");
285             fprintf(codefile, "/* %s */\n", m->name);
286             if (m->optional)
287                 fprintf (codefile,
288                          "if(%s) ",
289                          s);
290             else if(m->defval)
291                 gen_compare_defval(s + 1, m->defval);
292             fprintf (codefile, "{\n");
293             fprintf (codefile, "size_t %s_oldret HEIMDAL_UNUSED_ATTRIBUTE = ret;\n", tmpstr);
294             fprintf (codefile, "ret = 0;\n");
295             encode_type (s, m->type, m->gen_name);
296             fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
297             fprintf (codefile, "}\n");
298             free (s);
299         }
300         break;
301     }
302     case TSetOf: {
303
304         fprintf(codefile,
305                 "{\n"
306                 "heim_octet_string *val;\n"
307                 "size_t elen = 0, totallen = 0;\n"
308                 "int eret = 0;\n");
309
310         fprintf(codefile,
311                 "if ((%s)->len > UINT_MAX/sizeof(val[0]))\n"
312                 "return ERANGE;\n",
313                 name);
314
315         fprintf(codefile,
316                 "val = malloc(sizeof(val[0]) * (%s)->len);\n"
317                 "if (val == NULL && (%s)->len != 0) return ENOMEM;\n",
318                 name, name);
319
320         fprintf(codefile,
321                 "for(i = 0; i < (int)(%s)->len; i++) {\n",
322                 name);
323
324         fprintf(codefile,
325                 "ASN1_MALLOC_ENCODE(%s, val[i].data, "
326                 "val[i].length, &(%s)->val[i], &elen, eret);\n",
327                 t->subtype->symbol->gen_name,
328                 name);
329
330         fprintf(codefile,
331                 "if(eret) {\n"
332                 "i--;\n"
333                 "while (i >= 0) {\n"
334                 "free(val[i].data);\n"
335                 "i--;\n"
336                 "}\n"
337                 "free(val);\n"
338                 "return eret;\n"
339                 "}\n"
340                 "totallen += elen;\n"
341                 "}\n");
342
343         fprintf(codefile,
344                 "if (totallen > len) {\n"
345                 "for (i = 0; i < (int)(%s)->len; i++) {\n"
346                 "free(val[i].data);\n"
347                 "}\n"
348                 "free(val);\n"
349                 "return ASN1_OVERFLOW;\n"
350                 "}\n",
351                 name);
352
353         fprintf(codefile,
354                 "qsort(val, (%s)->len, sizeof(val[0]), _heim_der_set_sort);\n",
355                 name);
356
357         fprintf (codefile,
358                  "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
359                  "p -= val[i].length;\n"
360                  "ret += val[i].length;\n"
361                  "memcpy(p + 1, val[i].data, val[i].length);\n"
362                  "free(val[i].data);\n"
363                  "}\n"
364                  "free(val);\n"
365                  "}\n",
366                  name);
367         break;
368     }
369     case TSequenceOf: {
370         char *sname = NULL;
371         char *n = NULL;
372
373         fprintf (codefile,
374                  "for(i = (int)(%s)->len - 1; i >= 0; --i) {\n"
375                  "size_t %s_for_oldret = ret;\n"
376                  "ret = 0;\n",
377                  name, tmpstr);
378         if (asprintf (&n, "&(%s)->val[i]", name) < 0 || n == NULL)
379             errx(1, "malloc");
380         if (asprintf (&sname, "%s_S_Of", tmpstr) < 0 || sname == NULL)
381             errx(1, "malloc");
382         encode_type (n, t->subtype, sname);
383         fprintf (codefile,
384                  "ret += %s_for_oldret;\n"
385                  "}\n",
386                  tmpstr);
387         free (n);
388         free (sname);
389         break;
390     }
391     case TGeneralizedTime:
392         encode_primitive ("generalized_time", name);
393         constructed = 0;
394         break;
395     case TGeneralString:
396         encode_primitive ("general_string", name);
397         constructed = 0;
398         break;
399     case TTeletexString:
400         encode_primitive ("general_string", name);
401         constructed = 0;
402         break;
403     case TTag: {
404         char *tname = NULL;
405         int replace_tag = 0;
406         int prim = !(t->tag.tagclass != ASN1_C_UNIV &&
407                      t->tag.tagenv == TE_EXPLICIT) &&
408             is_primitive_type(t->subtype);
409         int c;
410         if (asprintf (&tname, "%s_tag", tmpstr) < 0 || tname == NULL)
411             errx(1, "malloc");
412         /*
413          * HACK HACK HACK
414          *
415          * This is part of the fix to the bug where we treated IMPLICIT tags of
416          * named types as EXPLICIT.  I.e.
417          *
418          *  Foo ::= SEQUENCE { ... }
419          *  Bar ::= SEQUENCE { foo [0] IMPLICIT Foo }
420          *
421          * would get a context [0] constructed tag *and* a universal sequence
422          * constructed tag when it should get only the first tag.
423          *
424          * Properly fixing this would require changing the signatures of the
425          * encode, length, and decode functions we generate to take an optional
426          * tag to replace the one the encoder would generate / decoder would
427          * expect.  That would change the ABI, which... isn't stable, but it's
428          * a bit soon to make that change.
429          *
430          * So, we're looking for IMPLICIT, and if we see any, we generate code
431          * to replace the tag.
432          *
433          * On the decode side we need to know what tag to restore.  For this we
434          * generate enums in the generated header.
435          *
436          * NOTE: We *do* "replace" the tags of IMPLICIT-tagged primitive types,
437          *       but our primitive codec functions leave those tags out, which
438          *       is why we don't have to der_replace_tag() them here.
439          */
440         /*
441          * If the tag is IMPLICIT and it's not primitive and the subtype is not
442          * any kind of structure...
443          */
444         if (t->tag.tagenv == TE_IMPLICIT && !prim &&
445             t->subtype->type != TSequenceOf && t->subtype->type != TSetOf &&
446             t->subtype->type != TChoice) {
447             /* If it is a named type for a structured thing */
448             if (t->subtype->symbol &&
449                 (t->subtype->type == TSequence ||
450                  t->subtype->type == TSet))
451                 replace_tag = 1;
452             else if (t->subtype->symbol && strcmp(t->subtype->symbol->name, "heim_any"))
453                 replace_tag = 1;
454         } else if (t->tag.tagenv == TE_IMPLICIT && prim && t->subtype->symbol)
455             /*
456              * Because the subtype is named we are generating its codec
457              * functions, and those will be adding their UNIVERSAL or whatever
458              * tags unlike our raw primtive codec library.
459              */
460             replace_tag = is_tagged_type(t->subtype->symbol->type);
461
462         if (replace_tag)
463             fprintf(codefile,
464                     "{ unsigned char *psave_%s = p;\n"
465                     "size_t l2_%s, lensave_%s = len;\n"
466                     "len = length_%s(%s);\n"
467                     /* Allocate a temp buffer for the encoder */
468                     "if ((p = malloc(len)) == NULL) return ENOMEM;\n"
469                     /* Make p point to the last byte of the allocated buf */
470                     "p += len - 1;\n",
471                     tmpstr, tmpstr, tmpstr,
472                     t->subtype->symbol->gen_name, name);
473
474         c = encode_type (name, t->subtype, tname);
475         /* Explicit non-UNIVERSAL tags are always constructed */
476         if (!c && t->tag.tagclass != ASN1_C_UNIV && t->tag.tagenv == TE_EXPLICIT)
477             c = 1;
478         if (replace_tag)
479             fprintf(codefile,
480                     "if (len) abort();\n"
481                     /*
482                      * Here we have `p' pointing to one byte before the buffer
483                      * we allocated above.
484                      *
485                      *     [ T_wrong | LL | VVVV ] // temp buffer
486                      *   ^   ^
487                      *   |   |
488                      *   |   \
489                      *   \    +-- p + 1
490                      *    +-- p
491                      *
492                      * psave_<fieldName> still points to the last byte in the
493                      * original buffer passed in where we should write the
494                      * encoding of <fieldName>.
495                      *
496                      * We adjust psave_<fieldName> to point to before the TLV
497                      * encoding of <fieldName> (with wrong tag) in the original
498                      * buffer (this may NOT be a valid pointer, but we won't
499                      * dereference it):
500                      *
501                      * [ ... | T_wrong | LL | VVVVV | ... ] // original buffer
502                      *      ^
503                      *      |
504                      *      \
505                      *       +-- psave_<fieldName>
506                      */
507                     "psave_%s -= l;\n"
508                     /*
509                      * We further adjust psave_<fieldName> to point to the last
510                      * byte of what should be the T(ag) of the TLV encoding of
511                      * <fieldName> (this is now a valid pointer), then...
512                      *
513                      *         |<--->| (not written yet)
514                      *         |     | |<-------->| (not written yet)
515                      * [ ... | T_right | LL | VVVVV | ... ] // original buffer
516                      *                ^
517                      *                |
518                      *                \
519                      *                 +-- psave_<fieldName>
520                      */
521                     "psave_%s += asn1_tag_length_%s;\n"
522                     /*
523                      * ...copy the L(ength)V(alue) of the TLV encoding of
524                      * <fieldName>.
525                      *
526                      * [ ... | T_right | LL | VVVVV | ... ] // original buffer
527                      *                   ^
528                      *                   |
529                      *                   \
530                      *                    +-- psave_<fieldName> + 1
531                      *
532                      *             |<----->| length is
533                      *             |       | `l' - asn1_tag_length_<fieldName>
534                      * [ T_wrong | LL | VVVV ] // temp buffer
535                      *   ^         ^
536                      *   |         |
537                      *   |         \
538                      *   \          +-- p + 1 + asn1_tag_length_%s
539                      *    +-- p + 1
540                      */
541                     "memcpy(psave_%s + 1, p + 1 + asn1_tag_length_%s, l - asn1_tag_length_%s);\n"
542                     /*
543                      * Encode the IMPLICIT tag.  Recall that encoders like
544                      * der_put_tag() take a pointer to the last byte they
545                      * should write to, and a length of bytes to the left of
546                      * that that they are allowed to write into.
547                      *
548                      * [ ... | T_right | LL | VVVVV | ... ] // original buffer
549                      *                ^
550                      *                |
551                      *                \
552                      *                 +-- psave_<fieldName>
553                      */
554                     "e = der_put_tag(psave_%s, %lu, %s, %s, %d, &l2_%s);\n"
555                     "if (e) return e;\n"
556                     /* Restore `len' and adjust it (see `p' below) */
557                     "len = lensave_%s - (l + %lu - asn1_tag_length_%s);\n"
558                     /*
559                      * Adjust `ret' to account for the difference in size
560                      * between the length of the right and wrong tags.
561                      */
562                     "ret += %lu - asn1_tag_length_%s;\n"
563                     /* Free the buffer and restore `p' */
564                     "free(p + 1);\n"
565                     /*
566                      * Make `p' point into the original buffer again, to one
567                      * byte before the bytes we wrote:
568                      *
569                      * [ ... | T_right | LL | VVVVV | ... ] // original buffer
570                      *      ^
571                      *      |
572                      *      \
573                      *       +-- p
574                      */
575                     "p = psave_%s - (1 + %lu - asn1_tag_length_%s); }\n",
576                     tmpstr, tmpstr, t->subtype->symbol->name,
577                     tmpstr, t->subtype->symbol->name, t->subtype->symbol->name,
578                     tmpstr, length_tag(t->tag.tagvalue),
579                     classname(t->tag.tagclass),
580                     c ? "CONS" : "PRIM",
581                     t->tag.tagvalue,
582                     tmpstr,
583
584                     tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name,
585                     length_tag(t->tag.tagvalue), t->subtype->symbol->name,
586                     tmpstr, length_tag(t->tag.tagvalue), t->subtype->symbol->name);
587         else
588             fprintf(codefile,
589                     "e = der_put_length_and_tag (p, len, ret, %s, %s, %s, &l);\n"
590                     "if (e) return e;\np -= l; len -= l; ret += l;\n\n",
591                     classname(t->tag.tagclass),
592                     c ? "CONS" : "PRIM",
593                     valuename(t->tag.tagclass, t->tag.tagvalue));
594         free(tname);
595         constructed = c;
596         break;
597     }
598     case TChoice:{
599         Member *m, *have_ellipsis = NULL;
600         char *s = NULL;
601
602         if (t->members == NULL)
603             break;
604
605         fprintf(codefile, "\n");
606
607         if (asprintf (&s, "(%s)", name) < 0 || s == NULL)
608             errx(1, "malloc");
609         fprintf(codefile, "switch(%s->element) {\n", s);
610
611         HEIM_TAILQ_FOREACH_REVERSE(m, t->members, memhead, members) {
612             char *s2 = NULL;
613
614             if (m->ellipsis) {
615                 have_ellipsis = m;
616                 continue;
617             }
618
619             fprintf (codefile, "case %s: {", m->label);
620             if (asprintf(&s2, "%s(%s)->u.%s", m->optional ? "" : "&",
621                          s, m->gen_name) < 0 || s2 == NULL)
622                 errx(1, "malloc");
623             if (m->optional)
624                 fprintf (codefile, "if(%s) {\n", s2);
625             fprintf (codefile, "size_t %s_oldret = ret;\n", tmpstr);
626             fprintf (codefile, "ret = 0;\n");
627             constructed = encode_type (s2, m->type, m->gen_name);
628             fprintf (codefile, "ret += %s_oldret;\n", tmpstr);
629             if(m->optional)
630                 fprintf (codefile, "}\n");
631             fprintf(codefile, "break;\n");
632             fprintf(codefile, "}\n");
633             free (s2);
634         }
635         free (s);
636         if (have_ellipsis) {
637             fprintf(codefile,
638                     "case %s: {\n"
639                     "if (len < (%s)->u.%s.length)\n"
640                     "return ASN1_OVERFLOW;\n"
641                     "p -= (%s)->u.%s.length;\n"
642                     "ret += (%s)->u.%s.length;\n"
643                     "memcpy(p + 1, (%s)->u.%s.data, (%s)->u.%s.length);\n"
644                     "break;\n"
645                     "}\n",
646                     have_ellipsis->label,
647                     name, have_ellipsis->gen_name,
648                     name, have_ellipsis->gen_name,
649                     name, have_ellipsis->gen_name,
650                     name, have_ellipsis->gen_name,
651                     name, have_ellipsis->gen_name);
652         }
653         fprintf(codefile, "};\n");
654         break;
655     }
656     case TOID:
657         encode_primitive ("oid", name);
658         constructed = 0;
659         break;
660     case TUTCTime:
661         encode_primitive ("utctime", name);
662         constructed = 0;
663         break;
664     case TUTF8String:
665         encode_primitive ("utf8string", name);
666         constructed = 0;
667         break;
668     case TPrintableString:
669         encode_primitive ("printable_string", name);
670         constructed = 0;
671         break;
672     case TIA5String:
673         encode_primitive ("ia5_string", name);
674         constructed = 0;
675         break;
676     case TBMPString:
677         encode_primitive ("bmp_string", name);
678         constructed = 0;
679         break;
680     case TUniversalString:
681         encode_primitive ("universal_string", name);
682         constructed = 0;
683         break;
684     case TVisibleString:
685         encode_primitive ("visible_string", name);
686         constructed = 0;
687         break;
688     case TNull:
689         fprintf (codefile, "/* NULL */\n");
690         constructed = 0;
691         break;
692     default:
693         abort ();
694     }
695     return constructed;
696 }
697
698 void
699 generate_type_encode (const Symbol *s)
700 {
701     fprintf (codefile, "int ASN1CALL\n"
702              "encode_%s(unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE, size_t len HEIMDAL_UNUSED_ATTRIBUTE,"
703              " const %s *data, size_t *size)\n"
704              "{\n",
705              s->gen_name, s->gen_name);
706
707     switch (s->type->type) {
708     case TInteger:
709     case TBoolean:
710     case TOctetString:
711     case TGeneralizedTime:
712     case TGeneralString:
713     case TTeletexString:
714     case TUTCTime:
715     case TUTF8String:
716     case TPrintableString:
717     case TIA5String:
718     case TBMPString:
719     case TUniversalString:
720     case TVisibleString:
721     case TNull:
722     case TBitString:
723     case TEnumerated:
724     case TOID:
725     case TSequence:
726     case TSequenceOf:
727     case TSet:
728     case TSetOf:
729     case TTag:
730     case TType:
731     case TChoice:
732         fprintf (codefile,
733                  "size_t ret HEIMDAL_UNUSED_ATTRIBUTE = 0;\n"
734                  "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n"
735                  "int i HEIMDAL_UNUSED_ATTRIBUTE, e HEIMDAL_UNUSED_ATTRIBUTE;\n\n");
736
737         encode_type("data", s->type, "Top");
738
739         fprintf (codefile, "*size = ret;\n"
740                  "return 0;\n");
741         break;
742     default:
743         abort ();
744     }
745     fprintf (codefile, "}\n\n");
746 }