sparc: use for_each_sg()
[linux/fpc-iii.git] / scripts / asn1_compiler.c
blob7750e9c31483b99bdf467db98757ca16e7152847
1 /* Simplified ASN.1 notation parser
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
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>
23 enum token_type {
24 DIRECTIVE_ABSENT,
25 DIRECTIVE_ALL,
26 DIRECTIVE_ANY,
27 DIRECTIVE_APPLICATION,
28 DIRECTIVE_AUTOMATIC,
29 DIRECTIVE_BEGIN,
30 DIRECTIVE_BIT,
31 DIRECTIVE_BMPString,
32 DIRECTIVE_BOOLEAN,
33 DIRECTIVE_BY,
34 DIRECTIVE_CHARACTER,
35 DIRECTIVE_CHOICE,
36 DIRECTIVE_CLASS,
37 DIRECTIVE_COMPONENT,
38 DIRECTIVE_COMPONENTS,
39 DIRECTIVE_CONSTRAINED,
40 DIRECTIVE_CONTAINING,
41 DIRECTIVE_DEFAULT,
42 DIRECTIVE_DEFINED,
43 DIRECTIVE_DEFINITIONS,
44 DIRECTIVE_EMBEDDED,
45 DIRECTIVE_ENCODED,
46 DIRECTIVE_ENCODING_CONTROL,
47 DIRECTIVE_END,
48 DIRECTIVE_ENUMERATED,
49 DIRECTIVE_EXCEPT,
50 DIRECTIVE_EXPLICIT,
51 DIRECTIVE_EXPORTS,
52 DIRECTIVE_EXTENSIBILITY,
53 DIRECTIVE_EXTERNAL,
54 DIRECTIVE_FALSE,
55 DIRECTIVE_FROM,
56 DIRECTIVE_GeneralString,
57 DIRECTIVE_GeneralizedTime,
58 DIRECTIVE_GraphicString,
59 DIRECTIVE_IA5String,
60 DIRECTIVE_IDENTIFIER,
61 DIRECTIVE_IMPLICIT,
62 DIRECTIVE_IMPLIED,
63 DIRECTIVE_IMPORTS,
64 DIRECTIVE_INCLUDES,
65 DIRECTIVE_INSTANCE,
66 DIRECTIVE_INSTRUCTIONS,
67 DIRECTIVE_INTEGER,
68 DIRECTIVE_INTERSECTION,
69 DIRECTIVE_ISO646String,
70 DIRECTIVE_MAX,
71 DIRECTIVE_MIN,
72 DIRECTIVE_MINUS_INFINITY,
73 DIRECTIVE_NULL,
74 DIRECTIVE_NumericString,
75 DIRECTIVE_OBJECT,
76 DIRECTIVE_OCTET,
77 DIRECTIVE_OF,
78 DIRECTIVE_OPTIONAL,
79 DIRECTIVE_ObjectDescriptor,
80 DIRECTIVE_PATTERN,
81 DIRECTIVE_PDV,
82 DIRECTIVE_PLUS_INFINITY,
83 DIRECTIVE_PRESENT,
84 DIRECTIVE_PRIVATE,
85 DIRECTIVE_PrintableString,
86 DIRECTIVE_REAL,
87 DIRECTIVE_RELATIVE_OID,
88 DIRECTIVE_SEQUENCE,
89 DIRECTIVE_SET,
90 DIRECTIVE_SIZE,
91 DIRECTIVE_STRING,
92 DIRECTIVE_SYNTAX,
93 DIRECTIVE_T61String,
94 DIRECTIVE_TAGS,
95 DIRECTIVE_TRUE,
96 DIRECTIVE_TeletexString,
97 DIRECTIVE_UNION,
98 DIRECTIVE_UNIQUE,
99 DIRECTIVE_UNIVERSAL,
100 DIRECTIVE_UTCTime,
101 DIRECTIVE_UTF8String,
102 DIRECTIVE_UniversalString,
103 DIRECTIVE_VideotexString,
104 DIRECTIVE_VisibleString,
105 DIRECTIVE_WITH,
106 NR__DIRECTIVES,
107 TOKEN_ASSIGNMENT = NR__DIRECTIVES,
108 TOKEN_OPEN_CURLY,
109 TOKEN_CLOSE_CURLY,
110 TOKEN_OPEN_SQUARE,
111 TOKEN_CLOSE_SQUARE,
112 TOKEN_OPEN_ACTION,
113 TOKEN_CLOSE_ACTION,
114 TOKEN_COMMA,
115 TOKEN_NUMBER,
116 TOKEN_TYPE_NAME,
117 TOKEN_ELEMENT_NAME,
118 NR__TOKENS
121 static const unsigned char token_to_tag[NR__TOKENS] = {
122 /* EOC goes first */
123 [DIRECTIVE_BOOLEAN] = ASN1_BOOL,
124 [DIRECTIVE_INTEGER] = ASN1_INT,
125 [DIRECTIVE_BIT] = ASN1_BTS,
126 [DIRECTIVE_OCTET] = ASN1_OTS,
127 [DIRECTIVE_NULL] = ASN1_NULL,
128 [DIRECTIVE_OBJECT] = ASN1_OID,
129 [DIRECTIVE_ObjectDescriptor] = ASN1_ODE,
130 [DIRECTIVE_EXTERNAL] = ASN1_EXT,
131 [DIRECTIVE_REAL] = ASN1_REAL,
132 [DIRECTIVE_ENUMERATED] = ASN1_ENUM,
133 [DIRECTIVE_EMBEDDED] = 0,
134 [DIRECTIVE_UTF8String] = ASN1_UTF8STR,
135 [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID,
136 /* 14 */
137 /* 15 */
138 [DIRECTIVE_SEQUENCE] = ASN1_SEQ,
139 [DIRECTIVE_SET] = ASN1_SET,
140 [DIRECTIVE_NumericString] = ASN1_NUMSTR,
141 [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
142 [DIRECTIVE_T61String] = ASN1_TEXSTR,
143 [DIRECTIVE_TeletexString] = ASN1_TEXSTR,
144 [DIRECTIVE_VideotexString] = ASN1_VIDSTR,
145 [DIRECTIVE_IA5String] = ASN1_IA5STR,
146 [DIRECTIVE_UTCTime] = ASN1_UNITIM,
147 [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
148 [DIRECTIVE_GraphicString] = ASN1_GRASTR,
149 [DIRECTIVE_VisibleString] = ASN1_VISSTR,
150 [DIRECTIVE_GeneralString] = ASN1_GENSTR,
151 [DIRECTIVE_UniversalString] = ASN1_UNITIM,
152 [DIRECTIVE_CHARACTER] = ASN1_CHRSTR,
153 [DIRECTIVE_BMPString] = ASN1_BMPSTR,
156 static const char asn1_classes[4][5] = {
157 [ASN1_UNIV] = "UNIV",
158 [ASN1_APPL] = "APPL",
159 [ASN1_CONT] = "CONT",
160 [ASN1_PRIV] = "PRIV"
163 static const char asn1_methods[2][5] = {
164 [ASN1_UNIV] = "PRIM",
165 [ASN1_APPL] = "CONS"
168 static const char *const asn1_universal_tags[32] = {
169 "EOC",
170 "BOOL",
171 "INT",
172 "BTS",
173 "OTS",
174 "NULL",
175 "OID",
176 "ODE",
177 "EXT",
178 "REAL",
179 "ENUM",
180 "EPDV",
181 "UTF8STR",
182 "RELOID",
183 NULL, /* 14 */
184 NULL, /* 15 */
185 "SEQ",
186 "SET",
187 "NUMSTR",
188 "PRNSTR",
189 "TEXSTR",
190 "VIDSTR",
191 "IA5STR",
192 "UNITIM",
193 "GENTIM",
194 "GRASTR",
195 "VISSTR",
196 "GENSTR",
197 "UNISTR",
198 "CHRSTR",
199 "BMPSTR",
200 NULL /* 31 */
203 static const char *filename;
204 static const char *grammar_name;
205 static const char *outputname;
206 static const char *headername;
208 static const char *const directives[NR__DIRECTIVES] = {
209 #define _(X) [DIRECTIVE_##X] = #X
210 _(ABSENT),
211 _(ALL),
212 _(ANY),
213 _(APPLICATION),
214 _(AUTOMATIC),
215 _(BEGIN),
216 _(BIT),
217 _(BMPString),
218 _(BOOLEAN),
219 _(BY),
220 _(CHARACTER),
221 _(CHOICE),
222 _(CLASS),
223 _(COMPONENT),
224 _(COMPONENTS),
225 _(CONSTRAINED),
226 _(CONTAINING),
227 _(DEFAULT),
228 _(DEFINED),
229 _(DEFINITIONS),
230 _(EMBEDDED),
231 _(ENCODED),
232 [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
233 _(END),
234 _(ENUMERATED),
235 _(EXCEPT),
236 _(EXPLICIT),
237 _(EXPORTS),
238 _(EXTENSIBILITY),
239 _(EXTERNAL),
240 _(FALSE),
241 _(FROM),
242 _(GeneralString),
243 _(GeneralizedTime),
244 _(GraphicString),
245 _(IA5String),
246 _(IDENTIFIER),
247 _(IMPLICIT),
248 _(IMPLIED),
249 _(IMPORTS),
250 _(INCLUDES),
251 _(INSTANCE),
252 _(INSTRUCTIONS),
253 _(INTEGER),
254 _(INTERSECTION),
255 _(ISO646String),
256 _(MAX),
257 _(MIN),
258 [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
259 [DIRECTIVE_NULL] = "NULL",
260 _(NumericString),
261 _(OBJECT),
262 _(OCTET),
263 _(OF),
264 _(OPTIONAL),
265 _(ObjectDescriptor),
266 _(PATTERN),
267 _(PDV),
268 [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
269 _(PRESENT),
270 _(PRIVATE),
271 _(PrintableString),
272 _(REAL),
273 [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
274 _(SEQUENCE),
275 _(SET),
276 _(SIZE),
277 _(STRING),
278 _(SYNTAX),
279 _(T61String),
280 _(TAGS),
281 _(TRUE),
282 _(TeletexString),
283 _(UNION),
284 _(UNIQUE),
285 _(UNIVERSAL),
286 _(UTCTime),
287 _(UTF8String),
288 _(UniversalString),
289 _(VideotexString),
290 _(VisibleString),
291 _(WITH)
294 struct action {
295 struct action *next;
296 unsigned char index;
297 char name[];
300 static struct action *action_list;
301 static unsigned nr_actions;
303 struct token {
304 unsigned short line;
305 enum token_type token_type : 8;
306 unsigned char size;
307 struct action *action;
308 const char *value;
309 struct type *type;
312 static struct token *token_list;
313 static unsigned nr_tokens;
314 static _Bool verbose;
316 #define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
318 static int directive_compare(const void *_key, const void *_pdir)
320 const struct token *token = _key;
321 const char *const *pdir = _pdir, *dir = *pdir;
322 size_t dlen, clen;
323 int val;
325 dlen = strlen(dir);
326 clen = (dlen < token->size) ? dlen : token->size;
328 //debug("cmp(%*.*s,%s) = ",
329 // (int)token->size, (int)token->size, token->value,
330 // dir);
332 val = memcmp(token->value, dir, clen);
333 if (val != 0) {
334 //debug("%d [cmp]\n", val);
335 return val;
338 if (dlen == token->size) {
339 //debug("0\n");
340 return 0;
342 //debug("%d\n", (int)dlen - (int)token->size);
343 return dlen - token->size; /* shorter -> negative */
347 * Tokenise an ASN.1 grammar
349 static void tokenise(char *buffer, char *end)
351 struct token *tokens;
352 char *line, *nl, *p, *q;
353 unsigned tix, lineno;
355 /* Assume we're going to have half as many tokens as we have
356 * characters
358 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
359 if (!tokens) {
360 perror(NULL);
361 exit(1);
363 tix = 0;
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';
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;
392 q++;
394 *p = '\0';
395 nl = p;
396 break;
397 } else {
398 p++;
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;
410 tokens[tix].line = lineno;
411 tokens[tix].value = p;
413 /* Handle string tokens */
414 if (isalpha(*p)) {
415 const char **dir;
417 /* Can be a directive, type name or element
418 * name. Find the end of the name.
420 q = p + 1;
421 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
422 q++;
423 tokens[tix].size = q - p;
424 p = q;
426 /* If it begins with a lowercase letter then
427 * it's an element name
429 if (islower(tokens[tix].value[0])) {
430 tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
431 continue;
434 /* Otherwise we need to search the directive
435 * table
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;
446 tokens[tix++].token_type = TOKEN_TYPE_NAME;
447 continue;
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;
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;
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;
478 if (memcmp(p, "})", 2) == 0) {
479 p += 2;
480 tokens[tix].size = 2;
481 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
482 continue;
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;
514 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
515 filename, lineno, *p);
516 exit(1);
520 nr_tokens = tix;
521 debug("Extracted %u tokens\n", nr_tokens);
523 #if 0
525 int n;
526 for (n = 0; n < nr_tokens; n++)
527 debug("Token %3u: '%*.*s'\n",
529 (int)token_list[n].size, (int)token_list[n].size,
530 token_list[n].value);
532 #endif
535 static void build_type_list(void);
536 static void parse(void);
537 static void render(FILE *out, FILE *hdr);
542 int main(int argc, char **argv)
544 struct stat st;
545 ssize_t readlen;
546 FILE *out, *hdr;
547 char *buffer, *p;
548 char *kbuild_verbose;
549 int fd;
551 if (argc != 4) {
552 fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
553 argv[0]);
554 exit(2);
557 kbuild_verbose = getenv("KBUILD_VERBOSE");
558 if (kbuild_verbose)
559 verbose = atoi(kbuild_verbose);
561 filename = argv[1];
562 outputname = argv[2];
563 headername = argv[3];
565 fd = open(filename, O_RDONLY);
566 if (fd < 0) {
567 perror(filename);
568 exit(1);
571 if (fstat(fd, &st) < 0) {
572 perror(filename);
573 exit(1);
576 if (!(buffer = malloc(st.st_size + 1))) {
577 perror(NULL);
578 exit(1);
581 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
582 perror(filename);
583 exit(1);
586 if (close(fd) < 0) {
587 perror(filename);
588 exit(1);
591 if (readlen != st.st_size) {
592 fprintf(stderr, "%s: Short read\n", filename);
593 exit(1);
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);
603 p = strchr(grammar_name, '.');
604 if (p)
605 *p = '\0';
607 buffer[readlen] = 0;
608 tokenise(buffer, buffer + readlen);
609 build_type_list();
610 parse();
612 out = fopen(outputname, "w");
613 if (!out) {
614 perror(outputname);
615 exit(1);
618 hdr = fopen(headername, "w");
619 if (!out) {
620 perror(headername);
621 exit(1);
624 render(out, hdr);
626 if (fclose(out) < 0) {
627 perror(outputname);
628 exit(1);
631 if (fclose(hdr) < 0) {
632 perror(headername);
633 exit(1);
636 return 0;
639 enum compound {
640 NOT_COMPOUND,
641 SET,
642 SET_OF,
643 SEQUENCE,
644 SEQUENCE_OF,
645 CHOICE,
646 ANY,
647 TYPE_REF,
648 TAG_OVERRIDE
651 struct 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
675 struct 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
685 static struct type *type_list;
686 static struct type **type_index;
687 static unsigned nr_types;
689 static int type_index_compare(const void *_a, const void *_b)
691 const struct type *const *a = _a, *const *b = _b;
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);
700 static int type_finder(const void *_key, const void *_ti)
702 const struct token *token = _key;
703 const struct type *const *ti = _ti;
704 const struct type *type = *ti;
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);
714 * Build up a list of types and a sorted index to that list.
716 static void build_type_list(void)
718 struct type *types;
719 unsigned nr, t, n;
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++;
727 if (nr == 0) {
728 fprintf(stderr, "%s: No defined types\n", filename);
729 exit(1);
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);
738 type_index = calloc(nr, sizeof(type_index[0]));
739 if (!type_index) {
740 perror(NULL);
741 exit(1);
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++;
754 types[t].name = &token_list[n + 1];
755 types[t].flags |= TYPE_STOP_MARKER;
757 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
759 debug("Extracted %u types\n", nr_types);
760 #if 0
761 for (n = 0; n < nr_types; n++) {
762 struct type *type = type_index[n];
763 debug("- %*.*s\n",
764 (int)type->name->size,
765 (int)type->name->size,
766 type->name->value);
768 #endif
771 static struct element *parse_type(struct token **_cursor, struct token *stop,
772 struct token *name);
775 * Parse the token stream
777 static void parse(void)
779 struct token *cursor;
780 struct type *type;
782 /* Parse one type definition statement at a time */
783 type = type_list;
784 do {
785 cursor = type->name;
787 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
788 cursor[1].token_type != TOKEN_ASSIGNMENT)
789 abort();
790 cursor += 2;
792 type->element = parse_type(&cursor, type[1].name, NULL);
793 type->element->type_def = type;
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);
802 } while (type++, !(type->flags & TYPE_STOP_MARKER));
804 debug("Extracted %u actions\n", nr_actions);
807 static struct element *element_list;
809 static struct element *alloc_elem(struct token *type)
811 struct element *e = calloc(1, sizeof(*e));
812 if (!e) {
813 perror(NULL);
814 exit(1);
816 e->list_next = element_list;
817 element_list = e;
818 return e;
821 static struct element *parse_compound(struct token **_cursor, struct token *end,
822 int alternates);
825 * Parse one type definition statement
827 static struct element *parse_type(struct token **_cursor, struct token *end,
828 struct token *name)
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;
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;
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);
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);
880 element->tag &= ~0x1f;
881 element->tag |= strtoul(cursor->value, &p, 10);
882 if (p - cursor->value != cursor->size)
883 abort();
884 cursor++;
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);
894 cursor++;
895 if (cursor >= end)
896 goto overrun_error;
897 labelled = 1;
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;
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;
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;
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;
942 case DIRECTIVE_EXTERNAL:
943 element->method = ASN1_CONS;
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;
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;
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;
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);
996 cursor->type = *ref;
997 (*ref)->ref_count++;
998 cursor++;
999 break;
1001 case DIRECTIVE_CHOICE:
1002 element->compound = CHOICE;
1003 cursor++;
1004 element->children = parse_compound(&cursor, end, 1);
1005 break;
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);
1022 break;
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);
1039 break;
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);
1048 /* Handle elements that are optional */
1049 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1050 cursor->token_type == DIRECTIVE_DEFAULT)
1052 cursor++;
1053 top->flags |= ELEMENT_SKIPPABLE;
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);
1067 action = malloc(sizeof(struct action) + cursor->size + 1);
1068 if (!action) {
1069 perror(NULL);
1070 exit(1);
1072 action->index = 0;
1073 memcpy(action->name, cursor->value, cursor->size);
1074 action->name[cursor->size] = 0;
1076 for (ppaction = &action_list;
1077 *ppaction;
1078 ppaction = &(*ppaction)->next
1080 int cmp = strcmp(action->name, (*ppaction)->name);
1081 if (cmp == 0) {
1082 free(action);
1083 action = *ppaction;
1084 goto found;
1086 if (cmp < 0) {
1087 action->next = *ppaction;
1088 *ppaction = action;
1089 nr_actions++;
1090 goto found;
1093 action->next = NULL;
1094 *ppaction = action;
1095 nr_actions++;
1096 found:
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);
1109 cursor++;
1112 *_cursor = cursor;
1113 return top;
1115 parse_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);
1121 overrun_error:
1122 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1123 exit(1);
1127 * Parse a compound type list
1129 static struct element *parse_compound(struct token **_cursor, struct token *end,
1130 int alternates)
1132 struct element *children, **child_p = &children, *element;
1133 struct token *cursor = *_cursor, *name;
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);
1141 cursor++;
1142 if (cursor >= end)
1143 goto overrun_error;
1145 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1146 fprintf(stderr, "%s:%d: Empty compound\n",
1147 filename, cursor->line);
1148 exit(1);
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;
1160 element = parse_type(&cursor, end, name);
1161 if (alternates)
1162 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1164 *child_p = element;
1165 child_p = &element->next;
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;
1176 children->flags &= ~ELEMENT_CONDITIONAL;
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);
1184 cursor++;
1186 *_cursor = cursor;
1187 return children;
1189 overrun_error:
1190 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1191 exit(1);
1194 static void render_element(FILE *out, struct element *e, struct element *tag);
1195 static void render_out_of_line_list(FILE *out);
1197 static int nr_entries;
1198 static int render_depth = 1;
1199 static struct element *render_list, **render_list_p = &render_list;
1201 __attribute__((format(printf, 2, 3)))
1202 static void render_opcode(FILE *out, const char *fmt, ...)
1204 va_list va;
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);
1212 nr_entries++;
1215 __attribute__((format(printf, 2, 3)))
1216 static void render_more(FILE *out, const char *fmt, ...)
1218 va_list va;
1220 if (out) {
1221 va_start(va, fmt);
1222 vfprintf(out, fmt, va);
1223 va_end(va);
1228 * Render the grammar into a state machine definition.
1230 static void render(FILE *out, FILE *hdr)
1232 struct element *e;
1233 struct action *action;
1234 struct type *root;
1235 int index;
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);
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);
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);
1273 fprintf(hdr, "\n");
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");
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");
1289 if (ferror(out)) {
1290 perror(outputname);
1291 exit(1);
1294 /* We do two passes - the first one calculates all the offsets */
1295 debug("Pass 1\n");
1296 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);
1302 for (e = element_list; e; e = e->list_next)
1303 e->flags &= ~ELEMENT_RENDERED;
1305 /* And then we actually render */
1306 debug("Pass 2\n");
1307 fprintf(out, "\n");
1308 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1309 grammar_name);
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);
1317 fprintf(out, "};\n");
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");
1328 * Render the out-of-line elements
1330 static void render_out_of_line_list(FILE *out)
1332 struct element *e, *ce;
1333 const char *act;
1334 int entry;
1336 while ((e = render_list)) {
1337 render_list = e->render_next;
1338 if (!render_list)
1339 render_list_p = &render_list;
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--;
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;
1364 default:
1365 break;
1367 if (e->action)
1368 render_opcode(out, "_action(ACT_%s),\n",
1369 e->action->name);
1370 render_opcode(out, "ASN1_OP_RETURN,\n");
1375 * Render an element.
1377 static void render_element(FILE *out, struct element *e, struct element *tag)
1379 struct element *ec;
1380 const char *cond, *act;
1381 int entry, skippable = 0, outofline = 0;
1383 if (e->flags & ELEMENT_SKIPPABLE ||
1384 (tag && tag->flags & ELEMENT_SKIPPABLE))
1385 skippable = 1;
1387 if ((e->type_def && e->type_def->ref_count > 1) ||
1388 skippable)
1389 outofline = 1;
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);
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;
1411 case TAG_OVERRIDE:
1412 render_element(out, e->children, e);
1413 return;
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;
1425 case CHOICE:
1426 goto dont_render_tag;
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;
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");
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;
1461 dont_render_tag:
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;
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;
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);
1496 break;
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;
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);
1528 break;
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.
1537 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1538 exit(1);
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;
1549 default:
1550 break;
1553 if (e->action)
1554 render_opcode(out, "_action(ACT_%s),\n", e->action->name);