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