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