blob: 7750e9c31483b99bdf467db98757ca16e7152847 [file] [log] [blame]
David Howells4520c6a2012-09-21 23:31:13 +01001/* 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;
Arnd Bergmanne9943932015-01-13 22:24:31 +0100314static _Bool verbose;
315
316#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
David Howells4520c6a2012-09-21 23:31:13 +0100317
318static int directive_compare(const void *_key, const void *_pdir)
319{
320 const struct token *token = _key;
321 const char *const *pdir = _pdir, *dir = *pdir;
322 size_t dlen, clen;
323 int val;
324
325 dlen = strlen(dir);
326 clen = (dlen < token->size) ? dlen : token->size;
327
Arnd Bergmanne9943932015-01-13 22:24:31 +0100328 //debug("cmp(%*.*s,%s) = ",
David Howells4520c6a2012-09-21 23:31:13 +0100329 // (int)token->size, (int)token->size, token->value,
330 // dir);
331
332 val = memcmp(token->value, dir, clen);
333 if (val != 0) {
Arnd Bergmanne9943932015-01-13 22:24:31 +0100334 //debug("%d [cmp]\n", val);
David Howells4520c6a2012-09-21 23:31:13 +0100335 return val;
336 }
337
338 if (dlen == token->size) {
Arnd Bergmanne9943932015-01-13 22:24:31 +0100339 //debug("0\n");
David Howells4520c6a2012-09-21 23:31:13 +0100340 return 0;
341 }
Arnd Bergmanne9943932015-01-13 22:24:31 +0100342 //debug("%d\n", (int)dlen - (int)token->size);
David Howells4520c6a2012-09-21 23:31:13 +0100343 return dlen - token->size; /* shorter -> negative */
344}
345
346/*
347 * Tokenise an ASN.1 grammar
348 */
349static void tokenise(char *buffer, char *end)
350{
351 struct token *tokens;
352 char *line, *nl, *p, *q;
353 unsigned tix, lineno;
354
355 /* Assume we're going to have half as many tokens as we have
356 * characters
357 */
358 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
359 if (!tokens) {
360 perror(NULL);
361 exit(1);
362 }
363 tix = 0;
364
365 lineno = 0;
366 while (buffer < end) {
367 /* First of all, break out a line */
368 lineno++;
369 line = buffer;
370 nl = memchr(line, '\n', end - buffer);
371 if (!nl) {
372 buffer = nl = end;
373 } else {
374 buffer = nl + 1;
375 *nl = '\0';
376 }
377
378 /* Remove "--" comments */
379 p = line;
380 next_comment:
381 while ((p = memchr(p, '-', nl - p))) {
382 if (p[1] == '-') {
383 /* Found a comment; see if there's a terminator */
384 q = p + 2;
385 while ((q = memchr(q, '-', nl - q))) {
386 if (q[1] == '-') {
387 /* There is - excise the comment */
388 q += 2;
389 memmove(p, q, nl - q);
390 goto next_comment;
391 }
392 q++;
393 }
394 *p = '\0';
395 nl = p;
396 break;
397 } else {
398 p++;
399 }
400 }
401
402 p = line;
403 while (p < nl) {
404 /* Skip white space */
405 while (p < nl && isspace(*p))
406 *(p++) = 0;
407 if (p >= nl)
408 break;
409
410 tokens[tix].line = lineno;
411 tokens[tix].value = p;
412
413 /* Handle string tokens */
414 if (isalpha(*p)) {
415 const char **dir;
416
417 /* Can be a directive, type name or element
418 * name. Find the end of the name.
419 */
420 q = p + 1;
421 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
422 q++;
423 tokens[tix].size = q - p;
424 p = q;
425
426 /* If it begins with a lowercase letter then
427 * it's an element name
428 */
429 if (islower(tokens[tix].value[0])) {
430 tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
431 continue;
432 }
433
434 /* Otherwise we need to search the directive
435 * table
436 */
437 dir = bsearch(&tokens[tix], directives,
438 sizeof(directives) / sizeof(directives[1]),
439 sizeof(directives[1]),
440 directive_compare);
441 if (dir) {
442 tokens[tix++].token_type = dir - directives;
443 continue;
444 }
445
446 tokens[tix++].token_type = TOKEN_TYPE_NAME;
447 continue;
448 }
449
450 /* Handle numbers */
451 if (isdigit(*p)) {
452 /* Find the end of the number */
453 q = p + 1;
454 while (q < nl && (isdigit(*q)))
455 q++;
456 tokens[tix].size = q - p;
457 p = q;
458 tokens[tix++].token_type = TOKEN_NUMBER;
459 continue;
460 }
461
462 if (nl - p >= 3) {
463 if (memcmp(p, "::=", 3) == 0) {
464 p += 3;
465 tokens[tix].size = 3;
466 tokens[tix++].token_type = TOKEN_ASSIGNMENT;
467 continue;
468 }
469 }
470
471 if (nl - p >= 2) {
472 if (memcmp(p, "({", 2) == 0) {
473 p += 2;
474 tokens[tix].size = 2;
475 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
476 continue;
477 }
478 if (memcmp(p, "})", 2) == 0) {
479 p += 2;
480 tokens[tix].size = 2;
481 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
482 continue;
483 }
484 }
485
486 if (nl - p >= 1) {
487 tokens[tix].size = 1;
488 switch (*p) {
489 case '{':
490 p += 1;
491 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
492 continue;
493 case '}':
494 p += 1;
495 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
496 continue;
497 case '[':
498 p += 1;
499 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
500 continue;
501 case ']':
502 p += 1;
503 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
504 continue;
505 case ',':
506 p += 1;
507 tokens[tix++].token_type = TOKEN_COMMA;
508 continue;
509 default:
510 break;
511 }
512 }
513
514 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
515 filename, lineno, *p);
516 exit(1);
517 }
518 }
519
520 nr_tokens = tix;
Arnd Bergmanne9943932015-01-13 22:24:31 +0100521 debug("Extracted %u tokens\n", nr_tokens);
David Howells4520c6a2012-09-21 23:31:13 +0100522
523#if 0
524 {
525 int n;
526 for (n = 0; n < nr_tokens; n++)
Arnd Bergmanne9943932015-01-13 22:24:31 +0100527 debug("Token %3u: '%*.*s'\n",
David Howells4520c6a2012-09-21 23:31:13 +0100528 n,
529 (int)token_list[n].size, (int)token_list[n].size,
530 token_list[n].value);
531 }
532#endif
533}
534
535static void build_type_list(void);
536static void parse(void);
537static void render(FILE *out, FILE *hdr);
538
539/*
540 *
541 */
542int main(int argc, char **argv)
543{
544 struct stat st;
545 ssize_t readlen;
546 FILE *out, *hdr;
547 char *buffer, *p;
Arnd Bergmanne9943932015-01-13 22:24:31 +0100548 char *kbuild_verbose;
David Howells4520c6a2012-09-21 23:31:13 +0100549 int fd;
550
551 if (argc != 4) {
552 fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
553 argv[0]);
554 exit(2);
555 }
556
Arnd Bergmanne9943932015-01-13 22:24:31 +0100557 kbuild_verbose = getenv("KBUILD_VERBOSE");
558 if (kbuild_verbose)
559 verbose = atoi(kbuild_verbose);
560
David Howells4520c6a2012-09-21 23:31:13 +0100561 filename = argv[1];
562 outputname = argv[2];
563 headername = argv[3];
564
565 fd = open(filename, O_RDONLY);
566 if (fd < 0) {
567 perror(filename);
568 exit(1);
569 }
570
571 if (fstat(fd, &st) < 0) {
572 perror(filename);
573 exit(1);
574 }
575
576 if (!(buffer = malloc(st.st_size + 1))) {
577 perror(NULL);
578 exit(1);
579 }
580
581 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
582 perror(filename);
583 exit(1);
584 }
585
586 if (close(fd) < 0) {
587 perror(filename);
588 exit(1);
589 }
590
591 if (readlen != st.st_size) {
592 fprintf(stderr, "%s: Short read\n", filename);
593 exit(1);
594 }
595
596 p = strrchr(argv[1], '/');
597 p = p ? p + 1 : argv[1];
598 grammar_name = strdup(p);
599 if (!p) {
600 perror(NULL);
601 exit(1);
602 }
603 p = strchr(grammar_name, '.');
604 if (p)
605 *p = '\0';
606
607 buffer[readlen] = 0;
608 tokenise(buffer, buffer + readlen);
609 build_type_list();
610 parse();
611
612 out = fopen(outputname, "w");
613 if (!out) {
614 perror(outputname);
615 exit(1);
616 }
617
618 hdr = fopen(headername, "w");
619 if (!out) {
620 perror(headername);
621 exit(1);
622 }
623
624 render(out, hdr);
625
626 if (fclose(out) < 0) {
627 perror(outputname);
628 exit(1);
629 }
630
631 if (fclose(hdr) < 0) {
632 perror(headername);
633 exit(1);
634 }
635
636 return 0;
637}
638
639enum compound {
640 NOT_COMPOUND,
641 SET,
642 SET_OF,
643 SEQUENCE,
644 SEQUENCE_OF,
645 CHOICE,
646 ANY,
647 TYPE_REF,
648 TAG_OVERRIDE
649};
650
651struct element {
652 struct type *type_def;
653 struct token *name;
654 struct token *type;
655 struct action *action;
656 struct element *children;
657 struct element *next;
658 struct element *render_next;
659 struct element *list_next;
660 uint8_t n_elements;
661 enum compound compound : 8;
662 enum asn1_class class : 8;
663 enum asn1_method method : 8;
664 uint8_t tag;
665 unsigned entry_index;
666 unsigned flags;
667#define ELEMENT_IMPLICIT 0x0001
668#define ELEMENT_EXPLICIT 0x0002
669#define ELEMENT_MARKED 0x0004
670#define ELEMENT_RENDERED 0x0008
671#define ELEMENT_SKIPPABLE 0x0010
672#define ELEMENT_CONDITIONAL 0x0020
673};
674
675struct type {
676 struct token *name;
677 struct token *def;
678 struct element *element;
679 unsigned ref_count;
680 unsigned flags;
681#define TYPE_STOP_MARKER 0x0001
682#define TYPE_BEGIN 0x0002
683};
684
685static struct type *type_list;
686static struct type **type_index;
687static unsigned nr_types;
688
689static int type_index_compare(const void *_a, const void *_b)
690{
691 const struct type *const *a = _a, *const *b = _b;
692
693 if ((*a)->name->size != (*b)->name->size)
694 return (*a)->name->size - (*b)->name->size;
695 else
696 return memcmp((*a)->name->value, (*b)->name->value,
697 (*a)->name->size);
698}
699
700static int type_finder(const void *_key, const void *_ti)
701{
702 const struct token *token = _key;
703 const struct type *const *ti = _ti;
704 const struct type *type = *ti;
705
706 if (token->size != type->name->size)
707 return token->size - type->name->size;
708 else
709 return memcmp(token->value, type->name->value,
710 token->size);
711}
712
713/*
714 * Build up a list of types and a sorted index to that list.
715 */
716static void build_type_list(void)
717{
718 struct type *types;
719 unsigned nr, t, n;
720
721 nr = 0;
722 for (n = 0; n < nr_tokens - 1; n++)
723 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
724 token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
725 nr++;
726
727 if (nr == 0) {
728 fprintf(stderr, "%s: No defined types\n", filename);
729 exit(1);
730 }
731
732 nr_types = nr;
733 types = type_list = calloc(nr + 1, sizeof(type_list[0]));
734 if (!type_list) {
735 perror(NULL);
736 exit(1);
737 }
738 type_index = calloc(nr, sizeof(type_index[0]));
739 if (!type_index) {
740 perror(NULL);
741 exit(1);
742 }
743
744 t = 0;
745 types[t].flags |= TYPE_BEGIN;
746 for (n = 0; n < nr_tokens - 1; n++) {
747 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
748 token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
749 types[t].name = &token_list[n];
750 type_index[t] = &types[t];
751 t++;
752 }
753 }
754 types[t].name = &token_list[n + 1];
755 types[t].flags |= TYPE_STOP_MARKER;
756
757 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
758
Arnd Bergmanne9943932015-01-13 22:24:31 +0100759 debug("Extracted %u types\n", nr_types);
David Howells4520c6a2012-09-21 23:31:13 +0100760#if 0
761 for (n = 0; n < nr_types; n++) {
762 struct type *type = type_index[n];
Arnd Bergmanne9943932015-01-13 22:24:31 +0100763 debug("- %*.*s\n",
David Howells4520c6a2012-09-21 23:31:13 +0100764 (int)type->name->size,
765 (int)type->name->size,
766 type->name->value);
767 }
768#endif
769}
770
771static struct element *parse_type(struct token **_cursor, struct token *stop,
772 struct token *name);
773
774/*
775 * Parse the token stream
776 */
777static void parse(void)
778{
779 struct token *cursor;
780 struct type *type;
781
782 /* Parse one type definition statement at a time */
783 type = type_list;
784 do {
785 cursor = type->name;
786
787 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
788 cursor[1].token_type != TOKEN_ASSIGNMENT)
789 abort();
790 cursor += 2;
791
792 type->element = parse_type(&cursor, type[1].name, NULL);
793 type->element->type_def = type;
794
795 if (cursor != type[1].name) {
796 fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
797 filename, cursor->line,
798 (int)cursor->size, (int)cursor->size, cursor->value);
799 exit(1);
800 }
801
802 } while (type++, !(type->flags & TYPE_STOP_MARKER));
803
Arnd Bergmanne9943932015-01-13 22:24:31 +0100804 debug("Extracted %u actions\n", nr_actions);
David Howells4520c6a2012-09-21 23:31:13 +0100805}
806
807static struct element *element_list;
808
809static struct element *alloc_elem(struct token *type)
810{
811 struct element *e = calloc(1, sizeof(*e));
812 if (!e) {
813 perror(NULL);
814 exit(1);
815 }
816 e->list_next = element_list;
817 element_list = e;
818 return e;
819}
820
821static struct element *parse_compound(struct token **_cursor, struct token *end,
822 int alternates);
823
824/*
825 * Parse one type definition statement
826 */
827static struct element *parse_type(struct token **_cursor, struct token *end,
828 struct token *name)
829{
830 struct element *top, *element;
831 struct action *action, **ppaction;
832 struct token *cursor = *_cursor;
833 struct type **ref;
834 char *p;
835 int labelled = 0, implicit = 0;
836
837 top = element = alloc_elem(cursor);
838 element->class = ASN1_UNIV;
839 element->method = ASN1_PRIM;
840 element->tag = token_to_tag[cursor->token_type];
841 element->name = name;
842
843 /* Extract the tag value if one given */
844 if (cursor->token_type == TOKEN_OPEN_SQUARE) {
845 cursor++;
846 if (cursor >= end)
847 goto overrun_error;
848 switch (cursor->token_type) {
849 case DIRECTIVE_UNIVERSAL:
850 element->class = ASN1_UNIV;
851 cursor++;
852 break;
853 case DIRECTIVE_APPLICATION:
854 element->class = ASN1_APPL;
855 cursor++;
856 break;
857 case TOKEN_NUMBER:
858 element->class = ASN1_CONT;
859 break;
860 case DIRECTIVE_PRIVATE:
861 element->class = ASN1_PRIV;
862 cursor++;
863 break;
864 default:
865 fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
866 filename, cursor->line,
867 (int)cursor->size, (int)cursor->size, cursor->value);
868 exit(1);
869 }
870
871 if (cursor >= end)
872 goto overrun_error;
873 if (cursor->token_type != TOKEN_NUMBER) {
874 fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
875 filename, cursor->line,
876 (int)cursor->size, (int)cursor->size, cursor->value);
877 exit(1);
878 }
879
880 element->tag &= ~0x1f;
881 element->tag |= strtoul(cursor->value, &p, 10);
882 if (p - cursor->value != cursor->size)
883 abort();
884 cursor++;
885
886 if (cursor >= end)
887 goto overrun_error;
888 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
889 fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
890 filename, cursor->line,
891 (int)cursor->size, (int)cursor->size, cursor->value);
892 exit(1);
893 }
894 cursor++;
895 if (cursor >= end)
896 goto overrun_error;
897 labelled = 1;
898 }
899
900 /* Handle implicit and explicit markers */
901 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
902 element->flags |= ELEMENT_IMPLICIT;
903 implicit = 1;
904 cursor++;
905 if (cursor >= end)
906 goto overrun_error;
907 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
908 element->flags |= ELEMENT_EXPLICIT;
909 cursor++;
910 if (cursor >= end)
911 goto overrun_error;
912 }
913
914 if (labelled) {
915 if (!implicit)
916 element->method |= ASN1_CONS;
917 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
918 element->children = alloc_elem(cursor);
919 element = element->children;
920 element->class = ASN1_UNIV;
921 element->method = ASN1_PRIM;
922 element->tag = token_to_tag[cursor->token_type];
923 element->name = name;
924 }
925
926 /* Extract the type we're expecting here */
927 element->type = cursor;
928 switch (cursor->token_type) {
929 case DIRECTIVE_ANY:
930 element->compound = ANY;
931 cursor++;
932 break;
933
934 case DIRECTIVE_NULL:
935 case DIRECTIVE_BOOLEAN:
936 case DIRECTIVE_ENUMERATED:
937 case DIRECTIVE_INTEGER:
938 element->compound = NOT_COMPOUND;
939 cursor++;
940 break;
941
942 case DIRECTIVE_EXTERNAL:
943 element->method = ASN1_CONS;
944
945 case DIRECTIVE_BMPString:
946 case DIRECTIVE_GeneralString:
947 case DIRECTIVE_GraphicString:
948 case DIRECTIVE_IA5String:
949 case DIRECTIVE_ISO646String:
950 case DIRECTIVE_NumericString:
951 case DIRECTIVE_PrintableString:
952 case DIRECTIVE_T61String:
953 case DIRECTIVE_TeletexString:
954 case DIRECTIVE_UniversalString:
955 case DIRECTIVE_UTF8String:
956 case DIRECTIVE_VideotexString:
957 case DIRECTIVE_VisibleString:
958 case DIRECTIVE_ObjectDescriptor:
959 case DIRECTIVE_GeneralizedTime:
960 case DIRECTIVE_UTCTime:
961 element->compound = NOT_COMPOUND;
962 cursor++;
963 break;
964
965 case DIRECTIVE_BIT:
966 case DIRECTIVE_OCTET:
967 element->compound = NOT_COMPOUND;
968 cursor++;
969 if (cursor >= end)
970 goto overrun_error;
971 if (cursor->token_type != DIRECTIVE_STRING)
972 goto parse_error;
973 cursor++;
974 break;
975
976 case DIRECTIVE_OBJECT:
977 element->compound = NOT_COMPOUND;
978 cursor++;
979 if (cursor >= end)
980 goto overrun_error;
981 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
982 goto parse_error;
983 cursor++;
984 break;
985
986 case TOKEN_TYPE_NAME:
987 element->compound = TYPE_REF;
988 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
989 type_finder);
990 if (!ref) {
991 fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
992 filename, cursor->line,
993 (int)cursor->size, (int)cursor->size, cursor->value);
994 exit(1);
995 }
996 cursor->type = *ref;
997 (*ref)->ref_count++;
998 cursor++;
999 break;
1000
1001 case DIRECTIVE_CHOICE:
1002 element->compound = CHOICE;
1003 cursor++;
1004 element->children = parse_compound(&cursor, end, 1);
1005 break;
1006
1007 case DIRECTIVE_SEQUENCE:
1008 element->compound = SEQUENCE;
1009 element->method = ASN1_CONS;
1010 cursor++;
1011 if (cursor >= end)
1012 goto overrun_error;
1013 if (cursor->token_type == DIRECTIVE_OF) {
1014 element->compound = SEQUENCE_OF;
1015 cursor++;
1016 if (cursor >= end)
1017 goto overrun_error;
1018 element->children = parse_type(&cursor, end, NULL);
1019 } else {
1020 element->children = parse_compound(&cursor, end, 0);
1021 }
1022 break;
1023
1024 case DIRECTIVE_SET:
1025 element->compound = SET;
1026 element->method = ASN1_CONS;
1027 cursor++;
1028 if (cursor >= end)
1029 goto overrun_error;
1030 if (cursor->token_type == DIRECTIVE_OF) {
1031 element->compound = SET_OF;
1032 cursor++;
1033 if (cursor >= end)
1034 goto parse_error;
1035 element->children = parse_type(&cursor, end, NULL);
1036 } else {
1037 element->children = parse_compound(&cursor, end, 1);
1038 }
1039 break;
1040
1041 default:
1042 fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
1043 filename, cursor->line,
1044 (int)cursor->size, (int)cursor->size, cursor->value);
1045 exit(1);
1046 }
1047
1048 /* Handle elements that are optional */
1049 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1050 cursor->token_type == DIRECTIVE_DEFAULT)
1051 ) {
1052 cursor++;
1053 top->flags |= ELEMENT_SKIPPABLE;
1054 }
1055
1056 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1057 cursor++;
1058 if (cursor >= end)
1059 goto overrun_error;
1060 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1061 fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
1062 filename, cursor->line,
1063 (int)cursor->size, (int)cursor->size, cursor->value);
1064 exit(1);
1065 }
1066
1067 action = malloc(sizeof(struct action) + cursor->size + 1);
1068 if (!action) {
1069 perror(NULL);
1070 exit(1);
1071 }
1072 action->index = 0;
1073 memcpy(action->name, cursor->value, cursor->size);
1074 action->name[cursor->size] = 0;
1075
1076 for (ppaction = &action_list;
1077 *ppaction;
1078 ppaction = &(*ppaction)->next
1079 ) {
1080 int cmp = strcmp(action->name, (*ppaction)->name);
1081 if (cmp == 0) {
1082 free(action);
1083 action = *ppaction;
1084 goto found;
1085 }
1086 if (cmp < 0) {
1087 action->next = *ppaction;
1088 *ppaction = action;
1089 nr_actions++;
1090 goto found;
1091 }
1092 }
1093 action->next = NULL;
1094 *ppaction = action;
1095 nr_actions++;
1096 found:
1097
1098 element->action = action;
1099 cursor->action = action;
1100 cursor++;
1101 if (cursor >= end)
1102 goto overrun_error;
1103 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1104 fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
1105 filename, cursor->line,
1106 (int)cursor->size, (int)cursor->size, cursor->value);
1107 exit(1);
1108 }
1109 cursor++;
1110 }
1111
1112 *_cursor = cursor;
1113 return top;
1114
1115parse_error:
1116 fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
1117 filename, cursor->line,
1118 (int)cursor->size, (int)cursor->size, cursor->value);
1119 exit(1);
1120
1121overrun_error:
1122 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1123 exit(1);
1124}
1125
1126/*
1127 * Parse a compound type list
1128 */
1129static struct element *parse_compound(struct token **_cursor, struct token *end,
1130 int alternates)
1131{
1132 struct element *children, **child_p = &children, *element;
1133 struct token *cursor = *_cursor, *name;
1134
1135 if (cursor->token_type != TOKEN_OPEN_CURLY) {
1136 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
1137 filename, cursor->line,
1138 (int)cursor->size, (int)cursor->size, cursor->value);
1139 exit(1);
1140 }
1141 cursor++;
1142 if (cursor >= end)
1143 goto overrun_error;
1144
1145 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1146 fprintf(stderr, "%s:%d: Empty compound\n",
1147 filename, cursor->line);
1148 exit(1);
1149 }
1150
1151 for (;;) {
1152 name = NULL;
1153 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1154 name = cursor;
1155 cursor++;
1156 if (cursor >= end)
1157 goto overrun_error;
1158 }
1159
1160 element = parse_type(&cursor, end, name);
1161 if (alternates)
1162 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1163
1164 *child_p = element;
1165 child_p = &element->next;
1166
1167 if (cursor >= end)
1168 goto overrun_error;
1169 if (cursor->token_type != TOKEN_COMMA)
1170 break;
1171 cursor++;
1172 if (cursor >= end)
1173 goto overrun_error;
1174 }
1175
1176 children->flags &= ~ELEMENT_CONDITIONAL;
1177
1178 if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1179 fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
1180 filename, cursor->line,
1181 (int)cursor->size, (int)cursor->size, cursor->value);
1182 exit(1);
1183 }
1184 cursor++;
1185
1186 *_cursor = cursor;
1187 return children;
1188
1189overrun_error:
1190 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1191 exit(1);
1192}
1193
1194static void render_element(FILE *out, struct element *e, struct element *tag);
1195static void render_out_of_line_list(FILE *out);
1196
1197static int nr_entries;
1198static int render_depth = 1;
1199static struct element *render_list, **render_list_p = &render_list;
1200
1201__attribute__((format(printf, 2, 3)))
1202static void render_opcode(FILE *out, const char *fmt, ...)
1203{
1204 va_list va;
1205
1206 if (out) {
1207 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1208 va_start(va, fmt);
1209 vfprintf(out, fmt, va);
1210 va_end(va);
1211 }
1212 nr_entries++;
1213}
1214
1215__attribute__((format(printf, 2, 3)))
1216static void render_more(FILE *out, const char *fmt, ...)
1217{
1218 va_list va;
1219
1220 if (out) {
1221 va_start(va, fmt);
1222 vfprintf(out, fmt, va);
1223 va_end(va);
1224 }
1225}
1226
1227/*
1228 * Render the grammar into a state machine definition.
1229 */
1230static void render(FILE *out, FILE *hdr)
1231{
1232 struct element *e;
1233 struct action *action;
1234 struct type *root;
1235 int index;
1236
1237 fprintf(hdr, "/*\n");
1238 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
1239 fprintf(hdr, " *\n");
1240 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1241 fprintf(hdr, " */\n");
1242 fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1243 fprintf(hdr, "\n");
1244 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1245 if (ferror(hdr)) {
1246 perror(headername);
1247 exit(1);
1248 }
1249
1250 fprintf(out, "/*\n");
1251 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
1252 fprintf(out, " *\n");
1253 fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1254 fprintf(out, " */\n");
1255 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1256 fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name);
1257 fprintf(out, "\n");
1258 if (ferror(out)) {
1259 perror(outputname);
1260 exit(1);
1261 }
1262
1263 /* Tabulate the action functions we might have to call */
1264 fprintf(hdr, "\n");
1265 index = 0;
1266 for (action = action_list; action; action = action->next) {
1267 action->index = index++;
1268 fprintf(hdr,
1269 "extern int %s(void *, size_t, unsigned char,"
1270 " const void *, size_t);\n",
1271 action->name);
1272 }
1273 fprintf(hdr, "\n");
1274
1275 fprintf(out, "enum %s_actions {\n", grammar_name);
1276 for (action = action_list; action; action = action->next)
1277 fprintf(out, "\tACT_%s = %u,\n",
1278 action->name, action->index);
1279 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1280 fprintf(out, "};\n");
1281
1282 fprintf(out, "\n");
1283 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1284 grammar_name, grammar_name);
1285 for (action = action_list; action; action = action->next)
1286 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1287 fprintf(out, "};\n");
1288
1289 if (ferror(out)) {
1290 perror(outputname);
1291 exit(1);
1292 }
1293
1294 /* We do two passes - the first one calculates all the offsets */
Arnd Bergmanne9943932015-01-13 22:24:31 +01001295 debug("Pass 1\n");
David Howells4520c6a2012-09-21 23:31:13 +01001296 nr_entries = 0;
1297 root = &type_list[0];
1298 render_element(NULL, root->element, NULL);
1299 render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1300 render_out_of_line_list(NULL);
1301
1302 for (e = element_list; e; e = e->list_next)
1303 e->flags &= ~ELEMENT_RENDERED;
1304
1305 /* And then we actually render */
Arnd Bergmanne9943932015-01-13 22:24:31 +01001306 debug("Pass 2\n");
David Howells4520c6a2012-09-21 23:31:13 +01001307 fprintf(out, "\n");
1308 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1309 grammar_name);
1310
1311 nr_entries = 0;
1312 root = &type_list[0];
1313 render_element(out, root->element, NULL);
1314 render_opcode(out, "ASN1_OP_COMPLETE,\n");
1315 render_out_of_line_list(out);
1316
1317 fprintf(out, "};\n");
1318
1319 fprintf(out, "\n");
1320 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1321 fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1322 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1323 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1324 fprintf(out, "};\n");
1325}
1326
1327/*
1328 * Render the out-of-line elements
1329 */
1330static void render_out_of_line_list(FILE *out)
1331{
1332 struct element *e, *ce;
1333 const char *act;
1334 int entry;
1335
1336 while ((e = render_list)) {
1337 render_list = e->render_next;
1338 if (!render_list)
1339 render_list_p = &render_list;
1340
1341 render_more(out, "\n");
1342 e->entry_index = entry = nr_entries;
1343 render_depth++;
1344 for (ce = e->children; ce; ce = ce->next)
1345 render_element(out, ce, NULL);
1346 render_depth--;
1347
1348 act = e->action ? "_ACT" : "";
1349 switch (e->compound) {
1350 case SEQUENCE:
1351 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1352 break;
1353 case SEQUENCE_OF:
1354 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1355 render_opcode(out, "_jump_target(%u),\n", entry);
1356 break;
1357 case SET:
1358 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1359 break;
1360 case SET_OF:
1361 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1362 render_opcode(out, "_jump_target(%u),\n", entry);
1363 break;
Antonio Alecrim Jreb8948a2013-09-16 11:04:54 -03001364 default:
1365 break;
David Howells4520c6a2012-09-21 23:31:13 +01001366 }
1367 if (e->action)
1368 render_opcode(out, "_action(ACT_%s),\n",
1369 e->action->name);
1370 render_opcode(out, "ASN1_OP_RETURN,\n");
1371 }
1372}
1373
1374/*
1375 * Render an element.
1376 */
1377static void render_element(FILE *out, struct element *e, struct element *tag)
1378{
1379 struct element *ec;
1380 const char *cond, *act;
1381 int entry, skippable = 0, outofline = 0;
1382
1383 if (e->flags & ELEMENT_SKIPPABLE ||
1384 (tag && tag->flags & ELEMENT_SKIPPABLE))
1385 skippable = 1;
1386
1387 if ((e->type_def && e->type_def->ref_count > 1) ||
1388 skippable)
1389 outofline = 1;
1390
1391 if (e->type_def && out) {
1392 render_more(out, "\t// %*.*s\n",
1393 (int)e->type_def->name->size, (int)e->type_def->name->size,
1394 e->type_def->name->value);
1395 }
1396
1397 /* Render the operation */
1398 cond = (e->flags & ELEMENT_CONDITIONAL ||
1399 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1400 act = e->action ? "_ACT" : "";
1401 switch (e->compound) {
1402 case ANY:
1403 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
1404 if (e->name)
1405 render_more(out, "\t\t// %*.*s",
1406 (int)e->name->size, (int)e->name->size,
1407 e->name->value);
1408 render_more(out, "\n");
1409 goto dont_render_tag;
1410
1411 case TAG_OVERRIDE:
1412 render_element(out, e->children, e);
1413 return;
1414
1415 case SEQUENCE:
1416 case SEQUENCE_OF:
1417 case SET:
1418 case SET_OF:
1419 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1420 cond,
1421 outofline ? "_JUMP" : "",
1422 skippable ? "_OR_SKIP" : "");
1423 break;
1424
1425 case CHOICE:
1426 goto dont_render_tag;
1427
1428 case TYPE_REF:
1429 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1430 goto dont_render_tag;
1431 default:
1432 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1433 cond, act,
1434 skippable ? "_OR_SKIP" : "");
1435 break;
1436 }
1437
1438 if (e->name)
1439 render_more(out, "\t\t// %*.*s",
1440 (int)e->name->size, (int)e->name->size,
1441 e->name->value);
1442 render_more(out, "\n");
1443
1444 /* Render the tag */
1445 if (!tag)
1446 tag = e;
1447 if (tag->class == ASN1_UNIV &&
1448 tag->tag != 14 &&
1449 tag->tag != 15 &&
1450 tag->tag != 31)
1451 render_opcode(out, "_tag(%s, %s, %s),\n",
1452 asn1_classes[tag->class],
1453 asn1_methods[tag->method | e->method],
1454 asn1_universal_tags[tag->tag]);
1455 else
1456 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1457 asn1_classes[tag->class],
1458 asn1_methods[tag->method | e->method],
1459 tag->tag);
1460 tag = NULL;
1461dont_render_tag:
1462
1463 /* Deal with compound types */
1464 switch (e->compound) {
1465 case TYPE_REF:
1466 render_element(out, e->type->type->element, tag);
1467 if (e->action)
1468 render_opcode(out, "ASN1_OP_ACT,\n");
1469 break;
1470
1471 case SEQUENCE:
1472 if (outofline) {
1473 /* Render out-of-line for multiple use or
1474 * skipability */
1475 render_opcode(out, "_jump_target(%u),", e->entry_index);
1476 if (e->type_def && e->type_def->name)
1477 render_more(out, "\t\t// --> %*.*s",
1478 (int)e->type_def->name->size,
1479 (int)e->type_def->name->size,
1480 e->type_def->name->value);
1481 render_more(out, "\n");
1482 if (!(e->flags & ELEMENT_RENDERED)) {
1483 e->flags |= ELEMENT_RENDERED;
1484 *render_list_p = e;
1485 render_list_p = &e->render_next;
1486 }
1487 return;
1488 } else {
1489 /* Render inline for single use */
1490 render_depth++;
1491 for (ec = e->children; ec; ec = ec->next)
1492 render_element(out, ec, NULL);
1493 render_depth--;
1494 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1495 }
1496 break;
1497
1498 case SEQUENCE_OF:
1499 case SET_OF:
1500 if (outofline) {
1501 /* Render out-of-line for multiple use or
1502 * skipability */
1503 render_opcode(out, "_jump_target(%u),", e->entry_index);
1504 if (e->type_def && e->type_def->name)
1505 render_more(out, "\t\t// --> %*.*s",
1506 (int)e->type_def->name->size,
1507 (int)e->type_def->name->size,
1508 e->type_def->name->value);
1509 render_more(out, "\n");
1510 if (!(e->flags & ELEMENT_RENDERED)) {
1511 e->flags |= ELEMENT_RENDERED;
1512 *render_list_p = e;
1513 render_list_p = &e->render_next;
1514 }
1515 return;
1516 } else {
1517 /* Render inline for single use */
1518 entry = nr_entries;
1519 render_depth++;
1520 render_element(out, e->children, NULL);
1521 render_depth--;
1522 if (e->compound == SEQUENCE_OF)
1523 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1524 else
1525 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1526 render_opcode(out, "_jump_target(%u),\n", entry);
1527 }
1528 break;
1529
1530 case SET:
1531 /* I can't think of a nice way to do SET support without having
1532 * a stack of bitmasks to make sure no element is repeated.
1533 * The bitmask has also to be checked that no non-optional
1534 * elements are left out whilst not preventing optional
1535 * elements from being left out.
1536 */
1537 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1538 exit(1);
1539
1540 case CHOICE:
1541 for (ec = e->children; ec; ec = ec->next)
1542 render_element(out, ec, NULL);
1543 if (!skippable)
1544 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1545 if (e->action)
1546 render_opcode(out, "ASN1_OP_ACT,\n");
1547 break;
1548
1549 default:
1550 break;
1551 }
1552
1553 if (e->action)
1554 render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1555}