blob: 22cd3671cf6ab4b3f39c9ad8216e90ba8ded27fb [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include "asn1fix_internal.h"
Lev Walkin4efbfb72005-02-25 14:20:30 +00002#include "asn1fix.h"
Lev Walkinf15320b2004-06-03 03:38:44 +00003
4/* Print everything to stderr */
5static void _default_error_logger(int _severity, const char *fmt, ...);
6
7/*
8 * Internal check functions.
9 */
Lev Walkind24c62d2004-09-15 11:47:23 +000010static int asn1f_fix_module__phase_1(arg_t *arg);
11static int asn1f_fix_module__phase_2(arg_t *arg);
Lev Walkinf15320b2004-06-03 03:38:44 +000012static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */
13static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */
Lev Walkin1ef05162004-08-25 00:42:25 +000014static int asn1f_resolve_constraints(arg_t *arg); /* For subtype constraints */
15static int asn1f_check_constraints(arg_t *arg); /* For subtype constraints */
Lev Walkinf593f102005-02-22 07:59:59 +000016static int asn1f_check_duplicate(arg_t *arg);
Lev Walkinf15320b2004-06-03 03:38:44 +000017
Lev Walkinb45e0672004-08-18 05:42:05 +000018arg_t a1f_replace_me_with_proper_interface_arg;
Lev Walkinf15320b2004-06-03 03:38:44 +000019
20/*
21 * Scan every module defined here in search for inconsistences.
22 */
23int
24asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
25 error_logger_f error_logger) {
26 arg_t arg;
27 int fatals = 0;
28 int warnings = 0;
29
30 /*
31 * Check validity of arguments.
32 */
33 if(asn == NULL) {
34 errno = EINVAL;
35 return -1;
36 }
37
38 /*
39 * If errors handler is not specified, default to internal one.
40 */
41 if(error_logger == 0) {
42 error_logger = _default_error_logger;
43 }
44
45 memset(&arg, 0, sizeof(arg));
46 arg.asn = asn;
47 arg.eh = error_logger;
48
49 if(flags & A1F_DEBUG) {
50 arg.debug = arg.eh;
51 arg.debug(-1, "Called %s() with flags %d", __func__, flags);
52 flags &= ~A1F_DEBUG;
53 }
54
Lev Walkin5253da42004-08-20 13:25:56 +000055 /* Allow SIZE() constraint for INTEGER and other types */
56 if(flags & A1F_EXTENDED_SizeConstraint) {
57 arg.flags |= A1F_EXTENDED_SizeConstraint;
58 flags &= ~A1F_EXTENDED_SizeConstraint;
59 if(arg.debug) {
60 arg.debug(-1,
61 "Extended SizeConstraint support enabled");
62 }
63 }
64
Lev Walkinb45e0672004-08-18 05:42:05 +000065 a1f_replace_me_with_proper_interface_arg = arg;
66
Lev Walkinf15320b2004-06-03 03:38:44 +000067 /*
68 * Check that we haven't missed an unknown flag.
69 */
70 if(flags) {
71 errno = EINVAL;
72 return -1;
73 }
74
75 /*
76 * Process each module in the list.
Lev Walkinf593f102005-02-22 07:59:59 +000077 * PHASE I.
Lev Walkinf15320b2004-06-03 03:38:44 +000078 */
79 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
Lev Walkind24c62d2004-09-15 11:47:23 +000080 int ret = asn1f_fix_module__phase_1(&arg);
Lev Walkinf15320b2004-06-03 03:38:44 +000081 /*
82 * These lines are used for illustration purposes.
83 * RET2RVAL() is used everywhere else.
84 */
85 if(ret == -1) fatals++;
86 if(ret == 1) warnings++;
87 }
Lev Walkinf593f102005-02-22 07:59:59 +000088 /* PHASE II. */
Lev Walkind24c62d2004-09-15 11:47:23 +000089 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
90 int ret = asn1f_fix_module__phase_2(&arg);
91 if(ret == -1) fatals++;
92 if(ret == 1) warnings++;
93 }
94
95 memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
Lev Walkinf15320b2004-06-03 03:38:44 +000096
97 /*
98 * Compute a return value.
99 */
100 return fatals?-1:warnings?1:0;
101}
102
103/*
104 * Check the internals of a single module.
105 */
106static int
Lev Walkind24c62d2004-09-15 11:47:23 +0000107asn1f_fix_module__phase_1(arg_t *arg) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000108 asn1p_expr_t *expr;
109 int rvalue = 0;
Lev Walkin1ef05162004-08-25 00:42:25 +0000110 int ret;
Lev Walkinf15320b2004-06-03 03:38:44 +0000111
Lev Walkinb45e0672004-08-18 05:42:05 +0000112 switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000113 case MSF_NOFLAGS:
114 case MSF_EXPLICIT_TAGS:
115 case MSF_IMPLICIT_TAGS:
116 case MSF_AUTOMATIC_TAGS:
117 break;
118 default:
119 FATAL("Module %s defined with ambiguous global tagging mode",
120 arg->mod->Identifier);
121 RET2RVAL(-1, rvalue);
122 }
123
Lev Walkinb45e0672004-08-18 05:42:05 +0000124 switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
125 case MSF_NOFLAGS:
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000126 /*
127 * arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
128 */
Lev Walkinb45e0672004-08-18 05:42:05 +0000129 break;
130 case MSF_unk_INSTRUCTIONS:
131 WARNING("Module %s defined with unrecognized "
132 "encoding reference", arg->mod->Identifier);
133 RET2RVAL(1, rvalue);
134 /* Fall through */
135 case MSF_TAG_INSTRUCTIONS:
136 case MSF_XER_INSTRUCTIONS:
137 break;
138 default:
139 FATAL("Module %s defined with ambiguous encoding reference",
140 arg->mod->Identifier);
141 RET2RVAL(-1, rvalue);
142 }
143
Lev Walkinf15320b2004-06-03 03:38:44 +0000144 /*
145 * Do various non-recursive transformations.
Lev Walkinf15320b2004-06-03 03:38:44 +0000146 */
147 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000148 arg->expr = expr;
149
Lev Walkinf593f102005-02-22 07:59:59 +0000150 /* Check whether this type is a duplicate */
151 ret = asn1f_check_duplicate(arg);
152 RET2RVAL(ret, rvalue);
153
Lev Walkinf15320b2004-06-03 03:38:44 +0000154 if(expr->meta_type == AMT_PARAMTYPE)
155 /* Do not process the parametrized type just yet */
156 continue;
157
158 DEBUG("=== Now processing \"%s\" at line %d ===",
159 expr->Identifier, expr->_lineno);
160 assert(expr->meta_type != AMT_INVALID);
161
162 /*
163 * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
164 */
165 ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
166 RET2RVAL(ret, rvalue);
167
168 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000169 * 2.5.4
170 */
171 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
172 RET2RVAL(ret, rvalue);
173
174 /*
Lev Walkind541c252004-09-05 10:36:22 +0000175 * Fix tagging of top-level types.
176 */
177 ret = asn1f_fix_constr_tag(arg, 1);
178 RET2RVAL(ret, rvalue);
179
180 /*
181 * 2.[234] Process SEQUENCE/SET/CHOICE types.
182 */
183 ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
184 RET2RVAL(ret, rvalue);
185
186 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000187 * 2.5.5
188 */
189 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
190 RET2RVAL(ret, rvalue);
191
192 /*
193 * Resolve references in constraints.
194 */
Lev Walkin1ef05162004-08-25 00:42:25 +0000195 ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
Lev Walkinf15320b2004-06-03 03:38:44 +0000196 RET2RVAL(ret, rvalue);
197
198 /*
199 * 6. INTEGER value processed at 2.5.4.
200 */
201
202 /*
203 * Make sure everybody's behaving well.
204 */
205 assert(arg->expr == expr);
206 }
207
208 /*
209 * 5. Automatic tagging
210 */
211 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000212
213 arg->expr = expr;
214
215 ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
216 RET2RVAL(ret, rvalue);
217
218 assert(arg->expr == expr);
219 }
220
221 /*
222 * 8. fix BIT STRING
223 * 9. fix spaces in cstrings
224 */
225 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000226 arg->expr = expr;
227
228 ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
229 RET2RVAL(ret, rvalue);
230
231 ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
232 RET2RVAL(ret, rvalue);
233
234 assert(arg->expr == expr);
235 }
236
237 /*
238 * ... Check for tags distinctness.
239 */
240 TQ_FOR(expr, &(arg->mod->members), next) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000241 arg->expr = expr;
242
243 ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
244 RET2RVAL(ret, rvalue);
245
246 assert(arg->expr == expr);
247 }
248
Lev Walkind24c62d2004-09-15 11:47:23 +0000249 return rvalue;
250}
251
252static int
253asn1f_fix_module__phase_2(arg_t *arg) {
254 asn1p_expr_t *expr;
255 int rvalue = 0;
256 int ret;
257
Lev Walkin1ef05162004-08-25 00:42:25 +0000258 TQ_FOR(expr, &(arg->mod->members), next) {
259 arg->expr = expr;
260
Lev Walkinf593f102005-02-22 07:59:59 +0000261 if(expr->meta_type == AMT_PARAMTYPE)
Lev Walkind541c252004-09-05 10:36:22 +0000262 /* Do not process the parametrized types here */
263 continue;
264
Lev Walkinb25fa062004-09-29 13:17:06 +0000265 /*
Lev Walkin3645c1c2004-10-31 00:11:50 +0000266 * Dereference DEFAULT values.
267 */
268 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_defaults);
269 RET2RVAL(ret, rvalue);
270
271 /*
Lev Walkinb25fa062004-09-29 13:17:06 +0000272 * Check semantic validity of constraints.
273 */
Lev Walkin1ef05162004-08-25 00:42:25 +0000274 ret = asn1f_recurse_expr(arg, asn1f_check_constraints);
275 RET2RVAL(ret, rvalue);
276
277 assert(arg->expr == expr);
278 }
279
Lev Walkinf15320b2004-06-03 03:38:44 +0000280 return rvalue;
281}
282
Lev Walkinf15320b2004-06-03 03:38:44 +0000283static int
284asn1f_fix_simple(arg_t *arg) {
285 int rvalue = 0;
286 int ret;
287
288 ret = asn1f_fix_enum(arg);
289 RET2RVAL(ret, rvalue);
290
291 ret = asn1f_fix_integer(arg);
292 RET2RVAL(ret, rvalue);
293
294 return rvalue;
295}
296
297static int
298asn1f_fix_constructed(arg_t *arg) {
299 int rvalue = 0;
300 int ret;
301
302 switch(arg->expr->expr_type) {
303 case ASN_CONSTR_SEQUENCE:
304 case ASN_CONSTR_SET:
305 case ASN_CONSTR_CHOICE:
306 break;
307 default:
308 return 0;
309 }
310
311 /* Check identifier distinctness */
312 ret = asn1f_check_unique_expr(arg, NULL);
313 RET2RVAL(ret, rvalue);
314
315 /* Fix extensibility */
316 ret = asn1f_fix_constr_ext(arg);
317 RET2RVAL(ret, rvalue);
318
319 /* Fix tagging */
Lev Walkind541c252004-09-05 10:36:22 +0000320 ret = asn1f_fix_constr_tag(arg, 0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000321 RET2RVAL(ret, rvalue);
322
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000323 /* Import COMPONENTS OF stuff */
324 ret = asn1f_pull_components_of(arg);
325 RET2RVAL(ret, rvalue);
326
Lev Walkinf15320b2004-06-03 03:38:44 +0000327 return rvalue;
328}
329
330static int
Lev Walkin1ef05162004-08-25 00:42:25 +0000331asn1f_resolve_constraints(arg_t *arg) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000332 asn1p_expr_t *top_parent;
Lev Walkin5253da42004-08-20 13:25:56 +0000333 asn1p_expr_type_e etype;
Lev Walkinf15320b2004-06-03 03:38:44 +0000334 int rvalue = 0;
335 int ret;
336
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000337 top_parent = asn1f_find_terminal_type(arg, arg->expr);
Lev Walkin5253da42004-08-20 13:25:56 +0000338 if(top_parent)
339 etype = top_parent->expr_type;
340 else etype = A1TC_INVALID;
341
Lev Walkind541c252004-09-05 10:36:22 +0000342 DEBUG("asn1f_resolve_constraints(%s)", arg->expr->Identifier);
343
Lev Walkin4ec3b4c2004-08-22 03:09:24 +0000344 ret = asn1constraint_resolve(arg, arg->expr->module,
345 arg->expr->constraints, etype, 0);
Lev Walkinb45e0672004-08-18 05:42:05 +0000346 RET2RVAL(ret, rvalue);
Lev Walkinf15320b2004-06-03 03:38:44 +0000347
Lev Walkin1ef05162004-08-25 00:42:25 +0000348 return rvalue;
349}
350
351static int
352asn1f_check_constraints(arg_t *arg) {
353 static enum asn1p_constraint_type_e test_types[] = {
354 ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
355 asn1p_expr_t *top_parent;
356 asn1cnst_range_t *range;
357 asn1p_expr_type_e etype;
358 unsigned int i;
359 int rvalue = 0;
360 int ret;
361
Lev Walkind541c252004-09-05 10:36:22 +0000362 DEBUG("asn1f_check_constraints(%s{%d/%d})",
363 arg->expr->Identifier,
364 arg->expr->meta_type, arg->expr->expr_type);
365
Lev Walkin1ef05162004-08-25 00:42:25 +0000366 top_parent = asn1f_find_terminal_type(arg, arg->expr);
367 if(!top_parent)
368 return 0;
369 etype = top_parent->expr_type;
370
Lev Walkinb45e0672004-08-18 05:42:05 +0000371 ret = asn1constraint_pullup(arg);
372 RET2RVAL(ret, rvalue);
373
Lev Walkin1ef05162004-08-25 00:42:25 +0000374 for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
375 range = asn1constraint_compute_PER_range(
Lev Walkinb9fa7802004-08-25 02:04:39 +0000376 etype,
Lev Walkin1ef05162004-08-25 00:42:25 +0000377 arg->expr->combined_constraints,
Lev Walkinb9fa7802004-08-25 02:04:39 +0000378 test_types[i], 0, 0, 0);
Lev Walkind541c252004-09-05 10:36:22 +0000379 if(!range && errno == EPERM) {
380 FATAL("This error happened for %s (%d) at line %d",
381 arg->expr->Identifier,
382 arg->expr->meta_type,
383 arg->expr->_lineno);
Lev Walkin1ef05162004-08-25 00:42:25 +0000384 return -1;
Lev Walkind541c252004-09-05 10:36:22 +0000385 }
Lev Walkin1ef05162004-08-25 00:42:25 +0000386 asn1constraint_range_free(range);
Lev Walkinb45e0672004-08-18 05:42:05 +0000387 }
Lev Walkin1ef05162004-08-25 00:42:25 +0000388
Lev Walkinf15320b2004-06-03 03:38:44 +0000389 return rvalue;
390}
391
Lev Walkinf593f102005-02-22 07:59:59 +0000392static int
393asn1f_check_duplicate(arg_t *arg) {
394 arg_t tmparg = *arg;
395
396 /*
397 * This is a linear scan in search of a similar type.
398 * The linear scan is just fine for the task, no need to over-optimize.
399 */
400 TQ_FOR(tmparg.mod, &arg->asn->modules, mod_next) {
401 TQ_FOR(tmparg.expr, &(tmparg.mod->members), next) {
402 assert(tmparg.expr->Identifier);
403 assert(arg->expr->Identifier);
404 if(tmparg.expr == arg->expr) break;
405
406 if(strcmp(tmparg.expr->Identifier,
407 arg->expr->Identifier) == 0) {
408 int diff_files = strcmp(arg->mod->source_file_name, tmparg.mod->source_file_name) ? 1 : 0;
409 FATAL("ASN.1 expression \"%s\" at line %d of module %s\n"
410 "clashes with expression \"%s\" at line %d of module %s"
411 "%s%s%s.\n"
412 "Please rename either instance to resolve the conflict",
413 arg->expr->Identifier,
414 arg->expr->_lineno,
415 arg->mod->Identifier,
416 tmparg.expr->Identifier,
417 tmparg.expr->_lineno,
418 tmparg.mod->Identifier,
419 diff_files ? " (" : "",
420 diff_files ? tmparg.mod->source_file_name : "",
421 diff_files ? ")" : ""
422 );
423 return -1;
424 }
425 }
426 if(tmparg.mod == arg->mod) break;
427 }
428
429 return 0;
430}
431
Lev Walkinf15320b2004-06-03 03:38:44 +0000432/*
433 * Print everything to stderr
434 */
435static void
436_default_error_logger(int _severity, const char *fmt, ...) {
437 va_list ap;
438 char *pfx = "";
439
440 switch(_severity) {
441 case -1: pfx = "DEBUG: "; break;
442 case 0: pfx = "WARNING: "; break;
443 case 1: pfx = "FATAL: "; break;
444 }
445
446 fprintf(stderr, "%s", pfx);
447 va_start(ap, fmt);
448 vfprintf(stderr, fmt, ap);
449 va_end(ap);
450 fprintf(stderr, "\n");
451}