Linux Audio

Check our new training course

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