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