]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - scripts/asn1_compiler.c
ASN.1: Fix non-match detection failure on data overrun
[mirror_ubuntu-bionic-kernel.git] / scripts / asn1_compiler.c
CommitLineData
4520c6a4
DH
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;
e994393a
AB
314static _Bool verbose;
315
316#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
4520c6a4
DH
317
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
e994393a 328 //debug("cmp(%*.*s,%s) = ",
4520c6a4
DH
329 // (int)token->size, (int)token->size, token->value,
330 // dir);
331
332 val = memcmp(token->value, dir, clen);
333 if (val != 0) {
e994393a 334 //debug("%d [cmp]\n", val);
4520c6a4
DH
335 return val;
336 }
337
338 if (dlen == token->size) {
e994393a 339 //debug("0\n");
4520c6a4
DH
340 return 0;
341 }
e994393a 342 //debug("%d\n", (int)dlen - (int)token->size);
4520c6a4
DH
343 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;
e994393a 521 debug("Extracted %u tokens\n", nr_tokens);
4520c6a4
DH
522
523#if 0
524 {
525 int n;
526 for (n = 0; n < nr_tokens; n++)
e994393a 527 debug("Token %3u: '%*.*s'\n",
4520c6a4
DH
528 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;
e994393a 548 char *kbuild_verbose;
4520c6a4
DH
549 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
e994393a
AB
557 kbuild_verbose = getenv("KBUILD_VERBOSE");
558 if (kbuild_verbose)
559 verbose = atoi(kbuild_verbose);
560
4520c6a4
DH
561 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
8d9b21dc 669#define ELEMENT_TAG_SPECIFIED 0x0004
4520c6a4
DH
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
e994393a 759 debug("Extracted %u types\n", nr_types);
4520c6a4
DH
760#if 0
761 for (n = 0; n < nr_types; n++) {
762 struct type *type = type_index[n];
e994393a 763 debug("- %*.*s\n",
4520c6a4
DH
764 (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
e994393a 804 debug("Extracted %u actions\n", nr_actions);
4520c6a4
DH
805}
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);
8d9b21dc 882 element->flags |= ELEMENT_TAG_SPECIFIED;
4520c6a4
DH
883 if (p - cursor->value != cursor->size)
884 abort();
885 cursor++;
886
887 if (cursor >= end)
888 goto overrun_error;
889 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
890 fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
891 filename, cursor->line,
892 (int)cursor->size, (int)cursor->size, cursor->value);
893 exit(1);
894 }
895 cursor++;
896 if (cursor >= end)
897 goto overrun_error;
898 labelled = 1;
899 }
900
901 /* Handle implicit and explicit markers */
902 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
903 element->flags |= ELEMENT_IMPLICIT;
904 implicit = 1;
905 cursor++;
906 if (cursor >= end)
907 goto overrun_error;
908 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
909 element->flags |= ELEMENT_EXPLICIT;
910 cursor++;
911 if (cursor >= end)
912 goto overrun_error;
913 }
914
915 if (labelled) {
916 if (!implicit)
917 element->method |= ASN1_CONS;
918 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
919 element->children = alloc_elem(cursor);
920 element = element->children;
921 element->class = ASN1_UNIV;
922 element->method = ASN1_PRIM;
923 element->tag = token_to_tag[cursor->token_type];
924 element->name = name;
925 }
926
927 /* Extract the type we're expecting here */
928 element->type = cursor;
929 switch (cursor->token_type) {
930 case DIRECTIVE_ANY:
931 element->compound = ANY;
932 cursor++;
933 break;
934
935 case DIRECTIVE_NULL:
936 case DIRECTIVE_BOOLEAN:
937 case DIRECTIVE_ENUMERATED:
938 case DIRECTIVE_INTEGER:
939 element->compound = NOT_COMPOUND;
940 cursor++;
941 break;
942
943 case DIRECTIVE_EXTERNAL:
944 element->method = ASN1_CONS;
945
946 case DIRECTIVE_BMPString:
947 case DIRECTIVE_GeneralString:
948 case DIRECTIVE_GraphicString:
949 case DIRECTIVE_IA5String:
950 case DIRECTIVE_ISO646String:
951 case DIRECTIVE_NumericString:
952 case DIRECTIVE_PrintableString:
953 case DIRECTIVE_T61String:
954 case DIRECTIVE_TeletexString:
955 case DIRECTIVE_UniversalString:
956 case DIRECTIVE_UTF8String:
957 case DIRECTIVE_VideotexString:
958 case DIRECTIVE_VisibleString:
959 case DIRECTIVE_ObjectDescriptor:
960 case DIRECTIVE_GeneralizedTime:
961 case DIRECTIVE_UTCTime:
962 element->compound = NOT_COMPOUND;
963 cursor++;
964 break;
965
966 case DIRECTIVE_BIT:
967 case DIRECTIVE_OCTET:
968 element->compound = NOT_COMPOUND;
969 cursor++;
970 if (cursor >= end)
971 goto overrun_error;
972 if (cursor->token_type != DIRECTIVE_STRING)
973 goto parse_error;
974 cursor++;
975 break;
976
977 case DIRECTIVE_OBJECT:
978 element->compound = NOT_COMPOUND;
979 cursor++;
980 if (cursor >= end)
981 goto overrun_error;
982 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
983 goto parse_error;
984 cursor++;
985 break;
986
987 case TOKEN_TYPE_NAME:
988 element->compound = TYPE_REF;
989 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
990 type_finder);
991 if (!ref) {
992 fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
993 filename, cursor->line,
994 (int)cursor->size, (int)cursor->size, cursor->value);
995 exit(1);
996 }
997 cursor->type = *ref;
998 (*ref)->ref_count++;
999 cursor++;
1000 break;
1001
1002 case DIRECTIVE_CHOICE:
1003 element->compound = CHOICE;
1004 cursor++;
1005 element->children = parse_compound(&cursor, end, 1);
1006 break;
1007
1008 case DIRECTIVE_SEQUENCE:
1009 element->compound = SEQUENCE;
1010 element->method = ASN1_CONS;
1011 cursor++;
1012 if (cursor >= end)
1013 goto overrun_error;
1014 if (cursor->token_type == DIRECTIVE_OF) {
1015 element->compound = SEQUENCE_OF;
1016 cursor++;
1017 if (cursor >= end)
1018 goto overrun_error;
1019 element->children = parse_type(&cursor, end, NULL);
1020 } else {
1021 element->children = parse_compound(&cursor, end, 0);
1022 }
1023 break;
1024
1025 case DIRECTIVE_SET:
1026 element->compound = SET;
1027 element->method = ASN1_CONS;
1028 cursor++;
1029 if (cursor >= end)
1030 goto overrun_error;
1031 if (cursor->token_type == DIRECTIVE_OF) {
1032 element->compound = SET_OF;
1033 cursor++;
1034 if (cursor >= end)
1035 goto parse_error;
1036 element->children = parse_type(&cursor, end, NULL);
1037 } else {
1038 element->children = parse_compound(&cursor, end, 1);
1039 }
1040 break;
1041
1042 default:
1043 fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
1044 filename, cursor->line,
1045 (int)cursor->size, (int)cursor->size, cursor->value);
1046 exit(1);
1047 }
1048
1049 /* Handle elements that are optional */
1050 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1051 cursor->token_type == DIRECTIVE_DEFAULT)
1052 ) {
1053 cursor++;
1054 top->flags |= ELEMENT_SKIPPABLE;
1055 }
1056
1057 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1058 cursor++;
1059 if (cursor >= end)
1060 goto overrun_error;
1061 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1062 fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
1063 filename, cursor->line,
1064 (int)cursor->size, (int)cursor->size, cursor->value);
1065 exit(1);
1066 }
1067
1068 action = malloc(sizeof(struct action) + cursor->size + 1);
1069 if (!action) {
1070 perror(NULL);
1071 exit(1);
1072 }
1073 action->index = 0;
1074 memcpy(action->name, cursor->value, cursor->size);
1075 action->name[cursor->size] = 0;
1076
1077 for (ppaction = &action_list;
1078 *ppaction;
1079 ppaction = &(*ppaction)->next
1080 ) {
1081 int cmp = strcmp(action->name, (*ppaction)->name);
1082 if (cmp == 0) {
1083 free(action);
1084 action = *ppaction;
1085 goto found;
1086 }
1087 if (cmp < 0) {
1088 action->next = *ppaction;
1089 *ppaction = action;
1090 nr_actions++;
1091 goto found;
1092 }
1093 }
1094 action->next = NULL;
1095 *ppaction = action;
1096 nr_actions++;
1097 found:
1098
1099 element->action = action;
1100 cursor->action = action;
1101 cursor++;
1102 if (cursor >= end)
1103 goto overrun_error;
1104 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1105 fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
1106 filename, cursor->line,
1107 (int)cursor->size, (int)cursor->size, cursor->value);
1108 exit(1);
1109 }
1110 cursor++;
1111 }
1112
1113 *_cursor = cursor;
1114 return top;
1115
1116parse_error:
1117 fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
1118 filename, cursor->line,
1119 (int)cursor->size, (int)cursor->size, cursor->value);
1120 exit(1);
1121
1122overrun_error:
1123 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1124 exit(1);
1125}
1126
1127/*
1128 * Parse a compound type list
1129 */
1130static struct element *parse_compound(struct token **_cursor, struct token *end,
1131 int alternates)
1132{
1133 struct element *children, **child_p = &children, *element;
1134 struct token *cursor = *_cursor, *name;
1135
1136 if (cursor->token_type != TOKEN_OPEN_CURLY) {
1137 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
1138 filename, cursor->line,
1139 (int)cursor->size, (int)cursor->size, cursor->value);
1140 exit(1);
1141 }
1142 cursor++;
1143 if (cursor >= end)
1144 goto overrun_error;
1145
1146 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1147 fprintf(stderr, "%s:%d: Empty compound\n",
1148 filename, cursor->line);
1149 exit(1);
1150 }
1151
1152 for (;;) {
1153 name = NULL;
1154 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1155 name = cursor;
1156 cursor++;
1157 if (cursor >= end)
1158 goto overrun_error;
1159 }
1160
1161 element = parse_type(&cursor, end, name);
1162 if (alternates)
1163 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1164
1165 *child_p = element;
1166 child_p = &element->next;
1167
1168 if (cursor >= end)
1169 goto overrun_error;
1170 if (cursor->token_type != TOKEN_COMMA)
1171 break;
1172 cursor++;
1173 if (cursor >= end)
1174 goto overrun_error;
1175 }
1176
1177 children->flags &= ~ELEMENT_CONDITIONAL;
1178
1179 if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1180 fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
1181 filename, cursor->line,
1182 (int)cursor->size, (int)cursor->size, cursor->value);
1183 exit(1);
1184 }
1185 cursor++;
1186
1187 *_cursor = cursor;
1188 return children;
1189
1190overrun_error:
1191 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1192 exit(1);
1193}
1194
1195static void render_element(FILE *out, struct element *e, struct element *tag);
1196static void render_out_of_line_list(FILE *out);
1197
1198static int nr_entries;
1199static int render_depth = 1;
1200static struct element *render_list, **render_list_p = &render_list;
1201
1202__attribute__((format(printf, 2, 3)))
1203static void render_opcode(FILE *out, const char *fmt, ...)
1204{
1205 va_list va;
1206
1207 if (out) {
1208 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1209 va_start(va, fmt);
1210 vfprintf(out, fmt, va);
1211 va_end(va);
1212 }
1213 nr_entries++;
1214}
1215
1216__attribute__((format(printf, 2, 3)))
1217static void render_more(FILE *out, const char *fmt, ...)
1218{
1219 va_list va;
1220
1221 if (out) {
1222 va_start(va, fmt);
1223 vfprintf(out, fmt, va);
1224 va_end(va);
1225 }
1226}
1227
1228/*
1229 * Render the grammar into a state machine definition.
1230 */
1231static void render(FILE *out, FILE *hdr)
1232{
1233 struct element *e;
1234 struct action *action;
1235 struct type *root;
1236 int index;
1237
1238 fprintf(hdr, "/*\n");
1239 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
1240 fprintf(hdr, " *\n");
1241 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1242 fprintf(hdr, " */\n");
1243 fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1244 fprintf(hdr, "\n");
1245 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1246 if (ferror(hdr)) {
1247 perror(headername);
1248 exit(1);
1249 }
1250
1251 fprintf(out, "/*\n");
1252 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
1253 fprintf(out, " *\n");
1254 fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1255 fprintf(out, " */\n");
1256 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1257 fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name);
1258 fprintf(out, "\n");
1259 if (ferror(out)) {
1260 perror(outputname);
1261 exit(1);
1262 }
1263
1264 /* Tabulate the action functions we might have to call */
1265 fprintf(hdr, "\n");
1266 index = 0;
1267 for (action = action_list; action; action = action->next) {
1268 action->index = index++;
1269 fprintf(hdr,
1270 "extern int %s(void *, size_t, unsigned char,"
1271 " const void *, size_t);\n",
1272 action->name);
1273 }
1274 fprintf(hdr, "\n");
1275
1276 fprintf(out, "enum %s_actions {\n", grammar_name);
1277 for (action = action_list; action; action = action->next)
1278 fprintf(out, "\tACT_%s = %u,\n",
1279 action->name, action->index);
1280 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1281 fprintf(out, "};\n");
1282
1283 fprintf(out, "\n");
1284 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1285 grammar_name, grammar_name);
1286 for (action = action_list; action; action = action->next)
1287 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1288 fprintf(out, "};\n");
1289
1290 if (ferror(out)) {
1291 perror(outputname);
1292 exit(1);
1293 }
1294
1295 /* We do two passes - the first one calculates all the offsets */
e994393a 1296 debug("Pass 1\n");
4520c6a4
DH
1297 nr_entries = 0;
1298 root = &type_list[0];
1299 render_element(NULL, root->element, NULL);
1300 render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1301 render_out_of_line_list(NULL);
1302
1303 for (e = element_list; e; e = e->list_next)
1304 e->flags &= ~ELEMENT_RENDERED;
1305
1306 /* And then we actually render */
e994393a 1307 debug("Pass 2\n");
4520c6a4
DH
1308 fprintf(out, "\n");
1309 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1310 grammar_name);
1311
1312 nr_entries = 0;
1313 root = &type_list[0];
1314 render_element(out, root->element, NULL);
1315 render_opcode(out, "ASN1_OP_COMPLETE,\n");
1316 render_out_of_line_list(out);
1317
1318 fprintf(out, "};\n");
1319
1320 fprintf(out, "\n");
1321 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1322 fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1323 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1324 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1325 fprintf(out, "};\n");
1326}
1327
1328/*
1329 * Render the out-of-line elements
1330 */
1331static void render_out_of_line_list(FILE *out)
1332{
1333 struct element *e, *ce;
1334 const char *act;
1335 int entry;
1336
1337 while ((e = render_list)) {
1338 render_list = e->render_next;
1339 if (!render_list)
1340 render_list_p = &render_list;
1341
1342 render_more(out, "\n");
1343 e->entry_index = entry = nr_entries;
1344 render_depth++;
1345 for (ce = e->children; ce; ce = ce->next)
1346 render_element(out, ce, NULL);
1347 render_depth--;
1348
1349 act = e->action ? "_ACT" : "";
1350 switch (e->compound) {
1351 case SEQUENCE:
1352 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1353 break;
1354 case SEQUENCE_OF:
1355 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1356 render_opcode(out, "_jump_target(%u),\n", entry);
1357 break;
1358 case SET:
1359 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1360 break;
1361 case SET_OF:
1362 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1363 render_opcode(out, "_jump_target(%u),\n", entry);
1364 break;
eb8948a0
AAJ
1365 default:
1366 break;
4520c6a4
DH
1367 }
1368 if (e->action)
1369 render_opcode(out, "_action(ACT_%s),\n",
1370 e->action->name);
1371 render_opcode(out, "ASN1_OP_RETURN,\n");
1372 }
1373}
1374
1375/*
1376 * Render an element.
1377 */
1378static void render_element(FILE *out, struct element *e, struct element *tag)
1379{
8d9b21dc 1380 struct element *ec, *x;
4520c6a4
DH
1381 const char *cond, *act;
1382 int entry, skippable = 0, outofline = 0;
1383
1384 if (e->flags & ELEMENT_SKIPPABLE ||
1385 (tag && tag->flags & ELEMENT_SKIPPABLE))
1386 skippable = 1;
1387
1388 if ((e->type_def && e->type_def->ref_count > 1) ||
1389 skippable)
1390 outofline = 1;
1391
1392 if (e->type_def && out) {
1393 render_more(out, "\t// %*.*s\n",
1394 (int)e->type_def->name->size, (int)e->type_def->name->size,
1395 e->type_def->name->value);
1396 }
1397
1398 /* Render the operation */
1399 cond = (e->flags & ELEMENT_CONDITIONAL ||
1400 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1401 act = e->action ? "_ACT" : "";
1402 switch (e->compound) {
1403 case ANY:
1404 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
1405 if (e->name)
1406 render_more(out, "\t\t// %*.*s",
1407 (int)e->name->size, (int)e->name->size,
1408 e->name->value);
1409 render_more(out, "\n");
1410 goto dont_render_tag;
1411
1412 case TAG_OVERRIDE:
1413 render_element(out, e->children, e);
1414 return;
1415
1416 case SEQUENCE:
1417 case SEQUENCE_OF:
1418 case SET:
1419 case SET_OF:
1420 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1421 cond,
1422 outofline ? "_JUMP" : "",
1423 skippable ? "_OR_SKIP" : "");
1424 break;
1425
1426 case CHOICE:
1427 goto dont_render_tag;
1428
1429 case TYPE_REF:
1430 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1431 goto dont_render_tag;
1432 default:
1433 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1434 cond, act,
1435 skippable ? "_OR_SKIP" : "");
1436 break;
1437 }
1438
8d9b21dc
DH
1439 x = tag ?: e;
1440 if (x->name)
4520c6a4 1441 render_more(out, "\t\t// %*.*s",
8d9b21dc
DH
1442 (int)x->name->size, (int)x->name->size,
1443 x->name->value);
4520c6a4
DH
1444 render_more(out, "\n");
1445
1446 /* Render the tag */
8d9b21dc 1447 if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
4520c6a4 1448 tag = e;
8d9b21dc 1449
4520c6a4
DH
1450 if (tag->class == ASN1_UNIV &&
1451 tag->tag != 14 &&
1452 tag->tag != 15 &&
1453 tag->tag != 31)
1454 render_opcode(out, "_tag(%s, %s, %s),\n",
1455 asn1_classes[tag->class],
1456 asn1_methods[tag->method | e->method],
1457 asn1_universal_tags[tag->tag]);
1458 else
1459 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1460 asn1_classes[tag->class],
1461 asn1_methods[tag->method | e->method],
1462 tag->tag);
1463 tag = NULL;
1464dont_render_tag:
1465
1466 /* Deal with compound types */
1467 switch (e->compound) {
1468 case TYPE_REF:
1469 render_element(out, e->type->type->element, tag);
1470 if (e->action)
3f3af97d
DH
1471 render_opcode(out, "ASN1_OP_%sACT,\n",
1472 skippable ? "MAYBE_" : "");
4520c6a4
DH
1473 break;
1474
1475 case SEQUENCE:
1476 if (outofline) {
1477 /* Render out-of-line for multiple use or
1478 * skipability */
1479 render_opcode(out, "_jump_target(%u),", e->entry_index);
1480 if (e->type_def && e->type_def->name)
1481 render_more(out, "\t\t// --> %*.*s",
1482 (int)e->type_def->name->size,
1483 (int)e->type_def->name->size,
1484 e->type_def->name->value);
1485 render_more(out, "\n");
1486 if (!(e->flags & ELEMENT_RENDERED)) {
1487 e->flags |= ELEMENT_RENDERED;
1488 *render_list_p = e;
1489 render_list_p = &e->render_next;
1490 }
1491 return;
1492 } else {
1493 /* Render inline for single use */
1494 render_depth++;
1495 for (ec = e->children; ec; ec = ec->next)
1496 render_element(out, ec, NULL);
1497 render_depth--;
1498 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1499 }
1500 break;
1501
1502 case SEQUENCE_OF:
1503 case SET_OF:
1504 if (outofline) {
1505 /* Render out-of-line for multiple use or
1506 * skipability */
1507 render_opcode(out, "_jump_target(%u),", e->entry_index);
1508 if (e->type_def && e->type_def->name)
1509 render_more(out, "\t\t// --> %*.*s",
1510 (int)e->type_def->name->size,
1511 (int)e->type_def->name->size,
1512 e->type_def->name->value);
1513 render_more(out, "\n");
1514 if (!(e->flags & ELEMENT_RENDERED)) {
1515 e->flags |= ELEMENT_RENDERED;
1516 *render_list_p = e;
1517 render_list_p = &e->render_next;
1518 }
1519 return;
1520 } else {
1521 /* Render inline for single use */
1522 entry = nr_entries;
1523 render_depth++;
1524 render_element(out, e->children, NULL);
1525 render_depth--;
1526 if (e->compound == SEQUENCE_OF)
1527 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1528 else
1529 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1530 render_opcode(out, "_jump_target(%u),\n", entry);
1531 }
1532 break;
1533
1534 case SET:
1535 /* I can't think of a nice way to do SET support without having
1536 * a stack of bitmasks to make sure no element is repeated.
1537 * The bitmask has also to be checked that no non-optional
1538 * elements are left out whilst not preventing optional
1539 * elements from being left out.
1540 */
1541 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1542 exit(1);
1543
1544 case CHOICE:
1545 for (ec = e->children; ec; ec = ec->next)
8d9b21dc 1546 render_element(out, ec, ec);
4520c6a4
DH
1547 if (!skippable)
1548 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1549 if (e->action)
1550 render_opcode(out, "ASN1_OP_ACT,\n");
1551 break;
1552
1553 default:
1554 break;
1555 }
1556
1557 if (e->action)
1558 render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1559}