Revert "asn1: use roken for generated source files"
[heimdal.git] / lib / asn1 / gen.c
blob39ea9d03749340add20ac6cad93b7d76320e41b5
1 /*
2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
36 #include "gen_locl.h"
38 extern const char *enum_prefix;
39 extern int prefix_enum;
41 RCSID("$Id$");
43 FILE *privheaderfile, *headerfile, *oidsfile, *codefile, *logfile, *templatefile;
44 FILE *symsfile;
46 #define STEM "asn1"
48 static const char *orig_filename;
49 static char *privheader, *header, *template;
50 static const char *headerbase = STEM;
52 /* XXX same as der_length_tag */
53 static size_t
54 length_tag(unsigned int tag)
56 size_t len = 0;
58 if(tag <= 30)
59 return 1;
60 while(tag) {
61 tag /= 128;
62 len++;
64 return len + 1;
68 * list of all IMPORTs
71 struct import {
72 const char *module;
73 struct import *next;
76 static struct import *imports = NULL;
78 void
79 add_import (const char *module)
81 struct import *tmp = emalloc (sizeof(*tmp));
83 tmp->module = module;
84 tmp->next = imports;
85 imports = tmp;
87 fprintf (headerfile, "#include <%s_asn1.h>\n", module);
91 * List of all exported symbols
94 struct sexport {
95 const char *name;
96 int defined;
97 struct sexport *next;
100 static struct sexport *exports = NULL;
102 void
103 add_export (const char *name)
105 struct sexport *tmp = emalloc (sizeof(*tmp));
107 tmp->name = name;
108 tmp->next = exports;
109 exports = tmp;
113 is_export(const char *name)
115 struct sexport *tmp;
117 if (exports == NULL) /* no export list, all exported */
118 return 1;
120 for (tmp = exports; tmp != NULL; tmp = tmp->next) {
121 if (strcmp(tmp->name, name) == 0) {
122 tmp->defined = 1;
123 return 1;
126 return 0;
129 const char *
130 get_filename (void)
132 return orig_filename;
135 void
136 init_generate (const char *filename, const char *base)
138 char *fn = NULL;
140 orig_filename = filename;
141 if (base != NULL) {
142 headerbase = strdup(base);
143 if (headerbase == NULL)
144 errx(1, "strdup");
147 /* public header file */
148 if (asprintf(&header, "%s.h", headerbase) < 0 || header == NULL)
149 errx(1, "malloc");
150 if (asprintf(&fn, "%s.hx", headerbase) < 0 || fn == NULL)
151 errx(1, "malloc");
152 headerfile = fopen (fn, "w");
153 if (headerfile == NULL)
154 err (1, "open %s", fn);
155 free(fn);
156 fn = NULL;
158 /* private header file */
159 if (asprintf(&privheader, "%s-priv.h", headerbase) < 0 || privheader == NULL)
160 errx(1, "malloc");
161 if (asprintf(&fn, "%s-priv.hx", headerbase) < 0 || fn == NULL)
162 errx(1, "malloc");
163 privheaderfile = fopen (fn, "w");
164 if (privheaderfile == NULL)
165 err (1, "open %s", fn);
166 free(fn);
167 fn = NULL;
169 /* template file */
170 if (asprintf(&template, "%s-template.x", headerbase) < 0 || template == NULL)
171 errx(1, "malloc");
172 fprintf (headerfile,
173 "/* Generated from %s */\n"
174 "/* Do not edit */\n\n",
175 filename);
176 fprintf (headerfile,
177 "#ifndef __%s_h__\n"
178 "#define __%s_h__\n\n", headerbase, headerbase);
179 fprintf (headerfile,
180 "#include <stddef.h>\n"
181 "#include <stdint.h>\n"
182 "#include <time.h>\n\n");
183 fprintf (headerfile,
184 "#ifndef __asn1_common_definitions__\n"
185 "#define __asn1_common_definitions__\n\n");
186 fprintf (headerfile,
187 "#ifndef __HEIM_BASE_DATA__\n"
188 "#define __HEIM_BASE_DATA__ 1\n"
189 "struct heim_base_data {\n"
190 " size_t length;\n"
191 " void *data;\n"
192 "};\n"
193 "typedef struct heim_base_data heim_octet_string;\n"
194 "#endif\n\n");
195 fprintf (headerfile,
196 "typedef struct heim_integer {\n"
197 " size_t length;\n"
198 " void *data;\n"
199 " int negative;\n"
200 "} heim_integer;\n\n");
201 fprintf (headerfile,
202 "typedef char *heim_general_string;\n\n"
204 fprintf (headerfile,
205 "typedef char *heim_utf8_string;\n\n"
207 fprintf (headerfile,
208 "typedef struct heim_base_data heim_printable_string;\n\n"
210 fprintf (headerfile,
211 "typedef struct heim_base_data heim_ia5_string;\n\n"
213 fprintf (headerfile,
214 "typedef struct heim_bmp_string {\n"
215 " size_t length;\n"
216 " uint16_t *data;\n"
217 "} heim_bmp_string;\n\n");
218 fprintf (headerfile,
219 "typedef struct heim_universal_string {\n"
220 " size_t length;\n"
221 " uint32_t *data;\n"
222 "} heim_universal_string;\n\n");
223 fprintf (headerfile,
224 "typedef char *heim_visible_string;\n\n"
226 fprintf (headerfile,
227 "typedef struct heim_oid {\n"
228 " size_t length;\n"
229 " unsigned *components;\n"
230 "} heim_oid;\n\n");
231 fprintf (headerfile,
232 "typedef struct heim_bit_string {\n"
233 " size_t length;\n"
234 " void *data;\n"
235 "} heim_bit_string;\n\n");
236 fprintf (headerfile,
237 "typedef struct heim_base_data heim_any;\n"
238 "typedef struct heim_base_data heim_any_set;\n"
239 "typedef struct heim_base_data HEIM_ANY;\n"
240 "typedef struct heim_base_data HEIM_ANY_SET;\n\n");
242 fprintf (headerfile,
243 "enum asn1_print_flags {\n"
244 " ASN1_PRINT_INDENT = 1,\n"
245 "};\n\n");
246 fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n"
247 " do { \\\n"
248 " (BL) = length_##T((S)); \\\n"
249 " (B) = malloc((BL)); \\\n"
250 " if((B) == NULL) { \\\n"
251 " *(L) = 0; \\\n"
252 " (R) = ENOMEM; \\\n"
253 " } else { \\\n"
254 " (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
255 " (S), (L)); \\\n"
256 " if((R) != 0) { \\\n"
257 " free((B)); \\\n"
258 " (B) = NULL; \\\n"
259 " *(L) = 0; \\\n"
260 " } \\\n"
261 " } \\\n"
262 " } while (0)\n\n",
263 headerfile);
264 fputs("#ifdef _WIN32\n"
265 "#ifndef ASN1_LIB\n"
266 "#define ASN1EXP __declspec(dllimport)\n"
267 "#else\n"
268 "#define ASN1EXP\n"
269 "#endif\n"
270 "#define ASN1CALL __stdcall\n"
271 "#else\n"
272 "#define ASN1EXP\n"
273 "#define ASN1CALL\n"
274 "#endif\n",
275 headerfile);
276 fprintf (headerfile, "struct units;\n\n");
277 fprintf (headerfile, "#endif\n\n");
278 if (asprintf(&fn, "%s_files", base) < 0 || fn == NULL)
279 errx(1, "malloc");
280 logfile = fopen(fn, "w");
281 if (logfile == NULL)
282 err (1, "open %s", fn);
283 free(fn);
284 fn = NULL;
286 if (asprintf(&fn, "%s_oids.x", base) < 0 || fn == NULL)
287 errx(1, "malloc");
288 oidsfile = fopen(fn, "w");
289 if (oidsfile == NULL)
290 err (1, "open %s", fn);
291 if (asprintf(&fn, "%s_syms.x", base) < 0 || fn == NULL)
292 errx(1, "malloc");
293 symsfile = fopen(fn, "w");
294 if (symsfile == NULL)
295 err (1, "open %s", fn);
296 free(fn);
297 fn = NULL;
299 /* if one code file, write into the one codefile */
300 if (one_code_file)
301 return;
303 templatefile = fopen (template, "w");
304 if (templatefile == NULL)
305 err (1, "open %s", template);
307 fprintf (templatefile,
308 "/* Generated from %s */\n"
309 "/* Do not edit */\n\n"
310 "#include <stdio.h>\n"
311 "#include <stdlib.h>\n"
312 "#include <time.h>\n"
313 "#include <string.h>\n"
314 "#include <errno.h>\n"
315 "#include <limits.h>\n"
316 "#include <asn1_err.h>\n"
317 "#include <%s>\n",
318 filename,
319 type_file_string);
321 fprintf (templatefile,
322 "#include <%s>\n"
323 "#include <%s>\n"
324 "#include <der.h>\n"
325 "#include <asn1-template.h>\n",
326 header, privheader);
331 void
332 close_generate (void)
334 fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
336 if (headerfile && fclose(headerfile) == EOF)
337 err(1, "writes to public header file failed");
338 if (privheaderfile && fclose(privheaderfile) == EOF)
339 err(1, "writes to private header file failed");
340 if (templatefile && fclose(templatefile) == EOF)
341 err(1, "writes to template file failed");
342 if (logfile) {
343 fprintf(logfile, "\n");
344 if (fclose(logfile) == EOF)
345 err(1, "writes to log file failed");
349 void
350 gen_assign_defval(const char *var, struct value *val)
352 switch(val->type) {
353 case stringvalue:
354 fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue);
355 break;
356 case integervalue:
357 fprintf(codefile, "%s = %lld;\n",
358 var, (long long)val->u.integervalue);
359 break;
360 case booleanvalue:
361 if(val->u.booleanvalue)
362 fprintf(codefile, "%s = 1;\n", var);
363 else
364 fprintf(codefile, "%s = 0;\n", var);
365 break;
366 default:
367 abort();
371 void
372 gen_compare_defval(const char *var, struct value *val)
374 switch(val->type) {
375 case stringvalue:
376 fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue);
377 break;
378 case integervalue:
379 fprintf(codefile, "if(%s != %lld)\n",
380 var, (long long)val->u.integervalue);
381 break;
382 case booleanvalue:
383 if(val->u.booleanvalue)
384 fprintf(codefile, "if(!%s)\n", var);
385 else
386 fprintf(codefile, "if(%s)\n", var);
387 break;
388 default:
389 abort();
393 void
394 generate_header_of_codefile(const char *name)
396 char *filename = NULL;
398 if (codefile != NULL)
399 abort();
401 if (asprintf (&filename, "%s_%s.x", STEM, name) < 0 || filename == NULL)
402 errx(1, "malloc");
403 codefile = fopen (filename, "w");
404 if (codefile == NULL)
405 err (1, "fopen %s", filename);
406 if (logfile)
407 fprintf(logfile, "%s ", filename);
408 free(filename);
409 filename = NULL;
410 fprintf (codefile,
411 "/* Generated from %s */\n"
412 "/* Do not edit */\n\n"
413 "#define ASN1_LIB\n\n"
414 "#include <stdio.h>\n"
415 "#include <stdlib.h>\n"
416 "#include <time.h>\n"
417 "#include <string.h>\n"
418 "#include <errno.h>\n"
419 "#include <limits.h>\n"
420 "#include <%s>\n",
421 orig_filename,
422 type_file_string);
424 fprintf (codefile,
425 "#include \"%s\"\n"
426 "#include \"%s\"\n",
427 header, privheader);
428 fprintf (codefile,
429 "#include <asn1_err.h>\n"
430 "#include <der.h>\n"
431 "#include <asn1-template.h>\n\n");
433 if (parse_units_flag)
434 fprintf (codefile,
435 "#include <parse_units.h>\n\n");
437 #ifdef _WIN32
438 fprintf(codefile, "#pragma warning(disable: 4101)\n\n");
439 #endif
442 void
443 close_codefile(void)
445 if (codefile == NULL)
446 abort();
448 if (fclose(codefile) == EOF)
449 err(1, "writes to source code file failed");
450 codefile = NULL;
454 void
455 generate_constant (const Symbol *s)
457 switch(s->value->type) {
458 case booleanvalue:
459 break;
460 case integervalue:
462 * Work around the fact that OpenSSL defines macros for PKIX constants
463 * that we want to generate as enums, which causes conflicts for things
464 * like ub-name (ub_name).
466 fprintf(headerfile,
467 "#ifdef %s\n"
468 "#undef %s\n"
469 "#endif\n"
470 "enum { %s = %lld };\n\n",
471 s->gen_name, s->gen_name, s->gen_name,
472 (long long)s->value->u.integervalue);
473 if (is_export(s->name))
474 fprintf(symsfile, "ASN1_SYM_INTVAL(\"%s\", \"%s\", %s, %lld)\n",
475 s->name, s->gen_name, s->gen_name,
476 (long long)s->value->u.integervalue);
477 break;
478 case nullvalue:
479 break;
480 case stringvalue:
481 break;
482 case objectidentifiervalue: {
483 struct objid *o, **list;
484 size_t i, len;
485 char *gen_upper;
487 if (!one_code_file)
488 generate_header_of_codefile(s->gen_name);
490 len = 0;
491 for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
492 len++;
493 if (len == 0) {
494 printf("s->gen_name: %s",s->gen_name);
495 fflush(stdout);
496 break;
498 list = emalloc(sizeof(*list) * len);
500 i = 0;
501 for (o = s->value->u.objectidentifiervalue; o != NULL; o = o->next)
502 list[i++] = o;
504 fprintf (headerfile, "/* OBJECT IDENTIFIER %s ::= { ", s->name);
505 for (i = len ; i > 0; i--) {
506 o = list[i - 1];
507 fprintf(headerfile, "%s(%d) ",
508 o->label ? o->label : "label-less", o->value);
511 fprintf (codefile, "static unsigned oid_%s_variable_num[%lu] = {",
512 s->gen_name, (unsigned long)len);
513 for (i = len ; i > 0; i--) {
514 fprintf(codefile, "%d%s ", list[i - 1]->value, i > 1 ? "," : "");
516 fprintf(codefile, "};\n");
518 fprintf (codefile, "const heim_oid asn1_oid_%s = "
519 "{ %lu, oid_%s_variable_num };\n\n",
520 s->gen_name, (unsigned long)len, s->gen_name);
522 fprintf(oidsfile, "DEFINE_OID_WITH_NAME(%s)\n", s->gen_name);
523 if (is_export(s->name))
524 fprintf(symsfile, "ASN1_SYM_OID(\"%s\", \"%s\", %s)\n",
525 s->name, s->gen_name, s->gen_name);
527 free(list);
529 /* header file */
531 gen_upper = strdup(s->gen_name);
532 len = strlen(gen_upper);
533 for (i = 0; i < len; i++)
534 gen_upper[i] = toupper((int)s->gen_name[i]);
536 fprintf (headerfile, "} */\n");
537 fprintf (headerfile,
538 "extern ASN1EXP const heim_oid asn1_oid_%s;\n"
539 "#define ASN1_OID_%s (&asn1_oid_%s)\n\n",
540 s->gen_name,
541 gen_upper,
542 s->gen_name);
544 free(gen_upper);
546 if (!one_code_file)
547 close_codefile();
549 break;
551 default:
552 abort();
557 is_tagged_type(const Type *t)
560 * Start by chasing aliasings like this:
562 * Type0 ::= ...
563 * Type1 ::= Type0
564 * ..
565 * TypeN ::= TypeN-1
567 * to <Type0>, then check if <Type0> is tagged.
569 while (t->type == TType) {
570 if (t->subtype)
571 t = t->subtype;
572 else if (t->symbol && t->symbol->type)
573 t = t->symbol->type;
574 else
575 abort();
578 if (t->type == TTag && t->tag.tagenv == TE_EXPLICIT)
579 return 1;
580 if (t->type == TTag) {
581 if (t->subtype)
582 return is_tagged_type(t->subtype);
583 if (t->symbol && t->symbol->type)
584 return is_tagged_type(t->symbol->type);
585 /* This is the tag */
586 return 1;
588 return 0;
592 is_primitive_type(const Type *t)
595 * Start by chasing aliasings like this:
597 * Type0 ::= ...
598 * Type1 ::= Type0
599 * ..
600 * TypeN ::= TypeN-1
602 * to <Type0>, then check if <Type0> is primitive.
604 while (t->type == TType &&
605 t->symbol &&
606 t->symbol->type) {
607 if (t->symbol->type->type == TType)
608 t = t->symbol->type; /* Alias */
609 else if (t->symbol->type->type == TTag &&
610 t->symbol->type->tag.tagenv == TE_IMPLICIT)
612 * IMPLICIT-tagged alias, something like:
614 * Type0 ::= [0] IMPLICIT ...
616 * Just recurse.
618 return is_primitive_type(t->symbol->type);
619 else
620 break;
623 /* EXPLICIT non-UNIVERSAL tags are always constructed */
624 if (t->type == TTag && t->tag.tagclass != ASN1_C_UNIV &&
625 t->tag.tagenv == TE_EXPLICIT)
626 return 0;
627 if (t->symbol && t->symbol->type) {
628 /* EXPLICIT non-UNIVERSAL tags are constructed */
629 if (t->symbol->type->type == TTag &&
630 t->symbol->type->tag.tagclass != ASN1_C_UNIV &&
631 t->symbol->type->tag.tagenv == TE_EXPLICIT)
632 return 0;
633 /* EXPLICIT UNIVERSAL tags are constructed if they are SEQUENCE/SET */
634 if (t->symbol->type->type == TTag &&
635 t->symbol->type->tag.tagclass == ASN1_C_UNIV) {
636 switch (t->symbol->type->tag.tagvalue) {
637 case UT_Sequence: return 0;
638 case UT_Set: return 0;
639 default: return 1;
643 switch(t->type) {
644 case TInteger:
645 case TBoolean:
646 case TOctetString:
647 case TBitString:
648 case TEnumerated:
649 case TGeneralizedTime:
650 case TGeneralString:
651 case TTeletexString:
652 case TOID:
653 case TUTCTime:
654 case TUTF8String:
655 case TPrintableString:
656 case TIA5String:
657 case TBMPString:
658 case TUniversalString:
659 case TVisibleString:
660 case TNull:
661 return 1;
662 case TTag:
663 return is_primitive_type(t->subtype);
664 default:
665 return 0;
669 static void
670 space(int level)
672 while(level-- > 0)
673 fprintf(headerfile, " ");
676 static const char *
677 last_member_p(struct member *m)
679 struct member *n = HEIM_TAILQ_NEXT(m, members);
680 if (n == NULL)
681 return "";
682 if (n->ellipsis && HEIM_TAILQ_NEXT(n, members) == NULL)
683 return "";
684 return ",";
687 static struct member *
688 have_ellipsis(Type *t)
690 struct member *m;
691 HEIM_TAILQ_FOREACH(m, t->members, members) {
692 if (m->ellipsis)
693 return m;
695 return NULL;
698 static void
699 define_asn1 (int level, Type *t)
701 switch (t->type) {
702 case TType:
703 if (!t->symbol && t->typeref.iosclass) {
704 fprintf(headerfile, "%s.&%s",
705 t->typeref.iosclass->symbol->name,
706 t->typeref.field->name);
707 } else
708 fprintf(headerfile, "%s", t->symbol->name);
709 break;
710 case TInteger:
711 if(t->members == NULL) {
712 fprintf (headerfile, "INTEGER");
713 if (t->range)
714 fprintf (headerfile, " (%lld..%lld)",
715 (long long)t->range->min,
716 (long long)t->range->max);
717 } else {
718 Member *m;
719 fprintf (headerfile, "INTEGER {\n");
720 HEIM_TAILQ_FOREACH(m, t->members, members) {
721 space (level + 1);
722 fprintf(headerfile, "%s(%d)%s\n", m->gen_name, m->val,
723 last_member_p(m));
725 space(level);
726 fprintf (headerfile, "}");
728 break;
729 case TBoolean:
730 fprintf (headerfile, "BOOLEAN");
731 break;
732 case TOctetString:
733 fprintf (headerfile, "OCTET STRING");
734 break;
735 case TEnumerated:
736 case TBitString: {
737 Member *m;
739 space(level);
740 if(t->type == TBitString)
741 fprintf (headerfile, "BIT STRING {\n");
742 else
743 fprintf (headerfile, "ENUMERATED {\n");
744 HEIM_TAILQ_FOREACH(m, t->members, members) {
745 space(level + 1);
746 fprintf (headerfile, "%s(%d)%s\n", m->name, m->val,
747 last_member_p(m));
749 space(level);
750 fprintf (headerfile, "}");
751 break;
753 case TChoice:
754 case TSet:
755 case TSequence: {
756 Member *m;
757 size_t max_width = 0;
759 if(t->type == TChoice)
760 fprintf(headerfile, "CHOICE {\n");
761 else if(t->type == TSet)
762 fprintf(headerfile, "SET {\n");
763 else
764 fprintf(headerfile, "SEQUENCE {\n");
765 HEIM_TAILQ_FOREACH(m, t->members, members) {
766 if(strlen(m->name) > max_width)
767 max_width = strlen(m->name);
769 max_width += 3;
770 if(max_width < 16) max_width = 16;
771 HEIM_TAILQ_FOREACH(m, t->members, members) {
772 size_t width = max_width;
773 space(level + 1);
774 if (m->ellipsis) {
775 fprintf (headerfile, "...");
776 } else {
777 width -= fprintf(headerfile, "%s", m->name);
778 fprintf(headerfile, "%*s", (int)width, "");
779 define_asn1(level + 1, m->type);
780 if(m->optional)
781 fprintf(headerfile, " OPTIONAL");
783 if(last_member_p(m))
784 fprintf (headerfile, ",");
785 fprintf (headerfile, "\n");
787 space(level);
788 fprintf (headerfile, "}");
789 break;
791 case TSequenceOf:
792 fprintf (headerfile, "SEQUENCE OF ");
793 define_asn1 (0, t->subtype);
794 break;
795 case TSetOf:
796 fprintf (headerfile, "SET OF ");
797 define_asn1 (0, t->subtype);
798 break;
799 case TGeneralizedTime:
800 fprintf (headerfile, "GeneralizedTime");
801 break;
802 case TGeneralString:
803 fprintf (headerfile, "GeneralString");
804 break;
805 case TTeletexString:
806 fprintf (headerfile, "TeletexString");
807 break;
808 case TTag: {
809 const char *classnames[] = { "UNIVERSAL ", "APPLICATION ",
810 "" /* CONTEXT */, "PRIVATE " };
811 if(t->tag.tagclass != ASN1_C_UNIV)
812 fprintf (headerfile, "[%s%d] ",
813 classnames[t->tag.tagclass],
814 t->tag.tagvalue);
815 if(t->tag.tagenv == TE_IMPLICIT)
816 fprintf (headerfile, "IMPLICIT ");
817 define_asn1 (level, t->subtype);
818 break;
820 case TUTCTime:
821 fprintf (headerfile, "UTCTime");
822 break;
823 case TUTF8String:
824 space(level);
825 fprintf (headerfile, "UTF8String");
826 break;
827 case TPrintableString:
828 space(level);
829 fprintf (headerfile, "PrintableString");
830 break;
831 case TIA5String:
832 space(level);
833 fprintf (headerfile, "IA5String");
834 break;
835 case TBMPString:
836 space(level);
837 fprintf (headerfile, "BMPString");
838 break;
839 case TUniversalString:
840 space(level);
841 fprintf (headerfile, "UniversalString");
842 break;
843 case TVisibleString:
844 space(level);
845 fprintf (headerfile, "VisibleString");
846 break;
847 case TOID :
848 space(level);
849 fprintf(headerfile, "OBJECT IDENTIFIER");
850 break;
851 case TNull:
852 space(level);
853 fprintf (headerfile, "NULL");
854 break;
855 default:
856 abort ();
860 static void
861 getnewbasename(char **newbasename, int typedefp, const char *basename, const char *name)
863 if (typedefp)
864 *newbasename = strdup(name);
865 else {
866 if (name[0] == '*')
867 name++;
868 if (asprintf(newbasename, "%s_%s", basename, name) < 0)
869 errx(1, "malloc");
871 if (*newbasename == NULL)
872 err(1, "malloc");
875 static void define_type(int, const char *, const char *, Type *, Type *, int, int);
878 * Get the SET/SEQUENCE member pair and CLASS field pair defining an open type.
880 * There are three cases:
882 * - open types embedded in OCTET STRING, with the open type object class
883 * relation declared via a constraint
885 * - open types not embedded in OCTET STRING, which are really more like ANY
886 * DEFINED BY types, so, HEIM_ANY
888 * - open types in a nested structure member where the type ID field is in a
889 * member of the ancestor structure (this happens in PKIX's `AttributeSet',
890 * where the open type is essentially a SET OF HEIM_ANY).
892 * In a type like PKIX's SingleAttribute the type ID member would be the one
893 * named "type" and the open type member would be the one named "value", and
894 * the corresponding fields of the ATTRIBUTE class would be named "id" and
895 * "Type".
897 * NOTE: We assume a single open type member pair in any SET/SEQUENCE. In
898 * principle there could be more pairs and we could iterate them, or
899 * better yet, we could be given the name of an open type member and then
900 * just find its related type ID member and fields, then our caller would
901 * iterate the SET/SEQUENCE type's members looking for open type members
902 * and would call this function for each one found.
904 void
905 get_open_type_defn_fields(const Type *t,
906 Member **typeidmember,
907 Member **opentypemember,
908 Field **typeidfield,
909 Field **opentypefield,
910 int *is_array_of)
912 Member *m;
913 Field *junk1, *junk2;
914 char *idmembername = NULL;
916 if (!typeidfield) typeidfield = &junk1;
917 if (!opentypefield) opentypefield = &junk2;
919 *typeidfield = *opentypefield = NULL;
920 *typeidmember = *opentypemember = NULL;
921 *is_array_of = 0;
923 /* Look for the open type member */
924 HEIM_TAILQ_FOREACH(m, t->members, members) {
925 Type *subtype = m->type;
926 Type *sOfType = NULL;
928 while (subtype->type == TTag ||
929 subtype->type == TSetOf ||
930 subtype->type == TSequenceOf) {
931 if (subtype->type == TTag && subtype->subtype) {
932 if (subtype->subtype->type == TOctetString ||
933 subtype->subtype->type == TBitString)
934 break;
935 subtype = subtype->subtype;
936 } else if (subtype->type == TSetOf || subtype->type == TSequenceOf) {
937 sOfType = subtype;
938 if (sOfType->symbol)
939 break;
940 if (subtype->subtype)
941 subtype = subtype->subtype;
942 } else
943 break;
946 * If we traversed through a non-inlined SET OF or SEQUENCE OF type,
947 * then this cannot be an open type field.
949 if (sOfType && sOfType->symbol)
950 continue;
952 * The type of the field we're interested in has to have an information
953 * object constraint.
955 if (!subtype->constraint)
956 continue;
957 if (subtype->type != TType && subtype->type != TTag)
958 continue;
960 * Check if it's an ANY-like member or like an OCTET STRING CONTAINING
961 * member. Those are the only two possibilities.
963 if ((subtype->type == TTag || subtype->type == TType) &&
964 subtype->subtype &&
965 subtype->constraint->ctype == CT_CONTENTS &&
966 subtype->constraint->u.content.type &&
967 subtype->constraint->u.content.type->type == TType &&
968 !subtype->constraint->u.content.type->subtype &&
969 subtype->constraint->u.content.type->constraint &&
970 subtype->constraint->u.content.type->constraint->ctype == CT_TABLE_CONSTRAINT) {
971 /* Type like OCTET STRING or BIT STRING CONTAINING open type */
972 *opentypemember = m;
973 *opentypefield = subtype->constraint->u.content.type->typeref.field;
974 *is_array_of = sOfType != NULL;
975 idmembername = subtype->constraint->u.content.type->constraint->u.content.crel.membername;
976 break;
977 } else if (subtype->symbol && strcmp(subtype->symbol->name, "HEIM_ANY") == 0) {
978 /* Open type, but NOT embedded in OCTET STRING or BIT STRING */
979 *opentypemember = m;
980 *opentypefield = subtype->typeref.field;
981 *is_array_of = sOfType != NULL;
982 idmembername = subtype->constraint->u.content.crel.membername;
983 break;
986 /* Look for the type ID member identified in the previous loop */
987 HEIM_TAILQ_FOREACH(m, t->members, members) {
988 if (!m->type->subtype || strcmp(m->name, idmembername))
989 continue;
990 if (m->type->constraint &&
991 m->type->constraint->ctype == CT_TABLE_CONSTRAINT)
992 *typeidfield = m->type->typeref.field;
993 else if (m->type->subtype->constraint &&
994 m->type->subtype->constraint->ctype == CT_TABLE_CONSTRAINT)
995 *typeidfield = m->type->subtype->typeref.field;
996 else
997 continue;
998 /* This is the type ID field (because there _is_ a subtype) */
999 *typeidmember = m;
1000 break;
1005 * Generate CHOICE-like struct fields for open types declared via
1006 * X.681/682/683 syntax.
1008 * We could support multiple open type members in a SET/SEQUENCE, but for now
1009 * we support only one.
1011 static void
1012 define_open_type(int level, const char *newbasename, const char *name, const char *basename, Type *pt, Type *t)
1014 Member *opentypemember, *typeidmember;
1015 Field *opentypefield, *typeidfield;
1016 ObjectField *of;
1017 IOSObjectSet *os = pt->actual_parameter;
1018 IOSObject **objects;
1019 size_t nobjs, i;
1020 int is_array_of_open_type;
1022 get_open_type_defn_fields(pt, &typeidmember, &opentypemember,
1023 &typeidfield, &opentypefield,
1024 &is_array_of_open_type);
1025 if (!opentypemember || !typeidmember ||
1026 !opentypefield || !typeidfield)
1027 errx(1, "Open type specification in %s is incomplete", name);
1029 sort_object_set(os, typeidfield, &objects, &nobjs);
1031 fprintf(headerfile, "struct {\n");
1033 /* Iterate objects in the object set, gen enum labels */
1034 fprintf(headerfile, "enum { choice_%s_iosnumunknown = 0,\n",
1035 newbasename);
1036 for (i = 0; i < nobjs; i++) {
1037 HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) {
1038 if (strcmp(of->name, typeidfield->name))
1039 continue;
1040 if (!of->value || !of->value->s)
1041 errx(1, "Unknown value in value field %s of object %s",
1042 of->name, objects[i]->symbol->name);
1043 fprintf(headerfile, "choice_%s_iosnum_%s,\n",
1044 newbasename, of->value->s->gen_name);
1047 fprintf(headerfile, "} element;\n");
1049 if (is_array_of_open_type)
1050 fprintf(headerfile, "unsigned int len;\n");
1052 /* Iterate objects in the object set, gen union arms */
1053 fprintf(headerfile, "union {\nvoid *_any;\n");
1054 for (i = 0; i < nobjs; i++) {
1055 HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) {
1056 char *n = NULL;
1058 if (strcmp(of->name, opentypefield->name))
1059 continue;
1060 if (!of->type || (!of->type->symbol && of->type->type != TTag) ||
1061 of->type->tag.tagclass != ASN1_C_UNIV) {
1062 warnx("Ignoring unknown or unset type field %s of object %s",
1063 of->name, objects[i]->symbol->name);
1064 continue;
1067 if (asprintf(&n, "*%s", objects[i]->symbol->gen_name) < 0 || n == NULL)
1068 err(1, "malloc");
1069 define_type(level + 2, n, newbasename, NULL, of->type, FALSE, FALSE);
1070 free(n);
1073 if (is_array_of_open_type) {
1074 fprintf(headerfile, "} *val;\n} _ioschoice_%s;\n", opentypemember->gen_name);
1075 } else {
1076 fprintf(headerfile, "} u;\n");
1077 fprintf(headerfile, "} _ioschoice_%s;\n", opentypemember->gen_name);
1079 free(objects);
1082 static void
1083 define_type(int level, const char *name, const char *basename, Type *pt, Type *t, int typedefp, int preservep)
1085 const char *label_prefix = NULL;
1086 const char *label_prefix_sep = NULL;
1087 char *newbasename = NULL;
1089 switch (t->type) {
1090 case TType:
1091 space(level);
1092 if (!t->symbol && t->actual_parameter)
1093 define_open_type(level, newbasename, name, basename, t, t);
1094 else if (!t->symbol && pt->actual_parameter)
1095 define_open_type(level, newbasename, name, basename, pt, t);
1096 else
1097 fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name);
1098 break;
1099 case TInteger:
1100 if (t->symbol && t->symbol->emitted_definition)
1101 break;
1103 space(level);
1104 if(t->members) {
1105 Member *m;
1107 label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : "");
1108 label_prefix_sep = prefix_enum ? "_" : "";
1109 fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
1110 HEIM_TAILQ_FOREACH(m, t->members, members) {
1111 space (level + 1);
1112 fprintf(headerfile, "%s%s%s = %d%s\n",
1113 label_prefix, label_prefix_sep,
1114 m->gen_name, m->val, last_member_p(m));
1116 fprintf(headerfile, "} %s;\n", name);
1117 } else if (t->range == NULL) {
1118 fprintf(headerfile, "heim_integer %s;\n", name);
1119 } else if (t->range->min < 0 &&
1120 (t->range->min < INT_MIN || t->range->max > INT_MAX)) {
1121 fprintf(headerfile, "int64_t %s;\n", name);
1122 } else if (t->range->min < 0) {
1123 fprintf (headerfile, "int %s;\n", name);
1124 } else if (t->range->max > UINT_MAX) {
1125 fprintf (headerfile, "uint64_t %s;\n", name);
1126 } else {
1127 fprintf (headerfile, "unsigned int %s;\n", name);
1129 break;
1130 case TBoolean:
1131 space(level);
1132 fprintf (headerfile, "int %s;\n", name);
1133 break;
1134 case TOctetString:
1135 space(level);
1136 fprintf (headerfile, "heim_octet_string %s;\n", name);
1137 break;
1138 case TBitString: {
1139 Member *m;
1140 Type i;
1141 struct range range = { 0, UINT_MAX };
1142 size_t max_memno = 0;
1143 size_t bitset_size;
1145 if (t->symbol && t->symbol->emitted_definition)
1146 break;
1147 memset(&i, 0, sizeof(i));
1150 * range.max implies the size of the base unsigned integer used for the
1151 * bitfield members. If it's less than or equal to UINT_MAX, then that
1152 * will be unsigned int, otherwise it will be uint64_t.
1154 * We could just use uint64_t, yes, but for now, and in case that any
1155 * projects were exposing the BIT STRING types' C representations in
1156 * ABIs prior to this compiler supporting BIT STRING with larger
1157 * members, we stick to this.
1159 HEIM_TAILQ_FOREACH(m, t->members, members) {
1160 if (m->val > max_memno)
1161 max_memno = m->val;
1163 if (max_memno > 63)
1164 range.max = INT64_MAX;
1165 else
1166 range.max = 1ULL << max_memno;
1168 i.type = TInteger;
1169 i.range = &range;
1170 i.members = NULL;
1171 i.constraint = NULL;
1173 space(level);
1174 if(HEIM_TAILQ_EMPTY(t->members))
1175 fprintf (headerfile, "heim_bit_string %s;\n", name);
1176 else {
1177 int pos = 0;
1178 getnewbasename(&newbasename, typedefp || level == 0, basename, name);
1180 fprintf (headerfile, "struct %s {\n", newbasename);
1181 HEIM_TAILQ_FOREACH(m, t->members, members) {
1182 char *n = NULL;
1185 * pad unused bits beween declared members (hopefully this
1186 * forces the compiler to give us an obvious layout)
1188 while (pos < m->val) {
1189 if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL)
1190 err(1, "malloc");
1191 define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE);
1192 free(n);
1193 pos++;
1196 n = NULL;
1197 if (asprintf (&n, "%s:1", m->gen_name) < 0 || n == NULL)
1198 errx(1, "malloc");
1199 define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE);
1200 free (n);
1201 n = NULL;
1202 pos++;
1204 /* pad unused tail (ditto) */
1205 bitset_size = max_memno;
1206 if (max_memno > 31)
1207 bitset_size += 64 - (max_memno % 64);
1208 else
1209 bitset_size = 32;
1210 while (pos < bitset_size) {
1211 char *n = NULL;
1212 if (asprintf (&n, "_unused%d:1", pos) < 0 || n == NULL)
1213 errx(1, "malloc");
1214 define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE);
1215 free(n);
1216 pos++;
1219 space(level);
1220 fprintf (headerfile, "} %s;\n\n", name);
1222 break;
1224 case TEnumerated: {
1225 Member *m;
1227 if (t->symbol && t->symbol->emitted_definition)
1228 break;
1230 label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : "");
1231 label_prefix_sep = prefix_enum ? "_" : "";
1232 space(level);
1233 fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
1234 HEIM_TAILQ_FOREACH(m, t->members, members) {
1235 space(level + 1);
1236 if (m->ellipsis)
1237 fprintf (headerfile, "/* ... */\n");
1238 else
1239 fprintf(headerfile, "%s%s%s = %d%s\n",
1240 label_prefix, label_prefix_sep,
1241 m->gen_name, m->val, last_member_p(m));
1243 space(level);
1244 fprintf (headerfile, "} %s;\n\n", name);
1245 break;
1247 case TSet:
1248 case TSequence: {
1249 Member *m;
1251 getnewbasename(&newbasename, typedefp || level == 0, basename, name);
1253 space(level);
1254 fprintf (headerfile, "struct %s {\n", newbasename);
1255 if (t->type == TSequence && preservep) {
1256 space(level + 1);
1257 fprintf(headerfile, "heim_octet_string _save;\n");
1259 HEIM_TAILQ_FOREACH(m, t->members, members) {
1260 if (m->ellipsis) {
1262 } else if (m->optional) {
1263 char *n = NULL;
1265 if (asprintf(&n, "*%s", m->gen_name) < 0 || n == NULL)
1266 errx(1, "malloc");
1267 define_type(level + 1, n, newbasename, t, m->type, FALSE, FALSE);
1268 free (n);
1269 } else
1270 define_type(level + 1, m->gen_name, newbasename, t, m->type, FALSE, FALSE);
1272 if (t->actual_parameter && t->actual_parameter->objects)
1273 define_open_type(level, newbasename, name, basename, t, t);
1274 space(level);
1275 fprintf (headerfile, "} %s;\n", name);
1276 break;
1278 case TSetOf:
1279 case TSequenceOf: {
1280 Type i;
1281 struct range range = { 0, UINT_MAX };
1283 getnewbasename(&newbasename, typedefp || level == 0, basename, name);
1285 memset(&i, 0, sizeof(i));
1286 i.type = TInteger;
1287 i.range = &range;
1289 space(level);
1290 fprintf (headerfile, "struct %s {\n", newbasename);
1291 define_type(level + 1, "len", newbasename, t, &i, FALSE, FALSE);
1292 define_type(level + 1, "*val", newbasename, t, t->subtype, FALSE, FALSE);
1293 space(level);
1294 fprintf (headerfile, "} %s;\n", name);
1295 break;
1297 case TGeneralizedTime:
1298 space(level);
1299 fprintf (headerfile, "time_t %s;\n", name);
1300 break;
1301 case TGeneralString:
1302 space(level);
1303 fprintf (headerfile, "heim_general_string %s;\n", name);
1304 break;
1305 case TTeletexString:
1306 space(level);
1307 fprintf (headerfile, "heim_general_string %s;\n", name);
1308 break;
1309 case TTag:
1310 define_type(level, name, basename, t, t->subtype, typedefp, preservep);
1311 break;
1312 case TChoice: {
1313 int first = 1;
1314 Member *m;
1316 getnewbasename(&newbasename, typedefp || level == 0, basename, name);
1318 space(level);
1319 fprintf (headerfile, "struct %s {\n", newbasename);
1320 if (preservep) {
1321 space(level + 1);
1322 fprintf(headerfile, "heim_octet_string _save;\n");
1324 space(level + 1);
1325 fprintf (headerfile, "enum %s_enum {\n", newbasename);
1326 m = have_ellipsis(t);
1327 if (m) {
1328 space(level + 2);
1329 fprintf (headerfile, "%s = 0,\n", m->label);
1330 first = 0;
1332 HEIM_TAILQ_FOREACH(m, t->members, members) {
1333 space(level + 2);
1334 if (m->ellipsis)
1335 fprintf (headerfile, "/* ... */\n");
1336 else
1337 fprintf (headerfile, "%s%s%s\n", m->label,
1338 first ? " = 1" : "",
1339 last_member_p(m));
1340 first = 0;
1342 space(level + 1);
1343 fprintf (headerfile, "} element;\n");
1344 space(level + 1);
1345 fprintf (headerfile, "union {\n");
1346 HEIM_TAILQ_FOREACH(m, t->members, members) {
1347 if (m->ellipsis) {
1348 space(level + 2);
1349 fprintf(headerfile, "heim_octet_string asn1_ellipsis;\n");
1350 } else if (m->optional) {
1351 char *n = NULL;
1353 if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL)
1354 errx(1, "malloc");
1355 define_type(level + 2, n, newbasename, t, m->type, FALSE, FALSE);
1356 free (n);
1357 } else
1358 define_type(level + 2, m->gen_name, newbasename, t, m->type, FALSE, FALSE);
1360 space(level + 1);
1361 fprintf (headerfile, "} u;\n");
1362 space(level);
1363 fprintf (headerfile, "} %s;\n", name);
1364 break;
1366 case TUTCTime:
1367 space(level);
1368 fprintf (headerfile, "time_t %s;\n", name);
1369 break;
1370 case TUTF8String:
1371 space(level);
1372 fprintf (headerfile, "heim_utf8_string %s;\n", name);
1373 break;
1374 case TPrintableString:
1375 space(level);
1376 fprintf (headerfile, "heim_printable_string %s;\n", name);
1377 break;
1378 case TIA5String:
1379 space(level);
1380 fprintf (headerfile, "heim_ia5_string %s;\n", name);
1381 break;
1382 case TBMPString:
1383 space(level);
1384 fprintf (headerfile, "heim_bmp_string %s;\n", name);
1385 break;
1386 case TUniversalString:
1387 space(level);
1388 fprintf (headerfile, "heim_universal_string %s;\n", name);
1389 break;
1390 case TVisibleString:
1391 space(level);
1392 fprintf (headerfile, "heim_visible_string %s;\n", name);
1393 break;
1394 case TOID :
1395 space(level);
1396 fprintf (headerfile, "heim_oid %s;\n", name);
1397 break;
1398 case TNull:
1399 space(level);
1400 fprintf (headerfile, "int %s;\n", name);
1401 break;
1402 default:
1403 abort ();
1405 free(newbasename);
1408 static void
1409 declare_type(const Symbol *s, Type *t, int typedefp)
1411 char *newbasename = NULL;
1413 if (typedefp)
1414 fprintf(headerfile, "typedef ");
1416 switch (t->type) {
1417 case TType:
1418 define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, TRUE);
1419 if (template_flag)
1420 generate_template_type_forward(s->gen_name);
1421 emitted_declaration(s);
1422 return;
1423 case TInteger:
1424 case TBoolean:
1425 case TOctetString:
1426 case TBitString:
1427 case TEnumerated:
1428 case TGeneralizedTime:
1429 case TGeneralString:
1430 case TTeletexString:
1431 case TUTCTime:
1432 case TUTF8String:
1433 case TPrintableString:
1434 case TIA5String:
1435 case TBMPString:
1436 case TUniversalString:
1437 case TVisibleString:
1438 case TOID :
1439 case TNull:
1440 define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, TRUE);
1441 if (template_flag)
1442 generate_template_type_forward(s->gen_name);
1443 emitted_declaration(s);
1444 emitted_definition(s);
1445 return;
1446 case TTag:
1447 declare_type(s, t->subtype, FALSE);
1448 emitted_declaration(s);
1449 return;
1450 default:
1451 break;
1454 switch (t->type) {
1455 case TSet:
1456 case TSequence:
1457 getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name);
1458 fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name);
1459 break;
1460 case TSetOf:
1461 case TSequenceOf:
1462 getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name);
1463 fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name);
1464 break;
1465 case TChoice:
1466 getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name);
1467 fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name);
1468 break;
1469 default:
1470 abort ();
1472 free(newbasename);
1473 emitted_declaration(s);
1476 static void generate_subtypes_header_helper(const Member *m);
1477 static void generate_type_header(const Symbol *);
1479 static void
1480 generate_subtypes_header_helper(const Member *m)
1482 Member *sm;
1483 Symbol *s;
1485 if (m->ellipsis)
1486 return;
1487 if (m->type->symbol && (s = getsym(m->type->symbol->name)) &&
1488 !s->emitted_definition) {
1489 /* A field of some named type; recurse */
1490 if (!m->optional && !m->defval)
1491 generate_type_header(s);
1492 return;
1494 if (!m->type->subtype && !m->type->members)
1495 return;
1496 if (m->type->type == TTag &&
1497 m->type->subtype && m->type->subtype->symbol &&
1498 (s = getsym(m->type->subtype->symbol->name))) {
1499 if (!m->optional && !m->defval)
1500 generate_type_header(s);
1501 return;
1503 if (m->type->subtype) {
1504 switch (m->type->subtype->type) {
1505 case TSet:
1506 case TSequence:
1507 case TChoice:
1508 break;
1509 default:
1510 return;
1512 /* A field of some anonymous (inlined) structured type */
1513 HEIM_TAILQ_FOREACH(sm, m->type->subtype->members, members) {
1514 generate_subtypes_header_helper(sm);
1517 if (m->type->members) {
1518 HEIM_TAILQ_FOREACH(sm, m->type->members, members) {
1519 generate_subtypes_header_helper(sm);
1524 static void
1525 generate_subtypes_header(const Symbol *s)
1527 Type *t = s->type;
1528 Member *m;
1531 * Recurse down structured types to make sure top-level types get
1532 * defined before they are referenced.
1534 * We'll take care to skip OPTIONAL member fields of constructed types so
1535 * that we can have circular types like:
1537 * Foo ::= SEQUENCE {
1538 * bar Bar OPTIONAL
1541 * Bar ::= SEQUENCE {
1542 * foo Foo OPTIONAL
1545 * not unlike XDR, which uses `*' to mean "optional", except in XDR it's
1546 * called a "pointer". With some care we should be able to eventually
1547 * support the silly XDR linked list example:
1549 * ListOfFoo ::= SEQUENCE {
1550 * someField SomeType,
1551 * next ListOfFoo OPTIONAL
1554 * Not that anyone needs it -- just use a SEQUENCE OF and be done.
1557 while (t->type == TTag && t->subtype) {
1558 switch (t->subtype->type) {
1559 case TTag:
1560 case TSet:
1561 case TSequence:
1562 case TChoice:
1563 t = t->subtype;
1564 continue;
1565 default:
1566 break;
1568 break;
1571 switch (t->type) {
1572 default: return;
1573 case TType: {
1574 Symbol *s2;
1575 if (t->symbol && (s2 = getsym(t->symbol->name)) != s)
1576 generate_type_header(s2);
1577 return;
1579 case TSet:
1580 case TSequence:
1581 case TChoice:
1582 break;
1585 HEIM_TAILQ_FOREACH(m, t->members, members) {
1586 generate_subtypes_header_helper(m);
1590 static void
1591 generate_type_header (const Symbol *s)
1593 Type *t = s->type;
1594 if (!s->type)
1595 return;
1598 * Recurse down the types of member fields of `s' to make sure that
1599 * referenced types have had their definitions emitted already if the
1600 * member fields are not OPTIONAL/DEFAULTed.
1602 generate_subtypes_header(s);
1603 fprintf(headerfile, "/*\n");
1604 fprintf(headerfile, "%s ::= ", s->name);
1605 define_asn1 (0, s->type);
1606 fprintf(headerfile, "\n*/\n\n");
1609 * Emit enums for the outermost tag of this type. These are needed for
1610 * dealing with IMPLICIT tags so we know what to rewrite the tag to when
1611 * decoding.
1613 * See gen_encode.c and gen_decode.c for a complete explanation. Short
1614 * version: we need to change the prototypes of the length/encode/decode
1615 * functions to take an optional IMPLICIT tag to use instead of the type's
1616 * outermost tag, but for now we hack it, and to do that we need to know
1617 * the type's outermost tag outside the context of the bodies of the codec
1618 * functions we generate for it. Using an enum means no extra space is
1619 * needed in stripped objects.
1621 if (!s->emitted_tag_enums) {
1622 while (t->type == TType && s->type->symbol && s->type->symbol->type) {
1623 if (t->subtype)
1624 t = t->subtype;
1625 else
1626 t = s->type->symbol->type;
1629 if (t->type == TType && t->symbol && strcmp(t->symbol->name, "HEIM_ANY")) {
1631 * This type is ultimately an alias of an imported type, so we don't
1632 * know its outermost tag here.
1634 fprintf(headerfile,
1635 "enum { asn1_tag_length_%s = asn1_tag_length_%s,\n"
1636 " asn1_tag_class_%s = asn1_tag_class_%s,\n"
1637 " asn1_tag_tag_%s = asn1_tag_tag_%s };\n",
1638 s->gen_name, s->type->symbol->gen_name,
1639 s->gen_name, s->type->symbol->gen_name,
1640 s->gen_name, s->type->symbol->gen_name);
1641 emitted_tag_enums(s);
1642 } else if (t->type != TType) {
1643 /* This type's outermost tag is known here */
1644 fprintf(headerfile,
1645 "enum { asn1_tag_length_%s = %lu,\n"
1646 " asn1_tag_class_%s = %d,\n"
1647 " asn1_tag_tag_%s = %d };\n",
1648 s->gen_name, (unsigned long)length_tag(s->type->tag.tagvalue),
1649 s->gen_name, s->type->tag.tagclass,
1650 s->gen_name, s->type->tag.tagvalue);
1651 emitted_tag_enums(s);
1655 if (s->emitted_definition)
1656 return;
1658 if (is_export(s->name))
1659 fprintf(symsfile, "ASN1_SYM_TYPE(\"%s\", \"%s\", %s)\n",
1660 s->name, s->gen_name, s->gen_name);
1661 fprintf(headerfile, "typedef ");
1662 define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE,
1663 preserve_type(s->name) ? TRUE : FALSE);
1664 fprintf(headerfile, "\n");
1666 emitted_definition(s);
1669 void
1670 generate_type_header_forwards(const Symbol *s)
1672 declare_type(s, s->type, TRUE);
1673 fprintf(headerfile, "\n");
1674 if (template_flag)
1675 generate_template_type_forward(s->gen_name);
1678 void
1679 generate_type (const Symbol *s)
1681 FILE *h;
1682 const char * exp;
1684 if (!one_code_file)
1685 generate_header_of_codefile(s->gen_name);
1687 generate_type_header(s);
1689 if (template_flag)
1690 generate_template(s);
1692 if (template_flag == 0 || is_template_compat(s) == 0) {
1693 generate_type_encode (s);
1694 generate_type_decode (s);
1695 generate_type_free (s);
1696 generate_type_length (s);
1697 generate_type_copy (s);
1698 generate_type_print_stub(s);
1700 generate_type_seq (s);
1701 generate_glue (s->type, s->gen_name);
1703 /* generate prototypes */
1705 if (is_export(s->name)) {
1706 h = headerfile;
1707 exp = "ASN1EXP ";
1708 } else {
1709 h = privheaderfile;
1710 exp = "";
1713 fprintf (h,
1714 "%sint ASN1CALL "
1715 "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
1716 exp,
1717 s->gen_name, s->gen_name);
1718 fprintf (h,
1719 "%sint ASN1CALL "
1720 "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
1721 exp,
1722 s->gen_name, s->gen_name);
1723 fprintf (h,
1724 "%ssize_t ASN1CALL length_%s(const %s *);\n",
1725 exp,
1726 s->gen_name, s->gen_name);
1727 fprintf (h,
1728 "%sint ASN1CALL copy_%s (const %s *, %s *);\n",
1729 exp,
1730 s->gen_name, s->gen_name, s->gen_name);
1731 fprintf (h,
1732 "%svoid ASN1CALL free_%s (%s *);\n",
1733 exp,
1734 s->gen_name, s->gen_name);
1736 fprintf(h,
1737 "%schar * ASN1CALL print_%s (const %s *, int);\n",
1738 exp,
1739 s->gen_name, s->gen_name);
1741 fprintf(h, "\n\n");
1743 if (!one_code_file) {
1744 fprintf(codefile, "\n\n");
1745 close_codefile();