ReactOS  0.4.15-dev-344-g6808e40
valid.c
Go to the documentation of this file.
1 /*
2  * valid.c : part of the code use to do the DTD handling and the validity
3  * checking
4  *
5  * See Copyright for the status of this software.
6  *
7  * daniel@veillard.com
8  */
9 
10 #define IN_LIBXML
11 #include "libxml.h"
12 
13 #include <string.h>
14 
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 
19 #include <libxml/xmlmemory.h>
20 #include <libxml/hash.h>
21 #include <libxml/uri.h>
22 #include <libxml/valid.h>
23 #include <libxml/parser.h>
24 #include <libxml/parserInternals.h>
25 #include <libxml/xmlerror.h>
26 #include <libxml/list.h>
27 #include <libxml/globals.h>
28 
30  int create);
31 /* #define DEBUG_VALID_ALGO */
32 /* #define DEBUG_REGEXP_ALGO */
33 
34 #define TODO \
35  xmlGenericError(xmlGenericErrorContext, \
36  "Unimplemented block at %s:%d\n", \
37  __FILE__, __LINE__);
38 
39 #ifdef LIBXML_VALID_ENABLED
40 static int
41 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
42  const xmlChar *value);
43 #endif
44 /************************************************************************
45  * *
46  * Error handling routines *
47  * *
48  ************************************************************************/
49 
57 static void
59 {
60  xmlGenericErrorFunc channel = NULL;
61  xmlParserCtxtPtr pctxt = NULL;
62  void *data = NULL;
63 
64  if (ctxt != NULL) {
65  channel = ctxt->error;
66  data = ctxt->userData;
67  /* Use the special values to detect if it is part of a parsing
68  context */
69  if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
70  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
71  long delta = (char *) ctxt - (char *) ctxt->userData;
72  if ((delta > 0) && (delta < 250))
73  pctxt = ctxt->userData;
74  }
75  }
76  if (extra)
77  __xmlRaiseError(NULL, channel, data,
79  XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
80  "Memory allocation failed : %s\n", extra);
81  else
82  __xmlRaiseError(NULL, channel, data,
84  XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
85  "Memory allocation failed\n");
86 }
87 
96 static void LIBXML_ATTR_FORMAT(3,0)
97 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
98  const char *msg, const char *extra)
99 {
100  xmlGenericErrorFunc channel = NULL;
101  xmlParserCtxtPtr pctxt = NULL;
102  void *data = NULL;
103 
104  if (ctxt != NULL) {
105  channel = ctxt->error;
106  data = ctxt->userData;
107  /* Use the special values to detect if it is part of a parsing
108  context */
109  if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
110  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
111  long delta = (char *) ctxt - (char *) ctxt->userData;
112  if ((delta > 0) && (delta < 250))
113  pctxt = ctxt->userData;
114  }
115  }
116  if (extra)
117  __xmlRaiseError(NULL, channel, data,
118  pctxt, NULL, XML_FROM_VALID, error,
119  XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
120  msg, extra);
121  else
122  __xmlRaiseError(NULL, channel, data,
123  pctxt, NULL, XML_FROM_VALID, error,
124  XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
125  "%s", msg);
126 }
127 
128 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
129 
140 static void LIBXML_ATTR_FORMAT(4,0)
141 xmlErrValidNode(xmlValidCtxtPtr ctxt,
143  const char *msg, const xmlChar * str1,
144  const xmlChar * str2, const xmlChar * str3)
145 {
146  xmlStructuredErrorFunc schannel = NULL;
147  xmlGenericErrorFunc channel = NULL;
148  xmlParserCtxtPtr pctxt = NULL;
149  void *data = NULL;
150 
151  if (ctxt != NULL) {
152  channel = ctxt->error;
153  data = ctxt->userData;
154  /* Use the special values to detect if it is part of a parsing
155  context */
156  if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
157  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
158  long delta = (char *) ctxt - (char *) ctxt->userData;
159  if ((delta > 0) && (delta < 250))
160  pctxt = ctxt->userData;
161  }
162  }
163  __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
164  XML_ERR_ERROR, NULL, 0,
165  (const char *) str1,
166  (const char *) str2,
167  (const char *) str3, 0, 0, msg, str1, str2, str3);
168 }
169 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
170 
171 #ifdef LIBXML_VALID_ENABLED
172 
183 static void LIBXML_ATTR_FORMAT(4,0)
184 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
186  const char *msg, const xmlChar * str1,
187  int int2, const xmlChar * str3)
188 {
189  xmlStructuredErrorFunc schannel = NULL;
190  xmlGenericErrorFunc channel = NULL;
191  xmlParserCtxtPtr pctxt = NULL;
192  void *data = NULL;
193 
194  if (ctxt != NULL) {
195  channel = ctxt->error;
196  data = ctxt->userData;
197  /* Use the special values to detect if it is part of a parsing
198  context */
199  if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
200  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
201  long delta = (char *) ctxt - (char *) ctxt->userData;
202  if ((delta > 0) && (delta < 250))
203  pctxt = ctxt->userData;
204  }
205  }
206  __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
207  XML_ERR_ERROR, NULL, 0,
208  (const char *) str1,
209  (const char *) str3,
210  NULL, int2, 0, msg, str1, int2, str3);
211 }
212 
224 static void LIBXML_ATTR_FORMAT(4,0)
225 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
227  const char *msg, const xmlChar * str1,
228  const xmlChar * str2, const xmlChar * str3)
229 {
230  xmlStructuredErrorFunc schannel = NULL;
231  xmlGenericErrorFunc channel = NULL;
232  xmlParserCtxtPtr pctxt = NULL;
233  void *data = NULL;
234 
235  if (ctxt != NULL) {
236  channel = ctxt->warning;
237  data = ctxt->userData;
238  /* Use the special values to detect if it is part of a parsing
239  context */
240  if ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
241  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1)) {
242  long delta = (char *) ctxt - (char *) ctxt->userData;
243  if ((delta > 0) && (delta < 250))
244  pctxt = ctxt->userData;
245  }
246  }
247  __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
248  XML_ERR_WARNING, NULL, 0,
249  (const char *) str1,
250  (const char *) str2,
251  (const char *) str3, 0, 0, msg, str1, str2, str3);
252 }
253 
254 
255 
256 #ifdef LIBXML_REGEXP_ENABLED
257 /*
258  * If regexp are enabled we can do continuous validation without the
259  * need of a tree to validate the content model. this is done in each
260  * callbacks.
261  * Each xmlValidState represent the validation state associated to the
262  * set of nodes currently open from the document root to the current element.
263  */
264 
265 
266 typedef struct _xmlValidState {
267  xmlElementPtr elemDecl; /* pointer to the content model */
268  xmlNodePtr node; /* pointer to the current node */
269  xmlRegExecCtxtPtr exec; /* regexp runtime */
270 } _xmlValidState;
271 
272 
273 static int
274 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
275  if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
276  ctxt->vstateMax = 10;
277  ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
278  sizeof(ctxt->vstateTab[0]));
279  if (ctxt->vstateTab == NULL) {
280  xmlVErrMemory(ctxt, "malloc failed");
281  return(-1);
282  }
283  }
284 
285  if (ctxt->vstateNr >= ctxt->vstateMax) {
286  xmlValidState *tmp;
287 
288  tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
289  2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
290  if (tmp == NULL) {
291  xmlVErrMemory(ctxt, "realloc failed");
292  return(-1);
293  }
294  ctxt->vstateMax *= 2;
295  ctxt->vstateTab = tmp;
296  }
297  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
298  ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
299  ctxt->vstateTab[ctxt->vstateNr].node = node;
300  if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
301  if (elemDecl->contModel == NULL)
302  xmlValidBuildContentModel(ctxt, elemDecl);
303  if (elemDecl->contModel != NULL) {
304  ctxt->vstateTab[ctxt->vstateNr].exec =
305  xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
306  } else {
307  ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
308  xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
310  "Failed to build content model regexp for %s\n",
311  node->name, NULL, NULL);
312  }
313  }
314  return(ctxt->vstateNr++);
315 }
316 
317 static int
318 vstateVPop(xmlValidCtxtPtr ctxt) {
319  xmlElementPtr elemDecl;
320 
321  if (ctxt->vstateNr < 1) return(-1);
322  ctxt->vstateNr--;
323  elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
324  ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
325  ctxt->vstateTab[ctxt->vstateNr].node = NULL;
326  if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
327  xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
328  }
329  ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
330  if (ctxt->vstateNr >= 1)
331  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
332  else
333  ctxt->vstate = NULL;
334  return(ctxt->vstateNr);
335 }
336 
337 #else /* not LIBXML_REGEXP_ENABLED */
338 /*
339  * If regexp are not enabled, it uses a home made algorithm less
340  * complex and easier to
341  * debug/maintain than a generic NFA -> DFA state based algo. The
342  * only restriction is on the deepness of the tree limited by the
343  * size of the occurs bitfield
344  *
345  * this is the content of a saved state for rollbacks
346  */
347 
348 #define ROLLBACK_OR 0
349 #define ROLLBACK_PARENT 1
350 
351 typedef struct _xmlValidState {
352  xmlElementContentPtr cont; /* pointer to the content model subtree */
353  xmlNodePtr node; /* pointer to the current node in the list */
354  long occurs;/* bitfield for multiple occurrences */
355  unsigned char depth; /* current depth in the overall tree */
356  unsigned char state; /* ROLLBACK_XXX */
357 } _xmlValidState;
358 
359 #define MAX_RECURSE 25000
360 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
361 #define CONT ctxt->vstate->cont
362 #define NODE ctxt->vstate->node
363 #define DEPTH ctxt->vstate->depth
364 #define OCCURS ctxt->vstate->occurs
365 #define STATE ctxt->vstate->state
366 
367 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
368 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
369 
370 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
371 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
372 
373 static int
374 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
375  xmlNodePtr node, unsigned char depth, long occurs,
376  unsigned char state) {
377  int i = ctxt->vstateNr - 1;
378 
379  if (ctxt->vstateNr > MAX_RECURSE) {
380  return(-1);
381  }
382  if (ctxt->vstateTab == NULL) {
383  ctxt->vstateMax = 8;
384  ctxt->vstateTab = (xmlValidState *) xmlMalloc(
385  ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
386  if (ctxt->vstateTab == NULL) {
387  xmlVErrMemory(ctxt, "malloc failed");
388  return(-1);
389  }
390  }
391  if (ctxt->vstateNr >= ctxt->vstateMax) {
392  xmlValidState *tmp;
393 
394  tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
395  2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
396  if (tmp == NULL) {
397  xmlVErrMemory(ctxt, "malloc failed");
398  return(-1);
399  }
400  ctxt->vstateMax *= 2;
401  ctxt->vstateTab = tmp;
402  ctxt->vstate = &ctxt->vstateTab[0];
403  }
404  /*
405  * Don't push on the stack a state already here
406  */
407  if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
408  (ctxt->vstateTab[i].node == node) &&
409  (ctxt->vstateTab[i].depth == depth) &&
410  (ctxt->vstateTab[i].occurs == occurs) &&
411  (ctxt->vstateTab[i].state == state))
412  return(ctxt->vstateNr);
413  ctxt->vstateTab[ctxt->vstateNr].cont = cont;
414  ctxt->vstateTab[ctxt->vstateNr].node = node;
415  ctxt->vstateTab[ctxt->vstateNr].depth = depth;
416  ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
417  ctxt->vstateTab[ctxt->vstateNr].state = state;
418  return(ctxt->vstateNr++);
419 }
420 
421 static int
422 vstateVPop(xmlValidCtxtPtr ctxt) {
423  if (ctxt->vstateNr <= 1) return(-1);
424  ctxt->vstateNr--;
425  ctxt->vstate = &ctxt->vstateTab[0];
426  ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
427  ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
428  ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
429  ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
430  ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
431  return(ctxt->vstateNr);
432 }
433 
434 #endif /* LIBXML_REGEXP_ENABLED */
435 
436 static int
437 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
438 {
439  if (ctxt->nodeMax <= 0) {
440  ctxt->nodeMax = 4;
441  ctxt->nodeTab =
442  (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
443  sizeof(ctxt->nodeTab[0]));
444  if (ctxt->nodeTab == NULL) {
445  xmlVErrMemory(ctxt, "malloc failed");
446  ctxt->nodeMax = 0;
447  return (0);
448  }
449  }
450  if (ctxt->nodeNr >= ctxt->nodeMax) {
451  xmlNodePtr *tmp;
452  tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
453  ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
454  if (tmp == NULL) {
455  xmlVErrMemory(ctxt, "realloc failed");
456  return (0);
457  }
458  ctxt->nodeMax *= 2;
459  ctxt->nodeTab = tmp;
460  }
461  ctxt->nodeTab[ctxt->nodeNr] = value;
462  ctxt->node = value;
463  return (ctxt->nodeNr++);
464 }
465 static xmlNodePtr
466 nodeVPop(xmlValidCtxtPtr ctxt)
467 {
468  xmlNodePtr ret;
469 
470  if (ctxt->nodeNr <= 0)
471  return (NULL);
472  ctxt->nodeNr--;
473  if (ctxt->nodeNr > 0)
474  ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
475  else
476  ctxt->node = NULL;
477  ret = ctxt->nodeTab[ctxt->nodeNr];
478  ctxt->nodeTab[ctxt->nodeNr] = NULL;
479  return (ret);
480 }
481 
482 #ifdef DEBUG_VALID_ALGO
483 static void
484 xmlValidPrintNode(xmlNodePtr cur) {
485  if (cur == NULL) {
487  return;
488  }
489  switch (cur->type) {
490  case XML_ELEMENT_NODE:
492  break;
493  case XML_TEXT_NODE:
495  break;
498  break;
499  case XML_ENTITY_REF_NODE:
501  break;
502  case XML_PI_NODE:
503  xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
504  break;
505  case XML_COMMENT_NODE:
507  break;
508  case XML_ATTRIBUTE_NODE:
510  break;
511  case XML_ENTITY_NODE:
513  break;
514  case XML_DOCUMENT_NODE:
516  break;
519  break;
522  break;
523  case XML_NOTATION_NODE:
525  break;
528  break;
529 #ifdef LIBXML_DOCB_ENABLED
530  case XML_DOCB_DOCUMENT_NODE:
532  break;
533 #endif
534  case XML_DTD_NODE:
536  break;
537  case XML_ELEMENT_DECL:
539  break;
540  case XML_ATTRIBUTE_DECL:
542  break;
543  case XML_ENTITY_DECL:
545  break;
546  case XML_NAMESPACE_DECL:
548  break;
549  case XML_XINCLUDE_START:
551  break;
552  case XML_XINCLUDE_END:
554  break;
555  }
556 }
557 
558 static void
559 xmlValidPrintNodeList(xmlNodePtr cur) {
560  if (cur == NULL)
562  while (cur != NULL) {
563  xmlValidPrintNode(cur);
564  cur = cur->next;
565  }
566 }
567 
568 static void
569 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
570  char expr[5000];
571 
572  expr[0] = 0;
574  xmlValidPrintNodeList(cur);
576  xmlSnprintfElementContent(expr, 5000, cont, 1);
578 }
579 
580 static void
581 xmlValidDebugState(xmlValidStatePtr state) {
583  if (state->cont == NULL)
585  else
586  switch (state->cont->type) {
589  break;
592  state->cont->name);
593  break;
596  break;
599  break;
600  }
601  xmlValidPrintNode(state->node);
603  state->depth, state->occurs, state->state);
604 }
605 
606 static void
607 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
608  int i, j;
609 
611  xmlValidDebugState(ctxt->vstate);
613  ctxt->vstateNr - 1);
614  for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
615  xmlValidDebugState(&ctxt->vstateTab[j]);
617 }
618 
619 /*****
620 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
621  *****/
622 
623 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
624 #define DEBUG_VALID_MSG(m) \
625  xmlGenericError(xmlGenericErrorContext, "%s\n", m);
626 
627 #else
628 #define DEBUG_VALID_STATE(n,c)
629 #define DEBUG_VALID_MSG(m)
630 #endif
631 
632 /* TODO: use hash table for accesses to elem and attribute definitions */
633 
634 
635 #define CHECK_DTD \
636  if (doc == NULL) return(0); \
637  else if ((doc->intSubset == NULL) && \
638  (doc->extSubset == NULL)) return(0)
639 
640 #ifdef LIBXML_REGEXP_ENABLED
641 
642 /************************************************************************
643  * *
644  * Content model validation based on the regexps *
645  * *
646  ************************************************************************/
647 
658 static int
659 xmlValidBuildAContentModel(xmlElementContentPtr content,
660  xmlValidCtxtPtr ctxt,
661  const xmlChar *name) {
662  if (content == NULL) {
663  xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
664  "Found NULL content in content model of %s\n",
665  name, NULL, NULL);
666  return(0);
667  }
668  switch (content->type) {
670  xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
671  "Found PCDATA in content model of %s\n",
672  name, NULL, NULL);
673  return(0);
674  break;
676  xmlAutomataStatePtr oldstate = ctxt->state;
677  xmlChar fn[50];
678  xmlChar *fullname;
679 
680  fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
681  if (fullname == NULL) {
682  xmlVErrMemory(ctxt, "Building content model");
683  return(0);
684  }
685 
686  switch (content->ocur) {
688  ctxt->state = xmlAutomataNewTransition(ctxt->am,
689  ctxt->state, NULL, fullname, NULL);
690  break;
692  ctxt->state = xmlAutomataNewTransition(ctxt->am,
693  ctxt->state, NULL, fullname, NULL);
694  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
695  break;
697  ctxt->state = xmlAutomataNewTransition(ctxt->am,
698  ctxt->state, NULL, fullname, NULL);
699  xmlAutomataNewTransition(ctxt->am, ctxt->state,
700  ctxt->state, fullname, NULL);
701  break;
703  ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
704  ctxt->state, NULL);
705  xmlAutomataNewTransition(ctxt->am,
706  ctxt->state, ctxt->state, fullname, NULL);
707  break;
708  }
709  if ((fullname != fn) && (fullname != content->name))
710  xmlFree(fullname);
711  break;
712  }
714  xmlAutomataStatePtr oldstate, oldend;
716 
717  /*
718  * Simply iterate over the content
719  */
720  oldstate = ctxt->state;
721  ocur = content->ocur;
722  if (ocur != XML_ELEMENT_CONTENT_ONCE) {
723  ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
724  oldstate = ctxt->state;
725  }
726  do {
727  xmlValidBuildAContentModel(content->c1, ctxt, name);
728  content = content->c2;
729  } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
730  (content->ocur == XML_ELEMENT_CONTENT_ONCE));
731  xmlValidBuildAContentModel(content, ctxt, name);
732  oldend = ctxt->state;
733  ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
734  switch (ocur) {
736  break;
738  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
739  break;
741  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
742  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
743  break;
745  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
746  break;
747  }
748  break;
749  }
750  case XML_ELEMENT_CONTENT_OR: {
751  xmlAutomataStatePtr oldstate, oldend;
753 
754  ocur = content->ocur;
755  if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
756  (ocur == XML_ELEMENT_CONTENT_MULT)) {
757  ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
758  ctxt->state, NULL);
759  }
760  oldstate = ctxt->state;
761  oldend = xmlAutomataNewState(ctxt->am);
762 
763  /*
764  * iterate over the subtypes and remerge the end with an
765  * epsilon transition
766  */
767  do {
768  ctxt->state = oldstate;
769  xmlValidBuildAContentModel(content->c1, ctxt, name);
770  xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
771  content = content->c2;
772  } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
773  (content->ocur == XML_ELEMENT_CONTENT_ONCE));
774  ctxt->state = oldstate;
775  xmlValidBuildAContentModel(content, ctxt, name);
776  xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
777  ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
778  switch (ocur) {
780  break;
782  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
783  break;
785  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
786  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
787  break;
789  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
790  break;
791  }
792  break;
793  }
794  default:
795  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
796  "ContentModel broken for element %s\n",
797  (const char *) name);
798  return(0);
799  }
800  return(1);
801 }
812 int
813 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
814 
815  if ((ctxt == NULL) || (elem == NULL))
816  return(0);
817  if (elem->type != XML_ELEMENT_DECL)
818  return(0);
819  if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
820  return(1);
821  /* TODO: should we rebuild in this case ? */
822  if (elem->contModel != NULL) {
823  if (!xmlRegexpIsDeterminist(elem->contModel)) {
824  ctxt->valid = 0;
825  return(0);
826  }
827  return(1);
828  }
829 
830  ctxt->am = xmlNewAutomata();
831  if (ctxt->am == NULL) {
832  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
834  "Cannot create automata for element %s\n",
835  elem->name, NULL, NULL);
836  return(0);
837  }
838  ctxt->state = xmlAutomataGetInitState(ctxt->am);
839  xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
840  xmlAutomataSetFinalState(ctxt->am, ctxt->state);
841  elem->contModel = xmlAutomataCompile(ctxt->am);
842  if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
843  char expr[5000];
844  expr[0] = 0;
845  xmlSnprintfElementContent(expr, 5000, elem->content, 1);
846  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
848  "Content model of %s is not determinist: %s\n",
849  elem->name, BAD_CAST expr, NULL);
850 #ifdef DEBUG_REGEXP_ALGO
851  xmlRegexpPrint(stderr, elem->contModel);
852 #endif
853  ctxt->valid = 0;
854  ctxt->state = NULL;
855  xmlFreeAutomata(ctxt->am);
856  ctxt->am = NULL;
857  return(0);
858  }
859  ctxt->state = NULL;
860  xmlFreeAutomata(ctxt->am);
861  ctxt->am = NULL;
862  return(1);
863 }
864 
865 #endif /* LIBXML_REGEXP_ENABLED */
866 
867 /****************************************************************
868  * *
869  * Util functions for data allocation/deallocation *
870  * *
871  ****************************************************************/
872 
880 xmlValidCtxtPtr xmlNewValidCtxt(void) {
882 
883  if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
884  xmlVErrMemory(NULL, "malloc failed");
885  return (NULL);
886  }
887 
888  (void) memset(ret, 0, sizeof (xmlValidCtxt));
889 
890  return (ret);
891 }
892 
899 void
900 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
901  if (cur->vstateTab != NULL)
902  xmlFree(cur->vstateTab);
903  if (cur->nodeTab != NULL)
904  xmlFree(cur->nodeTab);
905  xmlFree(cur);
906 }
907 
908 #endif /* LIBXML_VALID_ENABLED */
909 
924  xmlDictPtr dict = NULL;
925 
926  if (doc != NULL)
927  dict = doc->dict;
928 
929  switch(type) {
931  if (name == NULL) {
932  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
933  "xmlNewElementContent : name == NULL !\n",
934  NULL);
935  }
936  break;
940  if (name != NULL) {
941  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
942  "xmlNewElementContent : name != NULL !\n",
943  NULL);
944  }
945  break;
946  default:
947  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
948  "Internal: ELEMENT content corrupted invalid type\n",
949  NULL);
950  return(NULL);
951  }
953  if (ret == NULL) {
954  xmlVErrMemory(NULL, "malloc failed");
955  return(NULL);
956  }
957  memset(ret, 0, sizeof(xmlElementContent));
958  ret->type = type;
960  if (name != NULL) {
961  int l;
962  const xmlChar *tmp;
963 
964  tmp = xmlSplitQName3(name, &l);
965  if (tmp == NULL) {
966  if (dict == NULL)
967  ret->name = xmlStrdup(name);
968  else
969  ret->name = xmlDictLookup(dict, name, -1);
970  } else {
971  if (dict == NULL) {
972  ret->prefix = xmlStrndup(name, l);
973  ret->name = xmlStrdup(tmp);
974  } else {
975  ret->prefix = xmlDictLookup(dict, name, l);
976  ret->name = xmlDictLookup(dict, tmp, -1);
977  }
978  }
979  }
980  return(ret);
981 }
982 
996 }
997 
1009  xmlElementContentPtr ret = NULL, prev = NULL, tmp;
1010  xmlDictPtr dict = NULL;
1011 
1012  if (cur == NULL) return(NULL);
1013 
1014  if (doc != NULL)
1015  dict = doc->dict;
1016 
1018  if (ret == NULL) {
1019  xmlVErrMemory(NULL, "malloc failed");
1020  return(NULL);
1021  }
1022  memset(ret, 0, sizeof(xmlElementContent));
1023  ret->type = cur->type;
1024  ret->ocur = cur->ocur;
1025  if (cur->name != NULL) {
1026  if (dict)
1027  ret->name = xmlDictLookup(dict, cur->name, -1);
1028  else
1029  ret->name = xmlStrdup(cur->name);
1030  }
1031 
1032  if (cur->prefix != NULL) {
1033  if (dict)
1034  ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1035  else
1036  ret->prefix = xmlStrdup(cur->prefix);
1037  }
1038  if (cur->c1 != NULL)
1039  ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1040  if (ret->c1 != NULL)
1041  ret->c1->parent = ret;
1042  if (cur->c2 != NULL) {
1043  prev = ret;
1044  cur = cur->c2;
1045  while (cur != NULL) {
1047  if (tmp == NULL) {
1048  xmlVErrMemory(NULL, "malloc failed");
1049  return(ret);
1050  }
1051  memset(tmp, 0, sizeof(xmlElementContent));
1052  tmp->type = cur->type;
1053  tmp->ocur = cur->ocur;
1054  prev->c2 = tmp;
1055  if (cur->name != NULL) {
1056  if (dict)
1057  tmp->name = xmlDictLookup(dict, cur->name, -1);
1058  else
1059  tmp->name = xmlStrdup(cur->name);
1060  }
1061 
1062  if (cur->prefix != NULL) {
1063  if (dict)
1064  tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1065  else
1066  tmp->prefix = xmlStrdup(cur->prefix);
1067  }
1068  if (cur->c1 != NULL)
1069  tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1070  if (tmp->c1 != NULL)
1071  tmp->c1->parent = ret;
1072  prev = tmp;
1073  cur = cur->c2;
1074  }
1075  }
1076  return(ret);
1077 }
1078 
1090  return(xmlCopyDocElementContent(NULL, cur));
1091 }
1092 
1100 void
1102  xmlDictPtr dict = NULL;
1103  size_t depth = 0;
1104 
1105  if (cur == NULL)
1106  return;
1107  if (doc != NULL)
1108  dict = doc->dict;
1109 
1110  while (1) {
1112 
1113  while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1114  cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1115  depth += 1;
1116  }
1117 
1118  switch (cur->type) {
1123  break;
1124  default:
1125  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1126  "Internal: ELEMENT content corrupted invalid type\n",
1127  NULL);
1128  return;
1129  }
1130  if (dict) {
1131  if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1132  xmlFree((xmlChar *) cur->name);
1133  if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1134  xmlFree((xmlChar *) cur->prefix);
1135  } else {
1136  if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1137  if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1138  }
1139  parent = cur->parent;
1140  if ((depth == 0) || (parent == NULL)) {
1141  xmlFree(cur);
1142  break;
1143  }
1144  if (cur == parent->c1)
1145  parent->c1 = NULL;
1146  else
1147  parent->c2 = NULL;
1148  xmlFree(cur);
1149 
1150  if (parent->c2 != NULL) {
1151  cur = parent->c2;
1152  } else {
1153  depth -= 1;
1154  cur = parent;
1155  }
1156  }
1157 }
1158 
1166 void
1169 }
1170 
1171 #ifdef LIBXML_OUTPUT_ENABLED
1172 
1179 static void
1180 xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1181  switch (cur->ocur) {
1183  break;
1185  xmlBufferWriteChar(buf, "?");
1186  break;
1188  xmlBufferWriteChar(buf, "*");
1189  break;
1191  xmlBufferWriteChar(buf, "+");
1192  break;
1193  }
1194 }
1195 
1203 static void
1204 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1206 
1207  if (content == NULL) return;
1208 
1209  xmlBufferWriteChar(buf, "(");
1210  cur = content;
1211 
1212  do {
1213  if (cur == NULL) return;
1214 
1215  switch (cur->type) {
1217  xmlBufferWriteChar(buf, "#PCDATA");
1218  break;
1220  if (cur->prefix != NULL) {
1221  xmlBufferWriteCHAR(buf, cur->prefix);
1222  xmlBufferWriteChar(buf, ":");
1223  }
1224  xmlBufferWriteCHAR(buf, cur->name);
1225  break;
1228  if ((cur != content) &&
1229  (cur->parent != NULL) &&
1230  ((cur->type != cur->parent->type) ||
1231  (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1232  xmlBufferWriteChar(buf, "(");
1233  cur = cur->c1;
1234  continue;
1235  default:
1236  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1237  "Internal: ELEMENT cur corrupted invalid type\n",
1238  NULL);
1239  }
1240 
1241  while (cur != content) {
1243 
1244  if (parent == NULL) return;
1245 
1246  if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1247  (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1248  ((cur->type != parent->type) ||
1249  (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1250  xmlBufferWriteChar(buf, ")");
1251  xmlDumpElementOccur(buf, cur);
1252 
1253  if (cur == parent->c1) {
1254  if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1255  xmlBufferWriteChar(buf, " , ");
1256  else if (parent->type == XML_ELEMENT_CONTENT_OR)
1257  xmlBufferWriteChar(buf, " | ");
1258 
1259  cur = parent->c2;
1260  break;
1261  }
1262 
1263  cur = parent;
1264  }
1265  } while (cur != content);
1266 
1267  xmlBufferWriteChar(buf, ")");
1268  xmlDumpElementOccur(buf, content);
1269 }
1270 
1279 void
1280 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1282  int englob ATTRIBUTE_UNUSED) {
1283 }
1284 #endif /* LIBXML_OUTPUT_ENABLED */
1285 
1296 void
1298  int len;
1299 
1300  if (content == NULL) return;
1301  len = strlen(buf);
1302  if (size - len < 50) {
1303  if ((size - len > 4) && (buf[len - 1] != '.'))
1304  strcat(buf, " ...");
1305  return;
1306  }
1307  if (englob) strcat(buf, "(");
1308  switch (content->type) {
1310  strcat(buf, "#PCDATA");
1311  break;
1313  int qnameLen = xmlStrlen(content->name);
1314 
1315  if (content->prefix != NULL)
1316  qnameLen += xmlStrlen(content->prefix) + 1;
1317  if (size - len < qnameLen + 10) {
1318  strcat(buf, " ...");
1319  return;
1320  }
1321  if (content->prefix != NULL) {
1322  strcat(buf, (char *) content->prefix);
1323  strcat(buf, ":");
1324  }
1325  if (content->name != NULL)
1326  strcat(buf, (char *) content->name);
1327  break;
1328  }
1330  if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1331  (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1333  else
1335  len = strlen(buf);
1336  if (size - len < 50) {
1337  if ((size - len > 4) && (buf[len - 1] != '.'))
1338  strcat(buf, " ...");
1339  return;
1340  }
1341  strcat(buf, " , ");
1342  if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1343  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1344  (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1346  else
1348  break;
1350  if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1351  (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1353  else
1355  len = strlen(buf);
1356  if (size - len < 50) {
1357  if ((size - len > 4) && (buf[len - 1] != '.'))
1358  strcat(buf, " ...");
1359  return;
1360  }
1361  strcat(buf, " | ");
1362  if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1363  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1364  (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1366  else
1368  break;
1369  }
1370  if (size - strlen(buf) <= 2) return;
1371  if (englob)
1372  strcat(buf, ")");
1373  switch (content->ocur) {
1375  break;
1377  strcat(buf, "?");
1378  break;
1380  strcat(buf, "*");
1381  break;
1383  strcat(buf, "+");
1384  break;
1385  }
1386 }
1387 
1388 /****************************************************************
1389  * *
1390  * Registration of DTD declarations *
1391  * *
1392  ****************************************************************/
1393 
1400 static void
1402  if (elem == NULL) return;
1404  xmlFreeDocElementContent(elem->doc, elem->content);
1405  if (elem->name != NULL)
1406  xmlFree((xmlChar *) elem->name);
1407  if (elem->prefix != NULL)
1408  xmlFree((xmlChar *) elem->prefix);
1409 #ifdef LIBXML_REGEXP_ENABLED
1410  if (elem->contModel != NULL)
1411  xmlRegFreeRegexp(elem->contModel);
1412 #endif
1413  xmlFree(elem);
1414 }
1415 
1416 
1431  xmlDtdPtr dtd, const xmlChar *name,
1436  xmlAttributePtr oldAttributes = NULL;
1437  xmlChar *ns, *uqname;
1438 
1439  if (dtd == NULL) {
1440  return(NULL);
1441  }
1442  if (name == NULL) {
1443  return(NULL);
1444  }
1445 
1446  switch (type) {
1448  if (content != NULL) {
1449  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1450  "xmlAddElementDecl: content != NULL for EMPTY\n",
1451  NULL);
1452  return(NULL);
1453  }
1454  break;
1455  case XML_ELEMENT_TYPE_ANY:
1456  if (content != NULL) {
1457  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1458  "xmlAddElementDecl: content != NULL for ANY\n",
1459  NULL);
1460  return(NULL);
1461  }
1462  break;
1464  if (content == NULL) {
1465  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1466  "xmlAddElementDecl: content == NULL for MIXED\n",
1467  NULL);
1468  return(NULL);
1469  }
1470  break;
1472  if (content == NULL) {
1473  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1474  "xmlAddElementDecl: content == NULL for ELEMENT\n",
1475  NULL);
1476  return(NULL);
1477  }
1478  break;
1479  default:
1480  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1481  "Internal: ELEMENT decl corrupted invalid type\n",
1482  NULL);
1483  return(NULL);
1484  }
1485 
1486  /*
1487  * check if name is a QName
1488  */
1489  uqname = xmlSplitQName2(name, &ns);
1490  if (uqname != NULL)
1491  name = uqname;
1492 
1493  /*
1494  * Create the Element table if needed.
1495  */
1497  if (table == NULL) {
1498  xmlDictPtr dict = NULL;
1499 
1500  if (dtd->doc != NULL)
1501  dict = dtd->doc->dict;
1502  table = xmlHashCreateDict(0, dict);
1503  dtd->elements = (void *) table;
1504  }
1505  if (table == NULL) {
1506  xmlVErrMemory(ctxt,
1507  "xmlAddElementDecl: Table creation failed!\n");
1508  if (uqname != NULL)
1509  xmlFree(uqname);
1510  if (ns != NULL)
1511  xmlFree(ns);
1512  return(NULL);
1513  }
1514 
1515  /*
1516  * lookup old attributes inserted on an undefined element in the
1517  * internal subset.
1518  */
1519  if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1520  ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1521  if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1522  oldAttributes = ret->attributes;
1523  ret->attributes = NULL;
1524  xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1526  }
1527  }
1528 
1529  /*
1530  * The element may already be present if one of its attribute
1531  * was registered first
1532  */
1534  if (ret != NULL) {
1535  if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1536 #ifdef LIBXML_VALID_ENABLED
1537  /*
1538  * The element is already defined in this DTD.
1539  */
1540  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1541  "Redefinition of element %s\n",
1542  name, NULL, NULL);
1543 #endif /* LIBXML_VALID_ENABLED */
1544  if (uqname != NULL)
1545  xmlFree(uqname);
1546  if (ns != NULL)
1547  xmlFree(ns);
1548  return(NULL);
1549  }
1550  if (ns != NULL) {
1551  xmlFree(ns);
1552  ns = NULL;
1553  }
1554  } else {
1555  ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1556  if (ret == NULL) {
1557  xmlVErrMemory(ctxt, "malloc failed");
1558  if (uqname != NULL)
1559  xmlFree(uqname);
1560  if (ns != NULL)
1561  xmlFree(ns);
1562  return(NULL);
1563  }
1564  memset(ret, 0, sizeof(xmlElement));
1565  ret->type = XML_ELEMENT_DECL;
1566 
1567  /*
1568  * fill the structure.
1569  */
1570  ret->name = xmlStrdup(name);
1571  if (ret->name == NULL) {
1572  xmlVErrMemory(ctxt, "malloc failed");
1573  if (uqname != NULL)
1574  xmlFree(uqname);
1575  if (ns != NULL)
1576  xmlFree(ns);
1577  xmlFree(ret);
1578  return(NULL);
1579  }
1580  ret->prefix = ns;
1581 
1582  /*
1583  * Validity Check:
1584  * Insertion must not fail
1585  */
1586  if (xmlHashAddEntry2(table, name, ns, ret)) {
1587 #ifdef LIBXML_VALID_ENABLED
1588  /*
1589  * The element is already defined in this DTD.
1590  */
1591  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1592  "Redefinition of element %s\n",
1593  name, NULL, NULL);
1594 #endif /* LIBXML_VALID_ENABLED */
1596  if (uqname != NULL)
1597  xmlFree(uqname);
1598  return(NULL);
1599  }
1600  /*
1601  * For new element, may have attributes from earlier
1602  * definition in internal subset
1603  */
1604  ret->attributes = oldAttributes;
1605  }
1606 
1607  /*
1608  * Finish to fill the structure.
1609  */
1610  ret->etype = type;
1611  /*
1612  * Avoid a stupid copy when called by the parser
1613  * and flag it by setting a special parent value
1614  * so the parser doesn't unallocate it.
1615  */
1616  if ((ctxt != NULL) &&
1617  ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1618  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1619  ret->content = content;
1620  if (content != NULL)
1621  content->parent = (xmlElementContentPtr) 1;
1622  } else {
1623  ret->content = xmlCopyDocElementContent(dtd->doc, content);
1624  }
1625 
1626  /*
1627  * Link it to the DTD
1628  */
1629  ret->parent = dtd;
1630  ret->doc = dtd->doc;
1631  if (dtd->last == NULL) {
1632  dtd->children = dtd->last = (xmlNodePtr) ret;
1633  } else {
1634  dtd->last->next = (xmlNodePtr) ret;
1635  ret->prev = dtd->last;
1636  dtd->last = (xmlNodePtr) ret;
1637  }
1638  if (uqname != NULL)
1639  xmlFree(uqname);
1640  return(ret);
1641 }
1642 
1643 static void
1646 }
1647 
1654 void
1657 }
1658 
1659 #ifdef LIBXML_TREE_ENABLED
1660 
1668 static void *
1669 xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1670  xmlElementPtr elem = (xmlElementPtr) payload;
1671  xmlElementPtr cur;
1672 
1673  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1674  if (cur == NULL) {
1675  xmlVErrMemory(NULL, "malloc failed");
1676  return(NULL);
1677  }
1678  memset(cur, 0, sizeof(xmlElement));
1679  cur->type = XML_ELEMENT_DECL;
1680  cur->etype = elem->etype;
1681  if (elem->name != NULL)
1682  cur->name = xmlStrdup(elem->name);
1683  else
1684  cur->name = NULL;
1685  if (elem->prefix != NULL)
1686  cur->prefix = xmlStrdup(elem->prefix);
1687  else
1688  cur->prefix = NULL;
1689  cur->content = xmlCopyElementContent(elem->content);
1690  /* TODO : rebuild the attribute list on the copy */
1691  cur->attributes = NULL;
1692  return(cur);
1693 }
1694 
1704 xmlCopyElementTable(xmlElementTablePtr table) {
1705  return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1706 }
1707 #endif /* LIBXML_TREE_ENABLED */
1708 
1709 #ifdef LIBXML_OUTPUT_ENABLED
1710 
1718 void
1719 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1720  if ((buf == NULL) || (elem == NULL))
1721  return;
1722  switch (elem->etype) {
1724  xmlBufferWriteChar(buf, "<!ELEMENT ");
1725  if (elem->prefix != NULL) {
1726  xmlBufferWriteCHAR(buf, elem->prefix);
1727  xmlBufferWriteChar(buf, ":");
1728  }
1729  xmlBufferWriteCHAR(buf, elem->name);
1730  xmlBufferWriteChar(buf, " EMPTY>\n");
1731  break;
1732  case XML_ELEMENT_TYPE_ANY:
1733  xmlBufferWriteChar(buf, "<!ELEMENT ");
1734  if (elem->prefix != NULL) {
1735  xmlBufferWriteCHAR(buf, elem->prefix);
1736  xmlBufferWriteChar(buf, ":");
1737  }
1738  xmlBufferWriteCHAR(buf, elem->name);
1739  xmlBufferWriteChar(buf, " ANY>\n");
1740  break;
1742  xmlBufferWriteChar(buf, "<!ELEMENT ");
1743  if (elem->prefix != NULL) {
1744  xmlBufferWriteCHAR(buf, elem->prefix);
1745  xmlBufferWriteChar(buf, ":");
1746  }
1747  xmlBufferWriteCHAR(buf, elem->name);
1748  xmlBufferWriteChar(buf, " ");
1749  xmlDumpElementContent(buf, elem->content);
1750  xmlBufferWriteChar(buf, ">\n");
1751  break;
1753  xmlBufferWriteChar(buf, "<!ELEMENT ");
1754  if (elem->prefix != NULL) {
1755  xmlBufferWriteCHAR(buf, elem->prefix);
1756  xmlBufferWriteChar(buf, ":");
1757  }
1758  xmlBufferWriteCHAR(buf, elem->name);
1759  xmlBufferWriteChar(buf, " ");
1760  xmlDumpElementContent(buf, elem->content);
1761  xmlBufferWriteChar(buf, ">\n");
1762  break;
1763  default:
1764  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1765  "Internal: ELEMENT struct corrupted invalid type\n",
1766  NULL);
1767  }
1768 }
1769 
1778 static void
1779 xmlDumpElementDeclScan(void *elem, void *buf,
1780  const xmlChar *name ATTRIBUTE_UNUSED) {
1781  xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1782 }
1783 
1791 void
1792 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1793  if ((buf == NULL) || (table == NULL))
1794  return;
1795  xmlHashScan(table, xmlDumpElementDeclScan, buf);
1796 }
1797 #endif /* LIBXML_OUTPUT_ENABLED */
1798 
1811 
1813  if (ret == NULL) {
1814  xmlVErrMemory(NULL, "malloc failed");
1815  return(NULL);
1816  }
1817  memset(ret, 0, sizeof(xmlEnumeration));
1818 
1819  if (name != NULL)
1820  ret->name = xmlStrdup(name);
1821  return(ret);
1822 }
1823 
1830 void
1832  if (cur == NULL) return;
1833 
1834  if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1835 
1836  if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1837  xmlFree(cur);
1838 }
1839 
1840 #ifdef LIBXML_TREE_ENABLED
1841 
1851 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1853 
1854  if (cur == NULL) return(NULL);
1855  ret = xmlCreateEnumeration((xmlChar *) cur->name);
1856  if (ret == NULL) return(NULL);
1857 
1858  if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1859  else ret->next = NULL;
1860 
1861  return(ret);
1862 }
1863 #endif /* LIBXML_TREE_ENABLED */
1864 
1865 #ifdef LIBXML_OUTPUT_ENABLED
1866 
1873 static void
1874 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1875  if ((buf == NULL) || (cur == NULL))
1876  return;
1877 
1878  xmlBufferWriteCHAR(buf, cur->name);
1879  if (cur->next == NULL)
1880  xmlBufferWriteChar(buf, ")");
1881  else {
1882  xmlBufferWriteChar(buf, " | ");
1883  xmlDumpEnumeration(buf, cur->next);
1884  }
1885 }
1886 #endif /* LIBXML_OUTPUT_ENABLED */
1887 
1888 #ifdef LIBXML_VALID_ENABLED
1889 
1900 static int
1901 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1902  xmlAttributePtr cur;
1903  int ret = 0;
1904 
1905  if (elem == NULL) return(0);
1906  cur = elem->attributes;
1907  while (cur != NULL) {
1908  if (cur->atype == XML_ATTRIBUTE_ID) {
1909  ret ++;
1910  if ((ret > 1) && (err))
1911  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1912  "Element %s has too many ID attributes defined : %s\n",
1913  elem->name, cur->name, NULL);
1914  }
1915  cur = cur->nexth;
1916  }
1917  return(ret);
1918 }
1919 #endif /* LIBXML_VALID_ENABLED */
1920 
1927 static void
1929  xmlDictPtr dict;
1930 
1931  if (attr == NULL) return;
1932  if (attr->doc != NULL)
1933  dict = attr->doc->dict;
1934  else
1935  dict = NULL;
1937  if (attr->tree != NULL)
1938  xmlFreeEnumeration(attr->tree);
1939  if (dict) {
1940  if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1941  xmlFree((xmlChar *) attr->elem);
1942  if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1943  xmlFree((xmlChar *) attr->name);
1944  if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1945  xmlFree((xmlChar *) attr->prefix);
1946  if ((attr->defaultValue != NULL) &&
1947  (!xmlDictOwns(dict, attr->defaultValue)))
1948  xmlFree((xmlChar *) attr->defaultValue);
1949  } else {
1950  if (attr->elem != NULL)
1951  xmlFree((xmlChar *) attr->elem);
1952  if (attr->name != NULL)
1953  xmlFree((xmlChar *) attr->name);
1954  if (attr->defaultValue != NULL)
1955  xmlFree((xmlChar *) attr->defaultValue);
1956  if (attr->prefix != NULL)
1957  xmlFree((xmlChar *) attr->prefix);
1958  }
1959  xmlFree(attr);
1960 }
1961 
1962 
1982  xmlDtdPtr dtd, const xmlChar *elem,
1983  const xmlChar *name, const xmlChar *ns,
1985  const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1988  xmlElementPtr elemDef;
1989  xmlDictPtr dict = NULL;
1990 
1991  if (dtd == NULL) {
1993  return(NULL);
1994  }
1995  if (name == NULL) {
1997  return(NULL);
1998  }
1999  if (elem == NULL) {
2001  return(NULL);
2002  }
2003  if (dtd->doc != NULL)
2004  dict = dtd->doc->dict;
2005 
2006 #ifdef LIBXML_VALID_ENABLED
2007  /*
2008  * Check the type and possibly the default value.
2009  */
2010  switch (type) {
2011  case XML_ATTRIBUTE_CDATA:
2012  break;
2013  case XML_ATTRIBUTE_ID:
2014  break;
2015  case XML_ATTRIBUTE_IDREF:
2016  break;
2017  case XML_ATTRIBUTE_IDREFS:
2018  break;
2019  case XML_ATTRIBUTE_ENTITY:
2020  break;
2022  break;
2023  case XML_ATTRIBUTE_NMTOKEN:
2024  break;
2026  break;
2028  break;
2030  break;
2031  default:
2032  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2033  "Internal: ATTRIBUTE struct corrupted invalid type\n",
2034  NULL);
2036  return(NULL);
2037  }
2038  if ((defaultValue != NULL) &&
2039  (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2040  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2041  "Attribute %s of %s: invalid default value\n",
2042  elem, name, defaultValue);
2043  defaultValue = NULL;
2044  if (ctxt != NULL)
2045  ctxt->valid = 0;
2046  }
2047 #endif /* LIBXML_VALID_ENABLED */
2048 
2049  /*
2050  * Check first that an attribute defined in the external subset wasn't
2051  * already defined in the internal subset
2052  */
2053  if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2054  (dtd->doc->intSubset != NULL) &&
2055  (dtd->doc->intSubset->attributes != NULL)) {
2056  ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2057  if (ret != NULL) {
2059  return(NULL);
2060  }
2061  }
2062 
2063  /*
2064  * Create the Attribute table if needed.
2065  */
2067  if (table == NULL) {
2068  table = xmlHashCreateDict(0, dict);
2069  dtd->attributes = (void *) table;
2070  }
2071  if (table == NULL) {
2072  xmlVErrMemory(ctxt,
2073  "xmlAddAttributeDecl: Table creation failed!\n");
2075  return(NULL);
2076  }
2077 
2078 
2080  if (ret == NULL) {
2081  xmlVErrMemory(ctxt, "malloc failed");
2083  return(NULL);
2084  }
2085  memset(ret, 0, sizeof(xmlAttribute));
2086  ret->type = XML_ATTRIBUTE_DECL;
2087 
2088  /*
2089  * fill the structure.
2090  */
2091  ret->atype = type;
2092  /*
2093  * doc must be set before possible error causes call
2094  * to xmlFreeAttribute (because it's used to check on
2095  * dict use)
2096  */
2097  ret->doc = dtd->doc;
2098  if (dict) {
2099  ret->name = xmlDictLookup(dict, name, -1);
2100  ret->prefix = xmlDictLookup(dict, ns, -1);
2101  ret->elem = xmlDictLookup(dict, elem, -1);
2102  } else {
2103  ret->name = xmlStrdup(name);
2104  ret->prefix = xmlStrdup(ns);
2105  ret->elem = xmlStrdup(elem);
2106  }
2107  ret->def = def;
2108  ret->tree = tree;
2109  if (defaultValue != NULL) {
2110  if (dict)
2111  ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2112  else
2113  ret->defaultValue = xmlStrdup(defaultValue);
2114  }
2115 
2116  /*
2117  * Validity Check:
2118  * Search the DTD for previous declarations of the ATTLIST
2119  */
2120  if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2121 #ifdef LIBXML_VALID_ENABLED
2122  /*
2123  * The attribute is already defined in this DTD.
2124  */
2125  xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2126  "Attribute %s of element %s: already defined\n",
2127  name, elem, NULL);
2128 #endif /* LIBXML_VALID_ENABLED */
2130  return(NULL);
2131  }
2132 
2133  /*
2134  * Validity Check:
2135  * Multiple ID per element
2136  */
2137  elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2138  if (elemDef != NULL) {
2139 
2140 #ifdef LIBXML_VALID_ENABLED
2141  if ((type == XML_ATTRIBUTE_ID) &&
2142  (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2143  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2144  "Element %s has too may ID attributes defined : %s\n",
2145  elem, name, NULL);
2146  if (ctxt != NULL)
2147  ctxt->valid = 0;
2148  }
2149 #endif /* LIBXML_VALID_ENABLED */
2150 
2151  /*
2152  * Insert namespace default def first they need to be
2153  * processed first.
2154  */
2155  if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2156  ((ret->prefix != NULL &&
2157  (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2158  ret->nexth = elemDef->attributes;
2159  elemDef->attributes = ret;
2160  } else {
2161  xmlAttributePtr tmp = elemDef->attributes;
2162 
2163  while ((tmp != NULL) &&
2164  ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2165  ((ret->prefix != NULL &&
2166  (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2167  if (tmp->nexth == NULL)
2168  break;
2169  tmp = tmp->nexth;
2170  }
2171  if (tmp != NULL) {
2172  ret->nexth = tmp->nexth;
2173  tmp->nexth = ret;
2174  } else {
2175  ret->nexth = elemDef->attributes;
2176  elemDef->attributes = ret;
2177  }
2178  }
2179  }
2180 
2181  /*
2182  * Link it to the DTD
2183  */
2184  ret->parent = dtd;
2185  if (dtd->last == NULL) {
2186  dtd->children = dtd->last = (xmlNodePtr) ret;
2187  } else {
2188  dtd->last->next = (xmlNodePtr) ret;
2189  ret->prev = dtd->last;
2190  dtd->last = (xmlNodePtr) ret;
2191  }
2192  return(ret);
2193 }
2194 
2195 static void
2198 }
2199 
2206 void
2209 }
2210 
2211 #ifdef LIBXML_TREE_ENABLED
2212 
2220 static void *
2221 xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2222  xmlAttributePtr attr = (xmlAttributePtr) payload;
2223  xmlAttributePtr cur;
2224 
2225  cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2226  if (cur == NULL) {
2227  xmlVErrMemory(NULL, "malloc failed");
2228  return(NULL);
2229  }
2230  memset(cur, 0, sizeof(xmlAttribute));
2231  cur->type = XML_ATTRIBUTE_DECL;
2232  cur->atype = attr->atype;
2233  cur->def = attr->def;
2234  cur->tree = xmlCopyEnumeration(attr->tree);
2235  if (attr->elem != NULL)
2236  cur->elem = xmlStrdup(attr->elem);
2237  if (attr->name != NULL)
2238  cur->name = xmlStrdup(attr->name);
2239  if (attr->prefix != NULL)
2240  cur->prefix = xmlStrdup(attr->prefix);
2241  if (attr->defaultValue != NULL)
2242  cur->defaultValue = xmlStrdup(attr->defaultValue);
2243  return(cur);
2244 }
2245 
2255 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2256  return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2257 }
2258 #endif /* LIBXML_TREE_ENABLED */
2259 
2260 #ifdef LIBXML_OUTPUT_ENABLED
2261 
2269 void
2270 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2271  if ((buf == NULL) || (attr == NULL))
2272  return;
2273  xmlBufferWriteChar(buf, "<!ATTLIST ");
2274  xmlBufferWriteCHAR(buf, attr->elem);
2275  xmlBufferWriteChar(buf, " ");
2276  if (attr->prefix != NULL) {
2277  xmlBufferWriteCHAR(buf, attr->prefix);
2278  xmlBufferWriteChar(buf, ":");
2279  }
2281  switch (attr->atype) {
2282  case XML_ATTRIBUTE_CDATA:
2283  xmlBufferWriteChar(buf, " CDATA");
2284  break;
2285  case XML_ATTRIBUTE_ID:
2286  xmlBufferWriteChar(buf, " ID");
2287  break;
2288  case XML_ATTRIBUTE_IDREF:
2289  xmlBufferWriteChar(buf, " IDREF");
2290  break;
2291  case XML_ATTRIBUTE_IDREFS:
2292  xmlBufferWriteChar(buf, " IDREFS");
2293  break;
2294  case XML_ATTRIBUTE_ENTITY:
2295  xmlBufferWriteChar(buf, " ENTITY");
2296  break;
2298  xmlBufferWriteChar(buf, " ENTITIES");
2299  break;
2300  case XML_ATTRIBUTE_NMTOKEN:
2301  xmlBufferWriteChar(buf, " NMTOKEN");
2302  break;
2304  xmlBufferWriteChar(buf, " NMTOKENS");
2305  break;
2307  xmlBufferWriteChar(buf, " (");
2308  xmlDumpEnumeration(buf, attr->tree);
2309  break;
2311  xmlBufferWriteChar(buf, " NOTATION (");
2312  xmlDumpEnumeration(buf, attr->tree);
2313  break;
2314  default:
2315  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2316  "Internal: ATTRIBUTE struct corrupted invalid type\n",
2317  NULL);
2318  }
2319  switch (attr->def) {
2320  case XML_ATTRIBUTE_NONE:
2321  break;
2323  xmlBufferWriteChar(buf, " #REQUIRED");
2324  break;
2325  case XML_ATTRIBUTE_IMPLIED:
2326  xmlBufferWriteChar(buf, " #IMPLIED");
2327  break;
2328  case XML_ATTRIBUTE_FIXED:
2329  xmlBufferWriteChar(buf, " #FIXED");
2330  break;
2331  default:
2332  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2333  "Internal: ATTRIBUTE struct corrupted invalid def\n",
2334  NULL);
2335  }
2336  if (attr->defaultValue != NULL) {
2337  xmlBufferWriteChar(buf, " ");
2338  xmlBufferWriteQuotedString(buf, attr->defaultValue);
2339  }
2340  xmlBufferWriteChar(buf, ">\n");
2341 }
2342 
2350 static void
2351 xmlDumpAttributeDeclScan(void *attr, void *buf,
2352  const xmlChar *name ATTRIBUTE_UNUSED) {
2353  xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2354 }
2355 
2363 void
2364 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2365  if ((buf == NULL) || (table == NULL))
2366  return;
2367  xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2368 }
2369 #endif /* LIBXML_OUTPUT_ENABLED */
2370 
2371 /************************************************************************
2372  * *
2373  * NOTATIONs *
2374  * *
2375  ************************************************************************/
2382 static void
2384  if (nota == NULL) return;
2385  if (nota->name != NULL)
2386  xmlFree((xmlChar *) nota->name);
2387  if (nota->PublicID != NULL)
2388  xmlFree((xmlChar *) nota->PublicID);
2389  if (nota->SystemID != NULL)
2390  xmlFree((xmlChar *) nota->SystemID);
2391  xmlFree(nota);
2392 }
2393 
2394 
2409  const xmlChar *name,
2410  const xmlChar *PublicID, const xmlChar *SystemID) {
2413 
2414  if (dtd == NULL) {
2415  return(NULL);
2416  }
2417  if (name == NULL) {
2418  return(NULL);
2419  }
2420  if ((PublicID == NULL) && (SystemID == NULL)) {
2421  return(NULL);
2422  }
2423 
2424  /*
2425  * Create the Notation table if needed.
2426  */
2428  if (table == NULL) {
2429  xmlDictPtr dict = NULL;
2430  if (dtd->doc != NULL)
2431  dict = dtd->doc->dict;
2432 
2433  dtd->notations = table = xmlHashCreateDict(0, dict);
2434  }
2435  if (table == NULL) {
2436  xmlVErrMemory(ctxt,
2437  "xmlAddNotationDecl: Table creation failed!\n");
2438  return(NULL);
2439  }
2440 
2441  ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2442  if (ret == NULL) {
2443  xmlVErrMemory(ctxt, "malloc failed");
2444  return(NULL);
2445  }
2446  memset(ret, 0, sizeof(xmlNotation));
2447 
2448  /*
2449  * fill the structure.
2450  */
2451  ret->name = xmlStrdup(name);
2452  if (SystemID != NULL)
2453  ret->SystemID = xmlStrdup(SystemID);
2454  if (PublicID != NULL)
2455  ret->PublicID = xmlStrdup(PublicID);
2456 
2457  /*
2458  * Validity Check:
2459  * Check the DTD for previous declarations of the ATTLIST
2460  */
2461  if (xmlHashAddEntry(table, name, ret)) {
2462 #ifdef LIBXML_VALID_ENABLED
2463  xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2464  "xmlAddNotationDecl: %s already defined\n",
2465  (const char *) name);
2466 #endif /* LIBXML_VALID_ENABLED */
2468  return(NULL);
2469  }
2470  return(ret);
2471 }
2472 
2473 static void
2476 }
2477 
2484 void
2487 }
2488 
2489 #ifdef LIBXML_TREE_ENABLED
2490 
2498 static void *
2499 xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2500  xmlNotationPtr nota = (xmlNotationPtr) payload;
2501  xmlNotationPtr cur;
2502 
2503  cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2504  if (cur == NULL) {
2505  xmlVErrMemory(NULL, "malloc failed");
2506  return(NULL);
2507  }
2508  if (nota->name != NULL)
2509  cur->name = xmlStrdup(nota->name);
2510  else
2511  cur->name = NULL;
2512  if (nota->PublicID != NULL)
2513  cur->PublicID = xmlStrdup(nota->PublicID);
2514  else
2515  cur->PublicID = NULL;
2516  if (nota->SystemID != NULL)
2517  cur->SystemID = xmlStrdup(nota->SystemID);
2518  else
2519  cur->SystemID = NULL;
2520  return(cur);
2521 }
2522 
2532 xmlCopyNotationTable(xmlNotationTablePtr table) {
2533  return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2534 }
2535 #endif /* LIBXML_TREE_ENABLED */
2536 
2537 #ifdef LIBXML_OUTPUT_ENABLED
2538 
2545 void
2546 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2547  if ((buf == NULL) || (nota == NULL))
2548  return;
2549  xmlBufferWriteChar(buf, "<!NOTATION ");
2550  xmlBufferWriteCHAR(buf, nota->name);
2551  if (nota->PublicID != NULL) {
2552  xmlBufferWriteChar(buf, " PUBLIC ");
2554  if (nota->SystemID != NULL) {
2555  xmlBufferWriteChar(buf, " ");
2557  }
2558  } else {
2559  xmlBufferWriteChar(buf, " SYSTEM ");
2561  }
2562  xmlBufferWriteChar(buf, " >\n");
2563 }
2564 
2572 static void
2573 xmlDumpNotationDeclScan(void *nota, void *buf,
2574  const xmlChar *name ATTRIBUTE_UNUSED) {
2575  xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2576 }
2577 
2585 void
2586 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2587  if ((buf == NULL) || (table == NULL))
2588  return;
2589  xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2590 }
2591 #endif /* LIBXML_OUTPUT_ENABLED */
2592 
2593 /************************************************************************
2594  * *
2595  * IDs *
2596  * *
2597  ************************************************************************/
2605 #define DICT_FREE(str) \
2606  if ((str) && ((!dict) || \
2607  (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2608  xmlFree((char *)(str));
2609 
2616 static void
2618  xmlDictPtr dict = NULL;
2619 
2620  if (id == NULL) return;
2621 
2622  if (id->doc != NULL)
2623  dict = id->doc->dict;
2624 
2625  if (id->value != NULL)
2626  DICT_FREE(id->value)
2627  if (id->name != NULL)
2628  DICT_FREE(id->name)
2629  xmlFree(id);
2630 }
2631 
2632 
2644 xmlIDPtr
2646  xmlAttrPtr attr) {
2647  xmlIDPtr ret;
2649 
2650  if (doc == NULL) {
2651  return(NULL);
2652  }
2653  if (value == NULL) {
2654  return(NULL);
2655  }
2656  if (attr == NULL) {
2657  return(NULL);
2658  }
2659 
2660  /*
2661  * Create the ID table if needed.
2662  */
2663  table = (xmlIDTablePtr) doc->ids;
2664  if (table == NULL) {
2665  doc->ids = table = xmlHashCreateDict(0, doc->dict);
2666  }
2667  if (table == NULL) {
2668  xmlVErrMemory(ctxt,
2669  "xmlAddID: Table creation failed!\n");
2670  return(NULL);
2671  }
2672 
2673  ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2674  if (ret == NULL) {
2675  xmlVErrMemory(ctxt, "malloc failed");
2676  return(NULL);
2677  }
2678 
2679  /*
2680  * fill the structure.
2681  */
2682  ret->value = xmlStrdup(value);
2683  ret->doc = doc;
2684  if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2685  /*
2686  * Operating in streaming mode, attr is gonna disappear
2687  */
2688  if (doc->dict != NULL)
2689  ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2690  else
2691  ret->name = xmlStrdup(attr->name);
2692  ret->attr = NULL;
2693  } else {
2694  ret->attr = attr;
2695  ret->name = NULL;
2696  }
2697  ret->lineno = xmlGetLineNo(attr->parent);
2698 
2699  if (xmlHashAddEntry(table, value, ret) < 0) {
2700 #ifdef LIBXML_VALID_ENABLED
2701  /*
2702  * The id is already defined in this DTD.
2703  */
2704  if (ctxt != NULL) {
2705  xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2706  "ID %s already defined\n", value, NULL, NULL);
2707  }
2708 #endif /* LIBXML_VALID_ENABLED */
2709  xmlFreeID(ret);
2710  return(NULL);
2711  }
2712  if (attr != NULL)
2713  attr->atype = XML_ATTRIBUTE_ID;
2714  return(ret);
2715 }
2716 
2717 static void
2719  xmlFreeID((xmlIDPtr) id);
2720 }
2721 
2728 void
2731 }
2732 
2746 int
2748  if ((attr == NULL) || (attr->name == NULL)) return(0);
2749  if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2750  (!strcmp((char *) attr->name, "id")) &&
2751  (!strcmp((char *) attr->ns->prefix, "xml")))
2752  return(1);
2753  if (doc == NULL) return(0);
2754  if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2755  (doc->type != XML_HTML_DOCUMENT_NODE)) {
2756  return(0);
2757  } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2758  if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2759  ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2760  ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2761  return(1);
2762  return(0);
2763  } else if (elem == NULL) {
2764  return(0);
2765  } else {
2766  xmlAttributePtr attrDecl = NULL;
2767 
2768  xmlChar felem[50], fattr[50];
2769  xmlChar *fullelemname, *fullattrname;
2770 
2771  fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2772  xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2773  (xmlChar *)elem->name;
2774 
2775  fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2776  xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2777  (xmlChar *)attr->name;
2778 
2779  if (fullelemname != NULL && fullattrname != NULL) {
2780  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2781  fullattrname);
2782  if ((attrDecl == NULL) && (doc->extSubset != NULL))
2783  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2784  fullattrname);
2785  }
2786 
2787  if ((fullattrname != fattr) && (fullattrname != attr->name))
2788  xmlFree(fullattrname);
2789  if ((fullelemname != felem) && (fullelemname != elem->name))
2790  xmlFree(fullelemname);
2791 
2792  if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2793  return(1);
2794  }
2795  return(0);
2796 }
2797 
2807 int
2810  xmlIDPtr id;
2811  xmlChar *ID;
2812 
2813  if (doc == NULL) return(-1);
2814  if (attr == NULL) return(-1);
2815 
2816  table = (xmlIDTablePtr) doc->ids;
2817  if (table == NULL)
2818  return(-1);
2819 
2820  ID = xmlNodeListGetString(doc, attr->children, 1);
2821  if (ID == NULL)
2822  return(-1);
2823 
2824  id = xmlHashLookup(table, ID);
2825  if (id == NULL || id->attr != attr) {
2826  xmlFree(ID);
2827  return(-1);
2828  }
2829 
2831  xmlFree(ID);
2832  attr->atype = 0;
2833  return(0);
2834 }
2835 
2845 xmlAttrPtr
2848  xmlIDPtr id;
2849 
2850  if (doc == NULL) {
2851  return(NULL);
2852  }
2853 
2854  if (ID == NULL) {
2855  return(NULL);
2856  }
2857 
2858  table = (xmlIDTablePtr) doc->ids;
2859  if (table == NULL)
2860  return(NULL);
2861 
2862  id = xmlHashLookup(table, ID);
2863  if (id == NULL)
2864  return(NULL);
2865  if (id->attr == NULL) {
2866  /*
2867  * We are operating on a stream, return a well known reference
2868  * since the attribute node doesn't exist anymore
2869  */
2870  return((xmlAttrPtr) doc);
2871  }
2872  return(id->attr);
2873 }
2874 
2875 /************************************************************************
2876  * *
2877  * Refs *
2878  * *
2879  ************************************************************************/
2880 typedef struct xmlRemoveMemo_t
2881 {
2884 } xmlRemoveMemo;
2885 
2887 
2888 typedef struct xmlValidateMemo_t
2889 {
2891  const xmlChar *name;
2892 } xmlValidateMemo;
2893 
2895 
2902 static void
2905  if (ref == NULL) return;
2906  if (ref->value != NULL)
2907  xmlFree((xmlChar *)ref->value);
2908  if (ref->name != NULL)
2909  xmlFree((xmlChar *)ref->name);
2910  xmlFree(ref);
2911 }
2912 
2919 static void
2921  xmlListPtr list_ref = (xmlListPtr) payload;
2922  if (list_ref == NULL) return;
2923  xmlListDelete(list_ref);
2924 }
2925 
2933 static int
2934 xmlWalkRemoveRef(const void *data, void *user)
2935 {
2936  xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2937  xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2938  xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2939 
2940  if (attr0 == attr1) { /* Matched: remove and terminate walk */
2941  xmlListRemoveFirst(ref_list, (void *)data);
2942  return 0;
2943  }
2944  return 1;
2945 }
2946 
2954 static int
2956  const void *data1 ATTRIBUTE_UNUSED)
2957 {
2958  return (0);
2959 }
2960 
2972 xmlRefPtr
2974  xmlAttrPtr attr) {
2975  xmlRefPtr ret;
2977  xmlListPtr ref_list;
2978 
2979  if (doc == NULL) {
2980  return(NULL);
2981  }
2982  if (value == NULL) {
2983  return(NULL);
2984  }
2985  if (attr == NULL) {
2986  return(NULL);
2987  }
2988 
2989  /*
2990  * Create the Ref table if needed.
2991  */
2992  table = (xmlRefTablePtr) doc->refs;
2993  if (table == NULL) {
2994  doc->refs = table = xmlHashCreateDict(0, doc->dict);
2995  }
2996  if (table == NULL) {
2997  xmlVErrMemory(ctxt,
2998  "xmlAddRef: Table creation failed!\n");
2999  return(NULL);
3000  }
3001 
3002  ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3003  if (ret == NULL) {
3004  xmlVErrMemory(ctxt, "malloc failed");
3005  return(NULL);
3006  }
3007 
3008  /*
3009  * fill the structure.
3010  */
3011  ret->value = xmlStrdup(value);
3012  if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
3013  /*
3014  * Operating in streaming mode, attr is gonna disappear
3015  */
3016  ret->name = xmlStrdup(attr->name);
3017  ret->attr = NULL;
3018  } else {
3019  ret->name = NULL;
3020  ret->attr = attr;
3021  }
3022  ret->lineno = xmlGetLineNo(attr->parent);
3023 
3024  /* To add a reference :-
3025  * References are maintained as a list of references,
3026  * Lookup the entry, if no entry create new nodelist
3027  * Add the owning node to the NodeList
3028  * Return the ref
3029  */
3030 
3031  if (NULL == (ref_list = xmlHashLookup(table, value))) {
3032  if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
3033  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3034  "xmlAddRef: Reference list creation failed!\n",
3035  NULL);
3036  goto failed;
3037  }
3038  if (xmlHashAddEntry(table, value, ref_list) < 0) {
3039  xmlListDelete(ref_list);
3040  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3041  "xmlAddRef: Reference list insertion failed!\n",
3042  NULL);
3043  goto failed;
3044  }
3045  }
3046  if (xmlListAppend(ref_list, ret) != 0) {
3047  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3048  "xmlAddRef: Reference list insertion failed!\n",
3049  NULL);
3050  goto failed;
3051  }
3052  return(ret);
3053 failed:
3054  if (ret != NULL) {
3055  if (ret->value != NULL)
3056  xmlFree((char *)ret->value);
3057  if (ret->name != NULL)
3058  xmlFree((char *)ret->name);
3059  xmlFree(ret);
3060  }
3061  return(NULL);
3062 }
3063 
3070 void
3073 }
3074 
3087 int
3089  if (attr == NULL)
3090  return(0);
3091  if (doc == NULL) {
3092  doc = attr->doc;
3093  if (doc == NULL) return(0);
3094  }
3095 
3096  if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3097  return(0);
3098  } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3099  /* TODO @@@ */
3100  return(0);
3101  } else {
3102  xmlAttributePtr attrDecl;
3103 
3104  if (elem == NULL) return(0);
3105  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3106  if ((attrDecl == NULL) && (doc->extSubset != NULL))
3107  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3108  elem->name, attr->name);
3109 
3110  if ((attrDecl != NULL) &&
3111  (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3112  attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3113  return(1);
3114  }
3115  return(0);
3116 }
3117 
3127 int
3129  xmlListPtr ref_list;
3131  xmlChar *ID;
3133 
3134  if (doc == NULL) return(-1);
3135  if (attr == NULL) return(-1);
3136 
3137  table = (xmlRefTablePtr) doc->refs;
3138  if (table == NULL)
3139  return(-1);
3140 
3141  ID = xmlNodeListGetString(doc, attr->children, 1);
3142  if (ID == NULL)
3143  return(-1);
3144 
3145  ref_list = xmlHashLookup(table, ID);
3146  if(ref_list == NULL) {
3147  xmlFree(ID);
3148  return (-1);
3149  }
3150 
3151  /* At this point, ref_list refers to a list of references which
3152  * have the same key as the supplied attr. Our list of references
3153  * is ordered by reference address and we don't have that information
3154  * here to use when removing. We'll have to walk the list and
3155  * check for a matching attribute, when we find one stop the walk
3156  * and remove the entry.
3157  * The list is ordered by reference, so that means we don't have the
3158  * key. Passing the list and the reference to the walker means we
3159  * will have enough data to be able to remove the entry.
3160  */
3161  target.l = ref_list;
3162  target.ap = attr;
3163 
3164  /* Remove the supplied attr from our list */
3165  xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3166 
3167  /*If the list is empty then remove the list entry in the hash */
3168  if (xmlListEmpty(ref_list))
3170  xmlFree(ID);
3171  return(0);
3172 }
3173 
3183 xmlListPtr
3186 
3187  if (doc == NULL) {
3188  return(NULL);
3189  }
3190 
3191  if (ID == NULL) {
3192  return(NULL);
3193  }
3194 
3195  table = (xmlRefTablePtr) doc->refs;
3196  if (table == NULL)
3197  return(NULL);
3198 
3199  return (xmlHashLookup(table, ID));
3200 }
3201 
3202 /************************************************************************
3203  * *
3204  * Routines for validity checking *
3205  * *
3206  ************************************************************************/
3207 
3221  xmlElementPtr cur;
3222  xmlChar *uqname = NULL, *prefix = NULL;
3223 
3224  if ((dtd == NULL) || (name == NULL)) return(NULL);
3225  if (dtd->elements == NULL)
3226  return(NULL);
3228 
3229  uqname = xmlSplitQName2(name, &prefix);
3230  if (uqname != NULL)
3231  name = uqname;
3232  cur = xmlHashLookup2(table, name, prefix);
3233  if (prefix != NULL) xmlFree(prefix);
3234  if (uqname != NULL) xmlFree(uqname);
3235  return(cur);
3236 }
3248 static xmlElementPtr
3251  xmlElementPtr cur;
3252  xmlChar *uqname = NULL, *prefix = NULL;
3253 
3254  if (dtd == NULL) return(NULL);
3255  if (dtd->elements == NULL) {
3256  xmlDictPtr dict = NULL;
3257 
3258  if (dtd->doc != NULL)
3259  dict = dtd->doc->dict;
3260 
3261  if (!create)
3262  return(NULL);
3263  /*
3264  * Create the Element table if needed.
3265  */
3267  if (table == NULL) {
3268  table = xmlHashCreateDict(0, dict);
3269  dtd->elements = (void *) table;
3270  }
3271  if (table == NULL) {
3272  xmlVErrMemory(NULL, "element table allocation failed");
3273  return(NULL);
3274  }
3275  }
3277 
3278  uqname = xmlSplitQName2(name, &prefix);
3279  if (uqname != NULL)
3280  name = uqname;
3281  cur = xmlHashLookup2(table, name, prefix);
3282  if ((cur == NULL) && (create)) {
3283  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3284  if (cur == NULL) {
3285  xmlVErrMemory(NULL, "malloc failed");
3286  return(NULL);
3287  }
3288  memset(cur, 0, sizeof(xmlElement));
3289  cur->type = XML_ELEMENT_DECL;
3290 
3291  /*
3292  * fill the structure.
3293  */
3294  cur->name = xmlStrdup(name);
3295  cur->prefix = xmlStrdup(prefix);
3297 
3298  xmlHashAddEntry2(table, name, prefix, cur);
3299  }
3300  if (prefix != NULL) xmlFree(prefix);
3301  if (uqname != NULL) xmlFree(uqname);
3302  return(cur);
3303 }
3304 
3318  const xmlChar *prefix) {
3320 
3321  if (dtd == NULL) return(NULL);
3322  if (dtd->elements == NULL) return(NULL);
3324 
3325  return(xmlHashLookup2(table, name, prefix));
3326 }
3327 
3343  xmlAttributePtr cur;
3344  xmlChar *uqname = NULL, *prefix = NULL;
3345 
3346  if (dtd == NULL) return(NULL);
3347  if (dtd->attributes == NULL) return(NULL);
3348 
3350  if (table == NULL)
3351  return(NULL);
3352 
3353  uqname = xmlSplitQName2(name, &prefix);
3354 
3355  if (uqname != NULL) {
3356  cur = xmlHashLookup3(table, uqname, prefix, elem);
3357  if (prefix != NULL) xmlFree(prefix);
3358  if (uqname != NULL) xmlFree(uqname);
3359  } else
3360  cur = xmlHashLookup3(table, name, NULL, elem);
3361  return(cur);
3362 }
3363 
3379  const xmlChar *prefix) {
3381 
3382  if (dtd == NULL) return(NULL);
3383  if (dtd->attributes == NULL) return(NULL);
3385 
3386  return(xmlHashLookup3(table, name, prefix, elem));
3387 }
3388 
3402 
3403  if (dtd == NULL) return(NULL);
3404  if (dtd->notations == NULL) return(NULL);
3406 
3407  return(xmlHashLookup(table, name));
3408 }
3409 
3410 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3411 
3423 int
3424 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3425  const xmlChar *notationName) {
3426  xmlNotationPtr notaDecl;
3427  if ((doc == NULL) || (doc->intSubset == NULL) ||
3428  (notationName == NULL)) return(-1);
3429 
3430  notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3431  if ((notaDecl == NULL) && (doc->extSubset != NULL))
3432  notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3433 
3434  if ((notaDecl == NULL) && (ctxt != NULL)) {
3435  xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3436  "NOTATION %s is not declared\n",
3437  notationName, NULL, NULL);
3438  return(0);
3439  }
3440  return(1);
3441 }
3442 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3443 
3455 int
3457  xmlElementPtr elemDecl;
3458 
3459  if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3460 
3461  elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3462  if ((elemDecl == NULL) && (doc->extSubset != NULL))
3463  elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3464  if (elemDecl == NULL) return(-1);
3465  switch (elemDecl->etype) {
3467  return(-1);
3469  return(0);
3471  /*
3472  * return 1 for EMPTY since we want VC error to pop up
3473  * on <empty> </empty> for example
3474  */
3475  case XML_ELEMENT_TYPE_ANY:
3477  return(1);
3478  }
3479  return(1);
3480 }
3481 
3482 #ifdef LIBXML_VALID_ENABLED
3483 
3484 static int
3485 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3486  if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3487  /*
3488  * Use the new checks of production [4] [4a] amd [5] of the
3489  * Update 5 of XML-1.0
3490  */
3491  if (((c >= 'a') && (c <= 'z')) ||
3492  ((c >= 'A') && (c <= 'Z')) ||
3493  (c == '_') || (c == ':') ||
3494  ((c >= 0xC0) && (c <= 0xD6)) ||
3495  ((c >= 0xD8) && (c <= 0xF6)) ||
3496  ((c >= 0xF8) && (c <= 0x2FF)) ||
3497  ((c >= 0x370) && (c <= 0x37D)) ||
3498  ((c >= 0x37F) && (c <= 0x1FFF)) ||
3499  ((c >= 0x200C) && (c <= 0x200D)) ||
3500  ((c >= 0x2070) && (c <= 0x218F)) ||
3501  ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3502  ((c >= 0x3001) && (c <= 0xD7FF)) ||
3503  ((c >= 0xF900) && (c <= 0xFDCF)) ||
3504  ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3505  ((c >= 0x10000) && (c <= 0xEFFFF)))
3506  return(1);
3507  } else {
3508  if (IS_LETTER(c) || (c == '_') || (c == ':'))
3509  return(1);
3510  }
3511  return(0);
3512 }
3513 
3514 static int
3515 xmlIsDocNameChar(xmlDocPtr doc, int c) {
3516  if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3517  /*
3518  * Use the new checks of production [4] [4a] amd [5] of the
3519  * Update 5 of XML-1.0
3520  */
3521  if (((c >= 'a') && (c <= 'z')) ||
3522  ((c >= 'A') && (c <= 'Z')) ||
3523  ((c >= '0') && (c <= '9')) || /* !start */
3524  (c == '_') || (c == ':') ||
3525  (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3526  ((c >= 0xC0) && (c <= 0xD6)) ||
3527  ((c >= 0xD8) && (c <= 0xF6)) ||
3528  ((c >= 0xF8) && (c <= 0x2FF)) ||
3529  ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3530  ((c >= 0x370) && (c <= 0x37D)) ||
3531  ((c >= 0x37F) && (c <= 0x1FFF)) ||
3532  ((c >= 0x200C) && (c <= 0x200D)) ||
3533  ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3534  ((c >= 0x2070) && (c <= 0x218F)) ||
3535  ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3536  ((c >= 0x3001) && (c <= 0xD7FF)) ||
3537  ((c >= 0xF900) && (c <= 0xFDCF)) ||
3538  ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3539  ((c >= 0x10000) && (c <= 0xEFFFF)))
3540  return(1);
3541  } else {
3542  if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3543  (c == '.') || (c == '-') ||
3544  (c == '_') || (c == ':') ||
3545  (IS_COMBINING(c)) ||
3546  (IS_EXTENDER(c)))
3547  return(1);
3548  }
3549  return(0);
3550 }
3551 
3562 static int
3563 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3564  const xmlChar *cur;
3565  int val, len;
3566 
3567  if (value == NULL) return(0);
3568  cur = value;
3569  val = xmlStringCurrentChar(NULL, cur, &len);
3570  cur += len;
3571  if (!xmlIsDocNameStartChar(doc, val))
3572  return(0);
3573 
3574  val = xmlStringCurrentChar(NULL, cur, &len);
3575  cur += len;
3576  while (xmlIsDocNameChar(doc, val)) {
3577  val = xmlStringCurrentChar(NULL, cur, &len);
3578  cur += len;
3579  }
3580 
3581  if (val != 0) return(0);
3582 
3583  return(1);
3584 }
3585 
3595 int
3596 xmlValidateNameValue(const xmlChar *value) {
3597  return(xmlValidateNameValueInternal(NULL, value));
3598 }
3599 
3610 static int
3611 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3612  const xmlChar *cur;
3613  int val, len;
3614 
3615  if (value == NULL) return(0);
3616  cur = value;
3617  val = xmlStringCurrentChar(NULL, cur, &len);
3618  cur += len;
3619 
3620  if (!xmlIsDocNameStartChar(doc, val))
3621  return(0);
3622 
3623  val = xmlStringCurrentChar(NULL, cur, &len);
3624  cur += len;
3625  while (xmlIsDocNameChar(doc, val)) {
3626  val = xmlStringCurrentChar(NULL, cur, &len);
3627  cur += len;
3628  }
3629 
3630  /* Should not test IS_BLANK(val) here -- see erratum E20*/
3631  while (val == 0x20) {
3632  while (val == 0x20) {
3633  val = xmlStringCurrentChar(NULL, cur, &len);
3634  cur += len;
3635  }
3636 
3637  if (!xmlIsDocNameStartChar(doc, val))
3638  return(0);
3639 
3640  val = xmlStringCurrentChar(NULL, cur, &len);
3641  cur += len;
3642 
3643  while (xmlIsDocNameChar(doc, val)) {
3644  val = xmlStringCurrentChar(NULL, cur, &len);
3645  cur += len;
3646  }
3647  }
3648 
3649  if (val != 0) return(0);
3650 
3651  return(1);
3652 }
3653 
3663 int
3664 xmlValidateNamesValue(const xmlChar *value) {
3665  return(xmlValidateNamesValueInternal(NULL, value));
3666 }
3667 
3680 static int
3681 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3682  const xmlChar *cur;
3683  int val, len;
3684 
3685  if (value == NULL) return(0);
3686  cur = value;
3687  val = xmlStringCurrentChar(NULL, cur, &len);
3688  cur += len;
3689 
3690  if (!xmlIsDocNameChar(doc, val))
3691  return(0);
3692 
3693  val = xmlStringCurrentChar(NULL, cur, &len);
3694  cur += len;
3695  while (xmlIsDocNameChar(doc, val)) {
3696  val = xmlStringCurrentChar(NULL, cur, &len);
3697  cur += len;
3698  }
3699 
3700  if (val != 0) return(0);
3701 
3702  return(1);
3703 }
3704 
3716 int
3717 xmlValidateNmtokenValue(const xmlChar *value) {
3718  return(xmlValidateNmtokenValueInternal(NULL, value));
3719 }
3720 
3733 static int
3734 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3735  const xmlChar *cur;
3736  int val, len;
3737 
3738  if (value == NULL) return(0);
3739  cur = value;
3740  val = xmlStringCurrentChar(NULL, cur, &len);
3741  cur += len;
3742 
3743  while (IS_BLANK(val)) {
3744  val = xmlStringCurrentChar(NULL, cur, &len);
3745  cur += len;
3746  }
3747 
3748  if (!xmlIsDocNameChar(doc, val))
3749  return(0);
3750 
3751  while (xmlIsDocNameChar(doc, val)) {
3752  val = xmlStringCurrentChar(NULL, cur, &len);
3753  cur += len;
3754  }
3755 
3756  /* Should not test IS_BLANK(val) here -- see erratum E20*/
3757  while (val == 0x20) {
3758  while (val == 0x20) {
3759  val = xmlStringCurrentChar(NULL, cur, &len);
3760  cur += len;
3761  }
3762  if (val == 0) return(1);
3763 
3764  if (!xmlIsDocNameChar(doc, val))
3765  return(0);
3766 
3767  val = xmlStringCurrentChar(NULL, cur, &len);
3768  cur += len;
3769 
3770  while (xmlIsDocNameChar(doc, val)) {
3771  val = xmlStringCurrentChar(NULL, cur, &len);
3772  cur += len;
3773  }
3774  }
3775 
3776  if (val != 0) return(0);
3777 
3778  return(1);
3779 }
3780 
3792 int
3793 xmlValidateNmtokensValue(const xmlChar *value) {
3794  return(xmlValidateNmtokensValueInternal(NULL, value));
3795 }
3796 
3812 int
3813 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3815  int ret = 1;
3816 
3817  return(ret);
3818 }
3819 
3831 static int
3832 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3833  const xmlChar *value) {
3834  switch (type) {
3836  case XML_ATTRIBUTE_IDREFS:
3837  return(xmlValidateNamesValueInternal(doc, value));
3838  case XML_ATTRIBUTE_ENTITY:
3839  case XML_ATTRIBUTE_IDREF:
3840  case XML_ATTRIBUTE_ID:
3842  return(xmlValidateNameValueInternal(doc, value));
3845  return(xmlValidateNmtokensValueInternal(doc, value));
3846  case XML_ATTRIBUTE_NMTOKEN:
3847  return(xmlValidateNmtokenValueInternal(doc, value));
3848  case XML_ATTRIBUTE_CDATA:
3849  break;
3850  }
3851  return(1);
3852 }
3853 
3878 int
3879 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3880  return(xmlValidateAttributeValueInternal(NULL, type, value));
3881 }
3882 
3912 static int
3913 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3914  const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3915  int ret = 1;
3916  switch (type) {
3917  case XML_ATTRIBUTE_IDREFS:
3918  case XML_ATTRIBUTE_IDREF:
3919  case XML_ATTRIBUTE_ID:
3922  case XML_ATTRIBUTE_NMTOKEN:
3923  case XML_ATTRIBUTE_CDATA:
3924  break;
3925  case XML_ATTRIBUTE_ENTITY: {
3926  xmlEntityPtr ent;
3927 
3928  ent = xmlGetDocEntity(doc, value);
3929  /* yeah it's a bit messy... */
3930  if ((ent == NULL) && (doc->standalone == 1)) {
3931  doc->standalone = 0;
3932  ent = xmlGetDocEntity(doc, value);
3933  }
3934  if (ent == NULL) {
3935  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3937  "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3938  name, value, NULL);
3939  ret = 0;
3940  } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3941  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3943  "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3944  name, value, NULL);
3945  ret = 0;
3946  }
3947  break;
3948  }
3949  case XML_ATTRIBUTE_ENTITIES: {
3950  xmlChar *dup, *nam = NULL, *cur, save;
3951  xmlEntityPtr ent;
3952 
3953  dup = xmlStrdup(value);
3954  if (dup == NULL)
3955  return(0);
3956  cur = dup;
3957  while (*cur != 0) {
3958  nam = cur;
3959  while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3960  save = *cur;
3961  *cur = 0;
3962  ent = xmlGetDocEntity(doc, nam);
3963  if (ent == NULL) {
3964  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3966  "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3967  name, nam, NULL);
3968  ret = 0;
3969  } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3970  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3972  "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3973  name, nam, NULL);
3974  ret = 0;
3975  }
3976  if (save == 0)
3977  break;
3978  *cur = save;
3979  while (IS_BLANK_CH(*cur)) cur++;
3980  }
3981  xmlFree(dup);
3982  break;
3983  }
3984  case XML_ATTRIBUTE_NOTATION: {
3985  xmlNotationPtr nota;
3986 
3987  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3988  if ((nota == NULL) && (doc->extSubset != NULL))
3989  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3990 
3991  if (nota == NULL) {
3992  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3994  "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3995  name, value, NULL);
3996  ret = 0;
3997  }
3998  break;
3999  }
4000  }
4001  return(ret);
4002 }
4003 
4028 xmlChar *
4029 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4030  xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4031  xmlChar *ret, *dst;
4032  const xmlChar *src;
4033  xmlAttributePtr attrDecl = NULL;
4034  int extsubset = 0;
4035 
4036  if (doc == NULL) return(NULL);
4037  if (elem == NULL) return(NULL);
4038  if (name == NULL) return(NULL);
4039  if (value == NULL) return(NULL);
4040 
4041  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4042  xmlChar fn[50];
4043  xmlChar *fullname;
4044 
4045  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4046  if (fullname == NULL)
4047  return(NULL);
4048  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4049  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4050  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4051  if (attrDecl != NULL)
4052  extsubset = 1;
4053  }
4054  if ((fullname != fn) && (fullname != elem->name))
4055  xmlFree(fullname);
4056  }
4057  if ((attrDecl == NULL) && (doc->intSubset != NULL))
4058  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4059  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4060  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4061  if (attrDecl != NULL)
4062  extsubset = 1;
4063  }
4064 
4065  if (attrDecl == NULL)
4066  return(NULL);
4067  if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4068  return(NULL);
4069 
4070  ret = xmlStrdup(value);
4071  if (ret == NULL)
4072  return(NULL);
4073  src = value;
4074  dst = ret;
4075  while (*src == 0x20) src++;
4076  while (*src != 0) {
4077  if (*src == 0x20) {
4078  while (*src == 0x20) src++;
4079  if (*src != 0)
4080  *dst++ = 0x20;
4081  } else {
4082  *dst++ = *src++;
4083  }
4084  }
4085  *dst = 0;
4086  if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4087  xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4088 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4089  name, elem->name, NULL);
4090  ctxt->valid = 0;
4091  }
4092  return(ret);
4093 }
4094 
4114 xmlChar *
4115 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4116  const xmlChar *name, const xmlChar *value) {
4117  xmlChar *ret, *dst;
4118  const xmlChar *src;
4119  xmlAttributePtr attrDecl = NULL;
4120 
4121  if (doc == NULL) return(NULL);
4122  if (elem == NULL) return(NULL);
4123  if (name == NULL) return(NULL);
4124  if (value == NULL) return(NULL);
4125 
4126  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4127  xmlChar fn[50];
4128  xmlChar *fullname;
4129 
4130  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4131  if (fullname == NULL)
4132  return(NULL);
4133  if ((fullname != fn) && (fullname != elem->name))
4134  xmlFree(fullname);
4135  }
4136  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4137  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4138  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4139 
4140  if (attrDecl == NULL)
4141  return(NULL);
4142  if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4143  return(NULL);
4144 
4145  ret = xmlStrdup(value);
4146  if (ret == NULL)
4147  return(NULL);
4148  src = value;
4149  dst = ret;
4150  while (*src == 0x20) src++;
4151  while (*src != 0) {
4152  if (*src == 0x20) {
4153  while (*src == 0x20) src++;
4154  if (*src != 0)
4155  *dst++ = 0x20;
4156  } else {
4157  *dst++ = *src++;
4158  }
4159  }
4160  *dst = 0;
4161  return(ret);
4162 }
4163 
4164 static void
4165 xmlValidateAttributeIdCallback(void *payload, void *data,
4166  const xmlChar *name ATTRIBUTE_UNUSED) {
4167  xmlAttributePtr attr = (xmlAttributePtr) payload;
4168  int *count = (int *) data;
4169  if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4170 }
4171 
4190 int
4191 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4193  int ret = 1;
4194  int val;
4195  CHECK_DTD;
4196  if(attr == NULL) return(1);
4197 
4198  /* Attribute Default Legal */
4199  /* Enumeration */
4200  if (attr->defaultValue != NULL) {
4201  val = xmlValidateAttributeValueInternal(doc, attr->atype,
4202  attr->defaultValue);
4203  if (val == 0) {
4204  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4205  "Syntax of default value for attribute %s of %s is not valid\n",
4206  attr->name, attr->elem, NULL);
4207  }
4208  ret &= val;
4209  }
4210 
4211  /* ID Attribute Default */
4212  if ((attr->atype == XML_ATTRIBUTE_ID)&&
4213  (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4214  (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4215  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4216  "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4217  attr->name, attr->elem, NULL);
4218  ret = 0;
4219  }
4220 
4221  /* One ID per Element Type */
4222  if (attr->atype == XML_ATTRIBUTE_ID) {
4223  int nbId;
4224 
4225  /* the trick is that we parse DtD as their own internal subset */
4227  attr->elem);
4228  if (elem != NULL) {
4229  nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4230  } else {
4232 
4233  /*
4234  * The attribute may be declared in the internal subset and the
4235  * element in the external subset.
4236  */
4237  nbId = 0;
4238  if (doc->intSubset != NULL) {
4239  table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4240  xmlHashScan3(table, NULL, NULL, attr->elem,
4241  xmlValidateAttributeIdCallback, &nbId);
4242  }
4243  }
4244  if (nbId > 1) {
4245 
4246  xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4247  "Element %s has %d ID attribute defined in the internal subset : %s\n",
4248  attr->elem, nbId, attr->name);
4249  } else if (doc->extSubset != NULL) {
4250  int extId = 0;
4251  elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4252  if (elem != NULL) {
4253  extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4254  }
4255  if (extId > 1) {
4256  xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4257  "Element %s has %d ID attribute defined in the external subset : %s\n",
4258  attr->elem, extId, attr->name);
4259  } else if (extId + nbId > 1) {
4260  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4261 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4262  attr->elem, attr->name, NULL);
4263  }
4264  }
4265  }
4266 
4267  /* Validity Constraint: Enumeration */
4268  if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4269  xmlEnumerationPtr tree = attr->tree;
4270  while (tree != NULL) {
4271  if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4272  tree = tree->next;
4273  }
4274  if (tree == NULL) {
4275  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4276 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4277  attr->defaultValue, attr->name, attr->elem);
4278  ret = 0;
4279  }
4280  }
4281 
4282  return(ret);
4283 }
4284 
4301 int
4302 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4303  xmlElementPtr elem) {
4304  int ret = 1;
4305  xmlElementPtr tst;
4306 
4307  CHECK_DTD;
4308 
4309  if (elem == NULL) return(1);
4310 
4311 #if 0
4312 #ifdef LIBXML_REGEXP_ENABLED
4313  /* Build the regexp associated to the content model */
4314  ret = xmlValidBuildContentModel(ctxt, elem);
4315 #endif
4316 #endif
4317 
4318  /* No Duplicate Types */
4319  if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4321  const xmlChar *name;
4322 
4323  cur = elem->content;
4324  while (cur != NULL) {
4325  if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4326  if (cur->c1 == NULL) break;
4327  if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4328  name = cur->c1->name;
4329  next = cur->c2;
4330  while (next != NULL) {
4331  if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4332  if ((xmlStrEqual(next->name, name)) &&
4333  (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4334  if (cur->c1->prefix == NULL) {
4335  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4336  "Definition of %s has duplicate references of %s\n",
4337  elem->name, name, NULL);
4338  } else {
4339  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4340  "Definition of %s has duplicate references of %s:%s\n",
4341  elem->name, cur->c1->prefix, name);
4342  }
4343  ret = 0;
4344  }
4345  break;
4346  }
4347  if (next->c1 == NULL) break;
4348  if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4349  if ((xmlStrEqual(next->c1->name, name)) &&
4350  (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4351  if (cur->c1->prefix == NULL) {
4352  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4353  "Definition of %s has duplicate references to %s\n",
4354  elem->name, name, NULL);
4355  } else {
4356  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4357  "Definition of %s has duplicate references to %s:%s\n",
4358  elem->name, cur->c1->prefix, name);
4359  }
4360  ret = 0;
4361  }
4362  next = next->c2;
4363  }
4364  }
4365  cur = cur->c2;
4366  }
4367  }
4368 
4369  /* VC: Unique Element Type Declaration */
4370  tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4371  if ((tst != NULL ) && (tst != elem) &&
4372  ((tst->prefix == elem->prefix) ||
4373  (xmlStrEqual(tst->prefix, elem->prefix))) &&
4374  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4375  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4376  "Redefinition of element %s\n",
4377  elem->name, NULL, NULL);
4378  ret = 0;
4379  }
4380  tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4381  if ((tst != NULL ) && (tst != elem) &&
4382  ((tst->prefix == elem->prefix) ||
4383  (xmlStrEqual(tst->prefix, elem->prefix))) &&
4384  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4385  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4386  "Redefinition of element %s\n",
4387  elem->name, NULL, NULL);
4388  ret = 0;
4389  }
4390  /* One ID per Element Type
4391  * already done when registering the attribute
4392  if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4393  ret = 0;
4394  } */
4395  return(ret);
4396 }
4397 
4423 int
4424 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4426 {
4427  xmlAttributePtr attrDecl = NULL;
4428  int val;
4429  int ret = 1;
4430 
4431  CHECK_DTD;
4432  if ((elem == NULL) || (elem->name == NULL)) return(0);
4433  if ((attr == NULL) || (attr->name == NULL)) return(0);
4434 
4435  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4436  xmlChar fn[50];
4437  xmlChar *fullname;
4438 
4439  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4440  if (fullname == NULL)
4441  return(0);
4442  if (attr->ns != NULL) {
4443  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4444  attr->name, attr->ns->prefix);
4445  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4446  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4447  attr->name, attr->ns->prefix);
4448  } else {
4449  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4450  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4451  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4452  fullname, attr->name);
4453  }
4454  if ((fullname != fn) && (fullname != elem->name))
4455  xmlFree(fullname);
4456  }
4457  if (attrDecl == NULL) {
4458  if (attr->ns != NULL) {
4459  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4460  attr->name, attr->ns->prefix);
4461  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4462  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4463  attr->name, attr->ns->prefix);
4464  } else {
4465  attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4466  elem->name, attr->name);
4467  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4468  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4469  elem->name, attr->name);
4470  }
4471  }
4472 
4473 
4474  /* Validity Constraint: Attribute Value Type */
4475  if (attrDecl == NULL) {
4476  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4477  "No declaration for attribute %s of element %s\n",
4478  attr->name, elem->name, NULL);
4479  return(0);
4480  }
4481  attr->atype = attrDecl->atype;
4482 
4483  val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4484  if (val == 0) {
4485  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4486  "Syntax of value for attribute %s of %s is not valid\n",
4487  attr->name, elem->name, NULL);
4488  ret = 0;
4489  }
4490 
4491  /* Validity constraint: Fixed Attribute Default */
4492  if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4493  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4494  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4495  "Value for attribute %s of %s is different from default \"%s\"\n",
4496  attr->name, elem->name, attrDecl->defaultValue);
4497  ret = 0;
4498  }
4499  }
4500 
4501  /* Validity Constraint: ID uniqueness */
4502  if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4503  if (xmlAddID(ctxt, doc, value, attr) == NULL)
4504  ret = 0;
4505  }
4506 
4507  if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4508  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4509  if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4510  ret = 0;
4511  }
4512 
4513  /* Validity Constraint: Notation Attributes */
4514  if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4515  xmlEnumerationPtr tree = attrDecl->tree;
4516  xmlNotationPtr nota;
4517 
4518  /* First check that the given NOTATION was declared */
4519  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4520  if (nota == NULL)
4521  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4522 
4523  if (nota == NULL) {
4524  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4525  "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4526  value, attr->name, elem->name);
4527  ret = 0;
4528  }
4529 
4530  /* Second, verify that it's among the list */
4531  while (tree != NULL) {
4532  if (xmlStrEqual(tree->name, value)) break;
4533  tree = tree->next;
4534  }
4535  if (tree == NULL) {
4536  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4537 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4538  value, attr->name, elem->name);
4539  ret = 0;
4540  }
4541  }
4542 
4543  /* Validity Constraint: Enumeration */
4544  if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4545  xmlEnumerationPtr tree = attrDecl->tree;
4546  while (tree != NULL) {
4547  if (xmlStrEqual(tree->name, value)) break;
4548  tree = tree->next;
4549  }
4550  if (tree == NULL) {
4551  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4552  "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4553  value, attr->name, elem->name);
4554  ret = 0;
4555  }
4556  }
4557 
4558  /* Fixed Attribute Default */
4559  if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4560  (!xmlStrEqual(attrDecl->defaultValue, value))) {
4561  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4562  "Value for attribute %s of %s must be \"%s\"\n",
4563  attr->name, elem->name, attrDecl->defaultValue);
4564  ret = 0;
4565  }
4566 
4567  /* Extra check for the attribute value */
4568  ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4569  attrDecl->atype, value);
4570 
4571  return(ret);
4572 }
4573 
4600 int
4601 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4602 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4603  /* xmlElementPtr elemDecl; */
4604  xmlAttributePtr attrDecl = NULL;
4605  int val;
4606  int ret = 1;
4607 
4608  CHECK_DTD;
4609  if ((elem == NULL) || (elem->name == NULL)) return(0);
4610  if ((ns == NULL) || (ns->href == NULL)) return(0);
4611 
4612  if (prefix != NULL) {
4613  xmlChar fn[50];
4614  xmlChar *fullname;
4615 
4616  fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4617  if (fullname == NULL) {
4618  xmlVErrMemory(ctxt, "Validating namespace");
4619  return(0);
4620  }
4621  if (ns->prefix != NULL) {
4622  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4623  ns->prefix, BAD_CAST "xmlns");
4624  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4625  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4626  ns->prefix, BAD_CAST "xmlns");
4627  } else {
4628  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4629  BAD_CAST "xmlns");
4630  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4631  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4632  BAD_CAST "xmlns");
4633  }
4634  if ((fullname != fn) && (fullname != elem->name))
4635  xmlFree(fullname);
4636  }
4637  if (attrDecl == NULL) {
4638  if (ns->prefix != NULL) {
4639  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4640  ns->prefix, BAD_CAST "xmlns");
4641  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4642  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4643  ns->prefix, BAD_CAST "xmlns");
4644  } else {
4645  attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4646  elem->name, BAD_CAST "xmlns");
4647  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4648  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4649  elem->name, BAD_CAST "xmlns");
4650  }
4651  }
4652 
4653 
4654  /* Validity Constraint: Attribute Value Type */
4655  if (attrDecl == NULL) {
4656  if (ns->prefix != NULL) {
4657  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4658  "No declaration for attribute xmlns:%s of element %s\n",
4659  ns->prefix, elem->name, NULL);
4660  } else {
4661  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4662  "No declaration for attribute xmlns of element %s\n",
4663  elem->name, NULL, NULL);
4664  }
4665  return(0);
4666  }
4667 
4668  val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4669  if (val == 0) {
4670  if (ns->prefix != NULL) {
4671  xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4672  "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4673  ns->prefix, elem->name, NULL);
4674  } else {
4675  xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4676  "Syntax of value for attribute xmlns of %s is not valid\n",
4677  elem->name, NULL, NULL);
4678  }
4679  ret = 0;
4680  }
4681 
4682  /* Validity constraint: Fixed Attribute Default */
4683  if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4684  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4685  if (ns->prefix != NULL) {
4686  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4687  "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4688  ns->prefix, elem->name, attrDecl->defaultValue);
4689  } else {
4690  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4691  "Value for attribute xmlns of %s is different from default \"%s\"\n",
4692  elem->name, attrDecl->defaultValue, NULL);
4693  }
4694  ret = 0;
4695  }
4696  }
4697 
4698  /*
4699  * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4700  * xmlAddID and xmlAddRef for namespace declarations, but it makes
4701  * no practical sense to use ID types anyway.
4702  */
4703 #if 0
4704  /* Validity Constraint: ID uniqueness */
4705  if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4706  if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4707  ret = 0;
4708  }
4709 
4710  if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4711  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4712  if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4713  ret = 0;
4714  }
4715 #endif
4716 
4717  /* Validity Constraint: Notation Attributes */
4718  if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4719  xmlEnumerationPtr tree = attrDecl->tree;
4720  xmlNotationPtr nota;
4721 
4722  /* First check that the given NOTATION was declared */
4723  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4724  if (nota == NULL)
4725  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4726 
4727  if (nota == NULL) {
4728  if (ns->prefix != NULL) {
4729  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4730  "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4731  value, ns->prefix, elem->name);
4732  } else {
4733  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4734  "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4735  value, elem->name, NULL);
4736  }
4737  ret = 0;
4738  }
4739 
4740  /* Second, verify that it's among the list */
4741  while (tree != NULL) {
4742  if (xmlStrEqual(tree->name, value)) break;
4743  tree = tree->next;
4744  }
4745  if (tree == NULL) {
4746  if (ns->prefix != NULL) {
4747  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4748 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4749  value, ns->prefix, elem->name);
4750  } else {
4751  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4752 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4753  value, elem->name, NULL);
4754  }
4755  ret = 0;
4756  }
4757  }
4758 
4759  /* Validity Constraint: Enumeration */
4760  if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4761  xmlEnumerationPtr tree = attrDecl->tree;
4762  while (tree != NULL) {
4763  if (xmlStrEqual(tree->name, value)) break;
4764  tree = tree->next;
4765  }
4766  if (tree == NULL) {
4767  if (ns->prefix != NULL) {
4768  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4769 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4770  value, ns->prefix, elem->name);
4771  } else {
4772  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4773 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4774  value, elem->name, NULL);
4775  }
4776  ret = 0;
4777  }
4778  }
4779 
4780  /* Fixed Attribute Default */
4781  if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4782  (!xmlStrEqual(attrDecl->defaultValue, value))) {
4783  if (ns->prefix != NULL) {
4784  xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4785  "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4786  ns->prefix, elem->name, attrDecl->defaultValue);
4787  } else {
4788  xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4789  "Value for attribute xmlns of %s must be \"%s\"\n",
4790  elem->name, attrDecl->defaultValue, NULL);
4791  }
4792  ret = 0;
4793  }
4794 
4795  /* Extra check for the attribute value */
4796  if (ns->prefix != NULL) {
4797  ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4798  attrDecl->atype, value);
4799  } else {
4800  ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4801  attrDecl->atype, value);
4802  }
4803 
4804  return(ret);
4805 }
4806 
4807 #ifndef LIBXML_REGEXP_ENABLED
4808 
4818 static xmlNodePtr
4819 xmlValidateSkipIgnorable(xmlNodePtr child) {
4820  while (child != NULL) {
4821  switch (child->type) {
4822  /* These things are ignored (skipped) during validation. */
4823  case XML_PI_NODE:
4824  case XML_COMMENT_NODE:
4825  case XML_XINCLUDE_START:
4826  case XML_XINCLUDE_END:
4827  child = child->next;
4828  break;
4829  case XML_TEXT_NODE:
4830  if (xmlIsBlankNode(child))
4831  child = child->next;
4832  else
4833  return(child);
4834  break;
4835  /* keep current node */
4836  default:
4837  return(child);
4838  }
4839  }
4840  return(child);
4841 }
4842 
4854 static int
4855 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4856  int ret = -1;
4857  int determinist = 1;
4858 
4859  NODE = xmlValidateSkipIgnorable(NODE);
4860  if ((NODE == NULL) && (CONT == NULL))
4861  return(1);
4862  if ((NODE == NULL) &&
4863  ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4864  (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4865  return(1);
4866  }
4867  if (CONT == NULL) return(-1);
4868  if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4869  return(-2);
4870 
4871  /*
4872  * We arrive here when more states need to be examined
4873  */
4874 cont:
4875 
4876  /*
4877  * We just recovered from a rollback generated by a possible
4878  * epsilon transition, go directly to the analysis phase
4879  */
4880  if (STATE == ROLLBACK_PARENT) {
4881  DEBUG_VALID_MSG("restored parent branch");
4882  DEBUG_VALID_STATE(NODE, CONT)
4883  ret = 1;
4884  goto analyze;
4885  }
4886 
4887  DEBUG_VALID_STATE(NODE, CONT)
4888  /*
4889  * we may have to save a backup state here. This is the equivalent
4890  * of handling epsilon transition in NFAs.
4891  */
4892  if ((CONT != NULL) &&
4893  ((CONT->parent == NULL) ||
4894  (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4895  ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4896  (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4897  ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4898  DEBUG_VALID_MSG("saving parent branch");
4899  if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4900  return(0);
4901  }
4902 
4903 
4904  /*
4905  * Check first if the content matches
4906  */
4907  switch (CONT->type) {
4909  if (NODE == NULL) {
4910  DEBUG_VALID_MSG("pcdata failed no node");
4911  ret = 0;
4912  break;
4913  }
4914  if (NODE->type == XML_TEXT_NODE) {
4915  DEBUG_VALID_MSG("pcdata found, skip to next");
4916  /*
4917  * go to next element in the content model
4918  * skipping ignorable elems
4919  */
4920  do {
4921  NODE = NODE->next;
4922  NODE = xmlValidateSkipIgnorable(NODE);
4923  if ((NODE != NULL) &&
4924  (NODE->type == XML_ENTITY_REF_NODE))
4925  return(-2);
4926  } while ((NODE != NULL) &&
4927  ((NODE->type != XML_ELEMENT_NODE) &&
4928  (NODE->type != XML_TEXT_NODE) &&
4929  (NODE->type != XML_CDATA_SECTION_NODE)));
4930  ret = 1;
4931  break;
4932  } else {
4933  DEBUG_VALID_MSG("pcdata failed");
4934  ret = 0;
4935  break;
4936  }
4937  break;
4939  if (NODE == NULL) {
4940  DEBUG_VALID_MSG("element failed no node");
4941  ret = 0;
4942  break;
4943  }
4944  ret = ((NODE->type == XML_ELEMENT_NODE) &&
4945  (xmlStrEqual(NODE->name, CONT->name)));
4946  if (ret == 1) {
4947  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4948  ret = (CONT->prefix == NULL);
4949  } else if (CONT->prefix == NULL) {
4950  ret = 0;
4951  } else {
4952  ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4953  }
4954  }
4955  if (ret == 1) {
4956  DEBUG_VALID_MSG("element found, skip to next");
4957  /*
4958  * go to next element in the content model
4959  * skipping ignorable elems
4960  */
4961  do {
4962  NODE = NODE->next;
4963  NODE = xmlValidateSkipIgnorable(NODE);
4964  if ((NODE != NULL) &&
4965  (NODE->type == XML_ENTITY_REF_NODE))
4966  return(-2);
4967  } while ((NODE != NULL) &&
4968  ((NODE->type != XML_ELEMENT_NODE) &&
4969  (NODE->type != XML_TEXT_NODE) &&
4970  (NODE->type != XML_CDATA_SECTION_NODE)));
4971  } else {
4972  DEBUG_VALID_MSG("element failed");
4973  ret = 0;
4974  break;
4975  }
4976  break;
4978  /*
4979  * Small optimization.
4980  */
4981  if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4982  if ((NODE == NULL) ||
4983  (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4984  DEPTH++;
4985  CONT = CONT->c2;
4986  goto cont;
4987  }
4988  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4989  ret = (CONT->c1->prefix == NULL);
4990  } else if (CONT->c1->prefix == NULL) {
4991  ret = 0;
4992  } else {
4993  ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4994  }
4995  if (ret == 0) {
4996  DEPTH++;
4997  CONT = CONT->c2;
4998  goto cont;
4999  }
5000  }
5001 
5002  /*
5003  * save the second branch 'or' branch
5004  */
5005  DEBUG_VALID_MSG("saving 'or' branch");
5006  if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
5007  OCCURS, ROLLBACK_OR) < 0)
5008  return(-1);
5009  DEPTH++;
5010  CONT = CONT->c1;
5011  goto cont;
5013  /*
5014  * Small optimization.
5015  */
5016  if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
5017  ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
5018  (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
5019  if ((NODE == NULL) ||
5020  (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5021  DEPTH++;
5022  CONT = CONT->c2;
5023  goto cont;
5024  }
5025  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5026  ret = (CONT->c1->prefix == NULL);
5027  } else if (CONT->c1->prefix == NULL) {
5028  ret = 0;
5029  } else {
5030  ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5031  }
5032  if (ret == 0) {
5033  DEPTH++;
5034  CONT = CONT->c2;
5035  goto cont;
5036  }
5037  }
5038  DEPTH++;
5039  CONT = CONT->c1;
5040  goto cont;
5041  }
5042 
5043  /*
5044  * At this point handle going up in the tree
5045  */
5046  if (ret == -1) {
5047  DEBUG_VALID_MSG("error found returning");
5048  return(ret);
5049  }
5050 analyze:
5051  while (CONT != NULL) {
5052  /*
5053  * First do the analysis depending on the occurrence model at
5054  * this level.
5055  */
5056  if (ret == 0) {
5057  switch (CONT->ocur) {
5058  xmlNodePtr cur;
5059 
5061  cur = ctxt->vstate->node;
5062  DEBUG_VALID_MSG("Once branch failed, rollback");
5063  if (vstateVPop(ctxt) < 0 ) {
5064  DEBUG_VALID_MSG("exhaustion, failed");
5065  return(0);
5066  }
5067  if (cur != ctxt->vstate->node)
5068  determinist = -3;
5069  goto cont;
5071  if (OCCURRENCE == 0) {
5072  cur = ctxt->vstate->node;
5073  DEBUG_VALID_MSG("Plus branch failed, rollback");
5074  if (vstateVPop(ctxt) < 0 ) {
5075  DEBUG_VALID_MSG("exhaustion, failed");
5076  return(0);
5077  }
5078  if (cur != ctxt->vstate->node)
5079  determinist = -3;
5080  goto cont;
5081  }
5082  DEBUG_VALID_MSG("Plus branch found");
5083  ret = 1;
5084  break;
5086 #ifdef DEBUG_VALID_ALGO
5087  if (OCCURRENCE == 0) {
5088  DEBUG_VALID_MSG("Mult branch failed");
5089  } else {
5090  DEBUG_VALID_MSG("Mult branch found");
5091  }
5092 #endif
5093  ret = 1;
5094  break;
5096  DEBUG_VALID_MSG("Option branch failed");
5097  ret = 1;
5098  break;
5099  }
5100  } else {
5101  switch (CONT->ocur) {
5103  DEBUG_VALID_MSG("Option branch succeeded");
5104  ret = 1;
5105  break;
5107  DEBUG_VALID_MSG("Once branch succeeded");
5108  ret = 1;
5109  break;
5111  if (STATE == ROLLBACK_PARENT) {
5112  DEBUG_VALID_MSG("Plus branch rollback");
5113  ret = 1;
5114  break;
5115  }
5116  if (NODE == NULL) {
5117  DEBUG_VALID_MSG("Plus branch exhausted");
5118  ret = 1;
5119  break;
5120  }
5121  DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5122  SET_OCCURRENCE;
5123  goto cont;
5125  if (STATE == ROLLBACK_PARENT) {
5126  DEBUG_VALID_MSG("Mult branch rollback");
5127  ret = 1;
5128  break;
5129  }
5130  if (NODE == NULL) {
5131  DEBUG_VALID_MSG("Mult branch exhausted");
5132  ret = 1;
5133  break;
5134  }
5135  DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5136  /* SET_OCCURRENCE; */
5137  goto cont;
5138  }
5139  }
5140  STATE = 0;
5141 
5142  /*
5143  * Then act accordingly at the parent level
5144  */
5145  RESET_OCCURRENCE;
5146  if (CONT->parent == NULL)
5147  break;
5148 
5149  switch (CONT->parent->type) {
5151  DEBUG_VALID_MSG("Error: parent pcdata");
5152  return(-1);
5154  DEBUG_VALID_MSG("Error: parent element");
5155  return(-1);
5157  if (ret == 1) {
5158  DEBUG_VALID_MSG("Or succeeded");
5159  CONT = CONT->parent;
5160  DEPTH--;
5161  } else {
5162  DEBUG_VALID_MSG("Or failed");
5163  CONT = CONT->parent;
5164  DEPTH--;
5165  }
5166  break;
5168  if (ret == 0) {
5169  DEBUG_VALID_MSG("Sequence failed");
5170  CONT = CONT->parent;
5171  DEPTH--;
5172  } else if (CONT == CONT->parent->c1) {
5173  DEBUG_VALID_MSG("Sequence testing 2nd branch");
5174  CONT = CONT->parent->c2;
5175  goto cont;
5176  } else {
5177  DEBUG_VALID_MSG("Sequence succeeded");
5178  CONT = CONT->parent;
5179  DEPTH--;
5180  }
5181  }
5182  }
5183  if (NODE != NULL) {
5184  xmlNodePtr cur;
5185 
5186  cur = ctxt->vstate->node;
5187  DEBUG_VALID_MSG("Failed, remaining input, rollback");
5188  if (vstateVPop(ctxt) < 0 ) {
5189  DEBUG_VALID_MSG("exhaustion, failed");
5190  return(0);
5191  }
5192  if (cur != ctxt->vstate->node)
5193  determinist = -3;
5194  goto cont;
5195  }
5196  if (ret == 0) {
5197  xmlNodePtr cur;
5198 
5199  cur = ctxt->vstate->node;
5200  DEBUG_VALID_MSG("Failure, rollback");
5201  if (vstateVPop(ctxt) < 0 ) {
5202  DEBUG_VALID_MSG("exhaustion, failed");
5203  return(0);
5204  }
5205  if (cur != ctxt->vstate->node)
5206  determinist = -3;
5207  goto cont;
5208  }
5209  return(determinist);
5210 }
5211 #endif
5212 
5223 static void
5224 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5225  xmlNodePtr cur;
5226  int len;
5227 
5228  if (node == NULL) return;
5229  if (glob) strcat(buf, "(");
5230  cur = node;
5231  while (cur != NULL) {
5232  len = strlen(buf);
5233  if (size - len < 50) {
5234  if ((size - len > 4) && (buf[len - 1] != '.'))
5235  strcat(buf, " ...");
5236  return;
5237  }
5238  switch (cur->type) {
5239  case XML_ELEMENT_NODE:
5240  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5241  if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5242  if ((size - len > 4) && (buf[len - 1] != '.'))
5243  strcat(buf, " ...");
5244  return;
5245  }
5246  strcat(buf, (char *) cur->ns->prefix);
5247  strcat(buf, ":");
5248  }
5249  if (size - len < xmlStrlen(cur->name) + 10) {
5250  if ((size - len > 4) && (buf[len - 1] != '.'))
5251  strcat(buf, " ...");
5252  return;
5253  }
5254  strcat(buf, (char *) cur->name);
5255  if (cur->next != NULL)
5256  strcat(buf, " ");
5257  break;
5258  case XML_TEXT_NODE:
5259  if (xmlIsBlankNode(cur))
5260  break;
5261  /* Falls through. */
5263  case XML_ENTITY_REF_NODE:
5264  strcat(buf, "CDATA");
5265  if (cur->next != NULL)
5266  strcat(buf, " ");
5267  break;
5268  case XML_ATTRIBUTE_NODE:
5269  case XML_DOCUMENT_NODE:
5270 #ifdef LIBXML_DOCB_ENABLED
5271  case XML_DOCB_DOCUMENT_NODE:
5272 #endif
5276  case XML_NOTATION_NODE:
5277  case XML_NAMESPACE_DECL:
5278  strcat(buf, "???");
5279  if (cur->next != NULL)
5280  strcat(buf, " ");
5281  break;
5282