2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2009 - 2010 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
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
37 * Currently we generate C source code defining constant arrays of structures
38 * containing a sort of a "byte-coded" template of an ASN.1 compiler to be
39 * interpreted at run-time.
44 #include <vis-extras.h>
46 static const char *symbol_name(const char *, const Type *);
47 static void generate_template_type(const char *, const char **, const char *, const char *, const char *,
48 Type *, int, int, int);
51 ttype_symbol(const char *basename, const Type *t)
53 return t->symbol->gen_name;
57 integer_symbol(const char *basename, const Type *t)
61 * XXX enum foo -- compute the size either from inspecting the members
62 * and applying the ABI's rules for enum size, OR infer the field
63 * size from a template by using the offsetof field. The latter is
67 else if (t->range == NULL)
68 return "heim_integer";
69 else if (t->range->min < 0 &&
70 (t->range->min < INT_MIN || t->range->max > INT_MAX))
72 else if (t->range->min < 0)
74 else if (t->range->max > UINT_MAX)
81 boolean_symbol(const char *basename, const Type *t)
88 octetstring_symbol(const char *basename, const Type *t)
90 return "heim_octet_string";
94 sequence_symbol(const char *basename, const Type *t)
100 time_symbol(const char *basename, const Type *t)
106 tag_symbol(const char *basename, const Type *t)
108 return symbol_name(basename, t->subtype);
112 generalstring_symbol(const char *basename, const Type *t)
114 return "heim_general_string";
118 printablestring_symbol(const char *basename, const Type *t)
120 return "heim_printable_string";
124 ia5string_symbol(const char *basename, const Type *t)
126 return "heim_ia5_string";
130 teletexstring_symbol(const char *basename, const Type *t)
132 return "heim_general_string";
136 visiblestring_symbol(const char *basename, const Type *t)
138 return "heim_visible_string";
142 utf8string_symbol(const char *basename, const Type *t)
144 return "heim_utf8_string";
148 bmpstring_symbol(const char *basename, const Type *t)
150 return "heim_bmp_string";
154 universalstring_symbol(const char *basename, const Type *t)
156 return "heim_universal_string";
160 oid_symbol(const char *basename, const Type *t)
166 bitstring_symbol(const char *basename, const Type *t)
170 return "heim_bit_string";
175 /* Keep this sorted by `type' so we can just index this by type */
178 const char *(*symbol_name)(const char *, const Type *);
181 { TBitString, bitstring_symbol, 0 },
182 { TBoolean, boolean_symbol, 0 },
183 { TChoice, sequence_symbol, 1 },
184 { TEnumerated, integer_symbol, 0 },
185 { TGeneralString, generalstring_symbol, 0 },
186 { TTeletexString, teletexstring_symbol, 0 },
187 { TGeneralizedTime, time_symbol, 0 },
188 { TIA5String, ia5string_symbol, 0 },
189 { TInteger, integer_symbol, 0 },
190 { TNull, integer_symbol, 1 },
191 { TOID, oid_symbol, 0 },
192 { TOctetString, octetstring_symbol, 0 },
193 { TPrintableString, printablestring_symbol, 0 },
194 { TSequence, sequence_symbol, 1 },
195 { TSequenceOf, tag_symbol, 1 },
196 { TSet, sequence_symbol, 1 },
197 { TSetOf, tag_symbol, 1 },
198 { TTag, tag_symbol, 1 },
199 { TType, ttype_symbol, 1 },
200 { TUTCTime, time_symbol, 0 },
201 { TUTF8String, utf8string_symbol, 0 },
202 { TBMPString, bmpstring_symbol, 0 },
203 { TUniversalString, universalstring_symbol, 0 },
204 { TVisibleString, visiblestring_symbol, 0 },
217 is_supported_type_p(const Type *t)
219 return t->type >= 0 && t->type <= TVisibleString &&
220 types[t->type].type == t->type;
224 is_template_compat (const Symbol *s)
226 return is_supported_type_p(s->type);
230 symbol_name(const char *basename, const Type *t)
232 if (t->type >= 0 && t->type <= TVisibleString &&
233 types[t->type].type == t->type)
234 return (types[t->type].symbol_name)(basename, t);
235 if (t->type >= 0 && t->type <= TVisibleString)
236 errx(1, "types[] is not sorted");
237 errx(1, "unknown der type: %d\n", t->type);
243 partial_offset(const char *basetype, const char *name, int need_offset, int isstruct)
246 if (name == NULL || need_offset == 0)
248 if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL)
258 HEIM_TAILQ_ENTRY(template) members;
261 HEIM_TAILQ_HEAD(templatehead, template);
266 struct templatehead template;
267 HEIM_TAILQ_ENTRY(tlist) tmembers;
270 HEIM_TAILQ_HEAD(tlisthead, tlist);
272 static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
273 static struct template *
274 add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
275 static int tlist_cmp(const struct tlist *, const struct tlist *);
277 static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...)
278 __attribute__ ((__format__ (__printf__, 4, 5)));
279 static void add_line_string(struct templatehead *, const char *, const char *, const char *, ...)
280 __attribute__ ((__format__ (__printf__, 4, 5)));
281 static void add_line_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...)
282 __attribute__ ((__format__ (__printf__, 4, 5)));
285 static struct tlisthead tlistmaster = HEIM_TAILQ_HEAD_INITIALIZER(tlistmaster);
286 static unsigned long numdups = 0;
288 static struct tlist *
289 tlist_new(const char *name)
291 struct tlist *tl = calloc(1, sizeof(*tl));
292 tl->name = strdup(name);
293 HEIM_TAILQ_INIT(&tl->template);
298 tlist_header(struct tlist *t, const char *fmt, ...)
302 if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL)
308 tlist_count(struct tlist *tl)
310 unsigned int count = 0;
313 HEIM_TAILQ_FOREACH(q, &tl->template, members) {
320 tlist_add(struct tlist *tl)
322 HEIM_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers);
326 tlist_print(struct tlist *tl)
330 FILE *f = get_code_file();
332 fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name);
333 fprintf(f, "/* 0 */ %s,\n", tl->header);
334 HEIM_TAILQ_FOREACH(q, &tl->template, members) {
335 int last = (HEIM_TAILQ_LAST(&tl->template, templatehead) == q);
336 fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
341 static struct tlist *
342 tlist_find_by_name(const char *name)
345 HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
346 if (strcmp(ql->name, name) == 0)
353 tlist_cmp_name(const char *tname, const char *qname)
355 struct tlist *tl = tlist_find_by_name(tname);
356 struct tlist *ql = tlist_find_by_name(qname);
361 return tlist_cmp(tl, ql);
365 tlist_cmp(const struct tlist *tl, const struct tlist *ql)
368 struct template *t, *q;
372 ret = strcmp(tl->header, ql->header);
373 if (ret != 0) return ret;
375 q = HEIM_TAILQ_FIRST(&ql->template);
376 HEIM_TAILQ_FOREACH(t, &tl->template, members) {
377 if (q == NULL) return 1;
379 if (t->ptr == NULL || q->ptr == NULL) {
380 ret = strcmp(t->line, q->line);
381 if (ret != 0) return ret;
383 ret = strcmp(t->tt, q->tt);
384 if (ret != 0) return ret;
386 ret = strcmp(t->offset, q->offset);
387 if (ret != 0) return ret;
389 if ((ret = strcmp(t->ptr, q->ptr)) != 0 ||
390 (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0)
393 q = HEIM_TAILQ_NEXT(q, members);
395 if (q != NULL) return -1;
401 tlist_find_dup(const struct tlist *tl)
405 HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
406 if (tlist_cmp(ql, tl) == 0) {
416 * Add an entry to a template.
419 static struct template *
420 add_line(struct templatehead *t, const char *fmt, ...)
422 struct template *q = calloc(1, sizeof(*q));
425 if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL)
428 HEIM_TAILQ_INSERT_TAIL(t, q, members);
433 * Add an entry to a template, with the pointer field being a symbol name of a
434 * template (i.e., an array, which decays to a pointer as usual in C).
437 add_line_pointer(struct templatehead *t,
448 if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
452 q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr);
454 q->offset = strdup(offset);
455 q->ptr = strdup(ptr);
459 * Add an entry to a template where the pointer firled is a string literal.
462 add_line_string(struct templatehead *t,
473 if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
477 q = add_line(t, "{ %s, %s, \"%s\" }", tt, offset, str);
479 q->offset = strdup(offset);
480 q->ptr = strdup(str);
484 * Add an entry to a template, with the pointer field being a reference to
485 * named object of a type other than a template or other array type.
488 add_line_pointer_reference(struct templatehead *t,
499 if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
503 q = add_line(t, "{ %s, %s, (const void *)&asn1_%s }", tt, offset, ptr);
505 q->offset = strdup(offset);
506 q->ptr = strdup(ptr);
510 use_extern(const Symbol *s)
518 is_struct(const Type *t, int isstruct)
520 if (t->type == TType)
522 if (t->type == TSequence || t->type == TSet || t->type == TChoice)
525 return is_struct(t->subtype, isstruct);
527 if (t->type >= 0 && t->type <= TVisibleString &&
528 types[t->type].type == t->type) {
529 if (types[t->type].is_struct == 0)
533 if (t->type >= 0 && t->type <= TVisibleString)
534 errx(1, "types[] is not sorted");
535 errx(1, "unknown der type: %d\n", t->type);
540 compact_tag(const Type *t)
542 while (t->type == TTag)
548 defval(struct templatehead *temp, Member *m)
550 switch (m->defval->type) {
552 add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)%u }",
553 m->defval->u.booleanvalue);
556 add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)0 }");
559 const char *dv = "A1_DV_INTEGER";
565 if (t->type == TInteger && t->members)
567 if (t->type == TEnumerated)
571 else if (t->symbol && t->symbol->type)
574 errx(1, "DEFAULT values for unconstrained INTEGER members not supported");
578 dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */
579 else if (t->range->min < 0 &&
580 (t->range->min < INT_MIN || t->range->max > INT_MAX))
581 dv = "A1_DV_INTEGER64";
582 else if (t->range->min < 0)
583 dv = "A1_DV_INTEGER32";
584 else if (t->range->max > UINT_MAX)
585 dv = "A1_DV_INTEGER64";
587 dv = "A1_DV_INTEGER32";
588 add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)%llu }",
589 dv, (long long)m->defval->u.integervalue);
595 if (rk_strasvis("ed, m->defval->u.stringvalue,
596 VIS_CSTYLE | VIS_NL, "\"") < 0)
597 err(1, "Could not quote a string");
598 add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)\"%s\" }",
603 case objectidentifiervalue: {
605 size_t sz = sizeof("{ }");
609 for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) {
610 if ((len = snprintf(0, 0, " %d", o->value)) < 0)
611 err(1, "Could not format integer");
615 if ((p = s = malloc(sz)) == NULL)
616 err(1, "Could not allocate string");
618 len = snprintf(p, sz, "{");
621 for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) {
622 if ((len = snprintf(p, sz, " %d", o->value)) < 0 || len > sz - 1)
623 err(1, "Could not format integer");
627 len = snprintf(p, sz, " }");
631 add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)\"%s\" }", s);
640 objid_cmp(struct objid *oida, struct objid *oidb)
643 size_t ai, bi, alen, blen;
649 * Our OID values are backwards here. Comparing them is hard.
652 for (p = oida, alen = 0;
653 p && alen < sizeof(avals)/sizeof(avals[0]);
655 avals[alen++] = p->value;
656 for (p = oidb, blen = 0;
657 p && blen < sizeof(bvals)/sizeof(bvals[0]);
659 bvals[blen++] = p->value;
660 if (alen >= sizeof(avals)/sizeof(avals[0]) ||
661 blen >= sizeof(bvals)/sizeof(bvals[0]))
662 err(1, "OIDs with more components than %llu not supported",
663 (unsigned long long)sizeof(avals)/sizeof(avals[0]));
665 for (ai = 0, bi = 0; ai < alen && bi < blen;)
666 if ((c = avals[(alen-1)-(ai++)] - bvals[(blen-1)-(bi++)]))
669 if (ai == alen && bi == blen)
677 object_cmp(const void *va, const void *vb)
679 const IOSObject *oa = *(const IOSObject * const *)va;
680 const IOSObject *ob = *(const IOSObject * const *)vb;
682 switch (oa->typeidf->value->type) {
684 return oa->typeidf->value->u.booleanvalue -
685 ob->typeidf->value->u.booleanvalue;
689 return oa->typeidf->value->u.integervalue -
690 ob->typeidf->value->u.integervalue;
692 return strcmp(oa->typeidf->value->u.stringvalue,
693 ob->typeidf->value->u.stringvalue);
694 case objectidentifiervalue: {
695 return objid_cmp(oa->typeidf->value->u.objectidentifiervalue,
696 ob->typeidf->value->u.objectidentifiervalue);
705 sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */
706 Field *typeidfield, /* Field to sort by */
707 IOSObject ***objectsp, /* Output: array of objects */
708 size_t *nobjsp) /* Output: count of objects */
714 HEIM_TAILQ_FOREACH(o, os->objects, objects) {
715 ObjectField *typeidobjf = NULL;
718 HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
719 if (strcmp(of->name, typeidfield->name) == 0)
723 warnx("Ignoring incomplete object specification of %s "
724 "(missing type ID field)",
725 o->symbol ? o->symbol->name : "<unknown>");
728 o->typeidf = typeidobjf;
733 if ((objects = calloc(nobjs, sizeof(*objects))) == NULL)
734 err(1, "Out of memory");
738 HEIM_TAILQ_FOREACH(o, os->objects, objects) {
739 ObjectField *typeidobjf = NULL;
742 HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
743 if (strcmp(of->name, typeidfield->name) == 0)
749 qsort(objects, nobjs, sizeof(*objects), object_cmp);
753 template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield)
760 if (os->symbol->emitted_template)
763 sort_object_set(os, typeidfield, &objects, &nobjs);
765 tl = tlist_new(os->symbol->name);
766 add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", os->symbol->name);
767 for (i = 0; i < nobjs; i++) {
768 ObjectField *typeidobjf = NULL, *opentypeobjf = NULL;
774 HEIM_TAILQ_FOREACH(of, o->objfields, objfields) {
775 if (strcmp(of->name, typeidfield->name) == 0)
777 else if (strcmp(of->name, opentypefield->name) == 0)
781 continue; /* We've warned about this one already when sorting */
783 warnx("Ignoring incomplete object specification of %s "
784 "(missing open type field)",
785 o->symbol ? o->symbol->name : "<unknown>");
789 add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", o->symbol->name);
791 * Some of this logic could stand to move into sanity checks of object
792 * definitions in asn1parse.y.
794 switch (typeidobjf->value->type) {
796 add_line(&tl->template,
797 "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)%lld }",
798 (long long)typeidobjf->value->u.integervalue);
800 case objectidentifiervalue:
801 if (asprintf(&s, "oid_%s",
802 typeidobjf->value->s->gen_name) == -1 || !s)
803 err(1, "Out of memory");
804 add_line_pointer_reference(&tl->template, s, "0", "A1_OP_OPENTYPE_ID");
809 errx(1, "Only integer and OID types supported "
810 "for open type type-ID fields");
813 if (asprintf(&s, "sizeof(%s)",
814 opentypeobjf->type->symbol->gen_name) == -1 || !s)
815 err(1, "Out of memory");
816 add_line_pointer_reference(&tl->template,
817 opentypeobjf->type->symbol->gen_name, s,
823 tlist_header(tl, "{ 0, 0, ((void *)%lu) }", nobjs);
826 os->symbol->emitted_template = 1;
830 template_open_type(struct templatehead *temp,
831 const char *basetype,
836 Field *opentypefield,
838 int is_array_of_open_type)
842 if (typeididx >= 1<<10 || opentypeidx >= 1<<10)
843 errx(1, "SET/SEQUENCE with too many members (%s)", basetype);
845 if (asprintf(&s, "offsetof(%s, _ioschoice_%s)",
846 basetype, m->gen_name) == -1 || !s)
847 err(1, "Out of memory");
849 template_object_set(t->actual_parameter, typeidfield, opentypefield);
850 add_line_pointer(temp, t->actual_parameter->symbol->gen_name, s,
852 * We always sort object sets for now as we can't import
853 * values yet, so they must all be known.
855 "A1_OP_OPENTYPE_OBJSET | A1_OS_IS_SORTED |%s | (%llu << 10) | %llu",
856 is_array_of_open_type ? "A1_OS_OT_IS_ARRAY" : "0",
857 (unsigned long long)opentypeidx,
858 (unsigned long long)typeididx);
863 template_names(struct templatehead *temp, const char *basetype, const Type *t)
867 add_line_string(temp, basetype, "0", "A1_OP_NAME");
868 HEIM_TAILQ_FOREACH(m, t->members, members) {
869 add_line_string(temp, m->name, "0", "A1_OP_NAME");
874 template_members(struct templatehead *temp,
875 const char *basetype,
884 char *poffset = NULL;
886 if (optional && t->type != TTag && t->type != TType)
887 errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name);
889 poffset = partial_offset(basetype, name, need_offset, isstruct);
893 if (use_extern(t->symbol)) {
894 add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s%s, %s, &asn1_extern_%s}",
895 optional ? "|A1_FLAG_OPTIONAL" : "",
896 defaulted ? "|A1_FLAG_DEFAULT" : "",
897 implicit ? "|A1_FLAG_IMPLICIT" : "",
898 poffset, t->symbol->gen_name);
900 add_line_pointer(temp, t->symbol->gen_name, poffset,
902 optional ? "|A1_FLAG_OPTIONAL" : "",
903 defaulted ? "|A1_FLAG_DEFAULT" : "",
904 implicit ? "|A1_FLAG_IMPLICIT" : "");
910 char *varname = NULL;
915 else if (t->range == NULL)
916 itype = "HEIM_INTEGER";
917 else if (t->range->min < 0 &&
918 (t->range->min < INT_MIN || t->range->max > INT_MAX))
920 else if (t->range->min < 0)
922 else if (t->range->max > UINT_MAX)
923 itype = "UNSIGNED64";
928 * If `t->members' then we should generate a template for those
931 * We don't know the name of this field, and the type may not have a
932 * name. If it has no name, we should generate a name for it, and if
933 * it does have a name, use it, to name a template for its members.
935 * Then we could use that in _asn1_print() to pretty-print values of
938 if (t->members && t->symbol) {
943 if (asprintf(&varname, "%s_enum_names", t->symbol->gen_name) == -1 ||
945 err(1, "Out of memory");
947 tl = tlist_new(varname);
949 * XXX We're going to assume that t->members is sorted in
950 * numerically ascending order in the module source. We should
951 * really sort it here.
953 HEIM_TAILQ_FOREACH(m, t->members, members) {
954 if (m->val > UINT32_MAX)
955 continue; /* Wouldn't fit in the offset field */
956 add_line(&tl->template,
957 "{ A1_OP_NAME, %d, \"%s\" }", m->val, m->name);
960 tlist_header(tl, "{ 0, 0, ((void *)%lu) }", nmemb);
961 /* XXX Accidentally O(N^2)? */
962 if (!tlist_find_dup(tl)) {
966 add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, asn1_%s }", itype, poffset, varname);
968 add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset);
973 add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset);
976 add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset);
978 case TPrintableString:
979 add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset);
982 add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset);
985 add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset);
988 add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset);
990 case TUniversalString:
991 add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset);
994 add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset);
997 add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset);
999 case TGeneralizedTime:
1000 add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset);
1003 add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset);
1006 add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset);
1009 add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset);
1014 struct templatehead template;
1017 size_t count = 0, i;
1019 FILE *f = get_code_file();
1020 static unsigned long bmember_counter = 0;
1022 HEIM_TAILQ_INIT(&template);
1024 if (HEIM_TAILQ_EMPTY(t->members)) {
1025 add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset);
1029 if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL)
1033 HEIM_TAILQ_FOREACH(m, t->members, members) {
1034 add_line(&template, "{ 0, %d, \"%s\" }", m->val, m->gen_name);
1037 HEIM_TAILQ_FOREACH(q, &template, members) {
1041 fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname);
1042 fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)%lu) },\n",
1043 rfc1510_bitstring ? "|A1_HBF_RFC1510" : "",
1044 basetype, (unsigned long)count);
1046 HEIM_TAILQ_FOREACH(q, &template, members) {
1047 int last = (HEIM_TAILQ_LAST(&template, templatehead) == q);
1048 fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
1052 add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname);
1059 Member *opentypemember = NULL;
1060 Member *typeidmember = NULL;
1061 Field *opentypefield = NULL;
1062 Field *typeidfield = NULL;
1064 size_t i = 0, typeididx = 0, opentypeidx = 0;
1065 int is_array_of_open_type = 0;
1069 if (isstruct && t->actual_parameter)
1070 get_open_type_defn_fields(t, &typeidmember, &opentypemember,
1071 &typeidfield, &opentypefield,
1072 &is_array_of_open_type);
1074 fprintf(get_code_file(), "/* tset: members isstruct: %d */\n", isstruct);
1076 HEIM_TAILQ_FOREACH(m, t->members, members) {
1077 char *newbasename = NULL;
1082 if (typeidmember == m) typeididx = i;
1083 if (opentypemember == m) opentypeidx = i;
1086 if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
1089 newbasename = strdup(basetype);
1090 if (newbasename == NULL)
1096 template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1);
1102 if (isstruct && t->actual_parameter)
1103 template_open_type(temp, basetype, t, typeididx, opentypeidx,
1104 typeidfield, opentypefield, opentypemember,
1105 is_array_of_open_type);
1107 if (decorate_type(basetype, &ft, &fn, &deco_opt)) {
1110 poffset2 = partial_offset(basetype, fn, 1, isstruct);
1111 add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s",
1112 deco_opt ? "|A1_FLAG_OPTIONAL" : "");
1119 template_names(temp, basetype, t);
1123 Member *opentypemember = NULL;
1124 Member *typeidmember = NULL;
1125 Field *opentypefield = NULL;
1126 Field *typeidfield = NULL;
1128 size_t i = 0, typeididx = 0, opentypeidx = 0;
1129 int is_array_of_open_type = 0;
1133 if (isstruct && t->actual_parameter)
1134 get_open_type_defn_fields(t, &typeidmember, &opentypemember,
1135 &typeidfield, &opentypefield,
1136 &is_array_of_open_type);
1138 fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct);
1140 HEIM_TAILQ_FOREACH(m, t->members, members) {
1141 char *newbasename = NULL;
1146 if (typeidmember == m) typeididx = i;
1147 if (opentypemember == m) opentypeidx = i;
1150 if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
1153 newbasename = strdup(basetype);
1154 if (newbasename == NULL)
1160 template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1);
1166 if (isstruct && t->actual_parameter)
1167 template_open_type(temp, basetype, t, typeididx, opentypeidx,
1168 typeidfield, opentypefield, opentypemember,
1169 is_array_of_open_type);
1171 if (decorate_type(basetype, &ft, &fn, &deco_opt)) {
1174 poffset2 = partial_offset(basetype, fn, 1, isstruct);
1175 add_line_pointer(temp, ft, poffset2, "A1_OP_TYPE_DECORATE %s",
1176 deco_opt ? "|A1_FLAG_OPTIONAL" : "");
1183 template_names(temp, basetype, t);
1187 char *tname = NULL, *elname = NULL;
1188 const char *sename, *dupname;
1189 int subtype_is_struct = is_struct(t->subtype, isstruct);
1190 static unsigned long tag_counter = 0;
1191 int tagimplicit = 0;
1192 int prim = !(t->tag.tagclass != ASN1_C_UNIV &&
1193 t->tag.tagenv == TE_EXPLICIT) &&
1194 is_primitive_type(t->subtype);
1196 if (t->tag.tagenv == TE_IMPLICIT) {
1197 Type *t2 = t->subtype ? t->subtype : t->symbol->type;
1199 while (t2->type == TType && (t2->subtype || t2->symbol->type))
1200 t2 = t2->subtype ? t2->subtype : t2->symbol->type;
1201 if (t2->type != TChoice)
1205 fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp");
1207 if (subtype_is_struct)
1210 sename = symbol_name(basetype, t->subtype);
1212 if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL)
1216 if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL)
1219 generate_template_type(elname, &dupname, NULL, sename, name,
1220 t->subtype, 0, subtype_is_struct, 0);
1222 add_line_pointer(temp, dupname, poffset,
1223 "A1_TAG_T(%s,%s,%s)%s%s%s",
1224 classname(t->tag.tagclass),
1225 prim ? "PRIM" : "CONS",
1226 valuename(t->tag.tagclass, t->tag.tagvalue),
1227 optional ? "|A1_FLAG_OPTIONAL" : "",
1228 defaulted ? "|A1_FLAG_DEFAULT" : "",
1229 tagimplicit ? "|A1_FLAG_IMPLICIT" : "");
1238 const char *type = NULL, *tname, *dupname;
1239 char *sename = NULL, *elname = NULL;
1240 int subtype_is_struct = is_struct(t->subtype, 0);
1241 static unsigned long seof_counter = 0;
1243 if (name && subtype_is_struct) {
1244 tname = "seofTstruct";
1245 if (asprintf(&sename, "%s_%s_val", basetype, name) < 0)
1247 } else if (subtype_is_struct) {
1248 tname = "seofTstruct";
1249 if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0)
1255 tname = "seofTstruct";
1256 sename = strdup(symbol_name(basetype, t->subtype));
1261 if (t->type == TSetOf) type = "A1_OP_SETOF";
1262 else if (t->type == TSequenceOf) type = "A1_OP_SEQOF";
1265 if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL)
1268 generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype,
1269 0, subtype_is_struct, need_offset);
1271 add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname);
1276 struct templatehead template;
1278 size_t count = 0, i;
1280 FILE *f = get_code_file();
1284 static unsigned long choice_counter = 0;
1286 HEIM_TAILQ_INIT(&template);
1288 if (asprintf(&tname, "asn1_choice_%s_%s%lu",
1289 basetype, name ? name : "", choice_counter++) < 0 || tname == NULL)
1292 HEIM_TAILQ_FOREACH(m, t->members, members) {
1293 const char *dupname;
1294 char *elname = NULL;
1295 char *newbasename = NULL;
1296 int subtype_is_struct;
1303 subtype_is_struct = is_struct(m->type, 0);
1305 if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL)
1308 if (subtype_is_struct) {
1309 if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0)
1312 newbasename = strdup(basetype);
1314 if (newbasename == NULL)
1318 generate_template_type(elname, &dupname, NULL,
1319 symbol_name(newbasename, m->type),
1320 NULL, m->type, 0, subtype_is_struct, 1);
1322 add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }",
1323 m->label, isstruct ? "struct " : "",
1324 basetype, m->gen_name,
1331 HEIM_TAILQ_FOREACH(m, t->members, members) {
1332 add_line(&template, "{ 0, 0, \"%s\" }", m->name);
1337 if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL)
1341 HEIM_TAILQ_FOREACH(q, &template, members) {
1345 fprintf(f, "static const struct asn1_template %s[] = {\n", tname);
1346 fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)%lu) },\n",
1347 e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count);
1349 HEIM_TAILQ_FOREACH(q, &template, members) {
1350 int last = (HEIM_TAILQ_LAST(&template, templatehead) == q);
1351 fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
1355 add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname);
1369 gen_extern_stubs(FILE *f, const char *name)
1372 "static const struct asn1_type_func asn1_extern_%s = {\n"
1373 "\t(asn1_type_encode)encode_%s,\n"
1374 "\t(asn1_type_decode)decode_%s,\n"
1375 "\t(asn1_type_length)length_%s,\n"
1376 "\t(asn1_type_copy)copy_%s,\n"
1377 "\t(asn1_type_release)free_%s,\n"
1378 "\t(asn1_type_print)print_%s,\n"
1381 name, name, name, name,
1382 name, name, name, name);
1386 gen_template_import(const Symbol *s)
1388 FILE *f = get_code_file();
1390 if (template_flag == 0)
1393 gen_extern_stubs(f, s->gen_name);
1397 generate_template_type_forward(const char *name)
1399 fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", name);
1403 generate_template_objectset_forwards(const Symbol *s)
1407 fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n",
1412 generate_template_type(const char *varname,
1413 const char **dupname,
1414 const char *symname,
1415 const char *basetype,
1425 int have_ellipsis = 0;
1429 tl = tlist_new(varname);
1431 if (type->type == TTag && type->tag.tagenv == TE_IMPLICIT) {
1432 Type *t = type->subtype ? type->subtype : type->symbol->type;
1434 while (t->type == TType && (t->subtype || t->symbol->type))
1435 t = t->subtype ? t->subtype : t->symbol->type;
1436 if (t->type != TChoice)
1437 implicit = (type->tag.tagenv == TE_IMPLICIT);
1440 template_members(&tl->template, basetype, name, type, optional, 0,
1441 implicit, isstruct, need_offset);
1443 /* if its a sequence or set type, check if there is a ellipsis */
1444 if (type->type == TSequence || type->type == TSet) {
1446 HEIM_TAILQ_FOREACH(m, type->members, members) {
1454 n = asprintf(&szt, "struct %s_%s", basetype, name);
1456 n = asprintf(&szt, "struct %s", basetype);
1458 n = asprintf(&szt, "%s", basetype);
1459 if (n < 0 || szt == NULL)
1462 if (HEIM_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull)
1463 errx(1, "Tag %s...%s with no content ?", basetype, name ? name : "");
1465 fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name);
1467 tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)%lu) }",
1468 (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "",
1469 have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl));
1473 /* XXX Accidentally O(N^2)? */
1474 d = tlist_find_dup(tl);
1477 if (strcmp(d, tl->name) == 0)
1478 errx(1, "found dup of ourself: %s", d);
1482 *dupname = tl->name;
1490 generate_template(const Symbol *s)
1492 FILE *f = get_code_file();
1493 const char *dupname;
1495 if (use_extern(s)) {
1496 gen_extern_stubs(f, s->gen_name);
1500 generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1);
1505 "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n"
1507 " return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n"
1513 support_ber ? "A1_PF_ALLOW_BER" : "0");
1518 "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n"
1520 " return _asn1_encode%s(asn1_%s, p, len, data, size);\n"
1531 "length_%s(const %s *data)\n"
1533 " return _asn1_length%s(asn1_%s, data);\n"
1545 "free_%s(%s *data)\n"
1547 " _asn1_free_top(asn1_%s, data);\n"
1557 "copy_%s(const %s *from, %s *to)\n"
1559 " return _asn1_copy_top(asn1_%s, from, to);\n"
1570 "print_%s(const %s *data, int flags)\n"
1572 " return _asn1_print_top(asn1_%s, flags, data);\n"