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
);