1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "libparsifal/parsifal.h"
5 #include "libparsifal/dtdvalid.h"
6 
7 #define MAKE_DIFFGRAM 1
8 
9 #ifdef _MSC_VER
10 	#ifdef _DEBUG
11 		#include <crtdbg.h>
12 		#define _CRTDBG_MAP_ALLOC
13 	#endif
14 #endif
15 
16 #define OUTDIR "pxpout/"
17 
18 /* stack macros (from xmldef.h) */
19 #define STACK_PUSH(stack,item) (XMLVector_Append((stack), (item)))
20 #define STACK_PEEK(stack) (XMLVector_Get((stack),(stack)->length-1))
21 #define STACK_REMOVE(stack) (XMLVector_Remove((stack), (stack)->length-1))
22 #define STACK_POP(stack,item) \
23 ( ((stack)->length) ? (memcpy((item), STACK_PEEK((stack)), (stack)->itemSize), \
24 STACK_REMOVE((stack)), (item)) : NULL)
25 
26 #define EMPTY_COLS(num, pfile) { int i; for (i=0; i<(num); i++) fputs("<td>&nbsp;</td>", (pfile)); }
27 
28 #ifndef MAX_PATH
29 #define MAX_PATH 256
30 #endif
31 
32 enum tagSTATES { NONE, TESTSUITE, TESTCASES, TEST } STATES;
33 
34 #define PFOUT (((XMLCONFPARSER*)UserData)->pfout)
35 #define PFERR stdout
36 
37 typedef struct tagXMLCONFPARSER {
38 	LPXMLPARSER parser;
39 	LPXMLVECTOR stateStack;
40 	LPXMLDTDVALIDATOR v;
41 	int state;
42 	int inMixedContent;
43 	/* these are xmlconf specific: */
44 	LPXMLPARSER runParser;
45 	int testCount;
46 	int testSuccess;
47 	FILE *pfout, *pffailed;
48 } XMLCONFPARSER;
49 
50 typedef struct tagRUNPARSERDATA {
51 	XMLCH systemID[MAX_PATH];
52 	XMLCH testbasedir[MAX_PATH];
53 	XMLCH intEnt[MAX_PATH];
54 } RUNPARSERDATA;
55 
56 /* common routines: */
57 int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData);
58 int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
59 
60 /* TESTSUITE PARSER: */
61 void PrintEsc(FILE *fp, const XMLCH *str, int len);
62 int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts);
63 int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName);
64 int Characters(void *UserData, const XMLCH *Chars, int cbChars);
65 void ErrorHandler(LPXMLPARSER parser);
66 int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
67 
68 /* RUNTEST PARSER: */
69 int RunTest(XMLCONFPARSER *xcp, char *uri);
70 int RunTestResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader);
71 void RunTestErrorHandler(LPXMLPARSER parser);
72 void GetBaseDir(unsigned char *fullfile, unsigned char *targetdir);
73 int StartElementDetermineValidation(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts);
74 extern int fcompare(const char *fnam1, const char *fnam2);
75 
cstream(BYTE * buf,int cBytes,int * cBytesActual,void * inputData)76 int cstream(BYTE *buf, int cBytes, int *cBytesActual, void *inputData)
77 {
78 	*cBytesActual = fread(buf, 1, cBytes, (FILE*)inputData);
79 	return (*cBytesActual < cBytes);
80 }
81 
FreeInputData(void * UserData,LPXMLENTITY entity,LPBUFFEREDISTREAM reader)82 int FreeInputData(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
83 {
84 	fclose((FILE*)reader->inputData);
85 	return 0;
86 }
87 
88 /* TESTSUITE PARSER BEGIN */
89 
StartElement(void * UserData,const XMLCH * uri,const XMLCH * localName,const XMLCH * qName,LPXMLVECTOR atts)90 int StartElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts)
91 {
92 	XMLCONFPARSER *xcp = (XMLCONFPARSER*)UserData;
93 	LPXMLRUNTIMEATT att;
94 	int *pstate = STACK_PEEK(xcp->stateStack);
95 	xcp->state = (pstate) ? *pstate : NONE;
96 
97 	if (xcp->inMixedContent || xcp->state == TEST) {
98 		/* + other tags that allow mixed content tested here */
99 		/* if we're in mixed content, we don't bother to use stack, just
100 		   incrementing (and decrementing in EndElement) the counter: */
101 		xcp->inMixedContent++;
102 		/* could call mixed content legal tag check routine here e.g.
103 		if (!isvalidmixedcontent(state, qName)) return sin(); */
104 		fprintf(PFOUT, "<%s>", qName);
105 		return 0;
106 	}
107 
108 	if (xcp->state == NONE && !strcmp(qName, "TESTSUITE")) {
109 
110 		if (att = XMLParser_GetNamedItem(xcp->parser, "PROFILE"))
111 			fprintf(PFOUT, "<h1><b>%s</b></h1><br><h3>Parsifal XML Parser %s</h3>",
112 				att->value, XMLParser_GetVersionString());
113 		xcp->state = TESTSUITE;
114 	}
115 	else if (xcp->state == TESTSUITE && !strcmp(qName, "TESTCASES")) {
116 
117 		if (att = XMLParser_GetNamedItem(xcp->parser, "PROFILE")) {
118 			/* new testcase, spit out the profile header: */
119 			fprintf(PFOUT, "<br><br><h2>Testcase profile: <b>%s</b></h2><br>", att->value);
120 			fputs("<table cellspacing='0'>", PFOUT); /* open table for results */
121 		}
122 		xcp->state = TESTCASES;
123 	}
124 	else if (xcp->state == TESTCASES) {
125 
126 		if (!strcmp(qName, "TEST")) {
127 			if (att = XMLParser_GetNamedItem(xcp->parser, "URI")) {
128 				/* new test, run it: */
129 				if (!RunTest(xcp, att->value))
130 					fprintf(PFERR, "Fatal Error running test: %s\n", att->value);
131 			}
132 			xcp->state = TEST;
133 		}
134 		else if (!strcmp(qName, "TESTCASES")) { /* for some reason
135 
136 			there's TESTCASES inside TESTCASES in ibm tests,
137 			so it must ust be handled here: */
138 			xcp->state = TESTCASES;
139 		}
140 	}
141 	else {
142 		fprintf(PFERR, "Unexpected tag: %s\n", qName);
143 		return XML_ABORT;
144 	}
145 
146 	STACK_PUSH(xcp->stateStack, &xcp->state);
147 	return 0;
148 }
149 
EndElement(void * UserData,const XMLCH * uri,const XMLCH * localName,const XMLCH * qName)150 int EndElement(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName)
151 {
152 	XMLCONFPARSER *xcp = (XMLCONFPARSER*)UserData;
153 	if (xcp->inMixedContent) {
154 		xcp->inMixedContent--;
155 		fprintf(PFOUT, "</%s>", qName); /* EM or B tags */
156 	}
157 	else {
158 		if (STACK_POP(xcp->stateStack, &xcp->state)) {
159 			if (xcp->state == TEST) {
160 				/* close TEST description column and row: */
161 				fputs("</td>", PFOUT);
162 				EMPTY_COLS(3, PFOUT);
163 				fputs("</tr>", PFOUT);
164 			}
165 			else if (xcp->state == TESTCASES) {
166 				int *pstate = STACK_PEEK(xcp->stateStack);
167 				/* check is needed 'cos there can be TESTCASES inside TESTCASES */
168 				if (pstate && *pstate != TESTCASES) fputs("</table>", PFOUT);
169 			}
170 		}
171 	}
172 	return 0;
173 }
174 
PrintEsc(FILE * fp,const XMLCH * str,int len)175 void PrintEsc(FILE *fp, const XMLCH *str, int len)
176 {
177 	for (; len--; str++) {
178 		switch(*str) {
179 			case '&': fputs("&amp;", fp); break;
180 			case '\"': fputs("&quot;", fp); break;
181 			//case '\'': fprintf("&apos;", fp); break;
182 			case '<': fputs("&lt;", fp); break;
183 			case '>': fputs("&gt;", fp); break;
184 			case '\x9': fputs("&#9;", fp); break;
185 			case '\xA': fputs("&#10;", fp); break;
186 			case '\xD': fputs("&#13;", fp); break;
187 			default: fputc(*str, fp); break;
188 		}
189 	}
190 }
191 
Characters(void * UserData,const XMLCH * Chars,int cbChars)192 int Characters(void *UserData, const XMLCH *Chars, int cbChars)
193 {
194 	XMLCONFPARSER *xcp = (XMLCONFPARSER*)UserData;
195 	if (xcp->state == TEST)
196 		PrintEsc(PFOUT, Chars, cbChars);
197 	return 0;
198 }
199 
ErrorHandler(LPXMLPARSER parser)200 void ErrorHandler(LPXMLPARSER parser)
201 {
202 	if (parser->ErrorCode != ERR_XMLP_ABORT) {
203 		XMLCH *sysID = XMLParser_GetSystemID(parser);
204 
205 		if (sysID) fprintf(PFERR, "Parsing resource %s failed!\n", sysID);
206 		fprintf(PFERR, "Error: %s\nCode: %d\nLine: %d\nColumn: %d\n",
207 			parser->ErrorString, parser->ErrorCode,
208 			parser->ErrorLine, parser->ErrorColumn);
209 	}
210 }
211 
ResolveEntity(void * UserData,LPXMLENTITY entity,LPBUFFEREDISTREAM reader)212 int ResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
213 {
214 	FILE *f;
215 	if (!(f = fopen(entity->systemID, "rb"))) {
216 		fprintf(PFERR, "error opening file '%s'!\n", entity->systemID);
217 		return XML_ABORT;
218 	}
219 	reader->inputData = f;
220 	return 0;
221 }
222 /* TESTSUITE PARSER END */
223 
224 /* RUNTEST PARSER BEGIN */
225 /* these are parser routines that run the test itself,
226    we don't need many event handlers for it only
227    resolveEntityHandler and related stuff */
228 
229 
230 #define TYPE_VALID 1
231 #define TYPE_INVALID 2
232 #define TYPE_OTHER 3
233 
RunTest(XMLCONFPARSER * xcp,char * uri)234 int RunTest(XMLCONFPARSER *xcp, char *uri)
235 {
236 	LPXMLRUNTIMEATT att, tatt;
237 	XMLCH testuri[MAX_PATH];
238 	XMLCH xmlbase[MAX_PATH];
239 	XMLCH id[256];
240 	XMLCH *s;
241 	FILE *f;
242 	RUNPARSERDATA rdata;
243 	int result, expect;
244 	LPXMLPARSER parser = xcp->runParser;
245 	int type;
246 
247 	if ((s = XMLParser_GetPrefixMapping(xcp->parser, "xml:base")))
248 		strcpy(xmlbase, s); /* we save current xmlbase
249 							   (although it shouldn't get modified 'cos
250 							   main parser isn't running during RunTest()) */
251 	else {
252 		/* rmt-e2e-18:
253 		External entity containing start of entity declaration is
254 		base URI for system identifier, so:  */
255 		XMLCH *sysID = XMLParser_GetSystemID(xcp->parser);
256 		if (!sysID) xmlbase[0] = '\0';
257 		else GetBaseDir(sysID, xmlbase);
258 	}
259 
260 	strcpy(testuri, xmlbase);
261 	strcat(testuri, uri);
262 
263 	puts(testuri);
264 
265 	/* resolve basedir for external entities, DTD and for canonxml */
266 	GetBaseDir(testuri, rdata.testbasedir);
267 
268 	tatt = XMLParser_GetNamedItem(xcp->parser, "TYPE");
269 	if (tatt) {
270 		/* "Nonvalidating parsers must also accept "invalid" testcases,
271        but validating ones must reject them." */
272 		if (!strcmp(tatt->value, "valid")) type = TYPE_VALID;
273 		else if (!strcmp(tatt->value, "invalid")) type = TYPE_INVALID;
274 		else type = TYPE_OTHER; /* error, not-wf */
275 	}
276 
277 	if ((f = fopen(testuri, "rb"))) {
278 #ifdef TEST_VALIDATING
279 		xcp->v->UserData = &rdata;
280 		xcp->v->UserFlag = type;
281 		xcp->v->startElementHandlerFilter = StartElementDetermineValidation;
282 		result = XMLParser_ParseValidateDTD(xcp->v, parser, cstream, f, 0);
283 #else
284 		parser->UserData = &rdata;
285 		result = XMLParser_Parse(parser, cstream, f, 0);
286 #endif
287 		fclose(f);
288 	}
289 	else {
290 		fprintf(PFERR, "Error opening file %s\n", testuri);
291 		return 0;
292 	}
293 
294 	xcp->testCount++;
295 
296 	/* 1 row columns: ID, TYPE, PASS/FAIL, ERRORSTRING
297 	   2 row columns: ENTITIES + OUTPUT in one col, 3 empty cols
298 	   3 row: test description, 3 empty cols
299 	*/
300 	att = XMLParser_GetNamedItem(xcp->parser, "ID");
301 	strcpy(id, (att) ? att->value : "unknown");
302 	fputs((xcp->testCount % 2) ? "<tr bgcolor='#EEEEEE'>" : "<tr>", xcp->pfout);
303 	fprintf(xcp->pfout, "<td><a href='%s'>%s</a></td>", testuri, id);
304 
305 	if (tatt) {
306 		if (type == TYPE_VALID) expect = 1;
307 		else if (type == TYPE_INVALID)
308 #ifdef TEST_VALIDATING
309 			expect = 0;
310 #else
311 			expect = 1;
312 #endif
313 		else expect = 0;
314 		fprintf(xcp->pfout, "<td>%s</td>", tatt->value);
315 		if (result == expect) xcp->testSuccess++;
316 	}
317 	else {
318 		EMPTY_COLS(1, xcp->pfout);
319 	}
320 
321 	if (result != expect) fprintf(xcp->pffailed, "%s\n", id);
322 
323 	fprintf(xcp->pfout, "<td><font color='%s'>", (result == expect) ? "#008000" : "#FF0000");
324 	if (result)
325 		fprintf(xcp->pfout, "PASS</font></td><td>&nbsp;</td>");
326 	else {
327 		fputs("FAIL</font></td><td>", xcp->pfout);
328 #ifdef TEST_VALIDATING
329 		if (parser->ErrorCode == ERR_XMLP_VALIDATION)
330 			PrintEsc(xcp->pfout, xcp->v->ErrorString, strlen(xcp->v->ErrorString));
331 		else
332 #endif
333 		PrintEsc(xcp->pfout, parser->ErrorString, strlen(parser->ErrorString));
334 		fputs("</td>", xcp->pfout);
335 	}
336 
337 	fputs("</tr>", xcp->pfout);
338 	fputs((xcp->testCount % 2) ? "<tr bgcolor='#EEEEEE'>" : "<tr>", xcp->pfout);
339 
340 	if ((att = XMLParser_GetNamedItem(xcp->parser, "ENTITIES")))
341 		fprintf(xcp->pfout, "<td><b>entities:</b> %s&nbsp;&nbsp;", att->value);
342 	else
343 		fputs("<td>", xcp->pfout);
344 
345 	/* OUTPUT TEST */
346 	att = XMLParser_GetNamedItem(xcp->parser, "OUTPUT");
347 	if (att) {
348 		int compres;
349 		XMLCH cmd[2048];
350 		XMLCH outfile1[MAX_PATH], outfile2[MAX_PATH];
351 
352 		strcpy(outfile1, xmlbase);
353 		strcat(outfile1, att->value);
354 		sprintf(outfile2, "%s%s.xml", OUTDIR, id);
355 		sprintf(cmd, "canonxml %s %s %s", testuri, outfile2, rdata.testbasedir);
356 		system(cmd);
357 
358 		compres = fcompare(outfile1, outfile2);
359 
360 		fprintf(xcp->pfout, "<font color='%s'>OUTPUT:</font>",
361 			(!compres) ? "#008000" : "#FF0000");
362 		if (compres == -1)
363 			fputs(" error", xcp->pfout);
364 		else {
365 #ifdef MAKE_DIFFGRAM
366 			if (compres) {
367 				XMLCH difffile[MAX_PATH];
368 				sprintf(difffile, "%s%s-diffgram.xml", OUTDIR, id);
369 				sprintf(cmd, "xmldiff %s %s %s", outfile1, outfile2, difffile);
370 				system(cmd);
371 				fprintf(xcp->pfout, " <a href='%s'>1</a> <a href='%s'>2</a> <a href='%s'>diff</a>", outfile1, outfile2, difffile);
372 			}
373 			else
374 #endif
375 				fprintf(xcp->pfout, " <a href='%s'>1</a> <a href='%s'>2</a>", outfile1, outfile2);
376 		}
377 	}
378 	else {
379 		fputs("</td>", xcp->pfout);
380 	}
381 	/* OUTPUT TEST END */
382 
383 	if (!parser->ErrorCode) {
384 		EMPTY_COLS(3, xcp->pfout);
385 	}
386 	else {
387 		EMPTY_COLS(2, xcp->pfout);
388 #ifdef TEST_VALIDATING
389 		if (parser->ErrorCode == ERR_XMLP_VALIDATION)
390 			fprintf(xcp->pfout, "<td>Line: %d Col: %d ", xcp->v->ErrorLine, xcp->v->ErrorColumn);
391 		else
392 #endif
393 		fprintf(xcp->pfout, "<td>Line: %d Col: %d ", parser->ErrorLine, parser->ErrorColumn);
394 
395 		if (rdata.intEnt[0]) fprintf(xcp->pfout, "in entity: '%s' ", rdata.intEnt);
396 		if (rdata.systemID[0]) fprintf(xcp->pfout, "systemID: '%s'", rdata.systemID);
397 		fputs("</td>", xcp->pfout);
398 	}
399 
400 	fputs("</tr>", xcp->pfout);
401 	/* open new table row for test description (reported via Characters): */
402 	fputs((xcp->testCount % 2) ? "<tr bgcolor='#EEEEEE'><td>" : "<tr><td>", xcp->pfout);
403 	return 1;
404 }
405 
406 /* GetBaseDir gets path from <fullfile> string  into
407 <targetdir> string (which must be allocated for strlen(fullfile)+1)*/
GetBaseDir(unsigned char * fullfile,unsigned char * targetdir)408 void GetBaseDir(unsigned char *fullfile, unsigned char *targetdir)
409 {
410 	int slash = strlen(fullfile);
411 	while(slash && *(fullfile+slash) != '/') slash--;
412 	if (slash) {
413 		memcpy(targetdir, fullfile, slash+1);
414 		targetdir[slash+1] = '\0';
415 	}
416 	else {
417 		targetdir[0] = '\0';
418 	}
419 }
420 
RunTestResolveEntity(void * UserData,LPXMLENTITY entity,LPBUFFEREDISTREAM reader)421 int RunTestResolveEntity(void *UserData, LPXMLENTITY entity, LPBUFFEREDISTREAM reader)
422 {
423 	char testuri[MAX_PATH];
424 	FILE *f;
425 #ifdef TEST_VALIDATING
426 	RUNPARSERDATA *rdata = (RUNPARSERDATA*)((LPXMLDTDVALIDATOR)UserData)->UserData;
427 #else
428 	RUNPARSERDATA *rdata = (RUNPARSERDATA*)UserData;
429 #endif
430 	strcpy(testuri, rdata->testbasedir);
431 	strcat(testuri, entity->systemID);
432 
433 	if (!(f = fopen(testuri, "rb"))) {
434 		fprintf(PFERR, "Error opening file %s\n", testuri);
435 		return XML_ABORT;
436 	}
437 	reader->inputData = f;
438 	return 0;
439 }
440 
RunTestErrorHandler(LPXMLPARSER parser)441 void RunTestErrorHandler(LPXMLPARSER parser)
442 {
443 	XMLCH *systemID;
444 	LPXMLENTITY curEnt;
445 #ifndef TEST_VALIDATING
446 	RUNPARSERDATA *rdata = (RUNPARSERDATA*)parser->UserData;
447 #else
448 	RUNPARSERDATA *rdata = (RUNPARSERDATA*)((LPXMLDTDVALIDATOR)parser->UserData)->UserData;
449 	if (parser->ErrorCode == ERR_XMLP_VALIDATION &&
450 		_XMLParser_GetFlag(parser, XMLFLAG_VALIDATION_WARNINGS)) return;
451 #endif
452 	systemID = XMLParser_GetSystemID(parser);
453 	curEnt = XMLParser_GetCurrentEntity(parser);
454 	if (curEnt && !curEnt->systemID) strcpy(rdata->intEnt, curEnt->name);
455 	else rdata->intEnt[0] = '\0';
456 	if (systemID) strcpy(rdata->systemID, systemID);
457 	else rdata->systemID[0] = '\0';
458 }
459 
StartElementDetermineValidation(void * UserData,const XMLCH * uri,const XMLCH * localName,const XMLCH * qName,LPXMLVECTOR atts)460 int StartElementDetermineValidation(void *UserData, const XMLCH *uri, const XMLCH *localName, const XMLCH *qName, LPXMLVECTOR atts)
461 {
462 	LPXMLDTDVALIDATOR v = (LPXMLDTDVALIDATOR)UserData;
463 	if (v->UserFlag == TYPE_VALID || v->UserFlag == TYPE_INVALID) {
464 		_XMLParser_SetFlag(v->parser, XMLFLAG_VALIDATION_WARNINGS, 0);
465 	}
466 	else {
467 		_XMLParser_SetFlag(v->parser, XMLFLAG_VALIDATION_WARNINGS, 1);
468 	}
469 	v->startElementHandlerFilter = v->parser->startElementHandler = DTDValidate_StartElement;
470 	return DTDValidate_StartElement(UserData, uri, localName, qName, atts);
471 }
472 
473 /* RUNTEST PARSER END */
474 
main(int argc,char * argv[])475 int main(int argc, char* argv[])
476 {
477 	LPXMLPARSER parser;
478 	XMLCONFPARSER parserdata;
479 	FILE *f;
480 	char namePffailed[100];
481 
482 	#ifdef _MSC_VER
483 		#ifdef _DEBUG
484 			int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
485 			// Turn on leak-checking bit
486 			tmpFlag |= _CRTDBG_LEAK_CHECK_DF; /* dump leaks to output */
487 			// Set flag to the new value
488 			_CrtSetDbgFlag( tmpFlag );
489 		#endif
490 	#endif
491 
492 	if (argc != 3) {
493 		fprintf(PFERR, "Give filenames e.g. C:\\XMLCONF\\XMLCONF.XML RESULTS.HTML\n");
494 		return 1;
495 	}
496 
497 	/* Initialize xmlconf.xml parser: */
498 	if (!XMLParser_Create(&parser)) {
499 		fprintf(PFERR, "Error creating main parser in main()\n");
500 		return 1;
501 	}
502 
503 	parser->startElementHandler = StartElement;
504 	parser->endElementHandler = EndElement;
505 	parser->charactersHandler = Characters;
506 	parser->errorHandler = ErrorHandler;
507 	parser->resolveEntityHandler = ResolveEntity;
508 	parser->externalEntityParsedHandler = FreeInputData;
509 	parser->UserData = &parserdata;
510 
511 	parserdata.parser = parser;
512 	parserdata.inMixedContent = 0;
513 	parserdata.testCount = 0;
514 	parserdata.testSuccess = 0;
515 
516 	/* Initialize runParser: */
517 	/* we could create new parser in RunTest every time we're running
518 	   new test, but for extra stress testing we're using the
519 	   same parser: */
520 	if (!XMLParser_Create(&parserdata.runParser)) {
521 		fprintf(PFERR, "Error creating runParser in main()\n");
522 		return 1;
523 	}
524 #ifdef TEST_VALIDATING
525 	parserdata.v = XMLParser_CreateDTDValidator();
526 	if (!parserdata.v) {
527 		fprintf(PFERR, "Error creating DTDvalidator in main()\n");
528 		return 1;
529 	}
530 #endif
531 
532 	/* make parsifal to report undefined entities and not to use skippedEntity: */
533 	_XMLParser_SetFlag(parserdata.runParser, XMLFLAG_UNDEF_GENERAL_ENTITIES, 1);
534 	/* assign handlers: */
535 	parserdata.runParser->errorHandler = RunTestErrorHandler;
536 	parserdata.runParser->resolveEntityHandler = RunTestResolveEntity;
537 	parserdata.runParser->externalEntityParsedHandler = FreeInputData;
538 
539 	if (!XMLVector_Create(&parserdata.stateStack, 6, sizeof(int))) {
540 		fprintf(PFERR, "Error creating stack in main()\n");
541 		return 1;
542 	}
543 
544 	if (!(f = fopen(argv[1], "rb"))) {
545 		fprintf(PFERR, "Error opening input file %s\n", argv[1]);
546 		return 1;
547 	}
548 
549 	if (!(parserdata.pfout = fopen(argv[2], "wb"))) {
550 		fprintf(PFERR, "Error opening output file %s\n", argv[2]);
551 		return 1;
552 	}
553 
554 	sprintf(namePffailed, "%s-failed-%s.txt", argv[1], XMLParser_GetVersionString());
555 	if (!(parserdata.pffailed = fopen(namePffailed, "w"))) {
556 		fprintf(PFERR, "Error opening output file namePffailed\n", namePffailed);
557 		return 1;
558 	}
559 
560 	fputs("<html><body>", parserdata.pfout);
561 
562 	XMLParser_Parse(parser, cstream, f, NULL);
563 
564 	fprintf(parserdata.pfout, "<br><br><b>%d</b> tests successful out of total <b>%d</b>.",
565 		parserdata.testSuccess, parserdata.testCount);
566 	fputs("</body></html>", parserdata.pfout);
567 
568 	fclose(f);
569 	fclose(parserdata.pfout);
570 	XMLVector_Free(parserdata.stateStack);
571 	XMLParser_Free(parserdata.runParser);
572 	XMLParser_Free(parser);
573 #ifdef TEST_VALIDATING
574 	XMLParser_FreeDTDValidator(parserdata.v);
575 #endif
576 	return 0;
577 }
578 
579