blob: e2d280cef3196d398f1a27f900b6efa1248bedc4 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
5#include <assert.h>
6
7#include "asn1parser.h"
8
Lev Walkina00d6b32006-03-21 03:40:38 +00009static asn1p_expr_t *asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*)(asn1p_expr_t *, void *), void *);
10static asn1p_value_t *value_resolver(asn1p_value_t *, void *arg);
11
Lev Walkinea6635b2017-08-06 23:23:04 -070012void
13asn1p_expr_set_source(asn1p_expr_t *expr, asn1p_module_t *module, int lineno) {
14 if(expr) {
15 expr->module = module;
16 expr->_lineno = lineno;
17 asn1p_ref_set_source(expr->reference, module, lineno);
18 asn1p_value_set_source(expr->value, module, lineno);
19 asn1p_constraint_set_source(expr->constraints, module, lineno);
20 asn1p_constraint_set_source(expr->combined_constraints, module, lineno);
21 asn1p_expr_set_source(expr->rhs_pspecs, module, lineno);
22
23 asn1p_expr_t *memb;
24
25 TQ_FOR(memb, &(expr->members), next) {
26 asn1p_expr_set_source(memb, module, lineno);
27 }
28 }
29}
30
31int
32asn1p_expr_compare(const asn1p_expr_t *a, const asn1p_expr_t *b) {
Bi-Ruei, Chiudcc822a2017-10-19 01:06:57 +080033 if((a && !b) || (!a && b)) {
34 return -1;
35 }
36
Lev Walkinea6635b2017-08-06 23:23:04 -070037 if(a->meta_type != b->meta_type || a->expr_type != b->expr_type) {
38 return -1;
39 }
40
41 if((!a->Identifier && b->Identifier) || (a->Identifier && !b->Identifier)) {
42 return -1;
43 } else if(a->Identifier && strcmp(a->Identifier, b->Identifier)) {
44 return -1;
45 }
46
47 if((!a->reference && b->reference) || (a->reference && !b->reference)) {
48 return -1;
49 } else if(a->reference
50 && asn1p_ref_compare(a->reference, b->reference) != 0) {
51 return -1;
52 }
53
54 if((!a->value && b->value) || (a->value && !b->value)) {
55 return -1;
56 } else if(a->value && asn1p_value_compare(a->value, b->value)) {
57 return -1;
58 }
59
60 if((a->tag.tag_class != b->tag.tag_class)
61 || (a->tag.tag_mode != b->tag.tag_mode)
62 || (a->tag.tag_value != b->tag.tag_value)) {
63 return -1;
64 }
65
66 if((a->marker.flags != b->marker.flags)
67 || (a->marker.default_value && !b->marker.default_value)
68 || (!a->marker.default_value && b->marker.default_value)
69 || (a->marker.default_value
70 && asn1p_value_compare(a->marker.default_value,
71 b->marker.default_value))) {
72 return -1;
73 }
74
75 if(a->unique != b->unique) {
76 return -1;
77 }
78
79 const asn1p_expr_t *am = TQ_FIRST(&a->members);
80 const asn1p_expr_t *bm = TQ_FIRST(&b->members);
81 for(; am || bm; am = TQ_NEXT(am, next), bm = TQ_NEXT(bm, next)) {
82 if((am && !bm) || (!am && bm)) {
83 return -1;
84 } else if(asn1p_expr_compare(am, bm) != 0) {
85 return -1;
86 }
87 }
88
89 return 0;
90}
91
Lev Walkinf15320b2004-06-03 03:38:44 +000092/*
93 * Construct a new empty types collection.
94 */
95asn1p_expr_t *
Lev Walkina9532f42006-09-17 04:52:50 +000096asn1p_expr_new(int _lineno, asn1p_module_t *mod) {
Lev Walkinf15320b2004-06-03 03:38:44 +000097 asn1p_expr_t *expr;
98
99 expr = calloc(1, sizeof *expr);
100 if(expr) {
101 TQ_INIT(&(expr->members));
Lev Walkina00d6b32006-03-21 03:40:38 +0000102 expr->spec_index = -1;
Lev Walkina9532f42006-09-17 04:52:50 +0000103 expr->module = mod;
Lev Walkinf15320b2004-06-03 03:38:44 +0000104 expr->_lineno = _lineno;
Bi-Ruei, Chiub9adfc52016-11-09 00:17:25 +0800105 expr->ref_cnt = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000106 }
107
108 return expr;
109}
110
111asn1p_expr_t *
Lev Walkin070a52d2004-08-22 03:19:54 +0000112asn1p_expr_clone(asn1p_expr_t *expr, int skip_extensions) {
Lev Walkina00d6b32006-03-21 03:40:38 +0000113 return asn1p_expr_clone_impl(expr, skip_extensions, 0, 0);
114}
115
116asn1p_expr_t *
117asn1p_expr_clone_with_resolver(asn1p_expr_t *expr, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) {
118 return asn1p_expr_clone_impl(expr, 0, r, rarg);
119}
120
121static asn1p_expr_t *
122asn1p_expr_clone_impl(asn1p_expr_t *expr, int skip_extensions, asn1p_expr_t *(*r)(asn1p_expr_t *, void *), void *rarg) {
123 asn1p_value_t *(*vr)(asn1p_value_t *, void *) = 0;
124 asn1p_expr_t *clone = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000125 asn1p_expr_t *tcmemb; /* Child of tc */
Lev Walkin070a52d2004-08-22 03:19:54 +0000126 int hit_ext = 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000127
Lev Walkinf15320b2004-06-03 03:38:44 +0000128#define CLCOPY(field) do { clone->field = expr->field; } while(0)
Lev Walkina00d6b32006-03-21 03:40:38 +0000129#define CLCLONE(field, func) do { if(expr->field) { \
130 clone->field = func(expr->field); \
131 if(clone->field == NULL) { \
132 asn1p_expr_free(clone); \
133 return NULL; \
134 } \
Lev Walkinf15320b2004-06-03 03:38:44 +0000135 } } while(0)
Lev Walkina00d6b32006-03-21 03:40:38 +0000136#define CLVRCLONE(field, func) do { if(expr->field) { \
137 clone->field = func(expr->field, vr, rarg); \
138 if(clone->field == NULL) { \
139 asn1p_expr_free(clone); \
140 return NULL; \
141 } \
142 } } while(0)
143
144 if(r) {
145 vr = value_resolver;
146 clone = r(expr, rarg);
147 if(clone) {
148 /* Merge constraints */
149 if(expr->constraints) {
150 asn1p_constraint_t *tmpct = asn1p_constraint_clone_with_resolver(expr->constraints, vr, rarg);
151 if(clone->constraints) {
152 if(asn1p_constraint_insert(clone->constraints, tmpct)) {
153 asn1p_constraint_free(tmpct);
154 asn1p_expr_free(clone);
155 return NULL;
156 }
157 } else {
158 clone->constraints = tmpct;
159 }
Lev Walkin0c0bca62006-03-21 04:48:15 +0000160 assert(expr->combined_constraints == 0);
Lev Walkina00d6b32006-03-21 03:40:38 +0000161 }
Lev Walkin0c0bca62006-03-21 04:48:15 +0000162 /* Merge defaults */
163 CLCOPY(marker.flags);
164 CLVRCLONE(marker.default_value,
165 asn1p_value_clone_with_resolver);
166 if(clone->tag.tag_class == TC_NOCLASS) {
167 CLCOPY(tag);
168 } else if(expr->tag.tag_class != TC_NOCLASS) {
169 fprintf(stderr, "asn1c does not support "
170 "nested tagging in parameterization, "
171 "necessary at line %d\n",
172 expr->_lineno);
173 asn1p_expr_free(clone);
174 return NULL;
175 }
Lev Walkina00d6b32006-03-21 03:40:38 +0000176 return clone;
177 } else if(errno != ESRCH) {
178 return NULL; /* Hard error */
179 }
180 }
Lev Walkina9532f42006-09-17 04:52:50 +0000181 if(!clone) clone = asn1p_expr_new(expr->_lineno, expr->module);
Lev Walkina00d6b32006-03-21 03:40:38 +0000182 if(!clone) return NULL;
Lev Walkinf15320b2004-06-03 03:38:44 +0000183
184 /*
185 * Copy simple fields.
186 */
187 CLCOPY(meta_type);
188 CLCOPY(expr_type);
189 CLCOPY(tag);
Lev Walkin5498f2d2004-09-15 11:59:30 +0000190 CLCOPY(marker.flags); /* OPTIONAL/DEFAULT */
Lev Walkinf15320b2004-06-03 03:38:44 +0000191 CLCOPY(_mark);
Bi-Ruei, Chiudcc822a2017-10-19 01:06:57 +0800192 CLCOPY(parent_expr);
193 CLCOPY(_type_unique_index);
Lev Walkinf15320b2004-06-03 03:38:44 +0000194
195 clone->data = 0; /* Do not clone this */
196 clone->data_free = 0; /* Do not clone this */
197
198 /*
199 * Clone complex fields.
200 */
201 CLCLONE(Identifier, strdup);
202 CLCLONE(reference, asn1p_ref_clone);
Lev Walkina00d6b32006-03-21 03:40:38 +0000203 CLVRCLONE(constraints, asn1p_constraint_clone_with_resolver);
204 CLVRCLONE(combined_constraints, asn1p_constraint_clone_with_resolver);
205 CLCLONE(lhs_params, asn1p_paramlist_clone);
206 CLVRCLONE(value, asn1p_value_clone_with_resolver);
Lev Walkin0c0bca62006-03-21 04:48:15 +0000207 CLVRCLONE(marker.default_value, asn1p_value_clone_with_resolver);
Lev Walkinf15320b2004-06-03 03:38:44 +0000208 CLCLONE(with_syntax, asn1p_wsyntx_clone);
209
210 /*
211 * Copy all the children of this expr.
212 */
213 TQ_FOR(tcmemb, &(expr->members), next) {
Lev Walkin070a52d2004-08-22 03:19:54 +0000214 asn1p_expr_t *cmemb;
215
216 if(skip_extensions
217 && tcmemb->expr_type == A1TC_EXTENSIBLE) {
218 hit_ext++; /* Even if hit_ext wraps around, we're OK. */
219 continue;
220 }
221 if(hit_ext == 1) continue; /* Skip between ...'s */
222
Lev Walkina00d6b32006-03-21 03:40:38 +0000223 cmemb = asn1p_expr_clone_impl(tcmemb, skip_extensions, r, rarg);
Lev Walkinf15320b2004-06-03 03:38:44 +0000224 if(cmemb == NULL) {
225 asn1p_expr_free(clone);
226 return NULL;
227 }
Lev Walkin1004aa92004-09-08 00:28:11 +0000228 asn1p_expr_add(clone, cmemb);
Lev Walkinf15320b2004-06-03 03:38:44 +0000229 }
230
231 return clone;
232}
233
Lev Walkina00d6b32006-03-21 03:40:38 +0000234
235static asn1p_value_t *
236value_resolver(asn1p_value_t *value, void *rarg) {
237 asn1p_value_t *cval;
238 asn1p_expr_t *tmpexpr;
239 asn1p_expr_t *target;
240 asn1p_ref_t *ref;
241 struct {
242 asn1p_expr_t *(*expr_resolve)(asn1p_expr_t *, void *arg);
243 } *varg = rarg;
244
245 if(!value || value->type != ATV_REFERENCED) {
246 errno = ESRCH;
247 return NULL;
248 }
249
250 ref = value->value.reference;
Lev Walkina9532f42006-09-17 04:52:50 +0000251 tmpexpr = asn1p_expr_new(ref->_lineno, 0);
Lev Walkina00d6b32006-03-21 03:40:38 +0000252 tmpexpr->meta_type = AMT_TYPEREF;
253 tmpexpr->expr_type = A1TC_REFERENCE;
254 tmpexpr->reference = ref;
255 target = varg->expr_resolve(tmpexpr, rarg);
256 tmpexpr->reference = 0;
257 asn1p_expr_free(tmpexpr);
258
259 if(!target)
260 return NULL; /* errno's are compatible */
261
Lev Walkin5045dfa2006-03-21 09:41:28 +0000262 if(target->meta_type == AMT_VALUE) {
263 if(!target->value) {
264 fprintf(stderr,
265 "FATAL: Parameterization did not resolve "
266 "value reference at line %d\n", ref->_lineno);
267 asn1p_expr_free(target);
268 errno = EPERM;
269 return NULL;
270 }
271 cval = asn1p_value_clone(target->value);
272 } else if(target->meta_type == AMT_VALUESET) {
273 if(!target->constraints) {
274 fprintf(stderr,
275 "FATAL: Parameterization did not resolve "
276 "value set reference at line %d\n", ref->_lineno);
277 asn1p_expr_free(target);
278 errno = EPERM;
279 return NULL;
280 }
281 cval = asn1p_value_fromconstr(target->constraints, 1);
282 } else {
Lev Walkina00d6b32006-03-21 03:40:38 +0000283 errno = EPERM;
Lev Walkin5045dfa2006-03-21 09:41:28 +0000284 cval = NULL;
Lev Walkina00d6b32006-03-21 03:40:38 +0000285 }
286
Lev Walkina00d6b32006-03-21 03:40:38 +0000287 asn1p_expr_free(target);
288 return cval;
289}
290
Lev Walkinf15320b2004-06-03 03:38:44 +0000291/*
Lev Walkin1004aa92004-09-08 00:28:11 +0000292 * Add expression as a member of another.
293 */
294void
295asn1p_expr_add(asn1p_expr_t *to, asn1p_expr_t *what) {
296 TQ_ADD(&(to->members), what, next);
297 what->parent_expr = to;
298}
299
Lev Walkin0e90aa02013-03-19 16:17:13 -0700300/*
301 * Add inner expressions as members of another.
302 */
303void
304asn1p_expr_add_many(asn1p_expr_t *to, asn1p_expr_t *from_what) {
305 asn1p_expr_t *expr;
306 TQ_FOR(expr, &(from_what->members), next) {
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800307 expr->parent_expr = to;
308 }
Lev Walkin0e90aa02013-03-19 16:17:13 -0700309 TQ_CONCAT(&(to->members), &(from_what->members), next);
310}
311
Bi-Ruei, Chiudcc822a2017-10-19 01:06:57 +0800312/*
313 * Lookup a child by its name.
314 */
315asn1p_expr_t *
316asn1p_lookup_child(asn1p_expr_t *tc, const char *name) {
317 asn1p_expr_t *child_tc;
318
319 TQ_FOR(child_tc, &(tc->members), next) {
320 if(child_tc->Identifier
321 && strcmp(child_tc->Identifier, name) == 0) {
322 return child_tc;
323 }
324 }
325
326 errno = ESRCH;
327 return NULL;
328}
Lev Walkin1004aa92004-09-08 00:28:11 +0000329
330/*
Lev Walkinf15320b2004-06-03 03:38:44 +0000331 * Destruct the types collection structure.
332 */
333void
334asn1p_expr_free(asn1p_expr_t *expr) {
335 if(expr) {
336 asn1p_expr_t *tm;
337
Bi-Ruei, Chiub9adfc52016-11-09 00:17:25 +0800338 if (expr->ref_cnt) {
339 /* Decrease reference count only */
340 expr->ref_cnt--;
341 return;
342 }
343
Lev Walkin1004aa92004-09-08 00:28:11 +0000344 /* Remove all children */
345 while((tm = TQ_REMOVE(&(expr->members), next))) {
346 if(tm->parent_expr != expr)
347 printf("<%s:%p !-> %s:%p>\n",
348 tm->Identifier, tm->parent_expr,
349 expr->Identifier, expr);
350 assert(tm->parent_expr == expr);
351 asn1p_expr_free(tm);
352 }
353
Lev Walkind8b83642016-03-14 02:00:27 -0700354 free(expr->Identifier);
Markus Elfring671eb9a2016-03-14 17:07:26 +0100355 asn1p_ref_free(expr->reference);
356 asn1p_constraint_free(expr->constraints);
357 asn1p_constraint_free(expr->combined_constraints);
358 asn1p_paramlist_free(expr->lhs_params);
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800359 asn1p_expr_free(expr->rhs_pspecs);
Markus Elfring671eb9a2016-03-14 17:07:26 +0100360 asn1p_value_free(expr->value);
361 asn1p_value_free(expr->marker.default_value);
362 asn1p_wsyntx_free(expr->with_syntax);
Bi-Ruei, Chiu3dcf05b2017-05-04 21:45:05 +0800363 if(expr->specializations.pspec) {
364 int pspec;
365 for(pspec = 0; pspec < expr->specializations.pspecs_count; pspec++) {
366 asn1p_expr_free(expr->specializations.pspec[pspec].rhs_pspecs);
367 asn1p_expr_free(expr->specializations.pspec[pspec].my_clone);
368 }
369 free(expr->specializations.pspec);
370 }
Lev Walkin4dcf8362017-08-07 20:10:05 -0700371 asn1p_ioc_table_free(expr->ioc_table);
Lev Walkinf15320b2004-06-03 03:38:44 +0000372
Lev Walkinf15320b2004-06-03 03:38:44 +0000373 if(expr->data && expr->data_free)
374 expr->data_free(expr->data);
375
376 memset(expr, 0, sizeof(*expr));
377 free(expr);
378 }
379}
380
Lev Walkin71160962005-06-02 05:21:53 +0000381
Lev Walkina45518f2017-08-23 07:22:52 -0700382const char *asn1p_tag2string(const struct asn1p_type_tag_s *tag, char *buf) {
Lev Walkin8f294e02005-06-06 08:28:58 +0000383 static char buf_stat[TAG2STRING_BUFFER_SIZE];
Lev Walkin71160962005-06-02 05:21:53 +0000384 char *start;
385 char *end;
386
387 if(!buf) buf = buf_stat;
388 start = buf;
389 end = buf + TAG2STRING_BUFFER_SIZE;
390
391 if(tag->tag_class == TC_NOCLASS) {
392 *buf = 0;
393 return buf;
394 }
395
396 strcpy(buf, "[");
397 switch(tag->tag_class) {
398 case TC_NOCLASS:
399 assert(tag->tag_class != TC_NOCLASS);
400 break;
401 case TC_UNIVERSAL: strcat(buf, "UNIVERSAL "); break;
402 case TC_PRIVATE: strcat(buf, "PRIVATE "); break;
403 case TC_APPLICATION: strcat(buf, "APPLICATION "); break;
404 case TC_CONTEXT_SPECIFIC:
405 break;
406 }
407 buf += snprintf(buf + strlen(buf), end - buf,
Lev Walkinda997b12017-08-04 01:38:41 -0700408 "%s]", asn1p_itoa(tag->tag_value));
Lev Walkin8f294e02005-06-06 08:28:58 +0000409 assert((unsigned int)(buf - end) > sizeof(" IMPLICIT "));
Lev Walkin71160962005-06-02 05:21:53 +0000410
411 switch(tag->tag_mode) {
412 case TM_DEFAULT: break;
413 case TM_IMPLICIT: strcat(buf, " IMPLICIT"); break;
414 case TM_EXPLICIT: strcat(buf, " EXPLICIT"); break;
415 }
416
417 return start;
418}
Lev Walkinc0e03b92017-08-22 01:48:23 -0700419
420asn1p_paramlist_t *
421asn1p_get_namespace(asn1p_expr_t *expr) {
422 if(!expr) return NULL;
423 if(expr->lhs_params) return expr->lhs_params;
424 return asn1p_get_namespace(expr->parent_expr);
425}