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