diff options
Diffstat (limited to 'third_party/heimdal/lib/asn1/gen_template.c')
-rw-r--r-- | third_party/heimdal/lib/asn1/gen_template.c | 1675 |
1 files changed, 1675 insertions, 0 deletions
diff --git a/third_party/heimdal/lib/asn1/gen_template.c b/third_party/heimdal/lib/asn1/gen_template.c new file mode 100644 index 0000000..ad25fcf --- /dev/null +++ b/third_party/heimdal/lib/asn1/gen_template.c @@ -0,0 +1,1675 @@ +/* + * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Currently we generate C source code defining constant arrays of structures + * containing a sort of a "byte-coded" template of an ASN.1 compiler to be + * interpreted at run-time. + */ + +#include "gen_locl.h" +#include <vis.h> +#include <vis-extras.h> + +static const char *symbol_name(const char *, const Type *); +static void generate_template_type(const char *, const char **, const char *, const char *, const char *, + Type *, int, int, int); + +static const char * +ttype_symbol(const char *basename, const Type *t) +{ + return t->symbol->gen_name; +} + +static const char * +integer_symbol(const char *basename, const Type *t) +{ + if (t->members) + /* + * XXX enum foo -- compute the size either from inspecting the members + * and applying the ABI's rules for enum size, OR infer the field + * size from a template by using the offsetof field. The latter is + * hard to do though. + */ + return "int"; + else if (t->range == NULL) + return "heim_integer"; + else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + return "int64_t"; + else if (t->range->min < 0) + return "int"; + else if (t->range->max > UINT_MAX) + return "uint64_t"; + else + return "unsigned"; +} + +static const char * +boolean_symbol(const char *basename, const Type *t) +{ + return "int"; +} + + +static const char * +octetstring_symbol(const char *basename, const Type *t) +{ + return "heim_octet_string"; +} + +static const char * +sequence_symbol(const char *basename, const Type *t) +{ + return basename; +} + +static const char * +time_symbol(const char *basename, const Type *t) +{ + return "time_t"; +} + +static const char * +tag_symbol(const char *basename, const Type *t) +{ + return symbol_name(basename, t->subtype); +} + +static const char * +generalstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +printablestring_symbol(const char *basename, const Type *t) +{ + return "heim_printable_string"; +} + +static const char * +ia5string_symbol(const char *basename, const Type *t) +{ + return "heim_ia5_string"; +} + +static const char * +teletexstring_symbol(const char *basename, const Type *t) +{ + return "heim_general_string"; +} + +static const char * +visiblestring_symbol(const char *basename, const Type *t) +{ + return "heim_visible_string"; +} + +static const char * +utf8string_symbol(const char *basename, const Type *t) +{ + return "heim_utf8_string"; +} + +static const char * +bmpstring_symbol(const char *basename, const Type *t) +{ + return "heim_bmp_string"; +} + +static const char * +universalstring_symbol(const char *basename, const Type *t) +{ + return "heim_universal_string"; +} + +static const char * +oid_symbol(const char *basename, const Type *t) +{ + return "heim_oid"; +} + +static const char * +bitstring_symbol(const char *basename, const Type *t) +{ + if (t->members) + return basename; + return "heim_bit_string"; +} + + + +/* Keep this sorted by `type' so we can just index this by type */ +const struct { + enum typetype type; + const char *(*symbol_name)(const char *, const Type *); + int is_struct; +} types[] = { + { TBitString, bitstring_symbol, 0 }, + { TBoolean, boolean_symbol, 0 }, + { TChoice, sequence_symbol, 1 }, + { TEnumerated, integer_symbol, 0 }, + { TGeneralString, generalstring_symbol, 0 }, + { TTeletexString, teletexstring_symbol, 0 }, + { TGeneralizedTime, time_symbol, 0 }, + { TIA5String, ia5string_symbol, 0 }, + { TInteger, integer_symbol, 0 }, + { TNull, integer_symbol, 1 }, + { TOID, oid_symbol, 0 }, + { TOctetString, octetstring_symbol, 0 }, + { TPrintableString, printablestring_symbol, 0 }, + { TSequence, sequence_symbol, 1 }, + { TSequenceOf, tag_symbol, 1 }, + { TSet, sequence_symbol, 1 }, + { TSetOf, tag_symbol, 1 }, + { TTag, tag_symbol, 1 }, + { TType, ttype_symbol, 1 }, + { TUTCTime, time_symbol, 0 }, + { TUTF8String, utf8string_symbol, 0 }, + { TBMPString, bmpstring_symbol, 0 }, + { TUniversalString, universalstring_symbol, 0 }, + { TVisibleString, visiblestring_symbol, 0 }, +}; + +static FILE * +get_code_file(void) +{ + if (!one_code_file) + return templatefile; + return codefile; +} + + +static int +is_supported_type_p(const Type *t) +{ + return t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type; +} + +int +is_template_compat (const Symbol *s) +{ + return is_supported_type_p(s->type); +} + +static const char * +symbol_name(const char *basename, const Type *t) +{ + if (t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type) + return (types[t->type].symbol_name)(basename, t); + if (t->type >= 0 && t->type <= TVisibleString) + errx(1, "types[] is not sorted"); + errx(1, "unknown der type: %d\n", t->type); + return NULL; +} + + +static char * +partial_offset(const char *basetype, const char *name, int need_offset, int isstruct) +{ + char *str; + if (name == NULL || need_offset == 0) + return strdup("0"); + if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL) + errx(1, "malloc"); + return str; +} + +struct template { + char *line; + char *tt; + char *offset; + char *ptr; + HEIM_TAILQ_ENTRY(template) members; +}; + +HEIM_TAILQ_HEAD(templatehead, template); + +struct tlist { + char *name; + char *header; + struct templatehead template; + HEIM_TAILQ_ENTRY(tlist) tmembers; +}; + +HEIM_TAILQ_HEAD(tlisthead, tlist); + +static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static struct template * + add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3))); +static int tlist_cmp(const struct tlist *, const struct tlist *); + +static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +static void add_line_string(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); +static void add_line_pointer_reference(struct templatehead *, const char *, const char *, const char *, ...) + __attribute__ ((__format__ (__printf__, 4, 5))); + + +static struct tlisthead tlistmaster = HEIM_TAILQ_HEAD_INITIALIZER(tlistmaster); +static unsigned long numdups = 0; + +static struct tlist * +tlist_new(const char *name) +{ + struct tlist *tl = calloc(1, sizeof(*tl)); + tl->name = strdup(name); + HEIM_TAILQ_INIT(&tl->template); + return tl; +} + +static void +tlist_header(struct tlist *t, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL) + errx(1, "malloc"); + va_end(ap); +} + +static unsigned long +tlist_count(struct tlist *tl) +{ + unsigned int count = 0; + struct template *q; + + HEIM_TAILQ_FOREACH(q, &tl->template, members) { + count++; + } + return count; +} + +static void +tlist_add(struct tlist *tl) +{ + HEIM_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers); +} + +static void +tlist_print(struct tlist *tl) +{ + struct template *q; + unsigned int i = 1; + FILE *f = get_code_file(); + + fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name); + fprintf(f, "/* 0 */ %s,\n", tl->header); + HEIM_TAILQ_FOREACH(q, &tl->template, members) { + int last = (HEIM_TAILQ_LAST(&tl->template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); +} + +static struct tlist * +tlist_find_by_name(const char *name) +{ + struct tlist *ql; + HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (strcmp(ql->name, name) == 0) + return ql; + } + return NULL; +} + +static int +tlist_cmp_name(const char *tname, const char *qname) +{ + struct tlist *tl = tlist_find_by_name(tname); + struct tlist *ql = tlist_find_by_name(qname); + if (tl == NULL) + return 1; + if (ql == NULL) + return -1; + return tlist_cmp(tl, ql); +} + +static int +tlist_cmp(const struct tlist *tl, const struct tlist *ql) +{ + int ret; + struct template *t, *q; + + if (tl == ql) + return 0; + ret = strcmp(tl->header, ql->header); + if (ret != 0) return ret; + + q = HEIM_TAILQ_FIRST(&ql->template); + HEIM_TAILQ_FOREACH(t, &tl->template, members) { + if (q == NULL) return 1; + + if (t->ptr == NULL || q->ptr == NULL) { + ret = strcmp(t->line, q->line); + if (ret != 0) return ret; + } else { + ret = strcmp(t->tt, q->tt); + if (ret != 0) return ret; + + ret = strcmp(t->offset, q->offset); + if (ret != 0) return ret; + + if ((ret = strcmp(t->ptr, q->ptr)) != 0 || + (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0) + return ret; + } + q = HEIM_TAILQ_NEXT(q, members); + } + if (q != NULL) return -1; + return 0; +} + + +static const char * +tlist_find_dup(const struct tlist *tl) +{ + struct tlist *ql; + + HEIM_TAILQ_FOREACH(ql, &tlistmaster, tmembers) { + if (tlist_cmp(ql, tl) == 0) { + numdups++; + return ql->name; + } + } + return NULL; +} + + +/* + * Add an entry to a template. + */ + +static struct template * +add_line(struct templatehead *t, const char *fmt, ...) +{ + struct template *q = calloc(1, sizeof(*q)); + va_list ap; + va_start(ap, fmt); + if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL) + errx(1, "malloc"); + va_end(ap); + HEIM_TAILQ_INSERT_TAIL(t, q, members); + return q; +} + +/* + * Add an entry to a template, with the pointer field being a symbol name of a + * template (i.e., an array, which decays to a pointer as usual in C). + */ +static void +add_line_pointer(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + if (ptr[0] == '&') + q = add_line(t, "{ %s, %s, %s }", tt, offset, ptr); + else + q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +/* + * Add an entry to a template where the pointer field is a string literal. + */ +static void +add_line_string(struct templatehead *t, + const char *str, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, \"%s\" }", tt, offset, str); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(str); +} + +/* + * Add an entry to a template, with the pointer field being a reference to + * named object of a type other than a template or other array type. + */ +static void +add_line_pointer_reference(struct templatehead *t, + const char *ptr, + const char *offset, + const char *ttfmt, + ...) +{ + struct template *q; + va_list ap; + char *tt = NULL; + + va_start(ap, ttfmt); + if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL) + errx(1, "malloc"); + va_end(ap); + + q = add_line(t, "{ %s, %s, (const void *)&asn1_%s }", tt, offset, ptr); + q->tt = tt; + q->offset = strdup(offset); + q->ptr = strdup(ptr); +} + +static int +use_extern(const Symbol *s) +{ + if (s->type == NULL) + return 1; + return 0; +} + +static int +is_struct(const Type *t, int isstruct) +{ + if (t->type == TType) + return 0; + if (t->type == TSequence || t->type == TSet || t->type == TChoice) + return 1; + if (t->type == TTag) + return is_struct(t->subtype, isstruct); + + if (t->type >= 0 && t->type <= TVisibleString && + types[t->type].type == t->type) { + if (types[t->type].is_struct == 0) + return 0; + return isstruct; + } + if (t->type >= 0 && t->type <= TVisibleString) + errx(1, "types[] is not sorted"); + errx(1, "unknown der type: %d\n", t->type); + return isstruct; +} + +static const Type * +compact_tag(const Type *t) +{ + while (t->type == TTag) + t = t->subtype; + return t; +} + +static void +defval(struct templatehead *temp, Member *m) +{ + switch (m->defval->type) { + case booleanvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_BOOLEAN, ~0, (void *)(uintptr_t)%u }", + m->defval->u.booleanvalue); + break; + case nullvalue: + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_NULL, ~0, (void *)(uintptr_t)0 }"); + break; + case integervalue: { + const char *dv = "A1_DV_INTEGER"; + Type *t = m->type; + + for (;;) { + if (t->range) + break; + if (t->type == TInteger && t->members) + break; + if (t->type == TEnumerated) + break; + if (t->subtype) + t = t->subtype; + else if (t->symbol && t->symbol->type) + t = t->symbol->type; + else + errx(1, "DEFAULT values for unconstrained INTEGER members not supported"); + } + + if (t->members) + dv = "A1_DV_INTEGER32"; /* XXX Enum size assumptions! No good! */ + else if (t->range && t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + dv = "A1_DV_INTEGER64"; + else if (t->range && t->range->min < 0) + dv = "A1_DV_INTEGER32"; + else if (t->range && t->range->max > UINT_MAX) + dv = "A1_DV_INTEGER64"; + else + dv = "A1_DV_INTEGER32"; + add_line(temp, "{ A1_OP_DEFVAL|%s, ~0, (void *)(uintptr_t)%llu }", + dv, (long long)m->defval->u.integervalue); + break; + } + case stringvalue: { + char *quoted; + + if (rk_strasvis("ed, m->defval->u.stringvalue, + VIS_CSTYLE | VIS_NL, "\"") < 0) + err(1, "Could not quote a string"); + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_UTF8STRING, ~0, (void *)(uintptr_t)\"%s\" }", + quoted); + free(quoted); + break; + } + case objectidentifiervalue: { + struct objid *o; + size_t sz = sizeof("{ }"); + char *s, *p; + int len; + + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(0, 0, " %d", o->value)) < 0) + err(1, "Could not format integer"); + sz += len; + } + + if ((p = s = malloc(sz)) == NULL) + err(1, "Could not allocate string"); + + len = snprintf(p, sz, "{"); + sz -= len; + p += len; + for (o = m->defval->u.objectidentifiervalue; o != NULL; o = o->next) { + if ((len = snprintf(p, sz, " %d", o->value)) < 0 || len > sz - 1) + err(1, "Could not format integer"); + sz -= len; + p += len; + } + if ((len = snprintf(p, sz, " }")) >= sz) + abort(); + sz -= len; + if (sz != 0) + abort(); + + add_line(temp, "{ A1_OP_DEFVAL|A1_DV_INTEGER, ~0, (void *)(uintptr_t)\"%s\" }", s); + free(s); + break; + } + default: abort(); + } +} + +int +objid_cmp(struct objid *oida, struct objid *oidb) +{ + struct objid *p; + size_t ai, bi, alen, blen; + int avals[20]; + int bvals[20]; + int c; + + /* + * Our OID values are backwards here. Comparing them is hard. + */ + + for (p = oida, alen = 0; + p && alen < sizeof(avals)/sizeof(avals[0]); + p = p->next) + avals[alen++] = p->value; + for (p = oidb, blen = 0; + p && blen < sizeof(bvals)/sizeof(bvals[0]); + p = p->next) + bvals[blen++] = p->value; + if (alen >= sizeof(avals)/sizeof(avals[0]) || + blen >= sizeof(bvals)/sizeof(bvals[0])) + err(1, "OIDs with more components than %llu not supported", + (unsigned long long)sizeof(avals)/sizeof(avals[0])); + + for (ai = 0, bi = 0; ai < alen && bi < blen;) + if ((c = avals[(alen-1)-(ai++)] - bvals[(blen-1)-(bi++)])) + return c; + + if (ai == alen && bi == blen) + return 0; + if (ai == alen) + return 1; + return -1; +} + +int +object_cmp(const void *va, const void *vb) +{ + const IOSObject *oa = *(const IOSObject * const *)va; + const IOSObject *ob = *(const IOSObject * const *)vb; + + switch (oa->typeidf->value->type) { + case booleanvalue: + return oa->typeidf->value->u.booleanvalue - + ob->typeidf->value->u.booleanvalue; + case nullvalue: + return 0; + case integervalue: + return oa->typeidf->value->u.integervalue - + ob->typeidf->value->u.integervalue; + case stringvalue: + return strcmp(oa->typeidf->value->u.stringvalue, + ob->typeidf->value->u.stringvalue); + case objectidentifiervalue: { + return objid_cmp(oa->typeidf->value->u.objectidentifiervalue, + ob->typeidf->value->u.objectidentifiervalue); + } + default: + abort(); + return -1; + } +} + +void +sort_object_set(IOSObjectSet *os, /* Object set to sort fields of */ + Field *typeidfield, /* Field to sort by */ + IOSObject ***objectsp, /* Output: array of objects */ + size_t *nobjsp) /* Output: count of objects */ +{ + IOSObject **objects; + IOSObject *o; + size_t i, nobjs = 0; + + *objectsp = NULL; + + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + ObjectField *typeidobjf = NULL; + ObjectField *of; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + } + if (!typeidobjf) { + warnx("Ignoring incomplete object specification of %s " + "(missing type ID field)", + o->symbol ? o->symbol->name : "<unknown>"); + continue; + } + o->typeidf = typeidobjf; + nobjs++; + } + *nobjsp = nobjs; + + if (nobjs == 0) + return; + + if ((objects = calloc(nobjs, sizeof(*objects))) == NULL) + err(1, "Out of memory"); + *objectsp = objects; + + i = 0; + HEIM_TAILQ_FOREACH(o, os->objects, objects) { + ObjectField *typeidobjf = NULL; + ObjectField *of; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + } + if (typeidobjf) + objects[i++] = o; + } + qsort(objects, nobjs, sizeof(*objects), object_cmp); +} + +static void +template_object_set(IOSObjectSet *os, Field *typeidfield, Field *opentypefield) +{ + IOSObject **objects = NULL; + IOSObject *o; + struct tlist *tl; + size_t nobjs, i; + + if (os->symbol->emitted_template) + return; + + sort_object_set(os, typeidfield, &objects, &nobjs); + + tl = tlist_new(os->symbol->name); + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", os->symbol->name); + for (i = 0; i < nobjs; i++) { + ObjectField *typeidobjf = NULL, *opentypeobjf = NULL; + ObjectField *of; + char *s = NULL; + + o = objects[i]; + + HEIM_TAILQ_FOREACH(of, o->objfields, objfields) { + if (strcmp(of->name, typeidfield->name) == 0) + typeidobjf = of; + else if (strcmp(of->name, opentypefield->name) == 0) + opentypeobjf = of; + } + if (!typeidobjf) + continue; /* We've warned about this one already when sorting */ + if (!opentypeobjf) { + warnx("Ignoring incomplete object specification of %s " + "(missing open type field)", + o->symbol ? o->symbol->name : "<unknown>"); + continue; + } + + add_line(&tl->template, "{ A1_OP_NAME, 0, \"%s\" }", o->symbol->name); + /* + * Some of this logic could stand to move into sanity checks of object + * definitions in asn1parse.y. + */ + switch (typeidobjf->value->type) { + case integervalue: + add_line(&tl->template, + "{ A1_OP_OPENTYPE_ID | A1_OTI_IS_INTEGER, 0, (void *)(uintptr_t)%lld }", + (long long)typeidobjf->value->u.integervalue); + break; + case objectidentifiervalue: + if (asprintf(&s, "oid_%s", + typeidobjf->value->s->gen_name) == -1 || !s) + err(1, "Out of memory"); + add_line_pointer_reference(&tl->template, s, "0", "A1_OP_OPENTYPE_ID"); + free(s); + s = NULL; + break; + default: + errx(1, "Only integer and OID types supported " + "for open type type-ID fields"); + } + + if (asprintf(&s, "sizeof(%s)", + opentypeobjf->type->symbol->gen_name) == -1 || !s) + err(1, "Out of memory"); + add_line_pointer_reference(&tl->template, + opentypeobjf->type->symbol->gen_name, s, + "A1_OP_OPENTYPE"); + free(s); + } + free(objects); + + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nobjs); + tlist_print(tl); + tlist_add(tl); + os->symbol->emitted_template = 1; +} + +static void +template_open_type(struct templatehead *temp, + const char *basetype, + const Type *t, + size_t typeididx, + size_t opentypeidx, + Field *typeidfield, + Field *opentypefield, + Member *m, + int is_array_of_open_type) +{ + char *s = NULL; + + if (typeididx >= 1<<10 || opentypeidx >= 1<<10) + errx(1, "SET/SEQUENCE with too many members (%s)", basetype); + + if (asprintf(&s, "offsetof(%s, _ioschoice_%s)", + basetype, m->gen_name) == -1 || !s) + err(1, "Out of memory"); + + template_object_set(t->actual_parameter, typeidfield, opentypefield); + add_line_pointer(temp, t->actual_parameter->symbol->gen_name, s, + /* + * We always sort object sets for now as we can't import + * values yet, so they must all be known. + */ + "A1_OP_OPENTYPE_OBJSET | A1_OS_IS_SORTED |%s | (%llu << 10) | %llu", + is_array_of_open_type ? "A1_OS_OT_IS_ARRAY" : "0", + (unsigned long long)opentypeidx, + (unsigned long long)typeididx); + free(s); +} + +static void +template_names(struct templatehead *temp, const char *basetype, const Type *t) +{ + Member *m; + + add_line_string(temp, basetype, "0", "A1_OP_NAME"); + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line_string(temp, m->name, "0", "A1_OP_NAME"); + } +} + +static void +template_members(struct templatehead *temp, + const char *basetype, + const char *name, + const Type *t, + int optional, + int defaulted, + int implicit, + int isstruct, + int need_offset) +{ + char *poffset = NULL; + + if (optional && t->type != TTag && t->type != TType) + errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name); + + poffset = partial_offset(basetype, name, need_offset, isstruct); + + switch (t->type) { + case TType: + if (use_extern(t->symbol)) { + add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s%s, %s, &asn1_extern_%s}", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : "", + poffset, t->symbol->gen_name); + } else { + add_line_pointer(temp, t->symbol->gen_name, poffset, + "A1_OP_TYPE %s%s%s", + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + implicit ? "|A1_FLAG_IMPLICIT" : ""); + + } + break; + case TEnumerated: + case TInteger: { + char *varname = NULL; + char *itype = NULL; + + if (t->members) + itype = "IMEMBER"; + else if (t->range == NULL) + itype = "HEIM_INTEGER"; + else if (t->range->min < 0 && + (t->range->min < INT_MIN || t->range->max > INT_MAX)) + itype = "INTEGER64"; + else if (t->range->min < 0) + itype = "INTEGER"; + else if (t->range->max > UINT_MAX) + itype = "UNSIGNED64"; + else + itype = "UNSIGNED"; + + /* + * If `t->members' then we should generate a template for those + * members. + * + * We don't know the name of this field, and the type may not have a + * name. If it has no name, we should generate a name for it, and if + * it does have a name, use it, to name a template for its members. + * + * Then we could use that in _asn1_print() to pretty-print values of + * enumerations. + */ + if (t->members && t->symbol) { + struct tlist *tl; + Member *m; + size_t nmemb = 0; + + if (asprintf(&varname, "%s_enum_names", t->symbol->gen_name) == -1 || + varname == NULL) + err(1, "Out of memory"); + + tl = tlist_new(varname); + /* + * XXX We're going to assume that t->members is sorted in + * numerically ascending order in the module source. We should + * really sort it here. + */ + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > UINT32_MAX) + errx(1, "Cannot handle %s type %s with named bit %s " + "larger than 63", + t->type == TEnumerated ? "ENUMERATED" : "INTEGER", + name, m->gen_name); + add_line(&tl->template, + "{ A1_OP_NAME, %d, \"%s\" }", (int)m->val, m->name); + nmemb++; + } + tlist_header(tl, "{ 0, 0, ((void *)(uintptr_t)%zu) }", nmemb); + /* XXX Accidentally O(N^2)? */ + if (!tlist_find_dup(tl)) { + tlist_print(tl); + tlist_add(tl); + } + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, asn1_%s }", itype, poffset, varname); + } else { + add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset); + } + break; + } + case TGeneralString: + add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset); + break; + case TTeletexString: + add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset); + break; + case TPrintableString: + add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset); + break; + case TOctetString: + add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset); + break; + case TIA5String: + add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset); + break; + case TBMPString: + add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset); + break; + case TUniversalString: + add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset); + break; + case TVisibleString: + add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset); + break; + case TUTF8String: + add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset); + break; + case TGeneralizedTime: + add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset); + break; + case TUTCTime: + add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset); + break; + case TBoolean: + add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset); + break; + case TOID: + add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset); + break; + case TNull: + break; + case TBitString: { + struct templatehead template; + struct template *q; + Member *m; + size_t count = 0, i; + char *bname = NULL; + FILE *f = get_code_file(); + static unsigned long bmember_counter = 0; + + HEIM_TAILQ_INIT(&template); + + if (HEIM_TAILQ_EMPTY(t->members)) { + add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset); + break; + } + + if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL) + errx(1, "malloc"); + output_name(bname); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + if (m->val > UINT32_MAX) + errx(1, "Cannot handle BIT STRING type %s with named bit %s " + "larger than 63", name, m->gen_name); + add_line(&template, "{ 0, %d, \"%s\" }", (int)m->val, m->gen_name); + } + + HEIM_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname); + fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)(uintptr_t)%lu) },\n", + rfc1510_bitstring ? "|A1_HBF_RFC1510" : "", + basetype, (unsigned long)count); + i = 1; + HEIM_TAILQ_FOREACH(q, &template, members) { + int last = (HEIM_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname); + + free(bname); + + break; + } + case TSet: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + size_t i = 0, typeididx = 0, opentypeidx = 0; + int is_array_of_open_type = 0; + + if (isstruct && t->actual_parameter) + get_open_type_defn_fields(t, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + + fprintf(get_code_file(), "/* tset: members isstruct: %d */\n", isstruct); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *newbasename = NULL; + + if (m->ellipsis) + continue; + + if (typeidmember == m) typeididx = i; + if (opentypemember == m) opentypeidx = i; + + if (name) { + if (asprintf(&newbasename, "%s_%s", basetype, name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + if (newbasename == NULL) + errx(1, "malloc"); + + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); + + free(newbasename); + i++; + } + + if (isstruct && t->actual_parameter) + template_open_type(temp, basetype, t, typeididx, opentypeidx, + typeidfield, opentypefield, opentypemember, + is_array_of_open_type); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + if (isstruct) + template_names(temp, basetype, t); + break; + } + case TSequence: { + Member *opentypemember = NULL; + Member *typeidmember = NULL; + Field *opentypefield = NULL; + Field *typeidfield = NULL; + Member *m; + struct decoration deco; + ssize_t more_deco = -1; + size_t i = 0, typeididx = 0, opentypeidx = 0; + int is_array_of_open_type = 0; + + if (isstruct && t->actual_parameter) + get_open_type_defn_fields(t, &typeidmember, &opentypemember, + &typeidfield, &opentypefield, + &is_array_of_open_type); + + fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + char *newbasename = NULL; + + if (m->ellipsis) + continue; + + if (typeidmember == m) typeididx = i; + if (opentypemember == m) opentypeidx = i; + + if (name) { + if (asprintf(&newbasename, "%s_%s", basetype, name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + if (newbasename == NULL) + errx(1, "malloc"); + + if (m->defval) + defval(temp, m); + + template_members(temp, newbasename, m->gen_name, m->type, m->optional, m->defval ? 1 : 0, 0, isstruct, 1); + + free(newbasename); + i++; + } + + if (isstruct && t->actual_parameter) + template_open_type(temp, basetype, t, typeididx, opentypeidx, + typeidfield, opentypefield, opentypemember, + is_array_of_open_type); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + if (isstruct) + template_names(temp, basetype, t); + break; + } + case TTag: { + char *tname = NULL, *elname = NULL; + const char *sename, *dupname; + int subtype_is_struct = is_struct(t->subtype, isstruct); + static unsigned long tag_counter = 0; + int tagimplicit = 0; + int prim = !(t->tag.tagclass != ASN1_C_UNIV && + t->tag.tagenv == TE_EXPLICIT) && + is_primitive_type(t->subtype); + + if (t->tag.tagenv == TE_IMPLICIT) { + Type *t2 = t->subtype ? t->subtype : t->symbol->type; + + while (t2->type == TType && (t2->subtype || t2->symbol->type)) + t2 = t2->subtype ? t2->subtype : t2->symbol->type; + if (t2->type != TChoice) + tagimplicit = 1; + } + + fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp"); + + if (subtype_is_struct) + sename = basetype; + else + sename = symbol_name(basetype, t->subtype); + + if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL) + errx(1, "malloc"); + output_name(tname); + + if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL) + errx(1, "malloc"); + + generate_template_type(elname, &dupname, NULL, sename, name, + t->subtype, 0, subtype_is_struct, 0); + + add_line_pointer(temp, dupname, poffset, + "A1_TAG_T(%s,%s,%s)%s%s%s", + classname(t->tag.tagclass), + prim ? "PRIM" : "CONS", + valuename(t->tag.tagclass, t->tag.tagvalue), + optional ? "|A1_FLAG_OPTIONAL" : "", + defaulted ? "|A1_FLAG_DEFAULT" : "", + tagimplicit ? "|A1_FLAG_IMPLICIT" : ""); + + free(tname); + free(elname); + + break; + } + case TSetOf: + case TSequenceOf: { + const char *type = NULL, *tname, *dupname; + char *sename = NULL, *elname = NULL; + int subtype_is_struct = is_struct(t->subtype, 0); + static unsigned long seof_counter = 0; + + if (name && subtype_is_struct) { + tname = "seofTstruct"; + if (asprintf(&sename, "%s_%s_val", basetype, name) < 0) + errx(1, "malloc"); + } else if (subtype_is_struct) { + tname = "seofTstruct"; + if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0) + errx(1, "malloc"); + } else { + if (name) + tname = name; + else + tname = "seofTstruct"; + sename = strdup(symbol_name(basetype, t->subtype)); + } + if (sename == NULL) + errx(1, "malloc"); + + if (t->type == TSetOf) type = "A1_OP_SETOF"; + else if (t->type == TSequenceOf) type = "A1_OP_SEQOF"; + else abort(); + + if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL) + errx(1, "malloc"); + + generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype, + 0, subtype_is_struct, need_offset); + + add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname); + free(sename); + break; + } + case TChoice: { + struct decoration deco; + ssize_t more_deco = -1; + struct templatehead template; + struct template *q; + size_t count = 0, i; + char *tname = NULL; + FILE *f = get_code_file(); + Member *m; + int ellipsis = 0; + char *e; + static unsigned long choice_counter = 0; + + HEIM_TAILQ_INIT(&template); + + if (asprintf(&tname, "asn1_choice_%s_%s%lu", + basetype, name ? name : "", choice_counter++) < 0 || tname == NULL) + errx(1, "malloc"); + + HEIM_TAILQ_FOREACH(m, t->members, members) { + const char *dupname; + char *elname = NULL; + char *newbasename = NULL; + int subtype_is_struct; + + if (m->ellipsis) { + ellipsis = 1; + continue; + } + + subtype_is_struct = is_struct(m->type, 0); + + if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL) + errx(1, "malloc"); + + if (subtype_is_struct) { + if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0) + errx(1, "malloc"); + } else + newbasename = strdup(basetype); + + if (newbasename == NULL) + errx(1, "malloc"); + + + generate_template_type(elname, &dupname, NULL, + symbol_name(newbasename, m->type), + NULL, m->type, 0, subtype_is_struct, 1); + + add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }", + m->label, isstruct ? "struct " : "", + basetype, m->gen_name, + dupname); + + free(elname); + free(newbasename); + } + + HEIM_TAILQ_FOREACH(m, t->members, members) { + add_line(&template, "{ 0, 0, \"%s\" }", m->name); + } + + e = NULL; + if (ellipsis) { + if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL) + errx(1, "malloc"); + } + + HEIM_TAILQ_FOREACH(q, &template, members) { + count++; + } + + fprintf(f, "static const struct asn1_template %s[] = {\n", tname); + fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)(uintptr_t)%lu) },\n", + e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count); + i = 1; + HEIM_TAILQ_FOREACH(q, &template, members) { + int last = (HEIM_TAILQ_LAST(&template, templatehead) == q); + fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ","); + } + fprintf(f, "};\n"); + + add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname); + + while (decorate_type(basetype, &deco, &more_deco)) { + char *poffset2; + + poffset2 = partial_offset(basetype, deco.field_name, 1, isstruct); + + if (deco.ext) { + char *ptr = NULL; + + /* Decorated with external C type */ + if (asprintf(&ptr, "&asn1_extern_%s_%s", + basetype, deco.field_name) == -1 || ptr == NULL) + err(1, "out of memory"); + add_line_pointer(temp, ptr, poffset2, + "A1_OP_TYPE_DECORATE_EXTERN %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(ptr); + } else + /* Decorated with a templated ASN.1 type */ + add_line_pointer(temp, deco.field_type, poffset2, + "A1_OP_TYPE_DECORATE %s", + deco.opt ? "|A1_FLAG_OPTIONAL" : ""); + free(poffset2); + free(deco.field_type); + } + + free(e); + free(tname); + break; + } + default: + abort (); + } + if (poffset) + free(poffset); +} + +static void +gen_extern_stubs(FILE *f, const char *name) +{ + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s = {\n" + "\t(asn1_type_encode)encode_%s,\n" + "\t(asn1_type_decode)decode_%s,\n" + "\t(asn1_type_length)length_%s,\n" + "\t(asn1_type_copy)copy_%s,\n" + "\t(asn1_type_release)free_%s,\n" + "\t(asn1_type_print)print_%s,\n" + "\tsizeof(%s)\n" + "};\n", + name, name, name, name, + name, name, name, name); +} + +void +gen_template_import(const Symbol *s) +{ + FILE *f = get_code_file(); + + if (template_flag == 0) + return; + + gen_extern_stubs(f, s->gen_name); +} + +void +generate_template_type_forward(const char *name) +{ + fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", name); +} + +void +generate_template_objectset_forwards(const Symbol *s) +{ + if (!template_flag) + return; + fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", + s->gen_name); +} + +static void +generate_template_type(const char *varname, + const char **dupname, + const char *symname, + const char *basetype, + const char *name, + Type *type, + int optional, + int isstruct, + int need_offset) +{ + struct tlist *tl; + const char *d; + char *szt = NULL; + int have_ellipsis = 0; + int implicit = 0; + int n; + + tl = tlist_new(varname); + + if (type->type == TTag && type->tag.tagenv == TE_IMPLICIT) { + Type *t = type->subtype ? type->subtype : type->symbol->type; + + while (t->type == TType && (t->subtype || t->symbol->type)) + t = t->subtype ? t->subtype : t->symbol->type; + if (t->type != TChoice) + implicit = (type->tag.tagenv == TE_IMPLICIT); + } + + template_members(&tl->template, basetype, name, type, optional, 0, + implicit, isstruct, need_offset); + + /* if its a sequence or set type, check if there is a ellipsis */ + if (type->type == TSequence || type->type == TSet) { + Member *m; + HEIM_TAILQ_FOREACH(m, type->members, members) { + if (m->ellipsis) + have_ellipsis = 1; + } + } + + if (isstruct) + if (name) + n = asprintf(&szt, "struct %s_%s", basetype, name); + else + n = asprintf(&szt, "struct %s", basetype); + else + n = asprintf(&szt, "%s", basetype); + if (n < 0 || szt == NULL) + errx(1, "malloc"); + + if (HEIM_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull) + errx(1, "Tag %s...%s with no content ?", basetype, name ? name : ""); + + fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name); + + tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)(uintptr_t)%lu) }", + (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "", + have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl)); + + free(szt); + + /* XXX Accidentally O(N^2)? */ + d = tlist_find_dup(tl); + if (d) { +#if 0 + if (strcmp(d, tl->name) == 0) + errx(1, "found dup of ourself: %s", d); +#endif + *dupname = d; + } else { + *dupname = tl->name; + tlist_print(tl); + tlist_add(tl); + } +} + + +void +generate_template(const Symbol *s) +{ + FILE *f = get_code_file(); + const char *dupname; + struct decoration deco; + ssize_t more_deco = -1; + + if (use_extern(s)) { + gen_extern_stubs(f, s->gen_name); + return; + } + + while (decorate_type(s->gen_name, &deco, &more_deco)) { + if (!deco.ext) + continue; + if (deco.void_star && deco.header_name) + fprintf(f, "#include %s\n", deco.header_name); + fprintf(f, + "static const struct asn1_type_func asn1_extern_%s_%s = {\n" + "\t(asn1_type_encode)0,\n" + "\t(asn1_type_decode)0,\n" + "\t(asn1_type_length)0,\n" + "\t(asn1_type_copy)%s,\n" + "\t(asn1_type_release)%s,\n" + "\t(asn1_type_print)0,\n" + "\tsizeof(%s)\n" + "};\n", s->gen_name, deco.field_name, + deco.copy_function_name && deco.copy_function_name[0] ? + deco.copy_function_name : "0", + deco.free_function_name && deco.free_function_name[0] ? + deco.free_function_name : "0", + deco.void_star ? "void *" : deco.field_type); + free(deco.field_type); + } + + generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n" + "{\n" + " memset(data, 0, sizeof(*data));\n" + " return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname, + support_ber ? "A1_PF_ALLOW_BER" : "0"); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n" + "{\n" + " return _asn1_encode%s(asn1_%s, p, len, data, size);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + fuzzer_string, + dupname); + + fprintf(f, + "\n" + "size_t ASN1CALL\n" + "length_%s(const %s *data)\n" + "{\n" + " return _asn1_length%s(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + fuzzer_string, + dupname); + + + fprintf(f, + "\n" + "void ASN1CALL\n" + "free_%s(%s *data)\n" + "{\n" + " _asn1_free_top(asn1_%s, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "int ASN1CALL\n" + "copy_%s(const %s *from, %s *to)\n" + "{\n" + " return _asn1_copy_top(asn1_%s, from, to);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + s->gen_name, + dupname); + + fprintf(f, + "\n" + "char * ASN1CALL\n" + "print_%s(const %s *data, int flags)\n" + "{\n" + " return _asn1_print_top(asn1_%s, flags, data);\n" + "}\n" + "\n", + s->gen_name, + s->gen_name, + dupname); +} |