LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/asn1 - gen.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 931 1130 82.4 %
Date: 2024-06-13 04:01:37 Functions: 26 29 89.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "gen_locl.h"
      37             : 
      38             : extern const char *enum_prefix;
      39             : extern int prefix_enum;
      40             : 
      41             : RCSID("$Id$");
      42             : 
      43             : FILE *jsonfile, *privheaderfile, *headerfile, *oidsfile, *codefile, *logfile, *templatefile;
      44             : FILE *symsfile;
      45             : 
      46             : #define STEM "asn1"
      47             : 
      48             : static const char *orig_filename;
      49             : static char *privheader, *header, *template;
      50             : static const char *headerbase = STEM;
      51             : 
      52             : /* XXX same as der_length_tag */
      53             : static size_t
      54        5572 : length_tag(unsigned int tag)
      55             : {
      56        5572 :     size_t len = 0;
      57             : 
      58        5572 :     if(tag <= 30)
      59        5516 :         return 1;
      60         196 :     while(tag) {
      61          84 :         tag /= 128;
      62          84 :         len++;
      63             :     }
      64          56 :     return len + 1;
      65             : }
      66             : 
      67             : /*
      68             :  * list of all IMPORTs
      69             :  */
      70             : 
      71             : struct import {
      72             :     const char *module;
      73             :     struct import *next;
      74             : };
      75             : 
      76             : static struct import *imports = NULL;
      77             : 
      78             : void
      79         322 : add_import (const char *module)
      80             : {
      81         322 :     struct import *tmp = emalloc (sizeof(*tmp));
      82             : 
      83         322 :     tmp->module = module;
      84         322 :     tmp->next   = imports;
      85         322 :     imports     = tmp;
      86             : 
      87         322 :     fprintf (headerfile, "#include <%s_asn1.h>\n", module);
      88         322 :     fprintf(jsonfile, "{\"imports\":\"%s\"}\n", module);
      89         322 : }
      90             : 
      91             : /*
      92             :  * List of all exported symbols
      93             :  *
      94             :  * XXX A hash table would be nice here.
      95             :  */
      96             : 
      97             : struct sexport {
      98             :     const char *name;
      99             :     int defined;
     100             :     struct sexport *next;
     101             : };
     102             : 
     103             : static struct sexport *exports = NULL;
     104             : 
     105             : void
     106        1232 : add_export (const char *name)
     107             : {
     108        1232 :     struct sexport *tmp = emalloc (sizeof(*tmp));
     109             : 
     110        1232 :     tmp->name   = name;
     111        1232 :     tmp->next   = exports;
     112        1232 :     exports     = tmp;
     113        1232 : }
     114             : 
     115             : int
     116       29022 : is_export(const char *name)
     117             : {
     118             :     struct sexport *tmp;
     119             : 
     120       29022 :     if (exports == NULL) /* no export list, all exported */
     121       22288 :         return 1;
     122             : 
     123      370678 :     for (tmp = exports; tmp != NULL; tmp = tmp->next) {
     124      369068 :         if (strcmp(tmp->name, name) == 0) {
     125        5124 :             tmp->defined = 1;
     126        5124 :             return 1;
     127             :         }
     128             :     }
     129        1610 :     return 0;
     130             : }
     131             : 
     132             : const char *
     133           0 : get_filename (void)
     134             : {
     135           0 :     return orig_filename;
     136             : }
     137             : 
     138             : void
     139         224 : init_generate (const char *filename, const char *base)
     140             : {
     141         224 :     char *fn = NULL;
     142             : 
     143         224 :     orig_filename = filename;
     144         224 :     if (base != NULL) {
     145         224 :         headerbase = strdup(base);
     146         224 :         if (headerbase == NULL)
     147           0 :             errx(1, "strdup");
     148             :     }
     149             : 
     150             :     /* JSON file */
     151         224 :     if (asprintf(&fn, "%s.json", headerbase) < 0 || fn == NULL)
     152           0 :         errx(1, "malloc");
     153         224 :     jsonfile = fopen(fn, "w");
     154         224 :     if (jsonfile == NULL)
     155           0 :         err(1, "open %s", fn);
     156         224 :     free(fn);
     157         224 :     fn = NULL;
     158             : 
     159             :     /* public header file */
     160         224 :     if (asprintf(&header, "%s.h", headerbase) < 0 || header == NULL)
     161           0 :         errx(1, "malloc");
     162         224 :     if (asprintf(&fn, "%s.h", headerbase) < 0 || fn == NULL)
     163           0 :         errx(1, "malloc");
     164         224 :     headerfile = fopen (fn, "w");
     165         224 :     if (headerfile == NULL)
     166           0 :         err (1, "open %s", fn);
     167         224 :     free(fn);
     168         224 :     fn = NULL;
     169             : 
     170             :     /* private header file */
     171         224 :     if (asprintf(&privheader, "%s-priv.h", headerbase) < 0 || privheader == NULL)
     172           0 :         errx(1, "malloc");
     173         224 :     if (asprintf(&fn, "%s-priv.h", headerbase) < 0 || fn == NULL)
     174           0 :         errx(1, "malloc");
     175         224 :     privheaderfile = fopen (fn, "w");
     176         224 :     if (privheaderfile == NULL)
     177           0 :         err (1, "open %s", fn);
     178         224 :     free(fn);
     179         224 :     fn = NULL;
     180             : 
     181             :     /* template file */
     182         224 :     if (asprintf(&template, "%s-template.c", headerbase) < 0 || template == NULL)
     183           0 :         errx(1, "malloc");
     184         224 :     fprintf (headerfile,
     185             :              "/* Generated from %s */\n"
     186             :              "/* Do not edit */\n\n",
     187             :              filename);
     188         224 :     fprintf (headerfile,
     189             :              "#ifndef __%s_h__\n"
     190             :              "#define __%s_h__\n\n", headerbase, headerbase);
     191         224 :     fprintf (headerfile,
     192             :              "#include <stddef.h>\n"
     193             :              "#include <stdint.h>\n"
     194             :              "#include <time.h>\n\n");
     195         224 :     fprintf (headerfile,
     196             :              "#ifndef __asn1_common_definitions__\n"
     197             :              "#define __asn1_common_definitions__\n\n");
     198         224 :         fprintf (headerfile,
     199             :                  "#ifndef __HEIM_BASE_DATA__\n"
     200             :                  "#define __HEIM_BASE_DATA__ 1\n"
     201             :                  "struct heim_base_data {\n"
     202             :                  "    size_t length;\n"
     203             :                  "    void *data;\n"
     204             :                  "};\n"
     205             :                  "typedef struct heim_base_data heim_octet_string;\n"
     206             :                  "#endif\n\n");
     207         224 :     fprintf (headerfile,
     208             :              "typedef struct heim_integer {\n"
     209             :              "  size_t length;\n"
     210             :              "  void *data;\n"
     211             :              "  int negative;\n"
     212             :              "} heim_integer;\n\n");
     213         224 :     fprintf (headerfile,
     214             :              "typedef char *heim_general_string;\n\n"
     215             :              );
     216         224 :     fprintf (headerfile,
     217             :              "typedef char *heim_utf8_string;\n\n"
     218             :              );
     219         224 :     fprintf (headerfile,
     220             :              "typedef struct heim_base_data heim_printable_string;\n\n"
     221             :              );
     222         224 :     fprintf (headerfile,
     223             :              "typedef struct heim_base_data heim_ia5_string;\n\n"
     224             :              );
     225         224 :     fprintf (headerfile,
     226             :              "typedef struct heim_bmp_string {\n"
     227             :              "  size_t length;\n"
     228             :              "  uint16_t *data;\n"
     229             :              "} heim_bmp_string;\n\n");
     230         224 :     fprintf (headerfile,
     231             :              "typedef struct heim_universal_string {\n"
     232             :              "  size_t length;\n"
     233             :              "  uint32_t *data;\n"
     234             :              "} heim_universal_string;\n\n");
     235         224 :     fprintf (headerfile,
     236             :              "typedef char *heim_visible_string;\n\n"
     237             :              );
     238         224 :     fprintf (headerfile,
     239             :              "typedef struct heim_oid {\n"
     240             :              "  size_t length;\n"
     241             :              "  unsigned *components;\n"
     242             :              "} heim_oid;\n\n");
     243         224 :     fprintf (headerfile,
     244             :              "typedef struct heim_bit_string {\n"
     245             :              "  size_t length;\n"
     246             :              "  void *data;\n"
     247             :              "} heim_bit_string;\n\n");
     248         224 :     fprintf (headerfile,
     249             :              "typedef struct heim_base_data heim_any;\n"
     250             :              "typedef struct heim_base_data heim_any_set;\n"
     251             :              "typedef struct heim_base_data HEIM_ANY;\n"
     252             :              "typedef struct heim_base_data HEIM_ANY_SET;\n\n");
     253             : 
     254         224 :     fprintf (headerfile,
     255             :              "enum asn1_print_flags {\n"
     256             :              "   ASN1_PRINT_INDENT = 1,\n"
     257             :              "};\n\n");
     258         224 :     fputs("#define ASN1_MALLOC_ENCODE(T, B, BL, S, L, R)                  \\\n"
     259             :           "  do {                                                         \\\n"
     260             :           "    (BL) = length_##T((S));                                    \\\n"
     261             :           "    (B) = calloc(1, (BL));                                     \\\n"
     262             :           "    if((B) == NULL) {                                          \\\n"
     263             :           "      *(L) = 0;                                                \\\n"
     264             :           "      (R) = ENOMEM;                                            \\\n"
     265             :           "    } else {                                                   \\\n"
     266             :           "      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \\\n"
     267             :           "                       (S), (L));                              \\\n"
     268             :           "      if((R) != 0) {                                           \\\n"
     269             :           "        free((B));                                             \\\n"
     270             :           "        (B) = NULL;                                            \\\n"
     271             :           "        *(L) = 0;                                              \\\n"
     272             :           "      }                                                        \\\n"
     273             :           "    }                                                          \\\n"
     274             :           "  } while (0)\n\n",
     275             :           headerfile);
     276         224 :     fputs("#ifdef _WIN32\n"
     277             :           "#ifndef ASN1_LIB\n"
     278             :           "#define ASN1EXP  __declspec(dllimport)\n"
     279             :           "#else\n"
     280             :           "#define ASN1EXP\n"
     281             :           "#endif\n"
     282             :           "#define ASN1CALL __stdcall\n"
     283             :           "#else\n"
     284             :           "#define ASN1EXP\n"
     285             :           "#define ASN1CALL\n"
     286             :           "#endif\n",
     287             :           headerfile);
     288         224 :     fputs("#ifndef ENOTSUP\n"
     289             :           "/* Very old MSVC CRTs lack ENOTSUP */\n"
     290             :           "#define ENOTSUP EINVAL\n"
     291             :           "#endif\n",
     292             :           headerfile);
     293         224 :     fprintf (headerfile, "struct units;\n\n");
     294         224 :     fprintf (headerfile, "#endif\n\n");
     295         224 :     if (asprintf(&fn, "%s_files", base) < 0 || fn == NULL)
     296           0 :         errx(1, "malloc");
     297         224 :     logfile = fopen(fn, "w");
     298         224 :     if (logfile == NULL)
     299           0 :         err (1, "open %s", fn);
     300         224 :     free(fn);
     301         224 :     fn = NULL;
     302             : 
     303         224 :     if (asprintf(&fn, "%s_oids.c", base) < 0 || fn == NULL)
     304           0 :         errx(1, "malloc");
     305         224 :     oidsfile = fopen(fn, "w");
     306         224 :     if (oidsfile == NULL)
     307           0 :         err (1, "open %s", fn);
     308         224 :     if (asprintf(&fn, "%s_syms.c", base) < 0 || fn == NULL)
     309           0 :         errx(1, "malloc");
     310         224 :     symsfile = fopen(fn, "w");
     311         224 :     if (symsfile == NULL)
     312           0 :         err (1, "open %s", fn);
     313         224 :     free(fn);
     314         224 :     fn = NULL;
     315             : 
     316             :     /* if one code file, write into the one codefile */
     317         224 :     if (one_code_file)
     318         224 :         return;
     319             : 
     320           0 :     templatefile = fopen (template, "w");
     321           0 :     if (templatefile == NULL)
     322           0 :         err (1, "open %s", template);
     323             : 
     324           0 :     fprintf (templatefile,
     325             :              "/* Generated from %s */\n"
     326             :              "/* Do not edit */\n\n"
     327             :              "#include <stdio.h>\n"
     328             :              "#include <stdlib.h>\n"
     329             :              "#include <time.h>\n"
     330             :              "#include <string.h>\n"
     331             :              "#include <errno.h>\n"
     332             :              "#include <limits.h>\n"
     333             :              "#include <asn1_err.h>\n"
     334             :              "#include <%s>\n",
     335             :              filename,
     336             :              type_file_string);
     337             : 
     338           0 :     fprintf (templatefile,
     339             :              "#include <%s>\n"
     340             :              "#include <%s>\n"
     341             :              "#include <der.h>\n"
     342             :              "#include <asn1-template.h>\n",
     343             :              header, privheader);
     344             : 
     345             : 
     346             : }
     347             : 
     348             : void
     349         224 : close_generate (void)
     350             : {
     351         224 :     fprintf (headerfile, "#endif /* __%s_h__ */\n", headerbase);
     352             : 
     353         224 :     if (headerfile && fclose(headerfile) == EOF)
     354           0 :         err(1, "writes to public header file failed");
     355         224 :     if (privheaderfile && fclose(privheaderfile) == EOF)
     356           0 :         err(1, "writes to private header file failed");
     357         224 :     if (templatefile && fclose(templatefile) == EOF)
     358           0 :         err(1, "writes to template file failed");
     359         224 :     if (!jsonfile) abort();
     360         224 :     if (fclose(jsonfile) == EOF)
     361           0 :         err(1, "writes to JSON file failed");
     362         224 :     if (!oidsfile) abort();
     363         224 :     if (fclose(oidsfile) == EOF)
     364           0 :         err(1, "writes to OIDs file failed");
     365         224 :     if (!symsfile) abort();
     366         224 :     if (fclose(symsfile) == EOF)
     367           0 :         err(1, "writes to symbols file failed");
     368         224 :     if (!logfile) abort();
     369         224 :     fprintf(logfile, "\n");
     370         224 :     if (fclose(logfile) == EOF)
     371           0 :         err(1, "writes to log file failed");
     372         224 : }
     373             : 
     374             : void
     375           0 : gen_assign_defval(const char *var, struct value *val)
     376             : {
     377           0 :     switch(val->type) {
     378           0 :     case stringvalue:
     379           0 :         fprintf(codefile, "if((%s = strdup(\"%s\")) == NULL)\nreturn ENOMEM;\n", var, val->u.stringvalue);
     380           0 :         break;
     381           0 :     case integervalue:
     382           0 :         fprintf(codefile, "%s = %lld;\n",
     383           0 :                 var, (long long)val->u.integervalue);
     384           0 :         break;
     385           0 :     case booleanvalue:
     386           0 :         if(val->u.booleanvalue)
     387           0 :             fprintf(codefile, "%s = 1;\n", var);
     388             :         else
     389           0 :             fprintf(codefile, "%s = 0;\n", var);
     390           0 :         break;
     391           0 :     default:
     392           0 :         abort();
     393             :     }
     394           0 : }
     395             : 
     396             : void
     397           0 : gen_compare_defval(const char *var, struct value *val)
     398             : {
     399           0 :     switch(val->type) {
     400           0 :     case stringvalue:
     401           0 :         fprintf(codefile, "if(strcmp(%s, \"%s\") != 0)\n", var, val->u.stringvalue);
     402           0 :         break;
     403           0 :     case integervalue:
     404           0 :         fprintf(codefile, "if(%s != %lld)\n",
     405           0 :                 var, (long long)val->u.integervalue);
     406           0 :         break;
     407           0 :     case booleanvalue:
     408           0 :         if(val->u.booleanvalue)
     409           0 :             fprintf(codefile, "if(!%s)\n", var);
     410             :         else
     411           0 :             fprintf(codefile, "if(%s)\n", var);
     412           0 :         break;
     413           0 :     default:
     414           0 :         abort();
     415             :     }
     416           0 : }
     417             : 
     418             : void
     419         224 : generate_header_of_codefile(const char *name)
     420             : {
     421         224 :     char *filename = NULL;
     422             : 
     423         224 :     if (codefile != NULL)
     424           0 :         abort();
     425             : 
     426         224 :     if (asprintf (&filename, "%s_%s.c", STEM, name) < 0 || filename == NULL)
     427           0 :         errx(1, "malloc");
     428         224 :     codefile = fopen (filename, "w");
     429         224 :     if (codefile == NULL)
     430           0 :         err (1, "fopen %s", filename);
     431         224 :     if (logfile)
     432         224 :         fprintf(logfile, "%s ", filename);
     433         224 :     free(filename);
     434         224 :     filename = NULL;
     435         224 :     fprintf (codefile,
     436             :              "/* Generated from %s */\n"
     437             :              "/* Do not edit */\n\n"
     438             :              "#if defined(_WIN32) && !defined(ASN1_LIB)\n"
     439             :              "# error \"ASN1_LIB must be defined\"\n"
     440             :              "#endif\n"
     441             :              "#include <stdio.h>\n"
     442             :              "#include <stdlib.h>\n"
     443             :              "#include <time.h>\n"
     444             :              "#include <string.h>\n"
     445             :              "#include <errno.h>\n"
     446             :              "#include <limits.h>\n"
     447             :              "#include <%s>\n",
     448             :              orig_filename,
     449             :              type_file_string);
     450             : 
     451         224 :     fprintf (codefile,
     452             :              "#include \"%s\"\n"
     453             :              "#include \"%s\"\n",
     454             :              header, privheader);
     455         224 :     fprintf (codefile,
     456             :              "#include <asn1_err.h>\n"
     457             :              "#include <der.h>\n"
     458             :              "#include <asn1-template.h>\n\n");
     459             : 
     460         224 :     if (parse_units_flag)
     461         224 :         fprintf (codefile,
     462             :                  "#include <parse_units.h>\n\n");
     463             : 
     464             : #ifdef _WIN32
     465             :     fprintf(codefile, "#pragma warning(disable: 4101)\n\n");
     466             : #endif
     467         224 : }
     468             : 
     469             : void
     470         224 : close_codefile(void)
     471             : {
     472         224 :     if (codefile == NULL)
     473           0 :         abort();
     474             : 
     475         224 :     if (fclose(codefile) == EOF)
     476           0 :         err(1, "writes to source code file failed");
     477         224 :     codefile = NULL;
     478         224 : }
     479             : 
     480             : /* Object identifiers are parsed backwards; this reverses that */
     481             : struct objid **
     482        3626 : objid2list(struct objid *o)
     483             : {
     484             :     struct objid *el, **list;
     485             :     size_t i, len;
     486             : 
     487       27482 :     for (el = o, len = 0; el; el = el->next)
     488       23856 :         len++;
     489        3626 :     if (len == 0)
     490         210 :         return NULL;
     491        3416 :     list = ecalloc(len + 1, sizeof(*list));
     492             : 
     493       27272 :     for (i = 0; o; o = o->next)
     494       23856 :         list[i++] = o;
     495        3416 :     list[i] = NULL;
     496             : 
     497             :     /* Reverse the list */
     498       14350 :     for (i = 0; i < (len>>1); i++) {
     499       10934 :         el = list[i];
     500       10934 :         list[i] = list[len - (i + 1)];
     501       10934 :         list[len - (i + 1)] = el;
     502             :     }
     503        3416 :     return list;
     504             : }
     505             : 
     506             : void
     507        4074 : generate_constant (const Symbol *s)
     508             : {
     509        4074 :     switch(s->value->type) {
     510           0 :     case booleanvalue:
     511           0 :         break;
     512         672 :     case integervalue:
     513             :         /*
     514             :          * Work around the fact that OpenSSL defines macros for PKIX constants
     515             :          * that we want to generate as enums, which causes conflicts for things
     516             :          * like ub-name (ub_name).
     517             :          */
     518         672 :         fprintf(headerfile,
     519             :                 "#ifdef %s\n"
     520             :                 "#undef %s\n"
     521             :                 "#endif\n"
     522             :                 "enum { %s = %lld };\n\n",
     523             :                 s->gen_name, s->gen_name, s->gen_name,
     524         672 :                 (long long)s->value->u.integervalue);
     525         672 :         if (is_export(s->name))
     526         644 :             fprintf(symsfile, "ASN1_SYM_INTVAL(\"%s\", \"%s\", %s, %lld)\n",
     527             :                     s->name, s->gen_name, s->gen_name,
     528         644 :                     (long long)s->value->u.integervalue);
     529         672 :         fprintf(jsonfile,
     530             :                 "{\"name\":\"%s\",\"gen_name\":\"%s\",\"type\":\"INTEGER\","
     531             :                 "\"constant\":true,\"exported\":%s,\"value\":%lld}\n",
     532         672 :                 s->name, s->gen_name, is_export(s->name) ? "true" : "false",
     533         672 :                 (long long)s->value->u.integervalue);
     534         672 :         break;
     535           0 :     case nullvalue:
     536           0 :         break;
     537           0 :     case stringvalue:
     538           0 :         break;
     539        3402 :     case objectidentifiervalue: {
     540             :         struct objid *o, **list;
     541             :         size_t i, len;
     542             :         char *gen_upper;
     543             : 
     544        3402 :         if (!one_code_file)
     545           0 :             generate_header_of_codefile(s->gen_name);
     546             : 
     547        3402 :         list = objid2list(s->value->u.objectidentifiervalue);
     548        3402 :         for (len = 0; list && list[len]; len++)
     549             :             ;
     550        3402 :         if (len == 0) {
     551           0 :             errx(1, "Empty OBJECT IDENTIFIER named %s\n", s->name);
     552             :             break;
     553             :         }
     554             : 
     555        3402 :         fprintf(jsonfile,
     556             :                 "{\"name\":\"%s\",\"gen_name\":\"%s\","
     557             :                 "\"type\":\"OBJECT IDENTIFIER\","
     558             :                 "\"constant\":true,\"exported\":%s,\"value\":[\n",
     559        3402 :                 s->name, s->gen_name, is_export(s->name) ? "true" : "false");
     560        3402 :         fprintf (headerfile, "/* OBJECT IDENTIFIER %s ::= { ", s->name);
     561       27132 :         for (i = 0; i < len; i++) {
     562       23730 :             o = list[i];
     563       47460 :             fprintf(headerfile, "%s(%d) ",
     564       23730 :                     o->label ? o->label : "label-less", o->value);
     565       23730 :             if (o->label == NULL)
     566        7280 :                 fprintf(jsonfile, "%s{\"label\":null,\"value\":%d}",
     567             :                         i ? "," : "", o->value);
     568             :             else
     569       16450 :                 fprintf(jsonfile, "%s{\"label\":\"%s\",\"value\":%d}",
     570             :                         i ? "," : "", o->label, o->value);
     571             :         }
     572        3402 :         fprintf(jsonfile, "]}\n");
     573             : 
     574        3402 :         fprintf (codefile, "static unsigned oid_%s_variable_num[%lu] =  {",
     575             :                  s->gen_name, (unsigned long)len);
     576       27132 :         for (i = 0; list[i]; i++) {
     577       23730 :             fprintf(codefile, "%s %d", i ? "," : "", list[i]->value);
     578             :         }
     579        3402 :         fprintf(codefile, "};\n");
     580             : 
     581        3402 :         fprintf (codefile, "const heim_oid asn1_oid_%s = "
     582             :                  "{ %lu, oid_%s_variable_num };\n\n",
     583             :                  s->gen_name, (unsigned long)len, s->gen_name);
     584             : 
     585        3402 :         fprintf(oidsfile, "DEFINE_OID_WITH_NAME(%s)\n", s->gen_name);
     586        3402 :         if (is_export(s->name))
     587        3402 :             fprintf(symsfile, "ASN1_SYM_OID(\"%s\", \"%s\", %s)\n",
     588             :                     s->name, s->gen_name, s->gen_name);
     589             : 
     590        3402 :         free(list);
     591             : 
     592             :         /* header file */
     593             : 
     594        3402 :         gen_upper = strdup(s->gen_name);
     595        3402 :         len = strlen(gen_upper);
     596       71582 :         for (i = 0; i < len; i++)
     597       68180 :             gen_upper[i] = toupper((int)s->gen_name[i]);
     598             : 
     599        3402 :         fprintf (headerfile, "} */\n");
     600        3402 :         fprintf (headerfile,
     601             :                  "extern ASN1EXP const heim_oid asn1_oid_%s;\n"
     602             :                  "#define ASN1_OID_%s (&asn1_oid_%s)\n\n",
     603             :                  s->gen_name,
     604             :                  gen_upper,
     605             :                  s->gen_name);
     606             : 
     607        3402 :         free(gen_upper);
     608             : 
     609        3402 :         if (!one_code_file)
     610           0 :             close_codefile();
     611             : 
     612        3402 :         break;
     613             :     }
     614           0 :     default:
     615           0 :         abort();
     616             :     }
     617        4074 : }
     618             : 
     619             : int
     620          42 : is_tagged_type(const Type *t)
     621             : {
     622             :     /*
     623             :      * Start by chasing aliasings like this:
     624             :      *
     625             :      * Type0 ::= ...
     626             :      * Type1 ::= Type0
     627             :      * ..
     628             :      * TypeN ::= TypeN-1
     629             :      *
     630             :      * to <Type0>, then check if <Type0> is tagged.
     631             :      */
     632          84 :     while (t->type == TType) {
     633           0 :         if (t->subtype)
     634           0 :             t = t->subtype;
     635           0 :         else if (t->symbol && t->symbol->type)
     636           0 :             t = t->symbol->type;
     637             :         else
     638           0 :             abort();
     639             : 
     640             :     }
     641          42 :     if (t->type == TTag && t->tag.tagenv == TE_EXPLICIT)
     642          42 :         return 1;
     643           0 :     if (t->type == TTag) {
     644           0 :         if (t->subtype)
     645           0 :             return is_tagged_type(t->subtype);
     646           0 :         if (t->symbol && t->symbol->type)
     647           0 :             return is_tagged_type(t->symbol->type);
     648             :         /* This is the tag */
     649           0 :         return 1;
     650             :     }
     651           0 :     return 0;
     652             : }
     653             : 
     654             : int
     655       15862 : is_primitive_type(const Type *t)
     656             : {
     657             :     /*
     658             :      * Start by chasing aliasings like this:
     659             :      *
     660             :      * Type0 ::= ...
     661             :      * Type1 ::= Type0
     662             :      * ..
     663             :      * TypeN ::= TypeN-1
     664             :      *
     665             :      * to <Type0>, then check if <Type0> is primitive.
     666             :      */
     667       33362 :     while (t->type == TType &&
     668        3276 :            t->symbol &&
     669        1638 :            t->symbol->type) {
     670        1162 :         if (t->symbol->type->type == TType)
     671           0 :             t = t->symbol->type; /* Alias */
     672        2254 :         else if (t->symbol->type->type == TTag &&
     673        1092 :                  t->symbol->type->tag.tagenv == TE_IMPLICIT)
     674             :             /*
     675             :              * IMPLICIT-tagged alias, something like:
     676             :              *
     677             :              * Type0 ::= [0] IMPLICIT ...
     678             :              *
     679             :              * Just recurse.
     680             :              */
     681           0 :             return is_primitive_type(t->symbol->type);
     682             :         else
     683             :             break;
     684             : 
     685             :     }
     686             :     /* EXPLICIT non-UNIVERSAL tags are always constructed */
     687       15862 :     if (t->type == TTag && t->tag.tagclass != ASN1_C_UNIV &&
     688           0 :         t->tag.tagenv == TE_EXPLICIT)
     689           0 :         return 0;
     690       15862 :     if (t->symbol && t->symbol->type) {
     691             :         /* EXPLICIT non-UNIVERSAL tags are constructed */
     692        3374 :         if (t->symbol->type->type == TTag &&
     693        1666 :             t->symbol->type->tag.tagclass != ASN1_C_UNIV &&
     694          14 :             t->symbol->type->tag.tagenv == TE_EXPLICIT)
     695          14 :             return 0;
     696             :         /* EXPLICIT UNIVERSAL tags are constructed if they are SEQUENCE/SET */
     697        3346 :         if (t->symbol->type->type == TTag &&
     698        1638 :             t->symbol->type->tag.tagclass == ASN1_C_UNIV) {
     699        1638 :             switch (t->symbol->type->tag.tagvalue) {
     700         700 :             case UT_Sequence: return 0;
     701         112 :             case UT_Set: return 0;
     702         826 :             default: return 1;
     703             :             }
     704             :         }
     705             :     }
     706       14210 :     switch(t->type) {
     707        7308 :     case TInteger:
     708             :     case TBoolean:
     709             :     case TOctetString:
     710             :     case TBitString:
     711             :     case TEnumerated:
     712             :     case TGeneralizedTime:
     713             :     case TGeneralString:
     714             :     case TTeletexString:
     715             :     case TOID:
     716             :     case TUTCTime:
     717             :     case TUTF8String:
     718             :     case TPrintableString:
     719             :     case TIA5String:
     720             :     case TBMPString:
     721             :     case TUniversalString:
     722             :     case TVisibleString:
     723             :     case TNull:
     724        7308 :         return 1;
     725         560 :     case TTag:
     726         560 :         return is_primitive_type(t->subtype);
     727        6342 :     default:
     728        6342 :         return 0;
     729             :     }
     730             : }
     731             : 
     732             : static void
     733       98294 : space(int level)
     734             : {
     735      283486 :     while(level-- > 0)
     736       86898 :         fprintf(headerfile, "  ");
     737       98294 : }
     738             : 
     739             : static const char *
     740       70518 : last_member_p(struct member *m)
     741             : {
     742       70518 :     struct member *n = HEIM_TAILQ_NEXT(m, members);
     743       70518 :     if (n == NULL)
     744       11438 :         return "";
     745       59080 :     if (n->ellipsis && HEIM_TAILQ_NEXT(n, members) == NULL)
     746        1218 :         return "";
     747       57862 :     return ",";
     748             : }
     749             : 
     750             : static struct member *
     751        3500 : have_ellipsis(Type *t)
     752             : {
     753             :     struct member *m;
     754       15652 :     HEIM_TAILQ_FOREACH(m, t->members, members) {
     755       12670 :         if (m->ellipsis)
     756         518 :             return m;
     757             :     }
     758        2982 :     return NULL;
     759             : }
     760             : 
     761             : static void
     762       64148 : define_asn1 (int level, Type *t)
     763             : {
     764       64148 :     switch (t->type) {
     765       12558 :     case TType:
     766       12558 :         if (!t->symbol && t->typeref.iosclass) {
     767           0 :             fprintf(headerfile, "%s.&%s",
     768           0 :                     t->typeref.iosclass->symbol->name,
     769           0 :                     t->typeref.field->name);
     770       12558 :         } else if (t->symbol)
     771       12558 :             fprintf(headerfile, "%s", t->symbol->name);
     772             :         else
     773           0 :             abort();
     774       12558 :         break;
     775        3486 :     case TInteger:
     776        3486 :         if(t->members == NULL) {
     777        2184 :             fprintf (headerfile, "INTEGER");
     778        2184 :             if (t->range)
     779        1568 :                 fprintf (headerfile, " (%lld..%lld)",
     780        1568 :                          (long long)t->range->min,
     781        1568 :                          (long long)t->range->max);
     782             :         } else {
     783             :             Member *m;
     784        1302 :             fprintf (headerfile, "INTEGER {\n");
     785       23884 :             HEIM_TAILQ_FOREACH(m, t->members, members) {
     786       22582 :                 space (level + 1);
     787       45164 :                 fprintf(headerfile, "%s(%lld)%s\n", m->gen_name,
     788       22582 :                         (long long)m->val, last_member_p(m));
     789             :             }
     790        1302 :             space(level);
     791        1302 :             fprintf (headerfile, "}");
     792             :         }
     793        3486 :         break;
     794         252 :     case TBoolean:
     795         252 :         fprintf (headerfile, "BOOLEAN");
     796         252 :         break;
     797        2702 :     case TOctetString:
     798        2702 :         fprintf (headerfile, "OCTET STRING");
     799        2702 :         break;
     800         924 :     case TEnumerated:
     801             :     case TBitString: {
     802             :         Member *m;
     803             : 
     804         924 :         space(level);
     805         924 :         if(t->type == TBitString)
     806         924 :             fprintf (headerfile, "BIT STRING {\n");
     807             :         else
     808           0 :             fprintf (headerfile, "ENUMERATED {\n");
     809        6342 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
     810        5418 :             space(level + 1);
     811       10836 :             fprintf(headerfile, "%s(%lld)%s\n", m->name,
     812        5418 :                     (long long)m->val, last_member_p(m));
     813             :         }
     814         924 :         space(level);
     815         924 :         fprintf (headerfile, "}");
     816         924 :         break;
     817             :     }
     818        5390 :     case TChoice:
     819             :     case TSet:
     820             :     case TSequence: {
     821             :         Member *m;
     822        5390 :         size_t max_width = 0;
     823             : 
     824        5390 :         if(t->type == TChoice)
     825         588 :             fprintf(headerfile, "CHOICE {\n");
     826        4802 :         else if(t->type == TSet)
     827           0 :             fprintf(headerfile, "SET {\n");
     828             :         else
     829        4802 :             fprintf(headerfile, "SEQUENCE {\n");
     830       24584 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
     831       19194 :             if(strlen(m->name) > max_width)
     832       10738 :                 max_width = strlen(m->name);
     833             :         }
     834        5390 :         max_width += 3;
     835        5390 :         if(max_width < 16) max_width = 16;
     836       24584 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
     837       19194 :             size_t width = max_width;
     838       19194 :             space(level + 1);
     839       19194 :             if (m->ellipsis) {
     840         672 :                 fprintf (headerfile, "...");
     841             :             } else {
     842       18522 :                 width -= fprintf(headerfile, "%s", m->name);
     843       18522 :                 fprintf(headerfile, "%*s", (int)width, "");
     844       18522 :                 define_asn1(level + 1, m->type);
     845       18522 :                 if(m->optional)
     846        5432 :                     fprintf(headerfile, " OPTIONAL");
     847             :             }
     848       19194 :             if(last_member_p(m))
     849       19194 :                 fprintf (headerfile, ",");
     850       19194 :             fprintf (headerfile, "\n");
     851             :         }
     852        5390 :         space(level);
     853        5390 :         fprintf (headerfile, "}");
     854        5390 :         break;
     855             :     }
     856        1918 :     case TSequenceOf:
     857        1918 :         fprintf (headerfile, "SEQUENCE OF ");
     858        1918 :         define_asn1 (0, t->subtype);
     859        1918 :         break;
     860         252 :     case TSetOf:
     861         252 :         fprintf (headerfile, "SET OF ");
     862         252 :         define_asn1 (0, t->subtype);
     863         252 :         break;
     864         644 :     case TGeneralizedTime:
     865         644 :         fprintf (headerfile, "GeneralizedTime");
     866         644 :         break;
     867        1036 :     case TGeneralString:
     868        1036 :         fprintf (headerfile, "GeneralString");
     869        1036 :         break;
     870          98 :     case TTeletexString:
     871          98 :         fprintf (headerfile, "TeletexString");
     872          98 :         break;
     873       32452 :     case TTag: {
     874       32452 :         const char *classnames[] = { "UNIVERSAL ", "APPLICATION ",
     875             :                                      "" /* CONTEXT */, "PRIVATE " };
     876       32452 :         if(t->tag.tagclass != ASN1_C_UNIV)
     877       27916 :             fprintf (headerfile, "[%s%d] ",
     878       13958 :                      classnames[t->tag.tagclass],
     879             :                      t->tag.tagvalue);
     880       32452 :         if(t->tag.tagenv == TE_IMPLICIT)
     881        1260 :             fprintf (headerfile, "IMPLICIT ");
     882       32452 :         define_asn1 (level, t->subtype);
     883       32452 :         break;
     884             :     }
     885          14 :     case TUTCTime:
     886          14 :         fprintf (headerfile, "UTCTime");
     887          14 :         break;
     888        1204 :     case TUTF8String:
     889        1204 :         space(level);
     890        1204 :         fprintf (headerfile, "UTF8String");
     891        1204 :         break;
     892         112 :     case TPrintableString:
     893         112 :         space(level);
     894         112 :         fprintf (headerfile, "PrintableString");
     895         112 :         break;
     896         238 :     case TIA5String:
     897         238 :         space(level);
     898         238 :         fprintf (headerfile, "IA5String");
     899         238 :         break;
     900         126 :     case TBMPString:
     901         126 :         space(level);
     902         126 :         fprintf (headerfile, "BMPString");
     903         126 :         break;
     904          98 :     case TUniversalString:
     905          98 :         space(level);
     906          98 :         fprintf (headerfile, "UniversalString");
     907          98 :         break;
     908          28 :     case TVisibleString:
     909          28 :         space(level);
     910          28 :         fprintf (headerfile, "VisibleString");
     911          28 :         break;
     912         546 :     case TOID :
     913         546 :         space(level);
     914         546 :         fprintf(headerfile, "OBJECT IDENTIFIER");
     915         546 :         break;
     916          70 :     case TNull:
     917          70 :         space(level);
     918          70 :         fprintf (headerfile, "NULL");
     919          70 :         break;
     920           0 :     default:
     921           0 :         abort ();
     922             :     }
     923       64148 : }
     924             : 
     925             : static void
     926        9044 : getnewbasename(char **newbasename, int typedefp, const char *basename, const char *name)
     927             : {
     928        9044 :     if (typedefp)
     929        8358 :         *newbasename = strdup(name);
     930             :     else {
     931         686 :         if (name[0] == '*')
     932         448 :             name++;
     933         686 :         if (asprintf(newbasename, "%s_%s", basename, name) < 0)
     934           0 :             errx(1, "malloc");
     935             :     }
     936        9044 :     if (*newbasename == NULL)
     937           0 :         err(1, "malloc");
     938        9044 : }
     939             : 
     940             : static void define_type(int, const char *, const char *, Type *, Type *, int, int);
     941             : 
     942             : /*
     943             :  * Get the SET/SEQUENCE member pair and CLASS field pair defining an open type.
     944             :  *
     945             :  * There are three cases:
     946             :  *
     947             :  *  - open types embedded in OCTET STRING, with the open type object class
     948             :  *    relation declared via a constraint
     949             :  *
     950             :  *  - open types not embedded in OCTET STRING, which are really more like ANY
     951             :  *    DEFINED BY types, so, HEIM_ANY
     952             :  *
     953             :  *  - open types in a nested structure member where the type ID field is in a
     954             :  *    member of the ancestor structure (this happens in PKIX's `AttributeSet',
     955             :  *    where the open type is essentially a SET OF HEIM_ANY).
     956             :  *
     957             :  * In a type like PKIX's SingleAttribute the type ID member would be the one
     958             :  * named "type" and the open type member would be the one named "value", and
     959             :  * the corresponding fields of the ATTRIBUTE class would be named "id" and
     960             :  * "Type".
     961             :  *
     962             :  * NOTE: We assume a single open type member pair in any SET/SEQUENCE.  In
     963             :  *       principle there could be more pairs and we could iterate them, or
     964             :  *       better yet, we could be given the name of an open type member and then
     965             :  *       just find its related type ID member and fields, then our caller would
     966             :  *       iterate the SET/SEQUENCE type's members looking for open type members
     967             :  *       and would call this function for each one found.
     968             :  */
     969             : void
     970         168 : get_open_type_defn_fields(const Type *t,
     971             :                           Member **typeidmember,
     972             :                           Member **opentypemember,
     973             :                           Field **typeidfield,
     974             :                           Field **opentypefield,
     975             :                           int *is_array_of)
     976             : {
     977             :     Member *m;
     978             :     Field *junk1, *junk2;
     979         168 :     char *idmembername = NULL;
     980             : 
     981         168 :     if (!typeidfield) typeidfield = &junk1;
     982         168 :     if (!opentypefield) opentypefield = &junk2;
     983             : 
     984         168 :     *typeidfield = *opentypefield = NULL;
     985         168 :     *typeidmember = *opentypemember = NULL;
     986         168 :     *is_array_of = 0;
     987             : 
     988             :     /* Look for the open type member */
     989         364 :     HEIM_TAILQ_FOREACH(m, t->members, members) {
     990         364 :         Type *subtype = m->type;
     991         364 :         Type *sOfType = NULL;
     992             : 
     993        1456 :         while (subtype->type == TTag ||
     994         728 :                subtype->type == TSetOf ||
     995         336 :                subtype->type == TSequenceOf) {
     996         364 :             if (subtype->type == TTag && subtype->subtype) {
     997         588 :                 if (subtype->subtype->type == TOctetString ||
     998         280 :                     subtype->subtype->type == TBitString)
     999             :                     break;
    1000         280 :                 subtype = subtype->subtype;
    1001          56 :             } else if (subtype->type == TSetOf || subtype->type == TSequenceOf) {
    1002          56 :                 sOfType = subtype;
    1003          56 :                 if (sOfType->symbol)
    1004           0 :                     break;
    1005          56 :                 if (subtype->subtype)
    1006          56 :                     subtype = subtype->subtype;
    1007             :             } else
    1008             :                 break;
    1009             :         }
    1010             :         /*
    1011             :          * If we traversed through a non-inlined SET OF or SEQUENCE OF type,
    1012             :          * then this cannot be an open type field.
    1013             :          */
    1014         364 :         if (sOfType && sOfType->symbol)
    1015           0 :             continue;
    1016             :         /*
    1017             :          * The type of the field we're interested in has to have an information
    1018             :          * object constraint.
    1019             :          */
    1020         364 :         if (!subtype->constraint)
    1021         196 :             continue;
    1022         168 :         if (subtype->type != TType && subtype->type != TTag)
    1023           0 :             continue;
    1024             :         /*
    1025             :          * Check if it's an ANY-like member or like an OCTET STRING CONTAINING
    1026             :          * member.  Those are the only two possibilities.
    1027             :          */
    1028         336 :         if ((subtype->type == TTag || subtype->type == TType) &&
    1029         196 :             subtype->subtype &&
    1030          56 :             subtype->constraint->ctype == CT_CONTENTS &&
    1031          56 :             subtype->constraint->u.content.type &&
    1032          56 :             subtype->constraint->u.content.type->type == TType &&
    1033          56 :             !subtype->constraint->u.content.type->subtype &&
    1034          56 :             subtype->constraint->u.content.type->constraint &&
    1035          28 :             subtype->constraint->u.content.type->constraint->ctype == CT_TABLE_CONSTRAINT) {
    1036             :             /* Type like OCTET STRING or BIT STRING CONTAINING open type */
    1037          28 :             if (*opentypemember)
    1038           0 :                 errx(1, "Multiple open type members %s and %s for the same "
    1039           0 :                      "field %s?", (*opentypemember)->name, m->name,
    1040           0 :                      (*opentypefield)->name);
    1041          28 :             *opentypemember = m;
    1042          28 :             *opentypefield = subtype->constraint->u.content.type->typeref.field;
    1043          28 :             *is_array_of = sOfType != NULL;
    1044          28 :             idmembername = subtype->constraint->u.content.type->constraint->u.content.crel.membername;
    1045          28 :             break;
    1046         140 :         } else if (subtype->symbol && strcmp(subtype->symbol->name, "HEIM_ANY") == 0) {
    1047             :             /* Open type, but NOT embedded in OCTET STRING or BIT STRING */
    1048         140 :             if (*opentypemember)
    1049           0 :                 errx(1, "Multiple open type members %s and %s for the same "
    1050           0 :                      "field %s?", (*opentypemember)->name, m->name,
    1051           0 :                      (*opentypefield)->name);
    1052         140 :             *opentypemember = m;
    1053         140 :             *opentypefield = subtype->typeref.field;
    1054         140 :             *is_array_of = sOfType != NULL;
    1055         140 :             idmembername = subtype->constraint->u.content.crel.membername;
    1056         140 :             break;
    1057             :         }
    1058             :     }
    1059             : 
    1060         168 :     if (!idmembername)
    1061           0 :         errx(1, "Missing open type id member in %s",
    1062           0 :              t->symbol ? t->symbol->name : "<unknown type>");
    1063             :     /* Look for the type ID member identified in the previous loop */
    1064         168 :     HEIM_TAILQ_FOREACH(m, t->members, members) {
    1065         168 :         if (!m->type->subtype || strcmp(m->name, idmembername) != 0)
    1066           0 :             continue;
    1067         336 :         if (m->type->constraint &&
    1068         168 :             m->type->constraint->ctype == CT_TABLE_CONSTRAINT)
    1069         168 :             *typeidfield = m->type->typeref.field;
    1070           0 :         else if (m->type->subtype->constraint &&
    1071           0 :                  m->type->subtype->constraint->ctype == CT_TABLE_CONSTRAINT)
    1072           0 :             *typeidfield = m->type->subtype->typeref.field;
    1073             :         else
    1074           0 :             continue;
    1075             :         /* This is the type ID field (because there _is_ a subtype) */
    1076         168 :         *typeidmember = m;
    1077         168 :         break;
    1078             :     }
    1079         168 : }
    1080             : 
    1081             : /*
    1082             :  * Generate CHOICE-like struct fields for open types declared via
    1083             :  * X.681/682/683 syntax.
    1084             :  *
    1085             :  * We could support multiple open type members in a SET/SEQUENCE, but for now
    1086             :  * we support only one.
    1087             :  */
    1088             : static void
    1089          84 : define_open_type(int level, const char *newbasename, const char *name, const char *basename, Type *pt, Type *t)
    1090             : {
    1091             :     Member *opentypemember, *typeidmember;
    1092             :     Field *opentypefield, *typeidfield;
    1093             :     ObjectField *of;
    1094          84 :     IOSObjectSet *os = pt->actual_parameter;
    1095             :     IOSObject **objects;
    1096             :     size_t nobjs, i;
    1097             :     int is_array_of_open_type;
    1098             : 
    1099          84 :     get_open_type_defn_fields(pt, &typeidmember, &opentypemember,
    1100             :                               &typeidfield, &opentypefield,
    1101             :                               &is_array_of_open_type);
    1102         168 :     if (!opentypemember || !typeidmember ||
    1103         168 :         !opentypefield  || !typeidfield)
    1104           0 :         errx(1, "Open type specification in %s is incomplete", name);
    1105             : 
    1106          84 :     sort_object_set(os, typeidfield, &objects, &nobjs);
    1107             : 
    1108          84 :     fprintf(headerfile, "struct {\n");
    1109          84 :     fprintf(jsonfile, "{\"opentype\":true,\"arraytype\":%s,",
    1110          84 :             is_array_of_open_type ? "true" : "false");
    1111          84 :     fprintf(jsonfile, "\"classname\":\"%s\",", os->iosclass->symbol->name);
    1112          84 :     fprintf(jsonfile, "\"objectsetname\":\"%s\",", os->symbol->name);
    1113          84 :     fprintf(jsonfile, "\"typeidmember\":\"%s\",", typeidmember->name);
    1114          84 :     fprintf(jsonfile, "\"opentypemember\":\"%s\",", opentypemember->name);
    1115          84 :     fprintf(jsonfile, "\"typeidfield\":\"%s\",", typeidfield->name);
    1116          84 :     fprintf(jsonfile, "\"opentypefield\":\"%s\",", opentypefield->name);
    1117             : 
    1118             :     /* Iterate objects in the object set, gen enum labels */
    1119          84 :     fprintf(headerfile, "enum { choice_%s_iosnumunknown = 0,\n",
    1120             :             newbasename);
    1121        1106 :     for (i = 0; i < nobjs; i++) {
    1122        3346 :         HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) {
    1123        2324 :             if (strcmp(of->name, typeidfield->name) != 0)
    1124        1302 :                 continue;
    1125        1022 :             if (!of->value || !of->value->s)
    1126           0 :                 errx(1, "Unknown value in value field %s of object %s",
    1127           0 :                      of->name, objects[i]->symbol->name);
    1128        1022 :             fprintf(headerfile, "choice_%s_iosnum_%s,\n",
    1129        1022 :                     newbasename, of->value->s->gen_name);
    1130             :         }
    1131             :     }
    1132          84 :     fprintf(headerfile, "} element;\n");
    1133             : 
    1134          84 :     if (is_array_of_open_type)
    1135          28 :         fprintf(headerfile, "unsigned int len;\n");
    1136             : 
    1137             :     /* Iterate objects in the object set, gen union arms */
    1138          84 :     fprintf(headerfile, "union {\nvoid *_any;\n");
    1139          84 :     fprintf(jsonfile, "\"members\":[");
    1140        1106 :     for (i = 0; i < nobjs; i++) {
    1141        3346 :         HEIM_TAILQ_FOREACH(of, objects[i]->objfields, objfields) {
    1142        2324 :             char *n = NULL;
    1143             : 
    1144             :             /* XXX Print the type IDs into the jsonfile too pls */
    1145             : 
    1146        2324 :             if (strcmp(of->name, opentypefield->name) != 0)
    1147        2604 :                 continue;
    1148        2044 :             if (!of->type || (!of->type->symbol && of->type->type != TTag) ||
    1149        1022 :                 of->type->tag.tagclass != ASN1_C_UNIV) {
    1150           0 :                 warnx("Ignoring unknown or unset type field %s of object %s",
    1151           0 :                       of->name, objects[i]->symbol->name);
    1152           0 :                 continue;
    1153             :             }
    1154             : 
    1155        1022 :             if (asprintf(&n, "*%s", objects[i]->symbol->gen_name) < 0 || n == NULL)
    1156           0 :                 err(1, "malloc");
    1157        1022 :             define_type(level + 2, n, newbasename, NULL, of->type, FALSE, FALSE);
    1158        1022 :             fprintf(jsonfile, "%s", (i + 1) < nobjs ? "," : "");
    1159        1022 :             free(n);
    1160             :         }
    1161             :     }
    1162          84 :     fprintf(jsonfile, "]}\n");
    1163          84 :     if (is_array_of_open_type) {
    1164          28 :         fprintf(headerfile, "} *val;\n} _ioschoice_%s;\n", opentypemember->gen_name);
    1165             :     } else {
    1166          56 :         fprintf(headerfile, "} u;\n");
    1167          56 :         fprintf(headerfile, "} _ioschoice_%s;\n", opentypemember->gen_name);
    1168             :     }
    1169          84 :     free(objects);
    1170          84 : }
    1171             : 
    1172             : static const char * const tagclassnames[] = {
    1173             :     "UNIVERSAL", "APPLICATION", "CONTEXT", "PRIVATE"
    1174             : };
    1175             : 
    1176             : static void
    1177       46438 : define_type(int level, const char *name, const char *basename, Type *pt, Type *t, int typedefp, int preservep)
    1178             : {
    1179       46438 :     const char *label_prefix = NULL;
    1180       46438 :     const char *label_prefix_sep = NULL;
    1181       46438 :     char *newbasename = NULL;
    1182             : 
    1183      102480 :     fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\","
    1184             :             "\"is_type\":true,\"exported\":%s,\"typedef\":%s,",
    1185             :             basename, name,
    1186       57064 :             t->symbol && is_export(t->symbol->name) ? "true" : "false",
    1187             :             typedefp ? "true" : "false");
    1188             : 
    1189       46438 :     switch (t->type) {
    1190       10038 :     case TType:
    1191       10038 :         space(level);
    1192       10038 :         if (!t->symbol && t->actual_parameter) {
    1193           0 :             define_open_type(level, newbasename, name, basename, t, t);
    1194       10038 :         } else if (!t->symbol && pt->actual_parameter) {
    1195           0 :             define_open_type(level, newbasename, name, basename, pt, t);
    1196       10038 :         } else if (t->symbol) {
    1197       10038 :             fprintf(headerfile, "%s %s;\n", t->symbol->gen_name, name);
    1198       10038 :             fprintf(jsonfile, "\"ttype\":\"%s\","
    1199       10038 :                     "\"alias\":true\n", t->symbol->gen_name);
    1200             :         } else
    1201           0 :             abort();
    1202       10038 :         break;
    1203        8694 :     case TInteger:
    1204        8694 :         if (t->symbol && t->symbol->emitted_definition)
    1205           0 :             break;
    1206             : 
    1207        8694 :         space(level);
    1208        8694 :         if(t->members) {
    1209             :             Member *m;
    1210             : 
    1211         364 :             label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : "");
    1212         364 :             label_prefix_sep = prefix_enum ? "_" : "";
    1213         364 :             fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
    1214         364 :             fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"enum\","
    1215             :                     "\"members\":[\n");
    1216        4424 :             HEIM_TAILQ_FOREACH(m, t->members, members) {
    1217        4060 :                 space (level + 1);
    1218        8120 :                 fprintf(headerfile, "%s%s%s = %lld%s\n",
    1219             :                         label_prefix, label_prefix_sep,
    1220        4060 :                         m->gen_name, (long long)m->val, last_member_p(m));
    1221        8120 :                 fprintf(jsonfile, "{\"%s%s%s\":%lld}%s\n",
    1222             :                         label_prefix, label_prefix_sep,
    1223        4060 :                         m->gen_name, (long long)m->val, last_member_p(m));
    1224             :             }
    1225         364 :             fprintf(headerfile, "} %s;\n", name);
    1226         364 :             fprintf(jsonfile, "]");
    1227        8330 :         } else if (t->range == NULL) {
    1228         602 :             fprintf(headerfile, "heim_integer %s;\n", name);
    1229         602 :             fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"heim_integer\"");
    1230        7840 :         } else if (t->range->min < 0 &&
    1231         210 :                    (t->range->min < INT_MIN || t->range->max > INT_MAX)) {
    1232          14 :             fprintf(headerfile, "int64_t %s;\n", name);
    1233          14 :             fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"int64_t\"");
    1234        7714 :         } else if (t->range->min < 0) {
    1235          98 :             fprintf (headerfile, "int %s;\n", name);
    1236          98 :             fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"int\"");
    1237        7616 :         } else if (t->range->max > UINT_MAX) {
    1238           0 :             fprintf (headerfile, "uint64_t %s;\n", name);
    1239           0 :             fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"uint64_t\"");
    1240             :         } else {
    1241        7616 :             fprintf (headerfile, "unsigned int %s;\n", name);
    1242        7616 :             fprintf(jsonfile, "\"ttype\":\"INTEGER\",\"ctype\":\"unsigned int\"");
    1243             :         }
    1244        8694 :         break;
    1245         210 :     case TBoolean:
    1246         210 :         space(level);
    1247         210 :         fprintf (headerfile, "int %s;\n", name);
    1248         210 :         fprintf(jsonfile, "\"ttype\":\"BOOLEAN\",\"ctype\":\"unsigned int\"");
    1249         210 :         break;
    1250        1680 :     case TOctetString:
    1251        1680 :         space(level);
    1252        1680 :         fprintf (headerfile, "heim_octet_string %s;\n", name);
    1253        1680 :         fprintf(jsonfile, "\"ttype\":\"OCTET STRING\",\"ctype\":\"heim_octet_string\"");
    1254        1680 :         break;
    1255         490 :     case TBitString: {
    1256             :         Member *m;
    1257             :         Type i;
    1258         490 :         struct range range = { 0, UINT_MAX };
    1259         490 :         size_t max_memno = 0;
    1260             :         size_t bitset_size;
    1261             : 
    1262         490 :         if (t->symbol && t->symbol->emitted_definition)
    1263           0 :             break;
    1264         490 :         memset(&i, 0, sizeof(i));
    1265             : 
    1266             :         /*
    1267             :          * range.max implies the size of the base unsigned integer used for the
    1268             :          * bitfield members.  If it's less than or equal to UINT_MAX, then that
    1269             :          * will be unsigned int, otherwise it will be uint64_t.
    1270             :          *
    1271             :          * We could just use uint64_t, yes, but for now, and in case that any
    1272             :          * projects were exposing the BIT STRING types' C representations in
    1273             :          * ABIs prior to this compiler supporting BIT STRING with larger
    1274             :          * members, we stick to this.
    1275             :          */
    1276        2212 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
    1277        1722 :             if (m->val > max_memno)
    1278        1540 :                 max_memno = m->val;
    1279             :         }
    1280         490 :         if (max_memno > 63)
    1281           0 :             range.max = INT64_MAX;
    1282             :         else
    1283         490 :             range.max = 1ULL << max_memno;
    1284             : 
    1285         490 :         i.type = TInteger;
    1286         490 :         i.range = &range;
    1287         490 :         i.members = NULL;
    1288         490 :         i.constraint = NULL;
    1289             : 
    1290         490 :         space(level);
    1291         490 :         fprintf(jsonfile, "\"ttype\":\"BIT STRING\",");
    1292         490 :         if(HEIM_TAILQ_EMPTY(t->members)) {
    1293         308 :             fprintf (headerfile, "heim_bit_string %s;\n", name);
    1294         308 :             fprintf(jsonfile, "\"ctype\":\"heim_bit_string\"");
    1295             :         } else {
    1296         182 :             int64_t pos = 0;
    1297         182 :             getnewbasename(&newbasename, typedefp || level == 0, basename, name);
    1298             : 
    1299         182 :             fprintf (headerfile, "struct %s {\n", newbasename);
    1300         182 :             fprintf(jsonfile, "\"ctype\":\"struct %s\",\"members\":[\n", newbasename);
    1301        1904 :             HEIM_TAILQ_FOREACH(m, t->members, members) {
    1302        1722 :                 char *n = NULL;
    1303             : 
    1304             :                 /*
    1305             :                  * pad unused bits beween declared members (hopefully this
    1306             :                  * forces the compiler to give us an obvious layout)
    1307             :                  */
    1308        3766 :                 while (pos < m->val) {
    1309         644 :                     if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 ||
    1310         322 :                         n == NULL)
    1311           0 :                         err(1, "malloc");
    1312         322 :                     define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE);
    1313         322 :                     fprintf(jsonfile, ",");
    1314         322 :                     free(n);
    1315         322 :                     pos++;
    1316             :                 }
    1317             : 
    1318        1722 :                 n = NULL;
    1319        1722 :                 if (asprintf (&n, "%s:1", m->gen_name) < 0 || n == NULL)
    1320           0 :                     errx(1, "malloc");
    1321        1722 :                 define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE);
    1322        1722 :                 fprintf(jsonfile, "%s", last_member_p(m));
    1323        1722 :                 free (n);
    1324        1722 :                 n = NULL;
    1325        1722 :                 pos++;
    1326             :             }
    1327             :             /* pad unused tail (ditto) */
    1328         182 :             bitset_size = max_memno;
    1329         182 :             if (max_memno > 31)
    1330           0 :                 bitset_size += 64 - (max_memno % 64);
    1331             :             else
    1332         182 :                 bitset_size = 32;
    1333         182 :             if (pos < bitset_size)
    1334         154 :                 fprintf(jsonfile, ",");
    1335        4144 :             while (pos < bitset_size) {
    1336        3780 :                 char *n = NULL;
    1337        7560 :                 if (asprintf (&n, "_unused%lld:1", (long long)pos) < 0 ||
    1338        3780 :                     n == NULL)
    1339           0 :                     errx(1, "malloc");
    1340        3780 :                 define_type(level + 1, n, newbasename, NULL, &i, FALSE, FALSE);
    1341        3780 :                 fprintf(jsonfile, "%s", (pos + 1) < bitset_size ? "," : "");
    1342        3780 :                 free(n);
    1343        3780 :                 pos++;
    1344             :             }
    1345             : 
    1346         182 :             space(level);
    1347         182 :             fprintf (headerfile, "} %s;\n\n", name);
    1348         182 :             fprintf(jsonfile, "]");
    1349             :         }
    1350         490 :         break;
    1351             :     }
    1352           0 :     case TEnumerated: {
    1353             :         Member *m;
    1354             : 
    1355           0 :         if (t->symbol && t->symbol->emitted_definition)
    1356           0 :             break;
    1357             : 
    1358           0 :         label_prefix = prefix_enum ? name : (enum_prefix ? enum_prefix : "");
    1359           0 :         label_prefix_sep = prefix_enum ? "_" : "";
    1360           0 :         space(level);
    1361           0 :         fprintf (headerfile, "enum %s {\n", typedefp ? name : "");
    1362           0 :         fprintf(jsonfile, "\"ctype\":\"enum %s\",\"extensible\":%s,\"members\":[\n",
    1363           0 :                 typedefp ? name : "", have_ellipsis(t) ? "true" : "false");
    1364           0 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
    1365           0 :             space(level + 1);
    1366           0 :             if (m->ellipsis) {
    1367           0 :                 fprintf (headerfile, "/* ... */\n");
    1368             :             } else {
    1369           0 :                 fprintf(headerfile, "%s%s%s = %lld%s\n",
    1370             :                         label_prefix, label_prefix_sep,
    1371           0 :                         m->gen_name, (long long)m->val, last_member_p(m));
    1372           0 :                 fprintf(jsonfile, "{\"%s%s%s\":%lld%s}\n",
    1373             :                         label_prefix, label_prefix_sep,
    1374           0 :                         m->gen_name, (long long)m->val, last_member_p(m));
    1375             :             }
    1376             :         }
    1377           0 :         space(level);
    1378           0 :         fprintf (headerfile, "} %s;\n\n", name);
    1379           0 :         fprintf(jsonfile, "]");
    1380           0 :         break;
    1381             :     }
    1382        3066 :     case TSet:
    1383             :     case TSequence: {
    1384             :         Member *m;
    1385             :         struct decoration deco;
    1386        3066 :         ssize_t more_deco = -1;
    1387        3066 :         int decorated = 0;
    1388             : 
    1389        3066 :         getnewbasename(&newbasename, typedefp || level == 0, basename, name);
    1390             : 
    1391        3066 :         space(level);
    1392             : 
    1393        3066 :         fprintf (headerfile, "struct %s {\n", newbasename);
    1394        9198 :         fprintf(jsonfile, "\"ttype\":\"%s\",\"extensible\":%s,"
    1395             :                 "\"ctype\":\"struct %s\"",
    1396        3066 :                 t->type == TSet ? "SET" : "SEQUENCE",
    1397        3066 :                 have_ellipsis(t) ? "true" : "false", newbasename);
    1398        3066 :         if (t->type == TSequence && preservep) {
    1399          84 :             space(level + 1);
    1400          84 :             fprintf(headerfile, "heim_octet_string _save;\n");
    1401          84 :             fprintf(jsonfile, ",\"preserve\":true");
    1402             :         }
    1403        3066 :         fprintf(jsonfile, ",\"members\":[\n");
    1404       14420 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
    1405       11354 :             if (m->ellipsis) {
    1406             :                 ;
    1407       10878 :             } else if (m->optional) {
    1408        4074 :                 char *n = NULL;
    1409             : 
    1410        4074 :                 if (asprintf(&n, "*%s", m->gen_name) < 0 || n == NULL)
    1411           0 :                     errx(1, "malloc");
    1412        4074 :                 fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\","
    1413             :                         "\"optional\":true,\"type\":", m->name, m->gen_name);
    1414        4074 :                 define_type(level + 1, n, newbasename, t, m->type, FALSE, FALSE);
    1415        4074 :                 fprintf(jsonfile, "}%s", last_member_p(m));
    1416        4074 :                 free (n);
    1417             :             } else {
    1418        6804 :                 fprintf(jsonfile, "{\"name\":\"%s\",\"gen_name\":\"%s\","
    1419             :                         "\"optional\":false,\"type\":", m->name, m->gen_name);
    1420        6804 :                 define_type(level + 1, m->gen_name, newbasename, t, m->type, FALSE, FALSE);
    1421        6804 :                 fprintf(jsonfile, "}%s", last_member_p(m));
    1422             :             }
    1423             :         }
    1424        3066 :         fprintf(jsonfile, "]");
    1425        3066 :         if (t->actual_parameter && t->actual_parameter->objects) {
    1426          84 :             fprintf(jsonfile, ",\"opentype\":");
    1427          84 :             define_open_type(level, newbasename, name, basename, t, t);
    1428             :         }
    1429        6174 :         while (decorate_type(newbasename, &deco, &more_deco)) {
    1430          42 :             decorated++;
    1431          42 :             space(level + 1);
    1432          84 :             fprintf(headerfile, "%s %s%s;\n", deco.field_type,
    1433          42 :                     deco.opt ? "*" : "", deco.field_name);
    1434          42 :             if (deco.first)
    1435          42 :                 fprintf(jsonfile, ",\"decorate\":[");
    1436         462 :             fprintf(jsonfile, "%s{"
    1437             :                     "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s,"
    1438             :                     "\"external\":%s,\"pointer\":%s,\"void_star\":%s,"
    1439             :                     "\"struct_star\":%s,"
    1440             :                     "\"copy_function\":\"%s\","
    1441             :                     "\"free_function\":\"%s\",\"header_name\":%s%s%s"
    1442             :                     "}",
    1443          42 :                     deco.first ? "" : ",",
    1444             :                     deco.field_type, deco.field_name,
    1445          84 :                     deco.opt ? "true" : "false", deco.ext ? "true" : "false",
    1446          84 :                     deco.ptr ? "true" : "false", deco.void_star ? "true" : "false",
    1447          42 :                     deco.struct_star ? "true" : "false",
    1448          42 :                     deco.copy_function_name ? deco.copy_function_name : "",
    1449          42 :                     deco.free_function_name ? deco.free_function_name : "",
    1450          42 :                     deco.header_name && deco.header_name[0] == '"' ? "" : "\"",
    1451          42 :                     deco.header_name ? deco.header_name : "",
    1452          42 :                     deco.header_name && deco.header_name[0] == '"' ? "" : "\""
    1453             :                     );
    1454             :         }
    1455        3066 :         if (decorated)
    1456          42 :             fprintf(jsonfile, "]");
    1457        3066 :         space(level);
    1458        3066 :         fprintf (headerfile, "} %s;\n", name);
    1459        3066 :         free(deco.field_type);
    1460        3066 :         break;
    1461             :     }
    1462        1274 :     case TSetOf:
    1463             :     case TSequenceOf: {
    1464             :         Type i;
    1465        1274 :         struct range range = { 0, UINT_MAX };
    1466             : 
    1467        1274 :         getnewbasename(&newbasename, typedefp || level == 0, basename, name);
    1468             : 
    1469        1274 :         memset(&i, 0, sizeof(i));
    1470        1274 :         i.type = TInteger;
    1471        1274 :         i.range = &range;
    1472             : 
    1473        1274 :         space(level);
    1474        1274 :         fprintf (headerfile, "struct %s {\n", newbasename);
    1475        2548 :         fprintf(jsonfile, "\"ttype\":\"%s\",\"ctype\":\"struct %s\",\"members\":[",
    1476        1274 :                 t->type == TSetOf ? "SET OF" : "SEQUENCE OF", newbasename);
    1477        1274 :         define_type(level + 1, "len", newbasename, t, &i, FALSE, FALSE);
    1478        1274 :         fprintf(jsonfile, ",");
    1479        1274 :         define_type(level + 1, "*val", newbasename, t, t->subtype, FALSE, FALSE);
    1480        1274 :         space(level);
    1481        1274 :         fprintf (headerfile, "} %s;\n", name);
    1482        1274 :         fprintf(jsonfile, "]");
    1483        1274 :         break;
    1484             :     }
    1485         126 :     case TGeneralizedTime:
    1486         126 :         space(level);
    1487         126 :         fprintf (headerfile, "time_t %s;\n", name);
    1488         126 :         fprintf(jsonfile, "\"ttype\":\"GeneralizedTime\",\"ctype\":\"time_t\"");
    1489         126 :         break;
    1490         196 :     case TGeneralString:
    1491         196 :         space(level);
    1492         196 :         fprintf (headerfile, "heim_general_string %s;\n", name);
    1493         196 :         fprintf(jsonfile, "\"ttype\":\"GeneralString\",\"ctype\":\"heim_general_string\"");
    1494         196 :         break;
    1495          14 :     case TTeletexString:
    1496          14 :         space(level);
    1497          14 :         fprintf (headerfile, "heim_general_string %s;\n", name);
    1498          14 :         fprintf(jsonfile, "\"ttype\":\"TeletexString\",\"ctype\":\"heim_general_string\"");
    1499          14 :         break;
    1500       18704 :     case TTag:
    1501       37408 :         fprintf(jsonfile, "\"tagclass\":\"%s\",\"tagvalue\":%d,\"tagenv\":\"%s\",\n",
    1502       18704 :                 tagclassnames[t->tag.tagclass], t->tag.tagvalue,
    1503       18704 :                 t->tag.tagenv == TE_EXPLICIT ? "EXPLICIT" : "IMPLICIT");
    1504       18704 :         fprintf(jsonfile, "\"ttype\":\n");
    1505       18704 :         define_type(level, name, basename, t, t->subtype, typedefp, preservep);
    1506       18704 :         break;
    1507         434 :     case TChoice: {
    1508             :         struct decoration deco;
    1509         434 :         ssize_t more_deco = -1;
    1510         434 :         int decorated = 0;
    1511         434 :         int first = 1;
    1512             :         Member *m;
    1513             : 
    1514         434 :         getnewbasename(&newbasename, typedefp || level == 0, basename, name);
    1515             : 
    1516         434 :         space(level);
    1517         434 :         fprintf (headerfile, "struct %s {\n", newbasename);
    1518         434 :         fprintf(jsonfile, "\"ttype\":\"CHOICE\",\"ctype\":\"struct %s\"",
    1519             :                 newbasename);
    1520         434 :         if (preservep) {
    1521          14 :             space(level + 1);
    1522          14 :             fprintf(headerfile, "heim_octet_string _save;\n");
    1523          14 :             fprintf(jsonfile, ",\"preserve\":true");
    1524             :         }
    1525         434 :         space(level + 1);
    1526         434 :         fprintf (headerfile, "enum %s_enum {\n", newbasename);
    1527         434 :         m = have_ellipsis(t);
    1528         434 :         if (m) {
    1529          70 :             space(level + 2);
    1530          70 :             fprintf (headerfile, "%s = 0,\n", m->label);
    1531          70 :             first = 0;
    1532             :         }
    1533         434 :         fprintf(jsonfile, ",\"extensible\":%s", m ? "true" : "false");
    1534        1806 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
    1535        1372 :             space(level + 2);
    1536        1372 :             if (m->ellipsis)
    1537          70 :                 fprintf (headerfile, "/* ... */\n");
    1538             :             else
    1539        1302 :                 fprintf (headerfile, "%s%s%s\n", m->label,
    1540             :                          first ? " = 1" : "",
    1541             :                          last_member_p(m));
    1542        1372 :             first = 0;
    1543             :         }
    1544         434 :         space(level + 1);
    1545         434 :         fprintf (headerfile, "} element;\n");
    1546         434 :         space(level + 1);
    1547         434 :         fprintf (headerfile, "union {\n");
    1548         434 :         fprintf(jsonfile, ",\"members\":[\n");
    1549        1806 :         HEIM_TAILQ_FOREACH(m, t->members, members) {
    1550        1372 :             if (m->ellipsis) {
    1551          70 :                 space(level + 2);
    1552          70 :                 fprintf(headerfile, "heim_octet_string asn1_ellipsis;\n");
    1553        1302 :             } else if (m->optional) {
    1554           0 :                 char *n = NULL;
    1555             : 
    1556           0 :                 if (asprintf (&n, "*%s", m->gen_name) < 0 || n == NULL)
    1557           0 :                     errx(1, "malloc");
    1558           0 :                 fprintf(jsonfile, "{\"optional\":");
    1559           0 :                 define_type(level + 2, n, newbasename, t, m->type, FALSE, FALSE);
    1560           0 :                 fprintf(jsonfile, "}%s", last_member_p(m));
    1561           0 :                 free (n);
    1562             :             } else {
    1563        1302 :                 define_type(level + 2, m->gen_name, newbasename, t, m->type, FALSE, FALSE);
    1564        1302 :                 fprintf(jsonfile, "%s", last_member_p(m));
    1565             :             }
    1566             :         }
    1567         434 :         space(level + 1);
    1568         434 :         fprintf (headerfile, "} u;\n");
    1569         434 :         fprintf(jsonfile, "]");
    1570             : 
    1571         868 :         while (decorate_type(newbasename, &deco, &more_deco)) {
    1572           0 :             decorated++;
    1573           0 :             space(level + 1);
    1574           0 :             fprintf(headerfile, "%s %s%s;\n", deco.field_type,
    1575           0 :                     deco.opt ? "*" : "", deco.field_name);
    1576           0 :             if (deco.first)
    1577           0 :                 fprintf(jsonfile, ",\"decorate\":[");
    1578           0 :             fprintf(jsonfile, "%s{"
    1579             :                     "\"type\":\"%s\",\"name\":\"%s\",\"optional\":%s,"
    1580             :                     "\"external\":%s,\"pointer\":%s,\"void_star\":%s,"
    1581             :                     "\"struct_star\":%s,"
    1582             :                     "\"copy_function\":\"%s\","
    1583             :                     "\"free_function\":\"%s\",\"header_name\":%s%s%s"
    1584             :                     "}",
    1585           0 :                     deco.first ? "" : ",",
    1586             :                     deco.field_type, deco.field_name,
    1587           0 :                     deco.opt ? "true" : "false", deco.ext ? "true" : "false",
    1588           0 :                     deco.ptr ? "true" : "false", deco.void_star ? "true" : "false",
    1589           0 :                     deco.struct_star ? "true" : "false",
    1590           0 :                     deco.copy_function_name ? deco.copy_function_name : "",
    1591           0 :                     deco.free_function_name ? deco.free_function_name : "",
    1592           0 :                     deco.header_name && deco.header_name[0] == '"' ? "" : "\"",
    1593           0 :                     deco.header_name ? deco.header_name : "",
    1594           0 :                     deco.header_name && deco.header_name[0] == '"' ? "" : "\""
    1595             :                     );
    1596             :         }
    1597         434 :         if (decorated)
    1598           0 :             fprintf(jsonfile, "]");
    1599             : 
    1600         434 :         space(level);
    1601         434 :         fprintf (headerfile, "} %s;\n", name);
    1602         434 :         break;
    1603             :     }
    1604          14 :     case TUTCTime:
    1605          14 :         space(level);
    1606          14 :         fprintf (headerfile, "time_t %s;\n", name);
    1607          14 :         fprintf(jsonfile, "\"ttype\":\"UTCTime\",\"ctype\":\"time_t\"");
    1608          14 :         break;
    1609         644 :     case TUTF8String:
    1610         644 :         space(level);
    1611         644 :         fprintf (headerfile, "heim_utf8_string %s;\n", name);
    1612         644 :         fprintf(jsonfile, "\"ttype\":\"UTF8String\",\"ctype\":\"heim_utf8_string\"");
    1613         644 :         break;
    1614          28 :     case TPrintableString:
    1615          28 :         space(level);
    1616          28 :         fprintf (headerfile, "heim_printable_string %s;\n", name);
    1617          28 :         fprintf(jsonfile, "\"ttype\":\"PrintableString\",\"ctype\":\"heim_printable_string\"");
    1618          28 :         break;
    1619         154 :     case TIA5String:
    1620         154 :         space(level);
    1621         154 :         fprintf (headerfile, "heim_ia5_string %s;\n", name);
    1622         154 :         fprintf(jsonfile, "\"ttype\":\"IA5String\",\"ctype\":\"heim_ia5_string\"");
    1623         154 :         break;
    1624          42 :     case TBMPString:
    1625          42 :         space(level);
    1626          42 :         fprintf (headerfile, "heim_bmp_string %s;\n", name);
    1627          42 :         fprintf(jsonfile, "\"ttype\":\"BMPString\",\"ctype\":\"heim_bmp_string\"");
    1628          42 :         break;
    1629          14 :     case TUniversalString:
    1630          14 :         space(level);
    1631          14 :         fprintf (headerfile, "heim_universal_string %s;\n", name);
    1632          14 :         fprintf(jsonfile, "\"ttype\":\"UniversalString\",\"ctype\":\"heim_universal_string\"");
    1633          14 :         break;
    1634          28 :     case TVisibleString:
    1635          28 :         space(level);
    1636          28 :         fprintf (headerfile, "heim_visible_string %s;\n", name);
    1637          28 :         fprintf(jsonfile, "\"ttype\":\"VisibleString\",\"ctype\":\"heim_visible_string\"");
    1638          28 :         break;
    1639         518 :     case TOID :
    1640         518 :         space(level);
    1641         518 :         fprintf (headerfile, "heim_oid %s;\n", name);
    1642         518 :         fprintf(jsonfile, "\"ttype\":\"OBJECT IDENTIFIER\",\"ctype\":\"heim_oid\"");
    1643         518 :         break;
    1644          70 :     case TNull:
    1645          70 :         space(level);
    1646          70 :         fprintf (headerfile, "int %s;\n", name);
    1647          70 :         fprintf(jsonfile, "\"ttype\":\"NULL\",\"ctype\":\"int\"");
    1648          70 :         break;
    1649           0 :     default:
    1650           0 :         abort ();
    1651             :     }
    1652       46438 :     fprintf(jsonfile, "}\n");
    1653       46438 :     free(newbasename);
    1654       46438 : }
    1655             : 
    1656             : static void
    1657       10892 : declare_type(const Symbol *s, Type *t, int typedefp)
    1658             : {
    1659       10892 :     char *newbasename = NULL;
    1660             : 
    1661       10892 :     if (typedefp)
    1662        5698 :         fprintf(headerfile, "typedef ");
    1663             : 
    1664       10892 :     switch (t->type) {
    1665         462 :     case TType:
    1666         462 :         define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, TRUE);
    1667         462 :         if (template_flag)
    1668         462 :             generate_template_type_forward(s->gen_name);
    1669         462 :         emitted_declaration(s);
    1670         462 :         return;
    1671        1148 :     case TInteger:
    1672             :     case TBoolean:
    1673             :     case TOctetString:
    1674             :     case TBitString: 
    1675             :     case TEnumerated: 
    1676             :     case TGeneralizedTime:
    1677             :     case TGeneralString:
    1678             :     case TTeletexString:
    1679             :     case TUTCTime:
    1680             :     case TUTF8String:
    1681             :     case TPrintableString:
    1682             :     case TIA5String:
    1683             :     case TBMPString:
    1684             :     case TUniversalString:
    1685             :     case TVisibleString:
    1686             :     case TOID :
    1687             :     case TNull:
    1688        1148 :         define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE, TRUE);
    1689        1148 :         if (template_flag)
    1690        1050 :             generate_template_type_forward(s->gen_name);
    1691        1148 :         emitted_declaration(s);
    1692        1148 :         emitted_definition(s);
    1693        1148 :         return;
    1694        5194 :     case TTag:
    1695        5194 :         declare_type(s, t->subtype, FALSE);
    1696        5194 :         emitted_declaration(s);
    1697        5194 :         return;
    1698        4088 :     default:
    1699        4088 :         break;
    1700             :     }
    1701             : 
    1702        4088 :     switch (t->type) {
    1703        2898 :     case TSet:
    1704             :     case TSequence: {
    1705             :         struct decoration deco;
    1706        2898 :         ssize_t more_deco = -1;
    1707             : 
    1708        2898 :         getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name);
    1709        2898 :         fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name);
    1710        5838 :         while (decorate_type(newbasename, &deco, &more_deco)) {
    1711          42 :             if (deco.header_name)
    1712           0 :                 fprintf(headerfile, "#include %s\n", deco.header_name);
    1713          42 :             free(deco.field_type);
    1714             :         }
    1715        2898 :         break;
    1716             :     }
    1717         812 :     case TSetOf:
    1718             :     case TSequenceOf:
    1719         812 :         getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name);
    1720         812 :         fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name);
    1721         812 :         break;
    1722         378 :     case TChoice: {
    1723             :         struct decoration deco;
    1724         378 :         ssize_t more_deco = -1;
    1725             : 
    1726         378 :         getnewbasename(&newbasename, TRUE, s->gen_name, s->gen_name);
    1727         378 :         fprintf(headerfile, "struct %s %s;\n", newbasename, s->gen_name);
    1728         756 :         while (decorate_type(newbasename, &deco, &more_deco)) {
    1729           0 :             if (deco.header_name)
    1730           0 :                 fprintf(headerfile, "#include %s\n", deco.header_name);
    1731           0 :             free(deco.field_type);
    1732             :         }
    1733         378 :         break;
    1734             :     }
    1735           0 :     default:
    1736           0 :         abort ();
    1737             :     }
    1738        4088 :     free(newbasename);
    1739        4088 :     emitted_declaration(s);
    1740             : }
    1741             : 
    1742             : static void generate_subtypes_header_helper(const Member *m);
    1743             : static void generate_type_header(const Symbol *);
    1744             : 
    1745             : static void
    1746       18704 : generate_subtypes_header_helper(const Member *m)
    1747             : {
    1748             :     Member *sm;
    1749             :     Symbol *s;
    1750             : 
    1751       18704 :     if (m->ellipsis)
    1752         672 :         return;
    1753       19978 :     if (m->type->symbol && (s = getsym(m->type->symbol->name)) &&
    1754        1946 :         !s->emitted_definition) {
    1755             :         /* A field of some named type; recurse */
    1756         462 :         if (!m->optional && !m->defval)
    1757         420 :             generate_type_header(s);
    1758         462 :         return;
    1759             :     }
    1760       17570 :     if (!m->type->subtype && !m->type->members)
    1761        1484 :         return;
    1762       32158 :     if (m->type->type == TTag &&
    1763       40558 :         m->type->subtype && m->type->subtype->symbol &&
    1764        8414 :         (s = getsym(m->type->subtype->symbol->name))) {
    1765        8414 :         if (!m->optional && !m->defval)
    1766        5558 :             generate_type_header(s);
    1767        8414 :         return;
    1768             :     }
    1769        7672 :     if (m->type->subtype) {
    1770        7658 :         switch (m->type->subtype->type) {
    1771          70 :         case TSet:
    1772             :         case TSequence:
    1773             :         case TChoice:
    1774          70 :             break;
    1775        7588 :         default:
    1776        7588 :             return;
    1777             :         }
    1778             :         /* A field of some anonymous (inlined) structured type */
    1779         378 :         HEIM_TAILQ_FOREACH(sm, m->type->subtype->members, members) {
    1780         308 :             generate_subtypes_header_helper(sm);
    1781             :         }
    1782             :     }
    1783          84 :     if (m->type->members) {
    1784          42 :         HEIM_TAILQ_FOREACH(sm, m->type->members, members) {
    1785          28 :             generate_subtypes_header_helper(sm);
    1786             :         }
    1787             :     }
    1788             : }
    1789             : 
    1790             : static void
    1791       11004 : generate_subtypes_header(const Symbol *s)
    1792             : {
    1793       11004 :     Type *t = s->type;
    1794             :     Member *m;
    1795             : 
    1796             :     /*
    1797             :      * Recurse down structured types to make sure top-level types get
    1798             :      * defined before they are referenced.
    1799             :      *
    1800             :      * We'll take care to skip OPTIONAL member fields of constructed types so
    1801             :      * that we can have circular types like:
    1802             :      *
    1803             :      *  Foo ::= SEQUENCE {
    1804             :      *    bar Bar OPTIONAL
    1805             :      *  }
    1806             :      *
    1807             :      *  Bar ::= SEQUENCE {
    1808             :      *    foo Foo OPTIONAL
    1809             :      *  }
    1810             :      *
    1811             :      * not unlike XDR, which uses `*' to mean "optional", except in XDR it's
    1812             :      * called a "pointer".  With some care we should be able to eventually
    1813             :      * support the silly XDR linked list example:
    1814             :      *
    1815             :      *  ListOfFoo ::= SEQUENCE {
    1816             :      *    someField SomeType,
    1817             :      *    next ListOfFoo OPTIONAL
    1818             :      *  }
    1819             :      *
    1820             :      * Not that anyone needs it -- just use a SEQUENCE OF and be done.
    1821             :      */
    1822             : 
    1823       26838 :     while (t->type == TTag && t->subtype) {
    1824       10388 :         switch (t->subtype->type) {
    1825        4830 :         case TTag:
    1826             :         case TSet:
    1827             :         case TSequence:
    1828             :         case TChoice:
    1829        4830 :             t = t->subtype;
    1830        4830 :             continue;
    1831        5558 :         default:
    1832        5558 :             break;
    1833             :         }
    1834        5558 :         break;
    1835             :     }
    1836             : 
    1837       11004 :     switch (t->type) {
    1838        5558 :     default: return;
    1839         378 :     case TType: {
    1840             :         Symbol *s2;
    1841         378 :         if (t->symbol && (s2 = getsym(t->symbol->name)) != s)
    1842         378 :             generate_type_header(s2);
    1843         378 :         return;
    1844             :     }
    1845        5068 :     case TSet:
    1846             :     case TSequence:
    1847             :     case TChoice:
    1848        5068 :         break;
    1849             :     }
    1850             : 
    1851       23436 :     HEIM_TAILQ_FOREACH(m, t->members, members) {
    1852       18368 :         generate_subtypes_header_helper(m);
    1853             :     }
    1854             : }
    1855             : 
    1856             : static void
    1857       12054 : generate_type_header (const Symbol *s)
    1858             : {
    1859       12054 :     Type *t = s->type;
    1860             : 
    1861       12054 :     if (!s->type)
    1862        1050 :         return;
    1863             : 
    1864             :     /*
    1865             :      * Recurse down the types of member fields of `s' to make sure that
    1866             :      * referenced types have had their definitions emitted already if the
    1867             :      * member fields are not OPTIONAL/DEFAULTed.
    1868             :      */
    1869       11004 :     generate_subtypes_header(s);
    1870       11004 :     fprintf(headerfile, "/*\n");
    1871       11004 :     fprintf(headerfile, "%s ::= ", s->name);
    1872       11004 :     define_asn1 (0, s->type);
    1873       11004 :     fprintf(headerfile, "\n*/\n\n");
    1874             : 
    1875             :     /*
    1876             :      * Emit enums for the outermost tag of this type.  These are needed for
    1877             :      * dealing with IMPLICIT tags so we know what to rewrite the tag to when
    1878             :      * decoding.
    1879             :      *
    1880             :      * See gen_encode.c and gen_decode.c for a complete explanation.  Short
    1881             :      * version: we need to change the prototypes of the length/encode/decode
    1882             :      * functions to take an optional IMPLICIT tag to use instead of the type's
    1883             :      * outermost tag, but for now we hack it, and to do that we need to know
    1884             :      * the type's outermost tag outside the context of the bodies of the codec
    1885             :      * functions we generate for it.  Using an enum means no extra space is
    1886             :      * needed in stripped objects.
    1887             :      */
    1888       11004 :     if (!s->emitted_tag_enums) {
    1889       11648 :         while (t->type == TType && s->type->symbol && s->type->symbol->type) {
    1890         252 :             if (t->subtype)
    1891           0 :                 t = t->subtype;
    1892             :             else
    1893         252 :                 t = s->type->symbol->type;
    1894             :         }
    1895             : 
    1896        5824 :         if (t->type == TType && t->symbol &&
    1897         126 :             strcmp(t->symbol->name, "HEIM_ANY") != 0) {
    1898             :             /*
    1899             :              * This type is ultimately an alias of an imported type, so we don't
    1900             :              * know its outermost tag here.
    1901             :              */
    1902         336 :             fprintf(headerfile,
    1903             :                     "enum { asn1_tag_length_%s = asn1_tag_length_%s,\n"
    1904             :                     "       asn1_tag_class_%s = asn1_tag_class_%s,\n"
    1905             :                     "       asn1_tag_tag_%s = asn1_tag_tag_%s };\n",
    1906         112 :                     s->gen_name, s->type->symbol->gen_name,
    1907         112 :                     s->gen_name, s->type->symbol->gen_name,
    1908         112 :                     s->gen_name, s->type->symbol->gen_name);
    1909         112 :             emitted_tag_enums(s);
    1910        5586 :         } else if (t->type != TType) {
    1911             :             /* This type's outermost tag is known here */
    1912       16716 :             fprintf(headerfile,
    1913             :                     "enum { asn1_tag_length_%s = %lu,\n"
    1914             :                     "       asn1_tag_class_%s = %d,\n"
    1915             :                     "       asn1_tag_tag_%s = %d };\n",
    1916        5572 :                     s->gen_name, (unsigned long)length_tag(s->type->tag.tagvalue),
    1917        5572 :                     s->gen_name, s->type->tag.tagclass,
    1918        5572 :                     s->gen_name, s->type->tag.tagvalue);
    1919        5572 :             emitted_tag_enums(s);
    1920             :         }
    1921             :     }
    1922             : 
    1923       11004 :     if (s->emitted_definition)
    1924        6454 :         return;
    1925             : 
    1926        4550 :     if (is_export(s->name))
    1927        4354 :         fprintf(symsfile, "ASN1_SYM_TYPE(\"%s\", \"%s\", %s)\n",
    1928             :                 s->name, s->gen_name, s->gen_name);
    1929             : 
    1930        4550 :     fprintf(headerfile, "typedef ");
    1931        4550 :     define_type(0, s->gen_name, s->gen_name, NULL, s->type, TRUE,
    1932        4550 :                 preserve_type(s->name) ? TRUE : FALSE);
    1933        4550 :     fprintf(headerfile, "\n");
    1934             : 
    1935        4550 :     emitted_definition(s);
    1936             : }
    1937             : 
    1938             : void
    1939        5698 : generate_type_header_forwards(const Symbol *s)
    1940             : {
    1941        5698 :     declare_type(s, s->type, TRUE);
    1942        5698 :     fprintf(headerfile, "\n");
    1943        5698 :     if (template_flag)
    1944        5026 :         generate_template_type_forward(s->gen_name);
    1945        5698 : }
    1946             : 
    1947             : void
    1948        5698 : generate_type (const Symbol *s)
    1949             : {
    1950             :     FILE *h;
    1951             :     const char * exp;
    1952             : 
    1953        5698 :     if (!one_code_file)
    1954           0 :         generate_header_of_codefile(s->gen_name);
    1955             : 
    1956        5698 :     generate_type_header(s);
    1957             : 
    1958        5698 :     if (template_flag)
    1959        5026 :         generate_template(s);
    1960             : 
    1961        5698 :     if (template_flag == 0 || is_template_compat(s) == 0) {
    1962         672 :         generate_type_encode (s);
    1963         672 :         generate_type_decode (s);
    1964         672 :         generate_type_free (s);
    1965         672 :         generate_type_length (s);
    1966         672 :         generate_type_copy (s);
    1967         672 :         generate_type_print_stub(s);
    1968             :     }
    1969        5698 :     generate_type_seq (s);
    1970        5698 :     generate_glue (s->type, s->gen_name);
    1971             : 
    1972             :     /* generate prototypes */
    1973             : 
    1974        5698 :     if (is_export(s->name)) {
    1975        5362 :         h = headerfile;
    1976        5362 :         exp = "ASN1EXP ";
    1977             :     } else {
    1978         336 :         h = privheaderfile;
    1979         336 :         exp = "";
    1980             :     }
    1981             : 
    1982        5698 :     fprintf (h,
    1983             :              "%sint    ASN1CALL "
    1984             :              "decode_%s(const unsigned char *, size_t, %s *, size_t *);\n",
    1985             :              exp,
    1986             :              s->gen_name, s->gen_name);
    1987        5698 :     fprintf (h,
    1988             :              "%sint    ASN1CALL "
    1989             :              "encode_%s(unsigned char *, size_t, const %s *, size_t *);\n",
    1990             :              exp,
    1991             :              s->gen_name, s->gen_name);
    1992        5698 :     fprintf (h,
    1993             :              "%ssize_t ASN1CALL length_%s(const %s *);\n",
    1994             :              exp,
    1995             :              s->gen_name, s->gen_name);
    1996        5698 :     fprintf (h,
    1997             :              "%sint    ASN1CALL copy_%s  (const %s *, %s *);\n",
    1998             :              exp,
    1999             :              s->gen_name, s->gen_name, s->gen_name);
    2000        5698 :     fprintf (h,
    2001             :              "%svoid   ASN1CALL free_%s  (%s *);\n",
    2002             :              exp,
    2003             :              s->gen_name, s->gen_name);
    2004             : 
    2005        5698 :     fprintf(h,
    2006             :             "%schar * ASN1CALL print_%s (const %s *, int);\n",
    2007             :             exp,
    2008             :             s->gen_name, s->gen_name);
    2009             : 
    2010        5698 :     fprintf(h, "\n\n");
    2011             : 
    2012        5698 :     if (!one_code_file) {
    2013           0 :         fprintf(codefile, "\n\n");
    2014           0 :         close_codefile();
    2015             :     }
    2016        5698 : }

Generated by: LCOV version 1.13