xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/asn1/gen_template.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
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 H�gskolan
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 *
ttype_symbol(const char * basename,const Type * t)45 ttype_symbol(const char *basename, const Type *t)
46 {
47     return t->symbol->gen_name;
48 }
49 
50 static const char *
integer_symbol(const char * basename,const Type * t)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 *
boolean_symbol(const char * basename,const Type * t)72 boolean_symbol(const char *basename, const Type *t)
73 {
74     return "int";
75 }
76 
77 
78 static const char *
octetstring_symbol(const char * basename,const Type * t)79 octetstring_symbol(const char *basename, const Type *t)
80 {
81     return "heim_octet_string";
82 }
83 
84 static const char *
sequence_symbol(const char * basename,const Type * t)85 sequence_symbol(const char *basename, const Type *t)
86 {
87     return basename;
88 }
89 
90 static const char *
time_symbol(const char * basename,const Type * t)91 time_symbol(const char *basename, const Type *t)
92 {
93     return "time_t";
94 }
95 
96 static const char *
tag_symbol(const char * basename,const Type * t)97 tag_symbol(const char *basename, const Type *t)
98 {
99     return symbol_name(basename, t->subtype);
100 }
101 
102 static const char *
generalstring_symbol(const char * basename,const Type * t)103 generalstring_symbol(const char *basename, const Type *t)
104 {
105     return "heim_general_string";
106 }
107 
108 static const char *
printablestring_symbol(const char * basename,const Type * t)109 printablestring_symbol(const char *basename, const Type *t)
110 {
111     return "heim_printable_string";
112 }
113 
114 static const char *
ia5string_symbol(const char * basename,const Type * t)115 ia5string_symbol(const char *basename, const Type *t)
116 {
117     return "heim_ia5_string";
118 }
119 
120 static const char *
teletexstring_symbol(const char * basename,const Type * t)121 teletexstring_symbol(const char *basename, const Type *t)
122 {
123     return "heim_teletex_string";
124 }
125 
126 static const char *
visiblestring_symbol(const char * basename,const Type * t)127 visiblestring_symbol(const char *basename, const Type *t)
128 {
129     return "heim_visible_string";
130 }
131 
132 static const char *
utf8string_symbol(const char * basename,const Type * t)133 utf8string_symbol(const char *basename, const Type *t)
134 {
135     return "heim_utf8_string";
136 }
137 
138 static const char *
bmpstring_symbol(const char * basename,const Type * t)139 bmpstring_symbol(const char *basename, const Type *t)
140 {
141     return "heim_bmp_string";
142 }
143 
144 static const char *
universalstring_symbol(const char * basename,const Type * t)145 universalstring_symbol(const char *basename, const Type *t)
146 {
147     return "heim_universal_string";
148 }
149 
150 static const char *
oid_symbol(const char * basename,const Type * t)151 oid_symbol(const char *basename, const Type *t)
152 {
153     return "heim_oid";
154 }
155 
156 static const char *
bitstring_symbol(const char * basename,const Type * t)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 *
get_code_file(void)197 get_code_file(void)
198 {
199     if (!one_code_file)
200 	return templatefile;
201     return codefile;
202 }
203 
204 
205 static int
is_supported_type_p(const Type * t)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
is_template_compat(const Symbol * s)217 is_template_compat (const Symbol *s)
218 {
219     return is_supported_type_p(s->type);
220 }
221 
222 static const char *
symbol_name(const char * basename,const Type * t)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 *
partial_offset(const char * basetype,const char * name,int need_offset,int isstruct)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 *
tlist_new(const char * name)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
tlist_header(struct tlist * t,const char * fmt,...)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
tlist_count(struct tlist * tl)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
tlist_add(struct tlist * tl)309 tlist_add(struct tlist *tl)
310 {
311     ASN1_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers);
312 }
313 
314 static void
tlist_print(struct tlist * tl)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 *
tlist_find_by_name(const char * name)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
tlist_cmp_name(const char * tname,const char * qname)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
tlist_cmp(const struct tlist * tl,const struct tlist * ql)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 *
tlist_find_dup(const struct tlist * tl)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 *
add_line(struct templatehead * t,const char * fmt,...)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
add_line_pointer(struct templatehead * t,const char * ptr,const char * offset,const char * ttfmt,...)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
use_extern(const Symbol * s)442 use_extern(const Symbol *s)
443 {
444     if (s->type == NULL)
445 	return 1;
446     return 0;
447 }
448 
449 static int
is_struct(const Type * t,int isstruct)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 *
compact_tag(const Type * t)474 compact_tag(const Type *t)
475 {
476     while (t->type == TTag)
477 	t = t->subtype;
478     return t;
479 }
480 
481 static void
template_members(struct templatehead * temp,const char * basetype,const char * name,const Type * t,int optional,int implicit,int isstruct,int need_offset)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
gen_extern_stubs(FILE * f,const char * name)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
gen_template_import(const Symbol * s)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
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)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
generate_template(const Symbol * s)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