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