Finish refactoring of DomCodeToUsLayoutKeyboardCode().
[chromium-blink-merge.git] / third_party / libxml / src / testlimits.c
blob577f593ce497e4dd298f2d2dc8bc8fdf505b3bcf
1 /*
2 * testlimits.c: C program to run libxml2 regression tests checking various
3 * limits in document size. Will consume a lot of RAM and CPU cycles
5 * To compile on Unixes:
6 * cc -o testlimits `xml2-config --cflags` testlimits.c `xml2-config --libs` -lpthread
8 * See Copyright for the status of this software.
10 * daniel@veillard.com
13 #include "libxml.h"
14 #include <stdio.h>
16 #if !defined(_WIN32) || defined(__CYGWIN__)
17 #include <unistd.h>
18 #endif
19 #include <string.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <time.h>
25 #include <libxml/parser.h>
26 #include <libxml/parserInternals.h>
27 #include <libxml/tree.h>
28 #include <libxml/uri.h>
29 #ifdef LIBXML_READER_ENABLED
30 #include <libxml/xmlreader.h>
31 #endif
33 static int verbose = 0;
34 static int tests_quiet = 0;
36 /************************************************************************
37 * *
38 * time handling *
39 * *
40 ************************************************************************/
42 /* maximum time for one parsing before declaring a timeout */
43 #define MAX_TIME 2 /* seconds */
45 static clock_t t0;
46 int timeout = 0;
48 static void reset_timout(void) {
49 timeout = 0;
50 t0 = clock();
53 static int check_time(void) {
54 clock_t tnow = clock();
55 if (((tnow - t0) / CLOCKS_PER_SEC) > MAX_TIME) {
56 timeout = 1;
57 return(0);
59 return(1);
62 /************************************************************************
63 * *
64 * Huge document generator *
65 * *
66 ************************************************************************/
68 #include <libxml/xmlIO.h>
71 * Huge documents are built using fixed start and end chunks
72 * and filling between the two an unconventional amount of char data
74 typedef struct hugeTest hugeTest;
75 typedef hugeTest *hugeTestPtr;
76 struct hugeTest {
77 const char *description;
78 const char *name;
79 const char *start;
80 const char *end;
83 static struct hugeTest hugeTests[] = {
84 { "Huge text node", "huge:textNode", "<foo>", "</foo>" },
85 { "Huge attribute node", "huge:attrNode", "<foo bar='", "'/>" },
86 { "Huge comment node", "huge:commentNode", "<foo><!--", "--></foo>" },
87 { "Huge PI node", "huge:piNode", "<foo><?bar ", "?></foo>" },
90 static const char *current;
91 static int rlen;
92 static unsigned int currentTest = 0;
93 static int instate = 0;
95 /**
96 * hugeMatch:
97 * @URI: an URI to test
99 * Check for an huge: query
101 * Returns 1 if yes and 0 if another Input module should be used
103 static int
104 hugeMatch(const char * URI) {
105 if ((URI != NULL) && (!strncmp(URI, "huge:", 5)))
106 return(1);
107 return(0);
111 * hugeOpen:
112 * @URI: an URI to test
114 * Return a pointer to the huge: query handler, in this example simply
115 * the current pointer...
117 * Returns an Input context or NULL in case or error
119 static void *
120 hugeOpen(const char * URI) {
121 if ((URI == NULL) || (strncmp(URI, "huge:", 5)))
122 return(NULL);
124 for (currentTest = 0;currentTest < sizeof(hugeTests)/sizeof(hugeTests[0]);
125 currentTest++)
126 if (!strcmp(hugeTests[currentTest].name, URI))
127 goto found;
129 return(NULL);
131 found:
132 rlen = strlen(hugeTests[currentTest].start);
133 current = hugeTests[currentTest].start;
134 instate = 0;
135 return((void *) current);
139 * hugeClose:
140 * @context: the read context
142 * Close the huge: query handler
144 * Returns 0 or -1 in case of error
146 static int
147 hugeClose(void * context) {
148 if (context == NULL) return(-1);
149 fprintf(stderr, "\n");
150 return(0);
153 #define CHUNK 4096
155 char filling[CHUNK + 1];
157 static void fillFilling(void) {
158 int i;
160 for (i = 0;i < CHUNK;i++) {
161 filling[i] = 'a';
163 filling[CHUNK] = 0;
166 size_t maxlen = 64 * 1024 * 1024;
167 size_t curlen = 0;
168 size_t dotlen;
171 * hugeRead:
172 * @context: the read context
173 * @buffer: where to store data
174 * @len: number of bytes to read
176 * Implement an huge: query read.
178 * Returns the number of bytes read or -1 in case of error
180 static int
181 hugeRead(void *context, char *buffer, int len)
183 if ((context == NULL) || (buffer == NULL) || (len < 0))
184 return (-1);
186 if (instate == 0) {
187 if (len >= rlen) {
188 len = rlen;
189 rlen = 0;
190 memcpy(buffer, current, len);
191 instate = 1;
192 curlen = 0;
193 dotlen = maxlen / 10;
194 } else {
195 memcpy(buffer, current, len);
196 rlen -= len;
197 current += len;
199 } else if (instate == 2) {
200 if (len >= rlen) {
201 len = rlen;
202 rlen = 0;
203 memcpy(buffer, current, len);
204 instate = 3;
205 curlen = 0;
206 } else {
207 memcpy(buffer, current, len);
208 rlen -= len;
209 current += len;
211 } else if (instate == 1) {
212 if (len > CHUNK) len = CHUNK;
213 memcpy(buffer, &filling[0], len);
214 curlen += len;
215 if (curlen >= maxlen) {
216 rlen = strlen(hugeTests[currentTest].end);
217 current = hugeTests[currentTest].end;
218 instate = 2;
219 } else {
220 if (curlen > dotlen) {
221 fprintf(stderr, ".");
222 dotlen += maxlen / 10;
225 } else
226 len = 0;
227 return (len);
230 /************************************************************************
232 * Crazy document generator *
234 ************************************************************************/
236 unsigned int crazy_indx = 0;
238 const char *crazy = "<?xml version='1.0' encoding='UTF-8'?>\
239 <?tst ?>\
240 <!-- tst -->\
241 <!DOCTYPE foo [\
242 <?tst ?>\
243 <!-- tst -->\
244 <!ELEMENT foo (#PCDATA)>\
245 <!ELEMENT p (#PCDATA|emph)* >\
247 <?tst ?>\
248 <!-- tst -->\
249 <foo bar='foo'>\
250 <?tst ?>\
251 <!-- tst -->\
252 foo\
253 <![CDATA[ ]]>\
254 </foo>\
255 <?tst ?>\
256 <!-- tst -->";
259 * crazyMatch:
260 * @URI: an URI to test
262 * Check for a crazy: query
264 * Returns 1 if yes and 0 if another Input module should be used
266 static int
267 crazyMatch(const char * URI) {
268 if ((URI != NULL) && (!strncmp(URI, "crazy:", 6)))
269 return(1);
270 return(0);
274 * crazyOpen:
275 * @URI: an URI to test
277 * Return a pointer to the crazy: query handler, in this example simply
278 * the current pointer...
280 * Returns an Input context or NULL in case or error
282 static void *
283 crazyOpen(const char * URI) {
284 if ((URI == NULL) || (strncmp(URI, "crazy:", 6)))
285 return(NULL);
287 if (crazy_indx > strlen(crazy))
288 return(NULL);
289 reset_timout();
290 rlen = crazy_indx;
291 current = &crazy[0];
292 instate = 0;
293 return((void *) current);
297 * crazyClose:
298 * @context: the read context
300 * Close the crazy: query handler
302 * Returns 0 or -1 in case of error
304 static int
305 crazyClose(void * context) {
306 if (context == NULL) return(-1);
307 return(0);
312 * crazyRead:
313 * @context: the read context
314 * @buffer: where to store data
315 * @len: number of bytes to read
317 * Implement an crazy: query read.
319 * Returns the number of bytes read or -1 in case of error
321 static int
322 crazyRead(void *context, char *buffer, int len)
324 if ((context == NULL) || (buffer == NULL) || (len < 0))
325 return (-1);
327 if ((check_time() <= 0) && (instate == 1)) {
328 fprintf(stderr, "\ntimeout in crazy(%d)\n", crazy_indx);
329 rlen = strlen(crazy) - crazy_indx;
330 current = &crazy[crazy_indx];
331 instate = 2;
333 if (instate == 0) {
334 if (len >= rlen) {
335 len = rlen;
336 rlen = 0;
337 memcpy(buffer, current, len);
338 instate = 1;
339 curlen = 0;
340 } else {
341 memcpy(buffer, current, len);
342 rlen -= len;
343 current += len;
345 } else if (instate == 2) {
346 if (len >= rlen) {
347 len = rlen;
348 rlen = 0;
349 memcpy(buffer, current, len);
350 instate = 3;
351 curlen = 0;
352 } else {
353 memcpy(buffer, current, len);
354 rlen -= len;
355 current += len;
357 } else if (instate == 1) {
358 if (len > CHUNK) len = CHUNK;
359 memcpy(buffer, &filling[0], len);
360 curlen += len;
361 if (curlen >= maxlen) {
362 rlen = strlen(crazy) - crazy_indx;
363 current = &crazy[crazy_indx];
364 instate = 2;
366 } else
367 len = 0;
368 return (len);
370 /************************************************************************
372 * Libxml2 specific routines *
374 ************************************************************************/
376 static int nb_tests = 0;
377 static int nb_errors = 0;
378 static int nb_leaks = 0;
379 static int extraMemoryFromResolver = 0;
382 * We need to trap calls to the resolver to not account memory for the catalog
383 * which is shared to the current running test. We also don't want to have
384 * network downloads modifying tests.
386 static xmlParserInputPtr
387 testExternalEntityLoader(const char *URL, const char *ID,
388 xmlParserCtxtPtr ctxt) {
389 xmlParserInputPtr ret;
390 int memused = xmlMemUsed();
392 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
393 extraMemoryFromResolver += xmlMemUsed() - memused;
395 return(ret);
399 * Trapping the error messages at the generic level to grab the equivalent of
400 * stderr messages on CLI tools.
402 static char testErrors[32769];
403 static int testErrorsSize = 0;
405 static void XMLCDECL
406 channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
407 va_list args;
408 int res;
410 if (testErrorsSize >= 32768)
411 return;
412 va_start(args, msg);
413 res = vsnprintf(&testErrors[testErrorsSize],
414 32768 - testErrorsSize,
415 msg, args);
416 va_end(args);
417 if (testErrorsSize + res >= 32768) {
418 /* buffer is full */
419 testErrorsSize = 32768;
420 testErrors[testErrorsSize] = 0;
421 } else {
422 testErrorsSize += res;
424 testErrors[testErrorsSize] = 0;
428 * xmlParserPrintFileContext:
429 * @input: an xmlParserInputPtr input
431 * Displays current context within the input content for error tracking
434 static void
435 xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
436 xmlGenericErrorFunc chanl, void *data ) {
437 const xmlChar *cur, *base;
438 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
439 xmlChar content[81]; /* space for 80 chars + line terminator */
440 xmlChar *ctnt;
442 if (input == NULL) return;
443 cur = input->cur;
444 base = input->base;
445 /* skip backwards over any end-of-lines */
446 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
447 cur--;
449 n = 0;
450 /* search backwards for beginning-of-line (to max buff size) */
451 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
452 (*(cur) != '\n') && (*(cur) != '\r'))
453 cur--;
454 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
455 /* calculate the error position in terms of the current position */
456 col = input->cur - cur;
457 /* search forward for end-of-line (to max buff size) */
458 n = 0;
459 ctnt = content;
460 /* copy selected text to our buffer */
461 while ((*cur != 0) && (*(cur) != '\n') &&
462 (*(cur) != '\r') && (n < sizeof(content)-1)) {
463 *ctnt++ = *cur++;
464 n++;
466 *ctnt = 0;
467 /* print out the selected text */
468 chanl(data ,"%s\n", content);
469 /* create blank line with problem pointer */
470 n = 0;
471 ctnt = content;
472 /* (leave buffer space for pointer + line terminator) */
473 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
474 if (*(ctnt) != '\t')
475 *(ctnt) = ' ';
476 ctnt++;
478 *ctnt++ = '^';
479 *ctnt = 0;
480 chanl(data ,"%s\n", content);
483 static void
484 testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
485 char *file = NULL;
486 int line = 0;
487 int code = -1;
488 int domain;
489 void *data = NULL;
490 const char *str;
491 const xmlChar *name = NULL;
492 xmlNodePtr node;
493 xmlErrorLevel level;
494 xmlParserInputPtr input = NULL;
495 xmlParserInputPtr cur = NULL;
496 xmlParserCtxtPtr ctxt = NULL;
498 if (err == NULL)
499 return;
501 file = err->file;
502 line = err->line;
503 code = err->code;
504 domain = err->domain;
505 level = err->level;
506 node = err->node;
507 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
508 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
509 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
510 ctxt = err->ctxt;
512 str = err->message;
514 if (code == XML_ERR_OK)
515 return;
517 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
518 name = node->name;
521 * Maintain the compatibility with the legacy error handling
523 if (ctxt != NULL) {
524 input = ctxt->input;
525 if ((input != NULL) && (input->filename == NULL) &&
526 (ctxt->inputNr > 1)) {
527 cur = input;
528 input = ctxt->inputTab[ctxt->inputNr - 2];
530 if (input != NULL) {
531 if (input->filename)
532 channel(data, "%s:%d: ", input->filename, input->line);
533 else if ((line != 0) && (domain == XML_FROM_PARSER))
534 channel(data, "Entity: line %d: ", input->line);
536 } else {
537 if (file != NULL)
538 channel(data, "%s:%d: ", file, line);
539 else if ((line != 0) && (domain == XML_FROM_PARSER))
540 channel(data, "Entity: line %d: ", line);
542 if (name != NULL) {
543 channel(data, "element %s: ", name);
545 if (code == XML_ERR_OK)
546 return;
547 switch (domain) {
548 case XML_FROM_PARSER:
549 channel(data, "parser ");
550 break;
551 case XML_FROM_NAMESPACE:
552 channel(data, "namespace ");
553 break;
554 case XML_FROM_DTD:
555 case XML_FROM_VALID:
556 channel(data, "validity ");
557 break;
558 case XML_FROM_HTML:
559 channel(data, "HTML parser ");
560 break;
561 case XML_FROM_MEMORY:
562 channel(data, "memory ");
563 break;
564 case XML_FROM_OUTPUT:
565 channel(data, "output ");
566 break;
567 case XML_FROM_IO:
568 channel(data, "I/O ");
569 break;
570 case XML_FROM_XINCLUDE:
571 channel(data, "XInclude ");
572 break;
573 case XML_FROM_XPATH:
574 channel(data, "XPath ");
575 break;
576 case XML_FROM_XPOINTER:
577 channel(data, "parser ");
578 break;
579 case XML_FROM_REGEXP:
580 channel(data, "regexp ");
581 break;
582 case XML_FROM_MODULE:
583 channel(data, "module ");
584 break;
585 case XML_FROM_SCHEMASV:
586 channel(data, "Schemas validity ");
587 break;
588 case XML_FROM_SCHEMASP:
589 channel(data, "Schemas parser ");
590 break;
591 case XML_FROM_RELAXNGP:
592 channel(data, "Relax-NG parser ");
593 break;
594 case XML_FROM_RELAXNGV:
595 channel(data, "Relax-NG validity ");
596 break;
597 case XML_FROM_CATALOG:
598 channel(data, "Catalog ");
599 break;
600 case XML_FROM_C14N:
601 channel(data, "C14N ");
602 break;
603 case XML_FROM_XSLT:
604 channel(data, "XSLT ");
605 break;
606 default:
607 break;
609 if (code == XML_ERR_OK)
610 return;
611 switch (level) {
612 case XML_ERR_NONE:
613 channel(data, ": ");
614 break;
615 case XML_ERR_WARNING:
616 channel(data, "warning : ");
617 break;
618 case XML_ERR_ERROR:
619 channel(data, "error : ");
620 break;
621 case XML_ERR_FATAL:
622 channel(data, "error : ");
623 break;
625 if (code == XML_ERR_OK)
626 return;
627 if (str != NULL) {
628 int len;
629 len = xmlStrlen((const xmlChar *)str);
630 if ((len > 0) && (str[len - 1] != '\n'))
631 channel(data, "%s\n", str);
632 else
633 channel(data, "%s", str);
634 } else {
635 channel(data, "%s\n", "out of memory error");
637 if (code == XML_ERR_OK)
638 return;
640 if (ctxt != NULL) {
641 xmlParserPrintFileContextInternal(input, channel, data);
642 if (cur != NULL) {
643 if (cur->filename)
644 channel(data, "%s:%d: \n", cur->filename, cur->line);
645 else if ((line != 0) && (domain == XML_FROM_PARSER))
646 channel(data, "Entity: line %d: \n", cur->line);
647 xmlParserPrintFileContextInternal(cur, channel, data);
650 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
651 (err->int1 < 100) &&
652 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
653 xmlChar buf[150];
654 int i;
656 channel(data, "%s\n", err->str1);
657 for (i=0;i < err->int1;i++)
658 buf[i] = ' ';
659 buf[i++] = '^';
660 buf[i] = 0;
661 channel(data, "%s\n", buf);
665 static void
666 initializeLibxml2(void) {
667 xmlGetWarningsDefaultValue = 0;
668 xmlPedanticParserDefault(0);
670 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
671 xmlInitParser();
672 xmlSetExternalEntityLoader(testExternalEntityLoader);
673 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
675 * register the new I/O handlers
677 if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
678 hugeRead, hugeClose) < 0) {
679 fprintf(stderr, "failed to register Huge handlers\n");
680 exit(1);
682 if (xmlRegisterInputCallbacks(crazyMatch, crazyOpen,
683 crazyRead, crazyClose) < 0) {
684 fprintf(stderr, "failed to register Crazy handlers\n");
685 exit(1);
689 /************************************************************************
691 * SAX empty callbacks *
693 ************************************************************************/
695 unsigned long callbacks = 0;
698 * isStandaloneCallback:
699 * @ctxt: An XML parser context
701 * Is this document tagged standalone ?
703 * Returns 1 if true
705 static int
706 isStandaloneCallback(void *ctx ATTRIBUTE_UNUSED)
708 callbacks++;
709 return (0);
713 * hasInternalSubsetCallback:
714 * @ctxt: An XML parser context
716 * Does this document has an internal subset
718 * Returns 1 if true
720 static int
721 hasInternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
723 callbacks++;
724 return (0);
728 * hasExternalSubsetCallback:
729 * @ctxt: An XML parser context
731 * Does this document has an external subset
733 * Returns 1 if true
735 static int
736 hasExternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
738 callbacks++;
739 return (0);
743 * internalSubsetCallback:
744 * @ctxt: An XML parser context
746 * Does this document has an internal subset
748 static void
749 internalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
750 const xmlChar * name ATTRIBUTE_UNUSED,
751 const xmlChar * ExternalID ATTRIBUTE_UNUSED,
752 const xmlChar * SystemID ATTRIBUTE_UNUSED)
754 callbacks++;
755 return;
759 * externalSubsetCallback:
760 * @ctxt: An XML parser context
762 * Does this document has an external subset
764 static void
765 externalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
766 const xmlChar * name ATTRIBUTE_UNUSED,
767 const xmlChar * ExternalID ATTRIBUTE_UNUSED,
768 const xmlChar * SystemID ATTRIBUTE_UNUSED)
770 callbacks++;
771 return;
775 * resolveEntityCallback:
776 * @ctxt: An XML parser context
777 * @publicId: The public ID of the entity
778 * @systemId: The system ID of the entity
780 * Special entity resolver, better left to the parser, it has
781 * more context than the application layer.
782 * The default behaviour is to NOT resolve the entities, in that case
783 * the ENTITY_REF nodes are built in the structure (and the parameter
784 * values).
786 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
788 static xmlParserInputPtr
789 resolveEntityCallback(void *ctx ATTRIBUTE_UNUSED,
790 const xmlChar * publicId ATTRIBUTE_UNUSED,
791 const xmlChar * systemId ATTRIBUTE_UNUSED)
793 callbacks++;
794 return (NULL);
798 * getEntityCallback:
799 * @ctxt: An XML parser context
800 * @name: The entity name
802 * Get an entity by name
804 * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
806 static xmlEntityPtr
807 getEntityCallback(void *ctx ATTRIBUTE_UNUSED,
808 const xmlChar * name ATTRIBUTE_UNUSED)
810 callbacks++;
811 return (NULL);
815 * getParameterEntityCallback:
816 * @ctxt: An XML parser context
817 * @name: The entity name
819 * Get a parameter entity by name
821 * Returns the xmlParserInputPtr
823 static xmlEntityPtr
824 getParameterEntityCallback(void *ctx ATTRIBUTE_UNUSED,
825 const xmlChar * name ATTRIBUTE_UNUSED)
827 callbacks++;
828 return (NULL);
833 * entityDeclCallback:
834 * @ctxt: An XML parser context
835 * @name: the entity name
836 * @type: the entity type
837 * @publicId: The public ID of the entity
838 * @systemId: The system ID of the entity
839 * @content: the entity value (without processing).
841 * An entity definition has been parsed
843 static void
844 entityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
845 const xmlChar * name ATTRIBUTE_UNUSED,
846 int type ATTRIBUTE_UNUSED,
847 const xmlChar * publicId ATTRIBUTE_UNUSED,
848 const xmlChar * systemId ATTRIBUTE_UNUSED,
849 xmlChar * content ATTRIBUTE_UNUSED)
851 callbacks++;
852 return;
856 * attributeDeclCallback:
857 * @ctxt: An XML parser context
858 * @name: the attribute name
859 * @type: the attribute type
861 * An attribute definition has been parsed
863 static void
864 attributeDeclCallback(void *ctx ATTRIBUTE_UNUSED,
865 const xmlChar * elem ATTRIBUTE_UNUSED,
866 const xmlChar * name ATTRIBUTE_UNUSED,
867 int type ATTRIBUTE_UNUSED, int def ATTRIBUTE_UNUSED,
868 const xmlChar * defaultValue ATTRIBUTE_UNUSED,
869 xmlEnumerationPtr tree ATTRIBUTE_UNUSED)
871 callbacks++;
872 return;
876 * elementDeclCallback:
877 * @ctxt: An XML parser context
878 * @name: the element name
879 * @type: the element type
880 * @content: the element value (without processing).
882 * An element definition has been parsed
884 static void
885 elementDeclCallback(void *ctx ATTRIBUTE_UNUSED,
886 const xmlChar * name ATTRIBUTE_UNUSED,
887 int type ATTRIBUTE_UNUSED,
888 xmlElementContentPtr content ATTRIBUTE_UNUSED)
890 callbacks++;
891 return;
895 * notationDeclCallback:
896 * @ctxt: An XML parser context
897 * @name: The name of the notation
898 * @publicId: The public ID of the entity
899 * @systemId: The system ID of the entity
901 * What to do when a notation declaration has been parsed.
903 static void
904 notationDeclCallback(void *ctx ATTRIBUTE_UNUSED,
905 const xmlChar * name ATTRIBUTE_UNUSED,
906 const xmlChar * publicId ATTRIBUTE_UNUSED,
907 const xmlChar * systemId ATTRIBUTE_UNUSED)
909 callbacks++;
910 return;
914 * unparsedEntityDeclCallback:
915 * @ctxt: An XML parser context
916 * @name: The name of the entity
917 * @publicId: The public ID of the entity
918 * @systemId: The system ID of the entity
919 * @notationName: the name of the notation
921 * What to do when an unparsed entity declaration is parsed
923 static void
924 unparsedEntityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
925 const xmlChar * name ATTRIBUTE_UNUSED,
926 const xmlChar * publicId ATTRIBUTE_UNUSED,
927 const xmlChar * systemId ATTRIBUTE_UNUSED,
928 const xmlChar * notationName ATTRIBUTE_UNUSED)
930 callbacks++;
931 return;
935 * setDocumentLocatorCallback:
936 * @ctxt: An XML parser context
937 * @loc: A SAX Locator
939 * Receive the document locator at startup, actually xmlDefaultSAXLocator
940 * Everything is available on the context, so this is useless in our case.
942 static void
943 setDocumentLocatorCallback(void *ctx ATTRIBUTE_UNUSED,
944 xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
946 callbacks++;
947 return;
951 * startDocumentCallback:
952 * @ctxt: An XML parser context
954 * called when the document start being processed.
956 static void
957 startDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
959 callbacks++;
960 return;
964 * endDocumentCallback:
965 * @ctxt: An XML parser context
967 * called when the document end has been detected.
969 static void
970 endDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
972 callbacks++;
973 return;
976 #if 0
978 * startElementCallback:
979 * @ctxt: An XML parser context
980 * @name: The element name
982 * called when an opening tag has been processed.
984 static void
985 startElementCallback(void *ctx ATTRIBUTE_UNUSED,
986 const xmlChar * name ATTRIBUTE_UNUSED,
987 const xmlChar ** atts ATTRIBUTE_UNUSED)
989 callbacks++;
990 return;
994 * endElementCallback:
995 * @ctxt: An XML parser context
996 * @name: The element name
998 * called when the end of an element has been detected.
1000 static void
1001 endElementCallback(void *ctx ATTRIBUTE_UNUSED,
1002 const xmlChar * name ATTRIBUTE_UNUSED)
1004 callbacks++;
1005 return;
1007 #endif
1010 * charactersCallback:
1011 * @ctxt: An XML parser context
1012 * @ch: a xmlChar string
1013 * @len: the number of xmlChar
1015 * receiving some chars from the parser.
1016 * Question: how much at a time ???
1018 static void
1019 charactersCallback(void *ctx ATTRIBUTE_UNUSED,
1020 const xmlChar * ch ATTRIBUTE_UNUSED,
1021 int len ATTRIBUTE_UNUSED)
1023 callbacks++;
1024 return;
1028 * referenceCallback:
1029 * @ctxt: An XML parser context
1030 * @name: The entity name
1032 * called when an entity reference is detected.
1034 static void
1035 referenceCallback(void *ctx ATTRIBUTE_UNUSED,
1036 const xmlChar * name ATTRIBUTE_UNUSED)
1038 callbacks++;
1039 return;
1043 * ignorableWhitespaceCallback:
1044 * @ctxt: An XML parser context
1045 * @ch: a xmlChar string
1046 * @start: the first char in the string
1047 * @len: the number of xmlChar
1049 * receiving some ignorable whitespaces from the parser.
1050 * Question: how much at a time ???
1052 static void
1053 ignorableWhitespaceCallback(void *ctx ATTRIBUTE_UNUSED,
1054 const xmlChar * ch ATTRIBUTE_UNUSED,
1055 int len ATTRIBUTE_UNUSED)
1057 callbacks++;
1058 return;
1062 * processingInstructionCallback:
1063 * @ctxt: An XML parser context
1064 * @target: the target name
1065 * @data: the PI data's
1066 * @len: the number of xmlChar
1068 * A processing instruction has been parsed.
1070 static void
1071 processingInstructionCallback(void *ctx ATTRIBUTE_UNUSED,
1072 const xmlChar * target ATTRIBUTE_UNUSED,
1073 const xmlChar * data ATTRIBUTE_UNUSED)
1075 callbacks++;
1076 return;
1080 * cdataBlockCallback:
1081 * @ctx: the user data (XML parser context)
1082 * @value: The pcdata content
1083 * @len: the block length
1085 * called when a pcdata block has been parsed
1087 static void
1088 cdataBlockCallback(void *ctx ATTRIBUTE_UNUSED,
1089 const xmlChar * value ATTRIBUTE_UNUSED,
1090 int len ATTRIBUTE_UNUSED)
1092 callbacks++;
1093 return;
1097 * commentCallback:
1098 * @ctxt: An XML parser context
1099 * @value: the comment content
1101 * A comment has been parsed.
1103 static void
1104 commentCallback(void *ctx ATTRIBUTE_UNUSED,
1105 const xmlChar * value ATTRIBUTE_UNUSED)
1107 callbacks++;
1108 return;
1112 * warningCallback:
1113 * @ctxt: An XML parser context
1114 * @msg: the message to display/transmit
1115 * @...: extra parameters for the message display
1117 * Display and format a warning messages, gives file, line, position and
1118 * extra parameters.
1120 static void XMLCDECL
1121 warningCallback(void *ctx ATTRIBUTE_UNUSED,
1122 const char *msg ATTRIBUTE_UNUSED, ...)
1124 callbacks++;
1125 return;
1129 * errorCallback:
1130 * @ctxt: An XML parser context
1131 * @msg: the message to display/transmit
1132 * @...: extra parameters for the message display
1134 * Display and format a error messages, gives file, line, position and
1135 * extra parameters.
1137 static void XMLCDECL
1138 errorCallback(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
1139 ...)
1141 callbacks++;
1142 return;
1146 * fatalErrorCallback:
1147 * @ctxt: An XML parser context
1148 * @msg: the message to display/transmit
1149 * @...: extra parameters for the message display
1151 * Display and format a fatalError messages, gives file, line, position and
1152 * extra parameters.
1154 static void XMLCDECL
1155 fatalErrorCallback(void *ctx ATTRIBUTE_UNUSED,
1156 const char *msg ATTRIBUTE_UNUSED, ...)
1158 return;
1163 * SAX2 specific callbacks
1167 * startElementNsCallback:
1168 * @ctxt: An XML parser context
1169 * @name: The element name
1171 * called when an opening tag has been processed.
1173 static void
1174 startElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
1175 const xmlChar * localname ATTRIBUTE_UNUSED,
1176 const xmlChar * prefix ATTRIBUTE_UNUSED,
1177 const xmlChar * URI ATTRIBUTE_UNUSED,
1178 int nb_namespaces ATTRIBUTE_UNUSED,
1179 const xmlChar ** namespaces ATTRIBUTE_UNUSED,
1180 int nb_attributes ATTRIBUTE_UNUSED,
1181 int nb_defaulted ATTRIBUTE_UNUSED,
1182 const xmlChar ** attributes ATTRIBUTE_UNUSED)
1184 callbacks++;
1185 return;
1189 * endElementCallback:
1190 * @ctxt: An XML parser context
1191 * @name: The element name
1193 * called when the end of an element has been detected.
1195 static void
1196 endElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
1197 const xmlChar * localname ATTRIBUTE_UNUSED,
1198 const xmlChar * prefix ATTRIBUTE_UNUSED,
1199 const xmlChar * URI ATTRIBUTE_UNUSED)
1201 callbacks++;
1202 return;
1205 static xmlSAXHandler callbackSAX2HandlerStruct = {
1206 internalSubsetCallback,
1207 isStandaloneCallback,
1208 hasInternalSubsetCallback,
1209 hasExternalSubsetCallback,
1210 resolveEntityCallback,
1211 getEntityCallback,
1212 entityDeclCallback,
1213 notationDeclCallback,
1214 attributeDeclCallback,
1215 elementDeclCallback,
1216 unparsedEntityDeclCallback,
1217 setDocumentLocatorCallback,
1218 startDocumentCallback,
1219 endDocumentCallback,
1220 NULL,
1221 NULL,
1222 referenceCallback,
1223 charactersCallback,
1224 ignorableWhitespaceCallback,
1225 processingInstructionCallback,
1226 commentCallback,
1227 warningCallback,
1228 errorCallback,
1229 fatalErrorCallback,
1230 getParameterEntityCallback,
1231 cdataBlockCallback,
1232 externalSubsetCallback,
1233 XML_SAX2_MAGIC,
1234 NULL,
1235 startElementNsCallback,
1236 endElementNsCallback,
1237 NULL
1240 static xmlSAXHandlerPtr callbackSAX2Handler = &callbackSAX2HandlerStruct;
1242 /************************************************************************
1244 * The tests front-ends *
1246 ************************************************************************/
1249 * readerTest:
1250 * @filename: the file to parse
1251 * @max_size: size of the limit to test
1252 * @options: parsing options
1253 * @fail: should a failure be reported
1255 * Parse a memory generated file using SAX
1257 * Returns 0 in case of success, an error code otherwise
1259 static int
1260 saxTest(const char *filename, size_t limit, int options, int fail) {
1261 int res = 0;
1262 xmlParserCtxtPtr ctxt;
1263 xmlDocPtr doc;
1264 xmlSAXHandlerPtr old_sax;
1266 nb_tests++;
1268 maxlen = limit;
1269 ctxt = xmlNewParserCtxt();
1270 if (ctxt == NULL) {
1271 fprintf(stderr, "Failed to create parser context\n");
1272 return(1);
1274 old_sax = ctxt->sax;
1275 ctxt->sax = callbackSAX2Handler;
1276 ctxt->userData = NULL;
1277 doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
1279 if (doc != NULL) {
1280 fprintf(stderr, "SAX parsing generated a document !\n");
1281 xmlFreeDoc(doc);
1282 res = 0;
1283 } else if (ctxt->wellFormed == 0) {
1284 if (fail)
1285 res = 0;
1286 else {
1287 fprintf(stderr, "Failed to parse '%s' %lu\n", filename, limit);
1288 res = 1;
1290 } else {
1291 if (fail) {
1292 fprintf(stderr, "Failed to get failure for '%s' %lu\n",
1293 filename, limit);
1294 res = 1;
1295 } else
1296 res = 0;
1298 ctxt->sax = old_sax;
1299 xmlFreeParserCtxt(ctxt);
1301 return(res);
1303 #ifdef LIBXML_READER_ENABLED
1305 * readerTest:
1306 * @filename: the file to parse
1307 * @max_size: size of the limit to test
1308 * @options: parsing options
1309 * @fail: should a failure be reported
1311 * Parse a memory generated file using the xmlReader
1313 * Returns 0 in case of success, an error code otherwise
1315 static int
1316 readerTest(const char *filename, size_t limit, int options, int fail) {
1317 xmlTextReaderPtr reader;
1318 int res = 0;
1319 int ret;
1321 nb_tests++;
1323 maxlen = limit;
1324 reader = xmlReaderForFile(filename , NULL, options);
1325 if (reader == NULL) {
1326 fprintf(stderr, "Failed to open '%s' test\n", filename);
1327 return(1);
1329 ret = xmlTextReaderRead(reader);
1330 while (ret == 1) {
1331 ret = xmlTextReaderRead(reader);
1333 if (ret != 0) {
1334 if (fail)
1335 res = 0;
1336 else {
1337 if (strncmp(filename, "crazy:", 6) == 0)
1338 fprintf(stderr, "Failed to parse '%s' %u\n",
1339 filename, crazy_indx);
1340 else
1341 fprintf(stderr, "Failed to parse '%s' %lu\n",
1342 filename, limit);
1343 res = 1;
1345 } else {
1346 if (fail) {
1347 if (strncmp(filename, "crazy:", 6) == 0)
1348 fprintf(stderr, "Failed to get failure for '%s' %u\n",
1349 filename, crazy_indx);
1350 else
1351 fprintf(stderr, "Failed to get failure for '%s' %lu\n",
1352 filename, limit);
1353 res = 1;
1354 } else
1355 res = 0;
1357 if (timeout)
1358 res = 1;
1359 xmlFreeTextReader(reader);
1361 return(res);
1363 #endif
1365 /************************************************************************
1367 * Tests descriptions *
1369 ************************************************************************/
1371 typedef int (*functest) (const char *filename, size_t limit, int options,
1372 int fail);
1374 typedef struct limitDesc limitDesc;
1375 typedef limitDesc *limitDescPtr;
1376 struct limitDesc {
1377 const char *name; /* the huge generator name */
1378 size_t limit; /* the limit to test */
1379 int options; /* extra parser options */
1380 int fail; /* whether the test should fail */
1383 static limitDesc limitDescriptions[] = {
1384 /* max length of a text node in content */
1385 {"huge:textNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1386 {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1387 {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1388 /* max length of a text node in content */
1389 {"huge:attrNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1390 {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1391 {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1392 /* max length of a comment node */
1393 {"huge:commentNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1394 {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1395 {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1396 /* max length of a PI node */
1397 {"huge:piNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
1398 {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
1399 {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
1402 typedef struct testDesc testDesc;
1403 typedef testDesc *testDescPtr;
1404 struct testDesc {
1405 const char *desc; /* descripton of the test */
1406 functest func; /* function implementing the test */
1409 static
1410 testDesc testDescriptions[] = {
1411 { "Parsing of huge files with the sax parser", saxTest},
1412 /* { "Parsing of huge files with the tree parser", treeTest}, */
1413 #ifdef LIBXML_READER_ENABLED
1414 { "Parsing of huge files with the reader", readerTest},
1415 #endif
1416 {NULL, NULL}
1419 typedef struct testException testException;
1420 typedef testException *testExceptionPtr;
1421 struct testException {
1422 unsigned int test; /* the parser test number */
1423 unsigned int limit; /* the limit test number */
1424 int fail; /* new fail value or -1*/
1425 size_t size; /* new limit value or 0 */
1428 static
1429 testException testExceptions[] = {
1430 /* the SAX parser doesn't hit a limit of XML_MAX_TEXT_LENGTH text nodes */
1431 { 0, 1, 0, 0},
1434 static int
1435 launchTests(testDescPtr tst, unsigned int test) {
1436 int res = 0, err = 0;
1437 unsigned int i, j;
1438 size_t limit;
1439 int fail;
1441 if (tst == NULL) return(-1);
1443 for (i = 0;i < sizeof(limitDescriptions)/sizeof(limitDescriptions[0]);i++) {
1444 limit = limitDescriptions[i].limit;
1445 fail = limitDescriptions[i].fail;
1447 * Handle exceptions if any
1449 for (j = 0;j < sizeof(testExceptions)/sizeof(testExceptions[0]);j++) {
1450 if ((testExceptions[j].test == test) &&
1451 (testExceptions[j].limit == i)) {
1452 if (testExceptions[j].fail != -1)
1453 fail = testExceptions[j].fail;
1454 if (testExceptions[j].size != 0)
1455 limit = testExceptions[j].size;
1456 break;
1459 res = tst->func(limitDescriptions[i].name, limit,
1460 limitDescriptions[i].options, fail);
1461 if (res != 0) {
1462 nb_errors++;
1463 err++;
1466 return(err);
1470 static int
1471 runtest(unsigned int i) {
1472 int ret = 0, res;
1473 int old_errors, old_tests, old_leaks;
1475 old_errors = nb_errors;
1476 old_tests = nb_tests;
1477 old_leaks = nb_leaks;
1478 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
1479 printf("## %s\n", testDescriptions[i].desc);
1480 res = launchTests(&testDescriptions[i], i);
1481 if (res != 0)
1482 ret++;
1483 if (verbose) {
1484 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1485 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1486 else
1487 printf("Ran %d tests, %d errors, %d leaks\n",
1488 nb_tests - old_tests,
1489 nb_errors - old_errors,
1490 nb_leaks - old_leaks);
1492 return(ret);
1495 static int
1496 launchCrazySAX(unsigned int test, int fail) {
1497 int res = 0, err = 0;
1499 crazy_indx = test;
1501 res = saxTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
1502 if (res != 0) {
1503 nb_errors++;
1504 err++;
1506 if (tests_quiet == 0)
1507 fprintf(stderr, "%c", crazy[test]);
1509 return(err);
1512 #ifdef LIBXML_READER_ENABLED
1513 static int
1514 launchCrazy(unsigned int test, int fail) {
1515 int res = 0, err = 0;
1517 crazy_indx = test;
1519 res = readerTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
1520 if (res != 0) {
1521 nb_errors++;
1522 err++;
1524 if (tests_quiet == 0)
1525 fprintf(stderr, "%c", crazy[test]);
1527 return(err);
1529 #endif
1531 static int get_crazy_fail(int test) {
1533 * adding 1000000 of character 'a' leads to parser failure mostly
1534 * everywhere except in those special spots. Need to be updated
1535 * each time crazy is updated
1537 int fail = 1;
1538 if ((test == 44) || /* PI in Misc */
1539 ((test >= 50) && (test <= 55)) || /* Comment in Misc */
1540 (test == 79) || /* PI in DTD */
1541 ((test >= 85) && (test <= 90)) || /* Comment in DTD */
1542 (test == 154) || /* PI in Misc */
1543 ((test >= 160) && (test <= 165)) || /* Comment in Misc */
1544 ((test >= 178) && (test <= 181)) || /* attribute value */
1545 (test == 183) || /* Text */
1546 (test == 189) || /* PI in Content */
1547 (test == 191) || /* Text */
1548 ((test >= 195) && (test <= 200)) || /* Comment in Content */
1549 ((test >= 203) && (test <= 206)) || /* Text */
1550 (test == 215) || (test == 216) || /* in CDATA */
1551 (test == 219) || /* Text */
1552 (test == 231) || /* PI in Misc */
1553 ((test >= 237) && (test <= 242))) /* Comment in Misc */
1554 fail = 0;
1555 return(fail);
1558 static int
1559 runcrazy(void) {
1560 int ret = 0, res = 0;
1561 int old_errors, old_tests, old_leaks;
1562 unsigned int i;
1564 old_errors = nb_errors;
1565 old_tests = nb_tests;
1566 old_leaks = nb_leaks;
1568 #ifdef LIBXML_READER_ENABLED
1569 if (tests_quiet == 0) {
1570 printf("## Crazy tests on reader\n");
1572 for (i = 0;i < strlen(crazy);i++) {
1573 res += launchCrazy(i, get_crazy_fail(i));
1574 if (res != 0)
1575 ret++;
1577 #endif
1579 if (tests_quiet == 0) {
1580 printf("\n## Crazy tests on SAX\n");
1582 for (i = 0;i < strlen(crazy);i++) {
1583 res += launchCrazySAX(i, get_crazy_fail(i));
1584 if (res != 0)
1585 ret++;
1587 if (tests_quiet == 0)
1588 fprintf(stderr, "\n");
1589 if (verbose) {
1590 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1591 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1592 else
1593 printf("Ran %d tests, %d errors, %d leaks\n",
1594 nb_tests - old_tests,
1595 nb_errors - old_errors,
1596 nb_leaks - old_leaks);
1598 return(ret);
1603 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1604 int i, a, ret = 0;
1605 int subset = 0;
1607 fillFilling();
1608 initializeLibxml2();
1610 for (a = 1; a < argc;a++) {
1611 if (!strcmp(argv[a], "-v"))
1612 verbose = 1;
1613 else if (!strcmp(argv[a], "-quiet"))
1614 tests_quiet = 1;
1615 else if (!strcmp(argv[a], "-crazy"))
1616 subset = 1;
1618 if (subset == 0) {
1619 for (i = 0; testDescriptions[i].func != NULL; i++) {
1620 ret += runtest(i);
1623 ret += runcrazy();
1624 if ((nb_errors == 0) && (nb_leaks == 0)) {
1625 ret = 0;
1626 printf("Total %d tests, no errors\n",
1627 nb_tests);
1628 } else {
1629 ret = 1;
1630 printf("Total %d tests, %d errors, %d leaks\n",
1631 nb_tests, nb_errors, nb_leaks);
1633 xmlCleanupParser();
1634 xmlMemoryDump();
1636 return(ret);