testSAX.c revision 7e99c63be0c76e8456e69c7619f3979f97153c23
1/*
2 * tester.c : a small tester program for parsing using the SAX API.
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel.Veillard@w3.org
7 */
8
9#ifdef WIN32
10#include "win32config.h"
11#else
12#include "config.h"
13#endif
14
15#include <stdio.h>
16#include <string.h>
17#include <stdarg.h>
18
19#ifdef HAVE_SYS_TYPES_H
20#include <sys/types.h>
21#endif
22#ifdef HAVE_SYS_STAT_H
23#include <sys/stat.h>
24#endif
25#ifdef HAVE_FCNTL_H
26#include <fcntl.h>
27#endif
28#ifdef HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31#ifdef HAVE_STDLIB_H
32#include <stdlib.h>
33#endif
34#ifdef HAVE_STRING_H
35#include <string.h>
36#endif
37
38
39#include <libxml/xml-error.h>
40#include <libxml/parser.h>
41#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
42#include <libxml/tree.h>
43#include <libxml/debugXML.h>
44#include <libxml/xmlmemory.h>
45
46static int debug = 0;
47static int copy = 0;
48static int recovery = 0;
49static int push = 0;
50static int speed = 0;
51
52xmlSAXHandler emptySAXHandlerStruct = {
53    NULL, /* internalSubset */
54    NULL, /* isStandalone */
55    NULL, /* hasInternalSubset */
56    NULL, /* hasExternalSubset */
57    NULL, /* resolveEntity */
58    NULL, /* getEntity */
59    NULL, /* entityDecl */
60    NULL, /* notationDecl */
61    NULL, /* attributeDecl */
62    NULL, /* elementDecl */
63    NULL, /* unparsedEntityDecl */
64    NULL, /* setDocumentLocator */
65    NULL, /* startDocument */
66    NULL, /* endDocument */
67    NULL, /* startElement */
68    NULL, /* endElement */
69    NULL, /* reference */
70    NULL, /* characters */
71    NULL, /* ignorableWhitespace */
72    NULL, /* processingInstruction */
73    NULL, /* comment */
74    NULL, /* xmlParserWarning */
75    NULL, /* xmlParserError */
76    NULL, /* xmlParserError */
77    NULL, /* getParameterEntity */
78    NULL, /* cdataBlock; */
79};
80
81xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
82extern xmlSAXHandlerPtr debugSAXHandler;
83
84/************************************************************************
85 *									*
86 *				Debug Handlers				*
87 *									*
88 ************************************************************************/
89
90/**
91 * isStandaloneDebug:
92 * @ctxt:  An XML parser context
93 *
94 * Is this document tagged standalone ?
95 *
96 * Returns 1 if true
97 */
98int
99isStandaloneDebug(void *ctx)
100{
101    fprintf(stdout, "SAX.isStandalone()\n");
102    return(0);
103}
104
105/**
106 * hasInternalSubsetDebug:
107 * @ctxt:  An XML parser context
108 *
109 * Does this document has an internal subset
110 *
111 * Returns 1 if true
112 */
113int
114hasInternalSubsetDebug(void *ctx)
115{
116    fprintf(stdout, "SAX.hasInternalSubset()\n");
117    return(0);
118}
119
120/**
121 * hasExternalSubsetDebug:
122 * @ctxt:  An XML parser context
123 *
124 * Does this document has an external subset
125 *
126 * Returns 1 if true
127 */
128int
129hasExternalSubsetDebug(void *ctx)
130{
131    fprintf(stdout, "SAX.hasExternalSubset()\n");
132    return(0);
133}
134
135/**
136 * internalSubsetDebug:
137 * @ctxt:  An XML parser context
138 *
139 * Does this document has an internal subset
140 */
141void
142internalSubsetDebug(void *ctx, const xmlChar *name,
143	       const xmlChar *ExternalID, const xmlChar *SystemID)
144{
145    fprintf(stdout, "SAX.internalSubset(%s,", name);
146    if (ExternalID == NULL)
147	fprintf(stdout, " ,");
148    else
149	fprintf(stdout, " %s,", ExternalID);
150    if (SystemID == NULL)
151	fprintf(stdout, " )\n");
152    else
153	fprintf(stdout, " %s)\n", SystemID);
154}
155
156/**
157 * resolveEntityDebug:
158 * @ctxt:  An XML parser context
159 * @publicId: The public ID of the entity
160 * @systemId: The system ID of the entity
161 *
162 * Special entity resolver, better left to the parser, it has
163 * more context than the application layer.
164 * The default behaviour is to NOT resolve the entities, in that case
165 * the ENTITY_REF nodes are built in the structure (and the parameter
166 * values).
167 *
168 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
169 */
170xmlParserInputPtr
171resolveEntityDebug(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
172{
173    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
174
175
176    fprintf(stdout, "SAX.resolveEntity(");
177    if (publicId != NULL)
178	fprintf(stdout, "%s", (char *)publicId);
179    else
180	fprintf(stdout, " ");
181    if (systemId != NULL)
182	fprintf(stdout, ", %s)\n", (char *)systemId);
183    else
184	fprintf(stdout, ", )\n");
185/*********
186    if (systemId != NULL) {
187        return(xmlNewInputFromFile(ctxt, (char *) systemId));
188    }
189 *********/
190    return(NULL);
191}
192
193/**
194 * getEntityDebug:
195 * @ctxt:  An XML parser context
196 * @name: The entity name
197 *
198 * Get an entity by name
199 *
200 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
201 */
202xmlEntityPtr
203getEntityDebug(void *ctx, const xmlChar *name)
204{
205    fprintf(stdout, "SAX.getEntity(%s)\n", name);
206    return(NULL);
207}
208
209/**
210 * getParameterEntityDebug:
211 * @ctxt:  An XML parser context
212 * @name: The entity name
213 *
214 * Get a parameter entity by name
215 *
216 * Returns the xmlParserInputPtr
217 */
218xmlEntityPtr
219getParameterEntityDebug(void *ctx, const xmlChar *name)
220{
221    fprintf(stdout, "SAX.getParameterEntity(%s)\n", name);
222    return(NULL);
223}
224
225
226/**
227 * entityDeclDebug:
228 * @ctxt:  An XML parser context
229 * @name:  the entity name
230 * @type:  the entity type
231 * @publicId: The public ID of the entity
232 * @systemId: The system ID of the entity
233 * @content: the entity value (without processing).
234 *
235 * An entity definition has been parsed
236 */
237void
238entityDeclDebug(void *ctx, const xmlChar *name, int type,
239          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
240{
241    fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
242            name, type, publicId, systemId, content);
243}
244
245/**
246 * attributeDeclDebug:
247 * @ctxt:  An XML parser context
248 * @name:  the attribute name
249 * @type:  the attribute type
250 *
251 * An attribute definition has been parsed
252 */
253void
254attributeDeclDebug(void *ctx, const xmlChar *elem, const xmlChar *name,
255              int type, int def, const xmlChar *defaultValue,
256	      xmlEnumerationPtr tree)
257{
258    if (defaultValue == NULL)
259	fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
260            elem, name, type, def);
261    else
262	fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
263            elem, name, type, def, defaultValue);
264}
265
266/**
267 * elementDeclDebug:
268 * @ctxt:  An XML parser context
269 * @name:  the element name
270 * @type:  the element type
271 * @content: the element value (without processing).
272 *
273 * An element definition has been parsed
274 */
275void
276elementDeclDebug(void *ctx, const xmlChar *name, int type,
277	    xmlElementContentPtr content)
278{
279    fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n",
280            name, type);
281}
282
283/**
284 * notationDeclDebug:
285 * @ctxt:  An XML parser context
286 * @name: The name of the notation
287 * @publicId: The public ID of the entity
288 * @systemId: The system ID of the entity
289 *
290 * What to do when a notation declaration has been parsed.
291 */
292void
293notationDeclDebug(void *ctx, const xmlChar *name,
294	     const xmlChar *publicId, const xmlChar *systemId)
295{
296    fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n",
297            (char *) name, (char *) publicId, (char *) systemId);
298}
299
300/**
301 * unparsedEntityDeclDebug:
302 * @ctxt:  An XML parser context
303 * @name: The name of the entity
304 * @publicId: The public ID of the entity
305 * @systemId: The system ID of the entity
306 * @notationName: the name of the notation
307 *
308 * What to do when an unparsed entity declaration is parsed
309 */
310void
311unparsedEntityDeclDebug(void *ctx, const xmlChar *name,
312		   const xmlChar *publicId, const xmlChar *systemId,
313		   const xmlChar *notationName)
314{
315    fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
316            (char *) name, (char *) publicId, (char *) systemId,
317	    (char *) notationName);
318}
319
320/**
321 * setDocumentLocatorDebug:
322 * @ctxt:  An XML parser context
323 * @loc: A SAX Locator
324 *
325 * Receive the document locator at startup, actually xmlDefaultSAXLocator
326 * Everything is available on the context, so this is useless in our case.
327 */
328void
329setDocumentLocatorDebug(void *ctx, xmlSAXLocatorPtr loc)
330{
331    fprintf(stdout, "SAX.setDocumentLocator()\n");
332}
333
334/**
335 * startDocumentDebug:
336 * @ctxt:  An XML parser context
337 *
338 * called when the document start being processed.
339 */
340void
341startDocumentDebug(void *ctx)
342{
343    fprintf(stdout, "SAX.startDocument()\n");
344}
345
346/**
347 * endDocumentDebug:
348 * @ctxt:  An XML parser context
349 *
350 * called when the document end has been detected.
351 */
352void
353endDocumentDebug(void *ctx)
354{
355    fprintf(stdout, "SAX.endDocument()\n");
356}
357
358/**
359 * startElementDebug:
360 * @ctxt:  An XML parser context
361 * @name:  The element name
362 *
363 * called when an opening tag has been processed.
364 */
365void
366startElementDebug(void *ctx, const xmlChar *name, const xmlChar **atts)
367{
368    int i;
369
370    fprintf(stdout, "SAX.startElement(%s", (char *) name);
371    if (atts != NULL) {
372        for (i = 0;(atts[i] != NULL);i++) {
373	    fprintf(stdout, ", %s='", atts[i++]);
374	    if (atts[i] != NULL)
375	        fprintf(stdout, "%s'", atts[i]);
376	}
377    }
378    fprintf(stdout, ")\n");
379}
380
381/**
382 * endElementDebug:
383 * @ctxt:  An XML parser context
384 * @name:  The element name
385 *
386 * called when the end of an element has been detected.
387 */
388void
389endElementDebug(void *ctx, const xmlChar *name)
390{
391    fprintf(stdout, "SAX.endElement(%s)\n", (char *) name);
392}
393
394/**
395 * charactersDebug:
396 * @ctxt:  An XML parser context
397 * @ch:  a xmlChar string
398 * @len: the number of xmlChar
399 *
400 * receiving some chars from the parser.
401 * Question: how much at a time ???
402 */
403void
404charactersDebug(void *ctx, const xmlChar *ch, int len)
405{
406    char output[40];
407    int i;
408
409    for (i = 0;(i<len) && (i < 30);i++)
410	output[i] = ch[i];
411    output[i] = 0;
412
413    fprintf(stdout, "SAX.characters(%s, %d)\n", output, len);
414}
415
416/**
417 * referenceDebug:
418 * @ctxt:  An XML parser context
419 * @name:  The entity name
420 *
421 * called when an entity reference is detected.
422 */
423void
424referenceDebug(void *ctx, const xmlChar *name)
425{
426    fprintf(stdout, "SAX.reference(%s)\n", name);
427}
428
429/**
430 * ignorableWhitespaceDebug:
431 * @ctxt:  An XML parser context
432 * @ch:  a xmlChar string
433 * @start: the first char in the string
434 * @len: the number of xmlChar
435 *
436 * receiving some ignorable whitespaces from the parser.
437 * Question: how much at a time ???
438 */
439void
440ignorableWhitespaceDebug(void *ctx, const xmlChar *ch, int len)
441{
442    char output[40];
443    int i;
444
445    for (i = 0;(i<len) && (i < 30);i++)
446	output[i] = ch[i];
447    output[i] = 0;
448    fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
449}
450
451/**
452 * processingInstructionDebug:
453 * @ctxt:  An XML parser context
454 * @target:  the target name
455 * @data: the PI data's
456 * @len: the number of xmlChar
457 *
458 * A processing instruction has been parsed.
459 */
460void
461processingInstructionDebug(void *ctx, const xmlChar *target,
462                      const xmlChar *data)
463{
464    fprintf(stdout, "SAX.processingInstruction(%s, %s)\n",
465            (char *) target, (char *) data);
466}
467
468/**
469 * cdataBlockDebug:
470 * @ctx: the user data (XML parser context)
471 * @value:  The pcdata content
472 * @len:  the block length
473 *
474 * called when a pcdata block has been parsed
475 */
476void
477cdataBlockDebug(void *ctx, const xmlChar *value, int len)
478{
479    fprintf(stderr, "SAX.pcdata(%.20s, %d)\n",
480	    (char *) value, len);
481}
482
483/**
484 * commentDebug:
485 * @ctxt:  An XML parser context
486 * @value:  the comment content
487 *
488 * A comment has been parsed.
489 */
490void
491commentDebug(void *ctx, const xmlChar *value)
492{
493    fprintf(stdout, "SAX.comment(%s)\n", value);
494}
495
496/**
497 * warningDebug:
498 * @ctxt:  An XML parser context
499 * @msg:  the message to display/transmit
500 * @...:  extra parameters for the message display
501 *
502 * Display and format a warning messages, gives file, line, position and
503 * extra parameters.
504 */
505void
506warningDebug(void *ctx, const char *msg, ...)
507{
508    va_list args;
509
510    va_start(args, msg);
511    fprintf(stdout, "SAX.warning: ");
512    vfprintf(stdout, msg, args);
513    va_end(args);
514}
515
516/**
517 * errorDebug:
518 * @ctxt:  An XML parser context
519 * @msg:  the message to display/transmit
520 * @...:  extra parameters for the message display
521 *
522 * Display and format a error messages, gives file, line, position and
523 * extra parameters.
524 */
525void
526errorDebug(void *ctx, const char *msg, ...)
527{
528    va_list args;
529
530    va_start(args, msg);
531    fprintf(stdout, "SAX.error: ");
532    vfprintf(stdout, msg, args);
533    va_end(args);
534}
535
536/**
537 * fatalErrorDebug:
538 * @ctxt:  An XML parser context
539 * @msg:  the message to display/transmit
540 * @...:  extra parameters for the message display
541 *
542 * Display and format a fatalError messages, gives file, line, position and
543 * extra parameters.
544 */
545void
546fatalErrorDebug(void *ctx, const char *msg, ...)
547{
548    va_list args;
549
550    va_start(args, msg);
551    fprintf(stdout, "SAX.fatalError: ");
552    vfprintf(stdout, msg, args);
553    va_end(args);
554}
555
556xmlSAXHandler debugSAXHandlerStruct = {
557    internalSubsetDebug,
558    isStandaloneDebug,
559    hasInternalSubsetDebug,
560    hasExternalSubsetDebug,
561    resolveEntityDebug,
562    getEntityDebug,
563    entityDeclDebug,
564    notationDeclDebug,
565    attributeDeclDebug,
566    elementDeclDebug,
567    unparsedEntityDeclDebug,
568    setDocumentLocatorDebug,
569    startDocumentDebug,
570    endDocumentDebug,
571    startElementDebug,
572    endElementDebug,
573    referenceDebug,
574    charactersDebug,
575    ignorableWhitespaceDebug,
576    processingInstructionDebug,
577    commentDebug,
578    warningDebug,
579    errorDebug,
580    fatalErrorDebug,
581    getParameterEntityDebug,
582    cdataBlockDebug
583};
584
585xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
586
587/************************************************************************
588 *									*
589 *				Debug					*
590 *									*
591 ************************************************************************/
592
593void parseAndPrintFile(char *filename) {
594    int res;
595
596    if (push) {
597	FILE *f;
598
599	/*
600	 * Empty callbacks for checking
601	 */
602	f = fopen(filename, "r");
603	if (f != NULL) {
604	    int res;
605	    char chars[10];
606	    xmlParserCtxtPtr ctxt;
607
608	    res = fread(chars, 1, 4, f);
609	    if (res > 0) {
610		ctxt = xmlCreatePushParserCtxt(emptySAXHandler, NULL,
611			    chars, res, filename);
612		while ((res = fread(chars, 1, 3, f)) > 0) {
613		    xmlParseChunk(ctxt, chars, res, 0);
614		}
615		xmlParseChunk(ctxt, chars, 0, 1);
616		xmlFreeParserCtxt(ctxt);
617	    }
618	    fclose(f);
619	} else {
620	    fprintf(stderr, "Cannot read file %s\n", filename);
621	}
622	/*
623	 * Debug callback
624	 */
625	f = fopen(filename, "r");
626	if (f != NULL) {
627	    int res;
628	    char chars[10];
629	    xmlParserCtxtPtr ctxt;
630
631	    res = fread(chars, 1, 4, f);
632	    if (res > 0) {
633		ctxt = xmlCreatePushParserCtxt(debugSAXHandler, NULL,
634			    chars, res, filename);
635		while ((res = fread(chars, 1, 3, f)) > 0) {
636		    xmlParseChunk(ctxt, chars, res, 0);
637		}
638		res = xmlParseChunk(ctxt, chars, 0, 1);
639		xmlFreeParserCtxt(ctxt);
640		if (res != 0) {
641		    fprintf(stdout,
642		            "xmlSAXUserParseFile returned error %d\n", res);
643		}
644	    }
645	    fclose(f);
646	}
647    } else {
648	if (!speed) {
649	    /*
650	     * Empty callbacks for checking
651	     */
652	    res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
653	    if (res != 0) {
654		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
655	    }
656
657	    /*
658	     * Debug callback
659	     */
660	    res = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
661	    if (res != 0) {
662		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
663	    }
664	} else {
665	    /*
666	     * test 100x the SAX parse
667	     */
668	    int i;
669
670	    for (i = 0; i<100;i++)
671		res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
672	    if (res != 0) {
673		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
674	    }
675	}
676    }
677}
678
679
680int main(int argc, char **argv) {
681    int i;
682    int files = 0;
683
684    for (i = 1; i < argc ; i++) {
685	if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
686	    debug++;
687	else if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
688	    copy++;
689	else if ((!strcmp(argv[i], "-recover")) ||
690	         (!strcmp(argv[i], "--recover")))
691	    recovery++;
692	else if ((!strcmp(argv[i], "-push")) ||
693	         (!strcmp(argv[i], "--push")))
694	    push++;
695	else if ((!strcmp(argv[i], "-speed")) ||
696	         (!strcmp(argv[i], "--speed")))
697	    speed++;
698    }
699    for (i = 1; i < argc ; i++) {
700	if (argv[i][0] != '-') {
701	    parseAndPrintFile(argv[i]);
702	    files ++;
703	}
704    }
705    xmlCleanupParser();
706    xmlMemoryDump();
707
708    return(0);
709}
710