Root/
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 | } |
1546 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9