blob: dd0d5e73b642db2e8e675aeced0d2656b859ca39 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001#include <stdlib.h>
2#include <string.h>
3#include <errno.h>
4#include <stdarg.h>
5
6#include "asn1fix.h"
7#include "asn1fix_internal.h"
8
9/* Print everything to stderr */
10static void _default_error_logger(int _severity, const char *fmt, ...);
11
12/*
13 * Internal check functions.
14 */
15static int asn1f_fix_module(arg_t *arg);
16static int asn1f_fix_simple(arg_t *arg); /* For INTEGER/ENUMERATED */
17static int asn1f_fix_constructed(arg_t *arg); /* For SEQUENCE/SET/CHOICE */
18static int asn1f_fix_constraints(arg_t *arg); /* For subtype constraints */
19
Lev Walkinb45e0672004-08-18 05:42:05 +000020arg_t a1f_replace_me_with_proper_interface_arg;
Lev Walkinf15320b2004-06-03 03:38:44 +000021
22/*
23 * Scan every module defined here in search for inconsistences.
24 */
25int
26asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
27 error_logger_f error_logger) {
28 arg_t arg;
29 int fatals = 0;
30 int warnings = 0;
31
32 /*
33 * Check validity of arguments.
34 */
35 if(asn == NULL) {
36 errno = EINVAL;
37 return -1;
38 }
39
40 /*
41 * If errors handler is not specified, default to internal one.
42 */
43 if(error_logger == 0) {
44 error_logger = _default_error_logger;
45 }
46
47 memset(&arg, 0, sizeof(arg));
48 arg.asn = asn;
49 arg.eh = error_logger;
50
51 if(flags & A1F_DEBUG) {
52 arg.debug = arg.eh;
53 arg.debug(-1, "Called %s() with flags %d", __func__, flags);
54 flags &= ~A1F_DEBUG;
55 }
56
Lev Walkinb45e0672004-08-18 05:42:05 +000057 a1f_replace_me_with_proper_interface_arg = arg;
58
Lev Walkinf15320b2004-06-03 03:38:44 +000059 /*
60 * Check that we haven't missed an unknown flag.
61 */
62 if(flags) {
63 errno = EINVAL;
64 return -1;
65 }
66
67 /*
68 * Process each module in the list.
69 */
70 TQ_FOR(arg.mod, &(asn->modules), mod_next) {
71 int ret = asn1f_fix_module(&arg);
72 /*
73 * These lines are used for illustration purposes.
74 * RET2RVAL() is used everywhere else.
75 */
76 if(ret == -1) fatals++;
77 if(ret == 1) warnings++;
78 }
79
Lev Walkinb45e0672004-08-18 05:42:05 +000080 memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
81
Lev Walkinf15320b2004-06-03 03:38:44 +000082 /*
83 * Compute a return value.
84 */
85 return fatals?-1:warnings?1:0;
86}
87
88/*
89 * Check the internals of a single module.
90 */
91static int
92asn1f_fix_module(arg_t *arg) {
93 asn1p_expr_t *expr;
94 int rvalue = 0;
95
Lev Walkinb45e0672004-08-18 05:42:05 +000096 switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
Lev Walkinf15320b2004-06-03 03:38:44 +000097 case MSF_NOFLAGS:
98 case MSF_EXPLICIT_TAGS:
99 case MSF_IMPLICIT_TAGS:
100 case MSF_AUTOMATIC_TAGS:
101 break;
102 default:
103 FATAL("Module %s defined with ambiguous global tagging mode",
104 arg->mod->Identifier);
105 RET2RVAL(-1, rvalue);
106 }
107
Lev Walkinb45e0672004-08-18 05:42:05 +0000108 switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
109 case MSF_NOFLAGS:
110 //arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
111 break;
112 case MSF_unk_INSTRUCTIONS:
113 WARNING("Module %s defined with unrecognized "
114 "encoding reference", arg->mod->Identifier);
115 RET2RVAL(1, rvalue);
116 /* Fall through */
117 case MSF_TAG_INSTRUCTIONS:
118 case MSF_XER_INSTRUCTIONS:
119 break;
120 default:
121 FATAL("Module %s defined with ambiguous encoding reference",
122 arg->mod->Identifier);
123 RET2RVAL(-1, rvalue);
124 }
125
Lev Walkinf15320b2004-06-03 03:38:44 +0000126 /*
127 * Do various non-recursive transformations.
128 * Order is not important.
129 */
130 TQ_FOR(expr, &(arg->mod->members), next) {
131 int ret;
132 arg->expr = expr;
133
134 if(expr->meta_type == AMT_PARAMTYPE)
135 /* Do not process the parametrized type just yet */
136 continue;
137
138 DEBUG("=== Now processing \"%s\" at line %d ===",
139 expr->Identifier, expr->_lineno);
140 assert(expr->meta_type != AMT_INVALID);
141
142 /*
143 * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
144 */
145 ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
146 RET2RVAL(ret, rvalue);
147
148 /*
149 * 2.[234] Process SEQUENCE/SET/CHOICE types.
150 */
151 ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
152 RET2RVAL(ret, rvalue);
153
154 /*
155 * 2.5.4
156 */
157 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
158 RET2RVAL(ret, rvalue);
159
160 /*
161 * 2.5.5
162 */
163 ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
164 RET2RVAL(ret, rvalue);
165
166 /*
167 * Resolve references in constraints.
168 */
169 ret = asn1f_recurse_expr(arg, asn1f_fix_constraints);
170 RET2RVAL(ret, rvalue);
171
172 /*
173 * 6. INTEGER value processed at 2.5.4.
174 */
175
176 /*
177 * Make sure everybody's behaving well.
178 */
179 assert(arg->expr == expr);
180 }
181
182 /*
183 * 5. Automatic tagging
184 */
185 TQ_FOR(expr, &(arg->mod->members), next) {
186 int ret;
187
188 arg->expr = expr;
189
190 ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
191 RET2RVAL(ret, rvalue);
192
193 assert(arg->expr == expr);
194 }
195
196 /*
197 * 8. fix BIT STRING
198 * 9. fix spaces in cstrings
199 */
200 TQ_FOR(expr, &(arg->mod->members), next) {
201 int ret;
202 arg->expr = expr;
203
204 ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
205 RET2RVAL(ret, rvalue);
206
207 ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
208 RET2RVAL(ret, rvalue);
209
210 assert(arg->expr == expr);
211 }
212
213 /*
214 * ... Check for tags distinctness.
215 */
216 TQ_FOR(expr, &(arg->mod->members), next) {
217 int ret;
218 arg->expr = expr;
219
220 ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
221 RET2RVAL(ret, rvalue);
222
223 assert(arg->expr == expr);
224 }
225
226 return rvalue;
227}
228
229
230static int
231asn1f_fix_simple(arg_t *arg) {
232 int rvalue = 0;
233 int ret;
234
235 ret = asn1f_fix_enum(arg);
236 RET2RVAL(ret, rvalue);
237
238 ret = asn1f_fix_integer(arg);
239 RET2RVAL(ret, rvalue);
240
241 return rvalue;
242}
243
244static int
245asn1f_fix_constructed(arg_t *arg) {
246 int rvalue = 0;
247 int ret;
248
249 switch(arg->expr->expr_type) {
250 case ASN_CONSTR_SEQUENCE:
251 case ASN_CONSTR_SET:
252 case ASN_CONSTR_CHOICE:
253 break;
254 default:
255 return 0;
256 }
257
258 /* Check identifier distinctness */
259 ret = asn1f_check_unique_expr(arg, NULL);
260 RET2RVAL(ret, rvalue);
261
262 /* Fix extensibility */
263 ret = asn1f_fix_constr_ext(arg);
264 RET2RVAL(ret, rvalue);
265
266 /* Fix tagging */
267 ret = asn1f_fix_constr_tag(arg);
268 RET2RVAL(ret, rvalue);
269
270 return rvalue;
271}
272
273static int
Lev Walkinf15320b2004-06-03 03:38:44 +0000274asn1f_fix_constraints(arg_t *arg) {
Lev Walkinb45e0672004-08-18 05:42:05 +0000275 asn1p_expr_t *top_parent;
Lev Walkinf15320b2004-06-03 03:38:44 +0000276 int rvalue = 0;
277 int ret;
278
Lev Walkinb45e0672004-08-18 05:42:05 +0000279 ret = asn1constraint_resolve(arg, arg->expr->constraints);
280 RET2RVAL(ret, rvalue);
Lev Walkinf15320b2004-06-03 03:38:44 +0000281
Lev Walkinb45e0672004-08-18 05:42:05 +0000282 ret = asn1constraint_pullup(arg);
283 RET2RVAL(ret, rvalue);
284
285 top_parent = asn1f_find_terminal_type(arg, arg->expr, NULL);
286 if(top_parent) {
287 static enum asn1p_constraint_type_e test_types[] = {
288 ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
289 unsigned int i;
290 for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
291 asn1cnst_range_t *range;
292 range = asn1constraint_compute_PER_range(
293 top_parent->expr_type,
294 arg->expr->combined_constraints,
295 test_types[i], 0, 0);
296 if(!range && errno == EPERM)
297 return -1;
298 asn1constraint_range_free(range);
299 }
300 }
301
Lev Walkinf15320b2004-06-03 03:38:44 +0000302 return rvalue;
303}
304
305/*
306 * Print everything to stderr
307 */
308static void
309_default_error_logger(int _severity, const char *fmt, ...) {
310 va_list ap;
311 char *pfx = "";
312
313 switch(_severity) {
314 case -1: pfx = "DEBUG: "; break;
315 case 0: pfx = "WARNING: "; break;
316 case 1: pfx = "FATAL: "; break;
317 }
318
319 fprintf(stderr, "%s", pfx);
320 va_start(ap, fmt);
321 vfprintf(stderr, fmt, ap);
322 va_end(ap);
323 fprintf(stderr, "\n");
324}