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