1 #undef	NDEBUG
2 #include "asn1fix_internal.h"
3 
4 #ifdef	_WIN32
5 #include <io.h>
6 #include <direct.h>
7 #define	chdir _chdir
8 #else
9 #include <dirent.h>
10 #include <sysexits.h>
11 #endif
12 #include <errno.h>
13 
14 #include "asn1fix.h"
15 
16 #ifndef TOP_SRCDIR
17 #define TOP_SRCDIR_S    ".."
18 #else
19 #define STRINGIFY_MACRO2(x)  #x
20 #define STRINGIFY_MACRO(x)  STRINGIFY_MACRO2(x)
21 #define TOP_SRCDIR_S    STRINGIFY_MACRO(TOP_SRCDIR)
22 #endif
23 
24 static int check(const char *fname,
25 	enum asn1p_flags parser_flags,
26 	enum asn1f_flags fixer_flags);
27 static int post_fix_check(asn1p_t *asn);
28 static int post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *expr);
29 
30 int
main(int ac,char ** av)31 main(int ac, char **av) {
32 #ifdef	_WIN32
33 	intptr_t dir;
34 	struct _finddata_t c_file;
35 #else
36 	struct dirent *dp;
37 	DIR *dir;
38 #endif
39 	int failed = 0;
40 	int completed = 0;
41 	enum asn1p_flags parser_flags = A1P_NOFLAGS;
42 	enum asn1f_flags fixer_flags  = A1F_NOFLAGS;
43 	const char *filename;
44 	size_t len;
45 	int ret;
46 
47 	/*
48 	 * Just in case when one decides that some flags better be
49 	 * enabled during `ASN1_FIXER_FLAGS=1 make check` or some
50 	 * similar usage.
51 	 */
52 	if(getenv("ASN1_PARSER_FLAGS"))
53 		parser_flags = atoi(getenv("ASN1_PARSER_FLAGS"));
54 	if(getenv("ASN1_FIXER_FLAGS"))
55 		fixer_flags = atoi(getenv("ASN1_FIXER_FLAGS"));
56 
57 	/*
58 	 * Go into a directory with tests.
59 	 */
60 	if(ac <= 1) {
61 		fprintf(stderr, "Testing in ./tests...\n");
62 		ret = chdir("../tests");
63 		assert(ret == 0);
64 #ifdef	_WIN32
65 		dir = _findfirst("*.asn1", &c_file);
66 		assert(dir != -1L);
67 #else
68 		dir = opendir(".");
69 		assert(dir);
70 #endif	/* _WIN32 */
71 	} else {
72 		dir = 0;
73 	}
74 
75 	/*
76 	 * Scan every *.asn1 file and try to parse and fix it.
77 	 */
78 	if(dir) {
79 #ifdef	_WIN32
80 		do {
81 			filename = c_file.name;
82 #else
83 		while((dp = readdir(dir))) {
84 			filename = dp->d_name;
85 #endif	/* _WIN32 */
86 			len = strlen(filename);
87 			if(len <= 5 || strcmp(filename + len - 5, ".asn1"))
88 				continue;
89 			ret = check(filename, parser_flags, fixer_flags);
90 			if(ret) {
91 				fprintf(stderr, "FAILED: %s\n",
92 					filename);
93 				failed++;
94 			}
95 			completed++;
96 #ifdef	_WIN32
97 		} while(_findnext(dir, &c_file) == 0);
98 		_findclose(dir);
99 #else
100 		}
101 		closedir(dir);
102 #endif	/* _WIN32 */
103 
104 
105 		fprintf(stderr,
106 			"Tests COMPLETED: %d\n"
107 			"Tests FAILED:    %d\n"
108 			,
109 			completed, failed
110 		);
111 	} else {
112 		int i;
113 		for(i = 1; i < ac; i++) {
114 			ret = check(av[i], parser_flags, fixer_flags);
115 			if(ret) {
116 				fprintf(stderr, "FAILED: %s\n", av[i]);
117 				failed++;
118 			}
119 			completed++;
120 		}
121 	}
122 
123 	if(completed == 0) {
124 		fprintf(stderr, "No tests defined?!\n");
125 		exit(EX_NOINPUT);
126 	}
127 
128 	if(failed)
129 		exit(EX_DATAERR);
130 	return 0;
131 }
132 
133 static int
check(const char * fname,enum asn1p_flags parser_flags,enum asn1f_flags fixer_flags)134 check(const char *fname,
135 		enum asn1p_flags parser_flags,
136 		enum asn1f_flags fixer_flags) {
137 	asn1p_t *asn;
138 	int expected_parseable;		/* Is it expected to be parseable? */
139 	int expected_fix_code;		/* What code a fixer must return */
140 	int r_value = 0;
141 
142 	/*
143 	 * Figure out how the processing should go by inferring
144 	 * expectations from the file name.
145 	 */
146 	if(strstr(fname, "-OK.")) {
147 		expected_parseable = 1;
148 		expected_fix_code  = 0;
149 	} else if(strstr(fname, "-NP.")) {
150 		expected_parseable = 0;
151 		expected_fix_code  = 123;	/* Does not matter */
152 	} else if(strstr(fname, "-SE.")) {
153 		expected_parseable = 1;
154 		expected_fix_code  = -1;	/* Semantically incorrect */
155 	} else if(strstr(fname, "-SW.")) {
156 		expected_parseable = 1;
157 		expected_fix_code  = 1;	/* Semantically suspicious */
158 	} else {
159 		fprintf(stderr, "%s: Invalid file name format\n", fname);
160 		return -1;
161 	}
162 
163 	/* Flag modifiers */
164 	if(strstr(fname, "-blessSize-"))
165 		fixer_flags |= A1F_EXTENDED_SizeConstraint;
166 
167 	fprintf(stderr, "[=> %s]\n", fname);
168 
169 	/*
170 	 * Perform low-level parsing.
171 	 */
172 	if(!expected_parseable)
173 		fprintf(stderr, "Expecting error...\n");
174 	asn = asn1p_parse_file(fname, parser_flags);
175 	if(asn == NULL) {
176 		if(expected_parseable) {
177 			fprintf(stderr, "Cannot parse file \"%s\"\n", fname);
178 			r_value = -1;
179 		} else {
180 			fprintf(stderr,
181 				"Previous error is EXPECTED, no worry\n");
182 		}
183 	} else if(!expected_parseable) {
184 		fprintf(stderr,
185 			"The file \"%s\" is not expected to be parseable, "
186 			"yet parsing was successfull!\n", fname);
187 		r_value = -1;
188 	}
189 	if(!asn) return r_value;
190 
191 	if(r_value == 0) {
192 		asn1p_t *std_asn;
193 		std_asn = asn1p_parse_file(TOP_SRCDIR_S "/skeletons/standard-modules/ASN1C-UsefulInformationObjectClasses.asn1", A1P_NOFLAGS);
194 		if(std_asn) {
195 			asn1p_module_t *mod;
196 			while((mod = TQ_REMOVE(&(std_asn->modules), mod_next))) {
197 				mod->_tags |= MT_STANDARD_MODULE;
198 				TQ_ADD(&(asn->modules), mod, mod_next);
199 			}
200 			asn1p_delete(std_asn);
201 		}
202 	}
203 
204 	/*
205 	 * Perform semantical checks and fixes.
206 	 */
207 	if(r_value == 0) {
208 		int ret;
209 
210 		if(expected_fix_code)
211 			fprintf(stderr, "Expecting some problems...\n");
212 
213 		ret = asn1f_process(asn, fixer_flags, 0);
214 		if(ret) {
215 			if(ret == expected_fix_code) {
216 				fprintf(stderr,
217 					"Previous error is EXPECTED, "
218 					"no worry\n");
219 			} else {
220 				fprintf(stderr,
221 					"Cannot process file \"%s\": %d\n",
222 					fname, ret);
223 				r_value = -1;
224 		}
225 		} else if(ret != expected_fix_code) {
226 			fprintf(stderr,
227 				"File \"%s\" is expected "
228 				"to be semantically incorrect, "
229 				"yet processing was successful!\n",
230 				fname);
231 			r_value = -1;
232 		}
233 	}
234 
235 	/*
236 	 * Check validity of some values, if grammar has special
237 	 * instructions for that.
238 	 */
239 	if(r_value == 0) {
240 		if(post_fix_check(asn))
241 			r_value = -1;
242 	}
243 
244 	/*
245 	 * Destroy the asn.
246 	 */
247 #ifdef	CLEAN_EVERYTHING
248 	asn1p_delete(asn);
249 #endif
250 
251 	return r_value;
252 }
253 
254 
255 static int
post_fix_check(asn1p_t * asn)256 post_fix_check(asn1p_t *asn) {
257 	asn1p_module_t *mod;
258 	asn1p_expr_t *expr;
259 	int r_value = 0;
260 
261 	TQ_FOR(mod, &(asn->modules), mod_next) {
262 		TQ_FOR(expr, &(mod->members), next) {
263 			assert(expr->Identifier);
264 			if(strncmp(expr->Identifier, "check-", 6) == 0) {
265 				if(post_fix_check_element(mod, expr))
266 					r_value = -1;
267 			}
268 		}
269 	}
270 
271 	return r_value;
272 }
273 
274 
275 static int
post_fix_check_element(asn1p_module_t * mod,asn1p_expr_t * check_expr)276 post_fix_check_element(asn1p_module_t *mod, asn1p_expr_t *check_expr) {
277 	asn1p_expr_t *expr = NULL;
278 	char *name;
279 	asn1p_value_t *value;
280 
281 	if(check_expr->expr_type != ASN_BASIC_INTEGER
282 	|| check_expr->meta_type != AMT_VALUE) {
283 		fprintf(stderr,
284 			"CHECKER: Unsupported type of \"%s\" value: "
285 			"%d at line %d of %s\n",
286 			check_expr->Identifier,
287 			check_expr->expr_type,
288 			check_expr->_lineno,
289 			mod->source_file_name
290 		);
291 		return -1;
292 	}
293 
294 	assert(check_expr->meta_type == AMT_VALUE);
295 
296 	value = check_expr->value;
297 	if(value == NULL || value->type != ATV_INTEGER) {
298 		fprintf(stderr,
299 			"CHECKER: Unsupported value type of \"%s\": "
300 			"%d at line %d of %s\n",
301 			check_expr->Identifier,
302 			value?(signed)value->type:-1,
303 			expr->_lineno,
304 			mod->source_file_name
305 		);
306 		return -1;
307 	}
308 
309 	name = check_expr->Identifier + sizeof("check-") - 1;
310 
311 	/*
312 	 * Scan in search for the original.
313 	 */
314 	TQ_FOR(expr, &(mod->members), next) {
315 		if(strcmp(expr->Identifier, name) == 0)
316 			break;
317 	}
318 
319 	if(expr == NULL) {
320 		fprintf(stderr,
321 			"CHECKER: Value \"%s\" requested by "
322 			"\"check-%s\" at line %d of %s is not found!\n",
323 			name, name, check_expr->_lineno,
324 			mod->source_file_name
325 		);
326 		return -1;
327 	}
328 
329 	if(0 && expr->expr_type != check_expr->expr_type) {
330 		fprintf(stderr,
331 			"CHECKER: Value type of \"%s\" (=%d) at line %d "
332 			"does not have desired type %d as requested by "
333 			"\"check-%s\" in %s\n",
334 			expr->Identifier,
335 			expr->expr_type,
336 			expr->_lineno,
337 			check_expr->expr_type,
338 			name,
339 			mod->source_file_name
340 		);
341 		return -1;
342 	}
343 
344 	if(expr->value == NULL
345 	|| expr->value->type != value->type) {
346 		fprintf(stderr,
347 			"CHECKER: Value of \"%s\" (\"%s\", type=%d) at line %d "
348 			"does not have desired type %d as requested by "
349 			"\"check-%s\" in %s\n",
350 			expr->Identifier,
351 			asn1f_printable_value(expr->value),
352 			expr->value->type,
353 			expr->_lineno,
354 			value->type,
355 			name,
356 			mod->source_file_name
357 		);
358 		return -1;
359 	}
360 
361 	assert(value->type = ATV_INTEGER);
362 
363 	return 0;
364 }
365 
366 
367