xref: /aosp_15_r20/external/libxml2/debugXML.c (revision 7c5688314b92172186c154356a6374bf7684c3ca)
1 /*
2  * debugXML.c : This is a set of routines used for debugging the tree
3  *              produced by the XML parser.
4  *
5  * See Copyright for the status of this software.
6  *
7  * Daniel Veillard <[email protected]>
8  */
9 
10 #define IN_LIBXML
11 #include "libxml.h"
12 #ifdef LIBXML_DEBUG_ENABLED
13 
14 #include <string.h>
15 #include <stdlib.h>
16 
17 #include <libxml/debugXML.h>
18 #include <libxml/xmlmemory.h>
19 #include <libxml/tree.h>
20 #include <libxml/parser.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/HTMLtree.h>
23 #include <libxml/HTMLparser.h>
24 #include <libxml/xmlerror.h>
25 
26 #include "private/error.h"
27 
28 #define DUMP_TEXT_TYPE 1
29 
30 typedef struct _xmlDebugCtxt xmlDebugCtxt;
31 typedef xmlDebugCtxt *xmlDebugCtxtPtr;
32 struct _xmlDebugCtxt {
33     FILE *output;               /* the output file */
34     char shift[101];            /* used for indenting */
35     int depth;                  /* current depth */
36     xmlDocPtr doc;              /* current document */
37     xmlNodePtr node;		/* current node */
38     xmlDictPtr dict;		/* the doc dictionary */
39     int check;                  /* do just checkings */
40     int errors;                 /* number of errors found */
41     int nodict;			/* if the document has no dictionary */
42     int options;		/* options */
43 };
44 
45 static void xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node);
46 
47 static void
xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)48 xmlCtxtDumpInitCtxt(xmlDebugCtxtPtr ctxt)
49 {
50     int i;
51 
52     ctxt->depth = 0;
53     ctxt->check = 0;
54     ctxt->errors = 0;
55     ctxt->output = stdout;
56     ctxt->doc = NULL;
57     ctxt->node = NULL;
58     ctxt->dict = NULL;
59     ctxt->nodict = 0;
60     ctxt->options = 0;
61     for (i = 0; i < 100; i++)
62         ctxt->shift[i] = ' ';
63     ctxt->shift[100] = 0;
64 }
65 
66 static void
xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)67 xmlCtxtDumpCleanCtxt(xmlDebugCtxtPtr ctxt ATTRIBUTE_UNUSED)
68 {
69  /* remove the ATTRIBUTE_UNUSED when this is added */
70 }
71 
72 /**
73  * xmlNsCheckScope:
74  * @node: the node
75  * @ns: the namespace node
76  *
77  * Check that a given namespace is in scope on a node.
78  *
79  * Returns 1 if in scope, -1 in case of argument error,
80  *         -2 if the namespace is not in scope, and -3 if not on
81  *         an ancestor node.
82  */
83 static int
xmlNsCheckScope(xmlNodePtr node,xmlNsPtr ns)84 xmlNsCheckScope(xmlNodePtr node, xmlNsPtr ns)
85 {
86     xmlNsPtr cur;
87 
88     if ((node == NULL) || (ns == NULL))
89         return(-1);
90 
91     if ((node->type != XML_ELEMENT_NODE) &&
92 	(node->type != XML_ATTRIBUTE_NODE) &&
93 	(node->type != XML_DOCUMENT_NODE) &&
94 	(node->type != XML_TEXT_NODE) &&
95 	(node->type != XML_HTML_DOCUMENT_NODE) &&
96 	(node->type != XML_XINCLUDE_START))
97 	return(-2);
98 
99     while ((node != NULL) &&
100            ((node->type == XML_ELEMENT_NODE) ||
101             (node->type == XML_ATTRIBUTE_NODE) ||
102             (node->type == XML_TEXT_NODE) ||
103 	    (node->type == XML_XINCLUDE_START))) {
104 	if ((node->type == XML_ELEMENT_NODE) ||
105 	    (node->type == XML_XINCLUDE_START)) {
106 	    cur = node->nsDef;
107 	    while (cur != NULL) {
108 	        if (cur == ns)
109 		    return(1);
110 		if (xmlStrEqual(cur->prefix, ns->prefix))
111 		    return(-2);
112 		cur = cur->next;
113 	    }
114 	}
115 	node = node->parent;
116     }
117     /* the xml namespace may be declared on the document node */
118     if ((node != NULL) &&
119         ((node->type == XML_DOCUMENT_NODE) ||
120 	 (node->type == XML_HTML_DOCUMENT_NODE))) {
121 	 xmlNsPtr oldNs = ((xmlDocPtr) node)->oldNs;
122 	 if (oldNs == ns)
123 	     return(1);
124     }
125     return(-3);
126 }
127 
128 static void
xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)129 xmlCtxtDumpSpaces(xmlDebugCtxtPtr ctxt)
130 {
131     if (ctxt->check)
132         return;
133     if ((ctxt->output != NULL) && (ctxt->depth > 0)) {
134         if (ctxt->depth < 50)
135             fprintf(ctxt->output, "%s", &ctxt->shift[100 - 2 * ctxt->depth]);
136         else
137             fprintf(ctxt->output, "%s", ctxt->shift);
138     }
139 }
140 
141 /**
142  * xmlDebugErr:
143  * @ctxt:  a debug context
144  * @error:  the error code
145  *
146  * Handle a debug error.
147  */
148 static void
xmlDebugErr(xmlDebugCtxtPtr ctxt,int error,const char * msg)149 xmlDebugErr(xmlDebugCtxtPtr ctxt, int error, const char *msg)
150 {
151     ctxt->errors++;
152     fprintf(ctxt->output, "ERROR %d: %s", error, msg);
153 }
154 static void LIBXML_ATTR_FORMAT(3,0)
xmlDebugErr2(xmlDebugCtxtPtr ctxt,int error,const char * msg,int extra)155 xmlDebugErr2(xmlDebugCtxtPtr ctxt, int error, const char *msg, int extra)
156 {
157     ctxt->errors++;
158     fprintf(ctxt->output, "ERROR %d: ", error);
159     fprintf(ctxt->output, msg, extra);
160 }
161 static void LIBXML_ATTR_FORMAT(3,0)
xmlDebugErr3(xmlDebugCtxtPtr ctxt,int error,const char * msg,const char * extra)162 xmlDebugErr3(xmlDebugCtxtPtr ctxt, int error, const char *msg, const char *extra)
163 {
164     ctxt->errors++;
165     fprintf(ctxt->output, "ERROR %d: ", error);
166     fprintf(ctxt->output, msg, extra);
167 }
168 
169 /**
170  * xmlCtxtNsCheckScope:
171  * @ctxt: the debugging context
172  * @node: the node
173  * @ns: the namespace node
174  *
175  * Report if a given namespace is is not in scope.
176  */
177 static void
xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt,xmlNodePtr node,xmlNsPtr ns)178 xmlCtxtNsCheckScope(xmlDebugCtxtPtr ctxt, xmlNodePtr node, xmlNsPtr ns)
179 {
180     int ret;
181 
182     ret = xmlNsCheckScope(node, ns);
183     if (ret == -2) {
184         if (ns->prefix == NULL)
185 	    xmlDebugErr(ctxt, XML_CHECK_NS_SCOPE,
186 			"Reference to default namespace not in scope\n");
187 	else
188 	    xmlDebugErr3(ctxt, XML_CHECK_NS_SCOPE,
189 			 "Reference to namespace '%s' not in scope\n",
190 			 (char *) ns->prefix);
191     }
192     if (ret == -3) {
193         if (ns->prefix == NULL)
194 	    xmlDebugErr(ctxt, XML_CHECK_NS_ANCESTOR,
195 			"Reference to default namespace not on ancestor\n");
196 	else
197 	    xmlDebugErr3(ctxt, XML_CHECK_NS_ANCESTOR,
198 			 "Reference to namespace '%s' not on ancestor\n",
199 			 (char *) ns->prefix);
200     }
201 }
202 
203 /**
204  * xmlCtxtCheckString:
205  * @ctxt: the debug context
206  * @str: the string
207  *
208  * Do debugging on the string, currently it just checks the UTF-8 content
209  */
210 static void
xmlCtxtCheckString(xmlDebugCtxtPtr ctxt,const xmlChar * str)211 xmlCtxtCheckString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
212 {
213     if (str == NULL) return;
214     if (ctxt->check) {
215         if (!xmlCheckUTF8(str)) {
216 	    xmlDebugErr3(ctxt, XML_CHECK_NOT_UTF8,
217 			 "String is not UTF-8 %s", (const char *) str);
218 	}
219     }
220 }
221 
222 /**
223  * xmlCtxtCheckName:
224  * @ctxt: the debug context
225  * @name: the name
226  *
227  * Do debugging on the name, for example the dictionary status and
228  * conformance to the Name production.
229  */
230 static void
xmlCtxtCheckName(xmlDebugCtxtPtr ctxt,const xmlChar * name)231 xmlCtxtCheckName(xmlDebugCtxtPtr ctxt, const xmlChar * name)
232 {
233     if (ctxt->check) {
234 	if (name == NULL) {
235 	    xmlDebugErr(ctxt, XML_CHECK_NO_NAME, "Name is NULL");
236 	    return;
237 	}
238         if (xmlValidateName(name, 0)) {
239 	    xmlDebugErr3(ctxt, XML_CHECK_NOT_NCNAME,
240 			 "Name is not an NCName '%s'", (const char *) name);
241 	}
242 	if ((ctxt->dict != NULL) &&
243 	    (!xmlDictOwns(ctxt->dict, name)) &&
244             ((ctxt->doc == NULL) ||
245              ((ctxt->doc->parseFlags & (XML_PARSE_SAX1 | XML_PARSE_NODICT)) == 0))) {
246 	    xmlDebugErr3(ctxt, XML_CHECK_OUTSIDE_DICT,
247 			 "Name is not from the document dictionary '%s'",
248 			 (const char *) name);
249 	}
250     }
251 }
252 
253 static void
xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt,xmlNodePtr node)254 xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
255     xmlDocPtr doc;
256     xmlDictPtr dict;
257 
258     doc = node->doc;
259 
260     if (node->parent == NULL)
261         xmlDebugErr(ctxt, XML_CHECK_NO_PARENT,
262 	            "Node has no parent\n");
263     if (node->doc == NULL) {
264         xmlDebugErr(ctxt, XML_CHECK_NO_DOC,
265 	            "Node has no doc\n");
266         dict = NULL;
267     } else {
268 	dict = doc->dict;
269 	if ((dict == NULL) && (ctxt->nodict == 0)) {
270 	    ctxt->nodict = 1;
271 	}
272 	if (ctxt->doc == NULL)
273 	    ctxt->doc = doc;
274 
275 	if (ctxt->dict == NULL) {
276 	    ctxt->dict = dict;
277 	}
278     }
279     if ((node->parent != NULL) && (node->doc != node->parent->doc) &&
280         (!xmlStrEqual(node->name, BAD_CAST "pseudoroot")))
281         xmlDebugErr(ctxt, XML_CHECK_WRONG_DOC,
282 	            "Node doc differs from parent's one\n");
283     if (node->prev == NULL) {
284         if (node->type == XML_ATTRIBUTE_NODE) {
285 	    if ((node->parent != NULL) &&
286 	        (node != (xmlNodePtr) node->parent->properties))
287 		xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
288                     "Attr has no prev and not first of attr list\n");
289 
290         } else if ((node->parent != NULL) && (node->parent->children != node))
291 	    xmlDebugErr(ctxt, XML_CHECK_NO_PREV,
292                     "Node has no prev and not first of parent list\n");
293     } else {
294         if (node->prev->next != node)
295 	    xmlDebugErr(ctxt, XML_CHECK_WRONG_PREV,
296                         "Node prev->next : back link wrong\n");
297     }
298     if (node->next == NULL) {
299 	if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
300 	    (node->parent->last != node) &&
301 	    (node->parent->type == XML_ELEMENT_NODE))
302 	    xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
303                     "Node has no next and not last of parent list\n");
304     } else {
305         if (node->next->prev != node)
306 	    xmlDebugErr(ctxt, XML_CHECK_WRONG_NEXT,
307                     "Node next->prev : forward link wrong\n");
308         if (node->next->parent != node->parent)
309 	    xmlDebugErr(ctxt, XML_CHECK_WRONG_PARENT,
310                     "Node next->prev : forward link wrong\n");
311     }
312     if (node->type == XML_ELEMENT_NODE) {
313         xmlNsPtr ns;
314 
315 	ns = node->nsDef;
316 	while (ns != NULL) {
317 	    xmlCtxtNsCheckScope(ctxt, node, ns);
318 	    ns = ns->next;
319 	}
320 	if (node->ns != NULL)
321 	    xmlCtxtNsCheckScope(ctxt, node, node->ns);
322     } else if (node->type == XML_ATTRIBUTE_NODE) {
323 	if (node->ns != NULL)
324 	    xmlCtxtNsCheckScope(ctxt, node, node->ns);
325     }
326 
327     if ((node->type != XML_ELEMENT_NODE) &&
328 	(node->type != XML_ATTRIBUTE_NODE) &&
329 	(node->type != XML_ELEMENT_DECL) &&
330 	(node->type != XML_ATTRIBUTE_DECL) &&
331 	(node->type != XML_DTD_NODE) &&
332 	(node->type != XML_HTML_DOCUMENT_NODE) &&
333 	(node->type != XML_DOCUMENT_NODE)) {
334 	if (node->content != NULL)
335 	    xmlCtxtCheckString(ctxt, (const xmlChar *) node->content);
336     }
337     switch (node->type) {
338         case XML_ELEMENT_NODE:
339         case XML_ATTRIBUTE_NODE:
340 	    xmlCtxtCheckName(ctxt, node->name);
341 	    break;
342         case XML_TEXT_NODE:
343 	    if ((node->name == xmlStringText) ||
344 	        (node->name == xmlStringTextNoenc))
345 		break;
346 	    /* some case of entity substitution can lead to this */
347 	    if ((ctxt->dict != NULL) &&
348 	        (node->name == xmlDictLookup(ctxt->dict, BAD_CAST "nbktext",
349 		                             7)))
350 		break;
351 
352 	    xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
353 			 "Text node has wrong name '%s'",
354 			 (const char *) node->name);
355 	    break;
356         case XML_COMMENT_NODE:
357 	    if (node->name == xmlStringComment)
358 		break;
359 	    xmlDebugErr3(ctxt, XML_CHECK_WRONG_NAME,
360 			 "Comment node has wrong name '%s'",
361 			 (const char *) node->name);
362 	    break;
363         case XML_PI_NODE:
364 	    xmlCtxtCheckName(ctxt, node->name);
365 	    break;
366         case XML_CDATA_SECTION_NODE:
367 	    if (node->name == NULL)
368 		break;
369 	    xmlDebugErr3(ctxt, XML_CHECK_NAME_NOT_NULL,
370 			 "CData section has non NULL name '%s'",
371 			 (const char *) node->name);
372 	    break;
373         case XML_ENTITY_REF_NODE:
374         case XML_ENTITY_NODE:
375         case XML_DOCUMENT_TYPE_NODE:
376         case XML_DOCUMENT_FRAG_NODE:
377         case XML_NOTATION_NODE:
378         case XML_DTD_NODE:
379         case XML_ELEMENT_DECL:
380         case XML_ATTRIBUTE_DECL:
381         case XML_ENTITY_DECL:
382         case XML_NAMESPACE_DECL:
383         case XML_XINCLUDE_START:
384         case XML_XINCLUDE_END:
385         case XML_DOCUMENT_NODE:
386         case XML_HTML_DOCUMENT_NODE:
387 	    break;
388     }
389 }
390 
391 static void
xmlCtxtDumpString(xmlDebugCtxtPtr ctxt,const xmlChar * str)392 xmlCtxtDumpString(xmlDebugCtxtPtr ctxt, const xmlChar * str)
393 {
394     int i;
395 
396     if (ctxt->check) {
397         return;
398     }
399     /* TODO: check UTF8 content of the string */
400     if (str == NULL) {
401         fprintf(ctxt->output, "(NULL)");
402         return;
403     }
404     for (i = 0; i < 40; i++)
405         if (str[i] == 0)
406             return;
407         else if (IS_BLANK_CH(str[i]))
408             fputc(' ', ctxt->output);
409         else if (str[i] >= 0x80)
410             fprintf(ctxt->output, "#%X", str[i]);
411         else
412             fputc(str[i], ctxt->output);
413     fprintf(ctxt->output, "...");
414 }
415 
416 static void
xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)417 xmlCtxtDumpDtdNode(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
418 {
419     xmlCtxtDumpSpaces(ctxt);
420 
421     if (dtd == NULL) {
422         if (!ctxt->check)
423             fprintf(ctxt->output, "DTD node is NULL\n");
424         return;
425     }
426 
427     if (dtd->type != XML_DTD_NODE) {
428 	xmlDebugErr(ctxt, XML_CHECK_NOT_DTD,
429 	            "Node is not a DTD");
430         return;
431     }
432     if (!ctxt->check) {
433         if (dtd->name != NULL)
434             fprintf(ctxt->output, "DTD(%s)", (char *) dtd->name);
435         else
436             fprintf(ctxt->output, "DTD");
437         if (dtd->ExternalID != NULL)
438             fprintf(ctxt->output, ", PUBLIC %s", (char *) dtd->ExternalID);
439         if (dtd->SystemID != NULL)
440             fprintf(ctxt->output, ", SYSTEM %s", (char *) dtd->SystemID);
441         fprintf(ctxt->output, "\n");
442     }
443     /*
444      * Do a bit of checking
445      */
446     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) dtd);
447 }
448 
449 static void
xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt,xmlAttributePtr attr)450 xmlCtxtDumpAttrDecl(xmlDebugCtxtPtr ctxt, xmlAttributePtr attr)
451 {
452     xmlCtxtDumpSpaces(ctxt);
453 
454     if (attr == NULL) {
455         if (!ctxt->check)
456             fprintf(ctxt->output, "Attribute declaration is NULL\n");
457         return;
458     }
459     if (attr->type != XML_ATTRIBUTE_DECL) {
460 	xmlDebugErr(ctxt, XML_CHECK_NOT_ATTR_DECL,
461 	            "Node is not an attribute declaration");
462         return;
463     }
464     if (attr->name != NULL) {
465         if (!ctxt->check)
466             fprintf(ctxt->output, "ATTRDECL(%s)", (char *) attr->name);
467     } else
468 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
469 	            "Node attribute declaration has no name");
470     if (attr->elem != NULL) {
471         if (!ctxt->check)
472             fprintf(ctxt->output, " for %s", (char *) attr->elem);
473     } else
474 	xmlDebugErr(ctxt, XML_CHECK_NO_ELEM,
475 	            "Node attribute declaration has no element name");
476     if (!ctxt->check) {
477         switch (attr->atype) {
478             case XML_ATTRIBUTE_CDATA:
479                 fprintf(ctxt->output, " CDATA");
480                 break;
481             case XML_ATTRIBUTE_ID:
482                 fprintf(ctxt->output, " ID");
483                 break;
484             case XML_ATTRIBUTE_IDREF:
485                 fprintf(ctxt->output, " IDREF");
486                 break;
487             case XML_ATTRIBUTE_IDREFS:
488                 fprintf(ctxt->output, " IDREFS");
489                 break;
490             case XML_ATTRIBUTE_ENTITY:
491                 fprintf(ctxt->output, " ENTITY");
492                 break;
493             case XML_ATTRIBUTE_ENTITIES:
494                 fprintf(ctxt->output, " ENTITIES");
495                 break;
496             case XML_ATTRIBUTE_NMTOKEN:
497                 fprintf(ctxt->output, " NMTOKEN");
498                 break;
499             case XML_ATTRIBUTE_NMTOKENS:
500                 fprintf(ctxt->output, " NMTOKENS");
501                 break;
502             case XML_ATTRIBUTE_ENUMERATION:
503                 fprintf(ctxt->output, " ENUMERATION");
504                 break;
505             case XML_ATTRIBUTE_NOTATION:
506                 fprintf(ctxt->output, " NOTATION ");
507                 break;
508         }
509         if (attr->tree != NULL) {
510             int indx;
511             xmlEnumerationPtr cur = attr->tree;
512 
513             for (indx = 0; indx < 5; indx++) {
514                 if (indx != 0)
515                     fprintf(ctxt->output, "|%s", (char *) cur->name);
516                 else
517                     fprintf(ctxt->output, " (%s", (char *) cur->name);
518                 cur = cur->next;
519                 if (cur == NULL)
520                     break;
521             }
522             if (cur == NULL)
523                 fprintf(ctxt->output, ")");
524             else
525                 fprintf(ctxt->output, "...)");
526         }
527         switch (attr->def) {
528             case XML_ATTRIBUTE_NONE:
529                 break;
530             case XML_ATTRIBUTE_REQUIRED:
531                 fprintf(ctxt->output, " REQUIRED");
532                 break;
533             case XML_ATTRIBUTE_IMPLIED:
534                 fprintf(ctxt->output, " IMPLIED");
535                 break;
536             case XML_ATTRIBUTE_FIXED:
537                 fprintf(ctxt->output, " FIXED");
538                 break;
539         }
540         if (attr->defaultValue != NULL) {
541             fprintf(ctxt->output, "\"");
542             xmlCtxtDumpString(ctxt, attr->defaultValue);
543             fprintf(ctxt->output, "\"");
544         }
545         fprintf(ctxt->output, "\n");
546     }
547 
548     /*
549      * Do a bit of checking
550      */
551     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
552 }
553 
554 static void
xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt,xmlElementPtr elem)555 xmlCtxtDumpElemDecl(xmlDebugCtxtPtr ctxt, xmlElementPtr elem)
556 {
557     xmlCtxtDumpSpaces(ctxt);
558 
559     if (elem == NULL) {
560         if (!ctxt->check)
561             fprintf(ctxt->output, "Element declaration is NULL\n");
562         return;
563     }
564     if (elem->type != XML_ELEMENT_DECL) {
565 	xmlDebugErr(ctxt, XML_CHECK_NOT_ELEM_DECL,
566 	            "Node is not an element declaration");
567         return;
568     }
569     if (elem->name != NULL) {
570         if (!ctxt->check) {
571             fprintf(ctxt->output, "ELEMDECL(");
572             xmlCtxtDumpString(ctxt, elem->name);
573             fprintf(ctxt->output, ")");
574         }
575     } else
576 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
577 	            "Element declaration has no name");
578     if (!ctxt->check) {
579         switch (elem->etype) {
580             case XML_ELEMENT_TYPE_UNDEFINED:
581                 fprintf(ctxt->output, ", UNDEFINED");
582                 break;
583             case XML_ELEMENT_TYPE_EMPTY:
584                 fprintf(ctxt->output, ", EMPTY");
585                 break;
586             case XML_ELEMENT_TYPE_ANY:
587                 fprintf(ctxt->output, ", ANY");
588                 break;
589             case XML_ELEMENT_TYPE_MIXED:
590                 fprintf(ctxt->output, ", MIXED ");
591                 break;
592             case XML_ELEMENT_TYPE_ELEMENT:
593                 fprintf(ctxt->output, ", MIXED ");
594                 break;
595         }
596         if ((elem->type != XML_ELEMENT_NODE) && (elem->content != NULL)) {
597             char buf[5001];
598 
599             buf[0] = 0;
600             xmlSnprintfElementContent(buf, 5000, elem->content, 1);
601             buf[5000] = 0;
602             fprintf(ctxt->output, "%s", buf);
603         }
604         fprintf(ctxt->output, "\n");
605     }
606 
607     /*
608      * Do a bit of checking
609      */
610     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) elem);
611 }
612 
613 static void
xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)614 xmlCtxtDumpEntityDecl(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
615 {
616     xmlCtxtDumpSpaces(ctxt);
617 
618     if (ent == NULL) {
619         if (!ctxt->check)
620             fprintf(ctxt->output, "Entity declaration is NULL\n");
621         return;
622     }
623     if (ent->type != XML_ENTITY_DECL) {
624 	xmlDebugErr(ctxt, XML_CHECK_NOT_ENTITY_DECL,
625 	            "Node is not an entity declaration");
626         return;
627     }
628     if (ent->name != NULL) {
629         if (!ctxt->check) {
630             fprintf(ctxt->output, "ENTITYDECL(");
631             xmlCtxtDumpString(ctxt, ent->name);
632             fprintf(ctxt->output, ")");
633         }
634     } else
635 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
636 	            "Entity declaration has no name");
637     if (!ctxt->check) {
638         switch (ent->etype) {
639             case XML_INTERNAL_GENERAL_ENTITY:
640                 fprintf(ctxt->output, ", internal\n");
641                 break;
642             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
643                 fprintf(ctxt->output, ", external parsed\n");
644                 break;
645             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
646                 fprintf(ctxt->output, ", unparsed\n");
647                 break;
648             case XML_INTERNAL_PARAMETER_ENTITY:
649                 fprintf(ctxt->output, ", parameter\n");
650                 break;
651             case XML_EXTERNAL_PARAMETER_ENTITY:
652                 fprintf(ctxt->output, ", external parameter\n");
653                 break;
654             case XML_INTERNAL_PREDEFINED_ENTITY:
655                 fprintf(ctxt->output, ", predefined\n");
656                 break;
657         }
658         if (ent->ExternalID) {
659             xmlCtxtDumpSpaces(ctxt);
660             fprintf(ctxt->output, " ExternalID=%s\n",
661                     (char *) ent->ExternalID);
662         }
663         if (ent->SystemID) {
664             xmlCtxtDumpSpaces(ctxt);
665             fprintf(ctxt->output, " SystemID=%s\n",
666                     (char *) ent->SystemID);
667         }
668         if (ent->URI != NULL) {
669             xmlCtxtDumpSpaces(ctxt);
670             fprintf(ctxt->output, " URI=%s\n", (char *) ent->URI);
671         }
672         if (ent->content) {
673             xmlCtxtDumpSpaces(ctxt);
674             fprintf(ctxt->output, " content=");
675             xmlCtxtDumpString(ctxt, ent->content);
676             fprintf(ctxt->output, "\n");
677         }
678     }
679 
680     /*
681      * Do a bit of checking
682      */
683     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) ent);
684 }
685 
686 static void
xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)687 xmlCtxtDumpNamespace(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
688 {
689     xmlCtxtDumpSpaces(ctxt);
690 
691     if (ns == NULL) {
692         if (!ctxt->check)
693             fprintf(ctxt->output, "namespace node is NULL\n");
694         return;
695     }
696     if (ns->type != XML_NAMESPACE_DECL) {
697 	xmlDebugErr(ctxt, XML_CHECK_NOT_NS_DECL,
698 	            "Node is not a namespace declaration");
699         return;
700     }
701     if (ns->href == NULL) {
702         if (ns->prefix != NULL)
703 	    xmlDebugErr3(ctxt, XML_CHECK_NO_HREF,
704                     "Incomplete namespace %s href=NULL\n",
705                     (char *) ns->prefix);
706         else
707 	    xmlDebugErr(ctxt, XML_CHECK_NO_HREF,
708                     "Incomplete default namespace href=NULL\n");
709     } else {
710         if (!ctxt->check) {
711             if (ns->prefix != NULL)
712                 fprintf(ctxt->output, "namespace %s href=",
713                         (char *) ns->prefix);
714             else
715                 fprintf(ctxt->output, "default namespace href=");
716 
717             xmlCtxtDumpString(ctxt, ns->href);
718             fprintf(ctxt->output, "\n");
719         }
720     }
721 }
722 
723 static void
xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt,xmlNsPtr ns)724 xmlCtxtDumpNamespaceList(xmlDebugCtxtPtr ctxt, xmlNsPtr ns)
725 {
726     while (ns != NULL) {
727         xmlCtxtDumpNamespace(ctxt, ns);
728         ns = ns->next;
729     }
730 }
731 
732 static void
xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt,xmlEntityPtr ent)733 xmlCtxtDumpEntity(xmlDebugCtxtPtr ctxt, xmlEntityPtr ent)
734 {
735     xmlCtxtDumpSpaces(ctxt);
736 
737     if (ent == NULL) {
738         if (!ctxt->check)
739             fprintf(ctxt->output, "Entity is NULL\n");
740         return;
741     }
742     if (!ctxt->check) {
743         switch (ent->etype) {
744             case XML_INTERNAL_GENERAL_ENTITY:
745                 fprintf(ctxt->output, "INTERNAL_GENERAL_ENTITY ");
746                 break;
747             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
748                 fprintf(ctxt->output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
749                 break;
750             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
751                 fprintf(ctxt->output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
752                 break;
753             case XML_INTERNAL_PARAMETER_ENTITY:
754                 fprintf(ctxt->output, "INTERNAL_PARAMETER_ENTITY ");
755                 break;
756             case XML_EXTERNAL_PARAMETER_ENTITY:
757                 fprintf(ctxt->output, "EXTERNAL_PARAMETER_ENTITY ");
758                 break;
759             default:
760                 fprintf(ctxt->output, "ENTITY_%d ! ", (int) ent->etype);
761         }
762         fprintf(ctxt->output, "%s\n", ent->name);
763         if (ent->ExternalID) {
764             xmlCtxtDumpSpaces(ctxt);
765             fprintf(ctxt->output, "ExternalID=%s\n",
766                     (char *) ent->ExternalID);
767         }
768         if (ent->SystemID) {
769             xmlCtxtDumpSpaces(ctxt);
770             fprintf(ctxt->output, "SystemID=%s\n", (char *) ent->SystemID);
771         }
772         if (ent->URI) {
773             xmlCtxtDumpSpaces(ctxt);
774             fprintf(ctxt->output, "URI=%s\n", (char *) ent->URI);
775         }
776         if (ent->content) {
777             xmlCtxtDumpSpaces(ctxt);
778             fprintf(ctxt->output, "content=");
779             xmlCtxtDumpString(ctxt, ent->content);
780             fprintf(ctxt->output, "\n");
781         }
782     }
783 }
784 
785 /**
786  * xmlCtxtDumpAttr:
787  * @output:  the FILE * for the output
788  * @attr:  the attribute
789  * @depth:  the indentation level.
790  *
791  * Dumps debug information for the attribute
792  */
793 static void
xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)794 xmlCtxtDumpAttr(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
795 {
796     xmlCtxtDumpSpaces(ctxt);
797 
798     if (attr == NULL) {
799         if (!ctxt->check)
800             fprintf(ctxt->output, "Attr is NULL");
801         return;
802     }
803     if (!ctxt->check) {
804         fprintf(ctxt->output, "ATTRIBUTE ");
805 	xmlCtxtDumpString(ctxt, attr->name);
806         fprintf(ctxt->output, "\n");
807         if (attr->children != NULL) {
808             ctxt->depth++;
809             xmlCtxtDumpNodeList(ctxt, attr->children);
810             ctxt->depth--;
811         }
812     }
813     if (attr->name == NULL)
814 	xmlDebugErr(ctxt, XML_CHECK_NO_NAME,
815 	            "Attribute has no name");
816 
817     /*
818      * Do a bit of checking
819      */
820     xmlCtxtGenericNodeCheck(ctxt, (xmlNodePtr) attr);
821 }
822 
823 /**
824  * xmlCtxtDumpAttrList:
825  * @output:  the FILE * for the output
826  * @attr:  the attribute list
827  * @depth:  the indentation level.
828  *
829  * Dumps debug information for the attribute list
830  */
831 static void
xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt,xmlAttrPtr attr)832 xmlCtxtDumpAttrList(xmlDebugCtxtPtr ctxt, xmlAttrPtr attr)
833 {
834     while (attr != NULL) {
835         xmlCtxtDumpAttr(ctxt, attr);
836         attr = attr->next;
837     }
838 }
839 
840 /**
841  * xmlCtxtDumpOneNode:
842  * @output:  the FILE * for the output
843  * @node:  the node
844  * @depth:  the indentation level.
845  *
846  * Dumps debug information for the element node, it is not recursive
847  */
848 static void
xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)849 xmlCtxtDumpOneNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
850 {
851     if (node == NULL) {
852         if (!ctxt->check) {
853             xmlCtxtDumpSpaces(ctxt);
854             fprintf(ctxt->output, "node is NULL\n");
855         }
856         return;
857     }
858     ctxt->node = node;
859 
860     switch (node->type) {
861         case XML_ELEMENT_NODE:
862             if (!ctxt->check) {
863                 xmlCtxtDumpSpaces(ctxt);
864                 fprintf(ctxt->output, "ELEMENT ");
865                 if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
866                     xmlCtxtDumpString(ctxt, node->ns->prefix);
867                     fprintf(ctxt->output, ":");
868                 }
869                 xmlCtxtDumpString(ctxt, node->name);
870                 fprintf(ctxt->output, "\n");
871             }
872             break;
873         case XML_ATTRIBUTE_NODE:
874             if (!ctxt->check)
875                 xmlCtxtDumpSpaces(ctxt);
876             fprintf(ctxt->output, "Error, ATTRIBUTE found here\n");
877             xmlCtxtGenericNodeCheck(ctxt, node);
878             return;
879         case XML_TEXT_NODE:
880             if (!ctxt->check) {
881                 xmlCtxtDumpSpaces(ctxt);
882                 if (node->name == (const xmlChar *) xmlStringTextNoenc)
883                     fprintf(ctxt->output, "TEXT no enc");
884                 else
885                     fprintf(ctxt->output, "TEXT");
886 		if (ctxt->options & DUMP_TEXT_TYPE) {
887 		    if (node->content == (xmlChar *) &(node->properties))
888 			fprintf(ctxt->output, " compact\n");
889 		    else if (xmlDictOwns(ctxt->dict, node->content) == 1)
890 			fprintf(ctxt->output, " interned\n");
891 		    else
892 			fprintf(ctxt->output, "\n");
893 		} else
894 		    fprintf(ctxt->output, "\n");
895             }
896             break;
897         case XML_CDATA_SECTION_NODE:
898             if (!ctxt->check) {
899                 xmlCtxtDumpSpaces(ctxt);
900                 fprintf(ctxt->output, "CDATA_SECTION\n");
901             }
902             break;
903         case XML_ENTITY_REF_NODE:
904             if (!ctxt->check) {
905                 xmlCtxtDumpSpaces(ctxt);
906                 fprintf(ctxt->output, "ENTITY_REF(%s)\n",
907                         (char *) node->name);
908             }
909             break;
910         case XML_ENTITY_NODE:
911             if (!ctxt->check) {
912                 xmlCtxtDumpSpaces(ctxt);
913                 fprintf(ctxt->output, "ENTITY\n");
914             }
915             break;
916         case XML_PI_NODE:
917             if (!ctxt->check) {
918                 xmlCtxtDumpSpaces(ctxt);
919                 fprintf(ctxt->output, "PI %s\n", (char *) node->name);
920             }
921             break;
922         case XML_COMMENT_NODE:
923             if (!ctxt->check) {
924                 xmlCtxtDumpSpaces(ctxt);
925                 fprintf(ctxt->output, "COMMENT\n");
926             }
927             break;
928         case XML_DOCUMENT_NODE:
929         case XML_HTML_DOCUMENT_NODE:
930             if (!ctxt->check) {
931                 xmlCtxtDumpSpaces(ctxt);
932             }
933             fprintf(ctxt->output, "Error, DOCUMENT found here\n");
934             xmlCtxtGenericNodeCheck(ctxt, node);
935             return;
936         case XML_DOCUMENT_TYPE_NODE:
937             if (!ctxt->check) {
938                 xmlCtxtDumpSpaces(ctxt);
939                 fprintf(ctxt->output, "DOCUMENT_TYPE\n");
940             }
941             break;
942         case XML_DOCUMENT_FRAG_NODE:
943             if (!ctxt->check) {
944                 xmlCtxtDumpSpaces(ctxt);
945                 fprintf(ctxt->output, "DOCUMENT_FRAG\n");
946             }
947             break;
948         case XML_NOTATION_NODE:
949             if (!ctxt->check) {
950                 xmlCtxtDumpSpaces(ctxt);
951                 fprintf(ctxt->output, "NOTATION\n");
952             }
953             break;
954         case XML_DTD_NODE:
955             xmlCtxtDumpDtdNode(ctxt, (xmlDtdPtr) node);
956             return;
957         case XML_ELEMENT_DECL:
958             xmlCtxtDumpElemDecl(ctxt, (xmlElementPtr) node);
959             return;
960         case XML_ATTRIBUTE_DECL:
961             xmlCtxtDumpAttrDecl(ctxt, (xmlAttributePtr) node);
962             return;
963         case XML_ENTITY_DECL:
964             xmlCtxtDumpEntityDecl(ctxt, (xmlEntityPtr) node);
965             return;
966         case XML_NAMESPACE_DECL:
967             xmlCtxtDumpNamespace(ctxt, (xmlNsPtr) node);
968             return;
969         case XML_XINCLUDE_START:
970             if (!ctxt->check) {
971                 xmlCtxtDumpSpaces(ctxt);
972                 fprintf(ctxt->output, "INCLUDE START\n");
973             }
974             return;
975         case XML_XINCLUDE_END:
976             if (!ctxt->check) {
977                 xmlCtxtDumpSpaces(ctxt);
978                 fprintf(ctxt->output, "INCLUDE END\n");
979             }
980             return;
981         default:
982             if (!ctxt->check)
983                 xmlCtxtDumpSpaces(ctxt);
984 	    xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
985 	                "Unknown node type %d\n", node->type);
986             return;
987     }
988     if (node->doc == NULL) {
989         if (!ctxt->check) {
990             xmlCtxtDumpSpaces(ctxt);
991         }
992         fprintf(ctxt->output, "PBM: doc == NULL !!!\n");
993     }
994     ctxt->depth++;
995     if ((node->type == XML_ELEMENT_NODE) && (node->nsDef != NULL))
996         xmlCtxtDumpNamespaceList(ctxt, node->nsDef);
997     if ((node->type == XML_ELEMENT_NODE) && (node->properties != NULL))
998         xmlCtxtDumpAttrList(ctxt, node->properties);
999     if (node->type != XML_ENTITY_REF_NODE) {
1000         if ((node->type != XML_ELEMENT_NODE) && (node->content != NULL)) {
1001             if (!ctxt->check) {
1002                 xmlCtxtDumpSpaces(ctxt);
1003                 fprintf(ctxt->output, "content=");
1004                 xmlCtxtDumpString(ctxt, node->content);
1005                 fprintf(ctxt->output, "\n");
1006             }
1007         }
1008     } else {
1009         xmlEntityPtr ent;
1010 
1011         ent = xmlGetDocEntity(node->doc, node->name);
1012         if (ent != NULL)
1013             xmlCtxtDumpEntity(ctxt, ent);
1014     }
1015     ctxt->depth--;
1016 
1017     /*
1018      * Do a bit of checking
1019      */
1020     xmlCtxtGenericNodeCheck(ctxt, node);
1021 }
1022 
1023 /**
1024  * xmlCtxtDumpNode:
1025  * @output:  the FILE * for the output
1026  * @node:  the node
1027  * @depth:  the indentation level.
1028  *
1029  * Dumps debug information for the element node, it is recursive
1030  */
1031 static void
xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1032 xmlCtxtDumpNode(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1033 {
1034     if (node == NULL) {
1035         if (!ctxt->check) {
1036             xmlCtxtDumpSpaces(ctxt);
1037             fprintf(ctxt->output, "node is NULL\n");
1038         }
1039         return;
1040     }
1041     xmlCtxtDumpOneNode(ctxt, node);
1042     if ((node->type != XML_NAMESPACE_DECL) &&
1043         (node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
1044         ctxt->depth++;
1045         xmlCtxtDumpNodeList(ctxt, node->children);
1046         ctxt->depth--;
1047     }
1048 }
1049 
1050 /**
1051  * xmlCtxtDumpNodeList:
1052  * @output:  the FILE * for the output
1053  * @node:  the node list
1054  * @depth:  the indentation level.
1055  *
1056  * Dumps debug information for the list of element node, it is recursive
1057  */
1058 static void
xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt,xmlNodePtr node)1059 xmlCtxtDumpNodeList(xmlDebugCtxtPtr ctxt, xmlNodePtr node)
1060 {
1061     while (node != NULL) {
1062         xmlCtxtDumpNode(ctxt, node);
1063         node = node->next;
1064     }
1065 }
1066 
1067 static void
xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1068 xmlCtxtDumpDocHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1069 {
1070     if (doc == NULL) {
1071         if (!ctxt->check)
1072             fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1073         return;
1074     }
1075     ctxt->node = (xmlNodePtr) doc;
1076 
1077     switch (doc->type) {
1078         case XML_ELEMENT_NODE:
1079 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ELEMENT,
1080 	                "Misplaced ELEMENT node\n");
1081             break;
1082         case XML_ATTRIBUTE_NODE:
1083 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ATTRIBUTE,
1084 	                "Misplaced ATTRIBUTE node\n");
1085             break;
1086         case XML_TEXT_NODE:
1087 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_TEXT,
1088 	                "Misplaced TEXT node\n");
1089             break;
1090         case XML_CDATA_SECTION_NODE:
1091 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_CDATA,
1092 	                "Misplaced CDATA node\n");
1093             break;
1094         case XML_ENTITY_REF_NODE:
1095 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITYREF,
1096 	                "Misplaced ENTITYREF node\n");
1097             break;
1098         case XML_ENTITY_NODE:
1099 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_ENTITY,
1100 	                "Misplaced ENTITY node\n");
1101             break;
1102         case XML_PI_NODE:
1103 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_PI,
1104 	                "Misplaced PI node\n");
1105             break;
1106         case XML_COMMENT_NODE:
1107 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_COMMENT,
1108 	                "Misplaced COMMENT node\n");
1109             break;
1110         case XML_DOCUMENT_NODE:
1111 	    if (!ctxt->check)
1112 		fprintf(ctxt->output, "DOCUMENT\n");
1113             break;
1114         case XML_HTML_DOCUMENT_NODE:
1115 	    if (!ctxt->check)
1116 		fprintf(ctxt->output, "HTML DOCUMENT\n");
1117             break;
1118         case XML_DOCUMENT_TYPE_NODE:
1119 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_DOCTYPE,
1120 	                "Misplaced DOCTYPE node\n");
1121             break;
1122         case XML_DOCUMENT_FRAG_NODE:
1123 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_FRAGMENT,
1124 	                "Misplaced FRAGMENT node\n");
1125             break;
1126         case XML_NOTATION_NODE:
1127 	    xmlDebugErr(ctxt, XML_CHECK_FOUND_NOTATION,
1128 	                "Misplaced NOTATION node\n");
1129             break;
1130         default:
1131 	    xmlDebugErr2(ctxt, XML_CHECK_UNKNOWN_NODE,
1132 	                "Unknown node type %d\n", doc->type);
1133     }
1134 }
1135 
1136 /**
1137  * xmlCtxtDumpDocumentHead:
1138  * @output:  the FILE * for the output
1139  * @doc:  the document
1140  *
1141  * Dumps debug information concerning the document, not recursive
1142  */
1143 static void
xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1144 xmlCtxtDumpDocumentHead(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1145 {
1146     if (doc == NULL) return;
1147     xmlCtxtDumpDocHead(ctxt, doc);
1148     if (!ctxt->check) {
1149         if (doc->name != NULL) {
1150             fprintf(ctxt->output, "name=");
1151             xmlCtxtDumpString(ctxt, BAD_CAST doc->name);
1152             fprintf(ctxt->output, "\n");
1153         }
1154         if (doc->version != NULL) {
1155             fprintf(ctxt->output, "version=");
1156             xmlCtxtDumpString(ctxt, doc->version);
1157             fprintf(ctxt->output, "\n");
1158         }
1159         if (doc->encoding != NULL) {
1160             fprintf(ctxt->output, "encoding=");
1161             xmlCtxtDumpString(ctxt, doc->encoding);
1162             fprintf(ctxt->output, "\n");
1163         }
1164         if (doc->URL != NULL) {
1165             fprintf(ctxt->output, "URL=");
1166             xmlCtxtDumpString(ctxt, doc->URL);
1167             fprintf(ctxt->output, "\n");
1168         }
1169         if (doc->standalone)
1170             fprintf(ctxt->output, "standalone=true\n");
1171     }
1172     if (doc->oldNs != NULL)
1173         xmlCtxtDumpNamespaceList(ctxt, doc->oldNs);
1174 }
1175 
1176 /**
1177  * xmlCtxtDumpDocument:
1178  * @output:  the FILE * for the output
1179  * @doc:  the document
1180  *
1181  * Dumps debug information for the document, it's recursive
1182  */
1183 static void
xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1184 xmlCtxtDumpDocument(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1185 {
1186     if (doc == NULL) {
1187         if (!ctxt->check)
1188             fprintf(ctxt->output, "DOCUMENT == NULL !\n");
1189         return;
1190     }
1191     xmlCtxtDumpDocumentHead(ctxt, doc);
1192     if (((doc->type == XML_DOCUMENT_NODE) ||
1193          (doc->type == XML_HTML_DOCUMENT_NODE))
1194         && (doc->children != NULL)) {
1195         ctxt->depth++;
1196         xmlCtxtDumpNodeList(ctxt, doc->children);
1197         ctxt->depth--;
1198     }
1199 }
1200 
1201 static void
xmlCtxtDumpEntityCallback(void * payload,void * data,const xmlChar * name ATTRIBUTE_UNUSED)1202 xmlCtxtDumpEntityCallback(void *payload, void *data,
1203                           const xmlChar *name ATTRIBUTE_UNUSED)
1204 {
1205     xmlEntityPtr cur = (xmlEntityPtr) payload;
1206     xmlDebugCtxtPtr ctxt = (xmlDebugCtxtPtr) data;
1207     if (cur == NULL) {
1208         if (!ctxt->check)
1209             fprintf(ctxt->output, "Entity is NULL");
1210         return;
1211     }
1212     if (!ctxt->check) {
1213         fprintf(ctxt->output, "%s : ", (char *) cur->name);
1214         switch (cur->etype) {
1215             case XML_INTERNAL_GENERAL_ENTITY:
1216                 fprintf(ctxt->output, "INTERNAL GENERAL, ");
1217                 break;
1218             case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1219                 fprintf(ctxt->output, "EXTERNAL PARSED, ");
1220                 break;
1221             case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1222                 fprintf(ctxt->output, "EXTERNAL UNPARSED, ");
1223                 break;
1224             case XML_INTERNAL_PARAMETER_ENTITY:
1225                 fprintf(ctxt->output, "INTERNAL PARAMETER, ");
1226                 break;
1227             case XML_EXTERNAL_PARAMETER_ENTITY:
1228                 fprintf(ctxt->output, "EXTERNAL PARAMETER, ");
1229                 break;
1230             default:
1231 		xmlDebugErr2(ctxt, XML_CHECK_ENTITY_TYPE,
1232 			     "Unknown entity type %d\n", cur->etype);
1233         }
1234         if (cur->ExternalID != NULL)
1235             fprintf(ctxt->output, "ID \"%s\"", (char *) cur->ExternalID);
1236         if (cur->SystemID != NULL)
1237             fprintf(ctxt->output, "SYSTEM \"%s\"", (char *) cur->SystemID);
1238         if (cur->orig != NULL)
1239             fprintf(ctxt->output, "\n orig \"%s\"", (char *) cur->orig);
1240         if ((cur->type != XML_ELEMENT_NODE) && (cur->content != NULL))
1241             fprintf(ctxt->output, "\n content \"%s\"",
1242                     (char *) cur->content);
1243         fprintf(ctxt->output, "\n");
1244     }
1245 }
1246 
1247 /**
1248  * xmlCtxtDumpEntities:
1249  * @output:  the FILE * for the output
1250  * @doc:  the document
1251  *
1252  * Dumps debug information for all the entities in use by the document
1253  */
1254 static void
xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt,xmlDocPtr doc)1255 xmlCtxtDumpEntities(xmlDebugCtxtPtr ctxt, xmlDocPtr doc)
1256 {
1257     if (doc == NULL) return;
1258     xmlCtxtDumpDocHead(ctxt, doc);
1259     if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
1260         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1261             doc->intSubset->entities;
1262 
1263         if (!ctxt->check)
1264             fprintf(ctxt->output, "Entities in internal subset\n");
1265         xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1266     } else
1267         fprintf(ctxt->output, "No entities in internal subset\n");
1268     if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
1269         xmlEntitiesTablePtr table = (xmlEntitiesTablePtr)
1270             doc->extSubset->entities;
1271 
1272         if (!ctxt->check)
1273             fprintf(ctxt->output, "Entities in external subset\n");
1274         xmlHashScan(table, xmlCtxtDumpEntityCallback, ctxt);
1275     } else if (!ctxt->check)
1276         fprintf(ctxt->output, "No entities in external subset\n");
1277 }
1278 
1279 /**
1280  * xmlCtxtDumpDTD:
1281  * @output:  the FILE * for the output
1282  * @dtd:  the DTD
1283  *
1284  * Dumps debug information for the DTD
1285  */
1286 static void
xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt,xmlDtdPtr dtd)1287 xmlCtxtDumpDTD(xmlDebugCtxtPtr ctxt, xmlDtdPtr dtd)
1288 {
1289     if (dtd == NULL) {
1290         if (!ctxt->check)
1291             fprintf(ctxt->output, "DTD is NULL\n");
1292         return;
1293     }
1294     xmlCtxtDumpDtdNode(ctxt, dtd);
1295     if (dtd->children == NULL)
1296         fprintf(ctxt->output, "    DTD is empty\n");
1297     else {
1298         ctxt->depth++;
1299         xmlCtxtDumpNodeList(ctxt, dtd->children);
1300         ctxt->depth--;
1301     }
1302 }
1303 
1304 /************************************************************************
1305  *									*
1306  *			Public entry points for dump			*
1307  *									*
1308  ************************************************************************/
1309 
1310 /**
1311  * xmlDebugDumpString:
1312  * @output:  the FILE * for the output
1313  * @str:  the string
1314  *
1315  * Dumps information about the string, shorten it if necessary
1316  */
1317 void
xmlDebugDumpString(FILE * output,const xmlChar * str)1318 xmlDebugDumpString(FILE * output, const xmlChar * str)
1319 {
1320     int i;
1321 
1322     if (output == NULL)
1323 	output = stdout;
1324     if (str == NULL) {
1325         fprintf(output, "(NULL)");
1326         return;
1327     }
1328     for (i = 0; i < 40; i++)
1329         if (str[i] == 0)
1330             return;
1331         else if (IS_BLANK_CH(str[i]))
1332             fputc(' ', output);
1333         else if (str[i] >= 0x80)
1334             fprintf(output, "#%X", str[i]);
1335         else
1336             fputc(str[i], output);
1337     fprintf(output, "...");
1338 }
1339 
1340 /**
1341  * xmlDebugDumpAttr:
1342  * @output:  the FILE * for the output
1343  * @attr:  the attribute
1344  * @depth:  the indentation level.
1345  *
1346  * Dumps debug information for the attribute
1347  */
1348 void
xmlDebugDumpAttr(FILE * output,xmlAttrPtr attr,int depth)1349 xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
1350     xmlDebugCtxt ctxt;
1351 
1352     if (output == NULL) return;
1353     xmlCtxtDumpInitCtxt(&ctxt);
1354     ctxt.output = output;
1355     ctxt.depth = depth;
1356     xmlCtxtDumpAttr(&ctxt, attr);
1357     xmlCtxtDumpCleanCtxt(&ctxt);
1358 }
1359 
1360 
1361 /**
1362  * xmlDebugDumpEntities:
1363  * @output:  the FILE * for the output
1364  * @doc:  the document
1365  *
1366  * Dumps debug information for all the entities in use by the document
1367  */
1368 void
xmlDebugDumpEntities(FILE * output,xmlDocPtr doc)1369 xmlDebugDumpEntities(FILE * output, xmlDocPtr doc)
1370 {
1371     xmlDebugCtxt ctxt;
1372 
1373     if (output == NULL) return;
1374     xmlCtxtDumpInitCtxt(&ctxt);
1375     ctxt.output = output;
1376     xmlCtxtDumpEntities(&ctxt, doc);
1377     xmlCtxtDumpCleanCtxt(&ctxt);
1378 }
1379 
1380 /**
1381  * xmlDebugDumpAttrList:
1382  * @output:  the FILE * for the output
1383  * @attr:  the attribute list
1384  * @depth:  the indentation level.
1385  *
1386  * Dumps debug information for the attribute list
1387  */
1388 void
xmlDebugDumpAttrList(FILE * output,xmlAttrPtr attr,int depth)1389 xmlDebugDumpAttrList(FILE * output, xmlAttrPtr attr, int depth)
1390 {
1391     xmlDebugCtxt ctxt;
1392 
1393     if (output == NULL) return;
1394     xmlCtxtDumpInitCtxt(&ctxt);
1395     ctxt.output = output;
1396     ctxt.depth = depth;
1397     xmlCtxtDumpAttrList(&ctxt, attr);
1398     xmlCtxtDumpCleanCtxt(&ctxt);
1399 }
1400 
1401 /**
1402  * xmlDebugDumpOneNode:
1403  * @output:  the FILE * for the output
1404  * @node:  the node
1405  * @depth:  the indentation level.
1406  *
1407  * Dumps debug information for the element node, it is not recursive
1408  */
1409 void
xmlDebugDumpOneNode(FILE * output,xmlNodePtr node,int depth)1410 xmlDebugDumpOneNode(FILE * output, xmlNodePtr node, int depth)
1411 {
1412     xmlDebugCtxt ctxt;
1413 
1414     if (output == NULL) return;
1415     xmlCtxtDumpInitCtxt(&ctxt);
1416     ctxt.output = output;
1417     ctxt.depth = depth;
1418     xmlCtxtDumpOneNode(&ctxt, node);
1419     xmlCtxtDumpCleanCtxt(&ctxt);
1420 }
1421 
1422 /**
1423  * xmlDebugDumpNode:
1424  * @output:  the FILE * for the output
1425  * @node:  the node
1426  * @depth:  the indentation level.
1427  *
1428  * Dumps debug information for the element node, it is recursive
1429  */
1430 void
xmlDebugDumpNode(FILE * output,xmlNodePtr node,int depth)1431 xmlDebugDumpNode(FILE * output, xmlNodePtr node, int depth)
1432 {
1433     xmlDebugCtxt ctxt;
1434 
1435     if (output == NULL)
1436 	output = stdout;
1437     xmlCtxtDumpInitCtxt(&ctxt);
1438     ctxt.output = output;
1439     ctxt.depth = depth;
1440     xmlCtxtDumpNode(&ctxt, node);
1441     xmlCtxtDumpCleanCtxt(&ctxt);
1442 }
1443 
1444 /**
1445  * xmlDebugDumpNodeList:
1446  * @output:  the FILE * for the output
1447  * @node:  the node list
1448  * @depth:  the indentation level.
1449  *
1450  * Dumps debug information for the list of element node, it is recursive
1451  */
1452 void
xmlDebugDumpNodeList(FILE * output,xmlNodePtr node,int depth)1453 xmlDebugDumpNodeList(FILE * output, xmlNodePtr node, int depth)
1454 {
1455     xmlDebugCtxt ctxt;
1456 
1457     if (output == NULL)
1458 	output = stdout;
1459     xmlCtxtDumpInitCtxt(&ctxt);
1460     ctxt.output = output;
1461     ctxt.depth = depth;
1462     xmlCtxtDumpNodeList(&ctxt, node);
1463     xmlCtxtDumpCleanCtxt(&ctxt);
1464 }
1465 
1466 /**
1467  * xmlDebugDumpDocumentHead:
1468  * @output:  the FILE * for the output
1469  * @doc:  the document
1470  *
1471  * Dumps debug information concerning the document, not recursive
1472  */
1473 void
xmlDebugDumpDocumentHead(FILE * output,xmlDocPtr doc)1474 xmlDebugDumpDocumentHead(FILE * output, xmlDocPtr doc)
1475 {
1476     xmlDebugCtxt ctxt;
1477 
1478     if (output == NULL)
1479 	output = stdout;
1480     xmlCtxtDumpInitCtxt(&ctxt);
1481     ctxt.options |= DUMP_TEXT_TYPE;
1482     ctxt.output = output;
1483     xmlCtxtDumpDocumentHead(&ctxt, doc);
1484     xmlCtxtDumpCleanCtxt(&ctxt);
1485 }
1486 
1487 /**
1488  * xmlDebugDumpDocument:
1489  * @output:  the FILE * for the output
1490  * @doc:  the document
1491  *
1492  * Dumps debug information for the document, it's recursive
1493  */
1494 void
xmlDebugDumpDocument(FILE * output,xmlDocPtr doc)1495 xmlDebugDumpDocument(FILE * output, xmlDocPtr doc)
1496 {
1497     xmlDebugCtxt ctxt;
1498 
1499     if (output == NULL)
1500 	output = stdout;
1501     xmlCtxtDumpInitCtxt(&ctxt);
1502     ctxt.options |= DUMP_TEXT_TYPE;
1503     ctxt.output = output;
1504     xmlCtxtDumpDocument(&ctxt, doc);
1505     xmlCtxtDumpCleanCtxt(&ctxt);
1506 }
1507 
1508 /**
1509  * xmlDebugDumpDTD:
1510  * @output:  the FILE * for the output
1511  * @dtd:  the DTD
1512  *
1513  * Dumps debug information for the DTD
1514  */
1515 void
xmlDebugDumpDTD(FILE * output,xmlDtdPtr dtd)1516 xmlDebugDumpDTD(FILE * output, xmlDtdPtr dtd)
1517 {
1518     xmlDebugCtxt ctxt;
1519 
1520     if (output == NULL)
1521 	output = stdout;
1522     xmlCtxtDumpInitCtxt(&ctxt);
1523     ctxt.options |= DUMP_TEXT_TYPE;
1524     ctxt.output = output;
1525     xmlCtxtDumpDTD(&ctxt, dtd);
1526     xmlCtxtDumpCleanCtxt(&ctxt);
1527 }
1528 
1529 /************************************************************************
1530  *									*
1531  *			Public entry points for checkings		*
1532  *									*
1533  ************************************************************************/
1534 
1535 /**
1536  * xmlDebugCheckDocument:
1537  * @output:  the FILE * for the output
1538  * @doc:  the document
1539  *
1540  * Check the document for potential content problems, and output
1541  * the errors to @output
1542  *
1543  * Returns the number of errors found
1544  */
1545 int
xmlDebugCheckDocument(FILE * output,xmlDocPtr doc)1546 xmlDebugCheckDocument(FILE * output, xmlDocPtr doc)
1547 {
1548     xmlDebugCtxt ctxt;
1549 
1550     if (output == NULL)
1551 	output = stdout;
1552     xmlCtxtDumpInitCtxt(&ctxt);
1553     ctxt.output = output;
1554     ctxt.check = 1;
1555     xmlCtxtDumpDocument(&ctxt, doc);
1556     xmlCtxtDumpCleanCtxt(&ctxt);
1557     return(ctxt.errors);
1558 }
1559 
1560 #endif /* LIBXML_DEBUG_ENABLED */
1561