diff options
-rw-r--r-- | include/linux/asn1.h | 67 | ||||
-rw-r--r-- | include/linux/asn1_ber_bytecode.h | 87 | ||||
-rw-r--r-- | init/Kconfig | 8 | ||||
-rw-r--r-- | scripts/.gitignore | 1 | ||||
-rw-r--r-- | scripts/Makefile | 2 | ||||
-rw-r--r-- | scripts/Makefile.build | 11 | ||||
-rw-r--r-- | scripts/asn1_compiler.c | 1545 |
7 files changed, 1721 insertions, 0 deletions
diff --git a/include/linux/asn1.h b/include/linux/asn1.h new file mode 100644 index 000000000000..5c3f4e4b9a23 --- /dev/null +++ b/include/linux/asn1.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* ASN.1 BER/DER/CER encoding definitions | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _LINUX_ASN1_H | ||
13 | #define _LINUX_ASN1_H | ||
14 | |||
15 | /* Class */ | ||
16 | enum asn1_class { | ||
17 | ASN1_UNIV = 0, /* Universal */ | ||
18 | ASN1_APPL = 1, /* Application */ | ||
19 | ASN1_CONT = 2, /* Context */ | ||
20 | ASN1_PRIV = 3 /* Private */ | ||
21 | }; | ||
22 | #define ASN1_CLASS_BITS 0xc0 | ||
23 | |||
24 | |||
25 | enum asn1_method { | ||
26 | ASN1_PRIM = 0, /* Primitive */ | ||
27 | ASN1_CONS = 1 /* Constructed */ | ||
28 | }; | ||
29 | #define ASN1_CONS_BIT 0x20 | ||
30 | |||
31 | /* Tag */ | ||
32 | enum asn1_tag { | ||
33 | ASN1_EOC = 0, /* End Of Contents or N/A */ | ||
34 | ASN1_BOOL = 1, /* Boolean */ | ||
35 | ASN1_INT = 2, /* Integer */ | ||
36 | ASN1_BTS = 3, /* Bit String */ | ||
37 | ASN1_OTS = 4, /* Octet String */ | ||
38 | ASN1_NULL = 5, /* Null */ | ||
39 | ASN1_OID = 6, /* Object Identifier */ | ||
40 | ASN1_ODE = 7, /* Object Description */ | ||
41 | ASN1_EXT = 8, /* External */ | ||
42 | ASN1_REAL = 9, /* Real float */ | ||
43 | ASN1_ENUM = 10, /* Enumerated */ | ||
44 | ASN1_EPDV = 11, /* Embedded PDV */ | ||
45 | ASN1_UTF8STR = 12, /* UTF8 String */ | ||
46 | ASN1_RELOID = 13, /* Relative OID */ | ||
47 | /* 14 - Reserved */ | ||
48 | /* 15 - Reserved */ | ||
49 | ASN1_SEQ = 16, /* Sequence and Sequence of */ | ||
50 | ASN1_SET = 17, /* Set and Set of */ | ||
51 | ASN1_NUMSTR = 18, /* Numerical String */ | ||
52 | ASN1_PRNSTR = 19, /* Printable String */ | ||
53 | ASN1_TEXSTR = 20, /* T61 String / Teletext String */ | ||
54 | ASN1_VIDSTR = 21, /* Videotex String */ | ||
55 | ASN1_IA5STR = 22, /* IA5 String */ | ||
56 | ASN1_UNITIM = 23, /* Universal Time */ | ||
57 | ASN1_GENTIM = 24, /* General Time */ | ||
58 | ASN1_GRASTR = 25, /* Graphic String */ | ||
59 | ASN1_VISSTR = 26, /* Visible String */ | ||
60 | ASN1_GENSTR = 27, /* General String */ | ||
61 | ASN1_UNISTR = 28, /* Universal String */ | ||
62 | ASN1_CHRSTR = 29, /* Character String */ | ||
63 | ASN1_BMPSTR = 30, /* BMP String */ | ||
64 | ASN1_LONG_TAG = 31 /* Long form tag */ | ||
65 | }; | ||
66 | |||
67 | #endif /* _LINUX_ASN1_H */ | ||
diff --git a/include/linux/asn1_ber_bytecode.h b/include/linux/asn1_ber_bytecode.h new file mode 100644 index 000000000000..945d44ae529c --- /dev/null +++ b/include/linux/asn1_ber_bytecode.h | |||
@@ -0,0 +1,87 @@ | |||
1 | /* ASN.1 BER/DER/CER parsing state machine internal definitions | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #ifndef _LINUX_ASN1_BER_BYTECODE_H | ||
13 | #define _LINUX_ASN1_BER_BYTECODE_H | ||
14 | |||
15 | #ifdef __KERNEL__ | ||
16 | #include <linux/types.h> | ||
17 | #endif | ||
18 | #include <linux/asn1.h> | ||
19 | |||
20 | typedef int (*asn1_action_t)(void *context, | ||
21 | size_t hdrlen, /* In case of ANY type */ | ||
22 | unsigned char tag, /* In case of ANY type */ | ||
23 | const void *value, size_t vlen); | ||
24 | |||
25 | struct asn1_decoder { | ||
26 | const unsigned char *machine; | ||
27 | size_t machlen; | ||
28 | const asn1_action_t *actions; | ||
29 | }; | ||
30 | |||
31 | enum asn1_opcode { | ||
32 | /* The tag-matching ops come first and the odd-numbered slots | ||
33 | * are for OR_SKIP ops. | ||
34 | */ | ||
35 | #define ASN1_OP_MATCH__SKIP 0x01 | ||
36 | #define ASN1_OP_MATCH__ACT 0x02 | ||
37 | #define ASN1_OP_MATCH__JUMP 0x04 | ||
38 | #define ASN1_OP_MATCH__ANY 0x08 | ||
39 | #define ASN1_OP_MATCH__COND 0x10 | ||
40 | |||
41 | ASN1_OP_MATCH = 0x00, | ||
42 | ASN1_OP_MATCH_OR_SKIP = 0x01, | ||
43 | ASN1_OP_MATCH_ACT = 0x02, | ||
44 | ASN1_OP_MATCH_ACT_OR_SKIP = 0x03, | ||
45 | ASN1_OP_MATCH_JUMP = 0x04, | ||
46 | ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05, | ||
47 | ASN1_OP_MATCH_ANY = 0x08, | ||
48 | ASN1_OP_MATCH_ANY_ACT = 0x0a, | ||
49 | /* Everything before here matches unconditionally */ | ||
50 | |||
51 | ASN1_OP_COND_MATCH_OR_SKIP = 0x11, | ||
52 | ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13, | ||
53 | ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15, | ||
54 | ASN1_OP_COND_MATCH_ANY = 0x18, | ||
55 | ASN1_OP_COND_MATCH_ANY_ACT = 0x1a, | ||
56 | |||
57 | /* Everything before here will want a tag from the data */ | ||
58 | #define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT | ||
59 | |||
60 | /* These are here to help fill up space */ | ||
61 | ASN1_OP_COND_FAIL = 0x1b, | ||
62 | ASN1_OP_COMPLETE = 0x1c, | ||
63 | ASN1_OP_ACT = 0x1d, | ||
64 | ASN1_OP_RETURN = 0x1e, | ||
65 | |||
66 | /* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */ | ||
67 | ASN1_OP_END_SEQ = 0x20, | ||
68 | ASN1_OP_END_SET = 0x21, | ||
69 | ASN1_OP_END_SEQ_OF = 0x22, | ||
70 | ASN1_OP_END_SET_OF = 0x23, | ||
71 | ASN1_OP_END_SEQ_ACT = 0x24, | ||
72 | ASN1_OP_END_SET_ACT = 0x25, | ||
73 | ASN1_OP_END_SEQ_OF_ACT = 0x26, | ||
74 | ASN1_OP_END_SET_OF_ACT = 0x27, | ||
75 | #define ASN1_OP_END__SET 0x01 | ||
76 | #define ASN1_OP_END__OF 0x02 | ||
77 | #define ASN1_OP_END__ACT 0x04 | ||
78 | |||
79 | ASN1_OP__NR | ||
80 | }; | ||
81 | |||
82 | #define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG) | ||
83 | #define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG) | ||
84 | #define _jump_target(N) (N) | ||
85 | #define _action(N) (N) | ||
86 | |||
87 | #endif /* _LINUX_ASN1_BER_BYTECODE_H */ | ||
diff --git a/init/Kconfig b/init/Kconfig index af6c7f8ba019..66cc885abbc6 100644 --- a/init/Kconfig +++ b/init/Kconfig | |||
@@ -1612,4 +1612,12 @@ config PADATA | |||
1612 | depends on SMP | 1612 | depends on SMP |
1613 | bool | 1613 | bool |
1614 | 1614 | ||
1615 | config ASN1 | ||
1616 | tristate | ||
1617 | help | ||
1618 | Build a simple ASN.1 grammar compiler that produces a bytecode output | ||
1619 | that can be interpreted by the ASN.1 stream decoder and used to | ||
1620 | inform it as to what tags are to be expected in a stream and what | ||
1621 | functions to call on what tags. | ||
1622 | |||
1615 | source "kernel/Kconfig.locks" | 1623 | source "kernel/Kconfig.locks" |
diff --git a/scripts/.gitignore b/scripts/.gitignore index 65f362d931b5..fb070fa1038f 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore | |||
@@ -10,3 +10,4 @@ ihex2fw | |||
10 | recordmcount | 10 | recordmcount |
11 | docproc | 11 | docproc |
12 | sortextable | 12 | sortextable |
13 | asn1_compiler | ||
diff --git a/scripts/Makefile b/scripts/Makefile index a55b0067758a..01e7adb838d9 100644 --- a/scripts/Makefile +++ b/scripts/Makefile | |||
@@ -16,8 +16,10 @@ hostprogs-$(CONFIG_VT) += conmakehash | |||
16 | hostprogs-$(CONFIG_IKCONFIG) += bin2c | 16 | hostprogs-$(CONFIG_IKCONFIG) += bin2c |
17 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount | 17 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
18 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable | 18 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
19 | hostprogs-$(CONFIG_ASN1) += asn1_compiler | ||
19 | 20 | ||
20 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | 21 | HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include |
22 | HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include | ||
21 | 23 | ||
22 | always := $(hostprogs-y) $(hostprogs-m) | 24 | always := $(hostprogs-y) $(hostprogs-m) |
23 | 25 | ||
diff --git a/scripts/Makefile.build b/scripts/Makefile.build index ff1720d28d0c..0e801c3cdaf8 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build | |||
@@ -354,6 +354,17 @@ quiet_cmd_cpp_lds_S = LDS $@ | |||
354 | $(obj)/%.lds: $(src)/%.lds.S FORCE | 354 | $(obj)/%.lds: $(src)/%.lds.S FORCE |
355 | $(call if_changed_dep,cpp_lds_S) | 355 | $(call if_changed_dep,cpp_lds_S) |
356 | 356 | ||
357 | # ASN.1 grammar | ||
358 | # --------------------------------------------------------------------------- | ||
359 | quiet_cmd_asn1_compiler = ASN.1 $@ | ||
360 | cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ | ||
361 | $(subst .h,.c,$@) $(subst .c,.h,$@) | ||
362 | |||
363 | .PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h | ||
364 | |||
365 | $(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler | ||
366 | $(call cmd,asn1_compiler) | ||
367 | |||
357 | # Build the compiled-in targets | 368 | # Build the compiled-in targets |
358 | # --------------------------------------------------------------------------- | 369 | # --------------------------------------------------------------------------- |
359 | 370 | ||
diff --git a/scripts/asn1_compiler.c b/scripts/asn1_compiler.c new file mode 100644 index 000000000000..db0e5cd34c70 --- /dev/null +++ b/scripts/asn1_compiler.c | |||
@@ -0,0 +1,1545 @@ | |||
1 | /* Simplified ASN.1 notation parser | ||
2 | * | ||
3 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <stdarg.h> | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <stdint.h> | ||
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> | ||
22 | |||
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 | ||
119 | }; | ||
120 | |||
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, | ||
154 | }; | ||
155 | |||
156 | static const char asn1_classes[4][5] = { | ||
157 | [ASN1_UNIV] = "UNIV", | ||
158 | [ASN1_APPL] = "APPL", | ||
159 | [ASN1_CONT] = "CONT", | ||
160 | [ASN1_PRIV] = "PRIV" | ||
161 | }; | ||
162 | |||
163 | static const char asn1_methods[2][5] = { | ||
164 | [ASN1_UNIV] = "PRIM", | ||
165 | [ASN1_APPL] = "CONS" | ||
166 | }; | ||
167 | |||
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 */ | ||
201 | }; | ||
202 | |||
203 | static const char *filename; | ||
204 | static const char *grammar_name; | ||
205 | static const char *outputname; | ||
206 | static const char *headername; | ||
207 | |||
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) | ||
292 | }; | ||
293 | |||
294 | struct action { | ||
295 | struct action *next; | ||
296 | unsigned char index; | ||
297 | char name[]; | ||
298 | }; | ||
299 | |||
300 | static struct action *action_list; | ||
301 | static unsigned nr_actions; | ||
302 | |||
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; | ||
310 | }; | ||
311 | |||
312 | static struct token *token_list; | ||
313 | static unsigned nr_tokens; | ||
314 | |||
315 | static int directive_compare(const void *_key, const void *_pdir) | ||
316 | { | ||
317 | const struct token *token = _key; | ||
318 | const char *const *pdir = _pdir, *dir = *pdir; | ||
319 | size_t dlen, clen; | ||
320 | int val; | ||
321 | |||
322 | dlen = strlen(dir); | ||
323 | clen = (dlen < token->size) ? dlen : token->size; | ||
324 | |||
325 | //printf("cmp(%*.*s,%s) = ", | ||
326 | // (int)token->size, (int)token->size, token->value, | ||
327 | // dir); | ||
328 | |||
329 | val = memcmp(token->value, dir, clen); | ||
330 | if (val != 0) { | ||
331 | //printf("%d [cmp]\n", val); | ||
332 | return val; | ||
333 | } | ||
334 | |||
335 | if (dlen == token->size) { | ||
336 | //printf("0\n"); | ||
337 | return 0; | ||
338 | } | ||
339 | //printf("%d\n", (int)dlen - (int)token->size); | ||
340 | return dlen - token->size; /* shorter -> negative */ | ||
341 | } | ||
342 | |||
343 | /* | ||
344 | * Tokenise an ASN.1 grammar | ||
345 | */ | ||
346 | static void tokenise(char *buffer, char *end) | ||
347 | { | ||
348 | struct token *tokens; | ||
349 | char *line, *nl, *p, *q; | ||
350 | unsigned tix, lineno; | ||
351 | |||
352 | /* Assume we're going to have half as many tokens as we have | ||
353 | * characters | ||
354 | */ | ||
355 | token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); | ||
356 | if (!tokens) { | ||
357 | perror(NULL); | ||
358 | exit(1); | ||
359 | } | ||
360 | tix = 0; | ||
361 | |||
362 | lineno = 0; | ||
363 | while (buffer < end) { | ||
364 | /* First of all, break out a line */ | ||
365 | lineno++; | ||
366 | line = buffer; | ||
367 | nl = memchr(line, '\n', end - buffer); | ||
368 | if (!nl) { | ||
369 | buffer = nl = end; | ||
370 | } else { | ||
371 | buffer = nl + 1; | ||
372 | *nl = '\0'; | ||
373 | } | ||
374 | |||
375 | /* Remove "--" comments */ | ||
376 | p = line; | ||
377 | next_comment: | ||
378 | while ((p = memchr(p, '-', nl - p))) { | ||
379 | if (p[1] == '-') { | ||
380 | /* Found a comment; see if there's a terminator */ | ||
381 | q = p + 2; | ||
382 | while ((q = memchr(q, '-', nl - q))) { | ||
383 | if (q[1] == '-') { | ||
384 | /* There is - excise the comment */ | ||
385 | q += 2; | ||
386 | memmove(p, q, nl - q); | ||
387 | goto next_comment; | ||
388 | } | ||
389 | q++; | ||
390 | } | ||
391 | *p = '\0'; | ||
392 | nl = p; | ||
393 | break; | ||
394 | } else { | ||
395 | p++; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | p = line; | ||
400 | while (p < nl) { | ||
401 | /* Skip white space */ | ||
402 | while (p < nl && isspace(*p)) | ||
403 | *(p++) = 0; | ||
404 | if (p >= nl) | ||
405 | break; | ||
406 | |||
407 | tokens[tix].line = lineno; | ||
408 | tokens[tix].value = p; | ||
409 | |||
410 | /* Handle string tokens */ | ||
411 | if (isalpha(*p)) { | ||
412 | const char **dir; | ||
413 | |||
414 | /* Can be a directive, type name or element | ||
415 | * name. Find the end of the name. | ||
416 | */ | ||
417 | q = p + 1; | ||
418 | while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) | ||
419 | q++; | ||
420 | tokens[tix].size = q - p; | ||
421 | p = q; | ||
422 | |||
423 | /* If it begins with a lowercase letter then | ||
424 | * it's an element name | ||
425 | */ | ||
426 | if (islower(tokens[tix].value[0])) { | ||
427 | tokens[tix++].token_type = TOKEN_ELEMENT_NAME; | ||
428 | continue; | ||
429 | } | ||
430 | |||
431 | /* Otherwise we need to search the directive | ||
432 | * table | ||
433 | */ | ||
434 | dir = bsearch(&tokens[tix], directives, | ||
435 | sizeof(directives) / sizeof(directives[1]), | ||
436 | sizeof(directives[1]), | ||
437 | directive_compare); | ||
438 | if (dir) { | ||
439 | tokens[tix++].token_type = dir - directives; | ||
440 | continue; | ||
441 | } | ||
442 | |||
443 | tokens[tix++].token_type = TOKEN_TYPE_NAME; | ||
444 | continue; | ||
445 | } | ||
446 | |||
447 | /* Handle numbers */ | ||
448 | if (isdigit(*p)) { | ||
449 | /* Find the end of the number */ | ||
450 | q = p + 1; | ||
451 | while (q < nl && (isdigit(*q))) | ||
452 | q++; | ||
453 | tokens[tix].size = q - p; | ||
454 | p = q; | ||
455 | tokens[tix++].token_type = TOKEN_NUMBER; | ||
456 | continue; | ||
457 | } | ||
458 | |||
459 | if (nl - p >= 3) { | ||
460 | if (memcmp(p, "::=", 3) == 0) { | ||
461 | p += 3; | ||
462 | tokens[tix].size = 3; | ||
463 | tokens[tix++].token_type = TOKEN_ASSIGNMENT; | ||
464 | continue; | ||
465 | } | ||
466 | } | ||
467 | |||
468 | if (nl - p >= 2) { | ||
469 | if (memcmp(p, "({", 2) == 0) { | ||
470 | p += 2; | ||
471 | tokens[tix].size = 2; | ||
472 | tokens[tix++].token_type = TOKEN_OPEN_ACTION; | ||
473 | continue; | ||
474 | } | ||
475 | if (memcmp(p, "})", 2) == 0) { | ||
476 | p += 2; | ||
477 | tokens[tix].size = 2; | ||
478 | tokens[tix++].token_type = TOKEN_CLOSE_ACTION; | ||
479 | continue; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | if (nl - p >= 1) { | ||
484 | tokens[tix].size = 1; | ||
485 | switch (*p) { | ||
486 | case '{': | ||
487 | p += 1; | ||
488 | tokens[tix++].token_type = TOKEN_OPEN_CURLY; | ||
489 | continue; | ||
490 | case '}': | ||
491 | p += 1; | ||
492 | tokens[tix++].token_type = TOKEN_CLOSE_CURLY; | ||
493 | continue; | ||
494 | case '[': | ||
495 | p += 1; | ||
496 | tokens[tix++].token_type = TOKEN_OPEN_SQUARE; | ||
497 | continue; | ||
498 | case ']': | ||
499 | p += 1; | ||
500 | tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; | ||
501 | continue; | ||
502 | case ',': | ||
503 | p += 1; | ||
504 | tokens[tix++].token_type = TOKEN_COMMA; | ||
505 | continue; | ||
506 | default: | ||
507 | break; | ||
508 | } | ||
509 | } | ||
510 | |||
511 | fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", | ||
512 | filename, lineno, *p); | ||
513 | exit(1); | ||
514 | } | ||
515 | } | ||
516 | |||
517 | nr_tokens = tix; | ||
518 | printf("Extracted %u tokens\n", nr_tokens); | ||
519 | |||
520 | #if 0 | ||
521 | { | ||
522 | int n; | ||
523 | for (n = 0; n < nr_tokens; n++) | ||
524 | printf("Token %3u: '%*.*s'\n", | ||
525 | n, | ||
526 | (int)token_list[n].size, (int)token_list[n].size, | ||
527 | token_list[n].value); | ||
528 | } | ||
529 | #endif | ||
530 | } | ||
531 | |||
532 | static void build_type_list(void); | ||
533 | static void parse(void); | ||
534 | static void render(FILE *out, FILE *hdr); | ||
535 | |||
536 | /* | ||
537 | * | ||
538 | */ | ||
539 | int main(int argc, char **argv) | ||
540 | { | ||
541 | struct stat st; | ||
542 | ssize_t readlen; | ||
543 | FILE *out, *hdr; | ||
544 | char *buffer, *p; | ||
545 | int fd; | ||
546 | |||
547 | if (argc != 4) { | ||
548 | fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", | ||
549 | argv[0]); | ||
550 | exit(2); | ||
551 | } | ||
552 | |||
553 | filename = argv[1]; | ||
554 | outputname = argv[2]; | ||
555 | headername = argv[3]; | ||
556 | |||
557 | fd = open(filename, O_RDONLY); | ||
558 | if (fd < 0) { | ||
559 | perror(filename); | ||
560 | exit(1); | ||
561 | } | ||
562 | |||
563 | if (fstat(fd, &st) < 0) { | ||
564 | perror(filename); | ||
565 | exit(1); | ||
566 | } | ||
567 | |||
568 | if (!(buffer = malloc(st.st_size + 1))) { | ||
569 | perror(NULL); | ||
570 | exit(1); | ||
571 | } | ||
572 | |||
573 | if ((readlen = read(fd, buffer, st.st_size)) < 0) { | ||
574 | perror(filename); | ||
575 | exit(1); | ||
576 | } | ||
577 | |||
578 | if (close(fd) < 0) { | ||
579 | perror(filename); | ||
580 | exit(1); | ||
581 | } | ||
582 | |||
583 | if (readlen != st.st_size) { | ||
584 | fprintf(stderr, "%s: Short read\n", filename); | ||
585 | exit(1); | ||
586 | } | ||
587 | |||
588 | p = strrchr(argv[1], '/'); | ||
589 | p = p ? p + 1 : argv[1]; | ||
590 | grammar_name = strdup(p); | ||
591 | if (!p) { | ||
592 | perror(NULL); | ||
593 | exit(1); | ||
594 | } | ||
595 | p = strchr(grammar_name, '.'); | ||
596 | if (p) | ||
597 | *p = '\0'; | ||
598 | |||
599 | buffer[readlen] = 0; | ||
600 | tokenise(buffer, buffer + readlen); | ||
601 | build_type_list(); | ||
602 | parse(); | ||
603 | |||
604 | out = fopen(outputname, "w"); | ||
605 | if (!out) { | ||
606 | perror(outputname); | ||
607 | exit(1); | ||
608 | } | ||
609 | |||
610 | hdr = fopen(headername, "w"); | ||
611 | if (!out) { | ||
612 | perror(headername); | ||
613 | exit(1); | ||
614 | } | ||
615 | |||
616 | render(out, hdr); | ||
617 | |||
618 | if (fclose(out) < 0) { | ||
619 | perror(outputname); | ||
620 | exit(1); | ||
621 | } | ||
622 | |||
623 | if (fclose(hdr) < 0) { | ||
624 | perror(headername); | ||
625 | exit(1); | ||
626 | } | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | enum compound { | ||
632 | NOT_COMPOUND, | ||
633 | SET, | ||
634 | SET_OF, | ||
635 | SEQUENCE, | ||
636 | SEQUENCE_OF, | ||
637 | CHOICE, | ||
638 | ANY, | ||
639 | TYPE_REF, | ||
640 | TAG_OVERRIDE | ||
641 | }; | ||
642 | |||
643 | struct element { | ||
644 | struct type *type_def; | ||
645 | struct token *name; | ||
646 | struct token *type; | ||
647 | struct action *action; | ||
648 | struct element *children; | ||
649 | struct element *next; | ||
650 | struct element *render_next; | ||
651 | struct element *list_next; | ||
652 | uint8_t n_elements; | ||
653 | enum compound compound : 8; | ||
654 | enum asn1_class class : 8; | ||
655 | enum asn1_method method : 8; | ||
656 | uint8_t tag; | ||
657 | unsigned entry_index; | ||
658 | unsigned flags; | ||
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 | ||
665 | }; | ||
666 | |||
667 | struct type { | ||
668 | struct token *name; | ||
669 | struct token *def; | ||
670 | struct element *element; | ||
671 | unsigned ref_count; | ||
672 | unsigned flags; | ||
673 | #define TYPE_STOP_MARKER 0x0001 | ||
674 | #define TYPE_BEGIN 0x0002 | ||
675 | }; | ||
676 | |||
677 | static struct type *type_list; | ||
678 | static struct type **type_index; | ||
679 | static unsigned nr_types; | ||
680 | |||
681 | static int type_index_compare(const void *_a, const void *_b) | ||
682 | { | ||
683 | const struct type *const *a = _a, *const *b = _b; | ||
684 | |||
685 | if ((*a)->name->size != (*b)->name->size) | ||
686 | return (*a)->name->size - (*b)->name->size; | ||
687 | else | ||
688 | return memcmp((*a)->name->value, (*b)->name->value, | ||
689 | (*a)->name->size); | ||
690 | } | ||
691 | |||
692 | static int type_finder(const void *_key, const void *_ti) | ||
693 | { | ||
694 | const struct token *token = _key; | ||
695 | const struct type *const *ti = _ti; | ||
696 | const struct type *type = *ti; | ||
697 | |||
698 | if (token->size != type->name->size) | ||
699 | return token->size - type->name->size; | ||
700 | else | ||
701 | return memcmp(token->value, type->name->value, | ||
702 | token->size); | ||
703 | } | ||
704 | |||
705 | /* | ||
706 | * Build up a list of types and a sorted index to that list. | ||
707 | */ | ||
708 | static void build_type_list(void) | ||
709 | { | ||
710 | struct type *types; | ||
711 | unsigned nr, t, n; | ||
712 | |||
713 | nr = 0; | ||
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) | ||
717 | nr++; | ||
718 | |||
719 | if (nr == 0) { | ||
720 | fprintf(stderr, "%s: No defined types\n", filename); | ||
721 | exit(1); | ||
722 | } | ||
723 | |||
724 | nr_types = nr; | ||
725 | types = type_list = calloc(nr + 1, sizeof(type_list[0])); | ||
726 | if (!type_list) { | ||
727 | perror(NULL); | ||
728 | exit(1); | ||
729 | } | ||
730 | type_index = calloc(nr, sizeof(type_index[0])); | ||
731 | if (!type_index) { | ||
732 | perror(NULL); | ||
733 | exit(1); | ||
734 | } | ||
735 | |||
736 | t = 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]; | ||
743 | t++; | ||
744 | } | ||
745 | } | ||
746 | types[t].name = &token_list[n + 1]; | ||
747 | types[t].flags |= TYPE_STOP_MARKER; | ||
748 | |||
749 | qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); | ||
750 | |||
751 | printf("Extracted %u types\n", nr_types); | ||
752 | #if 0 | ||
753 | for (n = 0; n < nr_types; n++) { | ||
754 | struct type *type = type_index[n]; | ||
755 | printf("- %*.*s\n", | ||
756 | (int)type->name->size, | ||
757 | (int)type->name->size, | ||
758 | type->name->value); | ||
759 | } | ||
760 | #endif | ||
761 | } | ||
762 | |||
763 | static struct element *parse_type(struct token **_cursor, struct token *stop, | ||
764 | struct token *name); | ||
765 | |||
766 | /* | ||
767 | * Parse the token stream | ||
768 | */ | ||
769 | static void parse(void) | ||
770 | { | ||
771 | struct token *cursor; | ||
772 | struct type *type; | ||
773 | |||
774 | /* Parse one type definition statement at a time */ | ||
775 | type = type_list; | ||
776 | do { | ||
777 | cursor = type->name; | ||
778 | |||
779 | if (cursor[0].token_type != TOKEN_TYPE_NAME || | ||
780 | cursor[1].token_type != TOKEN_ASSIGNMENT) | ||
781 | abort(); | ||
782 | cursor += 2; | ||
783 | |||
784 | type->element = parse_type(&cursor, type[1].name, NULL); | ||
785 | type->element->type_def = type; | ||
786 | |||
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); | ||
791 | exit(1); | ||
792 | } | ||
793 | |||
794 | } while (type++, !(type->flags & TYPE_STOP_MARKER)); | ||
795 | |||
796 | printf("Extracted %u actions\n", nr_actions); | ||
797 | } | ||
798 | |||
799 | static struct element *element_list; | ||
800 | |||
801 | static struct element *alloc_elem(struct token *type) | ||
802 | { | ||
803 | struct element *e = calloc(1, sizeof(*e)); | ||
804 | if (!e) { | ||
805 | perror(NULL); | ||
806 | exit(1); | ||
807 | } | ||
808 | e->list_next = element_list; | ||
809 | element_list = e; | ||
810 | return e; | ||
811 | } | ||
812 | |||
813 | static struct element *parse_compound(struct token **_cursor, struct token *end, | ||
814 | int alternates); | ||
815 | |||
816 | /* | ||
817 | * Parse one type definition statement | ||
818 | */ | ||
819 | static struct element *parse_type(struct token **_cursor, struct token *end, | ||
820 | struct token *name) | ||
821 | { | ||
822 | struct element *top, *element; | ||
823 | struct action *action, **ppaction; | ||
824 | struct token *cursor = *_cursor; | ||
825 | struct type **ref; | ||
826 | char *p; | ||
827 | int labelled = 0, implicit = 0; | ||
828 | |||
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; | ||
834 | |||
835 | /* Extract the tag value if one given */ | ||
836 | if (cursor->token_type == TOKEN_OPEN_SQUARE) { | ||
837 | cursor++; | ||
838 | if (cursor >= end) | ||
839 | goto overrun_error; | ||
840 | switch (cursor->token_type) { | ||
841 | case DIRECTIVE_UNIVERSAL: | ||
842 | element->class = ASN1_UNIV; | ||
843 | cursor++; | ||
844 | break; | ||
845 | case DIRECTIVE_APPLICATION: | ||
846 | element->class = ASN1_APPL; | ||
847 | cursor++; | ||
848 | break; | ||
849 | case TOKEN_NUMBER: | ||
850 | element->class = ASN1_CONT; | ||
851 | break; | ||
852 | case DIRECTIVE_PRIVATE: | ||
853 | element->class = ASN1_PRIV; | ||
854 | cursor++; | ||
855 | break; | ||
856 | default: | ||
857 | fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", | ||
858 | filename, cursor->line, | ||
859 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
860 | exit(1); | ||
861 | } | ||
862 | |||
863 | if (cursor >= end) | ||
864 | goto overrun_error; | ||
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); | ||
869 | exit(1); | ||
870 | } | ||
871 | |||
872 | element->tag &= ~0x1f; | ||
873 | element->tag |= strtoul(cursor->value, &p, 10); | ||
874 | if (p - cursor->value != cursor->size) | ||
875 | abort(); | ||
876 | cursor++; | ||
877 | |||
878 | if (cursor >= end) | ||
879 | goto overrun_error; | ||
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); | ||
884 | exit(1); | ||
885 | } | ||
886 | cursor++; | ||
887 | if (cursor >= end) | ||
888 | goto overrun_error; | ||
889 | labelled = 1; | ||
890 | } | ||
891 | |||
892 | /* Handle implicit and explicit markers */ | ||
893 | if (cursor->token_type == DIRECTIVE_IMPLICIT) { | ||
894 | element->flags |= ELEMENT_IMPLICIT; | ||
895 | implicit = 1; | ||
896 | cursor++; | ||
897 | if (cursor >= end) | ||
898 | goto overrun_error; | ||
899 | } else if (cursor->token_type == DIRECTIVE_EXPLICIT) { | ||
900 | element->flags |= ELEMENT_EXPLICIT; | ||
901 | cursor++; | ||
902 | if (cursor >= end) | ||
903 | goto overrun_error; | ||
904 | } | ||
905 | |||
906 | if (labelled) { | ||
907 | if (!implicit) | ||
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; | ||
916 | } | ||
917 | |||
918 | /* Extract the type we're expecting here */ | ||
919 | element->type = cursor; | ||
920 | switch (cursor->token_type) { | ||
921 | case DIRECTIVE_ANY: | ||
922 | element->compound = ANY; | ||
923 | cursor++; | ||
924 | break; | ||
925 | |||
926 | case DIRECTIVE_NULL: | ||
927 | case DIRECTIVE_BOOLEAN: | ||
928 | case DIRECTIVE_ENUMERATED: | ||
929 | case DIRECTIVE_INTEGER: | ||
930 | element->compound = NOT_COMPOUND; | ||
931 | cursor++; | ||
932 | break; | ||
933 | |||
934 | case DIRECTIVE_EXTERNAL: | ||
935 | element->method = ASN1_CONS; | ||
936 | |||
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; | ||
954 | cursor++; | ||
955 | break; | ||
956 | |||
957 | case DIRECTIVE_BIT: | ||
958 | case DIRECTIVE_OCTET: | ||
959 | element->compound = NOT_COMPOUND; | ||
960 | cursor++; | ||
961 | if (cursor >= end) | ||
962 | goto overrun_error; | ||
963 | if (cursor->token_type != DIRECTIVE_STRING) | ||
964 | goto parse_error; | ||
965 | cursor++; | ||
966 | break; | ||
967 | |||
968 | case DIRECTIVE_OBJECT: | ||
969 | element->compound = NOT_COMPOUND; | ||
970 | cursor++; | ||
971 | if (cursor >= end) | ||
972 | goto overrun_error; | ||
973 | if (cursor->token_type != DIRECTIVE_IDENTIFIER) | ||
974 | goto parse_error; | ||
975 | cursor++; | ||
976 | break; | ||
977 | |||
978 | case TOKEN_TYPE_NAME: | ||
979 | element->compound = TYPE_REF; | ||
980 | ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), | ||
981 | type_finder); | ||
982 | if (!ref) { | ||
983 | fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", | ||
984 | filename, cursor->line, | ||
985 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
986 | exit(1); | ||
987 | } | ||
988 | cursor->type = *ref; | ||
989 | (*ref)->ref_count++; | ||
990 | cursor++; | ||
991 | break; | ||
992 | |||
993 | case DIRECTIVE_CHOICE: | ||
994 | element->compound = CHOICE; | ||
995 | cursor++; | ||
996 | element->children = parse_compound(&cursor, end, 1); | ||
997 | break; | ||
998 | |||
999 | case DIRECTIVE_SEQUENCE: | ||
1000 | element->compound = SEQUENCE; | ||
1001 | element->method = ASN1_CONS; | ||
1002 | cursor++; | ||
1003 | if (cursor >= end) | ||
1004 | goto overrun_error; | ||
1005 | if (cursor->token_type == DIRECTIVE_OF) { | ||
1006 | element->compound = SEQUENCE_OF; | ||
1007 | cursor++; | ||
1008 | if (cursor >= end) | ||
1009 | goto overrun_error; | ||
1010 | element->children = parse_type(&cursor, end, NULL); | ||
1011 | } else { | ||
1012 | element->children = parse_compound(&cursor, end, 0); | ||
1013 | } | ||
1014 | break; | ||
1015 | |||
1016 | case DIRECTIVE_SET: | ||
1017 | element->compound = SET; | ||
1018 | element->method = ASN1_CONS; | ||
1019 | cursor++; | ||
1020 | if (cursor >= end) | ||
1021 | goto overrun_error; | ||
1022 | if (cursor->token_type == DIRECTIVE_OF) { | ||
1023 | element->compound = SET_OF; | ||
1024 | cursor++; | ||
1025 | if (cursor >= end) | ||
1026 | goto parse_error; | ||
1027 | element->children = parse_type(&cursor, end, NULL); | ||
1028 | } else { | ||
1029 | element->children = parse_compound(&cursor, end, 1); | ||
1030 | } | ||
1031 | break; | ||
1032 | |||
1033 | default: | ||
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); | ||
1037 | exit(1); | ||
1038 | } | ||
1039 | |||
1040 | /* Handle elements that are optional */ | ||
1041 | if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL || | ||
1042 | cursor->token_type == DIRECTIVE_DEFAULT) | ||
1043 | ) { | ||
1044 | cursor++; | ||
1045 | top->flags |= ELEMENT_SKIPPABLE; | ||
1046 | } | ||
1047 | |||
1048 | if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) { | ||
1049 | cursor++; | ||
1050 | if (cursor >= end) | ||
1051 | goto overrun_error; | ||
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); | ||
1056 | exit(1); | ||
1057 | } | ||
1058 | |||
1059 | action = malloc(sizeof(struct action) + cursor->size + 1); | ||
1060 | if (!action) { | ||
1061 | perror(NULL); | ||
1062 | exit(1); | ||
1063 | } | ||
1064 | action->index = 0; | ||
1065 | memcpy(action->name, cursor->value, cursor->size); | ||
1066 | action->name[cursor->size] = 0; | ||
1067 | |||
1068 | for (ppaction = &action_list; | ||
1069 | *ppaction; | ||
1070 | ppaction = &(*ppaction)->next | ||
1071 | ) { | ||
1072 | int cmp = strcmp(action->name, (*ppaction)->name); | ||
1073 | if (cmp == 0) { | ||
1074 | free(action); | ||
1075 | action = *ppaction; | ||
1076 | goto found; | ||
1077 | } | ||
1078 | if (cmp < 0) { | ||
1079 | action->next = *ppaction; | ||
1080 | *ppaction = action; | ||
1081 | nr_actions++; | ||
1082 | goto found; | ||
1083 | } | ||
1084 | } | ||
1085 | action->next = NULL; | ||
1086 | *ppaction = action; | ||
1087 | nr_actions++; | ||
1088 | found: | ||
1089 | |||
1090 | element->action = action; | ||
1091 | cursor->action = action; | ||
1092 | cursor++; | ||
1093 | if (cursor >= end) | ||
1094 | goto overrun_error; | ||
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); | ||
1099 | exit(1); | ||
1100 | } | ||
1101 | cursor++; | ||
1102 | } | ||
1103 | |||
1104 | *_cursor = cursor; | ||
1105 | return top; | ||
1106 | |||
1107 | parse_error: | ||
1108 | fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", | ||
1109 | filename, cursor->line, | ||
1110 | (int)cursor->size, (int)cursor->size, cursor->value); | ||
1111 | exit(1); | ||
1112 | |||
1113 | overrun_error: | ||
1114 | fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); | ||
1115 | exit(1); | ||
1116 | } | ||
1117 | |||
1118 | /* | ||
1119 | * Parse a compound type list | ||
1120 | */ | ||
1121 | static struct element *parse_compound(struct token **_cursor, struct token *end, | ||
1122 | int alternates) | ||
1123 | { | ||
1124 | struct element *children, **child_p = &children, *element; | ||
1125 | struct token *cursor = *_cursor, *name; | ||
1126 | |||
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); | ||
1131 | exit(1); | ||
1132 | } | ||
1133 | cursor++; | ||
1134 | if (cursor >= end) | ||
1135 | goto overrun_error; | ||
1136 | |||
1137 | if (cursor->token_type == TOKEN_OPEN_CURLY) { | ||
1138 | fprintf(stderr, "%s:%d: Empty compound\n", | ||
1139 | filename, cursor->line); | ||
1140 | exit(1); | ||
1141 | } | ||
1142 | |||
1143 | for (;;) { | ||
1144 | name = NULL; | ||
1145 | if (cursor->token_type == TOKEN_ELEMENT_NAME) { | ||
1146 | name = cursor; | ||
1147 | cursor++; | ||
1148 | if (cursor >= end) | ||
1149 | goto overrun_error; | ||
1150 | } | ||
1151 | |||
1152 | element = parse_type(&cursor, end, name); | ||
1153 | if (alternates) | ||
1154 | element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL; | ||
1155 | |||
1156 | *child_p = element; | ||
1157 | child_p = &element->next; | ||
1158 | |||
1159 | if (cursor >= end) | ||
1160 | goto overrun_error; | ||
1161 | if (cursor->token_type != TOKEN_COMMA) | ||
1162 | break; | ||
1163 | cursor++; | ||
1164 | if (cursor >= end) | ||
1165 | goto overrun_error; | ||
1166 | } | ||
1167 | |||
1168 | children->flags &= ~ELEMENT_CONDITIONAL; | ||
1169 | |||
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); | ||
1174 | exit(1); | ||
1175 | } | ||
1176 | cursor++; | ||
1177 | |||
1178 | *_cursor = cursor; | ||
1179 | return children; | ||
1180 | |||
1181 | overrun_error: | ||
1182 | fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); | ||
1183 | exit(1); | ||
1184 | } | ||
1185 | |||
1186 | static void render_element(FILE *out, struct element *e, struct element *tag); | ||
1187 | static void render_out_of_line_list(FILE *out); | ||
1188 | |||
1189 | static int nr_entries; | ||
1190 | static int render_depth = 1; | ||
1191 | static struct element *render_list, **render_list_p = &render_list; | ||
1192 | |||
1193 | __attribute__((format(printf, 2, 3))) | ||
1194 | static void render_opcode(FILE *out, const char *fmt, ...) | ||
1195 | { | ||
1196 | va_list va; | ||
1197 | |||
1198 | if (out) { | ||
1199 | fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, ""); | ||
1200 | va_start(va, fmt); | ||
1201 | vfprintf(out, fmt, va); | ||
1202 | va_end(va); | ||
1203 | } | ||
1204 | nr_entries++; | ||
1205 | } | ||
1206 | |||
1207 | __attribute__((format(printf, 2, 3))) | ||
1208 | static void render_more(FILE *out, const char *fmt, ...) | ||
1209 | { | ||
1210 | va_list va; | ||
1211 | |||
1212 | if (out) { | ||
1213 | va_start(va, fmt); | ||
1214 | vfprintf(out, fmt, va); | ||
1215 | va_end(va); | ||
1216 | } | ||
1217 | } | ||
1218 | |||
1219 | /* | ||
1220 | * Render the grammar into a state machine definition. | ||
1221 | */ | ||
1222 | static void render(FILE *out, FILE *hdr) | ||
1223 | { | ||
1224 | struct element *e; | ||
1225 | struct action *action; | ||
1226 | struct type *root; | ||
1227 | int index; | ||
1228 | |||
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"); | ||
1235 | fprintf(hdr, "\n"); | ||
1236 | fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name); | ||
1237 | if (ferror(hdr)) { | ||
1238 | perror(headername); | ||
1239 | exit(1); | ||
1240 | } | ||
1241 | |||
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); | ||
1249 | fprintf(out, "\n"); | ||
1250 | if (ferror(out)) { | ||
1251 | perror(outputname); | ||
1252 | exit(1); | ||
1253 | } | ||
1254 | |||
1255 | /* Tabulate the action functions we might have to call */ | ||
1256 | fprintf(hdr, "\n"); | ||
1257 | index = 0; | ||
1258 | for (action = action_list; action; action = action->next) { | ||
1259 | action->index = index++; | ||
1260 | fprintf(hdr, | ||
1261 | "extern int %s(void *, size_t, unsigned char," | ||
1262 | " const void *, size_t);\n", | ||
1263 | action->name); | ||
1264 | } | ||
1265 | fprintf(hdr, "\n"); | ||
1266 | |||
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"); | ||
1273 | |||
1274 | 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"); | ||
1280 | |||
1281 | if (ferror(out)) { | ||
1282 | perror(outputname); | ||
1283 | exit(1); | ||
1284 | } | ||
1285 | |||
1286 | /* We do two passes - the first one calculates all the offsets */ | ||
1287 | printf("Pass 1\n"); | ||
1288 | nr_entries = 0; | ||
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); | ||
1293 | |||
1294 | for (e = element_list; e; e = e->list_next) | ||
1295 | e->flags &= ~ELEMENT_RENDERED; | ||
1296 | |||
1297 | /* And then we actually render */ | ||
1298 | printf("Pass 2\n"); | ||
1299 | fprintf(out, "\n"); | ||
1300 | fprintf(out, "static const unsigned char %s_machine[] = {\n", | ||
1301 | grammar_name); | ||
1302 | |||
1303 | nr_entries = 0; | ||
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); | ||
1308 | |||
1309 | fprintf(out, "};\n"); | ||
1310 | |||
1311 | 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"); | ||
1317 | } | ||
1318 | |||
1319 | /* | ||
1320 | * Render the out-of-line elements | ||
1321 | */ | ||
1322 | static void render_out_of_line_list(FILE *out) | ||
1323 | { | ||
1324 | struct element *e, *ce; | ||
1325 | const char *act; | ||
1326 | int entry; | ||
1327 | |||
1328 | while ((e = render_list)) { | ||
1329 | render_list = e->render_next; | ||
1330 | if (!render_list) | ||
1331 | render_list_p = &render_list; | ||
1332 | |||
1333 | render_more(out, "\n"); | ||
1334 | e->entry_index = entry = nr_entries; | ||
1335 | render_depth++; | ||
1336 | for (ce = e->children; ce; ce = ce->next) | ||
1337 | render_element(out, ce, NULL); | ||
1338 | render_depth--; | ||
1339 | |||
1340 | act = e->action ? "_ACT" : ""; | ||
1341 | switch (e->compound) { | ||
1342 | case SEQUENCE: | ||
1343 | render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); | ||
1344 | break; | ||
1345 | case SEQUENCE_OF: | ||
1346 | render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); | ||
1347 | render_opcode(out, "_jump_target(%u),\n", entry); | ||
1348 | break; | ||
1349 | case SET: | ||
1350 | render_opcode(out, "ASN1_OP_END_SET%s,\n", act); | ||
1351 | break; | ||
1352 | case SET_OF: | ||
1353 | render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); | ||
1354 | render_opcode(out, "_jump_target(%u),\n", entry); | ||
1355 | break; | ||
1356 | } | ||
1357 | if (e->action) | ||
1358 | render_opcode(out, "_action(ACT_%s),\n", | ||
1359 | e->action->name); | ||
1360 | render_opcode(out, "ASN1_OP_RETURN,\n"); | ||
1361 | } | ||
1362 | } | ||
1363 | |||
1364 | /* | ||
1365 | * Render an element. | ||
1366 | */ | ||
1367 | static void render_element(FILE *out, struct element *e, struct element *tag) | ||
1368 | { | ||
1369 | struct element *ec; | ||
1370 | const char *cond, *act; | ||
1371 | int entry, skippable = 0, outofline = 0; | ||
1372 | |||
1373 | if (e->flags & ELEMENT_SKIPPABLE || | ||
1374 | (tag && tag->flags & ELEMENT_SKIPPABLE)) | ||
1375 | skippable = 1; | ||
1376 | |||
1377 | if ((e->type_def && e->type_def->ref_count > 1) || | ||
1378 | skippable) | ||
1379 | outofline = 1; | ||
1380 | |||
1381 | if (e->type_def && out) { | ||
1382 | render_more(out, "\t// %*.*s\n", | ||
1383 | (int)e->type_def->name->size, (int)e->type_def->name->size, | ||
1384 | e->type_def->name->value); | ||
1385 | } | ||
1386 | |||
1387 | /* Render the operation */ | ||
1388 | cond = (e->flags & ELEMENT_CONDITIONAL || | ||
1389 | (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; | ||
1390 | act = e->action ? "_ACT" : ""; | ||
1391 | switch (e->compound) { | ||
1392 | case ANY: | ||
1393 | render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); | ||
1394 | if (e->name) | ||
1395 | render_more(out, "\t\t// %*.*s", | ||
1396 | (int)e->name->size, (int)e->name->size, | ||
1397 | e->name->value); | ||
1398 | render_more(out, "\n"); | ||
1399 | goto dont_render_tag; | ||
1400 | |||
1401 | case TAG_OVERRIDE: | ||
1402 | render_element(out, e->children, e); | ||
1403 | return; | ||
1404 | |||
1405 | case SEQUENCE: | ||
1406 | case SEQUENCE_OF: | ||
1407 | case SET: | ||
1408 | case SET_OF: | ||
1409 | render_opcode(out, "ASN1_OP_%sMATCH%s%s,", | ||
1410 | cond, | ||
1411 | outofline ? "_JUMP" : "", | ||
1412 | skippable ? "_OR_SKIP" : ""); | ||
1413 | break; | ||
1414 | |||
1415 | case CHOICE: | ||
1416 | goto dont_render_tag; | ||
1417 | |||
1418 | case TYPE_REF: | ||
1419 | if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) | ||
1420 | goto dont_render_tag; | ||
1421 | default: | ||
1422 | render_opcode(out, "ASN1_OP_%sMATCH%s%s,", | ||
1423 | cond, act, | ||
1424 | skippable ? "_OR_SKIP" : ""); | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | if (e->name) | ||
1429 | render_more(out, "\t\t// %*.*s", | ||
1430 | (int)e->name->size, (int)e->name->size, | ||
1431 | e->name->value); | ||
1432 | render_more(out, "\n"); | ||
1433 | |||
1434 | /* Render the tag */ | ||
1435 | if (!tag) | ||
1436 | tag = e; | ||
1437 | if (tag->class == ASN1_UNIV && | ||
1438 | tag->tag != 14 && | ||
1439 | tag->tag != 15 && | ||
1440 | tag->tag != 31) | ||
1441 | render_opcode(out, "_tag(%s, %s, %s),\n", | ||
1442 | asn1_classes[tag->class], | ||
1443 | asn1_methods[tag->method | e->method], | ||
1444 | asn1_universal_tags[tag->tag]); | ||
1445 | else | ||
1446 | render_opcode(out, "_tagn(%s, %s, %2u),\n", | ||
1447 | asn1_classes[tag->class], | ||
1448 | asn1_methods[tag->method | e->method], | ||
1449 | tag->tag); | ||
1450 | tag = NULL; | ||
1451 | dont_render_tag: | ||
1452 | |||
1453 | /* Deal with compound types */ | ||
1454 | switch (e->compound) { | ||
1455 | case TYPE_REF: | ||
1456 | render_element(out, e->type->type->element, tag); | ||
1457 | if (e->action) | ||
1458 | render_opcode(out, "ASN1_OP_ACT,\n"); | ||
1459 | break; | ||
1460 | |||
1461 | case SEQUENCE: | ||
1462 | if (outofline) { | ||
1463 | /* Render out-of-line for multiple use or | ||
1464 | * skipability */ | ||
1465 | render_opcode(out, "_jump_target(%u),", e->entry_index); | ||
1466 | if (e->type_def && e->type_def->name) | ||
1467 | render_more(out, "\t\t// --> %*.*s", | ||
1468 | (int)e->type_def->name->size, | ||
1469 | (int)e->type_def->name->size, | ||
1470 | e->type_def->name->value); | ||
1471 | render_more(out, "\n"); | ||
1472 | if (!(e->flags & ELEMENT_RENDERED)) { | ||
1473 | e->flags |= ELEMENT_RENDERED; | ||
1474 | *render_list_p = e; | ||
1475 | render_list_p = &e->render_next; | ||
1476 | } | ||
1477 | return; | ||
1478 | } else { | ||
1479 | /* Render inline for single use */ | ||
1480 | render_depth++; | ||
1481 | for (ec = e->children; ec; ec = ec->next) | ||
1482 | render_element(out, ec, NULL); | ||
1483 | render_depth--; | ||
1484 | render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); | ||
1485 | } | ||
1486 | break; | ||
1487 | |||
1488 | case SEQUENCE_OF: | ||
1489 | case SET_OF: | ||
1490 | if (outofline) { | ||
1491 | /* Render out-of-line for multiple use or | ||
1492 | * skipability */ | ||
1493 | render_opcode(out, "_jump_target(%u),", e->entry_index); | ||
1494 | if (e->type_def && e->type_def->name) | ||
1495 | render_more(out, "\t\t// --> %*.*s", | ||
1496 | (int)e->type_def->name->size, | ||
1497 | (int)e->type_def->name->size, | ||
1498 | e->type_def->name->value); | ||
1499 | render_more(out, "\n"); | ||
1500 | if (!(e->flags & ELEMENT_RENDERED)) { | ||
1501 | e->flags |= ELEMENT_RENDERED; | ||
1502 | *render_list_p = e; | ||
1503 | render_list_p = &e->render_next; | ||
1504 | } | ||
1505 | return; | ||
1506 | } else { | ||
1507 | /* Render inline for single use */ | ||
1508 | entry = nr_entries; | ||
1509 | render_depth++; | ||
1510 | render_element(out, e->children, NULL); | ||
1511 | render_depth--; | ||
1512 | if (e->compound == SEQUENCE_OF) | ||
1513 | render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); | ||
1514 | else | ||
1515 | render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); | ||
1516 | render_opcode(out, "_jump_target(%u),\n", entry); | ||
1517 | } | ||
1518 | break; | ||
1519 | |||
1520 | case SET: | ||
1521 | /* I can't think of a nice way to do SET support without having | ||
1522 | * a stack of bitmasks to make sure no element is repeated. | ||
1523 | * The bitmask has also to be checked that no non-optional | ||
1524 | * elements are left out whilst not preventing optional | ||
1525 | * elements from being left out. | ||
1526 | */ | ||
1527 | fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); | ||
1528 | exit(1); | ||
1529 | |||
1530 | case CHOICE: | ||
1531 | for (ec = e->children; ec; ec = ec->next) | ||
1532 | render_element(out, ec, NULL); | ||
1533 | if (!skippable) | ||
1534 | render_opcode(out, "ASN1_OP_COND_FAIL,\n"); | ||
1535 | if (e->action) | ||
1536 | render_opcode(out, "ASN1_OP_ACT,\n"); | ||
1537 | break; | ||
1538 | |||
1539 | default: | ||
1540 | break; | ||
1541 | } | ||
1542 | |||
1543 | if (e->action) | ||
1544 | render_opcode(out, "_action(ACT_%s),\n", e->action->name); | ||
1545 | } | ||