You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1198 lines
27 KiB
1198 lines
27 KiB
/* |
|
* testSAX.c : a small tester program for parsing using the SAX API. |
|
* |
|
* See Copyright for the status of this software. |
|
* |
|
* daniel@veillard.com |
|
*/ |
|
|
|
#include "libxml.h" |
|
|
|
#ifdef HAVE_SYS_TIME_H |
|
#include <sys/time.h> |
|
#endif |
|
#ifdef HAVE_SYS_TIMEB_H |
|
#include <sys/timeb.h> |
|
#endif |
|
#ifdef HAVE_TIME_H |
|
#include <time.h> |
|
#endif |
|
|
|
#ifdef LIBXML_SAX1_ENABLED |
|
#include <string.h> |
|
#include <stdarg.h> |
|
|
|
#ifdef HAVE_SYS_TYPES_H |
|
#include <sys/types.h> |
|
#endif |
|
#ifdef HAVE_SYS_STAT_H |
|
#include <sys/stat.h> |
|
#endif |
|
#ifdef HAVE_FCNTL_H |
|
#include <fcntl.h> |
|
#endif |
|
#ifdef HAVE_UNISTD_H |
|
#include <unistd.h> |
|
#endif |
|
#ifdef HAVE_STDLIB_H |
|
#include <stdlib.h> |
|
#endif |
|
#ifdef HAVE_STRING_H |
|
#include <string.h> |
|
#endif |
|
|
|
|
|
#include <libxml/globals.h> |
|
#include <libxml/xmlerror.h> |
|
#include <libxml/parser.h> |
|
#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */ |
|
#include <libxml/tree.h> |
|
#include <libxml/debugXML.h> |
|
#include <libxml/xmlmemory.h> |
|
|
|
static int debug = 0; |
|
static int copy = 0; |
|
static int recovery = 0; |
|
static int push = 0; |
|
static int speed = 0; |
|
static int noent = 0; |
|
static int quiet = 0; |
|
static int nonull = 0; |
|
static int sax2 = 0; |
|
static int repeat = 0; |
|
static int callbacks = 0; |
|
static int timing = 0; |
|
|
|
/* |
|
* Timing routines. |
|
*/ |
|
/* |
|
* Internal timing routines to remove the necessity to have unix-specific |
|
* function calls |
|
*/ |
|
|
|
#ifndef HAVE_GETTIMEOFDAY |
|
#ifdef HAVE_SYS_TIMEB_H |
|
#ifdef HAVE_SYS_TIME_H |
|
#ifdef HAVE_FTIME |
|
|
|
static int |
|
my_gettimeofday(struct timeval *tvp, void *tzp) |
|
{ |
|
struct timeb timebuffer; |
|
|
|
ftime(&timebuffer); |
|
if (tvp) { |
|
tvp->tv_sec = timebuffer.time; |
|
tvp->tv_usec = timebuffer.millitm * 1000L; |
|
} |
|
return (0); |
|
} |
|
#define HAVE_GETTIMEOFDAY 1 |
|
#define gettimeofday my_gettimeofday |
|
|
|
#endif /* HAVE_FTIME */ |
|
#endif /* HAVE_SYS_TIME_H */ |
|
#endif /* HAVE_SYS_TIMEB_H */ |
|
#endif /* !HAVE_GETTIMEOFDAY */ |
|
|
|
#if defined(HAVE_GETTIMEOFDAY) |
|
static struct timeval begin, end; |
|
|
|
/* |
|
* startTimer: call where you want to start timing |
|
*/ |
|
static void |
|
startTimer(void) |
|
{ |
|
gettimeofday(&begin, NULL); |
|
} |
|
|
|
/* |
|
* endTimer: call where you want to stop timing and to print out a |
|
* message about the timing performed; format is a printf |
|
* type argument |
|
*/ |
|
static void XMLCDECL |
|
endTimer(const char *fmt, ...) |
|
{ |
|
long msec; |
|
va_list ap; |
|
|
|
gettimeofday(&end, NULL); |
|
msec = end.tv_sec - begin.tv_sec; |
|
msec *= 1000; |
|
msec += (end.tv_usec - begin.tv_usec) / 1000; |
|
|
|
#ifndef HAVE_STDARG_H |
|
#error "endTimer required stdarg functions" |
|
#endif |
|
va_start(ap, fmt); |
|
vfprintf(stderr, fmt, ap); |
|
va_end(ap); |
|
|
|
fprintf(stderr, " took %ld ms\n", msec); |
|
} |
|
#elif defined(HAVE_TIME_H) |
|
/* |
|
* No gettimeofday function, so we have to make do with calling clock. |
|
* This is obviously less accurate, but there's little we can do about |
|
* that. |
|
*/ |
|
#ifndef CLOCKS_PER_SEC |
|
#define CLOCKS_PER_SEC 100 |
|
#endif |
|
|
|
static clock_t begin, end; |
|
static void |
|
startTimer(void) |
|
{ |
|
begin = clock(); |
|
} |
|
static void XMLCDECL |
|
endTimer(const char *fmt, ...) |
|
{ |
|
long msec; |
|
va_list ap; |
|
|
|
end = clock(); |
|
msec = ((end - begin) * 1000) / CLOCKS_PER_SEC; |
|
|
|
#ifndef HAVE_STDARG_H |
|
#error "endTimer required stdarg functions" |
|
#endif |
|
va_start(ap, fmt); |
|
vfprintf(stderr, fmt, ap); |
|
va_end(ap); |
|
fprintf(stderr, " took %ld ms\n", msec); |
|
} |
|
#else |
|
|
|
/* |
|
* We don't have a gettimeofday or time.h, so we just don't do timing |
|
*/ |
|
static void |
|
startTimer(void) |
|
{ |
|
/* |
|
* Do nothing |
|
*/ |
|
} |
|
static void XMLCDECL |
|
endTimer(char *format, ...) |
|
{ |
|
/* |
|
* We cannot do anything because we don't have a timing function |
|
*/ |
|
#ifdef HAVE_STDARG_H |
|
va_start(ap, format); |
|
vfprintf(stderr, format, ap); |
|
va_end(ap); |
|
fprintf(stderr, " was not timed\n", msec); |
|
#else |
|
/* We don't have gettimeofday, time or stdarg.h, what crazy world is |
|
* this ?! |
|
*/ |
|
#endif |
|
} |
|
#endif |
|
|
|
/* |
|
* empty SAX block |
|
*/ |
|
static xmlSAXHandler emptySAXHandlerStruct = { |
|
NULL, /* internalSubset */ |
|
NULL, /* isStandalone */ |
|
NULL, /* hasInternalSubset */ |
|
NULL, /* hasExternalSubset */ |
|
NULL, /* resolveEntity */ |
|
NULL, /* getEntity */ |
|
NULL, /* entityDecl */ |
|
NULL, /* notationDecl */ |
|
NULL, /* attributeDecl */ |
|
NULL, /* elementDecl */ |
|
NULL, /* unparsedEntityDecl */ |
|
NULL, /* setDocumentLocator */ |
|
NULL, /* startDocument */ |
|
NULL, /* endDocument */ |
|
NULL, /* startElement */ |
|
NULL, /* endElement */ |
|
NULL, /* reference */ |
|
NULL, /* characters */ |
|
NULL, /* ignorableWhitespace */ |
|
NULL, /* processingInstruction */ |
|
NULL, /* comment */ |
|
NULL, /* xmlParserWarning */ |
|
NULL, /* xmlParserError */ |
|
NULL, /* xmlParserError */ |
|
NULL, /* getParameterEntity */ |
|
NULL, /* cdataBlock; */ |
|
NULL, /* externalSubset; */ |
|
1, |
|
NULL, |
|
NULL, /* startElementNs */ |
|
NULL, /* endElementNs */ |
|
NULL /* xmlStructuredErrorFunc */ |
|
}; |
|
|
|
static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct; |
|
extern xmlSAXHandlerPtr debugSAXHandler; |
|
|
|
/************************************************************************ |
|
* * |
|
* Debug Handlers * |
|
* * |
|
************************************************************************/ |
|
|
|
/** |
|
* isStandaloneDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* Is this document tagged standalone ? |
|
* |
|
* Returns 1 if true |
|
*/ |
|
static int |
|
isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return(0); |
|
fprintf(stdout, "SAX.isStandalone()\n"); |
|
return(0); |
|
} |
|
|
|
/** |
|
* hasInternalSubsetDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* Does this document has an internal subset |
|
* |
|
* Returns 1 if true |
|
*/ |
|
static int |
|
hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return(0); |
|
fprintf(stdout, "SAX.hasInternalSubset()\n"); |
|
return(0); |
|
} |
|
|
|
/** |
|
* hasExternalSubsetDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* Does this document has an external subset |
|
* |
|
* Returns 1 if true |
|
*/ |
|
static int |
|
hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return(0); |
|
fprintf(stdout, "SAX.hasExternalSubset()\n"); |
|
return(0); |
|
} |
|
|
|
/** |
|
* internalSubsetDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* Does this document has an internal subset |
|
*/ |
|
static void |
|
internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, |
|
const xmlChar *ExternalID, const xmlChar *SystemID) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.internalSubset(%s,", name); |
|
if (ExternalID == NULL) |
|
fprintf(stdout, " ,"); |
|
else |
|
fprintf(stdout, " %s,", ExternalID); |
|
if (SystemID == NULL) |
|
fprintf(stdout, " )\n"); |
|
else |
|
fprintf(stdout, " %s)\n", SystemID); |
|
} |
|
|
|
/** |
|
* externalSubsetDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* Does this document has an external subset |
|
*/ |
|
static void |
|
externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, |
|
const xmlChar *ExternalID, const xmlChar *SystemID) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.externalSubset(%s,", name); |
|
if (ExternalID == NULL) |
|
fprintf(stdout, " ,"); |
|
else |
|
fprintf(stdout, " %s,", ExternalID); |
|
if (SystemID == NULL) |
|
fprintf(stdout, " )\n"); |
|
else |
|
fprintf(stdout, " %s)\n", SystemID); |
|
} |
|
|
|
/** |
|
* resolveEntityDebug: |
|
* @ctxt: An XML parser context |
|
* @publicId: The public ID of the entity |
|
* @systemId: The system ID of the entity |
|
* |
|
* Special entity resolver, better left to the parser, it has |
|
* more context than the application layer. |
|
* The default behaviour is to NOT resolve the entities, in that case |
|
* the ENTITY_REF nodes are built in the structure (and the parameter |
|
* values). |
|
* |
|
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. |
|
*/ |
|
static xmlParserInputPtr |
|
resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return(NULL); |
|
/* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */ |
|
|
|
|
|
fprintf(stdout, "SAX.resolveEntity("); |
|
if (publicId != NULL) |
|
fprintf(stdout, "%s", (char *)publicId); |
|
else |
|
fprintf(stdout, " "); |
|
if (systemId != NULL) |
|
fprintf(stdout, ", %s)\n", (char *)systemId); |
|
else |
|
fprintf(stdout, ", )\n"); |
|
/********* |
|
if (systemId != NULL) { |
|
return(xmlNewInputFromFile(ctxt, (char *) systemId)); |
|
} |
|
*********/ |
|
return(NULL); |
|
} |
|
|
|
/** |
|
* getEntityDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The entity name |
|
* |
|
* Get an entity by name |
|
* |
|
* Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour. |
|
*/ |
|
static xmlEntityPtr |
|
getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return(NULL); |
|
fprintf(stdout, "SAX.getEntity(%s)\n", name); |
|
return(NULL); |
|
} |
|
|
|
/** |
|
* getParameterEntityDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The entity name |
|
* |
|
* Get a parameter entity by name |
|
* |
|
* Returns the xmlParserInputPtr |
|
*/ |
|
static xmlEntityPtr |
|
getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return(NULL); |
|
fprintf(stdout, "SAX.getParameterEntity(%s)\n", name); |
|
return(NULL); |
|
} |
|
|
|
|
|
/** |
|
* entityDeclDebug: |
|
* @ctxt: An XML parser context |
|
* @name: the entity name |
|
* @type: the entity type |
|
* @publicId: The public ID of the entity |
|
* @systemId: The system ID of the entity |
|
* @content: the entity value (without processing). |
|
* |
|
* An entity definition has been parsed |
|
*/ |
|
static void |
|
entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, |
|
const xmlChar *publicId, const xmlChar *systemId, xmlChar *content) |
|
{ |
|
const xmlChar *nullstr = BAD_CAST "(null)"; |
|
/* not all libraries handle printing null pointers nicely */ |
|
if (publicId == NULL) |
|
publicId = nullstr; |
|
if (systemId == NULL) |
|
systemId = nullstr; |
|
if (content == NULL) |
|
content = (xmlChar *)nullstr; |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n", |
|
name, type, publicId, systemId, content); |
|
} |
|
|
|
/** |
|
* attributeDeclDebug: |
|
* @ctxt: An XML parser context |
|
* @name: the attribute name |
|
* @type: the attribute type |
|
* |
|
* An attribute definition has been parsed |
|
*/ |
|
static void |
|
attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem, |
|
const xmlChar * name, int type, int def, |
|
const xmlChar * defaultValue, xmlEnumerationPtr tree) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
if (defaultValue == NULL) |
|
fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n", |
|
elem, name, type, def); |
|
else |
|
fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n", |
|
elem, name, type, def, defaultValue); |
|
xmlFreeEnumeration(tree); |
|
} |
|
|
|
/** |
|
* elementDeclDebug: |
|
* @ctxt: An XML parser context |
|
* @name: the element name |
|
* @type: the element type |
|
* @content: the element value (without processing). |
|
* |
|
* An element definition has been parsed |
|
*/ |
|
static void |
|
elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type, |
|
xmlElementContentPtr content ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n", |
|
name, type); |
|
} |
|
|
|
/** |
|
* notationDeclDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The name of the notation |
|
* @publicId: The public ID of the entity |
|
* @systemId: The system ID of the entity |
|
* |
|
* What to do when a notation declaration has been parsed. |
|
*/ |
|
static void |
|
notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, |
|
const xmlChar *publicId, const xmlChar *systemId) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n", |
|
(char *) name, (char *) publicId, (char *) systemId); |
|
} |
|
|
|
/** |
|
* unparsedEntityDeclDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The name of the entity |
|
* @publicId: The public ID of the entity |
|
* @systemId: The system ID of the entity |
|
* @notationName: the name of the notation |
|
* |
|
* What to do when an unparsed entity declaration is parsed |
|
*/ |
|
static void |
|
unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, |
|
const xmlChar *publicId, const xmlChar *systemId, |
|
const xmlChar *notationName) |
|
{ |
|
const xmlChar *nullstr = BAD_CAST "(null)"; |
|
|
|
if (publicId == NULL) |
|
publicId = nullstr; |
|
if (systemId == NULL) |
|
systemId = nullstr; |
|
if (notationName == NULL) |
|
notationName = nullstr; |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n", |
|
(char *) name, (char *) publicId, (char *) systemId, |
|
(char *) notationName); |
|
} |
|
|
|
/** |
|
* setDocumentLocatorDebug: |
|
* @ctxt: An XML parser context |
|
* @loc: A SAX Locator |
|
* |
|
* Receive the document locator at startup, actually xmlDefaultSAXLocator |
|
* Everything is available on the context, so this is useless in our case. |
|
*/ |
|
static void |
|
setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.setDocumentLocator()\n"); |
|
} |
|
|
|
/** |
|
* startDocumentDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* called when the document start being processed. |
|
*/ |
|
static void |
|
startDocumentDebug(void *ctx ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.startDocument()\n"); |
|
} |
|
|
|
/** |
|
* endDocumentDebug: |
|
* @ctxt: An XML parser context |
|
* |
|
* called when the document end has been detected. |
|
*/ |
|
static void |
|
endDocumentDebug(void *ctx ATTRIBUTE_UNUSED) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.endDocument()\n"); |
|
} |
|
|
|
/** |
|
* startElementDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The element name |
|
* |
|
* called when an opening tag has been processed. |
|
*/ |
|
static void |
|
startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts) |
|
{ |
|
int i; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.startElement(%s", (char *) name); |
|
if (atts != NULL) { |
|
for (i = 0;(atts[i] != NULL);i++) { |
|
fprintf(stdout, ", %s='", atts[i++]); |
|
if (atts[i] != NULL) |
|
fprintf(stdout, "%s'", atts[i]); |
|
} |
|
} |
|
fprintf(stdout, ")\n"); |
|
} |
|
|
|
/** |
|
* endElementDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The element name |
|
* |
|
* called when the end of an element has been detected. |
|
*/ |
|
static void |
|
endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.endElement(%s)\n", (char *) name); |
|
} |
|
|
|
/** |
|
* charactersDebug: |
|
* @ctxt: An XML parser context |
|
* @ch: a xmlChar string |
|
* @len: the number of xmlChar |
|
* |
|
* receiving some chars from the parser. |
|
* Question: how much at a time ??? |
|
*/ |
|
static void |
|
charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) |
|
{ |
|
char output[40]; |
|
int i; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
for (i = 0;(i<len) && (i < 30);i++) |
|
output[i] = ch[i]; |
|
output[i] = 0; |
|
|
|
fprintf(stdout, "SAX.characters(%s, %d)\n", output, len); |
|
} |
|
|
|
/** |
|
* referenceDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The entity name |
|
* |
|
* called when an entity reference is detected. |
|
*/ |
|
static void |
|
referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.reference(%s)\n", name); |
|
} |
|
|
|
/** |
|
* ignorableWhitespaceDebug: |
|
* @ctxt: An XML parser context |
|
* @ch: a xmlChar string |
|
* @start: the first char in the string |
|
* @len: the number of xmlChar |
|
* |
|
* receiving some ignorable whitespaces from the parser. |
|
* Question: how much at a time ??? |
|
*/ |
|
static void |
|
ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len) |
|
{ |
|
char output[40]; |
|
int i; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
for (i = 0;(i<len) && (i < 30);i++) |
|
output[i] = ch[i]; |
|
output[i] = 0; |
|
fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", output, len); |
|
} |
|
|
|
/** |
|
* processingInstructionDebug: |
|
* @ctxt: An XML parser context |
|
* @target: the target name |
|
* @data: the PI data's |
|
* @len: the number of xmlChar |
|
* |
|
* A processing instruction has been parsed. |
|
*/ |
|
static void |
|
processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target, |
|
const xmlChar *data) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
if (data != NULL) |
|
fprintf(stdout, "SAX.processingInstruction(%s, %s)\n", |
|
(char *) target, (char *) data); |
|
else |
|
fprintf(stdout, "SAX.processingInstruction(%s, NULL)\n", |
|
(char *) target); |
|
} |
|
|
|
/** |
|
* cdataBlockDebug: |
|
* @ctx: the user data (XML parser context) |
|
* @value: The pcdata content |
|
* @len: the block length |
|
* |
|
* called when a pcdata block has been parsed |
|
*/ |
|
static void |
|
cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.pcdata(%.20s, %d)\n", |
|
(char *) value, len); |
|
} |
|
|
|
/** |
|
* commentDebug: |
|
* @ctxt: An XML parser context |
|
* @value: the comment content |
|
* |
|
* A comment has been parsed. |
|
*/ |
|
static void |
|
commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.comment(%s)\n", value); |
|
} |
|
|
|
/** |
|
* warningDebug: |
|
* @ctxt: An XML parser context |
|
* @msg: the message to display/transmit |
|
* @...: extra parameters for the message display |
|
* |
|
* Display and format a warning messages, gives file, line, position and |
|
* extra parameters. |
|
*/ |
|
static void XMLCDECL |
|
warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) |
|
{ |
|
va_list args; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
va_start(args, msg); |
|
fprintf(stdout, "SAX.warning: "); |
|
vfprintf(stdout, msg, args); |
|
va_end(args); |
|
} |
|
|
|
/** |
|
* errorDebug: |
|
* @ctxt: An XML parser context |
|
* @msg: the message to display/transmit |
|
* @...: extra parameters for the message display |
|
* |
|
* Display and format a error messages, gives file, line, position and |
|
* extra parameters. |
|
*/ |
|
static void XMLCDECL |
|
errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) |
|
{ |
|
va_list args; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
va_start(args, msg); |
|
fprintf(stdout, "SAX.error: "); |
|
vfprintf(stdout, msg, args); |
|
va_end(args); |
|
} |
|
|
|
/** |
|
* fatalErrorDebug: |
|
* @ctxt: An XML parser context |
|
* @msg: the message to display/transmit |
|
* @...: extra parameters for the message display |
|
* |
|
* Display and format a fatalError messages, gives file, line, position and |
|
* extra parameters. |
|
*/ |
|
static void XMLCDECL |
|
fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) |
|
{ |
|
va_list args; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
va_start(args, msg); |
|
fprintf(stdout, "SAX.fatalError: "); |
|
vfprintf(stdout, msg, args); |
|
va_end(args); |
|
} |
|
|
|
static xmlSAXHandler debugSAXHandlerStruct = { |
|
internalSubsetDebug, |
|
isStandaloneDebug, |
|
hasInternalSubsetDebug, |
|
hasExternalSubsetDebug, |
|
resolveEntityDebug, |
|
getEntityDebug, |
|
entityDeclDebug, |
|
notationDeclDebug, |
|
attributeDeclDebug, |
|
elementDeclDebug, |
|
unparsedEntityDeclDebug, |
|
setDocumentLocatorDebug, |
|
startDocumentDebug, |
|
endDocumentDebug, |
|
startElementDebug, |
|
endElementDebug, |
|
referenceDebug, |
|
charactersDebug, |
|
ignorableWhitespaceDebug, |
|
processingInstructionDebug, |
|
commentDebug, |
|
warningDebug, |
|
errorDebug, |
|
fatalErrorDebug, |
|
getParameterEntityDebug, |
|
cdataBlockDebug, |
|
externalSubsetDebug, |
|
1, |
|
NULL, |
|
NULL, |
|
NULL, |
|
NULL |
|
}; |
|
|
|
xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct; |
|
|
|
/* |
|
* SAX2 specific callbacks |
|
*/ |
|
/** |
|
* startElementNsDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The element name |
|
* |
|
* called when an opening tag has been processed. |
|
*/ |
|
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) |
|
{ |
|
int i; |
|
|
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.startElementNs(%s", (char *) localname); |
|
if (prefix == NULL) |
|
fprintf(stdout, ", NULL"); |
|
else |
|
fprintf(stdout, ", %s", (char *) prefix); |
|
if (URI == NULL) |
|
fprintf(stdout, ", NULL"); |
|
else |
|
fprintf(stdout, ", '%s'", (char *) URI); |
|
fprintf(stdout, ", %d", nb_namespaces); |
|
|
|
if (namespaces != NULL) { |
|
for (i = 0;i < nb_namespaces * 2;i++) { |
|
fprintf(stdout, ", xmlns"); |
|
if (namespaces[i] != NULL) |
|
fprintf(stdout, ":%s", namespaces[i]); |
|
i++; |
|
fprintf(stdout, "='%s'", namespaces[i]); |
|
} |
|
} |
|
fprintf(stdout, ", %d, %d", nb_attributes, nb_defaulted); |
|
if (attributes != NULL) { |
|
for (i = 0;i < nb_attributes * 5;i += 5) { |
|
if (attributes[i + 1] != NULL) |
|
fprintf(stdout, ", %s:%s='", attributes[i + 1], attributes[i]); |
|
else |
|
fprintf(stdout, ", %s='", attributes[i]); |
|
fprintf(stdout, "%.4s...', %d", attributes[i + 3], |
|
(int)(attributes[i + 4] - attributes[i + 3])); |
|
} |
|
} |
|
fprintf(stdout, ")\n"); |
|
} |
|
|
|
/** |
|
* endElementDebug: |
|
* @ctxt: An XML parser context |
|
* @name: The element name |
|
* |
|
* called when the end of an element has been detected. |
|
*/ |
|
static void |
|
endElementNsDebug(void *ctx ATTRIBUTE_UNUSED, |
|
const xmlChar *localname, |
|
const xmlChar *prefix, |
|
const xmlChar *URI) |
|
{ |
|
callbacks++; |
|
if (quiet) |
|
return; |
|
fprintf(stdout, "SAX.endElementNs(%s", (char *) localname); |
|
if (prefix == NULL) |
|
fprintf(stdout, ", NULL"); |
|
else |
|
fprintf(stdout, ", %s", (char *) prefix); |
|
if (URI == NULL) |
|
fprintf(stdout, ", NULL)\n"); |
|
else |
|
fprintf(stdout, ", '%s')\n", (char *) URI); |
|
} |
|
|
|
static xmlSAXHandler debugSAX2HandlerStruct = { |
|
internalSubsetDebug, |
|
isStandaloneDebug, |
|
hasInternalSubsetDebug, |
|
hasExternalSubsetDebug, |
|
resolveEntityDebug, |
|
getEntityDebug, |
|
entityDeclDebug, |
|
notationDeclDebug, |
|
attributeDeclDebug, |
|
elementDeclDebug, |
|
unparsedEntityDeclDebug, |
|
setDocumentLocatorDebug, |
|
startDocumentDebug, |
|
endDocumentDebug, |
|
NULL, |
|
NULL, |
|
referenceDebug, |
|
charactersDebug, |
|
ignorableWhitespaceDebug, |
|
processingInstructionDebug, |
|
commentDebug, |
|
warningDebug, |
|
errorDebug, |
|
fatalErrorDebug, |
|
getParameterEntityDebug, |
|
cdataBlockDebug, |
|
externalSubsetDebug, |
|
XML_SAX2_MAGIC, |
|
NULL, |
|
startElementNsDebug, |
|
endElementNsDebug, |
|
NULL |
|
}; |
|
|
|
static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct; |
|
|
|
/************************************************************************ |
|
* * |
|
* Debug * |
|
* * |
|
************************************************************************/ |
|
|
|
static void |
|
parseAndPrintFile(char *filename) { |
|
int res; |
|
|
|
#ifdef LIBXML_PUSH_ENABLED |
|
if (push) { |
|
FILE *f; |
|
|
|
if ((!quiet) && (!nonull)) { |
|
/* |
|
* Empty callbacks for checking |
|
*/ |
|
#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) |
|
f = fopen(filename, "rb"); |
|
#else |
|
f = fopen(filename, "r"); |
|
#endif |
|
if (f != NULL) { |
|
int ret; |
|
char chars[10]; |
|
xmlParserCtxtPtr ctxt; |
|
|
|
ret = fread(chars, 1, 4, f); |
|
if (ret > 0) { |
|
ctxt = xmlCreatePushParserCtxt(emptySAXHandler, NULL, |
|
chars, ret, filename); |
|
while ((ret = fread(chars, 1, 3, f)) > 0) { |
|
xmlParseChunk(ctxt, chars, ret, 0); |
|
} |
|
xmlParseChunk(ctxt, chars, 0, 1); |
|
xmlFreeParserCtxt(ctxt); |
|
} |
|
fclose(f); |
|
} else { |
|
xmlGenericError(xmlGenericErrorContext, |
|
"Cannot read file %s\n", filename); |
|
} |
|
} |
|
/* |
|
* Debug callback |
|
*/ |
|
#if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__) |
|
f = fopen(filename, "rb"); |
|
#else |
|
f = fopen(filename, "r"); |
|
#endif |
|
if (f != NULL) { |
|
int ret; |
|
char chars[10]; |
|
xmlParserCtxtPtr ctxt; |
|
|
|
ret = fread(chars, 1, 4, f); |
|
if (ret > 0) { |
|
if (sax2) |
|
ctxt = xmlCreatePushParserCtxt(debugSAX2Handler, NULL, |
|
chars, ret, filename); |
|
else |
|
ctxt = xmlCreatePushParserCtxt(debugSAXHandler, NULL, |
|
chars, ret, filename); |
|
while ((ret = fread(chars, 1, 3, f)) > 0) { |
|
xmlParseChunk(ctxt, chars, ret, 0); |
|
} |
|
ret = xmlParseChunk(ctxt, chars, 0, 1); |
|
xmlFreeParserCtxt(ctxt); |
|
if (ret != 0) { |
|
fprintf(stdout, |
|
"xmlSAXUserParseFile returned error %d\n", ret); |
|
} |
|
} |
|
fclose(f); |
|
} |
|
} else { |
|
#endif /* LIBXML_PUSH_ENABLED */ |
|
if (!speed) { |
|
/* |
|
* Empty callbacks for checking |
|
*/ |
|
if ((!quiet) && (!nonull)) { |
|
res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename); |
|
if (res != 0) { |
|
fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res); |
|
} |
|
} |
|
|
|
/* |
|
* Debug callback |
|
*/ |
|
callbacks = 0; |
|
if (repeat) { |
|
int i; |
|
for (i = 0;i < 99;i++) { |
|
if (sax2) |
|
res = xmlSAXUserParseFile(debugSAX2Handler, NULL, |
|
filename); |
|
else |
|
res = xmlSAXUserParseFile(debugSAXHandler, NULL, |
|
filename); |
|
} |
|
} |
|
if (sax2) |
|
res = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename); |
|
else |
|
res = xmlSAXUserParseFile(debugSAXHandler, NULL, filename); |
|
if (res != 0) { |
|
fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res); |
|
} |
|
if (quiet) |
|
fprintf(stdout, "%d callbacks generated\n", callbacks); |
|
} else { |
|
/* |
|
* test 100x the SAX parse |
|
*/ |
|
int i; |
|
|
|
for (i = 0; i<100;i++) |
|
res = xmlSAXUserParseFile(emptySAXHandler, NULL, filename); |
|
if (res != 0) { |
|
fprintf(stdout, "xmlSAXUserParseFile returned error %d\n", res); |
|
} |
|
} |
|
#ifdef LIBXML_PUSH_ENABLED |
|
} |
|
#endif |
|
} |
|
|
|
|
|
int main(int argc, char **argv) { |
|
int i; |
|
int files = 0; |
|
|
|
LIBXML_TEST_VERSION /* be safe, plus calls xmlInitParser */ |
|
|
|
for (i = 1; i < argc ; i++) { |
|
if ((!strcmp(argv[i], "-debug")) || (!strcmp(argv[i], "--debug"))) |
|
debug++; |
|
else if ((!strcmp(argv[i], "-copy")) || (!strcmp(argv[i], "--copy"))) |
|
copy++; |
|
else if ((!strcmp(argv[i], "-recover")) || |
|
(!strcmp(argv[i], "--recover"))) |
|
recovery++; |
|
else if ((!strcmp(argv[i], "-push")) || |
|
(!strcmp(argv[i], "--push"))) |
|
#ifdef LIBXML_PUSH_ENABLED |
|
push++; |
|
#else |
|
fprintf(stderr,"'push' not enabled in library - ignoring\n"); |
|
#endif /* LIBXML_PUSH_ENABLED */ |
|
else if ((!strcmp(argv[i], "-speed")) || |
|
(!strcmp(argv[i], "--speed"))) |
|
speed++; |
|
else if ((!strcmp(argv[i], "-timing")) || |
|
(!strcmp(argv[i], "--timing"))) { |
|
nonull++; |
|
timing++; |
|
quiet++; |
|
} else if ((!strcmp(argv[i], "-repeat")) || |
|
(!strcmp(argv[i], "--repeat"))) { |
|
repeat++; |
|
quiet++; |
|
} else if ((!strcmp(argv[i], "-noent")) || |
|
(!strcmp(argv[i], "--noent"))) |
|
noent++; |
|
else if ((!strcmp(argv[i], "-quiet")) || |
|
(!strcmp(argv[i], "--quiet"))) |
|
quiet++; |
|
else if ((!strcmp(argv[i], "-sax2")) || |
|
(!strcmp(argv[i], "--sax2"))) |
|
sax2++; |
|
else if ((!strcmp(argv[i], "-nonull")) || |
|
(!strcmp(argv[i], "--nonull"))) |
|
nonull++; |
|
} |
|
if (noent != 0) xmlSubstituteEntitiesDefault(1); |
|
for (i = 1; i < argc ; i++) { |
|
if (argv[i][0] != '-') { |
|
if (timing) { |
|
startTimer(); |
|
} |
|
parseAndPrintFile(argv[i]); |
|
if (timing) { |
|
endTimer("Parsing"); |
|
} |
|
files ++; |
|
} |
|
} |
|
xmlCleanupParser(); |
|
xmlMemoryDump(); |
|
|
|
return(0); |
|
} |
|
#else |
|
int main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) { |
|
printf("%s : SAX1 parsing support not compiled in\n", argv[0]); |
|
return(0); |
|
} |
|
#endif /* LIBXML_SAX1_ENABLED */
|
|
|