ReactOS  0.4.15-dev-5459-gb85f005
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 #include <stdlib.h>
15 
16 #include <libxml/xmlmemory.h>
17 #include <libxml/hash.h>
18 #include <libxml/uri.h>
19 #include <libxml/valid.h>
20 #include <libxml/parser.h>
21 #include <libxml/parserInternals.h>
22 #include <libxml/xmlerror.h>
23 #include <libxml/list.h>
24 #include <libxml/globals.h>
25 
27  int create);
28 /* #define DEBUG_VALID_ALGO */
29 /* #define DEBUG_REGEXP_ALGO */
30 
31 #define TODO \
32  xmlGenericError(xmlGenericErrorContext, \
33  "Unimplemented block at %s:%d\n", \
34  __FILE__, __LINE__);
35 
36 #ifdef LIBXML_VALID_ENABLED
37 static int
38 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
39  const xmlChar *value);
40 #endif
41 /************************************************************************
42  * *
43  * Error handling routines *
44  * *
45  ************************************************************************/
46 
54 static void
56 {
57  xmlGenericErrorFunc channel = NULL;
58  xmlParserCtxtPtr pctxt = NULL;
59  void *data = NULL;
60 
61  if (ctxt != NULL) {
62  channel = ctxt->error;
63  data = ctxt->userData;
64  /* Look up flag to detect if it is part of a parsing
65  context */
66  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
67  long delta = (char *) ctxt - (char *) ctxt->userData;
68  if ((delta > 0) && (delta < 250))
69  pctxt = ctxt->userData;
70  }
71  }
72  if (extra)
73  __xmlRaiseError(NULL, channel, data,
75  XML_ERR_FATAL, NULL, 0, extra, NULL, NULL, 0, 0,
76  "Memory allocation failed : %s\n", extra);
77  else
78  __xmlRaiseError(NULL, channel, data,
80  XML_ERR_FATAL, NULL, 0, NULL, NULL, NULL, 0, 0,
81  "Memory allocation failed\n");
82 }
83 
92 static void LIBXML_ATTR_FORMAT(3,0)
93 xmlErrValid(xmlValidCtxtPtr ctxt, xmlParserErrors error,
94  const char *msg, const char *extra)
95 {
96  xmlGenericErrorFunc channel = NULL;
97  xmlParserCtxtPtr pctxt = NULL;
98  void *data = NULL;
99 
100  if (ctxt != NULL) {
101  channel = ctxt->error;
102  data = ctxt->userData;
103  /* Look up flag to detect if it is part of a parsing
104  context */
105  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
106  long delta = (char *) ctxt - (char *) ctxt->userData;
107  if ((delta > 0) && (delta < 250))
108  pctxt = ctxt->userData;
109  }
110  }
111  if (extra)
112  __xmlRaiseError(NULL, channel, data,
113  pctxt, NULL, XML_FROM_VALID, error,
114  XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0,
115  msg, extra);
116  else
117  __xmlRaiseError(NULL, channel, data,
118  pctxt, NULL, XML_FROM_VALID, error,
119  XML_ERR_ERROR, NULL, 0, NULL, NULL, NULL, 0, 0,
120  "%s", msg);
121 }
122 
123 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
124 
135 static void LIBXML_ATTR_FORMAT(4,0)
136 xmlErrValidNode(xmlValidCtxtPtr ctxt,
138  const char *msg, const xmlChar * str1,
139  const xmlChar * str2, const xmlChar * str3)
140 {
141  xmlStructuredErrorFunc schannel = NULL;
142  xmlGenericErrorFunc channel = NULL;
143  xmlParserCtxtPtr pctxt = NULL;
144  void *data = NULL;
145 
146  if (ctxt != NULL) {
147  channel = ctxt->error;
148  data = ctxt->userData;
149  /* Look up flag to detect if it is part of a parsing
150  context */
151  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
152  long delta = (char *) ctxt - (char *) ctxt->userData;
153  if ((delta > 0) && (delta < 250))
154  pctxt = ctxt->userData;
155  }
156  }
157  __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
158  XML_ERR_ERROR, NULL, 0,
159  (const char *) str1,
160  (const char *) str2,
161  (const char *) str3, 0, 0, msg, str1, str2, str3);
162 }
163 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
164 
165 #ifdef LIBXML_VALID_ENABLED
166 
177 static void LIBXML_ATTR_FORMAT(4,0)
178 xmlErrValidNodeNr(xmlValidCtxtPtr ctxt,
180  const char *msg, const xmlChar * str1,
181  int int2, const xmlChar * str3)
182 {
183  xmlStructuredErrorFunc schannel = NULL;
184  xmlGenericErrorFunc channel = NULL;
185  xmlParserCtxtPtr pctxt = NULL;
186  void *data = NULL;
187 
188  if (ctxt != NULL) {
189  channel = ctxt->error;
190  data = ctxt->userData;
191  /* Look up flag to detect if it is part of a parsing
192  context */
193  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
194  long delta = (char *) ctxt - (char *) ctxt->userData;
195  if ((delta > 0) && (delta < 250))
196  pctxt = ctxt->userData;
197  }
198  }
199  __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
200  XML_ERR_ERROR, NULL, 0,
201  (const char *) str1,
202  (const char *) str3,
203  NULL, int2, 0, msg, str1, int2, str3);
204 }
205 
217 static void LIBXML_ATTR_FORMAT(4,0)
218 xmlErrValidWarning(xmlValidCtxtPtr ctxt,
220  const char *msg, const xmlChar * str1,
221  const xmlChar * str2, const xmlChar * str3)
222 {
223  xmlStructuredErrorFunc schannel = NULL;
224  xmlGenericErrorFunc channel = NULL;
225  xmlParserCtxtPtr pctxt = NULL;
226  void *data = NULL;
227 
228  if (ctxt != NULL) {
229  channel = ctxt->warning;
230  data = ctxt->userData;
231  /* Look up flag to detect if it is part of a parsing
232  context */
233  if (ctxt->flags & XML_VCTXT_USE_PCTXT) {
234  long delta = (char *) ctxt - (char *) ctxt->userData;
235  if ((delta > 0) && (delta < 250))
236  pctxt = ctxt->userData;
237  }
238  }
239  __xmlRaiseError(schannel, channel, data, pctxt, node, XML_FROM_VALID, error,
240  XML_ERR_WARNING, NULL, 0,
241  (const char *) str1,
242  (const char *) str2,
243  (const char *) str3, 0, 0, msg, str1, str2, str3);
244 }
245 
246 
247 
248 #ifdef LIBXML_REGEXP_ENABLED
249 /*
250  * If regexp are enabled we can do continuous validation without the
251  * need of a tree to validate the content model. this is done in each
252  * callbacks.
253  * Each xmlValidState represent the validation state associated to the
254  * set of nodes currently open from the document root to the current element.
255  */
256 
257 
258 typedef struct _xmlValidState {
259  xmlElementPtr elemDecl; /* pointer to the content model */
260  xmlNodePtr node; /* pointer to the current node */
261  xmlRegExecCtxtPtr exec; /* regexp runtime */
262 } _xmlValidState;
263 
264 
265 static int
266 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementPtr elemDecl, xmlNodePtr node) {
267  if ((ctxt->vstateMax == 0) || (ctxt->vstateTab == NULL)) {
268  ctxt->vstateMax = 10;
269  ctxt->vstateTab = (xmlValidState *) xmlMalloc(ctxt->vstateMax *
270  sizeof(ctxt->vstateTab[0]));
271  if (ctxt->vstateTab == NULL) {
272  xmlVErrMemory(ctxt, "malloc failed");
273  return(-1);
274  }
275  }
276 
277  if (ctxt->vstateNr >= ctxt->vstateMax) {
278  xmlValidState *tmp;
279 
280  tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
281  2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
282  if (tmp == NULL) {
283  xmlVErrMemory(ctxt, "realloc failed");
284  return(-1);
285  }
286  ctxt->vstateMax *= 2;
287  ctxt->vstateTab = tmp;
288  }
289  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr];
290  ctxt->vstateTab[ctxt->vstateNr].elemDecl = elemDecl;
291  ctxt->vstateTab[ctxt->vstateNr].node = node;
292  if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
293  if (elemDecl->contModel == NULL)
294  xmlValidBuildContentModel(ctxt, elemDecl);
295  if (elemDecl->contModel != NULL) {
296  ctxt->vstateTab[ctxt->vstateNr].exec =
297  xmlRegNewExecCtxt(elemDecl->contModel, NULL, NULL);
298  } else {
299  ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
300  xmlErrValidNode(ctxt, (xmlNodePtr) elemDecl,
302  "Failed to build content model regexp for %s\n",
303  node->name, NULL, NULL);
304  }
305  }
306  return(ctxt->vstateNr++);
307 }
308 
309 static int
310 vstateVPop(xmlValidCtxtPtr ctxt) {
311  xmlElementPtr elemDecl;
312 
313  if (ctxt->vstateNr < 1) return(-1);
314  ctxt->vstateNr--;
315  elemDecl = ctxt->vstateTab[ctxt->vstateNr].elemDecl;
316  ctxt->vstateTab[ctxt->vstateNr].elemDecl = NULL;
317  ctxt->vstateTab[ctxt->vstateNr].node = NULL;
318  if ((elemDecl != NULL) && (elemDecl->etype == XML_ELEMENT_TYPE_ELEMENT)) {
319  xmlRegFreeExecCtxt(ctxt->vstateTab[ctxt->vstateNr].exec);
320  }
321  ctxt->vstateTab[ctxt->vstateNr].exec = NULL;
322  if (ctxt->vstateNr >= 1)
323  ctxt->vstate = &ctxt->vstateTab[ctxt->vstateNr - 1];
324  else
325  ctxt->vstate = NULL;
326  return(ctxt->vstateNr);
327 }
328 
329 #else /* not LIBXML_REGEXP_ENABLED */
330 /*
331  * If regexp are not enabled, it uses a home made algorithm less
332  * complex and easier to
333  * debug/maintain than a generic NFA -> DFA state based algo. The
334  * only restriction is on the deepness of the tree limited by the
335  * size of the occurs bitfield
336  *
337  * this is the content of a saved state for rollbacks
338  */
339 
340 #define ROLLBACK_OR 0
341 #define ROLLBACK_PARENT 1
342 
343 typedef struct _xmlValidState {
344  xmlElementContentPtr cont; /* pointer to the content model subtree */
345  xmlNodePtr node; /* pointer to the current node in the list */
346  long occurs;/* bitfield for multiple occurrences */
347  unsigned char depth; /* current depth in the overall tree */
348  unsigned char state; /* ROLLBACK_XXX */
349 } _xmlValidState;
350 
351 #define MAX_RECURSE 25000
352 #define MAX_DEPTH ((sizeof(_xmlValidState.occurs)) * 8)
353 #define CONT ctxt->vstate->cont
354 #define NODE ctxt->vstate->node
355 #define DEPTH ctxt->vstate->depth
356 #define OCCURS ctxt->vstate->occurs
357 #define STATE ctxt->vstate->state
358 
359 #define OCCURRENCE (ctxt->vstate->occurs & (1 << DEPTH))
360 #define PARENT_OCCURRENCE (ctxt->vstate->occurs & ((1 << DEPTH) - 1))
361 
362 #define SET_OCCURRENCE ctxt->vstate->occurs |= (1 << DEPTH)
363 #define RESET_OCCURRENCE ctxt->vstate->occurs &= ((1 << DEPTH) - 1)
364 
365 static int
366 vstateVPush(xmlValidCtxtPtr ctxt, xmlElementContentPtr cont,
367  xmlNodePtr node, unsigned char depth, long occurs,
368  unsigned char state) {
369  int i = ctxt->vstateNr - 1;
370 
371  if (ctxt->vstateNr > MAX_RECURSE) {
372  return(-1);
373  }
374  if (ctxt->vstateTab == NULL) {
375  ctxt->vstateMax = 8;
376  ctxt->vstateTab = (xmlValidState *) xmlMalloc(
377  ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
378  if (ctxt->vstateTab == NULL) {
379  xmlVErrMemory(ctxt, "malloc failed");
380  return(-1);
381  }
382  }
383  if (ctxt->vstateNr >= ctxt->vstateMax) {
384  xmlValidState *tmp;
385 
386  tmp = (xmlValidState *) xmlRealloc(ctxt->vstateTab,
387  2 * ctxt->vstateMax * sizeof(ctxt->vstateTab[0]));
388  if (tmp == NULL) {
389  xmlVErrMemory(ctxt, "malloc failed");
390  return(-1);
391  }
392  ctxt->vstateMax *= 2;
393  ctxt->vstateTab = tmp;
394  ctxt->vstate = &ctxt->vstateTab[0];
395  }
396  /*
397  * Don't push on the stack a state already here
398  */
399  if ((i >= 0) && (ctxt->vstateTab[i].cont == cont) &&
400  (ctxt->vstateTab[i].node == node) &&
401  (ctxt->vstateTab[i].depth == depth) &&
402  (ctxt->vstateTab[i].occurs == occurs) &&
403  (ctxt->vstateTab[i].state == state))
404  return(ctxt->vstateNr);
405  ctxt->vstateTab[ctxt->vstateNr].cont = cont;
406  ctxt->vstateTab[ctxt->vstateNr].node = node;
407  ctxt->vstateTab[ctxt->vstateNr].depth = depth;
408  ctxt->vstateTab[ctxt->vstateNr].occurs = occurs;
409  ctxt->vstateTab[ctxt->vstateNr].state = state;
410  return(ctxt->vstateNr++);
411 }
412 
413 static int
414 vstateVPop(xmlValidCtxtPtr ctxt) {
415  if (ctxt->vstateNr <= 1) return(-1);
416  ctxt->vstateNr--;
417  ctxt->vstate = &ctxt->vstateTab[0];
418  ctxt->vstate->cont = ctxt->vstateTab[ctxt->vstateNr].cont;
419  ctxt->vstate->node = ctxt->vstateTab[ctxt->vstateNr].node;
420  ctxt->vstate->depth = ctxt->vstateTab[ctxt->vstateNr].depth;
421  ctxt->vstate->occurs = ctxt->vstateTab[ctxt->vstateNr].occurs;
422  ctxt->vstate->state = ctxt->vstateTab[ctxt->vstateNr].state;
423  return(ctxt->vstateNr);
424 }
425 
426 #endif /* LIBXML_REGEXP_ENABLED */
427 
428 static int
429 nodeVPush(xmlValidCtxtPtr ctxt, xmlNodePtr value)
430 {
431  if (ctxt->nodeMax <= 0) {
432  ctxt->nodeMax = 4;
433  ctxt->nodeTab =
434  (xmlNodePtr *) xmlMalloc(ctxt->nodeMax *
435  sizeof(ctxt->nodeTab[0]));
436  if (ctxt->nodeTab == NULL) {
437  xmlVErrMemory(ctxt, "malloc failed");
438  ctxt->nodeMax = 0;
439  return (0);
440  }
441  }
442  if (ctxt->nodeNr >= ctxt->nodeMax) {
443  xmlNodePtr *tmp;
444  tmp = (xmlNodePtr *) xmlRealloc(ctxt->nodeTab,
445  ctxt->nodeMax * 2 * sizeof(ctxt->nodeTab[0]));
446  if (tmp == NULL) {
447  xmlVErrMemory(ctxt, "realloc failed");
448  return (0);
449  }
450  ctxt->nodeMax *= 2;
451  ctxt->nodeTab = tmp;
452  }
453  ctxt->nodeTab[ctxt->nodeNr] = value;
454  ctxt->node = value;
455  return (ctxt->nodeNr++);
456 }
457 static xmlNodePtr
458 nodeVPop(xmlValidCtxtPtr ctxt)
459 {
460  xmlNodePtr ret;
461 
462  if (ctxt->nodeNr <= 0)
463  return (NULL);
464  ctxt->nodeNr--;
465  if (ctxt->nodeNr > 0)
466  ctxt->node = ctxt->nodeTab[ctxt->nodeNr - 1];
467  else
468  ctxt->node = NULL;
469  ret = ctxt->nodeTab[ctxt->nodeNr];
470  ctxt->nodeTab[ctxt->nodeNr] = NULL;
471  return (ret);
472 }
473 
474 #ifdef DEBUG_VALID_ALGO
475 static void
476 xmlValidPrintNode(xmlNodePtr cur) {
477  if (cur == NULL) {
479  return;
480  }
481  switch (cur->type) {
482  case XML_ELEMENT_NODE:
484  break;
485  case XML_TEXT_NODE:
487  break;
490  break;
491  case XML_ENTITY_REF_NODE:
492  xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
493  break;
494  case XML_PI_NODE:
495  xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
496  break;
497  case XML_COMMENT_NODE:
499  break;
500  case XML_ATTRIBUTE_NODE:
502  break;
503  case XML_ENTITY_NODE:
505  break;
506  case XML_DOCUMENT_NODE:
508  break;
511  break;
514  break;
515  case XML_NOTATION_NODE:
517  break;
520  break;
521  case XML_DTD_NODE:
523  break;
524  case XML_ELEMENT_DECL:
526  break;
527  case XML_ATTRIBUTE_DECL:
529  break;
530  case XML_ENTITY_DECL:
532  break;
533  case XML_NAMESPACE_DECL:
535  break;
536  case XML_XINCLUDE_START:
538  break;
539  case XML_XINCLUDE_END:
541  break;
542  }
543 }
544 
545 static void
546 xmlValidPrintNodeList(xmlNodePtr cur) {
547  if (cur == NULL)
549  while (cur != NULL) {
550  xmlValidPrintNode(cur);
551  cur = cur->next;
552  }
553 }
554 
555 static void
556 xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
557  char expr[5000];
558 
559  expr[0] = 0;
561  xmlValidPrintNodeList(cur);
563  xmlSnprintfElementContent(expr, 5000, cont, 1);
565 }
566 
567 static void
568 xmlValidDebugState(xmlValidStatePtr state) {
570  if (state->cont == NULL)
572  else
573  switch (state->cont->type) {
576  break;
579  state->cont->name);
580  break;
583  break;
586  break;
587  }
588  xmlValidPrintNode(state->node);
590  state->depth, state->occurs, state->state);
591 }
592 
593 static void
594 xmlValidStateDebug(xmlValidCtxtPtr ctxt) {
595  int i, j;
596 
598  xmlValidDebugState(ctxt->vstate);
600  ctxt->vstateNr - 1);
601  for (i = 0, j = ctxt->vstateNr - 1;(i < 3) && (j > 0);i++,j--)
602  xmlValidDebugState(&ctxt->vstateTab[j]);
604 }
605 
606 /*****
607 #define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
608  *****/
609 
610 #define DEBUG_VALID_STATE(n,c) xmlValidStateDebug(ctxt);
611 #define DEBUG_VALID_MSG(m) \
612  xmlGenericError(xmlGenericErrorContext, "%s\n", m);
613 
614 #else
615 #define DEBUG_VALID_STATE(n,c)
616 #define DEBUG_VALID_MSG(m)
617 #endif
618 
619 /* TODO: use hash table for accesses to elem and attribute definitions */
620 
621 
622 #define CHECK_DTD \
623  if (doc == NULL) return(0); \
624  else if ((doc->intSubset == NULL) && \
625  (doc->extSubset == NULL)) return(0)
626 
627 #ifdef LIBXML_REGEXP_ENABLED
628 
629 /************************************************************************
630  * *
631  * Content model validation based on the regexps *
632  * *
633  ************************************************************************/
634 
645 static int
646 xmlValidBuildAContentModel(xmlElementContentPtr content,
647  xmlValidCtxtPtr ctxt,
648  const xmlChar *name) {
649  if (content == NULL) {
650  xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
651  "Found NULL content in content model of %s\n",
652  name, NULL, NULL);
653  return(0);
654  }
655  switch (content->type) {
657  xmlErrValidNode(ctxt, NULL, XML_ERR_INTERNAL_ERROR,
658  "Found PCDATA in content model of %s\n",
659  name, NULL, NULL);
660  return(0);
661  break;
663  xmlAutomataStatePtr oldstate = ctxt->state;
664  xmlChar fn[50];
665  xmlChar *fullname;
666 
667  fullname = xmlBuildQName(content->name, content->prefix, fn, 50);
668  if (fullname == NULL) {
669  xmlVErrMemory(ctxt, "Building content model");
670  return(0);
671  }
672 
673  switch (content->ocur) {
675  ctxt->state = xmlAutomataNewTransition(ctxt->am,
676  ctxt->state, NULL, fullname, NULL);
677  break;
679  ctxt->state = xmlAutomataNewTransition(ctxt->am,
680  ctxt->state, NULL, fullname, NULL);
681  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
682  break;
684  ctxt->state = xmlAutomataNewTransition(ctxt->am,
685  ctxt->state, NULL, fullname, NULL);
686  xmlAutomataNewTransition(ctxt->am, ctxt->state,
687  ctxt->state, fullname, NULL);
688  break;
690  ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
691  ctxt->state, NULL);
692  xmlAutomataNewTransition(ctxt->am,
693  ctxt->state, ctxt->state, fullname, NULL);
694  break;
695  }
696  if ((fullname != fn) && (fullname != content->name))
697  xmlFree(fullname);
698  break;
699  }
701  xmlAutomataStatePtr oldstate, oldend;
703 
704  /*
705  * Simply iterate over the content
706  */
707  oldstate = ctxt->state;
708  ocur = content->ocur;
709  if (ocur != XML_ELEMENT_CONTENT_ONCE) {
710  ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldstate, NULL);
711  oldstate = ctxt->state;
712  }
713  do {
714  xmlValidBuildAContentModel(content->c1, ctxt, name);
715  content = content->c2;
716  } while ((content->type == XML_ELEMENT_CONTENT_SEQ) &&
717  (content->ocur == XML_ELEMENT_CONTENT_ONCE));
718  xmlValidBuildAContentModel(content, ctxt, name);
719  oldend = ctxt->state;
720  ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
721  switch (ocur) {
723  break;
725  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
726  break;
728  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
729  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
730  break;
732  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
733  break;
734  }
735  break;
736  }
737  case XML_ELEMENT_CONTENT_OR: {
738  xmlAutomataStatePtr oldstate, oldend;
740 
741  ocur = content->ocur;
742  if ((ocur == XML_ELEMENT_CONTENT_PLUS) ||
743  (ocur == XML_ELEMENT_CONTENT_MULT)) {
744  ctxt->state = xmlAutomataNewEpsilon(ctxt->am,
745  ctxt->state, NULL);
746  }
747  oldstate = ctxt->state;
748  oldend = xmlAutomataNewState(ctxt->am);
749 
750  /*
751  * iterate over the subtypes and remerge the end with an
752  * epsilon transition
753  */
754  do {
755  ctxt->state = oldstate;
756  xmlValidBuildAContentModel(content->c1, ctxt, name);
757  xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
758  content = content->c2;
759  } while ((content->type == XML_ELEMENT_CONTENT_OR) &&
760  (content->ocur == XML_ELEMENT_CONTENT_ONCE));
761  ctxt->state = oldstate;
762  xmlValidBuildAContentModel(content, ctxt, name);
763  xmlAutomataNewEpsilon(ctxt->am, ctxt->state, oldend);
764  ctxt->state = xmlAutomataNewEpsilon(ctxt->am, oldend, NULL);
765  switch (ocur) {
767  break;
769  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
770  break;
772  xmlAutomataNewEpsilon(ctxt->am, oldstate, ctxt->state);
773  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
774  break;
776  xmlAutomataNewEpsilon(ctxt->am, oldend, oldstate);
777  break;
778  }
779  break;
780  }
781  default:
782  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
783  "ContentModel broken for element %s\n",
784  (const char *) name);
785  return(0);
786  }
787  return(1);
788 }
799 int
800 xmlValidBuildContentModel(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
801 
802  if ((ctxt == NULL) || (elem == NULL))
803  return(0);
804  if (elem->type != XML_ELEMENT_DECL)
805  return(0);
806  if (elem->etype != XML_ELEMENT_TYPE_ELEMENT)
807  return(1);
808  /* TODO: should we rebuild in this case ? */
809  if (elem->contModel != NULL) {
810  if (!xmlRegexpIsDeterminist(elem->contModel)) {
811  ctxt->valid = 0;
812  return(0);
813  }
814  return(1);
815  }
816 
817  ctxt->am = xmlNewAutomata();
818  if (ctxt->am == NULL) {
819  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
821  "Cannot create automata for element %s\n",
822  elem->name, NULL, NULL);
823  return(0);
824  }
825  ctxt->state = xmlAutomataGetInitState(ctxt->am);
826  xmlValidBuildAContentModel(elem->content, ctxt, elem->name);
827  xmlAutomataSetFinalState(ctxt->am, ctxt->state);
828  elem->contModel = xmlAutomataCompile(ctxt->am);
829  if (xmlRegexpIsDeterminist(elem->contModel) != 1) {
830  char expr[5000];
831  expr[0] = 0;
832  xmlSnprintfElementContent(expr, 5000, elem->content, 1);
833  xmlErrValidNode(ctxt, (xmlNodePtr) elem,
835  "Content model of %s is not determinist: %s\n",
836  elem->name, BAD_CAST expr, NULL);
837 #ifdef DEBUG_REGEXP_ALGO
838  xmlRegexpPrint(stderr, elem->contModel);
839 #endif
840  ctxt->valid = 0;
841  ctxt->state = NULL;
842  xmlFreeAutomata(ctxt->am);
843  ctxt->am = NULL;
844  return(0);
845  }
846  ctxt->state = NULL;
847  xmlFreeAutomata(ctxt->am);
848  ctxt->am = NULL;
849  return(1);
850 }
851 
852 #endif /* LIBXML_REGEXP_ENABLED */
853 
854 /****************************************************************
855  * *
856  * Util functions for data allocation/deallocation *
857  * *
858  ****************************************************************/
859 
867 xmlValidCtxtPtr xmlNewValidCtxt(void) {
869 
870  if ((ret = xmlMalloc(sizeof (xmlValidCtxt))) == NULL) {
871  xmlVErrMemory(NULL, "malloc failed");
872  return (NULL);
873  }
874 
875  (void) memset(ret, 0, sizeof (xmlValidCtxt));
876 
877  return (ret);
878 }
879 
886 void
887 xmlFreeValidCtxt(xmlValidCtxtPtr cur) {
888  if (cur->vstateTab != NULL)
889  xmlFree(cur->vstateTab);
890  if (cur->nodeTab != NULL)
891  xmlFree(cur->nodeTab);
892  xmlFree(cur);
893 }
894 
895 #endif /* LIBXML_VALID_ENABLED */
896 
911  xmlDictPtr dict = NULL;
912 
913  if (doc != NULL)
914  dict = doc->dict;
915 
916  switch(type) {
918  if (name == NULL) {
919  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
920  "xmlNewElementContent : name == NULL !\n",
921  NULL);
922  }
923  break;
927  if (name != NULL) {
928  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
929  "xmlNewElementContent : name != NULL !\n",
930  NULL);
931  }
932  break;
933  default:
934  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
935  "Internal: ELEMENT content corrupted invalid type\n",
936  NULL);
937  return(NULL);
938  }
940  if (ret == NULL) {
941  xmlVErrMemory(NULL, "malloc failed");
942  return(NULL);
943  }
944  memset(ret, 0, sizeof(xmlElementContent));
945  ret->type = type;
947  if (name != NULL) {
948  int l;
949  const xmlChar *tmp;
950 
951  tmp = xmlSplitQName3(name, &l);
952  if (tmp == NULL) {
953  if (dict == NULL)
954  ret->name = xmlStrdup(name);
955  else
956  ret->name = xmlDictLookup(dict, name, -1);
957  } else {
958  if (dict == NULL) {
959  ret->prefix = xmlStrndup(name, l);
960  ret->name = xmlStrdup(tmp);
961  } else {
962  ret->prefix = xmlDictLookup(dict, name, l);
963  ret->name = xmlDictLookup(dict, tmp, -1);
964  }
965  }
966  }
967  return(ret);
968 }
969 
983 }
984 
996  xmlElementContentPtr ret = NULL, prev = NULL, tmp;
997  xmlDictPtr dict = NULL;
998 
999  if (cur == NULL) return(NULL);
1000 
1001  if (doc != NULL)
1002  dict = doc->dict;
1003 
1005  if (ret == NULL) {
1006  xmlVErrMemory(NULL, "malloc failed");
1007  return(NULL);
1008  }
1009  memset(ret, 0, sizeof(xmlElementContent));
1010  ret->type = cur->type;
1011  ret->ocur = cur->ocur;
1012  if (cur->name != NULL) {
1013  if (dict)
1014  ret->name = xmlDictLookup(dict, cur->name, -1);
1015  else
1016  ret->name = xmlStrdup(cur->name);
1017  }
1018 
1019  if (cur->prefix != NULL) {
1020  if (dict)
1021  ret->prefix = xmlDictLookup(dict, cur->prefix, -1);
1022  else
1023  ret->prefix = xmlStrdup(cur->prefix);
1024  }
1025  if (cur->c1 != NULL)
1026  ret->c1 = xmlCopyDocElementContent(doc, cur->c1);
1027  if (ret->c1 != NULL)
1028  ret->c1->parent = ret;
1029  if (cur->c2 != NULL) {
1030  prev = ret;
1031  cur = cur->c2;
1032  while (cur != NULL) {
1034  if (tmp == NULL) {
1035  xmlVErrMemory(NULL, "malloc failed");
1036  return(ret);
1037  }
1038  memset(tmp, 0, sizeof(xmlElementContent));
1039  tmp->type = cur->type;
1040  tmp->ocur = cur->ocur;
1041  prev->c2 = tmp;
1042  tmp->parent = prev;
1043  if (cur->name != NULL) {
1044  if (dict)
1045  tmp->name = xmlDictLookup(dict, cur->name, -1);
1046  else
1047  tmp->name = xmlStrdup(cur->name);
1048  }
1049 
1050  if (cur->prefix != NULL) {
1051  if (dict)
1052  tmp->prefix = xmlDictLookup(dict, cur->prefix, -1);
1053  else
1054  tmp->prefix = xmlStrdup(cur->prefix);
1055  }
1056  if (cur->c1 != NULL)
1057  tmp->c1 = xmlCopyDocElementContent(doc,cur->c1);
1058  if (tmp->c1 != NULL)
1059  tmp->c1->parent = ret;
1060  prev = tmp;
1061  cur = cur->c2;
1062  }
1063  }
1064  return(ret);
1065 }
1066 
1078  return(xmlCopyDocElementContent(NULL, cur));
1079 }
1080 
1088 void
1090  xmlDictPtr dict = NULL;
1091  size_t depth = 0;
1092 
1093  if (cur == NULL)
1094  return;
1095  if (doc != NULL)
1096  dict = doc->dict;
1097 
1098  while (1) {
1100 
1101  while ((cur->c1 != NULL) || (cur->c2 != NULL)) {
1102  cur = (cur->c1 != NULL) ? cur->c1 : cur->c2;
1103  depth += 1;
1104  }
1105 
1106  switch (cur->type) {
1111  break;
1112  default:
1113  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1114  "Internal: ELEMENT content corrupted invalid type\n",
1115  NULL);
1116  return;
1117  }
1118  if (dict) {
1119  if ((cur->name != NULL) && (!xmlDictOwns(dict, cur->name)))
1120  xmlFree((xmlChar *) cur->name);
1121  if ((cur->prefix != NULL) && (!xmlDictOwns(dict, cur->prefix)))
1122  xmlFree((xmlChar *) cur->prefix);
1123  } else {
1124  if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1125  if (cur->prefix != NULL) xmlFree((xmlChar *) cur->prefix);
1126  }
1127  parent = cur->parent;
1128  if ((depth == 0) || (parent == NULL)) {
1129  xmlFree(cur);
1130  break;
1131  }
1132  if (cur == parent->c1)
1133  parent->c1 = NULL;
1134  else
1135  parent->c2 = NULL;
1136  xmlFree(cur);
1137 
1138  if (parent->c2 != NULL) {
1139  cur = parent->c2;
1140  } else {
1141  depth -= 1;
1142  cur = parent;
1143  }
1144  }
1145 }
1146 
1154 void
1157 }
1158 
1159 #ifdef LIBXML_OUTPUT_ENABLED
1160 
1167 static void
1168 xmlDumpElementOccur(xmlBufferPtr buf, xmlElementContentPtr cur) {
1169  switch (cur->ocur) {
1171  break;
1173  xmlBufferWriteChar(buf, "?");
1174  break;
1176  xmlBufferWriteChar(buf, "*");
1177  break;
1179  xmlBufferWriteChar(buf, "+");
1180  break;
1181  }
1182 }
1183 
1191 static void
1192 xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content) {
1194 
1195  if (content == NULL) return;
1196 
1197  xmlBufferWriteChar(buf, "(");
1198  cur = content;
1199 
1200  do {
1201  if (cur == NULL) return;
1202 
1203  switch (cur->type) {
1205  xmlBufferWriteChar(buf, "#PCDATA");
1206  break;
1208  if (cur->prefix != NULL) {
1209  xmlBufferWriteCHAR(buf, cur->prefix);
1210  xmlBufferWriteChar(buf, ":");
1211  }
1212  xmlBufferWriteCHAR(buf, cur->name);
1213  break;
1216  if ((cur != content) &&
1217  (cur->parent != NULL) &&
1218  ((cur->type != cur->parent->type) ||
1219  (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1220  xmlBufferWriteChar(buf, "(");
1221  cur = cur->c1;
1222  continue;
1223  default:
1224  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1225  "Internal: ELEMENT cur corrupted invalid type\n",
1226  NULL);
1227  }
1228 
1229  while (cur != content) {
1230  xmlElementContentPtr parent = cur->parent;
1231 
1232  if (parent == NULL) return;
1233 
1234  if (((cur->type == XML_ELEMENT_CONTENT_OR) ||
1235  (cur->type == XML_ELEMENT_CONTENT_SEQ)) &&
1236  ((cur->type != parent->type) ||
1237  (cur->ocur != XML_ELEMENT_CONTENT_ONCE)))
1238  xmlBufferWriteChar(buf, ")");
1239  xmlDumpElementOccur(buf, cur);
1240 
1241  if (cur == parent->c1) {
1242  if (parent->type == XML_ELEMENT_CONTENT_SEQ)
1243  xmlBufferWriteChar(buf, " , ");
1244  else if (parent->type == XML_ELEMENT_CONTENT_OR)
1245  xmlBufferWriteChar(buf, " | ");
1246 
1247  cur = parent->c2;
1248  break;
1249  }
1250 
1251  cur = parent;
1252  }
1253  } while (cur != content);
1254 
1255  xmlBufferWriteChar(buf, ")");
1256  xmlDumpElementOccur(buf, content);
1257 }
1258 
1267 void
1268 xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1270  int englob ATTRIBUTE_UNUSED) {
1271 }
1272 #endif /* LIBXML_OUTPUT_ENABLED */
1273 
1284 void
1286  int len;
1287 
1288  if (content == NULL) return;
1289  len = strlen(buf);
1290  if (size - len < 50) {
1291  if ((size - len > 4) && (buf[len - 1] != '.'))
1292  strcat(buf, " ...");
1293  return;
1294  }
1295  if (englob) strcat(buf, "(");
1296  switch (content->type) {
1298  strcat(buf, "#PCDATA");
1299  break;
1301  int qnameLen = xmlStrlen(content->name);
1302 
1303  if (content->prefix != NULL)
1304  qnameLen += xmlStrlen(content->prefix) + 1;
1305  if (size - len < qnameLen + 10) {
1306  strcat(buf, " ...");
1307  return;
1308  }
1309  if (content->prefix != NULL) {
1310  strcat(buf, (char *) content->prefix);
1311  strcat(buf, ":");
1312  }
1313  if (content->name != NULL)
1314  strcat(buf, (char *) content->name);
1315  break;
1316  }
1318  if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1319  (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1321  else
1323  len = strlen(buf);
1324  if (size - len < 50) {
1325  if ((size - len > 4) && (buf[len - 1] != '.'))
1326  strcat(buf, " ...");
1327  return;
1328  }
1329  strcat(buf, " , ");
1330  if (((content->c2->type == XML_ELEMENT_CONTENT_OR) ||
1331  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1332  (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1334  else
1336  break;
1338  if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
1339  (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
1341  else
1343  len = strlen(buf);
1344  if (size - len < 50) {
1345  if ((size - len > 4) && (buf[len - 1] != '.'))
1346  strcat(buf, " ...");
1347  return;
1348  }
1349  strcat(buf, " | ");
1350  if (((content->c2->type == XML_ELEMENT_CONTENT_SEQ) ||
1351  (content->c2->ocur != XML_ELEMENT_CONTENT_ONCE)) &&
1352  (content->c2->type != XML_ELEMENT_CONTENT_ELEMENT))
1354  else
1356  break;
1357  }
1358  if (size - strlen(buf) <= 2) return;
1359  if (englob)
1360  strcat(buf, ")");
1361  switch (content->ocur) {
1363  break;
1365  strcat(buf, "?");
1366  break;
1368  strcat(buf, "*");
1369  break;
1371  strcat(buf, "+");
1372  break;
1373  }
1374 }
1375 
1376 /****************************************************************
1377  * *
1378  * Registration of DTD declarations *
1379  * *
1380  ****************************************************************/
1381 
1388 static void
1390  if (elem == NULL) return;
1392  xmlFreeDocElementContent(elem->doc, elem->content);
1393  if (elem->name != NULL)
1394  xmlFree((xmlChar *) elem->name);
1395  if (elem->prefix != NULL)
1396  xmlFree((xmlChar *) elem->prefix);
1397 #ifdef LIBXML_REGEXP_ENABLED
1398  if (elem->contModel != NULL)
1399  xmlRegFreeRegexp(elem->contModel);
1400 #endif
1401  xmlFree(elem);
1402 }
1403 
1404 
1419  xmlDtdPtr dtd, const xmlChar *name,
1424  xmlAttributePtr oldAttributes = NULL;
1425  xmlChar *ns, *uqname;
1426 
1427  if (dtd == NULL) {
1428  return(NULL);
1429  }
1430  if (name == NULL) {
1431  return(NULL);
1432  }
1433 
1434  switch (type) {
1436  if (content != NULL) {
1437  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1438  "xmlAddElementDecl: content != NULL for EMPTY\n",
1439  NULL);
1440  return(NULL);
1441  }
1442  break;
1443  case XML_ELEMENT_TYPE_ANY:
1444  if (content != NULL) {
1445  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1446  "xmlAddElementDecl: content != NULL for ANY\n",
1447  NULL);
1448  return(NULL);
1449  }
1450  break;
1452  if (content == NULL) {
1453  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1454  "xmlAddElementDecl: content == NULL for MIXED\n",
1455  NULL);
1456  return(NULL);
1457  }
1458  break;
1460  if (content == NULL) {
1461  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1462  "xmlAddElementDecl: content == NULL for ELEMENT\n",
1463  NULL);
1464  return(NULL);
1465  }
1466  break;
1467  default:
1468  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
1469  "Internal: ELEMENT decl corrupted invalid type\n",
1470  NULL);
1471  return(NULL);
1472  }
1473 
1474  /*
1475  * check if name is a QName
1476  */
1477  uqname = xmlSplitQName2(name, &ns);
1478  if (uqname != NULL)
1479  name = uqname;
1480 
1481  /*
1482  * Create the Element table if needed.
1483  */
1485  if (table == NULL) {
1486  xmlDictPtr dict = NULL;
1487 
1488  if (dtd->doc != NULL)
1489  dict = dtd->doc->dict;
1490  table = xmlHashCreateDict(0, dict);
1491  dtd->elements = (void *) table;
1492  }
1493  if (table == NULL) {
1494  xmlVErrMemory(ctxt,
1495  "xmlAddElementDecl: Table creation failed!\n");
1496  if (uqname != NULL)
1497  xmlFree(uqname);
1498  if (ns != NULL)
1499  xmlFree(ns);
1500  return(NULL);
1501  }
1502 
1503  /*
1504  * lookup old attributes inserted on an undefined element in the
1505  * internal subset.
1506  */
1507  if ((dtd->doc != NULL) && (dtd->doc->intSubset != NULL)) {
1508  ret = xmlHashLookup2(dtd->doc->intSubset->elements, name, ns);
1509  if ((ret != NULL) && (ret->etype == XML_ELEMENT_TYPE_UNDEFINED)) {
1510  oldAttributes = ret->attributes;
1511  ret->attributes = NULL;
1512  xmlHashRemoveEntry2(dtd->doc->intSubset->elements, name, ns, NULL);
1514  }
1515  }
1516 
1517  /*
1518  * The element may already be present if one of its attribute
1519  * was registered first
1520  */
1522  if (ret != NULL) {
1523  if (ret->etype != XML_ELEMENT_TYPE_UNDEFINED) {
1524 #ifdef LIBXML_VALID_ENABLED
1525  /*
1526  * The element is already defined in this DTD.
1527  */
1528  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1529  "Redefinition of element %s\n",
1530  name, NULL, NULL);
1531 #endif /* LIBXML_VALID_ENABLED */
1532  if (uqname != NULL)
1533  xmlFree(uqname);
1534  if (ns != NULL)
1535  xmlFree(ns);
1536  return(NULL);
1537  }
1538  if (ns != NULL) {
1539  xmlFree(ns);
1540  ns = NULL;
1541  }
1542  } else {
1543  ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1544  if (ret == NULL) {
1545  xmlVErrMemory(ctxt, "malloc failed");
1546  if (uqname != NULL)
1547  xmlFree(uqname);
1548  if (ns != NULL)
1549  xmlFree(ns);
1550  return(NULL);
1551  }
1552  memset(ret, 0, sizeof(xmlElement));
1553  ret->type = XML_ELEMENT_DECL;
1554 
1555  /*
1556  * fill the structure.
1557  */
1558  ret->name = xmlStrdup(name);
1559  if (ret->name == NULL) {
1560  xmlVErrMemory(ctxt, "malloc failed");
1561  if (uqname != NULL)
1562  xmlFree(uqname);
1563  if (ns != NULL)
1564  xmlFree(ns);
1565  xmlFree(ret);
1566  return(NULL);
1567  }
1568  ret->prefix = ns;
1569 
1570  /*
1571  * Validity Check:
1572  * Insertion must not fail
1573  */
1574  if (xmlHashAddEntry2(table, name, ns, ret)) {
1575 #ifdef LIBXML_VALID_ENABLED
1576  /*
1577  * The element is already defined in this DTD.
1578  */
1579  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ELEM_REDEFINED,
1580  "Redefinition of element %s\n",
1581  name, NULL, NULL);
1582 #endif /* LIBXML_VALID_ENABLED */
1584  if (uqname != NULL)
1585  xmlFree(uqname);
1586  return(NULL);
1587  }
1588  /*
1589  * For new element, may have attributes from earlier
1590  * definition in internal subset
1591  */
1592  ret->attributes = oldAttributes;
1593  }
1594 
1595  /*
1596  * Finish to fill the structure.
1597  */
1598  ret->etype = type;
1599  /*
1600  * Avoid a stupid copy when called by the parser
1601  * and flag it by setting a special parent value
1602  * so the parser doesn't unallocate it.
1603  */
1604  if ((ctxt != NULL) && (ctxt->flags & XML_VCTXT_USE_PCTXT)) {
1605  ret->content = content;
1606  if (content != NULL)
1607  content->parent = (xmlElementContentPtr) 1;
1608  } else {
1609  ret->content = xmlCopyDocElementContent(dtd->doc, content);
1610  }
1611 
1612  /*
1613  * Link it to the DTD
1614  */
1615  ret->parent = dtd;
1616  ret->doc = dtd->doc;
1617  if (dtd->last == NULL) {
1618  dtd->children = dtd->last = (xmlNodePtr) ret;
1619  } else {
1620  dtd->last->next = (xmlNodePtr) ret;
1621  ret->prev = dtd->last;
1622  dtd->last = (xmlNodePtr) ret;
1623  }
1624  if (uqname != NULL)
1625  xmlFree(uqname);
1626  return(ret);
1627 }
1628 
1629 static void
1632 }
1633 
1640 void
1643 }
1644 
1645 #ifdef LIBXML_TREE_ENABLED
1646 
1654 static void *
1655 xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1656  xmlElementPtr elem = (xmlElementPtr) payload;
1658 
1659  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
1660  if (cur == NULL) {
1661  xmlVErrMemory(NULL, "malloc failed");
1662  return(NULL);
1663  }
1664  memset(cur, 0, sizeof(xmlElement));
1665  cur->type = XML_ELEMENT_DECL;
1666  cur->etype = elem->etype;
1667  if (elem->name != NULL)
1668  cur->name = xmlStrdup(elem->name);
1669  else
1670  cur->name = NULL;
1671  if (elem->prefix != NULL)
1672  cur->prefix = xmlStrdup(elem->prefix);
1673  else
1674  cur->prefix = NULL;
1675  cur->content = xmlCopyElementContent(elem->content);
1676  /* TODO : rebuild the attribute list on the copy */
1677  cur->attributes = NULL;
1678  return(cur);
1679 }
1680 
1690 xmlCopyElementTable(xmlElementTablePtr table) {
1691  return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1692 }
1693 #endif /* LIBXML_TREE_ENABLED */
1694 
1695 #ifdef LIBXML_OUTPUT_ENABLED
1696 
1704 void
1705 xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
1706  if ((buf == NULL) || (elem == NULL))
1707  return;
1708  switch (elem->etype) {
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, " EMPTY>\n");
1717  break;
1718  case XML_ELEMENT_TYPE_ANY:
1719  xmlBufferWriteChar(buf, "<!ELEMENT ");
1720  if (elem->prefix != NULL) {
1721  xmlBufferWriteCHAR(buf, elem->prefix);
1722  xmlBufferWriteChar(buf, ":");
1723  }
1724  xmlBufferWriteCHAR(buf, elem->name);
1725  xmlBufferWriteChar(buf, " ANY>\n");
1726  break;
1728  xmlBufferWriteChar(buf, "<!ELEMENT ");
1729  if (elem->prefix != NULL) {
1730  xmlBufferWriteCHAR(buf, elem->prefix);
1731  xmlBufferWriteChar(buf, ":");
1732  }
1733  xmlBufferWriteCHAR(buf, elem->name);
1734  xmlBufferWriteChar(buf, " ");
1735  xmlDumpElementContent(buf, elem->content);
1736  xmlBufferWriteChar(buf, ">\n");
1737  break;
1739  xmlBufferWriteChar(buf, "<!ELEMENT ");
1740  if (elem->prefix != NULL) {
1741  xmlBufferWriteCHAR(buf, elem->prefix);
1742  xmlBufferWriteChar(buf, ":");
1743  }
1744  xmlBufferWriteCHAR(buf, elem->name);
1745  xmlBufferWriteChar(buf, " ");
1746  xmlDumpElementContent(buf, elem->content);
1747  xmlBufferWriteChar(buf, ">\n");
1748  break;
1749  default:
1750  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
1751  "Internal: ELEMENT struct corrupted invalid type\n",
1752  NULL);
1753  }
1754 }
1755 
1764 static void
1765 xmlDumpElementDeclScan(void *elem, void *buf,
1766  const xmlChar *name ATTRIBUTE_UNUSED) {
1767  xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1768 }
1769 
1777 void
1778 xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
1779  if ((buf == NULL) || (table == NULL))
1780  return;
1781  xmlHashScan(table, xmlDumpElementDeclScan, buf);
1782 }
1783 #endif /* LIBXML_OUTPUT_ENABLED */
1784 
1797 
1799  if (ret == NULL) {
1800  xmlVErrMemory(NULL, "malloc failed");
1801  return(NULL);
1802  }
1803  memset(ret, 0, sizeof(xmlEnumeration));
1804 
1805  if (name != NULL)
1806  ret->name = xmlStrdup(name);
1807  return(ret);
1808 }
1809 
1816 void
1818  if (cur == NULL) return;
1819 
1820  if (cur->next != NULL) xmlFreeEnumeration(cur->next);
1821 
1822  if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
1823  xmlFree(cur);
1824 }
1825 
1826 #ifdef LIBXML_TREE_ENABLED
1827 
1837 xmlCopyEnumeration(xmlEnumerationPtr cur) {
1839 
1840  if (cur == NULL) return(NULL);
1841  ret = xmlCreateEnumeration((xmlChar *) cur->name);
1842  if (ret == NULL) return(NULL);
1843 
1844  if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
1845  else ret->next = NULL;
1846 
1847  return(ret);
1848 }
1849 #endif /* LIBXML_TREE_ENABLED */
1850 
1851 #ifdef LIBXML_OUTPUT_ENABLED
1852 
1859 static void
1860 xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
1861  if ((buf == NULL) || (cur == NULL))
1862  return;
1863 
1864  xmlBufferWriteCHAR(buf, cur->name);
1865  if (cur->next == NULL)
1866  xmlBufferWriteChar(buf, ")");
1867  else {
1868  xmlBufferWriteChar(buf, " | ");
1869  xmlDumpEnumeration(buf, cur->next);
1870  }
1871 }
1872 #endif /* LIBXML_OUTPUT_ENABLED */
1873 
1874 #ifdef LIBXML_VALID_ENABLED
1875 
1886 static int
1887 xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem, int err) {
1889  int ret = 0;
1890 
1891  if (elem == NULL) return(0);
1892  cur = elem->attributes;
1893  while (cur != NULL) {
1894  if (cur->atype == XML_ATTRIBUTE_ID) {
1895  ret ++;
1896  if ((ret > 1) && (err))
1897  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_MULTIPLE_ID,
1898  "Element %s has too many ID attributes defined : %s\n",
1899  elem->name, cur->name, NULL);
1900  }
1901  cur = cur->nexth;
1902  }
1903  return(ret);
1904 }
1905 #endif /* LIBXML_VALID_ENABLED */
1906 
1913 static void
1915  xmlDictPtr dict;
1916 
1917  if (attr == NULL) return;
1918  if (attr->doc != NULL)
1919  dict = attr->doc->dict;
1920  else
1921  dict = NULL;
1923  if (attr->tree != NULL)
1924  xmlFreeEnumeration(attr->tree);
1925  if (dict) {
1926  if ((attr->elem != NULL) && (!xmlDictOwns(dict, attr->elem)))
1927  xmlFree((xmlChar *) attr->elem);
1928  if ((attr->name != NULL) && (!xmlDictOwns(dict, attr->name)))
1929  xmlFree((xmlChar *) attr->name);
1930  if ((attr->prefix != NULL) && (!xmlDictOwns(dict, attr->prefix)))
1931  xmlFree((xmlChar *) attr->prefix);
1932  if ((attr->defaultValue != NULL) &&
1933  (!xmlDictOwns(dict, attr->defaultValue)))
1934  xmlFree((xmlChar *) attr->defaultValue);
1935  } else {
1936  if (attr->elem != NULL)
1937  xmlFree((xmlChar *) attr->elem);
1938  if (attr->name != NULL)
1939  xmlFree((xmlChar *) attr->name);
1940  if (attr->defaultValue != NULL)
1941  xmlFree((xmlChar *) attr->defaultValue);
1942  if (attr->prefix != NULL)
1943  xmlFree((xmlChar *) attr->prefix);
1944  }
1945  xmlFree(attr);
1946 }
1947 
1948 
1968  xmlDtdPtr dtd, const xmlChar *elem,
1969  const xmlChar *name, const xmlChar *ns,
1971  const xmlChar *defaultValue, xmlEnumerationPtr tree) {
1974  xmlElementPtr elemDef;
1975  xmlDictPtr dict = NULL;
1976 
1977  if (dtd == NULL) {
1979  return(NULL);
1980  }
1981  if (name == NULL) {
1983  return(NULL);
1984  }
1985  if (elem == NULL) {
1987  return(NULL);
1988  }
1989  if (dtd->doc != NULL)
1990  dict = dtd->doc->dict;
1991 
1992 #ifdef LIBXML_VALID_ENABLED
1993  /*
1994  * Check the type and possibly the default value.
1995  */
1996  switch (type) {
1997  case XML_ATTRIBUTE_CDATA:
1998  break;
1999  case XML_ATTRIBUTE_ID:
2000  break;
2001  case XML_ATTRIBUTE_IDREF:
2002  break;
2003  case XML_ATTRIBUTE_IDREFS:
2004  break;
2005  case XML_ATTRIBUTE_ENTITY:
2006  break;
2008  break;
2009  case XML_ATTRIBUTE_NMTOKEN:
2010  break;
2012  break;
2014  break;
2016  break;
2017  default:
2018  xmlErrValid(ctxt, XML_ERR_INTERNAL_ERROR,
2019  "Internal: ATTRIBUTE struct corrupted invalid type\n",
2020  NULL);
2022  return(NULL);
2023  }
2024  if ((defaultValue != NULL) &&
2025  (!xmlValidateAttributeValueInternal(dtd->doc, type, defaultValue))) {
2026  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_DEFAULT,
2027  "Attribute %s of %s: invalid default value\n",
2028  elem, name, defaultValue);
2029  defaultValue = NULL;
2030  if (ctxt != NULL)
2031  ctxt->valid = 0;
2032  }
2033 #endif /* LIBXML_VALID_ENABLED */
2034 
2035  /*
2036  * Check first that an attribute defined in the external subset wasn't
2037  * already defined in the internal subset
2038  */
2039  if ((dtd->doc != NULL) && (dtd->doc->extSubset == dtd) &&
2040  (dtd->doc->intSubset != NULL) &&
2041  (dtd->doc->intSubset->attributes != NULL)) {
2042  ret = xmlHashLookup3(dtd->doc->intSubset->attributes, name, ns, elem);
2043  if (ret != NULL) {
2045  return(NULL);
2046  }
2047  }
2048 
2049  /*
2050  * Create the Attribute table if needed.
2051  */
2053  if (table == NULL) {
2054  table = xmlHashCreateDict(0, dict);
2055  dtd->attributes = (void *) table;
2056  }
2057  if (table == NULL) {
2058  xmlVErrMemory(ctxt,
2059  "xmlAddAttributeDecl: Table creation failed!\n");
2061  return(NULL);
2062  }
2063 
2064 
2066  if (ret == NULL) {
2067  xmlVErrMemory(ctxt, "malloc failed");
2069  return(NULL);
2070  }
2071  memset(ret, 0, sizeof(xmlAttribute));
2072  ret->type = XML_ATTRIBUTE_DECL;
2073 
2074  /*
2075  * fill the structure.
2076  */
2077  ret->atype = type;
2078  /*
2079  * doc must be set before possible error causes call
2080  * to xmlFreeAttribute (because it's used to check on
2081  * dict use)
2082  */
2083  ret->doc = dtd->doc;
2084  if (dict) {
2085  ret->name = xmlDictLookup(dict, name, -1);
2086  ret->prefix = xmlDictLookup(dict, ns, -1);
2087  ret->elem = xmlDictLookup(dict, elem, -1);
2088  } else {
2089  ret->name = xmlStrdup(name);
2090  ret->prefix = xmlStrdup(ns);
2091  ret->elem = xmlStrdup(elem);
2092  }
2093  ret->def = def;
2094  ret->tree = tree;
2095  if (defaultValue != NULL) {
2096  if (dict)
2097  ret->defaultValue = xmlDictLookup(dict, defaultValue, -1);
2098  else
2099  ret->defaultValue = xmlStrdup(defaultValue);
2100  }
2101 
2102  /*
2103  * Validity Check:
2104  * Search the DTD for previous declarations of the ATTLIST
2105  */
2106  if (xmlHashAddEntry3(table, ret->name, ret->prefix, ret->elem, ret) < 0) {
2107 #ifdef LIBXML_VALID_ENABLED
2108  /*
2109  * The attribute is already defined in this DTD.
2110  */
2111  xmlErrValidWarning(ctxt, (xmlNodePtr) dtd, XML_DTD_ATTRIBUTE_REDEFINED,
2112  "Attribute %s of element %s: already defined\n",
2113  name, elem, NULL);
2114 #endif /* LIBXML_VALID_ENABLED */
2116  return(NULL);
2117  }
2118 
2119  /*
2120  * Validity Check:
2121  * Multiple ID per element
2122  */
2123  elemDef = xmlGetDtdElementDesc2(dtd, elem, 1);
2124  if (elemDef != NULL) {
2125 
2126 #ifdef LIBXML_VALID_ENABLED
2127  if ((type == XML_ATTRIBUTE_ID) &&
2128  (xmlScanIDAttributeDecl(NULL, elemDef, 1) != 0)) {
2129  xmlErrValidNode(ctxt, (xmlNodePtr) dtd, XML_DTD_MULTIPLE_ID,
2130  "Element %s has too may ID attributes defined : %s\n",
2131  elem, name, NULL);
2132  if (ctxt != NULL)
2133  ctxt->valid = 0;
2134  }
2135 #endif /* LIBXML_VALID_ENABLED */
2136 
2137  /*
2138  * Insert namespace default def first they need to be
2139  * processed first.
2140  */
2141  if ((xmlStrEqual(ret->name, BAD_CAST "xmlns")) ||
2142  ((ret->prefix != NULL &&
2143  (xmlStrEqual(ret->prefix, BAD_CAST "xmlns"))))) {
2144  ret->nexth = elemDef->attributes;
2145  elemDef->attributes = ret;
2146  } else {
2147  xmlAttributePtr tmp = elemDef->attributes;
2148 
2149  while ((tmp != NULL) &&
2150  ((xmlStrEqual(tmp->name, BAD_CAST "xmlns")) ||
2151  ((ret->prefix != NULL &&
2152  (xmlStrEqual(ret->prefix, BAD_CAST "xmlns")))))) {
2153  if (tmp->nexth == NULL)
2154  break;
2155  tmp = tmp->nexth;
2156  }
2157  if (tmp != NULL) {
2158  ret->nexth = tmp->nexth;
2159  tmp->nexth = ret;
2160  } else {
2161  ret->nexth = elemDef->attributes;
2162  elemDef->attributes = ret;
2163  }
2164  }
2165  }
2166 
2167  /*
2168  * Link it to the DTD
2169  */
2170  ret->parent = dtd;
2171  if (dtd->last == NULL) {
2172  dtd->children = dtd->last = (xmlNodePtr) ret;
2173  } else {
2174  dtd->last->next = (xmlNodePtr) ret;
2175  ret->prev = dtd->last;
2176  dtd->last = (xmlNodePtr) ret;
2177  }
2178  return(ret);
2179 }
2180 
2181 static void
2184 }
2185 
2192 void
2195 }
2196 
2197 #ifdef LIBXML_TREE_ENABLED
2198 
2206 static void *
2207 xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2208  xmlAttributePtr attr = (xmlAttributePtr) payload;
2210 
2212  if (cur == NULL) {
2213  xmlVErrMemory(NULL, "malloc failed");
2214  return(NULL);
2215  }
2216  memset(cur, 0, sizeof(xmlAttribute));
2217  cur->type = XML_ATTRIBUTE_DECL;
2218  cur->atype = attr->atype;
2219  cur->def = attr->def;
2220  cur->tree = xmlCopyEnumeration(attr->tree);
2221  if (attr->elem != NULL)
2222  cur->elem = xmlStrdup(attr->elem);
2223  if (attr->name != NULL)
2224  cur->name = xmlStrdup(attr->name);
2225  if (attr->prefix != NULL)
2226  cur->prefix = xmlStrdup(attr->prefix);
2227  if (attr->defaultValue != NULL)
2228  cur->defaultValue = xmlStrdup(attr->defaultValue);
2229  return(cur);
2230 }
2231 
2241 xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2242  return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2243 }
2244 #endif /* LIBXML_TREE_ENABLED */
2245 
2246 #ifdef LIBXML_OUTPUT_ENABLED
2247 
2255 void
2256 xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
2257  if ((buf == NULL) || (attr == NULL))
2258  return;
2259  xmlBufferWriteChar(buf, "<!ATTLIST ");
2260  xmlBufferWriteCHAR(buf, attr->elem);
2261  xmlBufferWriteChar(buf, " ");
2262  if (attr->prefix != NULL) {
2263  xmlBufferWriteCHAR(buf, attr->prefix);
2264  xmlBufferWriteChar(buf, ":");
2265  }
2267  switch (attr->atype) {
2268  case XML_ATTRIBUTE_CDATA:
2269  xmlBufferWriteChar(buf, " CDATA");
2270  break;
2271  case XML_ATTRIBUTE_ID:
2272  xmlBufferWriteChar(buf, " ID");
2273  break;
2274  case XML_ATTRIBUTE_IDREF:
2275  xmlBufferWriteChar(buf, " IDREF");
2276  break;
2277  case XML_ATTRIBUTE_IDREFS:
2278  xmlBufferWriteChar(buf, " IDREFS");
2279  break;
2280  case XML_ATTRIBUTE_ENTITY:
2281  xmlBufferWriteChar(buf, " ENTITY");
2282  break;
2284  xmlBufferWriteChar(buf, " ENTITIES");
2285  break;
2286  case XML_ATTRIBUTE_NMTOKEN:
2287  xmlBufferWriteChar(buf, " NMTOKEN");
2288  break;
2290  xmlBufferWriteChar(buf, " NMTOKENS");
2291  break;
2293  xmlBufferWriteChar(buf, " (");
2294  xmlDumpEnumeration(buf, attr->tree);
2295  break;
2297  xmlBufferWriteChar(buf, " NOTATION (");
2298  xmlDumpEnumeration(buf, attr->tree);
2299  break;
2300  default:
2301  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2302  "Internal: ATTRIBUTE struct corrupted invalid type\n",
2303  NULL);
2304  }
2305  switch (attr->def) {
2306  case XML_ATTRIBUTE_NONE:
2307  break;
2309  xmlBufferWriteChar(buf, " #REQUIRED");
2310  break;
2311  case XML_ATTRIBUTE_IMPLIED:
2312  xmlBufferWriteChar(buf, " #IMPLIED");
2313  break;
2314  case XML_ATTRIBUTE_FIXED:
2315  xmlBufferWriteChar(buf, " #FIXED");
2316  break;
2317  default:
2318  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
2319  "Internal: ATTRIBUTE struct corrupted invalid def\n",
2320  NULL);
2321  }
2322  if (attr->defaultValue != NULL) {
2323  xmlBufferWriteChar(buf, " ");
2324  xmlBufferWriteQuotedString(buf, attr->defaultValue);
2325  }
2326  xmlBufferWriteChar(buf, ">\n");
2327 }
2328 
2336 static void
2337 xmlDumpAttributeDeclScan(void *attr, void *buf,
2338  const xmlChar *name ATTRIBUTE_UNUSED) {
2339  xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2340 }
2341 
2349 void
2350 xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
2351  if ((buf == NULL) || (table == NULL))
2352  return;
2353  xmlHashScan(table, xmlDumpAttributeDeclScan, buf);
2354 }
2355 #endif /* LIBXML_OUTPUT_ENABLED */
2356 
2357 /************************************************************************
2358  * *
2359  * NOTATIONs *
2360  * *
2361  ************************************************************************/
2368 static void
2370  if (nota == NULL) return;
2371  if (nota->name != NULL)
2372  xmlFree((xmlChar *) nota->name);
2373  if (nota->PublicID != NULL)
2374  xmlFree((xmlChar *) nota->PublicID);
2375  if (nota->SystemID != NULL)
2376  xmlFree((xmlChar *) nota->SystemID);
2377  xmlFree(nota);
2378 }
2379 
2380 
2395  const xmlChar *name,
2396  const xmlChar *PublicID, const xmlChar *SystemID) {
2399 
2400  if (dtd == NULL) {
2401  return(NULL);
2402  }
2403  if (name == NULL) {
2404  return(NULL);
2405  }
2406  if ((PublicID == NULL) && (SystemID == NULL)) {
2407  return(NULL);
2408  }
2409 
2410  /*
2411  * Create the Notation table if needed.
2412  */
2414  if (table == NULL) {
2415  xmlDictPtr dict = NULL;
2416  if (dtd->doc != NULL)
2417  dict = dtd->doc->dict;
2418 
2419  dtd->notations = table = xmlHashCreateDict(0, dict);
2420  }
2421  if (table == NULL) {
2422  xmlVErrMemory(ctxt,
2423  "xmlAddNotationDecl: Table creation failed!\n");
2424  return(NULL);
2425  }
2426 
2427  ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2428  if (ret == NULL) {
2429  xmlVErrMemory(ctxt, "malloc failed");
2430  return(NULL);
2431  }
2432  memset(ret, 0, sizeof(xmlNotation));
2433 
2434  /*
2435  * fill the structure.
2436  */
2437  ret->name = xmlStrdup(name);
2438  if (SystemID != NULL)
2439  ret->SystemID = xmlStrdup(SystemID);
2440  if (PublicID != NULL)
2441  ret->PublicID = xmlStrdup(PublicID);
2442 
2443  /*
2444  * Validity Check:
2445  * Check the DTD for previous declarations of the ATTLIST
2446  */
2447  if (xmlHashAddEntry(table, name, ret)) {
2448 #ifdef LIBXML_VALID_ENABLED
2449  xmlErrValid(NULL, XML_DTD_NOTATION_REDEFINED,
2450  "xmlAddNotationDecl: %s already defined\n",
2451  (const char *) name);
2452 #endif /* LIBXML_VALID_ENABLED */
2454  return(NULL);
2455  }
2456  return(ret);
2457 }
2458 
2459 static void
2462 }
2463 
2470 void
2473 }
2474 
2475 #ifdef LIBXML_TREE_ENABLED
2476 
2484 static void *
2485 xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2486  xmlNotationPtr nota = (xmlNotationPtr) payload;
2488 
2489  cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
2490  if (cur == NULL) {
2491  xmlVErrMemory(NULL, "malloc failed");
2492  return(NULL);
2493  }
2494  if (nota->name != NULL)
2495  cur->name = xmlStrdup(nota->name);
2496  else
2497  cur->name = NULL;
2498  if (nota->PublicID != NULL)
2499  cur->PublicID = xmlStrdup(nota->PublicID);
2500  else
2501  cur->PublicID = NULL;
2502  if (nota->SystemID != NULL)
2503  cur->SystemID = xmlStrdup(nota->SystemID);
2504  else
2505  cur->SystemID = NULL;
2506  return(cur);
2507 }
2508 
2518 xmlCopyNotationTable(xmlNotationTablePtr table) {
2519  return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2520 }
2521 #endif /* LIBXML_TREE_ENABLED */
2522 
2523 #ifdef LIBXML_OUTPUT_ENABLED
2524 
2531 void
2532 xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
2533  if ((buf == NULL) || (nota == NULL))
2534  return;
2535  xmlBufferWriteChar(buf, "<!NOTATION ");
2536  xmlBufferWriteCHAR(buf, nota->name);
2537  if (nota->PublicID != NULL) {
2538  xmlBufferWriteChar(buf, " PUBLIC ");
2540  if (nota->SystemID != NULL) {
2541  xmlBufferWriteChar(buf, " ");
2543  }
2544  } else {
2545  xmlBufferWriteChar(buf, " SYSTEM ");
2547  }
2548  xmlBufferWriteChar(buf, " >\n");
2549 }
2550 
2558 static void
2559 xmlDumpNotationDeclScan(void *nota, void *buf,
2560  const xmlChar *name ATTRIBUTE_UNUSED) {
2561  xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2562 }
2563 
2571 void
2572 xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
2573  if ((buf == NULL) || (table == NULL))
2574  return;
2575  xmlHashScan(table, xmlDumpNotationDeclScan, buf);
2576 }
2577 #endif /* LIBXML_OUTPUT_ENABLED */
2578 
2579 /************************************************************************
2580  * *
2581  * IDs *
2582  * *
2583  ************************************************************************/
2591 #define DICT_FREE(str) \
2592  if ((str) && ((!dict) || \
2593  (xmlDictOwns(dict, (const xmlChar *)(str)) == 0))) \
2594  xmlFree((char *)(str));
2595 
2602 static void
2604  xmlChar *dst;
2605  const xmlChar *src;
2606 
2607  if (str == NULL)
2608  return;
2609  src = str;
2610  dst = str;
2611 
2612  while (*src == 0x20) src++;
2613  while (*src != 0) {
2614  if (*src == 0x20) {
2615  while (*src == 0x20) src++;
2616  if (*src != 0)
2617  *dst++ = 0x20;
2618  } else {
2619  *dst++ = *src++;
2620  }
2621  }
2622  *dst = 0;
2623 }
2624 
2625 static int
2627  xmlParserCtxtPtr pctxt;
2628 
2629  if (ctxt == NULL)
2630  return(0);
2631  if ((ctxt->flags & XML_VCTXT_USE_PCTXT) == 0)
2632  return(0);
2633  pctxt = ctxt->userData;
2634  return(pctxt->parseMode == XML_PARSE_READER);
2635 }
2636 
2643 static void
2645  xmlDictPtr dict = NULL;
2646 
2647  if (id == NULL) return;
2648 
2649  if (id->doc != NULL)
2650  dict = id->doc->dict;
2651 
2652  if (id->value != NULL)
2653  DICT_FREE(id->value)
2654  if (id->name != NULL)
2655  DICT_FREE(id->name)
2656  xmlFree(id);
2657 }
2658 
2659 
2671 xmlIDPtr
2673  xmlAttrPtr attr) {
2674  xmlIDPtr ret;
2676 
2677  if (doc == NULL) {
2678  return(NULL);
2679  }
2680  if ((value == NULL) || (value[0] == 0)) {
2681  return(NULL);
2682  }
2683  if (attr == NULL) {
2684  return(NULL);
2685  }
2686 
2687  /*
2688  * Create the ID table if needed.
2689  */
2690  table = (xmlIDTablePtr) doc->ids;
2691  if (table == NULL) {
2692  doc->ids = table = xmlHashCreateDict(0, doc->dict);
2693  }
2694  if (table == NULL) {
2695  xmlVErrMemory(ctxt,
2696  "xmlAddID: Table creation failed!\n");
2697  return(NULL);
2698  }
2699 
2700  ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
2701  if (ret == NULL) {
2702  xmlVErrMemory(ctxt, "malloc failed");
2703  return(NULL);
2704  }
2705 
2706  /*
2707  * fill the structure.
2708  */
2709  ret->value = xmlStrdup(value);
2710  ret->doc = doc;
2711  if (xmlIsStreaming(ctxt)) {
2712  /*
2713  * Operating in streaming mode, attr is gonna disappear
2714  */
2715  if (doc->dict != NULL)
2716  ret->name = xmlDictLookup(doc->dict, attr->name, -1);
2717  else
2718  ret->name = xmlStrdup(attr->name);
2719  ret->attr = NULL;
2720  } else {
2721  ret->attr = attr;
2722  ret->name = NULL;
2723  }
2724  ret->lineno = xmlGetLineNo(attr->parent);
2725 
2726  if (xmlHashAddEntry(table, value, ret) < 0) {
2727 #ifdef LIBXML_VALID_ENABLED
2728  /*
2729  * The id is already defined in this DTD.
2730  */
2731  if (ctxt != NULL) {
2732  xmlErrValidNode(ctxt, attr->parent, XML_DTD_ID_REDEFINED,
2733  "ID %s already defined\n", value, NULL, NULL);
2734  }
2735 #endif /* LIBXML_VALID_ENABLED */
2736  xmlFreeID(ret);
2737  return(NULL);
2738  }
2739  if (attr != NULL)
2740  attr->atype = XML_ATTRIBUTE_ID;
2741  return(ret);
2742 }
2743 
2744 static void
2746  xmlFreeID((xmlIDPtr) id);
2747 }
2748 
2755 void
2758 }
2759 
2773 int
2775  if ((attr == NULL) || (attr->name == NULL)) return(0);
2776  if ((attr->ns != NULL) && (attr->ns->prefix != NULL) &&
2777  (!strcmp((char *) attr->name, "id")) &&
2778  (!strcmp((char *) attr->ns->prefix, "xml")))
2779  return(1);
2780  if (doc == NULL) return(0);
2781  if ((doc->intSubset == NULL) && (doc->extSubset == NULL) &&
2782  (doc->type != XML_HTML_DOCUMENT_NODE)) {
2783  return(0);
2784  } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
2785  if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
2786  ((xmlStrEqual(BAD_CAST "name", attr->name)) &&
2787  ((elem == NULL) || (xmlStrEqual(elem->name, BAD_CAST "a")))))
2788  return(1);
2789  return(0);
2790  } else if (elem == NULL) {
2791  return(0);
2792  } else {
2793  xmlAttributePtr attrDecl = NULL;
2794 
2795  xmlChar felem[50], fattr[50];
2796  xmlChar *fullelemname, *fullattrname;
2797 
2798  fullelemname = (elem->ns != NULL && elem->ns->prefix != NULL) ?
2799  xmlBuildQName(elem->name, elem->ns->prefix, felem, 50) :
2800  (xmlChar *)elem->name;
2801 
2802  fullattrname = (attr->ns != NULL && attr->ns->prefix != NULL) ?
2803  xmlBuildQName(attr->name, attr->ns->prefix, fattr, 50) :
2804  (xmlChar *)attr->name;
2805 
2806  if (fullelemname != NULL && fullattrname != NULL) {
2807  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullelemname,
2808  fullattrname);
2809  if ((attrDecl == NULL) && (doc->extSubset != NULL))
2810  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullelemname,
2811  fullattrname);
2812  }
2813 
2814  if ((fullattrname != fattr) && (fullattrname != attr->name))
2815  xmlFree(fullattrname);
2816  if ((fullelemname != felem) && (fullelemname != elem->name))
2817  xmlFree(fullelemname);
2818 
2819  if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
2820  return(1);
2821  }
2822  return(0);
2823 }
2824 
2834 int
2837  xmlIDPtr id;
2838  xmlChar *ID;
2839 
2840  if (doc == NULL) return(-1);
2841  if (attr == NULL) return(-1);
2842 
2843  table = (xmlIDTablePtr) doc->ids;
2844  if (table == NULL)
2845  return(-1);
2846 
2847  ID = xmlNodeListGetString(doc, attr->children, 1);
2848  if (ID == NULL)
2849  return(-1);
2851 
2852  id = xmlHashLookup(table, ID);
2853  if (id == NULL || id->attr != attr) {
2854  xmlFree(ID);
2855  return(-1);
2856  }
2857 
2859  xmlFree(ID);
2860  attr->atype = 0;
2861  return(0);
2862 }
2863 
2873 xmlAttrPtr
2876  xmlIDPtr id;
2877 
2878  if (doc == NULL) {
2879  return(NULL);
2880  }
2881 
2882  if (ID == NULL) {
2883  return(NULL);
2884  }
2885 
2886  table = (xmlIDTablePtr) doc->ids;
2887  if (table == NULL)
2888  return(NULL);
2889 
2890  id = xmlHashLookup(table, ID);
2891  if (id == NULL)
2892  return(NULL);
2893  if (id->attr == NULL) {
2894  /*
2895  * We are operating on a stream, return a well known reference
2896  * since the attribute node doesn't exist anymore
2897  */
2898  return((xmlAttrPtr) doc);
2899  }
2900  return(id->attr);
2901 }
2902 
2903 /************************************************************************
2904  * *
2905  * Refs *
2906  * *
2907  ************************************************************************/
2908 typedef struct xmlRemoveMemo_t
2909 {
2912 } xmlRemoveMemo;
2913 
2915 
2916 typedef struct xmlValidateMemo_t
2917 {
2919  const xmlChar *name;
2920 } xmlValidateMemo;
2921 
2923 
2930 static void
2933  if (ref == NULL) return;
2934  if (ref->value != NULL)
2935  xmlFree((xmlChar *)ref->value);
2936  if (ref->name != NULL)
2937  xmlFree((xmlChar *)ref->name);
2938  xmlFree(ref);
2939 }
2940 
2947 static void
2949  xmlListPtr list_ref = (xmlListPtr) payload;
2950  if (list_ref == NULL) return;
2951  xmlListDelete(list_ref);
2952 }
2953 
2961 static int
2962 xmlWalkRemoveRef(const void *data, void *user)
2963 {
2964  xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
2965  xmlAttrPtr attr1 = ((xmlRemoveMemoPtr)user)->ap;
2966  xmlListPtr ref_list = ((xmlRemoveMemoPtr)user)->l;
2967 
2968  if (attr0 == attr1) { /* Matched: remove and terminate walk */
2969  xmlListRemoveFirst(ref_list, (void *)data);
2970  return 0;
2971  }
2972  return 1;
2973 }
2974 
2982 static int
2984  const void *data1 ATTRIBUTE_UNUSED)
2985 {
2986  return (0);
2987 }
2988 
3002 xmlRefPtr
3004  xmlAttrPtr attr) {
3005  xmlRefPtr ret;
3007  xmlListPtr ref_list;
3008 
3009  if (doc == NULL) {
3010  return(NULL);
3011  }
3012  if (value == NULL) {
3013  return(NULL);
3014  }
3015  if (attr == NULL) {
3016  return(NULL);
3017  }
3018 
3019  /*
3020  * Create the Ref table if needed.
3021  */
3022  table = (xmlRefTablePtr) doc->refs;
3023  if (table == NULL) {
3024  doc->refs = table = xmlHashCreateDict(0, doc->dict);
3025  }
3026  if (table == NULL) {
3027  xmlVErrMemory(ctxt,
3028  "xmlAddRef: Table creation failed!\n");
3029  return(NULL);
3030  }
3031 
3032  ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
3033  if (ret == NULL) {
3034  xmlVErrMemory(ctxt, "malloc failed");
3035  return(NULL);
3036  }
3037 
3038  /*
3039  * fill the structure.
3040  */
3041  ret->value = xmlStrdup(value);
3042  if (xmlIsStreaming(ctxt)) {
3043  /*
3044  * Operating in streaming mode, attr is gonna disappear
3045  */
3046  ret->name = xmlStrdup(attr->name);
3047  ret->attr = NULL;
3048  } else {
3049  ret->name = NULL;
3050  ret->attr = attr;
3051  }
3052  ret->lineno = xmlGetLineNo(attr->parent);
3053 
3054  /* To add a reference :-
3055  * References are maintained as a list of references,
3056  * Lookup the entry, if no entry create new nodelist
3057  * Add the owning node to the NodeList
3058  * Return the ref
3059  */
3060 
3061  if (NULL == (ref_list = xmlHashLookup(table, value))) {
3062  if (NULL == (ref_list = xmlListCreate(xmlFreeRef, xmlDummyCompare))) {
3063  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3064  "xmlAddRef: Reference list creation failed!\n",
3065  NULL);
3066  goto failed;
3067  }
3068  if (xmlHashAddEntry(table, value, ref_list) < 0) {
3069  xmlListDelete(ref_list);
3070  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3071  "xmlAddRef: Reference list insertion failed!\n",
3072  NULL);
3073  goto failed;
3074  }
3075  }
3076  if (xmlListAppend(ref_list, ret) != 0) {
3077  xmlErrValid(NULL, XML_ERR_INTERNAL_ERROR,
3078  "xmlAddRef: Reference list insertion failed!\n",
3079  NULL);
3080  goto failed;
3081  }
3082  return(ret);
3083 failed:
3084  if (ret != NULL) {
3085  if (ret->value != NULL)
3086  xmlFree((char *)ret->value);
3087  if (ret->name != NULL)
3088  xmlFree((char *)ret->name);
3089  xmlFree(ret);
3090  }
3091  return(NULL);
3092 }
3093 
3102 void
3105 }
3106 
3121 int
3123  if (attr == NULL)
3124  return(0);
3125  if (doc == NULL) {
3126  doc = attr->doc;
3127  if (doc == NULL) return(0);
3128  }
3129 
3130  if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
3131  return(0);
3132  } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
3133  /* TODO @@@ */
3134  return(0);
3135  } else {
3136  xmlAttributePtr attrDecl;
3137 
3138  if (elem == NULL) return(0);
3139  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
3140  if ((attrDecl == NULL) && (doc->extSubset != NULL))
3141  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
3142  elem->name, attr->name);
3143 
3144  if ((attrDecl != NULL) &&
3145  (attrDecl->atype == XML_ATTRIBUTE_IDREF ||
3146  attrDecl->atype == XML_ATTRIBUTE_IDREFS))
3147  return(1);
3148  }
3149  return(0);
3150 }
3151 
3163 int
3165  xmlListPtr ref_list;
3167  xmlChar *ID;
3169 
3170  if (doc == NULL) return(-1);
3171  if (attr == NULL) return(-1);
3172 
3173  table = (xmlRefTablePtr) doc->refs;
3174  if (table == NULL)
3175  return(-1);
3176 
3177  ID = xmlNodeListGetString(doc, attr->children, 1);
3178  if (ID == NULL)
3179  return(-1);
3180 
3181  ref_list = xmlHashLookup(table, ID);
3182  if(ref_list == NULL) {
3183  xmlFree(ID);
3184  return (-1);
3185  }
3186 
3187  /* At this point, ref_list refers to a list of references which
3188  * have the same key as the supplied attr. Our list of references
3189  * is ordered by reference address and we don't have that information
3190  * here to use when removing. We'll have to walk the list and
3191  * check for a matching attribute, when we find one stop the walk
3192  * and remove the entry.
3193  * The list is ordered by reference, so that means we don't have the
3194  * key. Passing the list and the reference to the walker means we
3195  * will have enough data to be able to remove the entry.
3196  */
3197  target.l = ref_list;
3198  target.ap = attr;
3199 
3200  /* Remove the supplied attr from our list */
3201  xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
3202 
3203  /*If the list is empty then remove the list entry in the hash */
3204  if (xmlListEmpty(ref_list))
3206  xmlFree(ID);
3207  return(0);
3208 }
3209 
3221 xmlListPtr
3224 
3225  if (doc == NULL) {
3226  return(NULL);
3227  }
3228 
3229  if (ID == NULL) {
3230  return(NULL);
3231  }
3232 
3233  table = (xmlRefTablePtr) doc->refs;
3234  if (table == NULL)
3235  return(NULL);
3236 
3237  return (xmlHashLookup(table, ID));
3238 }
3239 
3240 /************************************************************************
3241  * *
3242  * Routines for validity checking *
3243  * *
3244  ************************************************************************/
3245 
3260  xmlChar *uqname = NULL, *prefix = NULL;
3261 
3262  if ((dtd == NULL) || (name == NULL)) return(NULL);
3263  if (dtd->elements == NULL)
3264  return(NULL);
3266 
3267  uqname = xmlSplitQName2(name, &prefix);
3268  if (uqname != NULL)
3269  name = uqname;
3270  cur = xmlHashLookup2(table, name, prefix);
3271  if (prefix != NULL) xmlFree(prefix);
3272  if (uqname != NULL) xmlFree(uqname);
3273  return(cur);
3274 }
3286 static xmlElementPtr
3290  xmlChar *uqname = NULL, *prefix = NULL;
3291 
3292  if (dtd == NULL) return(NULL);
3293  if (dtd->elements == NULL) {
3294  xmlDictPtr dict = NULL;
3295 
3296  if (dtd->doc != NULL)
3297  dict = dtd->doc->dict;
3298 
3299  if (!create)
3300  return(NULL);
3301  /*
3302  * Create the Element table if needed.
3303  */
3305  if (table == NULL) {
3306  table = xmlHashCreateDict(0, dict);
3307  dtd->elements = (void *) table;
3308  }
3309  if (table == NULL) {
3310  xmlVErrMemory(NULL, "element table allocation failed");
3311  return(NULL);
3312  }
3313  }
3315 
3316  uqname = xmlSplitQName2(name, &prefix);
3317  if (uqname != NULL)
3318  name = uqname;
3319  cur = xmlHashLookup2(table, name, prefix);
3320  if ((cur == NULL) && (create)) {
3321  cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
3322  if (cur == NULL) {
3323  xmlVErrMemory(NULL, "malloc failed");
3324  return(NULL);
3325  }
3326  memset(cur, 0, sizeof(xmlElement));
3327  cur->type = XML_ELEMENT_DECL;
3328 
3329  /*
3330  * fill the structure.
3331  */
3332  cur->name = xmlStrdup(name);
3333  cur->prefix = xmlStrdup(prefix);
3335 
3336  xmlHashAddEntry2(table, name, prefix, cur);
3337  }
3338  if (prefix != NULL) xmlFree(prefix);
3339  if (uqname != NULL) xmlFree(uqname);
3340  return(cur);
3341 }
3342 
3356  const xmlChar *prefix) {
3358 
3359  if (dtd == NULL) return(NULL);
3360  if (dtd->elements == NULL) return(NULL);
3362 
3363  return(xmlHashLookup2(table, name, prefix));
3364 }
3365 
3382  xmlChar *uqname = NULL, *prefix = NULL;
3383 
3384  if (dtd == NULL) return(NULL);
3385  if (dtd->attributes == NULL) return(NULL);
3386 
3388  if (table == NULL)
3389  return(NULL);
3390 
3391  uqname = xmlSplitQName2(name, &prefix);
3392 
3393  if (uqname != NULL) {
3394  cur = xmlHashLookup3(table, uqname, prefix, elem);
3395  if (prefix != NULL) xmlFree(prefix);
3396  if (uqname != NULL) xmlFree(uqname);
3397  } else
3399  return(cur);
3400 }
3401 
3417  const xmlChar *prefix) {
3419 
3420  if (dtd == NULL) return(NULL);
3421  if (dtd->attributes == NULL) return(NULL);
3423 
3424  return(xmlHashLookup3(table, name, prefix, elem));
3425 }
3426 
3440 
3441  if (dtd == NULL) return(NULL);
3442  if (dtd->notations == NULL) return(NULL);
3444 
3445  return(xmlHashLookup(table, name));
3446 }
3447 
3448 #if defined(LIBXML_VALID_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
3449 
3461 int
3462 xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3463  const xmlChar *notationName) {
3464  xmlNotationPtr notaDecl;
3465  if ((doc == NULL) || (doc->intSubset == NULL) ||
3466  (notationName == NULL)) return(-1);
3467 
3468  notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
3469  if ((notaDecl == NULL) && (doc->extSubset != NULL))
3470  notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
3471 
3472  if ((notaDecl == NULL) && (ctxt != NULL)) {
3473  xmlErrValidNode(ctxt, (xmlNodePtr) doc, XML_DTD_UNKNOWN_NOTATION,
3474  "NOTATION %s is not declared\n",
3475  notationName, NULL, NULL);
3476  return(0);
3477  }
3478  return(1);
3479 }
3480 #endif /* LIBXML_VALID_ENABLED or LIBXML_SCHEMAS_ENABLED */
3481 
3493 int
3495  xmlElementPtr elemDecl;
3496 
3497  if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
3498 
3499  elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
3500  if ((elemDecl == NULL) && (doc->extSubset != NULL))
3501  elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
3502  if (elemDecl == NULL) return(-1);
3503  switch (elemDecl->etype) {
3505  return(-1);
3507  return(0);
3509  /*
3510  * return 1 for EMPTY since we want VC error to pop up
3511  * on <empty> </empty> for example
3512  */
3513  case XML_ELEMENT_TYPE_ANY:
3515  return(1);
3516  }
3517  return(1);
3518 }
3519 
3520 #ifdef LIBXML_VALID_ENABLED
3521 
3522 static int
3523 xmlIsDocNameStartChar(xmlDocPtr doc, int c) {
3524  if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3525  /*
3526  * Use the new checks of production [4] [4a] amd [5] of the
3527  * Update 5 of XML-1.0
3528  */
3529  if (((c >= 'a') && (c <= 'z')) ||
3530  ((c >= 'A') && (c <= 'Z')) ||
3531  (c == '_') || (c == ':') ||
3532  ((c >= 0xC0) && (c <= 0xD6)) ||
3533  ((c >= 0xD8) && (c <= 0xF6)) ||
3534  ((c >= 0xF8) && (c <= 0x2FF)) ||
3535  ((c >= 0x370) && (c <= 0x37D)) ||
3536  ((c >= 0x37F) && (c <= 0x1FFF)) ||
3537  ((c >= 0x200C) && (c <= 0x200D)) ||
3538  ((c >= 0x2070) && (c <= 0x218F)) ||
3539  ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3540  ((c >= 0x3001) && (c <= 0xD7FF)) ||
3541  ((c >= 0xF900) && (c <= 0xFDCF)) ||
3542  ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3543  ((c >= 0x10000) && (c <= 0xEFFFF)))
3544  return(1);
3545  } else {
3546  if (IS_LETTER(c) || (c == '_') || (c == ':'))
3547  return(1);
3548  }
3549  return(0);
3550 }
3551 
3552 static int
3553 xmlIsDocNameChar(xmlDocPtr doc, int c) {
3554  if ((doc == NULL) || (doc->properties & XML_DOC_OLD10) == 0) {
3555  /*
3556  * Use the new checks of production [4] [4a] amd [5] of the
3557  * Update 5 of XML-1.0
3558  */
3559  if (((c >= 'a') && (c <= 'z')) ||
3560  ((c >= 'A') && (c <= 'Z')) ||
3561  ((c >= '0') && (c <= '9')) || /* !start */
3562  (c == '_') || (c == ':') ||
3563  (c == '-') || (c == '.') || (c == 0xB7) || /* !start */
3564  ((c >= 0xC0) && (c <= 0xD6)) ||
3565  ((c >= 0xD8) && (c <= 0xF6)) ||
3566  ((c >= 0xF8) && (c <= 0x2FF)) ||
3567  ((c >= 0x300) && (c <= 0x36F)) || /* !start */
3568  ((c >= 0x370) && (c <= 0x37D)) ||
3569  ((c >= 0x37F) && (c <= 0x1FFF)) ||
3570  ((c >= 0x200C) && (c <= 0x200D)) ||
3571  ((c >= 0x203F) && (c <= 0x2040)) || /* !start */
3572  ((c >= 0x2070) && (c <= 0x218F)) ||
3573  ((c >= 0x2C00) && (c <= 0x2FEF)) ||
3574  ((c >= 0x3001) && (c <= 0xD7FF)) ||
3575  ((c >= 0xF900) && (c <= 0xFDCF)) ||
3576  ((c >= 0xFDF0) && (c <= 0xFFFD)) ||
3577  ((c >= 0x10000) && (c <= 0xEFFFF)))
3578  return(1);
3579  } else {
3580  if ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
3581  (c == '.') || (c == '-') ||
3582  (c == '_') || (c == ':') ||
3583  (IS_COMBINING(c)) ||
3584  (IS_EXTENDER(c)))
3585  return(1);
3586  }
3587  return(0);
3588 }
3589 
3600 static int
3601 xmlValidateNameValueInternal(xmlDocPtr doc, const xmlChar *value) {
3602  const xmlChar *cur;
3603  int val, len;
3604 
3605  if (value == NULL) return(0);
3606  cur = value;
3608  cur += len;
3609  if (!xmlIsDocNameStartChar(doc, val))
3610  return(0);
3611 
3613  cur += len;
3614  while (xmlIsDocNameChar(doc, val)) {
3616  cur += len;
3617  }
3618 
3619  if (val != 0) return(0);
3620 
3621  return(1);
3622 }
3623 
3633 int
3634 xmlValidateNameValue(const xmlChar *value) {
3635  return(xmlValidateNameValueInternal(NULL, value));
3636 }
3637 
3648 static int
3649 xmlValidateNamesValueInternal(xmlDocPtr doc, const xmlChar *value) {
3650  const xmlChar *cur;
3651  int val, len;
3652 
3653  if (value == NULL) return(0);
3654  cur = value;
3656  cur += len;
3657 
3658  if (!xmlIsDocNameStartChar(doc, val))
3659  return(0);
3660 
3662  cur += len;
3663  while (xmlIsDocNameChar(doc, val)) {
3665  cur += len;
3666  }
3667 
3668  /* Should not test IS_BLANK(val) here -- see erratum E20*/
3669  while (val == 0x20) {
3670  while (val == 0x20) {
3672  cur += len;
3673  }
3674 
3675  if (!xmlIsDocNameStartChar(doc, val))
3676  return(0);
3677 
3679  cur += len;
3680 
3681  while (xmlIsDocNameChar(doc, val)) {
3683  cur += len;
3684  }
3685  }
3686 
3687  if (val != 0) return(0);
3688 
3689  return(1);
3690 }
3691 
3701 int
3702 xmlValidateNamesValue(const xmlChar *value) {
3703  return(xmlValidateNamesValueInternal(NULL, value));
3704 }
3705 
3718 static int
3719 xmlValidateNmtokenValueInternal(xmlDocPtr doc, const xmlChar *value) {
3720  const xmlChar *cur;
3721  int val, len;
3722 
3723  if (value == NULL) return(0);
3724  cur = value;
3726  cur += len;
3727 
3728  if (!xmlIsDocNameChar(doc, val))
3729  return(0);
3730 
3732  cur += len;
3733  while (xmlIsDocNameChar(doc, val)) {
3735  cur += len;
3736  }
3737 
3738  if (val != 0) return(0);
3739 
3740  return(1);
3741 }
3742 
3754 int
3755 xmlValidateNmtokenValue(const xmlChar *value) {
3756  return(xmlValidateNmtokenValueInternal(NULL, value));
3757 }
3758 
3771 static int
3772 xmlValidateNmtokensValueInternal(xmlDocPtr doc, const xmlChar *value) {
3773  const xmlChar *cur;
3774  int val, len;
3775 
3776  if (value == NULL) return(0);
3777  cur = value;
3779  cur += len;
3780 
3781  while (IS_BLANK(val)) {
3783  cur += len;
3784  }
3785 
3786  if (!xmlIsDocNameChar(doc, val))
3787  return(0);
3788 
3789  while (xmlIsDocNameChar(doc, val)) {
3791  cur += len;
3792  }
3793 
3794  /* Should not test IS_BLANK(val) here -- see erratum E20*/
3795  while (val == 0x20) {
3796  while (val == 0x20) {
3798  cur += len;
3799  }
3800  if (val == 0) return(1);
3801 
3802  if (!xmlIsDocNameChar(doc, val))
3803  return(0);
3804 
3806  cur += len;
3807 
3808  while (xmlIsDocNameChar(doc, val)) {
3810  cur += len;
3811  }
3812  }
3813 
3814  if (val != 0) return(0);
3815 
3816  return(1);
3817 }
3818 
3830 int
3831 xmlValidateNmtokensValue(const xmlChar *value) {
3832  return(xmlValidateNmtokensValueInternal(NULL, value));
3833 }
3834 
3850 int
3851 xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3853  int ret = 1;
3854 
3855  return(ret);
3856 }
3857 
3869 static int
3870 xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3871  const xmlChar *value) {
3872  switch (type) {
3874  case XML_ATTRIBUTE_IDREFS:
3875  return(xmlValidateNamesValueInternal(doc, value));
3876  case XML_ATTRIBUTE_ENTITY:
3877  case XML_ATTRIBUTE_IDREF:
3878  case XML_ATTRIBUTE_ID:
3880  return(xmlValidateNameValueInternal(doc, value));
3883  return(xmlValidateNmtokensValueInternal(doc, value));
3884  case XML_ATTRIBUTE_NMTOKEN:
3885  return(xmlValidateNmtokenValueInternal(doc, value));
3886  case XML_ATTRIBUTE_CDATA:
3887  break;
3888  }
3889  return(1);
3890 }
3891 
3916 int
3917 xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3918  return(xmlValidateAttributeValueInternal(NULL, type, value));
3919 }
3920 
3950 static int
3951 xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3952  const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3953  int ret = 1;
3954  switch (type) {
3955  case XML_ATTRIBUTE_IDREFS:
3956  case XML_ATTRIBUTE_IDREF:
3957  case XML_ATTRIBUTE_ID:
3960  case XML_ATTRIBUTE_NMTOKEN:
3961  case XML_ATTRIBUTE_CDATA:
3962  break;
3963  case XML_ATTRIBUTE_ENTITY: {
3964  xmlEntityPtr ent;
3965 
3966  ent = xmlGetDocEntity(doc, value);
3967  /* yeah it's a bit messy... */
3968  if ((ent == NULL) && (doc->standalone == 1)) {
3969  doc->standalone = 0;
3970  ent = xmlGetDocEntity(doc, value);
3971  }
3972  if (ent == NULL) {
3973  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3975  "ENTITY attribute %s reference an unknown entity \"%s\"\n",
3976  name, value, NULL);
3977  ret = 0;
3978  } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
3979  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
3981  "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
3982  name, value, NULL);
3983  ret = 0;
3984  }
3985  break;
3986  }
3987  case XML_ATTRIBUTE_ENTITIES: {
3988  xmlChar *dup, *nam = NULL, *cur, save;
3989  xmlEntityPtr ent;
3990 
3991  dup = xmlStrdup(value);
3992  if (dup == NULL)
3993  return(0);
3994  cur = dup;
3995  while (*cur != 0) {
3996  nam = cur;
3997  while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++;
3998  save = *cur;
3999  *cur = 0;
4000  ent = xmlGetDocEntity(doc, nam);
4001  if (ent == NULL) {
4002  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4004  "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
4005  name, nam, NULL);
4006  ret = 0;
4007  } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
4008  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4010  "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
4011  name, nam, NULL);
4012  ret = 0;
4013  }
4014  if (save == 0)
4015  break;
4016  *cur = save;
4017  while (IS_BLANK_CH(*cur)) cur++;
4018  }
4019  xmlFree(dup);
4020  break;
4021  }
4022  case XML_ATTRIBUTE_NOTATION: {
4023  xmlNotationPtr nota;
4024 
4025  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4026  if ((nota == NULL) && (doc->extSubset != NULL))
4027  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4028 
4029  if (nota == NULL) {
4030  xmlErrValidNode(ctxt, (xmlNodePtr) doc,
4032  "NOTATION attribute %s reference an unknown notation \"%s\"\n",
4033  name, value, NULL);
4034  ret = 0;
4035  }
4036  break;
4037  }
4038  }
4039  return(ret);
4040 }
4041 
4066 xmlChar *
4067 xmlValidCtxtNormalizeAttributeValue(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4068  xmlNodePtr elem, const xmlChar *name, const xmlChar *value) {
4069  xmlChar *ret;
4070  xmlAttributePtr attrDecl = NULL;
4071  int extsubset = 0;
4072 
4073  if (doc == NULL) return(NULL);
4074  if (elem == NULL) return(NULL);
4075  if (name == NULL) return(NULL);
4076  if (value == NULL) return(NULL);
4077 
4078  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4079  xmlChar fn[50];
4080  xmlChar *fullname;
4081 
4082  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4083  if (fullname == NULL)
4084  return(NULL);
4085  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, name);
4086  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4087  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname, name);
4088  if (attrDecl != NULL)
4089  extsubset = 1;
4090  }
4091  if ((fullname != fn) && (fullname != elem->name))
4092  xmlFree(fullname);
4093  }
4094  if ((attrDecl == NULL) && (doc->intSubset != NULL))
4095  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4096  if ((attrDecl == NULL) && (doc->extSubset != NULL)) {
4097  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4098  if (attrDecl != NULL)
4099  extsubset = 1;
4100  }
4101 
4102  if (attrDecl == NULL)
4103  return(NULL);
4104  if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4105  return(NULL);
4106 
4107  ret = xmlStrdup(value);
4108  if (ret == NULL)
4109  return(NULL);
4111  if ((doc->standalone) && (extsubset == 1) && (!xmlStrEqual(value, ret))) {
4112  xmlErrValidNode(ctxt, elem, XML_DTD_NOT_STANDALONE,
4113 "standalone: %s on %s value had to be normalized based on external subset declaration\n",
4114  name, elem->name, NULL);
4115  ctxt->valid = 0;
4116  }
4117  return(ret);
4118 }
4119 
4139 xmlChar *
4140 xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
4141  const xmlChar *name, const xmlChar *value) {
4142  xmlChar *ret;
4143  xmlAttributePtr attrDecl = NULL;
4144 
4145  if (doc == NULL) return(NULL);
4146  if (elem == NULL) return(NULL);
4147  if (name == NULL) return(NULL);
4148  if (value == NULL) return(NULL);
4149 
4150  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4151  xmlChar fn[50];
4152  xmlChar *fullname;
4153 
4154  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4155  if (fullname == NULL)
4156  return(NULL);
4157  if ((fullname != fn) && (fullname != elem->name))
4158  xmlFree(fullname);
4159  }
4160  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
4161  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4162  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
4163 
4164  if (attrDecl == NULL)
4165  return(NULL);
4166  if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
4167  return(NULL);
4168 
4169  ret = xmlStrdup(value);
4170  if (ret == NULL)
4171  return(NULL);
4173  return(ret);
4174 }
4175 
4176 static void
4177 xmlValidateAttributeIdCallback(void *payload, void *data,
4178  const xmlChar *name ATTRIBUTE_UNUSED) {
4179  xmlAttributePtr attr = (xmlAttributePtr) payload;
4180  int *count = (int *) data;
4181  if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4182 }
4183 
4202 int
4203 xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4205  int ret = 1;
4206  int val;
4207  CHECK_DTD;
4208  if(attr == NULL) return(1);
4209 
4210  /* Attribute Default Legal */
4211  /* Enumeration */
4212  if (attr->defaultValue != NULL) {
4213  val = xmlValidateAttributeValueInternal(doc, attr->atype,
4214  attr->defaultValue);
4215  if (val == 0) {
4216  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_DEFAULT,
4217  "Syntax of default value for attribute %s of %s is not valid\n",
4218  attr->name, attr->elem, NULL);
4219  }
4220  ret &= val;
4221  }
4222 
4223  /* ID Attribute Default */
4224  if ((attr->atype == XML_ATTRIBUTE_ID)&&
4225  (attr->def != XML_ATTRIBUTE_IMPLIED) &&
4226  (attr->def != XML_ATTRIBUTE_REQUIRED)) {
4227  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_FIXED,
4228  "ID attribute %s of %s is not valid must be #IMPLIED or #REQUIRED\n",
4229  attr->name, attr->elem, NULL);
4230  ret = 0;
4231  }
4232 
4233  /* One ID per Element Type */
4234  if (attr->atype == XML_ATTRIBUTE_ID) {
4235  int nbId;
4236 
4237  /* the trick is that we parse DtD as their own internal subset */
4239  attr->elem);
4240  if (elem != NULL) {
4241  nbId = xmlScanIDAttributeDecl(NULL, elem, 0);
4242  } else {
4244 
4245  /*
4246  * The attribute may be declared in the internal subset and the
4247  * element in the external subset.
4248  */
4249  nbId = 0;
4250  if (doc->intSubset != NULL) {
4251  table = (xmlAttributeTablePtr) doc->intSubset->attributes;
4252  xmlHashScan3(table, NULL, NULL, attr->elem,
4253  xmlValidateAttributeIdCallback, &nbId);
4254  }
4255  }
4256  if (nbId > 1) {
4257 
4258  xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4259  "Element %s has %d ID attribute defined in the internal subset : %s\n",
4260  attr->elem, nbId, attr->name);
4261  } else if (doc->extSubset != NULL) {
4262  int extId = 0;
4263  elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
4264  if (elem != NULL) {
4265  extId = xmlScanIDAttributeDecl(NULL, elem, 0);
4266  }
4267  if (extId > 1) {
4268  xmlErrValidNodeNr(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4269  "Element %s has %d ID attribute defined in the external subset : %s\n",
4270  attr->elem, extId, attr->name);
4271  } else if (extId + nbId > 1) {
4272  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ID_SUBSET,
4273 "Element %s has ID attributes defined in the internal and external subset : %s\n",
4274  attr->elem, attr->name, NULL);
4275  }
4276  }
4277  }
4278 
4279  /* Validity Constraint: Enumeration */
4280  if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
4281  xmlEnumerationPtr tree = attr->tree;
4282  while (tree != NULL) {
4283  if (xmlStrEqual(tree->name, attr->defaultValue)) break;
4284  tree = tree->next;
4285  }
4286  if (tree == NULL) {
4287  xmlErrValidNode(ctxt, (xmlNodePtr) attr, XML_DTD_ATTRIBUTE_VALUE,
4288 "Default value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4289  attr->defaultValue, attr->name, attr->elem);
4290  ret = 0;
4291  }
4292  }
4293 
4294  return(ret);
4295 }
4296 
4313 int
4314 xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4315  xmlElementPtr elem) {
4316  int ret = 1;
4317  xmlElementPtr tst;
4318 
4319  CHECK_DTD;
4320 
4321  if (elem == NULL) return(1);
4322 
4323 #if 0
4324 #ifdef LIBXML_REGEXP_ENABLED
4325  /* Build the regexp associated to the content model */
4326  ret = xmlValidBuildContentModel(ctxt, elem);
4327 #endif
4328 #endif
4329 
4330  /* No Duplicate Types */
4331  if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
4333  const xmlChar *name;
4334 
4335  cur = elem->content;
4336  while (cur != NULL) {
4337  if (cur->type != XML_ELEMENT_CONTENT_OR) break;
4338  if (cur->c1 == NULL) break;
4339  if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4340  name = cur->c1->name;
4341  next = cur->c2;
4342  while (next != NULL) {
4343  if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
4344  if ((xmlStrEqual(next->name, name)) &&
4345  (xmlStrEqual(next->prefix, cur->c1->prefix))) {
4346  if (cur->c1->prefix == NULL) {
4347  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4348  "Definition of %s has duplicate references of %s\n",
4349  elem->name, name, NULL);
4350  } else {
4351  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4352  "Definition of %s has duplicate references of %s:%s\n",
4353  elem->name, cur->c1->prefix, name);
4354  }
4355  ret = 0;
4356  }
4357  break;
4358  }
4359  if (next->c1 == NULL) break;
4360  if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
4361  if ((xmlStrEqual(next->c1->name, name)) &&
4362  (xmlStrEqual(next->c1->prefix, cur->c1->prefix))) {
4363  if (cur->c1->prefix == NULL) {
4364  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4365  "Definition of %s has duplicate references to %s\n",
4366  elem->name, name, NULL);
4367  } else {
4368  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_CONTENT_ERROR,
4369  "Definition of %s has duplicate references to %s:%s\n",
4370  elem->name, cur->c1->prefix, name);
4371  }
4372  ret = 0;
4373  }
4374  next = next->c2;
4375  }
4376  }
4377  cur = cur->c2;
4378  }
4379  }
4380 
4381  /* VC: Unique Element Type Declaration */
4382  tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
4383  if ((tst != NULL ) && (tst != elem) &&
4384  ((tst->prefix == elem->prefix) ||
4385  (xmlStrEqual(tst->prefix, elem->prefix))) &&
4386  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4387  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4388  "Redefinition of element %s\n",
4389  elem->name, NULL, NULL);
4390  ret = 0;
4391  }
4392  tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
4393  if ((tst != NULL ) && (tst != elem) &&
4394  ((tst->prefix == elem->prefix) ||
4395  (xmlStrEqual(tst->prefix, elem->prefix))) &&
4396  (tst->etype != XML_ELEMENT_TYPE_UNDEFINED)) {
4397  xmlErrValidNode(ctxt, (xmlNodePtr) elem, XML_DTD_ELEM_REDEFINED,
4398  "Redefinition of element %s\n",
4399  elem->name, NULL, NULL);
4400  ret = 0;
4401  }
4402  /* One ID per Element Type
4403  * already done when registering the attribute
4404  if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
4405  ret = 0;
4406  } */
4407  return(ret);
4408 }
4409 
4435 int
4436 xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4438 {
4439  xmlAttributePtr attrDecl = NULL;
4440  int val;
4441  int ret = 1;
4442 
4443  CHECK_DTD;
4444  if ((elem == NULL) || (elem->name == NULL)) return(0);
4445  if ((attr == NULL) || (attr->name == NULL)) return(0);
4446 
4447  if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
4448  xmlChar fn[50];
4449  xmlChar *fullname;
4450 
4451  fullname = xmlBuildQName(elem->name, elem->ns->prefix, fn, 50);
4452  if (fullname == NULL)
4453  return(0);
4454  if (attr->ns != NULL) {
4455  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4456  attr->name, attr->ns->prefix);
4457  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4458  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4459  attr->name, attr->ns->prefix);
4460  } else {
4461  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname, attr->name);
4462  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4463  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4464  fullname, attr->name);
4465  }
4466  if ((fullname != fn) && (fullname != elem->name))
4467  xmlFree(fullname);
4468  }
4469  if (attrDecl == NULL) {
4470  if (attr->ns != NULL) {
4471  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4472  attr->name, attr->ns->prefix);
4473  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4474  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4475  attr->name, attr->ns->prefix);
4476  } else {
4477  attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4478  elem->name, attr->name);
4479  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4480  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4481  elem->name, attr->name);
4482  }
4483  }
4484 
4485 
4486  /* Validity Constraint: Attribute Value Type */
4487  if (attrDecl == NULL) {
4488  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4489  "No declaration for attribute %s of element %s\n",
4490  attr->name, elem->name, NULL);
4491  return(0);
4492  }
4493  attr->atype = attrDecl->atype;
4494 
4495  val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4496  if (val == 0) {
4497  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4498  "Syntax of value for attribute %s of %s is not valid\n",
4499  attr->name, elem->name, NULL);
4500  ret = 0;
4501  }
4502 
4503  /* Validity constraint: Fixed Attribute Default */
4504  if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4505  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4506  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4507  "Value for attribute %s of %s is different from default \"%s\"\n",
4508  attr->name, elem->name, attrDecl->defaultValue);
4509  ret = 0;
4510  }
4511  }
4512 
4513  /* Validity Constraint: ID uniqueness */
4514  if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4515  if (xmlAddID(ctxt, doc, value, attr) == NULL)
4516  ret = 0;
4517  }
4518 
4519  if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4520  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4521  if (xmlAddRef(ctxt, doc, value, attr) == NULL)
4522  ret = 0;
4523  }
4524 
4525  /* Validity Constraint: Notation Attributes */
4526  if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4527  xmlEnumerationPtr tree = attrDecl->tree;
4528  xmlNotationPtr nota;
4529 
4530  /* First check that the given NOTATION was declared */
4531  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4532  if (nota == NULL)
4533  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4534 
4535  if (nota == NULL) {
4536  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4537  "Value \"%s\" for attribute %s of %s is not a declared Notation\n",
4538  value, attr->name, elem->name);
4539  ret = 0;
4540  }
4541 
4542  /* Second, verify that it's among the list */
4543  while (tree != NULL) {
4544  if (xmlStrEqual(tree->name, value)) break;
4545  tree = tree->next;
4546  }
4547  if (tree == NULL) {
4548  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4549 "Value \"%s\" for attribute %s of %s is not among the enumerated notations\n",
4550  value, attr->name, elem->name);
4551  ret = 0;
4552  }
4553  }
4554 
4555  /* Validity Constraint: Enumeration */
4556  if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4557  xmlEnumerationPtr tree = attrDecl->tree;
4558  while (tree != NULL) {
4559  if (xmlStrEqual(tree->name, value)) break;
4560  tree = tree->next;
4561  }
4562  if (tree == NULL) {
4563  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4564  "Value \"%s\" for attribute %s of %s is not among the enumerated set\n",
4565  value, attr->name, elem->name);
4566  ret = 0;
4567  }
4568  }
4569 
4570  /* Fixed Attribute Default */
4571  if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4572  (!xmlStrEqual(attrDecl->defaultValue, value))) {
4573  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4574  "Value for attribute %s of %s must be \"%s\"\n",
4575  attr->name, elem->name, attrDecl->defaultValue);
4576  ret = 0;
4577  }
4578 
4579  /* Extra check for the attribute value */
4580  ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
4581  attrDecl->atype, value);
4582 
4583  return(ret);
4584 }
4585 
4612 int
4613 xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4614 xmlNodePtr elem, const xmlChar *prefix, xmlNsPtr ns, const xmlChar *value) {
4615  /* xmlElementPtr elemDecl; */
4616  xmlAttributePtr attrDecl = NULL;
4617  int val;
4618  int ret = 1;
4619 
4620  CHECK_DTD;
4621  if ((elem == NULL) || (elem->name == NULL)) return(0);
4622  if ((ns == NULL) || (ns->href == NULL)) return(0);
4623 
4624  if (prefix != NULL) {
4625  xmlChar fn[50];
4626  xmlChar *fullname;
4627 
4628  fullname = xmlBuildQName(elem->name, prefix, fn, 50);
4629  if (fullname == NULL) {
4630  xmlVErrMemory(ctxt, "Validating namespace");
4631  return(0);
4632  }
4633  if (ns->prefix != NULL) {
4634  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, fullname,
4635  ns->prefix, BAD_CAST "xmlns");
4636  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4637  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, fullname,
4638  ns->prefix, BAD_CAST "xmlns");
4639  } else {
4640  attrDecl = xmlGetDtdAttrDesc(doc->intSubset, fullname,
4641  BAD_CAST "xmlns");
4642  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4643  attrDecl = xmlGetDtdAttrDesc(doc->extSubset, fullname,
4644  BAD_CAST "xmlns");
4645  }
4646  if ((fullname != fn) && (fullname != elem->name))
4647  xmlFree(fullname);
4648  }
4649  if (attrDecl == NULL) {
4650  if (ns->prefix != NULL) {
4651  attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
4652  ns->prefix, BAD_CAST "xmlns");
4653  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4654  attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
4655  ns->prefix, BAD_CAST "xmlns");
4656  } else {
4657  attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
4658  elem->name, BAD_CAST "xmlns");
4659  if ((attrDecl == NULL) && (doc->extSubset != NULL))
4660  attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
4661  elem->name, BAD_CAST "xmlns");
4662  }
4663  }
4664 
4665 
4666  /* Validity Constraint: Attribute Value Type */
4667  if (attrDecl == NULL) {
4668  if (ns->prefix != NULL) {
4669  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4670  "No declaration for attribute xmlns:%s of element %s\n",
4671  ns->prefix, elem->name, NULL);
4672  } else {
4673  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_ATTRIBUTE,
4674  "No declaration for attribute xmlns of element %s\n",
4675  elem->name, NULL, NULL);
4676  }
4677  return(0);
4678  }
4679 
4680  val = xmlValidateAttributeValueInternal(doc, attrDecl->atype, value);
4681  if (val == 0) {
4682  if (ns->prefix != NULL) {
4683  xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4684  "Syntax of value for attribute xmlns:%s of %s is not valid\n",
4685  ns->prefix, elem->name, NULL);
4686  } else {
4687  xmlErrValidNode(ctxt, elem, XML_DTD_INVALID_DEFAULT,
4688  "Syntax of value for attribute xmlns of %s is not valid\n",
4689  elem->name, NULL, NULL);
4690  }
4691  ret = 0;
4692  }
4693 
4694  /* Validity constraint: Fixed Attribute Default */
4695  if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
4696  if (!xmlStrEqual(value, attrDecl->defaultValue)) {
4697  if (ns->prefix != NULL) {
4698  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4699  "Value for attribute xmlns:%s of %s is different from default \"%s\"\n",
4700  ns->prefix, elem->name, attrDecl->defaultValue);
4701  } else {
4702  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_DEFAULT,
4703  "Value for attribute xmlns of %s is different from default \"%s\"\n",
4704  elem->name, attrDecl->defaultValue, NULL);
4705  }
4706  ret = 0;
4707  }
4708  }
4709 
4710  /*
4711  * Casting ns to xmlAttrPtr is wrong. We'd need separate functions
4712  * xmlAddID and xmlAddRef for namespace declarations, but it makes
4713  * no practical sense to use ID types anyway.
4714  */
4715 #if 0
4716  /* Validity Constraint: ID uniqueness */
4717  if (attrDecl->atype == XML_ATTRIBUTE_ID) {
4718  if (xmlAddID(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4719  ret = 0;
4720  }
4721 
4722  if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
4723  (attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
4724  if (xmlAddRef(ctxt, doc, value, (xmlAttrPtr) ns) == NULL)
4725  ret = 0;
4726  }
4727 #endif
4728 
4729  /* Validity Constraint: Notation Attributes */
4730  if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
4731  xmlEnumerationPtr tree = attrDecl->tree;
4732  xmlNotationPtr nota;
4733 
4734  /* First check that the given NOTATION was declared */
4735  nota = xmlGetDtdNotationDesc(doc->intSubset, value);
4736  if (nota == NULL)
4737  nota = xmlGetDtdNotationDesc(doc->extSubset, value);
4738 
4739  if (nota == NULL) {
4740  if (ns->prefix != NULL) {
4741  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4742  "Value \"%s\" for attribute xmlns:%s of %s is not a declared Notation\n",
4743  value, ns->prefix, elem->name);
4744  } else {
4745  xmlErrValidNode(ctxt, elem, XML_DTD_UNKNOWN_NOTATION,
4746  "Value \"%s\" for attribute xmlns of %s is not a declared Notation\n",
4747  value, elem->name, NULL);
4748  }
4749  ret = 0;
4750  }
4751 
4752  /* Second, verify that it's among the list */
4753  while (tree != NULL) {
4754  if (xmlStrEqual(tree->name, value)) break;
4755  tree = tree->next;
4756  }
4757  if (tree == NULL) {
4758  if (ns->prefix != NULL) {
4759  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4760 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated notations\n",
4761  value, ns->prefix, elem->name);
4762  } else {
4763  xmlErrValidNode(ctxt, elem, XML_DTD_NOTATION_VALUE,
4764 "Value \"%s\" for attribute xmlns of %s is not among the enumerated notations\n",
4765  value, elem->name, NULL);
4766  }
4767  ret = 0;
4768  }
4769  }
4770 
4771  /* Validity Constraint: Enumeration */
4772  if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
4773  xmlEnumerationPtr tree = attrDecl->tree;
4774  while (tree != NULL) {
4775  if (xmlStrEqual(tree->name, value)) break;
4776  tree = tree->next;
4777  }
4778  if (tree == NULL) {
4779  if (ns->prefix != NULL) {
4780  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4781 "Value \"%s\" for attribute xmlns:%s of %s is not among the enumerated set\n",
4782  value, ns->prefix, elem->name);
4783  } else {
4784  xmlErrValidNode(ctxt, elem, XML_DTD_ATTRIBUTE_VALUE,
4785 "Value \"%s\" for attribute xmlns of %s is not among the enumerated set\n",
4786  value, elem->name, NULL);
4787  }
4788  ret = 0;
4789  }
4790  }
4791 
4792  /* Fixed Attribute Default */
4793  if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
4794  (!xmlStrEqual(attrDecl->defaultValue, value))) {
4795  if (ns->prefix != NULL) {
4796  xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4797  "Value for attribute xmlns:%s of %s must be \"%s\"\n",
4798  ns->prefix, elem->name, attrDecl->defaultValue);
4799  } else {
4800  xmlErrValidNode(ctxt, elem, XML_DTD_ELEM_NAMESPACE,
4801  "Value for attribute xmlns of %s must be \"%s\"\n",
4802  elem->name, attrDecl->defaultValue, NULL);
4803  }
4804  ret = 0;
4805  }
4806 
4807  /* Extra check for the attribute value */
4808  if (ns->prefix != NULL) {
4809  ret &= xmlValidateAttributeValue2(ctxt, doc, ns->prefix,
4810  attrDecl->atype, value);
4811  } else {
4812  ret &= xmlValidateAttributeValue2(ctxt, doc, BAD_CAST "xmlns",
4813  attrDecl->atype, value);
4814  }
4815 
4816  return(ret);
4817 }
4818 
4819 #ifndef LIBXML_REGEXP_ENABLED
4820 
4830 static xmlNodePtr
4831 xmlValidateSkipIgnorable(xmlNodePtr child) {
4832  while (child != NULL) {
4833  switch (child->type) {
4834  /* These things are ignored (skipped) during validation. */
4835  case XML_PI_NODE:
4836  case XML_COMMENT_NODE:
4837  case XML_XINCLUDE_START:
4838  case XML_XINCLUDE_END:
4839  child = child->next;
4840  break;
4841  case XML_TEXT_NODE:
4842  if (xmlIsBlankNode(child))
4843  child = child->next;
4844  else
4845  return(child);
4846  break;
4847  /* keep current node */
4848  default:
4849  return(child);
4850  }
4851  }
4852  return(child);
4853 }
4854 
4866 static int
4867 xmlValidateElementType(xmlValidCtxtPtr ctxt) {
4868  int ret = -1;
4869  int determinist = 1;
4870 
4871  NODE = xmlValidateSkipIgnorable(NODE);
4872  if ((NODE == NULL) && (CONT == NULL))
4873  return(1);
4874  if ((NODE == NULL) &&
4875  ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4876  (CONT->ocur == XML_ELEMENT_CONTENT_OPT))) {
4877  return(1);
4878  }
4879  if (CONT == NULL) return(-1);
4880  if ((NODE != NULL) && (NODE->type == XML_ENTITY_REF_NODE))
4881  return(-2);
4882 
4883  /*
4884  * We arrive here when more states need to be examined
4885  */
4886 cont:
4887 
4888  /*
4889  * We just recovered from a rollback generated by a possible
4890  * epsilon transition, go directly to the analysis phase
4891  */
4892  if (STATE == ROLLBACK_PARENT) {
4893  DEBUG_VALID_MSG("restored parent branch");
4894  DEBUG_VALID_STATE(NODE, CONT)
4895  ret = 1;
4896  goto analyze;
4897  }
4898 
4899  DEBUG_VALID_STATE(NODE, CONT)
4900  /*
4901  * we may have to save a backup state here. This is the equivalent
4902  * of handling epsilon transition in NFAs.
4903  */
4904  if ((CONT != NULL) &&
4905  ((CONT->parent == NULL) ||
4906  (CONT->parent->type != XML_ELEMENT_CONTENT_OR)) &&
4907  ((CONT->ocur == XML_ELEMENT_CONTENT_MULT) ||
4908  (CONT->ocur == XML_ELEMENT_CONTENT_OPT) ||
4909  ((CONT->ocur == XML_ELEMENT_CONTENT_PLUS) && (OCCURRENCE)))) {
4910  DEBUG_VALID_MSG("saving parent branch");
4911  if (vstateVPush(ctxt, CONT, NODE, DEPTH, OCCURS, ROLLBACK_PARENT) < 0)
4912  return(0);
4913  }
4914 
4915 
4916  /*
4917  * Check first if the content matches
4918  */
4919  switch (CONT->type) {
4921  if (NODE == NULL) {
4922  DEBUG_VALID_MSG("pcdata failed no node");
4923  ret = 0;
4924  break;
4925  }
4926  if (NODE->type == XML_TEXT_NODE) {
4927  DEBUG_VALID_MSG("pcdata found, skip to next");
4928  /*
4929  * go to next element in the content model
4930  * skipping ignorable elems
4931  */
4932  do {
4933  NODE = NODE->next;
4934  NODE = xmlValidateSkipIgnorable(NODE);
4935  if ((NODE != NULL) &&
4936  (NODE->type == XML_ENTITY_REF_NODE))
4937  return(-2);
4938  } while ((NODE != NULL) &&
4939  ((NODE->type != XML_ELEMENT_NODE) &&
4940  (NODE->type != XML_TEXT_NODE) &&
4941  (NODE->type != XML_CDATA_SECTION_NODE)));
4942  ret = 1;
4943  break;
4944  } else {
4945  DEBUG_VALID_MSG("pcdata failed");
4946  ret = 0;
4947  break;
4948  }
4949  break;
4951  if (NODE == NULL) {
4952  DEBUG_VALID_MSG("element failed no node");
4953  ret = 0;
4954  break;
4955  }
4956  ret = ((NODE->type == XML_ELEMENT_NODE) &&
4957  (xmlStrEqual(NODE->name, CONT->name)));
4958  if (ret == 1) {
4959  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
4960  ret = (CONT->prefix == NULL);
4961  } else if (CONT->prefix == NULL) {
4962  ret = 0;
4963  } else {
4964  ret = xmlStrEqual(NODE->ns->prefix, CONT->prefix);
4965  }
4966  }
4967  if (ret == 1) {
4968  DEBUG_VALID_MSG("element found, skip to next");
4969  /*
4970  * go to next element in the content model
4971  * skipping ignorable elems
4972  */
4973  do {
4974  NODE = NODE->next;
4975  NODE = xmlValidateSkipIgnorable(NODE);
4976  if ((NODE != NULL) &&
4977  (NODE->type == XML_ENTITY_REF_NODE))
4978  return(-2);
4979  } while ((NODE != NULL) &&
4980  ((NODE->type != XML_ELEMENT_NODE) &&
4981  (NODE->type != XML_TEXT_NODE) &&
4982  (NODE->type != XML_CDATA_SECTION_NODE)));
4983  } else {
4984  DEBUG_VALID_MSG("element failed");
4985  ret = 0;
4986  break;
4987  }
4988  break;
4990  /*
4991  * Small optimization.
4992  */
4993  if (CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
4994  if ((NODE == NULL) ||
4995  (!xmlStrEqual(NODE->name, CONT->c1->name))) {
4996  DEPTH++;
4997  CONT = CONT->c2;
4998  goto cont;
4999  }
5000  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5001  ret = (CONT->c1->prefix == NULL);
5002  } else if (CONT->c1->prefix == NULL) {
5003  ret = 0;
5004  } else {
5005  ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5006  }
5007  if (ret == 0) {
5008  DEPTH++;
5009  CONT = CONT->c2;
5010  goto cont;
5011  }
5012  }
5013 
5014  /*
5015  * save the second branch 'or' branch
5016  */
5017  DEBUG_VALID_MSG("saving 'or' branch");
5018  if (vstateVPush(ctxt, CONT->c2, NODE, (unsigned char)(DEPTH + 1),
5019  OCCURS, ROLLBACK_OR) < 0)
5020  return(-1);
5021  DEPTH++;
5022  CONT = CONT->c1;
5023  goto cont;
5025  /*
5026  * Small optimization.
5027  */
5028  if ((CONT->c1->type == XML_ELEMENT_CONTENT_ELEMENT) &&
5029  ((CONT->c1->ocur == XML_ELEMENT_CONTENT_OPT) ||
5030  (CONT->c1->ocur == XML_ELEMENT_CONTENT_MULT))) {
5031  if ((NODE == NULL) ||
5032  (!xmlStrEqual(NODE->name, CONT->c1->name))) {
5033  DEPTH++;
5034  CONT = CONT->c2;
5035  goto cont;
5036  }
5037  if ((NODE->ns == NULL) || (NODE->ns->prefix == NULL)) {
5038  ret = (CONT->c1->prefix == NULL);
5039  } else if (CONT->c1->prefix == NULL) {
5040  ret = 0;
5041  } else {
5042  ret = xmlStrEqual(NODE->ns->prefix, CONT->c1->prefix);
5043  }
5044  if (ret == 0) {
5045  DEPTH++;
5046  CONT = CONT->c2;
5047  goto cont;
5048  }
5049  }
5050  DEPTH++;
5051  CONT = CONT->c1;
5052  goto cont;
5053  }
5054 
5055  /*
5056  * At this point handle going up in the tree
5057  */
5058  if (ret == -1) {
5059  DEBUG_VALID_MSG("error found returning");
5060  return(ret);
5061  }