ReactOS 0.4.15-dev-7906-g1b85a5f
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>
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
37static int
38xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
39 const xmlChar *value);
40#endif
41/************************************************************************
42 * *
43 * Error handling routines *
44 * *
45 ************************************************************************/
46
54static 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
92static void LIBXML_ATTR_FORMAT(3,0)
93xmlErrValid(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)
135static void LIBXML_ATTR_FORMAT(4,0)
136xmlErrValidNode(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,
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
177static void LIBXML_ATTR_FORMAT(4,0)
178xmlErrValidNodeNr(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,
201 (const char *) str1,
202 (const char *) str3,
203 NULL, int2, 0, msg, str1, int2, str3);
204}
205
217static void LIBXML_ATTR_FORMAT(4,0)
218xmlErrValidWarning(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,
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
258typedef 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
265static int
266vstateVPush(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
309static int
310vstateVPop(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
343typedef 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
365static int
366vstateVPush(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
413static int
414vstateVPop(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
428static int
429nodeVPush(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}
457static xmlNodePtr
458nodeVPop(xmlValidCtxtPtr ctxt)
459{
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
475static void
476xmlValidPrintNode(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;
493 break;
494 case XML_PI_NODE:
495 xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
496 break;
497 case XML_COMMENT_NODE:
499 break;
502 break;
503 case XML_ENTITY_NODE:
505 break;
508 break;
511 break;
514 break;
517 break;
520 break;
521 case XML_DTD_NODE:
523 break;
524 case XML_ELEMENT_DECL:
526 break;
529 break;
530 case XML_ENTITY_DECL:
532 break;
535 break;
538 break;
539 case XML_XINCLUDE_END:
541 break;
542 }
543}
544
545static void
546xmlValidPrintNodeList(xmlNodePtr cur) {
547 if (cur == NULL)
549 while (cur != NULL) {
550 xmlValidPrintNode(cur);
551 cur = cur->next;
552 }
553}
554
555static void
556xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
557 char expr[5000];
558
559 expr[0] = 0;
561 xmlValidPrintNodeList(cur);
563 xmlSnprintfElementContent(expr, 5000, cont, 1);
565}
566
567static void
568xmlValidDebugState(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
593static void
594xmlValidStateDebug(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
645static int
646xmlValidBuildAContentModel(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];
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))
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) &&
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 }
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) &&
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}
799int
800xmlValidBuildContentModel(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
867xmlValidCtxtPtr 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
886void
887xmlFreeValidCtxt(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
1079}
1080
1088void
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
1154void
1157}
1158
1159#ifdef LIBXML_OUTPUT_ENABLED
1167static void
1168xmlDumpElementOccur(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
1191static void
1192xmlDumpElementContent(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) {
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
1267void
1268xmlSprintfElementContent(char *buf ATTRIBUTE_UNUSED,
1270 int englob ATTRIBUTE_UNUSED) {
1271}
1272#endif /* LIBXML_OUTPUT_ENABLED */
1273
1284void
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
1388static 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;
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 {
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
1629static void
1632}
1633
1640void
1643}
1644
1645#ifdef LIBXML_TREE_ENABLED
1654static void *
1655xmlCopyElement(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
1656 xmlElementPtr elem = (xmlElementPtr) payload;
1658
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
1690xmlCopyElementTable(xmlElementTablePtr table) {
1691 return((xmlElementTablePtr) xmlHashCopy(table, xmlCopyElement));
1692}
1693#endif /* LIBXML_TREE_ENABLED */
1694
1695#ifdef LIBXML_OUTPUT_ENABLED
1704void
1705xmlDumpElementDecl(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;
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
1764static void
1765xmlDumpElementDeclScan(void *elem, void *buf,
1766 const xmlChar *name ATTRIBUTE_UNUSED) {
1767 xmlDumpElementDecl((xmlBufferPtr) buf, (xmlElementPtr) elem);
1768}
1769
1777void
1778xmlDumpElementTable(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
1816void
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
1837xmlCopyEnumeration(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
1859static void
1860xmlDumpEnumeration(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
1886static int
1887xmlScanIDAttributeDecl(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
1913static 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) {
1998 break;
1999 case XML_ATTRIBUTE_ID:
2000 break;
2002 break;
2004 break;
2006 break;
2008 break;
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
2181static void
2184}
2185
2192void
2195}
2196
2197#ifdef LIBXML_TREE_ENABLED
2206static void *
2207xmlCopyAttribute(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
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
2241xmlCopyAttributeTable(xmlAttributeTablePtr table) {
2242 return((xmlAttributeTablePtr) xmlHashCopy(table, xmlCopyAttribute));
2243}
2244#endif /* LIBXML_TREE_ENABLED */
2245
2246#ifdef LIBXML_OUTPUT_ENABLED
2255void
2256xmlDumpAttributeDecl(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) {
2269 xmlBufferWriteChar(buf, " CDATA");
2270 break;
2271 case XML_ATTRIBUTE_ID:
2272 xmlBufferWriteChar(buf, " ID");
2273 break;
2275 xmlBufferWriteChar(buf, " IDREF");
2276 break;
2278 xmlBufferWriteChar(buf, " IDREFS");
2279 break;
2281 xmlBufferWriteChar(buf, " ENTITY");
2282 break;
2284 xmlBufferWriteChar(buf, " ENTITIES");
2285 break;
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;
2312 xmlBufferWriteChar(buf, " #IMPLIED");
2313 break;
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
2336static void
2337xmlDumpAttributeDeclScan(void *attr, void *buf,
2338 const xmlChar *name ATTRIBUTE_UNUSED) {
2339 xmlDumpAttributeDecl((xmlBufferPtr) buf, (xmlAttributePtr) attr);
2340}
2341
2349void
2350xmlDumpAttributeTable(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 ************************************************************************/
2368static 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
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
2459static void
2462}
2463
2470void
2473}
2474
2475#ifdef LIBXML_TREE_ENABLED
2484static void *
2485xmlCopyNotation(void *payload, const xmlChar *name ATTRIBUTE_UNUSED) {
2486 xmlNotationPtr nota = (xmlNotationPtr) payload;
2488
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
2518xmlCopyNotationTable(xmlNotationTablePtr table) {
2519 return((xmlNotationTablePtr) xmlHashCopy(table, xmlCopyNotation));
2520}
2521#endif /* LIBXML_TREE_ENABLED */
2522
2523#ifdef LIBXML_OUTPUT_ENABLED
2531void
2532xmlDumpNotationDecl(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
2558static void
2559xmlDumpNotationDeclScan(void *nota, void *buf,
2560 const xmlChar *name ATTRIBUTE_UNUSED) {
2561 xmlDumpNotationDecl((xmlBufferPtr) buf, (xmlNotationPtr) nota);
2562}
2563
2571void
2572xmlDumpNotationTable(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
2602static 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
2625static 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
2643static 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
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
2744static void
2746 xmlFreeID((xmlIDPtr) id);
2747}
2748
2755void
2758}
2759
2773int
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
2834int
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
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 ************************************************************************/
2908typedef struct xmlRemoveMemo_t
2909{
2913
2915
2916typedef struct xmlValidateMemo_t
2917{
2921
2923
2930static 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
2947static void
2949 xmlListPtr list_ref = (xmlListPtr) payload;
2950 if (list_ref == NULL) return;
2951 xmlListDelete(list_ref);
2952}
2953
2961static int
2962xmlWalkRemoveRef(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
2982static int
2984 const void *data1 ATTRIBUTE_UNUSED)
2985{
2986 return (0);
2987}
2988
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);
3083failed:
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
3102void
3105}
3106
3121int
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
3163int
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
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}
3286static 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)) {
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)
3461int
3462xmlValidateNotationUse(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
3493int
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 */
3515 return(1);
3516 }
3517 return(1);
3518}
3519
3520#ifdef LIBXML_VALID_ENABLED
3521
3522static int
3523xmlIsDocNameStartChar(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
3552static int
3553xmlIsDocNameChar(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
3600static int
3601xmlValidateNameValueInternal(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
3633int
3634xmlValidateNameValue(const xmlChar *value) {
3635 return(xmlValidateNameValueInternal(NULL, value));
3636}
3637
3648static int
3649xmlValidateNamesValueInternal(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
3701int
3702xmlValidateNamesValue(const xmlChar *value) {
3703 return(xmlValidateNamesValueInternal(NULL, value));
3704}
3705
3718static int
3719xmlValidateNmtokenValueInternal(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
3754int
3755xmlValidateNmtokenValue(const xmlChar *value) {
3756 return(xmlValidateNmtokenValueInternal(NULL, value));
3757}
3758
3771static int
3772xmlValidateNmtokensValueInternal(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
3830int
3831xmlValidateNmtokensValue(const xmlChar *value) {
3832 return(xmlValidateNmtokensValueInternal(NULL, value));
3833}
3834
3850int
3851xmlValidateNotationDecl(xmlValidCtxtPtr ctxt ATTRIBUTE_UNUSED, xmlDocPtr doc ATTRIBUTE_UNUSED,
3853 int ret = 1;
3854
3855 return(ret);
3856}
3857
3869static int
3870xmlValidateAttributeValueInternal(xmlDocPtr doc, xmlAttributeType type,
3871 const xmlChar *value) {
3872 switch (type) {
3875 return(xmlValidateNamesValueInternal(doc, value));
3878 case XML_ATTRIBUTE_ID:
3880 return(xmlValidateNameValueInternal(doc, value));
3883 return(xmlValidateNmtokensValueInternal(doc, value));
3885 return(xmlValidateNmtokenValueInternal(doc, value));
3887 break;
3888 }
3889 return(1);
3890}
3891
3916int
3917xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
3918 return(xmlValidateAttributeValueInternal(NULL, type, value));
3919}
3920
3950static int
3951xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
3952 const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
3953 int ret = 1;
3954 switch (type) {
3957 case XML_ATTRIBUTE_ID:
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 }
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 }
4023 xmlNotationPtr nota;
4024
4026 if ((nota == NULL) && (doc->extSubset != NULL))
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
4066xmlChar *
4067xmlValidCtxtNormalizeAttributeValue(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];
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))
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
4139xmlChar *
4140xmlValidNormalizeAttributeValue(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];
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))
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
4176static void
4177xmlValidateAttributeIdCallback(void *payload, void *data,
4178 const xmlChar *name ATTRIBUTE_UNUSED) {
4180 int *count = (int *) data;
4181 if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
4182}
4183
4202int
4203xmlValidateAttributeDecl(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
4313int
4314xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
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))) &&
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))) &&
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
4435int
4436xmlValidateOneAttribute(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];
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))
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 */
4532 if (nota == NULL)
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
4612int
4613xmlValidateOneNamespace(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
4614xmlNodePtr 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];
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))
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 */
4736 if (nota == NULL)
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 ==