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 23enum 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 121static 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 156static const char asn1_classes[4][5] = { 157 [ASN1_UNIV] = "UNIV", 158 [ASN1_APPL] = "APPL", 159 [ASN1_CONT] = "CONT", 160 [ASN1_PRIV] = "PRIV" 161}; 162 163static const char asn1_methods[2][5] = { 164 [ASN1_UNIV] = "PRIM", 165 [ASN1_APPL] = "CONS" 166}; 167 168static 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 203static const char *filename; 204static const char *grammar_name; 205static const char *outputname; 206static const char *headername; 207 208static 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 294struct action { 295 struct action *next; 296 unsigned char index; 297 char name[]; 298}; 299 300static struct action *action_list; 301static unsigned nr_actions; 302 303struct 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 312static struct token *token_list; 313static unsigned nr_tokens; 314static _Bool verbose; 315 316#define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0) 317 318static int directive_compare(const void *_key, const void *_pdir) 319{ 320 const struct token *token = _key; 321 const char *const *pdir = _pdir, *dir = *pdir; 322 size_t dlen, clen; 323 int val; 324 325 dlen = strlen(dir); 326 clen = (dlen < token->size) ? dlen : token->size; 327 328 //debug("cmp(%*.*s,%s) = ", 329 // (int)token->size, (int)token->size, token->value, 330 // dir); 331 332 val = memcmp(token->value, dir, clen); 333 if (val != 0) { 334 //debug("%d [cmp]\n", val); 335 return val; 336 } 337 338 if (dlen == token->size) { 339 //debug("0\n"); 340 return 0; 341 } 342 //debug("%d\n", (int)dlen - (int)token->size); 343 return dlen - token->size; /* shorter -> negative */ 344} 345 346/* 347 * Tokenise an ASN.1 grammar 348 */ 349static void tokenise(char *buffer, char *end) 350{ 351 struct token *tokens; 352 char *line, *nl, *p, *q; 353 unsigned tix, lineno; 354 355 /* Assume we're going to have half as many tokens as we have 356 * characters 357 */ 358 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token)); 359 if (!tokens) { 360 perror(NULL); 361 exit(1); 362 } 363 tix = 0; 364 365 lineno = 0; 366 while (buffer < end) { 367 /* First of all, break out a line */ 368 lineno++; 369 line = buffer; 370 nl = memchr(line, '\n', end - buffer); 371 if (!nl) { 372 buffer = nl = end; 373 } else { 374 buffer = nl + 1; 375 *nl = '\0'; 376 } 377 378 /* Remove "--" comments */ 379 p = line; 380 next_comment: 381 while ((p = memchr(p, '-', nl - p))) { 382 if (p[1] == '-') { 383 /* Found a comment; see if there's a terminator */ 384 q = p + 2; 385 while ((q = memchr(q, '-', nl - q))) { 386 if (q[1] == '-') { 387 /* There is - excise the comment */ 388 q += 2; 389 memmove(p, q, nl - q); 390 goto next_comment; 391 } 392 q++; 393 } 394 *p = '\0'; 395 nl = p; 396 break; 397 } else { 398 p++; 399 } 400 } 401 402 p = line; 403 while (p < nl) { 404 /* Skip white space */ 405 while (p < nl && isspace(*p)) 406 *(p++) = 0; 407 if (p >= nl) 408 break; 409 410 tokens[tix].line = lineno; 411 tokens[tix].value = p; 412 413 /* Handle string tokens */ 414 if (isalpha(*p)) { 415 const char **dir; 416 417 /* Can be a directive, type name or element 418 * name. Find the end of the name. 419 */ 420 q = p + 1; 421 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_')) 422 q++; 423 tokens[tix].size = q - p; 424 p = q; 425 426 /* If it begins with a lowercase letter then 427 * it's an element name 428 */ 429 if (islower(tokens[tix].value[0])) { 430 tokens[tix++].token_type = TOKEN_ELEMENT_NAME; 431 continue; 432 } 433 434 /* Otherwise we need to search the directive 435 * table 436 */ 437 dir = bsearch(&tokens[tix], directives, 438 sizeof(directives) / sizeof(directives[1]), 439 sizeof(directives[1]), 440 directive_compare); 441 if (dir) { 442 tokens[tix++].token_type = dir - directives; 443 continue; 444 } 445 446 tokens[tix++].token_type = TOKEN_TYPE_NAME; 447 continue; 448 } 449 450 /* Handle numbers */ 451 if (isdigit(*p)) { 452 /* Find the end of the number */ 453 q = p + 1; 454 while (q < nl && (isdigit(*q))) 455 q++; 456 tokens[tix].size = q - p; 457 p = q; 458 tokens[tix++].token_type = TOKEN_NUMBER; 459 continue; 460 } 461 462 if (nl - p >= 3) { 463 if (memcmp(p, "::=", 3) == 0) { 464 p += 3; 465 tokens[tix].size = 3; 466 tokens[tix++].token_type = TOKEN_ASSIGNMENT; 467 continue; 468 } 469 } 470 471 if (nl - p >= 2) { 472 if (memcmp(p, "({", 2) == 0) { 473 p += 2; 474 tokens[tix].size = 2; 475 tokens[tix++].token_type = TOKEN_OPEN_ACTION; 476 continue; 477 } 478 if (memcmp(p, "})", 2) == 0) { 479 p += 2; 480 tokens[tix].size = 2; 481 tokens[tix++].token_type = TOKEN_CLOSE_ACTION; 482 continue; 483 } 484 } 485 486 if (nl - p >= 1) { 487 tokens[tix].size = 1; 488 switch (*p) { 489 case '{': 490 p += 1; 491 tokens[tix++].token_type = TOKEN_OPEN_CURLY; 492 continue; 493 case '}': 494 p += 1; 495 tokens[tix++].token_type = TOKEN_CLOSE_CURLY; 496 continue; 497 case '[': 498 p += 1; 499 tokens[tix++].token_type = TOKEN_OPEN_SQUARE; 500 continue; 501 case ']': 502 p += 1; 503 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE; 504 continue; 505 case ',': 506 p += 1; 507 tokens[tix++].token_type = TOKEN_COMMA; 508 continue; 509 default: 510 break; 511 } 512 } 513 514 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n", 515 filename, lineno, *p); 516 exit(1); 517 } 518 } 519 520 nr_tokens = tix; 521 debug("Extracted %u tokens\n", nr_tokens); 522 523#if 0 524 { 525 int n; 526 for (n = 0; n < nr_tokens; n++) 527 debug("Token %3u: '%*.*s'\n", 528 n, 529 (int)token_list[n].size, (int)token_list[n].size, 530 token_list[n].value); 531 } 532#endif 533} 534 535static void build_type_list(void); 536static void parse(void); 537static void render(FILE *out, FILE *hdr); 538 539/* 540 * 541 */ 542int main(int argc, char **argv) 543{ 544 struct stat st; 545 ssize_t readlen; 546 FILE *out, *hdr; 547 char *buffer, *p; 548 char *kbuild_verbose; 549 int fd; 550 551 if (argc != 4) { 552 fprintf(stderr, "Format: %s <grammar-file> <c-file> <hdr-file>\n", 553 argv[0]); 554 exit(2); 555 } 556 557 kbuild_verbose = getenv("KBUILD_VERBOSE"); 558 if (kbuild_verbose) 559 verbose = atoi(kbuild_verbose); 560 561 filename = argv[1]; 562 outputname = argv[2]; 563 headername = argv[3]; 564 565 fd = open(filename, O_RDONLY); 566 if (fd < 0) { 567 perror(filename); 568 exit(1); 569 } 570 571 if (fstat(fd, &st) < 0) { 572 perror(filename); 573 exit(1); 574 } 575 576 if (!(buffer = malloc(st.st_size + 1))) { 577 perror(NULL); 578 exit(1); 579 } 580 581 if ((readlen = read(fd, buffer, st.st_size)) < 0) { 582 perror(filename); 583 exit(1); 584 } 585 586 if (close(fd) < 0) { 587 perror(filename); 588 exit(1); 589 } 590 591 if (readlen != st.st_size) { 592 fprintf(stderr, "%s: Short read\n", filename); 593 exit(1); 594 } 595 596 p = strrchr(argv[1], '/'); 597 p = p ? p + 1 : argv[1]; 598 grammar_name = strdup(p); 599 if (!p) { 600 perror(NULL); 601 exit(1); 602 } 603 p = strchr(grammar_name, '.'); 604 if (p) 605 *p = '\0'; 606 607 buffer[readlen] = 0; 608 tokenise(buffer, buffer + readlen); 609 build_type_list(); 610 parse(); 611 612 out = fopen(outputname, "w"); 613 if (!out) { 614 perror(outputname); 615 exit(1); 616 } 617 618 hdr = fopen(headername, "w"); 619 if (!out) { 620 perror(headername); 621 exit(1); 622 } 623 624 render(out, hdr); 625 626 if (fclose(out) < 0) { 627 perror(outputname); 628 exit(1); 629 } 630 631 if (fclose(hdr) < 0) { 632 perror(headername); 633 exit(1); 634 } 635 636 return 0; 637} 638 639enum compound { 640 NOT_COMPOUND, 641 SET, 642 SET_OF, 643 SEQUENCE, 644 SEQUENCE_OF, 645 CHOICE, 646 ANY, 647 TYPE_REF, 648 TAG_OVERRIDE 649}; 650 651struct element { 652 struct type *type_def; 653 struct token *name; 654 struct token *type; 655 struct action *action; 656 struct element *children; 657 struct element *next; 658 struct element *render_next; 659 struct element *list_next; 660 uint8_t n_elements; 661 enum compound compound : 8; 662 enum asn1_class class : 8; 663 enum asn1_method method : 8; 664 uint8_t tag; 665 unsigned entry_index; 666 unsigned flags; 667#define ELEMENT_IMPLICIT 0x0001 668#define ELEMENT_EXPLICIT 0x0002 669#define ELEMENT_MARKED 0x0004 670#define ELEMENT_RENDERED 0x0008 671#define ELEMENT_SKIPPABLE 0x0010 672#define ELEMENT_CONDITIONAL 0x0020 673}; 674 675struct type { 676 struct token *name; 677 struct token *def; 678 struct element *element; 679 unsigned ref_count; 680 unsigned flags; 681#define TYPE_STOP_MARKER 0x0001 682#define TYPE_BEGIN 0x0002 683}; 684 685static struct type *type_list; 686static struct type **type_index; 687static unsigned nr_types; 688 689static int type_index_compare(const void *_a, const void *_b) 690{ 691 const struct type *const *a = _a, *const *b = _b; 692 693 if ((*a)->name->size != (*b)->name->size) 694 return (*a)->name->size - (*b)->name->size; 695 else 696 return memcmp((*a)->name->value, (*b)->name->value, 697 (*a)->name->size); 698} 699 700static int type_finder(const void *_key, const void *_ti) 701{ 702 const struct token *token = _key; 703 const struct type *const *ti = _ti; 704 const struct type *type = *ti; 705 706 if (token->size != type->name->size) 707 return token->size - type->name->size; 708 else 709 return memcmp(token->value, type->name->value, 710 token->size); 711} 712 713/* 714 * Build up a list of types and a sorted index to that list. 715 */ 716static void build_type_list(void) 717{ 718 struct type *types; 719 unsigned nr, t, n; 720 721 nr = 0; 722 for (n = 0; n < nr_tokens - 1; n++) 723 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && 724 token_list[n + 1].token_type == TOKEN_ASSIGNMENT) 725 nr++; 726 727 if (nr == 0) { 728 fprintf(stderr, "%s: No defined types\n", filename); 729 exit(1); 730 } 731 732 nr_types = nr; 733 types = type_list = calloc(nr + 1, sizeof(type_list[0])); 734 if (!type_list) { 735 perror(NULL); 736 exit(1); 737 } 738 type_index = calloc(nr, sizeof(type_index[0])); 739 if (!type_index) { 740 perror(NULL); 741 exit(1); 742 } 743 744 t = 0; 745 types[t].flags |= TYPE_BEGIN; 746 for (n = 0; n < nr_tokens - 1; n++) { 747 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME && 748 token_list[n + 1].token_type == TOKEN_ASSIGNMENT) { 749 types[t].name = &token_list[n]; 750 type_index[t] = &types[t]; 751 t++; 752 } 753 } 754 types[t].name = &token_list[n + 1]; 755 types[t].flags |= TYPE_STOP_MARKER; 756 757 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare); 758 759 debug("Extracted %u types\n", nr_types); 760#if 0 761 for (n = 0; n < nr_types; n++) { 762 struct type *type = type_index[n]; 763 debug("- %*.*s\n", 764 (int)type->name->size, 765 (int)type->name->size, 766 type->name->value); 767 } 768#endif 769} 770 771static struct element *parse_type(struct token **_cursor, struct token *stop, 772 struct token *name); 773 774/* 775 * Parse the token stream 776 */ 777static void parse(void) 778{ 779 struct token *cursor; 780 struct type *type; 781 782 /* Parse one type definition statement at a time */ 783 type = type_list; 784 do { 785 cursor = type->name; 786 787 if (cursor[0].token_type != TOKEN_TYPE_NAME || 788 cursor[1].token_type != TOKEN_ASSIGNMENT) 789 abort(); 790 cursor += 2; 791 792 type->element = parse_type(&cursor, type[1].name, NULL); 793 type->element->type_def = type; 794 795 if (cursor != type[1].name) { 796 fprintf(stderr, "%s:%d: Parse error at token '%*.*s'\n", 797 filename, cursor->line, 798 (int)cursor->size, (int)cursor->size, cursor->value); 799 exit(1); 800 } 801 802 } while (type++, !(type->flags & TYPE_STOP_MARKER)); 803 804 debug("Extracted %u actions\n", nr_actions); 805} 806 807static struct element *element_list; 808 809static struct element *alloc_elem(struct token *type) 810{ 811 struct element *e = calloc(1, sizeof(*e)); 812 if (!e) { 813 perror(NULL); 814 exit(1); 815 } 816 e->list_next = element_list; 817 element_list = e; 818 return e; 819} 820 821static struct element *parse_compound(struct token **_cursor, struct token *end, 822 int alternates); 823 824/* 825 * Parse one type definition statement 826 */ 827static struct element *parse_type(struct token **_cursor, struct token *end, 828 struct token *name) 829{ 830 struct element *top, *element; 831 struct action *action, **ppaction; 832 struct token *cursor = *_cursor; 833 struct type **ref; 834 char *p; 835 int labelled = 0, implicit = 0; 836 837 top = element = alloc_elem(cursor); 838 element->class = ASN1_UNIV; 839 element->method = ASN1_PRIM; 840 element->tag = token_to_tag[cursor->token_type]; 841 element->name = name; 842 843 /* Extract the tag value if one given */ 844 if (cursor->token_type == TOKEN_OPEN_SQUARE) { 845 cursor++; 846 if (cursor >= end) 847 goto overrun_error; 848 switch (cursor->token_type) { 849 case DIRECTIVE_UNIVERSAL: 850 element->class = ASN1_UNIV; 851 cursor++; 852 break; 853 case DIRECTIVE_APPLICATION: 854 element->class = ASN1_APPL; 855 cursor++; 856 break; 857 case TOKEN_NUMBER: 858 element->class = ASN1_CONT; 859 break; 860 case DIRECTIVE_PRIVATE: 861 element->class = ASN1_PRIV; 862 cursor++; 863 break; 864 default: 865 fprintf(stderr, "%s:%d: Unrecognised tag class token '%*.*s'\n", 866 filename, cursor->line, 867 (int)cursor->size, (int)cursor->size, cursor->value); 868 exit(1); 869 } 870 871 if (cursor >= end) 872 goto overrun_error; 873 if (cursor->token_type != TOKEN_NUMBER) { 874 fprintf(stderr, "%s:%d: Missing tag number '%*.*s'\n", 875 filename, cursor->line, 876 (int)cursor->size, (int)cursor->size, cursor->value); 877 exit(1); 878 } 879 880 element->tag &= ~0x1f; 881 element->tag |= strtoul(cursor->value, &p, 10); 882 if (p - cursor->value != cursor->size) 883 abort(); 884 cursor++; 885 886 if (cursor >= end) 887 goto overrun_error; 888 if (cursor->token_type != TOKEN_CLOSE_SQUARE) { 889 fprintf(stderr, "%s:%d: Missing closing square bracket '%*.*s'\n", 890 filename, cursor->line, 891 (int)cursor->size, (int)cursor->size, cursor->value); 892 exit(1); 893 } 894 cursor++; 895 if (cursor >= end) 896 goto overrun_error; 897 labelled = 1; 898 } 899 900 /* Handle implicit and explicit markers */ 901 if (cursor->token_type == DIRECTIVE_IMPLICIT) { 902 element->flags |= ELEMENT_IMPLICIT; 903 implicit = 1; 904 cursor++; 905 if (cursor >= end) 906 goto overrun_error; 907 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) { 908 element->flags |= ELEMENT_EXPLICIT; 909 cursor++; 910 if (cursor >= end) 911 goto overrun_error; 912 } 913 914 if (labelled) { 915 if (!implicit) 916 element->method |= ASN1_CONS; 917 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE; 918 element->children = alloc_elem(cursor); 919 element = element->children; 920 element->class = ASN1_UNIV; 921 element->method = ASN1_PRIM; 922 element->tag = token_to_tag[cursor->token_type]; 923 element->name = name; 924 } 925 926 /* Extract the type we're expecting here */ 927 element->type = cursor; 928 switch (cursor->token_type) { 929 case DIRECTIVE_ANY: 930 element->compound = ANY; 931 cursor++; 932 break; 933 934 case DIRECTIVE_NULL: 935 case DIRECTIVE_BOOLEAN: 936 case DIRECTIVE_ENUMERATED: 937 case DIRECTIVE_INTEGER: 938 element->compound = NOT_COMPOUND; 939 cursor++; 940 break; 941 942 case DIRECTIVE_EXTERNAL: 943 element->method = ASN1_CONS; 944 945 case DIRECTIVE_BMPString: 946 case DIRECTIVE_GeneralString: 947 case DIRECTIVE_GraphicString: 948 case DIRECTIVE_IA5String: 949 case DIRECTIVE_ISO646String: 950 case DIRECTIVE_NumericString: 951 case DIRECTIVE_PrintableString: 952 case DIRECTIVE_T61String: 953 case DIRECTIVE_TeletexString: 954 case DIRECTIVE_UniversalString: 955 case DIRECTIVE_UTF8String: 956 case DIRECTIVE_VideotexString: 957 case DIRECTIVE_VisibleString: 958 case DIRECTIVE_ObjectDescriptor: 959 case DIRECTIVE_GeneralizedTime: 960 case DIRECTIVE_UTCTime: 961 element->compound = NOT_COMPOUND; 962 cursor++; 963 break; 964 965 case DIRECTIVE_BIT: 966 case DIRECTIVE_OCTET: 967 element->compound = NOT_COMPOUND; 968 cursor++; 969 if (cursor >= end) 970 goto overrun_error; 971 if (cursor->token_type != DIRECTIVE_STRING) 972 goto parse_error; 973 cursor++; 974 break; 975 976 case DIRECTIVE_OBJECT: 977 element->compound = NOT_COMPOUND; 978 cursor++; 979 if (cursor >= end) 980 goto overrun_error; 981 if (cursor->token_type != DIRECTIVE_IDENTIFIER) 982 goto parse_error; 983 cursor++; 984 break; 985 986 case TOKEN_TYPE_NAME: 987 element->compound = TYPE_REF; 988 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]), 989 type_finder); 990 if (!ref) { 991 fprintf(stderr, "%s:%d: Type '%*.*s' undefined\n", 992 filename, cursor->line, 993 (int)cursor->size, (int)cursor->size, cursor->value); 994 exit(1); 995 } 996 cursor->type = *ref; 997 (*ref)->ref_count++; 998 cursor++; 999 break; 1000 1001 case DIRECTIVE_CHOICE: 1002 element->compound = CHOICE; 1003 cursor++; 1004 element->children = parse_compound(&cursor, end, 1); 1005 break; 1006 1007 case DIRECTIVE_SEQUENCE: 1008 element->compound = SEQUENCE; 1009 element->method = ASN1_CONS; 1010 cursor++; 1011 if (cursor >= end) 1012 goto overrun_error; 1013 if (cursor->token_type == DIRECTIVE_OF) { 1014 element->compound = SEQUENCE_OF; 1015 cursor++; 1016 if (cursor >= end) 1017 goto overrun_error; 1018 element->children = parse_type(&cursor, end, NULL); 1019 } else { 1020 element->children = parse_compound(&cursor, end, 0); 1021 } 1022 break; 1023 1024 case DIRECTIVE_SET: 1025 element->compound = SET; 1026 element->method = ASN1_CONS; 1027 cursor++; 1028 if (cursor >= end) 1029 goto overrun_error; 1030 if (cursor->token_type == DIRECTIVE_OF) { 1031 element->compound = SET_OF; 1032 cursor++; 1033 if (cursor >= end) 1034 goto parse_error; 1035 element->children = parse_type(&cursor, end, NULL); 1036 } else { 1037 element->children = parse_compound(&cursor, end, 1); 1038 } 1039 break; 1040 1041 default: 1042 fprintf(stderr, "%s:%d: Token '%*.*s' does not introduce a type\n", 1043 filename, cursor->line, 1044 (int)cursor->size, (int)cursor->size, cursor->value); 1045 exit(1); 1046 } 1047 1048 /* Handle elements that are optional */ 1049 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL || 1050 cursor->token_type == DIRECTIVE_DEFAULT) 1051 ) { 1052 cursor++; 1053 top->flags |= ELEMENT_SKIPPABLE; 1054 } 1055 1056 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) { 1057 cursor++; 1058 if (cursor >= end) 1059 goto overrun_error; 1060 if (cursor->token_type != TOKEN_ELEMENT_NAME) { 1061 fprintf(stderr, "%s:%d: Token '%*.*s' is not an action function name\n", 1062 filename, cursor->line, 1063 (int)cursor->size, (int)cursor->size, cursor->value); 1064 exit(1); 1065 } 1066 1067 action = malloc(sizeof(struct action) + cursor->size + 1); 1068 if (!action) { 1069 perror(NULL); 1070 exit(1); 1071 } 1072 action->index = 0; 1073 memcpy(action->name, cursor->value, cursor->size); 1074 action->name[cursor->size] = 0; 1075 1076 for (ppaction = &action_list; 1077 *ppaction; 1078 ppaction = &(*ppaction)->next 1079 ) { 1080 int cmp = strcmp(action->name, (*ppaction)->name); 1081 if (cmp == 0) { 1082 free(action); 1083 action = *ppaction; 1084 goto found; 1085 } 1086 if (cmp < 0) { 1087 action->next = *ppaction; 1088 *ppaction = action; 1089 nr_actions++; 1090 goto found; 1091 } 1092 } 1093 action->next = NULL; 1094 *ppaction = action; 1095 nr_actions++; 1096 found: 1097 1098 element->action = action; 1099 cursor->action = action; 1100 cursor++; 1101 if (cursor >= end) 1102 goto overrun_error; 1103 if (cursor->token_type != TOKEN_CLOSE_ACTION) { 1104 fprintf(stderr, "%s:%d: Missing close action, got '%*.*s'\n", 1105 filename, cursor->line, 1106 (int)cursor->size, (int)cursor->size, cursor->value); 1107 exit(1); 1108 } 1109 cursor++; 1110 } 1111 1112 *_cursor = cursor; 1113 return top; 1114 1115parse_error: 1116 fprintf(stderr, "%s:%d: Unexpected token '%*.*s'\n", 1117 filename, cursor->line, 1118 (int)cursor->size, (int)cursor->size, cursor->value); 1119 exit(1); 1120 1121overrun_error: 1122 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); 1123 exit(1); 1124} 1125 1126/* 1127 * Parse a compound type list 1128 */ 1129static struct element *parse_compound(struct token **_cursor, struct token *end, 1130 int alternates) 1131{ 1132 struct element *children, **child_p = &children, *element; 1133 struct token *cursor = *_cursor, *name; 1134 1135 if (cursor->token_type != TOKEN_OPEN_CURLY) { 1136 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%*.*s'\n", 1137 filename, cursor->line, 1138 (int)cursor->size, (int)cursor->size, cursor->value); 1139 exit(1); 1140 } 1141 cursor++; 1142 if (cursor >= end) 1143 goto overrun_error; 1144 1145 if (cursor->token_type == TOKEN_OPEN_CURLY) { 1146 fprintf(stderr, "%s:%d: Empty compound\n", 1147 filename, cursor->line); 1148 exit(1); 1149 } 1150 1151 for (;;) { 1152 name = NULL; 1153 if (cursor->token_type == TOKEN_ELEMENT_NAME) { 1154 name = cursor; 1155 cursor++; 1156 if (cursor >= end) 1157 goto overrun_error; 1158 } 1159 1160 element = parse_type(&cursor, end, name); 1161 if (alternates) 1162 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL; 1163 1164 *child_p = element; 1165 child_p = &element->next; 1166 1167 if (cursor >= end) 1168 goto overrun_error; 1169 if (cursor->token_type != TOKEN_COMMA) 1170 break; 1171 cursor++; 1172 if (cursor >= end) 1173 goto overrun_error; 1174 } 1175 1176 children->flags &= ~ELEMENT_CONDITIONAL; 1177 1178 if (cursor->token_type != TOKEN_CLOSE_CURLY) { 1179 fprintf(stderr, "%s:%d: Expected compound closure, got '%*.*s'\n", 1180 filename, cursor->line, 1181 (int)cursor->size, (int)cursor->size, cursor->value); 1182 exit(1); 1183 } 1184 cursor++; 1185 1186 *_cursor = cursor; 1187 return children; 1188 1189overrun_error: 1190 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename); 1191 exit(1); 1192} 1193 1194static void render_element(FILE *out, struct element *e, struct element *tag); 1195static void render_out_of_line_list(FILE *out); 1196 1197static int nr_entries; 1198static int render_depth = 1; 1199static struct element *render_list, **render_list_p = &render_list; 1200 1201__attribute__((format(printf, 2, 3))) 1202static void render_opcode(FILE *out, const char *fmt, ...) 1203{ 1204 va_list va; 1205 1206 if (out) { 1207 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, ""); 1208 va_start(va, fmt); 1209 vfprintf(out, fmt, va); 1210 va_end(va); 1211 } 1212 nr_entries++; 1213} 1214 1215__attribute__((format(printf, 2, 3))) 1216static void render_more(FILE *out, const char *fmt, ...) 1217{ 1218 va_list va; 1219 1220 if (out) { 1221 va_start(va, fmt); 1222 vfprintf(out, fmt, va); 1223 va_end(va); 1224 } 1225} 1226 1227/* 1228 * Render the grammar into a state machine definition. 1229 */ 1230static void render(FILE *out, FILE *hdr) 1231{ 1232 struct element *e; 1233 struct action *action; 1234 struct type *root; 1235 int index; 1236 1237 fprintf(hdr, "/*\n"); 1238 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n"); 1239 fprintf(hdr, " *\n"); 1240 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name); 1241 fprintf(hdr, " */\n"); 1242 fprintf(hdr, "#include <linux/asn1_decoder.h>\n"); 1243 fprintf(hdr, "\n"); 1244 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name); 1245 if (ferror(hdr)) { 1246 perror(headername); 1247 exit(1); 1248 } 1249 1250 fprintf(out, "/*\n"); 1251 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n"); 1252 fprintf(out, " *\n"); 1253 fprintf(out, " * ASN.1 parser for %s\n", grammar_name); 1254 fprintf(out, " */\n"); 1255 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n"); 1256 fprintf(out, "#include \"%s-asn1.h\"\n", grammar_name); 1257 fprintf(out, "\n"); 1258 if (ferror(out)) { 1259 perror(outputname); 1260 exit(1); 1261 } 1262 1263 /* Tabulate the action functions we might have to call */ 1264 fprintf(hdr, "\n"); 1265 index = 0; 1266 for (action = action_list; action; action = action->next) { 1267 action->index = index++; 1268 fprintf(hdr, 1269 "extern int %s(void *, size_t, unsigned char," 1270 " const void *, size_t);\n", 1271 action->name); 1272 } 1273 fprintf(hdr, "\n"); 1274 1275 fprintf(out, "enum %s_actions {\n", grammar_name); 1276 for (action = action_list; action; action = action->next) 1277 fprintf(out, "\tACT_%s = %u,\n", 1278 action->name, action->index); 1279 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions); 1280 fprintf(out, "};\n"); 1281 1282 fprintf(out, "\n"); 1283 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n", 1284 grammar_name, grammar_name); 1285 for (action = action_list; action; action = action->next) 1286 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name); 1287 fprintf(out, "};\n"); 1288 1289 if (ferror(out)) { 1290 perror(outputname); 1291 exit(1); 1292 } 1293 1294 /* We do two passes - the first one calculates all the offsets */ 1295 debug("Pass 1\n"); 1296 nr_entries = 0; 1297 root = &type_list[0]; 1298 render_element(NULL, root->element, NULL); 1299 render_opcode(NULL, "ASN1_OP_COMPLETE,\n"); 1300 render_out_of_line_list(NULL); 1301 1302 for (e = element_list; e; e = e->list_next) 1303 e->flags &= ~ELEMENT_RENDERED; 1304 1305 /* And then we actually render */ 1306 debug("Pass 2\n"); 1307 fprintf(out, "\n"); 1308 fprintf(out, "static const unsigned char %s_machine[] = {\n", 1309 grammar_name); 1310 1311 nr_entries = 0; 1312 root = &type_list[0]; 1313 render_element(out, root->element, NULL); 1314 render_opcode(out, "ASN1_OP_COMPLETE,\n"); 1315 render_out_of_line_list(out); 1316 1317 fprintf(out, "};\n"); 1318 1319 fprintf(out, "\n"); 1320 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name); 1321 fprintf(out, "\t.machine = %s_machine,\n", grammar_name); 1322 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name); 1323 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name); 1324 fprintf(out, "};\n"); 1325} 1326 1327/* 1328 * Render the out-of-line elements 1329 */ 1330static void render_out_of_line_list(FILE *out) 1331{ 1332 struct element *e, *ce; 1333 const char *act; 1334 int entry; 1335 1336 while ((e = render_list)) { 1337 render_list = e->render_next; 1338 if (!render_list) 1339 render_list_p = &render_list; 1340 1341 render_more(out, "\n"); 1342 e->entry_index = entry = nr_entries; 1343 render_depth++; 1344 for (ce = e->children; ce; ce = ce->next) 1345 render_element(out, ce, NULL); 1346 render_depth--; 1347 1348 act = e->action ? "_ACT" : ""; 1349 switch (e->compound) { 1350 case SEQUENCE: 1351 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); 1352 break; 1353 case SEQUENCE_OF: 1354 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); 1355 render_opcode(out, "_jump_target(%u),\n", entry); 1356 break; 1357 case SET: 1358 render_opcode(out, "ASN1_OP_END_SET%s,\n", act); 1359 break; 1360 case SET_OF: 1361 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); 1362 render_opcode(out, "_jump_target(%u),\n", entry); 1363 break; 1364 default: 1365 break; 1366 } 1367 if (e->action) 1368 render_opcode(out, "_action(ACT_%s),\n", 1369 e->action->name); 1370 render_opcode(out, "ASN1_OP_RETURN,\n"); 1371 } 1372} 1373 1374/* 1375 * Render an element. 1376 */ 1377static void render_element(FILE *out, struct element *e, struct element *tag) 1378{ 1379 struct element *ec; 1380 const char *cond, *act; 1381 int entry, skippable = 0, outofline = 0; 1382 1383 if (e->flags & ELEMENT_SKIPPABLE || 1384 (tag && tag->flags & ELEMENT_SKIPPABLE)) 1385 skippable = 1; 1386 1387 if ((e->type_def && e->type_def->ref_count > 1) || 1388 skippable) 1389 outofline = 1; 1390 1391 if (e->type_def && out) { 1392 render_more(out, "\t// %*.*s\n", 1393 (int)e->type_def->name->size, (int)e->type_def->name->size, 1394 e->type_def->name->value); 1395 } 1396 1397 /* Render the operation */ 1398 cond = (e->flags & ELEMENT_CONDITIONAL || 1399 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : ""; 1400 act = e->action ? "_ACT" : ""; 1401 switch (e->compound) { 1402 case ANY: 1403 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s,", cond, act); 1404 if (e->name) 1405 render_more(out, "\t\t// %*.*s", 1406 (int)e->name->size, (int)e->name->size, 1407 e->name->value); 1408 render_more(out, "\n"); 1409 goto dont_render_tag; 1410 1411 case TAG_OVERRIDE: 1412 render_element(out, e->children, e); 1413 return; 1414 1415 case SEQUENCE: 1416 case SEQUENCE_OF: 1417 case SET: 1418 case SET_OF: 1419 render_opcode(out, "ASN1_OP_%sMATCH%s%s,", 1420 cond, 1421 outofline ? "_JUMP" : "", 1422 skippable ? "_OR_SKIP" : ""); 1423 break; 1424 1425 case CHOICE: 1426 goto dont_render_tag; 1427 1428 case TYPE_REF: 1429 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0) 1430 goto dont_render_tag; 1431 default: 1432 render_opcode(out, "ASN1_OP_%sMATCH%s%s,", 1433 cond, act, 1434 skippable ? "_OR_SKIP" : ""); 1435 break; 1436 } 1437 1438 if (e->name) 1439 render_more(out, "\t\t// %*.*s", 1440 (int)e->name->size, (int)e->name->size, 1441 e->name->value); 1442 render_more(out, "\n"); 1443 1444 /* Render the tag */ 1445 if (!tag) 1446 tag = e; 1447 if (tag->class == ASN1_UNIV && 1448 tag->tag != 14 && 1449 tag->tag != 15 && 1450 tag->tag != 31) 1451 render_opcode(out, "_tag(%s, %s, %s),\n", 1452 asn1_classes[tag->class], 1453 asn1_methods[tag->method | e->method], 1454 asn1_universal_tags[tag->tag]); 1455 else 1456 render_opcode(out, "_tagn(%s, %s, %2u),\n", 1457 asn1_classes[tag->class], 1458 asn1_methods[tag->method | e->method], 1459 tag->tag); 1460 tag = NULL; 1461dont_render_tag: 1462 1463 /* Deal with compound types */ 1464 switch (e->compound) { 1465 case TYPE_REF: 1466 render_element(out, e->type->type->element, tag); 1467 if (e->action) 1468 render_opcode(out, "ASN1_OP_ACT,\n"); 1469 break; 1470 1471 case SEQUENCE: 1472 if (outofline) { 1473 /* Render out-of-line for multiple use or 1474 * skipability */ 1475 render_opcode(out, "_jump_target(%u),", e->entry_index); 1476 if (e->type_def && e->type_def->name) 1477 render_more(out, "\t\t// --> %*.*s", 1478 (int)e->type_def->name->size, 1479 (int)e->type_def->name->size, 1480 e->type_def->name->value); 1481 render_more(out, "\n"); 1482 if (!(e->flags & ELEMENT_RENDERED)) { 1483 e->flags |= ELEMENT_RENDERED; 1484 *render_list_p = e; 1485 render_list_p = &e->render_next; 1486 } 1487 return; 1488 } else { 1489 /* Render inline for single use */ 1490 render_depth++; 1491 for (ec = e->children; ec; ec = ec->next) 1492 render_element(out, ec, NULL); 1493 render_depth--; 1494 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act); 1495 } 1496 break; 1497 1498 case SEQUENCE_OF: 1499 case SET_OF: 1500 if (outofline) { 1501 /* Render out-of-line for multiple use or 1502 * skipability */ 1503 render_opcode(out, "_jump_target(%u),", e->entry_index); 1504 if (e->type_def && e->type_def->name) 1505 render_more(out, "\t\t// --> %*.*s", 1506 (int)e->type_def->name->size, 1507 (int)e->type_def->name->size, 1508 e->type_def->name->value); 1509 render_more(out, "\n"); 1510 if (!(e->flags & ELEMENT_RENDERED)) { 1511 e->flags |= ELEMENT_RENDERED; 1512 *render_list_p = e; 1513 render_list_p = &e->render_next; 1514 } 1515 return; 1516 } else { 1517 /* Render inline for single use */ 1518 entry = nr_entries; 1519 render_depth++; 1520 render_element(out, e->children, NULL); 1521 render_depth--; 1522 if (e->compound == SEQUENCE_OF) 1523 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act); 1524 else 1525 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act); 1526 render_opcode(out, "_jump_target(%u),\n", entry); 1527 } 1528 break; 1529 1530 case SET: 1531 /* I can't think of a nice way to do SET support without having 1532 * a stack of bitmasks to make sure no element is repeated. 1533 * The bitmask has also to be checked that no non-optional 1534 * elements are left out whilst not preventing optional 1535 * elements from being left out. 1536 */ 1537 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n"); 1538 exit(1); 1539 1540 case CHOICE: 1541 for (ec = e->children; ec; ec = ec->next) 1542 render_element(out, ec, NULL); 1543 if (!skippable) 1544 render_opcode(out, "ASN1_OP_COND_FAIL,\n"); 1545 if (e->action) 1546 render_opcode(out, "ASN1_OP_ACT,\n"); 1547 break; 1548 1549 default: 1550 break; 1551 } 1552 1553 if (e->action) 1554 render_opcode(out, "_action(ACT_%s),\n", e->action->name); 1555} 1556