VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/testrecurse.c

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

  • Property svn:eol-style set to native
File size: 32.8 KB
Line 
1/*
2 * testrecurse.c: C program to run libxml2 regression tests checking entities
3 * recursions
4 *
5 * To compile on Unixes:
6 * cc -o testrecurse `xml2-config --cflags` testrecurse.c `xml2-config --libs` -lpthread
7 *
8 * See Copyright for the status of this software.
9 *
10 * daniel@veillard.com
11 */
12
13#include "config.h"
14#include <stdio.h>
15
16#include <stdlib.h>
17#include <string.h>
18#include <sys/stat.h>
19
20#include <libxml/parser.h>
21#include <libxml/parserInternals.h>
22#include <libxml/tree.h>
23#include <libxml/uri.h>
24
25/*
26 * O_BINARY is just for Windows compatibility - if it isn't defined
27 * on this system, avoid any compilation error
28 */
29#ifdef O_BINARY
30#define RD_FLAGS O_RDONLY | O_BINARY
31#else
32#define RD_FLAGS O_RDONLY
33#endif
34
35#define OPT_SAX (1<<0)
36#define OPT_NO_SUBST (1<<1)
37
38typedef int (*functest) (const char *filename, const char *result,
39 const char *error, int options);
40
41typedef struct testDesc testDesc;
42typedef testDesc *testDescPtr;
43struct testDesc {
44 const char *desc; /* description of the test */
45 functest func; /* function implementing the test */
46 const char *in; /* glob to path for input files */
47 const char *out; /* output directory */
48 const char *suffix;/* suffix for output files */
49 const char *err; /* suffix for error output files */
50 int options; /* parser options for the test */
51};
52
53static int checkTestFile(const char *filename);
54
55
56#if defined(_WIN32)
57
58#include <windows.h>
59
60typedef struct
61{
62 size_t gl_pathc; /* Count of paths matched so far */
63 char **gl_pathv; /* List of matched pathnames. */
64 size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
65} glob_t;
66
67#define GLOB_DOOFFS 0
68static int glob(const char *pattern, ATTRIBUTE_UNUSED int flags,
69 ATTRIBUTE_UNUSED int errfunc(const char *epath, int eerrno),
70 glob_t *pglob) {
71 glob_t *ret;
72 WIN32_FIND_DATA FindFileData;
73 HANDLE hFind;
74 unsigned int nb_paths = 0;
75 char directory[500];
76 int len;
77
78 if ((pattern == NULL) || (pglob == NULL)) return(-1);
79
80 strncpy(directory, pattern, 499);
81 for (len = strlen(directory);len >= 0;len--) {
82 if (directory[len] == '/') {
83 len++;
84 directory[len] = 0;
85 break;
86 }
87 }
88 if (len <= 0)
89 len = 0;
90
91
92 ret = pglob;
93 memset(ret, 0, sizeof(glob_t));
94
95 hFind = FindFirstFileA(pattern, &FindFileData);
96 if (hFind == INVALID_HANDLE_VALUE)
97 return(0);
98 nb_paths = 20;
99 ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
100 if (ret->gl_pathv == NULL) {
101 FindClose(hFind);
102 return(-1);
103 }
104 strncpy(directory + len, FindFileData.cFileName, 499 - len);
105 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
106 if (ret->gl_pathv[ret->gl_pathc] == NULL)
107 goto done;
108 ret->gl_pathc++;
109 while(FindNextFileA(hFind, &FindFileData)) {
110 if (FindFileData.cFileName[0] == '.')
111 continue;
112 if (ret->gl_pathc + 2 > nb_paths) {
113 char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
114 if (tmp == NULL)
115 break;
116 ret->gl_pathv = tmp;
117 nb_paths *= 2;
118 }
119 strncpy(directory + len, FindFileData.cFileName, 499 - len);
120 ret->gl_pathv[ret->gl_pathc] = strdup(directory);
121 if (ret->gl_pathv[ret->gl_pathc] == NULL)
122 break;
123 ret->gl_pathc++;
124 }
125 ret->gl_pathv[ret->gl_pathc] = NULL;
126
127done:
128 FindClose(hFind);
129 return(0);
130}
131
132
133
134static void globfree(glob_t *pglob) {
135 unsigned int i;
136 if (pglob == NULL)
137 return;
138
139 for (i = 0;i < pglob->gl_pathc;i++) {
140 if (pglob->gl_pathv[i] != NULL)
141 free(pglob->gl_pathv[i]);
142 }
143}
144
145#else
146#include <glob.h>
147#endif
148
149/************************************************************************
150 * *
151 * Huge document generator *
152 * *
153 ************************************************************************/
154
155#include <libxml/xmlIO.h>
156
157typedef struct {
158 const char *URL;
159 const char *start;
160 const char *segment;
161 const char *finish;
162} xmlHugeDocParts;
163
164static const xmlHugeDocParts hugeDocTable[] = {
165 {
166 "test/recurse/huge.xml",
167
168 "<!DOCTYPE foo ["
169 "<!ELEMENT foo (bar*)> "
170 "<!ELEMENT bar (#PCDATA)> "
171 "<!ATTLIST bar attr CDATA #IMPLIED> "
172 "<!ENTITY a SYSTEM 'ga.ent'> "
173 "<!ENTITY b SYSTEM 'gb.ent'> "
174 "<!ENTITY c SYSTEM 'gc.ent'> "
175 "<!ENTITY f 'some internal data'> "
176 "<!ENTITY e '&f;&f;'> "
177 "<!ENTITY d '&e;&e;'> "
178 "]> "
179 "<foo>",
180
181 " <bar attr='&e; &f; &d;'>&a; &b; &c; &e; &f; &d;</bar>\n"
182 " <bar>_123456789_123456789_123456789_123456789</bar>\n"
183 " <bar>_123456789_123456789_123456789_123456789</bar>\n"
184 " <bar>_123456789_123456789_123456789_123456789</bar>\n"
185 " <bar>_123456789_123456789_123456789_123456789</bar>\n",
186
187 "</foo>"
188 },
189 {
190 "test/recurse/huge_dtd.dtd",
191
192 "<!ELEMENT foo (#PCDATA)>\n"
193 "<!ENTITY ent 'success'>\n"
194 "<!ENTITY % a SYSTEM 'pa.ent'>\n"
195 "<!ENTITY % b SYSTEM 'pb.ent'>\n"
196 "<!ENTITY % c SYSTEM 'pc.ent'>\n"
197 "<!ENTITY % d '<!-- comment -->'>\n"
198 "<!ENTITY % e '%d;%d;'>\n"
199 "<!ENTITY % f '%e;%e;'>\n",
200
201 "<!ENTITY ent '%a; %b; %c; %d; %e; %f;'>\n"
202 "%a; %b; %c; %d; %e; %f;\n"
203 "<!-- _123456789_123456789_123456789_123456789 -->\n"
204 "<!-- _123456789_123456789_123456789_123456789 -->\n"
205 "<!-- _123456789_123456789_123456789_123456789 -->\n",
206
207 ""
208 },
209 { NULL, NULL, NULL, NULL }
210};
211
212static const xmlHugeDocParts *hugeDocParts;
213static int curseg = 0;
214static const char *current;
215static int rlen;
216
217/**
218 * hugeMatch:
219 * @URI: an URI to test
220 *
221 * Check for a huge query
222 *
223 * Returns 1 if yes and 0 if another Input module should be used
224 */
225static int
226hugeMatch(const char * URI) {
227 int i;
228
229 if (URI == NULL)
230 return(0);
231
232 for (i = 0; hugeDocTable[i].URL; i++) {
233 if (strcmp(URI, hugeDocTable[i].URL) == 0)
234 return(1);
235 }
236
237 return(0);
238}
239
240/**
241 * hugeOpen:
242 * @URI: an URI to test
243 *
244 * Return a pointer to the huge query handler, in this example simply
245 * the current pointer...
246 *
247 * Returns an Input context or NULL in case or error
248 */
249static void *
250hugeOpen(const char * URI) {
251 int i;
252
253 if (URI == NULL)
254 return(NULL);
255
256 for (i = 0; hugeDocTable[i].URL; i++) {
257 if (strcmp(URI, hugeDocTable[i].URL) == 0) {
258 hugeDocParts = hugeDocTable + i;
259 curseg = 0;
260 current = hugeDocParts->start;
261 rlen = strlen(current);
262 return((void *) current);
263 }
264 }
265
266 return(NULL);
267}
268
269/**
270 * hugeClose:
271 * @context: the read context
272 *
273 * Close the huge query handler
274 *
275 * Returns 0 or -1 in case of error
276 */
277static int
278hugeClose(void * context) {
279 if (context == NULL) return(-1);
280 return(0);
281}
282
283#define MAX_NODES 1000
284
285/**
286 * hugeRead:
287 * @context: the read context
288 * @buffer: where to store data
289 * @len: number of bytes to read
290 *
291 * Implement an huge query read.
292 *
293 * Returns the number of bytes read or -1 in case of error
294 */
295static int
296hugeRead(void *context, char *buffer, int len)
297{
298 if ((context == NULL) || (buffer == NULL) || (len < 0))
299 return (-1);
300
301 if (len >= rlen) {
302 if (curseg >= MAX_NODES + 1) {
303 rlen = 0;
304 return(0);
305 }
306 len = rlen;
307 rlen = 0;
308 memcpy(buffer, current, len);
309 curseg ++;
310 if (curseg == MAX_NODES) {
311 current = hugeDocParts->finish;
312 } else {
313 current = hugeDocParts->segment;
314 }
315 rlen = strlen(current);
316 } else {
317 memcpy(buffer, current, len);
318 rlen -= len;
319 current += len;
320 }
321 return (len);
322}
323
324/************************************************************************
325 * *
326 * Libxml2 specific routines *
327 * *
328 ************************************************************************/
329
330static int nb_tests = 0;
331static int nb_errors = 0;
332static int nb_leaks = 0;
333static int extraMemoryFromResolver = 0;
334
335static int
336fatalError(void) {
337 fprintf(stderr, "Exitting tests on fatal error\n");
338 exit(1);
339}
340
341/*
342 * We need to trap calls to the resolver to not account memory for the catalog
343 * which is shared to the current running test. We also don't want to have
344 * network downloads modifying tests.
345 */
346static xmlParserInputPtr
347testExternalEntityLoader(const char *URL, const char *ID,
348 xmlParserCtxtPtr ctxt) {
349 xmlParserInputPtr ret;
350
351 if (checkTestFile(URL)) {
352 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
353 } else {
354 int memused = xmlMemUsed();
355 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
356 extraMemoryFromResolver += xmlMemUsed() - memused;
357 }
358
359 return(ret);
360}
361
362/*
363 * Trapping the error messages at the generic level to grab the equivalent of
364 * stderr messages on CLI tools.
365 */
366static char testErrors[32769];
367static int testErrorsSize = 0;
368
369static void
370channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
371 va_list args;
372 int res;
373
374 if (testErrorsSize >= 32768)
375 return;
376 va_start(args, msg);
377 res = vsnprintf(&testErrors[testErrorsSize],
378 32768 - testErrorsSize,
379 msg, args);
380 va_end(args);
381 if (testErrorsSize + res >= 32768) {
382 /* buffer is full */
383 testErrorsSize = 32768;
384 testErrors[testErrorsSize] = 0;
385 } else {
386 testErrorsSize += res;
387 }
388 testErrors[testErrorsSize] = 0;
389}
390
391/**
392 * xmlParserPrintFileContext:
393 * @input: an xmlParserInputPtr input
394 *
395 * Displays current context within the input content for error tracking
396 */
397
398static void
399xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
400 xmlGenericErrorFunc chanl, void *data ) {
401 const xmlChar *cur, *base;
402 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
403 xmlChar content[81]; /* space for 80 chars + line terminator */
404 xmlChar *ctnt;
405
406 if (input == NULL) return;
407 cur = input->cur;
408 base = input->base;
409 /* skip backwards over any end-of-lines */
410 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
411 cur--;
412 }
413 n = 0;
414 /* search backwards for beginning-of-line (to max buff size) */
415 while ((n++ < (sizeof(content)-1)) && (cur > base) &&
416 (*(cur) != '\n') && (*(cur) != '\r'))
417 cur--;
418 if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
419 /* calculate the error position in terms of the current position */
420 col = input->cur - cur;
421 /* search forward for end-of-line (to max buff size) */
422 n = 0;
423 ctnt = content;
424 /* copy selected text to our buffer */
425 while ((*cur != 0) && (*(cur) != '\n') &&
426 (*(cur) != '\r') && (n < sizeof(content)-1)) {
427 *ctnt++ = *cur++;
428 n++;
429 }
430 *ctnt = 0;
431 /* print out the selected text */
432 chanl(data ,"%s\n", content);
433 /* create blank line with problem pointer */
434 n = 0;
435 ctnt = content;
436 /* (leave buffer space for pointer + line terminator) */
437 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
438 if (*(ctnt) != '\t')
439 *(ctnt) = ' ';
440 ctnt++;
441 }
442 *ctnt++ = '^';
443 *ctnt = 0;
444 chanl(data ,"%s\n", content);
445}
446
447static void
448testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, const xmlError *err) {
449 char *file = NULL;
450 int line = 0;
451 int code = -1;
452 int domain;
453 void *data = NULL;
454 const char *str;
455 const xmlChar *name = NULL;
456 xmlNodePtr node;
457 xmlErrorLevel level;
458 xmlParserInputPtr input = NULL;
459 xmlParserInputPtr cur = NULL;
460 xmlParserCtxtPtr ctxt = NULL;
461
462 if (err == NULL)
463 return;
464
465 file = err->file;
466 line = err->line;
467 code = err->code;
468 domain = err->domain;
469 level = err->level;
470 node = err->node;
471 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
472 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
473 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
474 ctxt = err->ctxt;
475 }
476 str = err->message;
477
478 if (code == XML_ERR_OK)
479 return;
480
481 if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
482 name = node->name;
483
484 /*
485 * Maintain the compatibility with the legacy error handling
486 */
487 if (ctxt != NULL) {
488 input = ctxt->input;
489 if ((input != NULL) && (input->filename == NULL) &&
490 (ctxt->inputNr > 1)) {
491 cur = input;
492 input = ctxt->inputTab[ctxt->inputNr - 2];
493 }
494 if (input != NULL) {
495 if (input->filename)
496 channel(data, "%s:%d: ", input->filename, input->line);
497 else if ((line != 0) && (domain == XML_FROM_PARSER))
498 channel(data, "Entity: line %d: ", input->line);
499 }
500 } else {
501 if (file != NULL)
502 channel(data, "%s:%d: ", file, line);
503 else if ((line != 0) && (domain == XML_FROM_PARSER))
504 channel(data, "Entity: line %d: ", line);
505 }
506 if (name != NULL) {
507 channel(data, "element %s: ", name);
508 }
509 if (code == XML_ERR_OK)
510 return;
511 switch (domain) {
512 case XML_FROM_PARSER:
513 channel(data, "parser ");
514 break;
515 case XML_FROM_NAMESPACE:
516 channel(data, "namespace ");
517 break;
518 case XML_FROM_DTD:
519 case XML_FROM_VALID:
520 channel(data, "validity ");
521 break;
522 case XML_FROM_HTML:
523 channel(data, "HTML parser ");
524 break;
525 case XML_FROM_MEMORY:
526 channel(data, "memory ");
527 break;
528 case XML_FROM_OUTPUT:
529 channel(data, "output ");
530 break;
531 case XML_FROM_IO:
532 channel(data, "I/O ");
533 break;
534 case XML_FROM_XINCLUDE:
535 channel(data, "XInclude ");
536 break;
537 case XML_FROM_XPATH:
538 channel(data, "XPath ");
539 break;
540 case XML_FROM_XPOINTER:
541 channel(data, "parser ");
542 break;
543 case XML_FROM_REGEXP:
544 channel(data, "regexp ");
545 break;
546 case XML_FROM_MODULE:
547 channel(data, "module ");
548 break;
549 case XML_FROM_SCHEMASV:
550 channel(data, "Schemas validity ");
551 break;
552 case XML_FROM_SCHEMASP:
553 channel(data, "Schemas parser ");
554 break;
555 case XML_FROM_RELAXNGP:
556 channel(data, "Relax-NG parser ");
557 break;
558 case XML_FROM_RELAXNGV:
559 channel(data, "Relax-NG validity ");
560 break;
561 case XML_FROM_CATALOG:
562 channel(data, "Catalog ");
563 break;
564 case XML_FROM_C14N:
565 channel(data, "C14N ");
566 break;
567 case XML_FROM_XSLT:
568 channel(data, "XSLT ");
569 break;
570 default:
571 break;
572 }
573 if (code == XML_ERR_OK)
574 return;
575 switch (level) {
576 case XML_ERR_NONE:
577 channel(data, ": ");
578 break;
579 case XML_ERR_WARNING:
580 channel(data, "warning : ");
581 break;
582 case XML_ERR_ERROR:
583 channel(data, "error : ");
584 break;
585 case XML_ERR_FATAL:
586 channel(data, "error : ");
587 break;
588 }
589 if (code == XML_ERR_OK)
590 return;
591 if (str != NULL) {
592 int len;
593 len = xmlStrlen((const xmlChar *)str);
594 if ((len > 0) && (str[len - 1] != '\n'))
595 channel(data, "%s\n", str);
596 else
597 channel(data, "%s", str);
598 } else {
599 channel(data, "%s\n", "out of memory error");
600 }
601 if (code == XML_ERR_OK)
602 return;
603
604 if (ctxt != NULL) {
605 xmlParserPrintFileContextInternal(input, channel, data);
606 if (cur != NULL) {
607 if (cur->filename)
608 channel(data, "%s:%d: \n", cur->filename, cur->line);
609 else if ((line != 0) && (domain == XML_FROM_PARSER))
610 channel(data, "Entity: line %d: \n", cur->line);
611 xmlParserPrintFileContextInternal(cur, channel, data);
612 }
613 }
614 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
615 (err->int1 < 100) &&
616 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
617 xmlChar buf[150];
618 int i;
619
620 channel(data, "%s\n", err->str1);
621 for (i=0;i < err->int1;i++)
622 buf[i] = ' ';
623 buf[i++] = '^';
624 buf[i] = 0;
625 channel(data, "%s\n", buf);
626 }
627}
628
629static void
630initializeLibxml2(void) {
631 xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
632 xmlInitParser();
633 xmlSetExternalEntityLoader(testExternalEntityLoader);
634 xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
635 /*
636 * register the new I/O handlers
637 */
638 if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
639 hugeRead, hugeClose) < 0) {
640 fprintf(stderr, "failed to register Huge handler\n");
641 exit(1);
642 }
643}
644
645static void
646initSAX(xmlParserCtxtPtr ctxt) {
647 ctxt->sax->startElementNs = NULL;
648 ctxt->sax->endElementNs = NULL;
649 ctxt->sax->startElement = NULL;
650 ctxt->sax->endElement = NULL;
651 ctxt->sax->characters = NULL;
652 ctxt->sax->cdataBlock = NULL;
653 ctxt->sax->ignorableWhitespace = NULL;
654 ctxt->sax->processingInstruction = NULL;
655 ctxt->sax->comment = NULL;
656}
657
658/************************************************************************
659 * *
660 * File name and path utilities *
661 * *
662 ************************************************************************/
663
664static const char *baseFilename(const char *filename) {
665 const char *cur;
666 if (filename == NULL)
667 return(NULL);
668 cur = &filename[strlen(filename)];
669 while ((cur > filename) && (*cur != '/'))
670 cur--;
671 if (*cur == '/')
672 return(cur + 1);
673 return(cur);
674}
675
676static char *resultFilename(const char *filename, const char *out,
677 const char *suffix) {
678 const char *base;
679 char res[500];
680 char suffixbuff[500];
681
682/*************
683 if ((filename[0] == 't') && (filename[1] == 'e') &&
684 (filename[2] == 's') && (filename[3] == 't') &&
685 (filename[4] == '/'))
686 filename = &filename[5];
687 *************/
688
689 base = baseFilename(filename);
690 if (suffix == NULL)
691 suffix = ".tmp";
692 if (out == NULL)
693 out = "";
694
695 strncpy(suffixbuff,suffix,499);
696#ifdef VMS
697 if(strstr(base,".") && suffixbuff[0]=='.')
698 suffixbuff[0]='_';
699#endif
700
701 if (snprintf(res, 499, "%s%s%s", out, base, suffixbuff) >= 499)
702 res[499] = 0;
703 return(strdup(res));
704}
705
706static int checkTestFile(const char *filename) {
707 struct stat buf;
708
709 if (stat(filename, &buf) == -1)
710 return(0);
711
712#if defined(_WIN32)
713 if (!(buf.st_mode & _S_IFREG))
714 return(0);
715#else
716 if (!S_ISREG(buf.st_mode))
717 return(0);
718#endif
719
720 return(1);
721}
722
723
724
725/************************************************************************
726 * *
727 * Test to detect or not recursive entities *
728 * *
729 ************************************************************************/
730/**
731 * recursiveDetectTest:
732 * @filename: the file to parse
733 * @result: the file with expected result
734 * @err: the file with error messages: unused
735 *
736 * Parse a file loading DTD and replacing entities check it fails for
737 * lol cases
738 *
739 * Returns 0 in case of success, an error code otherwise
740 */
741static int
742recursiveDetectTest(const char *filename,
743 const char *result ATTRIBUTE_UNUSED,
744 const char *err ATTRIBUTE_UNUSED,
745 int options) {
746 xmlDocPtr doc;
747 xmlParserCtxtPtr ctxt;
748 int res = 0;
749 /*
750 * XML_PARSE_DTDVALID is the only way to load external entities
751 * without XML_PARSE_NOENT. The validation result doesn't matter
752 * anyway.
753 */
754 int parserOptions = XML_PARSE_DTDVALID;
755
756 nb_tests++;
757
758 ctxt = xmlNewParserCtxt();
759 if (options & OPT_SAX)
760 initSAX(ctxt);
761 if ((options & OPT_NO_SUBST) == 0)
762 parserOptions |= XML_PARSE_NOENT;
763 /*
764 * base of the test, parse with the old API
765 */
766 doc = xmlCtxtReadFile(ctxt, filename, NULL, parserOptions);
767 if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_ENTITY_LOOP)) {
768 fprintf(stderr, "Failed to detect recursion in %s\n", filename);
769 xmlFreeParserCtxt(ctxt);
770 xmlFreeDoc(doc);
771 return(1);
772 }
773 xmlFreeParserCtxt(ctxt);
774
775 return(res);
776}
777
778/**
779 * notRecursiveDetectTest:
780 * @filename: the file to parse
781 * @result: the file with expected result
782 * @err: the file with error messages: unused
783 *
784 * Parse a file loading DTD and replacing entities check it works for
785 * good cases
786 *
787 * Returns 0 in case of success, an error code otherwise
788 */
789static int
790notRecursiveDetectTest(const char *filename,
791 const char *result ATTRIBUTE_UNUSED,
792 const char *err ATTRIBUTE_UNUSED,
793 int options) {
794 xmlDocPtr doc;
795 xmlParserCtxtPtr ctxt;
796 int res = 0;
797 int parserOptions = XML_PARSE_DTDLOAD;
798
799 nb_tests++;
800
801 ctxt = xmlNewParserCtxt();
802 if (options & OPT_SAX)
803 initSAX(ctxt);
804 if ((options & OPT_NO_SUBST) == 0)
805 parserOptions |= XML_PARSE_NOENT;
806 /*
807 * base of the test, parse with the old API
808 */
809 doc = xmlCtxtReadFile(ctxt, filename, NULL, parserOptions);
810 if (doc == NULL) {
811 fprintf(stderr, "Failed to parse correct file %s\n", filename);
812 xmlFreeParserCtxt(ctxt);
813 return(1);
814 }
815 xmlFreeDoc(doc);
816 xmlFreeParserCtxt(ctxt);
817
818 return(res);
819}
820
821/**
822 * notRecursiveHugeTest:
823 * @filename: the file to parse
824 * @result: the file with expected result
825 * @err: the file with error messages: unused
826 *
827 * Parse a memory generated file
828 * good cases
829 *
830 * Returns 0 in case of success, an error code otherwise
831 */
832static int
833notRecursiveHugeTest(const char *filename ATTRIBUTE_UNUSED,
834 const char *result ATTRIBUTE_UNUSED,
835 const char *err ATTRIBUTE_UNUSED,
836 int options) {
837 xmlParserCtxtPtr ctxt;
838 xmlDocPtr doc;
839 int res = 0;
840 int parserOptions = XML_PARSE_DTDVALID;
841
842 nb_tests++;
843
844 ctxt = xmlNewParserCtxt();
845 if (options & OPT_SAX)
846 initSAX(ctxt);
847 if ((options & OPT_NO_SUBST) == 0)
848 parserOptions |= XML_PARSE_NOENT;
849 doc = xmlCtxtReadFile(ctxt, "test/recurse/huge.xml", NULL, parserOptions);
850 if (doc == NULL) {
851 fprintf(stderr, "Failed to parse huge.xml\n");
852 res = 1;
853 } else {
854 xmlEntityPtr ent;
855 unsigned long fixed_cost = 20;
856 unsigned long allowed_expansion = 1000000;
857 unsigned long f_size = xmlStrlen(BAD_CAST "some internal data");
858 unsigned long e_size;
859 unsigned long d_size;
860 unsigned long total_size;
861
862 ent = xmlGetDocEntity(doc, BAD_CAST "e");
863 e_size = f_size * 2 +
864 xmlStrlen(BAD_CAST "&f;") * 2 +
865 fixed_cost * 2;
866 if (ent->expandedSize != e_size) {
867 fprintf(stderr, "Wrong size for entity e: %lu (expected %lu)\n",
868 ent->expandedSize, e_size);
869 res = 1;
870 }
871
872 ent = xmlGetDocEntity(doc, BAD_CAST "b");
873 if (ent->expandedSize != e_size) {
874 fprintf(stderr, "Wrong size for entity b: %lu (expected %lu)\n",
875 ent->expandedSize, e_size);
876 res = 1;
877 }
878
879 ent = xmlGetDocEntity(doc, BAD_CAST "d");
880 d_size = e_size * 2 +
881 xmlStrlen(BAD_CAST "&e;") * 2 +
882 fixed_cost * 2;
883 if (ent->expandedSize != d_size) {
884 fprintf(stderr, "Wrong size for entity d: %lu (expected %lu)\n",
885 ent->expandedSize, d_size);
886 res = 1;
887 }
888
889 ent = xmlGetDocEntity(doc, BAD_CAST "c");
890 if (ent->expandedSize != d_size) {
891 fprintf(stderr, "Wrong size for entity c: %lu (expected %lu)\n",
892 ent->expandedSize, d_size);
893 res = 1;
894 }
895
896 if (ctxt->sizeentcopy < allowed_expansion) {
897 fprintf(stderr, "Total entity size too small: %lu\n",
898 ctxt->sizeentcopy);
899 res = 1;
900 }
901
902 total_size = (f_size + e_size + d_size + 3 * fixed_cost) *
903 (MAX_NODES - 1) * 3;
904 if (ctxt->sizeentcopy != total_size) {
905 fprintf(stderr, "Wrong total entity size: %lu (expected %lu)\n",
906 ctxt->sizeentcopy, total_size);
907 res = 1;
908 }
909
910 if (ctxt->sizeentities != 30) {
911 fprintf(stderr, "Wrong parsed entity size: %lu (expected %lu)\n",
912 ctxt->sizeentities, 30lu);
913 res = 1;
914 }
915 }
916
917 xmlFreeDoc(doc);
918 xmlFreeParserCtxt(ctxt);
919
920 return(res);
921}
922
923/**
924 * notRecursiveHugeTest:
925 * @filename: the file to parse
926 * @result: the file with expected result
927 * @err: the file with error messages: unused
928 *
929 * Parse a memory generated file
930 * good cases
931 *
932 * Returns 0 in case of success, an error code otherwise
933 */
934static int
935hugeDtdTest(const char *filename ATTRIBUTE_UNUSED,
936 const char *result ATTRIBUTE_UNUSED,
937 const char *err ATTRIBUTE_UNUSED,
938 int options) {
939 xmlParserCtxtPtr ctxt;
940 xmlDocPtr doc;
941 int res = 0;
942 int parserOptions = XML_PARSE_DTDVALID;
943
944 nb_tests++;
945
946 ctxt = xmlNewParserCtxt();
947 if (options & OPT_SAX)
948 initSAX(ctxt);
949 if ((options & OPT_NO_SUBST) == 0)
950 parserOptions |= XML_PARSE_NOENT;
951 doc = xmlCtxtReadFile(ctxt, "test/recurse/huge_dtd.xml", NULL,
952 parserOptions);
953 if (doc == NULL) {
954 fprintf(stderr, "Failed to parse huge_dtd.xml\n");
955 res = 1;
956 } else {
957 unsigned long fixed_cost = 20;
958 unsigned long allowed_expansion = 1000000;
959 unsigned long a_size = xmlStrlen(BAD_CAST "<!-- comment -->");
960 unsigned long b_size;
961 unsigned long c_size;
962 unsigned long e_size;
963 unsigned long f_size;
964 unsigned long total_size;
965
966 if (ctxt->sizeentcopy < allowed_expansion) {
967 fprintf(stderr, "Total entity size too small: %lu\n",
968 ctxt->sizeentcopy);
969 res = 1;
970 }
971
972 b_size = (a_size + strlen("&a;") + fixed_cost) * 2;
973 c_size = (b_size + strlen("&b;") + fixed_cost) * 2;
974 /*
975 * Internal parameter entites are substitued eagerly and
976 * need different accounting.
977 */
978 e_size = a_size * 2;
979 f_size = e_size * 2;
980 total_size = /* internal */
981 e_size + f_size + fixed_cost * 4 +
982 (a_size + e_size + f_size + fixed_cost * 3) *
983 (MAX_NODES - 1) * 2 +
984 /* external */
985 (a_size + b_size + c_size + fixed_cost * 3) *
986 (MAX_NODES - 1) * 2 +
987 /* final reference in main doc */
988 strlen("success") + fixed_cost;
989 if (ctxt->sizeentcopy != total_size) {
990 fprintf(stderr, "Wrong total entity size: %lu (expected %lu)\n",
991 ctxt->sizeentcopy, total_size);
992 res = 1;
993 }
994
995 total_size = strlen(hugeDocParts->start) +
996 strlen(hugeDocParts->segment) * (MAX_NODES - 1) +
997 strlen(hugeDocParts->finish) +
998 /*
999 * Other external entities pa.ent, pb.ent, pc.ent.
1000 * These are currently counted twice because they're
1001 * used both in DTD and EntityValue.
1002 */
1003 (16 + 6 + 6) * 2;
1004 if (ctxt->sizeentities != total_size) {
1005 fprintf(stderr, "Wrong parsed entity size: %lu (expected %lu)\n",
1006 ctxt->sizeentities, total_size);
1007 res = 1;
1008 }
1009 }
1010
1011 xmlFreeDoc(doc);
1012 xmlFreeParserCtxt(ctxt);
1013
1014 return(res);
1015}
1016
1017/************************************************************************
1018 * *
1019 * Tests Descriptions *
1020 * *
1021 ************************************************************************/
1022
1023static
1024testDesc testDescriptions[] = {
1025 { "Parsing recursive test cases" ,
1026 recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
1027 0 },
1028 { "Parsing recursive test cases (no substitution)" ,
1029 recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
1030 OPT_NO_SUBST },
1031 { "Parsing recursive test cases (SAX)" ,
1032 recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
1033 OPT_SAX },
1034 { "Parsing recursive test cases (SAX, no substitution)" ,
1035 recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
1036 OPT_SAX | OPT_NO_SUBST },
1037 { "Parsing non-recursive test cases" ,
1038 notRecursiveDetectTest, "./test/recurse/good*.xml", NULL, NULL, NULL,
1039 0 },
1040 { "Parsing non-recursive test cases (SAX)" ,
1041 notRecursiveDetectTest, "./test/recurse/good*.xml", NULL, NULL, NULL,
1042 OPT_SAX },
1043 { "Parsing non-recursive huge case" ,
1044 notRecursiveHugeTest, NULL, NULL, NULL, NULL,
1045 0 },
1046 { "Parsing non-recursive huge case (no substitution)" ,
1047 notRecursiveHugeTest, NULL, NULL, NULL, NULL,
1048 OPT_NO_SUBST },
1049 { "Parsing non-recursive huge case (SAX)" ,
1050 notRecursiveHugeTest, NULL, NULL, NULL, NULL,
1051 OPT_SAX },
1052 { "Parsing non-recursive huge case (SAX, no substitution)" ,
1053 notRecursiveHugeTest, NULL, NULL, NULL, NULL,
1054 OPT_SAX | OPT_NO_SUBST },
1055 { "Parsing non-recursive huge DTD case" ,
1056 hugeDtdTest, NULL, NULL, NULL, NULL,
1057 0 },
1058 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
1059};
1060
1061/************************************************************************
1062 * *
1063 * The main code driving the tests *
1064 * *
1065 ************************************************************************/
1066
1067static int
1068launchTests(testDescPtr tst) {
1069 int res = 0, err = 0;
1070 size_t i;
1071 char *result;
1072 char *error;
1073 int mem;
1074
1075 if (tst == NULL) return(-1);
1076 if (tst->in != NULL) {
1077 glob_t globbuf;
1078
1079 globbuf.gl_offs = 0;
1080 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
1081 for (i = 0;i < globbuf.gl_pathc;i++) {
1082 if (!checkTestFile(globbuf.gl_pathv[i]))
1083 continue;
1084 if (tst->suffix != NULL) {
1085 result = resultFilename(globbuf.gl_pathv[i], tst->out,
1086 tst->suffix);
1087 if (result == NULL) {
1088 fprintf(stderr, "Out of memory !\n");
1089 fatalError();
1090 }
1091 } else {
1092 result = NULL;
1093 }
1094 if (tst->err != NULL) {
1095 error = resultFilename(globbuf.gl_pathv[i], tst->out,
1096 tst->err);
1097 if (error == NULL) {
1098 fprintf(stderr, "Out of memory !\n");
1099 fatalError();
1100 }
1101 } else {
1102 error = NULL;
1103 }
1104 if ((result) &&(!checkTestFile(result))) {
1105 fprintf(stderr, "Missing result file %s\n", result);
1106 } else if ((error) &&(!checkTestFile(error))) {
1107 fprintf(stderr, "Missing error file %s\n", error);
1108 } else {
1109 mem = xmlMemUsed();
1110 extraMemoryFromResolver = 0;
1111 testErrorsSize = 0;
1112 testErrors[0] = 0;
1113 res = tst->func(globbuf.gl_pathv[i], result, error,
1114 tst->options | XML_PARSE_COMPACT);
1115 xmlResetLastError();
1116 if (res != 0) {
1117 fprintf(stderr, "File %s generated an error\n",
1118 globbuf.gl_pathv[i]);
1119 nb_errors++;
1120 err++;
1121 }
1122 else if (xmlMemUsed() != mem) {
1123 if ((xmlMemUsed() != mem) &&
1124 (extraMemoryFromResolver == 0)) {
1125 fprintf(stderr, "File %s leaked %d bytes\n",
1126 globbuf.gl_pathv[i], xmlMemUsed() - mem);
1127 nb_leaks++;
1128 err++;
1129 }
1130 }
1131 testErrorsSize = 0;
1132 }
1133 if (result)
1134 free(result);
1135 if (error)
1136 free(error);
1137 }
1138 globfree(&globbuf);
1139 } else {
1140 testErrorsSize = 0;
1141 testErrors[0] = 0;
1142 extraMemoryFromResolver = 0;
1143 res = tst->func(NULL, NULL, NULL, tst->options);
1144 if (res != 0) {
1145 nb_errors++;
1146 err++;
1147 }
1148 }
1149 return(err);
1150}
1151
1152static int verbose = 0;
1153static int tests_quiet = 0;
1154
1155static int
1156runtest(int i) {
1157 int ret = 0, res;
1158 int old_errors, old_tests, old_leaks;
1159
1160 old_errors = nb_errors;
1161 old_tests = nb_tests;
1162 old_leaks = nb_leaks;
1163 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
1164 printf("## %s\n", testDescriptions[i].desc);
1165 res = launchTests(&testDescriptions[i]);
1166 if (res != 0)
1167 ret++;
1168 if (verbose) {
1169 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
1170 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
1171 else
1172 printf("Ran %d tests, %d errors, %d leaks\n",
1173 nb_tests - old_tests,
1174 nb_errors - old_errors,
1175 nb_leaks - old_leaks);
1176 }
1177 return(ret);
1178}
1179
1180int
1181main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
1182 int i, a, ret = 0;
1183 int subset = 0;
1184
1185 initializeLibxml2();
1186
1187 for (a = 1; a < argc;a++) {
1188 if (!strcmp(argv[a], "-v"))
1189 verbose = 1;
1190 else if (!strcmp(argv[a], "-quiet"))
1191 tests_quiet = 1;
1192 else {
1193 for (i = 0; testDescriptions[i].func != NULL; i++) {
1194 if (strstr(testDescriptions[i].desc, argv[a])) {
1195 ret += runtest(i);
1196 subset++;
1197 }
1198 }
1199 }
1200 }
1201 if (subset == 0) {
1202 for (i = 0; testDescriptions[i].func != NULL; i++) {
1203 ret += runtest(i);
1204 }
1205 }
1206 if ((nb_errors == 0) && (nb_leaks == 0)) {
1207 ret = 0;
1208 printf("Total %d tests, no errors\n",
1209 nb_tests);
1210 } else {
1211 ret = 1;
1212 printf("Total %d tests, %d errors, %d leaks\n",
1213 nb_tests, nb_errors, nb_leaks);
1214 }
1215 xmlCleanupParser();
1216
1217 return(ret);
1218}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use