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;
315 static int directive_compare(const void *_key, const void *_pdir)
317 const struct token *token = _key;
318 const char *const *pdir = _pdir, *dir = *pdir;
323 clen = (dlen < token->size) ? dlen : token->size;
325 //printf("cmp(%*.*s,%s) = ",
326 // (int)token->size, (int)token->size, token->value,
329 val = memcmp(token->value, dir, clen);
331 //printf("%d [cmp]\n", val);
335 if (dlen == token->size) {
339 //printf("%d\n", (int)dlen - (int)token->size);
340 return dlen - token->size; /* shorter -> negative */
344 * Tokenise an ASN.1 grammar
346 static void tokenise(char *buffer, char *end)
348 struct token *tokens;
349 char *line, *nl, *p, *q;
350 unsigned tix, lineno;
352 /* Assume we're going to have half as many tokens as we have
355 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
363 while (buffer < end) {
364 /* First of all, break out a line */
367 nl = memchr(line, '\n', end - buffer);
375 /* Remove "--" comments */
378 while ((p = memchr(p, '-', nl - p))) {
380 /* Found a comment; see if there's a terminator */
382 while ((q = memchr(q, '-', nl - q))) {
384 /* There is - excise the comment */
386 memmove(p, q, nl - q);
401 /* Skip white space */
402 while (p < nl && isspace(*p))
407 tokens[tix].line = lineno;
408 tokens[tix].value = p;
410 /* Handle string tokens */
414 /* Can be a directive, type name or element
415 * name. Find the end of the name.
418 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
420 tokens[tix].size = q - p;
423 /* If it begins with a lowercase letter then
424 * it's an element name
426 if (islower(tokens[tix].value[0])) {
427 tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
431 /* Otherwise we need to search the directive
434 dir = bsearch(&tokens[tix], directives,
435 sizeof(directives) / sizeof(directives[1]),
436 sizeof(directives[1]),
439 tokens[tix++].token_type = dir - directives;
443 tokens[tix++].token_type = TOKEN_TYPE_NAME;
449 /* Find the end of the number */
451 while (q < nl && (isdigit(*q)))
453 tokens[tix].size = q - p;
455 tokens[tix++].token_type = TOKEN_NUMBER;
460 if (memcmp(p, "::=", 3) == 0) {
462 tokens[tix].size = 3;
463 tokens[tix++].token_type = TOKEN_ASSIGNMENT;
469 if (memcmp(p, "({", 2) == 0) {
471 tokens[tix].size = 2;
472 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
475 if (memcmp(p, "})", 2) == 0) {
477 tokens[tix].size = 2;
478 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
484 tokens[tix].size = 1;
488 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
492 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
496 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
500 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
504 tokens[tix++].token_type = TOKEN_COMMA;
511 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
512 filename, lineno, *p);
518 printf("Extracted %u tokens\n", nr_tokens);
523 for (n = 0; n < nr_tokens; n++)
524 printf("Token %3u: '%*.*s'\n",
526 (int)token_list[n].size, (int)token_list[n].size,
527 token_list[n].value);
532 static void build_type_list(void);
533 static void parse(void);
534 static void render(FILE *out, FILE *hdr);
539 int main(int argc, char **argv)
548 fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
554 outputname = argv[2];
555 headername = argv[3];
557 fd = open(filename, O_RDONLY);
563 if (fstat(fd, &st) < 0) {
568 if (!(buffer = malloc(st.st_size + 1))) {
573 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
583 if (readlen != st.st_size) {
584 fprintf(stderr, "%s: Short read\n", filename);
588 p = strrchr(argv[1], '/');
589 p = p ? p + 1 : argv[1];
590 grammar_name = strdup(p);
595 p = strchr(grammar_name, '.');
600 tokenise(buffer, buffer + readlen);
604 out = fopen(outputname, "w");
610 hdr = fopen(headername, "w");
618 if (fclose(out) < 0) {
623 if (fclose(hdr) < 0) {
644 struct type *type_def;
647 struct action *action;
648 struct element *children;
649 struct element *next;
650 struct element *render_next;
651 struct element *list_next;
653 enum compound compound : 8;
654 enum asn1_class class : 8;
655 enum asn1_method method : 8;
657 unsigned entry_index;
659 #define ELEMENT_IMPLICIT 0x0001
660 #define ELEMENT_EXPLICIT 0x0002
661 #define ELEMENT_MARKED 0x0004
662 #define ELEMENT_RENDERED 0x0008
663 #define ELEMENT_SKIPPABLE 0x0010
664 #define ELEMENT_CONDITIONAL 0x0020
670 struct element *element;
673 #define TYPE_STOP_MARKER 0x0001
674 #define TYPE_BEGIN 0x0002
677 static struct type *type_list;
678 static struct type **type_index;
679 static unsigned nr_types;
681 static int type_index_compare(const void *_a, const void *_b)
683 const struct type *const *a = _a, *const *b = _b;
685 if ((*a)->name->size != (*b)->name->size)
686 return (*a)->name->size - (*b)->name->size;
688 return memcmp((*a)->name->value, (*b)->name->value,
692 static int type_finder(const void *_key, const void *_ti)
694 const struct token *token = _key;
695 const struct type *const *ti = _ti;
696 const struct type *type = *ti;
698 if (token->size != type->name->size)
699 return token->size - type->name->size;
701 return memcmp(token->value, type->name->value,
706 * Build up a list of types and a sorted index to that list.
708 static void build_type_list(void)
714 for (n = 0; n < nr_tokens - 1; n++)
715 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
716 token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
720 fprintf(stderr, "%s: No defined types\n", filename);
725 types = type_list = calloc(nr + 1, sizeof(type_list[0]));
730 type_index = calloc(nr, sizeof(type_index[0]));
737 types[t].flags |= TYPE_BEGIN;
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 types[t].name = &token_list[n];
742 type_index[t] = &types[t];
746 types[t].name = &token_list[n + 1];
747 types[t].flags |= TYPE_STOP_MARKER;
749 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
751 printf("Extracted %u types\n", nr_types);
753 for (n = 0; n < nr_types; n++) {
754 struct type *type = type_index[n];
756 (int)type->name->size,
757 (int)type->name->size,
763 static struct element *parse_type(struct token **_cursor, struct token *stop,
767 * Parse the token stream
769 static void parse(void)
771 struct token *cursor;
774 /* Parse one type definition statement at a time */
779 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
780 cursor[1].token_type != TOKEN_ASSIGNMENT)
784 type->element = parse_type(&cursor, type[1].name, NULL);
785 type->element->type_def = type;
787 if (cursor != type[1].name) {
788 fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n",
789 filename, cursor->line,
790 (int)cursor->size, (int)cursor->size, cursor->value);
794 } while (type++, !(type->flags & TYPE_STOP_MARKER));
796 printf("Extracted %u actions\n", nr_actions);
799 static struct element *element_list;
801 static struct element *alloc_elem(struct token *type)
803 struct element *e = calloc(1, sizeof(*e));
808 e->list_next = element_list;
813 static struct element *parse_compound(struct token **_cursor, struct token *end,
817 * Parse one type definition statement
819 static struct element *parse_type(struct token **_cursor, struct token *end,
822 struct element *top, *element;
823 struct action *action, **ppaction;
824 struct token *cursor = *_cursor;
827 int labelled = 0, implicit = 0;
829 top = element = alloc_elem(cursor);
830 element->class = ASN1_UNIV;
831 element->method = ASN1_PRIM;
832 element->tag = token_to_tag[cursor->token_type];
833 element->name = name;
835 /* Extract the tag value if one given */
836 if (cursor->token_type == TOKEN_OPEN_SQUARE) {
840 switch (cursor->token_type) {
841 case DIRECTIVE_UNIVERSAL:
842 element->class = ASN1_UNIV;
845 case DIRECTIVE_APPLICATION:
846 element->class = ASN1_APPL;
850 element->class = ASN1_CONT;
852 case DIRECTIVE_PRIVATE:
853 element->class = ASN1_PRIV;
857 fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n",
858 filename, cursor->line,
859 (int)cursor->size, (int)cursor->size, cursor->value);
865 if (cursor->token_type != TOKEN_NUMBER) {
866 fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n",
867 filename, cursor->line,
868 (int)cursor->size, (int)cursor->size, cursor->value);
872 element->tag &= ~0x1f;
873 element->tag |= strtoul(cursor->value, &p, 10);
874 if (p - cursor->value != cursor->size)
880 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
881 fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n",
882 filename, cursor->line,
883 (int)cursor->size, (int)cursor->size, cursor->value);
892 /* Handle implicit and explicit markers */
893 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
894 element->flags |= ELEMENT_IMPLICIT;
899 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
900 element->flags |= ELEMENT_EXPLICIT;
908 element->method |= ASN1_CONS;
909 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
910 element->children = alloc_elem(cursor);
911 element = element->children;
912 element->class = ASN1_UNIV;
913 element->method = ASN1_PRIM;
914 element->tag = token_to_tag[cursor->token_type];
915 element->name = name;
918 /* Extract the type we're expecting here */
919 element->type = cursor;
920 switch (cursor->token_type) {
922 element->compound = ANY;
927 case DIRECTIVE_BOOLEAN:
928 case DIRECTIVE_ENUMERATED:
929 case DIRECTIVE_INTEGER:
930 element->compound = NOT_COMPOUND;
934 case DIRECTIVE_EXTERNAL:
935 element->method = ASN1_CONS;
937 case DIRECTIVE_BMPString:
938 case DIRECTIVE_GeneralString:
939 case DIRECTIVE_GraphicString:
940 case DIRECTIVE_IA5String:
941 case DIRECTIVE_ISO646String:
942 case DIRECTIVE_NumericString:
943 case DIRECTIVE_PrintableString:
944 case DIRECTIVE_T61String:
945 case DIRECTIVE_TeletexString:
946 case DIRECTIVE_UniversalString:
947 case DIRECTIVE_UTF8String:
948 case DIRECTIVE_VideotexString:
949 case DIRECTIVE_VisibleString:
950 case DIRECTIVE_ObjectDescriptor:
951 case DIRECTIVE_GeneralizedTime:
952 case DIRECTIVE_UTCTime:
953 element->compound = NOT_COMPOUND;
958 case DIRECTIVE_OCTET:
959 element->compound = NOT_COMPOUND;
963 if (cursor->token_type != DIRECTIVE_STRING)
968 case DIRECTIVE_OBJECT:
969 element->compound = NOT_COMPOUND;
973 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
978 case TOKEN_TYPE_NAME:
979 element->compound = TYPE_REF;
980 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
983 fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n",
984 filename, cursor->line,
985 (int)cursor->size, (int)cursor->size, cursor->value);
993 case DIRECTIVE_CHOICE:
994 element->compound = CHOICE;
996 element->children = parse_compound(&cursor, end, 1);
999 case DIRECTIVE_SEQUENCE:
1000 element->compound = SEQUENCE;
1001 element->method = ASN1_CONS;
1005 if (cursor->token_type == DIRECTIVE_OF) {
1006 element->compound = SEQUENCE_OF;
1010 element->children = parse_type(&cursor, end, NULL);
1012 element->children = parse_compound(&cursor, end, 0);
1017 element->compound = SET;
1018 element->method = ASN1_CONS;
1022 if (cursor->token_type == DIRECTIVE_OF) {
1023 element->compound = SET_OF;
1027 element->children = parse_type(&cursor, end, NULL);
1029 element->children = parse_compound(&cursor, end, 1);
1034 fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n",
1035 filename, cursor->line,
1036 (int)cursor->size, (int)cursor->size, cursor->value);
1040 /* Handle elements that are optional */
1041 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1042 cursor->token_type == DIRECTIVE_DEFAULT)
1045 top->flags |= ELEMENT_SKIPPABLE;
1048 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1052 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1053 fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n",
1054 filename, cursor->line,
1055 (int)cursor->size, (int)cursor->size, cursor->value);
1059 action = malloc(sizeof(struct action) + cursor->size + 1);
1065 memcpy(action->name, cursor->value, cursor->size);
1066 action->name[cursor->size] = 0;
1068 for (ppaction = &action_list;
1070 ppaction = &(*ppaction)->next
1072 int cmp = strcmp(action->name, (*ppaction)->name);
1079 action->next = *ppaction;
1085 action->next = NULL;
1090 element->action = action;
1091 cursor->action = action;
1095 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1096 fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n",
1097 filename, cursor->line,
1098 (int)cursor->size, (int)cursor->size, cursor->value);
1108 fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n",
1109 filename, cursor->line,
1110 (int)cursor->size, (int)cursor->size, cursor->value);
1114 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1119 * Parse a compound type list
1121 static struct element *parse_compound(struct token **_cursor, struct token *end,
1124 struct element *children, **child_p = &children, *element;
1125 struct token *cursor = *_cursor, *name;
1127 if (cursor->token_type != TOKEN_OPEN_CURLY) {
1128 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
1129 filename, cursor->line,
1130 (int)cursor->size, (int)cursor->size, cursor->value);
1137 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1138 fprintf(stderr, "%s:%d: Empty compound\n",
1139 filename, cursor->line);
1145 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1152 element = parse_type(&cursor, end, name);
1154 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1157 child_p = &element->next;
1161 if (cursor->token_type != TOKEN_COMMA)
1168 children->flags &= ~ELEMENT_CONDITIONAL;
1170 if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1171 fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n",
1172 filename, cursor->line,
1173 (int)cursor->size, (int)cursor->size, cursor->value);
1182 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1186 static void render_element(FILE *out, struct element *e, struct element *tag);
1187 static void render_out_of_line_list(FILE *out);
1189 static int nr_entries;
1190 static int render_depth = 1;
1191 static struct element *render_list, **render_list_p = &render_list;
1193 __attribute__((format(printf, 2, 3)))
1194 static void render_opcode(FILE *out, const char *fmt, ...)
1199 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1201 vfprintf(out, fmt, va);
1207 __attribute__((format(printf, 2, 3)))
1208 static void render_more(FILE *out, const char *fmt, ...)
1214 vfprintf(out, fmt, va);
1220 * Render the grammar into a state machine definition.
1222 static void render(FILE *out, FILE *hdr)
1225 struct action *action;
1229 fprintf(hdr, "/*\n");
1230 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
1231 fprintf(hdr, " *\n");
1232 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1233 fprintf(hdr, " */\n");
1234 fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1236 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1242 fprintf(out, "/*\n");
1243 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
1244 fprintf(out, " *\n");
1245 fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1246 fprintf(out, " */\n");
1247 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1248 fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name);
1255 /* Tabulate the action functions we might have to call */
1258 for (action = action_list; action; action = action->next) {
1259 action->index = index++;
1261 "extern int %s(void *, size_t, unsigned char,"
1262 " const void *, size_t);\n",
1267 fprintf(out, "enum %s_actions {\n", grammar_name);
1268 for (action = action_list; action; action = action->next)
1269 fprintf(out, "\tACT_%s = %u,\n",
1270 action->name, action->index);
1271 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1272 fprintf(out, "};\n");
1275 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1276 grammar_name, grammar_name);
1277 for (action = action_list; action; action = action->next)
1278 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1279 fprintf(out, "};\n");
1286 /* We do two passes - the first one calculates all the offsets */
1289 root = &type_list[0];
1290 render_element(NULL, root->element, NULL);
1291 render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1292 render_out_of_line_list(NULL);
1294 for (e = element_list; e; e = e->list_next)
1295 e->flags &= ~ELEMENT_RENDERED;
1297 /* And then we actually render */
1300 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1304 root = &type_list[0];
1305 render_element(out, root->element, NULL);
1306 render_opcode(out, "ASN1_OP_COMPLETE,\n");
1307 render_out_of_line_list(out);
1309 fprintf(out, "};\n");
1312 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1313 fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1314 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1315 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1316 fprintf(out, "};\n");
1320 * Render the out-of-line elements
1322 static void render_out_of_line_list(FILE *out)
1324 struct element *e, *ce;
1328 while ((e = render_list)) {
1329 render_list = e->render_next;
1331 render_list_p = &render_list;
1333 render_more(out, "\n");
1334 e->entry_index = entry = nr_entries;
1336 for (ce = e->children; ce; ce = ce->next)
1337 render_element(out, ce, NULL);
1340 act = e->action ? "_ACT" : "";
1341 switch (e->compound) {
1343 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1346 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1347 render_opcode(out, "_jump_target(%u),\n", entry);
1350 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1353 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1354 render_opcode(out, "_jump_target(%u),\n", entry);
1360 render_opcode(out, "_action(ACT_%s),\n",
1362 render_opcode(out, "ASN1_OP_RETURN,\n");
1367 * Render an element.
1369 static void render_element(FILE *out, struct element *e, struct element *tag)
1372 const char *cond, *act;
1373 int entry, skippable = 0, outofline = 0;
1375 if (e->flags & ELEMENT_SKIPPABLE ||
1376 (tag && tag->flags & ELEMENT_SKIPPABLE))
1379 if ((e->type_def && e->type_def->ref_count > 1) ||
1383 if (e->type_def && out) {
1384 render_more(out, "\t// %*.*s\n",
1385 (int)e->type_def->name->size, (int)e->type_def->name->size,
1386 e->type_def->name->value);
1389 /* Render the operation */
1390 cond = (e->flags & ELEMENT_CONDITIONAL ||
1391 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1392 act = e->action ? "_ACT" : "";
1393 switch (e->compound) {
1395 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act);
1397 render_more(out, "\t\t// %*.*s",
1398 (int)e->name->size, (int)e->name->size,
1400 render_more(out, "\n");
1401 goto dont_render_tag;
1404 render_element(out, e->children, e);
1411 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1413 outofline ? "_JUMP" : "",
1414 skippable ? "_OR_SKIP" : "");
1418 goto dont_render_tag;
1421 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1422 goto dont_render_tag;
1424 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1426 skippable ? "_OR_SKIP" : "");
1431 render_more(out, "\t\t// %*.*s",
1432 (int)e->name->size, (int)e->name->size,
1434 render_more(out, "\n");
1436 /* Render the tag */
1439 if (tag->class == ASN1_UNIV &&
1443 render_opcode(out, "_tag(%s, %s, %s),\n",
1444 asn1_classes[tag->class],
1445 asn1_methods[tag->method | e->method],
1446 asn1_universal_tags[tag->tag]);
1448 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1449 asn1_classes[tag->class],
1450 asn1_methods[tag->method | e->method],
1455 /* Deal with compound types */
1456 switch (e->compound) {
1458 render_element(out, e->type->type->element, tag);
1460 render_opcode(out, "ASN1_OP_ACT,\n");
1465 /* Render out-of-line for multiple use or
1467 render_opcode(out, "_jump_target(%u),", e->entry_index);
1468 if (e->type_def && e->type_def->name)
1469 render_more(out, "\t\t// --> %*.*s",
1470 (int)e->type_def->name->size,
1471 (int)e->type_def->name->size,
1472 e->type_def->name->value);
1473 render_more(out, "\n");
1474 if (!(e->flags & ELEMENT_RENDERED)) {
1475 e->flags |= ELEMENT_RENDERED;
1477 render_list_p = &e->render_next;
1481 /* Render inline for single use */
1483 for (ec = e->children; ec; ec = ec->next)
1484 render_element(out, ec, NULL);
1486 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1493 /* Render out-of-line for multiple use or
1495 render_opcode(out, "_jump_target(%u),", e->entry_index);
1496 if (e->type_def && e->type_def->name)
1497 render_more(out, "\t\t// --> %*.*s",
1498 (int)e->type_def->name->size,
1499 (int)e->type_def->name->size,
1500 e->type_def->name->value);
1501 render_more(out, "\n");
1502 if (!(e->flags & ELEMENT_RENDERED)) {
1503 e->flags |= ELEMENT_RENDERED;
1505 render_list_p = &e->render_next;
1509 /* Render inline for single use */
1512 render_element(out, e->children, NULL);
1514 if (e->compound == SEQUENCE_OF)
1515 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1517 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1518 render_opcode(out, "_jump_target(%u),\n", entry);
1523 /* I can't think of a nice way to do SET support without having
1524 * a stack of bitmasks to make sure no element is repeated.
1525 * The bitmask has also to be checked that no non-optional
1526 * elements are left out whilst not preventing optional
1527 * elements from being left out.
1529 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1533 for (ec = e->children; ec; ec = ec->next)
1534 render_element(out, ec, NULL);
1536 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1538 render_opcode(out, "ASN1_OP_ACT,\n");
1546 render_opcode(out, "_action(ACT_%s),\n", e->action->name);