root/scripts/asn1_compiler.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. directive_compare
  2. tokenise
  3. main
  4. type_index_compare
  5. type_finder
  6. build_type_list
  7. parse
  8. alloc_elem
  9. parse_type
  10. parse_compound
  11. dump_element
  12. dump_elements
  13. render_opcode
  14. render_more
  15. render
  16. render_out_of_line_list
  17. render_element

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* Simplified ASN.1 notation parser
   3  *
   4  * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   5  * Written by David Howells (dhowells@redhat.com)
   6  */
   7 
   8 #include <stdarg.h>
   9 #include <stdio.h>
  10 #include <stdlib.h>
  11 #include <stdint.h>
  12 #include <stdbool.h>
  13 #include <string.h>
  14 #include <ctype.h>
  15 #include <unistd.h>
  16 #include <fcntl.h>
  17 #include <sys/stat.h>
  18 #include <linux/asn1_ber_bytecode.h>
  19 
  20 enum token_type {
  21         DIRECTIVE_ABSENT,
  22         DIRECTIVE_ALL,
  23         DIRECTIVE_ANY,
  24         DIRECTIVE_APPLICATION,
  25         DIRECTIVE_AUTOMATIC,
  26         DIRECTIVE_BEGIN,
  27         DIRECTIVE_BIT,
  28         DIRECTIVE_BMPString,
  29         DIRECTIVE_BOOLEAN,
  30         DIRECTIVE_BY,
  31         DIRECTIVE_CHARACTER,
  32         DIRECTIVE_CHOICE,
  33         DIRECTIVE_CLASS,
  34         DIRECTIVE_COMPONENT,
  35         DIRECTIVE_COMPONENTS,
  36         DIRECTIVE_CONSTRAINED,
  37         DIRECTIVE_CONTAINING,
  38         DIRECTIVE_DEFAULT,
  39         DIRECTIVE_DEFINED,
  40         DIRECTIVE_DEFINITIONS,
  41         DIRECTIVE_EMBEDDED,
  42         DIRECTIVE_ENCODED,
  43         DIRECTIVE_ENCODING_CONTROL,
  44         DIRECTIVE_END,
  45         DIRECTIVE_ENUMERATED,
  46         DIRECTIVE_EXCEPT,
  47         DIRECTIVE_EXPLICIT,
  48         DIRECTIVE_EXPORTS,
  49         DIRECTIVE_EXTENSIBILITY,
  50         DIRECTIVE_EXTERNAL,
  51         DIRECTIVE_FALSE,
  52         DIRECTIVE_FROM,
  53         DIRECTIVE_GeneralString,
  54         DIRECTIVE_GeneralizedTime,
  55         DIRECTIVE_GraphicString,
  56         DIRECTIVE_IA5String,
  57         DIRECTIVE_IDENTIFIER,
  58         DIRECTIVE_IMPLICIT,
  59         DIRECTIVE_IMPLIED,
  60         DIRECTIVE_IMPORTS,
  61         DIRECTIVE_INCLUDES,
  62         DIRECTIVE_INSTANCE,
  63         DIRECTIVE_INSTRUCTIONS,
  64         DIRECTIVE_INTEGER,
  65         DIRECTIVE_INTERSECTION,
  66         DIRECTIVE_ISO646String,
  67         DIRECTIVE_MAX,
  68         DIRECTIVE_MIN,
  69         DIRECTIVE_MINUS_INFINITY,
  70         DIRECTIVE_NULL,
  71         DIRECTIVE_NumericString,
  72         DIRECTIVE_OBJECT,
  73         DIRECTIVE_OCTET,
  74         DIRECTIVE_OF,
  75         DIRECTIVE_OPTIONAL,
  76         DIRECTIVE_ObjectDescriptor,
  77         DIRECTIVE_PATTERN,
  78         DIRECTIVE_PDV,
  79         DIRECTIVE_PLUS_INFINITY,
  80         DIRECTIVE_PRESENT,
  81         DIRECTIVE_PRIVATE,
  82         DIRECTIVE_PrintableString,
  83         DIRECTIVE_REAL,
  84         DIRECTIVE_RELATIVE_OID,
  85         DIRECTIVE_SEQUENCE,
  86         DIRECTIVE_SET,
  87         DIRECTIVE_SIZE,
  88         DIRECTIVE_STRING,
  89         DIRECTIVE_SYNTAX,
  90         DIRECTIVE_T61String,
  91         DIRECTIVE_TAGS,
  92         DIRECTIVE_TRUE,
  93         DIRECTIVE_TeletexString,
  94         DIRECTIVE_UNION,
  95         DIRECTIVE_UNIQUE,
  96         DIRECTIVE_UNIVERSAL,
  97         DIRECTIVE_UTCTime,
  98         DIRECTIVE_UTF8String,
  99         DIRECTIVE_UniversalString,
 100         DIRECTIVE_VideotexString,
 101         DIRECTIVE_VisibleString,
 102         DIRECTIVE_WITH,
 103         NR__DIRECTIVES,
 104         TOKEN_ASSIGNMENT = NR__DIRECTIVES,
 105         TOKEN_OPEN_CURLY,
 106         TOKEN_CLOSE_CURLY,
 107         TOKEN_OPEN_SQUARE,
 108         TOKEN_CLOSE_SQUARE,
 109         TOKEN_OPEN_ACTION,
 110         TOKEN_CLOSE_ACTION,
 111         TOKEN_COMMA,
 112         TOKEN_NUMBER,
 113         TOKEN_TYPE_NAME,
 114         TOKEN_ELEMENT_NAME,
 115         NR__TOKENS
 116 };
 117 
 118 static const unsigned char token_to_tag[NR__TOKENS] = {
 119         /* EOC goes first */
 120         [DIRECTIVE_BOOLEAN]             = ASN1_BOOL,
 121         [DIRECTIVE_INTEGER]             = ASN1_INT,
 122         [DIRECTIVE_BIT]                 = ASN1_BTS,
 123         [DIRECTIVE_OCTET]               = ASN1_OTS,
 124         [DIRECTIVE_NULL]                = ASN1_NULL,
 125         [DIRECTIVE_OBJECT]              = ASN1_OID,
 126         [DIRECTIVE_ObjectDescriptor]    = ASN1_ODE,
 127         [DIRECTIVE_EXTERNAL]            = ASN1_EXT,
 128         [DIRECTIVE_REAL]                = ASN1_REAL,
 129         [DIRECTIVE_ENUMERATED]          = ASN1_ENUM,
 130         [DIRECTIVE_EMBEDDED]            = 0,
 131         [DIRECTIVE_UTF8String]          = ASN1_UTF8STR,
 132         [DIRECTIVE_RELATIVE_OID]        = ASN1_RELOID,
 133         /* 14 */
 134         /* 15 */
 135         [DIRECTIVE_SEQUENCE]            = ASN1_SEQ,
 136         [DIRECTIVE_SET]                 = ASN1_SET,
 137         [DIRECTIVE_NumericString]       = ASN1_NUMSTR,
 138         [DIRECTIVE_PrintableString]     = ASN1_PRNSTR,
 139         [DIRECTIVE_T61String]           = ASN1_TEXSTR,
 140         [DIRECTIVE_TeletexString]       = ASN1_TEXSTR,
 141         [DIRECTIVE_VideotexString]      = ASN1_VIDSTR,
 142         [DIRECTIVE_IA5String]           = ASN1_IA5STR,
 143         [DIRECTIVE_UTCTime]             = ASN1_UNITIM,
 144         [DIRECTIVE_GeneralizedTime]     = ASN1_GENTIM,
 145         [DIRECTIVE_GraphicString]       = ASN1_GRASTR,
 146         [DIRECTIVE_VisibleString]       = ASN1_VISSTR,
 147         [DIRECTIVE_GeneralString]       = ASN1_GENSTR,
 148         [DIRECTIVE_UniversalString]     = ASN1_UNITIM,
 149         [DIRECTIVE_CHARACTER]           = ASN1_CHRSTR,
 150         [DIRECTIVE_BMPString]           = ASN1_BMPSTR,
 151 };
 152 
 153 static const char asn1_classes[4][5] = {
 154         [ASN1_UNIV]     = "UNIV",
 155         [ASN1_APPL]     = "APPL",
 156         [ASN1_CONT]     = "CONT",
 157         [ASN1_PRIV]     = "PRIV"
 158 };
 159 
 160 static const char asn1_methods[2][5] = {
 161         [ASN1_UNIV]     = "PRIM",
 162         [ASN1_APPL]     = "CONS"
 163 };
 164 
 165 static const char *const asn1_universal_tags[32] = {
 166         "EOC",
 167         "BOOL",
 168         "INT",
 169         "BTS",
 170         "OTS",
 171         "NULL",
 172         "OID",
 173         "ODE",
 174         "EXT",
 175         "REAL",
 176         "ENUM",
 177         "EPDV",
 178         "UTF8STR",
 179         "RELOID",
 180         NULL,           /* 14 */
 181         NULL,           /* 15 */
 182         "SEQ",
 183         "SET",
 184         "NUMSTR",
 185         "PRNSTR",
 186         "TEXSTR",
 187         "VIDSTR",
 188         "IA5STR",
 189         "UNITIM",
 190         "GENTIM",
 191         "GRASTR",
 192         "VISSTR",
 193         "GENSTR",
 194         "UNISTR",
 195         "CHRSTR",
 196         "BMPSTR",
 197         NULL            /* 31 */
 198 };
 199 
 200 static const char *filename;
 201 static const char *grammar_name;
 202 static const char *outputname;
 203 static const char *headername;
 204 
 205 static const char *const directives[NR__DIRECTIVES] = {
 206 #define _(X) [DIRECTIVE_##X] = #X
 207         _(ABSENT),
 208         _(ALL),
 209         _(ANY),
 210         _(APPLICATION),
 211         _(AUTOMATIC),
 212         _(BEGIN),
 213         _(BIT),
 214         _(BMPString),
 215         _(BOOLEAN),
 216         _(BY),
 217         _(CHARACTER),
 218         _(CHOICE),
 219         _(CLASS),
 220         _(COMPONENT),
 221         _(COMPONENTS),
 222         _(CONSTRAINED),
 223         _(CONTAINING),
 224         _(DEFAULT),
 225         _(DEFINED),
 226         _(DEFINITIONS),
 227         _(EMBEDDED),
 228         _(ENCODED),
 229         [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
 230         _(END),
 231         _(ENUMERATED),
 232         _(EXCEPT),
 233         _(EXPLICIT),
 234         _(EXPORTS),
 235         _(EXTENSIBILITY),
 236         _(EXTERNAL),
 237         _(FALSE),
 238         _(FROM),
 239         _(GeneralString),
 240         _(GeneralizedTime),
 241         _(GraphicString),
 242         _(IA5String),
 243         _(IDENTIFIER),
 244         _(IMPLICIT),
 245         _(IMPLIED),
 246         _(IMPORTS),
 247         _(INCLUDES),
 248         _(INSTANCE),
 249         _(INSTRUCTIONS),
 250         _(INTEGER),
 251         _(INTERSECTION),
 252         _(ISO646String),
 253         _(MAX),
 254         _(MIN),
 255         [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
 256         [DIRECTIVE_NULL] = "NULL",
 257         _(NumericString),
 258         _(OBJECT),
 259         _(OCTET),
 260         _(OF),
 261         _(OPTIONAL),
 262         _(ObjectDescriptor),
 263         _(PATTERN),
 264         _(PDV),
 265         [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
 266         _(PRESENT),
 267         _(PRIVATE),
 268         _(PrintableString),
 269         _(REAL),
 270         [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
 271         _(SEQUENCE),
 272         _(SET),
 273         _(SIZE),
 274         _(STRING),
 275         _(SYNTAX),
 276         _(T61String),
 277         _(TAGS),
 278         _(TRUE),
 279         _(TeletexString),
 280         _(UNION),
 281         _(UNIQUE),
 282         _(UNIVERSAL),
 283         _(UTCTime),
 284         _(UTF8String),
 285         _(UniversalString),
 286         _(VideotexString),
 287         _(VisibleString),
 288         _(WITH)
 289 };
 290 
 291 struct action {
 292         struct action   *next;
 293         char            *name;
 294         unsigned char   index;
 295 };
 296 
 297 static struct action *action_list;
 298 static unsigned nr_actions;
 299 
 300 struct token {
 301         unsigned short  line;
 302         enum token_type token_type : 8;
 303         unsigned char   size;
 304         struct action   *action;
 305         char            *content;
 306         struct type     *type;
 307 };
 308 
 309 static struct token *token_list;
 310 static unsigned nr_tokens;
 311 static bool verbose_opt;
 312 static bool debug_opt;
 313 
 314 #define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
 315 #define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
 316 
 317 static int directive_compare(const void *_key, const void *_pdir)
 318 {
 319         const struct token *token = _key;
 320         const char *const *pdir = _pdir, *dir = *pdir;
 321         size_t dlen, clen;
 322         int val;
 323 
 324         dlen = strlen(dir);
 325         clen = (dlen < token->size) ? dlen : token->size;
 326 
 327         //debug("cmp(%s,%s) = ", token->content, dir);
 328 
 329         val = memcmp(token->content, dir, clen);
 330         if (val != 0) {
 331                 //debug("%d [cmp]\n", val);
 332                 return val;
 333         }
 334 
 335         if (dlen == token->size) {
 336                 //debug("0\n");
 337                 return 0;
 338         }
 339         //debug("%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, *start, *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                         start = 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                                 tokens[tix].content = malloc(tokens[tix].size + 1);
 424                                 if (!tokens[tix].content) {
 425                                         perror(NULL);
 426                                         exit(1);
 427                                 }
 428                                 memcpy(tokens[tix].content, start, tokens[tix].size);
 429                                 tokens[tix].content[tokens[tix].size] = 0;
 430                                 
 431                                 /* If it begins with a lowercase letter then
 432                                  * it's an element name
 433                                  */
 434                                 if (islower(tokens[tix].content[0])) {
 435                                         tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
 436                                         continue;
 437                                 }
 438 
 439                                 /* Otherwise we need to search the directive
 440                                  * table
 441                                  */
 442                                 dir = bsearch(&tokens[tix], directives,
 443                                               sizeof(directives) / sizeof(directives[1]),
 444                                               sizeof(directives[1]),
 445                                               directive_compare);
 446                                 if (dir) {
 447                                         tokens[tix++].token_type = dir - directives;
 448                                         continue;
 449                                 }
 450 
 451                                 tokens[tix++].token_type = TOKEN_TYPE_NAME;
 452                                 continue;
 453                         }
 454 
 455                         /* Handle numbers */
 456                         if (isdigit(*p)) {
 457                                 /* Find the end of the number */
 458                                 q = p + 1;
 459                                 while (q < nl && (isdigit(*q)))
 460                                         q++;
 461                                 tokens[tix].size = q - p;
 462                                 p = q;
 463                                 tokens[tix].content = malloc(tokens[tix].size + 1);
 464                                 if (!tokens[tix].content) {
 465                                         perror(NULL);
 466                                         exit(1);
 467                                 }
 468                                 memcpy(tokens[tix].content, start, tokens[tix].size);
 469                                 tokens[tix].content[tokens[tix].size] = 0;
 470                                 tokens[tix++].token_type = TOKEN_NUMBER;
 471                                 continue;
 472                         }
 473 
 474                         if (nl - p >= 3) {
 475                                 if (memcmp(p, "::=", 3) == 0) {
 476                                         p += 3;
 477                                         tokens[tix].size = 3;
 478                                         tokens[tix].content = "::=";
 479                                         tokens[tix++].token_type = TOKEN_ASSIGNMENT;
 480                                         continue;
 481                                 }
 482                         }
 483 
 484                         if (nl - p >= 2) {
 485                                 if (memcmp(p, "({", 2) == 0) {
 486                                         p += 2;
 487                                         tokens[tix].size = 2;
 488                                         tokens[tix].content = "({";
 489                                         tokens[tix++].token_type = TOKEN_OPEN_ACTION;
 490                                         continue;
 491                                 }
 492                                 if (memcmp(p, "})", 2) == 0) {
 493                                         p += 2;
 494                                         tokens[tix].size = 2;
 495                                         tokens[tix].content = "})";
 496                                         tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
 497                                         continue;
 498                                 }
 499                         }
 500 
 501                         if (nl - p >= 1) {
 502                                 tokens[tix].size = 1;
 503                                 switch (*p) {
 504                                 case '{':
 505                                         p += 1;
 506                                         tokens[tix].content = "{";
 507                                         tokens[tix++].token_type = TOKEN_OPEN_CURLY;
 508                                         continue;
 509                                 case '}':
 510                                         p += 1;
 511                                         tokens[tix].content = "}";
 512                                         tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
 513                                         continue;
 514                                 case '[':
 515                                         p += 1;
 516                                         tokens[tix].content = "[";
 517                                         tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
 518                                         continue;
 519                                 case ']':
 520                                         p += 1;
 521                                         tokens[tix].content = "]";
 522                                         tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
 523                                         continue;
 524                                 case ',':
 525                                         p += 1;
 526                                         tokens[tix].content = ",";
 527                                         tokens[tix++].token_type = TOKEN_COMMA;
 528                                         continue;
 529                                 default:
 530                                         break;
 531                                 }
 532                         }
 533 
 534                         fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
 535                                 filename, lineno, *p);
 536                         exit(1);
 537                 }
 538         }
 539 
 540         nr_tokens = tix;
 541         verbose("Extracted %u tokens\n", nr_tokens);
 542 
 543 #if 0
 544         {
 545                 int n;
 546                 for (n = 0; n < nr_tokens; n++)
 547                         debug("Token %3u: '%s'\n", n, token_list[n].content);
 548         }
 549 #endif
 550 }
 551 
 552 static void build_type_list(void);
 553 static void parse(void);
 554 static void dump_elements(void);
 555 static void render(FILE *out, FILE *hdr);
 556 
 557 /*
 558  *
 559  */
 560 int main(int argc, char **argv)
 561 {
 562         struct stat st;
 563         ssize_t readlen;
 564         FILE *out, *hdr;
 565         char *buffer, *p;
 566         char *kbuild_verbose;
 567         int fd;
 568 
 569         kbuild_verbose = getenv("KBUILD_VERBOSE");
 570         if (kbuild_verbose)
 571                 verbose_opt = atoi(kbuild_verbose);
 572 
 573         while (argc > 4) {
 574                 if (strcmp(argv[1], "-v") == 0)
 575                         verbose_opt = true;
 576                 else if (strcmp(argv[1], "-d") == 0)
 577                         debug_opt = true;
 578                 else
 579                         break;
 580                 memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
 581                 argc--;
 582         }
 583 
 584         if (argc != 4) {
 585                 fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
 586                         argv[0]);
 587                 exit(2);
 588         }
 589 
 590         filename = argv[1];
 591         outputname = argv[2];
 592         headername = argv[3];
 593 
 594         fd = open(filename, O_RDONLY);
 595         if (fd < 0) {
 596                 perror(filename);
 597                 exit(1);
 598         }
 599 
 600         if (fstat(fd, &st) < 0) {
 601                 perror(filename);
 602                 exit(1);
 603         }
 604 
 605         if (!(buffer = malloc(st.st_size + 1))) {
 606                 perror(NULL);
 607                 exit(1);
 608         }
 609 
 610         if ((readlen = read(fd, buffer, st.st_size)) < 0) {
 611                 perror(filename);
 612                 exit(1);
 613         }
 614 
 615         if (close(fd) < 0) {
 616                 perror(filename);
 617                 exit(1);
 618         }
 619 
 620         if (readlen != st.st_size) {
 621                 fprintf(stderr, "%s: Short read\n", filename);
 622                 exit(1);
 623         }
 624 
 625         p = strrchr(argv[1], '/');
 626         p = p ? p + 1 : argv[1];
 627         grammar_name = strdup(p);
 628         if (!p) {
 629                 perror(NULL);
 630                 exit(1);
 631         }
 632         p = strchr(grammar_name, '.');
 633         if (p)
 634                 *p = '\0';
 635 
 636         buffer[readlen] = 0;
 637         tokenise(buffer, buffer + readlen);
 638         build_type_list();
 639         parse();
 640         dump_elements();
 641 
 642         out = fopen(outputname, "w");
 643         if (!out) {
 644                 perror(outputname);
 645                 exit(1);
 646         }
 647 
 648         hdr = fopen(headername, "w");
 649         if (!hdr) {
 650                 perror(headername);
 651                 exit(1);
 652         }
 653 
 654         render(out, hdr);
 655 
 656         if (fclose(out) < 0) {
 657                 perror(outputname);
 658                 exit(1);
 659         }
 660 
 661         if (fclose(hdr) < 0) {
 662                 perror(headername);
 663                 exit(1);
 664         }
 665 
 666         return 0;
 667 }
 668 
 669 enum compound {
 670         NOT_COMPOUND,
 671         SET,
 672         SET_OF,
 673         SEQUENCE,
 674         SEQUENCE_OF,
 675         CHOICE,
 676         ANY,
 677         TYPE_REF,
 678         TAG_OVERRIDE
 679 };
 680 
 681 struct element {
 682         struct type     *type_def;
 683         struct token    *name;
 684         struct token    *type;
 685         struct action   *action;
 686         struct element  *children;
 687         struct element  *next;
 688         struct element  *render_next;
 689         struct element  *list_next;
 690         uint8_t         n_elements;
 691         enum compound   compound : 8;
 692         enum asn1_class class : 8;
 693         enum asn1_method method : 8;
 694         uint8_t         tag;
 695         unsigned        entry_index;
 696         unsigned        flags;
 697 #define ELEMENT_IMPLICIT        0x0001
 698 #define ELEMENT_EXPLICIT        0x0002
 699 #define ELEMENT_TAG_SPECIFIED   0x0004
 700 #define ELEMENT_RENDERED        0x0008
 701 #define ELEMENT_SKIPPABLE       0x0010
 702 #define ELEMENT_CONDITIONAL     0x0020
 703 };
 704 
 705 struct type {
 706         struct token    *name;
 707         struct token    *def;
 708         struct element  *element;
 709         unsigned        ref_count;
 710         unsigned        flags;
 711 #define TYPE_STOP_MARKER        0x0001
 712 #define TYPE_BEGIN              0x0002
 713 };
 714 
 715 static struct type *type_list;
 716 static struct type **type_index;
 717 static unsigned nr_types;
 718 
 719 static int type_index_compare(const void *_a, const void *_b)
 720 {
 721         const struct type *const *a = _a, *const *b = _b;
 722 
 723         if ((*a)->name->size != (*b)->name->size)
 724                 return (*a)->name->size - (*b)->name->size;
 725         else
 726                 return memcmp((*a)->name->content, (*b)->name->content,
 727                               (*a)->name->size);
 728 }
 729 
 730 static int type_finder(const void *_key, const void *_ti)
 731 {
 732         const struct token *token = _key;
 733         const struct type *const *ti = _ti;
 734         const struct type *type = *ti;
 735 
 736         if (token->size != type->name->size)
 737                 return token->size - type->name->size;
 738         else
 739                 return memcmp(token->content, type->name->content,
 740                               token->size);
 741 }
 742 
 743 /*
 744  * Build up a list of types and a sorted index to that list.
 745  */
 746 static void build_type_list(void)
 747 {
 748         struct type *types;
 749         unsigned nr, t, n;
 750 
 751         nr = 0;
 752         for (n = 0; n < nr_tokens - 1; n++)
 753                 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
 754                     token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
 755                         nr++;
 756 
 757         if (nr == 0) {
 758                 fprintf(stderr, "%s: No defined types\n", filename);
 759                 exit(1);
 760         }
 761 
 762         nr_types = nr;
 763         types = type_list = calloc(nr + 1, sizeof(type_list[0]));
 764         if (!type_list) {
 765                 perror(NULL);
 766                 exit(1);
 767         }
 768         type_index = calloc(nr, sizeof(type_index[0]));
 769         if (!type_index) {
 770                 perror(NULL);
 771                 exit(1);
 772         }
 773 
 774         t = 0;
 775         types[t].flags |= TYPE_BEGIN;
 776         for (n = 0; n < nr_tokens - 1; n++) {
 777                 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
 778                     token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
 779                         types[t].name = &token_list[n];
 780                         type_index[t] = &types[t];
 781                         t++;
 782                 }
 783         }
 784         types[t].name = &token_list[n + 1];
 785         types[t].flags |= TYPE_STOP_MARKER;
 786 
 787         qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
 788 
 789         verbose("Extracted %u types\n", nr_types);
 790 #if 0
 791         for (n = 0; n < nr_types; n++) {
 792                 struct type *type = type_index[n];
 793                 debug("- %*.*s\n", type->name->content);
 794         }
 795 #endif
 796 }
 797 
 798 static struct element *parse_type(struct token **_cursor, struct token *stop,
 799                                   struct token *name);
 800 
 801 /*
 802  * Parse the token stream
 803  */
 804 static void parse(void)
 805 {
 806         struct token *cursor;
 807         struct type *type;
 808 
 809         /* Parse one type definition statement at a time */
 810         type = type_list;
 811         do {
 812                 cursor = type->name;
 813 
 814                 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
 815                     cursor[1].token_type != TOKEN_ASSIGNMENT)
 816                         abort();
 817                 cursor += 2;
 818 
 819                 type->element = parse_type(&cursor, type[1].name, NULL);
 820                 type->element->type_def = type;
 821 
 822                 if (cursor != type[1].name) {
 823                         fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
 824                                 filename, cursor->line, cursor->content);
 825                         exit(1);
 826                 }
 827 
 828         } while (type++, !(type->flags & TYPE_STOP_MARKER));
 829 
 830         verbose("Extracted %u actions\n", nr_actions);
 831 }
 832 
 833 static struct element *element_list;
 834 
 835 static struct element *alloc_elem(struct token *type)
 836 {
 837         struct element *e = calloc(1, sizeof(*e));
 838         if (!e) {
 839                 perror(NULL);
 840                 exit(1);
 841         }
 842         e->list_next = element_list;
 843         element_list = e;
 844         return e;
 845 }
 846 
 847 static struct element *parse_compound(struct token **_cursor, struct token *end,
 848                                       int alternates);
 849 
 850 /*
 851  * Parse one type definition statement
 852  */
 853 static struct element *parse_type(struct token **_cursor, struct token *end,
 854                                   struct token *name)
 855 {
 856         struct element *top, *element;
 857         struct action *action, **ppaction;
 858         struct token *cursor = *_cursor;
 859         struct type **ref;
 860         char *p;
 861         int labelled = 0, implicit = 0;
 862 
 863         top = element = alloc_elem(cursor);
 864         element->class = ASN1_UNIV;
 865         element->method = ASN1_PRIM;
 866         element->tag = token_to_tag[cursor->token_type];
 867         element->name = name;
 868 
 869         /* Extract the tag value if one given */
 870         if (cursor->token_type == TOKEN_OPEN_SQUARE) {
 871                 cursor++;
 872                 if (cursor >= end)
 873                         goto overrun_error;
 874                 switch (cursor->token_type) {
 875                 case DIRECTIVE_UNIVERSAL:
 876                         element->class = ASN1_UNIV;
 877                         cursor++;
 878                         break;
 879                 case DIRECTIVE_APPLICATION:
 880                         element->class = ASN1_APPL;
 881                         cursor++;
 882                         break;
 883                 case TOKEN_NUMBER:
 884                         element->class = ASN1_CONT;
 885                         break;
 886                 case DIRECTIVE_PRIVATE:
 887                         element->class = ASN1_PRIV;
 888                         cursor++;
 889                         break;
 890                 default:
 891                         fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
 892                                 filename, cursor->line, cursor->content);
 893                         exit(1);
 894                 }
 895 
 896                 if (cursor >= end)
 897                         goto overrun_error;
 898                 if (cursor->token_type != TOKEN_NUMBER) {
 899                         fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
 900                                 filename, cursor->line, cursor->content);
 901                         exit(1);
 902                 }
 903 
 904                 element->tag &= ~0x1f;
 905                 element->tag |= strtoul(cursor->content, &p, 10);
 906                 element->flags |= ELEMENT_TAG_SPECIFIED;
 907                 if (p - cursor->content != cursor->size)
 908                         abort();
 909                 cursor++;
 910 
 911                 if (cursor >= end)
 912                         goto overrun_error;
 913                 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
 914                         fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
 915                                 filename, cursor->line, cursor->content);
 916                         exit(1);
 917                 }
 918                 cursor++;
 919                 if (cursor >= end)
 920                         goto overrun_error;
 921                 labelled = 1;
 922         }
 923 
 924         /* Handle implicit and explicit markers */
 925         if (cursor->token_type == DIRECTIVE_IMPLICIT) {
 926                 element->flags |= ELEMENT_IMPLICIT;
 927                 implicit = 1;
 928                 cursor++;
 929                 if (cursor >= end)
 930                         goto overrun_error;
 931         } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
 932                 element->flags |= ELEMENT_EXPLICIT;
 933                 cursor++;
 934                 if (cursor >= end)
 935                         goto overrun_error;
 936         }
 937 
 938         if (labelled) {
 939                 if (!implicit)
 940                         element->method |= ASN1_CONS;
 941                 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
 942                 element->children = alloc_elem(cursor);
 943                 element = element->children;
 944                 element->class = ASN1_UNIV;
 945                 element->method = ASN1_PRIM;
 946                 element->tag = token_to_tag[cursor->token_type];
 947                 element->name = name;
 948         }
 949 
 950         /* Extract the type we're expecting here */
 951         element->type = cursor;
 952         switch (cursor->token_type) {
 953         case DIRECTIVE_ANY:
 954                 element->compound = ANY;
 955                 cursor++;
 956                 break;
 957 
 958         case DIRECTIVE_NULL:
 959         case DIRECTIVE_BOOLEAN:
 960         case DIRECTIVE_ENUMERATED:
 961         case DIRECTIVE_INTEGER:
 962                 element->compound = NOT_COMPOUND;
 963                 cursor++;
 964                 break;
 965 
 966         case DIRECTIVE_EXTERNAL:
 967                 element->method = ASN1_CONS;
 968 
 969         case DIRECTIVE_BMPString:
 970         case DIRECTIVE_GeneralString:
 971         case DIRECTIVE_GraphicString:
 972         case DIRECTIVE_IA5String:
 973         case DIRECTIVE_ISO646String:
 974         case DIRECTIVE_NumericString:
 975         case DIRECTIVE_PrintableString:
 976         case DIRECTIVE_T61String:
 977         case DIRECTIVE_TeletexString:
 978         case DIRECTIVE_UniversalString:
 979         case DIRECTIVE_UTF8String:
 980         case DIRECTIVE_VideotexString:
 981         case DIRECTIVE_VisibleString:
 982         case DIRECTIVE_ObjectDescriptor:
 983         case DIRECTIVE_GeneralizedTime:
 984         case DIRECTIVE_UTCTime:
 985                 element->compound = NOT_COMPOUND;
 986                 cursor++;
 987                 break;
 988 
 989         case DIRECTIVE_BIT:
 990         case DIRECTIVE_OCTET:
 991                 element->compound = NOT_COMPOUND;
 992                 cursor++;
 993                 if (cursor >= end)
 994                         goto overrun_error;
 995                 if (cursor->token_type != DIRECTIVE_STRING)
 996                         goto parse_error;
 997                 cursor++;
 998                 break;
 999 
1000         case DIRECTIVE_OBJECT:
1001                 element->compound = NOT_COMPOUND;
1002                 cursor++;
1003                 if (cursor >= end)
1004                         goto overrun_error;
1005                 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
1006                         goto parse_error;
1007                 cursor++;
1008                 break;
1009 
1010         case TOKEN_TYPE_NAME:
1011                 element->compound = TYPE_REF;
1012                 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
1013                               type_finder);
1014                 if (!ref) {
1015                         fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1016                                 filename, cursor->line, cursor->content);
1017                         exit(1);
1018                 }
1019                 cursor->type = *ref;
1020                 (*ref)->ref_count++;
1021                 cursor++;
1022                 break;
1023 
1024         case DIRECTIVE_CHOICE:
1025                 element->compound = CHOICE;
1026                 cursor++;
1027                 element->children = parse_compound(&cursor, end, 1);
1028                 break;
1029 
1030         case DIRECTIVE_SEQUENCE:
1031                 element->compound = SEQUENCE;
1032                 element->method = ASN1_CONS;
1033                 cursor++;
1034                 if (cursor >= end)
1035                         goto overrun_error;
1036                 if (cursor->token_type == DIRECTIVE_OF) {
1037                         element->compound = SEQUENCE_OF;
1038                         cursor++;
1039                         if (cursor >= end)
1040                                 goto overrun_error;
1041                         element->children = parse_type(&cursor, end, NULL);
1042                 } else {
1043                         element->children = parse_compound(&cursor, end, 0);
1044                 }
1045                 break;
1046 
1047         case DIRECTIVE_SET:
1048                 element->compound = SET;
1049                 element->method = ASN1_CONS;
1050                 cursor++;
1051                 if (cursor >= end)
1052                         goto overrun_error;
1053                 if (cursor->token_type == DIRECTIVE_OF) {
1054                         element->compound = SET_OF;
1055                         cursor++;
1056                         if (cursor >= end)
1057                                 goto parse_error;
1058                         element->children = parse_type(&cursor, end, NULL);
1059                 } else {
1060                         element->children = parse_compound(&cursor, end, 1);
1061                 }
1062                 break;
1063 
1064         default:
1065                 fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1066                         filename, cursor->line, cursor->content);
1067                 exit(1);
1068         }
1069 
1070         /* Handle elements that are optional */
1071         if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1072                              cursor->token_type == DIRECTIVE_DEFAULT)
1073             ) {
1074                 cursor++;
1075                 top->flags |= ELEMENT_SKIPPABLE;
1076         }
1077 
1078         if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1079                 cursor++;
1080                 if (cursor >= end)
1081                         goto overrun_error;
1082                 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1083                         fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1084                                 filename, cursor->line, cursor->content);
1085                         exit(1);
1086                 }
1087 
1088                 action = malloc(sizeof(struct action));
1089                 if (!action) {
1090                         perror(NULL);
1091                         exit(1);
1092                 }
1093                 action->index = 0;
1094                 action->name = cursor->content;
1095 
1096                 for (ppaction = &action_list;
1097                      *ppaction;
1098                      ppaction = &(*ppaction)->next
1099                      ) {
1100                         int cmp = strcmp(action->name, (*ppaction)->name);
1101                         if (cmp == 0) {
1102                                 free(action);
1103                                 action = *ppaction;
1104                                 goto found;
1105                         }
1106                         if (cmp < 0) {
1107                                 action->next = *ppaction;
1108                                 *ppaction = action;
1109                                 nr_actions++;
1110                                 goto found;
1111                         }
1112                 }
1113                 action->next = NULL;
1114                 *ppaction = action;
1115                 nr_actions++;
1116         found:
1117 
1118                 element->action = action;
1119                 cursor->action = action;
1120                 cursor++;
1121                 if (cursor >= end)
1122                         goto overrun_error;
1123                 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1124                         fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1125                                 filename, cursor->line, cursor->content);
1126                         exit(1);
1127                 }
1128                 cursor++;
1129         }
1130 
1131         *_cursor = cursor;
1132         return top;
1133 
1134 parse_error:
1135         fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1136                 filename, cursor->line, cursor->content);
1137         exit(1);
1138 
1139 overrun_error:
1140         fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1141         exit(1);
1142 }
1143 
1144 /*
1145  * Parse a compound type list
1146  */
1147 static struct element *parse_compound(struct token **_cursor, struct token *end,
1148                                       int alternates)
1149 {
1150         struct element *children, **child_p = &children, *element;
1151         struct token *cursor = *_cursor, *name;
1152 
1153         if (cursor->token_type != TOKEN_OPEN_CURLY) {
1154                 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1155                         filename, cursor->line, cursor->content);
1156                 exit(1);
1157         }
1158         cursor++;
1159         if (cursor >= end)
1160                 goto overrun_error;
1161 
1162         if (cursor->token_type == TOKEN_OPEN_CURLY) {
1163                 fprintf(stderr, "%s:%d: Empty compound\n",
1164                         filename, cursor->line);
1165                 exit(1);
1166         }
1167 
1168         for (;;) {
1169                 name = NULL;
1170                 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1171                         name = cursor;
1172                         cursor++;
1173                         if (cursor >= end)
1174                                 goto overrun_error;
1175                 }
1176 
1177                 element = parse_type(&cursor, end, name);
1178                 if (alternates)
1179                         element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1180 
1181                 *child_p = element;
1182                 child_p = &element->next;
1183 
1184                 if (cursor >= end)
1185                         goto overrun_error;
1186                 if (cursor->token_type != TOKEN_COMMA)
1187                         break;
1188                 cursor++;
1189                 if (cursor >= end)
1190                         goto overrun_error;
1191         }
1192 
1193         children->flags &= ~ELEMENT_CONDITIONAL;
1194 
1195         if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1196                 fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1197                         filename, cursor->line, cursor->content);
1198                 exit(1);
1199         }
1200         cursor++;
1201 
1202         *_cursor = cursor;
1203         return children;
1204 
1205 overrun_error:
1206         fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1207         exit(1);
1208 }
1209 
1210 static void dump_element(const struct element *e, int level)
1211 {
1212         const struct element *c;
1213         const struct type *t = e->type_def;
1214         const char *name = e->name ? e->name->content : ".";
1215         const char *tname = t && t->name ? t->name->content : ".";
1216         char tag[32];
1217 
1218         if (e->class == 0 && e->method == 0 && e->tag == 0)
1219                 strcpy(tag, "<...>");
1220         else if (e->class == ASN1_UNIV)
1221                 sprintf(tag, "%s %s %s",
1222                         asn1_classes[e->class],
1223                         asn1_methods[e->method],
1224                         asn1_universal_tags[e->tag]);
1225         else
1226                 sprintf(tag, "%s %s %u",
1227                         asn1_classes[e->class],
1228                         asn1_methods[e->method],
1229                         e->tag);
1230 
1231         printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
1232                e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
1233                e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
1234                e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
1235                e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
1236                e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
1237                "-tTqQcaro"[e->compound],
1238                level, "",
1239                tag,
1240                tname,
1241                name,
1242                e->action ? e->action->name : "");
1243         if (e->compound == TYPE_REF)
1244                 dump_element(e->type->type->element, level + 3);
1245         else
1246                 for (c = e->children; c; c = c->next)
1247                         dump_element(c, level + 3);
1248 }
1249 
1250 static void dump_elements(void)
1251 {
1252         if (debug_opt)
1253                 dump_element(type_list[0].element, 0);
1254 }
1255 
1256 static void render_element(FILE *out, struct element *e, struct element *tag);
1257 static void render_out_of_line_list(FILE *out);
1258 
1259 static int nr_entries;
1260 static int render_depth = 1;
1261 static struct element *render_list, **render_list_p = &render_list;
1262 
1263 __attribute__((format(printf, 2, 3)))
1264 static void render_opcode(FILE *out, const char *fmt, ...)
1265 {
1266         va_list va;
1267 
1268         if (out) {
1269                 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1270                 va_start(va, fmt);
1271                 vfprintf(out, fmt, va);
1272                 va_end(va);
1273         }
1274         nr_entries++;
1275 }
1276 
1277 __attribute__((format(printf, 2, 3)))
1278 static void render_more(FILE *out, const char *fmt, ...)
1279 {
1280         va_list va;
1281 
1282         if (out) {
1283                 va_start(va, fmt);
1284                 vfprintf(out, fmt, va);
1285                 va_end(va);
1286         }
1287 }
1288 
1289 /*
1290  * Render the grammar into a state machine definition.
1291  */
1292 static void render(FILE *out, FILE *hdr)
1293 {
1294         struct element *e;
1295         struct action *action;
1296         struct type *root;
1297         int index;
1298 
1299         fprintf(hdr, "/*\n");
1300         fprintf(hdr, " * Automatically generated by asn1_compiler.  Do not edit\n");
1301         fprintf(hdr, " *\n");
1302         fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1303         fprintf(hdr, " */\n");
1304         fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1305         fprintf(hdr, "\n");
1306         fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1307         if (ferror(hdr)) {
1308                 perror(headername);
1309                 exit(1);
1310         }
1311 
1312         fprintf(out, "/*\n");
1313         fprintf(out, " * Automatically generated by asn1_compiler.  Do not edit\n");
1314         fprintf(out, " *\n");
1315         fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1316         fprintf(out, " */\n");
1317         fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1318         fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
1319         fprintf(out, "\n");
1320         if (ferror(out)) {
1321                 perror(outputname);
1322                 exit(1);
1323         }
1324 
1325         /* Tabulate the action functions we might have to call */
1326         fprintf(hdr, "\n");
1327         index = 0;
1328         for (action = action_list; action; action = action->next) {
1329                 action->index = index++;
1330                 fprintf(hdr,
1331                         "extern int %s(void *, size_t, unsigned char,"
1332                         " const void *, size_t);\n",
1333                         action->name);
1334         }
1335         fprintf(hdr, "\n");
1336 
1337         fprintf(out, "enum %s_actions {\n", grammar_name);
1338         for (action = action_list; action; action = action->next)
1339                 fprintf(out, "\tACT_%s = %u,\n",
1340                         action->name, action->index);
1341         fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1342         fprintf(out, "};\n");
1343 
1344         fprintf(out, "\n");
1345         fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1346                 grammar_name, grammar_name);
1347         for (action = action_list; action; action = action->next)
1348                 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1349         fprintf(out, "};\n");
1350 
1351         if (ferror(out)) {
1352                 perror(outputname);
1353                 exit(1);
1354         }
1355 
1356         /* We do two passes - the first one calculates all the offsets */
1357         verbose("Pass 1\n");
1358         nr_entries = 0;
1359         root = &type_list[0];
1360         render_element(NULL, root->element, NULL);
1361         render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1362         render_out_of_line_list(NULL);
1363 
1364         for (e = element_list; e; e = e->list_next)
1365                 e->flags &= ~ELEMENT_RENDERED;
1366 
1367         /* And then we actually render */
1368         verbose("Pass 2\n");
1369         fprintf(out, "\n");
1370         fprintf(out, "static const unsigned char %s_machine[] = {\n",
1371                 grammar_name);
1372 
1373         nr_entries = 0;
1374         root = &type_list[0];
1375         render_element(out, root->element, NULL);
1376         render_opcode(out, "ASN1_OP_COMPLETE,\n");
1377         render_out_of_line_list(out);
1378 
1379         fprintf(out, "};\n");
1380 
1381         fprintf(out, "\n");
1382         fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1383         fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1384         fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1385         fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1386         fprintf(out, "};\n");
1387 }
1388 
1389 /*
1390  * Render the out-of-line elements
1391  */
1392 static void render_out_of_line_list(FILE *out)
1393 {
1394         struct element *e, *ce;
1395         const char *act;
1396         int entry;
1397 
1398         while ((e = render_list)) {
1399                 render_list = e->render_next;
1400                 if (!render_list)
1401                         render_list_p = &render_list;
1402 
1403                 render_more(out, "\n");
1404                 e->entry_index = entry = nr_entries;
1405                 render_depth++;
1406                 for (ce = e->children; ce; ce = ce->next)
1407                         render_element(out, ce, NULL);
1408                 render_depth--;
1409 
1410                 act = e->action ? "_ACT" : "";
1411                 switch (e->compound) {
1412                 case SEQUENCE:
1413                         render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1414                         break;
1415                 case SEQUENCE_OF:
1416                         render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1417                         render_opcode(out, "_jump_target(%u),\n", entry);
1418                         break;
1419                 case SET:
1420                         render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1421                         break;
1422                 case SET_OF:
1423                         render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1424                         render_opcode(out, "_jump_target(%u),\n", entry);
1425                         break;
1426                 default:
1427                         break;
1428                 }
1429                 if (e->action)
1430                         render_opcode(out, "_action(ACT_%s),\n",
1431                                       e->action->name);
1432                 render_opcode(out, "ASN1_OP_RETURN,\n");
1433         }
1434 }
1435 
1436 /*
1437  * Render an element.
1438  */
1439 static void render_element(FILE *out, struct element *e, struct element *tag)
1440 {
1441         struct element *ec, *x;
1442         const char *cond, *act;
1443         int entry, skippable = 0, outofline = 0;
1444 
1445         if (e->flags & ELEMENT_SKIPPABLE ||
1446             (tag && tag->flags & ELEMENT_SKIPPABLE))
1447                 skippable = 1;
1448 
1449         if ((e->type_def && e->type_def->ref_count > 1) ||
1450             skippable)
1451                 outofline = 1;
1452 
1453         if (e->type_def && out) {
1454                 render_more(out, "\t// %s\n", e->type_def->name->content);
1455         }
1456 
1457         /* Render the operation */
1458         cond = (e->flags & ELEMENT_CONDITIONAL ||
1459                 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1460         act = e->action ? "_ACT" : "";
1461         switch (e->compound) {
1462         case ANY:
1463                 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1464                               cond, act, skippable ? "_OR_SKIP" : "");
1465                 if (e->name)
1466                         render_more(out, "\t\t// %s", e->name->content);
1467                 render_more(out, "\n");
1468                 goto dont_render_tag;
1469 
1470         case TAG_OVERRIDE:
1471                 render_element(out, e->children, e);
1472                 return;
1473 
1474         case SEQUENCE:
1475         case SEQUENCE_OF:
1476         case SET:
1477         case SET_OF:
1478                 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1479                               cond,
1480                               outofline ? "_JUMP" : "",
1481                               skippable ? "_OR_SKIP" : "");
1482                 break;
1483 
1484         case CHOICE:
1485                 goto dont_render_tag;
1486 
1487         case TYPE_REF:
1488                 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1489                         goto dont_render_tag;
1490         default:
1491                 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1492                               cond, act,
1493                               skippable ? "_OR_SKIP" : "");
1494                 break;
1495         }
1496 
1497         x = tag ?: e;
1498         if (x->name)
1499                 render_more(out, "\t\t// %s", x->name->content);
1500         render_more(out, "\n");
1501 
1502         /* Render the tag */
1503         if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
1504                 tag = e;
1505 
1506         if (tag->class == ASN1_UNIV &&
1507             tag->tag != 14 &&
1508             tag->tag != 15 &&
1509             tag->tag != 31)
1510                 render_opcode(out, "_tag(%s, %s, %s),\n",
1511                               asn1_classes[tag->class],
1512                               asn1_methods[tag->method | e->method],
1513                               asn1_universal_tags[tag->tag]);
1514         else
1515                 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1516                               asn1_classes[tag->class],
1517                               asn1_methods[tag->method | e->method],
1518                               tag->tag);
1519         tag = NULL;
1520 dont_render_tag:
1521 
1522         /* Deal with compound types */
1523         switch (e->compound) {
1524         case TYPE_REF:
1525                 render_element(out, e->type->type->element, tag);
1526                 if (e->action)
1527                         render_opcode(out, "ASN1_OP_%sACT,\n",
1528                                       skippable ? "MAYBE_" : "");
1529                 break;
1530 
1531         case SEQUENCE:
1532                 if (outofline) {
1533                         /* Render out-of-line for multiple use or
1534                          * skipability */
1535                         render_opcode(out, "_jump_target(%u),", e->entry_index);
1536                         if (e->type_def && e->type_def->name)
1537                                 render_more(out, "\t\t// --> %s",
1538                                             e->type_def->name->content);
1539                         render_more(out, "\n");
1540                         if (!(e->flags & ELEMENT_RENDERED)) {
1541                                 e->flags |= ELEMENT_RENDERED;
1542                                 *render_list_p = e;
1543                                 render_list_p = &e->render_next;
1544                         }
1545                         return;
1546                 } else {
1547                         /* Render inline for single use */
1548                         render_depth++;
1549                         for (ec = e->children; ec; ec = ec->next)
1550                                 render_element(out, ec, NULL);
1551                         render_depth--;
1552                         render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1553                 }
1554                 break;
1555 
1556         case SEQUENCE_OF:
1557         case SET_OF:
1558                 if (outofline) {
1559                         /* Render out-of-line for multiple use or
1560                          * skipability */
1561                         render_opcode(out, "_jump_target(%u),", e->entry_index);
1562                         if (e->type_def && e->type_def->name)
1563                                 render_more(out, "\t\t// --> %s",
1564                                             e->type_def->name->content);
1565                         render_more(out, "\n");
1566                         if (!(e->flags & ELEMENT_RENDERED)) {
1567                                 e->flags |= ELEMENT_RENDERED;
1568                                 *render_list_p = e;
1569                                 render_list_p = &e->render_next;
1570                         }
1571                         return;
1572                 } else {
1573                         /* Render inline for single use */
1574                         entry = nr_entries;
1575                         render_depth++;
1576                         render_element(out, e->children, NULL);
1577                         render_depth--;
1578                         if (e->compound == SEQUENCE_OF)
1579                                 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1580                         else
1581                                 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1582                         render_opcode(out, "_jump_target(%u),\n", entry);
1583                 }
1584                 break;
1585 
1586         case SET:
1587                 /* I can't think of a nice way to do SET support without having
1588                  * a stack of bitmasks to make sure no element is repeated.
1589                  * The bitmask has also to be checked that no non-optional
1590                  * elements are left out whilst not preventing optional
1591                  * elements from being left out.
1592                  */
1593                 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1594                 exit(1);
1595 
1596         case CHOICE:
1597                 for (ec = e->children; ec; ec = ec->next)
1598                         render_element(out, ec, ec);
1599                 if (!skippable)
1600                         render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1601                 if (e->action)
1602                         render_opcode(out, "ASN1_OP_ACT,\n");
1603                 break;
1604 
1605         default:
1606                 break;
1607         }
1608 
1609         if (e->action)
1610                 render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1611 }

/* [<][>][^][v][top][bottom][index][help] */