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