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