1 /*
2  * testSAX.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.com
7  */
8 
9 #include "libxml.h"
10 
11 #ifdef HAVE_SYS_TIME_H
12 #include <sys/time.h>
13 #endif
14 #ifdef HAVE_SYS_TIMEB_H
15 #include <sys/timeb.h>
16 #endif
17 #ifdef HAVE_TIME_H
18 #include <time.h>
19 #endif
20 
21 #ifdef LIBXML_SAX1_ENABLED
22 #include <string.h>
23 #include <stdarg.h>
24 
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
27 #endif
28 #ifdef HAVE_SYS_STAT_H
29 #include <sys/stat.h>
30 #endif
31 #ifdef HAVE_FCNTL_H
32 #include <fcntl.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 
44 
45 #include <libxml/globals.h>
46 #include <libxml/xmlerror.h>
47 #include <libxml/parser.h>
48 #include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
49 #include <libxml/tree.h>
50 #include <libxml/debugXML.h>
51 #include <libxml/xmlmemory.h>
52 
53 static int debug = 0;
54 static int copy = 0;
55 static int recovery = 0;
56 static int push = 0;
57 static int speed = 0;
58 static int noent = 0;
59 static int quiet = 0;
60 static int nonull = 0;
61 static int sax2 = 0;
62 static int repeat = 0;
63 static int callbacks = 0;
64 static int timing = 0;
65 
66 /*
67  * Timing routines.
68  */
69 /*
70  * Internal timing routines to remove the necessity to have unix-specific
71  * function calls
72  */
73 
74 #ifndef HAVE_GETTIMEOFDAY
75 #ifdef HAVE_SYS_TIMEB_H
76 #ifdef HAVE_SYS_TIME_H
77 #ifdef HAVE_FTIME
78 
79 static int
my_gettimeofday(struct timeval * tvp,void * tzp)80 my_gettimeofday(struct timeval *tvp, void *tzp)
81 {
82 	struct timeb timebuffer;
83 
84 	ftime(&timebuffer);
85 	if (tvp) {
86 		tvp->tv_sec = timebuffer.time;
87 		tvp->tv_usec = timebuffer.millitm * 1000L;
88 	}
89 	return (0);
90 }
91 #define HAVE_GETTIMEOFDAY 1
92 #define gettimeofday my_gettimeofday
93 
94 #endif /* HAVE_FTIME */
95 #endif /* HAVE_SYS_TIME_H */
96 #endif /* HAVE_SYS_TIMEB_H */
97 #endif /* !HAVE_GETTIMEOFDAY */
98 
99 #if defined(HAVE_GETTIMEOFDAY)
100 static struct timeval begin, end;
101 
102 /*
103  * startTimer: call where you want to start timing
104  */
105 static void
startTimer(void)106 startTimer(void)
107 {
108     gettimeofday(&begin, NULL);
109 }
110 
111 /*
112  * endTimer: call where you want to stop timing and to print out a
113  *           message about the timing performed; format is a printf
114  *           type argument
115  */
116 static void XMLCDECL
endTimer(const char * fmt,...)117 endTimer(const char *fmt, ...)
118 {
119     long msec;
120     va_list ap;
121 
122     gettimeofday(&end, NULL);
123     msec = end.tv_sec - begin.tv_sec;
124     msec *= 1000;
125     msec += (end.tv_usec - begin.tv_usec) / 1000;
126 
127 #ifndef HAVE_STDARG_H
128 #error "endTimer required stdarg functions"
129 #endif
130     va_start(ap, fmt);
131     vfprintf(stderr, fmt, ap);
132     va_end(ap);
133 
134     fprintf(stderr, " took %ld ms\n", msec);
135 }
136 #elif defined(HAVE_TIME_H)
137 /*
138  * No gettimeofday function, so we have to make do with calling clock.
139  * This is obviously less accurate, but there's little we can do about
140  * that.
141  */
142 #ifndef CLOCKS_PER_SEC
143 #define CLOCKS_PER_SEC 100
144 #endif
145 
146 static clock_t begin, end;
147 static void
startTimer(void)148 startTimer(void)
149 {
150     begin = clock();
151 }
152 static void XMLCDECL
endTimer(const char * fmt,...)153 endTimer(const char *fmt, ...)
154 {
155     long msec;
156     va_list ap;
157 
158     end = clock();
159     msec = ((end - begin) * 1000) / CLOCKS_PER_SEC;
160 
161 #ifndef HAVE_STDARG_H
162 #error "endTimer required stdarg functions"
163 #endif
164     va_start(ap, fmt);
165     vfprintf(stderr, fmt, ap);
166     va_end(ap);
167     fprintf(stderr, " took %ld ms\n", msec);
168 }
169 #else
170 
171 /*
172  * We don't have a gettimeofday or time.h, so we just don't do timing
173  */
174 static void
startTimer(void)175 startTimer(void)
176 {
177     /*
178      * Do nothing
179      */
180 }
181 static void XMLCDECL
endTimer(char * format,...)182 endTimer(char *format, ...)
183 {
184     /*
185      * We cannot do anything because we don't have a timing function
186      */
187 #ifdef HAVE_STDARG_H
188     va_start(ap, format);
189     vfprintf(stderr, format, ap);
190     va_end(ap);
191     fprintf(stderr, " was not timed\n", msec);
192 #else
193     /* We don't have gettimeofday, time or stdarg.h, what crazy world is
194      * this ?!
195      */
196 #endif
197 }
198 #endif
199 
200 /*
201  * empty SAX block
202  */
203 static xmlSAXHandler emptySAXHandlerStruct = {
204     NULL, /* internalSubset */
205     NULL, /* isStandalone */
206     NULL, /* hasInternalSubset */
207     NULL, /* hasExternalSubset */
208     NULL, /* resolveEntity */
209     NULL, /* getEntity */
210     NULL, /* entityDecl */
211     NULL, /* notationDecl */
212     NULL, /* attributeDecl */
213     NULL, /* elementDecl */
214     NULL, /* unparsedEntityDecl */
215     NULL, /* setDocumentLocator */
216     NULL, /* startDocument */
217     NULL, /* endDocument */
218     NULL, /* startElement */
219     NULL, /* endElement */
220     NULL, /* reference */
221     NULL, /* characters */
222     NULL, /* ignorableWhitespace */
223     NULL, /* processingInstruction */
224     NULL, /* comment */
225     NULL, /* xmlParserWarning */
226     NULL, /* xmlParserError */
227     NULL, /* xmlParserError */
228     NULL, /* getParameterEntity */
229     NULL, /* cdataBlock; */
230     NULL, /* externalSubset; */
231     1,
232     NULL,
233     NULL, /* startElementNs */
234     NULL, /* endElementNs */
235     NULL  /* xmlStructuredErrorFunc */
236 };
237 
238 static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
239 extern xmlSAXHandlerPtr debugSAXHandler;
240 
241 /************************************************************************
242  *									*
243  *				Debug Handlers				*
244  *									*
245  ************************************************************************/
246 
247 /**
248  * isStandaloneDebug:
249  * @ctxt:  An XML parser context
250  *
251  * Is this document tagged standalone ?
252  *
253  * Returns 1 if true
254  */
255 static int
isStandaloneDebug(void * ctx ATTRIBUTE_UNUSED)256 isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
257 {
258     callbacks++;
259     if (quiet)
260 	return(0);
261     fprintf(stdout, "SAX.isStandalone()\n");
262     return(0);
263 }
264 
265 /**
266  * hasInternalSubsetDebug:
267  * @ctxt:  An XML parser context
268  *
269  * Does this document has an internal subset
270  *
271  * Returns 1 if true
272  */
273 static int
hasInternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)274 hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
275 {
276     callbacks++;
277     if (quiet)
278 	return(0);
279     fprintf(stdout, "SAX.hasInternalSubset()\n");
280     return(0);
281 }
282 
283 /**
284  * hasExternalSubsetDebug:
285  * @ctxt:  An XML parser context
286  *
287  * Does this document has an external subset
288  *
289  * Returns 1 if true
290  */
291 static int
hasExternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)292 hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
293 {
294     callbacks++;
295     if (quiet)
296 	return(0);
297     fprintf(stdout, "SAX.hasExternalSubset()\n");
298     return(0);
299 }
300 
301 /**
302  * internalSubsetDebug:
303  * @ctxt:  An XML parser context
304  *
305  * Does this document has an internal subset
306  */
307 static void
internalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)308 internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
309 	       const xmlChar *ExternalID, const xmlChar *SystemID)
310 {
311     callbacks++;
312     if (quiet)
313 	return;
314     fprintf(stdout, "SAX.internalSubset(%s,", name);
315     if (ExternalID == NULL)
316 	fprintf(stdout, " ,");
317     else
318 	fprintf(stdout, " %s,", ExternalID);
319     if (SystemID == NULL)
320 	fprintf(stdout, " )\n");
321     else
322 	fprintf(stdout, " %s)\n", SystemID);
323 }
324 
325 /**
326  * externalSubsetDebug:
327  * @ctxt:  An XML parser context
328  *
329  * Does this document has an external subset
330  */
331 static void
externalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)332 externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
333 	       const xmlChar *ExternalID, const xmlChar *SystemID)
334 {
335     callbacks++;
336     if (quiet)
337 	return;
338     fprintf(stdout, "SAX.externalSubset(%s,", name);
339     if (ExternalID == NULL)
340 	fprintf(stdout, " ,");
341     else
342 	fprintf(stdout, " %s,", ExternalID);
343     if (SystemID == NULL)
344 	fprintf(stdout, " )\n");
345     else
346 	fprintf(stdout, " %s)\n", SystemID);
347 }
348 
349 /**
350  * resolveEntityDebug:
351  * @ctxt:  An XML parser context
352  * @publicId: The public ID of the entity
353  * @systemId: The system ID of the entity
354  *
355  * Special entity resolver, better left to the parser, it has
356  * more context than the application layer.
357  * The default behaviour is to NOT resolve the entities, in that case
358  * the ENTITY_REF nodes are built in the structure (and the parameter
359  * values).
360  *
361  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
362  */
363 static xmlParserInputPtr
resolveEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * publicId,const xmlChar * systemId)364 resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
365 {
366     callbacks++;
367     if (quiet)
368 	return(NULL);
369     /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
370 
371 
372     fprintf(stdout, "SAX.resolveEntity(");
373     if (publicId != NULL)
374 	fprintf(stdout, "%s", (char *)publicId);
375     else
376 	fprintf(stdout, " ");
377     if (systemId != NULL)
378 	fprintf(stdout, ", %s)\n", (char *)systemId);
379     else
380 	fprintf(stdout, ", )\n");
381 /*********
382     if (systemId != NULL) {
383         return(xmlNewInputFromFile(ctxt, (char *) systemId));
384     }
385  *********/
386     return(NULL);
387 }
388 
389 /**
390  * getEntityDebug:
391  * @ctxt:  An XML parser context
392  * @name: The entity name
393  *
394  * Get an entity by name
395  *
396  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
397  */
398 static xmlEntityPtr
getEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)399 getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
400 {
401     callbacks++;
402     if (quiet)
403 	return(NULL);
404     fprintf(stdout, "SAX.getEntity(%s)\n", name);
405     return(NULL);
406 }
407 
408 /**
409  * getParameterEntityDebug:
410  * @ctxt:  An XML parser context
411  * @name: The entity name
412  *
413  * Get a parameter entity by name
414  *
415  * Returns the xmlParserInputPtr
416  */
417 static xmlEntityPtr
getParameterEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)418 getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
419 {
420     callbacks++;
421     if (quiet)
422 	return(NULL);
423     fprintf(stdout, "SAX.getParameterEntity(%s)\n", name);
424     return(NULL);
425 }
426 
427 
428 /**
429  * entityDeclDebug:
430  * @ctxt:  An XML parser context
431  * @name:  the entity name
432  * @type:  the entity type
433  * @publicId: The public ID of the entity
434  * @systemId: The system ID of the entity
435  * @content: the entity value (without processing).
436  *
437  * An entity definition has been parsed
438  */
439 static void
entityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)440 entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
441           const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
442 {
443 const xmlChar *nullstr = BAD_CAST "(null)";
444     /* not all libraries handle printing null pointers nicely */
445     if (publicId == NULL)
446         publicId = nullstr;
447     if (systemId == NULL)
448         systemId = nullstr;
449     if (content == NULL)
450         content = (xmlChar *)nullstr;
451     callbacks++;
452     if (quiet)
453 	return;
454     fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
455             name, type, publicId, systemId, content);
456 }
457 
458 /**
459  * attributeDeclDebug:
460  * @ctxt:  An XML parser context
461  * @name:  the attribute name
462  * @type:  the attribute type
463  *
464  * An attribute definition has been parsed
465  */
466 static void
attributeDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * elem,const xmlChar * name,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)467 attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
468                    const xmlChar * name, int type, int def,
469                    const xmlChar * defaultValue, xmlEnumerationPtr tree)
470 {
471     callbacks++;
472     if (quiet)
473         return;
474     if (defaultValue == NULL)
475         fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
476                 elem, name, type, def);
477     else
478         fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
479                 elem, name, type, def, defaultValue);
480     xmlFreeEnumeration(tree);
481 }
482 
483 /**
484  * elementDeclDebug:
485  * @ctxt:  An XML parser context
486  * @name:  the element name
487  * @type:  the element type
488  * @content: the element value (without processing).
489  *
490  * An element definition has been parsed
491  */
492 static void
elementDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,xmlElementContentPtr content ATTRIBUTE_UNUSED)493 elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
494 	    xmlElementContentPtr content ATTRIBUTE_UNUSED)
495 {
496     callbacks++;
497     if (quiet)
498 	return;
499     fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n",
500             name, type);
501 }
502 
503 /**
504  * notationDeclDebug:
505  * @ctxt:  An XML parser context
506  * @name: The name of the notation
507  * @publicId: The public ID of the entity
508  * @systemId: The system ID of the entity
509  *
510  * What to do when a notation declaration has been parsed.
511  */
512 static void
notationDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)513 notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
514 	     const xmlChar *publicId, const xmlChar *systemId)
515 {
516     callbacks++;
517     if (quiet)
518 	return;
519     fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n",
520             (char *) name, (char *) publicId, (char *) systemId);
521 }
522 
523 /**
524  * unparsedEntityDeclDebug:
525  * @ctxt:  An XML parser context
526  * @name: The name of the entity
527  * @publicId: The public ID of the entity
528  * @systemId: The system ID of the entity
529  * @notationName: the name of the notation
530  *
531  * What to do when an unparsed entity declaration is parsed
532  */
533 static void
unparsedEntityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)534 unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
535 		   const xmlChar *publicId, const xmlChar *systemId,
536 		   const xmlChar *notationName)
537 {
538 const xmlChar *nullstr = BAD_CAST "(null)";
539 
540     if (publicId == NULL)
541         publicId = nullstr;
542     if (systemId == NULL)
543         systemId = nullstr;
544     if (notationName == NULL)
545         notationName = nullstr;
546     callbacks++;
547     if (quiet)
548 	return;
549     fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
550             (char *) name, (char *) publicId, (char *) systemId,
551 	    (char *) notationName);
552 }
553 
554 /**
555  * setDocumentLocatorDebug:
556  * @ctxt:  An XML parser context
557  * @loc: A SAX Locator
558  *
559  * Receive the document locator at startup, actually xmlDefaultSAXLocator
560  * Everything is available on the context, so this is useless in our case.
561  */
562 static void
setDocumentLocatorDebug(void * ctx ATTRIBUTE_UNUSED,xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)563 setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
564 {
565     callbacks++;
566     if (quiet)
567 	return;
568     fprintf(stdout, "SAX.setDocumentLocator()\n");
569 }
570 
571 /**
572  * startDocumentDebug:
573  * @ctxt:  An XML parser context
574  *
575  * called when the document start being processed.
576  */
577 static void
startDocumentDebug(void * ctx ATTRIBUTE_UNUSED)578 startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
579 {
580     callbacks++;
581     if (quiet)
582 	return;
583     fprintf(stdout, "SAX.startDocument()\n");
584 }
585 
586 /**
587  * endDocumentDebug:
588  * @ctxt:  An XML parser context
589  *
590  * called when the document end has been detected.
591  */
592 static void
endDocumentDebug(void * ctx ATTRIBUTE_UNUSED)593 endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
594 {
595     callbacks++;
596     if (quiet)
597 	return;
598     fprintf(stdout, "SAX.endDocument()\n");
599 }
600 
601 /**
602  * startElementDebug:
603  * @ctxt:  An XML parser context
604  * @name:  The element name
605  *
606  * called when an opening tag has been processed.
607  */
608 static void
startElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar ** atts)609 startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
610 {
611     int i;
612 
613     callbacks++;
614     if (quiet)
615 	return;
616     fprintf(stdout, "SAX.startElement(%s", (char *) name);
617     if (atts != NULL) {
618         for (i = 0;(atts[i] != NULL);i++) {
619 	    fprintf(stdout, ", %s='", atts[i++]);
620 	    if (atts[i] != NULL)
621 	        fprintf(stdout, "%s'", atts[i]);
622 	}
623     }
624     fprintf(stdout, ")\n");
625 }
626 
627 /**
628  * endElementDebug:
629  * @ctxt:  An XML parser context
630  * @name:  The element name
631  *
632  * called when the end of an element has been detected.
633  */
634 static void
endElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)635 endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
636 {
637     callbacks++;
638     if (quiet)
639 	return;
640     fprintf(stdout, "SAX.endElement(%s)\n", (char *) name);
641 }
642 
643 /**
644  * charactersDebug:
645  * @ctxt:  An XML parser context
646  * @ch:  a xmlChar string
647  * @len: the number of xmlChar
648  *
649  * receiving some chars from the parser.
650  * Question: how much at a time ???
651  */
652 static void
charactersDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)653 charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
654 {
655     char output[40];
656     int i;
657 
658     callbacks++;
659     if (quiet)
660 	return;
661     for (i = 0;(i<len) && (i < 30);i++)
662 	output[i] = ch[i];
663     output[i] = 0;
664 
665     fprintf(stdout, "SAX.characters(%s, %d)\n", output, len);
666 }
667 
668 /**
669  * referenceDebug:
670  * @ctxt:  An XML parser context
671  * @name:  The entity name
672  *
673  * called when an entity reference is detected.
674  */
675 static void
referenceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)676 referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
677 {
678     callbacks++;
679     if (quiet)
680 	return;
681     fprintf(stdout, "SAX.reference(%s)\n", name);
682 }
683 
684 /**
685  * ignorableWhitespaceDebug:
686  * @ctxt:  An XML parser context
687  * @ch:  a xmlChar string
688  * @start: the first char in the string
689  * @len: the number of xmlChar
690  *
691  * receiving some ignorable whitespaces from the parser.
692  * Question: how much at a time ???
693  */
694 static void
ignorableWhitespaceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)695 ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
696 {
697     char output[40];
698     int i;
699 
700     callbacks++;
701     if (quiet)
702 	return;
703     for (i = 0;(i<len) && (i < 30);i++)
704 	output[i] = ch[i];
705     output[i] = 0;
706     fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
707 }
708 
709 /**
710  * processingInstructionDebug:
711  * @ctxt:  An XML parser context
712  * @target:  the target name
713  * @data: the PI data's
714  * @len: the number of xmlChar
715  *
716  * A processing instruction has been parsed.
717  */
718 static void
processingInstructionDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * target,const xmlChar * data)719 processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
720                       const xmlChar *data)
721 {
722     callbacks++;
723     if (quiet)
724 	return;
725     if (data != NULL)
726 	fprintf(stdout, "SAX.processingInstruction(%s, %s)\n",
727 		(char *) target, (char *) data);
728     else
729 	fprintf(stdout, "SAX.processingInstruction(%s, NULL)\n",
730 		(char *) target);
731 }
732 
733 /**
734  * cdataBlockDebug:
735  * @ctx: the user data (XML parser context)
736  * @value:  The pcdata content
737  * @len:  the block length
738  *
739  * called when a pcdata block has been parsed
740  */
741 static void
cdataBlockDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value,int len)742 cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
743 {
744     callbacks++;
745     if (quiet)
746 	return;
747     fprintf(stdout, "SAX.pcdata(%.20s, %d)\n",
748 	    (char *) value, len);
749 }
750 
751 /**
752  * commentDebug:
753  * @ctxt:  An XML parser context
754  * @value:  the comment content
755  *
756  * A comment has been parsed.
757  */
758 static void
commentDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value)759 commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
760 {
761     callbacks++;
762     if (quiet)
763 	return;
764     fprintf(stdout, "SAX.comment(%s)\n", value);
765 }
766 
767 /**
768  * warningDebug:
769  * @ctxt:  An XML parser context
770  * @msg:  the message to display/transmit
771  * @...:  extra parameters for the message display
772  *
773  * Display and format a warning messages, gives file, line, position and
774  * extra parameters.
775  */
776 static void XMLCDECL
warningDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)777 warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
778 {
779     va_list args;
780 
781     callbacks++;
782     if (quiet)
783 	return;
784     va_start(args, msg);
785     fprintf(stdout, "SAX.warning: ");
786     vfprintf(stdout, msg, args);
787     va_end(args);
788 }
789 
790 /**
791  * errorDebug:
792  * @ctxt:  An XML parser context
793  * @msg:  the message to display/transmit
794  * @...:  extra parameters for the message display
795  *
796  * Display and format a error messages, gives file, line, position and
797  * extra parameters.
798  */
799 static void XMLCDECL
errorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)800 errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
801 {
802     va_list args;
803 
804     callbacks++;
805     if (quiet)
806 	return;
807     va_start(args, msg);
808     fprintf(stdout, "SAX.error: ");
809     vfprintf(stdout, msg, args);
810     va_end(args);
811 }
812 
813 /**
814  * fatalErrorDebug:
815  * @ctxt:  An XML parser context
816  * @msg:  the message to display/transmit
817  * @...:  extra parameters for the message display
818  *
819  * Display and format a fatalError messages, gives file, line, position and
820  * extra parameters.
821  */
822 static void XMLCDECL
fatalErrorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)823 fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
824 {
825     va_list args;
826 
827     callbacks++;
828     if (quiet)
829 	return;
830     va_start(args, msg);
831     fprintf(stdout, "SAX.fatalError: ");
832     vfprintf(stdout, msg, args);
833     va_end(args);
834 }
835 
836 static xmlSAXHandler debugSAXHandlerStruct = {
837     internalSubsetDebug,
838     isStandaloneDebug,
839     hasInternalSubsetDebug,
840     hasExternalSubsetDebug,
841     resolveEntityDebug,
842     getEntityDebug,
843     entityDeclDebug,
844     notationDeclDebug,
845     attributeDeclDebug,
846     elementDeclDebug,
847     unparsedEntityDeclDebug,
848     setDocumentLocatorDebug,
849     startDocumentDebug,
850     endDocumentDebug,
851     startElementDebug,
852     endElementDebug,
853     referenceDebug,
854     charactersDebug,
855     ignorableWhitespaceDebug,
856     processingInstructionDebug,
857     commentDebug,
858     warningDebug,
859     errorDebug,
860     fatalErrorDebug,
861     getParameterEntityDebug,
862     cdataBlockDebug,
863     externalSubsetDebug,
864     1,
865     NULL,
866     NULL,
867     NULL,
868     NULL
869 };
870 
871 xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
872 
873 /*
874  * SAX2 specific callbacks
875  */
876 /**
877  * startElementNsDebug:
878  * @ctxt:  An XML parser context
879  * @name:  The element name
880  *
881  * called when an opening tag has been processed.
882  */
883 static void
startElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)884 startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
885                     const xmlChar *localname,
886                     const xmlChar *prefix,
887                     const xmlChar *URI,
888 		    int nb_namespaces,
889 		    const xmlChar **namespaces,
890 		    int nb_attributes,
891 		    int nb_defaulted,
892 		    const xmlChar **attributes)
893 {
894     int i;
895 
896     callbacks++;
897     if (quiet)
898 	return;
899     fprintf(stdout, "SAX.startElementNs(%s", (char *) localname);
900     if (prefix == NULL)
901 	fprintf(stdout, ", NULL");
902     else
903 	fprintf(stdout, ", %s", (char *) prefix);
904     if (URI == NULL)
905 	fprintf(stdout, ", NULL");
906     else
907 	fprintf(stdout, ", '%s'", (char *) URI);
908     fprintf(stdout, ", %d", nb_namespaces);
909 
910     if (namespaces != NULL) {
911         for (i = 0;i < nb_namespaces * 2;i++) {
912 	    fprintf(stdout, ", xmlns");
913 	    if (namespaces[i] != NULL)
914 	        fprintf(stdout, ":%s", namespaces[i]);
915 	    i++;
916 	    fprintf(stdout, "='%s'", namespaces[i]);
917 	}
918     }
919     fprintf(stdout, ", %d, %d", nb_attributes, nb_defaulted);
920     if (attributes != NULL) {
921         for (i = 0;i < nb_attributes * 5;i += 5) {
922 	    if (attributes[i + 1] != NULL)
923 		fprintf(stdout, ", %s:%s='", attributes[i + 1], attributes[i]);
924 	    else
925 		fprintf(stdout, ", %s='", attributes[i]);
926 	    fprintf(stdout, "%.4s...', %d", attributes[i + 3],
927 		    (int)(attributes[i + 4] - attributes[i + 3]));
928 	}
929     }
930     fprintf(stdout, ")\n");
931 }
932 
933 /**
934  * endElementDebug:
935  * @ctxt:  An XML parser context
936  * @name:  The element name
937  *
938  * called when the end of an element has been detected.
939  */
940 static void
endElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)941 endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
942                   const xmlChar *localname,
943                   const xmlChar *prefix,
944                   const xmlChar *URI)
945 {
946     callbacks++;
947     if (quiet)
948 	return;
949     fprintf(stdout, "SAX.endElementNs(%s", (char *) localname);
950     if (prefix == NULL)
951 	fprintf(stdout, ", NULL");
952     else
953 	fprintf(stdout, ", %s", (char *) prefix);
954     if (URI == NULL)
955 	fprintf(stdout, ", NULL)\n");
956     else
957 	fprintf(stdout, ", '%s')\n", (char *) URI);
958 }
959 
960 static xmlSAXHandler debugSAX2HandlerStruct = {
961     internalSubsetDebug,
962     isStandaloneDebug,
963     hasInternalSubsetDebug,
964     hasExternalSubsetDebug,
965     resolveEntityDebug,
966     getEntityDebug,
967     entityDeclDebug,
968     notationDeclDebug,
969     attributeDeclDebug,
970     elementDeclDebug,
971     unparsedEntityDeclDebug,
972     setDocumentLocatorDebug,
973     startDocumentDebug,
974     endDocumentDebug,
975     NULL,
976     NULL,
977     referenceDebug,
978     charactersDebug,
979     ignorableWhitespaceDebug,
980     processingInstructionDebug,
981     commentDebug,
982     warningDebug,
983     errorDebug,
984     fatalErrorDebug,
985     getParameterEntityDebug,
986     cdataBlockDebug,
987     externalSubsetDebug,
988     XML_SAX2_MAGIC,
989     NULL,
990     startElementNsDebug,
991     endElementNsDebug,
992     NULL
993 };
994 
995 static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
996 
997 /************************************************************************
998  *									*
999  *				Debug					*
1000  *									*
1001  ************************************************************************/
1002 
1003 static void
parseAndPrintFile(char * filename)1004 parseAndPrintFile(char *filename) {
1005     int res;
1006 
1007 #ifdef LIBXML_PUSH_ENABLED
1008     if (push) {
1009 	FILE *f;
1010 
1011         if ((!quiet) && (!nonull)) {
1012 	    /*
1013 	     * Empty callbacks for checking
1014 	     */
1015 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1016 	    f = fopen(filename, "rb");
1017 #else
1018 	    f = fopen(filename, "r");
1019 #endif
1020 	    if (f != NULL) {
1021 		int ret;
1022 		char chars[10];
1023 		xmlParserCtxtPtr ctxt;
1024 
1025 		ret = fread(chars, 1, 4, f);
1026 		if (ret > 0) {
1027 		    ctxt = xmlCreatePushParserCtxt(emptySAXHandler, NULL,
1028 				chars, ret, filename);
1029 		    while ((ret = fread(chars, 1, 3, f)) > 0) {
1030 			xmlParseChunk(ctxt, chars, ret, 0);
1031 		    }
1032 		    xmlParseChunk(ctxt, chars, 0, 1);
1033 		    xmlFreeParserCtxt(ctxt);
1034 		}
1035 		fclose(f);
1036 	    } else {
1037 		xmlGenericError(xmlGenericErrorContext,
1038 			"Cannot read file %s\n", filename);
1039 	    }
1040 	}
1041 	/*
1042 	 * Debug callback
1043 	 */
1044 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1045 	f = fopen(filename, "rb");
1046 #else
1047 	f = fopen(filename, "r");
1048 #endif
1049 	if (f != NULL) {
1050 	    int ret;
1051 	    char chars[10];
1052 	    xmlParserCtxtPtr ctxt;
1053 
1054 	    ret = fread(chars, 1, 4, f);
1055 	    if (ret > 0) {
1056 	        if (sax2)
1057 		    ctxt = xmlCreatePushParserCtxt(debugSAX2Handler, NULL,
1058 				chars, ret, filename);
1059 		else
1060 		    ctxt = xmlCreatePushParserCtxt(debugSAXHandler, NULL,
1061 				chars, ret, filename);
1062 		while ((ret = fread(chars, 1, 3, f)) > 0) {
1063 		    xmlParseChunk(ctxt, chars, ret, 0);
1064 		}
1065 		ret = xmlParseChunk(ctxt, chars, 0, 1);
1066 		xmlFreeParserCtxt(ctxt);
1067 		if (ret != 0) {
1068 		    fprintf(stdout,
1069 		            "xmlSAXUserParseFile returned error %d\n", ret);
1070 		}
1071 	    }
1072 	    fclose(f);
1073 	}
1074     } else {
1075 #endif /* LIBXML_PUSH_ENABLED */
1076 	if (!speed) {
1077 	    /*
1078 	     * Empty callbacks for checking
1079 	     */
1080 	    if ((!quiet) && (!nonull)) {
1081 		res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1082 		if (res != 0) {
1083 		    fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
1084 		}
1085 	    }
1086 
1087 	    /*
1088 	     * Debug callback
1089 	     */
1090 	    callbacks = 0;
1091 	    if (repeat) {
1092 	        int i;
1093 		for (i = 0;i < 99;i++) {
1094 		    if (sax2)
1095 			res = xmlSAXUserParseFile(debugSAX2Handler, NULL,
1096 			                          filename);
1097 		    else
1098 			res = xmlSAXUserParseFile(debugSAXHandler, NULL,
1099 			                          filename);
1100 		}
1101 	    }
1102 	    if (sax2)
1103 	        res = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename);
1104 	    else
1105 		res = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
1106 	    if (res != 0) {
1107 		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
1108 	    }
1109 	    if (quiet)
1110 		fprintf(stdout, "%d callbacks generated\n", callbacks);
1111 	} else {
1112 	    /*
1113 	     * test 100x the SAX parse
1114 	     */
1115 	    int i;
1116 
1117 	    for (i = 0; i<100;i++)
1118 		res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1119 	    if (res != 0) {
1120 		fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res);
1121 	    }
1122 	}
1123 #ifdef LIBXML_PUSH_ENABLED
1124     }
1125 #endif
1126 }
1127 
1128 
main(int argc,char ** argv)1129 int main(int argc, char **argv) {
1130     int i;
1131     int files = 0;
1132 
1133     LIBXML_TEST_VERSION	/* be safe, plus calls xmlInitParser */
1134 
1135     for (i = 1; i < argc ; i++) {
1136 	if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug")))
1137 	    debug++;
1138 	else if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy")))
1139 	    copy++;
1140 	else if ((!strcmp(argv[i], "-recover")) ||
1141 	         (!strcmp(argv[i], "--recover")))
1142 	    recovery++;
1143 	else if ((!strcmp(argv[i], "-push")) ||
1144 	         (!strcmp(argv[i], "--push")))
1145 #ifdef LIBXML_PUSH_ENABLED
1146 	    push++;
1147 #else
1148 	    fprintf(stderr,"'push' not enabled in library - ignoring\n");
1149 #endif /* LIBXML_PUSH_ENABLED */
1150 	else if ((!strcmp(argv[i], "-speed")) ||
1151 	         (!strcmp(argv[i], "--speed")))
1152 	    speed++;
1153 	else if ((!strcmp(argv[i], "-timing")) ||
1154 	         (!strcmp(argv[i], "--timing"))) {
1155 	    nonull++;
1156 	    timing++;
1157 	    quiet++;
1158 	} else if ((!strcmp(argv[i], "-repeat")) ||
1159 	         (!strcmp(argv[i], "--repeat"))) {
1160 	    repeat++;
1161 	    quiet++;
1162 	} else if ((!strcmp(argv[i], "-noent")) ||
1163 	         (!strcmp(argv[i], "--noent")))
1164 	    noent++;
1165 	else if ((!strcmp(argv[i], "-quiet")) ||
1166 	         (!strcmp(argv[i], "--quiet")))
1167 	    quiet++;
1168 	else if ((!strcmp(argv[i], "-sax2")) ||
1169 	         (!strcmp(argv[i], "--sax2")))
1170 	    sax2++;
1171 	else if ((!strcmp(argv[i], "-nonull")) ||
1172 	         (!strcmp(argv[i], "--nonull")))
1173 	    nonull++;
1174     }
1175     if (noent != 0) xmlSubstituteEntitiesDefault(1);
1176     for (i = 1; i < argc ; i++) {
1177 	if (argv[i][0] != '-') {
1178 	    if (timing) {
1179 		startTimer();
1180 	    }
1181 	    parseAndPrintFile(argv[i]);
1182 	    if (timing) {
1183 		endTimer("Parsing");
1184 	    }
1185 	    files ++;
1186 	}
1187     }
1188     xmlCleanupParser();
1189     xmlMemoryDump();
1190 
1191     return(0);
1192 }
1193 #else
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)1194 int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1195     printf("%s : SAX1 parsing support not compiled in\n", argv[0]);
1196     return(0);
1197 }
1198 #endif /* LIBXML_SAX1_ENABLED */
1199