Merge from vendor branch HEIMDAL:
[dragonfly.git] / crypto / heimdal-0.6.3 / lib / asn1 / gen.c
1 /*
2  * Copyright (c) 1997 - 2002 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 RCSID("$Id: gen.c,v 1.50 2003/04/17 07:09:18 lha Exp $");
37
38 FILE *headerfile, *codefile, *logfile;
39
40 #define STEM "asn1"
41
42 static const char *orig_filename;
43 static char *header;
44 static char *headerbase = STEM;
45
46 /*
47  * list of all IMPORTs
48  */
49
50 struct import {
51     const char *module;
52     struct import *next;
53 };
54
55 static struct import *imports = NULL;
56
57 void
58 add_import (const char *module)
59 {
60     struct import *tmp = emalloc (sizeof(*tmp));
61
62     tmp->module = module;
63     tmp->next   = imports;
64     imports     = tmp;
65 }
66
67 const char *
68 filename (void)
69 {
70     return orig_filename;
71 }
72
73 void
74 init_generate (const char *filename, const char *base)
75 {
76     orig_filename = filename;
77     if(base)
78         asprintf(&headerbase, "%s", base);
79     asprintf(&header, "%s.h", headerbase);
80     headerfile = fopen (header, "w");
81     if (headerfile == NULL)
82         err (1, "open %s", header);
83     fprintf (headerfile,
84              "/* Generated from %s */\n"
85              "/* Do not edit */\n\n",
86              filename);
87     fprintf (headerfile, 
88              "#ifndef __%s_h__\n"
89              "#define __%s_h__\n\n", headerbase, headerbase);
90     fprintf (headerfile, 
91              "#include <stddef.h>\n"
92              "#include <time.h>\n\n");
93 #ifndef HAVE_TIMEGM
94     fprintf (headerfile, "time_t timegm (struct tm*);\n\n");
95 #endif
96     fprintf (headerfile,
97              "#ifndef __asn1_common_definitions__\n"
98              "#define __asn1_common_definitions__\n\n");
99     fprintf (headerfile,
100              "typedef struct octet_string {\n"
101              "  size_t length;\n"
102              "  void *data;\n"
103              "} octet_string;\n\n");
104     fprintf (headerfile,
105              "typedef char *general_string;\n\n"
106              );
107     fprintf (headerfile,
108              "typedef struct oid {\n"
109              "  size_t length;\n"
110              "  unsigned *components;\n"
111              "} oid;\n\n");
112     fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \\\n"
113           "  do {                                                         \\\n"
114           "    (BL) = length_##T((S));                                    \\\n"
115           "    (B) = malloc((BL));                                        \\\n"
116           "    if((B) == NULL) {                                          \\\n"
117           "      (R) = ENOMEM;                                            \\\n"
118           "    } else {                                                   \\\n"
119           "      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
120           "                       (S), (L));                              \\\n"
121           "      if((R) != 0) {                                           \\\n"
122           "        free((B));                                             \\\n"
123           "        (B) = NULL;                                            \\\n"
124           "      }                                                        \\\n"
125           "    }                                                          \\\n"
126           "  } while (0)\n\n",
127           headerfile);
128     fprintf (headerfile, "#endif\n\n");
129     logfile = fopen(STEM "_files", "w");
130     if (logfile == NULL)
131         err (1, "open " STEM "_files");
132 }
133
134 void
135 close_generate (void)
136 {
137     fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
138
139     fclose (headerfile);
140     fprintf (logfile, "\n");
141     fclose (logfile);
142 }
143
144 void
145 generate_constant (const Symbol *s)
146 {
147   fprintf (headerfile, "enum { %s = %d };\n\n",
148            s->gen_name, s->constant);
149 }
150
151 static void
152 space(int level)
153 {
154     while(level-- > 0)
155         fprintf(headerfile, "  ");
156 }
157
158 static void
159 define_asn1 (int level, Type *t)
160 {
161     switch (t->type) {
162     case TType:
163         space(level);
164         fprintf (headerfile, "%s", t->symbol->name);
165         break;
166     case TInteger:
167         space(level);
168         fprintf (headerfile, "INTEGER");
169         break;
170     case TUInteger:
171         space(level);
172         fprintf (headerfile, "UNSIGNED INTEGER");
173         break;
174     case TOctetString:
175         space(level);
176         fprintf (headerfile, "OCTET STRING");
177         break;
178     case TOID :
179         space(level);
180         fprintf(headerfile, "OBJECT IDENTIFIER");
181         break;
182     case TBitString: {
183         Member *m;
184         int tag = -1;
185
186         space(level);
187         fprintf (headerfile, "BIT STRING {\n");
188         for (m = t->members; m && m->val != tag; m = m->next) {
189             if (tag == -1)
190                 tag = m->val;
191             space(level + 1);
192             fprintf (headerfile, "%s(%d)%s\n", m->name, m->val, 
193                      m->next->val == tag?"":",");
194
195         }
196         space(level);
197         fprintf (headerfile, "}");
198         break;
199     }
200     case TEnumerated : {
201         Member *m;
202         int tag = -1;
203
204         space(level);
205         fprintf (headerfile, "ENUMERATED {\n");
206         for (m = t->members; m && m->val != tag; m = m->next) {
207             if (tag == -1)
208                 tag = m->val;
209             space(level + 1);
210             fprintf (headerfile, "%s(%d)%s\n", m->name, m->val, 
211                      m->next->val == tag?"":",");
212
213         }
214         space(level);
215         fprintf (headerfile, "}");
216         break;
217     }
218     case TSequence: {
219         Member *m;
220         int tag;
221         int max_width = 0;
222
223         space(level);
224         fprintf (headerfile, "SEQUENCE {\n");
225         for (m = t->members, tag = -1; m && m->val != tag; m = m->next) {
226             if (tag == -1)
227                 tag = m->val;
228             if(strlen(m->name) + (m->val > 9) > max_width)
229                 max_width = strlen(m->name) + (m->val > 9);
230         }
231         max_width += 3 + 2;
232         if(max_width < 16) max_width = 16;
233         for (m = t->members, tag = -1 ; m && m->val != tag; m = m->next) {
234             int width;
235             if (tag == -1)
236                 tag = m->val;
237             space(level + 1);
238             fprintf(headerfile, "%s[%d]", m->name, m->val);
239             width = max_width - strlen(m->name) - 3 - (m->val > 9) - 2;
240             fprintf(headerfile, "%*s", width, "");
241             define_asn1(level + 1, m->type);
242             if(m->optional)
243                 fprintf(headerfile, " OPTIONAL");
244             if(m->next->val != tag)
245                 fprintf (headerfile, ",");
246             fprintf (headerfile, "\n");
247         }
248         space(level);
249         fprintf (headerfile, "}");
250         break;
251     }
252     case TSequenceOf: {
253         space(level);
254         fprintf (headerfile, "SEQUENCE OF ");
255         define_asn1 (0, t->subtype);
256         break;
257     }
258     case TGeneralizedTime:
259         space(level);
260         fprintf (headerfile, "GeneralizedTime");
261         break;
262     case TGeneralString:
263         space(level);
264         fprintf (headerfile, "GeneralString");
265         break;
266     case TApplication:
267         fprintf (headerfile, "[APPLICATION %d] ", t->application);
268         define_asn1 (level, t->subtype);
269         break;
270     default:
271         abort ();
272     }
273 }
274
275 static void
276 define_type (int level, char *name, Type *t, int typedefp)
277 {
278     switch (t->type) {
279     case TType:
280         space(level);
281         fprintf (headerfile, "%s %s;\n", t->symbol->gen_name, name);
282         break;
283     case TInteger:
284         space(level);
285         if(t->members == NULL) {
286             fprintf (headerfile, "int %s;\n", name);
287         } else {
288             Member *m;
289             int tag = -1;
290             fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
291             for (m = t->members; m && m->val != tag; m = m->next) {
292                 if(tag == -1)
293                     tag = m->val;
294                 space (level + 1);
295                 fprintf(headerfile, "%s = %d%s\n", m->gen_name, m->val, 
296                         m->next->val == tag ? "" : ",");
297             }
298             fprintf (headerfile, "} %s;\n", name);
299         }
300         break;
301     case TUInteger:
302         space(level);
303         fprintf (headerfile, "unsigned int %s;\n", name);
304         break;
305     case TOctetString:
306         space(level);
307         fprintf (headerfile, "octet_string %s;\n", name);
308         break;
309     case TOID :
310         space(level);
311         fprintf (headerfile, "oid %s;\n", name);
312         break;
313     case TBitString: {
314         Member *m;
315         Type i;
316         int tag = -1;
317
318         i.type = TUInteger;
319         space(level);
320         fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
321         for (m = t->members; m && m->val != tag; m = m->next) {
322             char *n;
323
324             asprintf (&n, "%s:1", m->gen_name);
325             define_type (level + 1, n, &i, FALSE);
326             free (n);
327             if (tag == -1)
328                 tag = m->val;
329         }
330         space(level);
331         fprintf (headerfile, "} %s;\n\n", name);
332         break;
333     }
334     case TEnumerated: {
335         Member *m;
336         int tag = -1;
337
338         space(level);
339         fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
340         for (m = t->members; m && m->val != tag; m = m->next) {
341             if (tag == -1)
342                 tag = m->val;
343             space(level + 1);
344             fprintf (headerfile, "%s = %d%s\n", m->gen_name, m->val,
345                         m->next->val == tag ? "" : ",");
346         }
347         space(level);
348         fprintf (headerfile, "} %s;\n\n", name);
349         break;
350     }
351     case TSequence: {
352         Member *m;
353         int tag = -1;
354
355         space(level);
356         fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
357         for (m = t->members; m && m->val != tag; m = m->next) {
358             if (m->optional) {
359                 char *n;
360
361                 asprintf (&n, "*%s", m->gen_name);
362                 define_type (level + 1, n, m->type, FALSE);
363                 free (n);
364             } else
365                 define_type (level + 1, m->gen_name, m->type, FALSE);
366             if (tag == -1)
367                 tag = m->val;
368         }
369         space(level);
370         fprintf (headerfile, "} %s;\n", name);
371         break;
372     }
373     case TSequenceOf: {
374         Type i;
375
376         i.type = TUInteger;
377         i.application = 0;
378
379         space(level);
380         fprintf (headerfile, "struct %s {\n", typedefp ? name : "");
381         define_type (level + 1, "len", &i, FALSE);
382         define_type (level + 1, "*val", t->subtype, FALSE);
383         space(level);
384         fprintf (headerfile, "} %s;\n", name);
385         break;
386     }
387     case TGeneralizedTime:
388         space(level);
389         fprintf (headerfile, "time_t %s;\n", name);
390         break;
391     case TGeneralString:
392         space(level);
393         fprintf (headerfile, "general_string %s;\n", name);
394         break;
395     case TApplication:
396         define_type (level, name, t->subtype, FALSE);
397         break;
398     default:
399         abort ();
400     }
401 }
402
403 static void
404 generate_type_header (const Symbol *s)
405 {
406     fprintf (headerfile, "/*\n");
407     fprintf (headerfile, "%s ::= ", s->name);
408     define_asn1 (0, s->type);
409     fprintf (headerfile, "\n*/\n\n");
410
411     fprintf (headerfile, "typedef ");
412     define_type (0, s->gen_name, s->type, TRUE);
413
414     fprintf (headerfile, "\n");
415 }
416
417
418 void
419 generate_type (const Symbol *s)
420 {
421     struct import *i;
422     char *filename;
423
424     asprintf (&filename, "%s_%s.x", STEM, s->gen_name);
425     codefile = fopen (filename, "w");
426     if (codefile == NULL)
427         err (1, "fopen %s", filename);
428     fprintf(logfile, "%s ", filename);
429     free(filename);
430     fprintf (codefile, 
431              "/* Generated from %s */\n"
432              "/* Do not edit */\n\n"
433              "#include <stdio.h>\n"
434              "#include <stdlib.h>\n"
435              "#include <time.h>\n"
436              "#include <string.h>\n"
437              "#include <errno.h>\n",
438              orig_filename);
439
440     for (i = imports; i != NULL; i = i->next)
441         fprintf (codefile,
442                  "#include <%s_asn1.h>\n",
443                  i->module);
444     fprintf (codefile,
445              "#include <%s.h>\n",
446              headerbase);
447     fprintf (codefile,
448              "#include <asn1_err.h>\n"
449              "#include <der.h>\n"
450              "#include <parse_units.h>\n\n");
451     generate_type_header (s);
452     generate_type_encode (s);
453     generate_type_decode (s);
454     generate_type_free (s);
455     generate_type_length (s);
456     generate_type_copy (s);
457     generate_glue (s);
458     fprintf(headerfile, "\n\n");
459     fclose(codefile);
460 }