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.
21 #include <linux/asn1_ber_bytecode.h>
27 DIRECTIVE_APPLICATION,
39 DIRECTIVE_CONSTRAINED,
43 DIRECTIVE_DEFINITIONS,
46 DIRECTIVE_ENCODING_CONTROL,
52 DIRECTIVE_EXTENSIBILITY,
56 DIRECTIVE_GeneralString,
57 DIRECTIVE_GeneralizedTime,
58 DIRECTIVE_GraphicString,
66 DIRECTIVE_INSTRUCTIONS,
68 DIRECTIVE_INTERSECTION,
69 DIRECTIVE_ISO646String,
72 DIRECTIVE_MINUS_INFINITY,
74 DIRECTIVE_NumericString,
79 DIRECTIVE_ObjectDescriptor,
82 DIRECTIVE_PLUS_INFINITY,
85 DIRECTIVE_PrintableString,
87 DIRECTIVE_RELATIVE_OID,
96 DIRECTIVE_TeletexString,
101 DIRECTIVE_UTF8String,
102 DIRECTIVE_UniversalString,
103 DIRECTIVE_VideotexString,
104 DIRECTIVE_VisibleString,
107 TOKEN_ASSIGNMENT = NR__DIRECTIVES,
121 static const unsigned char token_to_tag[NR__TOKENS] = {
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,
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",
163 static const char asn1_methods[2][5] = {
164 [ASN1_UNIV] = "PRIM",
168 static const char *const asn1_universal_tags[32] = {
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
232 [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
258 [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
259 [DIRECTIVE_NULL] = "NULL",
268 [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
273 [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
300 static struct action *action_list;
301 static unsigned nr_actions;
305 enum token_type token_type : 8;
307 struct action *action;
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;
326 clen = (dlen < token->size) ? dlen : token->size;
328 //debug("cmp(%*.*s,%s) = ",
329 // (int)token->size, (int)token->size, token->value,
332 val = memcmp(token->value, dir, clen);
334 //debug("%d [cmp]\n", val);
338 if (dlen == token->size) {
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
358 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
366 while (buffer < end) {
367 /* First of all, break out a line */
370 nl = memchr(line, '\n', end - buffer);
378 /* Remove "--" comments */
381 while ((p = memchr(p, '-', nl - p))) {
383 /* Found a comment; see if there's a terminator */
385 while ((q = memchr(q, '-', nl - q))) {
387 /* There is - excise the comment */
389 memmove(p, q, nl - q);
404 /* Skip white space */
405 while (p < nl && isspace(*p))
410 tokens[tix].line = lineno;
411 tokens[tix].value = p;
413 /* Handle string tokens */
417 /* Can be a directive, type name or element
418 * name. Find the end of the name.
421 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
423 tokens[tix].size = q - p;
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;
434 /* Otherwise we need to search the directive
437 dir = bsearch(&tokens[tix], directives,
438 sizeof(directives) / sizeof(directives[1]),
439 sizeof(directives[1]),
442 tokens[tix++].token_type = dir - directives;
446 tokens[tix++].token_type = TOKEN_TYPE_NAME;
452 /* Find the end of the number */
454 while (q < nl && (isdigit(*q)))
456 tokens[tix].size = q - p;
458 tokens[tix++].token_type = TOKEN_NUMBER;
463 if (memcmp(p, "::=", 3) == 0) {
465 tokens[tix].size = 3;
466 tokens[tix++].token_type = TOKEN_ASSIGNMENT;
472 if (memcmp(p, "({", 2) == 0) {
474 tokens[tix].size = 2;
475 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
478 if (memcmp(p, "})", 2) == 0) {
480 tokens[tix].size = 2;
481 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
487 tokens[tix].size = 1;
491 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
495 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
499 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
503 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
507 tokens[tix++].token_type = TOKEN_COMMA;
514 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
515 filename, lineno, *p);
521 debug("Extracted %u tokens\n", nr_tokens);
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);
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)
548 char *kbuild_verbose;
552 fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
557 kbuild_verbose = getenv("KBUILD_VERBOSE");
559 verbose = atoi(kbuild_verbose);
562 outputname = argv[2];
563 headername = argv[3];
565 fd = open(filename, O_RDONLY);
571 if (fstat(fd, &st) < 0) {
576 if (!(buffer = malloc(st.st_size + 1))) {
581 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
591 if (readlen != st.st_size) {
592 fprintf(stderr, "%s: Short read\n", filename);
596 p = strrchr(argv[1], '/');
597 p = p ? p + 1 : argv[1];
598 grammar_name = strdup(p);
603 p = strchr(grammar_name, '.');
608 tokenise(buffer, buffer + readlen);
612 out = fopen(outputname, "w");
618 hdr = fopen(headername, "w");
626 if (fclose(out) < 0) {
631 if (fclose(hdr) < 0) {
652 struct type *type_def;
655 struct action *action;
656 struct element *children;
657 struct element *next;
658 struct element *render_next;
659 struct element *list_next;
661 enum compound compound : 8;
662 enum asn1_class class : 8;
663 enum asn1_method method : 8;
665 unsigned entry_index;
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
678 struct element *element;
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;
696 return memcmp((*a)->name->value, (*b)->name->value,
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;
709 return memcmp(token->value, type->name->value,
714 * Build up a list of types and a sorted index to that list.
716 static void build_type_list(void)
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)
728 fprintf(stderr, "%s: No defined types\n", filename);
733 types = type_list = calloc(nr + 1, sizeof(type_list[0]));
738 type_index = calloc(nr, sizeof(type_index[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];
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);
761 for (n = 0; n < nr_types; n++) {
762 struct type *type = type_index[n];
764 (int)type->name->size,
765 (int)type->name->size,
771 static struct element *parse_type(struct token **_cursor, struct token *stop,
775 * Parse the token stream
777 static void parse(void)
779 struct token *cursor;
782 /* Parse one type definition statement at a time */
787 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
788 cursor[1].token_type != TOKEN_ASSIGNMENT)
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);
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));
816 e->list_next = element_list;
821 static struct element *parse_compound(struct token **_cursor, struct token *end,
825 * Parse one type definition statement
827 static struct element *parse_type(struct token **_cursor, struct token *end,
830 struct element *top, *element;
831 struct action *action, **ppaction;
832 struct token *cursor = *_cursor;
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) {
848 switch (cursor->token_type) {
849 case DIRECTIVE_UNIVERSAL:
850 element->class = ASN1_UNIV;
853 case DIRECTIVE_APPLICATION:
854 element->class = ASN1_APPL;
858 element->class = ASN1_CONT;
860 case DIRECTIVE_PRIVATE:
861 element->class = ASN1_PRIV;
865 fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
866 filename, cursor->line,
867 (int)cursor->size, (int)cursor->size, cursor->value);
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);
880 element->tag &= ~0x1f;
881 element->tag |= strtoul(cursor->value, &p, 10);
882 if (p - cursor->value != cursor->size)
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);
900 /* Handle implicit and explicit markers */
901 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
902 element->flags |= ELEMENT_IMPLICIT;
907 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
908 element->flags |= ELEMENT_EXPLICIT;
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) {
930 element->compound = ANY;
935 case DIRECTIVE_BOOLEAN:
936 case DIRECTIVE_ENUMERATED:
937 case DIRECTIVE_INTEGER:
938 element->compound = NOT_COMPOUND;
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;
966 case DIRECTIVE_OCTET:
967 element->compound = NOT_COMPOUND;
971 if (cursor->token_type != DIRECTIVE_STRING)
976 case DIRECTIVE_OBJECT:
977 element->compound = NOT_COMPOUND;
981 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
986 case TOKEN_TYPE_NAME:
987 element->compound = TYPE_REF;
988 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
991 fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
992 filename, cursor->line,
993 (int)cursor->size, (int)cursor->size, cursor->value);
1001 case DIRECTIVE_CHOICE:
1002 element->compound = CHOICE;
1004 element->children = parse_compound(&cursor, end, 1);
1007 case DIRECTIVE_SEQUENCE:
1008 element->compound = SEQUENCE;
1009 element->method = ASN1_CONS;
1013 if (cursor->token_type == DIRECTIVE_OF) {
1014 element->compound = SEQUENCE_OF;
1018 element->children = parse_type(&cursor, end, NULL);
1020 element->children = parse_compound(&cursor, end, 0);
1025 element->compound = SET;
1026 element->method = ASN1_CONS;
1030 if (cursor->token_type == DIRECTIVE_OF) {
1031 element->compound = SET_OF;
1035 element->children = parse_type(&cursor, end, NULL);
1037 element->children = parse_compound(&cursor, end, 1);
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);
1048 /* Handle elements that are optional */
1049 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1050 cursor->token_type == DIRECTIVE_DEFAULT)
1053 top->flags |= ELEMENT_SKIPPABLE;
1056 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
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);
1067 action = malloc(sizeof(struct action) + cursor->size + 1);
1073 memcpy(action->name, cursor->value, cursor->size);
1074 action->name[cursor->size] = 0;
1076 for (ppaction = &action_list;
1078 ppaction = &(*ppaction)->next
1080 int cmp = strcmp(action->name, (*ppaction)->name);
1087 action->next = *ppaction;
1093 action->next = NULL;
1098 element->action = action;
1099 cursor->action = action;
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);
1116 fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
1117 filename, cursor->line,
1118 (int)cursor->size, (int)cursor->size, cursor->value);
1122 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1127 * Parse a compound type list
1129 static struct element *parse_compound(struct token **_cursor, struct token *end,
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);
1145 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1146 fprintf(stderr, "%s:%d: Empty compound\n",
1147 filename, cursor->line);
1153 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1160 element = parse_type(&cursor, end, name);
1162 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1165 child_p = &element->next;
1169 if (cursor->token_type != TOKEN_COMMA)
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);
1190 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
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, ...)
1207 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1209 vfprintf(out, fmt, va);
1215 __attribute__((format(printf, 2, 3)))
1216 static void render_more(FILE *out, const char *fmt, ...)
1222 vfprintf(out, fmt, va);
1228 * Render the grammar into a state machine definition.
1230 static void render(FILE *out, FILE *hdr)
1233 struct action *action;
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");
1244 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
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);
1263 /* Tabulate the action functions we might have to call */
1266 for (action = action_list; action; action = action->next) {
1267 action->index = index++;
1269 "extern int %s(void *, size_t, unsigned char,"
1270 " const void *, size_t);\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");
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");
1294 /* We do two passes - the first one calculates all the offsets */
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 */
1308 fprintf(out, "static const unsigned char %s_machine[] = {\n",
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");
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;
1336 while ((e = render_list)) {
1337 render_list = e->render_next;
1339 render_list_p = &render_list;
1341 render_more(out, "\n");
1342 e->entry_index = entry = nr_entries;
1344 for (ce = e->children; ce; ce = ce->next)
1345 render_element(out, ce, NULL);
1348 act = e->action ? "_ACT" : "";
1349 switch (e->compound) {
1351 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1354 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1355 render_opcode(out, "_jump_target(%u),\n", entry);
1358 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1361 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1362 render_opcode(out, "_jump_target(%u),\n", entry);
1368 render_opcode(out, "_action(ACT_%s),\n",
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)
1380 const char *cond, *act;
1381 int entry, skippable = 0, outofline = 0;
1383 if (e->flags & ELEMENT_SKIPPABLE ||
1384 (tag && tag->flags & ELEMENT_SKIPPABLE))
1387 if ((e->type_def && e->type_def->ref_count > 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) {
1403 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
1405 render_more(out, "\t\t// %*.*s",
1406 (int)e->name->size, (int)e->name->size,
1408 render_more(out, "\n");
1409 goto dont_render_tag;
1412 render_element(out, e->children, e);
1419 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1421 outofline ? "_JUMP" : "",
1422 skippable ? "_OR_SKIP" : "");
1426 goto dont_render_tag;
1429 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1430 goto dont_render_tag;
1432 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1434 skippable ? "_OR_SKIP" : "");
1439 render_more(out, "\t\t// %*.*s",
1440 (int)e->name->size, (int)e->name->size,
1442 render_more(out, "\n");
1444 /* Render the tag */
1447 if (tag->class == ASN1_UNIV &&
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]);
1456 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1457 asn1_classes[tag->class],
1458 asn1_methods[tag->method | e->method],
1463 /* Deal with compound types */
1464 switch (e->compound) {
1466 render_element(out, e->type->type->element, tag);
1468 render_opcode(out, "ASN1_OP_ACT,\n");
1473 /* Render out-of-line for multiple use or
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;
1485 render_list_p = &e->render_next;
1489 /* Render inline for single use */
1491 for (ec = e->children; ec; ec = ec->next)
1492 render_element(out, ec, NULL);
1494 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1501 /* Render out-of-line for multiple use or
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;
1513 render_list_p = &e->render_next;
1517 /* Render inline for single use */
1520 render_element(out, e->children, NULL);
1522 if (e->compound == SEQUENCE_OF)
1523 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1525 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1526 render_opcode(out, "_jump_target(%u),\n", entry);
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");
1541 for (ec = e->children; ec; ec = ec->next)
1542 render_element(out, ec, NULL);
1544 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1546 render_opcode(out, "ASN1_OP_ACT,\n");
1554 render_opcode(out, "_action(ACT_%s),\n", e->action->name);