The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/scripts/asn1_compiler.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 57bcd3548dd9433d98e2cfcffe27c665


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.