Home | History | Annotate | Line # | Download | only in asn1
      1 /*	$NetBSD: gen_template.c,v 1.3 2019/12/15 22:50:47 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1997 - 2005 Kungliga Tekniska Hgskolan
      5  * (Royal Institute of Technology, Stockholm, Sweden).
      6  * All rights reserved.
      7  *
      8  * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  *
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  *
     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.
     20  *
     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.
     24  *
     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
     35  * SUCH DAMAGE.
     36  */
     37 
     38 #include "gen_locl.h"
     39 
     40 static const char *symbol_name(const char *, const Type *);
     41 static void generate_template_type(const char *, const char **, const char *, const char *, const char *,
     42 				   Type *, int, int, int);
     43 
     44 static const char *
     45 ttype_symbol(const char *basename, const Type *t)
     46 {
     47     return t->symbol->gen_name;
     48 }
     49 
     50 static const char *
     51 integer_symbol(const char *basename, const Type *t)
     52 {
     53     if (t->members)
     54 	return "int"; /* XXX enum foo */
     55     else if (t->range == NULL)
     56 	return "heim_integer";
     57     else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX)
     58 	return "int64_t";
     59     else if (t->range->min >= 0 && t->range->max > UINT_MAX)
     60 	return "uint64_t";
     61     else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX)
     62 	return "int";
     63     else if (t->range->min >= 0 && t->range->max <= UINT_MAX)
     64 	return "unsigned";
     65     else {
     66 	abort();
     67         UNREACHABLE(return NULL);
     68     }
     69 }
     70 
     71 static const char *
     72 boolean_symbol(const char *basename, const Type *t)
     73 {
     74     return "int";
     75 }
     76 
     77 
     78 static const char *
     79 octetstring_symbol(const char *basename, const Type *t)
     80 {
     81     return "heim_octet_string";
     82 }
     83 
     84 static const char *
     85 sequence_symbol(const char *basename, const Type *t)
     86 {
     87     return basename;
     88 }
     89 
     90 static const char *
     91 time_symbol(const char *basename, const Type *t)
     92 {
     93     return "time_t";
     94 }
     95 
     96 static const char *
     97 tag_symbol(const char *basename, const Type *t)
     98 {
     99     return symbol_name(basename, t->subtype);
    100 }
    101 
    102 static const char *
    103 generalstring_symbol(const char *basename, const Type *t)
    104 {
    105     return "heim_general_string";
    106 }
    107 
    108 static const char *
    109 printablestring_symbol(const char *basename, const Type *t)
    110 {
    111     return "heim_printable_string";
    112 }
    113 
    114 static const char *
    115 ia5string_symbol(const char *basename, const Type *t)
    116 {
    117     return "heim_ia5_string";
    118 }
    119 
    120 static const char *
    121 teletexstring_symbol(const char *basename, const Type *t)
    122 {
    123     return "heim_teletex_string";
    124 }
    125 
    126 static const char *
    127 visiblestring_symbol(const char *basename, const Type *t)
    128 {
    129     return "heim_visible_string";
    130 }
    131 
    132 static const char *
    133 utf8string_symbol(const char *basename, const Type *t)
    134 {
    135     return "heim_utf8_string";
    136 }
    137 
    138 static const char *
    139 bmpstring_symbol(const char *basename, const Type *t)
    140 {
    141     return "heim_bmp_string";
    142 }
    143 
    144 static const char *
    145 universalstring_symbol(const char *basename, const Type *t)
    146 {
    147     return "heim_universal_string";
    148 }
    149 
    150 static const char *
    151 oid_symbol(const char *basename, const Type *t)
    152 {
    153     return "heim_oid";
    154 }
    155 
    156 static const char *
    157 bitstring_symbol(const char *basename, const Type *t)
    158 {
    159     if (t->members)
    160 	return basename;
    161     return "heim_bit_string";
    162 }
    163 
    164 
    165 
    166 struct {
    167     enum typetype type;
    168     const char *(*symbol_name)(const char *, const Type *);
    169     int is_struct;
    170 } types[] =  {
    171     { TBMPString, bmpstring_symbol, 0 },
    172     { TBitString, bitstring_symbol, 0 },
    173     { TBoolean, boolean_symbol, 0 },
    174     { TGeneralString, generalstring_symbol, 0 },
    175     { TGeneralizedTime, time_symbol, 0 },
    176     { TIA5String, ia5string_symbol, 0 },
    177     { TTeletexString, generalstring_symbol, 0 },
    178     { TInteger, integer_symbol, 0 },
    179     { TOID, oid_symbol, 0 },
    180     { TOctetString, octetstring_symbol, 0 },
    181     { TPrintableString, printablestring_symbol, 0 },
    182     { TSequence, sequence_symbol, 1 },
    183     { TSequenceOf, tag_symbol, 1 },
    184     { TSetOf, tag_symbol, 1 },
    185     { TTag, tag_symbol, 1 },
    186     { TType, ttype_symbol, 1 },
    187     { TUTCTime, time_symbol, 0 },
    188     { TUniversalString, universalstring_symbol, 0 },
    189     { TTeletexString, teletexstring_symbol, 0 },
    190     { TVisibleString,  visiblestring_symbol, 0 },
    191     { TUTF8String, utf8string_symbol, 0 },
    192     { TChoice, sequence_symbol, 1 },
    193     { TNull, integer_symbol, 1 }
    194 };
    195 
    196 static FILE *
    197 get_code_file(void)
    198 {
    199     if (!one_code_file)
    200 	return templatefile;
    201     return codefile;
    202 }
    203 
    204 
    205 static int
    206 is_supported_type_p(const Type *t)
    207 {
    208     size_t i;
    209 
    210     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
    211 	if (t->type == types[i].type)
    212 	    return 1;
    213     return 0;
    214 }
    215 
    216 int
    217 is_template_compat (const Symbol *s)
    218 {
    219     return is_supported_type_p(s->type);
    220 }
    221 
    222 static const char *
    223 symbol_name(const char *basename, const Type *t)
    224 {
    225     size_t i;
    226 
    227     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
    228 	if (t->type == types[i].type)
    229 	    return (types[i].symbol_name)(basename, t);
    230     printf("unknown der type: %d\n", t->type);
    231     exit(1);
    232 }
    233 
    234 
    235 static char *
    236 partial_offset(const char *basetype, const char *name, int need_offset, int isstruct)
    237 {
    238     char *str;
    239     if (name == NULL || need_offset == 0)
    240 	return strdup("0");
    241     if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL)
    242 	errx(1, "malloc");
    243     return str;
    244 }
    245 
    246 struct template {
    247     char *line;
    248     char *tt;
    249     char *offset;
    250     char *ptr;
    251     ASN1_TAILQ_ENTRY(template) members;
    252 };
    253 
    254 ASN1_TAILQ_HEAD(templatehead, template);
    255 
    256 struct tlist {
    257     char *name;
    258     char *header;
    259     struct templatehead template;
    260     ASN1_TAILQ_ENTRY(tlist) tmembers;
    261 };
    262 
    263 ASN1_TAILQ_HEAD(tlisthead, tlist);
    264 
    265 static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
    266 static struct template *
    267     add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
    268 static int tlist_cmp(const struct tlist *, const struct tlist *);
    269 
    270 static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...)
    271     __attribute__ ((__format__ (__printf__, 4, 5)));
    272 
    273 
    274 static struct tlisthead tlistmaster = ASN1_TAILQ_HEAD_INITIALIZER(tlistmaster);
    275 static unsigned long numdups = 0;
    276 
    277 static struct tlist *
    278 tlist_new(const char *name)
    279 {
    280     struct tlist *tl = calloc(1, sizeof(*tl));
    281     tl->name = strdup(name);
    282     ASN1_TAILQ_INIT(&tl->template);
    283     return tl;
    284 }
    285 
    286 static void
    287 tlist_header(struct tlist *t, const char *fmt, ...)
    288 {
    289     va_list ap;
    290     va_start(ap, fmt);
    291     if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL)
    292 	errx(1, "malloc");
    293     va_end(ap);
    294 }
    295 
    296 static unsigned long
    297 tlist_count(struct tlist *tl)
    298 {
    299     unsigned int count = 0;
    300     struct template *q;
    301 
    302     ASN1_TAILQ_FOREACH(q, &tl->template, members) {
    303 	count++;
    304     }
    305     return count;
    306 }
    307 
    308 static void
    309 tlist_add(struct tlist *tl)
    310 {
    311     ASN1_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers);
    312 }
    313 
    314 static void
    315 tlist_print(struct tlist *tl)
    316 {
    317     struct template *q;
    318     unsigned int i = 1;
    319     FILE *f = get_code_file();
    320 
    321     fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name);
    322     fprintf(f, "/* 0 */ %s,\n", tl->header);
    323     ASN1_TAILQ_FOREACH(q, &tl->template, members) {
    324 	int last = (ASN1_TAILQ_LAST(&tl->template, templatehead) == q);
    325 	fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
    326     }
    327     fprintf(f, "};\n");
    328 }
    329 
    330 static struct tlist *
    331 tlist_find_by_name(const char *name)
    332 {
    333     struct tlist *ql;
    334     ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
    335 	if (strcmp(ql->name, name) == 0)
    336 	    return ql;
    337     }
    338     return NULL;
    339 }
    340 
    341 static int
    342 tlist_cmp_name(const char *tname, const char *qname)
    343 {
    344     struct tlist *tl = tlist_find_by_name(tname);
    345     struct tlist *ql = tlist_find_by_name(qname);
    346     if (tl == NULL)
    347 	return 1;
    348     if (ql == NULL)
    349 	return -1;
    350     return tlist_cmp(tl, ql);
    351 }
    352 
    353 static int
    354 tlist_cmp(const struct tlist *tl, const struct tlist *ql)
    355 {
    356     int ret;
    357     struct template *t, *q;
    358 
    359     ret = strcmp(tl->header, ql->header);
    360     if (ret) return ret;
    361 
    362     q = ASN1_TAILQ_FIRST(&ql->template);
    363     ASN1_TAILQ_FOREACH(t, &tl->template, members) {
    364 	if (q == NULL) return 1;
    365 
    366 	if (t->ptr == NULL || q->ptr == NULL) {
    367 	    ret = strcmp(t->line, q->line);
    368 	    if (ret) return ret;
    369 	} else {
    370 	    ret = strcmp(t->tt, q->tt);
    371 	    if (ret) return ret;
    372 
    373 	    ret = strcmp(t->offset, q->offset);
    374 	    if (ret) return ret;
    375 
    376 	    if ((ret = strcmp(t->ptr, q->ptr)) != 0 ||
    377 		(ret = tlist_cmp_name(t->ptr, q->ptr)) != 0)
    378 		return ret;
    379 	}
    380 	q = ASN1_TAILQ_NEXT(q, members);
    381     }
    382     if (q != NULL) return -1;
    383     return 0;
    384 }
    385 
    386 
    387 static const char *
    388 tlist_find_dup(const struct tlist *tl)
    389 {
    390     struct tlist *ql;
    391 
    392     ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
    393 	if (tlist_cmp(ql, tl) == 0) {
    394 	    numdups++;
    395 	    return ql->name;
    396 	}
    397     }
    398     return NULL;
    399 }
    400 
    401 
    402 /*
    403  *
    404  */
    405 
    406 static struct template *
    407 add_line(struct templatehead *t, const char *fmt, ...)
    408 {
    409     struct template *q = calloc(1, sizeof(*q));
    410     va_list ap;
    411     va_start(ap, fmt);
    412     if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL)
    413 	errx(1, "malloc");
    414     va_end(ap);
    415     ASN1_TAILQ_INSERT_TAIL(t, q, members);
    416     return q;
    417 }
    418 
    419 static void
    420 add_line_pointer(struct templatehead *t,
    421 		 const char *ptr,
    422 		 const char *offset,
    423 		 const char *ttfmt,
    424 		 ...)
    425 {
    426     struct template *q;
    427     va_list ap;
    428     char *tt = NULL;
    429 
    430     va_start(ap, ttfmt);
    431     if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
    432 	errx(1, "malloc");
    433     va_end(ap);
    434 
    435     q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr);
    436     q->tt = tt;
    437     q->offset = strdup(offset);
    438     q->ptr = strdup(ptr);
    439 }
    440 
    441 static int
    442 use_extern(const Symbol *s)
    443 {
    444     if (s->type == NULL)
    445 	return 1;
    446     return 0;
    447 }
    448 
    449 static int
    450 is_struct(const Type *t, int isstruct)
    451 {
    452     size_t i;
    453 
    454     if (t->type == TType)
    455 	return 0;
    456     if (t->type == TSequence || t->type == TSet || t->type == TChoice)
    457 	return 1;
    458     if (t->type == TTag)
    459 	return is_struct(t->subtype, isstruct);
    460 
    461     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
    462 	if (t->type == types[i].type) {
    463 	    if (types[i].is_struct == 0)
    464 		return 0;
    465 	    else
    466 		break;
    467 	}
    468     }
    469 
    470     return isstruct;
    471 }
    472 
    473 static const Type *
    474 compact_tag(const Type *t)
    475 {
    476     while (t->type == TTag)
    477 	t = t->subtype;
    478     return t;
    479 }
    480 
    481 static void
    482 template_members(struct templatehead *temp, const char *basetype, const char *name, const Type *t, int optional, int implicit, int isstruct, int need_offset)
    483 {
    484     char *poffset = NULL;
    485 
    486     if (optional && t->type != TTag && t->type != TType)
    487 	errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name);
    488 
    489     poffset = partial_offset(basetype, name, need_offset, isstruct);
    490 
    491     switch (t->type) {
    492     case TType:
    493 	if (use_extern(t->symbol)) {
    494 	    add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s, %s, &asn1_extern_%s}",
    495 		     optional ? "|A1_FLAG_OPTIONAL" : "",
    496 		     implicit ? "|A1_FLAG_IMPLICIT" : "",
    497 		     poffset, t->symbol->gen_name);
    498 	} else {
    499 	    add_line_pointer(temp, t->symbol->gen_name, poffset,
    500 			     "A1_OP_TYPE %s%s",
    501 			     optional ? "|A1_FLAG_OPTIONAL" : "",
    502 			     implicit ? "|A1_FLAG_IMPLICIT" : "");
    503 
    504 	}
    505 	break;
    506     case TInteger: {
    507 	char *itype = NULL;
    508 
    509 	if (t->members)
    510 	    itype = "IMEMBER";
    511 	else if (t->range == NULL)
    512 	    itype = "HEIM_INTEGER";
    513 	else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX)
    514 	    itype = "INTEGER64";
    515 	else if (t->range->min >= 0 && t->range->max > UINT_MAX)
    516 	    itype = "UNSIGNED64";
    517 	else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX)
    518 	    itype = "INTEGER";
    519 	else if (t->range->min >= 0 && t->range->max <= UINT_MAX)
    520 	    itype = "UNSIGNED";
    521 	else
    522 	    errx(1, "%s: unsupported range %lld -> %lld",
    523 		 name, (long long)t->range->min, (long long)t->range->max);
    524 
    525 	add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset);
    526 	break;
    527     }
    528     case TGeneralString:
    529 	add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset);
    530 	break;
    531     case TTeletexString:
    532 	add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset);
    533 	break;
    534     case TPrintableString:
    535 	add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset);
    536 	break;
    537     case TOctetString:
    538 	add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset);
    539 	break;
    540     case TIA5String:
    541 	add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset);
    542 	break;
    543     case TBMPString:
    544 	add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset);
    545 	break;
    546     case TUniversalString:
    547 	add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset);
    548 	break;
    549     case TVisibleString:
    550 	add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset);
    551 	break;
    552     case TUTF8String:
    553 	add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset);
    554 	break;
    555     case TGeneralizedTime:
    556 	add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset);
    557 	break;
    558     case TUTCTime:
    559 	add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset);
    560 	break;
    561     case TBoolean:
    562 	add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset);
    563 	break;
    564     case TOID:
    565 	add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset);
    566 	break;
    567     case TNull:
    568 	break;
    569     case TBitString: {
    570 	struct templatehead template;
    571 	struct template *q;
    572 	Member *m;
    573 	size_t count = 0, i;
    574 	char *bname = NULL;
    575 	FILE *f = get_code_file();
    576 	static unsigned long bmember_counter = 0;
    577 
    578 	ASN1_TAILQ_INIT(&template);
    579 
    580 	if (ASN1_TAILQ_EMPTY(t->members)) {
    581 	    add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset);
    582 	    break;
    583 	}
    584 
    585 	if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL)
    586 	    errx(1, "malloc");
    587 	output_name(bname);
    588 
    589 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    590 	    add_line(&template, "{ 0, %d, 0 } /* %s */", m->val, m->gen_name);
    591 	}
    592 
    593 	ASN1_TAILQ_FOREACH(q, &template, members) {
    594 	    count++;
    595 	}
    596 
    597 	fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname);
    598 	fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)%lu) },\n",
    599 		rfc1510_bitstring ? "|A1_HBF_RFC1510" : "",
    600 		basetype, (unsigned long)count);
    601 	i = 1;
    602 	ASN1_TAILQ_FOREACH(q, &template, members) {
    603 	    int last = (ASN1_TAILQ_LAST(&template, templatehead) == q);
    604 	    fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
    605 	}
    606 	fprintf(f, "};\n");
    607 
    608 	add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname);
    609 
    610 	free(bname);
    611 
    612 	break;
    613     }
    614     case TSequence: {
    615 	Member *m;
    616 
    617 	fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct);
    618 
    619 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    620 	    char *newbasename = NULL;
    621 
    622 	    if (m->ellipsis)
    623 		continue;
    624 
    625 	    if (name) {
    626 		if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
    627 		    errx(1, "malloc");
    628 	    } else
    629 		newbasename = strdup(basetype);
    630 	    if (newbasename == NULL)
    631 		errx(1, "malloc");
    632 
    633 	    template_members(temp, newbasename, m->gen_name, m->type, m->optional, 0, isstruct, 1);
    634 
    635 	    free(newbasename);
    636 	}
    637 
    638 	break;
    639     }
    640     case TTag: {
    641 	char *tname = NULL, *elname = NULL;
    642 	const char *sename, *dupname;
    643 	int subtype_is_struct = is_struct(t->subtype, isstruct);
    644 	static unsigned long tag_counter = 0;
    645 	int tagimplicit = (t->tag.tagenv == TE_IMPLICIT);
    646 	struct type *subtype;
    647 
    648 	fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp");
    649 
    650 	if (tagimplicit) {
    651 
    652 	    struct type *type = t->subtype;
    653 	    int have_tag = 0;
    654 
    655 	    while (!have_tag) {
    656 		if (type->type == TTag) {
    657 		    fprintf(get_code_file(), "/* template_members: imp skip tag */\n");
    658 		    type = type->subtype;
    659 		    have_tag = 1;
    660 		} else if(type->type == TType && type->symbol && type->symbol->type) {
    661 		    /* XXX really, we should stop here and find a
    662 		     * pointer to where this is encoded instead of
    663 		     * generated an new structure and hope that the
    664 		     * optimizer catch it later.
    665 		     */
    666 		    subtype_is_struct = is_struct(type, isstruct);
    667 		    fprintf(get_code_file(), "/* template_members: imp skip type %s isstruct: %d */\n",
    668 			    type->symbol->name, subtype_is_struct);
    669 		    type = type->symbol->type;
    670 		} else {
    671 		    have_tag = 1;
    672 		}
    673 	    }
    674 	    subtype = type;
    675 	} else {
    676 	    subtype = t->subtype;
    677 	}
    678 
    679 	if (subtype_is_struct)
    680 	    sename = basetype;
    681 	else
    682 	    sename = symbol_name(basetype, subtype);
    683 
    684 	if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL)
    685 	    errx(1, "malloc");
    686 	output_name(tname);
    687 
    688 	if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL)
    689 	    errx(1, "malloc");
    690 
    691 	generate_template_type(elname, &dupname, NULL, sename, name,
    692 			       subtype, 0, subtype_is_struct, 0);
    693 
    694 	add_line_pointer(temp, dupname, poffset,
    695 			 "A1_TAG_T(%s,%s,%s)%s%s",
    696 			 classname(t->tag.tagclass),
    697 			 is_primitive_type(subtype->type)  ? "PRIM" : "CONS",
    698 			 valuename(t->tag.tagclass, t->tag.tagvalue),
    699 			 optional ? "|A1_FLAG_OPTIONAL" : "",
    700 			 tagimplicit ? "|A1_FLAG_IMPLICIT" : "");
    701 
    702 	free(tname);
    703 	free(elname);
    704 
    705 	break;
    706     }
    707     case TSetOf:
    708     case TSequenceOf: {
    709 	const char *type = NULL, *tname, *dupname;
    710 	char *sename = NULL, *elname = NULL;
    711 	int subtype_is_struct = is_struct(t->subtype, 0);
    712 	static unsigned long seof_counter = 0;
    713 
    714 	if (name && subtype_is_struct) {
    715 	    tname = "seofTstruct";
    716 	    if (asprintf(&sename, "%s_%s_val", basetype, name) < 0)
    717 		errx(1, "malloc");
    718 	} else if (subtype_is_struct) {
    719 	    tname = "seofTstruct";
    720 	    if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0)
    721 		errx(1, "malloc");
    722 	} else {
    723 	    if (name)
    724 		tname = name;
    725 	    else
    726 		tname = "seofTstruct";
    727 	    sename = strdup(symbol_name(basetype, t->subtype));
    728 	}
    729 	if (sename == NULL)
    730 	    errx(1, "malloc");
    731 
    732 	if (t->type == TSetOf) type = "A1_OP_SETOF";
    733 	else if (t->type == TSequenceOf) type = "A1_OP_SEQOF";
    734 	else abort();
    735 
    736 	if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL)
    737 	    errx(1, "malloc");
    738 
    739 	generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype,
    740 			       0, subtype_is_struct, need_offset);
    741 
    742 	add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname);
    743 	free(sename);
    744 	break;
    745     }
    746     case TChoice: {
    747 	struct templatehead template;
    748 	struct template *q;
    749 	size_t count = 0, i;
    750 	char *tname = NULL;
    751 	FILE *f = get_code_file();
    752 	Member *m;
    753 	int ellipsis = 0;
    754 	char *e;
    755 	static unsigned long choice_counter = 0;
    756 
    757 	ASN1_TAILQ_INIT(&template);
    758 
    759 	if (asprintf(&tname, "asn1_choice_%s_%s%lu",
    760 		     basetype, name ? name : "", choice_counter++) < 0 || tname == NULL)
    761 	    errx(1, "malloc");
    762 
    763 	ASN1_TAILQ_FOREACH(m, t->members, members) {
    764 	    const char *dupname;
    765 	    char *elname = NULL;
    766 	    char *newbasename = NULL;
    767 	    int subtype_is_struct;
    768 
    769 	    if (m->ellipsis) {
    770 		ellipsis = 1;
    771 		continue;
    772 	    }
    773 
    774 	    subtype_is_struct = is_struct(m->type, 0);
    775 
    776 	    if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL)
    777 		errx(1, "malloc");
    778 
    779 	    if (subtype_is_struct) {
    780 		if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0)
    781 		    errx(1, "malloc");
    782 	    } else
    783 		newbasename = strdup(basetype);
    784 
    785 	    if (newbasename == NULL)
    786 		errx(1, "malloc");
    787 
    788 
    789 	    generate_template_type(elname, &dupname, NULL,
    790 				   symbol_name(newbasename, m->type),
    791 				   NULL, m->type, 0, subtype_is_struct, 1);
    792 
    793 	    add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }",
    794 		     m->label, isstruct ? "struct " : "",
    795 		     basetype, m->gen_name,
    796 		     dupname);
    797 
    798 	    free(elname);
    799 	    free(newbasename);
    800 	}
    801 
    802 	e = NULL;
    803 	if (ellipsis) {
    804 	    if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL)
    805 		errx(1, "malloc");
    806 	}
    807 
    808 	ASN1_TAILQ_FOREACH(q, &template, members) {
    809 	    count++;
    810 	}
    811 
    812 	fprintf(f, "static const struct asn1_template %s[] = {\n", tname);
    813 	fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)%lu) },\n",
    814 		e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count);
    815 	i = 1;
    816 	ASN1_TAILQ_FOREACH(q, &template, members) {
    817 	    int last = (ASN1_TAILQ_LAST(&template, templatehead) == q);
    818 	    fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
    819 	}
    820 	fprintf(f, "};\n");
    821 
    822 	add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname);
    823 
    824 	free(e);
    825 	free(tname);
    826 	break;
    827     }
    828     default:
    829 	abort ();
    830     }
    831     if (poffset)
    832 	free(poffset);
    833 }
    834 
    835 static void
    836 gen_extern_stubs(FILE *f, const char *name)
    837 {
    838     fprintf(f,
    839 	    "static const struct asn1_type_func asn1_extern_%s = {\n"
    840 	    "\t(asn1_type_encode)encode_%s,\n"
    841 	    "\t(asn1_type_decode)decode_%s,\n"
    842 	    "\t(asn1_type_length)length_%s,\n"
    843 	    "\t(asn1_type_copy)copy_%s,\n"
    844 	    "\t(asn1_type_release)free_%s,\n"
    845 	    "\tsizeof(%s)\n"
    846 	    "};\n",
    847 	    name, name, name, name,
    848 	    name, name, name);
    849 }
    850 
    851 void
    852 gen_template_import(const Symbol *s)
    853 {
    854     FILE *f = get_code_file();
    855 
    856     if (template_flag == 0)
    857 	return;
    858 
    859     gen_extern_stubs(f, s->gen_name);
    860 }
    861 
    862 static void
    863 generate_template_type(const char *varname,
    864 		       const char **dupname,
    865 		       const char *symname,
    866 		       const char *basetype,
    867 		       const char *name,
    868 		       Type *type,
    869 		       int optional, int isstruct, int need_offset)
    870 {
    871     struct tlist *tl;
    872     const char *d;
    873     char *szt = NULL;
    874     int have_ellipsis = 0;
    875     int implicit = 0;
    876     int n;
    877 
    878     tl = tlist_new(varname);
    879 
    880     if (type->type == TTag)
    881 	implicit = (type->tag.tagenv == TE_IMPLICIT);
    882 
    883     fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", tl->name);
    884 
    885     template_members(&tl->template, basetype, name, type, optional, implicit, isstruct, need_offset);
    886 
    887     /* if its a sequence or set type, check if there is a ellipsis */
    888     if (type->type == TSequence || type->type == TSet) {
    889 	Member *m;
    890 	ASN1_TAILQ_FOREACH(m, type->members, members) {
    891 	    if (m->ellipsis)
    892 		have_ellipsis = 1;
    893 	}
    894     }
    895 
    896     if (isstruct)
    897 	if (name)
    898 	    n = asprintf(&szt, "struct %s_%s", basetype, name);
    899 	else
    900 	    n = asprintf(&szt, "struct %s", basetype);
    901     else
    902 	n = asprintf(&szt, "%s", basetype);
    903     if (n < 0 || szt == NULL)
    904 	errx(1, "malloc");
    905 
    906     if (ASN1_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull)
    907 	errx(1, "Tag %s...%s with no content ?", basetype, name ? name : "");
    908 
    909     fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name);
    910 
    911     tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)%lu) }",
    912 		 (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "",
    913 		 have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl));
    914 
    915     free(szt);
    916 
    917     d = tlist_find_dup(tl);
    918     if (d) {
    919 #if 0
    920 	if (strcmp(d, tl->name) == 0)
    921 	    errx(1, "found dup of ourself: %s", d);
    922 #endif
    923 	*dupname = d;
    924     } else {
    925 	*dupname = tl->name;
    926 	tlist_print(tl);
    927 	tlist_add(tl);
    928     }
    929 }
    930 
    931 
    932 void
    933 generate_template(const Symbol *s)
    934 {
    935     FILE *f = get_code_file();
    936     const char *dupname;
    937 
    938     if (use_extern(s)) {
    939 	gen_extern_stubs(f, s->gen_name);
    940 	return;
    941     }
    942 
    943     generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1);
    944 
    945     fprintf(f,
    946 	    "\n"
    947 	    "int\n"
    948 	    "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n"
    949 	    "{\n"
    950 	    "    return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n"
    951 	    "}\n"
    952 	    "\n",
    953 	    s->gen_name,
    954 	    s->gen_name,
    955 	    dupname,
    956 	    support_ber ? "A1_PF_ALLOW_BER" : "0");
    957 
    958     fprintf(f,
    959 	    "\n"
    960 	    "int\n"
    961 	    "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n"
    962 	    "{\n"
    963 	    "    return _asn1_encode%s(asn1_%s, p, len, data, size);\n"
    964 	    "}\n"
    965 	    "\n",
    966 	    s->gen_name,
    967 	    s->gen_name,
    968 	    fuzzer_string,
    969 	    dupname);
    970 
    971     fprintf(f,
    972 	    "\n"
    973 	    "size_t\n"
    974 	    "length_%s(const %s *data)\n"
    975 	    "{\n"
    976 	    "    return _asn1_length%s(asn1_%s, data);\n"
    977 	    "}\n"
    978 	    "\n",
    979 	    s->gen_name,
    980 	    s->gen_name,
    981 	    fuzzer_string,
    982 	    dupname);
    983 
    984 
    985     fprintf(f,
    986 	    "\n"
    987 	    "void\n"
    988 	    "free_%s(%s *data)\n"
    989 	    "{\n"
    990 	    "    _asn1_free_top(asn1_%s, data);\n"
    991 	    "}\n"
    992 	    "\n",
    993 	    s->gen_name,
    994 	    s->gen_name,
    995 	    dupname);
    996 
    997     fprintf(f,
    998 	    "\n"
    999 	    "int\n"
   1000 	    "copy_%s(const %s *from, %s *to)\n"
   1001 	    "{\n"
   1002 	    "    return _asn1_copy_top(asn1_%s, from, to);\n"
   1003 	    "}\n"
   1004 	    "\n",
   1005 	    s->gen_name,
   1006 	    s->gen_name,
   1007 	    s->gen_name,
   1008 	    dupname);
   1009 }
   1010