ReactOS  0.4.14-dev-317-g96040ec
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
1103  xmlDictPtr dict = NULL;
1104 
1105  if (doc != NULL)
1106  dict = doc->dict;
1107 
1108  while (cur != NULL) {
1109  next = cur->c2;
1110  switch (cur->type) {
1115  break;
1116  default:
1117  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1118  "Internal: ELEMENT content corrupted invalid type\n",
1119  NULL);
1120  return;
1121  }
1122  if (cur->c1 != NULL) xmlFreeDocElementContent(doc, cur->c1);
1123  if (dict) {
1124  if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1125  xmlFree((xmlChar *) cur->name);
1126  if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1127  xmlFree((xmlChar *) cur->prefix);
1128  } else {
1129  if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1130  if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1131  }
1132  xmlFree(cur);
1133  cur = next;
1134  }
1135 }
1136 
1144 void
1147 }
1148 
1149 #ifdef LIBXML_OUTPUT_ENABLED
1150 
1158 static void
1159 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
1160  if (content == NULL) return;
1161 
1162  if (glob) xmlBufferWriteChar(buf, "(");
1163  switch (content->type) {
1165  xmlBufferWriteChar(buf, "#PCDATA");
1166  break;
1168  if (content->prefix != NULL) {
1169  xmlBufferWriteCHAR(buf, content->prefix);
1170  xmlBufferWriteChar(buf, ":");
1171  }
1172  xmlBufferWriteCHAR(buf, content->name);
1173  break;
1175  if ((content->c1 != NULL) &&
1176  ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1177  (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
1178  xmlDumpElementContent(buf, content->c1, 1);
1179  else
1180  xmlDumpElementContent(buf, content->c1, 0);
1181  xmlBufferWriteChar(buf, " , ");
1182  if ((content->c2 != NULL) &&
1183  ((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1184  ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) &&
1185  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
1186  xmlDumpElementContent(buf, content->c2, 1);
1187  else
1188  xmlDumpElementContent(buf, content->c2, 0);
1189  break;
1191  if ((content->c1 != NULL) &&
1192  ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1193  (content->c1->type == XML_ELEMENT_CONTENT_SEQ)))
1194  xmlDumpElementContent(buf, content->c1, 1);
1195  else
1196  xmlDumpElementContent(buf, content->c1, 0);
1197  xmlBufferWriteChar(buf, " | ");
1198  if ((content->c2 != NULL) &&
1199  ((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1200  ((content->c2->type == XML_ELEMENT_CONTENT_OR) &&
1201  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE))))
1202  xmlDumpElementContent(buf, content->c2, 1);
1203  else
1204  xmlDumpElementContent(buf, content->c2, 0);
1205  break;
1206  default:
1207  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1208  "Internal: ELEMENT content corrupted invalid type\n",
1209  NULL);
1210  }
1211  if (glob)
1212  xmlBufferWriteChar(buf, ")");
1213  switch (content->ocur) {
1215  break;
1217  xmlBufferWriteChar(buf, "?");
1218  break;
1220  xmlBufferWriteChar(buf, "*");
1221  break;
1223  xmlBufferWriteChar(buf, "+");
1224  break;
1225  }
1226 }
1227 
1236 void
1237 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1239  int englob ATTRIBUTE_UNUSED) {
1240 }
1241 #endif /* LIBXML_OUTPUT_ENABLED */
1242 
1253 void
1255  int len;
1256 
1257  if (content == NULL) return;
1258  len = strlen(buf);
1259  if (size - len < 50) {
1260  if ((size - len > 4) && (buf[len - 1] != '.'))
1261  strcat(buf, " ...");
1262  return;
1263  }
1264  if (englob) strcat(buf, "(");
1265  switch (content->type) {
1267  strcat(buf, "#PCDATA");
1268  break;
1270  int qnameLen = xmlStrlen(content->name);
1271 
1272  if (content->prefix != NULL)
1273  qnameLen += xmlStrlen(content->prefix) + 1;
1274  if (size - len < qnameLen + 10) {
1275  strcat(buf, " ...");
1276  return;
1277  }
1278  if (content->prefix != NULL) {
1279  strcat(buf, (char *) content->prefix);
1280  strcat(buf, ":");
1281  }
1282  if (content->name != NULL)
1283  strcat(buf, (char *) content->name);
1284  break;
1285  }
1287  if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1288  (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1290  else
1292  len = strlen(buf);
1293  if (size - len < 50) {
1294  if ((size - len > 4) && (buf[len - 1] != '.'))
1295  strcat(buf, " ...");
1296  return;
1297  }
1298  strcat(buf, " , ");
1299  if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1300  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1301  (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1303  else
1305  break;
1307  if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1308  (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1310  else
1312  len = strlen(buf);
1313  if (size - len < 50) {
1314  if ((size - len > 4) && (buf[len - 1] != '.'))
1315  strcat(buf, " ...");
1316  return;
1317  }
1318  strcat(buf, " | ");
1319  if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1320  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1321  (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1323  else
1325  break;
1326  }
1327  if (size - strlen(buf) <= 2) return;
1328  if (englob)
1329  strcat(buf, ")");
1330  switch (content->ocur) {
1332  break;
1334  strcat(buf, "?");
1335  break;
1337  strcat(buf, "*");
1338  break;
1340  strcat(buf, "+");
1341  break;
1342  }
1343 }
1344 
1345 /****************************************************************
1346  * *
1347  * Registration of DTD declarations *
1348  * *
1349  ****************************************************************/
1350 
1357 static void
1359  if (elem == NULL) return;
1361  xmlFreeDocElementContent(elem->doc, elem->content);
1362  if (elem->name != NULL)
1363  xmlFree((xmlChar *) elem->name);
1364  if (elem->prefix != NULL)
1365  xmlFree((xmlChar *) elem->prefix);
1366 #ifdef LIBXML_REGEXP_ENABLED
1367  if (elem->contModel != NULL)
1368  xmlRegFreeRegexp(elem->contModel);
1369 #endif
1370  xmlFree(elem);
1371 }
1372 
1373 
1388  xmlDtdPtr dtd, const xmlChar *name,
1393  xmlAttributePtr oldAttributes = NULL;
1394  xmlChar *ns, *uqname;
1395 
1396  if (dtd == NULL) {
1397  return(NULL);
1398  }
1399  if (name == NULL) {
1400  return(NULL);
1401  }
1402 
1403  switch (type) {
1405  if (content != NULL) {
1406  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1407  "xmlAddElementDecl: content != NULL for EMPTY\n",
1408  NULL);
1409  return(NULL);
1410  }
1411  break;
1412  case XML_ELEMENT_TYPE_ANY:
1413  if (content != NULL) {
1414  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1415  "xmlAddElementDecl: content != NULL for ANY\n",
1416  NULL);
1417  return(NULL);
1418  }
1419  break;
1421  if (content == NULL) {
1422  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1423  "xmlAddElementDecl: content == NULL for MIXED\n",
1424  NULL);
1425  return(NULL);
1426  }
1427  break;
1429  if (content == NULL) {
1430  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1431  "xmlAddElementDecl: content == NULL for ELEMENT\n",
1432  NULL);
1433  return(NULL);
1434  }
1435  break;
1436  default:
1437  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1438  "Internal: ELEMENT decl corrupted invalid type\n",
1439  NULL);
1440  return(NULL);
1441  }
1442 
1443  /*
1444  * check if name is a QName
1445  */
1446  uqname = xmlSplitQName2(name, &ns);
1447  if (uqname != NULL)
1448  name = uqname;
1449 
1450  /*
1451  * Create the Element table if needed.
1452  */
1454  if (table == NULL) {
1455  xmlDictPtr dict = NULL;
1456 
1457  if (dtd->doc != NULL)
1458  dict = dtd->doc->dict;
1459  table = xmlHashCreateDict(0, dict);
1460  dtd->elements = (void *) table;
1461  }
1462  if (table == NULL) {
1463  xmlVErrMemory(ctxt,
1464  "xmlAddElementDecl: Table creation failed!\n");
1465  if (uqname != NULL)
1466  xmlFree(uqname);
1467  if (ns != NULL)
1468  xmlFree(ns);
1469  return(NULL);
1470  }
1471 
1472  /*
1473  * lookup old attributes inserted on an undefined element in the
1474  * internal subset.
1475  */
1476  if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1477  ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1478  if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1479  oldAttributes = ret->attributes;
1480  ret->attributes = NULL;
1481  xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1483  }
1484  }
1485 
1486  /*
1487  * The element may already be present if one of its attribute
1488  * was registered first
1489  */
1491  if (ret != NULL) {
1492  if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1493 #ifdef LIBXML_VALID_ENABLED
1494  /*
1495  * The element is already defined in this DTD.
1496  */
1497  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1498  "Redefinition of element %s\n",
1499  name, NULL, NULL);
1500 #endif /* LIBXML_VALID_ENABLED */
1501  if (uqname != NULL)
1502  xmlFree(uqname);
1503  if (ns != NULL)
1504  xmlFree(ns);
1505  return(NULL);
1506  }
1507  if (ns != NULL) {
1508  xmlFree(ns);
1509  ns = NULL;
1510  }
1511  } else {
1512  ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1513  if (ret == NULL) {
1514  xmlVErrMemory(ctxt, "malloc failed");
1515  if (uqname != NULL)
1516  xmlFree(uqname);
1517  if (ns != NULL)
1518  xmlFree(ns);
1519  return(NULL);
1520  }
1521  memset(ret, 0, sizeof(xmlElement));
1522  ret->type = XML_ELEMENT_DECL;
1523 
1524  /*
1525  * fill the structure.
1526  */
1527  ret->name = xmlStrdup(name);
1528  if (ret->name == NULL) {
1529  xmlVErrMemory(ctxt, "malloc failed");
1530  if (uqname != NULL)
1531  xmlFree(uqname);
1532  if (ns != NULL)
1533  xmlFree(ns);
1534  xmlFree(ret);
1535  return(NULL);
1536  }
1537  ret->prefix = ns;
1538 
1539  /*
1540  * Validity Check:
1541  * Insertion must not fail
1542  */
1543  if (xmlHashAddEntry2(table, name, ns, ret)) {
1544 #ifdef LIBXML_VALID_ENABLED
1545  /*
1546  * The element is already defined in this DTD.
1547  */
1548  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1549  "Redefinition of element %s\n",
1550  name, NULL, NULL);
1551 #endif /* LIBXML_VALID_ENABLED */
1553  if (uqname != NULL)
1554  xmlFree(uqname);
1555  return(NULL);
1556  }
1557  /*
1558  * For new element, may have attributes from earlier
1559  * definition in internal subset
1560  */
1561  ret->attributes = oldAttributes;
1562  }
1563 
1564  /*
1565  * Finish to fill the structure.
1566  */
1567  ret->etype = type;
1568  /*
1569  * Avoid a stupid copy when called by the parser
1570  * and flag it by setting a special parent value
1571  * so the parser doesn't unallocate it.
1572  */
1573  if ((ctxt != NULL) &&
1574  ((ctxt->finishDtd == XML_CTXT_FINISH_DTD_0) ||
1575  (ctxt->finishDtd == XML_CTXT_FINISH_DTD_1))) {
1576  ret->content = content;
1577  if (content != NULL)
1578  content->parent = (xmlElementContentPtr) 1;
1579  } else {
1580  ret->content = xmlCopyDocElementContent(dtd->doc, content);
1581  }
1582 
1583  /*
1584  * Link it to the DTD
1585  */
1586  ret->parent = dtd;
1587  ret->doc = dtd->doc;
1588  if (dtd->last == NULL) {
1589  dtd->children = dtd->last = (xmlNodePtr) ret;
1590  } else {
1591  dtd->last->next = (xmlNodePtr) ret;
1592  ret->prev = dtd->last;
1593  dtd->last = (xmlNodePtr) ret;
1594  }
1595  if (uqname != NULL)
1596  xmlFree(uqname);
1597  return(ret);
1598 }
1599 
1600 static void
1603 }
1604 
1611 void
1614 }
1615 
1616 #ifdef LIBXML_TREE_ENABLED
1617 
1625 static void *
1626 xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1627  xmlElementPtr elem = (xmlElementPtr) payload;
1628  xmlElementPtr cur;
1629 
1630  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1631  if (cur == NULL) {
1632  xmlVErrMemory(NULL, "malloc failed");
1633  return(NULL);
1634  }
1635  memset(cur, 0, sizeof(xmlElement));
1636  cur->type = XML_ELEMENT_DECL;
1637  cur->etype = elem->etype;
1638  if (elem->name != NULL)
1639  cur->name = xmlStrdup(elem->name);
1640  else
1641  cur->name = NULL;
1642  if (elem->prefix != NULL)
1643  cur->prefix = xmlStrdup(elem->prefix);
1644  else
1645  cur->prefix = NULL;
1646  cur->content = xmlCopyElementContent(elem->content);
1647  /* TODO : rebuild the attribute list on the copy */
1648  cur->attributes = NULL;
1649  return(cur);
1650 }
1651 
1661 xmlCopyElementTable(xmlElementTablePtr table) {
1662  return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1663 }
1664 #endif /* LIBXML_TREE_ENABLED */
1665 
1666 #ifdef LIBXML_OUTPUT_ENABLED
1667 
1675 void
1676 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1677  if ((buf == NULL) || (elem == NULL))
1678  return;
1679  switch (elem->etype) {
1681  xmlBufferWriteChar(buf, "<!ELEMENT ");
1682  if (elem->prefix != NULL) {
1683  xmlBufferWriteCHAR(buf, elem->prefix);
1684  xmlBufferWriteChar(buf, ":");
1685  }
1686  xmlBufferWriteCHAR(buf, elem->name);
1687  xmlBufferWriteChar(buf, " EMPTY>\n");
1688  break;
1689  case XML_ELEMENT_TYPE_ANY:
1690  xmlBufferWriteChar(buf, "<!ELEMENT ");
1691  if (elem->prefix != NULL) {
1692  xmlBufferWriteCHAR(buf, elem->prefix);
1693  xmlBufferWriteChar(buf, ":");
1694  }
1695  xmlBufferWriteCHAR(buf, elem->name);
1696  xmlBufferWriteChar(buf, " ANY>\n");
1697  break;
1699  xmlBufferWriteChar(buf, "<!ELEMENT ");
1700  if (elem->prefix != NULL) {
1701  xmlBufferWriteCHAR(buf, elem->prefix);
1702  xmlBufferWriteChar(buf, ":");
1703  }
1704  xmlBufferWriteCHAR(buf, elem->name);
1705  xmlBufferWriteChar(buf, " ");
1706  xmlDumpElementContent(buf, elem->content, 1);
1707  xmlBufferWriteChar(buf, ">\n");
1708  break;
1710  xmlBufferWriteChar(buf, "<!ELEMENT ");
1711  if (elem->prefix != NULL) {
1712  xmlBufferWriteCHAR(buf, elem->prefix);
1713  xmlBufferWriteChar(buf, ":");
1714  }
1715  xmlBufferWriteCHAR(buf, elem->name);
1716  xmlBufferWriteChar(buf, " ");
1717  xmlDumpElementContent(buf, elem->content, 1);
1718  xmlBufferWriteChar(buf, ">\n");
1719  break;
1720  default:
1721  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1722  "Internal: ELEMENT struct corrupted invalid type\n",
1723  NULL);
1724  }
1725 }
1726 
1735 static void
1736 xmlDumpElementDeclScan(void *elem, void *buf,
1737  const xmlChar *name ATTRIBUTE_UNUSED) {
1738  xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1739 }
1740 
1748 void
1749 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1750  if ((buf == NULL) || (table == NULL))
1751  return;
1752  xmlHashScan(table, xmlDumpElementDeclScan, buf);
1753 }
1754 #endif /* LIBXML_OUTPUT_ENABLED */
1755 
1768 
1770  if (ret == NULL) {
1771  xmlVErrMemory(NULL, "malloc failed");
1772  return(NULL);
1773  }
1774  memset(ret, 0, sizeof(xmlEnumeration));
1775 
1776  if (name != NULL)
1777  ret->name = xmlStrdup(name);
1778  return(ret);
1779 }
1780 
1787 void
1789  if (cur == NULL) return;
1790 
1791  if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1792 
1793  if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1794  xmlFree(cur);
1795 }
1796 
1797 #ifdef LIBXML_TREE_ENABLED
1798 
1808 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1810 
1811  if (cur == NULL) return(NULL);
1812  ret = xmlCreateEnumeration((xmlChar *) cur->name);
1813  if (ret == NULL) return(NULL);
1814 
1815  if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1816  else ret->next = NULL;
1817 
1818  return(ret);
1819 }
1820 #endif /* LIBXML_TREE_ENABLED */
1821 
1822 #ifdef LIBXML_OUTPUT_ENABLED
1823 
1830 static void
1831 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1832  if ((buf == NULL) || (cur == NULL))
1833  return;
1834 
1835  xmlBufferWriteCHAR(buf, cur->name);
1836  if (cur->next == NULL)
1837  xmlBufferWriteChar(buf, ")");
1838  else {
1839  xmlBufferWriteChar(buf, " | ");
1840  xmlDumpEnumeration(buf, cur->next);
1841  }
1842 }
1843 #endif /* LIBXML_OUTPUT_ENABLED */
1844 
1845 #ifdef LIBXML_VALID_ENABLED
1846 
1857 static int
1858 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1859  xmlAttributePtr cur;
1860  int ret = 0;
1861 
1862  if (elem == NULL) return(0);
1863  cur = elem->attributes;
1864  while (cur != NULL) {
1865  if (cur->atype == XML_ATTRIBUTE_ID) {
1866  ret ++;
1867  if ((ret > 1) && (err))
1868  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1869  "Element %s has too many ID attributes defined : %s\n",
1870  elem->name, cur->name, NULL);
1871  }
1872  cur = cur->nexth;
1873  }
1874  return(ret);
1875 }
1876 #endif /* LIBXML_VALID_ENABLED */
1877 
1884 static void
1886  xmlDictPtr dict;
1887 
1888  if (attr == NULL) return;
1889  if (attr->doc != NULL)
1890  dict = attr->doc->dict;
1891  else
1892  dict = NULL;
1894  if (attr->tree != NULL)
1895  xmlFreeEnumeration(attr->tree);
1896  if (dict) {
1897  if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1898  xmlFree((xmlChar *) attr->elem);
1899  if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1900  xmlFree((xmlChar *) attr->name);
1901  if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1902  xmlFree((xmlChar *) attr->prefix);
1903  if ((attr->defaultValue != NULL) &&
1904  (!xmlDictOwns(dict, attr->defaultValue)))
1905  xmlFree((xmlChar *) attr->defaultValue);
1906  } else {
1907  if (attr->elem != NULL)
1908  xmlFree((xmlChar *) attr->elem);
1909  if (attr->name != NULL)
1910  xmlFree((xmlChar *) attr->name);
1911  if (attr->defaultValue != NULL)
1912  xmlFree((xmlChar *) attr->defaultValue);
1913  if (attr->prefix != NULL)
1914  xmlFree((xmlChar *) attr->prefix);
1915  }
1916  xmlFree(attr);
1917 }
1918 
1919 
1939  xmlDtdPtr dtd, const xmlChar *elem,
1940  const xmlChar *name, const xmlChar *ns,
1942  const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1945  xmlElementPtr elemDef;
1946  xmlDictPtr dict = NULL;
1947 
1948  if (dtd == NULL) {
1950  return(NULL);
1951  }
1952  if (name == NULL) {
1954  return(NULL);
1955  }
1956  if (elem == NULL) {
1958  return(NULL);
1959  }
1960  if (dtd->doc != NULL)
1961  dict = dtd->doc->dict;
1962 
1963 #ifdef LIBXML_VALID_ENABLED
1964  /*
1965  * Check the type and possibly the default value.
1966  */
1967  switch (type) {
1968  case XML_ATTRIBUTE_CDATA:
1969  break;
1970  case XML_ATTRIBUTE_ID:
1971  break;
1972  case XML_ATTRIBUTE_IDREF:
1973  break;
1974  case XML_ATTRIBUTE_IDREFS:
1975  break;
1976  case XML_ATTRIBUTE_ENTITY:
1977  break;
1979  break;
1980  case XML_ATTRIBUTE_NMTOKEN:
1981  break;
1983  break;
1985  break;
1987  break;
1988  default:
1989  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1990  "Internal: ATTRIBUTE struct corrupted invalid type\n",
1991  NULL);
1993  return(NULL);
1994  }
1995  if ((defaultValue != NULL) &&
1996  (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
1997  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
1998  "Attribute %s of %s: invalid default value\n",
1999  elem, name, defaultValue);
2000  defaultValue = NULL;
2001  if (ctxt != NULL)
2002  ctxt->valid = 0;
2003  }
2004 #endif /* LIBXML_VALID_ENABLED */
2005 
2006  /*
2007  * Check first that an attribute defined in the external subset wasn't
2008  * already defined in the internal subset
2009  */
2010  if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2011  (dtd->doc->intSubset != NULL) &&
2012  (dtd->doc->intSubset->attributes != NULL)) {
2013  ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2014  if (ret != NULL) {
2016  return(NULL);
2017  }
2018  }
2019 
2020  /*
2021  * Create the Attribute table if needed.
2022  */
2024  if (table == NULL) {
2025  table = xmlHashCreateDict(0, dict);
2026  dtd->attributes = (void *) table;
2027  }
2028  if (table == NULL) {
2029  xmlVErrMemory(ctxt,
2030  "xmlAddAttributeDecl: Table creation failed!\n");
2032  return(NULL);
2033  }
2034 
2035 
2037  if (ret == NULL) {
2038  xmlVErrMemory(ctxt, "malloc failed");
2040  return(NULL);
2041  }
2042  memset(ret, 0, sizeof(xmlAttribute));
2043  ret->type = XML_ATTRIBUTE_DECL;
2044 
2045  /*
2046  * fill the structure.
2047  */
2048  ret->atype = type;
2049  /*
2050  * doc must be set before possible error causes call
2051  * to xmlFreeAttribute (because it's used to check on
2052  * dict use)
2053  */
2054  ret->doc = dtd->doc;
2055  if (dict) {
2056  ret->name = xmlDictLookup(dict, name, -1);
2057  ret->prefix = xmlDictLookup(dict, ns, -1);
2058  ret->elem = xmlDictLookup(dict, elem, -1);
2059  } else {
2060  ret->name = xmlStrdup(name);
2061  ret->prefix = xmlStrdup(ns);
2062  ret->elem = xmlStrdup(elem);
2063  }
2064  ret->def = def;
2065  ret->tree = tree;
2066  if (defaultValue != NULL) {
2067  if (dict)
2068  ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2069  else
2070  ret->defaultValue = xmlStrdup(defaultValue);
2071  }
2072 
2073  /*
2074  * Validity Check:
2075  * Search the DTD for previous declarations of the ATTLIST
2076  */
2077  if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2078 #ifdef LIBXML_VALID_ENABLED
2079  /*
2080  * The attribute is already defined in this DTD.
2081  */
2082  xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2083  "Attribute %s of element %s: already defined\n",
2084  name, elem, NULL);
2085 #endif /* LIBXML_VALID_ENABLED */
2087  return(NULL);
2088  }
2089 
2090  /*
2091  * Validity Check:
2092  * Multiple ID per element
2093  */
2094  elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2095  if (elemDef != NULL) {
2096 
2097 #ifdef LIBXML_VALID_ENABLED
2098  if ((type == XML_ATTRIBUTE_ID) &&
2099  (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2100  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2101  "Element %s has too may ID attributes defined : %s\n",
2102  elem, name, NULL);
2103  if (ctxt != NULL)
2104  ctxt->valid = 0;
2105  }
2106 #endif /* LIBXML_VALID_ENABLED */
2107 
2108  /*
2109  * Insert namespace default def first they need to be
2110  * processed first.
2111  */
2112  if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2113  ((ret->prefix != NULL &&
2114  (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2115  ret->nexth = elemDef->attributes;
2116  elemDef->attributes = ret;
2117  } else {
2118  xmlAttributePtr tmp = elemDef->attributes;
2119 
2120  while ((tmp != NULL) &&
2121  ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2122  ((ret->prefix != NULL &&
2123  (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2124  if (tmp->nexth == NULL)
2125  break;
2126  tmp = tmp->nexth;
2127  }
2128  if (tmp != NULL) {
2129  ret->nexth = tmp->nexth;
2130  tmp->nexth = ret;
2131  } else {
2132  ret->nexth = elemDef->attributes;
2133  elemDef->attributes = ret;
2134  }
2135  }
2136  }
2137 
2138  /*
2139  * Link it to the DTD
2140  */
2141  ret->parent = dtd;
2142  if (dtd->last == NULL) {
2143  dtd->children = dtd->last = (xmlNodePtr) ret;
2144  } else {
2145  dtd->last->next = (xmlNodePtr) ret;
2146  ret->prev = dtd->last;
2147  dtd->last = (xmlNodePtr) ret;
2148  }
2149  return(ret);
2150 }
2151 
2152 static void
2155 }
2156 
2163 void
2166 }
2167 
2168 #ifdef LIBXML_TREE_ENABLED
2169 
2177 static void *
2178 xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2179  xmlAttributePtr attr = (xmlAttributePtr) payload;
2180  xmlAttributePtr cur;
2181 
2182  cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
2183  if (cur == NULL) {
2184  xmlVErrMemory(NULL, "malloc failed");
2185  return(NULL);
2186  }
2187  memset(cur, 0, sizeof(xmlAttribute));
2188  cur->type = XML_ATTRIBUTE_DECL;
2189  cur->atype = attr->atype;
2190  cur->def = attr->def;
2191  cur->tree = xmlCopyEnumeration(attr->tree);
2192  if (attr->elem != NULL)
2193  cur->elem = xmlStrdup(attr->elem);
2194  if (attr->name != NULL)
2195  cur->name = xmlStrdup(attr->name);
2196  if (attr->prefix != NULL)
2197  cur->prefix = xmlStrdup(attr->prefix);
2198  if (attr->defaultValue != NULL)
2199  cur->defaultValue = xmlStrdup(attr->defaultValue);
2200  return(cur);
2201 }
2202 
2212 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2213  return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2214 }
2215 #endif /* LIBXML_TREE_ENABLED */
2216 
2217 #ifdef LIBXML_OUTPUT_ENABLED
2218 
2226 void
2227 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2228  if ((buf == NULL) || (attr == NULL))
2229  return;
2230  xmlBufferWriteChar(buf, "<!ATTLIST ");
2231  xmlBufferWriteCHAR(buf, attr->elem);
2232  xmlBufferWriteChar(buf, " ");
2233  if (attr->prefix != NULL) {
2234  xmlBufferWriteCHAR(buf, attr->prefix);
2235  xmlBufferWriteChar(buf, ":");
2236  }
2238  switch (attr->atype) {
2239  case XML_ATTRIBUTE_CDATA:
2240  xmlBufferWriteChar(buf, " CDATA");
2241  break;
2242  case XML_ATTRIBUTE_ID:
2243  xmlBufferWriteChar(buf, " ID");
2244  break;
2245  case XML_ATTRIBUTE_IDREF:
2246  xmlBufferWriteChar(buf, " IDREF");
2247  break;
2248  case XML_ATTRIBUTE_IDREFS:
2249  xmlBufferWriteChar(buf, " IDREFS");
2250  break;
2251  case XML_ATTRIBUTE_ENTITY:
2252  xmlBufferWriteChar(buf, " ENTITY");
2253  break;
2255  xmlBufferWriteChar(buf, " ENTITIES");
2256  break;
2257  case XML_ATTRIBUTE_NMTOKEN:
2258  xmlBufferWriteChar(buf, " NMTOKEN");
2259  break;
2261  xmlBufferWriteChar(buf, " NMTOKENS");
2262  break;
2264  xmlBufferWriteChar(buf, " (");
2265  xmlDumpEnumeration(buf, attr->tree);
2266  break;
2268  xmlBufferWriteChar(buf, " NOTATION (");
2269  xmlDumpEnumeration(buf, attr->tree);
2270  break;
2271  default:
2272  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2273  "Internal: ATTRIBUTE struct corrupted invalid type\n",
2274  NULL);
2275  }
2276  switch (attr->def) {
2277  case XML_ATTRIBUTE_NONE:
2278  break;
2280  xmlBufferWriteChar(buf, " #REQUIRED");
2281  break;
2282  case XML_ATTRIBUTE_IMPLIED:
2283  xmlBufferWriteChar(buf, " #IMPLIED");
2284  break;
2285  case XML_ATTRIBUTE_FIXED:
2286  xmlBufferWriteChar(buf, " #FIXED");
2287  break;
2288  default:
2289  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2290  "Internal: ATTRIBUTE struct corrupted invalid def\n",
2291  NULL);
2292  }
2293  if (attr->defaultValue != NULL) {
2294  xmlBufferWriteChar(buf, " ");
2295  xmlBufferWriteQuotedString(buf, attr->defaultValue);
2296  }
2297  xmlBufferWriteChar(buf, ">\n");
2298 }
2299 
2307 static void
2308 xmlDumpAttributeDeclScan(void *attr, void *buf,
2309  const xmlChar *name ATTRIBUTE_UNUSED) {
2310  xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2311 }
2312 
2320 void
2321 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2322  if ((buf == NULL) || (table == NULL))
2323  return;
2324  xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2325 }
2326 #endif /* LIBXML_OUTPUT_ENABLED */
2327 
2328 /************************************************************************
2329  * *
2330  * NOTATIONs *
2331  * *
2332  ************************************************************************/
2339 static void
2341  if (nota == NULL) return;
2342  if (nota->name != NULL)
2343  xmlFree((xmlChar *) nota->name);
2344  if (nota->PublicID != NULL)
2345  xmlFree((xmlChar *) nota->PublicID);
2346  if (nota->SystemID != NULL)
2347  xmlFree((xmlChar *) nota->SystemID);
2348  xmlFree(nota);
2349 }
2350 
2351 
2366  const xmlChar *name,
2367  const xmlChar *PublicID, const xmlChar *SystemID) {
2370 
2371  if (dtd == NULL) {
2372  return(NULL);
2373  }
2374  if (name == NULL) {
2375  return(NULL);
2376  }
2377  if ((PublicID == NULL) && (SystemID == NULL)) {
2378  return(NULL);
2379  }
2380 
2381  /*
2382  * Create the Notation table if needed.
2383  */
2385  if (table == NULL) {
2386  xmlDictPtr dict = NULL;
2387  if (dtd->doc != NULL)
2388  dict = dtd->doc->dict;
2389 
2390  dtd->notations = table = xmlHashCreateDict(0, dict);
2391  }
2392  if (table == NULL) {
2393  xmlVErrMemory(ctxt,
2394  "xmlAddNotationDecl: Table creation failed!\n");
2395  return(NULL);
2396  }
2397 
2398  ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2399  if (ret == NULL) {
2400  xmlVErrMemory(ctxt, "malloc failed");
2401  return(NULL);
2402  }
2403  memset(ret, 0, sizeof(xmlNotation));
2404 
2405  /*
2406  * fill the structure.
2407  */
2408  ret->name = xmlStrdup(name);
2409  if (SystemID != NULL)
2410  ret->SystemID = xmlStrdup(SystemID);
2411  if (PublicID != NULL)
2412  ret->PublicID = xmlStrdup(PublicID);
2413 
2414  /*
2415  * Validity Check:
2416  * Check the DTD for previous declarations of the ATTLIST
2417  */
2418  if (xmlHashAddEntry(table, name, ret)) {
2419 #ifdef LIBXML_VALID_ENABLED
2420  xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2421  "xmlAddNotationDecl: %s already defined\n",
2422  (const char *) name);
2423 #endif /* LIBXML_VALID_ENABLED */
2425  return(NULL);
2426  }
2427  return(ret);
2428 }
2429 
2430 static void
2433 }
2434 
2441 void
2444 }
2445 
2446 #ifdef LIBXML_TREE_ENABLED
2447 
2455 static void *
2456 xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2457  xmlNotationPtr nota = (xmlNotationPtr) payload;
2458  xmlNotationPtr cur;
2459 
2460  cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2461  if (cur == NULL) {
2462  xmlVErrMemory(NULL, "malloc failed");
2463  return(NULL);
2464  }
2465  if (nota->name != NULL)
2466  cur->name = xmlStrdup(nota->name);
2467  else
2468  cur->name = NULL;
2469  if (nota->PublicID != NULL)
2470  cur->PublicID = xmlStrdup(nota->PublicID);
2471  else
2472  cur->PublicID = NULL;
2473  if (nota->SystemID != NULL)
2474  cur->SystemID = xmlStrdup(nota->SystemID);
2475  else
2476  cur->SystemID = NULL;
2477  return(cur);
2478 }
2479 
2489 xmlCopyNotationTable(xmlNotationTablePtr table) {
2490  return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2491 }
2492 #endif /* LIBXML_TREE_ENABLED */
2493 
2494 #ifdef LIBXML_OUTPUT_ENABLED
2495 
2502 void
2503 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2504  if ((buf == NULL) || (nota == NULL))
2505  return;
2506  xmlBufferWriteChar(buf, "<!NOTATION ");
2507  xmlBufferWriteCHAR(buf, nota->name);
2508  if (nota->PublicID != NULL) {
2509  xmlBufferWriteChar(buf, " PUBLIC ");
2511  if (nota->SystemID != NULL) {
2512  xmlBufferWriteChar(buf, " ");
2514  }
2515  } else {
2516  xmlBufferWriteChar(buf, " SYSTEM ");
2518  }
2519  xmlBufferWriteChar(buf, " >\n");
2520 }
2521 
2529 static void
2530 xmlDumpNotationDeclScan(void *nota, void *buf,
2531  const xmlChar *name ATTRIBUTE_UNUSED) {
2532  xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2533 }
2534 
2542 void
2543 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2544  if ((buf == NULL) || (table == NULL))
2545  return;
2546  xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2547 }
2548 #endif /* LIBXML_OUTPUT_ENABLED */
2549 
2550 /************************************************************************
2551  * *
2552  * IDs *
2553  * *
2554  ************************************************************************/
2562 #define DICT_FREE(str) \
2563  if ((str) && ((!dict) || \
2564  (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2565  xmlFree((char *)(str));
2566 
2573 static void
2575  xmlDictPtr dict = NULL;
2576 
2577  if (id == NULL) return;
2578 
2579  if (id->doc != NULL)
2580  dict = id->doc->dict;
2581 
2582  if (id->value != NULL)
2583  DICT_FREE(id->value)
2584  if (id->name != NULL)
2585  DICT_FREE(id->name)
2586  xmlFree(id);
2587 }
2588 
2589 
2601 xmlIDPtr
2603  xmlAttrPtr attr) {
2604  xmlIDPtr ret;
2606 
2607  if (doc == NULL) {
2608  return(NULL);
2609  }
2610  if (value == NULL) {
2611  return(NULL);
2612  }
2613  if (attr == NULL) {
2614  return(NULL);
2615  }
2616 
2617  /*
2618  * Create the ID table if needed.
2619  */
2620  table = (xmlIDTablePtr) doc->ids;
2621  if (table == NULL) {
2622  doc->ids = table = xmlHashCreateDict(0, doc->dict);
2623  }
2624  if (table == NULL) {
2625  xmlVErrMemory(ctxt,
2626  "xmlAddID: Table creation failed!\n");
2627  return(NULL);
2628  }
2629 
2630  ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2631  if (ret == NULL) {
2632  xmlVErrMemory(ctxt, "malloc failed");
2633  return(NULL);
2634  }
2635 
2636  /*
2637  * fill the structure.
2638  */
2639  ret->value = xmlStrdup(value);
2640  ret->doc = doc;
2641  if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2642  /*
2643  * Operating in streaming mode, attr is gonna disapear
2644  */
2645  if (doc->dict != NULL)
2646  ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2647  else
2648  ret->name = xmlStrdup(attr->name);
2649  ret->attr = NULL;
2650  } else {
2651  ret->attr = attr;
2652  ret->name = NULL;
2653  }
2654  ret->lineno = xmlGetLineNo(attr->parent);
2655 
2656  if (xmlHashAddEntry(table, value, ret) < 0) {
2657 #ifdef LIBXML_VALID_ENABLED
2658  /*
2659  * The id is already defined in this DTD.
2660  */
2661  if (ctxt != NULL) {
2662  xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2663  "ID %s already defined\n", value, NULL, NULL);
2664  }
2665 #endif /* LIBXML_VALID_ENABLED */
2666  xmlFreeID(ret);
2667  return(NULL);
2668  }
2669  if (attr != NULL)
2670  attr->atype = XML_ATTRIBUTE_ID;
2671  return(ret);
2672 }
2673 
2674 static void
2676  xmlFreeID((xmlIDPtr) id);
2677 }
2678 
2685 void
2688 }
2689 
2703 int
2705  if ((attr == NULL) || (attr->name == NULL)) return(0);
2706  if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2707  (!strcmp((char *) attr->name, "id")) &&
2708  (!strcmp((char *) attr->ns->prefix, "xml")))
2709  return(1);
2710  if (doc == NULL) return(0);
2711  if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2712  (doc->type != XML_HTML_DOCUMENT_NODE)) {
2713  return(0);
2714  } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2715  if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2716  ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2717  ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2718  return(1);
2719  return(0);
2720  } else if (elem == NULL) {
2721  return(0);
2722  } else {
2723  xmlAttributePtr attrDecl = NULL;
2724 
2725  xmlChar felem[50], fattr[50];
2726  xmlChar *fullelemname, *fullattrname;
2727 
2728  fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2729  xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2730  (xmlChar *)elem->name;
2731 
2732  fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2733  xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2734  (xmlChar *)attr->name;
2735 
2736  if (fullelemname != NULL && fullattrname != NULL) {
2737  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2738  fullattrname);
2739  if ((attrDecl == NULL) && (doc->extSubset != NULL))
2740  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2741  fullattrname);
2742  }
2743 
2744  if ((fullattrname != fattr) && (fullattrname != attr->name))
2745  xmlFree(fullattrname);
2746  if ((fullelemname != felem) && (fullelemname != elem->name))
2747  xmlFree(fullelemname);
2748 
2749  if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2750  return(1);
2751  }
2752  return(0);
2753 }
2754 
2764 int
2767  xmlIDPtr id;
2768  xmlChar *ID;
2769 
2770  if (doc == NULL) return(-1);
2771  if (attr == NULL) return(-1);
2772 
2773  table = (xmlIDTablePtr) doc->ids;
2774  if (table == NULL)
2775  return(-1);
2776 
2777  ID = xmlNodeListGetString(doc, attr->children, 1);
2778  if (ID == NULL)
2779  return(-1);
2780 
2781  id = xmlHashLookup(table, ID);
2782  if (id == NULL || id->attr != attr) {
2783  xmlFree(ID);
2784  return(-1);
2785  }
2786 
2788  xmlFree(ID);
2789  attr->atype = 0;
2790  return(0);
2791 }
2792 
2802 xmlAttrPtr
2805  xmlIDPtr id;
2806 
2807  if (doc == NULL) {
2808  return(NULL);
2809  }
2810 
2811  if (ID == NULL) {
2812  return(NULL);
2813  }
2814 
2815  table = (xmlIDTablePtr) doc->ids;
2816  if (table == NULL)
2817  return(NULL);
2818 
2819  id = xmlHashLookup(table, ID);
2820  if (id == NULL)
2821  return(NULL);
2822  if (id->attr == NULL) {
2823  /*
2824  * We are operating on a stream, return a well known reference
2825  * since the attribute node doesn't exist anymore
2826  */
2827  return((xmlAttrPtr) doc);
2828  }
2829  return(id->attr);
2830 }
2831 
2832 /************************************************************************
2833  * *
2834  * Refs *
2835  * *
2836  ************************************************************************/
2837 typedef struct xmlRemoveMemo_t
2838 {
2841 } xmlRemoveMemo;
2842 
2844 
2845 typedef struct xmlValidateMemo_t
2846 {
2848  const xmlChar *name;
2849 } xmlValidateMemo;
2850 
2852 
2859 static void
2862  if (ref == NULL) return;
2863  if (ref->value != NULL)
2864  xmlFree((xmlChar *)ref->value);
2865  if (ref->name != NULL)
2866  xmlFree((xmlChar *)ref->name);
2867  xmlFree(ref);
2868 }
2869 
2876 static void
2878  xmlListPtr list_ref = (xmlListPtr) payload;
2879  if (list_ref == NULL) return;
2880  xmlListDelete(list_ref);
2881 }
2882 
2890 static int
2891 xmlWalkRemoveRef(const void *data, void *user)
2892 {
2893  xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2894  xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2895  xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2896 
2897  if (attr0 == attr1) { /* Matched: remove and terminate walk */
2898  xmlListRemoveFirst(ref_list, (void *)data);
2899  return 0;
2900  }
2901  return 1;
2902 }
2903 
2911 static int
2913  const void *data1 ATTRIBUTE_UNUSED)
2914 {
2915  return (0);
2916 }
2917 
2929 xmlRefPtr
2931  xmlAttrPtr attr) {
2932  xmlRefPtr ret;
2934  xmlListPtr ref_list;
2935 
2936  if (doc == NULL) {
2937  return(NULL);
2938  }
2939  if (value == NULL) {
2940  return(NULL);
2941  }
2942  if (attr == NULL) {
2943  return(NULL);
2944  }
2945 
2946  /*
2947  * Create the Ref table if needed.
2948  */
2949  table = (xmlRefTablePtr) doc->refs;
2950  if (table == NULL) {
2951  doc->refs = table = xmlHashCreateDict(0, doc->dict);
2952  }
2953  if (table == NULL) {
2954  xmlVErrMemory(ctxt,
2955  "xmlAddRef: Table creation failed!\n");
2956  return(NULL);
2957  }
2958 
2959  ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
2960  if (ret == NULL) {
2961  xmlVErrMemory(ctxt, "malloc failed");
2962  return(NULL);
2963  }
2964 
2965  /*
2966  * fill the structure.
2967  */
2968  ret->value = xmlStrdup(value);
2969  if ((ctxt != NULL) && (ctxt->vstateNr != 0)) {
2970  /*
2971  * Operating in streaming mode, attr is gonna disapear
2972  */
2973  ret->name = xmlStrdup(attr->name);
2974  ret->attr = NULL;
2975  } else {
2976  ret->name = NULL;
2977  ret->attr = attr;
2978  }
2979  ret->lineno = xmlGetLineNo(attr->parent);
2980 
2981  /* To add a reference :-
2982  * References are maintained as a list of references,
2983  * Lookup the entry, if no entry create new nodelist
2984  * Add the owning node to the NodeList
2985  * Return the ref
2986  */
2987 
2988  if (NULL == (ref_list = xmlHashLookup(table, value))) {
2989  if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
2990  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2991  "xmlAddRef: Reference list creation failed!\n",
2992  NULL);
2993  goto failed;
2994  }
2995  if (xmlHashAddEntry(table, value, ref_list) < 0) {
2996  xmlListDelete(ref_list);
2997  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2998  "xmlAddRef: Reference list insertion failed!\n",
2999  NULL);
3000  goto failed;
3001  }
3002  }
3003  if (xmlListAppend(ref_list, ret) != 0) {
3004  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3005  "xmlAddRef: Reference list insertion failed!\n",
3006  NULL);
3007  goto failed;
3008  }
3009  return(ret);
3010 failed:
3011  if (ret != NULL) {
3012  if (ret->value != NULL)
3013  xmlFree((char *)ret->value);
3014  if (ret->name != NULL)
3015  xmlFree((char *)ret->name);
3016  xmlFree(ret);
3017  }
3018  return(NULL);
3019 }
3020 
3027 void
3030 }
3031 
3044 int
3046  if (attr == NULL)
3047  return(0);
3048  if (doc == NULL) {
3049  doc = attr->doc;
3050  if (doc == NULL) return(0);
3051  }
3052 
3053  if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3054  return(0);
3055  } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3056  /* TODO @@@ */
3057  return(0);
3058  } else {
3059  xmlAttributePtr attrDecl;
3060 
3061  if (elem == NULL) return(0);
3062  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3063  if ((attrDecl == NULL) && (doc->extSubset != NULL))
3064  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3065  elem->name, attr->name);
3066 
3067  if ((attrDecl != NULL) &&
3068  (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3069  attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3070  return(1);
3071  }
3072  return(0);
3073 }
3074 
3084 int
3086  xmlListPtr ref_list;
3088  xmlChar *ID;
3090 
3091  if (doc == NULL) return(-1);
3092  if (attr == NULL) return(-1);
3093 
3094  table = (xmlRefTablePtr) doc->refs;
3095  if (table == NULL)
3096  return(-1);
3097 
3098  ID = xmlNodeListGetString(doc, attr->children, 1);
3099  if (ID == NULL)
3100  return(-1);
3101 
3102  ref_list = xmlHashLookup(table, ID);
3103  if(ref_list == NULL) {
3104  xmlFree(ID);
3105  return (-1);
3106  }
3107 
3108  /* At this point, ref_list refers to a list of references which
3109  * have the same key as the supplied attr. Our list of references
3110  * is ordered by reference address and we don't have that information
3111  * here to use when removing. We'll have to walk the list and
3112  * check for a matching attribute, when we find one stop the walk
3113  * and remove the entry.
3114  * The list is ordered by reference, so that means we don't have the
3115  * key. Passing the list and the reference to the walker means we
3116  * will have enough data to be able to remove the entry.
3117  */
3118  target.l = ref_list;
3119  target.ap = attr;
3120 
3121  /* Remove the supplied attr from our list */
3122  xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3123 
3124  /*If the list is empty then remove the list entry in the hash */
3125  if (xmlListEmpty(ref_list))
3127  xmlFree(ID);
3128  return(0);
3129 }
3130 
3140 xmlListPtr
3143 
3144  if (doc == NULL) {
3145  return(NULL);
3146  }
3147 
3148  if (ID == NULL) {
3149  return(NULL);
3150  }
3151 
3152  table = (xmlRefTablePtr) doc->refs;
3153  if (table == NULL)
3154  return(NULL);
3155 
3156  return (xmlHashLookup(table, ID));
3157 }
3158 
3159 /************************************************************************
3160  * *
3161  * Routines for validity checking *
3162  * *
3163  ************************************************************************/
3164 
3178  xmlElementPtr cur;
3179  xmlChar *uqname = NULL, *prefix = NULL;
3180 
3181  if ((dtd == NULL) || (name == NULL)) return(NULL);
3182  if (dtd->elements == NULL)
3183  return(NULL);
3185 
3186  uqname = xmlSplitQName2(name, &prefix);
3187  if (uqname != NULL)
3188  name = uqname;
3189  cur = xmlHashLookup2(table, name, prefix);
3190  if (prefix != NULL) xmlFree(prefix);
3191  if (uqname != NULL) xmlFree(uqname);
3192  return(cur);
3193 }
3205 static xmlElementPtr
3208  xmlElementPtr cur;
3209  xmlChar *uqname = NULL, *prefix = NULL;
3210 
3211  if (dtd == NULL) return(NULL);
3212  if (dtd->elements == NULL) {
3213  xmlDictPtr dict = NULL;
3214 
3215  if (dtd->doc != NULL)
3216  dict = dtd->doc->dict;
3217 
3218  if (!create)
3219  return(NULL);
3220  /*
3221  * Create the Element table if needed.
3222  */
3224  if (table == NULL) {
3225  table = xmlHashCreateDict(0, dict);
3226  dtd->elements = (void *) table;
3227  }
3228  if (table == NULL) {
3229  xmlVErrMemory(NULL, "element table allocation failed");
3230  return(NULL);
3231  }
3232  }
3234 
3235  uqname = xmlSplitQName2(name, &prefix);
3236  if (uqname != NULL)
3237  name = uqname;
3238  cur = xmlHashLookup2(table, name, prefix);
3239  if ((cur == NULL) && (create)) {
3240  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3241  if (cur == NULL) {
3242  xmlVErrMemory(NULL, "malloc failed");
3243  return(NULL);
3244  }
3245  memset(cur, 0, sizeof(xmlElement));
3246  cur->type = XML_ELEMENT_DECL;
3247 
3248  /*
3249  * fill the structure.
3250  */
3251  cur->name = xmlStrdup(name);
3252  cur->prefix = xmlStrdup(prefix);
3254 
3255  xmlHashAddEntry2(table, name, prefix, cur);
3256  }
3257  if (prefix != NULL) xmlFree(prefix);
3258  if (uqname != NULL) xmlFree(uqname);
3259  return(cur);
3260 }
3261 
3275  const xmlChar *prefix) {
3277 
3278  if (dtd == NULL) return(NULL);
3279  if (dtd->elements == NULL) return(NULL);
3281 
3282  return(xmlHashLookup2(table, name, prefix));
3283 }
3284 
3300  xmlAttributePtr cur;
3301  xmlChar *uqname = NULL, *prefix = NULL;
3302 
3303  if (dtd == NULL) return(NULL);
3304  if (dtd->attributes == NULL) return(NULL);
3305 
3307  if (table == NULL)
3308  return(NULL);
3309 
3310  uqname = xmlSplitQName2(name, &prefix);
3311 
3312  if (uqname != NULL) {
3313  cur = xmlHashLookup3(table, uqname, prefix, elem);
3314  if (prefix != NULL) xmlFree(prefix);
3315  if (uqname != NULL) xmlFree(uqname);
3316  } else
3317  cur = xmlHashLookup3(table, name, NULL, elem);
3318  return(cur);
3319 }
3320 
3336  const xmlChar *prefix) {
3338 
3339  if (dtd == NULL) return(NULL);
3340  if (dtd->attributes == NULL) return(NULL);
3342 
3343  return(xmlHashLookup3(table, name, prefix, elem));
3344 }
3345 
3359 
3360  if (dtd == NULL) return(NULL);
3361  if (dtd->notations == NULL) return(NULL);
3363 
3364  return(xmlHashLookup(table, name));
3365 }
3366 
3367 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3368 
3380 int
3381 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3382  const xmlChar *notationName) {
3383  xmlNotationPtr notaDecl;
3384  if ((doc == NULL) || (doc->intSubset == NULL) ||
3385  (notationName == NULL)) return(-1);
3386 
3387  notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3388  if ((notaDecl == NULL) && (doc->extSubset != NULL))
3389  notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3390 
3391  if ((notaDecl == NULL) && (ctxt != NULL)) {
3392  xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3393  "NOTATION %s is not declared\n",
3394  notationName, NULL, NULL);
3395  return(0);
3396  }
3397  return(1);
3398 }
3399 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3400 
3412 int
3414  xmlElementPtr elemDecl;
3415 
3416  if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3417 
3418  elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3419  if ((elemDecl == NULL) && (doc->extSubset != NULL))
3420  elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3421  if (elemDecl == NULL) return(-1);
3422  switch (elemDecl->etype) {
3424  return(-1);
3426  return(0);
3428  /*
3429  * return 1 for EMPTY since we want VC error to pop up
3430  * on <empty> </empty> for example
3431  */
3432  case XML_ELEMENT_TYPE_ANY:
3434  return(1);
3435  }
3436  return(1);
3437 }
3438 
3439 #ifdef LIBXML_VALID_ENABLED
3440 
3441 static int
3442 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3443  if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3444  /*
3445  * Use the new checks of production [4] [4a] amd [5] of the
3446  * Update 5 of XML-1.0
3447  */
3448  if (((c >= 'a') && (c <= 'z')) ||
3449  ((c >= 'A') && (c <= 'Z')) ||
3450  (c == '_') || (c == ':') ||
3451  ((c >= 0xC0) && (c <= 0xD6)) ||
3452  ((c >= 0xD8) && (c <= 0xF6)) ||
3453  ((c >= 0xF8) && (c <= 0x2FF)) ||
3454  ((c >= 0x370) && (c <= 0x37D)) ||
3455  ((c >= 0x37F) && (c <= 0x1FFF)) ||
3456  ((c >= 0x200C) && (c <= 0x200D)) ||
3457  ((c >= 0x2070) && (c <= 0x218F)) ||
3458  ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3459  ((c >= 0x3001) && (c <= 0xD7FF)) ||
3460  ((c >= 0xF900) && (c <= 0xFDCF)) ||
3461  ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3462  ((c >= 0x10000) && (c <= 0xEFFFF)))
3463  return(1);
3464  } else {
3465  if (IS_LETTER(c) || (c == '_') || (c == ':'))
3466  return(1);
3467  }
3468  return(0);
3469 }
3470 
3471 static int
3472 xmlIsDocNameChar(xmlDocPtr doc, int c) {
3473  if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3474  /*
3475  * Use the new checks of production [4] [4a] amd [5] of the
3476  * Update 5 of XML-1.0
3477  */
3478  if (((c >= 'a') && (c <= 'z')) ||
3479  ((c >= 'A') && (c <= 'Z')) ||
3480  ((c >= '0') && (c <= '9')) || /* !start */
3481  (c == '_') || (c == ':') ||
3482  (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3483  ((c >= 0xC0) && (c <= 0xD6)) ||
3484  ((c >= 0xD8) && (c <= 0xF6)) ||
3485  ((c >= 0xF8) && (c <= 0x2FF)) ||
3486  ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3487  ((c >= 0x370) && (c <= 0x37D)) ||
3488  ((c >= 0x37F) && (c <= 0x1FFF)) ||
3489  ((c >= 0x200C) && (c <= 0x200D)) ||
3490  ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3491  ((c >= 0x2070) && (c <= 0x218F)) ||
3492  ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3493  ((c >= 0x3001) && (c <= 0xD7FF)) ||
3494  ((c >= 0xF900) && (c <= 0xFDCF)) ||
3495  ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3496  ((c >= 0x10000) && (c <= 0xEFFFF)))
3497  return(1);
3498  } else {
3499  if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3500  (c == '.') || (c == '-') ||
3501  (c == '_') || (c == ':') ||
3502  (IS_COMBINING(c)) ||
3503  (IS_EXTENDER(c)))
3504  return(1);
3505  }
3506  return(0);
3507 }
3508 
3519 static int
3520 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3521  const xmlChar *cur;
3522  int val, len;
3523 
3524  if (value == NULL) return(0);
3525  cur = value;
3526  val = xmlStringCurrentChar(NULL, cur, &len);
3527  cur += len;
3528  if (!xmlIsDocNameStartChar(doc, val))
3529  return(0);
3530 
3531  val = xmlStringCurrentChar(NULL, cur, &len);
3532  cur += len;
3533  while (xmlIsDocNameChar(doc, val)) {
3534  val = xmlStringCurrentChar(NULL, cur, &len);
3535  cur += len;
3536  }
3537 
3538  if (val != 0) return(0);
3539 
3540  return(1);
3541 }
3542 
3552 int
3553 xmlValidateNameValue(const xmlChar *value) {
3554  return(xmlValidateNameValueInternal(NULL, value));
3555 }
3556 
3567 static int
3568 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3569  const xmlChar *cur;
3570  int val, len;
3571 
3572  if (value == NULL) return(0);
3573  cur = value;
3574  val = xmlStringCurrentChar(NULL, cur, &len);
3575  cur += len;
3576 
3577  if (!xmlIsDocNameStartChar(doc, val))
3578  return(0);
3579 
3580  val = xmlStringCurrentChar(NULL, cur, &len);
3581  cur += len;
3582  while (xmlIsDocNameChar(doc, val)) {
3583  val = xmlStringCurrentChar(NULL, cur, &len);
3584  cur += len;
3585  }
3586 
3587  /* Should not test IS_BLANK(val) here -- see erratum E20*/
3588  while (val == 0x20) {
3589  while (val == 0x20) {
3590  val = xmlStringCurrentChar(NULL, cur, &len);
3591  cur += len;
3592  }
3593 
3594  if (!xmlIsDocNameStartChar(doc, val))
3595  return(0);
3596 
3597  val = xmlStringCurrentChar(NULL, cur, &len);
3598  cur += len;
3599 
3600  while (xmlIsDocNameChar(doc, val)) {
3601  val = xmlStringCurrentChar(NULL, cur, &len);
3602  cur += len;
3603  }
3604  }
3605 
3606  if (val != 0) return(0);
3607 
3608  return(1);
3609 }
3610 
3620 int
3621 xmlValidateNamesValue(const xmlChar *value) {
3622  return(xmlValidateNamesValueInternal(NULL, value));
3623 }
3624 
3637 static int
3638 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3639  const xmlChar *cur;
3640  int val, len;
3641 
3642  if (value == NULL) return(0);
3643  cur = value;
3644  val = xmlStringCurrentChar(NULL, cur, &len);
3645  cur += len;
3646 
3647  if (!xmlIsDocNameChar(doc, val))
3648  return(0);
3649 
3650  val = xmlStringCurrentChar(NULL, cur, &len);
3651  cur += len;
3652  while (xmlIsDocNameChar(doc, val)) {
3653  val = xmlStringCurrentChar(NULL, cur, &len);
3654  cur += len;
3655  }
3656 
3657  if (val != 0) return(0);
3658 
3659  return(1);
3660 }
3661 
3673 int
3674 xmlValidateNmtokenValue(const xmlChar *value) {
3675  return(xmlValidateNmtokenValueInternal(NULL, value));
3676 }
3677 
3690 static int
3691 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3692  const xmlChar *cur;
3693  int val, len;
3694 
3695  if (value == NULL) return(0);
3696  cur = value;
3697  val = xmlStringCurrentChar(NULL, cur, &len);
3698  cur += len;
3699 
3700  while (IS_BLANK(val)) {
3701  val = xmlStringCurrentChar(NULL, cur, &len);
3702  cur += len;
3703  }
3704 
3705  if (!xmlIsDocNameChar(doc, val))
3706  return(0);
3707 
3708  while (xmlIsDocNameChar(doc, val)) {
3709  val = xmlStringCurrentChar(NULL, cur, &len);
3710  cur += len;
3711  }
3712 
3713  /* Should not test IS_BLANK(val) here -- see erratum E20*/
3714  while (val == 0x20) {
3715  while (val == 0x20) {
3716  val = xmlStringCurrentChar(NULL, cur, &len);
3717  cur += len;
3718  }
3719  if (val == 0) return(1);
3720 
3721  if (!xmlIsDocNameChar(doc, val))
3722  return(0);
3723 
3724  val = xmlStringCurrentChar(NULL, cur, &len);
3725  cur += len;
3726 
3727  while (xmlIsDocNameChar(doc, val)) {
3728  val = xmlStringCurrentChar(NULL, cur, &len);
3729  cur += len;
3730  }
3731  }
3732 
3733  if (val != 0) return(0);
3734 
3735  return(1);
3736 }
3737 
3749 int
3750 xmlValidateNmtokensValue(const xmlChar *value) {
3751  return(xmlValidateNmtokensValueInternal(NULL, value));
3752 }
3753 
3769 int
3770 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3772  int ret = 1;
3773 
3774  return(ret);
3775 }
3776 
3788 static int
3789 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3790  const xmlChar *value) {
3791  switch (type) {
3793  case XML_ATTRIBUTE_IDREFS:
3794  return(xmlValidateNamesValueInternal(doc, value));
3795  case XML_ATTRIBUTE_ENTITY:
3796  case XML_ATTRIBUTE_IDREF:
3797  case XML_ATTRIBUTE_ID:
3799  return(xmlValidateNameValueInternal(doc, value));
3802  return(xmlValidateNmtokensValueInternal(doc, value));
3803  case XML_ATTRIBUTE_NMTOKEN:
3804  return(xmlValidateNmtokenValueInternal(doc, value));
3805  case XML_ATTRIBUTE_CDATA:
3806  break;
3807  }
3808  return(1);
3809 }
3810 
3835 int
3836 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3837  return(xmlValidateAttributeValueInternal(NULL, type, value));
3838 }
3839 
3869 static int
3870 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3871  const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3872  int ret = 1;
3873  switch (type) {
3874  case XML_ATTRIBUTE_IDREFS:
3875  case XML_ATTRIBUTE_IDREF:
3876  case XML_ATTRIBUTE_ID:
3879  case XML_ATTRIBUTE_NMTOKEN:
3880  case XML_ATTRIBUTE_CDATA:
3881  break;
3882  case XML_ATTRIBUTE_ENTITY: {
3883  xmlEntityPtr ent;
3884 
3885  ent = xmlGetDocEntity(doc, value);
3886  /* yeah it's a bit messy... */
3887  if ((ent == NULL) && (doc->standalone == 1)) {
3888  doc->standalone = 0;
3889  ent = xmlGetDocEntity(doc, value);
3890  }
3891  if (ent == NULL) {
3892  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3894  "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3895  name, value, NULL);
3896  ret = 0;
3897  } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3898  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3900  "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3901  name, value, NULL);
3902  ret = 0;
3903  }
3904  break;
3905  }
3906  case XML_ATTRIBUTE_ENTITIES: {
3907  xmlChar *dup, *nam = NULL, *cur, save;
3908  xmlEntityPtr ent;
3909 
3910  dup = xmlStrdup(value);
3911  if (dup == NULL)
3912  return(0);
3913  cur = dup;
3914  while (*cur != 0) {
3915  nam = cur;
3916  while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3917  save = *cur;
3918  *cur = 0;
3919  ent = xmlGetDocEntity(doc, nam);
3920  if (ent == NULL) {
3921  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3923  "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
3924  name, nam, NULL);
3925  ret = 0;
3926  } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3927  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3929  "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
3930  name, nam, NULL);
3931  ret = 0;
3932  }
3933  if (save == 0)
3934  break;
3935  *cur = save;
3936  while (IS_BLANK_CH(*cur)) cur++;
3937  }
3938  xmlFree(dup);
3939  break;
3940  }
3941  case XML_ATTRIBUTE_NOTATION: {
3942  xmlNotationPtr nota;
3943 
3944  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
3945  if ((nota == NULL) && (doc->extSubset != NULL))
3946  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
3947 
3948  if (nota == NULL) {
3949  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3951  "NOTATION attribute %s reference an unknown notation \"%s\"\n",
3952  name, value, NULL);
3953  ret = 0;
3954  }
3955  break;
3956  }
3957  }
3958  return(ret);
3959 }
3960 
3985 xmlChar *
3986 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3987  xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
3988  xmlChar *ret, *dst;
3989  const xmlChar *src;
3990  xmlAttributePtr attrDecl = NULL;
3991  int extsubset = 0;
3992 
3993  if (doc == NULL) return(NULL);
3994  if (elem == NULL) return(NULL);
3995  if (name == NULL) return(NULL);
3996  if (value == NULL) return(NULL);
3997 
3998  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
3999  xmlChar fn[50];
4000  xmlChar *fullname;
4001 
4002  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4003  if (fullname == NULL)
4004  return(NULL);
4005  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4006  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4007  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4008  if (attrDecl != NULL)
4009  extsubset = 1;
4010  }
4011  if ((fullname != fn) && (fullname != elem->name))
4012  xmlFree(fullname);
4013  }
4014  if ((attrDecl == NULL) && (doc->intSubset != NULL))
4015  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4016  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4017  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4018  if (attrDecl != NULL)
4019  extsubset = 1;
4020  }
4021 
4022  if (attrDecl == NULL)
4023  return(NULL);
4024  if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4025  return(NULL);
4026 
4027  ret = xmlStrdup(value);
4028  if (ret == NULL)
4029  return(NULL);
4030  src = value;
4031  dst = ret;
4032  while (*src == 0x20) src++;
4033  while (*src != 0) {
4034  if (*src == 0x20) {
4035  while (*src == 0x20) src++;
4036  if (*src != 0)
4037  *dst++ = 0x20;
4038  } else {
4039  *dst++ = *src++;
4040  }
4041  }
4042  *dst = 0;
4043  if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4044  xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4045 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4046  name, elem->name, NULL);
4047  ctxt->valid = 0;
4048  }
4049  return(ret);
4050 }
4051 
4071 xmlChar *
4072 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4073  const xmlChar *name, const xmlChar *value) {
4074  xmlChar *ret, *dst;
4075  const xmlChar *src;
4076  xmlAttributePtr attrDecl = NULL;
4077 
4078  if (doc == NULL) return(NULL);
4079  if (elem == NULL) return(NULL);
4080  if (name == NULL) return(NULL);
4081  if (value == NULL) return(NULL);
4082 
4083  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4084  xmlChar fn[50];
4085  xmlChar *fullname;
4086 
4087  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4088  if (fullname == NULL)
4089  return(NULL);
4090  if ((fullname != fn) && (fullname != elem->name))
4091  xmlFree(fullname);
4092  }
4093  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4094  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4095  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4096 
4097  if (attrDecl == NULL)
4098  return(NULL);
4099  if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4100  return(NULL);
4101 
4102  ret = xmlStrdup(value);
4103  if (ret == NULL)
4104  return(NULL);
4105  src = value;
4106  dst = ret;
4107  while (*src == 0x20) src++;
4108  while (*src != 0) {
4109  if (*src == 0x20) {
4110  while (*src == 0x20) src++;
4111  if (*src != 0)
4112  *dst++ = 0x20;
4113  } else {
4114  *dst++ = *src++;
4115  }
4116  }
4117  *dst = 0;
4118  return(ret);
4119 }
4120 
4121 static void
4122 xmlValidateAttributeIdCallback(void *payload, void *data,
4123  const xmlChar *name ATTRIBUTE_UNUSED) {
4124  xmlAttributePtr attr = (xmlAttributePtr) payload;
4125  int *count = (int *) data;
4126  if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4127 }
4128 
4147 int
4148 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4150  int ret = 1;
4151  int val;
4152  CHECK_DTD;
4153  if(attr == NULL) return(1);
4154 
4155  /* Attribute Default Legal */
4156  /* Enumeration */
4157  if (attr->defaultValue != NULL) {
4158  val = xmlValidateAttributeValueInternal(doc, attr->atype,
4159  attr->defaultValue);
4160  if (val == 0) {
4161  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4162  "Syntax of default value for attribute %s of %s is not valid\n",
4163  attr->name, attr->elem, NULL);
4164  }
4165  ret &= val;
4166  }
4167 
4168  /* ID Attribute Default */
4169  if ((attr->atype == XML_ATTRIBUTE_ID)&&
4170  (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4171  (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4172  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4173  "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4174  attr->name, attr->elem, NULL);
4175  ret = 0;
4176  }
4177 
4178  /* One ID per Element Type */
4179  if (attr->atype == XML_ATTRIBUTE_ID) {
4180  int nbId;
4181 
4182  /* the trick is that we parse DtD as their own internal subset */
4184  attr->elem);
4185  if (elem != NULL) {
4186  nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4187  } else {
4189 
4190  /*
4191  * The attribute may be declared in the internal subset and the
4192  * element in the external subset.
4193  */
4194  nbId = 0;
4195  if (doc->intSubset != NULL) {
4196  table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4197  xmlHashScan3(table, NULL, NULL, attr->elem,
4198  xmlValidateAttributeIdCallback, &nbId);
4199  }
4200  }
4201  if (nbId > 1) {
4202 
4203  xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4204  "Element %s has %d ID attribute defined in the internal subset : %s\n",
4205  attr->elem, nbId, attr->name);
4206  } else if (doc->extSubset != NULL) {
4207  int extId = 0;
4208  elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4209  if (elem != NULL) {
4210  extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4211  }
4212  if (extId > 1) {
4213  xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4214  "Element %s has %d ID attribute defined in the external subset : %s\n",
4215  attr->elem, extId, attr->name);
4216  } else if (extId + nbId > 1) {
4217  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4218 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4219  attr->elem, attr->name, NULL);
4220  }
4221  }
4222  }
4223 
4224  /* Validity Constraint: Enumeration */
4225  if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4226  xmlEnumerationPtr tree = attr->tree;
4227  while (tree != NULL) {
4228  if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4229  tree = tree->next;
4230  }
4231  if (tree == NULL) {
4232  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4233 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4234  attr->defaultValue, attr->name, attr->elem);
4235  ret = 0;
4236  }
4237  }
4238 
4239  return(ret);
4240 }
4241 
4258 int
4259 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4260  xmlElementPtr elem) {
4261  int ret = 1;
4262  xmlElementPtr tst;
4263 
4264  CHECK_DTD;
4265 
4266  if (elem == NULL) return(1);
4267 
4268 #if 0
4269 #ifdef LIBXML_REGEXP_ENABLED
4270  /* Build the regexp associated to the content model */
4271  ret = xmlValidBuildContentModel(ctxt, elem);
4272 #endif
4273 #endif
4274 
4275  /* No Duplicate Types */
4276  if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4278  const xmlChar *name;
4279 
4280  cur = elem->content;
4281  while (cur != NULL) {
4282  if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4283  if (cur->c1 == NULL) break;
4284  if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4285  name = cur->c1->name;
4286  next = cur->c2;
4287  while (next != NULL) {
4288  if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4289  if ((xmlStrEqual(next->name, name)) &&
4290  (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4291  if (cur->c1->prefix == NULL) {
4292  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4293  "Definition of %s has duplicate references of %s\n",
4294  elem->name, name, NULL);
4295  } else {
4296  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4297  "Definition of %s has duplicate references of %s:%s\n",
4298  elem->name, cur->c1->prefix, name);
4299  }
4300  ret = 0;
4301  }
4302  break;
4303  }
4304  if (next->c1 == NULL) break;
4305  if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4306  if ((xmlStrEqual(next->c1->name, name)) &&
4307  (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4308  if (cur->c1->prefix == NULL) {
4309  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4310  "Definition of %s has duplicate references to %s\n",
4311  elem->name, name, NULL);
4312  } else {
4313  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4314  "Definition of %s has duplicate references to %s:%s\n",
4315  elem->name, cur->c1->prefix, name);
4316  }
4317  ret = 0;
4318  }
4319  next = next->c2;
4320  }
4321  }
4322  cur = cur->c2;
4323  }
4324  }
4325 
4326  /* VC: Unique Element Type Declaration */
4327  tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4328  if ((tst != NULL ) && (tst != elem) &&
4329  ((tst->prefix == elem->prefix) ||
4330  (xmlStrEqual(tst->prefix, elem->prefix))) &&
4331  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4332  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4333  "Redefinition of element %s\n",
4334  elem->name, NULL, NULL);
4335  ret = 0;
4336  }
4337  tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4338  if ((tst != NULL ) && (tst != elem) &&
4339  ((tst->prefix == elem->prefix) ||
4340  (xmlStrEqual(tst->prefix, elem->prefix))) &&
4341  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4342  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4343  "Redefinition of element %s\n",
4344  elem->name, NULL, NULL);
4345  ret = 0;
4346  }
4347  /* One ID per Element Type
4348  * already done when registering the attribute
4349  if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4350  ret = 0;
4351  } */
4352  return(ret);
4353 }
4354 
4380 int
4381 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4383 {
4384  xmlAttributePtr attrDecl = NULL;
4385  int val;
4386  int ret = 1;
4387 
4388  CHECK_DTD;
4389  if ((elem == NULL) || (elem->name == NULL)) return(0);
4390  if ((attr == NULL) || (attr->name == NULL)) return(0);
4391 
4392  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4393  xmlChar fn[50];
4394  xmlChar *fullname;
4395 
4396  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4397  if (fullname == NULL)
4398  return(0);
4399  if (attr->ns != NULL) {
4400  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4401  attr->name, attr->ns->prefix);
4402  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4403  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4404  attr->name, attr->ns->prefix);
4405  } else {
4406  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4407  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4408  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4409  fullname, attr->name);
4410  }
4411  if ((fullname != fn) && (fullname != elem->name))
4412  xmlFree(fullname);
4413  }
4414  if (attrDecl == NULL) {
4415  if (attr->ns != NULL) {
4416  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4417  attr->name, attr->ns->prefix);
4418  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4419  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4420  attr->name, attr->ns->prefix);
4421  } else {
4422  attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4423  elem->name, attr->name);
4424  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4425  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4426  elem->name, attr->name);
4427  }
4428  }
4429 
4430 
4431  /* Validity Constraint: Attribute Value Type */
4432  if (attrDecl == NULL) {
4433  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4434  "No declaration for attribute %s of element %s\n",
4435  attr->name, elem->name, NULL);
4436  return(0);
4437  }
4438  attr->atype = attrDecl->atype;
4439 
4440  val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4441  if (val == 0) {
4442  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4443  "Syntax of value for attribute %s of %s is not valid\n",
4444  attr->name, elem->name, NULL);
4445  ret = 0;
4446  }
4447 
4448  /* Validity constraint: Fixed Attribute Default */
4449  if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4450  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4451  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4452  "Value for attribute %s of %s is different from default \"%s\"\n",
4453  attr->name, elem->name, attrDecl->defaultValue);
4454  ret = 0;
4455  }
4456  }
4457 
4458  /* Validity Constraint: ID uniqueness */
4459  if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4460  if (xmlAddID(ctxt, doc, value, attr) == NULL)
4461  ret = 0;
4462  }
4463 
4464  if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4465  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4466  if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4467  ret = 0;
4468  }
4469 
4470  /* Validity Constraint: Notation Attributes */
4471  if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4472  xmlEnumerationPtr tree = attrDecl->tree;
4473  xmlNotationPtr nota;
4474 
4475  /* First check that the given NOTATION was declared */
4476  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4477  if (nota == NULL)
4478  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4479 
4480  if (nota == NULL) {
4481  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4482  "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4483  value, attr->name, elem->name);
4484  ret = 0;
4485  }
4486 
4487  /* Second, verify that it's among the list */
4488  while (tree != NULL) {
4489  if (xmlStrEqual(tree->name, value)) break;
4490  tree = tree->next;
4491  }
4492  if (tree == NULL) {
4493  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4494 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4495  value, attr->name, elem->name);
4496  ret = 0;
4497  }
4498  }
4499 
4500  /* Validity Constraint: Enumeration */
4501  if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4502  xmlEnumerationPtr tree = attrDecl->tree;
4503  while (tree != NULL) {
4504  if (xmlStrEqual(tree->name, value)) break;
4505  tree = tree->next;
4506  }
4507  if (tree == NULL) {
4508  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4509  "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4510  value, attr->name, elem->name);
4511  ret = 0;
4512  }
4513  }
4514 
4515  /* Fixed Attribute Default */
4516  if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4517  (!xmlStrEqual(attrDecl->defaultValue, value))) {
4518  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4519  "Value for attribute %s of %s must be \"%s\"\n",
4520  attr->name, elem->name, attrDecl->defaultValue);
4521  ret = 0;
4522  }
4523 
4524  /* Extra check for the attribute value */
4525  ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4526  attrDecl->atype, value);
4527 
4528  return(ret);
4529 }
4530 
4557 int
4558 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4559 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4560  /* xmlElementPtr elemDecl; */
4561  xmlAttributePtr attrDecl = NULL;
4562  int val;
4563  int ret = 1;
4564 
4565  CHECK_DTD;
4566  if ((elem == NULL) || (elem->name == NULL)) return(0);
4567  if ((ns == NULL) || (ns->href == NULL)) return(0);
4568 
4569  if (prefix != NULL) {
4570  xmlChar fn[50];
4571  xmlChar *fullname;
4572 
4573  fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4574  if (fullname == NULL) {
4575  xmlVErrMemory(ctxt, "Validating namespace");
4576  return(0);
4577  }
4578  if (ns->prefix != NULL) {
4579  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4580  ns->prefix, BAD_CAST "xmlns");
4581  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4582  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4583  ns->prefix, BAD_CAST "xmlns");
4584  } else {
4585  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4586  BAD_CAST "xmlns");
4587  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4588  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4589  BAD_CAST "xmlns");
4590  }
4591  if ((fullname != fn) && (fullname != elem->name))
4592  xmlFree(fullname);
4593  }
4594  if (attrDecl == NULL) {
4595  if (ns->prefix != NULL) {
4596  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4597  ns->prefix, BAD_CAST "xmlns");
4598  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4599  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4600  ns->prefix, BAD_CAST "xmlns");
4601  } else {
4602  attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4603  elem->name, BAD_CAST "xmlns");
4604  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4605  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4606  elem->name, BAD_CAST "xmlns");
4607  }
4608  }
4609 
4610 
4611  /* Validity Constraint: Attribute Value Type */
4612  if (attrDecl == NULL) {
4613  if (ns->prefix != NULL) {
4614  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4615  "No declaration for attribute xmlns:%s of element %s\n",
4616  ns->prefix, elem->name, NULL);
4617  } else {
4618  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4619  "No declaration for attribute xmlns of element %s\n",
4620  elem->name, NULL, NULL);
4621  }
4622  return(0);
4623  }
4624 
4625  val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4626  if (val == 0) {
4627  if (ns->prefix != NULL) {
4628  xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4629  "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4630  ns->prefix, elem->name, NULL);
4631  } else {
4632  xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4633  "Syntax of value for attribute xmlns of %s is not valid\n",
4634  elem->name, NULL, NULL);
4635  }
4636  ret = 0;
4637  }
4638 
4639  /* Validity constraint: Fixed Attribute Default */
4640  if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4641  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4642  if (ns->prefix != NULL) {
4643  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4644  "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4645  ns->prefix, elem->name, attrDecl->defaultValue);
4646  } else {
4647  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4648  "Value for attribute xmlns of %s is different from default \"%s\"\n",
4649  elem->name, attrDecl->defaultValue, NULL);
4650  }
4651  ret = 0;
4652  }
4653  }
4654 
4655  /*
4656  * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4657  * xmlAddID and xmlAddRef for namespace declarations, but it makes
4658  * no practical sense to use ID types anyway.
4659  */
4660 #if 0
4661  /* Validity Constraint: ID uniqueness */
4662  if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4663  if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4664  ret = 0;
4665  }
4666 
4667  if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4668  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4669  if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4670  ret = 0;
4671  }
4672 #endif
4673 
4674  /* Validity Constraint: Notation Attributes */
4675  if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4676  xmlEnumerationPtr tree = attrDecl->tree;
4677  xmlNotationPtr nota;
4678 
4679  /* First check that the given NOTATION was declared */
4680  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4681  if (nota == NULL)
4682  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4683 
4684  if (nota == NULL) {
4685  if (ns->prefix != NULL) {
4686  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4687  "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4688  value, ns->prefix, elem->name);
4689  } else {
4690  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4691  "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4692  value, elem->name, NULL);
4693  }
4694  ret = 0;
4695  }
4696 
4697  /* Second, verify that it's among the list */
4698  while (tree != NULL) {
4699  if (xmlStrEqual(tree->name, value)) break;
4700  tree = tree->next;
4701  }
4702  if (tree == NULL) {
4703  if (ns->prefix != NULL) {
4704  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4705 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4706  value, ns->prefix, elem->name);
4707  } else {
4708  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4709 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4710  value, elem->name, NULL);
4711  }
4712  ret = 0;
4713  }
4714  }
4715 
4716  /* Validity Constraint: Enumeration */
4717  if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4718  xmlEnumerationPtr tree = attrDecl->tree;
4719  while (tree != NULL) {
4720  if (xmlStrEqual(tree->name, value)) break;
4721  tree = tree->next;
4722  }
4723  if (tree == NULL) {
4724  if (ns->prefix != NULL) {
4725  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4726 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4727  value, ns->prefix, elem->name);
4728  } else {
4729  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4730 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4731  value, elem->name, NULL);
4732  }
4733  ret = 0;
4734  }
4735  }
4736 
4737  /* Fixed Attribute Default */
4738  if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4739  (!xmlStrEqual(attrDecl->defaultValue, value))) {
4740  if (ns->prefix != NULL) {
4741  xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4742  "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4743  ns->prefix, elem->name, attrDecl->defaultValue);
4744  } else {
4745  xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4746  "Value for attribute xmlns of %s must be \"%s\"\n",
4747  elem->name, attrDecl->defaultValue, NULL);
4748  }
4749  ret = 0;
4750  }
4751 
4752  /* Extra check for the attribute value */
4753  if (ns->prefix != NULL) {
4754  ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4755  attrDecl->atype, value);
4756  } else {
4757  ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4758  attrDecl->atype, value);
4759  }
4760 
4761  return(ret);
4762 }
4763 
4764 #ifndef LIBXML_REGEXP_ENABLED
4765 
4775 static xmlNodePtr
4776 xmlValidateSkipIgnorable(xmlNodePtr child) {
4777  while (child != NULL) {
4778  switch (child->type) {
4779  /* These things are ignored (skipped) during validation. */
4780  case XML_PI_NODE:
4781  case XML_COMMENT_NODE:
4782  case XML_XINCLUDE_START:
4783  case XML_XINCLUDE_END:
4784  child = child->next;
4785  break;
4786  case XML_TEXT_NODE:
4787  if (xmlIsBlankNode(child))
4788  child = child->next;
4789  else
4790  return(child);
4791  break;
4792  /* keep current node */
4793  default:
4794  return(child);
4795  }
4796  }
4797  return(child);
4798 }
4799 
4811 static int
4812 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4813  int ret = -1;
4814  int determinist = 1;
4815 
4816  NODE = xmlValidateSkipIgnorable(NODE);
4817  if ((NODE == NULL) && (CONT == NULL))
4818  return(1);
4819  if ((NODE == NULL) &&
4820  ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4821  (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4822  return(1);
4823  }
4824  if (CONT == NULL) return(-1);
4825  if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4826  return(-2);
4827 
4828  /*
4829  * We arrive here when more states need to be examined
4830  */
4831 cont:
4832 
4833  /*
4834  * We just recovered from a rollback generated by a possible
4835  * epsilon transition, go directly to the analysis phase
4836  */
4837  if (STATE == ROLLBACK_PARENT) {
4838  DEBUG_VALID_MSG("restored parent branch");
4839  DEBUG_VALID_STATE(NODE, CONT)
4840  ret = 1;
4841  goto analyze;
4842  }
4843 
4844  DEBUG_VALID_STATE(NODE, CONT)
4845  /*
4846  * we may have to save a backup state here. This is the equivalent
4847  * of handling epsilon transition in NFAs.
4848  */
4849  if ((CONT != NULL) &&
4850  ((CONT->parent == NULL) ||
4851  (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4852  ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4853  (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4854  ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4855  DEBUG_VALID_MSG("saving parent branch");
4856  if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4857  return(0);
4858  }
4859 
4860 
4861  /*
4862  * Check first if the content matches
4863  */
4864  switch (CONT->type) {
4866  if (NODE == NULL) {
4867  DEBUG_VALID_MSG("pcdata failed no node");
4868  ret = 0;
4869  break;
4870  }
4871  if (NODE->type == XML_TEXT_NODE) {
4872  DEBUG_VALID_MSG("pcdata found, skip to next");
4873  /*
4874  * go to next element in the content model
4875  * skipping ignorable elems
4876  */
4877  do {
4878  NODE = NODE->next;
4879  NODE = xmlValidateSkipIgnorable(NODE);
4880  if ((NODE != NULL) &&
4881  (NODE->type == XML_ENTITY_REF_NODE))
4882  return(-2);
4883  } while ((NODE != NULL) &&
4884  ((NODE->type != XML_ELEMENT_NODE) &&
4885  (NODE->type != XML_TEXT_NODE) &&
4886  (NODE->type != XML_CDATA_SECTION_NODE)));
4887  ret = 1;
4888  break;
4889  } else {
4890  DEBUG_VALID_MSG("pcdata failed");
4891  ret = 0;
4892  break;
4893  }
4894  break;
4896  if (NODE == NULL) {
4897  DEBUG_VALID_MSG("element failed no node");
4898  ret = 0;
4899  break;
4900  }
4901  ret = ((NODE->type == XML_ELEMENT_NODE) &&
4902  (xmlStrEqual(NODE->name, CONT->name)));
4903  if (ret == 1) {
4904  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4905  ret = (CONT->prefix == NULL);
4906  } else if (CONT->prefix == NULL) {
4907  ret = 0;
4908  } else {
4909  ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4910  }
4911  }
4912  if (ret == 1) {
4913  DEBUG_VALID_MSG("element found, skip to next");
4914  /*
4915  * go to next element in the content model
4916  * skipping ignorable elems
4917  */
4918  do {
4919  NODE = NODE->next;
4920  NODE = xmlValidateSkipIgnorable(NODE);
4921  if ((NODE != NULL) &&
4922  (NODE->type == XML_ENTITY_REF_NODE))
4923  return(-2);
4924  } while ((NODE != NULL) &&
4925  ((NODE->type != XML_ELEMENT_NODE) &&
4926  (NODE->type != XML_TEXT_NODE) &&
4927  (NODE->type != XML_CDATA_SECTION_NODE)));
4928  } else {
4929  DEBUG_VALID_MSG("element failed");
4930  ret = 0;
4931  break;
4932  }
4933  break;
4935  /*
4936  * Small optimization.
4937  */
4938  if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4939  if ((NODE == NULL) ||
4940  (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4941  DEPTH++;
4942  CONT = CONT->c2;
4943  goto cont;
4944  }
4945  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4946  ret = (CONT->c1->prefix == NULL);
4947  } else if (CONT->c1->prefix == NULL) {
4948  ret = 0;
4949  } else {
4950  ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4951  }
4952  if (ret == 0) {
4953  DEPTH++;
4954  CONT = CONT->c2;
4955  goto cont;
4956  }
4957  }
4958 
4959  /*
4960  * save the second branch 'or' branch
4961  */
4962  DEBUG_VALID_MSG("saving 'or' branch");
4963  if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
4964  OCCURS, ROLLBACK_OR) < 0)
4965  return(-1);
4966  DEPTH++;
4967  CONT = CONT->c1;
4968  goto cont;
4970  /*
4971  * Small optimization.
4972  */
4973  if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
4974  ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
4975  (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
4976  if ((NODE == NULL) ||
4977  (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4978  DEPTH++;
4979  CONT = CONT->c2;
4980  goto cont;
4981  }
4982  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4983  ret = (CONT->c1->prefix == NULL);
4984  } else if (CONT->c1->prefix == NULL) {
4985  ret = 0;
4986  } else {
4987  ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
4988  }
4989  if (ret == 0) {
4990  DEPTH++;
4991  CONT = CONT->c2;
4992  goto cont;
4993  }
4994  }
4995  DEPTH++;
4996  CONT = CONT->c1;
4997  goto cont;
4998  }
4999 
5000  /*
5001  * At this point handle going up in the tree
5002  */
5003  if (ret == -1) {
5004  DEBUG_VALID_MSG("error found returning");
5005  return(ret);
5006  }
5007 analyze:
5008  while (CONT != NULL) {
5009  /*
5010  * First do the analysis depending on the occurrence model at
5011  * this level.
5012  */
5013  if (ret == 0) {
5014  switch (CONT->ocur) {
5015  xmlNodePtr cur;
5016 
5018  cur = ctxt->vstate->node;
5019  DEBUG_VALID_MSG("Once branch failed, rollback");
5020  if (vstateVPop(ctxt) < 0 ) {
5021  DEBUG_VALID_MSG("exhaustion, failed");
5022  return(0);
5023  }
5024  if (cur != ctxt->vstate->node)
5025  determinist = -3;
5026  goto cont;
5028  if (OCCURRENCE == 0) {
5029  cur = ctxt->vstate->node;
5030  DEBUG_VALID_MSG("Plus branch failed, rollback");
5031  if (vstateVPop(ctxt) < 0 ) {
5032  DEBUG_VALID_MSG("exhaustion, failed");
5033  return(0);
5034  }
5035  if (cur != ctxt->vstate->node)
5036  determinist = -3;
5037  goto cont;
5038  }
5039  DEBUG_VALID_MSG("Plus branch found");
5040  ret = 1;
5041  break;
5043 #ifdef DEBUG_VALID_ALGO
5044  if (OCCURRENCE == 0) {
5045  DEBUG_VALID_MSG("Mult branch failed");
5046  } else {
5047  DEBUG_VALID_MSG("Mult branch found");
5048  }
5049 #endif
5050  ret = 1;
5051  break;
5053  DEBUG_VALID_MSG("Option branch failed");
5054  ret = 1;
5055  break;
5056  }
5057  } else {
5058  switch (CONT->ocur) {
5060  DEBUG_VALID_MSG("Option branch succeeded");
5061  ret = 1;
5062  break;
5064  DEBUG_VALID_MSG("Once branch succeeded");
5065  ret = 1;
5066  break;
5068  if (STATE == ROLLBACK_PARENT) {
5069  DEBUG_VALID_MSG("Plus branch rollback");
5070  ret = 1;
5071  break;
5072  }
5073  if (NODE == NULL) {
5074  DEBUG_VALID_MSG("Plus branch exhausted");
5075  ret = 1;
5076  break;
5077  }
5078  DEBUG_VALID_MSG("Plus branch succeeded, continuing");
5079  SET_OCCURRENCE;
5080  goto cont;
5082  if (STATE == ROLLBACK_PARENT) {
5083  DEBUG_VALID_MSG("Mult branch rollback");
5084  ret = 1;
5085  break;
5086  }
5087  if (NODE == NULL) {
5088  DEBUG_VALID_MSG("Mult branch exhausted");
5089  ret = 1;
5090  break;
5091  }
5092  DEBUG_VALID_MSG("Mult branch succeeded, continuing");
5093  /* SET_OCCURRENCE; */
5094  goto cont;
5095  }
5096  }
5097  STATE = 0;
5098 
5099  /*
5100  * Then act accordingly at the parent level
5101  */
5102  RESET_OCCURRENCE;
5103  if (CONT->parent == NULL)
5104  break;
5105 
5106  switch (CONT->parent->type) {
5108  DEBUG_VALID_MSG("Error: parent pcdata");
5109  return(-1);
5111  DEBUG_VALID_MSG("Error: parent element");
5112  return(-1);
5114  if (ret == 1) {
5115  DEBUG_VALID_MSG("Or succeeded");
5116  CONT = CONT->parent;
5117  DEPTH--;
5118  } else {
5119  DEBUG_VALID_MSG("Or failed");
5120  CONT = CONT->parent;
5121  DEPTH--;
5122  }
5123  break;
5125  if (ret == 0) {
5126  DEBUG_VALID_MSG("Sequence failed");
5127  CONT = CONT->parent;
5128  DEPTH--;
5129  } else if (CONT == CONT->parent->c1) {
5130  DEBUG_VALID_MSG("Sequence testing 2nd branch");
5131  CONT = CONT->parent->c2;
5132  goto cont;
5133  } else {
5134  DEBUG_VALID_MSG("Sequence succeeded");
5135  CONT = CONT->parent;
5136  DEPTH--;
5137  }
5138  }
5139  }
5140  if (NODE != NULL) {
5141  xmlNodePtr cur;
5142 
5143  cur = ctxt->vstate->node;
5144  DEBUG_VALID_MSG("Failed, remaining input, rollback");
5145  if (vstateVPop(ctxt) < 0 ) {
5146  DEBUG_VALID_MSG("exhaustion, failed");
5147  return(0);
5148  }
5149  if (cur != ctxt->vstate->node)
5150  determinist = -3;
5151  goto cont;
5152  }
5153  if (ret == 0) {
5154  xmlNodePtr cur;
5155 
5156  cur = ctxt->vstate->node;
5157  DEBUG_VALID_MSG("Failure, rollback");
5158  if (vstateVPop(ctxt) < 0 ) {
5159  DEBUG_VALID_MSG("exhaustion, failed");
5160  return(0);
5161  }
5162  if (cur != ctxt->vstate->node)
5163  determinist = -3;
5164  goto cont;
5165  }
5166  return(determinist);
5167 }
5168 #endif
5169 
5180 static void
5181 xmlSnprintfElements(char *buf, int size, xmlNodePtr node, int glob) {
5182  xmlNodePtr cur;
5183  int len;
5184 
5185  if (node == NULL) return;
5186  if (glob) strcat(buf, "(");
5187  cur = node;
5188  while (cur != NULL) {
5189  len = strlen(buf);
5190  if (size - len < 50) {
5191  if ((size - len > 4) && (buf[len - 1] != '.'))
5192  strcat(buf, " ...");
5193  return;
5194  }
5195  switch (cur->type) {
5196  case XML_ELEMENT_NODE:
5197  if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
5198  if (size - len < xmlStrlen(cur->ns->prefix) + 10) {
5199  if ((size - len > 4) && (buf[len - 1] != '.'))
5200  strcat(buf, " ...");
5201  return;
5202  }
5203  strcat(buf, (char *) cur->ns->prefix);
5204  strcat(buf, ":");
5205  }
5206  if (size - len < xmlStrlen(cur->name) + 10) {
5207  if ((size - len > 4) && (buf[len - 1] != '.'))
5208  strcat(buf, " ...");
5209  return;
5210  }
5211  strcat(buf, (char *) cur->name);
5212  if (cur->next != NULL)
5213  strcat(buf, " ");
5214  break;
5215  case XML_TEXT_NODE:
5216  if (xmlIsBlankNode(cur))
5217  break;
5218  /* Falls through. */
5220  case XML_ENTITY_REF_NODE:
5221  strcat(buf, "CDATA");
5222  if (cur->next != NULL)
5223  strcat(buf, " ");
5224  break;
5225  case XML_ATTRIBUTE_NODE:
5226  case XML_DOCUMENT_NODE:
5227 #ifdef LIBXML_DOCB_ENABLED
5228  case XML_DOCB_DOCUMENT_NODE:
5229 #endif
5233  case XML_NOTATION_NODE:
5234  case XML_NAMESPACE_DECL:
5235  strcat(buf, "???");
5236  if (cur->next != NULL)
5237  strcat(buf, " ");
5238  break;
5239  case XML_ENTITY_NODE:
5240  case XML_PI_NODE:
5241  case XML_DTD_NODE:
5242  case XML_COMMENT_NODE:
5243  case XML_ELEMENT_DECL:
5244  case XML_ATTRIBUTE_DECL:
5245  case XML_ENTITY_DECL:
5246  case XML_XINCLUDE_START:
5247  case XML_XINCLUDE_END:
5248  break;
5249  }
5250  cur = cur->next;
5251  }
5252  if (glob) strcat(buf, ")");
5253 }
5254 
5268 static int
5269 xmlValidateElementContent(xmlValidCtxtPtr ctxt, xmlNodePtr child,
5270  xmlElementPtr elemDecl, int warn, xmlNodePtr parent) {
5271  int ret = 1;
5272 #ifndef LIBXML_REGEXP_ENABLED
5273  xmlNodePtr repl = NULL, last = NULL, tmp;
5274 #endif
5275  xmlNodePtr cur;
5276  xmlElementContentPtr cont;
5277  const xmlChar *name;
5278 
5279  if ((elemDecl == NULL) || (parent == NULL) || (ctxt == NULL))
5280  return(-1);
5281  cont = elemDecl->content;
5282  name = elemDecl->name;
5283 
5284 #ifdef LIBXML_REGEXP_ENABLED
5285  /* Build the regexp associated to the content model */
5286  if (elemDecl->contModel == NULL)
5287  ret = xmlValidBuildContentModel(ctxt, elemDecl);
5288  if (elemDecl->contModel == NULL) {
5289  return(-1);
5290  } else {
5291  xmlRegExecCtxtPtr exec;
5292 
5293  if (!xmlRegexpIsDeterminist(elemDecl->contModel)) {
5294  return(-1);
5295  }
5296  ctxt->nodeMax = 0;
5297  ctxt->nodeNr = 0;
5298  ctxt->nodeTab = NULL;
5299  exec = xmlRegNewExecCtxt(elemDecl->