• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Simplified ASN.1 notation parser
2  *
3  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <ctype.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <linux/asn1_ber_bytecode.h>
22 
23 enum token_type {
24 	DIRECTIVE_ABSENT,
25 	DIRECTIVE_ALL,
26 	DIRECTIVE_ANY,
27 	DIRECTIVE_APPLICATION,
28 	DIRECTIVE_AUTOMATIC,
29 	DIRECTIVE_BEGIN,
30 	DIRECTIVE_BIT,
31 	DIRECTIVE_BMPString,
32 	DIRECTIVE_BOOLEAN,
33 	DIRECTIVE_BY,
34 	DIRECTIVE_CHARACTER,
35 	DIRECTIVE_CHOICE,
36 	DIRECTIVE_CLASS,
37 	DIRECTIVE_COMPONENT,
38 	DIRECTIVE_COMPONENTS,
39 	DIRECTIVE_CONSTRAINED,
40 	DIRECTIVE_CONTAINING,
41 	DIRECTIVE_DEFAULT,
42 	DIRECTIVE_DEFINED,
43 	DIRECTIVE_DEFINITIONS,
44 	DIRECTIVE_EMBEDDED,
45 	DIRECTIVE_ENCODED,
46 	DIRECTIVE_ENCODING_CONTROL,
47 	DIRECTIVE_END,
48 	DIRECTIVE_ENUMERATED,
49 	DIRECTIVE_EXCEPT,
50 	DIRECTIVE_EXPLICIT,
51 	DIRECTIVE_EXPORTS,
52 	DIRECTIVE_EXTENSIBILITY,
53 	DIRECTIVE_EXTERNAL,
54 	DIRECTIVE_FALSE,
55 	DIRECTIVE_FROM,
56 	DIRECTIVE_GeneralString,
57 	DIRECTIVE_GeneralizedTime,
58 	DIRECTIVE_GraphicString,
59 	DIRECTIVE_IA5String,
60 	DIRECTIVE_IDENTIFIER,
61 	DIRECTIVE_IMPLICIT,
62 	DIRECTIVE_IMPLIED,
63 	DIRECTIVE_IMPORTS,
64 	DIRECTIVE_INCLUDES,
65 	DIRECTIVE_INSTANCE,
66 	DIRECTIVE_INSTRUCTIONS,
67 	DIRECTIVE_INTEGER,
68 	DIRECTIVE_INTERSECTION,
69 	DIRECTIVE_ISO646String,
70 	DIRECTIVE_MAX,
71 	DIRECTIVE_MIN,
72 	DIRECTIVE_MINUS_INFINITY,
73 	DIRECTIVE_NULL,
74 	DIRECTIVE_NumericString,
75 	DIRECTIVE_OBJECT,
76 	DIRECTIVE_OCTET,
77 	DIRECTIVE_OF,
78 	DIRECTIVE_OPTIONAL,
79 	DIRECTIVE_ObjectDescriptor,
80 	DIRECTIVE_PATTERN,
81 	DIRECTIVE_PDV,
82 	DIRECTIVE_PLUS_INFINITY,
83 	DIRECTIVE_PRESENT,
84 	DIRECTIVE_PRIVATE,
85 	DIRECTIVE_PrintableString,
86 	DIRECTIVE_REAL,
87 	DIRECTIVE_RELATIVE_OID,
88 	DIRECTIVE_SEQUENCE,
89 	DIRECTIVE_SET,
90 	DIRECTIVE_SIZE,
91 	DIRECTIVE_STRING,
92 	DIRECTIVE_SYNTAX,
93 	DIRECTIVE_T61String,
94 	DIRECTIVE_TAGS,
95 	DIRECTIVE_TRUE,
96 	DIRECTIVE_TeletexString,
97 	DIRECTIVE_UNION,
98 	DIRECTIVE_UNIQUE,
99 	DIRECTIVE_UNIVERSAL,
100 	DIRECTIVE_UTCTime,
101 	DIRECTIVE_UTF8String,
102 	DIRECTIVE_UniversalString,
103 	DIRECTIVE_VideotexString,
104 	DIRECTIVE_VisibleString,
105 	DIRECTIVE_WITH,
106 	NR__DIRECTIVES,
107 	TOKEN_ASSIGNMENT = NR__DIRECTIVES,
108 	TOKEN_OPEN_CURLY,
109 	TOKEN_CLOSE_CURLY,
110 	TOKEN_OPEN_SQUARE,
111 	TOKEN_CLOSE_SQUARE,
112 	TOKEN_OPEN_ACTION,
113 	TOKEN_CLOSE_ACTION,
114 	TOKEN_COMMA,
115 	TOKEN_NUMBER,
116 	TOKEN_TYPE_NAME,
117 	TOKEN_ELEMENT_NAME,
118 	NR__TOKENS
119 };
120 
121 static const unsigned char token_to_tag[NR__TOKENS] = {
122 	/* EOC goes first */
123 	[DIRECTIVE_BOOLEAN]		= ASN1_BOOL,
124 	[DIRECTIVE_INTEGER]		= ASN1_INT,
125 	[DIRECTIVE_BIT]			= ASN1_BTS,
126 	[DIRECTIVE_OCTET]		= ASN1_OTS,
127 	[DIRECTIVE_NULL]		= ASN1_NULL,
128 	[DIRECTIVE_OBJECT]		= ASN1_OID,
129 	[DIRECTIVE_ObjectDescriptor]	= ASN1_ODE,
130 	[DIRECTIVE_EXTERNAL]		= ASN1_EXT,
131 	[DIRECTIVE_REAL]		= ASN1_REAL,
132 	[DIRECTIVE_ENUMERATED]		= ASN1_ENUM,
133 	[DIRECTIVE_EMBEDDED]		= 0,
134 	[DIRECTIVE_UTF8String]		= ASN1_UTF8STR,
135 	[DIRECTIVE_RELATIVE_OID]	= ASN1_RELOID,
136 	/* 14 */
137 	/* 15 */
138 	[DIRECTIVE_SEQUENCE]		= ASN1_SEQ,
139 	[DIRECTIVE_SET]			= ASN1_SET,
140 	[DIRECTIVE_NumericString]	= ASN1_NUMSTR,
141 	[DIRECTIVE_PrintableString]	= ASN1_PRNSTR,
142 	[DIRECTIVE_T61String]		= ASN1_TEXSTR,
143 	[DIRECTIVE_TeletexString]	= ASN1_TEXSTR,
144 	[DIRECTIVE_VideotexString]	= ASN1_VIDSTR,
145 	[DIRECTIVE_IA5String]		= ASN1_IA5STR,
146 	[DIRECTIVE_UTCTime]		= ASN1_UNITIM,
147 	[DIRECTIVE_GeneralizedTime]	= ASN1_GENTIM,
148 	[DIRECTIVE_GraphicString]	= ASN1_GRASTR,
149 	[DIRECTIVE_VisibleString]	= ASN1_VISSTR,
150 	[DIRECTIVE_GeneralString]	= ASN1_GENSTR,
151 	[DIRECTIVE_UniversalString]	= ASN1_UNITIM,
152 	[DIRECTIVE_CHARACTER]		= ASN1_CHRSTR,
153 	[DIRECTIVE_BMPString]		= ASN1_BMPSTR,
154 };
155 
156 static const char asn1_classes[4][5] = {
157 	[ASN1_UNIV]	= "UNIV",
158 	[ASN1_APPL]	= "APPL",
159 	[ASN1_CONT]	= "CONT",
160 	[ASN1_PRIV]	= "PRIV"
161 };
162 
163 static const char asn1_methods[2][5] = {
164 	[ASN1_UNIV]	= "PRIM",
165 	[ASN1_APPL]	= "CONS"
166 };
167 
168 static const char *const asn1_universal_tags[32] = {
169 	"EOC",
170 	"BOOL",
171 	"INT",
172 	"BTS",
173 	"OTS",
174 	"NULL",
175 	"OID",
176 	"ODE",
177 	"EXT",
178 	"REAL",
179 	"ENUM",
180 	"EPDV",
181 	"UTF8STR",
182 	"RELOID",
183 	NULL,		/* 14 */
184 	NULL,		/* 15 */
185 	"SEQ",
186 	"SET",
187 	"NUMSTR",
188 	"PRNSTR",
189 	"TEXSTR",
190 	"VIDSTR",
191 	"IA5STR",
192 	"UNITIM",
193 	"GENTIM",
194 	"GRASTR",
195 	"VISSTR",
196 	"GENSTR",
197 	"UNISTR",
198 	"CHRSTR",
199 	"BMPSTR",
200 	NULL		/* 31 */
201 };
202 
203 static const char *filename;
204 static const char *grammar_name;
205 static const char *outputname;
206 static const char *headername;
207 
208 static const char *const directives[NR__DIRECTIVES] = {
209 #define _(X) [DIRECTIVE_##X] = #X
210 	_(ABSENT),
211 	_(ALL),
212 	_(ANY),
213 	_(APPLICATION),
214 	_(AUTOMATIC),
215 	_(BEGIN),
216 	_(BIT),
217 	_(BMPString),
218 	_(BOOLEAN),
219 	_(BY),
220 	_(CHARACTER),
221 	_(CHOICE),
222 	_(CLASS),
223 	_(COMPONENT),
224 	_(COMPONENTS),
225 	_(CONSTRAINED),
226 	_(CONTAINING),
227 	_(DEFAULT),
228 	_(DEFINED),
229 	_(DEFINITIONS),
230 	_(EMBEDDED),
231 	_(ENCODED),
232 	[DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
233 	_(END),
234 	_(ENUMERATED),
235 	_(EXCEPT),
236 	_(EXPLICIT),
237 	_(EXPORTS),
238 	_(EXTENSIBILITY),
239 	_(EXTERNAL),
240 	_(FALSE),
241 	_(FROM),
242 	_(GeneralString),
243 	_(GeneralizedTime),
244 	_(GraphicString),
245 	_(IA5String),
246 	_(IDENTIFIER),
247 	_(IMPLICIT),
248 	_(IMPLIED),
249 	_(IMPORTS),
250 	_(INCLUDES),
251 	_(INSTANCE),
252 	_(INSTRUCTIONS),
253 	_(INTEGER),
254 	_(INTERSECTION),
255 	_(ISO646String),
256 	_(MAX),
257 	_(MIN),
258 	[DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
259 	[DIRECTIVE_NULL] = "NULL",
260 	_(NumericString),
261 	_(OBJECT),
262 	_(OCTET),
263 	_(OF),
264 	_(OPTIONAL),
265 	_(ObjectDescriptor),
266 	_(PATTERN),
267 	_(PDV),
268 	[DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
269 	_(PRESENT),
270 	_(PRIVATE),
271 	_(PrintableString),
272 	_(REAL),
273 	[DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
274 	_(SEQUENCE),
275 	_(SET),
276 	_(SIZE),
277 	_(STRING),
278 	_(SYNTAX),
279 	_(T61String),
280 	_(TAGS),
281 	_(TRUE),
282 	_(TeletexString),
283 	_(UNION),
284 	_(UNIQUE),
285 	_(UNIVERSAL),
286 	_(UTCTime),
287 	_(UTF8String),
288 	_(UniversalString),
289 	_(VideotexString),
290 	_(VisibleString),
291 	_(WITH)
292 };
293 
294 struct action {
295 	struct action	*next;
296 	unsigned char	index;
297 	char		name[];
298 };
299 
300 static struct action *action_list;
301 static unsigned nr_actions;
302 
303 struct token {
304 	unsigned short	line;
305 	enum token_type	token_type : 8;
306 	unsigned char	size;
307 	struct action	*action;
308 	const char	*value;
309 	struct type	*type;
310 };
311 
312 static struct token *token_list;
313 static unsigned nr_tokens;
314 
directive_compare(const void * _key,const void * _pdir)315 static int directive_compare(const void *_key, const void *_pdir)
316 {
317 	const struct token *token = _key;
318 	const char *const *pdir = _pdir, *dir = *pdir;
319 	size_t dlen, clen;
320 	int val;
321 
322 	dlen = strlen(dir);
323 	clen = (dlen < token->size) ? dlen : token->size;
324 
325 	//printf("cmp(%*.*s,%s) = ",
326 	//       (int)token->size, (int)token->size, token->value,
327 	//       dir);
328 
329 	val = memcmp(token->value, dir, clen);
330 	if (val != 0) {
331 		//printf("%d [cmp]\n", val);
332 		return val;
333 	}
334 
335 	if (dlen == token->size) {
336 		//printf("0\n");
337 		return 0;
338 	}
339 	//printf("%d\n", (int)dlen - (int)token->size);
340 	return dlen - token->size; /* shorter -> negative */
341 }
342 
343 /*
344  * Tokenise an ASN.1 grammar
345  */
tokenise(char * buffer,char * end)346 static void tokenise(char *buffer, char *end)
347 {
348 	struct token *tokens;
349 	char *line, *nl, *p, *q;
350 	unsigned tix, lineno;
351 
352 	/* Assume we're going to have half as many tokens as we have
353 	 * characters
354 	 */
355 	token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
356 	if (!tokens) {
357 		perror(NULL);
358 		exit(1);
359 	}
360 	tix = 0;
361 
362 	lineno = 0;
363 	while (buffer < end) {
364 		/* First of all, break out a line */
365 		lineno++;
366 		line = buffer;
367 		nl = memchr(line, '\n', end - buffer);
368 		if (!nl) {
369 			buffer = nl = end;
370 		} else {
371 			buffer = nl + 1;
372 			*nl = '\0';
373 		}
374 
375 		/* Remove "--" comments */
376 		p = line;
377 	next_comment:
378 		while ((p = memchr(p, '-', nl - p))) {
379 			if (p[1] == '-') {
380 				/* Found a comment; see if there's a terminator */
381 				q = p + 2;
382 				while ((q = memchr(q, '-', nl - q))) {
383 					if (q[1] == '-') {
384 						/* There is - excise the comment */
385 						q += 2;
386 						memmove(p, q, nl - q);
387 						goto next_comment;
388 					}
389 					q++;
390 				}
391 				*p = '\0';
392 				nl = p;
393 				break;
394 			} else {
395 				p++;
396 			}
397 		}
398 
399 		p = line;
400 		while (p < nl) {
401 			/* Skip white space */
402 			while (p < nl && isspace(*p))
403 				*(p++) = 0;
404 			if (p >= nl)
405 				break;
406 
407 			tokens[tix].line = lineno;
408 			tokens[tix].value = p;
409 
410 			/* Handle string tokens */
411 			if (isalpha(*p)) {
412 				const char **dir;
413 
414 				/* Can be a directive, type name or element
415 				 * name.  Find the end of the name.
416 				 */
417 				q = p + 1;
418 				while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
419 					q++;
420 				tokens[tix].size = q - p;
421 				p = q;
422 
423 				/* If it begins with a lowercase letter then
424 				 * it's an element name
425 				 */
426 				if (islower(tokens[tix].value[0])) {
427 					tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
428 					continue;
429 				}
430 
431 				/* Otherwise we need to search the directive
432 				 * table
433 				 */
434 				dir = bsearch(&tokens[tix], directives,
435 					      sizeof(directives) / sizeof(directives[1]),
436 					      sizeof(directives[1]),
437 					      directive_compare);
438 				if (dir) {
439 					tokens[tix++].token_type = dir - directives;
440 					continue;
441 				}
442 
443 				tokens[tix++].token_type = TOKEN_TYPE_NAME;
444 				continue;
445 			}
446 
447 			/* Handle numbers */
448 			if (isdigit(*p)) {
449 				/* Find the end of the number */
450 				q = p + 1;
451 				while (q < nl && (isdigit(*q)))
452 					q++;
453 				tokens[tix].size = q - p;
454 				p = q;
455 				tokens[tix++].token_type = TOKEN_NUMBER;
456 				continue;
457 			}
458 
459 			if (nl - p >= 3) {
460 				if (memcmp(p, "::=", 3) == 0) {
461 					p += 3;
462 					tokens[tix].size = 3;
463 					tokens[tix++].token_type = TOKEN_ASSIGNMENT;
464 					continue;
465 				}
466 			}
467 
468 			if (nl - p >= 2) {
469 				if (memcmp(p, "({", 2) == 0) {
470 					p += 2;
471 					tokens[tix].size = 2;
472 					tokens[tix++].token_type = TOKEN_OPEN_ACTION;
473 					continue;
474 				}
475 				if (memcmp(p, "})", 2) == 0) {
476 					p += 2;
477 					tokens[tix].size = 2;
478 					tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
479 					continue;
480 				}
481 			}
482 
483 			if (nl - p >= 1) {
484 				tokens[tix].size = 1;
485 				switch (*p) {
486 				case '{':
487 					p += 1;
488 					tokens[tix++].token_type = TOKEN_OPEN_CURLY;
489 					continue;
490 				case '}':
491 					p += 1;
492 					tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
493 					continue;
494 				case '[':
495 					p += 1;
496 					tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
497 					continue;
498 				case ']':
499 					p += 1;
500 					tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
501 					continue;
502 				case ',':
503 					p += 1;
504 					tokens[tix++].token_type = TOKEN_COMMA;
505 					continue;
506 				default:
507 					break;
508 				}
509 			}
510 
511 			fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
512 				filename, lineno, *p);
513 			exit(1);
514 		}
515 	}
516 
517 	nr_tokens = tix;
518 	printf("Extracted %u tokens\n", nr_tokens);
519 
520 #if 0
521 	{
522 		int n;
523 		for (n = 0; n < nr_tokens; n++)
524 			printf("Token %3u: '%*.*s'\n",
525 			       n,
526 			       (int)token_list[n].size, (int)token_list[n].size,
527 			       token_list[n].value);
528 	}
529 #endif
530 }
531 
532 static void build_type_list(void);
533 static void parse(void);
534 static void render(FILE *out, FILE *hdr);
535 
536 /*
537  *
538  */
main(int argc,char ** argv)539 int main(int argc, char **argv)
540 {
541 	struct stat st;
542 	ssize_t readlen;
543 	FILE *out, *hdr;
544 	char *buffer, *p;
545 	int fd;
546 
547 	if (argc != 4) {
548 		fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
549 			argv[0]);
550 		exit(2);
551 	}
552 
553 	filename = argv[1];
554 	outputname = argv[2];
555 	headername = argv[3];
556 
557 	fd = open(filename, O_RDONLY);
558 	if (fd < 0) {
559 		perror(filename);
560 		exit(1);
561 	}
562 
563 	if (fstat(fd, &st) < 0) {
564 		perror(filename);
565 		exit(1);
566 	}
567 
568 	if (!(buffer = malloc(st.st_size + 1))) {
569 		perror(NULL);
570 		exit(1);
571 	}
572 
573 	if ((readlen = read(fd, buffer, st.st_size)) < 0) {
574 		perror(filename);
575 		exit(1);
576 	}
577 
578 	if (close(fd) < 0) {
579 		perror(filename);
580 		exit(1);
581 	}
582 
583 	if (readlen != st.st_size) {
584 		fprintf(stderr, "%s: Short read\n", filename);
585 		exit(1);
586 	}
587 
588 	p = strrchr(argv[1], '/');
589 	p = p ? p + 1 : argv[1];
590 	grammar_name = strdup(p);
591 	if (!p) {
592 		perror(NULL);
593 		exit(1);
594 	}
595 	p = strchr(grammar_name, '.');
596 	if (p)
597 		*p = '\0';
598 
599 	buffer[readlen] = 0;
600 	tokenise(buffer, buffer + readlen);
601 	build_type_list();
602 	parse();
603 
604 	out = fopen(outputname, "w");
605 	if (!out) {
606 		perror(outputname);
607 		exit(1);
608 	}
609 
610 	hdr = fopen(headername, "w");
611 	if (!out) {
612 		perror(headername);
613 		exit(1);
614 	}
615 
616 	render(out, hdr);
617 
618 	if (fclose(out) < 0) {
619 		perror(outputname);
620 		exit(1);
621 	}
622 
623 	if (fclose(hdr) < 0) {
624 		perror(headername);
625 		exit(1);
626 	}
627 
628 	return 0;
629 }
630 
631 enum compound {
632 	NOT_COMPOUND,
633 	SET,
634 	SET_OF,
635 	SEQUENCE,
636 	SEQUENCE_OF,
637 	CHOICE,
638 	ANY,
639 	TYPE_REF,
640 	TAG_OVERRIDE
641 };
642 
643 struct element {
644 	struct type	*type_def;
645 	struct token	*name;
646 	struct token	*type;
647 	struct action	*action;
648 	struct element	*children;
649 	struct element	*next;
650 	struct element	*render_next;
651 	struct element	*list_next;
652 	uint8_t		n_elements;
653 	enum compound	compound : 8;
654 	enum asn1_class	class : 8;
655 	enum asn1_method method : 8;
656 	uint8_t		tag;
657 	unsigned	entry_index;
658 	unsigned	flags;
659 #define ELEMENT_IMPLICIT	0x0001
660 #define ELEMENT_EXPLICIT	0x0002
661 #define ELEMENT_MARKED		0x0004
662 #define ELEMENT_RENDERED	0x0008
663 #define ELEMENT_SKIPPABLE	0x0010
664 #define ELEMENT_CONDITIONAL	0x0020
665 };
666 
667 struct type {
668 	struct token	*name;
669 	struct token	*def;
670 	struct element	*element;
671 	unsigned	ref_count;
672 	unsigned	flags;
673 #define TYPE_STOP_MARKER	0x0001
674 #define TYPE_BEGIN		0x0002
675 };
676 
677 static struct type *type_list;
678 static struct type **type_index;
679 static unsigned nr_types;
680 
type_index_compare(const void * _a,const void * _b)681 static int type_index_compare(const void *_a, const void *_b)
682 {
683 	const struct type *const *a = _a, *const *b = _b;
684 
685 	if ((*a)->name->size != (*b)->name->size)
686 		return (*a)->name->size - (*b)->name->size;
687 	else
688 		return memcmp((*a)->name->value, (*b)->name->value,
689 			      (*a)->name->size);
690 }
691 
type_finder(const void * _key,const void * _ti)692 static int type_finder(const void *_key, const void *_ti)
693 {
694 	const struct token *token = _key;
695 	const struct type *const *ti = _ti;
696 	const struct type *type = *ti;
697 
698 	if (token->size != type->name->size)
699 		return token->size - type->name->size;
700 	else
701 		return memcmp(token->value, type->name->value,
702 			      token->size);
703 }
704 
705 /*
706  * Build up a list of types and a sorted index to that list.
707  */
build_type_list(void)708 static void build_type_list(void)
709 {
710 	struct type *types;
711 	unsigned nr, t, n;
712 
713 	nr = 0;
714 	for (n = 0; n < nr_tokens - 1; n++)
715 		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
716 		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
717 			nr++;
718 
719 	if (nr == 0) {
720 		fprintf(stderr, "%s: No defined types\n", filename);
721 		exit(1);
722 	}
723 
724 	nr_types = nr;
725 	types = type_list = calloc(nr + 1, sizeof(type_list[0]));
726 	if (!type_list) {
727 		perror(NULL);
728 		exit(1);
729 	}
730 	type_index = calloc(nr, sizeof(type_index[0]));
731 	if (!type_index) {
732 		perror(NULL);
733 		exit(1);
734 	}
735 
736 	t = 0;
737 	types[t].flags |= TYPE_BEGIN;
738 	for (n = 0; n < nr_tokens - 1; n++) {
739 		if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
740 		    token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
741 			types[t].name = &token_list[n];
742 			type_index[t] = &types[t];
743 			t++;
744 		}
745 	}
746 	types[t].name = &token_list[n + 1];
747 	types[t].flags |= TYPE_STOP_MARKER;
748 
749 	qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
750 
751 	printf("Extracted %u types\n", nr_types);
752 #if 0
753 	for (n = 0; n < nr_types; n++) {
754 		struct type *type = type_index[n];
755 		printf("- %*.*s\n",
756 		       (int)type->name->size,
757 		       (int)type->name->size,
758 		       type->name->value);
759 	}
760 #endif
761 }
762 
763 static struct element *parse_type(struct token **_cursor, struct token *stop,
764 				  struct token *name);
765 
766 /*
767  * Parse the token stream
768  */
parse(void)769 static void parse(void)
770 {
771 	struct token *cursor;
772 	struct type *type;
773 
774 	/* Parse one type definition statement at a time */
775 	type = type_list;
776 	do {
777 		cursor = type->name;
778 
779 		if (cursor[0].token_type != TOKEN_TYPE_NAME ||
780 		    cursor[1].token_type != TOKEN_ASSIGNMENT)
781 			abort();
782 		cursor += 2;
783 
784 		type->element = parse_type(&cursor, type[1].name, NULL);
785 		type->element->type_def = type;
786 
787 		if (cursor != type[1].name) {
788 			fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
789 				filename, cursor->line,
790 				(int)cursor->size, (int)cursor->size, cursor->value);
791 			exit(1);
792 		}
793 
794 	} while (type++, !(type->flags & TYPE_STOP_MARKER));
795 
796 	printf("Extracted %u actions\n", nr_actions);
797 }
798 
799 static struct element *element_list;
800 
alloc_elem(struct token * type)801 static struct element *alloc_elem(struct token *type)
802 {
803 	struct element *e = calloc(1, sizeof(*e));
804 	if (!e) {
805 		perror(NULL);
806 		exit(1);
807 	}
808 	e->list_next = element_list;
809 	element_list = e;
810 	return e;
811 }
812 
813 static struct element *parse_compound(struct token **_cursor, struct token *end,
814 				      int alternates);
815 
816 /*
817  * Parse one type definition statement
818  */
parse_type(struct token ** _cursor,struct token * end,struct token * name)819 static struct element *parse_type(struct token **_cursor, struct token *end,
820 				  struct token *name)
821 {
822 	struct element *top, *element;
823 	struct action *action, **ppaction;
824 	struct token *cursor = *_cursor;
825 	struct type **ref;
826 	char *p;
827 	int labelled = 0, implicit = 0;
828 
829 	top = element = alloc_elem(cursor);
830 	element->class = ASN1_UNIV;
831 	element->method = ASN1_PRIM;
832 	element->tag = token_to_tag[cursor->token_type];
833 	element->name = name;
834 
835 	/* Extract the tag value if one given */
836 	if (cursor->token_type == TOKEN_OPEN_SQUARE) {
837 		cursor++;
838 		if (cursor >= end)
839 			goto overrun_error;
840 		switch (cursor->token_type) {
841 		case DIRECTIVE_UNIVERSAL:
842 			element->class = ASN1_UNIV;
843 			cursor++;
844 			break;
845 		case DIRECTIVE_APPLICATION:
846 			element->class = ASN1_APPL;
847 			cursor++;
848 			break;
849 		case TOKEN_NUMBER:
850 			element->class = ASN1_CONT;
851 			break;
852 		case DIRECTIVE_PRIVATE:
853 			element->class = ASN1_PRIV;
854 			cursor++;
855 			break;
856 		default:
857 			fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
858 				filename, cursor->line,
859 				(int)cursor->size, (int)cursor->size, cursor->value);
860 			exit(1);
861 		}
862 
863 		if (cursor >= end)
864 			goto overrun_error;
865 		if (cursor->token_type != TOKEN_NUMBER) {
866 			fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
867 				filename, cursor->line,
868 				(int)cursor->size, (int)cursor->size, cursor->value);
869 			exit(1);
870 		}
871 
872 		element->tag &= ~0x1f;
873 		element->tag |= strtoul(cursor->value, &p, 10);
874 		if (p - cursor->value != cursor->size)
875 			abort();
876 		cursor++;
877 
878 		if (cursor >= end)
879 			goto overrun_error;
880 		if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
881 			fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
882 				filename, cursor->line,
883 				(int)cursor->size, (int)cursor->size, cursor->value);
884 			exit(1);
885 		}
886 		cursor++;
887 		if (cursor >= end)
888 			goto overrun_error;
889 		labelled = 1;
890 	}
891 
892 	/* Handle implicit and explicit markers */
893 	if (cursor->token_type == DIRECTIVE_IMPLICIT) {
894 		element->flags |= ELEMENT_IMPLICIT;
895 		implicit = 1;
896 		cursor++;
897 		if (cursor >= end)
898 			goto overrun_error;
899 	} else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
900 		element->flags |= ELEMENT_EXPLICIT;
901 		cursor++;
902 		if (cursor >= end)
903 			goto overrun_error;
904 	}
905 
906 	if (labelled) {
907 		if (!implicit)
908 			element->method |= ASN1_CONS;
909 		element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
910 		element->children = alloc_elem(cursor);
911 		element = element->children;
912 		element->class = ASN1_UNIV;
913 		element->method = ASN1_PRIM;
914 		element->tag = token_to_tag[cursor->token_type];
915 		element->name = name;
916 	}
917 
918 	/* Extract the type we're expecting here */
919 	element->type = cursor;
920 	switch (cursor->token_type) {
921 	case DIRECTIVE_ANY:
922 		element->compound = ANY;
923 		cursor++;
924 		break;
925 
926 	case DIRECTIVE_NULL:
927 	case DIRECTIVE_BOOLEAN:
928 	case DIRECTIVE_ENUMERATED:
929 	case DIRECTIVE_INTEGER:
930 		element->compound = NOT_COMPOUND;
931 		cursor++;
932 		break;
933 
934 	case DIRECTIVE_EXTERNAL:
935 		element->method = ASN1_CONS;
936 
937 	case DIRECTIVE_BMPString:
938 	case DIRECTIVE_GeneralString:
939 	case DIRECTIVE_GraphicString:
940 	case DIRECTIVE_IA5String:
941 	case DIRECTIVE_ISO646String:
942 	case DIRECTIVE_NumericString:
943 	case DIRECTIVE_PrintableString:
944 	case DIRECTIVE_T61String:
945 	case DIRECTIVE_TeletexString:
946 	case DIRECTIVE_UniversalString:
947 	case DIRECTIVE_UTF8String:
948 	case DIRECTIVE_VideotexString:
949 	case DIRECTIVE_VisibleString:
950 	case DIRECTIVE_ObjectDescriptor:
951 	case DIRECTIVE_GeneralizedTime:
952 	case DIRECTIVE_UTCTime:
953 		element->compound = NOT_COMPOUND;
954 		cursor++;
955 		break;
956 
957 	case DIRECTIVE_BIT:
958 	case DIRECTIVE_OCTET:
959 		element->compound = NOT_COMPOUND;
960 		cursor++;
961 		if (cursor >= end)
962 			goto overrun_error;
963 		if (cursor->token_type != DIRECTIVE_STRING)
964 			goto parse_error;
965 		cursor++;
966 		break;
967 
968 	case DIRECTIVE_OBJECT:
969 		element->compound = NOT_COMPOUND;
970 		cursor++;
971 		if (cursor >= end)
972 			goto overrun_error;
973 		if (cursor->token_type != DIRECTIVE_IDENTIFIER)
974 			goto parse_error;
975 		cursor++;
976 		break;
977 
978 	case TOKEN_TYPE_NAME:
979 		element->compound = TYPE_REF;
980 		ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
981 			      type_finder);
982 		if (!ref) {
983 			fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
984 				filename, cursor->line,
985 				(int)cursor->size, (int)cursor->size, cursor->value);
986 			exit(1);
987 		}
988 		cursor->type = *ref;
989 		(*ref)->ref_count++;
990 		cursor++;
991 		break;
992 
993 	case DIRECTIVE_CHOICE:
994 		element->compound = CHOICE;
995 		cursor++;
996 		element->children = parse_compound(&cursor, end, 1);
997 		break;
998 
999 	case DIRECTIVE_SEQUENCE:
1000 		element->compound = SEQUENCE;
1001 		element->method = ASN1_CONS;
1002 		cursor++;
1003 		if (cursor >= end)
1004 			goto overrun_error;
1005 		if (cursor->token_type == DIRECTIVE_OF) {
1006 			element->compound = SEQUENCE_OF;
1007 			cursor++;
1008 			if (cursor >= end)
1009 				goto overrun_error;
1010 			element->children = parse_type(&cursor, end, NULL);
1011 		} else {
1012 			element->children = parse_compound(&cursor, end, 0);
1013 		}
1014 		break;
1015 
1016 	case DIRECTIVE_SET:
1017 		element->compound = SET;
1018 		element->method = ASN1_CONS;
1019 		cursor++;
1020 		if (cursor >= end)
1021 			goto overrun_error;
1022 		if (cursor->token_type == DIRECTIVE_OF) {
1023 			element->compound = SET_OF;
1024 			cursor++;
1025 			if (cursor >= end)
1026 				goto parse_error;
1027 			element->children = parse_type(&cursor, end, NULL);
1028 		} else {
1029 			element->children = parse_compound(&cursor, end, 1);
1030 		}
1031 		break;
1032 
1033 	default:
1034 		fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
1035 			filename, cursor->line,
1036 			(int)cursor->size, (int)cursor->size, cursor->value);
1037 		exit(1);
1038 	}
1039 
1040 	/* Handle elements that are optional */
1041 	if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1042 			     cursor->token_type == DIRECTIVE_DEFAULT)
1043 	    ) {
1044 		cursor++;
1045 		top->flags |= ELEMENT_SKIPPABLE;
1046 	}
1047 
1048 	if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1049 		cursor++;
1050 		if (cursor >= end)
1051 			goto overrun_error;
1052 		if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1053 			fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
1054 				filename, cursor->line,
1055 				(int)cursor->size, (int)cursor->size, cursor->value);
1056 			exit(1);
1057 		}
1058 
1059 		action = malloc(sizeof(struct action) + cursor->size + 1);
1060 		if (!action) {
1061 			perror(NULL);
1062 			exit(1);
1063 		}
1064 		action->index = 0;
1065 		memcpy(action->name, cursor->value, cursor->size);
1066 		action->name[cursor->size] = 0;
1067 
1068 		for (ppaction = &action_list;
1069 		     *ppaction;
1070 		     ppaction = &(*ppaction)->next
1071 		     ) {
1072 			int cmp = strcmp(action->name, (*ppaction)->name);
1073 			if (cmp == 0) {
1074 				free(action);
1075 				action = *ppaction;
1076 				goto found;
1077 			}
1078 			if (cmp < 0) {
1079 				action->next = *ppaction;
1080 				*ppaction = action;
1081 				nr_actions++;
1082 				goto found;
1083 			}
1084 		}
1085 		action->next = NULL;
1086 		*ppaction = action;
1087 		nr_actions++;
1088 	found:
1089 
1090 		element->action = action;
1091 		cursor->action = action;
1092 		cursor++;
1093 		if (cursor >= end)
1094 			goto overrun_error;
1095 		if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1096 			fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
1097 				filename, cursor->line,
1098 				(int)cursor->size, (int)cursor->size, cursor->value);
1099 			exit(1);
1100 		}
1101 		cursor++;
1102 	}
1103 
1104 	*_cursor = cursor;
1105 	return top;
1106 
1107 parse_error:
1108 	fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
1109 		filename, cursor->line,
1110 		(int)cursor->size, (int)cursor->size, cursor->value);
1111 	exit(1);
1112 
1113 overrun_error:
1114 	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1115 	exit(1);
1116 }
1117 
1118 /*
1119  * Parse a compound type list
1120  */
parse_compound(struct token ** _cursor,struct token * end,int alternates)1121 static struct element *parse_compound(struct token **_cursor, struct token *end,
1122 				      int alternates)
1123 {
1124 	struct element *children, **child_p = &children, *element;
1125 	struct token *cursor = *_cursor, *name;
1126 
1127 	if (cursor->token_type != TOKEN_OPEN_CURLY) {
1128 		fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
1129 			filename, cursor->line,
1130 			(int)cursor->size, (int)cursor->size, cursor->value);
1131 		exit(1);
1132 	}
1133 	cursor++;
1134 	if (cursor >= end)
1135 		goto overrun_error;
1136 
1137 	if (cursor->token_type == TOKEN_OPEN_CURLY) {
1138 		fprintf(stderr, "%s:%d: Empty compound\n",
1139 			filename, cursor->line);
1140 		exit(1);
1141 	}
1142 
1143 	for (;;) {
1144 		name = NULL;
1145 		if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1146 			name = cursor;
1147 			cursor++;
1148 			if (cursor >= end)
1149 				goto overrun_error;
1150 		}
1151 
1152 		element = parse_type(&cursor, end, name);
1153 		if (alternates)
1154 			element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1155 
1156 		*child_p = element;
1157 		child_p = &element->next;
1158 
1159 		if (cursor >= end)
1160 			goto overrun_error;
1161 		if (cursor->token_type != TOKEN_COMMA)
1162 			break;
1163 		cursor++;
1164 		if (cursor >= end)
1165 			goto overrun_error;
1166 	}
1167 
1168 	children->flags &= ~ELEMENT_CONDITIONAL;
1169 
1170 	if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1171 		fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
1172 			filename, cursor->line,
1173 			(int)cursor->size, (int)cursor->size, cursor->value);
1174 		exit(1);
1175 	}
1176 	cursor++;
1177 
1178 	*_cursor = cursor;
1179 	return children;
1180 
1181 overrun_error:
1182 	fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1183 	exit(1);
1184 }
1185 
1186 static void render_element(FILE *out, struct element *e, struct element *tag);
1187 static void render_out_of_line_list(FILE *out);
1188 
1189 static int nr_entries;
1190 static int render_depth = 1;
1191 static struct element *render_list, **render_list_p = &render_list;
1192 
1193 __attribute__((format(printf, 2, 3)))
render_opcode(FILE * out,const char * fmt,...)1194 static void render_opcode(FILE *out, const char *fmt, ...)
1195 {
1196 	va_list va;
1197 
1198 	if (out) {
1199 		fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1200 		va_start(va, fmt);
1201 		vfprintf(out, fmt, va);
1202 		va_end(va);
1203 	}
1204 	nr_entries++;
1205 }
1206 
1207 __attribute__((format(printf, 2, 3)))
render_more(FILE * out,const char * fmt,...)1208 static void render_more(FILE *out, const char *fmt, ...)
1209 {
1210 	va_list va;
1211 
1212 	if (out) {
1213 		va_start(va, fmt);
1214 		vfprintf(out, fmt, va);
1215 		va_end(va);
1216 	}
1217 }
1218 
1219 /*
1220  * Render the grammar into a state machine definition.
1221  */
render(FILE * out,FILE * hdr)1222 static void render(FILE *out, FILE *hdr)
1223 {
1224 	struct element *e;
1225 	struct action *action;
1226 	struct type *root;
1227 	int index;
1228 
1229 	fprintf(hdr, "/*\n");
1230 	fprintf(hdr, " * Automatically generated by asn1_compiler.  Do not edit\n");
1231 	fprintf(hdr, " *\n");
1232 	fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1233 	fprintf(hdr, " */\n");
1234 	fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1235 	fprintf(hdr, "\n");
1236 	fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1237 	if (ferror(hdr)) {
1238 		perror(headername);
1239 		exit(1);
1240 	}
1241 
1242 	fprintf(out, "/*\n");
1243 	fprintf(out, " * Automatically generated by asn1_compiler.  Do not edit\n");
1244 	fprintf(out, " *\n");
1245 	fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1246 	fprintf(out, " */\n");
1247 	fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1248 	fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name);
1249 	fprintf(out, "\n");
1250 	if (ferror(out)) {
1251 		perror(outputname);
1252 		exit(1);
1253 	}
1254 
1255 	/* Tabulate the action functions we might have to call */
1256 	fprintf(hdr, "\n");
1257 	index = 0;
1258 	for (action = action_list; action; action = action->next) {
1259 		action->index = index++;
1260 		fprintf(hdr,
1261 			"extern int %s(void *, size_t, unsigned char,"
1262 			" const void *, size_t);\n",
1263 			action->name);
1264 	}
1265 	fprintf(hdr, "\n");
1266 
1267 	fprintf(out, "enum %s_actions {\n", grammar_name);
1268 	for (action = action_list; action; action = action->next)
1269 		fprintf(out, "\tACT_%s = %u,\n",
1270 			action->name, action->index);
1271 	fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1272 	fprintf(out, "};\n");
1273 
1274 	fprintf(out, "\n");
1275 	fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1276 		grammar_name, grammar_name);
1277 	for (action = action_list; action; action = action->next)
1278 		fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1279 	fprintf(out, "};\n");
1280 
1281 	if (ferror(out)) {
1282 		perror(outputname);
1283 		exit(1);
1284 	}
1285 
1286 	/* We do two passes - the first one calculates all the offsets */
1287 	printf("Pass 1\n");
1288 	nr_entries = 0;
1289 	root = &type_list[0];
1290 	render_element(NULL, root->element, NULL);
1291 	render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1292 	render_out_of_line_list(NULL);
1293 
1294 	for (e = element_list; e; e = e->list_next)
1295 		e->flags &= ~ELEMENT_RENDERED;
1296 
1297 	/* And then we actually render */
1298 	printf("Pass 2\n");
1299 	fprintf(out, "\n");
1300 	fprintf(out, "static const unsigned char %s_machine[] = {\n",
1301 		grammar_name);
1302 
1303 	nr_entries = 0;
1304 	root = &type_list[0];
1305 	render_element(out, root->element, NULL);
1306 	render_opcode(out, "ASN1_OP_COMPLETE,\n");
1307 	render_out_of_line_list(out);
1308 
1309 	fprintf(out, "};\n");
1310 
1311 	fprintf(out, "\n");
1312 	fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1313 	fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1314 	fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1315 	fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1316 	fprintf(out, "};\n");
1317 }
1318 
1319 /*
1320  * Render the out-of-line elements
1321  */
render_out_of_line_list(FILE * out)1322 static void render_out_of_line_list(FILE *out)
1323 {
1324 	struct element *e, *ce;
1325 	const char *act;
1326 	int entry;
1327 
1328 	while ((e = render_list)) {
1329 		render_list = e->render_next;
1330 		if (!render_list)
1331 			render_list_p = &render_list;
1332 
1333 		render_more(out, "\n");
1334 		e->entry_index = entry = nr_entries;
1335 		render_depth++;
1336 		for (ce = e->children; ce; ce = ce->next)
1337 			render_element(out, ce, NULL);
1338 		render_depth--;
1339 
1340 		act = e->action ? "_ACT" : "";
1341 		switch (e->compound) {
1342 		case SEQUENCE:
1343 			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1344 			break;
1345 		case SEQUENCE_OF:
1346 			render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1347 			render_opcode(out, "_jump_target(%u),\n", entry);
1348 			break;
1349 		case SET:
1350 			render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1351 			break;
1352 		case SET_OF:
1353 			render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1354 			render_opcode(out, "_jump_target(%u),\n", entry);
1355 			break;
1356 		}
1357 		if (e->action)
1358 			render_opcode(out, "_action(ACT_%s),\n",
1359 				      e->action->name);
1360 		render_opcode(out, "ASN1_OP_RETURN,\n");
1361 	}
1362 }
1363 
1364 /*
1365  * Render an element.
1366  */
render_element(FILE * out,struct element * e,struct element * tag)1367 static void render_element(FILE *out, struct element *e, struct element *tag)
1368 {
1369 	struct element *ec;
1370 	const char *cond, *act;
1371 	int entry, skippable = 0, outofline = 0;
1372 
1373 	if (e->flags & ELEMENT_SKIPPABLE ||
1374 	    (tag && tag->flags & ELEMENT_SKIPPABLE))
1375 		skippable = 1;
1376 
1377 	if ((e->type_def && e->type_def->ref_count > 1) ||
1378 	    skippable)
1379 		outofline = 1;
1380 
1381 	if (e->type_def && out) {
1382 		render_more(out, "\t// %*.*s\n",
1383 			    (int)e->type_def->name->size, (int)e->type_def->name->size,
1384 			    e->type_def->name->value);
1385 	}
1386 
1387 	/* Render the operation */
1388 	cond = (e->flags & ELEMENT_CONDITIONAL ||
1389 		(tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1390 	act = e->action ? "_ACT" : "";
1391 	switch (e->compound) {
1392 	case ANY:
1393 		render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
1394 		if (e->name)
1395 			render_more(out, "\t\t// %*.*s",
1396 				    (int)e->name->size, (int)e->name->size,
1397 				    e->name->value);
1398 		render_more(out, "\n");
1399 		goto dont_render_tag;
1400 
1401 	case TAG_OVERRIDE:
1402 		render_element(out, e->children, e);
1403 		return;
1404 
1405 	case SEQUENCE:
1406 	case SEQUENCE_OF:
1407 	case SET:
1408 	case SET_OF:
1409 		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1410 			      cond,
1411 			      outofline ? "_JUMP" : "",
1412 			      skippable ? "_OR_SKIP" : "");
1413 		break;
1414 
1415 	case CHOICE:
1416 		goto dont_render_tag;
1417 
1418 	case TYPE_REF:
1419 		if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1420 			goto dont_render_tag;
1421 	default:
1422 		render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1423 			      cond, act,
1424 			      skippable ? "_OR_SKIP" : "");
1425 		break;
1426 	}
1427 
1428 	if (e->name)
1429 		render_more(out, "\t\t// %*.*s",
1430 			    (int)e->name->size, (int)e->name->size,
1431 			    e->name->value);
1432 	render_more(out, "\n");
1433 
1434 	/* Render the tag */
1435 	if (!tag)
1436 		tag = e;
1437 	if (tag->class == ASN1_UNIV &&
1438 	    tag->tag != 14 &&
1439 	    tag->tag != 15 &&
1440 	    tag->tag != 31)
1441 		render_opcode(out, "_tag(%s, %s, %s),\n",
1442 			      asn1_classes[tag->class],
1443 			      asn1_methods[tag->method | e->method],
1444 			      asn1_universal_tags[tag->tag]);
1445 	else
1446 		render_opcode(out, "_tagn(%s, %s, %2u),\n",
1447 			      asn1_classes[tag->class],
1448 			      asn1_methods[tag->method | e->method],
1449 			      tag->tag);
1450 	tag = NULL;
1451 dont_render_tag:
1452 
1453 	/* Deal with compound types */
1454 	switch (e->compound) {
1455 	case TYPE_REF:
1456 		render_element(out, e->type->type->element, tag);
1457 		if (e->action)
1458 			render_opcode(out, "ASN1_OP_ACT,\n");
1459 		break;
1460 
1461 	case SEQUENCE:
1462 		if (outofline) {
1463 			/* Render out-of-line for multiple use or
1464 			 * skipability */
1465 			render_opcode(out, "_jump_target(%u),", e->entry_index);
1466 			if (e->type_def && e->type_def->name)
1467 				render_more(out, "\t\t// --> %*.*s",
1468 					    (int)e->type_def->name->size,
1469 					    (int)e->type_def->name->size,
1470 					    e->type_def->name->value);
1471 			render_more(out, "\n");
1472 			if (!(e->flags & ELEMENT_RENDERED)) {
1473 				e->flags |= ELEMENT_RENDERED;
1474 				*render_list_p = e;
1475 				render_list_p = &e->render_next;
1476 			}
1477 			return;
1478 		} else {
1479 			/* Render inline for single use */
1480 			render_depth++;
1481 			for (ec = e->children; ec; ec = ec->next)
1482 				render_element(out, ec, NULL);
1483 			render_depth--;
1484 			render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1485 		}
1486 		break;
1487 
1488 	case SEQUENCE_OF:
1489 	case SET_OF:
1490 		if (outofline) {
1491 			/* Render out-of-line for multiple use or
1492 			 * skipability */
1493 			render_opcode(out, "_jump_target(%u),", e->entry_index);
1494 			if (e->type_def && e->type_def->name)
1495 				render_more(out, "\t\t// --> %*.*s",
1496 					    (int)e->type_def->name->size,
1497 					    (int)e->type_def->name->size,
1498 					    e->type_def->name->value);
1499 			render_more(out, "\n");
1500 			if (!(e->flags & ELEMENT_RENDERED)) {
1501 				e->flags |= ELEMENT_RENDERED;
1502 				*render_list_p = e;
1503 				render_list_p = &e->render_next;
1504 			}
1505 			return;
1506 		} else {
1507 			/* Render inline for single use */
1508 			entry = nr_entries;
1509 			render_depth++;
1510 			render_element(out, e->children, NULL);
1511 			render_depth--;
1512 			if (e->compound == SEQUENCE_OF)
1513 				render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1514 			else
1515 				render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1516 			render_opcode(out, "_jump_target(%u),\n", entry);
1517 		}
1518 		break;
1519 
1520 	case SET:
1521 		/* I can't think of a nice way to do SET support without having
1522 		 * a stack of bitmasks to make sure no element is repeated.
1523 		 * The bitmask has also to be checked that no non-optional
1524 		 * elements are left out whilst not preventing optional
1525 		 * elements from being left out.
1526 		 */
1527 		fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1528 		exit(1);
1529 
1530 	case CHOICE:
1531 		for (ec = e->children; ec; ec = ec->next)
1532 			render_element(out, ec, NULL);
1533 		if (!skippable)
1534 			render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1535 		if (e->action)
1536 			render_opcode(out, "ASN1_OP_ACT,\n");
1537 		break;
1538 
1539 	default:
1540 		break;
1541 	}
1542 
1543 	if (e->action)
1544 		render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1545 }
1546