1 /* $NetBSD: gen.c,v 1.3 2014/04/24 13:45:34 pettai Exp $ */
4 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
8 * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the Institute nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 FILE *privheaderfile
, *headerfile
, *codefile
, *logfile
, *templatefile
;
47 static const char *orig_filename
;
48 static char *privheader
, *header
, *template;
49 static const char *headerbase
= STEM
;
60 static struct import
*imports
= NULL
;
63 add_import (const char *module
)
65 struct import
*tmp
= emalloc (sizeof(*tmp
));
71 fprintf (headerfile
, "#include <%s_asn1.h>\n", module
);
75 * List of all exported symbols
84 static struct sexport
*exports
= NULL
;
87 add_export (const char *name
)
89 struct sexport
*tmp
= emalloc (sizeof(*tmp
));
97 is_export(const char *name
)
101 if (exports
== NULL
) /* no export list, all exported */
104 for (tmp
= exports
; tmp
!= NULL
; tmp
= tmp
->next
) {
105 if (strcmp(tmp
->name
, name
) == 0) {
116 return orig_filename
;
120 init_generate (const char *filename
, const char *base
)
124 orig_filename
= filename
;
126 headerbase
= strdup(base
);
127 if (headerbase
== NULL
)
131 /* public header file */
132 if (asprintf(&header
, "%s.h", headerbase
) < 0 || header
== NULL
)
134 if (asprintf(&fn
, "%s.hx", headerbase
) < 0 || fn
== NULL
)
136 headerfile
= fopen (fn
, "w");
137 if (headerfile
== NULL
)
138 err (1, "open %s", fn
);
142 /* private header file */
143 if (asprintf(&privheader
, "%s-priv.h", headerbase
) < 0 || privheader
== NULL
)
145 if (asprintf(&fn
, "%s-priv.hx", headerbase
) < 0 || fn
== NULL
)
147 privheaderfile
= fopen (fn
, "w");
148 if (privheaderfile
== NULL
)
149 err (1, "open %s", fn
);
154 if (asprintf(&template, "%s-template.c", headerbase
) < 0 || template == NULL
)
157 "/* Generated from %s */\n"
158 "/* Do not edit */\n\n",
162 "#define __%s_h__\n\n", headerbase
, headerbase
);
164 "#include <stddef.h>\n"
165 "#include <time.h>\n\n");
167 "#ifndef __asn1_common_definitions__\n"
168 "#define __asn1_common_definitions__\n\n");
170 "typedef struct heim_integer {\n"
174 "} heim_integer;\n\n");
176 "typedef struct heim_octet_string {\n"
179 "} heim_octet_string;\n\n");
181 "typedef char *heim_general_string;\n\n"
184 "typedef char *heim_utf8_string;\n\n"
187 "typedef struct heim_octet_string heim_printable_string;\n\n"
190 "typedef struct heim_octet_string heim_ia5_string;\n\n"
193 "typedef struct heim_bmp_string {\n"
196 "} heim_bmp_string;\n\n");
198 "typedef struct heim_universal_string {\n"
201 "} heim_universal_string;\n\n");
203 "typedef char *heim_visible_string;\n\n"
206 "typedef struct heim_oid {\n"
208 " unsigned *components;\n"
211 "typedef struct heim_bit_string {\n"
214 "} heim_bit_string;\n\n");
216 "typedef struct heim_octet_string heim_any;\n"
217 "typedef struct heim_octet_string heim_any_set;\n\n");
218 fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R) \\\n"
220 " (BL) = length_##T((S)); \\\n"
221 " (B) = malloc((BL)); \\\n"
222 " if((B) == NULL) { \\\n"
223 " (R) = ENOMEM; \\\n"
225 " (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
227 " if((R) != 0) { \\\n"
234 fputs("#ifdef _WIN32\n"
236 "#define ASN1EXP __declspec(dllimport)\n"
240 "#define ASN1CALL __stdcall\n"
246 fprintf (headerfile
, "struct units;\n\n");
247 fprintf (headerfile
, "#endif\n\n");
248 if (asprintf(&fn
, "%s_files", base
) < 0 || fn
== NULL
)
250 logfile
= fopen(fn
, "w");
252 err (1, "open %s", fn
);
254 /* if one code file, write into the one codefile */
258 templatefile
= fopen (template, "w");
259 if (templatefile
== NULL
)
260 err (1, "open %s", template);
262 fprintf (templatefile
,
263 "/* Generated from %s */\n"
264 "/* Do not edit */\n\n"
265 "#include <stdio.h>\n"
266 "#include <stdlib.h>\n"
267 "#include <time.h>\n"
268 "#include <string.h>\n"
269 "#include <errno.h>\n"
270 "#include <limits.h>\n"
271 "#include <krb5/krb5-types.h>\n",
274 fprintf (templatefile
,
277 "#include <krb5/der.h>\n"
278 "#include <der-private.h>\n"
279 "#include <asn1-template.h>\n",
286 close_generate (void)
288 fprintf (headerfile
, "#endif /* __%s_h__ */\n", headerbase
);
293 fclose (privheaderfile
);
295 fclose (templatefile
);
297 fprintf (logfile
, "\n");
302 gen_assign_defval(const char *var
, struct value
*val
)
306 fprintf(codefile
, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var
, val
->u
.stringvalue
);
309 fprintf(codefile
, "%s = %d;\n", var
, val
->u
.integervalue
);
312 if(val
->u
.booleanvalue
)
313 fprintf(codefile
, "%s = TRUE;\n", var
);
315 fprintf(codefile
, "%s = FALSE;\n", var
);
323 gen_compare_defval(const char *var
, struct value
*val
)
327 fprintf(codefile
, "if(strcmp(%s, \"%s\") != 0)\n", var
, val
->u
.stringvalue
);
330 fprintf(codefile
, "if(%s != %d)\n", var
, val
->u
.integervalue
);
333 if(val
->u
.booleanvalue
)
334 fprintf(codefile
, "if(!%s)\n", var
);
336 fprintf(codefile
, "if(%s)\n", var
);
344 generate_header_of_codefile(const char *name
)
346 char *filename
= NULL
;
348 if (codefile
!= NULL
)
351 if (asprintf (&filename
, "%s_%s.x", STEM
, name
) < 0 || filename
== NULL
)
353 codefile
= fopen (filename
, "w");
354 if (codefile
== NULL
)
355 err (1, "fopen %s", filename
);
356 fprintf(logfile
, "%s ", filename
);
360 "/* Generated from %s */\n"
361 "/* Do not edit */\n\n"
362 "#define ASN1_LIB\n\n"
363 "#include <stdio.h>\n"
364 "#include <stdlib.h>\n"
365 "#include <time.h>\n"
366 "#include <string.h>\n"
367 "#include <errno.h>\n"
368 "#include <limits.h>\n"
369 "#include <krb5/krb5-types.h>\n",
370 basename(orig_filename
));
377 "#include <krb5/asn1_err.h>\n"
378 "#include <krb5/der.h>\n"
379 "#include <der-private.h>\n"
380 "#include <asn1-template.h>\n"
381 "#include <krb5/parse_units.h>\n\n");
388 if (codefile
== NULL
)
397 generate_constant (const Symbol
*s
)
399 switch(s
->value
->type
) {
403 fprintf (headerfile
, "enum { %s = %d };\n\n",
404 s
->gen_name
, s
->value
->u
.integervalue
);
410 case objectidentifiervalue
: {
411 struct objid
*o
, **list
;
416 generate_header_of_codefile(s
->gen_name
);
419 for (o
= s
->value
->u
.objectidentifiervalue
; o
!= NULL
; o
= o
->next
)
422 printf("s->gen_name: %s",s
->gen_name
);
426 list
= emalloc(sizeof(*list
) * len
);
429 for (o
= s
->value
->u
.objectidentifiervalue
; o
!= NULL
; o
= o
->next
)
432 fprintf (headerfile
, "/* OBJECT IDENTIFIER %s ::= { ", s
->name
);
433 for (i
= len
; i
> 0; i
--) {
435 fprintf(headerfile
, "%s(%d) ",
436 o
->label
? o
->label
: "label-less", o
->value
);
439 fprintf (codefile
, "static unsigned oid_%s_variable_num[%d] = {",
441 for (i
= len
; i
> 0; i
--) {
442 fprintf(codefile
, "%d%s ", list
[i
- 1]->value
, i
> 1 ? "," : "");
444 fprintf(codefile
, "};\n");
446 fprintf (codefile
, "const heim_oid asn1_oid_%s = "
447 "{ %d, oid_%s_variable_num };\n\n",
448 s
->gen_name
, len
, s
->gen_name
);
454 gen_upper
= strdup(s
->gen_name
);
455 len
= strlen(gen_upper
);
456 for (i
= 0; i
< len
; i
++)
457 gen_upper
[i
] = toupper((int)s
->gen_name
[i
]);
459 fprintf (headerfile
, "} */\n");
461 "extern ASN1EXP const heim_oid asn1_oid_%s;\n"
462 "#define ASN1_OID_%s (&asn1_oid_%s)\n\n",
480 is_primitive_type(int type
)
488 case TGeneralizedTime
:
494 case TPrintableString
:
497 case TUniversalString
:
510 fprintf(headerfile
, " ");
514 last_member_p(struct member
*m
)
516 struct member
*n
= ASN1_TAILQ_NEXT(m
, members
);
519 if (n
->ellipsis
&& ASN1_TAILQ_NEXT(n
, members
) == NULL
)
524 static struct member
*
525 have_ellipsis(Type
*t
)
528 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
536 define_asn1 (int level
, Type
*t
)
540 fprintf (headerfile
, "%s", t
->symbol
->name
);
543 if(t
->members
== NULL
) {
544 fprintf (headerfile
, "INTEGER");
546 fprintf (headerfile
, " (%d..%d)",
547 t
->range
->min
, t
->range
->max
);
550 fprintf (headerfile
, "INTEGER {\n");
551 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
553 fprintf(headerfile
, "%s(%d)%s\n", m
->gen_name
, m
->val
,
557 fprintf (headerfile
, "}");
561 fprintf (headerfile
, "BOOLEAN");
564 fprintf (headerfile
, "OCTET STRING");
571 if(t
->type
== TBitString
)
572 fprintf (headerfile
, "BIT STRING {\n");
574 fprintf (headerfile
, "ENUMERATED {\n");
575 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
577 fprintf (headerfile
, "%s(%d)%s\n", m
->name
, m
->val
,
581 fprintf (headerfile
, "}");
590 if(t
->type
== TChoice
)
591 fprintf(headerfile
, "CHOICE {\n");
592 else if(t
->type
== TSet
)
593 fprintf(headerfile
, "SET {\n");
595 fprintf(headerfile
, "SEQUENCE {\n");
596 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
597 if(strlen(m
->name
) > max_width
)
598 max_width
= strlen(m
->name
);
601 if(max_width
< 16) max_width
= 16;
602 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
603 int width
= max_width
;
606 fprintf (headerfile
, "...");
608 width
-= fprintf(headerfile
, "%s", m
->name
);
609 fprintf(headerfile
, "%*s", width
, "");
610 define_asn1(level
+ 1, m
->type
);
612 fprintf(headerfile
, " OPTIONAL");
615 fprintf (headerfile
, ",");
616 fprintf (headerfile
, "\n");
619 fprintf (headerfile
, "}");
623 fprintf (headerfile
, "SEQUENCE OF ");
624 define_asn1 (0, t
->subtype
);
627 fprintf (headerfile
, "SET OF ");
628 define_asn1 (0, t
->subtype
);
630 case TGeneralizedTime
:
631 fprintf (headerfile
, "GeneralizedTime");
634 fprintf (headerfile
, "GeneralString");
637 fprintf (headerfile
, "TeletexString");
640 const char *classnames
[] = { "UNIVERSAL ", "APPLICATION ",
641 "" /* CONTEXT */, "PRIVATE " };
642 if(t
->tag
.tagclass
!= ASN1_C_UNIV
)
643 fprintf (headerfile
, "[%s%d] ",
644 classnames
[t
->tag
.tagclass
],
646 if(t
->tag
.tagenv
== TE_IMPLICIT
)
647 fprintf (headerfile
, "IMPLICIT ");
648 define_asn1 (level
, t
->subtype
);
652 fprintf (headerfile
, "UTCTime");
656 fprintf (headerfile
, "UTF8String");
658 case TPrintableString
:
660 fprintf (headerfile
, "PrintableString");
664 fprintf (headerfile
, "IA5String");
668 fprintf (headerfile
, "BMPString");
670 case TUniversalString
:
672 fprintf (headerfile
, "UniversalString");
676 fprintf (headerfile
, "VisibleString");
680 fprintf(headerfile
, "OBJECT IDENTIFIER");
684 fprintf (headerfile
, "NULL");
692 getnewbasename(char **newbasename
, int typedefp
, const char *basename
, const char *name
)
695 *newbasename
= strdup(name
);
699 if (asprintf(newbasename
, "%s_%s", basename
, name
) < 0)
702 if (*newbasename
== NULL
)
707 define_type (int level
, const char *name
, const char *basename
, Type
*t
, int typedefp
, int preservep
)
709 char *newbasename
= NULL
;
714 fprintf (headerfile
, "%s %s;\n", t
->symbol
->gen_name
, name
);
720 fprintf (headerfile
, "enum %s {\n", typedefp
? name
: "");
721 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
723 fprintf(headerfile
, "%s = %d%s\n", m
->gen_name
, m
->val
,
726 fprintf (headerfile
, "} %s;\n", name
);
727 } else if (t
->range
== NULL
) {
728 fprintf (headerfile
, "heim_integer %s;\n", name
);
729 } else if (t
->range
->min
== INT_MIN
&& t
->range
->max
== INT_MAX
) {
730 fprintf (headerfile
, "int %s;\n", name
);
731 } else if (t
->range
->min
== 0 && t
->range
->max
== UINT_MAX
) {
732 fprintf (headerfile
, "unsigned int %s;\n", name
);
733 } else if (t
->range
->min
== 0 && t
->range
->max
== INT_MAX
) {
734 fprintf (headerfile
, "unsigned int %s;\n", name
);
736 errx(1, "%s: unsupported range %d -> %d",
737 name
, t
->range
->min
, t
->range
->max
);
741 fprintf (headerfile
, "int %s;\n", name
);
745 fprintf (headerfile
, "heim_octet_string %s;\n", name
);
750 struct range range
= { 0, INT_MAX
};
758 if(ASN1_TAILQ_EMPTY(t
->members
))
759 fprintf (headerfile
, "heim_bit_string %s;\n", name
);
762 getnewbasename(&newbasename
, typedefp
, basename
, name
);
764 fprintf (headerfile
, "struct %s {\n", newbasename
);
765 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
769 while (pos
< m
->val
) {
770 if (asprintf (&n
, "_unused%d:1", pos
) < 0 || n
== NULL
)
772 define_type (level
+ 1, n
, newbasename
, &i
, FALSE
, FALSE
);
778 if (asprintf (&n
, "%s:1", m
->gen_name
) < 0 || n
== NULL
)
780 define_type (level
+ 1, n
, newbasename
, &i
, FALSE
, FALSE
);
785 /* pad to 32 elements */
788 if (asprintf (&n
, "_unused%d:1", pos
) < 0 || n
== NULL
)
790 define_type (level
+ 1, n
, newbasename
, &i
, FALSE
, FALSE
);
796 fprintf (headerfile
, "} %s;\n\n", name
);
804 fprintf (headerfile
, "enum %s {\n", typedefp
? name
: "");
805 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
808 fprintf (headerfile
, "/* ... */\n");
810 fprintf (headerfile
, "%s = %d%s\n", m
->gen_name
, m
->val
,
814 fprintf (headerfile
, "} %s;\n\n", name
);
821 getnewbasename(&newbasename
, typedefp
, basename
, name
);
824 fprintf (headerfile
, "struct %s {\n", newbasename
);
825 if (t
->type
== TSequence
&& preservep
) {
827 fprintf(headerfile
, "heim_octet_string _save;\n");
829 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
832 } else if (m
->optional
) {
835 if (asprintf (&n
, "*%s", m
->gen_name
) < 0 || n
== NULL
)
837 define_type (level
+ 1, n
, newbasename
, m
->type
, FALSE
, FALSE
);
840 define_type (level
+ 1, m
->gen_name
, newbasename
, m
->type
, FALSE
, FALSE
);
843 fprintf (headerfile
, "} %s;\n", name
);
849 struct range range
= { 0, INT_MAX
};
851 getnewbasename(&newbasename
, typedefp
, basename
, name
);
859 fprintf (headerfile
, "struct %s {\n", newbasename
);
860 define_type (level
+ 1, "len", newbasename
, &i
, FALSE
, FALSE
);
861 define_type (level
+ 1, "*val", newbasename
, t
->subtype
, FALSE
, FALSE
);
863 fprintf (headerfile
, "} %s;\n", name
);
866 case TGeneralizedTime
:
868 fprintf (headerfile
, "time_t %s;\n", name
);
872 fprintf (headerfile
, "heim_general_string %s;\n", name
);
876 fprintf (headerfile
, "heim_general_string %s;\n", name
);
879 define_type (level
, name
, basename
, t
->subtype
, typedefp
, preservep
);
885 getnewbasename(&newbasename
, typedefp
, basename
, name
);
888 fprintf (headerfile
, "struct %s {\n", newbasename
);
891 fprintf(headerfile
, "heim_octet_string _save;\n");
894 fprintf (headerfile
, "enum {\n");
895 m
= have_ellipsis(t
);
898 fprintf (headerfile
, "%s = 0,\n", m
->label
);
901 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
904 fprintf (headerfile
, "/* ... */\n");
906 fprintf (headerfile
, "%s%s%s\n", m
->label
,
912 fprintf (headerfile
, "} element;\n");
914 fprintf (headerfile
, "union {\n");
915 ASN1_TAILQ_FOREACH(m
, t
->members
, members
) {
918 fprintf(headerfile
, "heim_octet_string asn1_ellipsis;\n");
919 } else if (m
->optional
) {
922 if (asprintf (&n
, "*%s", m
->gen_name
) < 0 || n
== NULL
)
924 define_type (level
+ 2, n
, newbasename
, m
->type
, FALSE
, FALSE
);
927 define_type (level
+ 2, m
->gen_name
, newbasename
, m
->type
, FALSE
, FALSE
);
930 fprintf (headerfile
, "} u;\n");
932 fprintf (headerfile
, "} %s;\n", name
);
937 fprintf (headerfile
, "time_t %s;\n", name
);
941 fprintf (headerfile
, "heim_utf8_string %s;\n", name
);
943 case TPrintableString
:
945 fprintf (headerfile
, "heim_printable_string %s;\n", name
);
949 fprintf (headerfile
, "heim_ia5_string %s;\n", name
);
953 fprintf (headerfile
, "heim_bmp_string %s;\n", name
);
955 case TUniversalString
:
957 fprintf (headerfile
, "heim_universal_string %s;\n", name
);
961 fprintf (headerfile
, "heim_visible_string %s;\n", name
);
965 fprintf (headerfile
, "heim_oid %s;\n", name
);
969 fprintf (headerfile
, "int %s;\n", name
);
979 generate_type_header (const Symbol
*s
)
981 int preservep
= preserve_type(s
->name
) ? TRUE
: FALSE
;
983 fprintf (headerfile
, "/*\n");
984 fprintf (headerfile
, "%s ::= ", s
->name
);
985 define_asn1 (0, s
->type
);
986 fprintf (headerfile
, "\n*/\n\n");
988 fprintf (headerfile
, "typedef ");
989 define_type (0, s
->gen_name
, s
->gen_name
, s
->type
, TRUE
, preservep
);
991 fprintf (headerfile
, "\n");
995 generate_type (const Symbol
*s
)
1001 generate_header_of_codefile(s
->gen_name
);
1003 generate_type_header (s
);
1006 generate_template(s
);
1008 if (template_flag
== 0 || is_template_compat(s
) == 0) {
1009 generate_type_encode (s
);
1010 generate_type_decode (s
);
1011 generate_type_free (s
);
1012 generate_type_length (s
);
1013 generate_type_copy (s
);
1015 generate_type_seq (s
);
1016 generate_glue (s
->type
, s
->gen_name
);
1018 /* generate prototypes */
1020 if (is_export(s
->name
)) {
1030 "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
1032 s
->gen_name
, s
->gen_name
);
1035 "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
1037 s
->gen_name
, s
->gen_name
);
1039 "%ssize_t ASN1CALL length_%s(const %s *);\n",
1041 s
->gen_name
, s
->gen_name
);
1043 "%sint ASN1CALL copy_%s (const %s *, %s *);\n",
1045 s
->gen_name
, s
->gen_name
, s
->gen_name
);
1047 "%svoid ASN1CALL free_%s (%s *);\n",
1049 s
->gen_name
, s
->gen_name
);
1053 if (!one_code_file
) {
1054 fprintf(codefile
, "\n\n");